From b2f680380ddf2f003882e59e00acd6c1952f91fc Mon Sep 17 00:00:00 2001 From: Benjamin LaHaise Date: Wed, 9 Mar 2016 15:05:56 -0500 Subject: x86/mm/32: Add support for 64-bit __get_user() on 32-bit kernels The existing __get_user() implementation does not support fetching 64-bit values on 32-bit x86. Implement this in a way that does not generate any incorrect warnings as cautioned by Russell King. Test code available at: http://www.kvack.org/~bcrl/x86_32-get_user.tar . Signed-off-by: Benjamin LaHaise Cc: Andy Lutomirski Cc: Borislav Petkov Cc: Brian Gerst Cc: Denys Vlasenko Cc: H. Peter Anvin Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: linux-kernel@vger.kernel.org Signed-off-by: Ingo Molnar diff --git a/arch/x86/include/asm/uaccess.h b/arch/x86/include/asm/uaccess.h index a969ae6..8b3fb76 100644 --- a/arch/x86/include/asm/uaccess.h +++ b/arch/x86/include/asm/uaccess.h @@ -333,7 +333,26 @@ do { \ } while (0) #ifdef CONFIG_X86_32 -#define __get_user_asm_u64(x, ptr, retval, errret) (x) = __get_user_bad() +#define __get_user_asm_u64(x, ptr, retval, errret) \ +({ \ + __typeof__(ptr) __ptr = (ptr); \ + asm volatile(ASM_STAC "\n" \ + "1: movl %2,%%eax\n" \ + "2: movl %3,%%edx\n" \ + "3: " ASM_CLAC "\n" \ + ".section .fixup,\"ax\"\n" \ + "4: mov %4,%0\n" \ + " xorl %%eax,%%eax\n" \ + " xorl %%edx,%%edx\n" \ + " jmp 3b\n" \ + ".previous\n" \ + _ASM_EXTABLE(1b, 4b) \ + _ASM_EXTABLE(2b, 4b) \ + : "=r" (retval), "=A"(x) \ + : "m" (__m(__ptr)), "m" __m(((u32 *)(__ptr)) + 1), \ + "i" (errret), "0" (retval)); \ +}) + #define __get_user_asm_ex_u64(x, ptr) (x) = __get_user_bad() #else #define __get_user_asm_u64(x, ptr, retval, errret) \ @@ -420,7 +439,7 @@ do { \ #define __get_user_nocheck(x, ptr, size) \ ({ \ int __gu_err; \ - unsigned long __gu_val; \ + __inttype(*(ptr)) __gu_val; \ __uaccess_begin(); \ __get_user_size(__gu_val, (ptr), (size), __gu_err, -EFAULT); \ __uaccess_end(); \ -- cgit v0.10.2 From a8175ba33542d625430b66a805ef315ea3b4e755 Mon Sep 17 00:00:00 2001 From: Crestez Dan Leonard Date: Fri, 29 Apr 2016 22:05:32 +0300 Subject: iio: ak8975: Support adapters limited to BYTE_DATA The device has simple 8-bit registers but the driver incorrectly uses block or word reads without checking functionality bits. Fix by using i2c_smbus_read_i2c_block_data_or_emulated instead of i2c_smbus_read_i2c_block_data or i2c_smbus_read_word_data. This will check functionality bits and use the fastest available transfer method. Signed-off-by: Crestez Dan Leonard Signed-off-by: Jonathan Cameron diff --git a/drivers/iio/magnetometer/ak8975.c b/drivers/iio/magnetometer/ak8975.c index dbf0661..c24b8a5 100644 --- a/drivers/iio/magnetometer/ak8975.c +++ b/drivers/iio/magnetometer/ak8975.c @@ -430,8 +430,8 @@ static int ak8975_who_i_am(struct i2c_client *client, * AK8975 | DEVICE_ID | NA * AK8963 | DEVICE_ID | NA */ - ret = i2c_smbus_read_i2c_block_data(client, AK09912_REG_WIA1, - 2, wia_val); + ret = i2c_smbus_read_i2c_block_data_or_emulated( + client, AK09912_REG_WIA1, 2, wia_val); if (ret < 0) { dev_err(&client->dev, "Error reading WIA\n"); return ret; @@ -543,9 +543,9 @@ static int ak8975_setup(struct i2c_client *client) } /* Get asa data and store in the device data. */ - ret = i2c_smbus_read_i2c_block_data(client, - data->def->ctrl_regs[ASA_BASE], - 3, data->asa); + ret = i2c_smbus_read_i2c_block_data_or_emulated( + client, data->def->ctrl_regs[ASA_BASE], + 3, data->asa); if (ret < 0) { dev_err(&client->dev, "Not able to read asa data\n"); return ret; @@ -686,6 +686,7 @@ static int ak8975_read_axis(struct iio_dev *indio_dev, int index, int *val) struct ak8975_data *data = iio_priv(indio_dev); const struct i2c_client *client = data->client; const struct ak_def *def = data->def; + u16 buff; int ret; mutex_lock(&data->lock); @@ -694,14 +695,17 @@ static int ak8975_read_axis(struct iio_dev *indio_dev, int index, int *val) if (ret) goto exit; - ret = i2c_smbus_read_word_data(client, def->data_regs[index]); + ret = i2c_smbus_read_i2c_block_data_or_emulated( + client, def->data_regs[index], + sizeof(buff), (u8*)&buff); if (ret < 0) goto exit; mutex_unlock(&data->lock); - /* Clamp to valid range. */ - *val = clamp_t(s16, ret, -def->range, def->range); + /* Swap bytes and convert to valid range. */ + buff = le16_to_cpu(buff); + *val = clamp_t(s16, buff, -def->range, def->range); return IIO_VAL_INT; exit: -- cgit v0.10.2 From 32133be6768257726b57094f673415418cb3dc48 Mon Sep 17 00:00:00 2001 From: Constantin Musca Date: Tue, 3 May 2016 15:05:45 +0300 Subject: iio: accel: Add support for Freescale MMA7660FC Minimal implementation of an IIO driver for the Freescale MMA7660FC 3-axis accelerometer. Datasheet: http://www.nxp.com/files/sensors/doc/data_sheet/MMA7660FC.pdf Includes: - ACPI support; - read_raw for x,y,z axes; - reading and setting the scale (range) parameter. - power management Signed-off-by: Constantin Musca Reviewed-by: Martin Klepplinger Signed-off-by: Jonathan Cameron diff --git a/drivers/iio/accel/Kconfig b/drivers/iio/accel/Kconfig index e4a758c..1df6361 100644 --- a/drivers/iio/accel/Kconfig +++ b/drivers/iio/accel/Kconfig @@ -136,6 +136,16 @@ config MMA7455_SPI To compile this driver as a module, choose M here: the module will be called mma7455_spi. +config MMA7660 + tristate "Freescale MMA7660FC 3-Axis Accelerometer Driver" + depends on I2C + help + Say yes here to get support for the Freescale MMA7660FC 3-Axis + accelerometer. + + Choosing M will build the driver as a module. If so, the module + will be called mma7660. + config MMA8452 tristate "Freescale MMA8452Q and similar Accelerometers Driver" depends on I2C diff --git a/drivers/iio/accel/Makefile b/drivers/iio/accel/Makefile index 71b6794..ba1165f 100644 --- a/drivers/iio/accel/Makefile +++ b/drivers/iio/accel/Makefile @@ -15,6 +15,8 @@ obj-$(CONFIG_MMA7455) += mma7455_core.o obj-$(CONFIG_MMA7455_I2C) += mma7455_i2c.o obj-$(CONFIG_MMA7455_SPI) += mma7455_spi.o +obj-$(CONFIG_MMA7660) += mma7660.o + obj-$(CONFIG_MMA8452) += mma8452.o obj-$(CONFIG_MMA9551_CORE) += mma9551_core.o diff --git a/drivers/iio/accel/mma7660.c b/drivers/iio/accel/mma7660.c new file mode 100644 index 0000000..0acdee5 --- /dev/null +++ b/drivers/iio/accel/mma7660.c @@ -0,0 +1,277 @@ +/** + * Freescale MMA7660FC 3-Axis Accelerometer + * + * Copyright (c) 2016, Intel Corporation. + * + * This file is subject to the terms and conditions of version 2 of + * the GNU General Public License. See the file COPYING in the main + * directory of this archive for more details. + * + * IIO driver for Freescale MMA7660FC; 7-bit I2C address: 0x4c. + */ + +#include +#include +#include +#include +#include + +#define MMA7660_DRIVER_NAME "mma7660" + +#define MMA7660_REG_XOUT 0x00 +#define MMA7660_REG_YOUT 0x01 +#define MMA7660_REG_ZOUT 0x02 +#define MMA7660_REG_OUT_BIT_ALERT BIT(6) + +#define MMA7660_REG_MODE 0x07 +#define MMA7660_REG_MODE_BIT_MODE BIT(0) +#define MMA7660_REG_MODE_BIT_TON BIT(2) + +#define MMA7660_I2C_READ_RETRIES 5 + +/* + * The accelerometer has one measurement range: + * + * -1.5g - +1.5g (6-bit, signed) + * + * scale = (1.5 + 1.5) * 9.81 / (2^6 - 1) = 0.467142857 + */ + +#define MMA7660_SCALE_AVAIL "0.467142857" + +const int mma7660_nscale = 467142857; + +#define MMA7660_CHANNEL(reg, axis) { \ + .type = IIO_ACCEL, \ + .address = reg, \ + .modified = 1, \ + .channel2 = IIO_MOD_##axis, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ +} + +static const struct iio_chan_spec mma7660_channels[] = { + MMA7660_CHANNEL(MMA7660_REG_XOUT, X), + MMA7660_CHANNEL(MMA7660_REG_YOUT, Y), + MMA7660_CHANNEL(MMA7660_REG_ZOUT, Z), +}; + +enum mma7660_mode { + MMA7660_MODE_STANDBY, + MMA7660_MODE_ACTIVE +}; + +struct mma7660_data { + struct i2c_client *client; + struct mutex lock; + enum mma7660_mode mode; +}; + +static IIO_CONST_ATTR(in_accel_scale_available, MMA7660_SCALE_AVAIL); + +static struct attribute *mma7660_attributes[] = { + &iio_const_attr_in_accel_scale_available.dev_attr.attr, + NULL, +}; + +static const struct attribute_group mma7660_attribute_group = { + .attrs = mma7660_attributes +}; + +static int mma7660_set_mode(struct mma7660_data *data, + enum mma7660_mode mode) +{ + int ret; + struct i2c_client *client = data->client; + + if (mode == data->mode) + return 0; + + ret = i2c_smbus_read_byte_data(client, MMA7660_REG_MODE); + if (ret < 0) { + dev_err(&client->dev, "failed to read sensor mode\n"); + return ret; + } + + if (mode == MMA7660_MODE_ACTIVE) { + ret &= ~MMA7660_REG_MODE_BIT_TON; + ret |= MMA7660_REG_MODE_BIT_MODE; + } else { + ret &= ~MMA7660_REG_MODE_BIT_TON; + ret &= ~MMA7660_REG_MODE_BIT_MODE; + } + + ret = i2c_smbus_write_byte_data(client, MMA7660_REG_MODE, ret); + if (ret < 0) { + dev_err(&client->dev, "failed to change sensor mode\n"); + return ret; + } + + data->mode = mode; + + return ret; +} + +static int mma7660_read_accel(struct mma7660_data *data, u8 address) +{ + int ret, retries = MMA7660_I2C_READ_RETRIES; + struct i2c_client *client = data->client; + + /* + * Read data. If the Alert bit is set, the register was read at + * the same time as the device was attempting to update the content. + * The solution is to read the register again. Do this only + * MMA7660_I2C_READ_RETRIES times to avoid spending too much time + * in the kernel. + */ + do { + ret = i2c_smbus_read_byte_data(client, address); + if (ret < 0) { + dev_err(&client->dev, "register read failed\n"); + return ret; + } + } while (retries-- > 0 && ret & MMA7660_REG_OUT_BIT_ALERT); + + if (ret & MMA7660_REG_OUT_BIT_ALERT) { + dev_err(&client->dev, "all register read retries failed\n"); + return -ETIMEDOUT; + } + + return ret; +} + +static int mma7660_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, long mask) +{ + struct mma7660_data *data = iio_priv(indio_dev); + int ret; + + switch (mask) { + case IIO_CHAN_INFO_RAW: + mutex_lock(&data->lock); + ret = mma7660_read_accel(data, chan->address); + mutex_unlock(&data->lock); + if (ret < 0) + return ret; + *val = sign_extend32(ret, 5); + return IIO_VAL_INT; + case IIO_CHAN_INFO_SCALE: + *val = 0; + *val2 = mma7660_nscale; + return IIO_VAL_INT_PLUS_NANO; + default: + return -EINVAL; + } + + return -EINVAL; +} + +static const struct iio_info mma7660_info = { + .driver_module = THIS_MODULE, + .read_raw = mma7660_read_raw, + .attrs = &mma7660_attribute_group, +}; + +static int mma7660_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + int ret; + struct iio_dev *indio_dev; + struct mma7660_data *data; + + indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); + if (!indio_dev) { + dev_err(&client->dev, "iio allocation failed!\n"); + return -ENOMEM; + } + + data = iio_priv(indio_dev); + data->client = client; + i2c_set_clientdata(client, indio_dev); + mutex_init(&data->lock); + data->mode = MMA7660_MODE_STANDBY; + + indio_dev->dev.parent = &client->dev; + indio_dev->info = &mma7660_info; + indio_dev->name = MMA7660_DRIVER_NAME; + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->channels = mma7660_channels; + indio_dev->num_channels = ARRAY_SIZE(mma7660_channels); + + ret = mma7660_set_mode(data, MMA7660_MODE_ACTIVE); + if (ret < 0) + return ret; + + ret = iio_device_register(indio_dev); + if (ret < 0) { + dev_err(&client->dev, "device_register failed\n"); + mma7660_set_mode(data, MMA7660_MODE_STANDBY); + } + + return ret; +} + +static int mma7660_remove(struct i2c_client *client) +{ + struct iio_dev *indio_dev = i2c_get_clientdata(client); + + iio_device_unregister(indio_dev); + + return mma7660_set_mode(iio_priv(indio_dev), MMA7660_MODE_STANDBY); +} + +#ifdef CONFIG_PM_SLEEP +static int mma7660_suspend(struct device *dev) +{ + struct mma7660_data *data; + + data = iio_priv(i2c_get_clientdata(to_i2c_client(dev))); + + return mma7660_set_mode(data, MMA7660_MODE_STANDBY); +} + +static int mma7660_resume(struct device *dev) +{ + struct mma7660_data *data; + + data = iio_priv(i2c_get_clientdata(to_i2c_client(dev))); + + return mma7660_set_mode(data, MMA7660_MODE_ACTIVE); +} + +static SIMPLE_DEV_PM_OPS(mma7660_pm_ops, mma7660_suspend, mma7660_resume); + +#define MMA7660_PM_OPS (&mma7660_pm_ops) +#else +#define MMA7660_PM_OPS NULL +#endif + +static const struct i2c_device_id mma7660_i2c_id[] = { + {"mma7660", 0}, + {} +}; + +static const struct acpi_device_id mma7660_acpi_id[] = { + {"MMA7660", 0}, + {} +}; + +MODULE_DEVICE_TABLE(acpi, mma7660_acpi_id); + +static struct i2c_driver mma7660_driver = { + .driver = { + .name = "mma7660", + .pm = MMA7660_PM_OPS, + .acpi_match_table = ACPI_PTR(mma7660_acpi_id), + }, + .probe = mma7660_probe, + .remove = mma7660_remove, + .id_table = mma7660_i2c_id, +}; + +module_i2c_driver(mma7660_driver); + +MODULE_AUTHOR("Constantin Musca "); +MODULE_DESCRIPTION("Freescale MMA7660FC 3-Axis Accelerometer driver"); +MODULE_LICENSE("GPL v2"); -- cgit v0.10.2 From a91e0b6de468cc4413d8ca260ed4ed0366dfb5b7 Mon Sep 17 00:00:00 2001 From: Stefan Wahren Date: Sat, 23 Apr 2016 19:57:57 +0000 Subject: iio: mxs-lradc: simplify TS registration This patch simplifies the TS registration of mxs-lradc by using devm_input_allocate_device. Signed-off-by: Stefan Wahren Reviewed-by: Marek Vasut Acked-by: Dmitry Torokhov Signed-off-by: Jonathan Cameron diff --git a/drivers/iio/adc/mxs-lradc.c b/drivers/iio/adc/mxs-lradc.c index ad26da1..3d1d370 100644 --- a/drivers/iio/adc/mxs-lradc.c +++ b/drivers/iio/adc/mxs-lradc.c @@ -1120,18 +1120,16 @@ static int mxs_lradc_ts_register(struct mxs_lradc *lradc) { struct input_dev *input; struct device *dev = lradc->dev; - int ret; if (!lradc->use_touchscreen) return 0; - input = input_allocate_device(); + input = devm_input_allocate_device(dev); if (!input) return -ENOMEM; input->name = DRIVER_NAME; input->id.bustype = BUS_HOST; - input->dev.parent = dev; input->open = mxs_lradc_ts_open; input->close = mxs_lradc_ts_close; @@ -1146,11 +1144,8 @@ static int mxs_lradc_ts_register(struct mxs_lradc *lradc) lradc->ts_input = input; input_set_drvdata(input, lradc); - ret = input_register_device(input); - if (ret) - input_free_device(lradc->ts_input); - return ret; + return input_register_device(input); } static void mxs_lradc_ts_unregister(struct mxs_lradc *lradc) @@ -1159,7 +1154,6 @@ static void mxs_lradc_ts_unregister(struct mxs_lradc *lradc) return; mxs_lradc_disable_ts(lradc); - input_unregister_device(lradc->ts_input); } /* -- cgit v0.10.2 From 962ed43a3eac49da65ad90fd1036e74faa5b5066 Mon Sep 17 00:00:00 2001 From: Stefan Wahren Date: Sat, 23 Apr 2016 19:57:58 +0000 Subject: iio: mxs-lradc: remove mxs_lradc_ts_unregister After using devm_input_allocate_device for registration the function mxs_lradc_ts_unregister isn't necessary anymore since mxs_lradc_ts_close already does the job. Signed-off-by: Stefan Wahren Suggested-by: Dmitry Torokhov Acked-by: Dmitry Torokhov Signed-off-by: Jonathan Cameron diff --git a/drivers/iio/adc/mxs-lradc.c b/drivers/iio/adc/mxs-lradc.c index 3d1d370..90242ba 100644 --- a/drivers/iio/adc/mxs-lradc.c +++ b/drivers/iio/adc/mxs-lradc.c @@ -1148,14 +1148,6 @@ static int mxs_lradc_ts_register(struct mxs_lradc *lradc) return input_register_device(input); } -static void mxs_lradc_ts_unregister(struct mxs_lradc *lradc) -{ - if (!lradc->use_touchscreen) - return; - - mxs_lradc_disable_ts(lradc); -} - /* * IRQ Handling */ @@ -1715,13 +1707,11 @@ static int mxs_lradc_probe(struct platform_device *pdev) ret = iio_device_register(iio); if (ret) { dev_err(dev, "Failed to register IIO device\n"); - goto err_ts; + return ret; } return 0; -err_ts: - mxs_lradc_ts_unregister(lradc); err_ts_register: mxs_lradc_hw_stop(lradc); err_dev: @@ -1739,7 +1729,6 @@ static int mxs_lradc_remove(struct platform_device *pdev) struct mxs_lradc *lradc = iio_priv(iio); iio_device_unregister(iio); - mxs_lradc_ts_unregister(lradc); mxs_lradc_hw_stop(lradc); mxs_lradc_trigger_remove(iio); iio_triggered_buffer_cleanup(iio); -- cgit v0.10.2 From 331dd5be97a9a241329a99cbe19e217273ae541b Mon Sep 17 00:00:00 2001 From: Stefan Wahren Date: Sat, 23 Apr 2016 19:57:59 +0000 Subject: iio: mxs-lradc: disable only masked channels in mxs_lradc_hw_stop Disabling of the touchscreen IRQs should be done in mxs_lradc_disable_ts. So disable only the masked virtual channels in mxs_lradc_hw_stop and finally remove the unused function mxs_lradc_irq_en_mask. Signed-off-by: Stefan Wahren Reviewed-by: Marek Vasut Tested-by: Marek Vasut Signed-off-by: Jonathan Cameron diff --git a/drivers/iio/adc/mxs-lradc.c b/drivers/iio/adc/mxs-lradc.c index 90242ba..b84d37c 100644 --- a/drivers/iio/adc/mxs-lradc.c +++ b/drivers/iio/adc/mxs-lradc.c @@ -373,13 +373,6 @@ static u32 mxs_lradc_plate_mask(struct mxs_lradc *lradc) return LRADC_CTRL0_MX28_PLATE_MASK; } -static u32 mxs_lradc_irq_en_mask(struct mxs_lradc *lradc) -{ - if (lradc->soc == IMX23_LRADC) - return LRADC_CTRL1_MX23_LRADC_IRQ_EN_MASK; - return LRADC_CTRL1_MX28_LRADC_IRQ_EN_MASK; -} - static u32 mxs_lradc_irq_mask(struct mxs_lradc *lradc) { if (lradc->soc == IMX23_LRADC) @@ -1496,7 +1489,9 @@ static void mxs_lradc_hw_stop(struct mxs_lradc *lradc) { int i; - mxs_lradc_reg_clear(lradc, mxs_lradc_irq_en_mask(lradc), LRADC_CTRL1); + mxs_lradc_reg_clear(lradc, + lradc->buffer_vchans << LRADC_CTRL1_LRADC_IRQ_EN_OFFSET, + LRADC_CTRL1); for (i = 0; i < LRADC_MAX_DELAY_CHANS; i++) mxs_lradc_reg_wrt(lradc, 0, LRADC_DELAY(i)); -- cgit v0.10.2 From 216912e3f1aa6c7216ba7913c8694c41c885fa04 Mon Sep 17 00:00:00 2001 From: Daniel Baluta Date: Fri, 29 Apr 2016 14:42:35 +0300 Subject: imu: bmi160: Add avail frequency and scale attributes Signed-off-by: Daniel Baluta Signed-off-by: Jonathan Cameron diff --git a/drivers/iio/imu/bmi160/bmi160_core.c b/drivers/iio/imu/bmi160/bmi160_core.c index 0bf92b0..914e2e7 100644 --- a/drivers/iio/imu/bmi160/bmi160_core.c +++ b/drivers/iio/imu/bmi160/bmi160_core.c @@ -20,6 +20,7 @@ #include #include #include +#include #include "bmi160.h" @@ -466,10 +467,36 @@ static int bmi160_write_raw(struct iio_dev *indio_dev, return 0; } +static +IIO_CONST_ATTR(in_accel_sampling_frequency_available, + "0.78125 1.5625 3.125 6.25 12.5 25 50 100 200 400 800 1600"); +static +IIO_CONST_ATTR(in_anglvel_sampling_frequency_available, + "25 50 100 200 400 800 1600 3200"); +static +IIO_CONST_ATTR(in_accel_scale_available, + "0.000598 0.001197 0.002394 0.004788"); +static +IIO_CONST_ATTR(in_anglvel_scale_available, + "0.001065 0.000532 0.000266 0.000133 0.000066"); + +static struct attribute *bmi160_attrs[] = { + &iio_const_attr_in_accel_sampling_frequency_available.dev_attr.attr, + &iio_const_attr_in_anglvel_sampling_frequency_available.dev_attr.attr, + &iio_const_attr_in_accel_scale_available.dev_attr.attr, + &iio_const_attr_in_anglvel_scale_available.dev_attr.attr, + NULL, +}; + +static const struct attribute_group bmi160_attrs_group = { + .attrs = bmi160_attrs, +}; + static const struct iio_info bmi160_info = { .driver_module = THIS_MODULE, .read_raw = bmi160_read_raw, .write_raw = bmi160_write_raw, + .attrs = &bmi160_attrs_group, }; static const char *bmi160_match_acpi_device(struct device *dev) -- cgit v0.10.2 From f59e6b5ae0a9dd94ac9a3d5d95f8650649343dc3 Mon Sep 17 00:00:00 2001 From: "Andrew F. Davis" Date: Sun, 1 May 2016 15:36:51 -0500 Subject: iio: health/afe440x: Fix kernel-doc format Fix kernel-doc formatting for structs, and while we are making little fixes, clarify the module description and update the copywrite. Signed-off-by: Andrew F. Davis Signed-off-by: Jonathan Cameron diff --git a/drivers/iio/health/afe4403.c b/drivers/iio/health/afe4403.c index 88e43f8..2094113 100644 --- a/drivers/iio/health/afe4403.c +++ b/drivers/iio/health/afe4403.c @@ -1,7 +1,7 @@ /* * AFE4403 Heart Rate Monitors and Low-Cost Pulse Oximeters * - * Copyright (C) 2015 Texas Instruments Incorporated - http://www.ti.com/ + * Copyright (C) 2015-2016 Texas Instruments Incorporated - http://www.ti.com/ * Andrew F. Davis * * This program is free software; you can redistribute it and/or modify @@ -103,13 +103,13 @@ #define AFE4403_TIAGAIN_RES_NONE 0x7 /** - * struct afe4403_data - * @dev - Device structure - * @spi - SPI device handle - * @regmap - Register map of the device - * @regulator - Pointer to the regulator for the IC - * @trig - IIO trigger for this device - * @irq - ADC_RDY line interrupt number + * struct afe4403_data - AFE4403 device instance data + * @dev: Device structure + * @spi: SPI device handle + * @regmap: Register map of the device + * @regulator: Pointer to the regulator for the IC + * @trig: IIO trigger for this device + * @irq: ADC_RDY line interrupt number */ struct afe4403_data { struct device *dev; @@ -704,5 +704,5 @@ static struct spi_driver afe4403_spi_driver = { module_spi_driver(afe4403_spi_driver); MODULE_AUTHOR("Andrew F. Davis "); -MODULE_DESCRIPTION("TI AFE4403 Heart Rate and Pulse Oximeter"); +MODULE_DESCRIPTION("TI AFE4403 Heart Rate Monitor and Pulse Oximeter AFE"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/iio/health/afe4404.c b/drivers/iio/health/afe4404.c index 5096a46..7127d03 100644 --- a/drivers/iio/health/afe4404.c +++ b/drivers/iio/health/afe4404.c @@ -1,7 +1,7 @@ /* * AFE4404 Heart Rate Monitors and Low-Cost Pulse Oximeters * - * Copyright (C) 2015 Texas Instruments Incorporated - http://www.ti.com/ + * Copyright (C) 2015-2016 Texas Instruments Incorporated - http://www.ti.com/ * Andrew F. Davis * * This program is free software; you can redistribute it and/or modify @@ -106,12 +106,12 @@ #define AFE4404_TIA_GAIN_RES_2_M 0x7 /** - * struct afe4404_data - * @dev - Device structure - * @regmap - Register map of the device - * @regulator - Pointer to the regulator for the IC - * @trig - IIO trigger for this device - * @irq - ADC_RDY line interrupt number + * struct afe4404_data - AFE4404 device instance data + * @dev: Device structure + * @regmap: Register map of the device + * @regulator: Pointer to the regulator for the IC + * @trig: IIO trigger for this device + * @irq: ADC_RDY line interrupt number */ struct afe4404_data { struct device *dev; @@ -675,5 +675,5 @@ static struct i2c_driver afe4404_i2c_driver = { module_i2c_driver(afe4404_i2c_driver); MODULE_AUTHOR("Andrew F. Davis "); -MODULE_DESCRIPTION("TI AFE4404 Heart Rate and Pulse Oximeter"); +MODULE_DESCRIPTION("TI AFE4404 Heart Rate Monitor and Pulse Oximeter AFE"); MODULE_LICENSE("GPL v2"); -- cgit v0.10.2 From daffd7a75c7e878845ddae8e16d9dc76eea7e2d2 Mon Sep 17 00:00:00 2001 From: "Andrew F. Davis" Date: Sun, 1 May 2016 15:36:52 -0500 Subject: iio: health/afe440x: Remove of_match_ptr and ifdefs The drivers DT tables are not built-in when OF is not enabled, this does not save us enough to justify ugly ifdefs. Clean this up. Signed-off-by: Andrew F. Davis Signed-off-by: Jonathan Cameron diff --git a/drivers/iio/health/afe4403.c b/drivers/iio/health/afe4403.c index 2094113..e3700cf 100644 --- a/drivers/iio/health/afe4403.c +++ b/drivers/iio/health/afe4403.c @@ -498,13 +498,11 @@ static const struct regmap_config afe4403_regmap_config = { .volatile_table = &afe4403_volatile_table, }; -#ifdef CONFIG_OF static const struct of_device_id afe4403_of_match[] = { { .compatible = "ti,afe4403", }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, afe4403_of_match); -#endif static int __maybe_unused afe4403_suspend(struct device *dev) { @@ -694,7 +692,7 @@ MODULE_DEVICE_TABLE(spi, afe4403_ids); static struct spi_driver afe4403_spi_driver = { .driver = { .name = AFE4403_DRIVER_NAME, - .of_match_table = of_match_ptr(afe4403_of_match), + .of_match_table = afe4403_of_match, .pm = &afe4403_pm_ops, }, .probe = afe4403_probe, diff --git a/drivers/iio/health/afe4404.c b/drivers/iio/health/afe4404.c index 7127d03..783b9b4 100644 --- a/drivers/iio/health/afe4404.c +++ b/drivers/iio/health/afe4404.c @@ -469,13 +469,11 @@ static const struct regmap_config afe4404_regmap_config = { .volatile_table = &afe4404_volatile_table, }; -#ifdef CONFIG_OF static const struct of_device_id afe4404_of_match[] = { { .compatible = "ti,afe4404", }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, afe4404_of_match); -#endif static int __maybe_unused afe4404_suspend(struct device *dev) { @@ -665,7 +663,7 @@ MODULE_DEVICE_TABLE(i2c, afe4404_ids); static struct i2c_driver afe4404_i2c_driver = { .driver = { .name = AFE4404_DRIVER_NAME, - .of_match_table = of_match_ptr(afe4404_of_match), + .of_match_table = afe4404_of_match, .pm = &afe4404_pm_ops, }, .probe = afe4404_probe, -- cgit v0.10.2 From e85fa0338b4c0399d7c42837f45f9afb8ede7541 Mon Sep 17 00:00:00 2001 From: "Andrew F. Davis" Date: Sun, 1 May 2016 15:36:53 -0500 Subject: iio: health/afe440x: Remove unneeded initializers The drivers set some register values during initialization that can be set at runtime, these defaults were used in testing but are not necessary, remove these. Signed-off-by: Andrew F. Davis Signed-off-by: Jonathan Cameron diff --git a/drivers/iio/health/afe4403.c b/drivers/iio/health/afe4403.c index e3700cf..5484785 100644 --- a/drivers/iio/health/afe4403.c +++ b/drivers/iio/health/afe4403.c @@ -472,12 +472,7 @@ static const struct iio_trigger_ops afe4403_trigger_ops = { static const struct reg_sequence afe4403_reg_sequences[] = { AFE4403_TIMING_PAIRS, - { AFE440X_CONTROL1, AFE440X_CONTROL1_TIMEREN | 0x000007}, - { AFE4403_TIA_AMB_GAIN, AFE4403_TIAGAIN_RES_1_M }, - { AFE440X_LEDCNTRL, (0x14 << AFE440X_LEDCNTRL_LED1_SHIFT) | - (0x14 << AFE440X_LEDCNTRL_LED2_SHIFT) }, - { AFE440X_CONTROL2, AFE440X_CONTROL2_TX_REF_050 << - AFE440X_CONTROL2_TX_REF_SHIFT }, + { AFE440X_CONTROL1, AFE440X_CONTROL1_TIMEREN }, }; static const struct regmap_range afe4403_yes_ranges[] = { diff --git a/drivers/iio/health/afe4404.c b/drivers/iio/health/afe4404.c index 783b9b4..2d4c522 100644 --- a/drivers/iio/health/afe4404.c +++ b/drivers/iio/health/afe4404.c @@ -443,10 +443,6 @@ static const struct iio_trigger_ops afe4404_trigger_ops = { static const struct reg_sequence afe4404_reg_sequences[] = { AFE4404_TIMING_PAIRS, { AFE440X_CONTROL1, AFE440X_CONTROL1_TIMEREN }, - { AFE4404_TIA_GAIN, AFE4404_TIA_GAIN_RES_50_K }, - { AFE440X_LEDCNTRL, (0xf << AFE4404_LEDCNTRL_ILED1_SHIFT) | - (0x3 << AFE4404_LEDCNTRL_ILED2_SHIFT) | - (0x3 << AFE4404_LEDCNTRL_ILED3_SHIFT) }, { AFE440X_CONTROL2, AFE440X_CONTROL3_OSC_ENABLE }, }; -- cgit v0.10.2 From 81f517270da632c0ddf4c511a086d5aa7e5606ee Mon Sep 17 00:00:00 2001 From: "Andrew F. Davis" Date: Sun, 1 May 2016 15:36:54 -0500 Subject: iio: health/afe440x: Always use separate gain values Locking the two gain stages to the same setting adds no value for us, so initialize them as unlocked and remove the sysfs for unlocking them. This also allows us to greatly simplify showing and setting the gain registers. Signed-off-by: Andrew F. Davis Signed-off-by: Jonathan Cameron diff --git a/Documentation/ABI/testing/sysfs-bus-iio-health-afe440x b/Documentation/ABI/testing/sysfs-bus-iio-health-afe440x index 3740f25..b19053a 100644 --- a/Documentation/ABI/testing/sysfs-bus-iio-health-afe440x +++ b/Documentation/ABI/testing/sysfs-bus-iio-health-afe440x @@ -8,15 +8,6 @@ Description: Transimpedance Amplifier. Y is 1 for Rf1 and Cf1, Y is 2 for Rf2 and Cf2 values. -What: /sys/bus/iio/devices/iio:deviceX/tia_separate_en -Date: December 2015 -KernelVersion: -Contact: Andrew F. Davis -Description: - Enable or disable separate settings for the TransImpedance - Amplifier above, when disabled both values are set by the - first channel. - What: /sys/bus/iio/devices/iio:deviceX/in_intensity_ledY_raw /sys/bus/iio/devices/iio:deviceX/in_intensity_ledY_ambient_raw Date: December 2015 diff --git a/drivers/iio/health/afe4403.c b/drivers/iio/health/afe4403.c index 5484785..bcff528 100644 --- a/drivers/iio/health/afe4403.c +++ b/drivers/iio/health/afe4403.c @@ -180,9 +180,9 @@ static ssize_t afe440x_show_register(struct device *dev, struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct afe4403_data *afe = iio_priv(indio_dev); struct afe440x_attr *afe440x_attr = to_afe440x_attr(attr); - unsigned int reg_val, type; + unsigned int reg_val; int vals[2]; - int ret, val_len; + int ret; ret = regmap_read(afe->regmap, afe440x_attr->reg, ®_val); if (ret) @@ -191,27 +191,13 @@ static ssize_t afe440x_show_register(struct device *dev, reg_val &= afe440x_attr->mask; reg_val >>= afe440x_attr->shift; - switch (afe440x_attr->type) { - case SIMPLE: - type = IIO_VAL_INT; - val_len = 1; - vals[0] = reg_val; - break; - case RESISTANCE: - case CAPACITANCE: - type = IIO_VAL_INT_PLUS_MICRO; - val_len = 2; - if (reg_val < afe440x_attr->table_size) { - vals[0] = afe440x_attr->val_table[reg_val].integer; - vals[1] = afe440x_attr->val_table[reg_val].fract; - break; - } + if (reg_val >= afe440x_attr->table_size) return -EINVAL; - default: - return -EINVAL; - } - return iio_format_value(buf, type, val_len, vals); + vals[0] = afe440x_attr->val_table[reg_val].integer; + vals[1] = afe440x_attr->val_table[reg_val].fract; + + return iio_format_value(buf, IIO_VAL_INT_PLUS_MICRO, 2, vals); } static ssize_t afe440x_store_register(struct device *dev, @@ -227,22 +213,12 @@ static ssize_t afe440x_store_register(struct device *dev, if (ret) return ret; - switch (afe440x_attr->type) { - case SIMPLE: - val = integer; - break; - case RESISTANCE: - case CAPACITANCE: - for (val = 0; val < afe440x_attr->table_size; val++) - if (afe440x_attr->val_table[val].integer == integer && - afe440x_attr->val_table[val].fract == fract) - break; - if (val == afe440x_attr->table_size) - return -EINVAL; - break; - default: + for (val = 0; val < afe440x_attr->table_size; val++) + if (afe440x_attr->val_table[val].integer == integer && + afe440x_attr->val_table[val].fract == fract) + break; + if (val == afe440x_attr->table_size) return -EINVAL; - } ret = regmap_update_bits(afe->regmap, afe440x_attr->reg, afe440x_attr->mask, @@ -253,16 +229,13 @@ static ssize_t afe440x_store_register(struct device *dev, return count; } -static AFE440X_ATTR(tia_separate_en, AFE4403_TIAGAIN, AFE440X_TIAGAIN_ENSEPGAIN, SIMPLE, NULL, 0); - -static AFE440X_ATTR(tia_resistance1, AFE4403_TIAGAIN, AFE4403_TIAGAIN_RES, RESISTANCE, afe4403_res_table, ARRAY_SIZE(afe4403_res_table)); -static AFE440X_ATTR(tia_capacitance1, AFE4403_TIAGAIN, AFE4403_TIAGAIN_CAP, CAPACITANCE, afe4403_cap_table, ARRAY_SIZE(afe4403_cap_table)); +static AFE440X_ATTR(tia_resistance1, AFE4403_TIAGAIN, AFE4403_TIAGAIN_RES, afe4403_res_table); +static AFE440X_ATTR(tia_capacitance1, AFE4403_TIAGAIN, AFE4403_TIAGAIN_CAP, afe4403_cap_table); -static AFE440X_ATTR(tia_resistance2, AFE4403_TIA_AMB_GAIN, AFE4403_TIAGAIN_RES, RESISTANCE, afe4403_res_table, ARRAY_SIZE(afe4403_res_table)); -static AFE440X_ATTR(tia_capacitance2, AFE4403_TIA_AMB_GAIN, AFE4403_TIAGAIN_RES, CAPACITANCE, afe4403_cap_table, ARRAY_SIZE(afe4403_cap_table)); +static AFE440X_ATTR(tia_resistance2, AFE4403_TIA_AMB_GAIN, AFE4403_TIAGAIN_RES, afe4403_res_table); +static AFE440X_ATTR(tia_capacitance2, AFE4403_TIA_AMB_GAIN, AFE4403_TIAGAIN_RES, afe4403_cap_table); static struct attribute *afe440x_attributes[] = { - &afe440x_attr_tia_separate_en.dev_attr.attr, &afe440x_attr_tia_resistance1.dev_attr.attr, &afe440x_attr_tia_capacitance1.dev_attr.attr, &afe440x_attr_tia_resistance2.dev_attr.attr, @@ -473,6 +446,7 @@ static const struct iio_trigger_ops afe4403_trigger_ops = { static const struct reg_sequence afe4403_reg_sequences[] = { AFE4403_TIMING_PAIRS, { AFE440X_CONTROL1, AFE440X_CONTROL1_TIMEREN }, + { AFE4403_TIAGAIN, AFE440X_TIAGAIN_ENSEPGAIN }, }; static const struct regmap_range afe4403_yes_ranges[] = { diff --git a/drivers/iio/health/afe4404.c b/drivers/iio/health/afe4404.c index 2d4c522..b9c1666 100644 --- a/drivers/iio/health/afe4404.c +++ b/drivers/iio/health/afe4404.c @@ -193,9 +193,9 @@ static ssize_t afe440x_show_register(struct device *dev, struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct afe4404_data *afe = iio_priv(indio_dev); struct afe440x_attr *afe440x_attr = to_afe440x_attr(attr); - unsigned int reg_val, type; + unsigned int reg_val; int vals[2]; - int ret, val_len; + int ret; ret = regmap_read(afe->regmap, afe440x_attr->reg, ®_val); if (ret) @@ -204,27 +204,13 @@ static ssize_t afe440x_show_register(struct device *dev, reg_val &= afe440x_attr->mask; reg_val >>= afe440x_attr->shift; - switch (afe440x_attr->type) { - case SIMPLE: - type = IIO_VAL_INT; - val_len = 1; - vals[0] = reg_val; - break; - case RESISTANCE: - case CAPACITANCE: - type = IIO_VAL_INT_PLUS_MICRO; - val_len = 2; - if (reg_val < afe440x_attr->table_size) { - vals[0] = afe440x_attr->val_table[reg_val].integer; - vals[1] = afe440x_attr->val_table[reg_val].fract; - break; - } + if (reg_val >= afe440x_attr->table_size) return -EINVAL; - default: - return -EINVAL; - } - return iio_format_value(buf, type, val_len, vals); + vals[0] = afe440x_attr->val_table[reg_val].integer; + vals[1] = afe440x_attr->val_table[reg_val].fract; + + return iio_format_value(buf, IIO_VAL_INT_PLUS_MICRO, 2, vals); } static ssize_t afe440x_store_register(struct device *dev, @@ -240,22 +226,12 @@ static ssize_t afe440x_store_register(struct device *dev, if (ret) return ret; - switch (afe440x_attr->type) { - case SIMPLE: - val = integer; - break; - case RESISTANCE: - case CAPACITANCE: - for (val = 0; val < afe440x_attr->table_size; val++) - if (afe440x_attr->val_table[val].integer == integer && - afe440x_attr->val_table[val].fract == fract) - break; - if (val == afe440x_attr->table_size) - return -EINVAL; - break; - default: + for (val = 0; val < afe440x_attr->table_size; val++) + if (afe440x_attr->val_table[val].integer == integer && + afe440x_attr->val_table[val].fract == fract) + break; + if (val == afe440x_attr->table_size) return -EINVAL; - } ret = regmap_update_bits(afe->regmap, afe440x_attr->reg, afe440x_attr->mask, @@ -266,16 +242,13 @@ static ssize_t afe440x_store_register(struct device *dev, return count; } -static AFE440X_ATTR(tia_separate_en, AFE4404_TIA_GAIN_SEP, AFE440X_TIAGAIN_ENSEPGAIN, SIMPLE, NULL, 0); - -static AFE440X_ATTR(tia_resistance1, AFE4404_TIA_GAIN, AFE4404_TIA_GAIN_RES, RESISTANCE, afe4404_res_table, ARRAY_SIZE(afe4404_res_table)); -static AFE440X_ATTR(tia_capacitance1, AFE4404_TIA_GAIN, AFE4404_TIA_GAIN_CAP, CAPACITANCE, afe4404_cap_table, ARRAY_SIZE(afe4404_cap_table)); +static AFE440X_ATTR(tia_resistance1, AFE4404_TIA_GAIN, AFE4404_TIA_GAIN_RES, afe4404_res_table); +static AFE440X_ATTR(tia_capacitance1, AFE4404_TIA_GAIN, AFE4404_TIA_GAIN_CAP, afe4404_cap_table); -static AFE440X_ATTR(tia_resistance2, AFE4404_TIA_GAIN_SEP, AFE4404_TIA_GAIN_RES, RESISTANCE, afe4404_res_table, ARRAY_SIZE(afe4404_res_table)); -static AFE440X_ATTR(tia_capacitance2, AFE4404_TIA_GAIN_SEP, AFE4404_TIA_GAIN_CAP, CAPACITANCE, afe4404_cap_table, ARRAY_SIZE(afe4404_cap_table)); +static AFE440X_ATTR(tia_resistance2, AFE4404_TIA_GAIN_SEP, AFE4404_TIA_GAIN_RES, afe4404_res_table); +static AFE440X_ATTR(tia_capacitance2, AFE4404_TIA_GAIN_SEP, AFE4404_TIA_GAIN_CAP, afe4404_cap_table); static struct attribute *afe440x_attributes[] = { - &afe440x_attr_tia_separate_en.dev_attr.attr, &afe440x_attr_tia_resistance1.dev_attr.attr, &afe440x_attr_tia_capacitance1.dev_attr.attr, &afe440x_attr_tia_resistance2.dev_attr.attr, @@ -443,6 +416,7 @@ static const struct iio_trigger_ops afe4404_trigger_ops = { static const struct reg_sequence afe4404_reg_sequences[] = { AFE4404_TIMING_PAIRS, { AFE440X_CONTROL1, AFE440X_CONTROL1_TIMEREN }, + { AFE4404_TIA_GAIN_SEP, AFE440X_TIAGAIN_ENSEPGAIN }, { AFE440X_CONTROL2, AFE440X_CONTROL3_OSC_ENABLE }, }; diff --git a/drivers/iio/health/afe440x.h b/drivers/iio/health/afe440x.h index c671ab7..544bbab 100644 --- a/drivers/iio/health/afe440x.h +++ b/drivers/iio/health/afe440x.h @@ -71,8 +71,7 @@ #define AFE440X_CONTROL1_TIMEREN BIT(8) /* TIAGAIN register fields */ -#define AFE440X_TIAGAIN_ENSEPGAIN_MASK BIT(15) -#define AFE440X_TIAGAIN_ENSEPGAIN_SHIFT 15 +#define AFE440X_TIAGAIN_ENSEPGAIN BIT(15) /* CONTROL2 register fields */ #define AFE440X_CONTROL2_PDN_AFE BIT(0) @@ -133,12 +132,6 @@ struct afe440x_reg_info { .output = true, \ } -enum afe440x_reg_type { - SIMPLE, - RESISTANCE, - CAPACITANCE, -}; - struct afe440x_val_table { int integer; int fract; @@ -167,7 +160,6 @@ struct afe440x_attr { unsigned int reg; unsigned int shift; unsigned int mask; - enum afe440x_reg_type type; const struct afe440x_val_table *val_table; unsigned int table_size; }; @@ -175,7 +167,7 @@ struct afe440x_attr { #define to_afe440x_attr(_dev_attr) \ container_of(_dev_attr, struct afe440x_attr, dev_attr) -#define AFE440X_ATTR(_name, _reg, _field, _type, _table, _size) \ +#define AFE440X_ATTR(_name, _reg, _field, _table) \ struct afe440x_attr afe440x_attr_##_name = { \ .dev_attr = __ATTR(_name, (S_IRUGO | S_IWUSR), \ afe440x_show_register, \ @@ -183,9 +175,8 @@ struct afe440x_attr { .reg = _reg, \ .shift = _field ## _SHIFT, \ .mask = _field ## _MASK, \ - .type = _type, \ .val_table = _table, \ - .table_size = _size, \ + .table_size = ARRAY_SIZE(_table), \ } #endif /* _AFE440X_H */ -- cgit v0.10.2 From 9d3d9a57e4242b155b965f58639a230b212a0ea5 Mon Sep 17 00:00:00 2001 From: "Andrew F. Davis" Date: Sun, 1 May 2016 15:36:55 -0500 Subject: iio: health/afe440x: Fix scan_index assignment The LED channels are not scannable and so scan_index should be negative, fix this here. Signed-off-by: Andrew F. Davis Signed-off-by: Jonathan Cameron diff --git a/drivers/iio/health/afe440x.h b/drivers/iio/health/afe440x.h index 544bbab..583d071 100644 --- a/drivers/iio/health/afe440x.h +++ b/drivers/iio/health/afe440x.h @@ -125,7 +125,7 @@ struct afe440x_reg_info { .type = IIO_CURRENT, \ .channel = _index, \ .address = _index, \ - .scan_index = _index, \ + .scan_index = -1, \ .extend_name = _name, \ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ BIT(IIO_CHAN_INFO_SCALE), \ -- cgit v0.10.2 From 2e0df3a583af9297259ff5512c1a843220492770 Mon Sep 17 00:00:00 2001 From: "Andrew F. Davis" Date: Sun, 1 May 2016 15:36:56 -0500 Subject: iio: health/afe440x: Remove unneeded offset handling No channel in the afe4403 driver has IIO_CHAN_INFO_OFFSET set so remove the handlers for this. Signed-off-by: Andrew F. Davis Signed-off-by: Jonathan Cameron diff --git a/drivers/iio/health/afe4403.c b/drivers/iio/health/afe4403.c index bcff528..cac6090 100644 --- a/drivers/iio/health/afe4403.c +++ b/drivers/iio/health/afe4403.c @@ -293,14 +293,6 @@ static int afe4403_read_raw(struct iio_dev *indio_dev, if (ret) return ret; return IIO_VAL_INT; - case IIO_CHAN_INFO_OFFSET: - ret = regmap_read(afe->regmap, reg_info.offreg, - val); - if (ret) - return ret; - *val &= reg_info.mask; - *val >>= reg_info.shift; - return IIO_VAL_INT; } break; case IIO_CURRENT: @@ -333,15 +325,6 @@ static int afe4403_write_raw(struct iio_dev *indio_dev, const struct afe440x_reg_info reg_info = afe4403_reg_info[chan->address]; switch (chan->type) { - case IIO_INTENSITY: - switch (mask) { - case IIO_CHAN_INFO_OFFSET: - return regmap_update_bits(afe->regmap, - reg_info.offreg, - reg_info.mask, - (val << reg_info.shift)); - } - break; case IIO_CURRENT: switch (mask) { case IIO_CHAN_INFO_RAW: -- cgit v0.10.2 From 606c7e6c1b02054febd78aac1d3cff448c7bd052 Mon Sep 17 00:00:00 2001 From: "Andrew F. Davis" Date: Sun, 1 May 2016 15:36:57 -0500 Subject: iio: health/afe4404: Remove LED3 input channel Input channel LED3 is only an alias for stage ALED2, this virtual channel does nothing for us, remove this channel. Signed-off-by: Andrew F. Davis Signed-off-by: Jonathan Cameron diff --git a/drivers/iio/health/afe4404.c b/drivers/iio/health/afe4404.c index b9c1666..2edb7d7 100644 --- a/drivers/iio/health/afe4404.c +++ b/drivers/iio/health/afe4404.c @@ -126,7 +126,6 @@ enum afe4404_chan_id { ALED1, LED2, ALED2, - LED3, LED1_ALED1, LED2_ALED2, ILED1, @@ -139,7 +138,6 @@ static const struct afe440x_reg_info afe4404_reg_info[] = { [ALED1] = AFE440X_REG_INFO(AFE440X_ALED1VAL, AFE4404_OFFDAC, AFE4404_OFFDAC_CURR_ALED1), [LED2] = AFE440X_REG_INFO(AFE440X_LED2VAL, AFE4404_OFFDAC, AFE4404_OFFDAC_CURR_LED2), [ALED2] = AFE440X_REG_INFO(AFE440X_ALED2VAL, AFE4404_OFFDAC, AFE4404_OFFDAC_CURR_ALED2), - [LED3] = AFE440X_REG_INFO(AFE440X_ALED2VAL, 0, NULL), [LED1_ALED1] = AFE440X_REG_INFO(AFE440X_LED1_ALED1VAL, 0, NULL), [LED2_ALED2] = AFE440X_REG_INFO(AFE440X_LED2_ALED2VAL, 0, NULL), [ILED1] = AFE440X_REG_INFO(AFE440X_LEDCNTRL, 0, AFE4404_LEDCNTRL_ILED1), @@ -153,7 +151,6 @@ static const struct iio_chan_spec afe4404_channels[] = { AFE440X_INTENSITY_CHAN(ALED1, "led1_ambient", BIT(IIO_CHAN_INFO_OFFSET)), AFE440X_INTENSITY_CHAN(LED2, "led2", BIT(IIO_CHAN_INFO_OFFSET)), AFE440X_INTENSITY_CHAN(ALED2, "led2_ambient", BIT(IIO_CHAN_INFO_OFFSET)), - AFE440X_INTENSITY_CHAN(LED3, "led3", BIT(IIO_CHAN_INFO_OFFSET)), AFE440X_INTENSITY_CHAN(LED1_ALED1, "led1-led1_ambient", 0), AFE440X_INTENSITY_CHAN(LED2_ALED2, "led2-led2_ambient", 0), /* LED current */ -- cgit v0.10.2 From 24b9dea764bdf0de8434fb4567e7f62038ba869e Mon Sep 17 00:00:00 2001 From: "Andrew F. Davis" Date: Sun, 1 May 2016 15:36:58 -0500 Subject: iio: health/afe440x: Remove channel names These AFEs have 4 ADC mesuring stages (called LED2, ALED2, LED1, and ALED1 in the datasheet), we map these as channels, these stages can serve different purposes depending on the application. For instance the AFE4404 has an additional LED (LED3), this LED can be timed to be active during stage 2 (or anystage, but the datasheet describes this case and the name of the stage reflects this use). This ability is used further in upcoming parts that tie the front-end gain and the LED timings together. For these reasons we remove explicit naming the channels. Without channel names it is best that the index numbers are in order to match the stage number, reorder the channel numbers. Signed-off-by: Andrew F. Davis Signed-off-by: Jonathan Cameron diff --git a/Documentation/ABI/testing/sysfs-bus-iio-health-afe440x b/Documentation/ABI/testing/sysfs-bus-iio-health-afe440x index b19053a..a067073 100644 --- a/Documentation/ABI/testing/sysfs-bus-iio-health-afe440x +++ b/Documentation/ABI/testing/sysfs-bus-iio-health-afe440x @@ -8,38 +8,35 @@ Description: Transimpedance Amplifier. Y is 1 for Rf1 and Cf1, Y is 2 for Rf2 and Cf2 values. -What: /sys/bus/iio/devices/iio:deviceX/in_intensity_ledY_raw - /sys/bus/iio/devices/iio:deviceX/in_intensity_ledY_ambient_raw -Date: December 2015 +What: /sys/bus/iio/devices/iio:deviceX/in_intensityY_raw +Date: May 2016 KernelVersion: Contact: Andrew F. Davis Description: Get measured values from the ADC for these stages. Y is the - specific LED number. The values are expressed in 24-bit twos - complement. - -What: /sys/bus/iio/devices/iio:deviceX/in_intensity_ledY-ledY_ambient_raw -Date: December 2015 -KernelVersion: -Contact: Andrew F. Davis -Description: - Get differential values from the ADC for these stages. Y is the - specific LED number. The values are expressed in 24-bit twos - complement for the specified LEDs. + specific stage number corresponding to datasheet stage names + as follows: + 1 -> LED2 + 2 -> ALED2/LED3 + 3 -> LED1 + 4 -> ALED1/LED4 + Note that channels 5 and 6 represent LED2-ALED2 and LED1-ALED1 + respectively which simply helper channels containing the + calculated difference in the value of stage 1 - 2 and 3 - 4. + The values are expressed in 24-bit twos complement. -What: /sys/bus/iio/devices/iio:deviceX/out_current_ledY_offset - /sys/bus/iio/devices/iio:deviceX/out_current_ledY_ambient_offset -Date: December 2015 +What: /sys/bus/iio/devices/iio:deviceX/in_intensityY_offset +Date: May 2016 KernelVersion: Contact: Andrew F. Davis Description: Get and set the offset cancellation DAC setting for these stages. The values are expressed in 5-bit sign-magnitude. -What: /sys/bus/iio/devices/iio:deviceX/out_current_ledY_raw -Date: December 2015 +What: /sys/bus/iio/devices/iio:deviceX/out_currentY_raw +Date: May 2016 KernelVersion: Contact: Andrew F. Davis Description: - Get and set the LED current for the specified LED. Y is the - specific LED number. + Get and set the LED current for the specified LED active during + this stage. Y is the specific stage number. diff --git a/drivers/iio/health/afe4403.c b/drivers/iio/health/afe4403.c index cac6090..4a58064 100644 --- a/drivers/iio/health/afe4403.c +++ b/drivers/iio/health/afe4403.c @@ -121,38 +121,38 @@ struct afe4403_data { }; enum afe4403_chan_id { + LED2 = 1, + ALED2, LED1, ALED1, - LED2, - ALED2, - LED1_ALED1, LED2_ALED2, + LED1_ALED1, ILED1, ILED2, }; static const struct afe440x_reg_info afe4403_reg_info[] = { - [LED1] = AFE440X_REG_INFO(AFE440X_LED1VAL, 0, NULL), - [ALED1] = AFE440X_REG_INFO(AFE440X_ALED1VAL, 0, NULL), [LED2] = AFE440X_REG_INFO(AFE440X_LED2VAL, 0, NULL), [ALED2] = AFE440X_REG_INFO(AFE440X_ALED2VAL, 0, NULL), - [LED1_ALED1] = AFE440X_REG_INFO(AFE440X_LED1_ALED1VAL, 0, NULL), + [LED1] = AFE440X_REG_INFO(AFE440X_LED1VAL, 0, NULL), + [ALED1] = AFE440X_REG_INFO(AFE440X_ALED1VAL, 0, NULL), [LED2_ALED2] = AFE440X_REG_INFO(AFE440X_LED2_ALED2VAL, 0, NULL), + [LED1_ALED1] = AFE440X_REG_INFO(AFE440X_LED1_ALED1VAL, 0, NULL), [ILED1] = AFE440X_REG_INFO(AFE440X_LEDCNTRL, 0, AFE440X_LEDCNTRL_LED1), [ILED2] = AFE440X_REG_INFO(AFE440X_LEDCNTRL, 0, AFE440X_LEDCNTRL_LED2), }; static const struct iio_chan_spec afe4403_channels[] = { /* ADC values */ - AFE440X_INTENSITY_CHAN(LED1, "led1", 0), - AFE440X_INTENSITY_CHAN(ALED1, "led1_ambient", 0), - AFE440X_INTENSITY_CHAN(LED2, "led2", 0), - AFE440X_INTENSITY_CHAN(ALED2, "led2_ambient", 0), - AFE440X_INTENSITY_CHAN(LED1_ALED1, "led1-led1_ambient", 0), - AFE440X_INTENSITY_CHAN(LED2_ALED2, "led2-led2_ambient", 0), + AFE440X_INTENSITY_CHAN(LED2, 0), + AFE440X_INTENSITY_CHAN(ALED2, 0), + AFE440X_INTENSITY_CHAN(LED1, 0), + AFE440X_INTENSITY_CHAN(ALED1, 0), + AFE440X_INTENSITY_CHAN(LED2_ALED2, 0), + AFE440X_INTENSITY_CHAN(LED1_ALED1, 0), /* LED current */ - AFE440X_CURRENT_CHAN(ILED1, "led1"), - AFE440X_CURRENT_CHAN(ILED2, "led2"), + AFE440X_CURRENT_CHAN(ILED1), + AFE440X_CURRENT_CHAN(ILED2), }; static const struct afe440x_val_table afe4403_res_table[] = { diff --git a/drivers/iio/health/afe4404.c b/drivers/iio/health/afe4404.c index 2edb7d7..7806a45 100644 --- a/drivers/iio/health/afe4404.c +++ b/drivers/iio/health/afe4404.c @@ -122,24 +122,24 @@ struct afe4404_data { }; enum afe4404_chan_id { + LED2 = 1, + ALED2, LED1, ALED1, - LED2, - ALED2, - LED1_ALED1, LED2_ALED2, + LED1_ALED1, ILED1, ILED2, ILED3, }; static const struct afe440x_reg_info afe4404_reg_info[] = { - [LED1] = AFE440X_REG_INFO(AFE440X_LED1VAL, AFE4404_OFFDAC, AFE4404_OFFDAC_CURR_LED1), - [ALED1] = AFE440X_REG_INFO(AFE440X_ALED1VAL, AFE4404_OFFDAC, AFE4404_OFFDAC_CURR_ALED1), [LED2] = AFE440X_REG_INFO(AFE440X_LED2VAL, AFE4404_OFFDAC, AFE4404_OFFDAC_CURR_LED2), [ALED2] = AFE440X_REG_INFO(AFE440X_ALED2VAL, AFE4404_OFFDAC, AFE4404_OFFDAC_CURR_ALED2), - [LED1_ALED1] = AFE440X_REG_INFO(AFE440X_LED1_ALED1VAL, 0, NULL), + [LED1] = AFE440X_REG_INFO(AFE440X_LED1VAL, AFE4404_OFFDAC, AFE4404_OFFDAC_CURR_LED1), + [ALED1] = AFE440X_REG_INFO(AFE440X_ALED1VAL, AFE4404_OFFDAC, AFE4404_OFFDAC_CURR_ALED1), [LED2_ALED2] = AFE440X_REG_INFO(AFE440X_LED2_ALED2VAL, 0, NULL), + [LED1_ALED1] = AFE440X_REG_INFO(AFE440X_LED1_ALED1VAL, 0, NULL), [ILED1] = AFE440X_REG_INFO(AFE440X_LEDCNTRL, 0, AFE4404_LEDCNTRL_ILED1), [ILED2] = AFE440X_REG_INFO(AFE440X_LEDCNTRL, 0, AFE4404_LEDCNTRL_ILED2), [ILED3] = AFE440X_REG_INFO(AFE440X_LEDCNTRL, 0, AFE4404_LEDCNTRL_ILED3), @@ -147,16 +147,16 @@ static const struct afe440x_reg_info afe4404_reg_info[] = { static const struct iio_chan_spec afe4404_channels[] = { /* ADC values */ - AFE440X_INTENSITY_CHAN(LED1, "led1", BIT(IIO_CHAN_INFO_OFFSET)), - AFE440X_INTENSITY_CHAN(ALED1, "led1_ambient", BIT(IIO_CHAN_INFO_OFFSET)), - AFE440X_INTENSITY_CHAN(LED2, "led2", BIT(IIO_CHAN_INFO_OFFSET)), - AFE440X_INTENSITY_CHAN(ALED2, "led2_ambient", BIT(IIO_CHAN_INFO_OFFSET)), - AFE440X_INTENSITY_CHAN(LED1_ALED1, "led1-led1_ambient", 0), - AFE440X_INTENSITY_CHAN(LED2_ALED2, "led2-led2_ambient", 0), + AFE440X_INTENSITY_CHAN(LED2, BIT(IIO_CHAN_INFO_OFFSET)), + AFE440X_INTENSITY_CHAN(ALED2, BIT(IIO_CHAN_INFO_OFFSET)), + AFE440X_INTENSITY_CHAN(LED1, BIT(IIO_CHAN_INFO_OFFSET)), + AFE440X_INTENSITY_CHAN(ALED1, BIT(IIO_CHAN_INFO_OFFSET)), + AFE440X_INTENSITY_CHAN(LED2_ALED2, 0), + AFE440X_INTENSITY_CHAN(LED1_ALED1, 0), /* LED current */ - AFE440X_CURRENT_CHAN(ILED1, "led1"), - AFE440X_CURRENT_CHAN(ILED2, "led2"), - AFE440X_CURRENT_CHAN(ILED3, "led3"), + AFE440X_CURRENT_CHAN(ILED1), + AFE440X_CURRENT_CHAN(ILED2), + AFE440X_CURRENT_CHAN(ILED3), }; static const struct afe440x_val_table afe4404_res_table[] = { diff --git a/drivers/iio/health/afe440x.h b/drivers/iio/health/afe440x.h index 583d071..713972f 100644 --- a/drivers/iio/health/afe440x.h +++ b/drivers/iio/health/afe440x.h @@ -103,7 +103,7 @@ struct afe440x_reg_info { .mask = _sm ## _MASK, \ } -#define AFE440X_INTENSITY_CHAN(_index, _name, _mask) \ +#define AFE440X_INTENSITY_CHAN(_index, _mask) \ { \ .type = IIO_INTENSITY, \ .channel = _index, \ @@ -115,20 +115,20 @@ struct afe440x_reg_info { .storagebits = 32, \ .endianness = IIO_CPU, \ }, \ - .extend_name = _name, \ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ _mask, \ + .indexed = true, \ } -#define AFE440X_CURRENT_CHAN(_index, _name) \ +#define AFE440X_CURRENT_CHAN(_index) \ { \ .type = IIO_CURRENT, \ .channel = _index, \ .address = _index, \ .scan_index = -1, \ - .extend_name = _name, \ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ BIT(IIO_CHAN_INFO_SCALE), \ + .indexed = true, \ .output = true, \ } -- cgit v0.10.2 From b36e8257641a043764c62240316610c81e36376c Mon Sep 17 00:00:00 2001 From: "Andrew F. Davis" Date: Sun, 1 May 2016 15:36:59 -0500 Subject: iio: health/afe440x: Use regmap fields These drivers can use regmap fields to access fields in registers, this allows us to remove some macros/defines and simplify code, do this here. Signed-off-by: Andrew F. Davis Signed-off-by: Jonathan Cameron diff --git a/drivers/iio/health/afe4403.c b/drivers/iio/health/afe4403.c index 4a58064..1950155 100644 --- a/drivers/iio/health/afe4403.c +++ b/drivers/iio/health/afe4403.c @@ -39,32 +39,6 @@ #define AFE4403_TIAGAIN 0x20 #define AFE4403_TIA_AMB_GAIN 0x21 -/* AFE4403 GAIN register fields */ -#define AFE4403_TIAGAIN_RES_MASK GENMASK(2, 0) -#define AFE4403_TIAGAIN_RES_SHIFT 0 -#define AFE4403_TIAGAIN_CAP_MASK GENMASK(7, 3) -#define AFE4403_TIAGAIN_CAP_SHIFT 3 - -/* AFE4403 LEDCNTRL register fields */ -#define AFE440X_LEDCNTRL_LED1_MASK GENMASK(15, 8) -#define AFE440X_LEDCNTRL_LED1_SHIFT 8 -#define AFE440X_LEDCNTRL_LED2_MASK GENMASK(7, 0) -#define AFE440X_LEDCNTRL_LED2_SHIFT 0 -#define AFE440X_LEDCNTRL_LED_RANGE_MASK GENMASK(17, 16) -#define AFE440X_LEDCNTRL_LED_RANGE_SHIFT 16 - -/* AFE4403 CONTROL2 register fields */ -#define AFE440X_CONTROL2_PWR_DWN_TX BIT(2) -#define AFE440X_CONTROL2_EN_SLOW_DIAG BIT(8) -#define AFE440X_CONTROL2_DIAG_OUT_TRI BIT(10) -#define AFE440X_CONTROL2_TX_BRDG_MOD BIT(11) -#define AFE440X_CONTROL2_TX_REF_MASK GENMASK(18, 17) -#define AFE440X_CONTROL2_TX_REF_SHIFT 17 - -/* AFE4404 NULL fields */ -#define NULL_MASK 0 -#define NULL_SHIFT 0 - /* AFE4403 LEDCNTRL values */ #define AFE440X_LEDCNTRL_RANGE_TX_HALF 0x1 #define AFE440X_LEDCNTRL_RANGE_TX_FULL 0x2 @@ -102,11 +76,35 @@ #define AFE4403_TIAGAIN_RES_1_M 0x6 #define AFE4403_TIAGAIN_RES_NONE 0x7 +enum afe4403_fields { + /* Gains */ + F_RF_LED1, F_CF_LED1, + F_RF_LED, F_CF_LED, + + /* LED Current */ + F_ILED1, F_ILED2, + + /* sentinel */ + F_MAX_FIELDS +}; + +static const struct reg_field afe4403_reg_fields[] = { + /* Gains */ + [F_RF_LED1] = REG_FIELD(AFE4403_TIAGAIN, 0, 2), + [F_CF_LED1] = REG_FIELD(AFE4403_TIAGAIN, 3, 7), + [F_RF_LED] = REG_FIELD(AFE4403_TIA_AMB_GAIN, 0, 2), + [F_CF_LED] = REG_FIELD(AFE4403_TIA_AMB_GAIN, 3, 7), + /* LED Current */ + [F_ILED1] = REG_FIELD(AFE440X_LEDCNTRL, 0, 7), + [F_ILED2] = REG_FIELD(AFE440X_LEDCNTRL, 8, 15), +}; + /** * struct afe4403_data - AFE4403 device instance data * @dev: Device structure * @spi: SPI device handle * @regmap: Register map of the device + * @fields: Register fields of the device * @regulator: Pointer to the regulator for the IC * @trig: IIO trigger for this device * @irq: ADC_RDY line interrupt number @@ -115,6 +113,7 @@ struct afe4403_data { struct device *dev; struct spi_device *spi; struct regmap *regmap; + struct regmap_field *fields[F_MAX_FIELDS]; struct regulator *regulator; struct iio_trigger *trig; int irq; @@ -131,15 +130,18 @@ enum afe4403_chan_id { ILED2, }; -static const struct afe440x_reg_info afe4403_reg_info[] = { - [LED2] = AFE440X_REG_INFO(AFE440X_LED2VAL, 0, NULL), - [ALED2] = AFE440X_REG_INFO(AFE440X_ALED2VAL, 0, NULL), - [LED1] = AFE440X_REG_INFO(AFE440X_LED1VAL, 0, NULL), - [ALED1] = AFE440X_REG_INFO(AFE440X_ALED1VAL, 0, NULL), - [LED2_ALED2] = AFE440X_REG_INFO(AFE440X_LED2_ALED2VAL, 0, NULL), - [LED1_ALED1] = AFE440X_REG_INFO(AFE440X_LED1_ALED1VAL, 0, NULL), - [ILED1] = AFE440X_REG_INFO(AFE440X_LEDCNTRL, 0, AFE440X_LEDCNTRL_LED1), - [ILED2] = AFE440X_REG_INFO(AFE440X_LEDCNTRL, 0, AFE440X_LEDCNTRL_LED2), +static const unsigned int afe4403_channel_values[] = { + [LED2] = AFE440X_LED2VAL, + [ALED2] = AFE440X_ALED2VAL, + [LED1] = AFE440X_LED1VAL, + [ALED1] = AFE440X_ALED1VAL, + [LED2_ALED2] = AFE440X_LED2_ALED2VAL, + [LED1_ALED1] = AFE440X_LED1_ALED1VAL, +}; + +static const unsigned int afe4403_channel_leds[] = { + [ILED1] = F_ILED1, + [ILED2] = F_ILED2, }; static const struct iio_chan_spec afe4403_channels[] = { @@ -184,13 +186,10 @@ static ssize_t afe440x_show_register(struct device *dev, int vals[2]; int ret; - ret = regmap_read(afe->regmap, afe440x_attr->reg, ®_val); + ret = regmap_field_read(afe->fields[afe440x_attr->field], ®_val); if (ret) return ret; - reg_val &= afe440x_attr->mask; - reg_val >>= afe440x_attr->shift; - if (reg_val >= afe440x_attr->table_size) return -EINVAL; @@ -220,20 +219,18 @@ static ssize_t afe440x_store_register(struct device *dev, if (val == afe440x_attr->table_size) return -EINVAL; - ret = regmap_update_bits(afe->regmap, afe440x_attr->reg, - afe440x_attr->mask, - (val << afe440x_attr->shift)); + ret = regmap_field_write(afe->fields[afe440x_attr->field], val); if (ret) return ret; return count; } -static AFE440X_ATTR(tia_resistance1, AFE4403_TIAGAIN, AFE4403_TIAGAIN_RES, afe4403_res_table); -static AFE440X_ATTR(tia_capacitance1, AFE4403_TIAGAIN, AFE4403_TIAGAIN_CAP, afe4403_cap_table); +static AFE440X_ATTR(tia_resistance1, F_RF_LED1, afe4403_res_table); +static AFE440X_ATTR(tia_capacitance1, F_CF_LED1, afe4403_cap_table); -static AFE440X_ATTR(tia_resistance2, AFE4403_TIA_AMB_GAIN, AFE4403_TIAGAIN_RES, afe4403_res_table); -static AFE440X_ATTR(tia_capacitance2, AFE4403_TIA_AMB_GAIN, AFE4403_TIAGAIN_RES, afe4403_cap_table); +static AFE440X_ATTR(tia_resistance2, F_RF_LED, afe4403_res_table); +static AFE440X_ATTR(tia_capacitance2, F_CF_LED, afe4403_cap_table); static struct attribute *afe440x_attributes[] = { &afe440x_attr_tia_resistance1.dev_attr.attr, @@ -282,14 +279,15 @@ static int afe4403_read_raw(struct iio_dev *indio_dev, int *val, int *val2, long mask) { struct afe4403_data *afe = iio_priv(indio_dev); - const struct afe440x_reg_info reg_info = afe4403_reg_info[chan->address]; + unsigned int reg = afe4403_channel_values[chan->address]; + unsigned int field = afe4403_channel_leds[chan->address]; int ret; switch (chan->type) { case IIO_INTENSITY: switch (mask) { case IIO_CHAN_INFO_RAW: - ret = afe4403_read(afe, reg_info.reg, val); + ret = afe4403_read(afe, reg, val); if (ret) return ret; return IIO_VAL_INT; @@ -298,11 +296,9 @@ static int afe4403_read_raw(struct iio_dev *indio_dev, case IIO_CURRENT: switch (mask) { case IIO_CHAN_INFO_RAW: - ret = regmap_read(afe->regmap, reg_info.reg, val); + ret = regmap_field_read(afe->fields[field], val); if (ret) return ret; - *val &= reg_info.mask; - *val >>= reg_info.shift; return IIO_VAL_INT; case IIO_CHAN_INFO_SCALE: *val = 0; @@ -322,16 +318,13 @@ static int afe4403_write_raw(struct iio_dev *indio_dev, int val, int val2, long mask) { struct afe4403_data *afe = iio_priv(indio_dev); - const struct afe440x_reg_info reg_info = afe4403_reg_info[chan->address]; + unsigned int field = afe4403_channel_leds[chan->address]; switch (chan->type) { case IIO_CURRENT: switch (mask) { case IIO_CHAN_INFO_RAW: - return regmap_update_bits(afe->regmap, - reg_info.reg, - reg_info.mask, - (val << reg_info.shift)); + return regmap_field_write(afe->fields[field], val); } break; default: @@ -366,7 +359,7 @@ static irqreturn_t afe4403_trigger_handler(int irq, void *private) for_each_set_bit(bit, indio_dev->active_scan_mask, indio_dev->masklength) { ret = spi_write_then_read(afe->spi, - &afe4403_reg_info[bit].reg, 1, + &afe4403_channel_values[bit], 1, rx, 3); if (ret) goto err; @@ -503,7 +496,7 @@ static int afe4403_probe(struct spi_device *spi) { struct iio_dev *indio_dev; struct afe4403_data *afe; - int ret; + int i, ret; indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*afe)); if (!indio_dev) @@ -522,6 +515,15 @@ static int afe4403_probe(struct spi_device *spi) return PTR_ERR(afe->regmap); } + for (i = 0; i < F_MAX_FIELDS; i++) { + afe->fields[i] = devm_regmap_field_alloc(afe->dev, afe->regmap, + afe4403_reg_fields[i]); + if (IS_ERR(afe->fields[i])) { + dev_err(afe->dev, "Unable to allocate regmap fields\n"); + return PTR_ERR(afe->fields[i]); + } + } + afe->regulator = devm_regulator_get(afe->dev, "tx_sup"); if (IS_ERR(afe->regulator)) { dev_err(afe->dev, "Unable to get regulator\n"); diff --git a/drivers/iio/health/afe4404.c b/drivers/iio/health/afe4404.c index 7806a45..0d1af4a 100644 --- a/drivers/iio/health/afe4404.c +++ b/drivers/iio/health/afe4404.c @@ -48,43 +48,9 @@ #define AFE4404_AVG_LED2_ALED2VAL 0x3f #define AFE4404_AVG_LED1_ALED1VAL 0x40 -/* AFE4404 GAIN register fields */ -#define AFE4404_TIA_GAIN_RES_MASK GENMASK(2, 0) -#define AFE4404_TIA_GAIN_RES_SHIFT 0 -#define AFE4404_TIA_GAIN_CAP_MASK GENMASK(5, 3) -#define AFE4404_TIA_GAIN_CAP_SHIFT 3 - -/* AFE4404 LEDCNTRL register fields */ -#define AFE4404_LEDCNTRL_ILED1_MASK GENMASK(5, 0) -#define AFE4404_LEDCNTRL_ILED1_SHIFT 0 -#define AFE4404_LEDCNTRL_ILED2_MASK GENMASK(11, 6) -#define AFE4404_LEDCNTRL_ILED2_SHIFT 6 -#define AFE4404_LEDCNTRL_ILED3_MASK GENMASK(17, 12) -#define AFE4404_LEDCNTRL_ILED3_SHIFT 12 - -/* AFE4404 CONTROL2 register fields */ -#define AFE440X_CONTROL2_ILED_2X_MASK BIT(17) -#define AFE440X_CONTROL2_ILED_2X_SHIFT 17 - /* AFE4404 CONTROL3 register fields */ #define AFE440X_CONTROL3_OSC_ENABLE BIT(9) -/* AFE4404 OFFDAC register current fields */ -#define AFE4404_OFFDAC_CURR_LED1_MASK GENMASK(9, 5) -#define AFE4404_OFFDAC_CURR_LED1_SHIFT 5 -#define AFE4404_OFFDAC_CURR_LED2_MASK GENMASK(19, 15) -#define AFE4404_OFFDAC_CURR_LED2_SHIFT 15 -#define AFE4404_OFFDAC_CURR_LED3_MASK GENMASK(4, 0) -#define AFE4404_OFFDAC_CURR_LED3_SHIFT 0 -#define AFE4404_OFFDAC_CURR_ALED1_MASK GENMASK(14, 10) -#define AFE4404_OFFDAC_CURR_ALED1_SHIFT 10 -#define AFE4404_OFFDAC_CURR_ALED2_MASK GENMASK(4, 0) -#define AFE4404_OFFDAC_CURR_ALED2_SHIFT 0 - -/* AFE4404 NULL fields */ -#define NULL_MASK 0 -#define NULL_SHIFT 0 - /* AFE4404 TIA_GAIN_CAP values */ #define AFE4404_TIA_GAIN_CAP_5_P 0x0 #define AFE4404_TIA_GAIN_CAP_2_5_P 0x1 @@ -105,10 +71,43 @@ #define AFE4404_TIA_GAIN_RES_1_M 0x6 #define AFE4404_TIA_GAIN_RES_2_M 0x7 +enum afe4404_fields { + /* Gains */ + F_TIA_GAIN_SEP, F_TIA_CF_SEP, + F_TIA_GAIN, TIA_CF, + + /* LED Current */ + F_ILED1, F_ILED2, F_ILED3, + + /* Offset DAC */ + F_OFFDAC_AMB2, F_OFFDAC_LED1, F_OFFDAC_AMB1, F_OFFDAC_LED2, + + /* sentinel */ + F_MAX_FIELDS +}; + +static const struct reg_field afe4404_reg_fields[] = { + /* Gains */ + [F_TIA_GAIN_SEP] = REG_FIELD(AFE4404_TIA_GAIN_SEP, 0, 2), + [F_TIA_CF_SEP] = REG_FIELD(AFE4404_TIA_GAIN_SEP, 3, 5), + [F_TIA_GAIN] = REG_FIELD(AFE4404_TIA_GAIN, 0, 2), + [TIA_CF] = REG_FIELD(AFE4404_TIA_GAIN, 3, 5), + /* LED Current */ + [F_ILED1] = REG_FIELD(AFE440X_LEDCNTRL, 0, 5), + [F_ILED2] = REG_FIELD(AFE440X_LEDCNTRL, 6, 11), + [F_ILED3] = REG_FIELD(AFE440X_LEDCNTRL, 12, 17), + /* Offset DAC */ + [F_OFFDAC_AMB2] = REG_FIELD(AFE4404_OFFDAC, 0, 4), + [F_OFFDAC_LED1] = REG_FIELD(AFE4404_OFFDAC, 5, 9), + [F_OFFDAC_AMB1] = REG_FIELD(AFE4404_OFFDAC, 10, 14), + [F_OFFDAC_LED2] = REG_FIELD(AFE4404_OFFDAC, 15, 19), +}; + /** * struct afe4404_data - AFE4404 device instance data * @dev: Device structure * @regmap: Register map of the device + * @fields: Register fields of the device * @regulator: Pointer to the regulator for the IC * @trig: IIO trigger for this device * @irq: ADC_RDY line interrupt number @@ -116,6 +115,7 @@ struct afe4404_data { struct device *dev; struct regmap *regmap; + struct regmap_field *fields[F_MAX_FIELDS]; struct regulator *regulator; struct iio_trigger *trig; int irq; @@ -133,16 +133,26 @@ enum afe4404_chan_id { ILED3, }; -static const struct afe440x_reg_info afe4404_reg_info[] = { - [LED2] = AFE440X_REG_INFO(AFE440X_LED2VAL, AFE4404_OFFDAC, AFE4404_OFFDAC_CURR_LED2), - [ALED2] = AFE440X_REG_INFO(AFE440X_ALED2VAL, AFE4404_OFFDAC, AFE4404_OFFDAC_CURR_ALED2), - [LED1] = AFE440X_REG_INFO(AFE440X_LED1VAL, AFE4404_OFFDAC, AFE4404_OFFDAC_CURR_LED1), - [ALED1] = AFE440X_REG_INFO(AFE440X_ALED1VAL, AFE4404_OFFDAC, AFE4404_OFFDAC_CURR_ALED1), - [LED2_ALED2] = AFE440X_REG_INFO(AFE440X_LED2_ALED2VAL, 0, NULL), - [LED1_ALED1] = AFE440X_REG_INFO(AFE440X_LED1_ALED1VAL, 0, NULL), - [ILED1] = AFE440X_REG_INFO(AFE440X_LEDCNTRL, 0, AFE4404_LEDCNTRL_ILED1), - [ILED2] = AFE440X_REG_INFO(AFE440X_LEDCNTRL, 0, AFE4404_LEDCNTRL_ILED2), - [ILED3] = AFE440X_REG_INFO(AFE440X_LEDCNTRL, 0, AFE4404_LEDCNTRL_ILED3), +static const unsigned int afe4404_channel_values[] = { + [LED2] = AFE440X_LED2VAL, + [ALED2] = AFE440X_ALED2VAL, + [LED1] = AFE440X_LED1VAL, + [ALED1] = AFE440X_ALED1VAL, + [LED2_ALED2] = AFE440X_LED2_ALED2VAL, + [LED1_ALED1] = AFE440X_LED1_ALED1VAL, +}; + +static const unsigned int afe4404_channel_leds[] = { + [ILED1] = F_ILED1, + [ILED2] = F_ILED2, + [ILED3] = F_ILED3, +}; + +static const unsigned int afe4404_channel_offdacs[] = { + [LED2] = F_OFFDAC_LED2, + [ALED2] = F_OFFDAC_AMB2, + [LED1] = F_OFFDAC_LED1, + [ALED1] = F_OFFDAC_AMB1, }; static const struct iio_chan_spec afe4404_channels[] = { @@ -194,13 +204,10 @@ static ssize_t afe440x_show_register(struct device *dev, int vals[2]; int ret; - ret = regmap_read(afe->regmap, afe440x_attr->reg, ®_val); + ret = regmap_field_read(afe->fields[afe440x_attr->field], ®_val); if (ret) return ret; - reg_val &= afe440x_attr->mask; - reg_val >>= afe440x_attr->shift; - if (reg_val >= afe440x_attr->table_size) return -EINVAL; @@ -230,20 +237,18 @@ static ssize_t afe440x_store_register(struct device *dev, if (val == afe440x_attr->table_size) return -EINVAL; - ret = regmap_update_bits(afe->regmap, afe440x_attr->reg, - afe440x_attr->mask, - (val << afe440x_attr->shift)); + ret = regmap_field_write(afe->fields[afe440x_attr->field], val); if (ret) return ret; return count; } -static AFE440X_ATTR(tia_resistance1, AFE4404_TIA_GAIN, AFE4404_TIA_GAIN_RES, afe4404_res_table); -static AFE440X_ATTR(tia_capacitance1, AFE4404_TIA_GAIN, AFE4404_TIA_GAIN_CAP, afe4404_cap_table); +static AFE440X_ATTR(tia_resistance1, F_TIA_GAIN, afe4404_res_table); +static AFE440X_ATTR(tia_capacitance1, TIA_CF, afe4404_cap_table); -static AFE440X_ATTR(tia_resistance2, AFE4404_TIA_GAIN_SEP, AFE4404_TIA_GAIN_RES, afe4404_res_table); -static AFE440X_ATTR(tia_capacitance2, AFE4404_TIA_GAIN_SEP, AFE4404_TIA_GAIN_CAP, afe4404_cap_table); +static AFE440X_ATTR(tia_resistance2, F_TIA_GAIN_SEP, afe4404_res_table); +static AFE440X_ATTR(tia_capacitance2, F_TIA_CF_SEP, afe4404_cap_table); static struct attribute *afe440x_attributes[] = { &afe440x_attr_tia_resistance1.dev_attr.attr, @@ -264,35 +269,32 @@ static int afe4404_read_raw(struct iio_dev *indio_dev, int *val, int *val2, long mask) { struct afe4404_data *afe = iio_priv(indio_dev); - const struct afe440x_reg_info reg_info = afe4404_reg_info[chan->address]; + unsigned int value_reg = afe4404_channel_values[chan->address]; + unsigned int led_field = afe4404_channel_leds[chan->address]; + unsigned int offdac_field = afe4404_channel_offdacs[chan->address]; int ret; switch (chan->type) { case IIO_INTENSITY: switch (mask) { case IIO_CHAN_INFO_RAW: - ret = regmap_read(afe->regmap, reg_info.reg, val); + ret = regmap_read(afe->regmap, value_reg, val); if (ret) return ret; return IIO_VAL_INT; case IIO_CHAN_INFO_OFFSET: - ret = regmap_read(afe->regmap, reg_info.offreg, - val); + ret = regmap_field_read(afe->fields[offdac_field], val); if (ret) return ret; - *val &= reg_info.mask; - *val >>= reg_info.shift; return IIO_VAL_INT; } break; case IIO_CURRENT: switch (mask) { case IIO_CHAN_INFO_RAW: - ret = regmap_read(afe->regmap, reg_info.reg, val); + ret = regmap_field_read(afe->fields[led_field], val); if (ret) return ret; - *val &= reg_info.mask; - *val >>= reg_info.shift; return IIO_VAL_INT; case IIO_CHAN_INFO_SCALE: *val = 0; @@ -312,25 +314,20 @@ static int afe4404_write_raw(struct iio_dev *indio_dev, int val, int val2, long mask) { struct afe4404_data *afe = iio_priv(indio_dev); - const struct afe440x_reg_info reg_info = afe4404_reg_info[chan->address]; + unsigned int led_field = afe4404_channel_leds[chan->address]; + unsigned int offdac_field = afe4404_channel_offdacs[chan->address]; switch (chan->type) { case IIO_INTENSITY: switch (mask) { case IIO_CHAN_INFO_OFFSET: - return regmap_update_bits(afe->regmap, - reg_info.offreg, - reg_info.mask, - (val << reg_info.shift)); + return regmap_field_write(afe->fields[offdac_field], val); } break; case IIO_CURRENT: switch (mask) { case IIO_CHAN_INFO_RAW: - return regmap_update_bits(afe->regmap, - reg_info.reg, - reg_info.mask, - (val << reg_info.shift)); + return regmap_field_write(afe->fields[led_field], val); } break; default: @@ -357,7 +354,7 @@ static irqreturn_t afe4404_trigger_handler(int irq, void *private) for_each_set_bit(bit, indio_dev->active_scan_mask, indio_dev->masklength) { - ret = regmap_read(afe->regmap, afe4404_reg_info[bit].reg, + ret = regmap_read(afe->regmap, afe4404_channel_values[bit], &buffer[i++]); if (ret) goto err; @@ -490,7 +487,7 @@ static int afe4404_probe(struct i2c_client *client, { struct iio_dev *indio_dev; struct afe4404_data *afe; - int ret; + int i, ret; indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*afe)); if (!indio_dev) @@ -508,6 +505,15 @@ static int afe4404_probe(struct i2c_client *client, return PTR_ERR(afe->regmap); } + for (i = 0; i < F_MAX_FIELDS; i++) { + afe->fields[i] = devm_regmap_field_alloc(afe->dev, afe->regmap, + afe4404_reg_fields[i]); + if (IS_ERR(afe->fields[i])) { + dev_err(afe->dev, "Unable to allocate regmap fields\n"); + return PTR_ERR(afe->fields[i]); + } + } + afe->regulator = devm_regulator_get(afe->dev, "tx_sup"); if (IS_ERR(afe->regulator)) { dev_err(afe->dev, "Unable to get regulator\n"); diff --git a/drivers/iio/health/afe440x.h b/drivers/iio/health/afe440x.h index 713972f..1a0f247 100644 --- a/drivers/iio/health/afe440x.h +++ b/drivers/iio/health/afe440x.h @@ -88,21 +88,6 @@ #define AFE440X_CONTROL0_WRITE 0x0 #define AFE440X_CONTROL0_READ 0x1 -struct afe440x_reg_info { - unsigned int reg; - unsigned int offreg; - unsigned int shift; - unsigned int mask; -}; - -#define AFE440X_REG_INFO(_reg, _offreg, _sm) \ - { \ - .reg = _reg, \ - .offreg = _offreg, \ - .shift = _sm ## _SHIFT, \ - .mask = _sm ## _MASK, \ - } - #define AFE440X_INTENSITY_CHAN(_index, _mask) \ { \ .type = IIO_INTENSITY, \ @@ -157,9 +142,7 @@ static DEVICE_ATTR_RO(_name) struct afe440x_attr { struct device_attribute dev_attr; - unsigned int reg; - unsigned int shift; - unsigned int mask; + unsigned int field; const struct afe440x_val_table *val_table; unsigned int table_size; }; @@ -167,14 +150,12 @@ struct afe440x_attr { #define to_afe440x_attr(_dev_attr) \ container_of(_dev_attr, struct afe440x_attr, dev_attr) -#define AFE440X_ATTR(_name, _reg, _field, _table) \ +#define AFE440X_ATTR(_name, _field, _table) \ struct afe440x_attr afe440x_attr_##_name = { \ .dev_attr = __ATTR(_name, (S_IRUGO | S_IWUSR), \ afe440x_show_register, \ afe440x_store_register), \ - .reg = _reg, \ - .shift = _field ## _SHIFT, \ - .mask = _field ## _MASK, \ + .field = _field, \ .val_table = _table, \ .table_size = ARRAY_SIZE(_table), \ } -- cgit v0.10.2 From 1276187c5261217aa9cc23ec153e0e903181c16b Mon Sep 17 00:00:00 2001 From: "Andrew F. Davis" Date: Sun, 1 May 2016 15:37:00 -0500 Subject: iio: health/afe440x: Make gain settings a modifier for the stages Currently the TIA gain settings are exported to userspace as sysfs entries that do not clearly represent their internal relation to the sampling stages. The gain settings are enabled on a per-stage basis, this can be seen in figure 24 of the current AFE4404 datasheet. These gain settings should therefore be tied to the channels that are read during these stages. Make this change here. Signed-off-by: Andrew F. Davis Signed-off-by: Jonathan Cameron diff --git a/Documentation/ABI/testing/sysfs-bus-iio-health-afe440x b/Documentation/ABI/testing/sysfs-bus-iio-health-afe440x index a067073..6adba90 100644 --- a/Documentation/ABI/testing/sysfs-bus-iio-health-afe440x +++ b/Documentation/ABI/testing/sysfs-bus-iio-health-afe440x @@ -1,13 +1,3 @@ -What: /sys/bus/iio/devices/iio:deviceX/tia_resistanceY - /sys/bus/iio/devices/iio:deviceX/tia_capacitanceY -Date: December 2015 -KernelVersion: -Contact: Andrew F. Davis -Description: - Get and set the resistance and the capacitance settings for the - Transimpedance Amplifier. Y is 1 for Rf1 and Cf1, Y is 2 for - Rf2 and Cf2 values. - What: /sys/bus/iio/devices/iio:deviceX/in_intensityY_raw Date: May 2016 KernelVersion: @@ -33,6 +23,15 @@ Description: Get and set the offset cancellation DAC setting for these stages. The values are expressed in 5-bit sign-magnitude. +What: /sys/bus/iio/devices/iio:deviceX/in_intensityY_resistance +What: /sys/bus/iio/devices/iio:deviceX/in_intensityY_capacitance +Date: May 2016 +KernelVersion: +Contact: Andrew F. Davis +Description: + Get and set the resistance and the capacitance settings for the + Transimpedance Amplifier during the associated stage. + What: /sys/bus/iio/devices/iio:deviceX/out_currentY_raw Date: May 2016 KernelVersion: diff --git a/drivers/iio/health/afe4403.c b/drivers/iio/health/afe4403.c index 1950155..610631b 100644 --- a/drivers/iio/health/afe4403.c +++ b/drivers/iio/health/afe4403.c @@ -161,7 +161,7 @@ static const struct afe440x_val_table afe4403_res_table[] = { { 500000 }, { 250000 }, { 100000 }, { 50000 }, { 25000 }, { 10000 }, { 1000000 }, { 0 }, }; -AFE440X_TABLE_ATTR(tia_resistance_available, afe4403_res_table); +AFE440X_TABLE_ATTR(in_intensity_resistance_available, afe4403_res_table); static const struct afe440x_val_table afe4403_cap_table[] = { { 0, 5000 }, { 0, 10000 }, { 0, 20000 }, { 0, 25000 }, @@ -173,7 +173,7 @@ static const struct afe440x_val_table afe4403_cap_table[] = { { 0, 205000 }, { 0, 210000 }, { 0, 220000 }, { 0, 225000 }, { 0, 230000 }, { 0, 235000 }, { 0, 245000 }, { 0, 250000 }, }; -AFE440X_TABLE_ATTR(tia_capacitance_available, afe4403_cap_table); +AFE440X_TABLE_ATTR(in_intensity_capacitance_available, afe4403_cap_table); static ssize_t afe440x_show_register(struct device *dev, struct device_attribute *attr, @@ -226,19 +226,29 @@ static ssize_t afe440x_store_register(struct device *dev, return count; } -static AFE440X_ATTR(tia_resistance1, F_RF_LED1, afe4403_res_table); -static AFE440X_ATTR(tia_capacitance1, F_CF_LED1, afe4403_cap_table); +static AFE440X_ATTR(in_intensity1_resistance, F_RF_LED, afe4403_res_table); +static AFE440X_ATTR(in_intensity1_capacitance, F_CF_LED, afe4403_cap_table); -static AFE440X_ATTR(tia_resistance2, F_RF_LED, afe4403_res_table); -static AFE440X_ATTR(tia_capacitance2, F_CF_LED, afe4403_cap_table); +static AFE440X_ATTR(in_intensity2_resistance, F_RF_LED, afe4403_res_table); +static AFE440X_ATTR(in_intensity2_capacitance, F_CF_LED, afe4403_cap_table); + +static AFE440X_ATTR(in_intensity3_resistance, F_RF_LED1, afe4403_res_table); +static AFE440X_ATTR(in_intensity3_capacitance, F_CF_LED1, afe4403_cap_table); + +static AFE440X_ATTR(in_intensity4_resistance, F_RF_LED1, afe4403_res_table); +static AFE440X_ATTR(in_intensity4_capacitance, F_CF_LED1, afe4403_cap_table); static struct attribute *afe440x_attributes[] = { - &afe440x_attr_tia_resistance1.dev_attr.attr, - &afe440x_attr_tia_capacitance1.dev_attr.attr, - &afe440x_attr_tia_resistance2.dev_attr.attr, - &afe440x_attr_tia_capacitance2.dev_attr.attr, - &dev_attr_tia_resistance_available.attr, - &dev_attr_tia_capacitance_available.attr, + &dev_attr_in_intensity_resistance_available.attr, + &dev_attr_in_intensity_capacitance_available.attr, + &afe440x_attr_in_intensity1_resistance.dev_attr.attr, + &afe440x_attr_in_intensity1_capacitance.dev_attr.attr, + &afe440x_attr_in_intensity2_resistance.dev_attr.attr, + &afe440x_attr_in_intensity2_capacitance.dev_attr.attr, + &afe440x_attr_in_intensity3_resistance.dev_attr.attr, + &afe440x_attr_in_intensity3_capacitance.dev_attr.attr, + &afe440x_attr_in_intensity4_resistance.dev_attr.attr, + &afe440x_attr_in_intensity4_capacitance.dev_attr.attr, NULL }; diff --git a/drivers/iio/health/afe4404.c b/drivers/iio/health/afe4404.c index 0d1af4a..69116cd 100644 --- a/drivers/iio/health/afe4404.c +++ b/drivers/iio/health/afe4404.c @@ -179,7 +179,7 @@ static const struct afe440x_val_table afe4404_res_table[] = { { .integer = 1000000, .fract = 0 }, { .integer = 2000000, .fract = 0 }, }; -AFE440X_TABLE_ATTR(tia_resistance_available, afe4404_res_table); +AFE440X_TABLE_ATTR(in_intensity_resistance_available, afe4404_res_table); static const struct afe440x_val_table afe4404_cap_table[] = { { .integer = 0, .fract = 5000 }, @@ -191,7 +191,7 @@ static const struct afe440x_val_table afe4404_cap_table[] = { { .integer = 0, .fract = 25000 }, { .integer = 0, .fract = 22500 }, }; -AFE440X_TABLE_ATTR(tia_capacitance_available, afe4404_cap_table); +AFE440X_TABLE_ATTR(in_intensity_capacitance_available, afe4404_cap_table); static ssize_t afe440x_show_register(struct device *dev, struct device_attribute *attr, @@ -244,19 +244,29 @@ static ssize_t afe440x_store_register(struct device *dev, return count; } -static AFE440X_ATTR(tia_resistance1, F_TIA_GAIN, afe4404_res_table); -static AFE440X_ATTR(tia_capacitance1, TIA_CF, afe4404_cap_table); +static AFE440X_ATTR(in_intensity1_resistance, F_TIA_GAIN_SEP, afe4404_res_table); +static AFE440X_ATTR(in_intensity1_capacitance, F_TIA_CF_SEP, afe4404_cap_table); -static AFE440X_ATTR(tia_resistance2, F_TIA_GAIN_SEP, afe4404_res_table); -static AFE440X_ATTR(tia_capacitance2, F_TIA_CF_SEP, afe4404_cap_table); +static AFE440X_ATTR(in_intensity2_resistance, F_TIA_GAIN_SEP, afe4404_res_table); +static AFE440X_ATTR(in_intensity2_capacitance, F_TIA_CF_SEP, afe4404_cap_table); + +static AFE440X_ATTR(in_intensity3_resistance, F_TIA_GAIN, afe4404_res_table); +static AFE440X_ATTR(in_intensity3_capacitance, TIA_CF, afe4404_cap_table); + +static AFE440X_ATTR(in_intensity4_resistance, F_TIA_GAIN, afe4404_res_table); +static AFE440X_ATTR(in_intensity4_capacitance, TIA_CF, afe4404_cap_table); static struct attribute *afe440x_attributes[] = { - &afe440x_attr_tia_resistance1.dev_attr.attr, - &afe440x_attr_tia_capacitance1.dev_attr.attr, - &afe440x_attr_tia_resistance2.dev_attr.attr, - &afe440x_attr_tia_capacitance2.dev_attr.attr, - &dev_attr_tia_resistance_available.attr, - &dev_attr_tia_capacitance_available.attr, + &dev_attr_in_intensity_resistance_available.attr, + &dev_attr_in_intensity_capacitance_available.attr, + &afe440x_attr_in_intensity1_resistance.dev_attr.attr, + &afe440x_attr_in_intensity1_capacitance.dev_attr.attr, + &afe440x_attr_in_intensity2_resistance.dev_attr.attr, + &afe440x_attr_in_intensity2_capacitance.dev_attr.attr, + &afe440x_attr_in_intensity3_resistance.dev_attr.attr, + &afe440x_attr_in_intensity3_capacitance.dev_attr.attr, + &afe440x_attr_in_intensity4_resistance.dev_attr.attr, + &afe440x_attr_in_intensity4_capacitance.dev_attr.attr, NULL }; -- cgit v0.10.2 From 3ff34ee2ad2aa16fdde728bd9048098f71391087 Mon Sep 17 00:00:00 2001 From: "Andrew F. Davis" Date: Sun, 1 May 2016 15:37:01 -0500 Subject: iio: health/afe440x: Match LED currents to stages The current channel number for the LEDs should match the stage number that they are active during, fix this here. Signed-off-by: Andrew F. Davis Signed-off-by: Jonathan Cameron diff --git a/drivers/iio/health/afe4403.c b/drivers/iio/health/afe4403.c index 610631b..059d521 100644 --- a/drivers/iio/health/afe4403.c +++ b/drivers/iio/health/afe4403.c @@ -126,8 +126,6 @@ enum afe4403_chan_id { ALED1, LED2_ALED2, LED1_ALED1, - ILED1, - ILED2, }; static const unsigned int afe4403_channel_values[] = { @@ -140,8 +138,8 @@ static const unsigned int afe4403_channel_values[] = { }; static const unsigned int afe4403_channel_leds[] = { - [ILED1] = F_ILED1, - [ILED2] = F_ILED2, + [LED2] = F_ILED2, + [LED1] = F_ILED1, }; static const struct iio_chan_spec afe4403_channels[] = { @@ -153,8 +151,8 @@ static const struct iio_chan_spec afe4403_channels[] = { AFE440X_INTENSITY_CHAN(LED2_ALED2, 0), AFE440X_INTENSITY_CHAN(LED1_ALED1, 0), /* LED current */ - AFE440X_CURRENT_CHAN(ILED1), - AFE440X_CURRENT_CHAN(ILED2), + AFE440X_CURRENT_CHAN(LED2), + AFE440X_CURRENT_CHAN(LED1), }; static const struct afe440x_val_table afe4403_res_table[] = { diff --git a/drivers/iio/health/afe4404.c b/drivers/iio/health/afe4404.c index 69116cd..aa8770b 100644 --- a/drivers/iio/health/afe4404.c +++ b/drivers/iio/health/afe4404.c @@ -128,9 +128,6 @@ enum afe4404_chan_id { ALED1, LED2_ALED2, LED1_ALED1, - ILED1, - ILED2, - ILED3, }; static const unsigned int afe4404_channel_values[] = { @@ -143,9 +140,9 @@ static const unsigned int afe4404_channel_values[] = { }; static const unsigned int afe4404_channel_leds[] = { - [ILED1] = F_ILED1, - [ILED2] = F_ILED2, - [ILED3] = F_ILED3, + [LED2] = F_ILED2, + [ALED2] = F_ILED3, + [LED1] = F_ILED1, }; static const unsigned int afe4404_channel_offdacs[] = { @@ -164,9 +161,9 @@ static const struct iio_chan_spec afe4404_channels[] = { AFE440X_INTENSITY_CHAN(LED2_ALED2, 0), AFE440X_INTENSITY_CHAN(LED1_ALED1, 0), /* LED current */ - AFE440X_CURRENT_CHAN(ILED1), - AFE440X_CURRENT_CHAN(ILED2), - AFE440X_CURRENT_CHAN(ILED3), + AFE440X_CURRENT_CHAN(LED2), + AFE440X_CURRENT_CHAN(ALED2), + AFE440X_CURRENT_CHAN(LED1), }; static const struct afe440x_val_table afe4404_res_table[] = { -- cgit v0.10.2 From e462350a95ee6d1ea53bc518f2bc5232b451e2e2 Mon Sep 17 00:00:00 2001 From: "Andrew F. Davis" Date: Sun, 1 May 2016 15:37:02 -0500 Subject: iio: health/afe440x: Remove unused definitions These definitions are not currently used and if the functionality they represent is needed the values should be added back to a table for easy userspace use. Signed-off-by: Andrew F. Davis Signed-off-by: Jonathan Cameron diff --git a/drivers/iio/health/afe4403.c b/drivers/iio/health/afe4403.c index 059d521..9a08146 100644 --- a/drivers/iio/health/afe4403.c +++ b/drivers/iio/health/afe4403.c @@ -39,43 +39,6 @@ #define AFE4403_TIAGAIN 0x20 #define AFE4403_TIA_AMB_GAIN 0x21 -/* AFE4403 LEDCNTRL values */ -#define AFE440X_LEDCNTRL_RANGE_TX_HALF 0x1 -#define AFE440X_LEDCNTRL_RANGE_TX_FULL 0x2 -#define AFE440X_LEDCNTRL_RANGE_TX_OFF 0x3 - -/* AFE4403 CONTROL2 values */ -#define AFE440X_CONTROL2_TX_REF_025 0x0 -#define AFE440X_CONTROL2_TX_REF_050 0x1 -#define AFE440X_CONTROL2_TX_REF_100 0x2 -#define AFE440X_CONTROL2_TX_REF_075 0x3 - -/* AFE4403 CONTROL3 values */ -#define AFE440X_CONTROL3_CLK_DIV_2 0x0 -#define AFE440X_CONTROL3_CLK_DIV_4 0x2 -#define AFE440X_CONTROL3_CLK_DIV_6 0x3 -#define AFE440X_CONTROL3_CLK_DIV_8 0x4 -#define AFE440X_CONTROL3_CLK_DIV_12 0x5 -#define AFE440X_CONTROL3_CLK_DIV_1 0x7 - -/* AFE4403 TIAGAIN_CAP values */ -#define AFE4403_TIAGAIN_CAP_5_P 0x0 -#define AFE4403_TIAGAIN_CAP_10_P 0x1 -#define AFE4403_TIAGAIN_CAP_20_P 0x2 -#define AFE4403_TIAGAIN_CAP_30_P 0x3 -#define AFE4403_TIAGAIN_CAP_55_P 0x8 -#define AFE4403_TIAGAIN_CAP_155_P 0x10 - -/* AFE4403 TIAGAIN_RES values */ -#define AFE4403_TIAGAIN_RES_500_K 0x0 -#define AFE4403_TIAGAIN_RES_250_K 0x1 -#define AFE4403_TIAGAIN_RES_100_K 0x2 -#define AFE4403_TIAGAIN_RES_50_K 0x3 -#define AFE4403_TIAGAIN_RES_25_K 0x4 -#define AFE4403_TIAGAIN_RES_10_K 0x5 -#define AFE4403_TIAGAIN_RES_1_M 0x6 -#define AFE4403_TIAGAIN_RES_NONE 0x7 - enum afe4403_fields { /* Gains */ F_RF_LED1, F_CF_LED1, diff --git a/drivers/iio/health/afe4404.c b/drivers/iio/health/afe4404.c index aa8770b..3a8131d 100644 --- a/drivers/iio/health/afe4404.c +++ b/drivers/iio/health/afe4404.c @@ -51,26 +51,6 @@ /* AFE4404 CONTROL3 register fields */ #define AFE440X_CONTROL3_OSC_ENABLE BIT(9) -/* AFE4404 TIA_GAIN_CAP values */ -#define AFE4404_TIA_GAIN_CAP_5_P 0x0 -#define AFE4404_TIA_GAIN_CAP_2_5_P 0x1 -#define AFE4404_TIA_GAIN_CAP_10_P 0x2 -#define AFE4404_TIA_GAIN_CAP_7_5_P 0x3 -#define AFE4404_TIA_GAIN_CAP_20_P 0x4 -#define AFE4404_TIA_GAIN_CAP_17_5_P 0x5 -#define AFE4404_TIA_GAIN_CAP_25_P 0x6 -#define AFE4404_TIA_GAIN_CAP_22_5_P 0x7 - -/* AFE4404 TIA_GAIN_RES values */ -#define AFE4404_TIA_GAIN_RES_500_K 0x0 -#define AFE4404_TIA_GAIN_RES_250_K 0x1 -#define AFE4404_TIA_GAIN_RES_100_K 0x2 -#define AFE4404_TIA_GAIN_RES_50_K 0x3 -#define AFE4404_TIA_GAIN_RES_25_K 0x4 -#define AFE4404_TIA_GAIN_RES_10_K 0x5 -#define AFE4404_TIA_GAIN_RES_1_M 0x6 -#define AFE4404_TIA_GAIN_RES_2_M 0x7 - enum afe4404_fields { /* Gains */ F_TIA_GAIN_SEP, F_TIA_CF_SEP, -- cgit v0.10.2 From 0825cce21f764c04a96b719af2b491011bc6c523 Mon Sep 17 00:00:00 2001 From: "Andrew F. Davis" Date: Sun, 1 May 2016 15:37:03 -0500 Subject: iio: health/afe4404: ENSEPGAIN is part of CONTROL2 register Rename this definition, no functional changes. Signed-off-by: Andrew F. Davis Signed-off-by: Jonathan Cameron diff --git a/drivers/iio/health/afe4404.c b/drivers/iio/health/afe4404.c index 3a8131d..4526640 100644 --- a/drivers/iio/health/afe4404.c +++ b/drivers/iio/health/afe4404.c @@ -48,8 +48,8 @@ #define AFE4404_AVG_LED2_ALED2VAL 0x3f #define AFE4404_AVG_LED1_ALED1VAL 0x40 -/* AFE4404 CONTROL3 register fields */ -#define AFE440X_CONTROL3_OSC_ENABLE BIT(9) +/* AFE4404 CONTROL2 register fields */ +#define AFE440X_CONTROL2_OSC_ENABLE BIT(9) enum afe4404_fields { /* Gains */ @@ -398,7 +398,7 @@ static const struct reg_sequence afe4404_reg_sequences[] = { AFE4404_TIMING_PAIRS, { AFE440X_CONTROL1, AFE440X_CONTROL1_TIMEREN }, { AFE4404_TIA_GAIN_SEP, AFE440X_TIAGAIN_ENSEPGAIN }, - { AFE440X_CONTROL2, AFE440X_CONTROL3_OSC_ENABLE }, + { AFE440X_CONTROL2, AFE440X_CONTROL2_OSC_ENABLE }, }; static const struct regmap_range afe4404_yes_ranges[] = { -- cgit v0.10.2 From 0f3a8c3f34f728e7c96651bb7271e1c388c9aac2 Mon Sep 17 00:00:00 2001 From: Daniel Baluta Date: Mon, 25 Apr 2016 16:15:51 +0300 Subject: iio: Add support for creating IIO devices via configfs This is similar with support for creating triggers via configfs. Devices will be hosted under: * /config/iio/devices We allow users to register "device types" under: * /config/iio/devices// Signed-off-by: Daniel Baluta Signed-off-by: Jonathan Cameron diff --git a/drivers/iio/Kconfig b/drivers/iio/Kconfig index 505e921..6743b18 100644 --- a/drivers/iio/Kconfig +++ b/drivers/iio/Kconfig @@ -46,6 +46,14 @@ config IIO_CONSUMERS_PER_TRIGGER This value controls the maximum number of consumers that a given trigger may handle. Default is 2. +config IIO_SW_DEVICE + tristate "Enable software IIO device support" + select IIO_CONFIGFS + help + Provides IIO core support for software devices. A software + device can be created via configfs or directly by a driver + using the API provided. + config IIO_SW_TRIGGER tristate "Enable software triggers support" select IIO_CONFIGFS diff --git a/drivers/iio/Makefile b/drivers/iio/Makefile index 20f6490..87e4c43 100644 --- a/drivers/iio/Makefile +++ b/drivers/iio/Makefile @@ -8,6 +8,7 @@ industrialio-$(CONFIG_IIO_BUFFER) += industrialio-buffer.o industrialio-$(CONFIG_IIO_TRIGGER) += industrialio-trigger.o obj-$(CONFIG_IIO_CONFIGFS) += industrialio-configfs.o +obj-$(CONFIG_IIO_SW_DEVICE) += industrialio-sw-device.o obj-$(CONFIG_IIO_SW_TRIGGER) += industrialio-sw-trigger.o obj-$(CONFIG_IIO_TRIGGERED_EVENT) += industrialio-triggered-event.o diff --git a/drivers/iio/industrialio-sw-device.c b/drivers/iio/industrialio-sw-device.c new file mode 100644 index 0000000..81b49cf --- /dev/null +++ b/drivers/iio/industrialio-sw-device.c @@ -0,0 +1,182 @@ +/* + * The Industrial I/O core, software IIO devices functions + * + * Copyright (c) 2016 Intel Corporation + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + */ + +#include +#include +#include +#include +#include + +#include +#include +#include + +static struct config_group *iio_devices_group; +static struct config_item_type iio_device_type_group_type; + +static struct config_item_type iio_devices_group_type = { + .ct_owner = THIS_MODULE, +}; + +static LIST_HEAD(iio_device_types_list); +static DEFINE_MUTEX(iio_device_types_lock); + +static +struct iio_sw_device_type *__iio_find_sw_device_type(const char *name, + unsigned len) +{ + struct iio_sw_device_type *d = NULL, *iter; + + list_for_each_entry(iter, &iio_device_types_list, list) + if (!strcmp(iter->name, name)) { + d = iter; + break; + } + + return d; +} + +int iio_register_sw_device_type(struct iio_sw_device_type *d) +{ + struct iio_sw_device_type *iter; + int ret = 0; + + mutex_lock(&iio_device_types_lock); + iter = __iio_find_sw_device_type(d->name, strlen(d->name)); + if (iter) + ret = -EBUSY; + else + list_add_tail(&d->list, &iio_device_types_list); + mutex_unlock(&iio_device_types_lock); + + if (ret) + return ret; + + d->group = configfs_register_default_group(iio_devices_group, d->name, + &iio_device_type_group_type); + if (IS_ERR(d->group)) + ret = PTR_ERR(d->group); + + return ret; +} +EXPORT_SYMBOL(iio_register_sw_device_type); + +void iio_unregister_sw_device_type(struct iio_sw_device_type *dt) +{ + struct iio_sw_device_type *iter; + + mutex_lock(&iio_device_types_lock); + iter = __iio_find_sw_device_type(dt->name, strlen(dt->name)); + if (iter) + list_del(&dt->list); + mutex_unlock(&iio_device_types_lock); + + configfs_unregister_default_group(dt->group); +} +EXPORT_SYMBOL(iio_unregister_sw_device_type); + +static +struct iio_sw_device_type *iio_get_sw_device_type(const char *name) +{ + struct iio_sw_device_type *dt; + + mutex_lock(&iio_device_types_lock); + dt = __iio_find_sw_device_type(name, strlen(name)); + if (dt && !try_module_get(dt->owner)) + dt = NULL; + mutex_unlock(&iio_device_types_lock); + + return dt; +} + +struct iio_sw_device *iio_sw_device_create(const char *type, const char *name) +{ + struct iio_sw_device *d; + struct iio_sw_device_type *dt; + + dt = iio_get_sw_device_type(type); + if (!dt) { + pr_err("Invalid device type: %s\n", type); + return ERR_PTR(-EINVAL); + } + d = dt->ops->probe(name); + if (IS_ERR(d)) + goto out_module_put; + + d->device_type = dt; + + return d; +out_module_put: + module_put(dt->owner); + return d; +} +EXPORT_SYMBOL(iio_sw_device_create); + +void iio_sw_device_destroy(struct iio_sw_device *d) +{ + struct iio_sw_device_type *dt = d->device_type; + + dt->ops->remove(d); + module_put(dt->owner); +} +EXPORT_SYMBOL(iio_sw_device_destroy); + +static struct config_group *device_make_group(struct config_group *group, + const char *name) +{ + struct iio_sw_device *d; + + d = iio_sw_device_create(group->cg_item.ci_name, name); + if (IS_ERR(d)) + return ERR_CAST(d); + + config_item_set_name(&d->group.cg_item, "%s", name); + + return &d->group; +} + +static void device_drop_group(struct config_group *group, + struct config_item *item) +{ + struct iio_sw_device *d = to_iio_sw_device(item); + + iio_sw_device_destroy(d); + config_item_put(item); +} + +static struct configfs_group_operations device_ops = { + .make_group = &device_make_group, + .drop_item = &device_drop_group, +}; + +static struct config_item_type iio_device_type_group_type = { + .ct_group_ops = &device_ops, + .ct_owner = THIS_MODULE, +}; + +static int __init iio_sw_device_init(void) +{ + iio_devices_group = + configfs_register_default_group(&iio_configfs_subsys.su_group, + "devices", + &iio_devices_group_type); + return PTR_ERR_OR_ZERO(iio_devices_group); +} +module_init(iio_sw_device_init); + +static void __exit iio_sw_device_exit(void) +{ + configfs_unregister_default_group(iio_devices_group); +} +module_exit(iio_sw_device_exit); + +MODULE_AUTHOR("Daniel Baluta "); +MODULE_DESCRIPTION("Industrial I/O software devices support"); +MODULE_LICENSE("GPL v2"); diff --git a/include/linux/iio/sw_device.h b/include/linux/iio/sw_device.h new file mode 100644 index 0000000..23ca415 --- /dev/null +++ b/include/linux/iio/sw_device.h @@ -0,0 +1,70 @@ +/* + * Industrial I/O software device interface + * + * Copyright (c) 2016 Intel Corporation + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + */ + +#ifndef __IIO_SW_DEVICE +#define __IIO_SW_DEVICE + +#include +#include +#include +#include + +#define module_iio_sw_device_driver(__iio_sw_device_type) \ + module_driver(__iio_sw_device_type, iio_register_sw_device_type, \ + iio_unregister_sw_device_type) + +struct iio_sw_device_ops; + +struct iio_sw_device_type { + const char *name; + struct module *owner; + const struct iio_sw_device_ops *ops; + struct list_head list; + struct config_group *group; +}; + +struct iio_sw_device { + struct iio_dev *device; + struct iio_sw_device_type *device_type; + struct config_group group; +}; + +struct iio_sw_device_ops { + struct iio_sw_device* (*probe)(const char *); + int (*remove)(struct iio_sw_device *); +}; + +static inline +struct iio_sw_device *to_iio_sw_device(struct config_item *item) +{ + return container_of(to_config_group(item), struct iio_sw_device, + group); +} + +int iio_register_sw_device_type(struct iio_sw_device_type *dt); +void iio_unregister_sw_device_type(struct iio_sw_device_type *dt); + +struct iio_sw_device *iio_sw_device_create(const char *, const char *); +void iio_sw_device_destroy(struct iio_sw_device *); + +int iio_sw_device_type_configfs_register(struct iio_sw_device_type *dt); +void iio_sw_device_type_configfs_unregister(struct iio_sw_device_type *dt); + +static inline +void iio_swd_group_init_type_name(struct iio_sw_device *d, + const char *name, + struct config_item_type *type) +{ +#ifdef CONFIG_CONFIGFS_FS + config_group_init_type_name(&d->group, name, type); +#endif +} + +#endif /* __IIO_SW_DEVICE */ -- cgit v0.10.2 From 3d85fb6f81046b51e4428e14fb9643ea75648630 Mon Sep 17 00:00:00 2001 From: Daniel Baluta Date: Mon, 25 Apr 2016 16:15:52 +0300 Subject: iio: dummy: Convert IIO dummy to configfs We register a new device type named "dummy", this will create a configfs entry under: * /config/iio/devices/dummy. Creating dummy devices is now as simple as: $ mkdir /config/iio/devices/dummy/my_dummy_device Signed-off-by: Daniel Baluta Signed-off-by: Jonathan Cameron diff --git a/drivers/iio/dummy/Kconfig b/drivers/iio/dummy/Kconfig index 71805ce..aa5824d 100644 --- a/drivers/iio/dummy/Kconfig +++ b/drivers/iio/dummy/Kconfig @@ -10,6 +10,7 @@ config IIO_DUMMY_EVGEN config IIO_SIMPLE_DUMMY tristate "An example driver with no hardware requirements" + depends on IIO_SW_DEVICE help Driver intended mainly as documentation for how to write a driver. May also be useful for testing userspace code diff --git a/drivers/iio/dummy/iio_simple_dummy.c b/drivers/iio/dummy/iio_simple_dummy.c index 43fe4ba..ad3410e 100644 --- a/drivers/iio/dummy/iio_simple_dummy.c +++ b/drivers/iio/dummy/iio_simple_dummy.c @@ -17,26 +17,18 @@ #include #include #include +#include #include #include #include #include +#include #include "iio_simple_dummy.h" -/* - * A few elements needed to fake a bus for this driver - * Note instances parameter controls how many of these - * dummy devices are registered. - */ -static unsigned instances = 1; -module_param(instances, uint, 0); - -/* Pointer array used to fake bus elements */ -static struct iio_dev **iio_dummy_devs; - -/* Fake a name for the part number, usually obtained from the id table */ -static const char *iio_dummy_part_number = "iio_dummy_part_no"; +static struct config_item_type iio_dummy_type = { + .ct_owner = THIS_MODULE, +}; /** * struct iio_dummy_accel_calibscale - realworld to register mapping @@ -572,12 +564,18 @@ static int iio_dummy_init_device(struct iio_dev *indio_dev) * const struct i2c_device_id *id) * SPI: iio_dummy_probe(struct spi_device *spi) */ -static int iio_dummy_probe(int index) +static struct iio_sw_device *iio_dummy_probe(const char *name) { int ret; struct iio_dev *indio_dev; struct iio_dummy_state *st; + struct iio_sw_device *swd; + swd = kzalloc(sizeof(*swd), GFP_KERNEL); + if (!swd) { + ret = -ENOMEM; + goto error_kzalloc; + } /* * Allocate an IIO device. * @@ -608,7 +606,7 @@ static int iio_dummy_probe(int index) * i2c_set_clientdata(client, indio_dev); * spi_set_drvdata(spi, indio_dev); */ - iio_dummy_devs[index] = indio_dev; + swd->device = indio_dev; /* * Set the device name. @@ -619,7 +617,7 @@ static int iio_dummy_probe(int index) * indio_dev->name = id->name; * indio_dev->name = spi_get_device_id(spi)->name; */ - indio_dev->name = iio_dummy_part_number; + indio_dev->name = kstrdup(name, GFP_KERNEL); /* Provide description of available channels */ indio_dev->channels = iio_dummy_channels; @@ -646,7 +644,9 @@ static int iio_dummy_probe(int index) if (ret < 0) goto error_unconfigure_buffer; - return 0; + iio_swd_group_init_type_name(swd, name, &iio_dummy_type); + + return swd; error_unconfigure_buffer: iio_simple_dummy_unconfigure_buffer(indio_dev); error_unregister_events: @@ -654,16 +654,18 @@ error_unregister_events: error_free_device: iio_device_free(indio_dev); error_ret: - return ret; + kfree(swd); +error_kzalloc: + return ERR_PTR(ret); } /** * iio_dummy_remove() - device instance removal function - * @index: device index. + * @swd: pointer to software IIO device abstraction * * Parameters follow those of iio_dummy_probe for buses. */ -static void iio_dummy_remove(int index) +static int iio_dummy_remove(struct iio_sw_device *swd) { /* * Get a pointer to the device instance iio_dev structure @@ -671,7 +673,7 @@ static void iio_dummy_remove(int index) * struct iio_dev *indio_dev = i2c_get_clientdata(client); * struct iio_dev *indio_dev = spi_get_drvdata(spi); */ - struct iio_dev *indio_dev = iio_dummy_devs[index]; + struct iio_dev *indio_dev = swd->device; /* Unregister the device */ iio_device_unregister(indio_dev); @@ -684,11 +686,13 @@ static void iio_dummy_remove(int index) iio_simple_dummy_events_unregister(indio_dev); /* Free all structures */ + kfree(indio_dev->name); iio_device_free(indio_dev); -} + return 0; +} /** - * iio_dummy_init() - device driver registration + * module_iio_sw_device_driver() - device driver registration * * Varies depending on bus type of the device. As there is no device * here, call probe directly. For information on device registration @@ -697,50 +701,18 @@ static void iio_dummy_remove(int index) * spi: * Documentation/spi/spi-summary */ -static __init int iio_dummy_init(void) -{ - int i, ret; - - if (instances > 10) { - instances = 1; - return -EINVAL; - } - - /* Fake a bus */ - iio_dummy_devs = kcalloc(instances, sizeof(*iio_dummy_devs), - GFP_KERNEL); - /* Here we have no actual device so call probe */ - for (i = 0; i < instances; i++) { - ret = iio_dummy_probe(i); - if (ret < 0) - goto error_remove_devs; - } - return 0; - -error_remove_devs: - while (i--) - iio_dummy_remove(i); - - kfree(iio_dummy_devs); - return ret; -} -module_init(iio_dummy_init); +static const struct iio_sw_device_ops iio_dummy_device_ops = { + .probe = iio_dummy_probe, + .remove = iio_dummy_remove, +}; -/** - * iio_dummy_exit() - device driver removal - * - * Varies depending on bus type of the device. - * As there is no device here, call remove directly. - */ -static __exit void iio_dummy_exit(void) -{ - int i; +static struct iio_sw_device_type iio_dummy_device = { + .name = "dummy", + .owner = THIS_MODULE, + .ops = &iio_dummy_device_ops, +}; - for (i = 0; i < instances; i++) - iio_dummy_remove(i); - kfree(iio_dummy_devs); -} -module_exit(iio_dummy_exit); +module_iio_sw_device_driver(iio_dummy_device); MODULE_AUTHOR("Jonathan Cameron "); MODULE_DESCRIPTION("IIO dummy driver"); -- cgit v0.10.2 From 6994aea7842d824a8cc38c950ddcab3f8a75c278 Mon Sep 17 00:00:00 2001 From: Daniel Baluta Date: Mon, 25 Apr 2016 16:15:53 +0300 Subject: Documentation: iio: Add IIO software devices docs Signed-off-by: Daniel Baluta Signed-off-by: Jonathan Cameron diff --git a/Documentation/ABI/testing/configfs-iio b/Documentation/ABI/testing/configfs-iio index 2483756..aebda53 100644 --- a/Documentation/ABI/testing/configfs-iio +++ b/Documentation/ABI/testing/configfs-iio @@ -19,3 +19,16 @@ KernelVersion: 4.4 Description: High resolution timers directory. Creating a directory here will result in creating a hrtimer trigger in the IIO subsystem. + +What: /config/iio/devices +Date: April 2016 +KernelVersion: 4.7 +Description: + Industrial IO software devices directory. + +What: /config/iio/devices/dummy +Date: April 2016 +KernelVersion: 4.7 +Description: + Dummy IIO devices directory. Creating a directory here will result + in creating a dummy IIO device in the IIO subystem. -- cgit v0.10.2 From ed859fc17d67f4c0ade6f5a58365e621f88de3cf Mon Sep 17 00:00:00 2001 From: Martin Kepplinger Date: Mon, 25 Apr 2016 14:08:25 +0200 Subject: iio: mma8452: add support for oversampling ratio This adds the following sysfs files according to the iio ABI: -rw-r--r-- 4096 in_accel_oversampling_ratio -r--r--r-- 4096 in_accel_oversampling_ratio_available Internally, the device knows about 4 different power modes that differ in oversampling ratio (and power consumption). We just show the user what oversampling ratio(s) is/are available, depending on the current frequency. The referenced table in the datasheets makes it easier to understand. Signed-off-by: Martin Kepplinger Signed-off-by: Christoph Muellner Signed-off-by: Jonathan Cameron diff --git a/drivers/iio/accel/mma8452.c b/drivers/iio/accel/mma8452.c index e225d3c..458c827 100644 --- a/drivers/iio/accel/mma8452.c +++ b/drivers/iio/accel/mma8452.c @@ -76,6 +76,8 @@ #define MMA8452_CTRL_DR_DEFAULT 0x4 /* 50 Hz sample frequency */ #define MMA8452_CTRL_REG2 0x2b #define MMA8452_CTRL_REG2_RST BIT(6) +#define MMA8452_CTRL_REG2_MODS_SHIFT 3 +#define MMA8452_CTRL_REG2_MODS_MASK 0x1b #define MMA8452_CTRL_REG4 0x2d #define MMA8452_CTRL_REG5 0x2e #define MMA8452_OFF_X 0x2f @@ -257,20 +259,17 @@ static const int mma8452_samp_freq[8][2] = { {6, 250000}, {1, 560000} }; -/* Datasheet table 35 (step time vs sample frequency) */ -static const int mma8452_transient_time_step_us[8] = { - 1250, - 2500, - 5000, - 10000, - 20000, - 20000, - 20000, - 20000 +/* Datasheet table: step time "Relationship with the ODR" (sample frequency) */ +static const int mma8452_transient_time_step_us[4][8] = { + { 1250, 2500, 5000, 10000, 20000, 20000, 20000, 20000 }, /* normal */ + { 1250, 2500, 5000, 10000, 20000, 80000, 80000, 80000 }, /* l p l n */ + { 1250, 2500, 2500, 2500, 2500, 2500, 2500, 2500 }, /* high res*/ + { 1250, 2500, 5000, 10000, 20000, 80000, 160000, 160000 } /* l p */ }; -/* Datasheet table 18 (normal mode) */ -static const int mma8452_hp_filter_cutoff[8][4][2] = { +/* Datasheet table "High-Pass Filter Cutoff Options" */ +static const int mma8452_hp_filter_cutoff[4][8][4][2] = { + { /* normal */ { {16, 0}, {8, 0}, {4, 0}, {2, 0} }, /* 800 Hz sample */ { {16, 0}, {8, 0}, {4, 0}, {2, 0} }, /* 400 Hz sample */ { {8, 0}, {4, 0}, {2, 0}, {1, 0} }, /* 200 Hz sample */ @@ -279,8 +278,61 @@ static const int mma8452_hp_filter_cutoff[8][4][2] = { { {2, 0}, {1, 0}, {0, 500000}, {0, 250000} }, /* 12.5 Hz sample */ { {2, 0}, {1, 0}, {0, 500000}, {0, 250000} }, /* 6.25 Hz sample */ { {2, 0}, {1, 0}, {0, 500000}, {0, 250000} } /* 1.56 Hz sample */ + }, + { /* low noise low power */ + { {16, 0}, {8, 0}, {4, 0}, {2, 0} }, + { {16, 0}, {8, 0}, {4, 0}, {2, 0} }, + { {8, 0}, {4, 0}, {2, 0}, {1, 0} }, + { {4, 0}, {2, 0}, {1, 0}, {0, 500000} }, + { {2, 0}, {1, 0}, {0, 500000}, {0, 250000} }, + { {0, 500000}, {0, 250000}, {0, 125000}, {0, 063000} }, + { {0, 500000}, {0, 250000}, {0, 125000}, {0, 063000} }, + { {0, 500000}, {0, 250000}, {0, 125000}, {0, 063000} } + }, + { /* high resolution */ + { {16, 0}, {8, 0}, {4, 0}, {2, 0} }, + { {16, 0}, {8, 0}, {4, 0}, {2, 0} }, + { {16, 0}, {8, 0}, {4, 0}, {2, 0} }, + { {16, 0}, {8, 0}, {4, 0}, {2, 0} }, + { {16, 0}, {8, 0}, {4, 0}, {2, 0} }, + { {16, 0}, {8, 0}, {4, 0}, {2, 0} }, + { {16, 0}, {8, 0}, {4, 0}, {2, 0} }, + { {16, 0}, {8, 0}, {4, 0}, {2, 0} } + }, + { /* low power */ + { {16, 0}, {8, 0}, {4, 0}, {2, 0} }, + { {8, 0}, {4, 0}, {2, 0}, {1, 0} }, + { {4, 0}, {2, 0}, {1, 0}, {0, 500000} }, + { {2, 0}, {1, 0}, {0, 500000}, {0, 250000} }, + { {1, 0}, {0, 500000}, {0, 250000}, {0, 125000} }, + { {0, 250000}, {0, 125000}, {0, 063000}, {0, 031000} }, + { {0, 250000}, {0, 125000}, {0, 063000}, {0, 031000} }, + { {0, 250000}, {0, 125000}, {0, 063000}, {0, 031000} } + } }; +/* Datasheet table "MODS Oversampling modes averaging values at each ODR" */ +static const u16 mma8452_os_ratio[4][8] = { + /* 800 Hz, 400 Hz, ... , 1.56 Hz */ + { 2, 4, 4, 4, 4, 16, 32, 128 }, /* normal */ + { 2, 4, 4, 4, 4, 4, 8, 32 }, /* low power low noise */ + { 2, 4, 8, 16, 32, 128, 256, 1024 }, /* high resolution */ + { 2, 2, 2, 2, 2, 2, 4, 16 } /* low power */ +}; + +static int mma8452_get_power_mode(struct mma8452_data *data) +{ + int reg; + + reg = i2c_smbus_read_byte_data(data->client, + MMA8452_CTRL_REG2); + if (reg < 0) + return reg; + + return ((reg & MMA8452_CTRL_REG2_MODS_MASK) >> + MMA8452_CTRL_REG2_MODS_SHIFT); +} + static ssize_t mma8452_show_samp_freq_avail(struct device *dev, struct device_attribute *attr, char *buf) @@ -306,10 +358,39 @@ static ssize_t mma8452_show_hp_cutoff_avail(struct device *dev, { struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct mma8452_data *data = iio_priv(indio_dev); + int i, j; + + i = mma8452_get_odr_index(data); + j = mma8452_get_power_mode(data); + if (j < 0) + return j; + + return mma8452_show_int_plus_micros(buf, mma8452_hp_filter_cutoff[j][i], + ARRAY_SIZE(mma8452_hp_filter_cutoff[0][0])); +} + +static ssize_t mma8452_show_os_ratio_avail(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *indio_dev = dev_to_iio_dev(dev); + struct mma8452_data *data = iio_priv(indio_dev); int i = mma8452_get_odr_index(data); + int j; + u16 val = 0; + size_t len = 0; + + for (j = 0; j < ARRAY_SIZE(mma8452_os_ratio); j++) { + if (val == mma8452_os_ratio[j][i]) + continue; + + val = mma8452_os_ratio[j][i]; + + len += scnprintf(buf + len, PAGE_SIZE - len, "%d ", val); + } + buf[len - 1] = '\n'; - return mma8452_show_int_plus_micros(buf, mma8452_hp_filter_cutoff[i], - ARRAY_SIZE(mma8452_hp_filter_cutoff[0])); + return len; } static IIO_DEV_ATTR_SAMP_FREQ_AVAIL(mma8452_show_samp_freq_avail); @@ -317,6 +398,8 @@ static IIO_DEVICE_ATTR(in_accel_scale_available, S_IRUGO, mma8452_show_scale_avail, NULL, 0); static IIO_DEVICE_ATTR(in_accel_filter_high_pass_3db_frequency_available, S_IRUGO, mma8452_show_hp_cutoff_avail, NULL, 0); +static IIO_DEVICE_ATTR(in_accel_oversampling_ratio_available, S_IRUGO, + mma8452_show_os_ratio_avail, NULL, 0); static int mma8452_get_samp_freq_index(struct mma8452_data *data, int val, int val2) @@ -335,24 +418,33 @@ static int mma8452_get_scale_index(struct mma8452_data *data, int val, int val2) static int mma8452_get_hp_filter_index(struct mma8452_data *data, int val, int val2) { - int i = mma8452_get_odr_index(data); + int i, j; + + i = mma8452_get_odr_index(data); + j = mma8452_get_power_mode(data); + if (j < 0) + return j; - return mma8452_get_int_plus_micros_index(mma8452_hp_filter_cutoff[i], - ARRAY_SIZE(mma8452_hp_filter_cutoff[0]), val, val2); + return mma8452_get_int_plus_micros_index(mma8452_hp_filter_cutoff[j][i], + ARRAY_SIZE(mma8452_hp_filter_cutoff[0][0]), val, val2); } static int mma8452_read_hp_filter(struct mma8452_data *data, int *hz, int *uHz) { - int i, ret; + int j, i, ret; ret = i2c_smbus_read_byte_data(data->client, MMA8452_HP_FILTER_CUTOFF); if (ret < 0) return ret; i = mma8452_get_odr_index(data); + j = mma8452_get_power_mode(data); + if (j < 0) + return j; + ret &= MMA8452_HP_FILTER_CUTOFF_SEL_MASK; - *hz = mma8452_hp_filter_cutoff[i][ret][0]; - *uHz = mma8452_hp_filter_cutoff[i][ret][1]; + *hz = mma8452_hp_filter_cutoff[j][i][ret][0]; + *uHz = mma8452_hp_filter_cutoff[j][i][ret][1]; return 0; } @@ -414,6 +506,15 @@ static int mma8452_read_raw(struct iio_dev *indio_dev, } return IIO_VAL_INT_PLUS_MICRO; + case IIO_CHAN_INFO_OVERSAMPLING_RATIO: + ret = mma8452_get_power_mode(data); + if (ret < 0) + return ret; + + i = mma8452_get_odr_index(data); + + *val = mma8452_os_ratio[ret][i]; + return IIO_VAL_INT; } return -EINVAL; @@ -480,6 +581,21 @@ fail: return ret; } +static int mma8452_set_power_mode(struct mma8452_data *data, u8 mode) +{ + int reg; + + reg = i2c_smbus_read_byte_data(data->client, + MMA8452_CTRL_REG2); + if (reg < 0) + return reg; + + reg &= ~MMA8452_CTRL_REG2_MODS_MASK; + reg |= mode << MMA8452_CTRL_REG2_MODS_SHIFT; + + return mma8452_change_config(data, MMA8452_CTRL_REG2, reg); +} + /* returns >0 if in freefall mode, 0 if not or <0 if an error occurred */ static int mma8452_freefall_mode_enabled(struct mma8452_data *data) { @@ -597,6 +713,14 @@ static int mma8452_write_raw(struct iio_dev *indio_dev, return mma8452_change_config(data, MMA8452_DATA_CFG, data->data_cfg); + case IIO_CHAN_INFO_OVERSAMPLING_RATIO: + ret = mma8452_get_odr_index(data); + + for (i = 0; i < ARRAY_SIZE(mma8452_os_ratio); i++) { + if (mma8452_os_ratio[i][ret] == val) + return mma8452_set_power_mode(data, i); + } + default: return -EINVAL; } @@ -610,7 +734,7 @@ static int mma8452_read_thresh(struct iio_dev *indio_dev, int *val, int *val2) { struct mma8452_data *data = iio_priv(indio_dev); - int ret, us; + int ret, us, power_mode; switch (info) { case IIO_EV_INFO_VALUE: @@ -629,7 +753,11 @@ static int mma8452_read_thresh(struct iio_dev *indio_dev, if (ret < 0) return ret; - us = ret * mma8452_transient_time_step_us[ + power_mode = mma8452_get_power_mode(data); + if (power_mode < 0) + return power_mode; + + us = ret * mma8452_transient_time_step_us[power_mode][ mma8452_get_odr_index(data)]; *val = us / USEC_PER_SEC; *val2 = us % USEC_PER_SEC; @@ -677,8 +805,12 @@ static int mma8452_write_thresh(struct iio_dev *indio_dev, val); case IIO_EV_INFO_PERIOD: + ret = mma8452_get_power_mode(data); + if (ret < 0) + return ret; + steps = (val * USEC_PER_SEC + val2) / - mma8452_transient_time_step_us[ + mma8452_transient_time_step_us[ret][ mma8452_get_odr_index(data)]; if (steps < 0 || steps > 0xff) @@ -978,7 +1110,8 @@ static struct attribute_group mma8452_event_attribute_group = { BIT(IIO_CHAN_INFO_CALIBBIAS), \ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SAMP_FREQ) | \ BIT(IIO_CHAN_INFO_SCALE) | \ - BIT(IIO_CHAN_INFO_HIGH_PASS_FILTER_3DB_FREQUENCY), \ + BIT(IIO_CHAN_INFO_HIGH_PASS_FILTER_3DB_FREQUENCY) | \ + BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \ .scan_index = idx, \ .scan_type = { \ .sign = 's', \ @@ -998,7 +1131,8 @@ static struct attribute_group mma8452_event_attribute_group = { .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ BIT(IIO_CHAN_INFO_CALIBBIAS), \ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SAMP_FREQ) | \ - BIT(IIO_CHAN_INFO_SCALE), \ + BIT(IIO_CHAN_INFO_SCALE) | \ + BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \ .scan_index = idx, \ .scan_type = { \ .sign = 's', \ @@ -1171,6 +1305,7 @@ static struct attribute *mma8452_attributes[] = { &iio_dev_attr_sampling_frequency_available.dev_attr.attr, &iio_dev_attr_in_accel_scale_available.dev_attr.attr, &iio_dev_attr_in_accel_filter_high_pass_3db_frequency_available.dev_attr.attr, + &iio_dev_attr_in_accel_oversampling_ratio_available.dev_attr.attr, NULL }; -- cgit v0.10.2 From 3282e6b8f89eaeaf4915ee6cc57bcf06d1d6cead Mon Sep 17 00:00:00 2001 From: Sudeep Holla Date: Wed, 4 May 2016 17:50:59 +0100 Subject: x86/topology: Remove redundant ENABLE_TOPO_DEFINES Commit c8e56d20f2d1 ("x86: Kill CONFIG_X86_HT") removed CONFIG_X86_HT and defined ENABLE_TOPO_DEFINES always if CONFIG_SMP, which makes ENABLE_TOPO_DEFINES redundant. This patch removes the redundant ENABLE_TOPO_DEFINES and instead uses CONFIG_SMP directly Signed-off-by: Sudeep Holla Acked-by: Borislav Petkov Cc: Andy Lutomirski Cc: Borislav Petkov Cc: Brian Gerst Cc: Denys Vlasenko Cc: H. Peter Anvin Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/1462380659-5968-1-git-send-email-sudeep.holla@arm.com Signed-off-by: Ingo Molnar diff --git a/arch/x86/include/asm/topology.h b/arch/x86/include/asm/topology.h index 7f991bd5..c9a4ed7 100644 --- a/arch/x86/include/asm/topology.h +++ b/arch/x86/include/asm/topology.h @@ -25,16 +25,6 @@ #ifndef _ASM_X86_TOPOLOGY_H #define _ASM_X86_TOPOLOGY_H -#ifdef CONFIG_X86_32 -# ifdef CONFIG_SMP -# define ENABLE_TOPO_DEFINES -# endif -#else -# ifdef CONFIG_SMP -# define ENABLE_TOPO_DEFINES -# endif -#endif - /* * to preserve the visibility of NUMA_NO_NODE definition, * moved to there from here. May be used independent of @@ -123,7 +113,7 @@ extern const struct cpumask *cpu_coregroup_mask(int cpu); #define topology_physical_package_id(cpu) (cpu_data(cpu).phys_proc_id) #define topology_core_id(cpu) (cpu_data(cpu).cpu_core_id) -#ifdef ENABLE_TOPO_DEFINES +#ifdef CONFIG_SMP #define topology_core_cpumask(cpu) (per_cpu(cpu_core_map, cpu)) #define topology_sibling_cpumask(cpu) (per_cpu(cpu_sibling_map, cpu)) -- cgit v0.10.2 From f0133acc7d4835cfbb86393b7d2a4fba7519585b Mon Sep 17 00:00:00 2001 From: Borislav Petkov Date: Sun, 8 May 2016 20:58:40 +0200 Subject: x86/cpu: Correct comments and messages in P4 erratum 037 handling code Remove the linebreak in the conditional and s/errata/erratum/ as the singular is "erratum". No functionality change. Signed-off-by: Borislav Petkov Cc: Andy Lutomirski Cc: Borislav Petkov Cc: Brian Gerst Cc: Denys Vlasenko Cc: H. Peter Anvin Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/1462733920-7224-1-git-send-email-bp@alien8.de Signed-off-by: Ingo Molnar diff --git a/arch/x86/kernel/cpu/intel.c b/arch/x86/kernel/cpu/intel.c index f71a349..5354080 100644 --- a/arch/x86/kernel/cpu/intel.c +++ b/arch/x86/kernel/cpu/intel.c @@ -263,15 +263,14 @@ static void intel_workarounds(struct cpuinfo_x86 *c) } /* - * P4 Xeon errata 037 workaround. + * P4 Xeon erratum 037 workaround. * Hardware prefetcher may cause stale data to be loaded into the cache. */ if ((c->x86 == 15) && (c->x86_model == 1) && (c->x86_mask == 1)) { if (msr_set_bit(MSR_IA32_MISC_ENABLE, - MSR_IA32_MISC_ENABLE_PREFETCH_DISABLE_BIT) - > 0) { + MSR_IA32_MISC_ENABLE_PREFETCH_DISABLE_BIT) > 0) { pr_info("CPU: C0 stepping P4 Xeon detected.\n"); - pr_info("CPU: Disabling hardware prefetching (Errata 037)\n"); + pr_info("CPU: Disabling hardware prefetching (Erratum 037)\n"); } } -- cgit v0.10.2 From 67d7a982bab6702d84415ea889996fae72a7d3b2 Mon Sep 17 00:00:00 2001 From: Mathias Krause Date: Tue, 10 May 2016 23:07:02 +0200 Subject: x86/extable: Ensure entries are swapped completely when sorting The x86 exception table sorting was changed in this recent commit: 29934b0fb8ff ("x86/extable: use generic search and sort routines") ... to use the arch independent code in lib/extable.c. However, the patch was mangled somehow on its way into the kernel from the last version posted at: https://lkml.org/lkml/2016/1/27/232 The committed version kind of attempted to incorporate the changes of contemporary commit done in the x86 tree: 548acf19234d ("x86/mm: Expand the exception table logic to allow new handling options") ... as in _completely_ _ignoring_ the x86 specific 'handler' member of struct exception_table_entry. This effectively broke the sorting as entries will only be partly swapped now. Fortunately, the x86 Kconfig selects BUILDTIME_EXTABLE_SORT, so the exception table doesn't need to be sorted at runtime. However, in case that ever changes, we better not break the exception table sorting just because of that. Fix this by providing a swap_ex_entry_fixup() macro that takes care of the 'handler' member. Signed-off-by: Mathias Krause Reviewed-by: Ard Biesheuvel Cc: Andrew Morton Cc: Andy Lutomirski Cc: Andy Lutomirski Cc: Borislav Petkov Cc: Borislav Petkov Cc: Brian Gerst Cc: Denys Vlasenko Cc: H. Peter Anvin Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: Tony Luck Link: http://lkml.kernel.org/r/1462914422-2911-1-git-send-email-minipli@googlemail.com Signed-off-by: Ingo Molnar diff --git a/arch/x86/include/asm/uaccess.h b/arch/x86/include/asm/uaccess.h index 8b3fb76..86c48f3 100644 --- a/arch/x86/include/asm/uaccess.h +++ b/arch/x86/include/asm/uaccess.h @@ -108,6 +108,14 @@ struct exception_table_entry { #define ARCH_HAS_RELATIVE_EXTABLE +#define swap_ex_entry_fixup(a, b, tmp, delta) \ + do { \ + (a)->fixup = (b)->fixup + (delta); \ + (b)->fixup = (tmp).fixup - (delta); \ + (a)->handler = (b)->handler + (delta); \ + (b)->handler = (tmp).handler - (delta); \ + } while (0) + extern int fixup_exception(struct pt_regs *regs, int trapnr); extern bool ex_has_fault_handler(unsigned long ip); extern int early_fixup_exception(unsigned long *ip); -- cgit v0.10.2 From 2763ac94f3e4d3711863729f4c11500d245f68cc Mon Sep 17 00:00:00 2001 From: Matt Ranostay Date: Wed, 11 May 2016 21:47:48 -0700 Subject: iio: potentiometer: tpl0102: remove unneeded i2c check functionality test Actually I2C_FUNC_SMBUS_WORD_DATA isn't need for this device, and regmap handles all single byte reads transparently. Signed-off-by: Matt Ranostay Signed-off-by: Jonathan Cameron diff --git a/drivers/iio/potentiometer/tpl0102.c b/drivers/iio/potentiometer/tpl0102.c index 5c304d4..7b6b545 100644 --- a/drivers/iio/potentiometer/tpl0102.c +++ b/drivers/iio/potentiometer/tpl0102.c @@ -116,10 +116,6 @@ static int tpl0102_probe(struct i2c_client *client, struct tpl0102_data *data; struct iio_dev *indio_dev; - if (!i2c_check_functionality(client->adapter, - I2C_FUNC_SMBUS_WORD_DATA)) - return -EOPNOTSUPP; - indio_dev = devm_iio_device_alloc(dev, sizeof(*data)); if (!indio_dev) return -ENOMEM; -- cgit v0.10.2 From bf2a5600a3ebc9dc5f085b47791009e25ade0157 Mon Sep 17 00:00:00 2001 From: Tiberiu Breana Date: Thu, 5 May 2016 18:48:55 +0300 Subject: iio: accel: Add support for Bosch BMA220 This commit adds basic support for the Bosch Sensortec BMA220 digital triaxial acceleration sensor. The device datasheet can be found here: http://www.mouser.com/pdfdocs/BSTBMA220DS00308.PDF Includes: - raw readings - ACPI detection - power management Signed-off-by: Tiberiu Breana Signed-off-by: Jonathan Cameron diff --git a/drivers/iio/accel/Kconfig b/drivers/iio/accel/Kconfig index 1df6361..3132587 100644 --- a/drivers/iio/accel/Kconfig +++ b/drivers/iio/accel/Kconfig @@ -17,6 +17,16 @@ config BMA180 To compile this driver as a module, choose M here: the module will be called bma180. +config BMA220 + tristate "Bosch BMA220 3-Axis Accelerometer Driver" + depends on SPI + help + Say yes here to add support for the Bosch BMA220 triaxial + acceleration sensor. + + To compile this driver as a module, choose M here: the + module will be called bma220_spi. + config BMC150_ACCEL tristate "Bosch BMC150 Accelerometer Driver" select IIO_BUFFER diff --git a/drivers/iio/accel/Makefile b/drivers/iio/accel/Makefile index ba1165f..6cedbec 100644 --- a/drivers/iio/accel/Makefile +++ b/drivers/iio/accel/Makefile @@ -4,6 +4,7 @@ # When adding new entries keep the list in alphabetical order obj-$(CONFIG_BMA180) += bma180.o +obj-$(CONFIG_BMA220) += bma220_spi.o obj-$(CONFIG_BMC150_ACCEL) += bmc150-accel-core.o obj-$(CONFIG_BMC150_ACCEL_I2C) += bmc150-accel-i2c.o obj-$(CONFIG_BMC150_ACCEL_SPI) += bmc150-accel-spi.o diff --git a/drivers/iio/accel/bma220_spi.c b/drivers/iio/accel/bma220_spi.c new file mode 100644 index 0000000..7343575 --- /dev/null +++ b/drivers/iio/accel/bma220_spi.c @@ -0,0 +1,277 @@ +/** + * BMA220 Digital triaxial acceleration sensor driver + * + * Copyright (c) 2016, Intel Corporation. + * + * This file is subject to the terms and conditions of version 2 of + * the GNU General Public License. See the file COPYING in the main + * directory of this archive for more details. + */ + +#include +#include +#include +#include +#include +#include + +#define BMA220_REG_ID 0x00 +#define BMA220_REG_ACCEL_X 0x02 +#define BMA220_REG_ACCEL_Y 0x03 +#define BMA220_REG_ACCEL_Z 0x04 +#define BMA220_REG_RANGE 0x11 +#define BMA220_REG_SUSPEND 0x18 + +#define BMA220_CHIP_ID 0xDD +#define BMA220_READ_MASK 0x80 +#define BMA220_RANGE_MASK 0x03 +#define BMA220_DATA_SHIFT 2 +#define BMA220_SUSPEND_SLEEP 0xFF +#define BMA220_SUSPEND_WAKE 0x00 + +#define BMA220_DEVICE_NAME "bma220" +#define BMA220_SCALE_AVAILABLE "0.623 1.248 2.491 4.983" + +#define BMA220_ACCEL_CHANNEL(index, reg, axis) { \ + .type = IIO_ACCEL, \ + .address = reg, \ + .modified = 1, \ + .channel2 = IIO_MOD_##axis, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ +} + +static IIO_CONST_ATTR(in_accel_scale_available, BMA220_SCALE_AVAILABLE); + +static struct attribute *bma220_attributes[] = { + &iio_const_attr_in_accel_scale_available.dev_attr.attr, + NULL, +}; + +static const struct attribute_group bma220_attribute_group = { + .attrs = bma220_attributes, +}; + +static const int bma220_scale_table[][4] = { + {0, 623000}, {1, 248000}, {2, 491000}, {4, 983000} +}; + +struct bma220_data { + struct spi_device *spi_device; + struct mutex lock; + u8 tx_buf[2] ____cacheline_aligned; +}; + +static const struct iio_chan_spec bma220_channels[] = { + BMA220_ACCEL_CHANNEL(0, BMA220_REG_ACCEL_X, X), + BMA220_ACCEL_CHANNEL(1, BMA220_REG_ACCEL_Y, Y), + BMA220_ACCEL_CHANNEL(2, BMA220_REG_ACCEL_Z, Z), +}; + +static inline int bma220_read_reg(struct spi_device *spi, u8 reg) +{ + return spi_w8r8(spi, reg | BMA220_READ_MASK); +} + +static int bma220_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, long mask) +{ + int ret; + u8 range_idx; + struct bma220_data *data = iio_priv(indio_dev); + + switch (mask) { + case IIO_CHAN_INFO_RAW: + ret = bma220_read_reg(data->spi_device, chan->address); + if (ret < 0) + return -EINVAL; + *val = sign_extend32(ret >> BMA220_DATA_SHIFT, 5); + return IIO_VAL_INT; + case IIO_CHAN_INFO_SCALE: + ret = bma220_read_reg(data->spi_device, BMA220_REG_RANGE); + if (ret < 0) + return ret; + range_idx = ret & BMA220_RANGE_MASK; + *val = bma220_scale_table[range_idx][0]; + *val2 = bma220_scale_table[range_idx][1]; + return IIO_VAL_INT_PLUS_MICRO; + } + + return -EINVAL; +} + +static int bma220_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int val, int val2, long mask) +{ + int i; + int ret; + int index = -1; + struct bma220_data *data = iio_priv(indio_dev); + + switch (mask) { + case IIO_CHAN_INFO_SCALE: + for (i = 0; i < ARRAY_SIZE(bma220_scale_table); i++) + if (val == bma220_scale_table[i][0] && + val2 == bma220_scale_table[i][1]) { + index = i; + break; + } + if (index < 0) + return -EINVAL; + + mutex_lock(&data->lock); + data->tx_buf[0] = BMA220_REG_RANGE; + data->tx_buf[1] = index; + ret = spi_write(data->spi_device, data->tx_buf, + sizeof(data->tx_buf)); + if (ret < 0) + dev_err(&data->spi_device->dev, + "failed to set measurement range\n"); + mutex_unlock(&data->lock); + + return 0; + } + + return -EINVAL; +} + +static const struct iio_info bma220_info = { + .driver_module = THIS_MODULE, + .read_raw = bma220_read_raw, + .write_raw = bma220_write_raw, + .attrs = &bma220_attribute_group, +}; + +static int bma220_init(struct spi_device *spi) +{ + int ret; + + ret = bma220_read_reg(spi, BMA220_REG_ID); + if (ret != BMA220_CHIP_ID) + return -ENODEV; + + /* Make sure the chip is powered on */ + ret = bma220_read_reg(spi, BMA220_REG_SUSPEND); + if (ret < 0) + return ret; + else if (ret == BMA220_SUSPEND_WAKE) + return bma220_read_reg(spi, BMA220_REG_SUSPEND); + + return 0; +} + +static int bma220_deinit(struct spi_device *spi) +{ + int ret; + + /* Make sure the chip is powered off */ + ret = bma220_read_reg(spi, BMA220_REG_SUSPEND); + if (ret < 0) + return ret; + else if (ret == BMA220_SUSPEND_SLEEP) + return bma220_read_reg(spi, BMA220_REG_SUSPEND); + + return 0; +} + +static int bma220_probe(struct spi_device *spi) +{ + int ret; + struct iio_dev *indio_dev; + struct bma220_data *data; + + indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*data)); + if (!indio_dev) { + dev_err(&spi->dev, "iio allocation failed!\n"); + return -ENOMEM; + } + + data = iio_priv(indio_dev); + data->spi_device = spi; + spi_set_drvdata(spi, indio_dev); + mutex_init(&data->lock); + + indio_dev->dev.parent = &spi->dev; + indio_dev->info = &bma220_info; + indio_dev->name = BMA220_DEVICE_NAME; + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->channels = bma220_channels; + indio_dev->num_channels = ARRAY_SIZE(bma220_channels); + + ret = bma220_init(data->spi_device); + if (ret < 0) + return ret; + + ret = iio_device_register(indio_dev); + if (ret < 0) { + dev_err(&spi->dev, "iio_device_register failed\n"); + return bma220_deinit(spi); + } + + return ret; +} + +static int bma220_remove(struct spi_device *spi) +{ + struct iio_dev *indio_dev = spi_get_drvdata(spi); + + iio_device_unregister(indio_dev); + + return bma220_deinit(spi); +} + +#ifdef CONFIG_PM_SLEEP +static int bma220_suspend(struct device *dev) +{ + struct bma220_data *data = + iio_priv(spi_get_drvdata(to_spi_device(dev))); + + /* The chip can be suspended/woken up by a simple register read. */ + return bma220_read_reg(data->spi_device, BMA220_REG_SUSPEND); +} + +static int bma220_resume(struct device *dev) +{ + struct bma220_data *data = + iio_priv(spi_get_drvdata(to_spi_device(dev))); + + return bma220_read_reg(data->spi_device, BMA220_REG_SUSPEND); +} + +static SIMPLE_DEV_PM_OPS(bma220_pm_ops, bma220_suspend, bma220_resume); + +#define BMA220_PM_OPS (&bma220_pm_ops) +#else +#define BMA220_PM_OPS NULL +#endif + +static const struct spi_device_id bma220_spi_id[] = { + {"bma220", 0}, + {} +}; + +static const struct acpi_device_id bma220_acpi_id[] = { + {"BMA0220", 0}, + {} +}; + +MODULE_DEVICE_TABLE(spi, bma220_spi_id); + +static struct spi_driver bma220_driver = { + .driver = { + .name = "bma220_spi", + .pm = BMA220_PM_OPS, + .acpi_match_table = ACPI_PTR(bma220_acpi_id), + }, + .probe = bma220_probe, + .remove = bma220_remove, + .id_table = bma220_spi_id, +}; + +module_spi_driver(bma220_driver); + +MODULE_AUTHOR("Tiberiu Breana "); +MODULE_DESCRIPTION("BMA220 acceleration sensor driver"); +MODULE_LICENSE("GPL v2"); -- cgit v0.10.2 From 9d75db36df146d212ade86a1aa69b718ebf31ac8 Mon Sep 17 00:00:00 2001 From: Daniel Baluta Date: Tue, 26 Apr 2016 15:39:58 +0300 Subject: iio: magn: Add support for BMM150 magnetometer BMM150 is register compatible with magnetometer part of BMC156. Datasheet is at: http://www.mouser.com/ds/2/783/BST-BMM150-DS001-01-786480.pdf Signed-off-by: Daniel Baluta Signed-off-by: Jonathan Cameron diff --git a/drivers/iio/magnetometer/bmc150_magn_i2c.c b/drivers/iio/magnetometer/bmc150_magn_i2c.c index eddc7f0..ee05722 100644 --- a/drivers/iio/magnetometer/bmc150_magn_i2c.c +++ b/drivers/iio/magnetometer/bmc150_magn_i2c.c @@ -2,6 +2,7 @@ * 3-axis magnetometer driver supporting following I2C Bosch-Sensortec chips: * - BMC150 * - BMC156 + * - BMM150 * * Copyright (c) 2016, Intel Corporation. * @@ -49,6 +50,7 @@ static int bmc150_magn_i2c_remove(struct i2c_client *client) static const struct acpi_device_id bmc150_magn_acpi_match[] = { {"BMC150B", 0}, {"BMC156B", 0}, + {"BMM150B", 0}, {}, }; MODULE_DEVICE_TABLE(acpi, bmc150_magn_acpi_match); @@ -56,6 +58,7 @@ MODULE_DEVICE_TABLE(acpi, bmc150_magn_acpi_match); static const struct i2c_device_id bmc150_magn_i2c_id[] = { {"bmc150_magn", 0}, {"bmc156_magn", 0}, + {"bmm150_magn", 0}, {} }; MODULE_DEVICE_TABLE(i2c, bmc150_magn_i2c_id); diff --git a/drivers/iio/magnetometer/bmc150_magn_spi.c b/drivers/iio/magnetometer/bmc150_magn_spi.c index c4c738a..7d4152d 100644 --- a/drivers/iio/magnetometer/bmc150_magn_spi.c +++ b/drivers/iio/magnetometer/bmc150_magn_spi.c @@ -2,6 +2,7 @@ * 3-axis magnetometer driver support following SPI Bosch-Sensortec chips: * - BMC150 * - BMC156 + * - BMM150 * * Copyright (c) 2016, Intel Corporation. * @@ -41,6 +42,7 @@ static int bmc150_magn_spi_remove(struct spi_device *spi) static const struct spi_device_id bmc150_magn_spi_id[] = { {"bmc150_magn", 0}, {"bmc156_magn", 0}, + {"bmm150_magn", 0}, {} }; MODULE_DEVICE_TABLE(spi, bmc150_magn_spi_id); @@ -48,6 +50,7 @@ MODULE_DEVICE_TABLE(spi, bmc150_magn_spi_id); static const struct acpi_device_id bmc150_magn_acpi_match[] = { {"BMC150B", 0}, {"BMC156B", 0}, + {"BMM150B", 0}, {}, }; MODULE_DEVICE_TABLE(acpi, bmc150_magn_acpi_match); -- cgit v0.10.2 From ba35f111aa6f386df33f950aeaea53a2bf040cc2 Mon Sep 17 00:00:00 2001 From: Matt Ranostay Date: Sun, 15 May 2016 22:18:46 -0700 Subject: iio: adc: ti-ads1015: add support for ADS1115 part TI ADS1115 is a 16-bit resolution ADC that is register map compatible with the ADS1015 device. Signed-off-by: Matt Ranostay Acked-by: Daniel Baluta Acked-by: Crt Mori Signed-off-by: Jonathan Cameron diff --git a/drivers/iio/adc/ti-ads1015.c b/drivers/iio/adc/ti-ads1015.c index 73cbf0b..a835423 100644 --- a/drivers/iio/adc/ti-ads1015.c +++ b/drivers/iio/adc/ti-ads1015.c @@ -55,6 +55,11 @@ #define ADS1015_DEFAULT_DATA_RATE 4 #define ADS1015_DEFAULT_CHAN 0 +enum { + ADS1015, + ADS1115, +}; + enum ads1015_channels { ADS1015_AIN0_AIN1 = 0, ADS1015_AIN0_AIN3, @@ -71,6 +76,10 @@ static const unsigned int ads1015_data_rate[] = { 128, 250, 490, 920, 1600, 2400, 3300, 3300 }; +static const unsigned int ads1115_data_rate[] = { + 8, 16, 32, 64, 128, 250, 475, 860 +}; + static const struct { int scale; int uscale; @@ -123,6 +132,42 @@ static const struct { }, \ } +#define ADS1115_V_CHAN(_chan, _addr) { \ + .type = IIO_VOLTAGE, \ + .indexed = 1, \ + .address = _addr, \ + .channel = _chan, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ + BIT(IIO_CHAN_INFO_SCALE) | \ + BIT(IIO_CHAN_INFO_SAMP_FREQ), \ + .scan_index = _addr, \ + .scan_type = { \ + .sign = 's', \ + .realbits = 16, \ + .storagebits = 16, \ + .endianness = IIO_CPU, \ + }, \ +} + +#define ADS1115_V_DIFF_CHAN(_chan, _chan2, _addr) { \ + .type = IIO_VOLTAGE, \ + .differential = 1, \ + .indexed = 1, \ + .address = _addr, \ + .channel = _chan, \ + .channel2 = _chan2, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ + BIT(IIO_CHAN_INFO_SCALE) | \ + BIT(IIO_CHAN_INFO_SAMP_FREQ), \ + .scan_index = _addr, \ + .scan_type = { \ + .sign = 's', \ + .realbits = 16, \ + .storagebits = 16, \ + .endianness = IIO_CPU, \ + }, \ +} + struct ads1015_data { struct regmap *regmap; /* @@ -131,6 +176,8 @@ struct ads1015_data { */ struct mutex lock; struct ads1015_channel_data channel_data[ADS1015_CHANNELS]; + + unsigned int *data_rate; }; static bool ads1015_is_writeable_reg(struct device *dev, unsigned int reg) @@ -157,6 +204,18 @@ static const struct iio_chan_spec ads1015_channels[] = { IIO_CHAN_SOFT_TIMESTAMP(ADS1015_TIMESTAMP), }; +static const struct iio_chan_spec ads1115_channels[] = { + ADS1115_V_DIFF_CHAN(0, 1, ADS1015_AIN0_AIN1), + ADS1115_V_DIFF_CHAN(0, 3, ADS1015_AIN0_AIN3), + ADS1115_V_DIFF_CHAN(1, 3, ADS1015_AIN1_AIN3), + ADS1115_V_DIFF_CHAN(2, 3, ADS1015_AIN2_AIN3), + ADS1115_V_CHAN(0, ADS1015_AIN0), + ADS1115_V_CHAN(1, ADS1015_AIN1), + ADS1115_V_CHAN(2, ADS1015_AIN2), + ADS1115_V_CHAN(3, ADS1015_AIN3), + IIO_CHAN_SOFT_TIMESTAMP(ADS1015_TIMESTAMP), +}; + static int ads1015_set_power_state(struct ads1015_data *data, bool on) { int ret; @@ -196,7 +255,7 @@ int ads1015_get_adc_result(struct ads1015_data *data, int chan, int *val) return ret; if (change) { - conv_time = DIV_ROUND_UP(USEC_PER_SEC, ads1015_data_rate[dr]); + conv_time = DIV_ROUND_UP(USEC_PER_SEC, data->data_rate[dr]); usleep_range(conv_time, conv_time + 1); } @@ -263,7 +322,7 @@ static int ads1015_set_data_rate(struct ads1015_data *data, int chan, int rate) int i, ret, rindex = -1; for (i = 0; i < ARRAY_SIZE(ads1015_data_rate); i++) - if (ads1015_data_rate[i] == rate) { + if (data->data_rate[i] == rate) { rindex = i; break; } @@ -291,7 +350,9 @@ static int ads1015_read_raw(struct iio_dev *indio_dev, mutex_lock(&indio_dev->mlock); mutex_lock(&data->lock); switch (mask) { - case IIO_CHAN_INFO_RAW: + case IIO_CHAN_INFO_RAW: { + int shift = chan->scan_type.shift; + if (iio_buffer_enabled(indio_dev)) { ret = -EBUSY; break; @@ -307,8 +368,7 @@ static int ads1015_read_raw(struct iio_dev *indio_dev, break; } - /* 12 bit res, D0 is bit 4 in conversion register */ - *val = sign_extend32(*val >> 4, 11); + *val = sign_extend32(*val >> shift, 15 - shift); ret = ads1015_set_power_state(data, false); if (ret < 0) @@ -316,6 +376,7 @@ static int ads1015_read_raw(struct iio_dev *indio_dev, ret = IIO_VAL_INT; break; + } case IIO_CHAN_INFO_SCALE: idx = data->channel_data[chan->address].pga; *val = ads1015_scale[idx].scale; @@ -324,7 +385,7 @@ static int ads1015_read_raw(struct iio_dev *indio_dev, break; case IIO_CHAN_INFO_SAMP_FREQ: idx = data->channel_data[chan->address].data_rate; - *val = ads1015_data_rate[idx]; + *val = data->data_rate[idx]; ret = IIO_VAL_INT; break; default: @@ -380,12 +441,15 @@ static const struct iio_buffer_setup_ops ads1015_buffer_setup_ops = { }; static IIO_CONST_ATTR(scale_available, "3 2 1 0.5 0.25 0.125"); -static IIO_CONST_ATTR(sampling_frequency_available, - "128 250 490 920 1600 2400 3300"); + +static IIO_CONST_ATTR_NAMED(ads1015_sampling_frequency_available, + sampling_frequency_available, "128 250 490 920 1600 2400 3300"); +static IIO_CONST_ATTR_NAMED(ads1115_sampling_frequency_available, + sampling_frequency_available, "8 16 32 64 128 250 475 860"); static struct attribute *ads1015_attributes[] = { &iio_const_attr_scale_available.dev_attr.attr, - &iio_const_attr_sampling_frequency_available.dev_attr.attr, + &iio_const_attr_ads1015_sampling_frequency_available.dev_attr.attr, NULL, }; @@ -393,11 +457,28 @@ static const struct attribute_group ads1015_attribute_group = { .attrs = ads1015_attributes, }; -static const struct iio_info ads1015_info = { +static struct attribute *ads1115_attributes[] = { + &iio_const_attr_scale_available.dev_attr.attr, + &iio_const_attr_ads1115_sampling_frequency_available.dev_attr.attr, + NULL, +}; + +static const struct attribute_group ads1115_attribute_group = { + .attrs = ads1115_attributes, +}; + +static struct iio_info ads1015_info = { + .driver_module = THIS_MODULE, + .read_raw = ads1015_read_raw, + .write_raw = ads1015_write_raw, + .attrs = &ads1015_attribute_group, +}; + +static struct iio_info ads1115_info = { .driver_module = THIS_MODULE, .read_raw = ads1015_read_raw, .write_raw = ads1015_write_raw, - .attrs = &ads1015_attribute_group, + .attrs = &ads1115_attribute_group, }; #ifdef CONFIG_OF @@ -500,12 +581,24 @@ static int ads1015_probe(struct i2c_client *client, mutex_init(&data->lock); indio_dev->dev.parent = &client->dev; - indio_dev->info = &ads1015_info; indio_dev->name = ADS1015_DRV_NAME; - indio_dev->channels = ads1015_channels; - indio_dev->num_channels = ARRAY_SIZE(ads1015_channels); indio_dev->modes = INDIO_DIRECT_MODE; + switch (id->driver_data) { + case ADS1015: + indio_dev->channels = ads1015_channels; + indio_dev->num_channels = ARRAY_SIZE(ads1015_channels); + indio_dev->info = &ads1015_info; + data->data_rate = (unsigned int *) &ads1015_data_rate; + break; + case ADS1115: + indio_dev->channels = ads1115_channels; + indio_dev->num_channels = ARRAY_SIZE(ads1115_channels); + indio_dev->info = &ads1115_info; + data->data_rate = (unsigned int *) &ads1115_data_rate; + break; + } + /* we need to keep this ABI the same as used by hwmon ADS1015 driver */ ads1015_get_channels_config(client); @@ -590,7 +683,8 @@ static const struct dev_pm_ops ads1015_pm_ops = { }; static const struct i2c_device_id ads1015_id[] = { - {"ads1015", 0}, + {"ads1015", ADS1015}, + {"ads1115", ADS1115}, {} }; MODULE_DEVICE_TABLE(i2c, ads1015_id); -- cgit v0.10.2 From 194dc4c714132a63a7a731fe4debeccbdfab13e1 Mon Sep 17 00:00:00 2001 From: Tiberiu Breana Date: Mon, 16 May 2016 14:58:23 +0300 Subject: iio: accel: Add triggered buffer support for BMA220 Signed-off-by: Tiberiu Breana Signed-off-by: Jonathan Cameron diff --git a/drivers/iio/accel/bma220_spi.c b/drivers/iio/accel/bma220_spi.c index 7343575..1098d10 100644 --- a/drivers/iio/accel/bma220_spi.c +++ b/drivers/iio/accel/bma220_spi.c @@ -11,9 +11,12 @@ #include #include #include +#include #include #include #include +#include +#include #define BMA220_REG_ID 0x00 #define BMA220_REG_ACCEL_X 0x02 @@ -39,8 +42,22 @@ .channel2 = IIO_MOD_##axis, \ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ + .scan_index = index, \ + .scan_type = { \ + .sign = 's', \ + .realbits = 6, \ + .storagebits = 8, \ + .shift = BMA220_DATA_SHIFT, \ + .endianness = IIO_CPU, \ + }, \ } +enum bma220_axis { + AXIS_X, + AXIS_Y, + AXIS_Z, +}; + static IIO_CONST_ATTR(in_accel_scale_available, BMA220_SCALE_AVAILABLE); static struct attribute *bma220_attributes[] = { @@ -59,6 +76,7 @@ static const int bma220_scale_table[][4] = { struct bma220_data { struct spi_device *spi_device; struct mutex lock; + s8 buffer[16]; /* 3x8-bit channels + 5x8 padding + 8x8 timestamp */ u8 tx_buf[2] ____cacheline_aligned; }; @@ -66,6 +84,7 @@ static const struct iio_chan_spec bma220_channels[] = { BMA220_ACCEL_CHANNEL(0, BMA220_REG_ACCEL_X, X), BMA220_ACCEL_CHANNEL(1, BMA220_REG_ACCEL_Y, Y), BMA220_ACCEL_CHANNEL(2, BMA220_REG_ACCEL_Z, Z), + IIO_CHAN_SOFT_TIMESTAMP(3), }; static inline int bma220_read_reg(struct spi_device *spi, u8 reg) @@ -73,6 +92,35 @@ static inline int bma220_read_reg(struct spi_device *spi, u8 reg) return spi_w8r8(spi, reg | BMA220_READ_MASK); } +static const unsigned long bma220_accel_scan_masks[] = { + BIT(AXIS_X) | BIT(AXIS_Y) | BIT(AXIS_Z), + 0 +}; + +static irqreturn_t bma220_trigger_handler(int irq, void *p) +{ + int ret; + struct iio_poll_func *pf = p; + struct iio_dev *indio_dev = pf->indio_dev; + struct bma220_data *data = iio_priv(indio_dev); + struct spi_device *spi = data->spi_device; + + mutex_lock(&data->lock); + data->tx_buf[0] = BMA220_REG_ACCEL_X | BMA220_READ_MASK; + ret = spi_write_then_read(spi, data->tx_buf, 1, data->buffer, + ARRAY_SIZE(bma220_channels) - 1); + if (ret < 0) + goto err; + + iio_push_to_buffers_with_timestamp(indio_dev, data->buffer, + pf->timestamp); +err: + mutex_unlock(&data->lock); + iio_trigger_notify_done(indio_dev->trig); + + return IRQ_HANDLED; +} + static int bma220_read_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int *val, int *val2, long mask) @@ -199,18 +247,30 @@ static int bma220_probe(struct spi_device *spi) indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->channels = bma220_channels; indio_dev->num_channels = ARRAY_SIZE(bma220_channels); + indio_dev->available_scan_masks = bma220_accel_scan_masks; ret = bma220_init(data->spi_device); if (ret < 0) return ret; + ret = iio_triggered_buffer_setup(indio_dev, NULL, + bma220_trigger_handler, NULL); + if (ret < 0) { + dev_err(&spi->dev, "iio triggered buffer setup failed\n"); + goto err_suspend; + } + ret = iio_device_register(indio_dev); if (ret < 0) { dev_err(&spi->dev, "iio_device_register failed\n"); - return bma220_deinit(spi); + iio_triggered_buffer_cleanup(indio_dev); + goto err_suspend; } - return ret; + return 0; + +err_suspend: + return bma220_deinit(spi); } static int bma220_remove(struct spi_device *spi) @@ -218,6 +278,7 @@ static int bma220_remove(struct spi_device *spi) struct iio_dev *indio_dev = spi_get_drvdata(spi); iio_device_unregister(indio_dev); + iio_triggered_buffer_cleanup(indio_dev); return bma220_deinit(spi); } -- cgit v0.10.2 From cdd469ad9e008a58ed465efa09f8594f1387e8ce Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Tue, 17 May 2016 12:25:37 -0400 Subject: iio: Export I2C module alias information The I2C drivers have an i2c_device_id array but that information isn't exported to the modules using the MODULE_DEVICE_TABLE() macro. So the modules autoloading won't work if the I2C device is registered using OF or legacy board files due missing alias information in the modules. The issue was found using Kieran Bingham's coccinelle semantic patch: https://lkml.org/lkml/2016/5/10/520 Signed-off-by: Javier Martinez Canillas Signed-off-by: Jonathan Cameron diff --git a/drivers/iio/humidity/am2315.c b/drivers/iio/humidity/am2315.c index 3be6d20..8de39bd 100644 --- a/drivers/iio/humidity/am2315.c +++ b/drivers/iio/humidity/am2315.c @@ -278,6 +278,7 @@ static const struct i2c_device_id am2315_i2c_id[] = { {"am2315", 0}, {} }; +MODULE_DEVICE_TABLE(i2c, am2315_i2c_id); static const struct acpi_device_id am2315_acpi_id[] = { {"AOS2315", 0}, diff --git a/drivers/iio/humidity/htu21.c b/drivers/iio/humidity/htu21.c index 11cbc38..0fbbd8c 100644 --- a/drivers/iio/humidity/htu21.c +++ b/drivers/iio/humidity/htu21.c @@ -236,6 +236,7 @@ static const struct i2c_device_id htu21_id[] = { {"ms8607-humidity", MS8607}, {} }; +MODULE_DEVICE_TABLE(i2c, htu21_id); static struct i2c_driver htu21_driver = { .probe = htu21_probe, diff --git a/drivers/iio/pressure/hp206c.c b/drivers/iio/pressure/hp206c.c index 90f2b6e..12f769e 100644 --- a/drivers/iio/pressure/hp206c.c +++ b/drivers/iio/pressure/hp206c.c @@ -401,6 +401,7 @@ static const struct i2c_device_id hp206c_id[] = { {"hp206c"}, {} }; +MODULE_DEVICE_TABLE(i2c, hp206c_id); #ifdef CONFIG_ACPI static const struct acpi_device_id hp206c_acpi_match[] = { diff --git a/drivers/iio/pressure/ms5637.c b/drivers/iio/pressure/ms5637.c index e68052c..8fb6f7a 100644 --- a/drivers/iio/pressure/ms5637.c +++ b/drivers/iio/pressure/ms5637.c @@ -173,6 +173,7 @@ static const struct i2c_device_id ms5637_id[] = { {"ms8607-temppressure", 1}, {} }; +MODULE_DEVICE_TABLE(i2c, ms5637_id); static struct i2c_driver ms5637_driver = { .probe = ms5637_probe, diff --git a/drivers/iio/temperature/tsys02d.c b/drivers/iio/temperature/tsys02d.c index ab6fe8f..c0a19a0 100644 --- a/drivers/iio/temperature/tsys02d.c +++ b/drivers/iio/temperature/tsys02d.c @@ -174,6 +174,7 @@ static const struct i2c_device_id tsys02d_id[] = { {"tsys02d", 0}, {} }; +MODULE_DEVICE_TABLE(i2c, tsys02d_id); static struct i2c_driver tsys02d_driver = { .probe = tsys02d_probe, -- cgit v0.10.2 From 9a47894fbeda2ab92c6ec57ee359adeaf283b962 Mon Sep 17 00:00:00 2001 From: Cristina Moraru Date: Thu, 19 May 2016 08:55:46 +0300 Subject: iio: max5487: Add support for Maxim digital potentiometers Add implementation for Maxim MAX5487, MAX5488, MAX5489 digital potentiometers. Datasheet: http://datasheets.maximintegrated.com/en/ds/MAX5487-MAX5489.pdf Signed-off-by: Cristina Moraru CC: Daniel Baluta Signed-off-by: Jonathan Cameron diff --git a/drivers/iio/potentiometer/Kconfig b/drivers/iio/potentiometer/Kconfig index 6acb238..0941c8d4 100644 --- a/drivers/iio/potentiometer/Kconfig +++ b/drivers/iio/potentiometer/Kconfig @@ -15,6 +15,17 @@ config DS1803 To compile this driver as a module, choose M here: the module will be called ds1803. +config MAX5487 + tristate "Maxim MAX5487/MAX5488/MAX5489 Digital Potentiometer driver" + depends on SPI + help + Say yes here to build support for the Maxim + MAX5487, MAX5488, MAX5489 digital potentiometer + chips. + + To compile this driver as a module, choose M here: the + module will be called max5487. + config MCP4131 tristate "Microchip MCP413X/414X/415X/416X/423X/424X/425X/426X Digital Potentiometer driver" depends on SPI diff --git a/drivers/iio/potentiometer/Makefile b/drivers/iio/potentiometer/Makefile index 6007faa..8adb58f 100644 --- a/drivers/iio/potentiometer/Makefile +++ b/drivers/iio/potentiometer/Makefile @@ -4,6 +4,7 @@ # When adding new entries keep the list in alphabetical order obj-$(CONFIG_DS1803) += ds1803.o +obj-$(CONFIG_MAX5487) += max5487.o obj-$(CONFIG_MCP4131) += mcp4131.o obj-$(CONFIG_MCP4531) += mcp4531.o obj-$(CONFIG_TPL0102) += tpl0102.o diff --git a/drivers/iio/potentiometer/max5487.c b/drivers/iio/potentiometer/max5487.c new file mode 100644 index 0000000..6c50939 --- /dev/null +++ b/drivers/iio/potentiometer/max5487.c @@ -0,0 +1,161 @@ +/* + * max5487.c - Support for MAX5487, MAX5488, MAX5489 digital potentiometers + * + * Copyright (C) 2016 Cristina-Gabriela Moraru + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ +#include +#include +#include + +#include +#include + +#define MAX5487_WRITE_WIPER_A (0x01 << 8) +#define MAX5487_WRITE_WIPER_B (0x02 << 8) + +/* copy both wiper regs to NV regs */ +#define MAX5487_COPY_AB_TO_NV (0x23 << 8) +/* copy both NV regs to wiper regs */ +#define MAX5487_COPY_NV_TO_AB (0x33 << 8) + +#define MAX5487_MAX_POS 255 + +struct max5487_data { + struct spi_device *spi; + int kohms; +}; + +#define MAX5487_CHANNEL(ch, addr) { \ + .type = IIO_RESISTANCE, \ + .indexed = 1, \ + .output = 1, \ + .channel = ch, \ + .address = addr, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ +} + +static const struct iio_chan_spec max5487_channels[] = { + MAX5487_CHANNEL(0, MAX5487_WRITE_WIPER_A), + MAX5487_CHANNEL(1, MAX5487_WRITE_WIPER_B), +}; + +static int max5487_write_cmd(struct spi_device *spi, u16 cmd) +{ + return spi_write(spi, (const void *) &cmd, sizeof(u16)); +} + +static int max5487_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, long mask) +{ + struct max5487_data *data = iio_priv(indio_dev); + + if (mask != IIO_CHAN_INFO_SCALE) + return -EINVAL; + + *val = 1000 * data->kohms; + *val2 = MAX5487_MAX_POS; + + return IIO_VAL_FRACTIONAL; +} + +static int max5487_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int val, int val2, long mask) +{ + struct max5487_data *data = iio_priv(indio_dev); + + if (mask != IIO_CHAN_INFO_RAW) + return -EINVAL; + + if (val < 0 || val > MAX5487_MAX_POS) + return -EINVAL; + + return max5487_write_cmd(data->spi, chan->address | val); +} + +static const struct iio_info max5487_info = { + .read_raw = max5487_read_raw, + .write_raw = max5487_write_raw, + .driver_module = THIS_MODULE, +}; + +static int max5487_spi_probe(struct spi_device *spi) +{ + struct iio_dev *indio_dev; + struct max5487_data *data; + const struct spi_device_id *id = spi_get_device_id(spi); + int ret; + + indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*data)); + if (!indio_dev) + return -ENOMEM; + + dev_set_drvdata(&spi->dev, indio_dev); + data = iio_priv(indio_dev); + + data->spi = spi; + data->kohms = id->driver_data; + + indio_dev->info = &max5487_info; + indio_dev->name = id->name; + indio_dev->dev.parent = &spi->dev; + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->channels = max5487_channels; + indio_dev->num_channels = ARRAY_SIZE(max5487_channels); + + /* restore both wiper regs from NV regs */ + ret = max5487_write_cmd(data->spi, MAX5487_COPY_NV_TO_AB); + if (ret < 0) + return ret; + + return iio_device_register(indio_dev); +} + +static int max5487_spi_remove(struct spi_device *spi) +{ + struct iio_dev *indio_dev = dev_get_drvdata(&spi->dev); + + iio_device_unregister(indio_dev); + + /* save both wiper regs to NV regs */ + return max5487_write_cmd(spi, MAX5487_COPY_AB_TO_NV); +} + +static const struct spi_device_id max5487_id[] = { + { "MAX5487", 10 }, + { "MAX5488", 50 }, + { "MAX5489", 100 }, + { } +}; +MODULE_DEVICE_TABLE(spi, max5487_id); + +static const struct acpi_device_id max5487_acpi_match[] = { + { "MAX5487", 10 }, + { "MAX5488", 50 }, + { "MAX5489", 100 }, + { }, +}; +MODULE_DEVICE_TABLE(acpi, max5487_acpi_match); + +static struct spi_driver max5487_driver = { + .driver = { + .name = "max5487", + .owner = THIS_MODULE, + .acpi_match_table = ACPI_PTR(max5487_acpi_match), + }, + .id_table = max5487_id, + .probe = max5487_spi_probe, + .remove = max5487_spi_remove +}; +module_spi_driver(max5487_driver); + +MODULE_AUTHOR("Cristina-Gabriela Moraru "); +MODULE_DESCRIPTION("max5487 SPI driver"); +MODULE_LICENSE("GPL v2"); -- cgit v0.10.2 From 44072b2c8da876e19c862ef609c14c8c4aecb48f Mon Sep 17 00:00:00 2001 From: Quentin Schulz Date: Wed, 18 May 2016 17:16:18 +0200 Subject: iio: adc: nau7802: Expose possible gains in sysfs The Nuvoton NAU7802 ADC is able to adjust its gain but prior knowledge of its possible values was required to adjust it. Users had to guess the possible gain values based on the ADC datasheet or on this driver's code. This exposes the possible values in the in_voltage_scale_available file of each nau7802 ADC device. The gain is set for the whole ADC and is therefore not configurable by channel. Thus, there exists only one in_voltage_scale_available file for each nau7802 ADC device even if it has two separate channels. Signed-off-by: Quentin Schulz Acked-by: Alexandre Belloni Signed-off-by: Jonathan Cameron diff --git a/drivers/iio/adc/nau7802.c b/drivers/iio/adc/nau7802.c index e525aa6..57365c5 100644 --- a/drivers/iio/adc/nau7802.c +++ b/drivers/iio/adc/nau7802.c @@ -79,10 +79,29 @@ static const struct iio_chan_spec nau7802_chan_array[] = { static const u16 nau7802_sample_freq_avail[] = {10, 20, 40, 80, 10, 10, 10, 320}; +static ssize_t nau7802_show_scales(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct nau7802_state *st = iio_priv(dev_to_iio_dev(dev)); + int i, len = 0; + + for (i = 0; i < ARRAY_SIZE(st->scale_avail); i++) + len += scnprintf(buf + len, PAGE_SIZE - len, "0.%09d ", + st->scale_avail[i]); + + buf[len-1] = '\n'; + + return len; +} + static IIO_CONST_ATTR_SAMP_FREQ_AVAIL("10 40 80 320"); +static IIO_DEVICE_ATTR(in_voltage_scale_available, S_IRUGO, nau7802_show_scales, + NULL, 0); + static struct attribute *nau7802_attributes[] = { &iio_const_attr_sampling_frequency_available.dev_attr.attr, + &iio_dev_attr_in_voltage_scale_available.dev_attr.attr, NULL }; -- cgit v0.10.2 From b7a96bb96fa0dfa3974c1f7830aa698959bff155 Mon Sep 17 00:00:00 2001 From: Alison Schofield Date: Sun, 15 May 2016 11:37:27 -0700 Subject: iio: light: jsa1212: remove unneeded i2c check functionality test This driver does not call i2c_smbus_read|write_byte_data(), so remove the corresponding functionality test. It uses regmap to handle byte transfers transparently. Signed-off-by: Alison Schofield Reviewed-by:Kuppuswamy Sathyanarayanan Reviewed-by: Matt Ranostay Signed-off-by: Jonathan Cameron diff --git a/drivers/iio/light/jsa1212.c b/drivers/iio/light/jsa1212.c index 99a6281..e8a8931 100644 --- a/drivers/iio/light/jsa1212.c +++ b/drivers/iio/light/jsa1212.c @@ -325,9 +325,6 @@ static int jsa1212_probe(struct i2c_client *client, struct regmap *regmap; int ret; - if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) - return -EOPNOTSUPP; - indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); if (!indio_dev) return -ENOMEM; -- cgit v0.10.2 From 14beaa8f5ab11b881c5e822e2474f5278d0946d5 Mon Sep 17 00:00:00 2001 From: Matt Ranostay Date: Wed, 4 May 2016 22:57:30 -0700 Subject: iio: pressure: bmp280: add humidity support Enable humidity support for the BME280 part Signed-off-by: Matt Ranostay Acked-by: Vlad Dogaru Signed-off-by: Jonathan Cameron diff --git a/drivers/iio/pressure/Kconfig b/drivers/iio/pressure/Kconfig index cda9f12..9125a93 100644 --- a/drivers/iio/pressure/Kconfig +++ b/drivers/iio/pressure/Kconfig @@ -12,7 +12,8 @@ config BMP280 select REGMAP_I2C help Say yes here to build support for Bosch Sensortec BMP180 and BMP280 - pressure and temperature sensors. + pressure and temperature sensors. Also supports the BE280 with + an additional humidty sensor channel. To compile this driver as a module, choose M here: the module will be called bmp280. diff --git a/drivers/iio/pressure/bmp280.c b/drivers/iio/pressure/bmp280.c index 2f1498e..1876b50 100644 --- a/drivers/iio/pressure/bmp280.c +++ b/drivers/iio/pressure/bmp280.c @@ -10,6 +10,7 @@ * Datasheet: * https://ae-bst.resource.bosch.com/media/_tech/media/datasheets/BST-BMP180-DS000-121.pdf * https://ae-bst.resource.bosch.com/media/_tech/media/datasheets/BST-BMP280-DS001-12.pdf + * https://ae-bst.resource.bosch.com/media/_tech/media/datasheets/BST-BME280_DS001-11.pdf */ #define pr_fmt(fmt) "bmp280: " fmt @@ -23,6 +24,8 @@ #include /* BMP280 specific registers */ +#define BMP280_REG_HUMIDITY_LSB 0xFE +#define BMP280_REG_HUMIDITY_MSB 0xFD #define BMP280_REG_TEMP_XLSB 0xFC #define BMP280_REG_TEMP_LSB 0xFB #define BMP280_REG_TEMP_MSB 0xFA @@ -31,7 +34,17 @@ #define BMP280_REG_PRESS_MSB 0xF7 #define BMP280_REG_CONFIG 0xF5 +#define BMP280_REG_CTRL_MEAS 0xF4 #define BMP280_REG_STATUS 0xF3 +#define BMP280_REG_CTRL_HUMIDITY 0xF2 + +/* Due to non linear mapping, and data sizes we can't do a bulk read */ +#define BMP280_REG_COMP_H1 0xA1 +#define BMP280_REG_COMP_H2 0xE1 +#define BMP280_REG_COMP_H3 0xE3 +#define BMP280_REG_COMP_H4 0xE4 +#define BMP280_REG_COMP_H5 0xE5 +#define BMP280_REG_COMP_H6 0xE7 #define BMP280_REG_COMP_TEMP_START 0x88 #define BMP280_COMP_TEMP_REG_COUNT 6 @@ -46,6 +59,15 @@ #define BMP280_FILTER_8X (BIT(3) | BIT(2)) #define BMP280_FILTER_16X BIT(4) +#define BMP280_OSRS_HUMIDITY_MASK (BIT(2) | BIT(1) | BIT(0)) +#define BMP280_OSRS_HUMIDITIY_X(osrs_h) ((osrs_h) << 0) +#define BMP280_OSRS_HUMIDITY_SKIP 0 +#define BMP280_OSRS_HUMIDITY_1X BMP280_OSRS_HUMIDITIY_X(1) +#define BMP280_OSRS_HUMIDITY_2X BMP280_OSRS_HUMIDITIY_X(2) +#define BMP280_OSRS_HUMIDITY_4X BMP280_OSRS_HUMIDITIY_X(3) +#define BMP280_OSRS_HUMIDITY_8X BMP280_OSRS_HUMIDITIY_X(4) +#define BMP280_OSRS_HUMIDITY_16X BMP280_OSRS_HUMIDITIY_X(5) + #define BMP280_OSRS_TEMP_MASK (BIT(7) | BIT(6) | BIT(5)) #define BMP280_OSRS_TEMP_SKIP 0 #define BMP280_OSRS_TEMP_X(osrs_t) ((osrs_t) << 5) @@ -92,6 +114,7 @@ #define BMP180_CHIP_ID 0x55 #define BMP280_CHIP_ID 0x58 +#define BME280_CHIP_ID 0x60 #define BMP280_SOFT_RESET_VAL 0xB6 struct bmp280_data { @@ -103,6 +126,7 @@ struct bmp280_data { /* log of base 2 of oversampling rate */ u8 oversampling_press; u8 oversampling_temp; + u8 oversampling_humid; /* * Carryover value from temperature conversion, used in pressure @@ -120,9 +144,13 @@ struct bmp280_chip_info { const int *oversampling_press_avail; int num_oversampling_press_avail; + const int *oversampling_humid_avail; + int num_oversampling_humid_avail; + int (*chip_config)(struct bmp280_data *); int (*read_temp)(struct bmp280_data *, int *); int (*read_press)(struct bmp280_data *, int *, int *); + int (*read_humid)(struct bmp280_data *, int *, int *); }; /* @@ -143,12 +171,18 @@ static const struct iio_chan_spec bmp280_channels[] = { .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED) | BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), }, + { + .type = IIO_HUMIDITYRELATIVE, + .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED) | + BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), + }, }; static bool bmp280_is_writeable_reg(struct device *dev, unsigned int reg) { switch (reg) { case BMP280_REG_CONFIG: + case BMP280_REG_CTRL_HUMIDITY: case BMP280_REG_CTRL_MEAS: case BMP280_REG_RESET: return true; @@ -160,6 +194,8 @@ static bool bmp280_is_writeable_reg(struct device *dev, unsigned int reg) static bool bmp280_is_volatile_reg(struct device *dev, unsigned int reg) { switch (reg) { + case BMP280_REG_HUMIDITY_LSB: + case BMP280_REG_HUMIDITY_MSB: case BMP280_REG_TEMP_XLSB: case BMP280_REG_TEMP_LSB: case BMP280_REG_TEMP_MSB: @@ -177,7 +213,7 @@ static const struct regmap_config bmp280_regmap_config = { .reg_bits = 8, .val_bits = 8, - .max_register = BMP280_REG_TEMP_XLSB, + .max_register = BMP280_REG_HUMIDITY_LSB, .cache_type = REGCACHE_RBTREE, .writeable_reg = bmp280_is_writeable_reg, @@ -185,6 +221,70 @@ static const struct regmap_config bmp280_regmap_config = { }; /* + * Returns humidity in percent, resolution is 0.01 percent. Output value of + * "47445" represents 47445/1024 = 46.333 %RH. + * + * Taken from BME280 datasheet, Section 4.2.3, "Compensation formula". + */ + +static u32 bmp280_compensate_humidity(struct bmp280_data *data, + s32 adc_humidity) +{ + struct device *dev = &data->client->dev; + unsigned int H1, H3, tmp; + int H2, H4, H5, H6, ret, var; + + ret = regmap_read(data->regmap, BMP280_REG_COMP_H1, &H1); + if (ret < 0) { + dev_err(dev, "failed to read H1 comp value\n"); + return ret; + } + + ret = regmap_bulk_read(data->regmap, BMP280_REG_COMP_H2, &tmp, 2); + if (ret < 0) { + dev_err(dev, "failed to read H2 comp value\n"); + return ret; + } + H2 = sign_extend32(le16_to_cpu(tmp), 15); + + ret = regmap_read(data->regmap, BMP280_REG_COMP_H3, &H3); + if (ret < 0) { + dev_err(dev, "failed to read H3 comp value\n"); + return ret; + } + + ret = regmap_bulk_read(data->regmap, BMP280_REG_COMP_H4, &tmp, 2); + if (ret < 0) { + dev_err(dev, "failed to read H4 comp value\n"); + return ret; + } + H4 = sign_extend32(((be16_to_cpu(tmp) >> 4) & 0xff0) | + (be16_to_cpu(tmp) & 0xf), 11); + + ret = regmap_bulk_read(data->regmap, BMP280_REG_COMP_H5, &tmp, 2); + if (ret < 0) { + dev_err(dev, "failed to read H5 comp value\n"); + return ret; + } + H5 = sign_extend32(((le16_to_cpu(tmp) >> 4) & 0xfff), 11); + + ret = regmap_read(data->regmap, BMP280_REG_COMP_H6, &tmp); + if (ret < 0) { + dev_err(dev, "failed to read H6 comp value\n"); + return ret; + } + H6 = sign_extend32(tmp, 7); + + var = ((s32)data->t_fine) - 76800; + var = ((((adc_humidity << 14) - (H4 << 20) - (H5 * var)) + 16384) >> 15) + * (((((((var * H6) >> 10) * (((var * H3) >> 11) + 32768)) >> 10) + + 2097152) * H2 + 8192) >> 14); + var -= ((((var >> 15) * (var >> 15)) >> 7) * H1) >> 4; + + return var >> 12; +}; + +/* * Returns temperature in DegC, resolution is 0.01 DegC. Output value of * "5123" equals 51.23 DegC. t_fine carries fine temperature as global * value. @@ -324,6 +424,34 @@ static int bmp280_read_press(struct bmp280_data *data, return IIO_VAL_FRACTIONAL; } +static int bmp280_read_humid(struct bmp280_data *data, int *val, int *val2) +{ + int ret; + __be16 tmp = 0; + s32 adc_humidity; + u32 comp_humidity; + + /* Read and compensate temperature so we get a reading of t_fine. */ + ret = bmp280_read_temp(data, NULL); + if (ret < 0) + return ret; + + ret = regmap_bulk_read(data->regmap, BMP280_REG_HUMIDITY_MSB, + (u8 *) &tmp, 2); + if (ret < 0) { + dev_err(&data->client->dev, "failed to read humidity\n"); + return ret; + } + + adc_humidity = be16_to_cpu(tmp); + comp_humidity = bmp280_compensate_humidity(data, adc_humidity); + + *val = comp_humidity; + *val2 = 1024; + + return IIO_VAL_FRACTIONAL; +} + static int bmp280_read_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int *val, int *val2, long mask) @@ -336,6 +464,9 @@ static int bmp280_read_raw(struct iio_dev *indio_dev, switch (mask) { case IIO_CHAN_INFO_PROCESSED: switch (chan->type) { + case IIO_HUMIDITYRELATIVE: + ret = data->chip_info->read_humid(data, val, val2); + break; case IIO_PRESSURE: ret = data->chip_info->read_press(data, val, val2); break; @@ -349,6 +480,10 @@ static int bmp280_read_raw(struct iio_dev *indio_dev, break; case IIO_CHAN_INFO_OVERSAMPLING_RATIO: switch (chan->type) { + case IIO_HUMIDITYRELATIVE: + *val = 1 << data->oversampling_humid; + ret = IIO_VAL_INT; + break; case IIO_PRESSURE: *val = 1 << data->oversampling_press; ret = IIO_VAL_INT; @@ -372,6 +507,23 @@ static int bmp280_read_raw(struct iio_dev *indio_dev, return ret; } +static int bmp280_write_oversampling_ratio_humid(struct bmp280_data *data, + int val) +{ + int i; + const int *avail = data->chip_info->oversampling_humid_avail; + const int n = data->chip_info->num_oversampling_humid_avail; + + for (i = 0; i < n; i++) { + if (avail[i] == val) { + data->oversampling_humid = ilog2(val); + + return data->chip_info->chip_config(data); + } + } + return -EINVAL; +} + static int bmp280_write_oversampling_ratio_temp(struct bmp280_data *data, int val) { @@ -417,6 +569,9 @@ static int bmp280_write_raw(struct iio_dev *indio_dev, case IIO_CHAN_INFO_OVERSAMPLING_RATIO: mutex_lock(&data->lock); switch (chan->type) { + case IIO_HUMIDITYRELATIVE: + ret = bmp280_write_oversampling_ratio_humid(data, val); + break; case IIO_PRESSURE: ret = bmp280_write_oversampling_ratio_press(data, val); break; @@ -535,6 +690,37 @@ static const struct bmp280_chip_info bmp280_chip_info = { .read_press = bmp280_read_press, }; +static int bme280_chip_config(struct bmp280_data *data) +{ + int ret = bmp280_chip_config(data); + u8 osrs = BMP280_OSRS_HUMIDITIY_X(data->oversampling_humid + 1); + + if (ret < 0) + return ret; + + return regmap_update_bits(data->regmap, BMP280_REG_CTRL_HUMIDITY, + BMP280_OSRS_HUMIDITY_MASK, osrs); +} + +static const struct bmp280_chip_info bme280_chip_info = { + .regmap_config = &bmp280_regmap_config, + + .oversampling_temp_avail = bmp280_oversampling_avail, + .num_oversampling_temp_avail = ARRAY_SIZE(bmp280_oversampling_avail), + + .oversampling_press_avail = bmp280_oversampling_avail, + .num_oversampling_press_avail = ARRAY_SIZE(bmp280_oversampling_avail), + + .oversampling_humid_avail = bmp280_oversampling_avail, + .num_oversampling_humid_avail = ARRAY_SIZE(bmp280_oversampling_avail), + + .chip_config = bme280_chip_config, + .read_temp = bmp280_read_temp, + .read_press = bmp280_read_press, + .read_humid = bmp280_read_humid, +}; + + static bool bmp180_is_writeable_reg(struct device *dev, unsigned int reg) { switch (reg) { @@ -849,21 +1035,29 @@ static int bmp280_probe(struct i2c_client *client, indio_dev->dev.parent = &client->dev; indio_dev->name = id->name; indio_dev->channels = bmp280_channels; - indio_dev->num_channels = ARRAY_SIZE(bmp280_channels); indio_dev->info = &bmp280_info; indio_dev->modes = INDIO_DIRECT_MODE; switch (id->driver_data) { case BMP180_CHIP_ID: + indio_dev->num_channels = 2; data->chip_info = &bmp180_chip_info; data->oversampling_press = ilog2(8); data->oversampling_temp = ilog2(1); break; case BMP280_CHIP_ID: + indio_dev->num_channels = 2; data->chip_info = &bmp280_chip_info; data->oversampling_press = ilog2(16); data->oversampling_temp = ilog2(2); break; + case BME280_CHIP_ID: + indio_dev->num_channels = 3; + data->chip_info = &bme280_chip_info; + data->oversampling_press = ilog2(16); + data->oversampling_humid = ilog2(16); + data->oversampling_temp = ilog2(2); + break; default: return -EINVAL; } @@ -895,6 +1089,7 @@ static const struct acpi_device_id bmp280_acpi_match[] = { {"BMP0280", BMP280_CHIP_ID }, {"BMP0180", BMP180_CHIP_ID }, {"BMP0085", BMP180_CHIP_ID }, + {"BME0280", BME280_CHIP_ID }, { }, }; MODULE_DEVICE_TABLE(acpi, bmp280_acpi_match); @@ -903,6 +1098,7 @@ static const struct i2c_device_id bmp280_id[] = { {"bmp280", BMP280_CHIP_ID }, {"bmp180", BMP180_CHIP_ID }, {"bmp085", BMP180_CHIP_ID }, + {"bme280", BME280_CHIP_ID }, { }, }; MODULE_DEVICE_TABLE(i2c, bmp280_id); -- cgit v0.10.2 From 866b148a73e72af919ff836f3dfb5a6022823623 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Sun, 22 May 2016 11:05:57 +0200 Subject: MAINTAINERS: Add file patterns for iio device tree bindings Submitters of device tree binding documentation may forget to CC the subsystem maintainer if this is missing. Signed-off-by: Geert Uytterhoeven Cc: Jonathan Cameron Cc: Hartmut Knaack Cc: Lars-Peter Clausen Cc: Peter Meerwald-Stadler Cc: linux-iio@vger.kernel.org Signed-off-by: Jonathan Cameron diff --git a/MAINTAINERS b/MAINTAINERS index 1ace393..cb1eadd 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -5541,6 +5541,7 @@ R: Lars-Peter Clausen R: Peter Meerwald-Stadler L: linux-iio@vger.kernel.org S: Maintained +F: Documentation/devicetree/bindings/iio/ F: drivers/iio/ F: drivers/staging/iio/ F: include/linux/iio/ -- cgit v0.10.2 From 5291582dc6a4a9c1167ee86748bce5444633d7cc Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Sun, 22 May 2016 11:06:22 +0200 Subject: MAINTAINERS: Add file patterns for staging iio device tree bindings Submitters of device tree binding documentation may forget to CC the subsystem maintainer if this is missing. Signed-off-by: Geert Uytterhoeven Cc: Jonathan Cameron Cc: linux-iio@vger.kernel.org Signed-off-by: Jonathan Cameron diff --git a/MAINTAINERS b/MAINTAINERS index cb1eadd..0c484c4 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -10561,6 +10561,7 @@ STAGING - INDUSTRIAL IO M: Jonathan Cameron L: linux-iio@vger.kernel.org S: Odd Fixes +F: Documentation/devicetree/bindings/staging/iio/ F: drivers/staging/iio/ STAGING - LIRC (LINUX INFRARED REMOTE CONTROL) DRIVERS -- cgit v0.10.2 From 4f3532506a339d91e593da59eea4e7143e698ca3 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 17 May 2016 08:42:12 +0000 Subject: ASoC: rsnd: open 31bit of SSICKR mask SSICKR (Gen2) / BRGCKR (Gen3) 31bit mask should be opened, because BRGB (= for 48kHz) might select it. Special thanks Yokoyama-san Reported-by: Hiroyuki Yokoyama Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown diff --git a/sound/soc/sh/rcar/adg.c b/sound/soc/sh/rcar/adg.c index 606399d..0891014 100644 --- a/sound/soc/sh/rcar/adg.c +++ b/sound/soc/sh/rcar/adg.c @@ -522,7 +522,7 @@ static void rsnd_adg_get_clkout(struct rsnd_priv *priv, } } - rsnd_mod_bset(adg_mod, SSICKR, 0x00FF0000, ckr); + rsnd_mod_bset(adg_mod, SSICKR, 0x80FF0000, ckr); rsnd_mod_write(adg_mod, BRRA, rbga); rsnd_mod_write(adg_mod, BRRB, rbgb); -- cgit v0.10.2 From 8ac8aa61f87eda944cf29229c9c20cba9e83f1ea Mon Sep 17 00:00:00 2001 From: Matt Ranostay Date: Tue, 17 May 2016 15:02:03 -0700 Subject: iio: adc: ti-ads1015: add datasheet names Add datasheet names for ADC channels to allow iio consumers access. Signed-off-by: Matt Ranostay Acked-by: Daniel Baluta Signed-off-by: Jonathan Cameron diff --git a/drivers/iio/adc/ti-ads1015.c b/drivers/iio/adc/ti-ads1015.c index a835423..8be192a 100644 --- a/drivers/iio/adc/ti-ads1015.c +++ b/drivers/iio/adc/ti-ads1015.c @@ -110,6 +110,7 @@ static const struct { .shift = 4, \ .endianness = IIO_CPU, \ }, \ + .datasheet_name = "AIN"#_chan, \ } #define ADS1015_V_DIFF_CHAN(_chan, _chan2, _addr) { \ @@ -130,6 +131,7 @@ static const struct { .shift = 4, \ .endianness = IIO_CPU, \ }, \ + .datasheet_name = "AIN"#_chan"-AIN"#_chan2, \ } #define ADS1115_V_CHAN(_chan, _addr) { \ @@ -147,6 +149,7 @@ static const struct { .storagebits = 16, \ .endianness = IIO_CPU, \ }, \ + .datasheet_name = "AIN"#_chan, \ } #define ADS1115_V_DIFF_CHAN(_chan, _chan2, _addr) { \ @@ -166,6 +169,7 @@ static const struct { .storagebits = 16, \ .endianness = IIO_CPU, \ }, \ + .datasheet_name = "AIN"#_chan"-AIN"#_chan2, \ } struct ads1015_data { -- cgit v0.10.2 From ef2d71d6b7fbbb57e332883d8fad39f2adb9199e Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sat, 14 May 2016 18:42:08 +0100 Subject: iio: triggers: Make trigger ops structure explicitly non optional. This structure has not been optional for a long time (if ever) but the code implies that it is. As we then use it later in a fashion that would crash if it was in fact NULL, it's inconsistent so fix it up by removing unnecessary checks. Reported-by: Dan Carpenter Signed-off-by: Jonathan Cameron diff --git a/drivers/iio/industrialio-trigger.c b/drivers/iio/industrialio-trigger.c index ae2806a..6729112 100644 --- a/drivers/iio/industrialio-trigger.c +++ b/drivers/iio/industrialio-trigger.c @@ -68,6 +68,10 @@ int iio_trigger_register(struct iio_trigger *trig_info) { int ret; + /* trig_info->ops is required for the module member */ + if (!trig_info->ops) + return -EINVAL; + trig_info->id = ida_simple_get(&iio_trigger_ida, 0, 0, GFP_KERNEL); if (trig_info->id < 0) return trig_info->id; @@ -164,8 +168,7 @@ EXPORT_SYMBOL(iio_trigger_poll_chained); void iio_trigger_notify_done(struct iio_trigger *trig) { - if (atomic_dec_and_test(&trig->use_count) && trig->ops && - trig->ops->try_reenable) + if (atomic_dec_and_test(&trig->use_count) && trig->ops->try_reenable) if (trig->ops->try_reenable(trig)) /* Missed an interrupt so launch new poll now */ iio_trigger_poll(trig); @@ -219,7 +222,7 @@ static int iio_trigger_attach_poll_func(struct iio_trigger *trig, return ret; } - if (trig->ops && trig->ops->set_trigger_state && notinuse) { + if (trig->ops->set_trigger_state && notinuse) { ret = trig->ops->set_trigger_state(trig, true); if (ret < 0) module_put(pf->indio_dev->info->driver_module); @@ -236,7 +239,7 @@ static int iio_trigger_detach_poll_func(struct iio_trigger *trig, = (bitmap_weight(trig->pool, CONFIG_IIO_CONSUMERS_PER_TRIGGER) == 1); - if (trig->ops && trig->ops->set_trigger_state && no_other_users) { + if (trig->ops->set_trigger_state && no_other_users) { ret = trig->ops->set_trigger_state(trig, false); if (ret) return ret; @@ -358,7 +361,7 @@ static ssize_t iio_trigger_write_current(struct device *dev, return ret; } - if (trig && trig->ops && trig->ops->validate_device) { + if (trig && trig->ops->validate_device) { ret = trig->ops->validate_device(trig, indio_dev); if (ret) return ret; -- cgit v0.10.2 From e039e2f5b4dab9a90bb5441a154c01a051b1abfa Mon Sep 17 00:00:00 2001 From: Gregor Boirie Date: Tue, 19 Apr 2016 11:18:32 +0200 Subject: iio:st_pressure:initial lps22hb sensor support Initial support for ST LPS22HB pressure sensor. Datasheet: http://www2.st.com/resource/en/datasheet/lps22hb.pdf Features: * pressure data and timestamping channels * sampling frequency selection * interrupt based trigger * over I2C or SPI Signed-off-by: Gregor Boirie Signed-off-by: Jonathan Cameron diff --git a/Documentation/devicetree/bindings/iio/st-sensors.txt b/Documentation/devicetree/bindings/iio/st-sensors.txt index 5844cf7..e41fe34 100644 --- a/Documentation/devicetree/bindings/iio/st-sensors.txt +++ b/Documentation/devicetree/bindings/iio/st-sensors.txt @@ -64,3 +64,4 @@ Pressure sensors: - st,lps001wp-press - st,lps25h-press - st,lps331ap-press +- st,lps22hb-press diff --git a/drivers/iio/pressure/Kconfig b/drivers/iio/pressure/Kconfig index 9125a93..8d654f6 100644 --- a/drivers/iio/pressure/Kconfig +++ b/drivers/iio/pressure/Kconfig @@ -131,7 +131,7 @@ config IIO_ST_PRESS select IIO_TRIGGERED_BUFFER if (IIO_BUFFER) help Say yes here to build support for STMicroelectronics pressure - sensors: LPS001WP, LPS25H, LPS331AP. + sensors: LPS001WP, LPS25H, LPS331AP, LPS22HB. This driver can also be built as a module. If so, these modules will be created: diff --git a/drivers/iio/pressure/st_pressure.h b/drivers/iio/pressure/st_pressure.h index f5f4149..903a21e 100644 --- a/drivers/iio/pressure/st_pressure.h +++ b/drivers/iio/pressure/st_pressure.h @@ -17,6 +17,7 @@ #define LPS001WP_PRESS_DEV_NAME "lps001wp" #define LPS25H_PRESS_DEV_NAME "lps25h" #define LPS331AP_PRESS_DEV_NAME "lps331ap" +#define LPS22HB_PRESS_DEV_NAME "lps22hb" /** * struct st_sensors_platform_data - default press platform data diff --git a/drivers/iio/pressure/st_pressure_core.c b/drivers/iio/pressure/st_pressure_core.c index 9e9b72a..c0ff3bf 100644 --- a/drivers/iio/pressure/st_pressure_core.c +++ b/drivers/iio/pressure/st_pressure_core.c @@ -113,6 +113,26 @@ #define ST_PRESS_LPS25H_OUT_XL_ADDR 0x28 #define ST_TEMP_LPS25H_OUT_L_ADDR 0x2b +/* CUSTOM VALUES FOR LPS22HB SENSOR */ +#define ST_PRESS_LPS22HB_WAI_EXP 0xb1 +#define ST_PRESS_LPS22HB_ODR_ADDR 0x10 +#define ST_PRESS_LPS22HB_ODR_MASK 0x70 +#define ST_PRESS_LPS22HB_ODR_AVL_1HZ_VAL 0x01 +#define ST_PRESS_LPS22HB_ODR_AVL_10HZ_VAL 0x02 +#define ST_PRESS_LPS22HB_ODR_AVL_25HZ_VAL 0x03 +#define ST_PRESS_LPS22HB_ODR_AVL_50HZ_VAL 0x04 +#define ST_PRESS_LPS22HB_ODR_AVL_75HZ_VAL 0x05 +#define ST_PRESS_LPS22HB_PW_ADDR 0x10 +#define ST_PRESS_LPS22HB_PW_MASK 0x70 +#define ST_PRESS_LPS22HB_BDU_ADDR 0x10 +#define ST_PRESS_LPS22HB_BDU_MASK 0x02 +#define ST_PRESS_LPS22HB_DRDY_IRQ_ADDR 0x12 +#define ST_PRESS_LPS22HB_DRDY_IRQ_INT1_MASK 0x04 +#define ST_PRESS_LPS22HB_DRDY_IRQ_INT2_MASK 0x08 +#define ST_PRESS_LPS22HB_IHL_IRQ_ADDR 0x12 +#define ST_PRESS_LPS22HB_IHL_IRQ_MASK 0x80 +#define ST_PRESS_LPS22HB_MULTIREAD_BIT true + static const struct iio_chan_spec st_press_1_channels[] = { { .type = IIO_PRESSURE, @@ -183,6 +203,27 @@ static const struct iio_chan_spec st_press_lps001wp_channels[] = { IIO_CHAN_SOFT_TIMESTAMP(1) }; +static const struct iio_chan_spec st_press_lps22hb_channels[] = { + { + .type = IIO_PRESSURE, + .channel2 = IIO_NO_MOD, + .address = ST_PRESS_1_OUT_XL_ADDR, + .scan_index = 0, + .scan_type = { + .sign = 'u', + .realbits = 24, + .storagebits = 24, + .endianness = IIO_LE, + }, + .info_mask_separate = + BIT(IIO_CHAN_INFO_RAW) | + BIT(IIO_CHAN_INFO_SCALE), + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), + .modified = 0, + }, + IIO_CHAN_SOFT_TIMESTAMP(1) +}; + static const struct st_sensor_settings st_press_sensors_settings[] = { { .wai = ST_PRESS_LPS331AP_WAI_EXP, @@ -326,6 +367,51 @@ static const struct st_sensor_settings st_press_sensors_settings[] = { .multi_read_bit = ST_PRESS_LPS25H_MULTIREAD_BIT, .bootime = 2, }, + { + .wai = ST_PRESS_LPS22HB_WAI_EXP, + .wai_addr = ST_SENSORS_DEFAULT_WAI_ADDRESS, + .sensors_supported = { + [0] = LPS22HB_PRESS_DEV_NAME, + }, + .ch = (struct iio_chan_spec *)st_press_lps22hb_channels, + .num_ch = ARRAY_SIZE(st_press_lps22hb_channels), + .odr = { + .addr = ST_PRESS_LPS22HB_ODR_ADDR, + .mask = ST_PRESS_LPS22HB_ODR_MASK, + .odr_avl = { + { 1, ST_PRESS_LPS22HB_ODR_AVL_1HZ_VAL, }, + { 10, ST_PRESS_LPS22HB_ODR_AVL_10HZ_VAL, }, + { 25, ST_PRESS_LPS22HB_ODR_AVL_25HZ_VAL, }, + { 50, ST_PRESS_LPS22HB_ODR_AVL_50HZ_VAL, }, + { 75, ST_PRESS_LPS22HB_ODR_AVL_75HZ_VAL, }, + }, + }, + .pw = { + .addr = ST_PRESS_LPS22HB_PW_ADDR, + .mask = ST_PRESS_LPS22HB_PW_MASK, + .value_off = ST_SENSORS_DEFAULT_POWER_OFF_VALUE, + }, + .fs = { + .fs_avl = { + [0] = { + .num = ST_PRESS_FS_AVL_1260MB, + .gain = ST_PRESS_KPASCAL_NANO_SCALE, + }, + }, + }, + .bdu = { + .addr = ST_PRESS_LPS22HB_BDU_ADDR, + .mask = ST_PRESS_LPS22HB_BDU_MASK, + }, + .drdy_irq = { + .addr = ST_PRESS_LPS22HB_DRDY_IRQ_ADDR, + .mask_int1 = ST_PRESS_LPS22HB_DRDY_IRQ_INT1_MASK, + .mask_int2 = ST_PRESS_LPS22HB_DRDY_IRQ_INT2_MASK, + .addr_ihl = ST_PRESS_LPS22HB_IHL_IRQ_ADDR, + .mask_ihl = ST_PRESS_LPS22HB_IHL_IRQ_MASK, + }, + .multi_read_bit = ST_PRESS_LPS22HB_MULTIREAD_BIT, + }, }; static int st_press_write_raw(struct iio_dev *indio_dev, @@ -454,10 +540,9 @@ int st_press_common_probe(struct iio_dev *indio_dev) indio_dev->channels = press_data->sensor_settings->ch; indio_dev->num_channels = press_data->sensor_settings->num_ch; - if (press_data->sensor_settings->fs.addr != 0) - press_data->current_fullscale = - (struct st_sensor_fullscale_avl *) - &press_data->sensor_settings->fs.fs_avl[0]; + press_data->current_fullscale = + (struct st_sensor_fullscale_avl *) + &press_data->sensor_settings->fs.fs_avl[0]; press_data->odr = press_data->sensor_settings->odr.odr_avl[0].hz; diff --git a/drivers/iio/pressure/st_pressure_i2c.c b/drivers/iio/pressure/st_pressure_i2c.c index 8fcf976..ed18701 100644 --- a/drivers/iio/pressure/st_pressure_i2c.c +++ b/drivers/iio/pressure/st_pressure_i2c.c @@ -32,6 +32,10 @@ static const struct of_device_id st_press_of_match[] = { .compatible = "st,lps331ap-press", .data = LPS331AP_PRESS_DEV_NAME, }, + { + .compatible = "st,lps22hb-press", + .data = LPS22HB_PRESS_DEV_NAME, + }, {}, }; MODULE_DEVICE_TABLE(of, st_press_of_match); diff --git a/drivers/iio/pressure/st_pressure_spi.c b/drivers/iio/pressure/st_pressure_spi.c index 40c0692..5505080 100644 --- a/drivers/iio/pressure/st_pressure_spi.c +++ b/drivers/iio/pressure/st_pressure_spi.c @@ -50,6 +50,7 @@ static const struct spi_device_id st_press_id_table[] = { { LPS001WP_PRESS_DEV_NAME }, { LPS25H_PRESS_DEV_NAME }, { LPS331AP_PRESS_DEV_NAME }, + { LPS22HB_PRESS_DEV_NAME }, {}, }; MODULE_DEVICE_TABLE(spi, st_press_id_table); -- cgit v0.10.2 From dfe3ab1af0765eb800da5ce4cb4c685783096d9c Mon Sep 17 00:00:00 2001 From: Gregor Boirie Date: Tue, 19 Apr 2016 11:18:38 +0200 Subject: iio:st_sensors: unexport st_sensors_get_buffer_element Remove st_sensors_get_buffer_element symbol export since not explicitly used outside of st_sensors driver. Signed-off-by: Gregor Boirie Signed-off-by: Jonathan Cameron diff --git a/drivers/iio/common/st_sensors/st_sensors_buffer.c b/drivers/iio/common/st_sensors/st_sensors_buffer.c index c558985..4ccc438 100644 --- a/drivers/iio/common/st_sensors/st_sensors_buffer.c +++ b/drivers/iio/common/st_sensors/st_sensors_buffer.c @@ -22,7 +22,7 @@ #include -int st_sensors_get_buffer_element(struct iio_dev *indio_dev, u8 *buf) +static int st_sensors_get_buffer_element(struct iio_dev *indio_dev, u8 *buf) { int i, len; int total = 0; @@ -49,7 +49,6 @@ int st_sensors_get_buffer_element(struct iio_dev *indio_dev, u8 *buf) return total; } -EXPORT_SYMBOL(st_sensors_get_buffer_element); irqreturn_t st_sensors_trigger_handler(int irq, void *p) { diff --git a/include/linux/iio/common/st_sensors.h b/include/linux/iio/common/st_sensors.h index d029ffa..78a1934 100644 --- a/include/linux/iio/common/st_sensors.h +++ b/include/linux/iio/common/st_sensors.h @@ -251,8 +251,6 @@ struct st_sensor_data { #ifdef CONFIG_IIO_BUFFER irqreturn_t st_sensors_trigger_handler(int irq, void *p); - -int st_sensors_get_buffer_element(struct iio_dev *indio_dev, u8 *buf); #endif #ifdef CONFIG_IIO_TRIGGER -- cgit v0.10.2 From 169a88c1ee19b0734c9703d51a6d8ebe538f5bc3 Mon Sep 17 00:00:00 2001 From: Gregor Boirie Date: Tue, 19 Apr 2016 11:18:39 +0200 Subject: iio:st_sensors: emulate SMBus block read if needed Use SMBus "block read" protocol only when supported by adapter. Signed-off-by: Gregor Boirie Signed-off-by: Jonathan Cameron diff --git a/drivers/iio/common/st_sensors/st_sensors_i2c.c b/drivers/iio/common/st_sensors/st_sensors_i2c.c index 98cfee29..b43aa36 100644 --- a/drivers/iio/common/st_sensors/st_sensors_i2c.c +++ b/drivers/iio/common/st_sensors/st_sensors_i2c.c @@ -48,8 +48,8 @@ static int st_sensors_i2c_read_multiple_byte( if (multiread_bit) reg_addr |= ST_SENSORS_I2C_MULTIREAD; - return i2c_smbus_read_i2c_block_data(to_i2c_client(dev), - reg_addr, len, data); + return i2c_smbus_read_i2c_block_data_or_emulated(to_i2c_client(dev), + reg_addr, len, data); } static int st_sensors_i2c_write_byte(struct st_sensor_transfer_buffer *tb, -- cgit v0.10.2 From 14f295c846063c4f1812b09427195cee522aa006 Mon Sep 17 00:00:00 2001 From: Gregor Boirie Date: Tue, 19 Apr 2016 11:18:40 +0200 Subject: iio:st_sensors: fix power regulator usage Ensure failure to enable power regulators is properly handled. Signed-off-by: Gregor Boirie Signed-off-by: Jonathan Cameron diff --git a/drivers/iio/accel/st_accel_core.c b/drivers/iio/accel/st_accel_core.c index dc73f2d..b8d3c3c 100644 --- a/drivers/iio/accel/st_accel_core.c +++ b/drivers/iio/accel/st_accel_core.c @@ -757,13 +757,15 @@ int st_accel_common_probe(struct iio_dev *indio_dev) indio_dev->info = &accel_info; mutex_init(&adata->tb.buf_lock); - st_sensors_power_enable(indio_dev); + err = st_sensors_power_enable(indio_dev); + if (err) + return err; err = st_sensors_check_device_support(indio_dev, ARRAY_SIZE(st_accel_sensors_settings), st_accel_sensors_settings); if (err < 0) - return err; + goto st_accel_power_off; adata->num_data_channels = ST_ACCEL_NUMBER_DATA_CHANNELS; adata->multiread_bit = adata->sensor_settings->multi_read_bit; @@ -780,11 +782,11 @@ int st_accel_common_probe(struct iio_dev *indio_dev) err = st_sensors_init_sensor(indio_dev, adata->dev->platform_data); if (err < 0) - return err; + goto st_accel_power_off; err = st_accel_allocate_ring(indio_dev); if (err < 0) - return err; + goto st_accel_power_off; if (irq > 0) { err = st_sensors_allocate_trigger(indio_dev, @@ -807,6 +809,8 @@ st_accel_device_register_error: st_sensors_deallocate_trigger(indio_dev); st_accel_probe_trigger_error: st_accel_deallocate_ring(indio_dev); +st_accel_power_off: + st_sensors_power_disable(indio_dev); return err; } diff --git a/drivers/iio/common/st_sensors/st_sensors_core.c b/drivers/iio/common/st_sensors/st_sensors_core.c index dffe006..00078b5 100644 --- a/drivers/iio/common/st_sensors/st_sensors_core.c +++ b/drivers/iio/common/st_sensors/st_sensors_core.c @@ -228,7 +228,7 @@ int st_sensors_set_axis_enable(struct iio_dev *indio_dev, u8 axis_enable) } EXPORT_SYMBOL(st_sensors_set_axis_enable); -void st_sensors_power_enable(struct iio_dev *indio_dev) +int st_sensors_power_enable(struct iio_dev *indio_dev) { struct st_sensor_data *pdata = iio_priv(indio_dev); int err; @@ -237,18 +237,37 @@ void st_sensors_power_enable(struct iio_dev *indio_dev) pdata->vdd = devm_regulator_get_optional(indio_dev->dev.parent, "vdd"); if (!IS_ERR(pdata->vdd)) { err = regulator_enable(pdata->vdd); - if (err != 0) + if (err != 0) { dev_warn(&indio_dev->dev, "Failed to enable specified Vdd supply\n"); + return err; + } + } else { + err = PTR_ERR(pdata->vdd); + if (err != -ENODEV) + return err; } pdata->vdd_io = devm_regulator_get_optional(indio_dev->dev.parent, "vddio"); if (!IS_ERR(pdata->vdd_io)) { err = regulator_enable(pdata->vdd_io); - if (err != 0) + if (err != 0) { dev_warn(&indio_dev->dev, "Failed to enable specified Vdd_IO supply\n"); + goto st_sensors_disable_vdd; + } + } else { + err = PTR_ERR(pdata->vdd_io); + if (err != -ENODEV) + goto st_sensors_disable_vdd; } + + return 0; + +st_sensors_disable_vdd: + if (!IS_ERR_OR_NULL(pdata->vdd)) + regulator_disable(pdata->vdd); + return err; } EXPORT_SYMBOL(st_sensors_power_enable); @@ -256,10 +275,10 @@ void st_sensors_power_disable(struct iio_dev *indio_dev) { struct st_sensor_data *pdata = iio_priv(indio_dev); - if (!IS_ERR(pdata->vdd)) + if (!IS_ERR_OR_NULL(pdata->vdd)) regulator_disable(pdata->vdd); - if (!IS_ERR(pdata->vdd_io)) + if (!IS_ERR_OR_NULL(pdata->vdd_io)) regulator_disable(pdata->vdd_io); } EXPORT_SYMBOL(st_sensors_power_disable); diff --git a/drivers/iio/gyro/st_gyro_core.c b/drivers/iio/gyro/st_gyro_core.c index 52a3c87..ae1377d 100644 --- a/drivers/iio/gyro/st_gyro_core.c +++ b/drivers/iio/gyro/st_gyro_core.c @@ -425,13 +425,15 @@ int st_gyro_common_probe(struct iio_dev *indio_dev) indio_dev->info = &gyro_info; mutex_init(&gdata->tb.buf_lock); - st_sensors_power_enable(indio_dev); + err = st_sensors_power_enable(indio_dev); + if (err) + return err; err = st_sensors_check_device_support(indio_dev, ARRAY_SIZE(st_gyro_sensors_settings), st_gyro_sensors_settings); if (err < 0) - return err; + goto st_gyro_power_off; gdata->num_data_channels = ST_GYRO_NUMBER_DATA_CHANNELS; gdata->multiread_bit = gdata->sensor_settings->multi_read_bit; @@ -445,11 +447,11 @@ int st_gyro_common_probe(struct iio_dev *indio_dev) err = st_sensors_init_sensor(indio_dev, (struct st_sensors_platform_data *)&gyro_pdata); if (err < 0) - return err; + goto st_gyro_power_off; err = st_gyro_allocate_ring(indio_dev); if (err < 0) - return err; + goto st_gyro_power_off; if (irq > 0) { err = st_sensors_allocate_trigger(indio_dev, @@ -472,6 +474,8 @@ st_gyro_device_register_error: st_sensors_deallocate_trigger(indio_dev); st_gyro_probe_trigger_error: st_gyro_deallocate_ring(indio_dev); +st_gyro_power_off: + st_sensors_power_disable(indio_dev); return err; } diff --git a/drivers/iio/magnetometer/st_magn_core.c b/drivers/iio/magnetometer/st_magn_core.c index 62036d2..7c94adc 100644 --- a/drivers/iio/magnetometer/st_magn_core.c +++ b/drivers/iio/magnetometer/st_magn_core.c @@ -588,13 +588,15 @@ int st_magn_common_probe(struct iio_dev *indio_dev) indio_dev->info = &magn_info; mutex_init(&mdata->tb.buf_lock); - st_sensors_power_enable(indio_dev); + err = st_sensors_power_enable(indio_dev); + if (err) + return err; err = st_sensors_check_device_support(indio_dev, ARRAY_SIZE(st_magn_sensors_settings), st_magn_sensors_settings); if (err < 0) - return err; + goto st_magn_power_off; mdata->num_data_channels = ST_MAGN_NUMBER_DATA_CHANNELS; mdata->multiread_bit = mdata->sensor_settings->multi_read_bit; @@ -607,11 +609,11 @@ int st_magn_common_probe(struct iio_dev *indio_dev) err = st_sensors_init_sensor(indio_dev, NULL); if (err < 0) - return err; + goto st_magn_power_off; err = st_magn_allocate_ring(indio_dev); if (err < 0) - return err; + goto st_magn_power_off; if (irq > 0) { err = st_sensors_allocate_trigger(indio_dev, @@ -634,6 +636,8 @@ st_magn_device_register_error: st_sensors_deallocate_trigger(indio_dev); st_magn_probe_trigger_error: st_magn_deallocate_ring(indio_dev); +st_magn_power_off: + st_sensors_power_disable(indio_dev); return err; } diff --git a/drivers/iio/pressure/st_pressure_core.c b/drivers/iio/pressure/st_pressure_core.c index c0ff3bf..4d317af 100644 --- a/drivers/iio/pressure/st_pressure_core.c +++ b/drivers/iio/pressure/st_pressure_core.c @@ -527,13 +527,15 @@ int st_press_common_probe(struct iio_dev *indio_dev) indio_dev->info = &press_info; mutex_init(&press_data->tb.buf_lock); - st_sensors_power_enable(indio_dev); + err = st_sensors_power_enable(indio_dev); + if (err) + return err; err = st_sensors_check_device_support(indio_dev, ARRAY_SIZE(st_press_sensors_settings), st_press_sensors_settings); if (err < 0) - return err; + goto st_press_power_off; press_data->num_data_channels = ST_PRESS_NUMBER_DATA_CHANNELS; press_data->multiread_bit = press_data->sensor_settings->multi_read_bit; @@ -554,11 +556,11 @@ int st_press_common_probe(struct iio_dev *indio_dev) err = st_sensors_init_sensor(indio_dev, press_data->dev->platform_data); if (err < 0) - return err; + goto st_press_power_off; err = st_press_allocate_ring(indio_dev); if (err < 0) - return err; + goto st_press_power_off; if (irq > 0) { err = st_sensors_allocate_trigger(indio_dev, @@ -581,6 +583,8 @@ st_press_device_register_error: st_sensors_deallocate_trigger(indio_dev); st_press_probe_trigger_error: st_press_deallocate_ring(indio_dev); +st_press_power_off: + st_sensors_power_disable(indio_dev); return err; } diff --git a/include/linux/iio/common/st_sensors.h b/include/linux/iio/common/st_sensors.h index 78a1934..91d5f68 100644 --- a/include/linux/iio/common/st_sensors.h +++ b/include/linux/iio/common/st_sensors.h @@ -278,7 +278,7 @@ int st_sensors_set_enable(struct iio_dev *indio_dev, bool enable); int st_sensors_set_axis_enable(struct iio_dev *indio_dev, u8 axis_enable); -void st_sensors_power_enable(struct iio_dev *indio_dev); +int st_sensors_power_enable(struct iio_dev *indio_dev); void st_sensors_power_disable(struct iio_dev *indio_dev); -- cgit v0.10.2 From c70df20e31595cf696c8b4f50fc7d82b69f3dd5c Mon Sep 17 00:00:00 2001 From: Alison Schofield Date: Tue, 24 May 2016 12:16:23 -0700 Subject: iio: adc: ad7266: claim direct mode during sensor read Driver was checking for direct mode but not locking it down. Use iio_device_claim_direct_mode() to guarantee device stays in direct mode. Signed-off-by: Alison Schofield Acked-by: Daniel Baluta Signed-off-by: Jonathan Cameron diff --git a/drivers/iio/adc/ad7266.c b/drivers/iio/adc/ad7266.c index 21e19b6..01240ae 100644 --- a/drivers/iio/adc/ad7266.c +++ b/drivers/iio/adc/ad7266.c @@ -154,12 +154,11 @@ static int ad7266_read_raw(struct iio_dev *indio_dev, switch (m) { case IIO_CHAN_INFO_RAW: - if (iio_buffer_enabled(indio_dev)) - return -EBUSY; - - ret = ad7266_read_single(st, val, chan->address); + ret = iio_device_claim_direct_mode(indio_dev); if (ret) return ret; + ret = ad7266_read_single(st, val, chan->address); + iio_device_release_direct_mode(indio_dev); *val = (*val >> 2) & 0xfff; if (chan->scan_type.sign == 's') -- cgit v0.10.2 From a52f238e7c808d9fd1f9dfc675f583b77156cdeb Mon Sep 17 00:00:00 2001 From: Alison Schofield Date: Tue, 24 May 2016 12:18:06 -0700 Subject: iio: adc: ad7476: use iio helper function to guarantee direct mode Replace the code that guarantees the device stays in direct mode with iio_device_claim_direct_mode() which does same. Signed-off-by: Alison Schofield Acked-by: Daniel Baluta Signed-off-by: Jonathan Cameron diff --git a/drivers/iio/adc/ad7476.c b/drivers/iio/adc/ad7476.c index be85c2a..810c9a9 100644 --- a/drivers/iio/adc/ad7476.c +++ b/drivers/iio/adc/ad7476.c @@ -106,12 +106,11 @@ static int ad7476_read_raw(struct iio_dev *indio_dev, switch (m) { case IIO_CHAN_INFO_RAW: - mutex_lock(&indio_dev->mlock); - if (iio_buffer_enabled(indio_dev)) - ret = -EBUSY; - else - ret = ad7476_scan_direct(st); - mutex_unlock(&indio_dev->mlock); + ret = iio_device_claim_direct_mode(indio_dev); + if (ret) + return ret; + ret = ad7476_scan_direct(st); + iio_device_release_direct_mode(indio_dev); if (ret < 0) return ret; -- cgit v0.10.2 From 6fea8a426b67455a58b59964cee905754ab77497 Mon Sep 17 00:00:00 2001 From: Alison Schofield Date: Tue, 24 May 2016 12:18:43 -0700 Subject: iio: adc: ad7887: use iio helper function to guarantee direct mode Replace the code that guarantees the device stays in direct mode with iio_device_claim_direct_mode() which does same. Signed-off-by: Alison Schofield Acked-by: Daniel Baluta Signed-off-by: Jonathan Cameron diff --git a/drivers/iio/adc/ad7887.c b/drivers/iio/adc/ad7887.c index 2d3c397..ee2ccc1 100644 --- a/drivers/iio/adc/ad7887.c +++ b/drivers/iio/adc/ad7887.c @@ -156,12 +156,11 @@ static int ad7887_read_raw(struct iio_dev *indio_dev, switch (m) { case IIO_CHAN_INFO_RAW: - mutex_lock(&indio_dev->mlock); - if (iio_buffer_enabled(indio_dev)) - ret = -EBUSY; - else - ret = ad7887_scan_direct(st, chan->address); - mutex_unlock(&indio_dev->mlock); + ret = iio_device_claim_direct_mode(indio_dev); + if (ret) + return ret; + ret = ad7887_scan_direct(st, chan->address); + iio_device_release_direct_mode(indio_dev); if (ret < 0) return ret; -- cgit v0.10.2 From 9f57e068e01c14f34f69244e1f4a6c567d93cdfe Mon Sep 17 00:00:00 2001 From: Alison Schofield Date: Tue, 24 May 2016 12:19:49 -0700 Subject: iio: adc: ad7923: use iio helper function to guarantee direct mode Replace the code that guarantees the device stays in direct mode with iio_device_claim_direct_mode() which does same. Signed-off-by: Alison Schofield Acked-by: Daniel Baluta Signed-off-by: Jonathan Cameron diff --git a/drivers/iio/adc/ad7923.c b/drivers/iio/adc/ad7923.c index 45e29cc..ff444c1 100644 --- a/drivers/iio/adc/ad7923.c +++ b/drivers/iio/adc/ad7923.c @@ -233,12 +233,11 @@ static int ad7923_read_raw(struct iio_dev *indio_dev, switch (m) { case IIO_CHAN_INFO_RAW: - mutex_lock(&indio_dev->mlock); - if (iio_buffer_enabled(indio_dev)) - ret = -EBUSY; - else - ret = ad7923_scan_direct(st, chan->address); - mutex_unlock(&indio_dev->mlock); + ret = iio_device_claim_direct_mode(indio_dev); + if (ret) + return ret; + ret = ad7923_scan_direct(st, chan->address); + iio_device_release_direct_mode(indio_dev); if (ret < 0) return ret; -- cgit v0.10.2 From 1bb86ecb6c03e156cdbd89978320c839e9f954b4 Mon Sep 17 00:00:00 2001 From: Alison Schofield Date: Tue, 24 May 2016 12:20:24 -0700 Subject: iio: adc: ad799x: use iio helper function to guarantee direct mode Replace the code that guarantees the device stays in direct mode with iio_device_claim_direct_mode() which does same. Signed-off-by: Alison Schofield Acked-by: Daniel Baluta Signed-off-by: Jonathan Cameron diff --git a/drivers/iio/adc/ad799x.c b/drivers/iio/adc/ad799x.c index a3f5254..ec0200d 100644 --- a/drivers/iio/adc/ad799x.c +++ b/drivers/iio/adc/ad799x.c @@ -282,12 +282,11 @@ static int ad799x_read_raw(struct iio_dev *indio_dev, switch (m) { case IIO_CHAN_INFO_RAW: - mutex_lock(&indio_dev->mlock); - if (iio_buffer_enabled(indio_dev)) - ret = -EBUSY; - else - ret = ad799x_scan_direct(st, chan->scan_index); - mutex_unlock(&indio_dev->mlock); + ret = iio_device_claim_direct_mode(indio_dev); + if (ret) + return ret; + ret = ad799x_scan_direct(st, chan->scan_index); + iio_device_release_direct_mode(indio_dev); if (ret < 0) return ret; @@ -395,11 +394,9 @@ static int ad799x_write_event_config(struct iio_dev *indio_dev, struct ad799x_state *st = iio_priv(indio_dev); int ret; - mutex_lock(&indio_dev->mlock); - if (iio_buffer_enabled(indio_dev)) { - ret = -EBUSY; - goto done; - } + ret = iio_device_claim_direct_mode(indio_dev); + if (ret) + return ret; if (state) st->config |= BIT(chan->scan_index) << AD799X_CHANNEL_SHIFT; @@ -412,10 +409,7 @@ static int ad799x_write_event_config(struct iio_dev *indio_dev, st->config &= ~AD7998_ALERT_EN; ret = ad799x_write_config(st, st->config); - -done: - mutex_unlock(&indio_dev->mlock); - + iio_device_release_direct_mode(indio_dev); return ret; } -- cgit v0.10.2 From 0c4b650029ec6d8b13b527c5b775549c2a06c898 Mon Sep 17 00:00:00 2001 From: Peter Robinson Date: Wed, 25 May 2016 14:31:13 +0100 Subject: tools: iio: Add ability to install/uninstall Add options to the Makefile for install/uninstall similar to other tools. Signed-off-by: Peter Robinson Signed-off-by: Jonathan Cameron diff --git a/tools/iio/Makefile b/tools/iio/Makefile index 3a7a54f..5c32e90 100644 --- a/tools/iio/Makefile +++ b/tools/iio/Makefile @@ -1,6 +1,10 @@ CC = $(CROSS_COMPILE)gcc CFLAGS += -Wall -g -D_GNU_SOURCE +BINDIR=usr/bin +INSTALL_PROGRAM=install -m 755 -p +DEL_FILE=rm -f + all: iio_event_monitor lsiio generic_buffer iio_event_monitor: iio_event_monitor.o iio_utils.o @@ -11,6 +15,17 @@ generic_buffer: generic_buffer.o iio_utils.o %.o: %.c iio_utils.h +install: + - mkdir -p $(INSTALL_ROOT)/$(BINDIR) + - $(INSTALL_PROGRAM) "iio_event_monitor" "$(INSTALL_ROOT)/$(BINDIR)/iio_event_monitor" + - $(INSTALL_PROGRAM) "lsiio" "$(INSTALL_ROOT)/$(BINDIR)/lsiio" + - $(INSTALL_PROGRAM) "generic_buffer" "$(INSTALL_ROOT)/$(BINDIR)/generic_buffer" + +uninstall: + $(DEL_FILE) "$(INSTALL_ROOT)/$(BINDIR)/iio_event_monitor" + $(DEL_FILE) "$(INSTALL_ROOT)/$(BINDIR)/lsiio" + $(DEL_FILE) "$(INSTALL_ROOT)/$(BINDIR)/generic_buffer" + .PHONY: clean clean: rm -f *.o iio_event_monitor lsiio generic_buffer -- cgit v0.10.2 From 5d48d6b0203de854587e8338376661e2315b2571 Mon Sep 17 00:00:00 2001 From: Daniel Baluta Date: Tue, 24 May 2016 18:03:55 +0300 Subject: tools: iio: Rename generic_buffer to iio_generic_buffer This makes it clear that generic_buffer is an IIO tool and also complies with filename conventions in tools/iio. Signed-off-by: Daniel Baluta Signed-off-by: Jonathan Cameron diff --git a/tools/iio/Makefile b/tools/iio/Makefile index 5c32e90..5446d62 100644 --- a/tools/iio/Makefile +++ b/tools/iio/Makefile @@ -5,13 +5,13 @@ BINDIR=usr/bin INSTALL_PROGRAM=install -m 755 -p DEL_FILE=rm -f -all: iio_event_monitor lsiio generic_buffer +all: iio_event_monitor lsiio iio_generic_buffer iio_event_monitor: iio_event_monitor.o iio_utils.o lsiio: lsiio.o iio_utils.o -generic_buffer: generic_buffer.o iio_utils.o +iio_generic_buffer: iio_generic_buffer.o iio_utils.o %.o: %.c iio_utils.h @@ -19,13 +19,13 @@ install: - mkdir -p $(INSTALL_ROOT)/$(BINDIR) - $(INSTALL_PROGRAM) "iio_event_monitor" "$(INSTALL_ROOT)/$(BINDIR)/iio_event_monitor" - $(INSTALL_PROGRAM) "lsiio" "$(INSTALL_ROOT)/$(BINDIR)/lsiio" - - $(INSTALL_PROGRAM) "generic_buffer" "$(INSTALL_ROOT)/$(BINDIR)/generic_buffer" + - $(INSTALL_PROGRAM) "iio_generic_buffer" "$(INSTALL_ROOT)/$(BINDIR)/iio_generic_buffer" uninstall: $(DEL_FILE) "$(INSTALL_ROOT)/$(BINDIR)/iio_event_monitor" $(DEL_FILE) "$(INSTALL_ROOT)/$(BINDIR)/lsiio" - $(DEL_FILE) "$(INSTALL_ROOT)/$(BINDIR)/generic_buffer" + $(DEL_FILE) "$(INSTALL_ROOT)/$(BINDIR)/iio_generic_buffer" .PHONY: clean clean: - rm -f *.o iio_event_monitor lsiio generic_buffer + rm -f *.o iio_event_monitor lsiio iio_generic_buffer diff --git a/tools/iio/generic_buffer.c b/tools/iio/generic_buffer.c deleted file mode 100644 index 2429c78..0000000 --- a/tools/iio/generic_buffer.c +++ /dev/null @@ -1,581 +0,0 @@ -/* Industrialio buffer test code. - * - * Copyright (c) 2008 Jonathan Cameron - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is primarily intended as an example application. - * Reads the current buffer setup from sysfs and starts a short capture - * from the specified device, pretty printing the result after appropriate - * conversion. - * - * Command line parameters - * generic_buffer -n -t - * If trigger name is not specified the program assumes you want a dataready - * trigger associated with the device and goes looking for it. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "iio_utils.h" - -/** - * enum autochan - state for the automatic channel enabling mechanism - */ -enum autochan { - AUTOCHANNELS_DISABLED, - AUTOCHANNELS_ENABLED, - AUTOCHANNELS_ACTIVE, -}; - -/** - * size_from_channelarray() - calculate the storage size of a scan - * @channels: the channel info array - * @num_channels: number of channels - * - * Has the side effect of filling the channels[i].location values used - * in processing the buffer output. - **/ -int size_from_channelarray(struct iio_channel_info *channels, int num_channels) -{ - int bytes = 0; - int i = 0; - - while (i < num_channels) { - if (bytes % channels[i].bytes == 0) - channels[i].location = bytes; - else - channels[i].location = bytes - bytes % channels[i].bytes - + channels[i].bytes; - - bytes = channels[i].location + channels[i].bytes; - i++; - } - - return bytes; -} - -void print1byte(uint8_t input, struct iio_channel_info *info) -{ - /* - * Shift before conversion to avoid sign extension - * of left aligned data - */ - input >>= info->shift; - input &= info->mask; - if (info->is_signed) { - int8_t val = (int8_t)(input << (8 - info->bits_used)) >> - (8 - info->bits_used); - printf("%05f ", ((float)val + info->offset) * info->scale); - } else { - printf("%05f ", ((float)input + info->offset) * info->scale); - } -} - -void print2byte(uint16_t input, struct iio_channel_info *info) -{ - /* First swap if incorrect endian */ - if (info->be) - input = be16toh(input); - else - input = le16toh(input); - - /* - * Shift before conversion to avoid sign extension - * of left aligned data - */ - input >>= info->shift; - input &= info->mask; - if (info->is_signed) { - int16_t val = (int16_t)(input << (16 - info->bits_used)) >> - (16 - info->bits_used); - printf("%05f ", ((float)val + info->offset) * info->scale); - } else { - printf("%05f ", ((float)input + info->offset) * info->scale); - } -} - -void print4byte(uint32_t input, struct iio_channel_info *info) -{ - /* First swap if incorrect endian */ - if (info->be) - input = be32toh(input); - else - input = le32toh(input); - - /* - * Shift before conversion to avoid sign extension - * of left aligned data - */ - input >>= info->shift; - input &= info->mask; - if (info->is_signed) { - int32_t val = (int32_t)(input << (32 - info->bits_used)) >> - (32 - info->bits_used); - printf("%05f ", ((float)val + info->offset) * info->scale); - } else { - printf("%05f ", ((float)input + info->offset) * info->scale); - } -} - -void print8byte(uint64_t input, struct iio_channel_info *info) -{ - /* First swap if incorrect endian */ - if (info->be) - input = be64toh(input); - else - input = le64toh(input); - - /* - * Shift before conversion to avoid sign extension - * of left aligned data - */ - input >>= info->shift; - input &= info->mask; - if (info->is_signed) { - int64_t val = (int64_t)(input << (64 - info->bits_used)) >> - (64 - info->bits_used); - /* special case for timestamp */ - if (info->scale == 1.0f && info->offset == 0.0f) - printf("%" PRId64 " ", val); - else - printf("%05f ", - ((float)val + info->offset) * info->scale); - } else { - printf("%05f ", ((float)input + info->offset) * info->scale); - } -} - -/** - * process_scan() - print out the values in SI units - * @data: pointer to the start of the scan - * @channels: information about the channels. - * Note: size_from_channelarray must have been called first - * to fill the location offsets. - * @num_channels: number of channels - **/ -void process_scan(char *data, - struct iio_channel_info *channels, - int num_channels) -{ - int k; - - for (k = 0; k < num_channels; k++) - switch (channels[k].bytes) { - /* only a few cases implemented so far */ - case 1: - print1byte(*(uint8_t *)(data + channels[k].location), - &channels[k]); - break; - case 2: - print2byte(*(uint16_t *)(data + channels[k].location), - &channels[k]); - break; - case 4: - print4byte(*(uint32_t *)(data + channels[k].location), - &channels[k]); - break; - case 8: - print8byte(*(uint64_t *)(data + channels[k].location), - &channels[k]); - break; - default: - break; - } - printf("\n"); -} - -static int enable_disable_all_channels(char *dev_dir_name, int enable) -{ - const struct dirent *ent; - char scanelemdir[256]; - DIR *dp; - int ret; - - snprintf(scanelemdir, sizeof(scanelemdir), - FORMAT_SCAN_ELEMENTS_DIR, dev_dir_name); - scanelemdir[sizeof(scanelemdir)-1] = '\0'; - - dp = opendir(scanelemdir); - if (!dp) { - fprintf(stderr, "Enabling/disabling channels: can't open %s\n", - scanelemdir); - return -EIO; - } - - ret = -ENOENT; - while (ent = readdir(dp), ent) { - if (iioutils_check_suffix(ent->d_name, "_en")) { - printf("%sabling: %s\n", - enable ? "En" : "Dis", - ent->d_name); - ret = write_sysfs_int(ent->d_name, scanelemdir, - enable); - if (ret < 0) - fprintf(stderr, "Failed to enable/disable %s\n", - ent->d_name); - } - } - - if (closedir(dp) == -1) { - perror("Enabling/disabling channels: " - "Failed to close directory"); - return -errno; - } - return 0; -} - -void print_usage(void) -{ - fprintf(stderr, "Usage: generic_buffer [options]...\n" - "Capture, convert and output data from IIO device buffer\n" - " -a Auto-activate all available channels\n" - " -c Do n conversions\n" - " -e Disable wait for event (new data)\n" - " -g Use trigger-less mode\n" - " -l Set buffer length to n samples\n" - " -n Set device name (mandatory)\n" - " -t Set trigger name\n" - " -w Set delay between reads in us (event-less mode)\n"); -} - -int main(int argc, char **argv) -{ - unsigned long num_loops = 2; - unsigned long timedelay = 1000000; - unsigned long buf_len = 128; - - int ret, c, i, j, toread; - int fp; - - int num_channels; - char *trigger_name = NULL, *device_name = NULL; - char *dev_dir_name, *buf_dir_name; - - int datardytrigger = 1; - char *data; - ssize_t read_size; - int dev_num, trig_num; - char *buffer_access; - int scan_size; - int noevents = 0; - int notrigger = 0; - enum autochan autochannels = AUTOCHANNELS_DISABLED; - char *dummy; - - struct iio_channel_info *channels; - - while ((c = getopt(argc, argv, "ac:egl:n:t:w:")) != -1) { - switch (c) { - case 'a': - autochannels = AUTOCHANNELS_ENABLED; - break; - case 'c': - errno = 0; - num_loops = strtoul(optarg, &dummy, 10); - if (errno) - return -errno; - - break; - case 'e': - noevents = 1; - break; - case 'g': - notrigger = 1; - break; - case 'l': - errno = 0; - buf_len = strtoul(optarg, &dummy, 10); - if (errno) - return -errno; - - break; - case 'n': - device_name = optarg; - break; - case 't': - trigger_name = optarg; - datardytrigger = 0; - break; - case 'w': - errno = 0; - timedelay = strtoul(optarg, &dummy, 10); - if (errno) - return -errno; - break; - case '?': - print_usage(); - return -1; - } - } - - if (!device_name) { - fprintf(stderr, "Device name not set\n"); - print_usage(); - return -1; - } - - /* Find the device requested */ - dev_num = find_type_by_name(device_name, "iio:device"); - if (dev_num < 0) { - fprintf(stderr, "Failed to find the %s\n", device_name); - return dev_num; - } - - printf("iio device number being used is %d\n", dev_num); - - ret = asprintf(&dev_dir_name, "%siio:device%d", iio_dir, dev_num); - if (ret < 0) - return -ENOMEM; - - if (!notrigger) { - if (!trigger_name) { - /* - * Build the trigger name. If it is device associated - * its name is _dev[n] where n matches - * the device number found above. - */ - ret = asprintf(&trigger_name, - "%s-dev%d", device_name, dev_num); - if (ret < 0) { - ret = -ENOMEM; - goto error_free_dev_dir_name; - } - } - - /* Look for this "-devN" trigger */ - trig_num = find_type_by_name(trigger_name, "trigger"); - if (trig_num < 0) { - /* OK try the simpler "-trigger" suffix instead */ - free(trigger_name); - ret = asprintf(&trigger_name, - "%s-trigger", device_name); - if (ret < 0) { - ret = -ENOMEM; - goto error_free_dev_dir_name; - } - } - - trig_num = find_type_by_name(trigger_name, "trigger"); - if (trig_num < 0) { - fprintf(stderr, "Failed to find the trigger %s\n", - trigger_name); - ret = trig_num; - goto error_free_triggername; - } - - printf("iio trigger number being used is %d\n", trig_num); - } else { - printf("trigger-less mode selected\n"); - } - - /* - * Parse the files in scan_elements to identify what channels are - * present - */ - ret = build_channel_array(dev_dir_name, &channels, &num_channels); - if (ret) { - fprintf(stderr, "Problem reading scan element information\n" - "diag %s\n", dev_dir_name); - goto error_free_triggername; - } - if (num_channels && autochannels == AUTOCHANNELS_ENABLED) { - fprintf(stderr, "Auto-channels selected but some channels " - "are already activated in sysfs\n"); - fprintf(stderr, "Proceeding without activating any channels\n"); - } - - if (!num_channels && autochannels == AUTOCHANNELS_ENABLED) { - fprintf(stderr, - "No channels are enabled, enabling all channels\n"); - - ret = enable_disable_all_channels(dev_dir_name, 1); - if (ret) { - fprintf(stderr, "Failed to enable all channels\n"); - goto error_free_triggername; - } - - /* This flags that we need to disable the channels again */ - autochannels = AUTOCHANNELS_ACTIVE; - - ret = build_channel_array(dev_dir_name, &channels, - &num_channels); - if (ret) { - fprintf(stderr, "Problem reading scan element " - "information\n" - "diag %s\n", dev_dir_name); - goto error_disable_channels; - } - if (!num_channels) { - fprintf(stderr, "Still no channels after " - "auto-enabling, giving up\n"); - goto error_disable_channels; - } - } - - if (!num_channels && autochannels == AUTOCHANNELS_DISABLED) { - fprintf(stderr, - "No channels are enabled, we have nothing to scan.\n"); - fprintf(stderr, "Enable channels manually in " - FORMAT_SCAN_ELEMENTS_DIR - "/*_en or pass -a to autoenable channels and " - "try again.\n", dev_dir_name); - ret = -ENOENT; - goto error_free_triggername; - } - - /* - * Construct the directory name for the associated buffer. - * As we know that the lis3l02dq has only one buffer this may - * be built rather than found. - */ - ret = asprintf(&buf_dir_name, - "%siio:device%d/buffer", iio_dir, dev_num); - if (ret < 0) { - ret = -ENOMEM; - goto error_free_channels; - } - - if (!notrigger) { - printf("%s %s\n", dev_dir_name, trigger_name); - /* - * Set the device trigger to be the data ready trigger found - * above - */ - ret = write_sysfs_string_and_verify("trigger/current_trigger", - dev_dir_name, - trigger_name); - if (ret < 0) { - fprintf(stderr, - "Failed to write current_trigger file\n"); - goto error_free_buf_dir_name; - } - } - - /* Setup ring buffer parameters */ - ret = write_sysfs_int("length", buf_dir_name, buf_len); - if (ret < 0) - goto error_free_buf_dir_name; - - /* Enable the buffer */ - ret = write_sysfs_int("enable", buf_dir_name, 1); - if (ret < 0) { - fprintf(stderr, - "Failed to enable buffer: %s\n", strerror(-ret)); - goto error_free_buf_dir_name; - } - - scan_size = size_from_channelarray(channels, num_channels); - data = malloc(scan_size * buf_len); - if (!data) { - ret = -ENOMEM; - goto error_free_buf_dir_name; - } - - ret = asprintf(&buffer_access, "/dev/iio:device%d", dev_num); - if (ret < 0) { - ret = -ENOMEM; - goto error_free_data; - } - - /* Attempt to open non blocking the access dev */ - fp = open(buffer_access, O_RDONLY | O_NONBLOCK); - if (fp == -1) { /* TODO: If it isn't there make the node */ - ret = -errno; - fprintf(stderr, "Failed to open %s\n", buffer_access); - goto error_free_buffer_access; - } - - for (j = 0; j < num_loops; j++) { - if (!noevents) { - struct pollfd pfd = { - .fd = fp, - .events = POLLIN, - }; - - ret = poll(&pfd, 1, -1); - if (ret < 0) { - ret = -errno; - goto error_close_buffer_access; - } else if (ret == 0) { - continue; - } - - toread = buf_len; - } else { - usleep(timedelay); - toread = 64; - } - - read_size = read(fp, data, toread * scan_size); - if (read_size < 0) { - if (errno == EAGAIN) { - fprintf(stderr, "nothing available\n"); - continue; - } else { - break; - } - } - for (i = 0; i < read_size / scan_size; i++) - process_scan(data + scan_size * i, channels, - num_channels); - } - - /* Stop the buffer */ - ret = write_sysfs_int("enable", buf_dir_name, 0); - if (ret < 0) - goto error_close_buffer_access; - - if (!notrigger) - /* Disconnect the trigger - just write a dummy name. */ - ret = write_sysfs_string("trigger/current_trigger", - dev_dir_name, "NULL"); - if (ret < 0) - fprintf(stderr, "Failed to write to %s\n", - dev_dir_name); - -error_close_buffer_access: - if (close(fp) == -1) - perror("Failed to close buffer"); - -error_free_buffer_access: - free(buffer_access); -error_free_data: - free(data); -error_free_buf_dir_name: - free(buf_dir_name); -error_free_channels: - for (i = num_channels - 1; i >= 0; i--) { - free(channels[i].name); - free(channels[i].generic_name); - } - free(channels); -error_free_triggername: - if (datardytrigger) - free(trigger_name); -error_disable_channels: - if (autochannels == AUTOCHANNELS_ACTIVE) { - ret = enable_disable_all_channels(dev_dir_name, 0); - if (ret) - fprintf(stderr, "Failed to disable all channels\n"); - } -error_free_dev_dir_name: - free(dev_dir_name); - - return ret; -} diff --git a/tools/iio/iio_generic_buffer.c b/tools/iio/iio_generic_buffer.c new file mode 100644 index 0000000..2429c78 --- /dev/null +++ b/tools/iio/iio_generic_buffer.c @@ -0,0 +1,581 @@ +/* Industrialio buffer test code. + * + * Copyright (c) 2008 Jonathan Cameron + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + * + * This program is primarily intended as an example application. + * Reads the current buffer setup from sysfs and starts a short capture + * from the specified device, pretty printing the result after appropriate + * conversion. + * + * Command line parameters + * generic_buffer -n -t + * If trigger name is not specified the program assumes you want a dataready + * trigger associated with the device and goes looking for it. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "iio_utils.h" + +/** + * enum autochan - state for the automatic channel enabling mechanism + */ +enum autochan { + AUTOCHANNELS_DISABLED, + AUTOCHANNELS_ENABLED, + AUTOCHANNELS_ACTIVE, +}; + +/** + * size_from_channelarray() - calculate the storage size of a scan + * @channels: the channel info array + * @num_channels: number of channels + * + * Has the side effect of filling the channels[i].location values used + * in processing the buffer output. + **/ +int size_from_channelarray(struct iio_channel_info *channels, int num_channels) +{ + int bytes = 0; + int i = 0; + + while (i < num_channels) { + if (bytes % channels[i].bytes == 0) + channels[i].location = bytes; + else + channels[i].location = bytes - bytes % channels[i].bytes + + channels[i].bytes; + + bytes = channels[i].location + channels[i].bytes; + i++; + } + + return bytes; +} + +void print1byte(uint8_t input, struct iio_channel_info *info) +{ + /* + * Shift before conversion to avoid sign extension + * of left aligned data + */ + input >>= info->shift; + input &= info->mask; + if (info->is_signed) { + int8_t val = (int8_t)(input << (8 - info->bits_used)) >> + (8 - info->bits_used); + printf("%05f ", ((float)val + info->offset) * info->scale); + } else { + printf("%05f ", ((float)input + info->offset) * info->scale); + } +} + +void print2byte(uint16_t input, struct iio_channel_info *info) +{ + /* First swap if incorrect endian */ + if (info->be) + input = be16toh(input); + else + input = le16toh(input); + + /* + * Shift before conversion to avoid sign extension + * of left aligned data + */ + input >>= info->shift; + input &= info->mask; + if (info->is_signed) { + int16_t val = (int16_t)(input << (16 - info->bits_used)) >> + (16 - info->bits_used); + printf("%05f ", ((float)val + info->offset) * info->scale); + } else { + printf("%05f ", ((float)input + info->offset) * info->scale); + } +} + +void print4byte(uint32_t input, struct iio_channel_info *info) +{ + /* First swap if incorrect endian */ + if (info->be) + input = be32toh(input); + else + input = le32toh(input); + + /* + * Shift before conversion to avoid sign extension + * of left aligned data + */ + input >>= info->shift; + input &= info->mask; + if (info->is_signed) { + int32_t val = (int32_t)(input << (32 - info->bits_used)) >> + (32 - info->bits_used); + printf("%05f ", ((float)val + info->offset) * info->scale); + } else { + printf("%05f ", ((float)input + info->offset) * info->scale); + } +} + +void print8byte(uint64_t input, struct iio_channel_info *info) +{ + /* First swap if incorrect endian */ + if (info->be) + input = be64toh(input); + else + input = le64toh(input); + + /* + * Shift before conversion to avoid sign extension + * of left aligned data + */ + input >>= info->shift; + input &= info->mask; + if (info->is_signed) { + int64_t val = (int64_t)(input << (64 - info->bits_used)) >> + (64 - info->bits_used); + /* special case for timestamp */ + if (info->scale == 1.0f && info->offset == 0.0f) + printf("%" PRId64 " ", val); + else + printf("%05f ", + ((float)val + info->offset) * info->scale); + } else { + printf("%05f ", ((float)input + info->offset) * info->scale); + } +} + +/** + * process_scan() - print out the values in SI units + * @data: pointer to the start of the scan + * @channels: information about the channels. + * Note: size_from_channelarray must have been called first + * to fill the location offsets. + * @num_channels: number of channels + **/ +void process_scan(char *data, + struct iio_channel_info *channels, + int num_channels) +{ + int k; + + for (k = 0; k < num_channels; k++) + switch (channels[k].bytes) { + /* only a few cases implemented so far */ + case 1: + print1byte(*(uint8_t *)(data + channels[k].location), + &channels[k]); + break; + case 2: + print2byte(*(uint16_t *)(data + channels[k].location), + &channels[k]); + break; + case 4: + print4byte(*(uint32_t *)(data + channels[k].location), + &channels[k]); + break; + case 8: + print8byte(*(uint64_t *)(data + channels[k].location), + &channels[k]); + break; + default: + break; + } + printf("\n"); +} + +static int enable_disable_all_channels(char *dev_dir_name, int enable) +{ + const struct dirent *ent; + char scanelemdir[256]; + DIR *dp; + int ret; + + snprintf(scanelemdir, sizeof(scanelemdir), + FORMAT_SCAN_ELEMENTS_DIR, dev_dir_name); + scanelemdir[sizeof(scanelemdir)-1] = '\0'; + + dp = opendir(scanelemdir); + if (!dp) { + fprintf(stderr, "Enabling/disabling channels: can't open %s\n", + scanelemdir); + return -EIO; + } + + ret = -ENOENT; + while (ent = readdir(dp), ent) { + if (iioutils_check_suffix(ent->d_name, "_en")) { + printf("%sabling: %s\n", + enable ? "En" : "Dis", + ent->d_name); + ret = write_sysfs_int(ent->d_name, scanelemdir, + enable); + if (ret < 0) + fprintf(stderr, "Failed to enable/disable %s\n", + ent->d_name); + } + } + + if (closedir(dp) == -1) { + perror("Enabling/disabling channels: " + "Failed to close directory"); + return -errno; + } + return 0; +} + +void print_usage(void) +{ + fprintf(stderr, "Usage: generic_buffer [options]...\n" + "Capture, convert and output data from IIO device buffer\n" + " -a Auto-activate all available channels\n" + " -c Do n conversions\n" + " -e Disable wait for event (new data)\n" + " -g Use trigger-less mode\n" + " -l Set buffer length to n samples\n" + " -n Set device name (mandatory)\n" + " -t Set trigger name\n" + " -w Set delay between reads in us (event-less mode)\n"); +} + +int main(int argc, char **argv) +{ + unsigned long num_loops = 2; + unsigned long timedelay = 1000000; + unsigned long buf_len = 128; + + int ret, c, i, j, toread; + int fp; + + int num_channels; + char *trigger_name = NULL, *device_name = NULL; + char *dev_dir_name, *buf_dir_name; + + int datardytrigger = 1; + char *data; + ssize_t read_size; + int dev_num, trig_num; + char *buffer_access; + int scan_size; + int noevents = 0; + int notrigger = 0; + enum autochan autochannels = AUTOCHANNELS_DISABLED; + char *dummy; + + struct iio_channel_info *channels; + + while ((c = getopt(argc, argv, "ac:egl:n:t:w:")) != -1) { + switch (c) { + case 'a': + autochannels = AUTOCHANNELS_ENABLED; + break; + case 'c': + errno = 0; + num_loops = strtoul(optarg, &dummy, 10); + if (errno) + return -errno; + + break; + case 'e': + noevents = 1; + break; + case 'g': + notrigger = 1; + break; + case 'l': + errno = 0; + buf_len = strtoul(optarg, &dummy, 10); + if (errno) + return -errno; + + break; + case 'n': + device_name = optarg; + break; + case 't': + trigger_name = optarg; + datardytrigger = 0; + break; + case 'w': + errno = 0; + timedelay = strtoul(optarg, &dummy, 10); + if (errno) + return -errno; + break; + case '?': + print_usage(); + return -1; + } + } + + if (!device_name) { + fprintf(stderr, "Device name not set\n"); + print_usage(); + return -1; + } + + /* Find the device requested */ + dev_num = find_type_by_name(device_name, "iio:device"); + if (dev_num < 0) { + fprintf(stderr, "Failed to find the %s\n", device_name); + return dev_num; + } + + printf("iio device number being used is %d\n", dev_num); + + ret = asprintf(&dev_dir_name, "%siio:device%d", iio_dir, dev_num); + if (ret < 0) + return -ENOMEM; + + if (!notrigger) { + if (!trigger_name) { + /* + * Build the trigger name. If it is device associated + * its name is _dev[n] where n matches + * the device number found above. + */ + ret = asprintf(&trigger_name, + "%s-dev%d", device_name, dev_num); + if (ret < 0) { + ret = -ENOMEM; + goto error_free_dev_dir_name; + } + } + + /* Look for this "-devN" trigger */ + trig_num = find_type_by_name(trigger_name, "trigger"); + if (trig_num < 0) { + /* OK try the simpler "-trigger" suffix instead */ + free(trigger_name); + ret = asprintf(&trigger_name, + "%s-trigger", device_name); + if (ret < 0) { + ret = -ENOMEM; + goto error_free_dev_dir_name; + } + } + + trig_num = find_type_by_name(trigger_name, "trigger"); + if (trig_num < 0) { + fprintf(stderr, "Failed to find the trigger %s\n", + trigger_name); + ret = trig_num; + goto error_free_triggername; + } + + printf("iio trigger number being used is %d\n", trig_num); + } else { + printf("trigger-less mode selected\n"); + } + + /* + * Parse the files in scan_elements to identify what channels are + * present + */ + ret = build_channel_array(dev_dir_name, &channels, &num_channels); + if (ret) { + fprintf(stderr, "Problem reading scan element information\n" + "diag %s\n", dev_dir_name); + goto error_free_triggername; + } + if (num_channels && autochannels == AUTOCHANNELS_ENABLED) { + fprintf(stderr, "Auto-channels selected but some channels " + "are already activated in sysfs\n"); + fprintf(stderr, "Proceeding without activating any channels\n"); + } + + if (!num_channels && autochannels == AUTOCHANNELS_ENABLED) { + fprintf(stderr, + "No channels are enabled, enabling all channels\n"); + + ret = enable_disable_all_channels(dev_dir_name, 1); + if (ret) { + fprintf(stderr, "Failed to enable all channels\n"); + goto error_free_triggername; + } + + /* This flags that we need to disable the channels again */ + autochannels = AUTOCHANNELS_ACTIVE; + + ret = build_channel_array(dev_dir_name, &channels, + &num_channels); + if (ret) { + fprintf(stderr, "Problem reading scan element " + "information\n" + "diag %s\n", dev_dir_name); + goto error_disable_channels; + } + if (!num_channels) { + fprintf(stderr, "Still no channels after " + "auto-enabling, giving up\n"); + goto error_disable_channels; + } + } + + if (!num_channels && autochannels == AUTOCHANNELS_DISABLED) { + fprintf(stderr, + "No channels are enabled, we have nothing to scan.\n"); + fprintf(stderr, "Enable channels manually in " + FORMAT_SCAN_ELEMENTS_DIR + "/*_en or pass -a to autoenable channels and " + "try again.\n", dev_dir_name); + ret = -ENOENT; + goto error_free_triggername; + } + + /* + * Construct the directory name for the associated buffer. + * As we know that the lis3l02dq has only one buffer this may + * be built rather than found. + */ + ret = asprintf(&buf_dir_name, + "%siio:device%d/buffer", iio_dir, dev_num); + if (ret < 0) { + ret = -ENOMEM; + goto error_free_channels; + } + + if (!notrigger) { + printf("%s %s\n", dev_dir_name, trigger_name); + /* + * Set the device trigger to be the data ready trigger found + * above + */ + ret = write_sysfs_string_and_verify("trigger/current_trigger", + dev_dir_name, + trigger_name); + if (ret < 0) { + fprintf(stderr, + "Failed to write current_trigger file\n"); + goto error_free_buf_dir_name; + } + } + + /* Setup ring buffer parameters */ + ret = write_sysfs_int("length", buf_dir_name, buf_len); + if (ret < 0) + goto error_free_buf_dir_name; + + /* Enable the buffer */ + ret = write_sysfs_int("enable", buf_dir_name, 1); + if (ret < 0) { + fprintf(stderr, + "Failed to enable buffer: %s\n", strerror(-ret)); + goto error_free_buf_dir_name; + } + + scan_size = size_from_channelarray(channels, num_channels); + data = malloc(scan_size * buf_len); + if (!data) { + ret = -ENOMEM; + goto error_free_buf_dir_name; + } + + ret = asprintf(&buffer_access, "/dev/iio:device%d", dev_num); + if (ret < 0) { + ret = -ENOMEM; + goto error_free_data; + } + + /* Attempt to open non blocking the access dev */ + fp = open(buffer_access, O_RDONLY | O_NONBLOCK); + if (fp == -1) { /* TODO: If it isn't there make the node */ + ret = -errno; + fprintf(stderr, "Failed to open %s\n", buffer_access); + goto error_free_buffer_access; + } + + for (j = 0; j < num_loops; j++) { + if (!noevents) { + struct pollfd pfd = { + .fd = fp, + .events = POLLIN, + }; + + ret = poll(&pfd, 1, -1); + if (ret < 0) { + ret = -errno; + goto error_close_buffer_access; + } else if (ret == 0) { + continue; + } + + toread = buf_len; + } else { + usleep(timedelay); + toread = 64; + } + + read_size = read(fp, data, toread * scan_size); + if (read_size < 0) { + if (errno == EAGAIN) { + fprintf(stderr, "nothing available\n"); + continue; + } else { + break; + } + } + for (i = 0; i < read_size / scan_size; i++) + process_scan(data + scan_size * i, channels, + num_channels); + } + + /* Stop the buffer */ + ret = write_sysfs_int("enable", buf_dir_name, 0); + if (ret < 0) + goto error_close_buffer_access; + + if (!notrigger) + /* Disconnect the trigger - just write a dummy name. */ + ret = write_sysfs_string("trigger/current_trigger", + dev_dir_name, "NULL"); + if (ret < 0) + fprintf(stderr, "Failed to write to %s\n", + dev_dir_name); + +error_close_buffer_access: + if (close(fp) == -1) + perror("Failed to close buffer"); + +error_free_buffer_access: + free(buffer_access); +error_free_data: + free(data); +error_free_buf_dir_name: + free(buf_dir_name); +error_free_channels: + for (i = num_channels - 1; i >= 0; i--) { + free(channels[i].name); + free(channels[i].generic_name); + } + free(channels); +error_free_triggername: + if (datardytrigger) + free(trigger_name); +error_disable_channels: + if (autochannels == AUTOCHANNELS_ACTIVE) { + ret = enable_disable_all_channels(dev_dir_name, 0); + if (ret) + fprintf(stderr, "Failed to disable all channels\n"); + } +error_free_dev_dir_name: + free(dev_dir_name); + + return ret; +} -- cgit v0.10.2 From 7103b99b031cb0ff6979331757bfc4893f37ae9e Mon Sep 17 00:00:00 2001 From: Matt Ranostay Date: Tue, 24 May 2016 21:29:18 -0700 Subject: iio: chemical: atlas-ph-sensor: reorg driver to allow multiple chips Signed-off-by: Matt Ranostay Signed-off-by: Jonathan Cameron diff --git a/drivers/iio/chemical/atlas-ph-sensor.c b/drivers/iio/chemical/atlas-ph-sensor.c index 62b37cd..e85477c 100644 --- a/drivers/iio/chemical/atlas-ph-sensor.c +++ b/drivers/iio/chemical/atlas-ph-sensor.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -43,20 +44,25 @@ #define ATLAS_REG_PWR_CONTROL 0x06 -#define ATLAS_REG_CALIB_STATUS 0x0d -#define ATLAS_REG_CALIB_STATUS_MASK 0x07 -#define ATLAS_REG_CALIB_STATUS_LOW BIT(0) -#define ATLAS_REG_CALIB_STATUS_MID BIT(1) -#define ATLAS_REG_CALIB_STATUS_HIGH BIT(2) +#define ATLAS_REG_PH_CALIB_STATUS 0x0d +#define ATLAS_REG_PH_CALIB_STATUS_MASK 0x07 +#define ATLAS_REG_PH_CALIB_STATUS_LOW BIT(0) +#define ATLAS_REG_PH_CALIB_STATUS_MID BIT(1) +#define ATLAS_REG_PH_CALIB_STATUS_HIGH BIT(2) -#define ATLAS_REG_TEMP_DATA 0x0e +#define ATLAS_REG_PH_TEMP_DATA 0x0e #define ATLAS_REG_PH_DATA 0x16 #define ATLAS_PH_INT_TIME_IN_US 450000 +enum { + ATLAS_PH_SM, +}; + struct atlas_data { struct i2c_client *client; struct iio_trigger *trig; + struct atlas_device *chip; struct regmap *regmap; struct irq_work work; @@ -84,9 +90,10 @@ static const struct regmap_config atlas_regmap_config = { .cache_type = REGCACHE_RBTREE, }; -static const struct iio_chan_spec atlas_channels[] = { +static const struct iio_chan_spec atlas_ph_channels[] = { { .type = IIO_PH, + .address = ATLAS_REG_PH_DATA, .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE), .scan_index = 0, @@ -100,7 +107,7 @@ static const struct iio_chan_spec atlas_channels[] = { IIO_CHAN_SOFT_TIMESTAMP(1), { .type = IIO_TEMP, - .address = ATLAS_REG_TEMP_DATA, + .address = ATLAS_REG_PH_TEMP_DATA, .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE), .output = 1, @@ -108,6 +115,52 @@ static const struct iio_chan_spec atlas_channels[] = { }, }; +static int atlas_check_ph_calibration(struct atlas_data *data) +{ + struct device *dev = &data->client->dev; + int ret; + unsigned int val; + + ret = regmap_read(data->regmap, ATLAS_REG_PH_CALIB_STATUS, &val); + if (ret) + return ret; + + if (!(val & ATLAS_REG_PH_CALIB_STATUS_MASK)) { + dev_warn(dev, "device has not been calibrated\n"); + return 0; + } + + if (!(val & ATLAS_REG_PH_CALIB_STATUS_LOW)) + dev_warn(dev, "device missing low point calibration\n"); + + if (!(val & ATLAS_REG_PH_CALIB_STATUS_MID)) + dev_warn(dev, "device missing mid point calibration\n"); + + if (!(val & ATLAS_REG_PH_CALIB_STATUS_HIGH)) + dev_warn(dev, "device missing high point calibration\n"); + + return 0; +} + +struct atlas_device { + const struct iio_chan_spec *channels; + int num_channels; + int data_reg; + + int (*calibration)(struct atlas_data *data); + int delay; +}; + +static struct atlas_device atlas_devices[] = { + [ATLAS_PH_SM] = { + .channels = atlas_ph_channels, + .num_channels = 3, + .data_reg = ATLAS_REG_PH_DATA, + .calibration = &atlas_check_ph_calibration, + .delay = ATLAS_PH_INT_TIME_IN_US, + }, +}; + static int atlas_set_powermode(struct atlas_data *data, int on) { return regmap_write(data->regmap, ATLAS_REG_PWR_CONTROL, on); @@ -178,8 +231,9 @@ static irqreturn_t atlas_trigger_handler(int irq, void *private) struct atlas_data *data = iio_priv(indio_dev); int ret; - ret = regmap_bulk_read(data->regmap, ATLAS_REG_PH_DATA, - (u8 *) &data->buffer, sizeof(data->buffer[0])); + ret = regmap_bulk_read(data->regmap, data->chip->data_reg, + (u8 *) &data->buffer, + sizeof(__be32) * (data->chip->num_channels - 2)); if (!ret) iio_push_to_buffers_with_timestamp(indio_dev, data->buffer, @@ -200,7 +254,7 @@ static irqreturn_t atlas_interrupt_handler(int irq, void *private) return IRQ_HANDLED; } -static int atlas_read_ph_measurement(struct atlas_data *data, __be32 *val) +static int atlas_read_measurement(struct atlas_data *data, int reg, __be32 *val) { struct device *dev = &data->client->dev; int suspended = pm_runtime_suspended(dev); @@ -213,11 +267,9 @@ static int atlas_read_ph_measurement(struct atlas_data *data, __be32 *val) } if (suspended) - usleep_range(ATLAS_PH_INT_TIME_IN_US, - ATLAS_PH_INT_TIME_IN_US + 100000); + usleep_range(data->chip->delay, data->chip->delay + 100000); - ret = regmap_bulk_read(data->regmap, ATLAS_REG_PH_DATA, - (u8 *) val, sizeof(*val)); + ret = regmap_bulk_read(data->regmap, reg, (u8 *) val, sizeof(*val)); pm_runtime_mark_last_busy(dev); pm_runtime_put_autosuspend(dev); @@ -247,7 +299,8 @@ static int atlas_read_raw(struct iio_dev *indio_dev, if (iio_buffer_enabled(indio_dev)) ret = -EBUSY; else - ret = atlas_read_ph_measurement(data, ®); + ret = atlas_read_measurement(data, + chan->address, ®); mutex_unlock(&indio_dev->mlock); break; @@ -303,37 +356,24 @@ static const struct iio_info atlas_info = { .write_raw = atlas_write_raw, }; -static int atlas_check_calibration(struct atlas_data *data) -{ - struct device *dev = &data->client->dev; - int ret; - unsigned int val; - - ret = regmap_read(data->regmap, ATLAS_REG_CALIB_STATUS, &val); - if (ret) - return ret; - - if (!(val & ATLAS_REG_CALIB_STATUS_MASK)) { - dev_warn(dev, "device has not been calibrated\n"); - return 0; - } - - if (!(val & ATLAS_REG_CALIB_STATUS_LOW)) - dev_warn(dev, "device missing low point calibration\n"); - - if (!(val & ATLAS_REG_CALIB_STATUS_MID)) - dev_warn(dev, "device missing mid point calibration\n"); - - if (!(val & ATLAS_REG_CALIB_STATUS_HIGH)) - dev_warn(dev, "device missing high point calibration\n"); +static const struct i2c_device_id atlas_id[] = { + { "atlas-ph-sm", ATLAS_PH_SM}, + {} +}; +MODULE_DEVICE_TABLE(i2c, atlas_id); - return 0; +static const struct of_device_id atlas_dt_ids[] = { + { .compatible = "atlas,ph-sm", .data = (void *)ATLAS_PH_SM, }, + { } }; +MODULE_DEVICE_TABLE(of, atlas_dt_ids); static int atlas_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct atlas_data *data; + struct atlas_device *chip; + const struct of_device_id *of_id; struct iio_trigger *trig; struct iio_dev *indio_dev; int ret; @@ -342,10 +382,16 @@ static int atlas_probe(struct i2c_client *client, if (!indio_dev) return -ENOMEM; + of_id = of_match_device(atlas_dt_ids, &client->dev); + if (!of_id) + chip = &atlas_devices[id->driver_data]; + else + chip = &atlas_devices[(unsigned long)of_id->data]; + indio_dev->info = &atlas_info; indio_dev->name = ATLAS_DRV_NAME; - indio_dev->channels = atlas_channels; - indio_dev->num_channels = ARRAY_SIZE(atlas_channels); + indio_dev->channels = chip->channels; + indio_dev->num_channels = chip->num_channels; indio_dev->modes = INDIO_BUFFER_SOFTWARE | INDIO_DIRECT_MODE; indio_dev->dev.parent = &client->dev; @@ -358,6 +404,7 @@ static int atlas_probe(struct i2c_client *client, data = iio_priv(indio_dev); data->client = client; data->trig = trig; + data->chip = chip; trig->dev.parent = indio_dev->dev.parent; trig->ops = &atlas_interrupt_trigger_ops; iio_trigger_set_drvdata(trig, indio_dev); @@ -379,7 +426,7 @@ static int atlas_probe(struct i2c_client *client, return -EINVAL; } - ret = atlas_check_calibration(data); + ret = chip->calibration(data); if (ret) return ret; @@ -480,18 +527,6 @@ static const struct dev_pm_ops atlas_pm_ops = { atlas_runtime_resume, NULL) }; -static const struct i2c_device_id atlas_id[] = { - { "atlas-ph-sm", 0 }, - {} -}; -MODULE_DEVICE_TABLE(i2c, atlas_id); - -static const struct of_device_id atlas_dt_ids[] = { - { .compatible = "atlas,ph-sm" }, - { } -}; -MODULE_DEVICE_TABLE(of, atlas_dt_ids); - static struct i2c_driver atlas_driver = { .driver = { .name = ATLAS_DRV_NAME, -- cgit v0.10.2 From 4b9d2090a444d44f16788b9ad60180011d133f97 Mon Sep 17 00:00:00 2001 From: Matt Ranostay Date: Tue, 24 May 2016 21:29:19 -0700 Subject: iio: electricalconductivity: add IIO_ELECTRICALCONDUCTIVITY type Signed-off-by: Matt Ranostay Signed-off-by: Jonathan Cameron diff --git a/Documentation/ABI/testing/sysfs-bus-iio b/Documentation/ABI/testing/sysfs-bus-iio index df44998..e7f590c 100644 --- a/Documentation/ABI/testing/sysfs-bus-iio +++ b/Documentation/ABI/testing/sysfs-bus-iio @@ -1565,3 +1565,10 @@ Description: * X is in the plane of the propellers, perpendicular to Y axis, and positive towards the starboard side of the UAV ; * Z is perpendicular to propellers plane and positive upwards. + +What: /sys/bus/iio/devices/iio:deviceX/in_electricalconductivity_raw +KernelVersion: 4.8 +Contact: linux-iio@vger.kernel.org +Description: + Raw (unscaled no offset etc.) electric conductivity reading that + can be processed to siemens per meter. diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c index e6319a9..2a85bd8 100644 --- a/drivers/iio/industrialio-core.c +++ b/drivers/iio/industrialio-core.c @@ -80,6 +80,7 @@ static const char * const iio_chan_type_name_spec[] = { [IIO_RESISTANCE] = "resistance", [IIO_PH] = "ph", [IIO_UVINDEX] = "uvindex", + [IIO_ELECTRICALCONDUCTIVITY] = "electricalconductivity", }; static const char * const iio_modifier_names[] = { diff --git a/include/uapi/linux/iio/types.h b/include/uapi/linux/iio/types.h index b0916fc..22e5e58 100644 --- a/include/uapi/linux/iio/types.h +++ b/include/uapi/linux/iio/types.h @@ -39,6 +39,7 @@ enum iio_chan_type { IIO_RESISTANCE, IIO_PH, IIO_UVINDEX, + IIO_ELECTRICALCONDUCTIVITY, }; enum iio_modifier { -- cgit v0.10.2 From e8dd92bfbff2516f3e76bf08f38131c522454edd Mon Sep 17 00:00:00 2001 From: Matt Ranostay Date: Tue, 24 May 2016 21:29:20 -0700 Subject: iio: chemical: atlas-ph-sensor: add EC feature Signed-off-by: Matt Ranostay Signed-off-by: Jonathan Cameron diff --git a/Documentation/devicetree/bindings/iio/chemical/atlas,ec-sm.txt b/Documentation/devicetree/bindings/iio/chemical/atlas,ec-sm.txt new file mode 100644 index 0000000..2962bd9 --- /dev/null +++ b/Documentation/devicetree/bindings/iio/chemical/atlas,ec-sm.txt @@ -0,0 +1,22 @@ +* Atlas Scientific EC-SM OEM sensor + +http://www.atlas-scientific.com/_files/_datasheets/_oem/EC_oem_datasheet.pdf + +Required properties: + + - compatible: must be "atlas,ec-sm" + - reg: the I2C address of the sensor + - interrupt-parent: should be the phandle for the interrupt controller + - interrupts: the sole interrupt generated by the device + + Refer to interrupt-controller/interrupts.txt for generic interrupt client + node bindings. + +Example: + +atlas@64 { + compatible = "atlas,ec-sm"; + reg = <0x64>; + interrupt-parent = <&gpio1>; + interrupts = <16 2>; +}; diff --git a/drivers/iio/chemical/Kconfig b/drivers/iio/chemical/Kconfig index f73290f..4bcc025 100644 --- a/drivers/iio/chemical/Kconfig +++ b/drivers/iio/chemical/Kconfig @@ -5,15 +5,17 @@ menu "Chemical Sensors" config ATLAS_PH_SENSOR - tristate "Atlas Scientific OEM pH-SM sensor" + tristate "Atlas Scientific OEM SM sensors" depends on I2C select REGMAP_I2C select IIO_BUFFER select IIO_TRIGGERED_BUFFER select IRQ_WORK help - Say Y here to build I2C interface support for the Atlas - Scientific OEM pH-SM sensor. + Say Y here to build I2C interface support for the following + Atlas Scientific OEM SM sensors: + * pH SM sensor + * EC SM sensor To compile this driver as module, choose M here: the module will be called atlas-ph-sensor. diff --git a/drivers/iio/chemical/atlas-ph-sensor.c b/drivers/iio/chemical/atlas-ph-sensor.c index e85477c..02e85db 100644 --- a/drivers/iio/chemical/atlas-ph-sensor.c +++ b/drivers/iio/chemical/atlas-ph-sensor.c @@ -50,13 +50,28 @@ #define ATLAS_REG_PH_CALIB_STATUS_MID BIT(1) #define ATLAS_REG_PH_CALIB_STATUS_HIGH BIT(2) +#define ATLAS_REG_EC_CALIB_STATUS 0x0f +#define ATLAS_REG_EC_CALIB_STATUS_MASK 0x0f +#define ATLAS_REG_EC_CALIB_STATUS_DRY BIT(0) +#define ATLAS_REG_EC_CALIB_STATUS_SINGLE BIT(1) +#define ATLAS_REG_EC_CALIB_STATUS_LOW BIT(2) +#define ATLAS_REG_EC_CALIB_STATUS_HIGH BIT(3) + #define ATLAS_REG_PH_TEMP_DATA 0x0e #define ATLAS_REG_PH_DATA 0x16 +#define ATLAS_REG_EC_PROBE 0x08 +#define ATLAS_REG_EC_TEMP_DATA 0x10 +#define ATLAS_REG_EC_DATA 0x18 +#define ATLAS_REG_TDS_DATA 0x1c +#define ATLAS_REG_PSS_DATA 0x20 + #define ATLAS_PH_INT_TIME_IN_US 450000 +#define ATLAS_EC_INT_TIME_IN_US 650000 enum { ATLAS_PH_SM, + ATLAS_EC_SM, }; struct atlas_data { @@ -66,12 +81,13 @@ struct atlas_data { struct regmap *regmap; struct irq_work work; - __be32 buffer[4]; /* 32-bit pH data + 32-bit pad + 64-bit timestamp */ + __be32 buffer[6]; /* 96-bit data + 32-bit pad + 64-bit timestamp */ }; static const struct regmap_range atlas_volatile_ranges[] = { regmap_reg_range(ATLAS_REG_INT_CONTROL, ATLAS_REG_INT_CONTROL), regmap_reg_range(ATLAS_REG_PH_DATA, ATLAS_REG_PH_DATA + 4), + regmap_reg_range(ATLAS_REG_EC_DATA, ATLAS_REG_PSS_DATA + 4), }; static const struct regmap_access_table atlas_volatile_table = { @@ -86,7 +102,7 @@ static const struct regmap_config atlas_regmap_config = { .val_bits = 8, .volatile_table = &atlas_volatile_table, - .max_register = ATLAS_REG_PH_DATA + 4, + .max_register = ATLAS_REG_PSS_DATA + 4, .cache_type = REGCACHE_RBTREE, }; @@ -115,6 +131,50 @@ static const struct iio_chan_spec atlas_ph_channels[] = { }, }; +#define ATLAS_EC_CHANNEL(_idx, _addr) \ + {\ + .type = IIO_CONCENTRATION, \ + .indexed = 1, \ + .channel = _idx, \ + .address = _addr, \ + .info_mask_separate = \ + BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE), \ + .scan_index = _idx + 1, \ + .scan_type = { \ + .sign = 'u', \ + .realbits = 32, \ + .storagebits = 32, \ + .endianness = IIO_BE, \ + }, \ + } + +static const struct iio_chan_spec atlas_ec_channels[] = { + { + .type = IIO_ELECTRICALCONDUCTIVITY, + .address = ATLAS_REG_EC_DATA, + .info_mask_separate = + BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE), + .scan_index = 0, + .scan_type = { + .sign = 'u', + .realbits = 32, + .storagebits = 32, + .endianness = IIO_BE, + }, + }, + ATLAS_EC_CHANNEL(0, ATLAS_REG_TDS_DATA), + ATLAS_EC_CHANNEL(1, ATLAS_REG_PSS_DATA), + IIO_CHAN_SOFT_TIMESTAMP(3), + { + .type = IIO_TEMP, + .address = ATLAS_REG_EC_TEMP_DATA, + .info_mask_separate = + BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE), + .output = 1, + .scan_index = -1 + }, +}; + static int atlas_check_ph_calibration(struct atlas_data *data) { struct device *dev = &data->client->dev; @@ -142,6 +202,44 @@ static int atlas_check_ph_calibration(struct atlas_data *data) return 0; } +static int atlas_check_ec_calibration(struct atlas_data *data) +{ + struct device *dev = &data->client->dev; + int ret; + unsigned int val; + + ret = regmap_bulk_read(data->regmap, ATLAS_REG_EC_PROBE, &val, 2); + if (ret) + return ret; + + dev_info(dev, "probe set to K = %d.%.2d", be16_to_cpu(val) / 100, + be16_to_cpu(val) % 100); + + ret = regmap_read(data->regmap, ATLAS_REG_EC_CALIB_STATUS, &val); + if (ret) + return ret; + + if (!(val & ATLAS_REG_EC_CALIB_STATUS_MASK)) { + dev_warn(dev, "device has not been calibrated\n"); + return 0; + } + + if (!(val & ATLAS_REG_EC_CALIB_STATUS_DRY)) + dev_warn(dev, "device missing dry point calibration\n"); + + if (val & ATLAS_REG_EC_CALIB_STATUS_SINGLE) { + dev_warn(dev, "device using single point calibration\n"); + } else { + if (!(val & ATLAS_REG_EC_CALIB_STATUS_LOW)) + dev_warn(dev, "device missing low point calibration\n"); + + if (!(val & ATLAS_REG_EC_CALIB_STATUS_HIGH)) + dev_warn(dev, "device missing high point calibration\n"); + } + + return 0; +} + struct atlas_device { const struct iio_chan_spec *channels; int num_channels; @@ -159,6 +257,14 @@ static struct atlas_device atlas_devices[] = { .calibration = &atlas_check_ph_calibration, .delay = ATLAS_PH_INT_TIME_IN_US, }, + [ATLAS_EC_SM] = { + .channels = atlas_ec_channels, + .num_channels = 5, + .data_reg = ATLAS_REG_EC_DATA, + .calibration = &atlas_check_ec_calibration, + .delay = ATLAS_EC_INT_TIME_IN_US, + }, + }; static int atlas_set_powermode(struct atlas_data *data, int on) @@ -294,6 +400,8 @@ static int atlas_read_raw(struct iio_dev *indio_dev, (u8 *) ®, sizeof(reg)); break; case IIO_PH: + case IIO_CONCENTRATION: + case IIO_ELECTRICALCONDUCTIVITY: mutex_lock(&indio_dev->mlock); if (iio_buffer_enabled(indio_dev)) @@ -324,6 +432,14 @@ static int atlas_read_raw(struct iio_dev *indio_dev, *val = 1; /* 0.001 */ *val2 = 1000; break; + case IIO_ELECTRICALCONDUCTIVITY: + *val = 1; /* 0.00001 */ + *val = 100000; + break; + case IIO_CONCENTRATION: + *val = 0; /* 0.000000001 */ + *val2 = 1000; + return IIO_VAL_INT_PLUS_NANO; default: return -EINVAL; } @@ -358,12 +474,14 @@ static const struct iio_info atlas_info = { static const struct i2c_device_id atlas_id[] = { { "atlas-ph-sm", ATLAS_PH_SM}, + { "atlas-ec-sm", ATLAS_EC_SM}, {} }; MODULE_DEVICE_TABLE(i2c, atlas_id); static const struct of_device_id atlas_dt_ids[] = { { .compatible = "atlas,ph-sm", .data = (void *)ATLAS_PH_SM, }, + { .compatible = "atlas,ec-sm", .data = (void *)ATLAS_EC_SM, }, { } }; MODULE_DEVICE_TABLE(of, atlas_dt_ids); -- cgit v0.10.2 From 0aea7ac8548a9cda7a5003b39fe9b6031f0c19e0 Mon Sep 17 00:00:00 2001 From: Daniel Baluta Date: Tue, 24 May 2016 15:42:28 +0300 Subject: iio: magnetometer: bmc150: Document Bosch supported chips bmc150 driver supports also BMC156 and BMM150 chips. Signed-off-by: Daniel Baluta Signed-off-by: Jonathan Cameron diff --git a/drivers/iio/magnetometer/Kconfig b/drivers/iio/magnetometer/Kconfig index 84e6559..1f842ab 100644 --- a/drivers/iio/magnetometer/Kconfig +++ b/drivers/iio/magnetometer/Kconfig @@ -44,6 +44,7 @@ config BMC150_MAGN_I2C This driver is only implementing magnetometer part, which has its own address and register map. + This driver also supports I2C Bosch BMC156 and BMM150 chips. To compile this driver as a module, choose M here: the module will be called bmc150_magn_i2c. @@ -60,6 +61,7 @@ config BMC150_MAGN_SPI This driver is only implementing magnetometer part, which has its own address and register map. + This driver also supports SPI Bosch BMC156 and BMM150 chips. To compile this driver as a module, choose M here: the module will be called bmc150_magn_spi. -- cgit v0.10.2 From 90e9a9500f16e60bf96c95cd6b74f84d56e12ef0 Mon Sep 17 00:00:00 2001 From: Matt Ranostay Date: Mon, 23 May 2016 23:27:30 -0700 Subject: iio: proximity: as3935: remove redundant MODULE_ALIAS MODULE_ALIAS isn't needed since the module name is the same as the alias defined. Signed-off-by: Matt Ranostay Signed-off-by: Jonathan Cameron diff --git a/drivers/iio/proximity/as3935.c b/drivers/iio/proximity/as3935.c index f4d29d5..c12fde2 100644 --- a/drivers/iio/proximity/as3935.c +++ b/drivers/iio/proximity/as3935.c @@ -461,4 +461,3 @@ module_spi_driver(as3935_driver); MODULE_AUTHOR("Matt Ranostay "); MODULE_DESCRIPTION("AS3935 lightning sensor"); MODULE_LICENSE("GPL"); -MODULE_ALIAS("spi:as3935"); -- cgit v0.10.2 From 4f20d5927b8e900ff1c3ee590b700ca71cd3f3ca Mon Sep 17 00:00:00 2001 From: Crestez Dan Leonard Date: Mon, 23 May 2016 21:39:56 +0300 Subject: iio: iio_generic_buffer: Cleanup when receiving signals This will clean (disable buffer/trigger/channels) when doing something like a CTRL-C. Otherwise restarting generic_buffer requires a manual echo 0 > buffer/enable This also cleanup up all the code freeing string buffers at the end of main. We initialize all pointers to NULL so that cleanup can all be done under a single error label. Signed-off-by: Crestez Dan Leonard Signed-off-by: Jonathan Cameron diff --git a/tools/iio/iio_generic_buffer.c b/tools/iio/iio_generic_buffer.c index 2429c78..972f400 100644 --- a/tools/iio/iio_generic_buffer.c +++ b/tools/iio/iio_generic_buffer.c @@ -32,6 +32,8 @@ #include #include #include +#include +#include #include "iio_utils.h" /** @@ -254,6 +256,65 @@ void print_usage(void) " -w Set delay between reads in us (event-less mode)\n"); } +enum autochan autochannels = AUTOCHANNELS_DISABLED; +char *dev_dir_name = NULL; +char *buf_dir_name = NULL; +bool current_trigger_set = false; + +void cleanup(void) +{ + int ret; + + /* Disable trigger */ + if (dev_dir_name && current_trigger_set) { + /* Disconnect the trigger - just write a dummy name. */ + ret = write_sysfs_string("trigger/current_trigger", + dev_dir_name, "NULL"); + if (ret < 0) + fprintf(stderr, "Failed to disable trigger: %s\n", + strerror(-ret)); + current_trigger_set = false; + } + + /* Disable buffer */ + if (buf_dir_name) { + ret = write_sysfs_int("enable", buf_dir_name, 0); + if (ret < 0) + fprintf(stderr, "Failed to disable buffer: %s\n", + strerror(-ret)); + } + + /* Disable channels if auto-enabled */ + if (dev_dir_name && autochannels == AUTOCHANNELS_ACTIVE) { + ret = enable_disable_all_channels(dev_dir_name, 0); + if (ret) + fprintf(stderr, "Failed to disable all channels\n"); + autochannels = AUTOCHANNELS_DISABLED; + } +} + +void sig_handler(int signum) +{ + fprintf(stderr, "Caught signal %d\n", signum); + cleanup(); + exit(-signum); +} + +void register_cleanup(void) +{ + struct sigaction sa = { .sa_handler = sig_handler }; + const int signums[] = { SIGINT, SIGTERM, SIGABRT }; + int ret, i; + + for (i = 0; i < ARRAY_SIZE(signums); ++i) { + ret = sigaction(signums[i], &sa, NULL); + if (ret) { + perror("Failed to register signal handler"); + exit(-1); + } + } +} + int main(int argc, char **argv) { unsigned long num_loops = 2; @@ -261,25 +322,24 @@ int main(int argc, char **argv) unsigned long buf_len = 128; int ret, c, i, j, toread; - int fp; + int fp = -1; - int num_channels; + int num_channels = 0; char *trigger_name = NULL, *device_name = NULL; - char *dev_dir_name, *buf_dir_name; - int datardytrigger = 1; - char *data; + char *data = NULL; ssize_t read_size; int dev_num, trig_num; - char *buffer_access; + char *buffer_access = NULL; int scan_size; int noevents = 0; int notrigger = 0; - enum autochan autochannels = AUTOCHANNELS_DISABLED; char *dummy; struct iio_channel_info *channels; + register_cleanup(); + while ((c = getopt(argc, argv, "ac:egl:n:t:w:")) != -1) { switch (c) { case 'a': @@ -288,8 +348,10 @@ int main(int argc, char **argv) case 'c': errno = 0; num_loops = strtoul(optarg, &dummy, 10); - if (errno) - return -errno; + if (errno) { + ret = -errno; + goto error; + } break; case 'e': @@ -301,26 +363,30 @@ int main(int argc, char **argv) case 'l': errno = 0; buf_len = strtoul(optarg, &dummy, 10); - if (errno) - return -errno; + if (errno) { + ret = -errno; + goto error; + } break; case 'n': device_name = optarg; break; case 't': - trigger_name = optarg; - datardytrigger = 0; + trigger_name = strdup(optarg); break; case 'w': errno = 0; timedelay = strtoul(optarg, &dummy, 10); - if (errno) - return -errno; + if (errno) { + ret = -errno; + goto error; + } break; case '?': print_usage(); - return -1; + ret = -1; + goto error; } } @@ -334,14 +400,17 @@ int main(int argc, char **argv) dev_num = find_type_by_name(device_name, "iio:device"); if (dev_num < 0) { fprintf(stderr, "Failed to find the %s\n", device_name); - return dev_num; + ret = dev_num; + goto error; } printf("iio device number being used is %d\n", dev_num); ret = asprintf(&dev_dir_name, "%siio:device%d", iio_dir, dev_num); - if (ret < 0) - return -ENOMEM; + if (ret < 0) { + ret = -ENOMEM; + goto error; + } if (!notrigger) { if (!trigger_name) { @@ -354,7 +423,7 @@ int main(int argc, char **argv) "%s-dev%d", device_name, dev_num); if (ret < 0) { ret = -ENOMEM; - goto error_free_dev_dir_name; + goto error; } } @@ -367,7 +436,7 @@ int main(int argc, char **argv) "%s-trigger", device_name); if (ret < 0) { ret = -ENOMEM; - goto error_free_dev_dir_name; + goto error; } } @@ -376,7 +445,7 @@ int main(int argc, char **argv) fprintf(stderr, "Failed to find the trigger %s\n", trigger_name); ret = trig_num; - goto error_free_triggername; + goto error; } printf("iio trigger number being used is %d\n", trig_num); @@ -392,7 +461,7 @@ int main(int argc, char **argv) if (ret) { fprintf(stderr, "Problem reading scan element information\n" "diag %s\n", dev_dir_name); - goto error_free_triggername; + goto error; } if (num_channels && autochannels == AUTOCHANNELS_ENABLED) { fprintf(stderr, "Auto-channels selected but some channels " @@ -407,7 +476,7 @@ int main(int argc, char **argv) ret = enable_disable_all_channels(dev_dir_name, 1); if (ret) { fprintf(stderr, "Failed to enable all channels\n"); - goto error_free_triggername; + goto error; } /* This flags that we need to disable the channels again */ @@ -419,12 +488,12 @@ int main(int argc, char **argv) fprintf(stderr, "Problem reading scan element " "information\n" "diag %s\n", dev_dir_name); - goto error_disable_channels; + goto error; } if (!num_channels) { fprintf(stderr, "Still no channels after " "auto-enabling, giving up\n"); - goto error_disable_channels; + goto error; } } @@ -436,7 +505,7 @@ int main(int argc, char **argv) "/*_en or pass -a to autoenable channels and " "try again.\n", dev_dir_name); ret = -ENOENT; - goto error_free_triggername; + goto error; } /* @@ -448,7 +517,7 @@ int main(int argc, char **argv) "%siio:device%d/buffer", iio_dir, dev_num); if (ret < 0) { ret = -ENOMEM; - goto error_free_channels; + goto error; } if (!notrigger) { @@ -463,34 +532,34 @@ int main(int argc, char **argv) if (ret < 0) { fprintf(stderr, "Failed to write current_trigger file\n"); - goto error_free_buf_dir_name; + goto error; } } /* Setup ring buffer parameters */ ret = write_sysfs_int("length", buf_dir_name, buf_len); if (ret < 0) - goto error_free_buf_dir_name; + goto error; /* Enable the buffer */ ret = write_sysfs_int("enable", buf_dir_name, 1); if (ret < 0) { fprintf(stderr, "Failed to enable buffer: %s\n", strerror(-ret)); - goto error_free_buf_dir_name; + goto error; } scan_size = size_from_channelarray(channels, num_channels); data = malloc(scan_size * buf_len); if (!data) { ret = -ENOMEM; - goto error_free_buf_dir_name; + goto error; } ret = asprintf(&buffer_access, "/dev/iio:device%d", dev_num); if (ret < 0) { ret = -ENOMEM; - goto error_free_data; + goto error; } /* Attempt to open non blocking the access dev */ @@ -498,7 +567,7 @@ int main(int argc, char **argv) if (fp == -1) { /* TODO: If it isn't there make the node */ ret = -errno; fprintf(stderr, "Failed to open %s\n", buffer_access); - goto error_free_buffer_access; + goto error; } for (j = 0; j < num_loops; j++) { @@ -511,7 +580,7 @@ int main(int argc, char **argv) ret = poll(&pfd, 1, -1); if (ret < 0) { ret = -errno; - goto error_close_buffer_access; + goto error; } else if (ret == 0) { continue; } @@ -536,45 +605,20 @@ int main(int argc, char **argv) num_channels); } - /* Stop the buffer */ - ret = write_sysfs_int("enable", buf_dir_name, 0); - if (ret < 0) - goto error_close_buffer_access; - - if (!notrigger) - /* Disconnect the trigger - just write a dummy name. */ - ret = write_sysfs_string("trigger/current_trigger", - dev_dir_name, "NULL"); - if (ret < 0) - fprintf(stderr, "Failed to write to %s\n", - dev_dir_name); +error: + cleanup(); -error_close_buffer_access: - if (close(fp) == -1) + if (fp >= 0 && close(fp) == -1) perror("Failed to close buffer"); - -error_free_buffer_access: free(buffer_access); -error_free_data: free(data); -error_free_buf_dir_name: free(buf_dir_name); -error_free_channels: for (i = num_channels - 1; i >= 0; i--) { free(channels[i].name); free(channels[i].generic_name); } free(channels); -error_free_triggername: - if (datardytrigger) - free(trigger_name); -error_disable_channels: - if (autochannels == AUTOCHANNELS_ACTIVE) { - ret = enable_disable_all_channels(dev_dir_name, 0); - if (ret) - fprintf(stderr, "Failed to disable all channels\n"); - } -error_free_dev_dir_name: + free(trigger_name); free(dev_dir_name); return ret; -- cgit v0.10.2 From de397db8ab9e292ed3b5be42d0892a0ec717330d Mon Sep 17 00:00:00 2001 From: Crestez Dan Leonard Date: Mon, 23 May 2016 21:39:57 +0300 Subject: iio: iio_generic_buffer: Add --device-num option This makes it possible to distinguish between iio devices with the same name. Signed-off-by: Crestez Dan Leonard Signed-off-by: Jonathan Cameron diff --git a/tools/iio/iio_generic_buffer.c b/tools/iio/iio_generic_buffer.c index 972f400..3f16e9f 100644 --- a/tools/iio/iio_generic_buffer.c +++ b/tools/iio/iio_generic_buffer.c @@ -251,7 +251,9 @@ void print_usage(void) " -e Disable wait for event (new data)\n" " -g Use trigger-less mode\n" " -l Set buffer length to n samples\n" - " -n Set device name (mandatory)\n" + " --device-name -n \n" + " --device-num -N \n" + " Set device by name or number (mandatory)\n" " -t Set trigger name\n" " -w Set delay between reads in us (event-less mode)\n"); } @@ -315,6 +317,12 @@ void register_cleanup(void) } } +static const struct option longopts[] = { + { "device-name", 1, 0, 'n' }, + { "device-num", 1, 0, 'N' }, + { }, +}; + int main(int argc, char **argv) { unsigned long num_loops = 2; @@ -329,7 +337,7 @@ int main(int argc, char **argv) char *data = NULL; ssize_t read_size; - int dev_num, trig_num; + int dev_num = -1, trig_num; char *buffer_access = NULL; int scan_size; int noevents = 0; @@ -340,7 +348,7 @@ int main(int argc, char **argv) register_cleanup(); - while ((c = getopt(argc, argv, "ac:egl:n:t:w:")) != -1) { + while ((c = getopt_long(argc, argv, "ac:egl:n:N:t:w:", longopts, NULL)) != -1) { switch (c) { case 'a': autochannels = AUTOCHANNELS_ENABLED; @@ -370,7 +378,15 @@ int main(int argc, char **argv) break; case 'n': - device_name = optarg; + device_name = strdup(optarg); + break; + case 'N': + errno = 0; + dev_num = strtoul(optarg, &dummy, 10); + if (errno) { + ret = -errno; + goto error; + } break; case 't': trigger_name = strdup(optarg); @@ -390,26 +406,42 @@ int main(int argc, char **argv) } } - if (!device_name) { - fprintf(stderr, "Device name not set\n"); - print_usage(); - return -1; - } - /* Find the device requested */ - dev_num = find_type_by_name(device_name, "iio:device"); - if (dev_num < 0) { - fprintf(stderr, "Failed to find the %s\n", device_name); - ret = dev_num; + if (dev_num < 0 && !device_name) { + fprintf(stderr, "Device not set\n"); + print_usage(); + ret = -1; + goto error; + } else if (dev_num >= 0 && device_name) { + fprintf(stderr, "Only one of --device-num or --device-name needs to be set\n"); + print_usage(); + ret = -1; goto error; + } else if (dev_num < 0) { + dev_num = find_type_by_name(device_name, "iio:device"); + if (dev_num < 0) { + fprintf(stderr, "Failed to find the %s\n", device_name); + ret = dev_num; + goto error; + } } - printf("iio device number being used is %d\n", dev_num); ret = asprintf(&dev_dir_name, "%siio:device%d", iio_dir, dev_num); - if (ret < 0) { - ret = -ENOMEM; - goto error; + if (ret < 0) + return -ENOMEM; + /* Fetch device_name if specified by number */ + if (!device_name) { + device_name = malloc(IIO_MAX_NAME_LENGTH); + if (!device_name) { + ret = -ENOMEM; + goto error; + } + ret = read_sysfs_string("name", dev_dir_name, device_name); + if (ret < 0) { + fprintf(stderr, "Failed to read name of device %d\n", dev_num); + goto error; + } } if (!notrigger) { @@ -619,6 +651,7 @@ error: } free(channels); free(trigger_name); + free(device_name); free(dev_dir_name); return ret; -- cgit v0.10.2 From 7c7e9dad7017ff5b5f0524ea6d85dcda3c62431e Mon Sep 17 00:00:00 2001 From: Crestez Dan Leonard Date: Mon, 23 May 2016 21:39:58 +0300 Subject: iio: iio_generic_buffer: Add --trigger-num option Signed-off-by: Crestez Dan Leonard Signed-off-by: Jonathan Cameron diff --git a/tools/iio/iio_generic_buffer.c b/tools/iio/iio_generic_buffer.c index 3f16e9f..e8c3052 100644 --- a/tools/iio/iio_generic_buffer.c +++ b/tools/iio/iio_generic_buffer.c @@ -254,7 +254,9 @@ void print_usage(void) " --device-name -n \n" " --device-num -N \n" " Set device by name or number (mandatory)\n" - " -t Set trigger name\n" + " --trigger-name -t \n" + " --trigger-num -T \n" + " Set trigger by name or number\n" " -w Set delay between reads in us (event-less mode)\n"); } @@ -320,6 +322,8 @@ void register_cleanup(void) static const struct option longopts[] = { { "device-name", 1, 0, 'n' }, { "device-num", 1, 0, 'N' }, + { "trigger-name", 1, 0, 't' }, + { "trigger-num", 1, 0, 'T' }, { }, }; @@ -348,7 +352,7 @@ int main(int argc, char **argv) register_cleanup(); - while ((c = getopt_long(argc, argv, "ac:egl:n:N:t:w:", longopts, NULL)) != -1) { + while ((c = getopt_long(argc, argv, "ac:egl:n:N:t:T:w:", longopts, NULL)) != -1) { switch (c) { case 'a': autochannels = AUTOCHANNELS_ENABLED; @@ -391,6 +395,12 @@ int main(int argc, char **argv) case 't': trigger_name = strdup(optarg); break; + case 'T': + errno = 0; + trig_num = strtoul(optarg, &dummy, 10); + if (errno) + return -errno; + break; case 'w': errno = 0; timedelay = strtoul(optarg, &dummy, 10); @@ -444,7 +454,23 @@ int main(int argc, char **argv) } } - if (!notrigger) { + if (notrigger) { + printf("trigger-less mode selected\n"); + } if (trig_num > 0) { + char *trig_dev_name; + ret = asprintf(&trig_dev_name, "%strigger%d", iio_dir, trig_num); + if (ret < 0) { + return -ENOMEM; + } + trigger_name = malloc(IIO_MAX_NAME_LENGTH); + ret = read_sysfs_string("name", trig_dev_name, trigger_name); + free(trig_dev_name); + if (ret < 0) { + fprintf(stderr, "Failed to read trigger%d name from\n", trig_num); + return ret; + } + printf("iio trigger number being used is %d\n", trig_num); + } else { if (!trigger_name) { /* * Build the trigger name. If it is device associated @@ -481,8 +507,6 @@ int main(int argc, char **argv) } printf("iio trigger number being used is %d\n", trig_num); - } else { - printf("trigger-less mode selected\n"); } /* -- cgit v0.10.2 From 4c6d7e228968bdc238ae7213d919f34b7838fe59 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 20 May 2016 09:50:54 +0200 Subject: drivers: sh: Stop using the legacy clock domain on ARM Since commits 71d076ceb245f0d9 ("ARM: shmobile: Enable PM and PM_GENERIC_DOMAINS for SoCs with PM Domains") and 2ee98234b88174f2 ("arm64: renesas: Enable PM and PM_GENERIC_DOMAINS for SoCs with PM Domains"), CONFIG_PM and CONFIG_PM_GENERIC_DOMAINS are enabled unconditionally for Renesas ARM-based SoCs. Hence the legacy clock domain is no longer used on these SoCs. Remove the related support code, and stop entering drivers/sh/ on ARM. Signed-off-by: Geert Uytterhoeven Signed-off-by: Simon Horman diff --git a/drivers/Makefile b/drivers/Makefile index 0b6f3d6..a7187b9 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -128,7 +128,6 @@ obj-$(CONFIG_SGI_SN) += sn/ obj-y += firmware/ obj-$(CONFIG_CRYPTO) += crypto/ obj-$(CONFIG_SUPERH) += sh/ -obj-$(CONFIG_ARCH_SHMOBILE) += sh/ ifndef CONFIG_ARCH_USES_GETTIMEOFFSET obj-y += clocksource/ endif diff --git a/drivers/sh/pm_runtime.c b/drivers/sh/pm_runtime.c index a9bac3b..c887ecd 100644 --- a/drivers/sh/pm_runtime.c +++ b/drivers/sh/pm_runtime.c @@ -34,15 +34,6 @@ static struct pm_clk_notifier_block platform_bus_notifier = { static int __init sh_pm_runtime_init(void) { - if (IS_ENABLED(CONFIG_OF) && IS_ENABLED(CONFIG_ARCH_SHMOBILE)) { - if (!of_find_compatible_node(NULL, NULL, - "renesas,cpg-mstp-clocks")) - return 0; - if (IS_ENABLED(CONFIG_PM_GENERIC_DOMAINS_OF) && - of_find_node_with_property(NULL, "#power-domain-cells")) - return 0; - } - pm_clk_add_notifier(&platform_bus_type, &platform_bus_notifier); return 0; } -- cgit v0.10.2 From 3fd0498b842f2932558797ec297dc30f6eb5cec0 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 20 May 2016 09:50:55 +0200 Subject: MAINTAINERS: Drop drivers/sh/ for Renesas ARM None of the code under drivers/sh/ is used anymore on Renesas ARM. Signed-off-by: Geert Uytterhoeven diff --git a/MAINTAINERS b/MAINTAINERS index 7304d2e..e6bf587 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1664,7 +1664,6 @@ F: arch/arm/boot/dts/sh* F: arch/arm/configs/shmobile_defconfig F: arch/arm/include/debug/renesas-scif.S F: arch/arm/mach-shmobile/ -F: drivers/sh/ F: drivers/soc/renesas/ F: include/linux/soc/renesas/ -- cgit v0.10.2 From 99cf4b267e4863b95c7d33f59371b6ccdfd4a4ce Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Wed, 25 May 2016 10:49:52 -0300 Subject: ASoC: ak4613: Remove owner assignment from platform_driver This platform_driver does not need to set an owner as it will be populated by the driver core. Generated by scripts/coccinelle/api/platform_no_drv_owner.cocci. Signed-off-by: Fabio Estevam Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/ak4613.c b/sound/soc/codecs/ak4613.c index 647f69d..33d2f2e1 100644 --- a/sound/soc/codecs/ak4613.c +++ b/sound/soc/codecs/ak4613.c @@ -530,7 +530,6 @@ static int ak4613_i2c_remove(struct i2c_client *client) static struct i2c_driver ak4613_i2c_driver = { .driver = { .name = "ak4613-codec", - .owner = THIS_MODULE, .of_match_table = ak4613_of_match, }, .probe = ak4613_i2c_probe, -- cgit v0.10.2 From 480ca357fd7f86a381a5b35a8157aa176eddbed4 Mon Sep 17 00:00:00 2001 From: Andi Kleen Date: Mon, 23 May 2016 17:52:24 -0700 Subject: perf thread: Adopt get_main_thread from db-export.c Move the get_main_thread function from db-export.c to thread.c so that it can be used elsewhere. Signed-off-by: Andi Kleen Cc: Jiri Olsa Link: http://lkml.kernel.org/r/1464051145-19968-2-git-send-email-andi@firstfloor.org [ Removed leftover bits from db-export.h ] Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/util/db-export.c b/tools/perf/util/db-export.c index c9a6dc1..b0c2b5c 100644 --- a/tools/perf/util/db-export.c +++ b/tools/perf/util/db-export.c @@ -233,17 +233,6 @@ int db_export__symbol(struct db_export *dbe, struct symbol *sym, return 0; } -static struct thread *get_main_thread(struct machine *machine, struct thread *thread) -{ - if (thread->pid_ == thread->tid) - return thread__get(thread); - - if (thread->pid_ == -1) - return NULL; - - return machine__find_thread(machine, thread->pid_, thread->pid_); -} - static int db_ids_from_al(struct db_export *dbe, struct addr_location *al, u64 *dso_db_id, u64 *sym_db_id, u64 *offset) { @@ -382,7 +371,7 @@ int db_export__sample(struct db_export *dbe, union perf_event *event, if (err) return err; - main_thread = get_main_thread(al->machine, thread); + main_thread = thread__main_thread(al->machine, thread); if (main_thread) comm = machine__thread_exec_comm(al->machine, main_thread); diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c index 45fcb71..ada58e6 100644 --- a/tools/perf/util/thread.c +++ b/tools/perf/util/thread.c @@ -265,3 +265,14 @@ void thread__find_cpumode_addr_location(struct thread *thread, break; } } + +struct thread *thread__main_thread(struct machine *machine, struct thread *thread) +{ + if (thread->pid_ == thread->tid) + return thread__get(thread); + + if (thread->pid_ == -1) + return NULL; + + return machine__find_thread(machine, thread->pid_, thread->pid_); +} diff --git a/tools/perf/util/thread.h b/tools/perf/util/thread.h index 45fba13..08fcb14 100644 --- a/tools/perf/util/thread.h +++ b/tools/perf/util/thread.h @@ -81,6 +81,8 @@ void thread__insert_map(struct thread *thread, struct map *map); int thread__fork(struct thread *thread, struct thread *parent, u64 timestamp); size_t thread__fprintf(struct thread *thread, FILE *fp); +struct thread *thread__main_thread(struct machine *machine, struct thread *thread); + void thread__find_addr_map(struct thread *thread, u8 cpumode, enum map_type type, u64 addr, struct addr_location *al); -- cgit v0.10.2 From 97c79a38cd454602645f0470ffb444b3b75ce574 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 28 Apr 2016 13:16:33 -0300 Subject: perf core: Per event callchain limit Additionally to being able to control the system wide maximum depth via /proc/sys/kernel/perf_event_max_stack, now we are able to ask for different depths per event, using perf_event_attr.sample_max_stack for that. This uses an u16 hole at the end of perf_event_attr, that, when perf_event_attr.sample_type has the PERF_SAMPLE_CALLCHAIN, if sample_max_stack is zero, means use perf_event_max_stack, otherwise it'll be bounds checked under callchain_mutex. Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Alexei Starovoitov Cc: Brendan Gregg Cc: David Ahern Cc: Frederic Weisbecker Cc: He Kuang Cc: Jiri Olsa Cc: Linus Torvalds Cc: Masami Hiramatsu Cc: Milian Wolff Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Thomas Gleixner Cc: Vince Weaver Cc: Wang Nan Cc: Zefan Li Link: http://lkml.kernel.org/n/tip-kolmn1yo40p7jhswxwrc7rrd@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h index 6b87be9..0e43355 100644 --- a/include/linux/perf_event.h +++ b/include/linux/perf_event.h @@ -1076,7 +1076,7 @@ extern void perf_callchain_kernel(struct perf_callchain_entry_ctx *entry, struct extern struct perf_callchain_entry * get_perf_callchain(struct pt_regs *regs, u32 init_nr, bool kernel, bool user, u32 max_stack, bool crosstask, bool add_mark); -extern int get_callchain_buffers(void); +extern int get_callchain_buffers(int max_stack); extern void put_callchain_buffers(void); extern int sysctl_perf_event_max_stack; diff --git a/include/uapi/linux/perf_event.h b/include/uapi/linux/perf_event.h index 36ce552..c66a485 100644 --- a/include/uapi/linux/perf_event.h +++ b/include/uapi/linux/perf_event.h @@ -276,6 +276,9 @@ enum perf_event_read_format { /* * Hardware event_id to monitor via a performance monitoring event: + * + * @sample_max_stack: Max number of frame pointers in a callchain, + * should be < /proc/sys/kernel/perf_event_max_stack */ struct perf_event_attr { @@ -385,7 +388,8 @@ struct perf_event_attr { * Wakeup watermark for AUX area */ __u32 aux_watermark; - __u32 __reserved_2; /* align to __u64 */ + __u16 sample_max_stack; + __u16 __reserved_2; /* align to __u64 */ }; #define perf_flags(attr) (*(&(attr)->read_format + 1)) diff --git a/kernel/bpf/stackmap.c b/kernel/bpf/stackmap.c index a82d760..f1de5c1 100644 --- a/kernel/bpf/stackmap.c +++ b/kernel/bpf/stackmap.c @@ -99,7 +99,7 @@ static struct bpf_map *stack_map_alloc(union bpf_attr *attr) if (err) goto free_smap; - err = get_callchain_buffers(); + err = get_callchain_buffers(sysctl_perf_event_max_stack); if (err) goto free_smap; diff --git a/kernel/events/callchain.c b/kernel/events/callchain.c index 179ef46..e9fdb52 100644 --- a/kernel/events/callchain.c +++ b/kernel/events/callchain.c @@ -104,7 +104,7 @@ fail: return -ENOMEM; } -int get_callchain_buffers(void) +int get_callchain_buffers(int event_max_stack) { int err = 0; int count; @@ -121,6 +121,15 @@ int get_callchain_buffers(void) /* If the allocation failed, give up */ if (!callchain_cpus_entries) err = -ENOMEM; + /* + * If requesting per event more than the global cap, + * return a different error to help userspace figure + * this out. + * + * And also do it here so that we have &callchain_mutex held. + */ + if (event_max_stack > sysctl_perf_event_max_stack) + err = -EOVERFLOW; goto exit; } @@ -174,11 +183,12 @@ perf_callchain(struct perf_event *event, struct pt_regs *regs) bool user = !event->attr.exclude_callchain_user; /* Disallow cross-task user callchains. */ bool crosstask = event->ctx->task && event->ctx->task != current; + const u32 max_stack = event->attr.sample_max_stack; if (!kernel && !user) return NULL; - return get_perf_callchain(regs, 0, kernel, user, sysctl_perf_event_max_stack, crosstask, true); + return get_perf_callchain(regs, 0, kernel, user, max_stack, crosstask, true); } struct perf_callchain_entry * diff --git a/kernel/events/core.c b/kernel/events/core.c index 050a290..79363f2 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c @@ -8843,7 +8843,7 @@ perf_event_alloc(struct perf_event_attr *attr, int cpu, if (!event->parent) { if (event->attr.sample_type & PERF_SAMPLE_CALLCHAIN) { - err = get_callchain_buffers(); + err = get_callchain_buffers(attr->sample_max_stack); if (err) goto err_addr_filters; } @@ -9165,6 +9165,9 @@ SYSCALL_DEFINE5(perf_event_open, return -EINVAL; } + if (!attr.sample_max_stack) + attr.sample_max_stack = sysctl_perf_event_max_stack; + /* * In cgroup mode, the pid argument is used to pass the fd * opened to the cgroup directory in cgroupfs. The cpu argument -- cgit v0.10.2 From 792d48b4cf9c248ab2bf66c140a27c48e116bed7 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 28 Apr 2016 19:03:42 -0300 Subject: perf tools: Per event max-stack settings The tooling counterpart, now it is possible to do: # perf record -e sched:sched_switch/max-stack=10/ -e cycles/call-graph=dwarf,max-stack=4/ -e cpu-cycles/call-graph=dwarf,max-stack=1024/ usleep 1 [ perf record: Woken up 1 times to write data ] [ perf record: Captured and wrote 0.052 MB perf.data (5 samples) ] # perf evlist -v sched:sched_switch: type: 2, size: 112, config: 0x110, { sample_period, sample_freq }: 1, sample_type: IP|TID|TIME|CALLCHAIN|CPU|PERIOD|RAW|IDENTIFIER, read_format: ID, disabled: 1, inherit: 1, mmap: 1, comm: 1, enable_on_exec: 1, task: 1, sample_id_all: 1, exclude_guest: 1, mmap2: 1, comm_exec: 1, sample_max_stack: 10 cycles/call-graph=dwarf,max-stack=4/: size: 112, { sample_period, sample_freq }: 4000, sample_type: IP|TID|TIME|CALLCHAIN|PERIOD|REGS_USER|STACK_USER|IDENTIFIER, read_format: ID, disabled: 1, inherit: 1, freq: 1, enable_on_exec: 1, sample_id_all: 1, exclude_guest: 1, exclude_callchain_user: 1, sample_regs_user: 0xff0fff, sample_stack_user: 8192, sample_max_stack: 4 cpu-cycles/call-graph=dwarf,max-stack=1024/: size: 112, { sample_period, sample_freq }: 4000, sample_type: IP|TID|TIME|CALLCHAIN|PERIOD|REGS_USER|STACK_USER|IDENTIFIER, read_format: ID, disabled: 1, inherit: 1, freq: 1, enable_on_exec: 1, sample_id_all: 1, exclude_guest: 1, exclude_callchain_user: 1, sample_regs_user: 0xff0fff, sample_stack_user: 8192, sample_max_stack: 1024 # Tip: use 'perf evlist --trace-fields' to show fields for tracepoint events Using just /max-stack=N/ means /call-graph=fp,max-stack=N/, that should be further configurable by means of some .perfconfig knob. Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Alexei Starovoitov Cc: Brendan Gregg Cc: David Ahern Cc: Frederic Weisbecker Cc: He Kuang Cc: Jiri Olsa Cc: Linus Torvalds Cc: Masami Hiramatsu Cc: Milian Wolff Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Thomas Gleixner Cc: Vince Weaver Cc: Wang Nan Cc: Zefan Li Link: http://lkml.kernel.org/n/tip-kolmn1yo40p7jhswxwrc7rrd@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/util/callchain.h b/tools/perf/util/callchain.h index 65e2a4f..a70f6b5 100644 --- a/tools/perf/util/callchain.h +++ b/tools/perf/util/callchain.h @@ -94,6 +94,7 @@ struct callchain_param { enum perf_call_graph_mode record_mode; u32 dump_size; enum chain_mode mode; + u16 max_stack; u32 print_limit; double min_percent; sort_chain_func_t sort; diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index 02c177d..245ac50 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c @@ -572,6 +572,8 @@ void perf_evsel__config_callchain(struct perf_evsel *evsel, perf_evsel__set_sample_bit(evsel, CALLCHAIN); + attr->sample_max_stack = param->max_stack; + if (param->record_mode == CALLCHAIN_LBR) { if (!opts->branch_stack) { if (attr->exclude_user) { @@ -635,7 +637,8 @@ static void apply_config_terms(struct perf_evsel *evsel, struct perf_event_attr *attr = &evsel->attr; struct callchain_param param; u32 dump_size = 0; - char *callgraph_buf = NULL; + int max_stack = 0; + const char *callgraph_buf = NULL; /* callgraph default */ param.record_mode = callchain_param.record_mode; @@ -662,6 +665,9 @@ static void apply_config_terms(struct perf_evsel *evsel, case PERF_EVSEL__CONFIG_TERM_STACK_USER: dump_size = term->val.stack_user; break; + case PERF_EVSEL__CONFIG_TERM_MAX_STACK: + max_stack = term->val.max_stack; + break; case PERF_EVSEL__CONFIG_TERM_INHERIT: /* * attr->inherit should has already been set by @@ -677,7 +683,12 @@ static void apply_config_terms(struct perf_evsel *evsel, } /* User explicitly set per-event callgraph, clear the old setting and reset. */ - if ((callgraph_buf != NULL) || (dump_size > 0)) { + if ((callgraph_buf != NULL) || (dump_size > 0) || max_stack) { + if (max_stack) { + param.max_stack = max_stack; + if (callgraph_buf == NULL) + callgraph_buf = "fp"; + } /* parse callgraph parameters */ if (callgraph_buf != NULL) { @@ -1329,6 +1340,7 @@ int perf_event_attr__fprintf(FILE *fp, struct perf_event_attr *attr, PRINT_ATTRf(clockid, p_signed); PRINT_ATTRf(sample_regs_intr, p_hex); PRINT_ATTRf(aux_watermark, p_unsigned); + PRINT_ATTRf(sample_max_stack, p_unsigned); return ret; } diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h index c1f1015..028412b 100644 --- a/tools/perf/util/evsel.h +++ b/tools/perf/util/evsel.h @@ -44,6 +44,7 @@ enum { PERF_EVSEL__CONFIG_TERM_CALLGRAPH, PERF_EVSEL__CONFIG_TERM_STACK_USER, PERF_EVSEL__CONFIG_TERM_INHERIT, + PERF_EVSEL__CONFIG_TERM_MAX_STACK, PERF_EVSEL__CONFIG_TERM_MAX, }; @@ -56,6 +57,7 @@ struct perf_evsel_config_term { bool time; char *callgraph; u64 stack_user; + int max_stack; bool inherit; } val; }; diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index bcbc983..89d40bb 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -900,6 +900,7 @@ static const char *config_term_names[__PARSE_EVENTS__TERM_TYPE_NR] = { [PARSE_EVENTS__TERM_TYPE_STACKSIZE] = "stack-size", [PARSE_EVENTS__TERM_TYPE_NOINHERIT] = "no-inherit", [PARSE_EVENTS__TERM_TYPE_INHERIT] = "inherit", + [PARSE_EVENTS__TERM_TYPE_MAX_STACK] = "max-stack", }; static bool config_term_shrinked; @@ -995,6 +996,9 @@ do { \ case PARSE_EVENTS__TERM_TYPE_NAME: CHECK_TYPE_VAL(STR); break; + case PARSE_EVENTS__TERM_TYPE_MAX_STACK: + CHECK_TYPE_VAL(NUM); + break; default: err->str = strdup("unknown term"); err->idx = term->err_term; @@ -1040,6 +1044,7 @@ static int config_term_tracepoint(struct perf_event_attr *attr, case PARSE_EVENTS__TERM_TYPE_STACKSIZE: case PARSE_EVENTS__TERM_TYPE_INHERIT: case PARSE_EVENTS__TERM_TYPE_NOINHERIT: + case PARSE_EVENTS__TERM_TYPE_MAX_STACK: return config_term_common(attr, term, err); default: if (err) { @@ -1109,6 +1114,9 @@ do { \ case PARSE_EVENTS__TERM_TYPE_NOINHERIT: ADD_CONFIG_TERM(INHERIT, inherit, term->val.num ? 0 : 1); break; + case PARSE_EVENTS__TERM_TYPE_MAX_STACK: + ADD_CONFIG_TERM(MAX_STACK, max_stack, term->val.num); + break; default: break; } diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h index d740c3c..46c05cc 100644 --- a/tools/perf/util/parse-events.h +++ b/tools/perf/util/parse-events.h @@ -68,6 +68,7 @@ enum { PARSE_EVENTS__TERM_TYPE_STACKSIZE, PARSE_EVENTS__TERM_TYPE_NOINHERIT, PARSE_EVENTS__TERM_TYPE_INHERIT, + PARSE_EVENTS__TERM_TYPE_MAX_STACK, __PARSE_EVENTS__TERM_TYPE_NR, }; diff --git a/tools/perf/util/parse-events.l b/tools/perf/util/parse-events.l index 1477fbc..01af1ee 100644 --- a/tools/perf/util/parse-events.l +++ b/tools/perf/util/parse-events.l @@ -199,6 +199,7 @@ branch_type { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE time { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_TIME); } call-graph { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_CALLGRAPH); } stack-size { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_STACKSIZE); } +max-stack { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_MAX_STACK); } inherit { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_INHERIT); } no-inherit { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_NOINHERIT); } , { return ','; } diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index 2335b28..43d30ea 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c @@ -593,6 +593,7 @@ do { \ if (bswap_safe(f, 0)) \ attr->f = bswap_##sz(attr->f); \ } while(0) +#define bswap_field_16(f) bswap_field(f, 16) #define bswap_field_32(f) bswap_field(f, 32) #define bswap_field_64(f) bswap_field(f, 64) @@ -608,6 +609,7 @@ do { \ bswap_field_64(sample_regs_user); bswap_field_32(sample_stack_user); bswap_field_32(aux_watermark); + bswap_field_16(sample_max_stack); /* * After read_format are bitfields. Check read_format because -- cgit v0.10.2 From c45628b0a3f90c4ffeca5f72f227008ceedc21c5 Mon Sep 17 00:00:00 2001 From: Wang Nan Date: Tue, 24 May 2016 02:28:59 +0000 Subject: perf record: Robustify perf_event__synth_time_conv() It is possible that all events in an evlist are overwritable. perf_event__synth_time_conv() should not crash in this case. record__pick_pc() is used to check avaliability. Signed-off-by: Wang Nan Cc: Jiri Olsa Cc: Masami Hiramatsu Cc: Namhyung Kim Cc: Zefan Li Cc: pi3orama@163.com Link: http://lkml.kernel.org/r/1464056944-166978-3-git-send-email-wangnan0@huawei.com Signed-off-by: He Kuang [ Split from a larger patch ] Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/arch/x86/util/tsc.c b/tools/perf/arch/x86/util/tsc.c index 357f1b1..2e5567c 100644 --- a/tools/perf/arch/x86/util/tsc.c +++ b/tools/perf/arch/x86/util/tsc.c @@ -62,6 +62,8 @@ int perf_event__synth_time_conv(const struct perf_event_mmap_page *pc, struct perf_tsc_conversion tc; int err; + if (!pc) + return 0; err = perf_read_tsc_conversion(pc, &tc); if (err == -EOPNOTSUPP) return 0; diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index dc3fcb5..d4cf1b0 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -655,6 +655,13 @@ perf_event__synth_time_conv(const struct perf_event_mmap_page *pc __maybe_unused return 0; } +static const struct perf_event_mmap_page *record__pick_pc(struct record *rec) +{ + if (rec->evlist && rec->evlist->mmap && rec->evlist->mmap[0].base) + return rec->evlist->mmap[0].base; + return NULL; +} + static int record__synthesize(struct record *rec) { struct perf_session *session = rec->session; @@ -692,7 +699,7 @@ static int record__synthesize(struct record *rec) } } - err = perf_event__synth_time_conv(rec->evlist->mmap[0].base, tool, + err = perf_event__synth_time_conv(record__pick_pc(rec), tool, process_synthesized_event, machine); if (err) goto out; -- cgit v0.10.2 From f3058a1c1932aa1b027856945163144bda6366df Mon Sep 17 00:00:00 2001 From: Wang Nan Date: Tue, 24 May 2016 02:28:59 +0000 Subject: perf evlist: Don't poll and mmap overwritable events There's no need to receive events from overwritable ring buffer. Instead, perf should make them run in background until some external event of interest takes place. This patch makes ignores normal events from overwrite evlists. Overwritable events must be mapped readonly and backward, so if evlist and evsel doesn't match (evsel->overwrite is true but either evlist is read/write or evlist is not backward, and vice versa), skip mapping it. Signed-off-by: Wang Nan Cc: Jiri Olsa Cc: Masami Hiramatsu Cc: Namhyung Kim Cc: Zefan Li Cc: pi3orama@163.com Link: http://lkml.kernel.org/r/1464056944-166978-3-git-send-email-wangnan0@huawei.com Signed-off-by: He Kuang [ Split from a larger patch ] Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index e82ba90..50d7b80 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c @@ -462,9 +462,9 @@ int perf_evlist__alloc_pollfd(struct perf_evlist *evlist) return 0; } -static int __perf_evlist__add_pollfd(struct perf_evlist *evlist, int fd, int idx) +static int __perf_evlist__add_pollfd(struct perf_evlist *evlist, int fd, int idx, short revent) { - int pos = fdarray__add(&evlist->pollfd, fd, POLLIN | POLLERR | POLLHUP); + int pos = fdarray__add(&evlist->pollfd, fd, revent | POLLERR | POLLHUP); /* * Save the idx so that when we filter out fds POLLHUP'ed we can * close the associated evlist->mmap[] entry. @@ -480,7 +480,7 @@ static int __perf_evlist__add_pollfd(struct perf_evlist *evlist, int fd, int idx int perf_evlist__add_pollfd(struct perf_evlist *evlist, int fd) { - return __perf_evlist__add_pollfd(evlist, fd, -1); + return __perf_evlist__add_pollfd(evlist, fd, -1, POLLIN); } static void perf_evlist__munmap_filtered(struct fdarray *fda, int fd) @@ -983,15 +983,28 @@ static int __perf_evlist__mmap(struct perf_evlist *evlist, int idx, return 0; } +static bool +perf_evlist__should_poll(struct perf_evlist *evlist __maybe_unused, + struct perf_evsel *evsel) +{ + if (evsel->overwrite) + return false; + return true; +} + static int perf_evlist__mmap_per_evsel(struct perf_evlist *evlist, int idx, struct mmap_params *mp, int cpu, int thread, int *output) { struct perf_evsel *evsel; + int revent; evlist__for_each(evlist, evsel) { int fd; + if (evsel->overwrite != (evlist->overwrite && evlist->backward)) + continue; + if (evsel->system_wide && thread) continue; @@ -1008,6 +1021,8 @@ static int perf_evlist__mmap_per_evsel(struct perf_evlist *evlist, int idx, perf_evlist__mmap_get(evlist, idx); } + revent = perf_evlist__should_poll(evlist, evsel) ? POLLIN : 0; + /* * The system_wide flag causes a selected event to be opened * always without a pid. Consequently it will never get a @@ -1016,7 +1031,7 @@ static int perf_evlist__mmap_per_evsel(struct perf_evlist *evlist, int idx, * Therefore don't add it for polling. */ if (!evsel->system_wide && - __perf_evlist__add_pollfd(evlist, fd, idx) < 0) { + __perf_evlist__add_pollfd(evlist, fd, idx, revent) < 0) { perf_evlist__mmap_put(evlist, idx); return -1; } -- cgit v0.10.2 From e10e4ef63b54912feffb1dc48ff7d03d931b1647 Mon Sep 17 00:00:00 2001 From: Wang Nan Date: Wed, 25 May 2016 13:44:49 +0000 Subject: perf evlist: Check 'base' pointer before checking refcnt when put a mmap evlist->mmap[i]->refcnt could be 0 if an evlist has no evsel or if all evsels don't match the evlist during mmap. For example, when all evsels are overwritable but the evlist itself is normal. To avoid crashing, perf should check 'base' pointer before checking refcnt, and raise bug only when base is not NULL. Signed-off-by: Wang Nan Cc: He Kuang Cc: Jiri Olsa Cc: Masami Hiramatsu Cc: Namhyung Kim Cc: Zefan Li Cc: pi3orama@163.com Link: http://lkml.kernel.org/r/1464183898-174512-2-git-send-email-wangnan0@huawei.com [ Renamed 'mmap' variable, it is reserved in old distros such as Ubuntu 12.04, breaking the build ] Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index 50d7b80..58ede32 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c @@ -856,9 +856,11 @@ static void perf_evlist__mmap_get(struct perf_evlist *evlist, int idx) static void perf_evlist__mmap_put(struct perf_evlist *evlist, int idx) { - BUG_ON(atomic_read(&evlist->mmap[idx].refcnt) == 0); + struct perf_mmap *md = &evlist->mmap[idx]; + + BUG_ON(md->base && atomic_read(&md->refcnt) == 0); - if (atomic_dec_and_test(&evlist->mmap[idx].refcnt)) + if (atomic_dec_and_test(&md->refcnt)) __perf_evlist__munmap(evlist, idx); } -- cgit v0.10.2 From 5a5ddeb6e3559675070df6b39ba32a4dd1ab4dd5 Mon Sep 17 00:00:00 2001 From: Wang Nan Date: Wed, 25 May 2016 13:44:50 +0000 Subject: perf evlist: Choose correct reading direction according to evlist->backward Now we have evlist->backward to indicate the mmap direction. Make perf_evlist__mmap_read() choose right direction automatically. Signed-off-by: Wang Nan Cc: He Kuang Cc: Jiri Olsa Cc: Masami Hiramatsu Cc: Namhyung Kim Cc: Zefan Li Cc: pi3orama@163.com Link: http://lkml.kernel.org/r/1464183898-174512-3-git-send-email-wangnan0@huawei.com Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index 58ede32..719729e 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c @@ -777,7 +777,7 @@ broken_event: return event; } -union perf_event *perf_evlist__mmap_read(struct perf_evlist *evlist, int idx) +union perf_event *perf_evlist__mmap_read_forward(struct perf_evlist *evlist, int idx) { struct perf_mmap *md = &evlist->mmap[idx]; u64 head; @@ -832,6 +832,13 @@ perf_evlist__mmap_read_backward(struct perf_evlist *evlist, int idx) return perf_mmap__read(md, false, start, end, &md->prev); } +union perf_event *perf_evlist__mmap_read(struct perf_evlist *evlist, int idx) +{ + if (!evlist->backward) + return perf_evlist__mmap_read_forward(evlist, idx); + return perf_evlist__mmap_read_backward(evlist, idx); +} + void perf_evlist__mmap_read_catchup(struct perf_evlist *evlist, int idx) { struct perf_mmap *md = &evlist->mmap[idx]; diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h index d740fb8..68cb136 100644 --- a/tools/perf/util/evlist.h +++ b/tools/perf/util/evlist.h @@ -131,6 +131,8 @@ struct perf_sample_id *perf_evlist__id2sid(struct perf_evlist *evlist, u64 id); union perf_event *perf_evlist__mmap_read(struct perf_evlist *evlist, int idx); +union perf_event *perf_evlist__mmap_read_forward(struct perf_evlist *evlist, + int idx); union perf_event *perf_evlist__mmap_read_backward(struct perf_evlist *evlist, int idx); void perf_evlist__mmap_read_catchup(struct perf_evlist *evlist, int idx); -- cgit v0.10.2 From 258e4bfcbdaa6d128c391e6e25f03d54dee4f226 Mon Sep 17 00:00:00 2001 From: Wang Nan Date: Wed, 25 May 2016 13:44:57 +0000 Subject: tools: Pass arg to fdarray__filter's call back function Before this patch there's no way to pass arguments to fdarray__filter's call back function. This improvement will be used by 'perf record' to support unmapping ring buffer for both main evlist and overwrite evlist. Without this patch there's no way to track overwrite evlist from 'struct fdarray'. Signed-off-by: Wang Nan Cc: He Kuang Cc: Jiri Olsa Cc: Masami Hiramatsu Cc: Namhyung Kim Cc: Zefan Li Cc: pi3orama@163.com Link: http://lkml.kernel.org/r/1464183898-174512-10-git-send-email-wangnan0@huawei.com Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/lib/api/fd/array.c b/tools/lib/api/fd/array.c index 0e636c4..b0a035f 100644 --- a/tools/lib/api/fd/array.c +++ b/tools/lib/api/fd/array.c @@ -85,7 +85,8 @@ int fdarray__add(struct fdarray *fda, int fd, short revents) } int fdarray__filter(struct fdarray *fda, short revents, - void (*entry_destructor)(struct fdarray *fda, int fd)) + void (*entry_destructor)(struct fdarray *fda, int fd, void *arg), + void *arg) { int fd, nr = 0; @@ -95,7 +96,7 @@ int fdarray__filter(struct fdarray *fda, short revents, for (fd = 0; fd < fda->nr; ++fd) { if (fda->entries[fd].revents & revents) { if (entry_destructor) - entry_destructor(fda, fd); + entry_destructor(fda, fd, arg); continue; } diff --git a/tools/lib/api/fd/array.h b/tools/lib/api/fd/array.h index 45db018..e87fd80 100644 --- a/tools/lib/api/fd/array.h +++ b/tools/lib/api/fd/array.h @@ -34,7 +34,8 @@ void fdarray__delete(struct fdarray *fda); int fdarray__add(struct fdarray *fda, int fd, short revents); int fdarray__poll(struct fdarray *fda, int timeout); int fdarray__filter(struct fdarray *fda, short revents, - void (*entry_destructor)(struct fdarray *fda, int fd)); + void (*entry_destructor)(struct fdarray *fda, int fd, void *arg), + void *arg); int fdarray__grow(struct fdarray *fda, int extra); int fdarray__fprintf(struct fdarray *fda, FILE *fp); diff --git a/tools/perf/tests/fdarray.c b/tools/perf/tests/fdarray.c index c809463..59dbd05 100644 --- a/tools/perf/tests/fdarray.c +++ b/tools/perf/tests/fdarray.c @@ -36,7 +36,7 @@ int test__fdarray__filter(int subtest __maybe_unused) } fdarray__init_revents(fda, POLLIN); - nr_fds = fdarray__filter(fda, POLLHUP, NULL); + nr_fds = fdarray__filter(fda, POLLHUP, NULL, NULL); if (nr_fds != fda->nr_alloc) { pr_debug("\nfdarray__filter()=%d != %d shouldn't have filtered anything", nr_fds, fda->nr_alloc); @@ -44,7 +44,7 @@ int test__fdarray__filter(int subtest __maybe_unused) } fdarray__init_revents(fda, POLLHUP); - nr_fds = fdarray__filter(fda, POLLHUP, NULL); + nr_fds = fdarray__filter(fda, POLLHUP, NULL, NULL); if (nr_fds != 0) { pr_debug("\nfdarray__filter()=%d != %d, should have filtered all fds", nr_fds, fda->nr_alloc); @@ -57,7 +57,7 @@ int test__fdarray__filter(int subtest __maybe_unused) pr_debug("\nfiltering all but fda->entries[2]:"); fdarray__fprintf_prefix(fda, "before", stderr); - nr_fds = fdarray__filter(fda, POLLHUP, NULL); + nr_fds = fdarray__filter(fda, POLLHUP, NULL, NULL); fdarray__fprintf_prefix(fda, " after", stderr); if (nr_fds != 1) { pr_debug("\nfdarray__filter()=%d != 1, should have left just one event", nr_fds); @@ -78,7 +78,7 @@ int test__fdarray__filter(int subtest __maybe_unused) pr_debug("\nfiltering all but (fda->entries[0], fda->entries[3]):"); fdarray__fprintf_prefix(fda, "before", stderr); - nr_fds = fdarray__filter(fda, POLLHUP, NULL); + nr_fds = fdarray__filter(fda, POLLHUP, NULL, NULL); fdarray__fprintf_prefix(fda, " after", stderr); if (nr_fds != 2) { pr_debug("\nfdarray__filter()=%d != 2, should have left just two events", diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index 719729e..e0f3094 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c @@ -483,7 +483,8 @@ int perf_evlist__add_pollfd(struct perf_evlist *evlist, int fd) return __perf_evlist__add_pollfd(evlist, fd, -1, POLLIN); } -static void perf_evlist__munmap_filtered(struct fdarray *fda, int fd) +static void perf_evlist__munmap_filtered(struct fdarray *fda, int fd, + void *arg __maybe_unused) { struct perf_evlist *evlist = container_of(fda, struct perf_evlist, pollfd); @@ -493,7 +494,7 @@ static void perf_evlist__munmap_filtered(struct fdarray *fda, int fd) int perf_evlist__filter_pollfd(struct perf_evlist *evlist, short revents_and_mask) { return fdarray__filter(&evlist->pollfd, revents_and_mask, - perf_evlist__munmap_filtered); + perf_evlist__munmap_filtered, NULL); } int perf_evlist__poll(struct perf_evlist *evlist, int timeout) -- cgit v0.10.2 From dcd1e2a7ba63710843d559f1570628321e62223e Mon Sep 17 00:00:00 2001 From: Taeung Song Date: Fri, 27 May 2016 19:01:14 +0900 Subject: perf tools: Add arch/*/include/generated/ to .gitignore Commit 1b700c997500 ("perf tools: Build syscall table .c header from kernel's syscall_64.tbl") automatically generates per-arch syscall table arrays, e.g.: arch/x86/include/generated/asm/syscalls_64.c So add this directory to .gitignore Signed-off-by: Taeung Song Cc: Adrian Hunter Cc: Alexander Shishkin Cc: David Ahern Cc: Jiri Olsa Cc: Masami Hiramatsu Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Wang Nan Fixes: 1b700c997500 ("perf tools: Build syscall table .c header from kernel's syscall_64.tbl") Link: http://lkml.kernel.org/r/1464343274-19403-1-git-send-email-treeze.taeung@gmail.com Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/.gitignore b/tools/perf/.gitignore index 3d1bb80..3db3db9 100644 --- a/tools/perf/.gitignore +++ b/tools/perf/.gitignore @@ -30,3 +30,4 @@ config.mak.autogen *.pyo .config-detected util/intel-pt-decoder/inat-tables.c +arch/*/include/generated/ -- cgit v0.10.2 From 11870d714a1b744a0225e90b0b395346357defe9 Mon Sep 17 00:00:00 2001 From: Masami Hiramatsu Date: Sun, 29 May 2016 00:15:13 +0900 Subject: perf symbols: Introduce filename__readable to check readability Introduce filename__readable to check readability by opening the file directly. Since the access(R_OK) just checks the readability based on real UID/GID, it is ignored that the effective UID/GID and capabilities for some special file (e.g. /proc/kcore). filename__readable() directly opens given file with O_RDONLY so that the kernel checks it by effective UID/GID and capabilities. Signed-off-by: Masami Hiramatsu Acked-by: Namhyung Kim Cc: Ananth N Mavinakayanahalli Cc: Brendan Gregg Cc: Hemant Kumar Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/20160528151513.16098.97576.stgit@devbox Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index 54c4ff2..a469346 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c @@ -1641,6 +1641,20 @@ static int find_matching_kcore(struct map *map, char *dir, size_t dir_sz) return ret; } +/* + * Use open(O_RDONLY) to check readability directly instead of access(R_OK) + * since access(R_OK) only checks with real UID/GID but open() use effective + * UID/GID and actual capabilities (e.g. /proc/kcore requires CAP_SYS_RAWIO). + */ +static bool filename__readable(const char *file) +{ + int fd = open(file, O_RDONLY); + if (fd < 0) + return false; + close(fd); + return true; +} + static char *dso__find_kallsyms(struct dso *dso, struct map *map) { u8 host_build_id[BUILD_ID_SIZE]; @@ -1668,7 +1682,6 @@ static char *dso__find_kallsyms(struct dso *dso, struct map *map) /* Use /proc/kallsyms if possible */ if (is_host) { DIR *d; - int fd; /* If no cached kcore go with /proc/kallsyms */ d = opendir(path); @@ -1677,16 +1690,15 @@ static char *dso__find_kallsyms(struct dso *dso, struct map *map) closedir(d); /* - * Do not check the build-id cache, until we know we cannot use - * /proc/kcore. + * Do not check the build-id cache, unless we know we cannot use + * /proc/kcore or module maps don't match to /proc/kallsyms. + * To check readability of /proc/kcore, do not use access(R_OK) + * since /proc/kcore requires CAP_SYS_RAWIO to read and access + * can't check it. */ - fd = open("/proc/kcore", O_RDONLY); - if (fd != -1) { - close(fd); - /* If module maps match go with /proc/kallsyms */ - if (!validate_kcore_addresses("/proc/kallsyms", map)) - goto proc_kallsyms; - } + if (filename__readable("/proc/kcore") && + !validate_kcore_addresses("/proc/kallsyms", map)) + goto proc_kallsyms; /* Find kallsyms in build-id cache with kcore */ if (!find_matching_kcore(map, path, sizeof(path))) -- cgit v0.10.2 From 4e4b6c0668dcd907a36d281802beafa96c916548 Mon Sep 17 00:00:00 2001 From: Masami Hiramatsu Date: Sun, 29 May 2016 00:15:28 +0900 Subject: perf symbols: Cleanup the code flow of dso__find_kallsyms Cleanup the code flow of dso__find_kallsyms() to remove redundant checking code and add some comment for readability. Signed-off-by: Masami Hiramatsu Acked-by: Namhyung Kim Cc: Ananth N Mavinakayanahalli Cc: Brendan Gregg Cc: Hemant Kumar Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/20160528151522.16098.43446.stgit@devbox Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index a469346..1df6092 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c @@ -1674,21 +1674,8 @@ static char *dso__find_kallsyms(struct dso *dso, struct map *map) sizeof(host_build_id)) == 0) is_host = dso__build_id_equal(dso, host_build_id); - build_id__sprintf(dso->build_id, sizeof(dso->build_id), sbuild_id); - - scnprintf(path, sizeof(path), "%s/%s/%s", buildid_dir, - DSO__NAME_KCORE, sbuild_id); - - /* Use /proc/kallsyms if possible */ + /* Try a fast path for /proc/kallsyms if possible */ if (is_host) { - DIR *d; - - /* If no cached kcore go with /proc/kallsyms */ - d = opendir(path); - if (!d) - goto proc_kallsyms; - closedir(d); - /* * Do not check the build-id cache, unless we know we cannot use * /proc/kcore or module maps don't match to /proc/kallsyms. @@ -1699,18 +1686,24 @@ static char *dso__find_kallsyms(struct dso *dso, struct map *map) if (filename__readable("/proc/kcore") && !validate_kcore_addresses("/proc/kallsyms", map)) goto proc_kallsyms; - - /* Find kallsyms in build-id cache with kcore */ - if (!find_matching_kcore(map, path, sizeof(path))) - return strdup(path); - - goto proc_kallsyms; } + build_id__sprintf(dso->build_id, sizeof(dso->build_id), sbuild_id); + /* Find kallsyms in build-id cache with kcore */ + scnprintf(path, sizeof(path), "%s/%s/%s", + buildid_dir, DSO__NAME_KCORE, sbuild_id); + if (!find_matching_kcore(map, path, sizeof(path))) return strdup(path); + /* Use current /proc/kallsyms if possible */ + if (is_host) { +proc_kallsyms: + return strdup("/proc/kallsyms"); + } + + /* Finally, find a cache of kallsyms */ scnprintf(path, sizeof(path), "%s/%s/%s", buildid_dir, DSO__NAME_KALLSYMS, sbuild_id); @@ -1721,9 +1714,6 @@ static char *dso__find_kallsyms(struct dso *dso, struct map *map) } return strdup(path); - -proc_kallsyms: - return strdup("/proc/kallsyms"); } static int dso__load_kernel_sym(struct dso *dso, struct map *map, -- cgit v0.10.2 From 01412261d99497021353c4b1d67e8df6c9cdc3c6 Mon Sep 17 00:00:00 2001 From: Masami Hiramatsu Date: Sun, 29 May 2016 00:15:37 +0900 Subject: perf buildid-cache: Use path/to/bin/buildid/elf instead of path/to/bin/buildid Use path/to/bin/buildid/elf instead of path/to/bin/buildid to store corresponding elf binary. This also stores vdso in buildid/vdso, kallsyms in buildid/kallsyms. Note that the existing caches are not updated until user adds or updates the cache. Anyway, if there is the old style build-id cache it falls back to use it. (IOW, it is backward compatible) Signed-off-by: Masami Hiramatsu Signed-off-by: Masami Hiramatsu Acked-by: Namhyung Kim Cc: Ananth N Mavinakayanahalli Cc: Brendan Gregg Cc: Hemant Kumar Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/20160528151537.16098.85815.stgit@devbox Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/util/build-id.c b/tools/perf/util/build-id.c index 67e5966..67f986c 100644 --- a/tools/perf/util/build-id.c +++ b/tools/perf/util/build-id.c @@ -144,7 +144,32 @@ static int asnprintf(char **strp, size_t size, const char *fmt, ...) return ret; } -static char *build_id__filename(const char *sbuild_id, char *bf, size_t size) +char *build_id_cache__kallsyms_path(const char *sbuild_id, char *bf, + size_t size) +{ + bool is_alloc = !!bf; + bool retry_old = true; + + asnprintf(&bf, size, "%s/%s/%s/kallsyms", + buildid_dir, DSO__NAME_KALLSYMS, sbuild_id); +retry: + if (!access(bf, F_OK)) + return bf; + if (is_alloc) + free(bf); + if (retry_old) { + /* Try old style kallsyms cache */ + asnprintf(&bf, size, "%s/%s/%s", + buildid_dir, DSO__NAME_KALLSYMS, sbuild_id); + retry_old = false; + goto retry; + } + + return NULL; +} + +static char *build_id_cache__linkname(const char *sbuild_id, char *bf, + size_t size) { char *tmp = bf; int ret = asnprintf(&bf, size, "%s/.build-id/%.2s/%s", buildid_dir, @@ -154,23 +179,52 @@ static char *build_id__filename(const char *sbuild_id, char *bf, size_t size) return bf; } +static const char *build_id_cache__basename(bool is_kallsyms, bool is_vdso) +{ + return is_kallsyms ? "kallsyms" : (is_vdso ? "vdso" : "elf"); +} + char *dso__build_id_filename(const struct dso *dso, char *bf, size_t size) { - char build_id_hex[SBUILD_ID_SIZE]; + bool is_kallsyms = dso__is_kallsyms((struct dso *)dso); + bool is_vdso = dso__is_vdso((struct dso *)dso); + char sbuild_id[SBUILD_ID_SIZE]; + char *linkname; + bool alloc = (bf == NULL); + int ret; if (!dso->has_build_id) return NULL; - build_id__sprintf(dso->build_id, sizeof(dso->build_id), build_id_hex); - return build_id__filename(build_id_hex, bf, size); + build_id__sprintf(dso->build_id, sizeof(dso->build_id), sbuild_id); + linkname = build_id_cache__linkname(sbuild_id, NULL, 0); + if (!linkname) + return NULL; + + /* Check if old style build_id cache */ + if (is_regular_file(linkname)) + ret = asnprintf(&bf, size, "%s", linkname); + else + ret = asnprintf(&bf, size, "%s/%s", linkname, + build_id_cache__basename(is_kallsyms, is_vdso)); + if (ret < 0 || (!alloc && size < (unsigned int)ret)) + bf = NULL; + free(linkname); + + return bf; } bool dso__build_id_is_kmod(const struct dso *dso, char *bf, size_t size) { - char *id_name, *ch; + char *id_name = NULL, *ch; struct stat sb; + char sbuild_id[SBUILD_ID_SIZE]; + + if (!dso->has_build_id) + goto err; - id_name = dso__build_id_filename(dso, bf, size); + build_id__sprintf(dso->build_id, sizeof(dso->build_id), sbuild_id); + id_name = build_id_cache__linkname(sbuild_id, NULL, 0); if (!id_name) goto err; if (access(id_name, F_OK)) @@ -194,18 +248,14 @@ bool dso__build_id_is_kmod(const struct dso *dso, char *bf, size_t size) if (ch - 3 < bf) goto err; + free(id_name); return strncmp(".ko", ch - 3, 3) == 0; err: - /* - * If dso__build_id_filename work, get id_name again, - * because id_name points to bf and is broken. - */ - if (id_name) - id_name = dso__build_id_filename(dso, bf, size); pr_err("Invalid build id: %s\n", id_name ? : dso->long_name ? : dso->short_name ? : "[unknown]"); + free(id_name); return false; } @@ -341,7 +391,8 @@ void disable_buildid_cache(void) } static char *build_id_cache__dirname_from_path(const char *name, - bool is_kallsyms, bool is_vdso) + bool is_kallsyms, bool is_vdso, + const char *sbuild_id) { char *realname = (char *)name, *filename; bool slash = is_kallsyms || is_vdso; @@ -352,8 +403,9 @@ static char *build_id_cache__dirname_from_path(const char *name, return NULL; } - if (asprintf(&filename, "%s%s%s", buildid_dir, slash ? "/" : "", - is_vdso ? DSO__NAME_VDSO : realname) < 0) + if (asprintf(&filename, "%s%s%s%s%s", buildid_dir, slash ? "/" : "", + is_vdso ? DSO__NAME_VDSO : realname, + sbuild_id ? "/" : "", sbuild_id ?: "") < 0) filename = NULL; if (!slash) @@ -368,7 +420,8 @@ int build_id_cache__list_build_ids(const char *pathname, char *dir_name; int ret = 0; - dir_name = build_id_cache__dirname_from_path(pathname, false, false); + dir_name = build_id_cache__dirname_from_path(pathname, false, false, + NULL); if (!dir_name) return -ENOMEM; @@ -385,7 +438,7 @@ int build_id_cache__add_s(const char *sbuild_id, const char *name, { const size_t size = PATH_MAX; char *realname = NULL, *filename = NULL, *dir_name = NULL, - *linkname = zalloc(size), *targetname, *tmp; + *linkname = zalloc(size), *tmp; int err = -1; if (!is_kallsyms) { @@ -394,14 +447,22 @@ int build_id_cache__add_s(const char *sbuild_id, const char *name, goto out_free; } - dir_name = build_id_cache__dirname_from_path(name, is_kallsyms, is_vdso); + dir_name = build_id_cache__dirname_from_path(name, is_kallsyms, + is_vdso, sbuild_id); if (!dir_name) goto out_free; + /* Remove old style build-id cache */ + if (is_regular_file(dir_name)) + if (unlink(dir_name)) + goto out_free; + if (mkdir_p(dir_name, 0755)) goto out_free; - if (asprintf(&filename, "%s/%s", dir_name, sbuild_id) < 0) { + /* Save the allocated buildid dirname */ + if (asprintf(&filename, "%s/%s", dir_name, + build_id_cache__basename(is_kallsyms, is_vdso)) < 0) { filename = NULL; goto out_free; } @@ -415,7 +476,7 @@ int build_id_cache__add_s(const char *sbuild_id, const char *name, goto out_free; } - if (!build_id__filename(sbuild_id, linkname, size)) + if (!build_id_cache__linkname(sbuild_id, linkname, size)) goto out_free; tmp = strrchr(linkname, '/'); *tmp = '\0'; @@ -424,10 +485,10 @@ int build_id_cache__add_s(const char *sbuild_id, const char *name, goto out_free; *tmp = '/'; - targetname = filename + strlen(buildid_dir) - 5; - memcpy(targetname, "../..", 5); + tmp = dir_name + strlen(buildid_dir) - 5; + memcpy(tmp, "../..", 5); - if (symlink(targetname, linkname) == 0) + if (symlink(tmp, linkname) == 0) err = 0; out_free: if (!is_kallsyms) @@ -452,7 +513,7 @@ static int build_id_cache__add_b(const u8 *build_id, size_t build_id_size, bool build_id_cache__cached(const char *sbuild_id) { bool ret = false; - char *filename = build_id__filename(sbuild_id, NULL, 0); + char *filename = build_id_cache__linkname(sbuild_id, NULL, 0); if (filename && !access(filename, F_OK)) ret = true; @@ -471,7 +532,7 @@ int build_id_cache__remove_s(const char *sbuild_id) if (filename == NULL || linkname == NULL) goto out_free; - if (!build_id__filename(sbuild_id, linkname, size)) + if (!build_id_cache__linkname(sbuild_id, linkname, size)) goto out_free; if (access(linkname, F_OK)) @@ -489,7 +550,7 @@ int build_id_cache__remove_s(const char *sbuild_id) tmp = strrchr(linkname, '/') + 1; snprintf(tmp, size - (tmp - linkname), "%s", filename); - if (unlink(linkname)) + if (rm_rf(linkname)) goto out_free; err = 0; @@ -501,7 +562,7 @@ out_free: static int dso__cache_build_id(struct dso *dso, struct machine *machine) { - bool is_kallsyms = dso->kernel && dso->long_name[0] != '/'; + bool is_kallsyms = dso__is_kallsyms(dso); bool is_vdso = dso__is_vdso(dso); const char *name = dso->long_name; char nm[PATH_MAX]; diff --git a/tools/perf/util/build-id.h b/tools/perf/util/build-id.h index 64af3e2..e5435f4 100644 --- a/tools/perf/util/build-id.h +++ b/tools/perf/util/build-id.h @@ -14,6 +14,8 @@ struct dso; int build_id__sprintf(const u8 *build_id, int len, char *bf); int sysfs__sprintf_build_id(const char *root_dir, char *sbuild_id); int filename__sprintf_build_id(const char *pathname, char *sbuild_id); +char *build_id_cache__kallsyms_path(const char *sbuild_id, char *bf, + size_t size); char *dso__build_id_filename(const struct dso *dso, char *bf, size_t size); bool dso__build_id_is_kmod(const struct dso *dso, char *bf, size_t size); diff --git a/tools/perf/util/dso.h b/tools/perf/util/dso.h index 0953280..76d79d0 100644 --- a/tools/perf/util/dso.h +++ b/tools/perf/util/dso.h @@ -349,6 +349,11 @@ static inline bool dso__is_kcore(struct dso *dso) dso->binary_type == DSO_BINARY_TYPE__GUEST_KCORE; } +static inline bool dso__is_kallsyms(struct dso *dso) +{ + return dso->kernel && dso->long_name[0] != '/'; +} + void dso__free_a2l(struct dso *dso); enum dso_type dso__type(struct dso *dso, struct machine *machine); diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index 1df6092..09c5c34 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c @@ -1704,10 +1704,7 @@ proc_kallsyms: } /* Finally, find a cache of kallsyms */ - scnprintf(path, sizeof(path), "%s/%s/%s", - buildid_dir, DSO__NAME_KALLSYMS, sbuild_id); - - if (access(path, F_OK)) { + if (!build_id_cache__kallsyms_path(sbuild_id, path, sizeof(path))) { pr_err("No kallsyms or vmlinux with build-id %s was found\n", sbuild_id); return NULL; -- cgit v0.10.2 From 500e06b9a3f50d3db992eb3b8dc309f695d33f63 Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Tue, 31 May 2016 19:09:55 +0530 Subject: ASoC: hdac_hdmi: Fix potential NULL dereference Static checker warns: Pointer 'hlink' returned from call to function 'snd_hdac_ext_bus_get_link' at line may be NULL and will be dereferenced" So we should always check the return of snd_hdac_ext_bus_get_link() before referencing the link pointer Signed-off-by: Vinod Koul Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c index 181cd3b..2abb742 100644 --- a/sound/soc/codecs/hdac_hdmi.c +++ b/sound/soc/codecs/hdac_hdmi.c @@ -1474,6 +1474,11 @@ static int hdmi_codec_probe(struct snd_soc_codec *codec) * exit, we call pm_runtime_suspend() so that will do for us */ hlink = snd_hdac_ext_bus_get_link(edev->ebus, dev_name(&edev->hdac.dev)); + if (!hlink) { + dev_err(&edev->hdac.dev, "hdac link not found\n"); + return -EIO; + } + snd_hdac_ext_bus_link_get(edev->ebus, hlink); ret = create_fill_widget_route_map(dapm); @@ -1634,6 +1639,11 @@ static int hdac_hdmi_dev_probe(struct hdac_ext_device *edev) /* hold the ref while we probe */ hlink = snd_hdac_ext_bus_get_link(edev->ebus, dev_name(&edev->hdac.dev)); + if (!hlink) { + dev_err(&edev->hdac.dev, "hdac link not found\n"); + return -EIO; + } + snd_hdac_ext_bus_link_get(edev->ebus, hlink); hdmi_priv = devm_kzalloc(&codec->dev, sizeof(*hdmi_priv), GFP_KERNEL); @@ -1744,6 +1754,11 @@ static int hdac_hdmi_runtime_suspend(struct device *dev) } hlink = snd_hdac_ext_bus_get_link(ebus, dev_name(dev)); + if (!hlink) { + dev_err(dev, "hdac link not found\n"); + return -EIO; + } + snd_hdac_ext_bus_link_put(ebus, hlink); return 0; @@ -1765,6 +1780,11 @@ static int hdac_hdmi_runtime_resume(struct device *dev) return 0; hlink = snd_hdac_ext_bus_get_link(ebus, dev_name(dev)); + if (!hlink) { + dev_err(dev, "hdac link not found\n"); + return -EIO; + } + snd_hdac_ext_bus_link_get(ebus, hlink); err = snd_hdac_display_power(bus, true); -- cgit v0.10.2 From becc7ae544c61395b5eba7b9913e14aa567ca07a Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Sun, 22 May 2016 11:06:06 +0200 Subject: MAINTAINERS: Add file patterns for mtd device tree bindings Submitters of device tree binding documentation may forget to CC the subsystem maintainer if this is missing. Signed-off-by: Geert Uytterhoeven Cc: David Woodhouse Cc: linux-mtd@lists.infradead.org Signed-off-by: Brian Norris diff --git a/MAINTAINERS b/MAINTAINERS index 7304d2e..adcb370 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -7457,6 +7457,7 @@ Q: http://patchwork.ozlabs.org/project/linux-mtd/list/ T: git git://git.infradead.org/linux-mtd.git T: git git://git.infradead.org/l2-mtd.git S: Maintained +F: Documentation/devicetree/bindings/mtd/ F: drivers/mtd/ F: include/linux/mtd/ F: include/uapi/mtd/ -- cgit v0.10.2 From 8e1cc0e4bab7b44a55ea59d26683b618b34950bc Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Thu, 2 Jun 2016 12:55:05 +0300 Subject: ASoC: davinci-mcasp: Fix dra7 DMA offset when using CFG port The TX and RX offset is different for each serializers when using the CFG port for DMA access. When using the CFG port only one serializer can be used per direction so print error message and only configure the first serializer's offset. Reported-by: Misael Lopez Cruz Suggested-by: Misael Lopez Cruz Signed-off-by: Peter Ujfalusi Signed-off-by: Mark Brown diff --git a/sound/soc/davinci/davinci-mcasp.c b/sound/soc/davinci/davinci-mcasp.c index 0f66fda..237dc67 100644 --- a/sound/soc/davinci/davinci-mcasp.c +++ b/sound/soc/davinci/davinci-mcasp.c @@ -1513,8 +1513,9 @@ static struct davinci_mcasp_pdata am33xx_mcasp_pdata = { }; static struct davinci_mcasp_pdata dra7_mcasp_pdata = { - .tx_dma_offset = 0x200, - .rx_dma_offset = 0x284, + /* The CFG port offset will be calculated if it is needed */ + .tx_dma_offset = 0, + .rx_dma_offset = 0, .version = MCASP_VERSION_4, }; @@ -1734,6 +1735,52 @@ static int davinci_mcasp_get_dma_type(struct davinci_mcasp *mcasp) return PCM_EDMA; } +static u32 davinci_mcasp_txdma_offset(struct davinci_mcasp_pdata *pdata) +{ + int i; + u32 offset = 0; + + if (pdata->version != MCASP_VERSION_4) + return pdata->tx_dma_offset; + + for (i = 0; i < pdata->num_serializer; i++) { + if (pdata->serial_dir[i] == TX_MODE) { + if (!offset) { + offset = DAVINCI_MCASP_TXBUF_REG(i); + } else { + pr_err("%s: Only one serializer allowed!\n", + __func__); + break; + } + } + } + + return offset; +} + +static u32 davinci_mcasp_rxdma_offset(struct davinci_mcasp_pdata *pdata) +{ + int i; + u32 offset = 0; + + if (pdata->version != MCASP_VERSION_4) + return pdata->rx_dma_offset; + + for (i = 0; i < pdata->num_serializer; i++) { + if (pdata->serial_dir[i] == RX_MODE) { + if (!offset) { + offset = DAVINCI_MCASP_RXBUF_REG(i); + } else { + pr_err("%s: Only one serializer allowed!\n", + __func__); + break; + } + } + } + + return offset; +} + static int davinci_mcasp_probe(struct platform_device *pdev) { struct snd_dmaengine_dai_dma_data *dma_data; @@ -1862,7 +1909,7 @@ static int davinci_mcasp_probe(struct platform_device *pdev) if (dat) dma_data->addr = dat->start; else - dma_data->addr = mem->start + pdata->tx_dma_offset; + dma_data->addr = mem->start + davinci_mcasp_txdma_offset(pdata); dma = &mcasp->dma_request[SNDRV_PCM_STREAM_PLAYBACK]; res = platform_get_resource(pdev, IORESOURCE_DMA, 0); @@ -1883,7 +1930,8 @@ static int davinci_mcasp_probe(struct platform_device *pdev) if (dat) dma_data->addr = dat->start; else - dma_data->addr = mem->start + pdata->rx_dma_offset; + dma_data->addr = + mem->start + davinci_mcasp_rxdma_offset(pdata); dma = &mcasp->dma_request[SNDRV_PCM_STREAM_CAPTURE]; res = platform_get_resource(pdev, IORESOURCE_DMA, 1); diff --git a/sound/soc/davinci/davinci-mcasp.h b/sound/soc/davinci/davinci-mcasp.h index 1e8787f..afddc80 100644 --- a/sound/soc/davinci/davinci-mcasp.h +++ b/sound/soc/davinci/davinci-mcasp.h @@ -85,9 +85,9 @@ (n << 2)) /* Transmit Buffer for Serializer n */ -#define DAVINCI_MCASP_TXBUF_REG 0x200 +#define DAVINCI_MCASP_TXBUF_REG(n) (0x200 + (n << 2)) /* Receive Buffer for Serializer n */ -#define DAVINCI_MCASP_RXBUF_REG 0x280 +#define DAVINCI_MCASP_RXBUF_REG(n) (0x280 + (n << 2)) /* McASP FIFO Registers */ #define DAVINCI_MCASP_V2_AFIFO_BASE (0x1010) -- cgit v0.10.2 From 6de7df8d1b1a45a07d6ecc6b4f94179e1e68f5ec Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Tue, 31 May 2016 23:12:00 +0200 Subject: ASoC: hdmi-codec: select CONFIG_HDMI SND_SOC_HDMI_CODEC can be enabled without HDMI support, leading to a link error: In function `hdmi_codec_hw_params': sound/soc/codecs/hdmi-codec.c:188: undefined reference to `hdmi_audio_infoframe_init' sound/built-in.o:(.debug_addr+0x1a5c0): undefined reference to `hdmi_audio_infoframe_init' This changes the Kconfig file to select HDMI, as the other codec using hdmi_audio_infoframe_init already does. Signed-off-by: Arnd Bergmann Acked-by: Jyri Sarha Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 4d82a58..f3fb98f 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -483,9 +483,10 @@ config SND_SOC_DMIC tristate config SND_SOC_HDMI_CODEC - tristate - select SND_PCM_ELD - select SND_PCM_IEC958 + tristate + select SND_PCM_ELD + select SND_PCM_IEC958 + select HDMI config SND_SOC_ES8328 tristate "Everest Semi ES8328 CODEC" -- cgit v0.10.2 From 1a99ae3f00d3c7c7885ee529ac9a874b19caa0cf Mon Sep 17 00:00:00 2001 From: Xunlei Pang Date: Tue, 10 May 2016 21:03:18 +0800 Subject: sched/fair: Fix the wrong throttled clock time for cfs_rq_clock_task() Two minor fixes for cfs_rq_clock_task(): 1) If cfs_rq is currently being throttled, we need to subtract the cfs throttled clock time. 2) Make "throttled_clock_task_time" update SMP unrelated. Now UP cases need it as well. Signed-off-by: Xunlei Pang Signed-off-by: Peter Zijlstra (Intel) Cc: Juri Lelli Cc: Linus Torvalds Cc: Mike Galbraith Cc: Peter Zijlstra Cc: Steven Rostedt Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/1462885398-14724-1-git-send-email-xlpang@redhat.com Signed-off-by: Ingo Molnar diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c index 218f8e8..1e87bb6 100644 --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c @@ -3688,7 +3688,7 @@ static inline struct cfs_bandwidth *tg_cfs_bandwidth(struct task_group *tg) static inline u64 cfs_rq_clock_task(struct cfs_rq *cfs_rq) { if (unlikely(cfs_rq->throttle_count)) - return cfs_rq->throttled_clock_task; + return cfs_rq->throttled_clock_task - cfs_rq->throttled_clock_task_time; return rq_clock_task(rq_of(cfs_rq)) - cfs_rq->throttled_clock_task_time; } @@ -3826,13 +3826,11 @@ static int tg_unthrottle_up(struct task_group *tg, void *data) struct cfs_rq *cfs_rq = tg->cfs_rq[cpu_of(rq)]; cfs_rq->throttle_count--; -#ifdef CONFIG_SMP if (!cfs_rq->throttle_count) { /* adjust cfs_rq_clock_task() */ cfs_rq->throttled_clock_task_time += rq_clock_task(rq) - cfs_rq->throttled_clock_task; } -#endif return 0; } -- cgit v0.10.2 From df55f462b905f3b2d40ec3fb865891382a6ebfb1 Mon Sep 17 00:00:00 2001 From: "Gaurav Jindal (Gaurav Jindal)" Date: Thu, 12 May 2016 10:13:33 +0000 Subject: sched/idle: Optimize the generic idle loop Currently, smp_processor_id() is used to fetch the current CPU in cpu_idle_loop(). Every time the idle thread runs, it fetches the current CPU using smp_processor_id(). Since the idle thread is per CPU, the current CPU is constant, so we can lift the load out of the loop, saving execution cycles/time in the loop. x86-64: Before patch (execution in loop): 148: 0f ae e8 lfence 14b: 65 8b 04 25 00 00 00 00 mov %gs:0x0,%eax 152: 00 153: 89 c0 mov %eax,%eax 155: 49 0f a3 04 24 bt %rax,(%r12) After patch (execution in loop): 150: 0f ae e8 lfence 153: 4d 0f a3 34 24 bt %r14,(%r12) ARM64: Before patch (execution in loop): 168: d5033d9f dsb ld 16c: b9405661 ldr w1,[x19,#84] 170: 1100fc20 add w0,w1,#0x3f 174: 6b1f003f cmp w1,wzr 178: 1a81b000 csel w0,w0,w1,lt 17c: 130c7000 asr w0,w0,#6 180: 937d7c00 sbfiz x0,x0,#3,#32 184: f8606aa0 ldr x0,[x21,x0] 188: 9ac12401 lsr x1,x0,x1 18c: 36000e61 tbz w1,#0,358 After patch (execution in loop): 1a8: d50339df dsb ld 1ac: f8776ac0 ldr x0,[x22,x23] ab0: ea18001f tst x0,x24 1b4: 54000ea0 b.eq 388 Further observance on ARM64 for 4 seconds shows that cpu_idle_loop is called 8672 times. Shifting the code will save instructions executed in loop and eventually time as well. Signed-off-by: Gaurav Jindal Signed-off-by: Peter Zijlstra (Intel) Reviewed-by: Sanjeev Yadav Cc: Linus Torvalds Cc: Mike Galbraith Cc: Peter Zijlstra Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/20160512101330.GA488@gauravjindalubtnb.del.spreadtrum.com Signed-off-by: Ingo Molnar diff --git a/kernel/sched/idle.c b/kernel/sched/idle.c index bd12c6c..db4ff7c 100644 --- a/kernel/sched/idle.c +++ b/kernel/sched/idle.c @@ -201,6 +201,8 @@ exit_idle: */ static void cpu_idle_loop(void) { + int cpu = smp_processor_id(); + while (1) { /* * If the arch has a polling bit, we maintain an invariant: @@ -219,7 +221,7 @@ static void cpu_idle_loop(void) check_pgt_cache(); rmb(); - if (cpu_is_offline(smp_processor_id())) { + if (cpu_is_offline(cpu)) { cpuhp_report_idle_dead(); arch_cpu_idle_dead(); } -- cgit v0.10.2 From 150593bf869393d10a79f6bd3df2585ecc20a9bb Mon Sep 17 00:00:00 2001 From: Oleg Nesterov Date: Wed, 18 May 2016 19:02:18 +0200 Subject: sched/api: Introduce task_rcu_dereference() and try_get_task_struct() Generally task_struct is only protected by RCU if it was found on a RCU protected list (say, for_each_process() or find_task_by_vpid()). As Kirill pointed out rq->curr isn't protected by RCU, the scheduler drops the (potentially) last reference without RCU gp, this means that we need to fix the code which uses foreign_rq->curr under rcu_read_lock(). Add a new helper which can be used to dereference rq->curr or any other pointer to task_struct assuming that it should be cleared or updated before the final put_task_struct(). It returns non-NULL only if this task can't go away before rcu_read_unlock(). ( Also add try_get_task_struct() to make it easier to use this API correctly. ) Suggested-by: Kirill Tkhai Signed-off-by: Oleg Nesterov [ Updated comments; added try_get_task_struct()] Signed-off-by: Peter Zijlstra (Intel) Cc: Chris Metcalf Cc: Christoph Lameter Cc: Kirill Tkhai Cc: Linus Torvalds Cc: Mike Galbraith Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: Vladimir Davydov Link: http://lkml.kernel.org/r/20160518170218.GY3192@twins.programming.kicks-ass.net Signed-off-by: Ingo Molnar diff --git a/include/linux/sched.h b/include/linux/sched.h index 6e42ada..dee41bf 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -2139,6 +2139,9 @@ static inline void put_task_struct(struct task_struct *t) __put_task_struct(t); } +struct task_struct *task_rcu_dereference(struct task_struct **ptask); +struct task_struct *try_get_task_struct(struct task_struct **ptask); + #ifdef CONFIG_VIRT_CPU_ACCOUNTING_GEN extern void task_cputime(struct task_struct *t, cputime_t *utime, cputime_t *stime); diff --git a/kernel/exit.c b/kernel/exit.c index 9e6e135..2fb4d44 100644 --- a/kernel/exit.c +++ b/kernel/exit.c @@ -211,6 +211,82 @@ repeat: } /* + * Note that if this function returns a valid task_struct pointer (!NULL) + * task->usage must remain >0 for the duration of the RCU critical section. + */ +struct task_struct *task_rcu_dereference(struct task_struct **ptask) +{ + struct sighand_struct *sighand; + struct task_struct *task; + + /* + * We need to verify that release_task() was not called and thus + * delayed_put_task_struct() can't run and drop the last reference + * before rcu_read_unlock(). We check task->sighand != NULL, + * but we can read the already freed and reused memory. + */ +retry: + task = rcu_dereference(*ptask); + if (!task) + return NULL; + + probe_kernel_address(&task->sighand, sighand); + + /* + * Pairs with atomic_dec_and_test() in put_task_struct(). If this task + * was already freed we can not miss the preceding update of this + * pointer. + */ + smp_rmb(); + if (unlikely(task != READ_ONCE(*ptask))) + goto retry; + + /* + * We've re-checked that "task == *ptask", now we have two different + * cases: + * + * 1. This is actually the same task/task_struct. In this case + * sighand != NULL tells us it is still alive. + * + * 2. This is another task which got the same memory for task_struct. + * We can't know this of course, and we can not trust + * sighand != NULL. + * + * In this case we actually return a random value, but this is + * correct. + * + * If we return NULL - we can pretend that we actually noticed that + * *ptask was updated when the previous task has exited. Or pretend + * that probe_slab_address(&sighand) reads NULL. + * + * If we return the new task (because sighand is not NULL for any + * reason) - this is fine too. This (new) task can't go away before + * another gp pass. + * + * And note: We could even eliminate the false positive if re-read + * task->sighand once again to avoid the falsely NULL. But this case + * is very unlikely so we don't care. + */ + if (!sighand) + return NULL; + + return task; +} + +struct task_struct *try_get_task_struct(struct task_struct **ptask) +{ + struct task_struct *task; + + rcu_read_lock(); + task = task_rcu_dereference(ptask); + if (task) + get_task_struct(task); + rcu_read_unlock(); + + return task; +} + +/* * Determine if a process group is "orphaned", according to the POSIX * definition in 2.2.2.52. Orphaned process groups are not to be affected * by terminal-generated stop signals. Newly orphaned process groups are -- cgit v0.10.2 From bac7857319bcf7fed329a10bb760053e761115c0 Mon Sep 17 00:00:00 2001 From: Oleg Nesterov Date: Wed, 18 May 2016 21:57:33 +0200 Subject: sched/fair: Use task_rcu_dereference() Simplify task_numa_compare()'s task reference magic by using task_rcu_dereference(). Signed-off-by: Oleg Nesterov Signed-off-by: Peter Zijlstra (Intel) Cc: Chris Metcalf Cc: Christoph Lameter Cc: Kirill Tkhai Cc: Kirill Tkhai Cc: Linus Torvalds Cc: Mike Galbraith Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: Vladimir Davydov Link: http://lkml.kernel.org/r/20160518195733.GA15914@redhat.com Signed-off-by: Ingo Molnar diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c index 1e87bb6..c6dd8ba 100644 --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c @@ -1305,6 +1305,8 @@ static void task_numa_assign(struct task_numa_env *env, { if (env->best_task) put_task_struct(env->best_task); + if (p) + get_task_struct(p); env->best_task = p; env->best_imp = imp; @@ -1372,31 +1374,11 @@ static void task_numa_compare(struct task_numa_env *env, long imp = env->p->numa_group ? groupimp : taskimp; long moveimp = imp; int dist = env->dist; - bool assigned = false; rcu_read_lock(); - - raw_spin_lock_irq(&dst_rq->lock); - cur = dst_rq->curr; - /* - * No need to move the exiting task or idle task. - */ - if ((cur->flags & PF_EXITING) || is_idle_task(cur)) + cur = task_rcu_dereference(&dst_rq->curr); + if (cur && ((cur->flags & PF_EXITING) || is_idle_task(cur))) cur = NULL; - else { - /* - * The task_struct must be protected here to protect the - * p->numa_faults access in the task_weight since the - * numa_faults could already be freed in the following path: - * finish_task_switch() - * --> put_task_struct() - * --> __put_task_struct() - * --> task_numa_free() - */ - get_task_struct(cur); - } - - raw_spin_unlock_irq(&dst_rq->lock); /* * Because we have preemption enabled we can get migrated around and @@ -1479,7 +1461,6 @@ balance: */ if (!load_too_imbalanced(src_load, dst_load, env)) { imp = moveimp - 1; - put_task_struct(cur); cur = NULL; goto assign; } @@ -1505,16 +1486,9 @@ balance: env->dst_cpu = select_idle_sibling(env->p, env->dst_cpu); assign: - assigned = true; task_numa_assign(env, cur, imp); unlock: rcu_read_unlock(); - /* - * The dst_rq->curr isn't assigned. The protection for task_struct is - * finished. - */ - if (cur && !assigned) - put_task_struct(cur); } static void task_numa_find_cpu(struct task_numa_env *env, -- cgit v0.10.2 From f2fb6bef92514432398a653df1c2f1041d79ac46 Mon Sep 17 00:00:00 2001 From: Kan Liang Date: Wed, 23 Mar 2016 11:24:37 -0700 Subject: perf/core: Optimize side-band event delivery The perf_event_aux() function iterates all PMUs and all events in their respective per-CPU contexts to find the events to deliver side-band records to. For example, the brk test case in lkp triggers many mmap() operations, which, if we're also running perf, results in many perf_event_aux() invocations. If we enable uncore PMU support (even when uncore events are not used), dozens of uncore PMUs will be iterated, which can significantly decrease brk_test's throughput. For example, the brk throughput: without uncore PMUs: 2647573 ops_per_sec with uncore PMUs: 1768444 ops_per_sec ... a 33% reduction. To get at the per-CPU events that need side-band records, this patch puts these events on a per-CPU list, this avoids iterating the PMUs and any events that do not need side-band records. Per task events are unchanged to avoid extra overhead on the context switch paths. Suggested-by: Peter Zijlstra (Intel) Reported-by: Huang, Ying Signed-off-by: Kan Liang Signed-off-by: Peter Zijlstra (Intel) Cc: Alexander Shishkin Cc: Arnaldo Carvalho de Melo Cc: Jiri Olsa Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Thomas Gleixner Cc: Vince Weaver Link: http://lkml.kernel.org/r/1458757477-3781-1-git-send-email-kan.liang@intel.com Signed-off-by: Ingo Molnar diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h index 0e43355..92e9ce7 100644 --- a/include/linux/perf_event.h +++ b/include/linux/perf_event.h @@ -517,6 +517,11 @@ struct swevent_hlist { struct perf_cgroup; struct ring_buffer; +struct pmu_event_list { + raw_spinlock_t lock; + struct list_head list; +}; + /** * struct perf_event - performance event kernel representation: */ @@ -675,6 +680,7 @@ struct perf_event { int cgrp_defer_enabled; #endif + struct list_head sb_list; #endif /* CONFIG_PERF_EVENTS */ }; diff --git a/kernel/events/core.c b/kernel/events/core.c index 79363f2..6615c89 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c @@ -335,6 +335,7 @@ static atomic_t perf_sched_count; static DEFINE_PER_CPU(atomic_t, perf_cgroup_events); static DEFINE_PER_CPU(int, perf_sched_cb_usages); +static DEFINE_PER_CPU(struct pmu_event_list, pmu_sb_events); static atomic_t nr_mmap_events __read_mostly; static atomic_t nr_comm_events __read_mostly; @@ -3665,6 +3666,26 @@ static void free_event_rcu(struct rcu_head *head) static void ring_buffer_attach(struct perf_event *event, struct ring_buffer *rb); +static void detach_sb_event(struct perf_event *event) +{ + struct pmu_event_list *pel = per_cpu_ptr(&pmu_sb_events, event->cpu); + + raw_spin_lock(&pel->lock); + list_del_rcu(&event->sb_list); + raw_spin_unlock(&pel->lock); +} + +static void unaccount_pmu_sb_event(struct perf_event *event) +{ + if (event->parent) + return; + + if (event->attach_state & PERF_ATTACH_TASK) + return; + + detach_sb_event(event); +} + static void unaccount_event_cpu(struct perf_event *event, int cpu) { if (event->parent) @@ -3728,6 +3749,8 @@ static void unaccount_event(struct perf_event *event) } unaccount_event_cpu(event, event->cpu); + + unaccount_pmu_sb_event(event); } static void perf_sched_delayed(struct work_struct *work) @@ -5888,13 +5911,25 @@ perf_event_aux_task_ctx(perf_event_aux_output_cb output, void *data, rcu_read_unlock(); } +static void perf_event_sb_iterate(perf_event_aux_output_cb output, void *data) +{ + struct pmu_event_list *pel = this_cpu_ptr(&pmu_sb_events); + struct perf_event *event; + + list_for_each_entry_rcu(event, &pel->list, sb_list) { + if (event->state < PERF_EVENT_STATE_INACTIVE) + continue; + if (!event_filter_match(event)) + continue; + output(event, data); + } +} + static void perf_event_aux(perf_event_aux_output_cb output, void *data, struct perf_event_context *task_ctx) { - struct perf_cpu_context *cpuctx; struct perf_event_context *ctx; - struct pmu *pmu; int ctxn; /* @@ -5909,20 +5944,15 @@ perf_event_aux(perf_event_aux_output_cb output, void *data, } rcu_read_lock(); - list_for_each_entry_rcu(pmu, &pmus, entry) { - cpuctx = get_cpu_ptr(pmu->pmu_cpu_context); - if (cpuctx->unique_pmu != pmu) - goto next; - perf_event_aux_ctx(&cpuctx->ctx, output, data, false); - ctxn = pmu->task_ctx_nr; - if (ctxn < 0) - goto next; + preempt_disable(); + perf_event_sb_iterate(output, data); + + for_each_task_context_nr(ctxn) { ctx = rcu_dereference(current->perf_event_ctxp[ctxn]); if (ctx) perf_event_aux_ctx(ctx, output, data, false); -next: - put_cpu_ptr(pmu->pmu_cpu_context); } + preempt_enable(); rcu_read_unlock(); } @@ -8615,6 +8645,32 @@ unlock: return pmu; } +static void attach_sb_event(struct perf_event *event) +{ + struct pmu_event_list *pel = per_cpu_ptr(&pmu_sb_events, event->cpu); + + raw_spin_lock(&pel->lock); + list_add_rcu(&event->sb_list, &pel->list); + raw_spin_unlock(&pel->lock); +} + +static void account_pmu_sb_event(struct perf_event *event) +{ + struct perf_event_attr *attr = &event->attr; + + if (event->parent) + return; + + if (event->attach_state & PERF_ATTACH_TASK) + return; + + if (attr->mmap || attr->mmap_data || attr->mmap2 || + attr->comm || attr->comm_exec || + attr->task || + attr->context_switch) + attach_sb_event(event); +} + static void account_event_cpu(struct perf_event *event, int cpu) { if (event->parent) @@ -8695,6 +8751,8 @@ static void account_event(struct perf_event *event) enabled: account_event_cpu(event, event->cpu); + + account_pmu_sb_event(event); } /* @@ -10203,6 +10261,9 @@ static void __init perf_event_init_all_cpus(void) swhash = &per_cpu(swevent_htable, cpu); mutex_init(&swhash->hlist_mutex); INIT_LIST_HEAD(&per_cpu(active_ctx_list, cpu)); + + INIT_LIST_HEAD(&per_cpu(pmu_sb_events.list, cpu)); + raw_spin_lock_init(&per_cpu(pmu_sb_events.lock, cpu)); } } -- cgit v0.10.2 From aab5b71ef2b5c62323b9abe397e2db57b18e1f78 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Thu, 12 May 2016 17:26:46 +0200 Subject: perf/core: Rename the perf_event_aux*() APIs to perf_event_sb*(), to separate them from AUX ring-buffer records There are now two different things called AUX in perf, the infrastructure to deliver the mmap/comm/task records and the AUX part in the mmap buffer (with associated AUX_RECORD). Since the former is internal, rename it to side-band to reduce the confusion factor. No change in functionality. Signed-off-by: Peter Zijlstra (Intel) Cc: Alexander Shishkin Cc: Arnaldo Carvalho de Melo Cc: Jiri Olsa Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Thomas Gleixner Cc: Vince Weaver Cc: linux-kernel@vger.kernel.org Signed-off-by: Ingo Molnar diff --git a/kernel/events/core.c b/kernel/events/core.c index 6615c89..f54454e 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c @@ -5879,11 +5879,11 @@ perf_event_read_event(struct perf_event *event, perf_output_end(&handle); } -typedef void (perf_event_aux_output_cb)(struct perf_event *event, void *data); +typedef void (perf_iterate_f)(struct perf_event *event, void *data); static void -perf_event_aux_ctx(struct perf_event_context *ctx, - perf_event_aux_output_cb output, +perf_iterate_ctx(struct perf_event_context *ctx, + perf_iterate_f output, void *data, bool all) { struct perf_event *event; @@ -5900,18 +5900,7 @@ perf_event_aux_ctx(struct perf_event_context *ctx, } } -static void -perf_event_aux_task_ctx(perf_event_aux_output_cb output, void *data, - struct perf_event_context *task_ctx) -{ - rcu_read_lock(); - preempt_disable(); - perf_event_aux_ctx(task_ctx, output, data, false); - preempt_enable(); - rcu_read_unlock(); -} - -static void perf_event_sb_iterate(perf_event_aux_output_cb output, void *data) +static void perf_iterate_sb_cpu(perf_iterate_f output, void *data) { struct pmu_event_list *pel = this_cpu_ptr(&pmu_sb_events); struct perf_event *event; @@ -5925,33 +5914,40 @@ static void perf_event_sb_iterate(perf_event_aux_output_cb output, void *data) } } +/* + * Iterate all events that need to receive side-band events. + * + * For new callers; ensure that account_pmu_sb_event() includes + * your event, otherwise it might not get delivered. + */ static void -perf_event_aux(perf_event_aux_output_cb output, void *data, +perf_iterate_sb(perf_iterate_f output, void *data, struct perf_event_context *task_ctx) { struct perf_event_context *ctx; int ctxn; + rcu_read_lock(); + preempt_disable(); + /* - * If we have task_ctx != NULL we only notify - * the task context itself. The task_ctx is set - * only for EXIT events before releasing task + * If we have task_ctx != NULL we only notify the task context itself. + * The task_ctx is set only for EXIT events before releasing task * context. */ if (task_ctx) { - perf_event_aux_task_ctx(output, data, task_ctx); - return; + perf_iterate_ctx(task_ctx, output, data, false); + goto done; } - rcu_read_lock(); - preempt_disable(); - perf_event_sb_iterate(output, data); + perf_iterate_sb_cpu(output, data); for_each_task_context_nr(ctxn) { ctx = rcu_dereference(current->perf_event_ctxp[ctxn]); if (ctx) - perf_event_aux_ctx(ctx, output, data, false); + perf_iterate_ctx(ctx, output, data, false); } +done: preempt_enable(); rcu_read_unlock(); } @@ -6001,7 +5997,7 @@ void perf_event_exec(void) perf_event_enable_on_exec(ctxn); - perf_event_aux_ctx(ctx, perf_event_addr_filters_exec, NULL, + perf_iterate_ctx(ctx, perf_event_addr_filters_exec, NULL, true); } rcu_read_unlock(); @@ -6045,9 +6041,9 @@ static int __perf_pmu_output_stop(void *info) }; rcu_read_lock(); - perf_event_aux_ctx(&cpuctx->ctx, __perf_event_output_stop, &ro, false); + perf_iterate_ctx(&cpuctx->ctx, __perf_event_output_stop, &ro, false); if (cpuctx->task_ctx) - perf_event_aux_ctx(cpuctx->task_ctx, __perf_event_output_stop, + perf_iterate_ctx(cpuctx->task_ctx, __perf_event_output_stop, &ro, false); rcu_read_unlock(); @@ -6176,7 +6172,7 @@ static void perf_event_task(struct task_struct *task, }, }; - perf_event_aux(perf_event_task_output, + perf_iterate_sb(perf_event_task_output, &task_event, task_ctx); } @@ -6255,7 +6251,7 @@ static void perf_event_comm_event(struct perf_comm_event *comm_event) comm_event->event_id.header.size = sizeof(comm_event->event_id) + size; - perf_event_aux(perf_event_comm_output, + perf_iterate_sb(perf_event_comm_output, comm_event, NULL); } @@ -6486,7 +6482,7 @@ got_name: mmap_event->event_id.header.size = sizeof(mmap_event->event_id) + size; - perf_event_aux(perf_event_mmap_output, + perf_iterate_sb(perf_event_mmap_output, mmap_event, NULL); @@ -6569,7 +6565,7 @@ static void perf_addr_filters_adjust(struct vm_area_struct *vma) if (!ctx) continue; - perf_event_aux_ctx(ctx, __perf_addr_filters_adjust, vma, true); + perf_iterate_ctx(ctx, __perf_addr_filters_adjust, vma, true); } rcu_read_unlock(); } @@ -6756,7 +6752,7 @@ static void perf_event_switch(struct task_struct *task, }, }; - perf_event_aux(perf_event_switch_output, + perf_iterate_sb(perf_event_switch_output, &switch_event, NULL); } @@ -8654,6 +8650,13 @@ static void attach_sb_event(struct perf_event *event) raw_spin_unlock(&pel->lock); } +/* + * We keep a list of all !task (and therefore per-cpu) events + * that need to receive side-band records. + * + * This avoids having to scan all the various PMU per-cpu contexts + * looking for them. + */ static void account_pmu_sb_event(struct perf_event *event) { struct perf_event_attr *attr = &event->attr; -- cgit v0.10.2 From ab7fdefba68f66c8523571c3b3a940635d781824 Mon Sep 17 00:00:00 2001 From: Kan Liang Date: Tue, 3 May 2016 00:26:06 -0700 Subject: perf/core: Fix implicitly enable dynamic interrupt throttle This patch fixes an issue which was introduced by commit: 91a612eea9a3 ("perf/core: Fix dynamic interrupt throttle") ... which commit unconditionally sets the perf_sample_allowed_ns value to !0. But that could trigger a bug in the following corner case: The user can disable the dynamic interrupt throttle mechanism by setting perf_cpu_time_max_percent to 0. Then they change perf_event_max_sample_rate. For this case, the mechanism will be enabled implicitly, because perf_sample_allowed_ns becomes !0 - which is not what we want. This patch only updates perf_sample_allowed_ns when the dynamic interrupt throttle mechanism is enabled. Signed-off-by: Kan Liang Signed-off-by: Peter Zijlstra (Intel) Cc: Alexander Shishkin Cc: Arnaldo Carvalho de Melo Cc: Jiri Olsa Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Thomas Gleixner Cc: Vince Weaver Cc: acme@kernel.org Link: http://lkml.kernel.org/r/1462260366-3160-1-git-send-email-kan.liang@intel.com Signed-off-by: Ingo Molnar diff --git a/kernel/events/core.c b/kernel/events/core.c index f54454e..f94f164 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c @@ -397,6 +397,13 @@ int perf_proc_update_handler(struct ctl_table *table, int write, if (ret || !write) return ret; + /* + * If throttling is disabled don't allow the write: + */ + if (sysctl_perf_cpu_time_max_percent == 100 || + sysctl_perf_cpu_time_max_percent == 0) + return -EINVAL; + max_samples_per_tick = DIV_ROUND_UP(sysctl_perf_event_sample_rate, HZ); perf_sample_period_ns = NSEC_PER_SEC / sysctl_perf_event_sample_rate; update_perf_cpu_limits(); -- cgit v0.10.2 From 20f362785869196fb61a76661a48321169a9046e Mon Sep 17 00:00:00 2001 From: Lukasz Odzioba Date: Mon, 16 May 2016 23:16:18 +0200 Subject: perf/x86/intel: Add 'static' keyword to locally used arrays Add the 'static' keyword to intel_bdw_event_constraints[], snb_events_attrs[], nhm_events_attrs[] and intel_skl_event_constraints arrays[], because they are only used locally. Signed-off-by: Lukasz Odzioba Signed-off-by: Peter Zijlstra (Intel) Cc: Alexander Shishkin Cc: Arnaldo Carvalho de Melo Cc: Jiri Olsa Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Thomas Gleixner Cc: Vince Weaver Cc: akpm@linux-foundation.org Cc: hpa@zytor.com Cc: kan.liang@intel.com Cc: lukasz.anaczkowski@intel.com Cc: zheng.z.yan@intel.com Link: http://lkml.kernel.org/r/1463433378-16816-1-git-send-email-lukasz.odzioba@intel.com Signed-off-by: Ingo Molnar diff --git a/arch/x86/events/intel/core.c b/arch/x86/events/intel/core.c index 7c66695..ad08caf 100644 --- a/arch/x86/events/intel/core.c +++ b/arch/x86/events/intel/core.c @@ -177,7 +177,7 @@ static struct event_constraint intel_slm_event_constraints[] __read_mostly = EVENT_CONSTRAINT_END }; -struct event_constraint intel_skl_event_constraints[] = { +static struct event_constraint intel_skl_event_constraints[] = { FIXED_EVENT_CONSTRAINT(0x00c0, 0), /* INST_RETIRED.ANY */ FIXED_EVENT_CONSTRAINT(0x003c, 1), /* CPU_CLK_UNHALTED.CORE */ FIXED_EVENT_CONSTRAINT(0x0300, 2), /* CPU_CLK_UNHALTED.REF */ @@ -225,12 +225,12 @@ EVENT_ATTR_STR(mem-loads, mem_ld_nhm, "event=0x0b,umask=0x10,ldlat=3"); EVENT_ATTR_STR(mem-loads, mem_ld_snb, "event=0xcd,umask=0x1,ldlat=3"); EVENT_ATTR_STR(mem-stores, mem_st_snb, "event=0xcd,umask=0x2"); -struct attribute *nhm_events_attrs[] = { +static struct attribute *nhm_events_attrs[] = { EVENT_PTR(mem_ld_nhm), NULL, }; -struct attribute *snb_events_attrs[] = { +static struct attribute *snb_events_attrs[] = { EVENT_PTR(mem_ld_snb), EVENT_PTR(mem_st_snb), NULL, @@ -258,7 +258,7 @@ static struct event_constraint intel_hsw_event_constraints[] = { EVENT_CONSTRAINT_END }; -struct event_constraint intel_bdw_event_constraints[] = { +static struct event_constraint intel_bdw_event_constraints[] = { FIXED_EVENT_CONSTRAINT(0x00c0, 0), /* INST_RETIRED.ANY */ FIXED_EVENT_CONSTRAINT(0x003c, 1), /* CPU_CLK_UNHALTED.CORE */ FIXED_EVENT_CONSTRAINT(0x0300, 2), /* CPU_CLK_UNHALTED.REF */ -- cgit v0.10.2 From 9c489fce7a4a46c8a408e16e126bf3225401c7b5 Mon Sep 17 00:00:00 2001 From: Lukasz Odzioba Date: Mon, 16 May 2016 23:16:59 +0200 Subject: perf/x86/intel: Change offcore response masks for Knights Landing Due to change in register definition we need to update OCR mask: MSR_OFFCORE_RESP0 reserved bits: 3,4,18,29,30,33,34, 8,11,14 MSR_OFFCORE_RESP1 reserved bits: 3,4,18,29,30,33,34, 38 Reported-by: Andi Kleen Signed-off-by: Lukasz Odzioba Signed-off-by: Peter Zijlstra (Intel) Cc: Alexander Shishkin Cc: Arnaldo Carvalho de Melo Cc: Jiri Olsa Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Thomas Gleixner Cc: Vince Weaver Cc: akpm@linux-foundation.org Cc: hpa@zytor.com Cc: kan.liang@intel.com Cc: lukasz.anaczkowski@intel.com Cc: zheng.z.yan@intel.com Link: http://lkml.kernel.org/r/1463433419-16893-1-git-send-email-lukasz.odzioba@intel.com Signed-off-by: Ingo Molnar diff --git a/arch/x86/events/intel/core.c b/arch/x86/events/intel/core.c index ad08caf..0941f84 100644 --- a/arch/x86/events/intel/core.c +++ b/arch/x86/events/intel/core.c @@ -186,10 +186,8 @@ static struct event_constraint intel_skl_event_constraints[] = { }; static struct extra_reg intel_knl_extra_regs[] __read_mostly = { - INTEL_UEVENT_EXTRA_REG(0x01b7, - MSR_OFFCORE_RSP_0, 0x7f9ffbffffull, RSP_0), - INTEL_UEVENT_EXTRA_REG(0x02b7, - MSR_OFFCORE_RSP_1, 0x3f9ffbffffull, RSP_1), + INTEL_UEVENT_EXTRA_REG(0x01b7, MSR_OFFCORE_RSP_0, 0x799ffbb6e7ull, RSP_0), + INTEL_UEVENT_EXTRA_REG(0x02b7, MSR_OFFCORE_RSP_1, 0x399ffbffe7ull, RSP_1), EVENT_EXTRA_END }; -- cgit v0.10.2 From a54fa07930c0f7db55ecb4cc16b86d74101332c0 Mon Sep 17 00:00:00 2001 From: Kan Liang Date: Sun, 15 May 2016 23:18:24 -0700 Subject: perf/x86/intel/uncore: Locate specific box by checking full device info Some platforms, e.g. Knights Landing, use a common PCI device ID for multiple instances of an uncore PMU device type. So it is impossible to locate the specific instances only by PCI device ID. The current code specially handles Knights Landing by arbitrarily pointing an instance to an unused uncore box. However, we still have no idea which uncore device is mapped to which box. Furthermore, there could be more platforms which use a common PCI device ID for uncore devices. We have to specially handle them one by one. This patch records full device information (slot, func, and device ID) in id_table[]. So the probe function can point the instance to a specific uncore box by checking the full device information. Tested-by: Lukasz Odzioba Signed-off-by: Kan Liang Signed-off-by: Peter Zijlstra (Intel) Acked-by: tglx@linutronix.de Cc: Alexander Shishkin Cc: Arnaldo Carvalho de Melo Cc: Jiri Olsa Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Thomas Gleixner Cc: Vince Weaver Cc: bp@suse.de Cc: harish.chegondi@intel.com Cc: hubert.chrzaniuk@intel.com Cc: lawrence.f.meadows@intel.com Link: http://lkml.kernel.org/r/1463379504-39003-1-git-send-email-kan.liang@intel.com Signed-off-by: Ingo Molnar diff --git a/arch/x86/events/intel/uncore.c b/arch/x86/events/intel/uncore.c index fce7406..6549058 100644 --- a/arch/x86/events/intel/uncore.c +++ b/arch/x86/events/intel/uncore.c @@ -882,7 +882,7 @@ uncore_types_init(struct intel_uncore_type **types, bool setid) static int uncore_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) { struct intel_uncore_type *type; - struct intel_uncore_pmu *pmu; + struct intel_uncore_pmu *pmu = NULL; struct intel_uncore_box *box; int phys_id, pkg, ret; @@ -903,20 +903,37 @@ static int uncore_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id } type = uncore_pci_uncores[UNCORE_PCI_DEV_TYPE(id->driver_data)]; + /* - * for performance monitoring unit with multiple boxes, - * each box has a different function id. + * Some platforms, e.g. Knights Landing, use a common PCI device ID + * for multiple instances of an uncore PMU device type. We should check + * PCI slot and func to indicate the uncore box. */ - pmu = &type->pmus[UNCORE_PCI_DEV_IDX(id->driver_data)]; - /* Knights Landing uses a common PCI device ID for multiple instances of - * an uncore PMU device type. There is only one entry per device type in - * the knl_uncore_pci_ids table inspite of multiple devices present for - * some device types. Hence PCI device idx would be 0 for all devices. - * So increment pmu pointer to point to an unused array element. - */ - if (boot_cpu_data.x86_model == 87) { - while (pmu->func_id >= 0) - pmu++; + if (id->driver_data & ~0xffff) { + struct pci_driver *pci_drv = pdev->driver; + const struct pci_device_id *ids = pci_drv->id_table; + unsigned int devfn; + + while (ids && ids->vendor) { + if ((ids->vendor == pdev->vendor) && + (ids->device == pdev->device)) { + devfn = PCI_DEVFN(UNCORE_PCI_DEV_DEV(ids->driver_data), + UNCORE_PCI_DEV_FUNC(ids->driver_data)); + if (devfn == pdev->devfn) { + pmu = &type->pmus[UNCORE_PCI_DEV_IDX(ids->driver_data)]; + break; + } + } + ids++; + } + if (pmu == NULL) + return -ENODEV; + } else { + /* + * for performance monitoring unit with multiple boxes, + * each box has a different function id. + */ + pmu = &type->pmus[UNCORE_PCI_DEV_IDX(id->driver_data)]; } if (WARN_ON_ONCE(pmu->boxes[pkg] != NULL)) diff --git a/arch/x86/events/intel/uncore.h b/arch/x86/events/intel/uncore.h index 79766b9..66c3a36 100644 --- a/arch/x86/events/intel/uncore.h +++ b/arch/x86/events/intel/uncore.h @@ -15,7 +15,11 @@ #define UNCORE_PMC_IDX_FIXED UNCORE_PMC_IDX_MAX_GENERIC #define UNCORE_PMC_IDX_MAX (UNCORE_PMC_IDX_FIXED + 1) +#define UNCORE_PCI_DEV_FULL_DATA(dev, func, type, idx) \ + ((dev << 24) | (func << 16) | (type << 8) | idx) #define UNCORE_PCI_DEV_DATA(type, idx) ((type << 8) | idx) +#define UNCORE_PCI_DEV_DEV(data) ((data >> 24) & 0xff) +#define UNCORE_PCI_DEV_FUNC(data) ((data >> 16) & 0xff) #define UNCORE_PCI_DEV_TYPE(data) ((data >> 8) & 0xff) #define UNCORE_PCI_DEV_IDX(data) (data & 0xff) #define UNCORE_EXTRA_PCI_DEV 0xff diff --git a/arch/x86/events/intel/uncore_snbep.c b/arch/x86/events/intel/uncore_snbep.c index b262586..7336e55 100644 --- a/arch/x86/events/intel/uncore_snbep.c +++ b/arch/x86/events/intel/uncore_snbep.c @@ -2164,21 +2164,101 @@ static struct intel_uncore_type *knl_pci_uncores[] = { */ static const struct pci_device_id knl_uncore_pci_ids[] = { - { /* MC UClk */ + { /* MC0 UClk */ PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x7841), - .driver_data = UNCORE_PCI_DEV_DATA(KNL_PCI_UNCORE_MC_UCLK, 0), + .driver_data = UNCORE_PCI_DEV_FULL_DATA(10, 0, KNL_PCI_UNCORE_MC_UCLK, 0), }, - { /* MC DClk Channel */ + { /* MC1 UClk */ + PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x7841), + .driver_data = UNCORE_PCI_DEV_FULL_DATA(11, 0, KNL_PCI_UNCORE_MC_UCLK, 1), + }, + { /* MC0 DClk CH 0 */ + PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x7843), + .driver_data = UNCORE_PCI_DEV_FULL_DATA(8, 2, KNL_PCI_UNCORE_MC_DCLK, 0), + }, + { /* MC0 DClk CH 1 */ + PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x7843), + .driver_data = UNCORE_PCI_DEV_FULL_DATA(8, 3, KNL_PCI_UNCORE_MC_DCLK, 1), + }, + { /* MC0 DClk CH 2 */ + PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x7843), + .driver_data = UNCORE_PCI_DEV_FULL_DATA(8, 4, KNL_PCI_UNCORE_MC_DCLK, 2), + }, + { /* MC1 DClk CH 0 */ + PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x7843), + .driver_data = UNCORE_PCI_DEV_FULL_DATA(9, 2, KNL_PCI_UNCORE_MC_DCLK, 3), + }, + { /* MC1 DClk CH 1 */ PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x7843), - .driver_data = UNCORE_PCI_DEV_DATA(KNL_PCI_UNCORE_MC_DCLK, 0), + .driver_data = UNCORE_PCI_DEV_FULL_DATA(9, 3, KNL_PCI_UNCORE_MC_DCLK, 4), + }, + { /* MC1 DClk CH 2 */ + PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x7843), + .driver_data = UNCORE_PCI_DEV_FULL_DATA(9, 4, KNL_PCI_UNCORE_MC_DCLK, 5), + }, + { /* EDC0 UClk */ + PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x7833), + .driver_data = UNCORE_PCI_DEV_FULL_DATA(15, 0, KNL_PCI_UNCORE_EDC_UCLK, 0), + }, + { /* EDC1 UClk */ + PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x7833), + .driver_data = UNCORE_PCI_DEV_FULL_DATA(16, 0, KNL_PCI_UNCORE_EDC_UCLK, 1), + }, + { /* EDC2 UClk */ + PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x7833), + .driver_data = UNCORE_PCI_DEV_FULL_DATA(17, 0, KNL_PCI_UNCORE_EDC_UCLK, 2), + }, + { /* EDC3 UClk */ + PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x7833), + .driver_data = UNCORE_PCI_DEV_FULL_DATA(18, 0, KNL_PCI_UNCORE_EDC_UCLK, 3), }, - { /* EDC UClk */ + { /* EDC4 UClk */ PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x7833), - .driver_data = UNCORE_PCI_DEV_DATA(KNL_PCI_UNCORE_EDC_UCLK, 0), + .driver_data = UNCORE_PCI_DEV_FULL_DATA(19, 0, KNL_PCI_UNCORE_EDC_UCLK, 4), + }, + { /* EDC5 UClk */ + PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x7833), + .driver_data = UNCORE_PCI_DEV_FULL_DATA(20, 0, KNL_PCI_UNCORE_EDC_UCLK, 5), + }, + { /* EDC6 UClk */ + PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x7833), + .driver_data = UNCORE_PCI_DEV_FULL_DATA(21, 0, KNL_PCI_UNCORE_EDC_UCLK, 6), + }, + { /* EDC7 UClk */ + PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x7833), + .driver_data = UNCORE_PCI_DEV_FULL_DATA(22, 0, KNL_PCI_UNCORE_EDC_UCLK, 7), + }, + { /* EDC0 EClk */ + PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x7835), + .driver_data = UNCORE_PCI_DEV_FULL_DATA(24, 2, KNL_PCI_UNCORE_EDC_ECLK, 0), + }, + { /* EDC1 EClk */ + PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x7835), + .driver_data = UNCORE_PCI_DEV_FULL_DATA(25, 2, KNL_PCI_UNCORE_EDC_ECLK, 1), + }, + { /* EDC2 EClk */ + PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x7835), + .driver_data = UNCORE_PCI_DEV_FULL_DATA(26, 2, KNL_PCI_UNCORE_EDC_ECLK, 2), + }, + { /* EDC3 EClk */ + PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x7835), + .driver_data = UNCORE_PCI_DEV_FULL_DATA(27, 2, KNL_PCI_UNCORE_EDC_ECLK, 3), + }, + { /* EDC4 EClk */ + PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x7835), + .driver_data = UNCORE_PCI_DEV_FULL_DATA(28, 2, KNL_PCI_UNCORE_EDC_ECLK, 4), + }, + { /* EDC5 EClk */ + PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x7835), + .driver_data = UNCORE_PCI_DEV_FULL_DATA(29, 2, KNL_PCI_UNCORE_EDC_ECLK, 5), + }, + { /* EDC6 EClk */ + PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x7835), + .driver_data = UNCORE_PCI_DEV_FULL_DATA(30, 2, KNL_PCI_UNCORE_EDC_ECLK, 6), }, - { /* EDC EClk */ + { /* EDC7 EClk */ PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x7835), - .driver_data = UNCORE_PCI_DEV_DATA(KNL_PCI_UNCORE_EDC_ECLK, 0), + .driver_data = UNCORE_PCI_DEV_FULL_DATA(31, 2, KNL_PCI_UNCORE_EDC_ECLK, 7), }, { /* M2PCIe */ PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x7817), -- cgit v0.10.2 From a1396555abff9ff9b74c2e4da13e27e81fd094b2 Mon Sep 17 00:00:00 2001 From: Vineet Gupta Date: Mon, 9 May 2016 15:07:40 +0530 Subject: perf/abi: Change the errno for sampling event not supported in hardware Change the return code for sampling event not supported from -ENOTSUPP to -EOPNOTSUPP. This allows userspace to identify this case specifically, instead of printing the catch-all error message it did previously. Technically this is an ABI change, but we think we can get away with it. Old behavior: ------- | # perf record ls | Error: | The sys_perf_event_open() syscall returned with 524 (Unknown error 524) | for event (cycles:ppp). | /bin/dmesg may provide additional information. | No CONFIG_PERF_EVENTS=y kernel support configured? New behavior: ------- | # perf record ls | Error: | PMU Hardware doesn't support sampling/overflow-interrupts. Signed-off-by: Vineet Gupta Signed-off-by: Peter Zijlstra (Intel) Cc: Cc: Cc: Cc: Alexander Shishkin Cc: Arnaldo Carvalho de Melo Cc: Jiri Olsa Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Thomas Gleixner Cc: Vince Weaver Cc: Vineet Gupta Link: http://lkml.kernel.org/r/1462786660-2900-3-git-send-email-vgupta@synopsys.com Signed-off-by: Ingo Molnar diff --git a/kernel/events/core.c b/kernel/events/core.c index f94f164..5d48306 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c @@ -9309,7 +9309,7 @@ SYSCALL_DEFINE5(perf_event_open, if (is_sampling_event(event)) { if (event->pmu->capabilities & PERF_PMU_CAP_NO_INTERRUPT) { - err = -ENOTSUPP; + err = -EOPNOTSUPP; goto err_alloc; } } -- cgit v0.10.2 From dc89e75a9412db5b1105a140182ec1e35a8351b4 Mon Sep 17 00:00:00 2001 From: Vineet Gupta Date: Mon, 9 May 2016 15:07:39 +0530 Subject: tools/perf: Handle -EOPNOTSUPP for sampling events This allows (with a previous change to the perf error return ABI) for calling out in userspace the exact reason for perf record failing when PMU doesn't support overflow interrupts. Note that this needs to be put ahead of existing precise_ip check as that gets hit otherwise for the sampling fail case as well. Signed-off-by: Vineet Gupta Signed-off-by: Peter Zijlstra (Intel) Cc: Cc: Cc: Cc: Alexander Shishkin Cc: Arnaldo Carvalho de Melo Cc: Jiri Olsa Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Thomas Gleixner Cc: Vince Weaver Cc: Vineet Gupta Link: http://lkml.kernel.org/r/1462786660-2900-2-git-send-email-vgupta@synopsys.com Signed-off-by: Ingo Molnar diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index 245ac50..8d30cbd 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c @@ -2384,6 +2384,9 @@ int perf_evsel__open_strerror(struct perf_evsel *evsel, struct target *target, "No such device - did you specify an out-of-range profile CPU?"); break; case EOPNOTSUPP: + if (evsel->attr.sample_period != 0) + return scnprintf(msg, size, "%s", + "PMU Hardware doesn't support sampling/overflow-interrupts."); if (evsel->attr.precise_ip) return scnprintf(msg, size, "%s", "\'precise\' request may not be supported. Try removing 'p' modifier."); -- cgit v0.10.2 From 70b8301f6b8f7bc053377a9cbd0c4e42e29d9807 Mon Sep 17 00:00:00 2001 From: Andi Kleen Date: Thu, 19 May 2016 17:09:55 -0700 Subject: x86/topology: Add topology_max_smt_threads() For SMT specific workarounds it is useful to know if SMT is active on any online CPU in the system. This currently requires a loop over all online CPUs. Add a global variable that is updated with the maximum number of smt threads on any CPU on online/offline, and use it for topology_max_smt_threads() The single call is easier to use than a loop. Not exported to user space because user space already can use the existing sibling interfaces to find this out. Signed-off-by: Andi Kleen Signed-off-by: Peter Zijlstra (Intel) Cc: Alexander Shishkin Cc: Arnaldo Carvalho de Melo Cc: Jiri Olsa Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Thomas Gleixner Cc: Vince Weaver Cc: acme@kernel.org Cc: jolsa@kernel.org Link: http://lkml.kernel.org/r/1463703002-19686-2-git-send-email-andi@firstfloor.org Signed-off-by: Ingo Molnar diff --git a/arch/x86/include/asm/topology.h b/arch/x86/include/asm/topology.h index 7f991bd5..e346572 100644 --- a/arch/x86/include/asm/topology.h +++ b/arch/x86/include/asm/topology.h @@ -129,6 +129,14 @@ extern const struct cpumask *cpu_coregroup_mask(int cpu); extern unsigned int __max_logical_packages; #define topology_max_packages() (__max_logical_packages) + +extern int __max_smt_threads; + +static inline int topology_max_smt_threads(void) +{ + return __max_smt_threads; +} + int topology_update_package_map(unsigned int apicid, unsigned int cpu); extern int topology_phys_to_logical_pkg(unsigned int pkg); #else @@ -136,6 +144,7 @@ extern int topology_phys_to_logical_pkg(unsigned int pkg); static inline int topology_update_package_map(unsigned int apicid, unsigned int cpu) { return 0; } static inline int topology_phys_to_logical_pkg(unsigned int pkg) { return 0; } +static inline int topology_max_smt_threads(void) { return 1; } #endif static inline void arch_fix_phys_package_id(int num, u32 slot) diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c index fafe8b9..2ed0ec1 100644 --- a/arch/x86/kernel/smpboot.c +++ b/arch/x86/kernel/smpboot.c @@ -105,6 +105,9 @@ static unsigned int max_physical_pkg_id __read_mostly; unsigned int __max_logical_packages __read_mostly; EXPORT_SYMBOL(__max_logical_packages); +/* Maximum number of SMT threads on any online core */ +int __max_smt_threads __read_mostly; + static inline void smpboot_setup_warm_reset_vector(unsigned long start_eip) { unsigned long flags; @@ -493,7 +496,7 @@ void set_cpu_sibling_map(int cpu) bool has_mp = has_smt || boot_cpu_data.x86_max_cores > 1; struct cpuinfo_x86 *c = &cpu_data(cpu); struct cpuinfo_x86 *o; - int i; + int i, threads; cpumask_set_cpu(cpu, cpu_sibling_setup_mask); @@ -550,6 +553,10 @@ void set_cpu_sibling_map(int cpu) if (match_die(c, o) && !topology_same_node(c, o)) primarily_use_numa_for_topology(); } + + threads = cpumask_weight(topology_sibling_cpumask(cpu)); + if (threads > __max_smt_threads) + __max_smt_threads = threads; } /* maps the cpu to the sched domain representing multi-core */ @@ -1441,6 +1448,21 @@ __init void prefill_possible_map(void) #ifdef CONFIG_HOTPLUG_CPU +/* Recompute SMT state for all CPUs on offline */ +static void recompute_smt_state(void) +{ + int max_threads, cpu; + + max_threads = 0; + for_each_online_cpu (cpu) { + int threads = cpumask_weight(topology_sibling_cpumask(cpu)); + + if (threads > max_threads) + max_threads = threads; + } + __max_smt_threads = max_threads; +} + static void remove_siblinginfo(int cpu) { int sibling; @@ -1465,6 +1487,7 @@ static void remove_siblinginfo(int cpu) c->phys_proc_id = 0; c->cpu_core_id = 0; cpumask_clear_cpu(cpu, cpu_sibling_setup_mask); + recompute_smt_state(); } static void remove_cpu_from_maps(int cpu) -- cgit v0.10.2 From fc07e9f983b4b11922c22b6cccadc1f342f05a4c Mon Sep 17 00:00:00 2001 From: Andi Kleen Date: Thu, 19 May 2016 17:09:56 -0700 Subject: perf/x86: Support sysfs files depending on SMT status Add a way to show different sysfs events attributes depending on HyperThreading is on or off. This is difficult to determine early at boot, so we just do it dynamically when the sysfs attribute is read. Signed-off-by: Andi Kleen Signed-off-by: Peter Zijlstra (Intel) Cc: Alexander Shishkin Cc: Arnaldo Carvalho de Melo Cc: Jiri Olsa Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Thomas Gleixner Cc: Vince Weaver Cc: acme@kernel.org Cc: jolsa@kernel.org Link: http://lkml.kernel.org/r/1463703002-19686-3-git-send-email-andi@firstfloor.org Signed-off-by: Ingo Molnar diff --git a/arch/x86/events/core.c b/arch/x86/events/core.c index 33787ee..929655d 100644 --- a/arch/x86/events/core.c +++ b/arch/x86/events/core.c @@ -1622,6 +1622,29 @@ ssize_t events_sysfs_show(struct device *dev, struct device_attribute *attr, cha } EXPORT_SYMBOL_GPL(events_sysfs_show); +ssize_t events_ht_sysfs_show(struct device *dev, struct device_attribute *attr, + char *page) +{ + struct perf_pmu_events_ht_attr *pmu_attr = + container_of(attr, struct perf_pmu_events_ht_attr, attr); + + /* + * Report conditional events depending on Hyper-Threading. + * + * This is overly conservative as usually the HT special + * handling is not needed if the other CPU thread is idle. + * + * Note this does not (and cannot) handle the case when thread + * siblings are invisible, for example with virtualization + * if they are owned by some other guest. The user tool + * has to re-read when a thread sibling gets onlined later. + */ + return sprintf(page, "%s", + topology_max_smt_threads() > 1 ? + pmu_attr->event_str_ht : + pmu_attr->event_str_noht); +} + EVENT_ATTR(cpu-cycles, CPU_CYCLES ); EVENT_ATTR(instructions, INSTRUCTIONS ); EVENT_ATTR(cache-references, CACHE_REFERENCES ); diff --git a/arch/x86/events/perf_event.h b/arch/x86/events/perf_event.h index 8bd764d..e2d7285 100644 --- a/arch/x86/events/perf_event.h +++ b/arch/x86/events/perf_event.h @@ -668,6 +668,14 @@ static struct perf_pmu_events_attr event_attr_##v = { \ .event_str = str, \ }; +#define EVENT_ATTR_STR_HT(_name, v, noht, ht) \ +static struct perf_pmu_events_ht_attr event_attr_##v = { \ + .attr = __ATTR(_name, 0444, events_ht_sysfs_show, NULL),\ + .id = 0, \ + .event_str_noht = noht, \ + .event_str_ht = ht, \ +} + extern struct x86_pmu x86_pmu __read_mostly; static inline bool x86_pmu_has_lbr_callstack(void) @@ -803,6 +811,8 @@ struct attribute **merge_attr(struct attribute **a, struct attribute **b); ssize_t events_sysfs_show(struct device *dev, struct device_attribute *attr, char *page); +ssize_t events_ht_sysfs_show(struct device *dev, struct device_attribute *attr, + char *page); #ifdef CONFIG_CPU_SUP_AMD diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h index 92e9ce7..a7593d6 100644 --- a/include/linux/perf_event.h +++ b/include/linux/perf_event.h @@ -1334,6 +1334,13 @@ struct perf_pmu_events_attr { const char *event_str; }; +struct perf_pmu_events_ht_attr { + struct device_attribute attr; + u64 id; + const char *event_str_ht; + const char *event_str_noht; +}; + ssize_t perf_event_sysfs_show(struct device *dev, struct device_attribute *attr, char *page); -- cgit v0.10.2 From a39fcae7a83629312cc06cee7a745b9a8203327f Mon Sep 17 00:00:00 2001 From: Andi Kleen Date: Thu, 19 May 2016 17:09:57 -0700 Subject: perf/x86/intel: Add topdown events to Intel Core Add declarations for the events needed for topdown to the Intel big core CPUs starting with Sandy Bridge. We need to report different values if HyperThreading is on or off. The only thing this patch does is to export some events in sysfs. topdown level 1 uses a set of abstracted metrics which are generic to out of order CPU cores (although some CPUs may not implement all of them): topdown-total-slots Available slots in the pipeline topdown-slots-issued Slots issued into the pipeline topdown-slots-retired Slots successfully retired topdown-fetch-bubbles Pipeline gaps in the frontend topdown-recovery-bubbles Pipeline gaps during recovery from misspeculation A slot is a single operation in the CPU pipe line. These metrics then allow to compute four useful metrics: FrontendBound, BackendBound, Retiring, BadSpeculation. The formulas to compute the metrics are generic, they only change based on the availability on the abstracted input values. The kernel declares the events supported by the current CPU and their scaling factors (such as the pipeline width) and perf stat then computes the formulas based on the available metrics. This is similar how existing perf metrics, such as TSC metrics or IPC, are implemented. This abstracts all CPU pipe line specific knowledge in the kernel driver, but still avoids the need for larger scale perf interface changes. For HyperThreading the any bit is needed to get accurate values when both threads are executing. This implies that the events can only be collected as root or with perf_event_paranoid=-1 for now. The basic scheme is based on the following paper: Yasin, A Top Down Method for Performance analysis and Counter architecture ISPASS14 (pdf available via google) Signed-off-by: Andi Kleen Signed-off-by: Peter Zijlstra (Intel) Cc: Alexander Shishkin Cc: Arnaldo Carvalho de Melo Cc: Jiri Olsa Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Thomas Gleixner Cc: Vince Weaver Cc: acme@kernel.org Cc: jolsa@kernel.org Link: http://lkml.kernel.org/r/1463703002-19686-4-git-send-email-andi@firstfloor.org Signed-off-by: Ingo Molnar diff --git a/arch/x86/events/intel/core.c b/arch/x86/events/intel/core.c index 0941f84..4f51bc4 100644 --- a/arch/x86/events/intel/core.c +++ b/arch/x86/events/intel/core.c @@ -228,9 +228,46 @@ static struct attribute *nhm_events_attrs[] = { NULL, }; +/* + * topdown events for Intel Core CPUs. + * + * The events are all in slots, which is a free slot in a 4 wide + * pipeline. Some events are already reported in slots, for cycle + * events we multiply by the pipeline width (4). + * + * With Hyper Threading on, topdown metrics are either summed or averaged + * between the threads of a core: (count_t0 + count_t1). + * + * For the average case the metric is always scaled to pipeline width, + * so we use factor 2 ((count_t0 + count_t1) / 2 * 4) + */ + +EVENT_ATTR_STR_HT(topdown-total-slots, td_total_slots, + "event=0x3c,umask=0x0", /* cpu_clk_unhalted.thread */ + "event=0x3c,umask=0x0,any=1"); /* cpu_clk_unhalted.thread_any */ +EVENT_ATTR_STR_HT(topdown-total-slots.scale, td_total_slots_scale, "4", "2"); +EVENT_ATTR_STR(topdown-slots-issued, td_slots_issued, + "event=0xe,umask=0x1"); /* uops_issued.any */ +EVENT_ATTR_STR(topdown-slots-retired, td_slots_retired, + "event=0xc2,umask=0x2"); /* uops_retired.retire_slots */ +EVENT_ATTR_STR(topdown-fetch-bubbles, td_fetch_bubbles, + "event=0x9c,umask=0x1"); /* idq_uops_not_delivered_core */ +EVENT_ATTR_STR_HT(topdown-recovery-bubbles, td_recovery_bubbles, + "event=0xd,umask=0x3,cmask=1", /* int_misc.recovery_cycles */ + "event=0xd,umask=0x3,cmask=1,any=1"); /* int_misc.recovery_cycles_any */ +EVENT_ATTR_STR_HT(topdown-recovery-bubbles.scale, td_recovery_bubbles_scale, + "4", "2"); + static struct attribute *snb_events_attrs[] = { EVENT_PTR(mem_ld_snb), EVENT_PTR(mem_st_snb), + EVENT_PTR(td_slots_issued), + EVENT_PTR(td_slots_retired), + EVENT_PTR(td_fetch_bubbles), + EVENT_PTR(td_total_slots), + EVENT_PTR(td_total_slots_scale), + EVENT_PTR(td_recovery_bubbles), + EVENT_PTR(td_recovery_bubbles_scale), NULL, }; @@ -3435,6 +3472,13 @@ static struct attribute *hsw_events_attrs[] = { EVENT_PTR(cycles_ct), EVENT_PTR(mem_ld_hsw), EVENT_PTR(mem_st_hsw), + EVENT_PTR(td_slots_issued), + EVENT_PTR(td_slots_retired), + EVENT_PTR(td_fetch_bubbles), + EVENT_PTR(td_total_slots), + EVENT_PTR(td_total_slots_scale), + EVENT_PTR(td_recovery_bubbles), + EVENT_PTR(td_recovery_bubbles_scale), NULL }; @@ -3803,6 +3847,12 @@ __init int intel_pmu_init(void) memcpy(hw_cache_extra_regs, skl_hw_cache_extra_regs, sizeof(hw_cache_extra_regs)); intel_pmu_lbr_init_skl(); + /* INT_MISC.RECOVERY_CYCLES has umask 1 in Skylake */ + event_attr_td_recovery_bubbles.event_str_noht = + "event=0xd,umask=0x1,cmask=1"; + event_attr_td_recovery_bubbles.event_str_ht = + "event=0xd,umask=0x1,cmask=1,any=1"; + x86_pmu.event_constraints = intel_skl_event_constraints; x86_pmu.pebs_constraints = intel_skl_pebs_event_constraints; x86_pmu.extra_regs = intel_skl_extra_regs; -- cgit v0.10.2 From eb12b8ece71cfd4c96df37198b9903fc639768d8 Mon Sep 17 00:00:00 2001 From: Andi Kleen Date: Thu, 19 May 2016 17:09:58 -0700 Subject: perf/x86/intel: Add topdown events to Intel Atom Add topdown event declarations to Silvermont / Airmont. These cores do not support the full Top Down metrics, but an useful subset (FrontendBound, Retiring, Backend Bound/Bad Speculation). The perf stat tool automatically handles the missing events and combines the available metrics. Signed-off-by: Andi Kleen Signed-off-by: Peter Zijlstra (Intel) Cc: Alexander Shishkin Cc: Arnaldo Carvalho de Melo Cc: Jiri Olsa Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Thomas Gleixner Cc: Vince Weaver Cc: acme@kernel.org Cc: jolsa@kernel.org Link: http://lkml.kernel.org/r/1463703002-19686-5-git-send-email-andi@firstfloor.org Signed-off-by: Ingo Molnar diff --git a/arch/x86/events/intel/core.c b/arch/x86/events/intel/core.c index 4f51bc4..593b167 100644 --- a/arch/x86/events/intel/core.c +++ b/arch/x86/events/intel/core.c @@ -1367,6 +1367,29 @@ static __initconst const u64 atom_hw_cache_event_ids }, }; +EVENT_ATTR_STR(topdown-total-slots, td_total_slots_slm, "event=0x3c"); +EVENT_ATTR_STR(topdown-total-slots.scale, td_total_slots_scale_slm, "2"); +/* no_alloc_cycles.not_delivered */ +EVENT_ATTR_STR(topdown-fetch-bubbles, td_fetch_bubbles_slm, + "event=0xca,umask=0x50"); +EVENT_ATTR_STR(topdown-fetch-bubbles.scale, td_fetch_bubbles_scale_slm, "2"); +/* uops_retired.all */ +EVENT_ATTR_STR(topdown-slots-issued, td_slots_issued_slm, + "event=0xc2,umask=0x10"); +/* uops_retired.all */ +EVENT_ATTR_STR(topdown-slots-retired, td_slots_retired_slm, + "event=0xc2,umask=0x10"); + +static struct attribute *slm_events_attrs[] = { + EVENT_PTR(td_total_slots_slm), + EVENT_PTR(td_total_slots_scale_slm), + EVENT_PTR(td_fetch_bubbles_slm), + EVENT_PTR(td_fetch_bubbles_scale_slm), + EVENT_PTR(td_slots_issued_slm), + EVENT_PTR(td_slots_retired_slm), + NULL +}; + static struct extra_reg intel_slm_extra_regs[] __read_mostly = { /* must define OFFCORE_RSP_X first, see intel_fixup_er() */ @@ -3629,6 +3652,7 @@ __init int intel_pmu_init(void) x86_pmu.pebs_constraints = intel_slm_pebs_event_constraints; x86_pmu.extra_regs = intel_slm_extra_regs; x86_pmu.flags |= PMU_FL_HAS_RSP_1; + x86_pmu.cpu_events = slm_events_attrs; pr_cont("Silvermont events, "); break; -- cgit v0.10.2 From 030ba6cd105c68ce919c5e239853b567490cd059 Mon Sep 17 00:00:00 2001 From: Andi Kleen Date: Thu, 19 May 2016 17:09:59 -0700 Subject: perf/x86/intel: Use new topology_max_smt_threads() in HT leak workaround Now that we have topology_max_smt_threads() use it to detect the HT workarounds for older CPUs. Signed-off-by: Andi Kleen Signed-off-by: Peter Zijlstra (Intel) Cc: Alexander Shishkin Cc: Arnaldo Carvalho de Melo Cc: Jiri Olsa Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Thomas Gleixner Cc: Vince Weaver Cc: acme@kernel.org Cc: jolsa@kernel.org Link: http://lkml.kernel.org/r/1463703002-19686-6-git-send-email-andi@firstfloor.org Signed-off-by: Ingo Molnar diff --git a/arch/x86/events/intel/core.c b/arch/x86/events/intel/core.c index 593b167..5081b4c 100644 --- a/arch/x86/events/intel/core.c +++ b/arch/x86/events/intel/core.c @@ -3989,16 +3989,14 @@ __init int intel_pmu_init(void) */ static __init int fixup_ht_bug(void) { - int cpu = smp_processor_id(); - int w, c; + int c; /* * problem not present on this CPU model, nothing to do */ if (!(x86_pmu.flags & PMU_FL_EXCL_ENABLED)) return 0; - w = cpumask_weight(topology_sibling_cpumask(cpu)); - if (w > 1) { + if (topology_max_smt_threads() > 1) { pr_info("PMU erratum BJ122, BV98, HSD29 worked around, HT is on\n"); return 0; } -- cgit v0.10.2 From 133e89ef5ef338e1358b16246521ba17d935c396 Mon Sep 17 00:00:00 2001 From: Davidlohr Bueso Date: Fri, 13 May 2016 11:56:26 -0700 Subject: locking/rwsem: Enable lockless waiter wakeup(s) As wake_qs gain users, we can teach rwsems about them such that waiters can be awoken without the wait_lock. This is for both readers and writer, the former being the most ideal candidate as we can batch the wakeups shortening the critical region that much more -- ie writer task blocking a bunch of tasks waiting to service page-faults (mmap_sem readers). In general applying wake_qs to rwsem (xadd) is not difficult as the wait_lock is intended to be released soon _anyways_, with the exception of when a writer slowpath will proactively wakeup any queued readers if it sees that the lock is owned by a reader, in which we simply do the wakeups with the lock held (see comment in __rwsem_down_write_failed_common()). Similar to other locking primitives, delaying the waiter being awoken does allow, at least in theory, the lock to be stolen in the case of writers, however no harm was seen in this (in fact lock stealing tends to be a _good_ thing in most workloads), and this is a tiny window anyways. Some page-fault (pft) and mmap_sem intensive benchmarks show some pretty constant reduction in systime (by up to ~8 and ~10%) on a 2-socket, 12 core AMD box. In addition, on an 8-core Westmere doing page allocations (page_test) aim9: 4.6-rc6 4.6-rc6 rwsemv2 Min page_test 378167.89 ( 0.00%) 382613.33 ( 1.18%) Min exec_test 499.00 ( 0.00%) 502.67 ( 0.74%) Min fork_test 3395.47 ( 0.00%) 3537.64 ( 4.19%) Hmean page_test 395433.06 ( 0.00%) 414693.68 ( 4.87%) Hmean exec_test 499.67 ( 0.00%) 505.30 ( 1.13%) Hmean fork_test 3504.22 ( 0.00%) 3594.95 ( 2.59%) Stddev page_test 17426.57 ( 0.00%) 26649.92 (-52.93%) Stddev exec_test 0.47 ( 0.00%) 1.41 (-199.05%) Stddev fork_test 63.74 ( 0.00%) 32.59 ( 48.86%) Max page_test 429873.33 ( 0.00%) 456960.00 ( 6.30%) Max exec_test 500.33 ( 0.00%) 507.66 ( 1.47%) Max fork_test 3653.33 ( 0.00%) 3650.90 ( -0.07%) 4.6-rc6 4.6-rc6 rwsemv2 User 1.12 0.04 System 0.23 0.04 Elapsed 727.27 721.98 Signed-off-by: Davidlohr Bueso Signed-off-by: Peter Zijlstra (Intel) Cc: Andrew Morton Cc: Linus Torvalds Cc: Paul E. McKenney Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: Waiman.Long@hpe.com Cc: dave@stgolabs.net Cc: jason.low2@hp.com Cc: peter@hurleysoftware.com Link: http://lkml.kernel.org/r/1463165787-25937-2-git-send-email-dave@stgolabs.net Signed-off-by: Ingo Molnar diff --git a/kernel/locking/rwsem-xadd.c b/kernel/locking/rwsem-xadd.c index 09e30c6..80b05ac 100644 --- a/kernel/locking/rwsem-xadd.c +++ b/kernel/locking/rwsem-xadd.c @@ -114,12 +114,16 @@ enum rwsem_wake_type { * - the 'active part' of count (&0x0000ffff) reached 0 (but may have changed) * - the 'waiting part' of count (&0xffff0000) is -ve (and will still be so) * - there must be someone on the queue - * - the spinlock must be held by the caller + * - the wait_lock must be held by the caller + * - tasks are marked for wakeup, the caller must later invoke wake_up_q() + * to actually wakeup the blocked task(s) and drop the reference count, + * preferably when the wait_lock is released * - woken process blocks are discarded from the list after having task zeroed - * - writers are only woken if downgrading is false + * - writers are only marked woken if downgrading is false */ static struct rw_semaphore * -__rwsem_do_wake(struct rw_semaphore *sem, enum rwsem_wake_type wake_type) +__rwsem_mark_wake(struct rw_semaphore *sem, + enum rwsem_wake_type wake_type, struct wake_q_head *wake_q) { struct rwsem_waiter *waiter; struct task_struct *tsk; @@ -128,13 +132,16 @@ __rwsem_do_wake(struct rw_semaphore *sem, enum rwsem_wake_type wake_type) waiter = list_entry(sem->wait_list.next, struct rwsem_waiter, list); if (waiter->type == RWSEM_WAITING_FOR_WRITE) { - if (wake_type == RWSEM_WAKE_ANY) - /* Wake writer at the front of the queue, but do not - * grant it the lock yet as we want other writers - * to be able to steal it. Readers, on the other hand, - * will block as they will notice the queued writer. + if (wake_type == RWSEM_WAKE_ANY) { + /* + * Mark writer at the front of the queue for wakeup. + * Until the task is actually later awoken later by + * the caller, other writers are able to steal it. + * Readers, on the other hand, will block as they + * will notice the queued writer. */ - wake_up_process(waiter->task); + wake_q_add(wake_q, waiter->task); + } goto out; } @@ -196,7 +203,7 @@ __rwsem_do_wake(struct rw_semaphore *sem, enum rwsem_wake_type wake_type) */ smp_mb(); waiter->task = NULL; - wake_up_process(tsk); + wake_q_add(wake_q, tsk); put_task_struct(tsk); } while (--loop); @@ -216,6 +223,7 @@ struct rw_semaphore __sched *rwsem_down_read_failed(struct rw_semaphore *sem) long count, adjustment = -RWSEM_ACTIVE_READ_BIAS; struct rwsem_waiter waiter; struct task_struct *tsk = current; + WAKE_Q(wake_q); /* set up my own style of waitqueue */ waiter.task = tsk; @@ -238,9 +246,10 @@ struct rw_semaphore __sched *rwsem_down_read_failed(struct rw_semaphore *sem) if (count == RWSEM_WAITING_BIAS || (count > RWSEM_WAITING_BIAS && adjustment != -RWSEM_ACTIVE_READ_BIAS)) - sem = __rwsem_do_wake(sem, RWSEM_WAKE_ANY); + sem = __rwsem_mark_wake(sem, RWSEM_WAKE_ANY, &wake_q); raw_spin_unlock_irq(&sem->wait_lock); + wake_up_q(&wake_q); /* wait to be given the lock */ while (true) { @@ -440,6 +449,7 @@ __rwsem_down_write_failed_common(struct rw_semaphore *sem, int state) bool waiting = true; /* any queued threads before us */ struct rwsem_waiter waiter; struct rw_semaphore *ret = sem; + WAKE_Q(wake_q); /* undo write bias from down_write operation, stop active locking */ count = rwsem_atomic_update(-RWSEM_ACTIVE_WRITE_BIAS, sem); @@ -472,8 +482,19 @@ __rwsem_down_write_failed_common(struct rw_semaphore *sem, int state) * no active writers, the lock must be read owned; so we try to * wake any read locks that were queued ahead of us. */ - if (count > RWSEM_WAITING_BIAS) - sem = __rwsem_do_wake(sem, RWSEM_WAKE_READERS); + if (count > RWSEM_WAITING_BIAS) { + WAKE_Q(wake_q); + + sem = __rwsem_mark_wake(sem, RWSEM_WAKE_READERS, &wake_q); + /* + * The wakeup is normally called _after_ the wait_lock + * is released, but given that we are proactively waking + * readers we can deal with the wake_q overhead as it is + * similar to releasing and taking the wait_lock again + * for attempting rwsem_try_write_lock(). + */ + wake_up_q(&wake_q); + } } else count = rwsem_atomic_update(RWSEM_WAITING_BIAS, sem); @@ -509,8 +530,9 @@ out_nolock: if (list_empty(&sem->wait_list)) rwsem_atomic_update(-RWSEM_WAITING_BIAS, sem); else - __rwsem_do_wake(sem, RWSEM_WAKE_ANY); + __rwsem_mark_wake(sem, RWSEM_WAKE_ANY, &wake_q); raw_spin_unlock_irq(&sem->wait_lock); + wake_up_q(&wake_q); return ERR_PTR(-EINTR); } @@ -537,6 +559,7 @@ __visible struct rw_semaphore *rwsem_wake(struct rw_semaphore *sem) { unsigned long flags; + WAKE_Q(wake_q); /* * If a spinner is present, it is not necessary to do the wakeup. @@ -573,9 +596,10 @@ locked: /* do nothing if list empty */ if (!list_empty(&sem->wait_list)) - sem = __rwsem_do_wake(sem, RWSEM_WAKE_ANY); + sem = __rwsem_mark_wake(sem, RWSEM_WAKE_ANY, &wake_q); raw_spin_unlock_irqrestore(&sem->wait_lock, flags); + wake_up_q(&wake_q); return sem; } @@ -590,14 +614,16 @@ __visible struct rw_semaphore *rwsem_downgrade_wake(struct rw_semaphore *sem) { unsigned long flags; + WAKE_Q(wake_q); raw_spin_lock_irqsave(&sem->wait_lock, flags); /* do nothing if list empty */ if (!list_empty(&sem->wait_list)) - sem = __rwsem_do_wake(sem, RWSEM_WAKE_READ_OWNED); + sem = __rwsem_mark_wake(sem, RWSEM_WAKE_READ_OWNED, &wake_q); raw_spin_unlock_irqrestore(&sem->wait_lock, flags); + wake_up_q(&wake_q); return sem; } -- cgit v0.10.2 From e38513905eeaae59056eac2c9ac55a43b1fc41b2 Mon Sep 17 00:00:00 2001 From: Davidlohr Bueso Date: Fri, 13 May 2016 11:56:27 -0700 Subject: locking/rwsem: Rework zeroing reader waiter->task Readers that are awoken will expect a nil ->task indicating that a wakeup has occurred. Because of the way readers are implemented, there's a small chance that the waiter will never block in the slowpath (rwsem_down_read_failed), and therefore requires some form of reference counting to avoid the following scenario: rwsem_down_read_failed() rwsem_wake() get_task_struct(); spin_lock_irq(&wait_lock); list_add_tail(&waiter.list) spin_unlock_irq(&wait_lock); raw_spin_lock_irqsave(&wait_lock) __rwsem_do_wake() while (1) { set_task_state(TASK_UNINTERRUPTIBLE); waiter->task = NULL if (!waiter.task) // true break; schedule() // never reached __set_task_state(TASK_RUNNING); do_exit(); wake_up_process(tsk); // boom ... and therefore race with do_exit() when the caller returns. There is also a mismatch between the smp_mb() and its documentation, in that the serialization is done between reading the task and the nil store. Furthermore, in addition to having the overlapping of loads and stores to waiter->task guaranteed to be ordered within that CPU, both wake_up_process() originally and now wake_q_add() already imply barriers upon successful calls, which serves the comment. Now, as an alternative to perhaps inverting the checks in the blocker side (which has its own penalty in that schedule is unavoidable), with lockless wakeups this situation is naturally addressed and we can just use the refcount held by wake_q_add(), instead doing so explicitly. Of course, we must guarantee that the nil store is done as the _last_ operation in that the task must already be marked for deletion to not fall into the race above. Spurious wakeups are also handled transparently in that the task's reference is only removed when wake_up_q() is actually called _after_ the nil store. Signed-off-by: Davidlohr Bueso Signed-off-by: Peter Zijlstra (Intel) Cc: Andrew Morton Cc: Linus Torvalds Cc: Paul E. McKenney Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: Waiman.Long@hpe.com Cc: dave@stgolabs.net Cc: jason.low2@hp.com Cc: peter@hurleysoftware.com Link: http://lkml.kernel.org/r/1463165787-25937-3-git-send-email-dave@stgolabs.net Signed-off-by: Ingo Molnar diff --git a/kernel/locking/rwsem-xadd.c b/kernel/locking/rwsem-xadd.c index 80b05ac..fcbf75a 100644 --- a/kernel/locking/rwsem-xadd.c +++ b/kernel/locking/rwsem-xadd.c @@ -194,17 +194,15 @@ __rwsem_mark_wake(struct rw_semaphore *sem, waiter = list_entry(next, struct rwsem_waiter, list); next = waiter->list.next; tsk = waiter->task; + + wake_q_add(wake_q, tsk); /* - * Make sure we do not wakeup the next reader before - * setting the nil condition to grant the next reader; - * otherwise we could miss the wakeup on the other - * side and end up sleeping again. See the pairing - * in rwsem_down_read_failed(). + * Ensure that the last operation is setting the reader + * waiter to nil such that rwsem_down_read_failed() cannot + * race with do_exit() by always holding a reference count + * to the task to wakeup. */ - smp_mb(); - waiter->task = NULL; - wake_q_add(wake_q, tsk); - put_task_struct(tsk); + smp_store_release(&waiter->task, NULL); } while (--loop); sem->wait_list.next = next; @@ -228,7 +226,6 @@ struct rw_semaphore __sched *rwsem_down_read_failed(struct rw_semaphore *sem) /* set up my own style of waitqueue */ waiter.task = tsk; waiter.type = RWSEM_WAITING_FOR_READ; - get_task_struct(tsk); raw_spin_lock_irq(&sem->wait_lock); if (list_empty(&sem->wait_list)) -- cgit v0.10.2 From c0fcb6c2d332041256dc55d8a1ec3c0a2d0befb8 Mon Sep 17 00:00:00 2001 From: Jason Low Date: Mon, 16 May 2016 17:38:00 -0700 Subject: locking/rwsem: Optimize write lock by reducing operations in slowpath When acquiring the rwsem write lock in the slowpath, we first try to set count to RWSEM_WAITING_BIAS. When that is successful, we then atomically add the RWSEM_WAITING_BIAS in cases where there are other tasks on the wait list. This causes write lock operations to often issue multiple atomic operations. We can instead make the list_is_singular() check first, and then set the count accordingly, so that we issue at most 1 atomic operation when acquiring the write lock and reduce unnecessary cacheline contention. Signed-off-by: Jason Low Signed-off-by: Peter Zijlstra (Intel) Acked-by: Waiman Long Acked-by: Davidlohr Bueso Cc: Andrew Morton Cc: Arnd Bergmann Cc: Christoph Lameter Cc: Fenghua Yu Cc: Heiko Carstens Cc: Ivan Kokshaysky Cc: Jason Low Cc: Linus Torvalds Cc: Martin Schwidefsky Cc: Matt Turner Cc: Paul E. McKenney Cc: Peter Hurley Cc: Peter Zijlstra Cc: Richard Henderson Cc: Terry Rudd Cc: Thomas Gleixner Cc: Tim Chen Cc: Tony Luck Link: http://lkml.kernel.org/r/1463445486-16078-2-git-send-email-jason.low2@hpe.com Signed-off-by: Ingo Molnar diff --git a/kernel/locking/rwsem-xadd.c b/kernel/locking/rwsem-xadd.c index fcbf75a..b957da7 100644 --- a/kernel/locking/rwsem-xadd.c +++ b/kernel/locking/rwsem-xadd.c @@ -261,17 +261,28 @@ struct rw_semaphore __sched *rwsem_down_read_failed(struct rw_semaphore *sem) } EXPORT_SYMBOL(rwsem_down_read_failed); +/* + * This function must be called with the sem->wait_lock held to prevent + * race conditions between checking the rwsem wait list and setting the + * sem->count accordingly. + */ static inline bool rwsem_try_write_lock(long count, struct rw_semaphore *sem) { /* - * Try acquiring the write lock. Check count first in order - * to reduce unnecessary expensive cmpxchg() operations. + * Avoid trying to acquire write lock if count isn't RWSEM_WAITING_BIAS. */ - if (count == RWSEM_WAITING_BIAS && - cmpxchg_acquire(&sem->count, RWSEM_WAITING_BIAS, - RWSEM_ACTIVE_WRITE_BIAS) == RWSEM_WAITING_BIAS) { - if (!list_is_singular(&sem->wait_list)) - rwsem_atomic_update(RWSEM_WAITING_BIAS, sem); + if (count != RWSEM_WAITING_BIAS) + return false; + + /* + * Acquire the lock by trying to set it to ACTIVE_WRITE_BIAS. If there + * are other tasks on the wait list, we need to add on WAITING_BIAS. + */ + count = list_is_singular(&sem->wait_list) ? + RWSEM_ACTIVE_WRITE_BIAS : + RWSEM_ACTIVE_WRITE_BIAS + RWSEM_WAITING_BIAS; + + if (cmpxchg_acquire(&sem->count, RWSEM_WAITING_BIAS, count) == RWSEM_WAITING_BIAS) { rwsem_set_owner(sem); return true; } -- cgit v0.10.2 From 6e2814745c67ab422b86262b05e6f23a56f28aa3 Mon Sep 17 00:00:00 2001 From: Jason Low Date: Fri, 20 May 2016 15:19:36 -0700 Subject: locking/mutex: Set and clear owner using WRITE_ONCE() The mutex owner can get read and written to locklessly. Use WRITE_ONCE when setting and clearing the owner field in order to avoid optimizations such as store tearing. This avoids situations where the owner field gets written to with multiple stores and another thread could concurrently read and use a partially written owner value. Signed-off-by: Jason Low Signed-off-by: Peter Zijlstra (Intel) Acked-by: Davidlohr Bueso Acked-by: Waiman Long Cc: Andrew Morton Cc: Linus Torvalds Cc: Paul E. McKenney Cc: Peter Zijlstra Cc: Scott J Norton Cc: Terry Rudd Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/1463782776.2479.9.camel@j-VirtualBox Signed-off-by: Ingo Molnar diff --git a/kernel/locking/mutex-debug.h b/kernel/locking/mutex-debug.h index 0799fd3..372e653 100644 --- a/kernel/locking/mutex-debug.h +++ b/kernel/locking/mutex-debug.h @@ -29,12 +29,12 @@ extern void debug_mutex_init(struct mutex *lock, const char *name, static inline void mutex_set_owner(struct mutex *lock) { - lock->owner = current; + WRITE_ONCE(lock->owner, current); } static inline void mutex_clear_owner(struct mutex *lock) { - lock->owner = NULL; + WRITE_ONCE(lock->owner, NULL); } #define spin_lock_mutex(lock, flags) \ diff --git a/kernel/locking/mutex.h b/kernel/locking/mutex.h index 5cda397..12f9619 100644 --- a/kernel/locking/mutex.h +++ b/kernel/locking/mutex.h @@ -17,14 +17,20 @@ __list_del((waiter)->list.prev, (waiter)->list.next) #ifdef CONFIG_MUTEX_SPIN_ON_OWNER +/* + * The mutex owner can get read and written to locklessly. + * We should use WRITE_ONCE when writing the owner value to + * avoid store tearing, otherwise, a thread could potentially + * read a partially written and incomplete owner value. + */ static inline void mutex_set_owner(struct mutex *lock) { - lock->owner = current; + WRITE_ONCE(lock->owner, current); } static inline void mutex_clear_owner(struct mutex *lock) { - lock->owner = NULL; + WRITE_ONCE(lock->owner, NULL); } #else static inline void mutex_set_owner(struct mutex *lock) -- cgit v0.10.2 From ed8ebd1d514126c0e54fbdbd231427dc91c877c2 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Wed, 25 May 2016 16:11:57 -0400 Subject: percpu, locking: Revert ("percpu: Replace smp_read_barrier_depends() with lockless_dereference()") lockless_dereference() is planned to grow a sanity check to ensure that the input parameter is a pointer. __ref_is_percpu() passes in an unsinged long value which is a combination of a pointer and a flag. While it can be casted to a pointer lvalue, the casting looks messy and it's a special case anyway. Let's revert back to open-coding READ_ONCE() and explicit barrier. This doesn't cause any functional changes. Signed-off-by: Tejun Heo Signed-off-by: Peter Zijlstra (Intel) Cc: Alexey Dobriyan Cc: Andrew Morton Cc: Linus Torvalds Cc: Paul E. McKenney Cc: Paul McKenney Cc: Peter Zijlstra Cc: Pranith Kumar Cc: Thomas Gleixner Cc: kernel-team@fb.com Link: http://lkml.kernel.org/g/20160522185040.GA23664@p183.telecom.by Signed-off-by: Ingo Molnar diff --git a/include/linux/percpu-refcount.h b/include/linux/percpu-refcount.h index 84f542d..1c7eec0 100644 --- a/include/linux/percpu-refcount.h +++ b/include/linux/percpu-refcount.h @@ -136,14 +136,12 @@ static inline bool __ref_is_percpu(struct percpu_ref *ref, * used as a pointer. If the compiler generates a separate fetch * when using it as a pointer, __PERCPU_REF_ATOMIC may be set in * between contaminating the pointer value, meaning that - * ACCESS_ONCE() is required when fetching it. - * - * Also, we need a data dependency barrier to be paired with - * smp_store_release() in __percpu_ref_switch_to_percpu(). - * - * Use lockless deref which contains both. + * READ_ONCE() is required when fetching it. */ - percpu_ptr = lockless_dereference(ref->percpu_count_ptr); + percpu_ptr = READ_ONCE(ref->percpu_count_ptr); + + /* paired with smp_store_release() in __percpu_ref_switch_to_percpu() */ + smp_read_barrier_depends(); /* * Theoretically, the following could test just ATOMIC; however, -- cgit v0.10.2 From afa814841c812cd1a36dbbb124542a487c2df5ee Mon Sep 17 00:00:00 2001 From: Alison Schofield Date: Wed, 1 Jun 2016 21:28:14 -0700 Subject: iio: adc: ad7793: claim direct mode when writing frequency Driver was checking for direct mode and trying to lock it, but left a gap where mode could change before the desired operation. Use iio_device_claim_direct_mode() to guarantee device stays in direct mode. Refactor function to clarify look-up followed by lock sequence. Signed-off-by: Alison Schofield Cc: Daniel Baluta Acked-by: Lars-Peter Clausen Signed-off-by: Jonathan Cameron diff --git a/drivers/iio/adc/ad7793.c b/drivers/iio/adc/ad7793.c index 7b07bb6..a43722f 100644 --- a/drivers/iio/adc/ad7793.c +++ b/drivers/iio/adc/ad7793.c @@ -369,13 +369,6 @@ static ssize_t ad7793_write_frequency(struct device *dev, long lval; int i, ret; - mutex_lock(&indio_dev->mlock); - if (iio_buffer_enabled(indio_dev)) { - mutex_unlock(&indio_dev->mlock); - return -EBUSY; - } - mutex_unlock(&indio_dev->mlock); - ret = kstrtol(buf, 10, &lval); if (ret) return ret; @@ -383,20 +376,21 @@ static ssize_t ad7793_write_frequency(struct device *dev, if (lval == 0) return -EINVAL; - ret = -EINVAL; - for (i = 0; i < 16; i++) - if (lval == st->chip_info->sample_freq_avail[i]) { - mutex_lock(&indio_dev->mlock); - st->mode &= ~AD7793_MODE_RATE(-1); - st->mode |= AD7793_MODE_RATE(i); - ad_sd_write_reg(&st->sd, AD7793_REG_MODE, - sizeof(st->mode), st->mode); - mutex_unlock(&indio_dev->mlock); - ret = 0; - } + if (lval == st->chip_info->sample_freq_avail[i]) + break; + if (i == 16) + return -EINVAL; - return ret ? ret : len; + ret = iio_device_claim_direct_mode(indio_dev); + if (ret) + return ret; + st->mode &= ~AD7793_MODE_RATE(-1); + st->mode |= AD7793_MODE_RATE(i); + ad_sd_write_reg(&st->sd, AD7793_REG_MODE, sizeof(st->mode), st->mode); + iio_device_release_direct_mode(indio_dev); + + return len; } static IIO_DEV_ATTR_SAMP_FREQ(S_IWUSR | S_IRUGO, -- cgit v0.10.2 From d7203ad864db0b34f0e106ec0659890c4e58c143 Mon Sep 17 00:00:00 2001 From: Alison Schofield Date: Tue, 31 May 2016 21:35:49 -0700 Subject: iio: adc: ad7791: claim direct mode when writing frequency Driver was checking for direct mode and trying to lock it, but left a gap where mode could change before the desired operation. Use iio_device_claim_direct_mode() to guarantee device stays in direct mode. Refactor function to clarify look-up followed by lock sequence. Signed-off-by: Alison Schofield Cc: Daniel Baluta Acked-by: Lars-Peter Clausen Signed-off-by: Jonathan Cameron diff --git a/drivers/iio/adc/ad7791.c b/drivers/iio/adc/ad7791.c index cf172d58..1dfe641 100644 --- a/drivers/iio/adc/ad7791.c +++ b/drivers/iio/adc/ad7791.c @@ -272,30 +272,22 @@ static ssize_t ad7791_write_frequency(struct device *dev, struct ad7791_state *st = iio_priv(indio_dev); int i, ret; - mutex_lock(&indio_dev->mlock); - if (iio_buffer_enabled(indio_dev)) { - mutex_unlock(&indio_dev->mlock); - return -EBUSY; - } - mutex_unlock(&indio_dev->mlock); - - ret = -EINVAL; - - for (i = 0; i < ARRAY_SIZE(ad7791_sample_freq_avail); i++) { - if (sysfs_streq(ad7791_sample_freq_avail[i], buf)) { - - mutex_lock(&indio_dev->mlock); - st->filter &= ~AD7791_FILTER_RATE_MASK; - st->filter |= i; - ad_sd_write_reg(&st->sd, AD7791_REG_FILTER, - sizeof(st->filter), st->filter); - mutex_unlock(&indio_dev->mlock); - ret = 0; + for (i = 0; i < ARRAY_SIZE(ad7791_sample_freq_avail); i++) + if (sysfs_streq(ad7791_sample_freq_avail[i], buf)) break; - } - } + if (i == ARRAY_SIZE(ad7791_sample_freq_avail)) + return -EINVAL; + + ret = iio_device_claim_direct_mode(indio_dev); + if (ret) + return ret; + st->filter &= ~AD7791_FILTER_RATE_MASK; + st->filter |= i; + ad_sd_write_reg(&st->sd, AD7791_REG_FILTER, sizeof(st->filter), + st->filter); + iio_device_release_direct_mode(indio_dev); - return ret ? ret : len; + return len; } static IIO_DEV_ATTR_SAMP_FREQ(S_IWUSR | S_IRUGO, -- cgit v0.10.2 From fea89e2dfceaf78d132b12a4aab3db3c04fb5639 Mon Sep 17 00:00:00 2001 From: "Andrew F. Davis" Date: Tue, 31 May 2016 12:00:12 -0500 Subject: iio: adc: ti_am335x_adc: use variable names for sizeof() operator Fix the code formatting to use the kernel preferred style of using the actual variables to determize the size using the sizeof() operator. Signed-off-by: Andrew F. Davis Signed-off-by: Jonathan Cameron diff --git a/drivers/iio/adc/ti_am335x_adc.c b/drivers/iio/adc/ti_am335x_adc.c index c1e0553..9f406d0 100644 --- a/drivers/iio/adc/ti_am335x_adc.c +++ b/drivers/iio/adc/ti_am335x_adc.c @@ -326,8 +326,7 @@ static int tiadc_channel_init(struct iio_dev *indio_dev, int channels) int i; indio_dev->num_channels = channels; - chan_array = kcalloc(channels, - sizeof(struct iio_chan_spec), GFP_KERNEL); + chan_array = kcalloc(channels, sizeof(*chan_array), GFP_KERNEL); if (chan_array == NULL) return -ENOMEM; @@ -467,8 +466,7 @@ static int tiadc_probe(struct platform_device *pdev) return -EINVAL; } - indio_dev = devm_iio_device_alloc(&pdev->dev, - sizeof(struct tiadc_device)); + indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*indio_dev)); if (indio_dev == NULL) { dev_err(&pdev->dev, "failed to allocate iio device\n"); return -ENOMEM; -- cgit v0.10.2 From 27aa832d1882da4b6595abe99e287f46b2d54f45 Mon Sep 17 00:00:00 2001 From: "Andrew F. Davis" Date: Tue, 31 May 2016 12:00:07 -0500 Subject: iio: adc: ti_am335x_adc: use SIMPLE_DEV_PM_OPS helper macro Replace ifdefs with SIMPLE_DEV_PM_OPS helper macro. Signed-off-by: Andrew F. Davis Signed-off-by: Jonathan Cameron diff --git a/drivers/iio/adc/ti_am335x_adc.c b/drivers/iio/adc/ti_am335x_adc.c index 9f406d0..8a36875 100644 --- a/drivers/iio/adc/ti_am335x_adc.c +++ b/drivers/iio/adc/ti_am335x_adc.c @@ -529,8 +529,7 @@ static int tiadc_remove(struct platform_device *pdev) return 0; } -#ifdef CONFIG_PM -static int tiadc_suspend(struct device *dev) +static int __maybe_unused tiadc_suspend(struct device *dev) { struct iio_dev *indio_dev = dev_get_drvdata(dev); struct tiadc_device *adc_dev = iio_priv(indio_dev); @@ -548,7 +547,7 @@ static int tiadc_suspend(struct device *dev) return 0; } -static int tiadc_resume(struct device *dev) +static int __maybe_unused tiadc_resume(struct device *dev) { struct iio_dev *indio_dev = dev_get_drvdata(dev); struct tiadc_device *adc_dev = iio_priv(indio_dev); @@ -565,14 +564,7 @@ static int tiadc_resume(struct device *dev) return 0; } -static const struct dev_pm_ops tiadc_pm_ops = { - .suspend = tiadc_suspend, - .resume = tiadc_resume, -}; -#define TIADC_PM_OPS (&tiadc_pm_ops) -#else -#define TIADC_PM_OPS NULL -#endif +static SIMPLE_DEV_PM_OPS(tiadc_pm_ops, tiadc_suspend, tiadc_resume); static const struct of_device_id ti_adc_dt_ids[] = { { .compatible = "ti,am3359-adc", }, @@ -583,7 +575,7 @@ MODULE_DEVICE_TABLE(of, ti_adc_dt_ids); static struct platform_driver tiadc_driver = { .driver = { .name = "TI-am335x-adc", - .pm = TIADC_PM_OPS, + .pm = &tiadc_pm_ops, .of_match_table = ti_adc_dt_ids, }, .probe = tiadc_probe, -- cgit v0.10.2 From bc2e1126eccb47517b9d1c685020c38600f99a3d Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 6 Mar 2016 20:02:56 +0000 Subject: iio:trigger: Experimental kthread tight loop trigger (thread only) This patch is in response to that of Gregor Boirie who proposed using a tight kthread within a device driver (be it with the support factored out into a helper library) in order to basically spin as fast as possible. It is meant as a talking point rather than a formal proposal of the code (though we are heading towards that I think). Also gives people some working code to mess around with. I proposed that this could be done with a trigger with a few constraints and this is the proof (be it ugly) of that. There are some constraints though, some of which we would want to relax if this were to move forward. * Will only run the thread part of the registered pollfunc. This is to avoid the overhead of jumping in and out of interrupt context. Is the overhead significant? Not certain but feels like it should be! * This limitation precludes any device that 'must' do some work in interrupt context. However, that is true of few if any drivers and I suspect that any that do will be restricted to using triggers they provide themselves. Usually we have a top half mainly to grab a timestamp as soon after the dataready type signal as possible. Signed-off-by: Jonathan Cameron Acked-by: Daniel Baluta diff --git a/drivers/iio/trigger/Kconfig b/drivers/iio/trigger/Kconfig index 519e677..809b2e7 100644 --- a/drivers/iio/trigger/Kconfig +++ b/drivers/iio/trigger/Kconfig @@ -24,6 +24,18 @@ config IIO_INTERRUPT_TRIGGER To compile this driver as a module, choose M here: the module will be called iio-trig-interrupt. +config IIO_TIGHTLOOP_TRIGGER + tristate "A kthread based hammering loop trigger" + depends on IIO_SW_TRIGGER + help + An experimental trigger, used to allow sensors to be sampled as fast + as possible under the limitations of whatever else is going on. + Uses a tight loop in a kthread. Will only work with lower half only + trigger consumers. + + To compile this driver as a module, choose M here: the + module will be called iio-trig-loop. + config IIO_SYSFS_TRIGGER tristate "SYSFS trigger" depends on SYSFS diff --git a/drivers/iio/trigger/Makefile b/drivers/iio/trigger/Makefile index fe06eb5..aab4dc2 100644 --- a/drivers/iio/trigger/Makefile +++ b/drivers/iio/trigger/Makefile @@ -7,3 +7,4 @@ obj-$(CONFIG_IIO_HRTIMER_TRIGGER) += iio-trig-hrtimer.o obj-$(CONFIG_IIO_INTERRUPT_TRIGGER) += iio-trig-interrupt.o obj-$(CONFIG_IIO_SYSFS_TRIGGER) += iio-trig-sysfs.o +obj-$(CONFIG_IIO_TIGHTLOOP_TRIGGER) += iio-trig-loop.o diff --git a/drivers/iio/trigger/iio-trig-loop.c b/drivers/iio/trigger/iio-trig-loop.c new file mode 100644 index 0000000..dc6be28 --- /dev/null +++ b/drivers/iio/trigger/iio-trig-loop.c @@ -0,0 +1,143 @@ +/* + * Copyright 2016 Jonathan Cameron + * + * Licensed under the GPL-2. + * + * Based on a mashup of the hrtimer trigger and continuous sampling proposal of + * Gregor Boirie + * + * Note this is still rather experimental and may eat babies. + * + * Todo + * * Protect against connection of devices that 'need' the top half + * handler. + * * Work out how to run top half handlers in this context if it is + * safe to do so (timestamp grabbing for example) + * + * Tested against a max1363. Used about 33% cpu for the thread and 20% + * for generic_buffer piping to /dev/null. Watermark set at 64 on a 128 + * element kfifo buffer. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +struct iio_loop_info { + struct iio_sw_trigger swt; + struct task_struct *task; +}; + +static struct config_item_type iio_loop_type = { + .ct_owner = THIS_MODULE, +}; + +static int iio_loop_thread(void *data) +{ + struct iio_trigger *trig = data; + + set_freezable(); + + do { + iio_trigger_poll_chained(trig); + } while (likely(!kthread_freezable_should_stop(NULL))); + + return 0; +} + +static int iio_loop_trigger_set_state(struct iio_trigger *trig, bool state) +{ + struct iio_loop_info *loop_trig = iio_trigger_get_drvdata(trig); + + if (state) { + loop_trig->task = kthread_run(iio_loop_thread, + trig, trig->name); + if (unlikely(IS_ERR(loop_trig->task))) { + dev_err(&trig->dev, + "failed to create trigger loop thread\n"); + return PTR_ERR(loop_trig->task); + } + } else { + kthread_stop(loop_trig->task); + } + + return 0; +} + +static const struct iio_trigger_ops iio_loop_trigger_ops = { + .set_trigger_state = iio_loop_trigger_set_state, + .owner = THIS_MODULE, +}; + +static struct iio_sw_trigger *iio_trig_loop_probe(const char *name) +{ + struct iio_loop_info *trig_info; + int ret; + + trig_info = kzalloc(sizeof(*trig_info), GFP_KERNEL); + if (!trig_info) + return ERR_PTR(-ENOMEM); + + trig_info->swt.trigger = iio_trigger_alloc("%s", name); + if (!trig_info->swt.trigger) { + ret = -ENOMEM; + goto err_free_trig_info; + } + + iio_trigger_set_drvdata(trig_info->swt.trigger, trig_info); + trig_info->swt.trigger->ops = &iio_loop_trigger_ops; + + ret = iio_trigger_register(trig_info->swt.trigger); + if (ret) + goto err_free_trigger; + + iio_swt_group_init_type_name(&trig_info->swt, name, &iio_loop_type); + + return &trig_info->swt; + +err_free_trigger: + iio_trigger_free(trig_info->swt.trigger); +err_free_trig_info: + kfree(trig_info); + + return ERR_PTR(ret); +} + +static int iio_trig_loop_remove(struct iio_sw_trigger *swt) +{ + struct iio_loop_info *trig_info; + + trig_info = iio_trigger_get_drvdata(swt->trigger); + + iio_trigger_unregister(swt->trigger); + iio_trigger_free(swt->trigger); + kfree(trig_info); + + return 0; +} + +static const struct iio_sw_trigger_ops iio_trig_loop_ops = { + .probe = iio_trig_loop_probe, + .remove = iio_trig_loop_remove, +}; + +static struct iio_sw_trigger_type iio_trig_loop = { + .name = "loop", + .owner = THIS_MODULE, + .ops = &iio_trig_loop_ops, +}; + +module_iio_sw_trigger_driver(iio_trig_loop); + +MODULE_AUTHOR("Jonathan Cameron "); +MODULE_DESCRIPTION("Loop based trigger for the iio subsystem"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:iio-trig-loop"); -- cgit v0.10.2 From 90525176d71995ffde2d0c532f2758304c666a08 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 31 May 2016 12:47:46 -0300 Subject: perf evsel: Provide way to extract integer value from format_field Out of perf_evsel__intval(), that requires passing the variable name, that will then be searched in the list of tracepoint variables for the given evsel. In cases such as syscall file descriptor ("fd") tracking, this is wasteful, we need just to use perf_evsel__field() and cache the format_field. Cc: Adrian Hunter Cc: David Ahern Cc: Jiri Olsa Cc: Milian Wolff Cc: Namhyung Kim Cc: Wang Nan Link: http://lkml.kernel.org/n/tip-r6f89jx9j5nkx037d0naviqy@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index 8d30cbd..f4f01b2 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c @@ -2251,17 +2251,11 @@ void *perf_evsel__rawptr(struct perf_evsel *evsel, struct perf_sample *sample, return sample->raw_data + offset; } -u64 perf_evsel__intval(struct perf_evsel *evsel, struct perf_sample *sample, - const char *name) +u64 format_field__intval(struct format_field *field, struct perf_sample *sample, + bool needs_swap) { - struct format_field *field = perf_evsel__field(evsel, name); - void *ptr; u64 value; - - if (!field) - return 0; - - ptr = sample->raw_data + field->offset; + void *ptr = sample->raw_data + field->offset; switch (field->size) { case 1: @@ -2279,7 +2273,7 @@ u64 perf_evsel__intval(struct perf_evsel *evsel, struct perf_sample *sample, return 0; } - if (!evsel->needs_swap) + if (!needs_swap) return value; switch (field->size) { @@ -2296,6 +2290,17 @@ u64 perf_evsel__intval(struct perf_evsel *evsel, struct perf_sample *sample, return 0; } +u64 perf_evsel__intval(struct perf_evsel *evsel, struct perf_sample *sample, + const char *name) +{ + struct format_field *field = perf_evsel__field(evsel, name); + + if (!field) + return 0; + + return field ? format_field__intval(field, sample, evsel->needs_swap) : 0; +} + bool perf_evsel__fallback(struct perf_evsel *evsel, int err, char *msg, size_t msgsize) { diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h index 028412b..828ddd1 100644 --- a/tools/perf/util/evsel.h +++ b/tools/perf/util/evsel.h @@ -261,6 +261,8 @@ static inline char *perf_evsel__strval(struct perf_evsel *evsel, struct format_field; +u64 format_field__intval(struct format_field *field, struct perf_sample *sample, bool needs_swap); + struct format_field *perf_evsel__field(struct perf_evsel *evsel, const char *name); #define perf_evsel__match(evsel, t, c) \ -- cgit v0.10.2 From 946ae1d41d4b0c77b9f63b4a0393d8a1283a7f9d Mon Sep 17 00:00:00 2001 From: Wang Nan Date: Tue, 31 May 2016 13:06:15 +0000 Subject: perf evlist: Fix alloc_mmap() failure path If zalloc fail, setting evlist->mmap[i].fd is unsafe and perf_evlist__alloc_mmap() should bail out right after that. Signed-off-by: Wang Nan Acked-by: Masami Hiramatsu Cc: He Kuang Cc: Jiri Olsa Cc: Namhyung Kim Cc: Zefan Li Cc: pi3orama@163.com Fixes: d4c6fb36ac2c ("perf evsel: Record fd into perf_mmap") Link: http://lkml.kernel.org/r/1464699975-230440-1-git-send-email-wangnan0@huawei.com Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index e0f3094..1b918aa 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c @@ -946,9 +946,12 @@ static int perf_evlist__alloc_mmap(struct perf_evlist *evlist) if (cpu_map__empty(evlist->cpus)) evlist->nr_mmaps = thread_map__nr(evlist->threads); evlist->mmap = zalloc(evlist->nr_mmaps * sizeof(struct perf_mmap)); + if (!evlist->mmap) + return -ENOMEM; + for (i = 0; i < evlist->nr_mmaps; i++) evlist->mmap[i].fd = -1; - return evlist->mmap != NULL ? 0 : -ENOMEM; + return 0; } struct mmap_params { -- cgit v0.10.2 From 703e01652d25edbd249e3043c26543157f0ef15c Mon Sep 17 00:00:00 2001 From: Lucas Stach Date: Thu, 17 Mar 2016 18:27:50 +0100 Subject: tools lib api: Respect CROSS_COMPILE for the linker This fixes cross compilation of libapi. Signed-off-by: Lucas Stach Cc: Jiri Olsa Cc: kernel@pengutronix.de Cc: patchwork-lst@pengutronix.de Link: http://lkml.kernel.org/r/1458235670-27341-1-git-send-email-l.stach@pengutronix.de Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/lib/api/Makefile b/tools/lib/api/Makefile index 316f308..67ff93e 100644 --- a/tools/lib/api/Makefile +++ b/tools/lib/api/Makefile @@ -10,6 +10,7 @@ endif CC = $(CROSS_COMPILE)gcc AR = $(CROSS_COMPILE)ar +LD = $(CROSS_COMPILE)ld MAKEFLAGS += --no-print-directory -- cgit v0.10.2 From 40f20e5074b035c7111e135aa939d1d1a96a2480 Mon Sep 17 00:00:00 2001 From: He Kuang Date: Mon, 16 May 2016 04:51:19 +0000 Subject: perf script: Show call graphs when 1st event doesn't have it but some other has There's a display inconsistency when there are multiple tracepoint events, some of which have the 'call-graph' config option set but the first one hasn't, i.e. the whole logic for call graph processing is enabled only if the first tracepoint event has call-graph set. For instance, if we record signal_deliver with call-graph and signal_generate without: $ perf record -g -a -e signal:signal_deliver -e signal:signal_generate/call-graph=no/ [ perf record: Captured and wrote 0.017 MB perf.data (2 samples) ] $ perf script kworker/u2:1 13 [000] 6563.875949: signal:signal_generate: sig=2 errno=0 code=128 comm=perf pid=1313 grp=1 res=0 ff61cc __send_signal+0x3ec ([kernel.kallsyms]) perf 1313 [000] 6563.877584: signal:signal_deliver: sig=2 errno=0 code=128 sa_handler=43115e sa_flags=14000000 7ffff314 get_signal+0x80007f0023a4 ([kernel.kallsyms]) 7fffe358 do_signal+0x80007f002028 ([kernel.kallsyms]) 7fffa5e8 exit_to_usermode_loop+0x80007f002053 ([kernel.kallsyms]) ... Then we exchange the order of these two events in commandline, and keep signal_generate without call-graph. $ perf record -g -a -e signal:signal_generate/call-graph=no/ -e signal:signal_deliver [ perf record: Captured and wrote 0.017 MB perf.data (2 samples) ] $ perf script kworker/u2:2 1314 [000] 6933.353060: signal:signal_generate: sig=2 errno=0 code=128 comm=perf pid=1321 grp=1 res=0 perf 1321 [000] 6933.353872: signal:signal_deliver: sig=2 errno=0 code=128 sa_handler=43115e sa_flags=14000000 This time, the callchain of the event signal_deliver disappeared. The problem is caused by that perf only checks for the first evsel in evlist and decides if callchain should be printed. This patch traverses all evsels in evlist to see if any of them have callchains, and shows the right result: $ perf script kworker/u2:2 1314 [000] 6933.353060: signal:signal_generate: sig=2 errno=0 code=128 comm=perf pid=1321 grp=1 res=0 ff61cc __send_signal+0x3ec ([kernel.kallsyms]) perf 1321 [000] 6933.353872: signal:signal_deliver: sig=2 errno=0 code=128 sa_handler=43115e sa_flags=14000000 7ffff314 get_signal+0x80007f0023a4 ([kernel.kallsyms]) 7fffe358 do_signal+0x80007f002028 ([kernel.kallsyms]) 7fffa5e8 exit_to_usermode_loop+0x80007f002053 ([kernel.kallsyms]) ... Signed-off-by: He Kuang Tested-by: Arnaldo Carvalho de Melo Cc: Alexander Shishkin Cc: Ingo Molnar Cc: Peter Zijlstra Cc: Wang Nan Link: http://lkml.kernel.org/r/1463374279-97209-1-git-send-email-hekuang@huawei.com Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c index e3ce2f3..4601123 100644 --- a/tools/perf/builtin-script.c +++ b/tools/perf/builtin-script.c @@ -339,7 +339,7 @@ static void set_print_ip_opts(struct perf_event_attr *attr) */ static int perf_session__check_output_opt(struct perf_session *session) { - int j; + unsigned int j; struct perf_evsel *evsel; for (j = 0; j < PERF_TYPE_MAX; ++j) { @@ -388,17 +388,20 @@ static int perf_session__check_output_opt(struct perf_session *session) struct perf_event_attr *attr; j = PERF_TYPE_TRACEPOINT; - evsel = perf_session__find_first_evtype(session, j); - if (evsel == NULL) - goto out; - attr = &evsel->attr; + evlist__for_each(session->evlist, evsel) { + if (evsel->attr.type != j) + continue; + + attr = &evsel->attr; - if (attr->sample_type & PERF_SAMPLE_CALLCHAIN) { - output[j].fields |= PERF_OUTPUT_IP; - output[j].fields |= PERF_OUTPUT_SYM; - output[j].fields |= PERF_OUTPUT_DSO; - set_print_ip_opts(attr); + if (attr->sample_type & PERF_SAMPLE_CALLCHAIN) { + output[j].fields |= PERF_OUTPUT_IP; + output[j].fields |= PERF_OUTPUT_SYM; + output[j].fields |= PERF_OUTPUT_DSO; + set_print_ip_opts(attr); + goto out; + } } } -- cgit v0.10.2 From d7e3528eed85b51ddca2f281d2d4e7d687f28d60 Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Tue, 31 May 2016 14:05:27 -0700 Subject: irqchip: bcm2835: Avoid arch/arm-specific handle_IRQ With commit 76ba59f8366f genirq: Add irq_domain-aware core IRQ handler architecture-specific irq handlers are no longer necessary. Update the bcm2835 irq driver to use the core irq handler. As a bonus, this allows the driver to support arm64 as well. Signed-off-by: Eric Anholt Acked-by: Stephen Warren Link: https://lkml.kernel.org/r/1464728727-16300-1-git-send-email-eric@anholt.net [jac reworded commit message for clarity] Signed-off-by: Jason Cooper diff --git a/drivers/irqchip/irq-bcm2835.c b/drivers/irqchip/irq-bcm2835.c index bf9cc5f..44d7c38 100644 --- a/drivers/irqchip/irq-bcm2835.c +++ b/drivers/irqchip/irq-bcm2835.c @@ -52,7 +52,6 @@ #include #include -#include /* Put the bank and irq (32 bits) into the hwirq */ #define MAKE_HWIRQ(b, n) ((b << 5) | (n)) @@ -242,7 +241,7 @@ static void __exception_irq_entry bcm2835_handle_irq( u32 hwirq; while ((hwirq = get_next_armctrl_hwirq()) != ~0) - handle_IRQ(irq_linear_revmap(intc.domain, hwirq), regs); + handle_domain_irq(intc.domain, hwirq, regs); } static void bcm2836_chained_handle_irq(struct irq_desc *desc) diff --git a/drivers/irqchip/irq-bcm2836.c b/drivers/irqchip/irq-bcm2836.c index 72ff1d5..2787598 100644 --- a/drivers/irqchip/irq-bcm2836.c +++ b/drivers/irqchip/irq-bcm2836.c @@ -180,7 +180,7 @@ __exception_irq_entry bcm2836_arm_irqchip_handle_irq(struct pt_regs *regs) } else if (stat) { u32 hwirq = ffs(stat) - 1; - handle_IRQ(irq_linear_revmap(intc.domain, hwirq), regs); + handle_domain_irq(intc.domain, hwirq, regs); } } -- cgit v0.10.2 From 17a2634bcb88e52bd637fdaa47d7ff0bddb0188f Mon Sep 17 00:00:00 2001 From: Andi Kleen Date: Mon, 6 Jun 2016 07:36:06 -0700 Subject: perf test: Ignore .scale and other special files 'perf test' tries to parse all entries in /sys/devices/cpu/events/. Ignore the special entries like '.scale', which cannot be directly parsed as an event. This patch assumes all files containing a '.' are special and can be ignored. Reported-by: Arnaldo Carvalho de Melo Signed-off-by: Andi Kleen Cc: Jiri Olsa Link: http://lkml.kernel.org/r/1465223766-29902-1-git-send-email-andi@firstfloor.org Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/tests/parse-events.c b/tools/perf/tests/parse-events.c index 7865f68..b2a2c74 100644 --- a/tools/perf/tests/parse-events.c +++ b/tools/perf/tests/parse-events.c @@ -1783,8 +1783,8 @@ static int test_pmu_events(void) struct evlist_test e; char name[MAX_NAME]; - if (!strcmp(ent->d_name, ".") || - !strcmp(ent->d_name, "..")) + /* Names containing . are special and cannot be used directly */ + if (strchr(ent->d_name, '.')) continue; snprintf(name, MAX_NAME, "cpu/event=%s/u", ent->d_name); -- cgit v0.10.2 From 44b1e60ab576c343aa592a2a6c679297cc69740d Mon Sep 17 00:00:00 2001 From: Andi Kleen Date: Mon, 30 May 2016 12:49:42 -0300 Subject: perf stat: Basic support for TopDown in perf stat Add basic plumbing for TopDown in perf stat TopDown is intended to replace the frontend cycles idle/ backend cycles idle metrics in standard perf stat output. These metrics are not reliable in many workloads, due to out of order effects. This implements a new --topdown mode in perf stat (similar to --transaction) that measures the pipe line bottlenecks using standardized formulas. The measurement can be all done with 5 counters (one fixed counter) The result are four metrics: FrontendBound, BackendBound, BadSpeculation, Retiring that describe the CPU pipeline behavior on a high level. The full top down methology has many hierarchical metrics. This implementation only supports level 1 which can be collected without multiplexing. A full implementation of top down on top of perf is available in pmu-tools toplev. (http://github.com/andikleen/pmu-tools) The current version works on Intel Core CPUs starting with Sandy Bridge, and Atom CPUs starting with Silvermont. In principle the generic metrics should be also implementable on other out of order CPUs. TopDown level 1 uses a set of abstracted metrics which are generic to out of order CPU cores (although some CPUs may not implement all of them): topdown-total-slots Available slots in the pipeline topdown-slots-issued Slots issued into the pipeline topdown-slots-retired Slots successfully retired topdown-fetch-bubbles Pipeline gaps in the frontend topdown-recovery-bubbles Pipeline gaps during recovery from misspeculation These metrics then allow to compute four useful metrics: FrontendBound, BackendBound, Retiring, BadSpeculation. Add a new --topdown options to enable events. When --topdown is specified set up events for all topdown events supported by the kernel. Add topdown-* as a special case to the event parser, as is needed for all events containing -. The actual code to compute the metrics is in follow-on patches. v2: Use standard sysctl read function. v3: Move x86 specific code to arch/ v4: Enable --metric-only implicitly for topdown. v5: Add --single-thread option to not force per core mode v6: Fix output order of topdown metrics v7: Allow combining with -d v8: Remove --single-thread again v9: Rename functions, adding arch_ and topdown_. v10: Expand man page and describe TopDown better Paste intro into commit description. Print error when malloc fails. Signed-off-by: Andi Kleen Acked-by: Jiri Olsa Link: http://lkml.kernel.org/r/1464119559-17203-1-git-send-email-andi@firstfloor.org Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/Documentation/perf-stat.txt b/tools/perf/Documentation/perf-stat.txt index 04f23b4..d96ccd4 100644 --- a/tools/perf/Documentation/perf-stat.txt +++ b/tools/perf/Documentation/perf-stat.txt @@ -204,6 +204,38 @@ Aggregate counts per physical processor for system-wide mode measurements. --no-aggr:: Do not aggregate counts across all monitored CPUs. +--topdown:: +Print top down level 1 metrics if supported by the CPU. This allows to +determine bottle necks in the CPU pipeline for CPU bound workloads, +by breaking the cycles consumed down into frontend bound, backend bound, +bad speculation and retiring. + +Frontend bound means that the CPU cannot fetch and decode instructions fast +enough. Backend bound means that computation or memory access is the bottle +neck. Bad Speculation means that the CPU wasted cycles due to branch +mispredictions and similar issues. Retiring means that the CPU computed without +an apparently bottleneck. The bottleneck is only the real bottleneck +if the workload is actually bound by the CPU and not by something else. + +For best results it is usually a good idea to use it with interval +mode like -I 1000, as the bottleneck of workloads can change often. + +The top down metrics are collected per core instead of per +CPU thread. Per core mode is automatically enabled +and -a (global monitoring) is needed, requiring root rights or +perf.perf_event_paranoid=-1. + +Topdown uses the full Performance Monitoring Unit, and needs +disabling of the NMI watchdog (as root): +echo 0 > /proc/sys/kernel/nmi_watchdog +for best results. Otherwise the bottlenecks may be inconsistent +on workload with changing phases. + +This enables --metric-only, unless overriden with --no-metric-only. + +To interpret the results it is usually needed to know on which +CPUs the workload runs on. If needed the CPUs can be forced using +taskset. EXAMPLES -------- diff --git a/tools/perf/arch/x86/util/Build b/tools/perf/arch/x86/util/Build index 4659703..4cd8a16 100644 --- a/tools/perf/arch/x86/util/Build +++ b/tools/perf/arch/x86/util/Build @@ -3,6 +3,7 @@ libperf-y += tsc.o libperf-y += pmu.o libperf-y += kvm-stat.o libperf-y += perf_regs.o +libperf-y += group.o libperf-$(CONFIG_DWARF) += dwarf-regs.o libperf-$(CONFIG_BPF_PROLOGUE) += dwarf-regs.o diff --git a/tools/perf/arch/x86/util/group.c b/tools/perf/arch/x86/util/group.c new file mode 100644 index 0000000..37f92aa --- /dev/null +++ b/tools/perf/arch/x86/util/group.c @@ -0,0 +1,27 @@ +#include +#include "api/fs/fs.h" +#include "util/group.h" + +/* + * Check whether we can use a group for top down. + * Without a group may get bad results due to multiplexing. + */ +bool arch_topdown_check_group(bool *warn) +{ + int n; + + if (sysctl__read_int("kernel/nmi_watchdog", &n) < 0) + return false; + if (n > 0) { + *warn = true; + return false; + } + return true; +} + +void arch_topdown_group_warn(void) +{ + fprintf(stderr, + "nmi_watchdog enabled with topdown. May give wrong results.\n" + "Disable with echo 0 > /proc/sys/kernel/nmi_watchdog\n"); +} diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index ee7ada7..fd76bb0 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c @@ -59,10 +59,13 @@ #include "util/thread.h" #include "util/thread_map.h" #include "util/counts.h" +#include "util/group.h" #include "util/session.h" #include "util/tool.h" +#include "util/group.h" #include "asm/bug.h" +#include #include #include #include @@ -98,6 +101,15 @@ static const char * transaction_limited_attrs = { "}" }; +static const char * topdown_attrs[] = { + "topdown-total-slots", + "topdown-slots-retired", + "topdown-recovery-bubbles", + "topdown-fetch-bubbles", + "topdown-slots-issued", + NULL, +}; + static struct perf_evlist *evsel_list; static struct target target = { @@ -112,6 +124,7 @@ static volatile pid_t child_pid = -1; static bool null_run = false; static int detailed_run = 0; static bool transaction_run; +static bool topdown_run = false; static bool big_num = true; static int big_num_opt = -1; static const char *csv_sep = NULL; @@ -124,6 +137,7 @@ static unsigned int initial_delay = 0; static unsigned int unit_width = 4; /* strlen("unit") */ static bool forever = false; static bool metric_only = false; +static bool force_metric_only = false; static struct timespec ref_time; static struct cpu_map *aggr_map; static aggr_get_id_t aggr_get_id; @@ -1520,6 +1534,14 @@ static int stat__set_big_num(const struct option *opt __maybe_unused, return 0; } +static int enable_metric_only(const struct option *opt __maybe_unused, + const char *s __maybe_unused, int unset) +{ + force_metric_only = true; + metric_only = !unset; + return 0; +} + static const struct option stat_options[] = { OPT_BOOLEAN('T', "transaction", &transaction_run, "hardware transaction statistics"), @@ -1578,8 +1600,10 @@ static const struct option stat_options[] = { "aggregate counts per thread", AGGR_THREAD), OPT_UINTEGER('D', "delay", &initial_delay, "ms to wait before starting measurement after program start"), - OPT_BOOLEAN(0, "metric-only", &metric_only, - "Only print computed metrics. No raw values"), + OPT_CALLBACK_NOOPT(0, "metric-only", &metric_only, NULL, + "Only print computed metrics. No raw values", enable_metric_only), + OPT_BOOLEAN(0, "topdown", &topdown_run, + "measure topdown level 1 statistics"), OPT_END() }; @@ -1772,12 +1796,62 @@ static int perf_stat_init_aggr_mode_file(struct perf_stat *st) return 0; } +static int topdown_filter_events(const char **attr, char **str, bool use_group) +{ + int off = 0; + int i; + int len = 0; + char *s; + + for (i = 0; attr[i]; i++) { + if (pmu_have_event("cpu", attr[i])) { + len += strlen(attr[i]) + 1; + attr[i - off] = attr[i]; + } else + off++; + } + attr[i - off] = NULL; + + *str = malloc(len + 1 + 2); + if (!*str) + return -1; + s = *str; + if (i - off == 0) { + *s = 0; + return 0; + } + if (use_group) + *s++ = '{'; + for (i = 0; attr[i]; i++) { + strcpy(s, attr[i]); + s += strlen(s); + *s++ = ','; + } + if (use_group) { + s[-1] = '}'; + *s = 0; + } else + s[-1] = 0; + return 0; +} + +__weak bool arch_topdown_check_group(bool *warn) +{ + *warn = false; + return false; +} + +__weak void arch_topdown_group_warn(void) +{ +} + /* * Add default attributes, if there were no attributes specified or * if -d/--detailed, -d -d or -d -d -d is used: */ static int add_default_attributes(void) { + int err; struct perf_event_attr default_attrs0[] = { { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_TASK_CLOCK }, @@ -1896,7 +1970,6 @@ static int add_default_attributes(void) return 0; if (transaction_run) { - int err; if (pmu_have_event("cpu", "cycles-ct") && pmu_have_event("cpu", "el-start")) err = parse_events(evsel_list, transaction_attrs, NULL); @@ -1909,6 +1982,46 @@ static int add_default_attributes(void) return 0; } + if (topdown_run) { + char *str = NULL; + bool warn = false; + + if (stat_config.aggr_mode != AGGR_GLOBAL && + stat_config.aggr_mode != AGGR_CORE) { + pr_err("top down event configuration requires --per-core mode\n"); + return -1; + } + stat_config.aggr_mode = AGGR_CORE; + if (nr_cgroups || !target__has_cpu(&target)) { + pr_err("top down event configuration requires system-wide mode (-a)\n"); + return -1; + } + + if (!force_metric_only) + metric_only = true; + if (topdown_filter_events(topdown_attrs, &str, + arch_topdown_check_group(&warn)) < 0) { + pr_err("Out of memory\n"); + return -1; + } + if (topdown_attrs[0] && str) { + if (warn) + arch_topdown_group_warn(); + err = parse_events(evsel_list, str, NULL); + if (err) { + fprintf(stderr, + "Cannot set up top down events %s: %d\n", + str, err); + free(str); + return -1; + } + } else { + fprintf(stderr, "System does not support topdown\n"); + return -1; + } + free(str); + } + if (!evsel_list->nr_entries) { if (target__has_cpu(&target)) default_attrs0[0].config = PERF_COUNT_SW_CPU_CLOCK; diff --git a/tools/perf/util/group.h b/tools/perf/util/group.h new file mode 100644 index 0000000..116debe --- /dev/null +++ b/tools/perf/util/group.h @@ -0,0 +1,7 @@ +#ifndef GROUP_H +#define GROUP_H 1 + +bool arch_topdown_check_group(bool *warn); +void arch_topdown_group_warn(void); + +#endif diff --git a/tools/perf/util/parse-events.l b/tools/perf/util/parse-events.l index 01af1ee..3c15b33 100644 --- a/tools/perf/util/parse-events.l +++ b/tools/perf/util/parse-events.l @@ -260,6 +260,7 @@ cycles-ct { return str(yyscanner, PE_KERNEL_PMU_EVENT); } cycles-t { return str(yyscanner, PE_KERNEL_PMU_EVENT); } mem-loads { return str(yyscanner, PE_KERNEL_PMU_EVENT); } mem-stores { return str(yyscanner, PE_KERNEL_PMU_EVENT); } +topdown-[a-z-]+ { return str(yyscanner, PE_KERNEL_PMU_EVENT); } L1-dcache|l1-d|l1d|L1-data | L1-icache|l1-i|l1i|L1-instruction | -- cgit v0.10.2 From 239bd47f8355eb5defc865cf408824b6cfeca5dc Mon Sep 17 00:00:00 2001 From: Andi Kleen Date: Tue, 24 May 2016 12:52:37 -0700 Subject: perf stat: Add computation of TopDown formulas Implement the TopDown formulas in 'perf stat'. The topdown basic metrics reported by the kernel are collected, and the formulas are computed and output as normal metrics. See the kernel commit exporting the events for details on the used metrics. Committer note: Output example: # perf stat --topdown -a usleep 1 Performance counter stats for 'system wide': retiring bad speculation frontend bound backend bound S0-C0 2 23.8% 11.6% 28.3% 36.3% S0-C1 2 16.2% 15.7% 36.5% 31.6% 0.000579956 seconds time elapsed # v2: Always print all metrics, only use thresholds for coloring. v3: Mark retiring over threshold green, not red. v4: Only print one decimal digit Fix color printing of one metric v5: Avoid printing -0.0 v6: Remove extra frontend event lookup Signed-off-by: Andi Kleen Acked-by: Jiri Olsa Link: http://lkml.kernel.org/r/1464119559-17203-2-git-send-email-andi@firstfloor.org Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/util/stat-shadow.c b/tools/perf/util/stat-shadow.c index aa9efe0..8a2bbd2 100644 --- a/tools/perf/util/stat-shadow.c +++ b/tools/perf/util/stat-shadow.c @@ -36,6 +36,11 @@ static struct stats runtime_dtlb_cache_stats[NUM_CTX][MAX_NR_CPUS]; static struct stats runtime_cycles_in_tx_stats[NUM_CTX][MAX_NR_CPUS]; static struct stats runtime_transaction_stats[NUM_CTX][MAX_NR_CPUS]; static struct stats runtime_elision_stats[NUM_CTX][MAX_NR_CPUS]; +static struct stats runtime_topdown_total_slots[NUM_CTX][MAX_NR_CPUS]; +static struct stats runtime_topdown_slots_issued[NUM_CTX][MAX_NR_CPUS]; +static struct stats runtime_topdown_slots_retired[NUM_CTX][MAX_NR_CPUS]; +static struct stats runtime_topdown_fetch_bubbles[NUM_CTX][MAX_NR_CPUS]; +static struct stats runtime_topdown_recovery_bubbles[NUM_CTX][MAX_NR_CPUS]; static bool have_frontend_stalled; struct stats walltime_nsecs_stats; @@ -82,6 +87,11 @@ void perf_stat__reset_shadow_stats(void) sizeof(runtime_transaction_stats)); memset(runtime_elision_stats, 0, sizeof(runtime_elision_stats)); memset(&walltime_nsecs_stats, 0, sizeof(walltime_nsecs_stats)); + memset(runtime_topdown_total_slots, 0, sizeof(runtime_topdown_total_slots)); + memset(runtime_topdown_slots_retired, 0, sizeof(runtime_topdown_slots_retired)); + memset(runtime_topdown_slots_issued, 0, sizeof(runtime_topdown_slots_issued)); + memset(runtime_topdown_fetch_bubbles, 0, sizeof(runtime_topdown_fetch_bubbles)); + memset(runtime_topdown_recovery_bubbles, 0, sizeof(runtime_topdown_recovery_bubbles)); } /* @@ -105,6 +115,16 @@ void perf_stat__update_shadow_stats(struct perf_evsel *counter, u64 *count, update_stats(&runtime_transaction_stats[ctx][cpu], count[0]); else if (perf_stat_evsel__is(counter, ELISION_START)) update_stats(&runtime_elision_stats[ctx][cpu], count[0]); + else if (perf_stat_evsel__is(counter, TOPDOWN_TOTAL_SLOTS)) + update_stats(&runtime_topdown_total_slots[ctx][cpu], count[0]); + else if (perf_stat_evsel__is(counter, TOPDOWN_SLOTS_ISSUED)) + update_stats(&runtime_topdown_slots_issued[ctx][cpu], count[0]); + else if (perf_stat_evsel__is(counter, TOPDOWN_SLOTS_RETIRED)) + update_stats(&runtime_topdown_slots_retired[ctx][cpu], count[0]); + else if (perf_stat_evsel__is(counter, TOPDOWN_FETCH_BUBBLES)) + update_stats(&runtime_topdown_fetch_bubbles[ctx][cpu],count[0]); + else if (perf_stat_evsel__is(counter, TOPDOWN_RECOVERY_BUBBLES)) + update_stats(&runtime_topdown_recovery_bubbles[ctx][cpu], count[0]); else if (perf_evsel__match(counter, HARDWARE, HW_STALLED_CYCLES_FRONTEND)) update_stats(&runtime_stalled_cycles_front_stats[ctx][cpu], count[0]); else if (perf_evsel__match(counter, HARDWARE, HW_STALLED_CYCLES_BACKEND)) @@ -302,6 +322,107 @@ static void print_ll_cache_misses(int cpu, out->print_metric(out->ctx, color, "%7.2f%%", "of all LL-cache hits", ratio); } +/* + * High level "TopDown" CPU core pipe line bottleneck break down. + * + * Basic concept following + * Yasin, A Top Down Method for Performance analysis and Counter architecture + * ISPASS14 + * + * The CPU pipeline is divided into 4 areas that can be bottlenecks: + * + * Frontend -> Backend -> Retiring + * BadSpeculation in addition means out of order execution that is thrown away + * (for example branch mispredictions) + * Frontend is instruction decoding. + * Backend is execution, like computation and accessing data in memory + * Retiring is good execution that is not directly bottlenecked + * + * The formulas are computed in slots. + * A slot is an entry in the pipeline each for the pipeline width + * (for example a 4-wide pipeline has 4 slots for each cycle) + * + * Formulas: + * BadSpeculation = ((SlotsIssued - SlotsRetired) + RecoveryBubbles) / + * TotalSlots + * Retiring = SlotsRetired / TotalSlots + * FrontendBound = FetchBubbles / TotalSlots + * BackendBound = 1.0 - BadSpeculation - Retiring - FrontendBound + * + * The kernel provides the mapping to the low level CPU events and any scaling + * needed for the CPU pipeline width, for example: + * + * TotalSlots = Cycles * 4 + * + * The scaling factor is communicated in the sysfs unit. + * + * In some cases the CPU may not be able to measure all the formulas due to + * missing events. In this case multiple formulas are combined, as possible. + * + * Full TopDown supports more levels to sub-divide each area: for example + * BackendBound into computing bound and memory bound. For now we only + * support Level 1 TopDown. + */ + +static double sanitize_val(double x) +{ + if (x < 0 && x >= -0.02) + return 0.0; + return x; +} + +static double td_total_slots(int ctx, int cpu) +{ + return avg_stats(&runtime_topdown_total_slots[ctx][cpu]); +} + +static double td_bad_spec(int ctx, int cpu) +{ + double bad_spec = 0; + double total_slots; + double total; + + total = avg_stats(&runtime_topdown_slots_issued[ctx][cpu]) - + avg_stats(&runtime_topdown_slots_retired[ctx][cpu]) + + avg_stats(&runtime_topdown_recovery_bubbles[ctx][cpu]); + total_slots = td_total_slots(ctx, cpu); + if (total_slots) + bad_spec = total / total_slots; + return sanitize_val(bad_spec); +} + +static double td_retiring(int ctx, int cpu) +{ + double retiring = 0; + double total_slots = td_total_slots(ctx, cpu); + double ret_slots = avg_stats(&runtime_topdown_slots_retired[ctx][cpu]); + + if (total_slots) + retiring = ret_slots / total_slots; + return retiring; +} + +static double td_fe_bound(int ctx, int cpu) +{ + double fe_bound = 0; + double total_slots = td_total_slots(ctx, cpu); + double fetch_bub = avg_stats(&runtime_topdown_fetch_bubbles[ctx][cpu]); + + if (total_slots) + fe_bound = fetch_bub / total_slots; + return fe_bound; +} + +static double td_be_bound(int ctx, int cpu) +{ + double sum = (td_fe_bound(ctx, cpu) + + td_bad_spec(ctx, cpu) + + td_retiring(ctx, cpu)); + if (sum == 0) + return 0; + return sanitize_val(1.0 - sum); +} + void perf_stat__print_shadow_stats(struct perf_evsel *evsel, double avg, int cpu, struct perf_stat_output_ctx *out) @@ -309,6 +430,7 @@ void perf_stat__print_shadow_stats(struct perf_evsel *evsel, void *ctxp = out->ctx; print_metric_t print_metric = out->print_metric; double total, ratio = 0.0, total2; + const char *color = NULL; int ctx = evsel_context(evsel); if (perf_evsel__match(evsel, HARDWARE, HW_INSTRUCTIONS)) { @@ -452,6 +574,46 @@ void perf_stat__print_shadow_stats(struct perf_evsel *evsel, avg / ratio); else print_metric(ctxp, NULL, NULL, "CPUs utilized", 0); + } else if (perf_stat_evsel__is(evsel, TOPDOWN_FETCH_BUBBLES)) { + double fe_bound = td_fe_bound(ctx, cpu); + + if (fe_bound > 0.2) + color = PERF_COLOR_RED; + print_metric(ctxp, color, "%8.1f%%", "frontend bound", + fe_bound * 100.); + } else if (perf_stat_evsel__is(evsel, TOPDOWN_SLOTS_RETIRED)) { + double retiring = td_retiring(ctx, cpu); + + if (retiring > 0.7) + color = PERF_COLOR_GREEN; + print_metric(ctxp, color, "%8.1f%%", "retiring", + retiring * 100.); + } else if (perf_stat_evsel__is(evsel, TOPDOWN_RECOVERY_BUBBLES)) { + double bad_spec = td_bad_spec(ctx, cpu); + + if (bad_spec > 0.1) + color = PERF_COLOR_RED; + print_metric(ctxp, color, "%8.1f%%", "bad speculation", + bad_spec * 100.); + } else if (perf_stat_evsel__is(evsel, TOPDOWN_SLOTS_ISSUED)) { + double be_bound = td_be_bound(ctx, cpu); + const char *name = "backend bound"; + static int have_recovery_bubbles = -1; + + /* In case the CPU does not support topdown-recovery-bubbles */ + if (have_recovery_bubbles < 0) + have_recovery_bubbles = pmu_have_event("cpu", + "topdown-recovery-bubbles"); + if (!have_recovery_bubbles) + name = "backend bound/bad spec"; + + if (be_bound > 0.2) + color = PERF_COLOR_RED; + if (td_total_slots(ctx, cpu) > 0) + print_metric(ctxp, color, "%8.1f%%", name, + be_bound * 100.); + else + print_metric(ctxp, NULL, NULL, name, 0); } else if (runtime_nsecs_stats[cpu].n != 0) { char unit = 'M'; char unit_buf[10]; diff --git a/tools/perf/util/stat.c b/tools/perf/util/stat.c index ffa1d06..c1ba255 100644 --- a/tools/perf/util/stat.c +++ b/tools/perf/util/stat.c @@ -79,6 +79,11 @@ static const char *id_str[PERF_STAT_EVSEL_ID__MAX] = { ID(TRANSACTION_START, cpu/tx-start/), ID(ELISION_START, cpu/el-start/), ID(CYCLES_IN_TX_CP, cpu/cycles-ct/), + ID(TOPDOWN_TOTAL_SLOTS, topdown-total-slots), + ID(TOPDOWN_SLOTS_ISSUED, topdown-slots-issued), + ID(TOPDOWN_SLOTS_RETIRED, topdown-slots-retired), + ID(TOPDOWN_FETCH_BUBBLES, topdown-fetch-bubbles), + ID(TOPDOWN_RECOVERY_BUBBLES, topdown-recovery-bubbles), }; #undef ID diff --git a/tools/perf/util/stat.h b/tools/perf/util/stat.h index 0150e78..c29bb94 100644 --- a/tools/perf/util/stat.h +++ b/tools/perf/util/stat.h @@ -17,6 +17,11 @@ enum perf_stat_evsel_id { PERF_STAT_EVSEL_ID__TRANSACTION_START, PERF_STAT_EVSEL_ID__ELISION_START, PERF_STAT_EVSEL_ID__CYCLES_IN_TX_CP, + PERF_STAT_EVSEL_ID__TOPDOWN_TOTAL_SLOTS, + PERF_STAT_EVSEL_ID__TOPDOWN_SLOTS_ISSUED, + PERF_STAT_EVSEL_ID__TOPDOWN_SLOTS_RETIRED, + PERF_STAT_EVSEL_ID__TOPDOWN_FETCH_BUBBLES, + PERF_STAT_EVSEL_ID__TOPDOWN_RECOVERY_BUBBLES, PERF_STAT_EVSEL_ID__MAX, }; -- cgit v0.10.2 From 41c8ca2a924b359e8f1768f8550487cd13a1ec03 Mon Sep 17 00:00:00 2001 From: Andi Kleen Date: Tue, 24 May 2016 12:52:38 -0700 Subject: perf stat: Print topology/time headers with --metric-only When --metric-only is enabled there were no headers for the topology in interval mode. Also when headers were printed they were on a separate line. Before: $ perf stat --metric-only -A -I 1000 -a 1.001038376 frontend cycles idle insn per cycle stalled cycles per insn branch-misses of all branches 1.001038376 CPU0 123.54% 0.23 5.29 7.61% 1.001038376 CPU1 137.78% 0.24 5.13 10.07% 1.001038376 CPU2 64.48% 0.22 5.50 6.84% After: $ perf stat --metric-only -A -I 1000 -a 1.001111114 CPU0 82.46% 0.32 2.60 7.64% 1.001111114 CPU1 126.63% 0.02 42.83 0.15% 1.001111114 CPU2 193.54% 0.32 2.59 6.92% v2: Move all headers on a single line Reported-by: Jiri Olsa Signed-off-by: Andi Kleen Acked-by: Jiri Olsa Link: http://lkml.kernel.org/r/1464119559-17203-3-git-send-email-andi@firstfloor.org Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index fd76bb0..a168e72 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c @@ -1316,7 +1316,7 @@ static int aggr_header_lens[] = { [AGGR_GLOBAL] = 0, }; -static void print_metric_headers(char *prefix) +static void print_metric_headers(const char *prefix, bool no_indent) { struct perf_stat_output_ctx out; struct perf_evsel *counter; @@ -1327,7 +1327,7 @@ static void print_metric_headers(char *prefix) if (prefix) fprintf(stat_config.output, "%s", prefix); - if (!csv_output) + if (!csv_output && !no_indent) fprintf(stat_config.output, "%*s", aggr_header_lens[stat_config.aggr_mode], ""); @@ -1352,28 +1352,40 @@ static void print_interval(char *prefix, struct timespec *ts) sprintf(prefix, "%6lu.%09lu%s", ts->tv_sec, ts->tv_nsec, csv_sep); - if (num_print_interval == 0 && !csv_output && !metric_only) { + if (num_print_interval == 0 && !csv_output) { switch (stat_config.aggr_mode) { case AGGR_SOCKET: - fprintf(output, "# time socket cpus counts %*s events\n", unit_width, "unit"); + fprintf(output, "# time socket cpus"); + if (!metric_only) + fprintf(output, " counts %*s events\n", unit_width, "unit"); break; case AGGR_CORE: - fprintf(output, "# time core cpus counts %*s events\n", unit_width, "unit"); + fprintf(output, "# time core cpus"); + if (!metric_only) + fprintf(output, " counts %*s events\n", unit_width, "unit"); break; case AGGR_NONE: - fprintf(output, "# time CPU counts %*s events\n", unit_width, "unit"); + fprintf(output, "# time CPU"); + if (!metric_only) + fprintf(output, " counts %*s events\n", unit_width, "unit"); break; case AGGR_THREAD: - fprintf(output, "# time comm-pid counts %*s events\n", unit_width, "unit"); + fprintf(output, "# time comm-pid"); + if (!metric_only) + fprintf(output, " counts %*s events\n", unit_width, "unit"); break; case AGGR_GLOBAL: default: - fprintf(output, "# time counts %*s events\n", unit_width, "unit"); + fprintf(output, "# time"); + if (!metric_only) + fprintf(output, " counts %*s events\n", unit_width, "unit"); case AGGR_UNSET: break; } } + if (num_print_interval == 0 && metric_only) + print_metric_headers(" ", true); if (++num_print_interval == 25) num_print_interval = 0; } @@ -1442,8 +1454,8 @@ static void print_counters(struct timespec *ts, int argc, const char **argv) if (metric_only) { static int num_print_iv; - if (num_print_iv == 0) - print_metric_headers(prefix); + if (num_print_iv == 0 && !interval) + print_metric_headers(prefix, false); if (num_print_iv++ == 25) num_print_iv = 0; if (stat_config.aggr_mode == AGGR_GLOBAL && prefix) -- cgit v0.10.2 From c51fd6395d67a6d414834db7f892c95594247d6f Mon Sep 17 00:00:00 2001 From: Andi Kleen Date: Tue, 24 May 2016 12:52:39 -0700 Subject: perf stat: Add missing aggregation headers for --metric-only CSV When in CSV mode --metric-only outputs an header, unlike the other modes. Previously it did not properly print headers for the aggregation columns, so the headers were actually shifted against the real values. Fix this here by outputting the correct headers for CSV. v2: Indent array. Signed-off-by: Andi Kleen Acked-by: Jiri Olsa Link: http://lkml.kernel.org/r/1464119559-17203-4-git-send-email-andi@firstfloor.org Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index a168e72..dff6373 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c @@ -1316,6 +1316,14 @@ static int aggr_header_lens[] = { [AGGR_GLOBAL] = 0, }; +static const char *aggr_header_csv[] = { + [AGGR_CORE] = "core,cpus,", + [AGGR_SOCKET] = "socket,cpus", + [AGGR_NONE] = "cpu,", + [AGGR_THREAD] = "comm-pid,", + [AGGR_GLOBAL] = "" +}; + static void print_metric_headers(const char *prefix, bool no_indent) { struct perf_stat_output_ctx out; @@ -1330,6 +1338,12 @@ static void print_metric_headers(const char *prefix, bool no_indent) if (!csv_output && !no_indent) fprintf(stat_config.output, "%*s", aggr_header_lens[stat_config.aggr_mode], ""); + if (csv_output) { + if (stat_config.interval) + fputs("time,", stat_config.output); + fputs(aggr_header_csv[stat_config.aggr_mode], + stat_config.output); + } /* Print metrics headers only */ evlist__for_each(evsel_list, counter) { -- cgit v0.10.2 From 78f71c996fb92d129ec75d572e2f5367a4f4c757 Mon Sep 17 00:00:00 2001 From: Taeung Song Date: Mon, 6 Jun 2016 19:52:52 +0900 Subject: perf config: Fix abnormal termination at perf_parse_file() If a config file has wrong key-value pairs, the perf process will be forcibly terminated by die() at perf_parse_file() called by perf_config() so terminal settings can be crushed because of unusual termination. For example: If user config file has a wrong value 'red;default' instead of a normal value like 'red, default' for a key 'colors.top', # cat ~/.perfconfig [colors] medium = red;default # wrong value and if running sub-command 'top', # perf top perf process is dead by force and terminal setting is broken with a messge like below. Fatal: bad config file line 2 in /root/.perfconfig So fix it. If perf_config() can return on failure without calling die() at perf_parse_file(), this problem can be solved. And if a config file has wrong values, show the error message and then use default config values instead of wrong config values. Signed-off-by: Taeung Song Tested-by: Arnaldo Carvalho de Melo Cc: Alexander Shishkin Cc: Jiri Olsa Cc: Masami Hiramatsu Cc: Namhyung Kim Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1465210380-26749-2-git-send-email-treeze.taeung@gmail.com Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/util/config.c b/tools/perf/util/config.c index dad7d82..b500737 100644 --- a/tools/perf/util/config.c +++ b/tools/perf/util/config.c @@ -275,7 +275,8 @@ static int perf_parse_file(config_fn_t fn, void *data) break; } } - die("bad config file line %d in %s", config_linenr, config_file_name); + pr_err("bad config file line %d in %s\n", config_linenr, config_file_name); + return -1; } static int parse_unit_factor(const char *end, unsigned long *val) @@ -479,16 +480,15 @@ static int perf_config_global(void) int perf_config(config_fn_t fn, void *data) { - int ret = 0, found = 0; + int ret = -1; const char *home = NULL; /* Setting $PERF_CONFIG makes perf read _only_ the given config file. */ if (config_exclusive_filename) return perf_config_from_file(fn, config_exclusive_filename, data); if (perf_config_system() && !access(perf_etc_perfconfig(), R_OK)) { - ret += perf_config_from_file(fn, perf_etc_perfconfig(), - data); - found += 1; + if (perf_config_from_file(fn, perf_etc_perfconfig(), data) < 0) + goto out; } home = getenv("HOME"); @@ -514,14 +514,12 @@ int perf_config(config_fn_t fn, void *data) if (!st.st_size) goto out_free; - ret += perf_config_from_file(fn, user_config, data); - found += 1; + ret = perf_config_from_file(fn, user_config, data); + out_free: free(user_config); } out: - if (found == 0) - return -1; return ret; } -- cgit v0.10.2 From 7db91f251056f90fec4121f028680ab3153a0f3c Mon Sep 17 00:00:00 2001 From: Taeung Song Date: Mon, 6 Jun 2016 19:52:54 +0900 Subject: perf config: Handle the error when config set is NULL at collect_config() collect_config() collect all config key-value pairs from config files and put each config info in config set. But if config set (i.e. 'set' variable at collect_config()) is NULL, this is wrong so handle it. Signed-off-by: Taeung Song Cc: Alexander Shishkin Cc: Jiri Olsa Cc: Masami Hiramatsu Cc: Namhyung Kim Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1465210380-26749-4-git-send-email-treeze.taeung@gmail.com Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/util/config.c b/tools/perf/util/config.c index b500737..c73f1c4 100644 --- a/tools/perf/util/config.c +++ b/tools/perf/util/config.c @@ -607,8 +607,12 @@ static int collect_config(const char *var, const char *value, struct perf_config_section *section = NULL; struct perf_config_item *item = NULL; struct perf_config_set *set = perf_config_set; - struct list_head *sections = &set->sections; + struct list_head *sections; + if (set == NULL) + return -1; + + sections = &set->sections; key = ptr = strdup(var); if (!key) { pr_debug("%s: strdup failed\n", __func__); -- cgit v0.10.2 From b4cbfa5670414a567a8a3b368047538f522eff6a Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 2 Jun 2016 10:51:59 -0300 Subject: tools lib bpf: Use IS_ERR() reporting macros with bpf_map__get_private() To try to, over time, consistently use the IS_ERR() interface instead of using two return values, i.e. the integer return value for an error and the pointer address to return the bpf_map->priv pointer. Also rename it to bpf__priv(), to leave the "get" term for reference counting. Noticed while working on using BPF for collecting non-integer syscall argument payloads (struct sockaddr in calls such as connect(), for instance), where we need to use BPF maps and thus generalise bpf__setup_stdout() to connect bpf_output events with maps in a bpf proggie. Acked-by: Wang Nan Cc: Adrian Hunter Cc: David Ahern Cc: Jiri Olsa Cc: Milian Wolff Cc: Namhyung Kim Link: http://lkml.kernel.org/n/tip-saypxyd6ptrct379jqgxx4bl@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c index 7e543c3..9bba1a9 100644 --- a/tools/lib/bpf/libbpf.c +++ b/tools/lib/bpf/libbpf.c @@ -1351,14 +1351,9 @@ int bpf_map__set_private(struct bpf_map *map, void *priv, return 0; } -int bpf_map__get_private(struct bpf_map *map, void **ppriv) +void *bpf_map__priv(struct bpf_map *map) { - if (!map) - return -EINVAL; - - if (ppriv) - *ppriv = map->priv; - return 0; + return map ? map->priv : ERR_PTR(-EINVAL); } struct bpf_map * diff --git a/tools/lib/bpf/libbpf.h b/tools/lib/bpf/libbpf.h index a51594c..916abf9 100644 --- a/tools/lib/bpf/libbpf.h +++ b/tools/lib/bpf/libbpf.h @@ -187,6 +187,6 @@ const char *bpf_map__get_name(struct bpf_map *map); typedef void (*bpf_map_clear_priv_t)(struct bpf_map *, void *); int bpf_map__set_private(struct bpf_map *map, void *priv, bpf_map_clear_priv_t clear_priv); -int bpf_map__get_private(struct bpf_map *map, void **ppriv); +void *bpf_map__priv(struct bpf_map *map); #endif diff --git a/tools/perf/util/bpf-loader.c b/tools/perf/util/bpf-loader.c index 493307d..e9a034e 100644 --- a/tools/perf/util/bpf-loader.c +++ b/tools/perf/util/bpf-loader.c @@ -897,15 +897,13 @@ bpf_map_priv__clone(struct bpf_map_priv *priv) static int bpf_map__add_op(struct bpf_map *map, struct bpf_map_op *op) { - struct bpf_map_priv *priv; + struct bpf_map_priv *priv = bpf_map__priv(map); const char *map_name; - int err; map_name = bpf_map__get_name(map); - err = bpf_map__get_private(map, (void **)&priv); - if (err) { + if (IS_ERR(priv)) { pr_debug("Failed to get private from map %s\n", map_name); - return err; + return PTR_ERR(priv); } if (!priv) { @@ -1264,12 +1262,11 @@ bpf_map_config_foreach_key(struct bpf_map *map, const char *name; struct bpf_map_op *op; struct bpf_map_def def; - struct bpf_map_priv *priv; + struct bpf_map_priv *priv = bpf_map__priv(map); name = bpf_map__get_name(map); - err = bpf_map__get_private(map, (void **)&priv); - if (err) { + if (IS_ERR(priv)) { pr_debug("ERROR: failed to get private from map %s\n", name); return -BPF_LOADER_ERRNO__INTERNAL; } @@ -1489,10 +1486,9 @@ int bpf__setup_stdout(struct perf_evlist *evlist __maybe_unused) bool need_init = false; bpf__for_each_stdout_map(map, obj, tmp) { - struct bpf_map_priv *priv; + struct bpf_map_priv *priv = bpf_map__priv(map); - err = bpf_map__get_private(map, (void **)&priv); - if (err) + if (IS_ERR(priv)) return -BPF_LOADER_ERRNO__INTERNAL; /* @@ -1520,10 +1516,9 @@ int bpf__setup_stdout(struct perf_evlist *evlist __maybe_unused) } bpf__for_each_stdout_map(map, obj, tmp) { - struct bpf_map_priv *priv; + struct bpf_map_priv *priv = bpf_map__priv(map); - err = bpf_map__get_private(map, (void **)&priv); - if (err) + if (IS_ERR(priv)) return -BPF_LOADER_ERRNO__INTERNAL; if (priv) continue; -- cgit v0.10.2 From 009ad5d5945697a887f0c1b2d581503d92dcde6f Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 2 Jun 2016 11:02:05 -0300 Subject: tools lib bpf: Rename bpf_map__get_name() to bpf_map__name() For consistency, leaving "get" for reference counting. Acked-by: Wang Nan Cc: Adrian Hunter Cc: David Ahern Cc: Jiri Olsa Cc: Milian Wolff Cc: Namhyung Kim Link: http://lkml.kernel.org/n/tip-crnflv84ejyhpba933ec71gs@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c index 9bba1a9..4dc617b 100644 --- a/tools/lib/bpf/libbpf.c +++ b/tools/lib/bpf/libbpf.c @@ -1328,11 +1328,9 @@ int bpf_map__get_def(struct bpf_map *map, struct bpf_map_def *pdef) return 0; } -const char *bpf_map__get_name(struct bpf_map *map) +const char *bpf_map__name(struct bpf_map *map) { - if (!map) - return NULL; - return map->name; + return map ? map->name : NULL; } int bpf_map__set_private(struct bpf_map *map, void *priv, diff --git a/tools/lib/bpf/libbpf.h b/tools/lib/bpf/libbpf.h index 916abf9..f8fbba4 100644 --- a/tools/lib/bpf/libbpf.h +++ b/tools/lib/bpf/libbpf.h @@ -182,7 +182,7 @@ bpf_map__next(struct bpf_map *map, struct bpf_object *obj); int bpf_map__get_fd(struct bpf_map *map); int bpf_map__get_def(struct bpf_map *map, struct bpf_map_def *pdef); -const char *bpf_map__get_name(struct bpf_map *map); +const char *bpf_map__name(struct bpf_map *map); typedef void (*bpf_map_clear_priv_t)(struct bpf_map *, void *); int bpf_map__set_private(struct bpf_map *map, void *priv, diff --git a/tools/perf/util/bpf-loader.c b/tools/perf/util/bpf-loader.c index e9a034e..c819eb8 100644 --- a/tools/perf/util/bpf-loader.c +++ b/tools/perf/util/bpf-loader.c @@ -897,10 +897,9 @@ bpf_map_priv__clone(struct bpf_map_priv *priv) static int bpf_map__add_op(struct bpf_map *map, struct bpf_map_op *op) { + const char *map_name = bpf_map__name(map); struct bpf_map_priv *priv = bpf_map__priv(map); - const char *map_name; - map_name = bpf_map__get_name(map); if (IS_ERR(priv)) { pr_debug("Failed to get private from map %s\n", map_name); return PTR_ERR(priv); @@ -948,11 +947,9 @@ __bpf_map__config_value(struct bpf_map *map, { struct bpf_map_def def; struct bpf_map_op *op; - const char *map_name; + const char *map_name = bpf_map__name(map); int err; - map_name = bpf_map__get_name(map); - err = bpf_map__get_def(map, &def); if (err) { pr_debug("Unable to get map definition from '%s'\n", @@ -1014,10 +1011,9 @@ __bpf_map__config_event(struct bpf_map *map, struct perf_evsel *evsel; struct bpf_map_def def; struct bpf_map_op *op; - const char *map_name; + const char *map_name = bpf_map__name(map); int err; - map_name = bpf_map__get_name(map); evsel = perf_evlist__find_evsel_by_str(evlist, term->val.str); if (!evsel) { pr_debug("Event (for '%s') '%s' doesn't exist\n", @@ -1259,13 +1255,11 @@ bpf_map_config_foreach_key(struct bpf_map *map, void *arg) { int err, map_fd; - const char *name; struct bpf_map_op *op; struct bpf_map_def def; + const char *name = bpf_map__name(map); struct bpf_map_priv *priv = bpf_map__priv(map); - name = bpf_map__get_name(map); - if (IS_ERR(priv)) { pr_debug("ERROR: failed to get private from map %s\n", name); return -BPF_LOADER_ERRNO__INTERNAL; @@ -1472,9 +1466,9 @@ int bpf__apply_obj_config(void) #define bpf__for_each_stdout_map(pos, obj, objtmp) \ bpf__for_each_map(pos, obj, objtmp) \ - if (bpf_map__get_name(pos) && \ + if (bpf_map__name(pos) && \ (strcmp("__bpf_stdout__", \ - bpf_map__get_name(pos)) == 0)) + bpf_map__name(pos)) == 0)) int bpf__setup_stdout(struct perf_evlist *evlist __maybe_unused) { -- cgit v0.10.2 From 53897a78ca6d4bd64e8c17d76cfec65d237f9447 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 2 Jun 2016 14:21:06 -0300 Subject: tools lib bpf: Use IS_ERR() reporting macros with bpf_map__get_def() And for consistency, rename it to bpf_map__def(), leaving "get" for reference counting. Also make it return a const pointer, as suggested by Wang. Acked-by: Wang Nan Cc: Adrian Hunter Cc: David Ahern Cc: Jiri Olsa Cc: Milian Wolff Cc: Namhyung Kim Link: http://lkml.kernel.org/n/tip-mer00xqkiho0ymg66b5i9luw@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c index 4dc617b..215be67 100644 --- a/tools/lib/bpf/libbpf.c +++ b/tools/lib/bpf/libbpf.c @@ -1319,13 +1319,9 @@ int bpf_map__get_fd(struct bpf_map *map) return map->fd; } -int bpf_map__get_def(struct bpf_map *map, struct bpf_map_def *pdef) +const struct bpf_map_def *bpf_map__def(struct bpf_map *map) { - if (!map || !pdef) - return -EINVAL; - - *pdef = map->def; - return 0; + return map ? &map->def : ERR_PTR(-EINVAL); } const char *bpf_map__name(struct bpf_map *map) diff --git a/tools/lib/bpf/libbpf.h b/tools/lib/bpf/libbpf.h index f8fbba4..bad5bac 100644 --- a/tools/lib/bpf/libbpf.h +++ b/tools/lib/bpf/libbpf.h @@ -181,7 +181,7 @@ bpf_map__next(struct bpf_map *map, struct bpf_object *obj); (pos) = bpf_map__next((pos), (obj))) int bpf_map__get_fd(struct bpf_map *map); -int bpf_map__get_def(struct bpf_map *map, struct bpf_map_def *pdef); +const struct bpf_map_def *bpf_map__def(struct bpf_map *map); const char *bpf_map__name(struct bpf_map *map); typedef void (*bpf_map_clear_priv_t)(struct bpf_map *, void *); diff --git a/tools/perf/util/bpf-loader.c b/tools/perf/util/bpf-loader.c index c819eb8..73c1e7c 100644 --- a/tools/perf/util/bpf-loader.c +++ b/tools/perf/util/bpf-loader.c @@ -945,28 +945,26 @@ static int __bpf_map__config_value(struct bpf_map *map, struct parse_events_term *term) { - struct bpf_map_def def; struct bpf_map_op *op; const char *map_name = bpf_map__name(map); - int err; + const struct bpf_map_def *def = bpf_map__def(map); - err = bpf_map__get_def(map, &def); - if (err) { + if (IS_ERR(def)) { pr_debug("Unable to get map definition from '%s'\n", map_name); return -BPF_LOADER_ERRNO__INTERNAL; } - if (def.type != BPF_MAP_TYPE_ARRAY) { + if (def->type != BPF_MAP_TYPE_ARRAY) { pr_debug("Map %s type is not BPF_MAP_TYPE_ARRAY\n", map_name); return -BPF_LOADER_ERRNO__OBJCONF_MAP_TYPE; } - if (def.key_size < sizeof(unsigned int)) { + if (def->key_size < sizeof(unsigned int)) { pr_debug("Map %s has incorrect key size\n", map_name); return -BPF_LOADER_ERRNO__OBJCONF_MAP_KEYSIZE; } - switch (def.value_size) { + switch (def->value_size) { case 1: case 2: case 4: @@ -1009,10 +1007,9 @@ __bpf_map__config_event(struct bpf_map *map, struct perf_evlist *evlist) { struct perf_evsel *evsel; - struct bpf_map_def def; + const struct bpf_map_def *def; struct bpf_map_op *op; const char *map_name = bpf_map__name(map); - int err; evsel = perf_evlist__find_evsel_by_str(evlist, term->val.str); if (!evsel) { @@ -1021,18 +1018,18 @@ __bpf_map__config_event(struct bpf_map *map, return -BPF_LOADER_ERRNO__OBJCONF_MAP_NOEVT; } - err = bpf_map__get_def(map, &def); - if (err) { + def = bpf_map__def(map); + if (IS_ERR(def)) { pr_debug("Unable to get map definition from '%s'\n", map_name); - return err; + return PTR_ERR(def); } /* * No need to check key_size and value_size: * kernel has already checked them. */ - if (def.type != BPF_MAP_TYPE_PERF_EVENT_ARRAY) { + if (def->type != BPF_MAP_TYPE_PERF_EVENT_ARRAY) { pr_debug("Map %s type is not BPF_MAP_TYPE_PERF_EVENT_ARRAY\n", map_name); return -BPF_LOADER_ERRNO__OBJCONF_MAP_TYPE; @@ -1081,9 +1078,8 @@ config_map_indices_range_check(struct parse_events_term *term, const char *map_name) { struct parse_events_array *array = &term->array; - struct bpf_map_def def; + const struct bpf_map_def *def; unsigned int i; - int err; if (!array->nr_ranges) return 0; @@ -1093,8 +1089,8 @@ config_map_indices_range_check(struct parse_events_term *term, return -BPF_LOADER_ERRNO__INTERNAL; } - err = bpf_map__get_def(map, &def); - if (err) { + def = bpf_map__def(map); + if (IS_ERR(def)) { pr_debug("ERROR: Unable to get map definition from '%s'\n", map_name); return -BPF_LOADER_ERRNO__INTERNAL; @@ -1105,7 +1101,7 @@ config_map_indices_range_check(struct parse_events_term *term, size_t length = array->ranges[i].length; unsigned int idx = start + length - 1; - if (idx >= def.max_entries) { + if (idx >= def->max_entries) { pr_debug("ERROR: index %d too large\n", idx); return -BPF_LOADER_ERRNO__OBJCONF_MAP_IDX2BIG; } @@ -1198,14 +1194,14 @@ out: } typedef int (*map_config_func_t)(const char *name, int map_fd, - struct bpf_map_def *pdef, + const struct bpf_map_def *pdef, struct bpf_map_op *op, void *pkey, void *arg); static int foreach_key_array_all(map_config_func_t func, void *arg, const char *name, - int map_fd, struct bpf_map_def *pdef, + int map_fd, const struct bpf_map_def *pdef, struct bpf_map_op *op) { unsigned int i; @@ -1225,7 +1221,7 @@ foreach_key_array_all(map_config_func_t func, static int foreach_key_array_ranges(map_config_func_t func, void *arg, const char *name, int map_fd, - struct bpf_map_def *pdef, + const struct bpf_map_def *pdef, struct bpf_map_op *op) { unsigned int i, j; @@ -1256,7 +1252,7 @@ bpf_map_config_foreach_key(struct bpf_map *map, { int err, map_fd; struct bpf_map_op *op; - struct bpf_map_def def; + const struct bpf_map_def *def; const char *name = bpf_map__name(map); struct bpf_map_priv *priv = bpf_map__priv(map); @@ -1269,8 +1265,8 @@ bpf_map_config_foreach_key(struct bpf_map *map, return 0; } - err = bpf_map__get_def(map, &def); - if (err) { + def = bpf_map__def(map); + if (IS_ERR(def)) { pr_debug("ERROR: failed to get definition from map %s\n", name); return -BPF_LOADER_ERRNO__INTERNAL; } @@ -1281,17 +1277,17 @@ bpf_map_config_foreach_key(struct bpf_map *map, } list_for_each_entry(op, &priv->ops_list, list) { - switch (def.type) { + switch (def->type) { case BPF_MAP_TYPE_ARRAY: case BPF_MAP_TYPE_PERF_EVENT_ARRAY: switch (op->key_type) { case BPF_MAP_KEY_ALL: err = foreach_key_array_all(func, arg, name, - map_fd, &def, op); + map_fd, def, op); break; case BPF_MAP_KEY_RANGES: err = foreach_key_array_ranges(func, arg, name, - map_fd, &def, + map_fd, def, op); break; default: @@ -1401,7 +1397,7 @@ apply_config_evsel_for_key(const char *name, int map_fd, void *pkey, static int apply_obj_config_map_for_key(const char *name, int map_fd, - struct bpf_map_def *pdef __maybe_unused, + const struct bpf_map_def *pdef, struct bpf_map_op *op, void *pkey, void *arg __maybe_unused) { -- cgit v0.10.2 From 6e009e65a1e5202313fdaccde3bcb94272989eba Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 3 Jun 2016 12:15:52 -0300 Subject: tools lib bpf: Rename bpf_map__get_fd() to bpf_map__fd() For consistency, leaving "get" for reference counting. Acked-by: Wang Nan Cc: Adrian Hunter Cc: David Ahern Cc: Jiri Olsa Cc: Milian Wolff Cc: Namhyung Kim Link: http://lkml.kernel.org/n/tip-msy8sxfz9th6gl2xjeci2btm@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c index 215be67..57924db 100644 --- a/tools/lib/bpf/libbpf.c +++ b/tools/lib/bpf/libbpf.c @@ -1311,12 +1311,9 @@ int bpf_program__nth_fd(struct bpf_program *prog, int n) return fd; } -int bpf_map__get_fd(struct bpf_map *map) +int bpf_map__fd(struct bpf_map *map) { - if (!map) - return -EINVAL; - - return map->fd; + return map ? map->fd : -EINVAL; } const struct bpf_map_def *bpf_map__def(struct bpf_map *map) diff --git a/tools/lib/bpf/libbpf.h b/tools/lib/bpf/libbpf.h index bad5bac..cb838d0 100644 --- a/tools/lib/bpf/libbpf.h +++ b/tools/lib/bpf/libbpf.h @@ -180,7 +180,7 @@ bpf_map__next(struct bpf_map *map, struct bpf_object *obj); (pos) != NULL; \ (pos) = bpf_map__next((pos), (obj))) -int bpf_map__get_fd(struct bpf_map *map); +int bpf_map__fd(struct bpf_map *map); const struct bpf_map_def *bpf_map__def(struct bpf_map *map); const char *bpf_map__name(struct bpf_map *map); diff --git a/tools/perf/util/bpf-loader.c b/tools/perf/util/bpf-loader.c index 73c1e7c..12e6ef4 100644 --- a/tools/perf/util/bpf-loader.c +++ b/tools/perf/util/bpf-loader.c @@ -1270,7 +1270,7 @@ bpf_map_config_foreach_key(struct bpf_map *map, pr_debug("ERROR: failed to get definition from map %s\n", name); return -BPF_LOADER_ERRNO__INTERNAL; } - map_fd = bpf_map__get_fd(map); + map_fd = bpf_map__fd(map); if (map_fd < 0) { pr_debug("ERROR: failed to get fd from map %s\n", name); return map_fd; -- cgit v0.10.2 From a7fe0450b0142d0eb4a543840a43e22682debf25 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 3 Jun 2016 12:22:51 -0300 Subject: tools lib bpf: Remove _get_ from non-refcount method names The use of this term is not warranted here, we use it in the kernel sources and in tools/ for refcounting, so, for consistency, rename them. Acked-bu: Wang Nan Cc: Adrian Hunter Cc: David Ahern Cc: Jiri Olsa Cc: Milian Wolff Cc: Namhyung Kim Link: http://lkml.kernel.org/n/tip-4ya1ot2e2fkrz48ws9ebiofs@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c index 57924db..0412182 100644 --- a/tools/lib/bpf/libbpf.c +++ b/tools/lib/bpf/libbpf.c @@ -1186,20 +1186,14 @@ bpf_object__next(struct bpf_object *prev) return next; } -const char * -bpf_object__get_name(struct bpf_object *obj) +const char *bpf_object__name(struct bpf_object *obj) { - if (!obj) - return ERR_PTR(-EINVAL); - return obj->path; + return obj ? obj->path : ERR_PTR(-EINVAL); } -unsigned int -bpf_object__get_kversion(struct bpf_object *obj) +unsigned int bpf_object__kversion(struct bpf_object *obj) { - if (!obj) - return 0; - return obj->kern_version; + return obj ? obj->kern_version : 0; } struct bpf_program * @@ -1375,7 +1369,7 @@ bpf_map__next(struct bpf_map *prev, struct bpf_object *obj) } struct bpf_map * -bpf_object__get_map_by_name(struct bpf_object *obj, const char *name) +bpf_object__find_map_by_name(struct bpf_object *obj, const char *name) { struct bpf_map *pos; diff --git a/tools/lib/bpf/libbpf.h b/tools/lib/bpf/libbpf.h index cb838d0..ea65775 100644 --- a/tools/lib/bpf/libbpf.h +++ b/tools/lib/bpf/libbpf.h @@ -55,8 +55,8 @@ void bpf_object__close(struct bpf_object *object); /* Load/unload object into/from kernel */ int bpf_object__load(struct bpf_object *obj); int bpf_object__unload(struct bpf_object *obj); -const char *bpf_object__get_name(struct bpf_object *obj); -unsigned int bpf_object__get_kversion(struct bpf_object *obj); +const char *bpf_object__name(struct bpf_object *obj); +unsigned int bpf_object__kversion(struct bpf_object *obj); struct bpf_object *bpf_object__next(struct bpf_object *prev); #define bpf_object__for_each_safe(pos, tmp) \ @@ -171,7 +171,7 @@ struct bpf_map_def { */ struct bpf_map; struct bpf_map * -bpf_object__get_map_by_name(struct bpf_object *obj, const char *name); +bpf_object__find_map_by_name(struct bpf_object *obj, const char *name); struct bpf_map * bpf_map__next(struct bpf_map *map, struct bpf_object *obj); diff --git a/tools/perf/util/bpf-loader.c b/tools/perf/util/bpf-loader.c index 12e6ef4..c19010e 100644 --- a/tools/perf/util/bpf-loader.c +++ b/tools/perf/util/bpf-loader.c @@ -1137,7 +1137,7 @@ bpf__obj_config_map(struct bpf_object *obj, goto out; } - map = bpf_object__get_map_by_name(obj, map_name); + map = bpf_object__find_map_by_name(obj, map_name); if (!map) { pr_debug("ERROR: Map %s doesn't exist\n", map_name); err = -BPF_LOADER_ERRNO__OBJCONF_MAP_NOTEXIST; @@ -1662,7 +1662,7 @@ int bpf__strerror_load(struct bpf_object *obj, { bpf__strerror_head(err, buf, size); case LIBBPF_ERRNO__KVER: { - unsigned int obj_kver = bpf_object__get_kversion(obj); + unsigned int obj_kver = bpf_object__kversion(obj); unsigned int real_kver; if (fetch_kernel_version(&real_kver, NULL, 0)) { -- cgit v0.10.2 From be834ffbd15ea9d73ba96fdbdcb1012add7e3bdf Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 3 Jun 2016 12:36:39 -0300 Subject: tools lib bpf: Make bpf_program__get_private() use IS_ERR() For consistency with bpf_map__priv() and elsewhere. Acked-by: Wang Nan Cc: Adrian Hunter Cc: David Ahern Cc: Jiri Olsa Cc: Milian Wolff Cc: Namhyung Kim Link: http://lkml.kernel.org/n/tip-x17nk5mrazkf45z0l0ahlmo8@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c index 0412182..7eb7fb2 100644 --- a/tools/lib/bpf/libbpf.c +++ b/tools/lib/bpf/libbpf.c @@ -1230,10 +1230,9 @@ int bpf_program__set_private(struct bpf_program *prog, return 0; } -int bpf_program__get_private(struct bpf_program *prog, void **ppriv) +void *bpf_program__priv(struct bpf_program *prog) { - *ppriv = prog->priv; - return 0; + return prog ? prog->priv : ERR_PTR(-EINVAL); } const char *bpf_program__title(struct bpf_program *prog, bool needs_copy) diff --git a/tools/lib/bpf/libbpf.h b/tools/lib/bpf/libbpf.h index ea65775..372cecb 100644 --- a/tools/lib/bpf/libbpf.h +++ b/tools/lib/bpf/libbpf.h @@ -81,8 +81,7 @@ typedef void (*bpf_program_clear_priv_t)(struct bpf_program *, int bpf_program__set_private(struct bpf_program *prog, void *priv, bpf_program_clear_priv_t clear_priv); -int bpf_program__get_private(struct bpf_program *prog, - void **ppriv); +void *bpf_program__priv(struct bpf_program *prog); const char *bpf_program__title(struct bpf_program *prog, bool needs_copy); diff --git a/tools/perf/util/bpf-loader.c b/tools/perf/util/bpf-loader.c index c19010e..1907d53 100644 --- a/tools/perf/util/bpf-loader.c +++ b/tools/perf/util/bpf-loader.c @@ -380,15 +380,14 @@ preproc_gen_prologue(struct bpf_program *prog, int n, struct bpf_insn *orig_insns, int orig_insns_cnt, struct bpf_prog_prep_result *res) { + struct bpf_prog_priv *priv = bpf_program__priv(prog); struct probe_trace_event *tev; struct perf_probe_event *pev; - struct bpf_prog_priv *priv; struct bpf_insn *buf; size_t prologue_cnt = 0; int i, err; - err = bpf_program__get_private(prog, (void **)&priv); - if (err || !priv) + if (IS_ERR(priv) || !priv) goto errout; pev = &priv->pev; @@ -535,13 +534,12 @@ static int map_prologue(struct perf_probe_event *pev, int *mapping, static int hook_load_preprocessor(struct bpf_program *prog) { + struct bpf_prog_priv *priv = bpf_program__priv(prog); struct perf_probe_event *pev; - struct bpf_prog_priv *priv; bool need_prologue = false; int err, i; - err = bpf_program__get_private(prog, (void **)&priv); - if (err || !priv) { + if (IS_ERR(priv) || !priv) { pr_debug("Internal error when hook preprocessor\n"); return -BPF_LOADER_ERRNO__INTERNAL; } @@ -607,9 +605,11 @@ int bpf__probe(struct bpf_object *obj) if (err) goto out; - err = bpf_program__get_private(prog, (void **)&priv); - if (err || !priv) + priv = bpf_program__priv(prog); + if (IS_ERR(priv) || !priv) { + err = PTR_ERR(priv); goto out; + } pev = &priv->pev; err = convert_perf_probe_events(pev, 1); @@ -645,13 +645,12 @@ int bpf__unprobe(struct bpf_object *obj) { int err, ret = 0; struct bpf_program *prog; - struct bpf_prog_priv *priv; bpf_object__for_each_program(prog, obj) { + struct bpf_prog_priv *priv = bpf_program__priv(prog); int i; - err = bpf_program__get_private(prog, (void **)&priv); - if (err || !priv) + if (IS_ERR(priv) || !priv) continue; for (i = 0; i < priv->pev.ntevs; i++) { @@ -702,14 +701,12 @@ int bpf__foreach_tev(struct bpf_object *obj, int err; bpf_object__for_each_program(prog, obj) { + struct bpf_prog_priv *priv = bpf_program__priv(prog); struct probe_trace_event *tev; struct perf_probe_event *pev; - struct bpf_prog_priv *priv; int i, fd; - err = bpf_program__get_private(prog, - (void **)&priv); - if (err || !priv) { + if (IS_ERR(priv) || !priv) { pr_debug("bpf: failed to get private field\n"); return -BPF_LOADER_ERRNO__INTERNAL; } -- cgit v0.10.2 From edb13ed47c1a196eca4b669b7c20d26b27260813 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 3 Jun 2016 12:38:21 -0300 Subject: tools lib bpf: Rename set_private() to set_priv() For consistency with class__priv() elsewhere, and with the callback typedef for clearing those areas (e.g. bpf_map_clear_priv_t). Acked-by: Wang Nan Cc: Adrian Hunter Cc: David Ahern Cc: Jiri Olsa Cc: Milian Wolff Cc: Namhyung Kim Link: http://lkml.kernel.org/n/tip-rnbiyv27ohw8xppsgx0el3xb@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c index 7eb7fb2..462e526 100644 --- a/tools/lib/bpf/libbpf.c +++ b/tools/lib/bpf/libbpf.c @@ -1218,9 +1218,8 @@ bpf_program__next(struct bpf_program *prev, struct bpf_object *obj) return &obj->programs[idx]; } -int bpf_program__set_private(struct bpf_program *prog, - void *priv, - bpf_program_clear_priv_t clear_priv) +int bpf_program__set_priv(struct bpf_program *prog, void *priv, + bpf_program_clear_priv_t clear_priv) { if (prog->priv && prog->clear_priv) prog->clear_priv(prog, prog->priv); @@ -1319,8 +1318,8 @@ const char *bpf_map__name(struct bpf_map *map) return map ? map->name : NULL; } -int bpf_map__set_private(struct bpf_map *map, void *priv, - bpf_map_clear_priv_t clear_priv) +int bpf_map__set_priv(struct bpf_map *map, void *priv, + bpf_map_clear_priv_t clear_priv) { if (!map) return -EINVAL; diff --git a/tools/lib/bpf/libbpf.h b/tools/lib/bpf/libbpf.h index 372cecb..722f46b 100644 --- a/tools/lib/bpf/libbpf.h +++ b/tools/lib/bpf/libbpf.h @@ -78,8 +78,8 @@ struct bpf_program *bpf_program__next(struct bpf_program *prog, typedef void (*bpf_program_clear_priv_t)(struct bpf_program *, void *); -int bpf_program__set_private(struct bpf_program *prog, void *priv, - bpf_program_clear_priv_t clear_priv); +int bpf_program__set_priv(struct bpf_program *prog, void *priv, + bpf_program_clear_priv_t clear_priv); void *bpf_program__priv(struct bpf_program *prog); @@ -184,8 +184,8 @@ const struct bpf_map_def *bpf_map__def(struct bpf_map *map); const char *bpf_map__name(struct bpf_map *map); typedef void (*bpf_map_clear_priv_t)(struct bpf_map *, void *); -int bpf_map__set_private(struct bpf_map *map, void *priv, - bpf_map_clear_priv_t clear_priv); +int bpf_map__set_priv(struct bpf_map *map, void *priv, + bpf_map_clear_priv_t clear_priv); void *bpf_map__priv(struct bpf_map *map); #endif diff --git a/tools/perf/util/bpf-loader.c b/tools/perf/util/bpf-loader.c index 1907d53..dcc8845 100644 --- a/tools/perf/util/bpf-loader.c +++ b/tools/perf/util/bpf-loader.c @@ -339,7 +339,7 @@ config_bpf_program(struct bpf_program *prog) } pr_debug("bpf: config '%s' is ok\n", config_str); - err = bpf_program__set_private(prog, priv, clear_prog_priv); + err = bpf_program__set_priv(prog, priv, clear_prog_priv); if (err) { pr_debug("Failed to set priv for program '%s'\n", config_str); goto errout; @@ -910,7 +910,7 @@ bpf_map__add_op(struct bpf_map *map, struct bpf_map_op *op) } INIT_LIST_HEAD(&priv->ops_list); - if (bpf_map__set_private(map, priv, bpf_map_priv__clear)) { + if (bpf_map__set_priv(map, priv, bpf_map_priv__clear)) { free(priv); return -BPF_LOADER_ERRNO__INTERNAL; } @@ -1515,7 +1515,7 @@ int bpf__setup_stdout(struct perf_evlist *evlist __maybe_unused) if (!priv) return -ENOMEM; - err = bpf_map__set_private(map, priv, bpf_map_priv__clear); + err = bpf_map__set_priv(map, priv, bpf_map_priv__clear); if (err) { bpf_map_priv__clear(map, priv); return err; -- cgit v0.10.2 From 572f1f613a109e03b52e72b62df2d2c0e595d3bd Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Tue, 7 Jun 2016 11:03:08 +0800 Subject: ASoC: rt5670: fix HP Playback Volume control The register setting for HP Playback Volume is inverted. So, set the invert flag in SOC_DOUBLE_TLV. Signed-off-by: Bard Liao Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/rt5670.c b/sound/soc/codecs/rt5670.c index 49a9e70..0af5ddb 100644 --- a/sound/soc/codecs/rt5670.c +++ b/sound/soc/codecs/rt5670.c @@ -619,7 +619,7 @@ static const struct snd_kcontrol_new rt5670_snd_controls[] = { RT5670_L_MUTE_SFT, RT5670_R_MUTE_SFT, 1, 1), SOC_DOUBLE_TLV("HP Playback Volume", RT5670_HP_VOL, RT5670_L_VOL_SFT, RT5670_R_VOL_SFT, - 39, 0, out_vol_tlv), + 39, 1, out_vol_tlv), /* OUTPUT Control */ SOC_DOUBLE("OUT Channel Switch", RT5670_LOUT1, RT5670_VOL_L_SFT, RT5670_VOL_R_SFT, 1, 1), -- cgit v0.10.2 From c58c49ac630979a285d574b3f72a528209515fb3 Mon Sep 17 00:00:00 2001 From: Wang Nan Date: Tue, 7 Jun 2016 03:54:38 +0000 Subject: perf tools: Fix crash in build_id_cache__kallsyms_path() build_id_cache__kallsyms_path() accepts a string buffer but also allocs a buffer using asnprintf. Unfortunately, the its only user passes it a stack-allocated buffer. Freeing it causes crashes like this: $ perf script *** Error in `/home/wangnan/perf': free(): invalid pointer: 0x00007fffffff9630 *** ======= Backtrace: ========= lib64/libc.so.6(+0x6eeef)[0x7ffff5dbaeef] lib64/libc.so.6(+0x78cae)[0x7ffff5dc4cae] lib64/libc.so.6(+0x79987)[0x7ffff5dc5987] /home/w00229757/perf(build_id_cache__kallsyms_path+0x6b)[0x49681b] /home/w00229757/perf[0x4bdd40] /home/w00229757/perf(dso__load+0xa3a)[0x4c048a] /home/w00229757/perf(map__load+0x6f)[0x4d561f] /home/w00229757/perf(thread__find_addr_map+0x235)[0x49e935] /home/w00229757/perf(machine__resolve+0x7d)[0x49ec6d] /home/w00229757/perf[0x4555a8] /home/w00229757/perf[0x4d9507] /home/w00229757/perf[0x4d9e80] /home/w00229757/perf(ordered_events__flush+0x354)[0x4dd444] /home/w00229757/perf(perf_session__process_events+0x3d0)[0x4dc140] /home/w00229757/perf(cmd_script+0x12b0)[0x4592e0] /home/w00229757/perf[0x4911f1] /home/w00229757/perf(main+0x68f)[0x4352ef] /lib64/libc.so.6(__libc_start_main+0xf5)[0x7ffff5d6dbd5] /home/w00229757/perf[0x435415] ======= Memory map: ======== This patch simplifies build_id_cache__kallsyms_path(), not even considering allocating a string buffer, so never frees anything. Its caller should manage memory allocation. Signed-off-by: Wang Nan Cc: Masami Hiramatsu Cc: Zefan Li Cc: pi3orama@163.com Fixes: 01412261d994 ("perf buildid-cache: Use path/to/bin/buildid/elf instead of path/to/bin/buildid") Link: http://lkml.kernel.org/r/1465271678-7392-1-git-send-email-wangnan0@huawei.com Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/util/build-id.c b/tools/perf/util/build-id.c index 67f986c..20aef90 100644 --- a/tools/perf/util/build-id.c +++ b/tools/perf/util/build-id.c @@ -147,20 +147,17 @@ static int asnprintf(char **strp, size_t size, const char *fmt, ...) char *build_id_cache__kallsyms_path(const char *sbuild_id, char *bf, size_t size) { - bool is_alloc = !!bf; bool retry_old = true; - asnprintf(&bf, size, "%s/%s/%s/kallsyms", - buildid_dir, DSO__NAME_KALLSYMS, sbuild_id); + snprintf(bf, size, "%s/%s/%s/kallsyms", + buildid_dir, DSO__NAME_KALLSYMS, sbuild_id); retry: if (!access(bf, F_OK)) return bf; - if (is_alloc) - free(bf); if (retry_old) { /* Try old style kallsyms cache */ - asnprintf(&bf, size, "%s/%s/%s", - buildid_dir, DSO__NAME_KALLSYMS, sbuild_id); + snprintf(bf, size, "%s/%s/%s", + buildid_dir, DSO__NAME_KALLSYMS, sbuild_id); retry_old = false; goto retry; } -- cgit v0.10.2 From 25d8f48f78f37dd6af08bd11212ab3d53a4c8cc6 Mon Sep 17 00:00:00 2001 From: Taeung Song Date: Tue, 7 Jun 2016 18:26:11 +0900 Subject: perf config: Constructor should free its allocated memory when failing Because of die() at perf_parse_file() a config set was freed in collect_config(), if failed. But it is natural to free a config set after collect_config() is done when some problems happened. So, in case of failure, lastly free a config set at perf_config_set__new() instead of freeing the config set in collect_config(). Signed-off-by: Taeung Song Cc: Alexander Shishkin Cc: Jiri Olsa Cc: Masami Hiramatsu Cc: Namhyung Kim Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1465291577-20973-2-git-send-email-treeze.taeung@gmail.com Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/util/config.c b/tools/perf/util/config.c index c73f1c4..e086f59 100644 --- a/tools/perf/util/config.c +++ b/tools/perf/util/config.c @@ -643,7 +643,6 @@ static int collect_config(const char *var, const char *value, out_free: free(key); - perf_config_set__delete(set); return -1; } @@ -653,7 +652,10 @@ struct perf_config_set *perf_config_set__new(void) if (set) { INIT_LIST_HEAD(&set->sections); - perf_config(collect_config, set); + if (perf_config(collect_config, set) < 0) { + perf_config_set__delete(set); + set = NULL; + } } return set; -- cgit v0.10.2 From 8beeb00f2c8498686eee02b8edcd1488b903c90b Mon Sep 17 00:00:00 2001 From: Taeung Song Date: Tue, 7 Jun 2016 18:26:12 +0900 Subject: perf config: Use new perf_config_set__init() to initialize config set Instead of perf_config(), this function initializes config set by reading various files: user config ~/.perfconfig and system config $(sysconfdir)/perfconfig). If there are the same config variable in both user and system config files, user config has higher priority than system config. Signed-off-by: Taeung Song Cc: Alexander Shishkin Cc: Jiri Olsa Cc: Masami Hiramatsu Cc: Namhyung Kim Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1465291577-20973-3-git-send-email-treeze.taeung@gmail.com Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/util/config.c b/tools/perf/util/config.c index e086f59..8749eca 100644 --- a/tools/perf/util/config.c +++ b/tools/perf/util/config.c @@ -646,13 +646,58 @@ out_free: return -1; } +static int perf_config_set__init(struct perf_config_set *set) +{ + int ret = -1; + const char *home = NULL; + + /* Setting $PERF_CONFIG makes perf read _only_ the given config file. */ + if (config_exclusive_filename) + return perf_config_from_file(collect_config, config_exclusive_filename, set); + if (perf_config_system() && !access(perf_etc_perfconfig(), R_OK)) { + if (perf_config_from_file(collect_config, perf_etc_perfconfig(), set) < 0) + goto out; + } + + home = getenv("HOME"); + if (perf_config_global() && home) { + char *user_config = strdup(mkpath("%s/.perfconfig", home)); + struct stat st; + + if (user_config == NULL) { + warning("Not enough memory to process %s/.perfconfig, " + "ignoring it.", home); + goto out; + } + + if (stat(user_config, &st) < 0) + goto out_free; + + if (st.st_uid && (st.st_uid != geteuid())) { + warning("File %s not owned by current user or root, " + "ignoring it.", user_config); + goto out_free; + } + + if (!st.st_size) + goto out_free; + + ret = perf_config_from_file(collect_config, user_config, set); + +out_free: + free(user_config); + } +out: + return ret; +} + struct perf_config_set *perf_config_set__new(void) { struct perf_config_set *set = zalloc(sizeof(*set)); if (set) { INIT_LIST_HEAD(&set->sections); - if (perf_config(collect_config, set) < 0) { + if (perf_config_set__init(set) < 0) { perf_config_set__delete(set); set = NULL; } -- cgit v0.10.2 From 195106b9ff87da6da600b2c33d6a8b38281e1af3 Mon Sep 17 00:00:00 2001 From: He Kuang Date: Fri, 3 Jun 2016 03:33:10 +0000 Subject: perf unwind: Use LIBUNWIND_DIR for remote libunwind feature check Pass LIBUNWIND_DIR to feature check flags for remote libunwind tests. So perf can be able to detect remote libunwind libraries from arbitrary directory. Signed-off-by: He Kuang Acked-by: Jiri Olsa Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Andi Kleen Cc: David Ahern Cc: Ekaterina Tumanova Cc: Josh Poimboeuf Cc: Kan Liang Cc: Masami Hiramatsu Cc: Namhyung Kim Cc: Pekka Enberg Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Sukadev Bhattiprolu Cc: Wang Nan Link: http://lkml.kernel.org/r/1464924803-22214-2-git-send-email-hekuang@huawei.com Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/config/Makefile b/tools/perf/config/Makefile index 1e46277..6f9f566 100644 --- a/tools/perf/config/Makefile +++ b/tools/perf/config/Makefile @@ -67,9 +67,18 @@ endif # # make DEBUG=1 LIBUNWIND_DIR=/opt/libunwind/ # + +libunwind_arch_set_flags = $(eval $(libunwind_arch_set_flags_code)) +define libunwind_arch_set_flags_code + FEATURE_CHECK_CFLAGS-libunwind-$(1) = -I$(LIBUNWIND_DIR)/include + FEATURE_CHECK_LDFLAGS-libunwind-$(1) = -L$(LIBUNWIND_DIR)/lib +endef + ifdef LIBUNWIND_DIR LIBUNWIND_CFLAGS = -I$(LIBUNWIND_DIR)/include LIBUNWIND_LDFLAGS = -L$(LIBUNWIND_DIR)/lib + LIBUNWIND_ARCHS = x86 x86_64 arm aarch64 debug-frame-arm debug-frame-aarch64 + $(foreach libunwind_arch,$(LIBUNWIND_ARCHS),$(call libunwind_arch_set_flags,$(libunwind_arch))) endif LIBUNWIND_LDFLAGS += $(LIBUNWIND_LIBS) -- cgit v0.10.2 From c1d1d0d9b302cb5f0365f4de78dd7fcbf7983c05 Mon Sep 17 00:00:00 2001 From: He Kuang Date: Fri, 3 Jun 2016 03:33:11 +0000 Subject: perf unwind: Decouple thread->address_space on libunwind Currently, the type of thread->addr_space is unw_addr_space_t, which is a pointer defined in libunwind headers. For local libunwind, we can simple include "libunwind.h", but for remote libunwind, the header file is depends on the target libunwind platform. This patch uses 'void *' instead to decouple the dependence on libunwind. Signed-off-by: He Kuang Acked-by: Jiri Olsa Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Andi Kleen Cc: David Ahern Cc: Ekaterina Tumanova Cc: Josh Poimboeuf Cc: Kan Liang Cc: Masami Hiramatsu Cc: Namhyung Kim Cc: Pekka Enberg Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Sukadev Bhattiprolu Cc: Wang Nan Link: http://lkml.kernel.org/r/1464924803-22214-3-git-send-email-hekuang@huawei.com Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/util/thread.h b/tools/perf/util/thread.h index 08fcb14..4c9f0aa 100644 --- a/tools/perf/util/thread.h +++ b/tools/perf/util/thread.h @@ -9,9 +9,6 @@ #include "symbol.h" #include #include -#ifdef HAVE_LIBUNWIND_SUPPORT -#include -#endif struct thread_stack; @@ -36,7 +33,7 @@ struct thread { void *priv; struct thread_stack *ts; #ifdef HAVE_LIBUNWIND_SUPPORT - unw_addr_space_t addr_space; + void *addr_space; #endif }; -- cgit v0.10.2 From f83c04156c1483f16ac548516f41212cf244e441 Mon Sep 17 00:00:00 2001 From: He Kuang Date: Fri, 3 Jun 2016 03:33:12 +0000 Subject: perf unwind: Introduce 'struct unwind_libunwind_ops' for local unwind Currently, libunwind operations are fixed, and they are chosen according to the host architecture. This will lead to a problem that if a thread is run as x86_32 on a x86_64 machine, perf will use libunwind methods for x86_64 to parse the callchain and get wrong results. This patch changes the fixed methods of libunwind operations to be thread/map related, and each thread can have individual libunwind operations. Local libunwind methods are registered as default value. Signed-off-by: He Kuang Acked-by: Jiri Olsa Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Andi Kleen Cc: David Ahern Cc: Ekaterina Tumanova Cc: Josh Poimboeuf Cc: Kan Liang Cc: Masami Hiramatsu Cc: Namhyung Kim Cc: Pekka Enberg Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Sukadev Bhattiprolu Cc: Wang Nan Link: http://lkml.kernel.org/r/1464924803-22214-4-git-send-email-hekuang@huawei.com Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/util/thread.h b/tools/perf/util/thread.h index 4c9f0aa..07ffb18 100644 --- a/tools/perf/util/thread.h +++ b/tools/perf/util/thread.h @@ -11,6 +11,7 @@ #include struct thread_stack; +struct unwind_libunwind_ops; struct thread { union { @@ -33,7 +34,8 @@ struct thread { void *priv; struct thread_stack *ts; #ifdef HAVE_LIBUNWIND_SUPPORT - void *addr_space; + void *addr_space; + struct unwind_libunwind_ops *unwind_libunwind_ops; #endif }; diff --git a/tools/perf/util/unwind-libunwind.c b/tools/perf/util/unwind-libunwind.c index 63687d3..b0c5db1 100644 --- a/tools/perf/util/unwind-libunwind.c +++ b/tools/perf/util/unwind-libunwind.c @@ -579,7 +579,7 @@ static unw_accessors_t accessors = { .get_proc_name = get_proc_name, }; -int unwind__prepare_access(struct thread *thread) +static int _unwind__prepare_access(struct thread *thread) { if (callchain_param.record_mode != CALLCHAIN_DWARF) return 0; @@ -594,7 +594,7 @@ int unwind__prepare_access(struct thread *thread) return 0; } -void unwind__flush_access(struct thread *thread) +static void _unwind__flush_access(struct thread *thread) { if (callchain_param.record_mode != CALLCHAIN_DWARF) return; @@ -602,7 +602,7 @@ void unwind__flush_access(struct thread *thread) unw_flush_cache(thread->addr_space, 0, 0); } -void unwind__finish_access(struct thread *thread) +static void _unwind__finish_access(struct thread *thread) { if (callchain_param.record_mode != CALLCHAIN_DWARF) return; @@ -662,7 +662,7 @@ static int get_entries(struct unwind_info *ui, unwind_entry_cb_t cb, return ret; } -int unwind__get_entries(unwind_entry_cb_t cb, void *arg, +static int _unwind__get_entries(unwind_entry_cb_t cb, void *arg, struct thread *thread, struct perf_sample *data, int max_stack) { @@ -680,3 +680,48 @@ int unwind__get_entries(unwind_entry_cb_t cb, void *arg, return get_entries(&ui, cb, arg, max_stack); } + +static struct unwind_libunwind_ops +_unwind_libunwind_ops = { + .prepare_access = _unwind__prepare_access, + .flush_access = _unwind__flush_access, + .finish_access = _unwind__finish_access, + .get_entries = _unwind__get_entries, +}; + +struct unwind_libunwind_ops * +local_unwind_libunwind_ops = &_unwind_libunwind_ops; + +static void unwind__register_ops(struct thread *thread, + struct unwind_libunwind_ops *ops) +{ + thread->unwind_libunwind_ops = ops; +} + +int unwind__prepare_access(struct thread *thread) +{ + unwind__register_ops(thread, local_unwind_libunwind_ops); + + return thread->unwind_libunwind_ops->prepare_access(thread); +} + +void unwind__flush_access(struct thread *thread) +{ + if (thread->unwind_libunwind_ops) + thread->unwind_libunwind_ops->flush_access(thread); +} + +void unwind__finish_access(struct thread *thread) +{ + if (thread->unwind_libunwind_ops) + thread->unwind_libunwind_ops->finish_access(thread); +} + +int unwind__get_entries(unwind_entry_cb_t cb, void *arg, + struct thread *thread, + struct perf_sample *data, int max_stack) +{ + if (thread->unwind_libunwind_ops) + return thread->unwind_libunwind_ops->get_entries(cb, arg, thread, data, max_stack); + return 0; +} diff --git a/tools/perf/util/unwind.h b/tools/perf/util/unwind.h index 12790cf..bbd73d9 100644 --- a/tools/perf/util/unwind.h +++ b/tools/perf/util/unwind.h @@ -14,6 +14,15 @@ struct unwind_entry { typedef int (*unwind_entry_cb_t)(struct unwind_entry *entry, void *arg); +struct unwind_libunwind_ops { + int (*prepare_access)(struct thread *thread); + void (*flush_access)(struct thread *thread); + void (*finish_access)(struct thread *thread); + int (*get_entries)(unwind_entry_cb_t cb, void *arg, + struct thread *thread, + struct perf_sample *data, int max_stack); +}; + #ifdef HAVE_DWARF_UNWIND_SUPPORT int unwind__get_entries(unwind_entry_cb_t cb, void *arg, struct thread *thread, -- cgit v0.10.2 From 8132a2a84147d3c98cf580d5759387325fbabf73 Mon Sep 17 00:00:00 2001 From: He Kuang Date: Fri, 3 Jun 2016 03:33:13 +0000 Subject: perf unwind: Move unwind__prepare_access from thread_new into thread__insert_map To determine the libunwind methods to use, we should get the 32bit/64bit information from maps of a thread. When a thread is newly created, the information is not prepared. This patch moves unwind__prepare_access() into thread__insert_map() so we can get the information we need from maps. Meanwhile, let thread__insert_map() return value and show messages on error. Signed-off-by: He Kuang Acked-by: Jiri Olsa Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Andi Kleen Cc: David Ahern Cc: Ekaterina Tumanova Cc: Josh Poimboeuf Cc: Kan Liang Cc: Masami Hiramatsu Cc: Namhyung Kim Cc: Pekka Enberg Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Sukadev Bhattiprolu Cc: Wang Nan Link: http://lkml.kernel.org/r/1464924803-22214-5-git-send-email-hekuang@huawei.com Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c index 205d270..9d931f5 100644 --- a/tools/perf/util/machine.c +++ b/tools/perf/util/machine.c @@ -1353,11 +1353,16 @@ int machine__process_mmap2_event(struct machine *machine, if (map == NULL) goto out_problem_map; - thread__insert_map(thread, map); + ret = thread__insert_map(thread, map); + if (ret) + goto out_problem_insert; + thread__put(thread); map__put(map); return 0; +out_problem_insert: + map__put(map); out_problem_map: thread__put(thread); out_problem: @@ -1403,11 +1408,16 @@ int machine__process_mmap_event(struct machine *machine, union perf_event *event if (map == NULL) goto out_problem_map; - thread__insert_map(thread, map); + ret = thread__insert_map(thread, map); + if (ret) + goto out_problem_insert; + thread__put(thread); map__put(map); return 0; +out_problem_insert: + map__put(map); out_problem_map: thread__put(thread); out_problem: diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c index ada58e6..0bf55256 100644 --- a/tools/perf/util/thread.c +++ b/tools/perf/util/thread.c @@ -43,9 +43,6 @@ struct thread *thread__new(pid_t pid, pid_t tid) thread->cpu = -1; INIT_LIST_HEAD(&thread->comm_list); - if (unwind__prepare_access(thread) < 0) - goto err_thread; - comm_str = malloc(32); if (!comm_str) goto err_thread; @@ -201,10 +198,18 @@ size_t thread__fprintf(struct thread *thread, FILE *fp) map_groups__fprintf(thread->mg, fp); } -void thread__insert_map(struct thread *thread, struct map *map) +int thread__insert_map(struct thread *thread, struct map *map) { + int ret; + + ret = unwind__prepare_access(thread); + if (ret) + return ret; + map_groups__fixup_overlappings(thread->mg, map, stderr); map_groups__insert(thread->mg, map); + + return 0; } static int thread__clone_map_groups(struct thread *thread, diff --git a/tools/perf/util/thread.h b/tools/perf/util/thread.h index 07ffb18..99263cb 100644 --- a/tools/perf/util/thread.h +++ b/tools/perf/util/thread.h @@ -76,7 +76,7 @@ int thread__comm_len(struct thread *thread); struct comm *thread__comm(const struct thread *thread); struct comm *thread__exec_comm(const struct thread *thread); const char *thread__comm_str(const struct thread *thread); -void thread__insert_map(struct thread *thread, struct map *map); +int thread__insert_map(struct thread *thread, struct map *map); int thread__fork(struct thread *thread, struct thread *parent, u64 timestamp); size_t thread__fprintf(struct thread *thread, FILE *fp); -- cgit v0.10.2 From 403cacb8a25eb86d564750fce2293978814d2d15 Mon Sep 17 00:00:00 2001 From: He Kuang Date: Fri, 3 Jun 2016 03:33:14 +0000 Subject: perf unwind: Don't mix LIBUNWIND_LIBS into LIBUNWIND_LDFLAGS LIBUNWIND_LIBS contains libunwind libraries used for local only, don't mix this into LIBUNWIND_LDFLAGS so we can later use LIBUNWIND_LDFLAGS both for local and remote libunwind. Signed-off-by: He Kuang Acked-by: Jiri Olsa Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Andi Kleen Cc: David Ahern Cc: Ekaterina Tumanova Cc: Josh Poimboeuf Cc: Kan Liang Cc: Masami Hiramatsu Cc: Namhyung Kim Cc: Pekka Enberg Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Sukadev Bhattiprolu Cc: Wang Nan Link: http://lkml.kernel.org/r/1464924803-22214-6-git-send-email-hekuang@huawei.com Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/config/Makefile b/tools/perf/config/Makefile index 6f9f566..118df2d 100644 --- a/tools/perf/config/Makefile +++ b/tools/perf/config/Makefile @@ -80,13 +80,12 @@ ifdef LIBUNWIND_DIR LIBUNWIND_ARCHS = x86 x86_64 arm aarch64 debug-frame-arm debug-frame-aarch64 $(foreach libunwind_arch,$(LIBUNWIND_ARCHS),$(call libunwind_arch_set_flags,$(libunwind_arch))) endif -LIBUNWIND_LDFLAGS += $(LIBUNWIND_LIBS) # Set per-feature check compilation flags FEATURE_CHECK_CFLAGS-libunwind = $(LIBUNWIND_CFLAGS) -FEATURE_CHECK_LDFLAGS-libunwind = $(LIBUNWIND_LDFLAGS) +FEATURE_CHECK_LDFLAGS-libunwind = $(LIBUNWIND_LDFLAGS) $(LIBUNWIND_LIBS) FEATURE_CHECK_CFLAGS-libunwind-debug-frame = $(LIBUNWIND_CFLAGS) -FEATURE_CHECK_LDFLAGS-libunwind-debug-frame = $(LIBUNWIND_LDFLAGS) +FEATURE_CHECK_LDFLAGS-libunwind-debug-frame = $(LIBUNWIND_LDFLAGS) $(LIBUNWIND_LIBS) ifeq ($(NO_PERF_REGS),0) CFLAGS += -DHAVE_PERF_REGS_SUPPORT @@ -409,7 +408,7 @@ ifndef NO_LIBUNWIND CFLAGS += -DHAVE_LIBUNWIND_SUPPORT EXTLIBS += $(LIBUNWIND_LIBS) CFLAGS += $(LIBUNWIND_CFLAGS) - LDFLAGS += $(LIBUNWIND_LDFLAGS) + LDFLAGS += $(LIBUNWIND_LDFLAGS) $(LIBUNWIND_LIBS) endif ifndef NO_LIBAUDIT -- cgit v0.10.2 From 9d8e14d306ef2f5daf2fd099ef07c39dd83e2c0d Mon Sep 17 00:00:00 2001 From: He Kuang Date: Fri, 3 Jun 2016 03:33:15 +0000 Subject: perf unwind: Separate local/remote libunwind config CONFIG_LIBUNWIND/NO_LIBUNWIND are changed to CONFIG_LOCAL_LIBUNWIND/ NO_LOCAL_LIBUNWIND for retaining local unwind features. The new CONFIG_LIBUNWIND stands for either local or remote or both unwind are supported, and NO_LIBUNWIND means that neither local nor remote unwind is supported. LIBUNWIND_LIBS is eliminated in LDFLAGS if local libunwind is not supported. Signed-off-by: He Kuang Acked-by: Jiri Olsa Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Andi Kleen Cc: David Ahern Cc: Ekaterina Tumanova Cc: Josh Poimboeuf Cc: Kan Liang Cc: Masami Hiramatsu Cc: Namhyung Kim Cc: Pekka Enberg Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Sukadev Bhattiprolu Cc: Wang Nan Link: http://lkml.kernel.org/r/1464924803-22214-7-git-send-email-hekuang@huawei.com Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/arch/arm/util/Build b/tools/perf/arch/arm/util/Build index d22e3d0..f98da17 100644 --- a/tools/perf/arch/arm/util/Build +++ b/tools/perf/arch/arm/util/Build @@ -1,4 +1,4 @@ libperf-$(CONFIG_DWARF) += dwarf-regs.o -libperf-$(CONFIG_LIBUNWIND) += unwind-libunwind.o +libperf-$(CONFIG_LOCAL_LIBUNWIND) += unwind-libunwind.o libperf-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o diff --git a/tools/perf/arch/arm64/util/Build b/tools/perf/arch/arm64/util/Build index e58123a8..02f41db 100644 --- a/tools/perf/arch/arm64/util/Build +++ b/tools/perf/arch/arm64/util/Build @@ -1,2 +1,2 @@ libperf-$(CONFIG_DWARF) += dwarf-regs.o -libperf-$(CONFIG_LIBUNWIND) += unwind-libunwind.o +libperf-$(CONFIG_LOCAL_LIBUNWIND) += unwind-libunwind.o diff --git a/tools/perf/arch/x86/util/Build b/tools/perf/arch/x86/util/Build index 4cd8a16..f95e6f4 100644 --- a/tools/perf/arch/x86/util/Build +++ b/tools/perf/arch/x86/util/Build @@ -8,7 +8,7 @@ libperf-y += group.o libperf-$(CONFIG_DWARF) += dwarf-regs.o libperf-$(CONFIG_BPF_PROLOGUE) += dwarf-regs.o -libperf-$(CONFIG_LIBUNWIND) += unwind-libunwind.o +libperf-$(CONFIG_LOCAL_LIBUNWIND) += unwind-libunwind.o libperf-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o libperf-$(CONFIG_AUXTRACE) += auxtrace.o diff --git a/tools/perf/config/Makefile b/tools/perf/config/Makefile index 118df2d..3918687 100644 --- a/tools/perf/config/Makefile +++ b/tools/perf/config/Makefile @@ -353,10 +353,20 @@ ifeq ($(ARCH),powerpc) endif ifndef NO_LIBUNWIND + have_libunwind := ifneq ($(feature-libunwind), 1) msg := $(warning No libunwind found. Please install libunwind-dev[el] >= 1.1 and/or set LIBUNWIND_DIR); + NO_LOCAL_LIBUNWIND := 1 + else + have_libunwind := 1 + $(call detected,CONFIG_LOCAL_LIBUNWIND) + endif + + ifneq ($(have_libunwind), 1) NO_LIBUNWIND := 1 endif +else + NO_LOCAL_LIBUNWIND := 1 endif ifndef NO_LIBBPF @@ -394,7 +404,7 @@ else NO_DWARF_UNWIND := 1 endif -ifndef NO_LIBUNWIND +ifndef NO_LOCAL_LIBUNWIND ifeq ($(ARCH),$(filter $(ARCH),arm arm64)) $(call feature_check,libunwind-debug-frame) ifneq ($(feature-libunwind-debug-frame), 1) @@ -405,10 +415,14 @@ ifndef NO_LIBUNWIND # non-ARM has no dwarf_find_debug_frame() function: CFLAGS += -DNO_LIBUNWIND_DEBUG_FRAME endif - CFLAGS += -DHAVE_LIBUNWIND_SUPPORT EXTLIBS += $(LIBUNWIND_LIBS) + LDFLAGS += $(LIBUNWIND_LIBS) +endif + +ifndef NO_LIBUNWIND + CFLAGS += -DHAVE_LIBUNWIND_SUPPORT CFLAGS += $(LIBUNWIND_CFLAGS) - LDFLAGS += $(LIBUNWIND_LDFLAGS) $(LIBUNWIND_LIBS) + LDFLAGS += $(LIBUNWIND_LDFLAGS) endif ifndef NO_LIBAUDIT -- cgit v0.10.2 From a597b547d6a599b088e3789a9095bd9bf2b28aaa Mon Sep 17 00:00:00 2001 From: He Kuang Date: Fri, 3 Jun 2016 03:33:16 +0000 Subject: perf unwind: Rename unwind-libunwind.c to unwind-libunwind-local.c Since unwind-libunwind.c contains code for specific arithecture, we change it's name to unwind-libunwind-local.c, and let it only be built if local libunwind is supported. Signed-off-by: He Kuang Acked-by: Jiri Olsa Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Andi Kleen Cc: David Ahern Cc: Ekaterina Tumanova Cc: Josh Poimboeuf Cc: Kan Liang Cc: Masami Hiramatsu Cc: Namhyung Kim Cc: Pekka Enberg Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Sukadev Bhattiprolu Cc: Wang Nan Link: http://lkml.kernel.org/r/1464924803-22214-8-git-send-email-hekuang@huawei.com Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/util/Build b/tools/perf/util/Build index 8c6c8a0..5e23d85 100644 --- a/tools/perf/util/Build +++ b/tools/perf/util/Build @@ -99,7 +99,7 @@ libperf-$(CONFIG_DWARF) += probe-finder.o libperf-$(CONFIG_DWARF) += dwarf-aux.o libperf-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o -libperf-$(CONFIG_LIBUNWIND) += unwind-libunwind.o +libperf-$(CONFIG_LOCAL_LIBUNWIND) += unwind-libunwind-local.o libperf-$(CONFIG_LIBBABELTRACE) += data-convert-bt.o diff --git a/tools/perf/util/unwind-libunwind-local.c b/tools/perf/util/unwind-libunwind-local.c new file mode 100644 index 0000000..b0c5db1 --- /dev/null +++ b/tools/perf/util/unwind-libunwind-local.c @@ -0,0 +1,727 @@ +/* + * Post mortem Dwarf CFI based unwinding on top of regs and stack dumps. + * + * Lots of this code have been borrowed or heavily inspired from parts of + * the libunwind 0.99 code which are (amongst other contributors I may have + * forgotten): + * + * Copyright (C) 2002-2007 Hewlett-Packard Co + * Contributed by David Mosberger-Tang + * + * And the bugs have been added by: + * + * Copyright (C) 2010, Frederic Weisbecker + * Copyright (C) 2012, Jiri Olsa + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "callchain.h" +#include "thread.h" +#include "session.h" +#include "perf_regs.h" +#include "unwind.h" +#include "symbol.h" +#include "util.h" +#include "debug.h" +#include "asm/bug.h" + +extern int +UNW_OBJ(dwarf_search_unwind_table) (unw_addr_space_t as, + unw_word_t ip, + unw_dyn_info_t *di, + unw_proc_info_t *pi, + int need_unwind_info, void *arg); + +#define dwarf_search_unwind_table UNW_OBJ(dwarf_search_unwind_table) + +extern int +UNW_OBJ(dwarf_find_debug_frame) (int found, unw_dyn_info_t *di_debug, + unw_word_t ip, + unw_word_t segbase, + const char *obj_name, unw_word_t start, + unw_word_t end); + +#define dwarf_find_debug_frame UNW_OBJ(dwarf_find_debug_frame) + +#define DW_EH_PE_FORMAT_MASK 0x0f /* format of the encoded value */ +#define DW_EH_PE_APPL_MASK 0x70 /* how the value is to be applied */ + +/* Pointer-encoding formats: */ +#define DW_EH_PE_omit 0xff +#define DW_EH_PE_ptr 0x00 /* pointer-sized unsigned value */ +#define DW_EH_PE_udata4 0x03 /* unsigned 32-bit value */ +#define DW_EH_PE_udata8 0x04 /* unsigned 64-bit value */ +#define DW_EH_PE_sdata4 0x0b /* signed 32-bit value */ +#define DW_EH_PE_sdata8 0x0c /* signed 64-bit value */ + +/* Pointer-encoding application: */ +#define DW_EH_PE_absptr 0x00 /* absolute value */ +#define DW_EH_PE_pcrel 0x10 /* rel. to addr. of encoded value */ + +/* + * The following are not documented by LSB v1.3, yet they are used by + * GCC, presumably they aren't documented by LSB since they aren't + * used on Linux: + */ +#define DW_EH_PE_funcrel 0x40 /* start-of-procedure-relative */ +#define DW_EH_PE_aligned 0x50 /* aligned pointer */ + +/* Flags intentionaly not handled, since they're not needed: + * #define DW_EH_PE_indirect 0x80 + * #define DW_EH_PE_uleb128 0x01 + * #define DW_EH_PE_udata2 0x02 + * #define DW_EH_PE_sleb128 0x09 + * #define DW_EH_PE_sdata2 0x0a + * #define DW_EH_PE_textrel 0x20 + * #define DW_EH_PE_datarel 0x30 + */ + +struct unwind_info { + struct perf_sample *sample; + struct machine *machine; + struct thread *thread; +}; + +#define dw_read(ptr, type, end) ({ \ + type *__p = (type *) ptr; \ + type __v; \ + if ((__p + 1) > (type *) end) \ + return -EINVAL; \ + __v = *__p++; \ + ptr = (typeof(ptr)) __p; \ + __v; \ + }) + +static int __dw_read_encoded_value(u8 **p, u8 *end, u64 *val, + u8 encoding) +{ + u8 *cur = *p; + *val = 0; + + switch (encoding) { + case DW_EH_PE_omit: + *val = 0; + goto out; + case DW_EH_PE_ptr: + *val = dw_read(cur, unsigned long, end); + goto out; + default: + break; + } + + switch (encoding & DW_EH_PE_APPL_MASK) { + case DW_EH_PE_absptr: + break; + case DW_EH_PE_pcrel: + *val = (unsigned long) cur; + break; + default: + return -EINVAL; + } + + if ((encoding & 0x07) == 0x00) + encoding |= DW_EH_PE_udata4; + + switch (encoding & DW_EH_PE_FORMAT_MASK) { + case DW_EH_PE_sdata4: + *val += dw_read(cur, s32, end); + break; + case DW_EH_PE_udata4: + *val += dw_read(cur, u32, end); + break; + case DW_EH_PE_sdata8: + *val += dw_read(cur, s64, end); + break; + case DW_EH_PE_udata8: + *val += dw_read(cur, u64, end); + break; + default: + return -EINVAL; + } + + out: + *p = cur; + return 0; +} + +#define dw_read_encoded_value(ptr, end, enc) ({ \ + u64 __v; \ + if (__dw_read_encoded_value(&ptr, end, &__v, enc)) { \ + return -EINVAL; \ + } \ + __v; \ + }) + +static u64 elf_section_offset(int fd, const char *name) +{ + Elf *elf; + GElf_Ehdr ehdr; + GElf_Shdr shdr; + u64 offset = 0; + + elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL); + if (elf == NULL) + return 0; + + do { + if (gelf_getehdr(elf, &ehdr) == NULL) + break; + + if (!elf_section_by_name(elf, &ehdr, &shdr, name, NULL)) + break; + + offset = shdr.sh_offset; + } while (0); + + elf_end(elf); + return offset; +} + +#ifndef NO_LIBUNWIND_DEBUG_FRAME +static int elf_is_exec(int fd, const char *name) +{ + Elf *elf; + GElf_Ehdr ehdr; + int retval = 0; + + elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL); + if (elf == NULL) + return 0; + if (gelf_getehdr(elf, &ehdr) == NULL) + goto out; + + retval = (ehdr.e_type == ET_EXEC); + +out: + elf_end(elf); + pr_debug("unwind: elf_is_exec(%s): %d\n", name, retval); + return retval; +} +#endif + +struct table_entry { + u32 start_ip_offset; + u32 fde_offset; +}; + +struct eh_frame_hdr { + unsigned char version; + unsigned char eh_frame_ptr_enc; + unsigned char fde_count_enc; + unsigned char table_enc; + + /* + * The rest of the header is variable-length and consists of the + * following members: + * + * encoded_t eh_frame_ptr; + * encoded_t fde_count; + */ + + /* A single encoded pointer should not be more than 8 bytes. */ + u64 enc[2]; + + /* + * struct { + * encoded_t start_ip; + * encoded_t fde_addr; + * } binary_search_table[fde_count]; + */ + char data[0]; +} __packed; + +static int unwind_spec_ehframe(struct dso *dso, struct machine *machine, + u64 offset, u64 *table_data, u64 *segbase, + u64 *fde_count) +{ + struct eh_frame_hdr hdr; + u8 *enc = (u8 *) &hdr.enc; + u8 *end = (u8 *) &hdr.data; + ssize_t r; + + r = dso__data_read_offset(dso, machine, offset, + (u8 *) &hdr, sizeof(hdr)); + if (r != sizeof(hdr)) + return -EINVAL; + + /* We dont need eh_frame_ptr, just skip it. */ + dw_read_encoded_value(enc, end, hdr.eh_frame_ptr_enc); + + *fde_count = dw_read_encoded_value(enc, end, hdr.fde_count_enc); + *segbase = offset; + *table_data = (enc - (u8 *) &hdr) + offset; + return 0; +} + +static int read_unwind_spec_eh_frame(struct dso *dso, struct machine *machine, + u64 *table_data, u64 *segbase, + u64 *fde_count) +{ + int ret = -EINVAL, fd; + u64 offset = dso->data.eh_frame_hdr_offset; + + if (offset == 0) { + fd = dso__data_get_fd(dso, machine); + if (fd < 0) + return -EINVAL; + + /* Check the .eh_frame section for unwinding info */ + offset = elf_section_offset(fd, ".eh_frame_hdr"); + dso->data.eh_frame_hdr_offset = offset; + dso__data_put_fd(dso); + } + + if (offset) + ret = unwind_spec_ehframe(dso, machine, offset, + table_data, segbase, + fde_count); + + return ret; +} + +#ifndef NO_LIBUNWIND_DEBUG_FRAME +static int read_unwind_spec_debug_frame(struct dso *dso, + struct machine *machine, u64 *offset) +{ + int fd; + u64 ofs = dso->data.debug_frame_offset; + + if (ofs == 0) { + fd = dso__data_get_fd(dso, machine); + if (fd < 0) + return -EINVAL; + + /* Check the .debug_frame section for unwinding info */ + ofs = elf_section_offset(fd, ".debug_frame"); + dso->data.debug_frame_offset = ofs; + dso__data_put_fd(dso); + } + + *offset = ofs; + if (*offset) + return 0; + + return -EINVAL; +} +#endif + +static struct map *find_map(unw_word_t ip, struct unwind_info *ui) +{ + struct addr_location al; + + thread__find_addr_map(ui->thread, PERF_RECORD_MISC_USER, + MAP__FUNCTION, ip, &al); + if (!al.map) { + /* + * We've seen cases (softice) where DWARF unwinder went + * through non executable mmaps, which we need to lookup + * in MAP__VARIABLE tree. + */ + thread__find_addr_map(ui->thread, PERF_RECORD_MISC_USER, + MAP__VARIABLE, ip, &al); + } + return al.map; +} + +static int +find_proc_info(unw_addr_space_t as, unw_word_t ip, unw_proc_info_t *pi, + int need_unwind_info, void *arg) +{ + struct unwind_info *ui = arg; + struct map *map; + unw_dyn_info_t di; + u64 table_data, segbase, fde_count; + int ret = -EINVAL; + + map = find_map(ip, ui); + if (!map || !map->dso) + return -EINVAL; + + pr_debug("unwind: find_proc_info dso %s\n", map->dso->name); + + /* Check the .eh_frame section for unwinding info */ + if (!read_unwind_spec_eh_frame(map->dso, ui->machine, + &table_data, &segbase, &fde_count)) { + memset(&di, 0, sizeof(di)); + di.format = UNW_INFO_FORMAT_REMOTE_TABLE; + di.start_ip = map->start; + di.end_ip = map->end; + di.u.rti.segbase = map->start + segbase; + di.u.rti.table_data = map->start + table_data; + di.u.rti.table_len = fde_count * sizeof(struct table_entry) + / sizeof(unw_word_t); + ret = dwarf_search_unwind_table(as, ip, &di, pi, + need_unwind_info, arg); + } + +#ifndef NO_LIBUNWIND_DEBUG_FRAME + /* Check the .debug_frame section for unwinding info */ + if (ret < 0 && + !read_unwind_spec_debug_frame(map->dso, ui->machine, &segbase)) { + int fd = dso__data_get_fd(map->dso, ui->machine); + int is_exec = elf_is_exec(fd, map->dso->name); + unw_word_t base = is_exec ? 0 : map->start; + const char *symfile; + + if (fd >= 0) + dso__data_put_fd(map->dso); + + symfile = map->dso->symsrc_filename ?: map->dso->name; + + memset(&di, 0, sizeof(di)); + if (dwarf_find_debug_frame(0, &di, ip, base, symfile, + map->start, map->end)) + return dwarf_search_unwind_table(as, ip, &di, pi, + need_unwind_info, arg); + } +#endif + + return ret; +} + +static int access_fpreg(unw_addr_space_t __maybe_unused as, + unw_regnum_t __maybe_unused num, + unw_fpreg_t __maybe_unused *val, + int __maybe_unused __write, + void __maybe_unused *arg) +{ + pr_err("unwind: access_fpreg unsupported\n"); + return -UNW_EINVAL; +} + +static int get_dyn_info_list_addr(unw_addr_space_t __maybe_unused as, + unw_word_t __maybe_unused *dil_addr, + void __maybe_unused *arg) +{ + return -UNW_ENOINFO; +} + +static int resume(unw_addr_space_t __maybe_unused as, + unw_cursor_t __maybe_unused *cu, + void __maybe_unused *arg) +{ + pr_err("unwind: resume unsupported\n"); + return -UNW_EINVAL; +} + +static int +get_proc_name(unw_addr_space_t __maybe_unused as, + unw_word_t __maybe_unused addr, + char __maybe_unused *bufp, size_t __maybe_unused buf_len, + unw_word_t __maybe_unused *offp, void __maybe_unused *arg) +{ + pr_err("unwind: get_proc_name unsupported\n"); + return -UNW_EINVAL; +} + +static int access_dso_mem(struct unwind_info *ui, unw_word_t addr, + unw_word_t *data) +{ + struct map *map; + ssize_t size; + + map = find_map(addr, ui); + if (!map) { + pr_debug("unwind: no map for %lx\n", (unsigned long)addr); + return -1; + } + + if (!map->dso) + return -1; + + size = dso__data_read_addr(map->dso, map, ui->machine, + addr, (u8 *) data, sizeof(*data)); + + return !(size == sizeof(*data)); +} + +static int access_mem(unw_addr_space_t __maybe_unused as, + unw_word_t addr, unw_word_t *valp, + int __write, void *arg) +{ + struct unwind_info *ui = arg; + struct stack_dump *stack = &ui->sample->user_stack; + u64 start, end; + int offset; + int ret; + + /* Don't support write, probably not needed. */ + if (__write || !stack || !ui->sample->user_regs.regs) { + *valp = 0; + return 0; + } + + ret = perf_reg_value(&start, &ui->sample->user_regs, PERF_REG_SP); + if (ret) + return ret; + + end = start + stack->size; + + /* Check overflow. */ + if (addr + sizeof(unw_word_t) < addr) + return -EINVAL; + + if (addr < start || addr + sizeof(unw_word_t) >= end) { + ret = access_dso_mem(ui, addr, valp); + if (ret) { + pr_debug("unwind: access_mem %p not inside range" + " 0x%" PRIx64 "-0x%" PRIx64 "\n", + (void *) (uintptr_t) addr, start, end); + *valp = 0; + return ret; + } + return 0; + } + + offset = addr - start; + *valp = *(unw_word_t *)&stack->data[offset]; + pr_debug("unwind: access_mem addr %p val %lx, offset %d\n", + (void *) (uintptr_t) addr, (unsigned long)*valp, offset); + return 0; +} + +static int access_reg(unw_addr_space_t __maybe_unused as, + unw_regnum_t regnum, unw_word_t *valp, + int __write, void *arg) +{ + struct unwind_info *ui = arg; + int id, ret; + u64 val; + + /* Don't support write, I suspect we don't need it. */ + if (__write) { + pr_err("unwind: access_reg w %d\n", regnum); + return 0; + } + + if (!ui->sample->user_regs.regs) { + *valp = 0; + return 0; + } + + id = libunwind__arch_reg_id(regnum); + if (id < 0) + return -EINVAL; + + ret = perf_reg_value(&val, &ui->sample->user_regs, id); + if (ret) { + pr_err("unwind: can't read reg %d\n", regnum); + return ret; + } + + *valp = (unw_word_t) val; + pr_debug("unwind: reg %d, val %lx\n", regnum, (unsigned long)*valp); + return 0; +} + +static void put_unwind_info(unw_addr_space_t __maybe_unused as, + unw_proc_info_t *pi __maybe_unused, + void *arg __maybe_unused) +{ + pr_debug("unwind: put_unwind_info called\n"); +} + +static int entry(u64 ip, struct thread *thread, + unwind_entry_cb_t cb, void *arg) +{ + struct unwind_entry e; + struct addr_location al; + + thread__find_addr_location(thread, PERF_RECORD_MISC_USER, + MAP__FUNCTION, ip, &al); + + e.ip = ip; + e.map = al.map; + e.sym = al.sym; + + pr_debug("unwind: %s:ip = 0x%" PRIx64 " (0x%" PRIx64 ")\n", + al.sym ? al.sym->name : "''", + ip, + al.map ? al.map->map_ip(al.map, ip) : (u64) 0); + + return cb(&e, arg); +} + +static void display_error(int err) +{ + switch (err) { + case UNW_EINVAL: + pr_err("unwind: Only supports local.\n"); + break; + case UNW_EUNSPEC: + pr_err("unwind: Unspecified error.\n"); + break; + case UNW_EBADREG: + pr_err("unwind: Register unavailable.\n"); + break; + default: + break; + } +} + +static unw_accessors_t accessors = { + .find_proc_info = find_proc_info, + .put_unwind_info = put_unwind_info, + .get_dyn_info_list_addr = get_dyn_info_list_addr, + .access_mem = access_mem, + .access_reg = access_reg, + .access_fpreg = access_fpreg, + .resume = resume, + .get_proc_name = get_proc_name, +}; + +static int _unwind__prepare_access(struct thread *thread) +{ + if (callchain_param.record_mode != CALLCHAIN_DWARF) + return 0; + + thread->addr_space = unw_create_addr_space(&accessors, 0); + if (!thread->addr_space) { + pr_err("unwind: Can't create unwind address space.\n"); + return -ENOMEM; + } + + unw_set_caching_policy(thread->addr_space, UNW_CACHE_GLOBAL); + return 0; +} + +static void _unwind__flush_access(struct thread *thread) +{ + if (callchain_param.record_mode != CALLCHAIN_DWARF) + return; + + unw_flush_cache(thread->addr_space, 0, 0); +} + +static void _unwind__finish_access(struct thread *thread) +{ + if (callchain_param.record_mode != CALLCHAIN_DWARF) + return; + + unw_destroy_addr_space(thread->addr_space); +} + +static int get_entries(struct unwind_info *ui, unwind_entry_cb_t cb, + void *arg, int max_stack) +{ + u64 val; + unw_word_t ips[max_stack]; + unw_addr_space_t addr_space; + unw_cursor_t c; + int ret, i = 0; + + ret = perf_reg_value(&val, &ui->sample->user_regs, PERF_REG_IP); + if (ret) + return ret; + + ips[i++] = (unw_word_t) val; + + /* + * If we need more than one entry, do the DWARF + * unwind itself. + */ + if (max_stack - 1 > 0) { + WARN_ONCE(!ui->thread, "WARNING: ui->thread is NULL"); + addr_space = ui->thread->addr_space; + + if (addr_space == NULL) + return -1; + + ret = unw_init_remote(&c, addr_space, ui); + if (ret) + display_error(ret); + + while (!ret && (unw_step(&c) > 0) && i < max_stack) { + unw_get_reg(&c, UNW_REG_IP, &ips[i]); + ++i; + } + + max_stack = i; + } + + /* + * Display what we got based on the order setup. + */ + for (i = 0; i < max_stack && !ret; i++) { + int j = i; + + if (callchain_param.order == ORDER_CALLER) + j = max_stack - i - 1; + ret = ips[j] ? entry(ips[j], ui->thread, cb, arg) : 0; + } + + return ret; +} + +static int _unwind__get_entries(unwind_entry_cb_t cb, void *arg, + struct thread *thread, + struct perf_sample *data, int max_stack) +{ + struct unwind_info ui = { + .sample = data, + .thread = thread, + .machine = thread->mg->machine, + }; + + if (!data->user_regs.regs) + return -EINVAL; + + if (max_stack <= 0) + return -EINVAL; + + return get_entries(&ui, cb, arg, max_stack); +} + +static struct unwind_libunwind_ops +_unwind_libunwind_ops = { + .prepare_access = _unwind__prepare_access, + .flush_access = _unwind__flush_access, + .finish_access = _unwind__finish_access, + .get_entries = _unwind__get_entries, +}; + +struct unwind_libunwind_ops * +local_unwind_libunwind_ops = &_unwind_libunwind_ops; + +static void unwind__register_ops(struct thread *thread, + struct unwind_libunwind_ops *ops) +{ + thread->unwind_libunwind_ops = ops; +} + +int unwind__prepare_access(struct thread *thread) +{ + unwind__register_ops(thread, local_unwind_libunwind_ops); + + return thread->unwind_libunwind_ops->prepare_access(thread); +} + +void unwind__flush_access(struct thread *thread) +{ + if (thread->unwind_libunwind_ops) + thread->unwind_libunwind_ops->flush_access(thread); +} + +void unwind__finish_access(struct thread *thread) +{ + if (thread->unwind_libunwind_ops) + thread->unwind_libunwind_ops->finish_access(thread); +} + +int unwind__get_entries(unwind_entry_cb_t cb, void *arg, + struct thread *thread, + struct perf_sample *data, int max_stack) +{ + if (thread->unwind_libunwind_ops) + return thread->unwind_libunwind_ops->get_entries(cb, arg, thread, data, max_stack); + return 0; +} diff --git a/tools/perf/util/unwind-libunwind.c b/tools/perf/util/unwind-libunwind.c deleted file mode 100644 index b0c5db1..0000000 --- a/tools/perf/util/unwind-libunwind.c +++ /dev/null @@ -1,727 +0,0 @@ -/* - * Post mortem Dwarf CFI based unwinding on top of regs and stack dumps. - * - * Lots of this code have been borrowed or heavily inspired from parts of - * the libunwind 0.99 code which are (amongst other contributors I may have - * forgotten): - * - * Copyright (C) 2002-2007 Hewlett-Packard Co - * Contributed by David Mosberger-Tang - * - * And the bugs have been added by: - * - * Copyright (C) 2010, Frederic Weisbecker - * Copyright (C) 2012, Jiri Olsa - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "callchain.h" -#include "thread.h" -#include "session.h" -#include "perf_regs.h" -#include "unwind.h" -#include "symbol.h" -#include "util.h" -#include "debug.h" -#include "asm/bug.h" - -extern int -UNW_OBJ(dwarf_search_unwind_table) (unw_addr_space_t as, - unw_word_t ip, - unw_dyn_info_t *di, - unw_proc_info_t *pi, - int need_unwind_info, void *arg); - -#define dwarf_search_unwind_table UNW_OBJ(dwarf_search_unwind_table) - -extern int -UNW_OBJ(dwarf_find_debug_frame) (int found, unw_dyn_info_t *di_debug, - unw_word_t ip, - unw_word_t segbase, - const char *obj_name, unw_word_t start, - unw_word_t end); - -#define dwarf_find_debug_frame UNW_OBJ(dwarf_find_debug_frame) - -#define DW_EH_PE_FORMAT_MASK 0x0f /* format of the encoded value */ -#define DW_EH_PE_APPL_MASK 0x70 /* how the value is to be applied */ - -/* Pointer-encoding formats: */ -#define DW_EH_PE_omit 0xff -#define DW_EH_PE_ptr 0x00 /* pointer-sized unsigned value */ -#define DW_EH_PE_udata4 0x03 /* unsigned 32-bit value */ -#define DW_EH_PE_udata8 0x04 /* unsigned 64-bit value */ -#define DW_EH_PE_sdata4 0x0b /* signed 32-bit value */ -#define DW_EH_PE_sdata8 0x0c /* signed 64-bit value */ - -/* Pointer-encoding application: */ -#define DW_EH_PE_absptr 0x00 /* absolute value */ -#define DW_EH_PE_pcrel 0x10 /* rel. to addr. of encoded value */ - -/* - * The following are not documented by LSB v1.3, yet they are used by - * GCC, presumably they aren't documented by LSB since they aren't - * used on Linux: - */ -#define DW_EH_PE_funcrel 0x40 /* start-of-procedure-relative */ -#define DW_EH_PE_aligned 0x50 /* aligned pointer */ - -/* Flags intentionaly not handled, since they're not needed: - * #define DW_EH_PE_indirect 0x80 - * #define DW_EH_PE_uleb128 0x01 - * #define DW_EH_PE_udata2 0x02 - * #define DW_EH_PE_sleb128 0x09 - * #define DW_EH_PE_sdata2 0x0a - * #define DW_EH_PE_textrel 0x20 - * #define DW_EH_PE_datarel 0x30 - */ - -struct unwind_info { - struct perf_sample *sample; - struct machine *machine; - struct thread *thread; -}; - -#define dw_read(ptr, type, end) ({ \ - type *__p = (type *) ptr; \ - type __v; \ - if ((__p + 1) > (type *) end) \ - return -EINVAL; \ - __v = *__p++; \ - ptr = (typeof(ptr)) __p; \ - __v; \ - }) - -static int __dw_read_encoded_value(u8 **p, u8 *end, u64 *val, - u8 encoding) -{ - u8 *cur = *p; - *val = 0; - - switch (encoding) { - case DW_EH_PE_omit: - *val = 0; - goto out; - case DW_EH_PE_ptr: - *val = dw_read(cur, unsigned long, end); - goto out; - default: - break; - } - - switch (encoding & DW_EH_PE_APPL_MASK) { - case DW_EH_PE_absptr: - break; - case DW_EH_PE_pcrel: - *val = (unsigned long) cur; - break; - default: - return -EINVAL; - } - - if ((encoding & 0x07) == 0x00) - encoding |= DW_EH_PE_udata4; - - switch (encoding & DW_EH_PE_FORMAT_MASK) { - case DW_EH_PE_sdata4: - *val += dw_read(cur, s32, end); - break; - case DW_EH_PE_udata4: - *val += dw_read(cur, u32, end); - break; - case DW_EH_PE_sdata8: - *val += dw_read(cur, s64, end); - break; - case DW_EH_PE_udata8: - *val += dw_read(cur, u64, end); - break; - default: - return -EINVAL; - } - - out: - *p = cur; - return 0; -} - -#define dw_read_encoded_value(ptr, end, enc) ({ \ - u64 __v; \ - if (__dw_read_encoded_value(&ptr, end, &__v, enc)) { \ - return -EINVAL; \ - } \ - __v; \ - }) - -static u64 elf_section_offset(int fd, const char *name) -{ - Elf *elf; - GElf_Ehdr ehdr; - GElf_Shdr shdr; - u64 offset = 0; - - elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL); - if (elf == NULL) - return 0; - - do { - if (gelf_getehdr(elf, &ehdr) == NULL) - break; - - if (!elf_section_by_name(elf, &ehdr, &shdr, name, NULL)) - break; - - offset = shdr.sh_offset; - } while (0); - - elf_end(elf); - return offset; -} - -#ifndef NO_LIBUNWIND_DEBUG_FRAME -static int elf_is_exec(int fd, const char *name) -{ - Elf *elf; - GElf_Ehdr ehdr; - int retval = 0; - - elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL); - if (elf == NULL) - return 0; - if (gelf_getehdr(elf, &ehdr) == NULL) - goto out; - - retval = (ehdr.e_type == ET_EXEC); - -out: - elf_end(elf); - pr_debug("unwind: elf_is_exec(%s): %d\n", name, retval); - return retval; -} -#endif - -struct table_entry { - u32 start_ip_offset; - u32 fde_offset; -}; - -struct eh_frame_hdr { - unsigned char version; - unsigned char eh_frame_ptr_enc; - unsigned char fde_count_enc; - unsigned char table_enc; - - /* - * The rest of the header is variable-length and consists of the - * following members: - * - * encoded_t eh_frame_ptr; - * encoded_t fde_count; - */ - - /* A single encoded pointer should not be more than 8 bytes. */ - u64 enc[2]; - - /* - * struct { - * encoded_t start_ip; - * encoded_t fde_addr; - * } binary_search_table[fde_count]; - */ - char data[0]; -} __packed; - -static int unwind_spec_ehframe(struct dso *dso, struct machine *machine, - u64 offset, u64 *table_data, u64 *segbase, - u64 *fde_count) -{ - struct eh_frame_hdr hdr; - u8 *enc = (u8 *) &hdr.enc; - u8 *end = (u8 *) &hdr.data; - ssize_t r; - - r = dso__data_read_offset(dso, machine, offset, - (u8 *) &hdr, sizeof(hdr)); - if (r != sizeof(hdr)) - return -EINVAL; - - /* We dont need eh_frame_ptr, just skip it. */ - dw_read_encoded_value(enc, end, hdr.eh_frame_ptr_enc); - - *fde_count = dw_read_encoded_value(enc, end, hdr.fde_count_enc); - *segbase = offset; - *table_data = (enc - (u8 *) &hdr) + offset; - return 0; -} - -static int read_unwind_spec_eh_frame(struct dso *dso, struct machine *machine, - u64 *table_data, u64 *segbase, - u64 *fde_count) -{ - int ret = -EINVAL, fd; - u64 offset = dso->data.eh_frame_hdr_offset; - - if (offset == 0) { - fd = dso__data_get_fd(dso, machine); - if (fd < 0) - return -EINVAL; - - /* Check the .eh_frame section for unwinding info */ - offset = elf_section_offset(fd, ".eh_frame_hdr"); - dso->data.eh_frame_hdr_offset = offset; - dso__data_put_fd(dso); - } - - if (offset) - ret = unwind_spec_ehframe(dso, machine, offset, - table_data, segbase, - fde_count); - - return ret; -} - -#ifndef NO_LIBUNWIND_DEBUG_FRAME -static int read_unwind_spec_debug_frame(struct dso *dso, - struct machine *machine, u64 *offset) -{ - int fd; - u64 ofs = dso->data.debug_frame_offset; - - if (ofs == 0) { - fd = dso__data_get_fd(dso, machine); - if (fd < 0) - return -EINVAL; - - /* Check the .debug_frame section for unwinding info */ - ofs = elf_section_offset(fd, ".debug_frame"); - dso->data.debug_frame_offset = ofs; - dso__data_put_fd(dso); - } - - *offset = ofs; - if (*offset) - return 0; - - return -EINVAL; -} -#endif - -static struct map *find_map(unw_word_t ip, struct unwind_info *ui) -{ - struct addr_location al; - - thread__find_addr_map(ui->thread, PERF_RECORD_MISC_USER, - MAP__FUNCTION, ip, &al); - if (!al.map) { - /* - * We've seen cases (softice) where DWARF unwinder went - * through non executable mmaps, which we need to lookup - * in MAP__VARIABLE tree. - */ - thread__find_addr_map(ui->thread, PERF_RECORD_MISC_USER, - MAP__VARIABLE, ip, &al); - } - return al.map; -} - -static int -find_proc_info(unw_addr_space_t as, unw_word_t ip, unw_proc_info_t *pi, - int need_unwind_info, void *arg) -{ - struct unwind_info *ui = arg; - struct map *map; - unw_dyn_info_t di; - u64 table_data, segbase, fde_count; - int ret = -EINVAL; - - map = find_map(ip, ui); - if (!map || !map->dso) - return -EINVAL; - - pr_debug("unwind: find_proc_info dso %s\n", map->dso->name); - - /* Check the .eh_frame section for unwinding info */ - if (!read_unwind_spec_eh_frame(map->dso, ui->machine, - &table_data, &segbase, &fde_count)) { - memset(&di, 0, sizeof(di)); - di.format = UNW_INFO_FORMAT_REMOTE_TABLE; - di.start_ip = map->start; - di.end_ip = map->end; - di.u.rti.segbase = map->start + segbase; - di.u.rti.table_data = map->start + table_data; - di.u.rti.table_len = fde_count * sizeof(struct table_entry) - / sizeof(unw_word_t); - ret = dwarf_search_unwind_table(as, ip, &di, pi, - need_unwind_info, arg); - } - -#ifndef NO_LIBUNWIND_DEBUG_FRAME - /* Check the .debug_frame section for unwinding info */ - if (ret < 0 && - !read_unwind_spec_debug_frame(map->dso, ui->machine, &segbase)) { - int fd = dso__data_get_fd(map->dso, ui->machine); - int is_exec = elf_is_exec(fd, map->dso->name); - unw_word_t base = is_exec ? 0 : map->start; - const char *symfile; - - if (fd >= 0) - dso__data_put_fd(map->dso); - - symfile = map->dso->symsrc_filename ?: map->dso->name; - - memset(&di, 0, sizeof(di)); - if (dwarf_find_debug_frame(0, &di, ip, base, symfile, - map->start, map->end)) - return dwarf_search_unwind_table(as, ip, &di, pi, - need_unwind_info, arg); - } -#endif - - return ret; -} - -static int access_fpreg(unw_addr_space_t __maybe_unused as, - unw_regnum_t __maybe_unused num, - unw_fpreg_t __maybe_unused *val, - int __maybe_unused __write, - void __maybe_unused *arg) -{ - pr_err("unwind: access_fpreg unsupported\n"); - return -UNW_EINVAL; -} - -static int get_dyn_info_list_addr(unw_addr_space_t __maybe_unused as, - unw_word_t __maybe_unused *dil_addr, - void __maybe_unused *arg) -{ - return -UNW_ENOINFO; -} - -static int resume(unw_addr_space_t __maybe_unused as, - unw_cursor_t __maybe_unused *cu, - void __maybe_unused *arg) -{ - pr_err("unwind: resume unsupported\n"); - return -UNW_EINVAL; -} - -static int -get_proc_name(unw_addr_space_t __maybe_unused as, - unw_word_t __maybe_unused addr, - char __maybe_unused *bufp, size_t __maybe_unused buf_len, - unw_word_t __maybe_unused *offp, void __maybe_unused *arg) -{ - pr_err("unwind: get_proc_name unsupported\n"); - return -UNW_EINVAL; -} - -static int access_dso_mem(struct unwind_info *ui, unw_word_t addr, - unw_word_t *data) -{ - struct map *map; - ssize_t size; - - map = find_map(addr, ui); - if (!map) { - pr_debug("unwind: no map for %lx\n", (unsigned long)addr); - return -1; - } - - if (!map->dso) - return -1; - - size = dso__data_read_addr(map->dso, map, ui->machine, - addr, (u8 *) data, sizeof(*data)); - - return !(size == sizeof(*data)); -} - -static int access_mem(unw_addr_space_t __maybe_unused as, - unw_word_t addr, unw_word_t *valp, - int __write, void *arg) -{ - struct unwind_info *ui = arg; - struct stack_dump *stack = &ui->sample->user_stack; - u64 start, end; - int offset; - int ret; - - /* Don't support write, probably not needed. */ - if (__write || !stack || !ui->sample->user_regs.regs) { - *valp = 0; - return 0; - } - - ret = perf_reg_value(&start, &ui->sample->user_regs, PERF_REG_SP); - if (ret) - return ret; - - end = start + stack->size; - - /* Check overflow. */ - if (addr + sizeof(unw_word_t) < addr) - return -EINVAL; - - if (addr < start || addr + sizeof(unw_word_t) >= end) { - ret = access_dso_mem(ui, addr, valp); - if (ret) { - pr_debug("unwind: access_mem %p not inside range" - " 0x%" PRIx64 "-0x%" PRIx64 "\n", - (void *) (uintptr_t) addr, start, end); - *valp = 0; - return ret; - } - return 0; - } - - offset = addr - start; - *valp = *(unw_word_t *)&stack->data[offset]; - pr_debug("unwind: access_mem addr %p val %lx, offset %d\n", - (void *) (uintptr_t) addr, (unsigned long)*valp, offset); - return 0; -} - -static int access_reg(unw_addr_space_t __maybe_unused as, - unw_regnum_t regnum, unw_word_t *valp, - int __write, void *arg) -{ - struct unwind_info *ui = arg; - int id, ret; - u64 val; - - /* Don't support write, I suspect we don't need it. */ - if (__write) { - pr_err("unwind: access_reg w %d\n", regnum); - return 0; - } - - if (!ui->sample->user_regs.regs) { - *valp = 0; - return 0; - } - - id = libunwind__arch_reg_id(regnum); - if (id < 0) - return -EINVAL; - - ret = perf_reg_value(&val, &ui->sample->user_regs, id); - if (ret) { - pr_err("unwind: can't read reg %d\n", regnum); - return ret; - } - - *valp = (unw_word_t) val; - pr_debug("unwind: reg %d, val %lx\n", regnum, (unsigned long)*valp); - return 0; -} - -static void put_unwind_info(unw_addr_space_t __maybe_unused as, - unw_proc_info_t *pi __maybe_unused, - void *arg __maybe_unused) -{ - pr_debug("unwind: put_unwind_info called\n"); -} - -static int entry(u64 ip, struct thread *thread, - unwind_entry_cb_t cb, void *arg) -{ - struct unwind_entry e; - struct addr_location al; - - thread__find_addr_location(thread, PERF_RECORD_MISC_USER, - MAP__FUNCTION, ip, &al); - - e.ip = ip; - e.map = al.map; - e.sym = al.sym; - - pr_debug("unwind: %s:ip = 0x%" PRIx64 " (0x%" PRIx64 ")\n", - al.sym ? al.sym->name : "''", - ip, - al.map ? al.map->map_ip(al.map, ip) : (u64) 0); - - return cb(&e, arg); -} - -static void display_error(int err) -{ - switch (err) { - case UNW_EINVAL: - pr_err("unwind: Only supports local.\n"); - break; - case UNW_EUNSPEC: - pr_err("unwind: Unspecified error.\n"); - break; - case UNW_EBADREG: - pr_err("unwind: Register unavailable.\n"); - break; - default: - break; - } -} - -static unw_accessors_t accessors = { - .find_proc_info = find_proc_info, - .put_unwind_info = put_unwind_info, - .get_dyn_info_list_addr = get_dyn_info_list_addr, - .access_mem = access_mem, - .access_reg = access_reg, - .access_fpreg = access_fpreg, - .resume = resume, - .get_proc_name = get_proc_name, -}; - -static int _unwind__prepare_access(struct thread *thread) -{ - if (callchain_param.record_mode != CALLCHAIN_DWARF) - return 0; - - thread->addr_space = unw_create_addr_space(&accessors, 0); - if (!thread->addr_space) { - pr_err("unwind: Can't create unwind address space.\n"); - return -ENOMEM; - } - - unw_set_caching_policy(thread->addr_space, UNW_CACHE_GLOBAL); - return 0; -} - -static void _unwind__flush_access(struct thread *thread) -{ - if (callchain_param.record_mode != CALLCHAIN_DWARF) - return; - - unw_flush_cache(thread->addr_space, 0, 0); -} - -static void _unwind__finish_access(struct thread *thread) -{ - if (callchain_param.record_mode != CALLCHAIN_DWARF) - return; - - unw_destroy_addr_space(thread->addr_space); -} - -static int get_entries(struct unwind_info *ui, unwind_entry_cb_t cb, - void *arg, int max_stack) -{ - u64 val; - unw_word_t ips[max_stack]; - unw_addr_space_t addr_space; - unw_cursor_t c; - int ret, i = 0; - - ret = perf_reg_value(&val, &ui->sample->user_regs, PERF_REG_IP); - if (ret) - return ret; - - ips[i++] = (unw_word_t) val; - - /* - * If we need more than one entry, do the DWARF - * unwind itself. - */ - if (max_stack - 1 > 0) { - WARN_ONCE(!ui->thread, "WARNING: ui->thread is NULL"); - addr_space = ui->thread->addr_space; - - if (addr_space == NULL) - return -1; - - ret = unw_init_remote(&c, addr_space, ui); - if (ret) - display_error(ret); - - while (!ret && (unw_step(&c) > 0) && i < max_stack) { - unw_get_reg(&c, UNW_REG_IP, &ips[i]); - ++i; - } - - max_stack = i; - } - - /* - * Display what we got based on the order setup. - */ - for (i = 0; i < max_stack && !ret; i++) { - int j = i; - - if (callchain_param.order == ORDER_CALLER) - j = max_stack - i - 1; - ret = ips[j] ? entry(ips[j], ui->thread, cb, arg) : 0; - } - - return ret; -} - -static int _unwind__get_entries(unwind_entry_cb_t cb, void *arg, - struct thread *thread, - struct perf_sample *data, int max_stack) -{ - struct unwind_info ui = { - .sample = data, - .thread = thread, - .machine = thread->mg->machine, - }; - - if (!data->user_regs.regs) - return -EINVAL; - - if (max_stack <= 0) - return -EINVAL; - - return get_entries(&ui, cb, arg, max_stack); -} - -static struct unwind_libunwind_ops -_unwind_libunwind_ops = { - .prepare_access = _unwind__prepare_access, - .flush_access = _unwind__flush_access, - .finish_access = _unwind__finish_access, - .get_entries = _unwind__get_entries, -}; - -struct unwind_libunwind_ops * -local_unwind_libunwind_ops = &_unwind_libunwind_ops; - -static void unwind__register_ops(struct thread *thread, - struct unwind_libunwind_ops *ops) -{ - thread->unwind_libunwind_ops = ops; -} - -int unwind__prepare_access(struct thread *thread) -{ - unwind__register_ops(thread, local_unwind_libunwind_ops); - - return thread->unwind_libunwind_ops->prepare_access(thread); -} - -void unwind__flush_access(struct thread *thread) -{ - if (thread->unwind_libunwind_ops) - thread->unwind_libunwind_ops->flush_access(thread); -} - -void unwind__finish_access(struct thread *thread) -{ - if (thread->unwind_libunwind_ops) - thread->unwind_libunwind_ops->finish_access(thread); -} - -int unwind__get_entries(unwind_entry_cb_t cb, void *arg, - struct thread *thread, - struct perf_sample *data, int max_stack) -{ - if (thread->unwind_libunwind_ops) - return thread->unwind_libunwind_ops->get_entries(cb, arg, thread, data, max_stack); - return 0; -} -- cgit v0.10.2 From f6d725324ab281880a0b736df5812e3a1e807779 Mon Sep 17 00:00:00 2001 From: He Kuang Date: Fri, 3 Jun 2016 03:33:17 +0000 Subject: perf tools: Extract common API out of unwind-libunwind-local.c This patch extracts common unwind-libunwind APIs out of unwind-libunwind-local.c, this part will be used by both local and remote libunwind. Signed-off-by: He Kuang Acked-by: Jiri Olsa Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Andi Kleen Cc: David Ahern Cc: Ekaterina Tumanova Cc: Josh Poimboeuf Cc: Kan Liang Cc: Masami Hiramatsu Cc: Namhyung Kim Cc: Pekka Enberg Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Sukadev Bhattiprolu Cc: Wang Nan Link: http://lkml.kernel.org/r/1464924803-22214-9-git-send-email-hekuang@huawei.com Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/util/Build b/tools/perf/util/Build index 5e23d85..004fb1d 100644 --- a/tools/perf/util/Build +++ b/tools/perf/util/Build @@ -100,6 +100,7 @@ libperf-$(CONFIG_DWARF) += dwarf-aux.o libperf-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o libperf-$(CONFIG_LOCAL_LIBUNWIND) += unwind-libunwind-local.o +libperf-$(CONFIG_LIBUNWIND) += unwind-libunwind.o libperf-$(CONFIG_LIBBABELTRACE) += data-convert-bt.o diff --git a/tools/perf/util/unwind-libunwind-local.c b/tools/perf/util/unwind-libunwind-local.c index b0c5db1..9c70486 100644 --- a/tools/perf/util/unwind-libunwind-local.c +++ b/tools/perf/util/unwind-libunwind-local.c @@ -691,37 +691,3 @@ _unwind_libunwind_ops = { struct unwind_libunwind_ops * local_unwind_libunwind_ops = &_unwind_libunwind_ops; - -static void unwind__register_ops(struct thread *thread, - struct unwind_libunwind_ops *ops) -{ - thread->unwind_libunwind_ops = ops; -} - -int unwind__prepare_access(struct thread *thread) -{ - unwind__register_ops(thread, local_unwind_libunwind_ops); - - return thread->unwind_libunwind_ops->prepare_access(thread); -} - -void unwind__flush_access(struct thread *thread) -{ - if (thread->unwind_libunwind_ops) - thread->unwind_libunwind_ops->flush_access(thread); -} - -void unwind__finish_access(struct thread *thread) -{ - if (thread->unwind_libunwind_ops) - thread->unwind_libunwind_ops->finish_access(thread); -} - -int unwind__get_entries(unwind_entry_cb_t cb, void *arg, - struct thread *thread, - struct perf_sample *data, int max_stack) -{ - if (thread->unwind_libunwind_ops) - return thread->unwind_libunwind_ops->get_entries(cb, arg, thread, data, max_stack); - return 0; -} diff --git a/tools/perf/util/unwind-libunwind.c b/tools/perf/util/unwind-libunwind.c new file mode 100644 index 0000000..f86f903 --- /dev/null +++ b/tools/perf/util/unwind-libunwind.c @@ -0,0 +1,38 @@ +#include "unwind.h" +#include "thread.h" + +struct unwind_libunwind_ops __weak *local_unwind_libunwind_ops; + +static void unwind__register_ops(struct thread *thread, + struct unwind_libunwind_ops *ops) +{ + thread->unwind_libunwind_ops = ops; +} + +int unwind__prepare_access(struct thread *thread) +{ + unwind__register_ops(thread, local_unwind_libunwind_ops); + + return thread->unwind_libunwind_ops->prepare_access(thread); +} + +void unwind__flush_access(struct thread *thread) +{ + if (thread->unwind_libunwind_ops) + thread->unwind_libunwind_ops->flush_access(thread); +} + +void unwind__finish_access(struct thread *thread) +{ + if (thread->unwind_libunwind_ops) + thread->unwind_libunwind_ops->finish_access(thread); +} + +int unwind__get_entries(unwind_entry_cb_t cb, void *arg, + struct thread *thread, + struct perf_sample *data, int max_stack) +{ + if (thread->unwind_libunwind_ops) + return thread->unwind_libunwind_ops->get_entries(cb, arg, thread, data, max_stack); + return 0; +} -- cgit v0.10.2 From 940e6987fcfb6092cda8f2f87f2937c55fa038c4 Mon Sep 17 00:00:00 2001 From: He Kuang Date: Fri, 3 Jun 2016 03:33:18 +0000 Subject: perf tools: Export normalize_arch() function Export normalize_arch() function, so other part of perf can get normalized form of arch string. Signed-off-by: He Kuang Acked-by: Jiri Olsa Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Andi Kleen Cc: David Ahern Cc: Ekaterina Tumanova Cc: Josh Poimboeuf Cc: Kan Liang Cc: Masami Hiramatsu Cc: Namhyung Kim Cc: Pekka Enberg Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Sukadev Bhattiprolu Cc: Wang Nan Link: http://lkml.kernel.org/r/1464924803-22214-10-git-send-email-hekuang@huawei.com Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/arch/common.c b/tools/perf/arch/common.c index e83c8ce..fa090a9 100644 --- a/tools/perf/arch/common.c +++ b/tools/perf/arch/common.c @@ -102,7 +102,7 @@ static int lookup_triplets(const char *const *triplets, const char *name) * Return architecture name in a normalized form. * The conversion logic comes from the Makefile. */ -static const char *normalize_arch(char *arch) +const char *normalize_arch(char *arch) { if (!strcmp(arch, "x86_64")) return "x86"; diff --git a/tools/perf/arch/common.h b/tools/perf/arch/common.h index 7529cfb..6b01c73 100644 --- a/tools/perf/arch/common.h +++ b/tools/perf/arch/common.h @@ -6,5 +6,6 @@ extern const char *objdump_path; int perf_env__lookup_objdump(struct perf_env *env); +const char *normalize_arch(char *arch); #endif /* ARCH_PERF_COMMON_H */ -- cgit v0.10.2 From 1ca830b110cd9d067327571f1136fdbf1ef2b4d3 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 23 May 2016 08:45:44 -0300 Subject: [media] v4l2-ioctl: fix stupid mistake in cropcap condition Fix duplicate tests in condition. The second test for vidioc_cropcap should have tested for vidioc_g_selection instead. Signed-off-by: Hans Verkuil Reported-by: David Binderman Acked-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c index 28e5be2..528390f 100644 --- a/drivers/media/v4l2-core/v4l2-ioctl.c +++ b/drivers/media/v4l2-core/v4l2-ioctl.c @@ -2171,7 +2171,7 @@ static int v4l_cropcap(const struct v4l2_ioctl_ops *ops, * The determine_valid_ioctls() call already should ensure * that this can never happen, but just in case... */ - if (WARN_ON(!ops->vidioc_cropcap && !ops->vidioc_cropcap)) + if (WARN_ON(!ops->vidioc_cropcap && !ops->vidioc_g_selection)) return -ENOTTY; if (ops->vidioc_cropcap) -- cgit v0.10.2 From d64ec10ec8b43a519f132e7c33c1815a4e86949e Mon Sep 17 00:00:00 2001 From: He Kuang Date: Fri, 3 Jun 2016 03:33:19 +0000 Subject: perf unwind: Check the target platform before assigning unwind methods Currently, 'perf script' uses host unwind methods to parse perf.data callchain info without taking the target architecture into account, i.e. assuming the perf.data file was generated on the same machine where the analysis is being performed. So we get wrong result without any warnings when unwinding callchains of x86(32-bit) on x86(64-bit) machine. This patch adds an extra step that checks the target platform before assigning unwind methods. In later patches in this series, we can use this info to assign the right unwind methods for supported platforms. Committer note: After fixing it to register the local unwinder for live mode tools ('perf trace', 'perf top'), i.e. tools that don't use a perf.data file, it works as intended and passes the 'perf test unwind' test: # perf trace -e nanosleep --call dwarf usleep 1 0.328 ( 0.058 ms): usleep/11115 nanosleep(rqtp: 0x7fff083fa480) = 0 __nanosleep_nocancel+0x7 (/usr/lib64/libc-2.22.so) usleep+0x34 (/usr/lib64/libc-2.22.so) main+0x1eb (/usr/bin/usleep) __libc_start_main+0xf0 (/usr/lib64/libc-2.22.so) _start+0x29 (/usr/bin/usleep) # perf test 48 48: Test dwarf unwind : Ok # Signed-off-by: He Kuang Acked-by: Jiri Olsa Tested-by: Arnaldo Carvalho de Melo Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Andi Kleen Cc: David Ahern Cc: Ekaterina Tumanova Cc: Josh Poimboeuf Cc: Kan Liang Cc: Masami Hiramatsu Cc: Namhyung Kim Cc: Pekka Enberg Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Sukadev Bhattiprolu Cc: Wang Nan Link: http://lkml.kernel.org/r/1464924803-22214-11-git-send-email-hekuang@huawei.com [ Fixed exit path for 'live' mode tools, where we need to default to local unwinding ] Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c index 0bf55256..f30f956 100644 --- a/tools/perf/util/thread.c +++ b/tools/perf/util/thread.c @@ -202,7 +202,7 @@ int thread__insert_map(struct thread *thread, struct map *map) { int ret; - ret = unwind__prepare_access(thread); + ret = unwind__prepare_access(thread, map); if (ret) return ret; diff --git a/tools/perf/util/unwind-libunwind.c b/tools/perf/util/unwind-libunwind.c index f86f903..0086726 100644 --- a/tools/perf/util/unwind-libunwind.c +++ b/tools/perf/util/unwind-libunwind.c @@ -1,5 +1,8 @@ #include "unwind.h" #include "thread.h" +#include "session.h" +#include "debug.h" +#include "arch/common.h" struct unwind_libunwind_ops __weak *local_unwind_libunwind_ops; @@ -9,8 +12,28 @@ static void unwind__register_ops(struct thread *thread, thread->unwind_libunwind_ops = ops; } -int unwind__prepare_access(struct thread *thread) +int unwind__prepare_access(struct thread *thread, struct map *map) { + const char *arch; + enum dso_type dso_type; + + if (thread->addr_space) { + pr_debug("unwind: thread map already set, dso=%s\n", + map->dso->name); + return 0; + } + + /* env->arch is NULL for live-mode (i.e. perf top) */ + if (!thread->mg->machine->env || !thread->mg->machine->env->arch) + goto out_register; + + dso_type = dso__type(map->dso, thread->mg->machine); + if (dso_type == DSO__TYPE_UNKNOWN) + return 0; + + arch = normalize_arch(thread->mg->machine->env->arch); + pr_debug("unwind: target platform=%s\n", arch); +out_register: unwind__register_ops(thread, local_unwind_libunwind_ops); return thread->unwind_libunwind_ops->prepare_access(thread); diff --git a/tools/perf/util/unwind.h b/tools/perf/util/unwind.h index bbd73d9..bf9f593 100644 --- a/tools/perf/util/unwind.h +++ b/tools/perf/util/unwind.h @@ -30,11 +30,12 @@ int unwind__get_entries(unwind_entry_cb_t cb, void *arg, /* libunwind specific */ #ifdef HAVE_LIBUNWIND_SUPPORT int libunwind__arch_reg_id(int regnum); -int unwind__prepare_access(struct thread *thread); +int unwind__prepare_access(struct thread *thread, struct map *map); void unwind__flush_access(struct thread *thread); void unwind__finish_access(struct thread *thread); #else -static inline int unwind__prepare_access(struct thread *thread __maybe_unused) +static inline int unwind__prepare_access(struct thread *thread __maybe_unused, + struct map *map __maybe_unused) { return 0; } @@ -53,7 +54,8 @@ unwind__get_entries(unwind_entry_cb_t cb __maybe_unused, return 0; } -static inline int unwind__prepare_access(struct thread *thread __maybe_unused) +static inline int unwind__prepare_access(struct thread *thread __maybe_unused, + struct map *map __maybe_unused) { return 0; } -- cgit v0.10.2 From eeb118c5d77878948e09308afe4fd9d0efe68ef7 Mon Sep 17 00:00:00 2001 From: He Kuang Date: Fri, 3 Jun 2016 03:33:20 +0000 Subject: perf unwind: Change fixed name of libunwind__arch_reg_id to macro For local libunwind, it uses the fixed methods to convert register id according to the host platform, but in remote libunwind, this convert function should be the one for remote architecture. This patch changes the fixed name to macro and code for each remote platform can be compiled indivadually. Signed-off-by: He Kuang Acked-by: Jiri Olsa Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Andi Kleen Cc: David Ahern Cc: Ekaterina Tumanova Cc: Josh Poimboeuf Cc: Kan Liang Cc: Masami Hiramatsu Cc: Namhyung Kim Cc: Pekka Enberg Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Sukadev Bhattiprolu Cc: Wang Nan Link: http://lkml.kernel.org/r/1464924803-22214-12-git-send-email-hekuang@huawei.com Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/util/unwind-libunwind-local.c b/tools/perf/util/unwind-libunwind-local.c index 9c70486..631b40d 100644 --- a/tools/perf/util/unwind-libunwind-local.c +++ b/tools/perf/util/unwind-libunwind-local.c @@ -508,7 +508,7 @@ static int access_reg(unw_addr_space_t __maybe_unused as, return 0; } - id = libunwind__arch_reg_id(regnum); + id = LIBUNWIND__ARCH_REG_ID(regnum); if (id < 0) return -EINVAL; diff --git a/tools/perf/util/unwind.h b/tools/perf/util/unwind.h index bf9f593..b074662 100644 --- a/tools/perf/util/unwind.h +++ b/tools/perf/util/unwind.h @@ -29,7 +29,10 @@ int unwind__get_entries(unwind_entry_cb_t cb, void *arg, struct perf_sample *data, int max_stack); /* libunwind specific */ #ifdef HAVE_LIBUNWIND_SUPPORT -int libunwind__arch_reg_id(int regnum); +#ifndef LIBUNWIND__ARCH_REG_ID +#define LIBUNWIND__ARCH_REG_ID(regnum) libunwind__arch_reg_id(regnum) +#endif +int LIBUNWIND__ARCH_REG_ID(int regnum); int unwind__prepare_access(struct thread *thread, struct map *map); void unwind__flush_access(struct thread *thread); void unwind__finish_access(struct thread *thread); -- cgit v0.10.2 From 19473e7ba8f8f443f09d4187791de9d6f95fdc1d Mon Sep 17 00:00:00 2001 From: He Kuang Date: Fri, 3 Jun 2016 03:33:21 +0000 Subject: perf unwind: Introduce flag to separate local/remote unwind compilation This is a preparation for including unwind-libunwind-local.c in other files for remote libunwind. Signed-off-by: He Kuang Acked-by: Jiri Olsa Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Andi Kleen Cc: David Ahern Cc: Ekaterina Tumanova Cc: Josh Poimboeuf Cc: Kan Liang Cc: Masami Hiramatsu Cc: Namhyung Kim Cc: Pekka Enberg Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Sukadev Bhattiprolu Cc: Wang Nan Link: http://lkml.kernel.org/r/1464924803-22214-13-git-send-email-hekuang@huawei.com Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/util/unwind-libunwind-local.c b/tools/perf/util/unwind-libunwind-local.c index 631b40d..01c2e86 100644 --- a/tools/perf/util/unwind-libunwind-local.c +++ b/tools/perf/util/unwind-libunwind-local.c @@ -22,8 +22,10 @@ #include #include #include +#ifndef REMOTE_UNWIND_LIBUNWIND #include #include +#endif #include "callchain.h" #include "thread.h" #include "session.h" @@ -689,5 +691,7 @@ _unwind_libunwind_ops = { .get_entries = _unwind__get_entries, }; +#ifndef REMOTE_UNWIND_LIBUNWIND struct unwind_libunwind_ops * local_unwind_libunwind_ops = &_unwind_libunwind_ops; +#endif -- cgit v0.10.2 From 52ffe0ff02fc053a025c381d5808e9ecd3206dfe Mon Sep 17 00:00:00 2001 From: He Kuang Date: Fri, 3 Jun 2016 03:33:22 +0000 Subject: perf callchain: Support x86 target platform Support x86(32-bit) cross platform callchain unwind. Signed-off-by: He Kuang Acked-by: Jiri Olsa Tested-by: Arnaldo Carvalho de Melo Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Andi Kleen Cc: David Ahern Cc: Ekaterina Tumanova Cc: Josh Poimboeuf Cc: Kan Liang Cc: Masami Hiramatsu Cc: Namhyung Kim Cc: Pekka Enberg Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Sukadev Bhattiprolu Cc: Wang Nan Link: http://lkml.kernel.org/r/1464924803-22214-14-git-send-email-hekuang@huawei.com Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/arch/x86/util/unwind-libunwind.c b/tools/perf/arch/x86/util/unwind-libunwind.c index db25e93..4f16661 100644 --- a/tools/perf/arch/x86/util/unwind-libunwind.c +++ b/tools/perf/arch/x86/util/unwind-libunwind.c @@ -1,12 +1,14 @@ +#ifndef REMOTE_UNWIND_LIBUNWIND #include #include #include "perf_regs.h" #include "../../util/unwind.h" #include "../../util/debug.h" +#endif #ifdef HAVE_ARCH_X86_64_SUPPORT -int libunwind__arch_reg_id(int regnum) +int LIBUNWIND__ARCH_REG_ID(int regnum) { int id; @@ -70,7 +72,7 @@ int libunwind__arch_reg_id(int regnum) return id; } #else -int libunwind__arch_reg_id(int regnum) +int LIBUNWIND__ARCH_REG_ID(int regnum) { int id; diff --git a/tools/perf/config/Makefile b/tools/perf/config/Makefile index 3918687..34999fb 100644 --- a/tools/perf/config/Makefile +++ b/tools/perf/config/Makefile @@ -354,6 +354,14 @@ endif ifndef NO_LIBUNWIND have_libunwind := + + ifeq ($(feature-libunwind-x86), 1) + $(call detected,CONFIG_LIBUNWIND_X86) + CFLAGS += -DHAVE_LIBUNWIND_X86_SUPPORT + LDFLAGS += -lunwind-x86 + have_libunwind = 1 + endif + ifneq ($(feature-libunwind), 1) msg := $(warning No libunwind found. Please install libunwind-dev[el] >= 1.1 and/or set LIBUNWIND_DIR); NO_LOCAL_LIBUNWIND := 1 diff --git a/tools/perf/util/Build b/tools/perf/util/Build index 004fb1d..7746e09 100644 --- a/tools/perf/util/Build +++ b/tools/perf/util/Build @@ -101,6 +101,7 @@ libperf-$(CONFIG_DWARF) += dwarf-aux.o libperf-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o libperf-$(CONFIG_LOCAL_LIBUNWIND) += unwind-libunwind-local.o libperf-$(CONFIG_LIBUNWIND) += unwind-libunwind.o +libperf-$(CONFIG_LIBUNWIND_X86) += libunwind/x86_32.o libperf-$(CONFIG_LIBBABELTRACE) += data-convert-bt.o diff --git a/tools/perf/util/libunwind/x86_32.c b/tools/perf/util/libunwind/x86_32.c new file mode 100644 index 0000000..d98c17e --- /dev/null +++ b/tools/perf/util/libunwind/x86_32.c @@ -0,0 +1,37 @@ +/* + * This file setups defines to compile arch specific binary from the + * generic one. + * + * The function 'LIBUNWIND__ARCH_REG_ID' name is set according to arch + * name and the defination of this function is included directly from + * 'arch/x86/util/unwind-libunwind.c', to make sure that this function + * is defined no matter what arch the host is. + * + * Finally, the arch specific unwind methods are exported which will + * be assigned to each x86 thread. + */ + +#define REMOTE_UNWIND_LIBUNWIND +#define LIBUNWIND__ARCH_REG_ID(regnum) libunwind__x86_reg_id(regnum) + +#include "unwind.h" +#include "debug.h" +#include "libunwind-x86.h" +#include <../../../../arch/x86/include/uapi/asm/perf_regs.h> + +/* HAVE_ARCH_X86_64_SUPPORT is used in'arch/x86/util/unwind-libunwind.c' + * for x86_32, we undef it to compile code for x86_32 only. + */ +#undef HAVE_ARCH_X86_64_SUPPORT +#include "../../arch/x86/util/unwind-libunwind.c" + +/* Explicitly define NO_LIBUNWIND_DEBUG_FRAME, because non-ARM has no + * dwarf_find_debug_frame() function. + */ +#ifndef NO_LIBUNWIND_DEBUG_FRAME +#define NO_LIBUNWIND_DEBUG_FRAME +#endif +#include "util/unwind-libunwind-local.c" + +struct unwind_libunwind_ops * +x86_32_unwind_libunwind_ops = &_unwind_libunwind_ops; diff --git a/tools/perf/util/unwind-libunwind.c b/tools/perf/util/unwind-libunwind.c index 0086726..e65515a 100644 --- a/tools/perf/util/unwind-libunwind.c +++ b/tools/perf/util/unwind-libunwind.c @@ -5,6 +5,7 @@ #include "arch/common.h" struct unwind_libunwind_ops __weak *local_unwind_libunwind_ops; +struct unwind_libunwind_ops __weak *x86_32_unwind_libunwind_ops; static void unwind__register_ops(struct thread *thread, struct unwind_libunwind_ops *ops) @@ -16,6 +17,7 @@ int unwind__prepare_access(struct thread *thread, struct map *map) { const char *arch; enum dso_type dso_type; + struct unwind_libunwind_ops *ops = local_unwind_libunwind_ops; if (thread->addr_space) { pr_debug("unwind: thread map already set, dso=%s\n", @@ -32,9 +34,18 @@ int unwind__prepare_access(struct thread *thread, struct map *map) return 0; arch = normalize_arch(thread->mg->machine->env->arch); - pr_debug("unwind: target platform=%s\n", arch); + + if (!strcmp(arch, "x86")) { + if (dso_type != DSO__TYPE_64BIT) + ops = x86_32_unwind_libunwind_ops; + } + + if (!ops) { + pr_err("unwind: target platform=%s is not supported\n", arch); + return -1; + } out_register: - unwind__register_ops(thread, local_unwind_libunwind_ops); + unwind__register_ops(thread, ops); return thread->unwind_libunwind_ops->prepare_access(thread); } -- cgit v0.10.2 From 057fbfb25cde4a368418f3f720cdc31d48800c4d Mon Sep 17 00:00:00 2001 From: He Kuang Date: Fri, 3 Jun 2016 03:33:23 +0000 Subject: perf callchain: Support aarch64 cross-platform Support aarch64 cross platform callchain unwind. Signed-off-by: He Kuang Acked-by: Jiri Olsa Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Andi Kleen Cc: David Ahern Cc: Ekaterina Tumanova Cc: Josh Poimboeuf Cc: Kan Liang Cc: Masami Hiramatsu Cc: Namhyung Kim Cc: Pekka Enberg Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Sukadev Bhattiprolu Cc: Wang Nan Link: http://lkml.kernel.org/r/1464924803-22214-15-git-send-email-hekuang@huawei.com Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/arch/arm64/util/unwind-libunwind.c b/tools/perf/arch/arm64/util/unwind-libunwind.c index a87afa9..c116b71 100644 --- a/tools/perf/arch/arm64/util/unwind-libunwind.c +++ b/tools/perf/arch/arm64/util/unwind-libunwind.c @@ -1,11 +1,13 @@ +#ifndef REMOTE_UNWIND_LIBUNWIND #include #include #include "perf_regs.h" #include "../../util/unwind.h" #include "../../util/debug.h" +#endif -int libunwind__arch_reg_id(int regnum) +int LIBUNWIND__ARCH_REG_ID(int regnum) { switch (regnum) { case UNW_AARCH64_X0: diff --git a/tools/perf/config/Makefile b/tools/perf/config/Makefile index 34999fb..47e8f58 100644 --- a/tools/perf/config/Makefile +++ b/tools/perf/config/Makefile @@ -362,6 +362,18 @@ ifndef NO_LIBUNWIND have_libunwind = 1 endif + ifeq ($(feature-libunwind-aarch64), 1) + $(call detected,CONFIG_LIBUNWIND_AARCH64) + CFLAGS += -DHAVE_LIBUNWIND_AARCH64_SUPPORT + LDFLAGS += -lunwind-aarch64 + have_libunwind = 1 + $(call feature_check,libunwind-debug-frame-aarch64) + ifneq ($(feature-libunwind-debug-frame-aarch64), 1) + msg := $(warning No debug_frame support found in libunwind-aarch64); + CFLAGS += -DNO_LIBUNWIND_DEBUG_FRAME_AARCH64 + endif + endif + ifneq ($(feature-libunwind), 1) msg := $(warning No libunwind found. Please install libunwind-dev[el] >= 1.1 and/or set LIBUNWIND_DIR); NO_LOCAL_LIBUNWIND := 1 diff --git a/tools/perf/util/Build b/tools/perf/util/Build index 7746e09..fced833 100644 --- a/tools/perf/util/Build +++ b/tools/perf/util/Build @@ -102,6 +102,7 @@ libperf-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o libperf-$(CONFIG_LOCAL_LIBUNWIND) += unwind-libunwind-local.o libperf-$(CONFIG_LIBUNWIND) += unwind-libunwind.o libperf-$(CONFIG_LIBUNWIND_X86) += libunwind/x86_32.o +libperf-$(CONFIG_LIBUNWIND_AARCH64) += libunwind/arm64.o libperf-$(CONFIG_LIBBABELTRACE) += data-convert-bt.o diff --git a/tools/perf/util/libunwind/arm64.c b/tools/perf/util/libunwind/arm64.c new file mode 100644 index 0000000..4fb5395 --- /dev/null +++ b/tools/perf/util/libunwind/arm64.c @@ -0,0 +1,35 @@ +/* + * This file setups defines to compile arch specific binary from the + * generic one. + * + * The function 'LIBUNWIND__ARCH_REG_ID' name is set according to arch + * name and the defination of this function is included directly from + * 'arch/arm64/util/unwind-libunwind.c', to make sure that this function + * is defined no matter what arch the host is. + * + * Finally, the arch specific unwind methods are exported which will + * be assigned to each arm64 thread. + */ + +#define REMOTE_UNWIND_LIBUNWIND + +#define LIBUNWIND__ARCH_REG_ID(regnum) libunwind__arm64_reg_id(regnum) + +#include "unwind.h" +#include "debug.h" +#include "libunwind-aarch64.h" +#include <../../../../arch/arm64/include/uapi/asm/perf_regs.h> +#include "../../arch/arm64/util/unwind-libunwind.c" + +/* NO_LIBUNWIND_DEBUG_FRAME is a feature flag for local libunwind, + * assign NO_LIBUNWIND_DEBUG_FRAME_AARCH64 to it for compiling arm64 + * unwind methods. + */ +#undef NO_LIBUNWIND_DEBUG_FRAME +#ifdef NO_LIBUNWIND_DEBUG_FRAME_AARCH64 +#define NO_LIBUNWIND_DEBUG_FRAME +#endif +#include "util/unwind-libunwind-local.c" + +struct unwind_libunwind_ops * +arm64_unwind_libunwind_ops = &_unwind_libunwind_ops; diff --git a/tools/perf/util/unwind-libunwind.c b/tools/perf/util/unwind-libunwind.c index e65515a..8547119 100644 --- a/tools/perf/util/unwind-libunwind.c +++ b/tools/perf/util/unwind-libunwind.c @@ -6,6 +6,7 @@ struct unwind_libunwind_ops __weak *local_unwind_libunwind_ops; struct unwind_libunwind_ops __weak *x86_32_unwind_libunwind_ops; +struct unwind_libunwind_ops __weak *arm64_unwind_libunwind_ops; static void unwind__register_ops(struct thread *thread, struct unwind_libunwind_ops *ops) @@ -38,6 +39,9 @@ int unwind__prepare_access(struct thread *thread, struct map *map) if (!strcmp(arch, "x86")) { if (dso_type != DSO__TYPE_64BIT) ops = x86_32_unwind_libunwind_ops; + } else if (!strcmp(arch, "arm64") || !strcmp(arch, "arm")) { + if (dso_type == DSO__TYPE_64BIT) + ops = arm64_unwind_libunwind_ops; } if (!ops) { -- cgit v0.10.2 From 6519c3d7b8621c9f4333c98ed4b703029b51ba79 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 24 May 2016 09:09:33 -0300 Subject: [media] adv7604: Don't ignore pad number in subdev DV timings pad operations The dv_timings_cap() and enum_dv_timings() pad operations take a pad number as an input argument and return the DV timings capabilities and list of supported DV timings for that pad. Commit bd3e275f3ec0 ("[media] media: i2c: adv7604: Use v4l2-dv-timings helpers") broke this as it started ignoring the pad number, always returning the information associated with the currently selected input. Fix it. Fixes: bd3e275f3ec0 ("[media] media: i2c: adv7604: Use v4l2-dv-timings helpers") Signed-off-by: Laurent Pinchart Signed-off-by: Hans Verkuil Cc: # for v4.6 Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/i2c/adv7604.c b/drivers/media/i2c/adv7604.c index beb2841..3f1ab49 100644 --- a/drivers/media/i2c/adv7604.c +++ b/drivers/media/i2c/adv7604.c @@ -779,11 +779,31 @@ static const struct v4l2_dv_timings_cap adv76xx_timings_cap_digital = { V4L2_DV_BT_CAP_CUSTOM) }; -static inline const struct v4l2_dv_timings_cap * -adv76xx_get_dv_timings_cap(struct v4l2_subdev *sd) +/* + * Return the DV timings capabilities for the requested sink pad. As a special + * case, pad value -1 returns the capabilities for the currently selected input. + */ +static const struct v4l2_dv_timings_cap * +adv76xx_get_dv_timings_cap(struct v4l2_subdev *sd, int pad) { - return is_digital_input(sd) ? &adv76xx_timings_cap_digital : - &adv7604_timings_cap_analog; + if (pad == -1) { + struct adv76xx_state *state = to_state(sd); + + pad = state->selected_input; + } + + switch (pad) { + case ADV76XX_PAD_HDMI_PORT_A: + case ADV7604_PAD_HDMI_PORT_B: + case ADV7604_PAD_HDMI_PORT_C: + case ADV7604_PAD_HDMI_PORT_D: + return &adv76xx_timings_cap_digital; + + case ADV7604_PAD_VGA_RGB: + case ADV7604_PAD_VGA_COMP: + default: + return &adv7604_timings_cap_analog; + } } @@ -1329,7 +1349,7 @@ static int stdi2dv_timings(struct v4l2_subdev *sd, const struct v4l2_bt_timings *bt = &v4l2_dv_timings_presets[i].bt; if (!v4l2_valid_dv_timings(&v4l2_dv_timings_presets[i], - adv76xx_get_dv_timings_cap(sd), + adv76xx_get_dv_timings_cap(sd, -1), adv76xx_check_dv_timings, NULL)) continue; if (vtotal(bt) != stdi->lcf + 1) @@ -1430,18 +1450,22 @@ static int adv76xx_enum_dv_timings(struct v4l2_subdev *sd, return -EINVAL; return v4l2_enum_dv_timings_cap(timings, - adv76xx_get_dv_timings_cap(sd), adv76xx_check_dv_timings, NULL); + adv76xx_get_dv_timings_cap(sd, timings->pad), + adv76xx_check_dv_timings, NULL); } static int adv76xx_dv_timings_cap(struct v4l2_subdev *sd, struct v4l2_dv_timings_cap *cap) { struct adv76xx_state *state = to_state(sd); + unsigned int pad = cap->pad; if (cap->pad >= state->source_pad) return -EINVAL; - *cap = *adv76xx_get_dv_timings_cap(sd); + *cap = *adv76xx_get_dv_timings_cap(sd, pad); + cap->pad = pad; + return 0; } @@ -1450,9 +1474,9 @@ static int adv76xx_dv_timings_cap(struct v4l2_subdev *sd, static void adv76xx_fill_optional_dv_timings_fields(struct v4l2_subdev *sd, struct v4l2_dv_timings *timings) { - v4l2_find_dv_timings_cap(timings, adv76xx_get_dv_timings_cap(sd), - is_digital_input(sd) ? 250000 : 1000000, - adv76xx_check_dv_timings, NULL); + v4l2_find_dv_timings_cap(timings, adv76xx_get_dv_timings_cap(sd, -1), + is_digital_input(sd) ? 250000 : 1000000, + adv76xx_check_dv_timings, NULL); } static unsigned int adv7604_read_hdmi_pixelclock(struct v4l2_subdev *sd) @@ -1620,7 +1644,7 @@ static int adv76xx_s_dv_timings(struct v4l2_subdev *sd, bt = &timings->bt; - if (!v4l2_valid_dv_timings(timings, adv76xx_get_dv_timings_cap(sd), + if (!v4l2_valid_dv_timings(timings, adv76xx_get_dv_timings_cap(sd, -1), adv76xx_check_dv_timings, NULL)) return -ERANGE; -- cgit v0.10.2 From d0e08b0077f49e209bc90305ddf1ca434ac6cc0e Mon Sep 17 00:00:00 2001 From: Jiancheng Xue Date: Thu, 12 May 2016 09:41:37 +0800 Subject: usb: ehci-platform: add reset controller number in struct ehci_platform_priv Some ehci compatible controllers have more than one reset signal lines, e.g., Synopsys DWC USB2.0 Host-AHB Controller has two resets hreset_i_n and phy_rst_i_n. Two more resets are added in this patch in order for this kind of controller to use this driver directly. Signed-off-by: Jiancheng Xue Acked-by: Alan Stern Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/host/ehci-platform.c b/drivers/usb/host/ehci-platform.c index 1757ebb..bc33f45 100644 --- a/drivers/usb/host/ehci-platform.c +++ b/drivers/usb/host/ehci-platform.c @@ -39,11 +39,12 @@ #define DRIVER_DESC "EHCI generic platform driver" #define EHCI_MAX_CLKS 3 +#define EHCI_MAX_RSTS 3 #define hcd_to_ehci_priv(h) ((struct ehci_platform_priv *)hcd_to_ehci(h)->priv) struct ehci_platform_priv { struct clk *clks[EHCI_MAX_CLKS]; - struct reset_control *rst; + struct reset_control *rsts[EHCI_MAX_RSTS]; struct phy **phys; int num_phys; bool reset_on_resume; @@ -149,7 +150,7 @@ static int ehci_platform_probe(struct platform_device *dev) struct usb_ehci_pdata *pdata = dev_get_platdata(&dev->dev); struct ehci_platform_priv *priv; struct ehci_hcd *ehci; - int err, irq, phy_num, clk = 0; + int err, irq, phy_num, clk = 0, rst; if (usb_disabled()) return -ENODEV; @@ -234,16 +235,22 @@ static int ehci_platform_probe(struct platform_device *dev) } } - priv->rst = devm_reset_control_get_optional(&dev->dev, NULL); - if (IS_ERR(priv->rst)) { - err = PTR_ERR(priv->rst); - if (err == -EPROBE_DEFER) - goto err_put_clks; - priv->rst = NULL; - } else { - err = reset_control_deassert(priv->rst); - if (err) - goto err_put_clks; + for (rst = 0; rst < EHCI_MAX_RSTS; rst++) { + priv->rsts[rst] = of_reset_control_get_by_index( + dev->dev.of_node, rst); + if (IS_ERR(priv->rsts[rst])) { + err = PTR_ERR(priv->rsts[rst]); + if (err == -EPROBE_DEFER) + goto err_reset; + priv->rsts[rst] = NULL; + break; + } + + err = reset_control_deassert(priv->rsts[rst]); + if (err) { + reset_control_put(priv->rsts[rst]); + goto err_reset; + } } if (pdata->big_endian_desc) @@ -300,8 +307,10 @@ err_power: if (pdata->power_off) pdata->power_off(dev); err_reset: - if (priv->rst) - reset_control_assert(priv->rst); + while (--rst >= 0) { + reset_control_assert(priv->rsts[rst]); + reset_control_put(priv->rsts[rst]); + } err_put_clks: while (--clk >= 0) clk_put(priv->clks[clk]); @@ -319,15 +328,17 @@ static int ehci_platform_remove(struct platform_device *dev) struct usb_hcd *hcd = platform_get_drvdata(dev); struct usb_ehci_pdata *pdata = dev_get_platdata(&dev->dev); struct ehci_platform_priv *priv = hcd_to_ehci_priv(hcd); - int clk; + int clk, rst; usb_remove_hcd(hcd); if (pdata->power_off) pdata->power_off(dev); - if (priv->rst) - reset_control_assert(priv->rst); + for (rst = 0; rst < EHCI_MAX_RSTS && priv->rsts[rst]; rst++) { + reset_control_assert(priv->rsts[rst]); + reset_control_put(priv->rsts[rst]); + } for (clk = 0; clk < EHCI_MAX_CLKS && priv->clks[clk]; clk++) clk_put(priv->clks[clk]); -- cgit v0.10.2 From 134a92659f9382f00f94b880183472b0769ad53e Mon Sep 17 00:00:00 2001 From: Alexander Popov Date: Fri, 20 May 2016 12:37:28 +0300 Subject: usbip: don't call stub_device_reset() during stub_disconnect() stub_disconnect() calls stub_device_reset() during usb_unbind_device() when usb device is locked. So usb_lock_device_for_reset() in stub_device_reset() in that case polls for one second and returns -EBUSY anyway. Remove useless flag USBIP_EH_RESET from SDEV_EVENT_REMOVED. Signed-off-by: Alexander Popov Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/usbip/usbip_common.h b/drivers/usb/usbip/usbip_common.h index c7508cb..9f49037 100644 --- a/drivers/usb/usbip/usbip_common.h +++ b/drivers/usb/usbip/usbip_common.h @@ -245,7 +245,7 @@ enum usbip_side { #define USBIP_EH_RESET (1 << 2) #define USBIP_EH_UNUSABLE (1 << 3) -#define SDEV_EVENT_REMOVED (USBIP_EH_SHUTDOWN | USBIP_EH_RESET | USBIP_EH_BYE) +#define SDEV_EVENT_REMOVED (USBIP_EH_SHUTDOWN | USBIP_EH_BYE) #define SDEV_EVENT_DOWN (USBIP_EH_SHUTDOWN | USBIP_EH_RESET) #define SDEV_EVENT_ERROR_TCP (USBIP_EH_SHUTDOWN | USBIP_EH_RESET) #define SDEV_EVENT_ERROR_SUBMIT (USBIP_EH_SHUTDOWN | USBIP_EH_RESET) -- cgit v0.10.2 From a092a16b14ea4f757fa3e0a0fb6544a356f274ba Mon Sep 17 00:00:00 2001 From: Sandhya Bankar Date: Tue, 31 May 2016 08:32:55 -0400 Subject: usb: cdc-acm: Space prohibited before close parenthesis ')'. Space prohibited before close parenthesis ')'. Signed-off-by: Sandhya Bankar Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index 94a14f5..def5a54 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c @@ -946,7 +946,7 @@ static int wait_serial_change(struct acm *acm, unsigned long arg) DECLARE_WAITQUEUE(wait, current); struct async_icount old, new; - if (arg & (TIOCM_DSR | TIOCM_RI | TIOCM_CD )) + if (arg & (TIOCM_DSR | TIOCM_RI | TIOCM_CD)) return -EINVAL; do { spin_lock_irq(&acm->read_lock); -- cgit v0.10.2 From 600bb2160546d3310f8f01838b6088569c1b6fdb Mon Sep 17 00:00:00 2001 From: Sandhya Bankar Date: Wed, 1 Jun 2016 08:48:04 -0400 Subject: usb: microtek: Use "foo *bar" instead of "foo * bar". Use "foo *bar" instead of "foo * bar". Signed-off-by: Sandhya Bankar Acked-by: Oliver Neukum Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/image/microtek.h b/drivers/usb/image/microtek.h index ccce318..7e32ae7 100644 --- a/drivers/usb/image/microtek.h +++ b/drivers/usb/image/microtek.h @@ -13,11 +13,11 @@ typedef void (*mts_scsi_cmnd_callback)(struct scsi_cmnd *); struct mts_transfer_context { - struct mts_desc* instance; + struct mts_desc *instance; mts_scsi_cmnd_callback final_callback; struct scsi_cmnd *srb; - void* data; + void *data; unsigned data_length; int data_pipe; int fragment; @@ -38,7 +38,7 @@ struct mts_desc { u8 ep_response; u8 ep_image; - struct Scsi_Host * host; + struct Scsi_Host *host; struct urb *urb; struct mts_transfer_context context; -- cgit v0.10.2 From 7c348f1cfb6d8c6911fcb6d13b4c267a8bc93856 Mon Sep 17 00:00:00 2001 From: Sudip Mukherjee Date: Mon, 6 Jun 2016 22:23:32 +0100 Subject: usb: usbip: remove null check The only caller of get_gadget_descs() has already dereferenced udc before calling this function, so udc can not be NULL at this point of the code and hence no use of checking it. Signed-off-by: Sudip Mukherjee Reviewed-by: Krzysztof Opasiak Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/usbip/vudc_sysfs.c b/drivers/usb/usbip/vudc_sysfs.c index 99397fa..0f98f2c 100644 --- a/drivers/usb/usbip/vudc_sysfs.c +++ b/drivers/usb/usbip/vudc_sysfs.c @@ -40,7 +40,7 @@ int get_gadget_descs(struct vudc *udc) struct usb_ctrlrequest req; int ret; - if (!udc || !udc->driver || !udc->pullup) + if (!udc->driver || !udc->pullup) return -EINVAL; req.bRequestType = USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_DEVICE; -- cgit v0.10.2 From 495660cb53ba7c8cc8fcb577ad05001f12b58632 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 1 Jun 2016 09:29:56 +0200 Subject: usb: misc: usb3503: Set platform data Driver supports two paths of device instantiation: as platform and i2c device. In the platform path it lacks of storing the driver specific structure as drvdata. Signed-off-by: Krzysztof Kozlowski Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/misc/usb3503.c b/drivers/usb/misc/usb3503.c index b45cb77..0cf2987 100644 --- a/drivers/usb/misc/usb3503.c +++ b/drivers/usb/misc/usb3503.c @@ -338,6 +338,7 @@ static int usb3503_platform_probe(struct platform_device *pdev) if (!hub) return -ENOMEM; hub->dev = &pdev->dev; + platform_set_drvdata(pdev, hub); return usb3503_probe(hub); } -- cgit v0.10.2 From 62c32e4641e7c5f6e0cad72bea0c8645c33d51b6 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 1 Jun 2016 09:29:57 +0200 Subject: usb: misc: usb3503: Clean up on driver unbind The driver should clean up after itself by unpreparing the clock when it is unbound. Signed-off-by: Krzysztof Kozlowski Reviewed-by: Javier Martinez Canillas Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/misc/usb3503.c b/drivers/usb/misc/usb3503.c index 0cf2987..8e7737d 100644 --- a/drivers/usb/misc/usb3503.c +++ b/drivers/usb/misc/usb3503.c @@ -330,6 +330,17 @@ static int usb3503_i2c_probe(struct i2c_client *i2c, return usb3503_probe(hub); } +static int usb3503_i2c_remove(struct i2c_client *i2c) +{ + struct usb3503 *hub; + + hub = i2c_get_clientdata(i2c); + if (hub->clk) + clk_disable_unprepare(hub->clk); + + return 0; +} + static int usb3503_platform_probe(struct platform_device *pdev) { struct usb3503 *hub; @@ -343,6 +354,17 @@ static int usb3503_platform_probe(struct platform_device *pdev) return usb3503_probe(hub); } +static int usb3503_platform_remove(struct platform_device *pdev) +{ + struct usb3503 *hub; + + hub = platform_get_drvdata(pdev); + if (hub->clk) + clk_disable_unprepare(hub->clk); + + return 0; +} + #ifdef CONFIG_PM_SLEEP static int usb3503_i2c_suspend(struct device *dev) { @@ -396,6 +418,7 @@ static struct i2c_driver usb3503_i2c_driver = { .of_match_table = of_match_ptr(usb3503_of_match), }, .probe = usb3503_i2c_probe, + .remove = usb3503_i2c_remove, .id_table = usb3503_id, }; @@ -405,6 +428,7 @@ static struct platform_driver usb3503_platform_driver = { .of_match_table = of_match_ptr(usb3503_of_match), }, .probe = usb3503_platform_probe, + .remove = usb3503_platform_remove, }; static int __init usb3503_init(void) -- cgit v0.10.2 From 7150bc9b4d43471fa37b26f5839892d4cf1fe09b Mon Sep 17 00:00:00 2001 From: Wenyou Yang Date: Wed, 8 Jun 2016 12:15:10 +0800 Subject: usb: ohci-at91: Forcibly suspend ports while USB suspend In order to the save power consumption, as a workaround, suspend forcibly the USB PORTA/B/C via set the SUSPEND_A/B/C bits of OHCI Interrupt Configuration Register in the SFRs while OHCI USB suspend. This suspend operation must be done before the USB clock is disabled, resume after the USB clock is enabled. Signed-off-by: Wenyou Yang Signed-off-by: Greg Kroah-Hartman diff --git a/Documentation/devicetree/bindings/usb/atmel-usb.txt b/Documentation/devicetree/bindings/usb/atmel-usb.txt index 5883b73..888deaa 100644 --- a/Documentation/devicetree/bindings/usb/atmel-usb.txt +++ b/Documentation/devicetree/bindings/usb/atmel-usb.txt @@ -3,8 +3,10 @@ Atmel SOC USB controllers OHCI Required properties: - - compatible: Should be "atmel,at91rm9200-ohci" for USB controllers - used in host mode. + - compatible: Should be one of the following + "atmel,at91rm9200-ohci" for USB controllers used in host mode. + "atmel,sama5d2-ohci" for USB controllers used in host mode + on SAMA5D2 which can force to suspend. - reg: Address and length of the register set for the device - interrupts: Should contain ehci interrupt - clocks: Should reference the peripheral, host and system clocks diff --git a/drivers/usb/host/ohci-at91.c b/drivers/usb/host/ohci-at91.c index d177372..54e8feb 100644 --- a/drivers/usb/host/ohci-at91.c +++ b/drivers/usb/host/ohci-at91.c @@ -21,8 +21,11 @@ #include #include #include +#include +#include #include #include +#include #include "ohci.h" @@ -45,12 +48,18 @@ struct at91_usbh_data { u8 overcurrent_changed[AT91_MAX_USBH_PORTS]; }; +struct ohci_at91_caps { + bool suspend_ctrl; +}; + struct ohci_at91_priv { struct clk *iclk; struct clk *fclk; struct clk *hclk; bool clocked; bool wakeup; /* Saved wake-up state for resume */ + const struct ohci_at91_caps *caps; + struct regmap *sfr_regmap; }; /* interface and function clocks; sometimes also an AHB clock */ @@ -132,6 +141,17 @@ static void at91_stop_hc(struct platform_device *pdev) /*-------------------------------------------------------------------------*/ +struct regmap *at91_dt_syscon_sfr(void) +{ + struct regmap *regmap; + + regmap = syscon_regmap_lookup_by_compatible("atmel,sama5d2-sfr"); + if (IS_ERR(regmap)) + regmap = NULL; + + return regmap; +} + static void usb_hcd_at91_remove (struct usb_hcd *, struct platform_device *); /* configure so an HC device and id are always provided */ @@ -197,6 +217,17 @@ static int usb_hcd_at91_probe(const struct hc_driver *driver, goto err; } + ohci_at91->caps = (const struct ohci_at91_caps *) + of_device_get_match_data(&pdev->dev); + if (!ohci_at91->caps) + return -ENODEV; + + if (ohci_at91->caps->suspend_ctrl) { + ohci_at91->sfr_regmap = at91_dt_syscon_sfr(); + if (!ohci_at91->sfr_regmap) + dev_warn(dev, "failed to find sfr node\n"); + } + board = hcd->self.controller->platform_data; ohci = hcd_to_ohci(hcd); ohci->num_ports = board->ports; @@ -440,8 +471,17 @@ static irqreturn_t ohci_hcd_at91_overcurrent_irq(int irq, void *data) return IRQ_HANDLED; } +static const struct ohci_at91_caps at91rm9200_caps = { + .suspend_ctrl = false, +}; + +static const struct ohci_at91_caps sama5d2_caps = { + .suspend_ctrl = true, +}; + static const struct of_device_id at91_ohci_dt_ids[] = { - { .compatible = "atmel,at91rm9200-ohci" }, + { .compatible = "atmel,at91rm9200-ohci", .data = &at91rm9200_caps }, + { .compatible = "atmel,sama5d2-ohci", .data = &sama5d2_caps }, { /* sentinel */ } }; @@ -581,6 +621,38 @@ static int ohci_hcd_at91_drv_remove(struct platform_device *pdev) return 0; } +static int ohci_at91_port_ctrl(struct regmap *regmap, bool enable) +{ + u32 regval; + int ret; + + if (!regmap) + return -EINVAL; + + ret = regmap_read(regmap, SFR_OHCIICR, ®val); + if (ret) + return ret; + + if (enable) + regval &= ~SFR_OHCIICR_USB_SUSPEND; + else + regval |= SFR_OHCIICR_USB_SUSPEND; + + regmap_write(regmap, SFR_OHCIICR, regval); + + return 0; +} + +static int ohci_at91_port_suspend(struct regmap *regmap) +{ + return ohci_at91_port_ctrl(regmap, false); +} + +static int ohci_at91_port_resume(struct regmap *regmap) +{ + return ohci_at91_port_ctrl(regmap, true); +} + static int __maybe_unused ohci_hcd_at91_drv_suspend(struct device *dev) { @@ -618,6 +690,9 @@ ohci_hcd_at91_drv_suspend(struct device *dev) ohci_writel(ohci, ohci->hc_control, &ohci->regs->control); ohci->rh_state = OHCI_RH_HALTED; + if (ohci_at91->caps->suspend_ctrl) + ohci_at91_port_suspend(ohci_at91->sfr_regmap); + /* flush the writes */ (void) ohci_readl (ohci, &ohci->regs->control); at91_stop_clock(ohci_at91); @@ -637,6 +712,9 @@ ohci_hcd_at91_drv_resume(struct device *dev) at91_start_clock(ohci_at91); + if (ohci_at91->caps->suspend_ctrl) + ohci_at91_port_resume(ohci_at91->sfr_regmap); + ohci_resume(hcd, false); return 0; } diff --git a/include/soc/at91/at91_sfr.h b/include/soc/at91/at91_sfr.h new file mode 100644 index 0000000..04a3a1e --- /dev/null +++ b/include/soc/at91/at91_sfr.h @@ -0,0 +1,29 @@ +/* + * Header file for the Atmel DDR/SDR SDRAM Controller + * + * Copyright (C) 2016 Atmel Corporation + * + * Author: Wenyou Yang + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ +#ifndef __AT91_SFR_H__ +#define __AT91_SFR_H__ + +#define SFR_DDRCFG 0x04 /* DDR Configuration Register */ +/* 0x08 ~ 0x0c: Reserved */ +#define SFR_OHCIICR 0x10 /* OHCI Interrupt Configuration Register */ +#define SFR_OHCIISR 0x14 /* OHCI Interrupt Status Register */ + +#define SFR_OHCIICR_SUSPEND_A BIT(8) +#define SFR_OHCIICR_SUSPEND_B BIT(9) +#define SFR_OHCIICR_SUSPEND_C BIT(10) + +#define SFR_OHCIICR_USB_SUSPEND (SFR_OHCIICR_SUSPEND_A | \ + SFR_OHCIICR_SUSPEND_B | \ + SFR_OHCIICR_SUSPEND_C) + +#endif -- cgit v0.10.2 From cab43282682e0f46d6a74dd4f54f52595af5eefa Mon Sep 17 00:00:00 2001 From: Wenyou Yang Date: Wed, 8 Jun 2016 12:15:11 +0800 Subject: ARM: at91/dt: sama5d2: Use new compatible for ohci node Use compatible "atmel,sama5d2-ohci" to be capable of suspending ports while sleep to save the power consumption. Signed-off-by: Wenyou Yang Signed-off-by: Greg Kroah-Hartman diff --git a/arch/arm/boot/dts/sama5d2.dtsi b/arch/arm/boot/dts/sama5d2.dtsi index 2827e7a..5dd2734 100644 --- a/arch/arm/boot/dts/sama5d2.dtsi +++ b/arch/arm/boot/dts/sama5d2.dtsi @@ -232,7 +232,7 @@ }; usb1: ohci@00400000 { - compatible = "atmel,at91rm9200-ohci", "usb-ohci"; + compatible = "atmel,sama5d2-ohci", "usb-ohci"; reg = <0x00400000 0x100000>; interrupts = <41 IRQ_TYPE_LEVEL_HIGH 2>; clocks = <&uhphs_clk>, <&uhphs_clk>, <&uhpck>; -- cgit v0.10.2 From 62d9694a003dba585026df36c181e3ca930aeafc Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Thu, 2 Jun 2016 17:14:06 +0200 Subject: ohci-platform: Add support for controllers with multiple reset lines At least the EHCI/OHCI found on the Allwinnner H3 SoC needs multiple reset lines, the controller will not initialize while the reset for its companion is still asserted, which means we need to de-assert 2 resets for the controller to work. Signed-off-by: Hans de Goede Signed-off-by: Greg Kroah-Hartman diff --git a/Documentation/devicetree/bindings/usb/usb-ohci.txt b/Documentation/devicetree/bindings/usb/usb-ohci.txt index 19233b7..9df4569 100644 --- a/Documentation/devicetree/bindings/usb/usb-ohci.txt +++ b/Documentation/devicetree/bindings/usb/usb-ohci.txt @@ -14,7 +14,7 @@ Optional properties: - clocks : a list of phandle + clock specifier pairs - phys : phandle + phy specifier pair - phy-names : "usb" -- resets : phandle + reset specifier pair +- resets : a list of phandle + reset specifier pairs Example: diff --git a/drivers/usb/host/ohci-platform.c b/drivers/usb/host/ohci-platform.c index ae1c988..898b740 100644 --- a/drivers/usb/host/ohci-platform.c +++ b/drivers/usb/host/ohci-platform.c @@ -33,11 +33,12 @@ #define DRIVER_DESC "OHCI generic platform driver" #define OHCI_MAX_CLKS 3 +#define OHCI_MAX_RESETS 2 #define hcd_to_ohci_priv(h) ((struct ohci_platform_priv *)hcd_to_ohci(h)->priv) struct ohci_platform_priv { struct clk *clks[OHCI_MAX_CLKS]; - struct reset_control *rst; + struct reset_control *resets[OHCI_MAX_RESETS]; struct phy **phys; int num_phys; }; @@ -117,7 +118,7 @@ static int ohci_platform_probe(struct platform_device *dev) struct usb_ohci_pdata *pdata = dev_get_platdata(&dev->dev); struct ohci_platform_priv *priv; struct ohci_hcd *ohci; - int err, irq, phy_num, clk = 0; + int err, irq, phy_num, clk = 0, rst = 0; if (usb_disabled()) return -ENODEV; @@ -195,19 +196,21 @@ static int ohci_platform_probe(struct platform_device *dev) break; } } - - } - - priv->rst = devm_reset_control_get_optional(&dev->dev, NULL); - if (IS_ERR(priv->rst)) { - err = PTR_ERR(priv->rst); - if (err == -EPROBE_DEFER) - goto err_put_clks; - priv->rst = NULL; - } else { - err = reset_control_deassert(priv->rst); - if (err) - goto err_put_clks; + for (rst = 0; rst < OHCI_MAX_RESETS; rst++) { + priv->resets[rst] = + devm_reset_control_get_shared_by_index( + &dev->dev, rst); + if (IS_ERR(priv->resets[rst])) { + err = PTR_ERR(priv->resets[rst]); + if (err == -EPROBE_DEFER) + goto err_reset; + priv->resets[rst] = NULL; + break; + } + err = reset_control_deassert(priv->resets[rst]); + if (err) + goto err_reset; + } } if (pdata->big_endian_desc) @@ -265,8 +268,8 @@ err_power: if (pdata->power_off) pdata->power_off(dev); err_reset: - if (priv->rst) - reset_control_assert(priv->rst); + while (--rst >= 0) + reset_control_assert(priv->resets[rst]); err_put_clks: while (--clk >= 0) clk_put(priv->clks[clk]); @@ -284,15 +287,15 @@ static int ohci_platform_remove(struct platform_device *dev) struct usb_hcd *hcd = platform_get_drvdata(dev); struct usb_ohci_pdata *pdata = dev_get_platdata(&dev->dev); struct ohci_platform_priv *priv = hcd_to_ohci_priv(hcd); - int clk; + int clk, rst; usb_remove_hcd(hcd); if (pdata->power_off) pdata->power_off(dev); - if (priv->rst) - reset_control_assert(priv->rst); + for (rst = 0; rst < OHCI_MAX_RESETS && priv->resets[rst]; rst++) + reset_control_assert(priv->resets[rst]); for (clk = 0; clk < OHCI_MAX_CLKS && priv->clks[clk]; clk++) clk_put(priv->clks[clk]); -- cgit v0.10.2 From 494025c634a09f141d9282a5cfdbc24b5415a871 Mon Sep 17 00:00:00 2001 From: Li Dongyang Date: Mon, 9 May 2016 10:53:46 -0400 Subject: staging: lustre: o2iblnd: make rdma_create_id() support containers Add support for lustre's ko2iblnd driver to work with containers which was requested by Sebastien Buisson. Signed-off-by: Li Dongyang Intel-bug-id: https://jira.hpdd.intel.com/browse/LU-6215 Reviewed-on: http://review.whamcloud.com/18759 Reviewed-by: James Simmons Reviewed-by: Sebastien Buisson Reviewed-by: Oleg Drokin Signed-off-by: James Simmons Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.h b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.h index b22984f..45bbe93 100644 --- a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.h +++ b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.h @@ -109,7 +109,7 @@ extern kib_tunables_t kiblnd_tunables; IBLND_CREDIT_HIGHWATER_V1 : \ t->lnd_peercredits_hiw) -#define kiblnd_rdma_create_id(cb, dev, ps, qpt) rdma_create_id(&init_net, \ +#define kiblnd_rdma_create_id(cb, dev, ps, qpt) rdma_create_id(current->nsproxy->net_ns, \ cb, dev, \ ps, qpt) -- cgit v0.10.2 From cd779f2edec4a33f12144fb1588abc0d220e36bc Mon Sep 17 00:00:00 2001 From: James Simmons Date: Mon, 9 May 2016 10:53:47 -0400 Subject: staging: lustre: libcfs: fix memort leak in libcfs crypto layer During code review Boyko discovered a memory leak. This patch fixes that leak. Signed-off-by: James Simmons Intel-bug-id: https://jira.hpdd.intel.com/browse/LU-4423 Reviewed-on: http://review.whamcloud.com/19716 Reviewed-by: Alexander Boyko Reviewed-by: Frank Zago Reviewed-by: Oleg Drokin Signed-off-by: James Simmons Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/lustre/lnet/libcfs/linux/linux-crypto.c b/drivers/staging/lustre/lnet/libcfs/linux/linux-crypto.c index 84f9b7b..5c0116a 100644 --- a/drivers/staging/lustre/lnet/libcfs/linux/linux-crypto.c +++ b/drivers/staging/lustre/lnet/libcfs/linux/linux-crypto.c @@ -99,6 +99,7 @@ static int cfs_crypto_hash_alloc(enum cfs_crypto_hash_alg hash_alg, (*type)->cht_size); if (err != 0) { + ahash_request_free(*req); crypto_free_ahash(tfm); return err; } -- cgit v0.10.2 From 147280d88f8e0e6544da68c658531eed70b9632d Mon Sep 17 00:00:00 2001 From: James Simmons Date: Mon, 9 May 2016 10:53:48 -0400 Subject: staging: lustre: ko2iblnd: fix memory corruption with fragments In my test of the upstream client this change exposed a long standing issues where we have a offset that is not page algined would causes us to access memory beyond the scatter gather list which was causing memory corruption when all 256 fragments were in use. Signed-off-by: James Simmons Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c index 6c59f2f..4bb32f1 100644 --- a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c +++ b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c @@ -2011,8 +2011,8 @@ static void kiblnd_destroy_tx_pool(kib_pool_t *pool) sizeof(*tx->tx_pages)); if (tx->tx_frags) LIBCFS_FREE(tx->tx_frags, - IBLND_MAX_RDMA_FRAGS * - sizeof(*tx->tx_frags)); + (1 + IBLND_MAX_RDMA_FRAGS) * + sizeof(*tx->tx_frags)); if (tx->tx_wrq) LIBCFS_FREE(tx->tx_wrq, (1 + IBLND_MAX_RDMA_FRAGS) * @@ -2090,11 +2090,12 @@ static int kiblnd_create_tx_pool(kib_poolset_t *ps, int size, } LIBCFS_CPT_ALLOC(tx->tx_frags, lnet_cpt_table(), ps->ps_cpt, - IBLND_MAX_RDMA_FRAGS * sizeof(*tx->tx_frags)); + (1 + IBLND_MAX_RDMA_FRAGS) * + sizeof(*tx->tx_frags)); if (!tx->tx_frags) break; - sg_init_table(tx->tx_frags, IBLND_MAX_RDMA_FRAGS); + sg_init_table(tx->tx_frags, IBLND_MAX_RDMA_FRAGS + 1); LIBCFS_CPT_ALLOC(tx->tx_wrq, lnet_cpt_table(), ps->ps_cpt, (1 + IBLND_MAX_RDMA_FRAGS) * diff --git a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd_cb.c b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd_cb.c index bbfee53..0f7e3a1 100644 --- a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd_cb.c +++ b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd_cb.c @@ -689,6 +689,10 @@ kiblnd_setup_rd_iov(lnet_ni_t *ni, kib_tx_t *tx, kib_rdma_desc_t *rd, sg_set_page(sg, page, fragnob, page_offset); sg = sg_next(sg); + if (!sg) { + CERROR("lacking enough sg entries to map tx\n"); + return -EFAULT; + } if (offset + fragnob < iov->iov_len) { offset += fragnob; @@ -733,6 +737,10 @@ kiblnd_setup_rd_kiov(lnet_ni_t *ni, kib_tx_t *tx, kib_rdma_desc_t *rd, sg_set_page(sg, kiov->kiov_page, fragnob, kiov->kiov_offset + offset); sg = sg_next(sg); + if (!sg) { + CERROR("lacking enough sg entries to map tx\n"); + return -EFAULT; + } offset = 0; kiov++; -- cgit v0.10.2 From 423b09b8f45c8771bca84d41c3254c3904d78a0a Mon Sep 17 00:00:00 2001 From: Muhammad Falak R Wani Date: Wed, 11 May 2016 20:53:31 +0530 Subject: staging: lustre: use setup_timer(). Use setup_timer() for initializing the timer, instead of structure assignments. This is the preferred/standard way. Signed-off-by: Muhammad Falak R Wani Acked-by: James Simmons Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/lustre/lnet/lnet/net_fault.c b/drivers/staging/lustre/lnet/lnet/net_fault.c index 7d76f28..e4aceb7 100644 --- a/drivers/staging/lustre/lnet/lnet/net_fault.c +++ b/drivers/staging/lustre/lnet/lnet/net_fault.c @@ -760,9 +760,7 @@ lnet_delay_rule_add(struct lnet_fault_attr *attr) wait_event(delay_dd.dd_ctl_waitq, delay_dd.dd_running); } - init_timer(&rule->dl_timer); - rule->dl_timer.function = delay_timer_cb; - rule->dl_timer.data = (unsigned long)rule; + setup_timer(&rule->dl_timer, delay_timer_cb, (unsigned long)rule); spin_lock_init(&rule->dl_lock); INIT_LIST_HEAD(&rule->dl_msg_list); -- cgit v0.10.2 From db3c16cdde24ecd59df0f24f93f1a4ba177f4b82 Mon Sep 17 00:00:00 2001 From: Lidza Louina Date: Mon, 16 May 2016 14:51:42 -0400 Subject: staging/lustre/ptlrpc: Removes potential null dereference The lustre_msg_buf method could return NULL. Subsequent code didn't check if it's null before using it. This patch adds two checks. Signed-off-by: Lidza Louina Acked-by: Oleg Drokin Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/lustre/lustre/ptlrpc/sec.c b/drivers/staging/lustre/lustre/ptlrpc/sec.c index 187fd1d..657b41f 100644 --- a/drivers/staging/lustre/lustre/ptlrpc/sec.c +++ b/drivers/staging/lustre/lustre/ptlrpc/sec.c @@ -2196,6 +2196,9 @@ int sptlrpc_pack_user_desc(struct lustre_msg *msg, int offset) pud = lustre_msg_buf(msg, offset, 0); + if (!pud) + return -EINVAL; + pud->pud_uid = from_kuid(&init_user_ns, current_uid()); pud->pud_gid = from_kgid(&init_user_ns, current_gid()); pud->pud_fsuid = from_kuid(&init_user_ns, current_fsuid()); diff --git a/drivers/staging/lustre/lustre/ptlrpc/sec_plain.c b/drivers/staging/lustre/lustre/ptlrpc/sec_plain.c index 37c9f4c..ec8edbf 100644 --- a/drivers/staging/lustre/lustre/ptlrpc/sec_plain.c +++ b/drivers/staging/lustre/lustre/ptlrpc/sec_plain.c @@ -574,8 +574,12 @@ int plain_alloc_reqbuf(struct ptlrpc_sec *sec, lustre_init_msg_v2(req->rq_reqbuf, PLAIN_PACK_SEGMENTS, buflens, NULL); req->rq_reqmsg = lustre_msg_buf(req->rq_reqbuf, PLAIN_PACK_MSG_OFF, 0); - if (req->rq_pack_udesc) - sptlrpc_pack_user_desc(req->rq_reqbuf, PLAIN_PACK_USER_OFF); + if (req->rq_pack_udesc) { + int rc = sptlrpc_pack_user_desc(req->rq_reqbuf, + PLAIN_PACK_USER_OFF); + if (rc < 0) + return rc; + } return 0; } -- cgit v0.10.2 From c6c7a17010697377df1241a2914e3c1e5582e234 Mon Sep 17 00:00:00 2001 From: Tobin C Harding Date: Mon, 23 May 2016 10:14:22 +1000 Subject: staging: lustre: llite: kzalloc/copy_to_user to memdup_user kzalloc call followed by copy_to_user can be replaced by call to memdup_user. Signed-off-by: Tobin C Harding Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/lustre/lustre/llite/dir.c b/drivers/staging/lustre/lustre/llite/dir.c index 4b00d1a..85c50e0 100644 --- a/drivers/staging/lustre/lustre/llite/dir.c +++ b/drivers/staging/lustre/lustre/llite/dir.c @@ -1076,17 +1076,11 @@ static int copy_and_ioctl(int cmd, struct obd_export *exp, void *copy; int rc; - copy = kzalloc(size, GFP_NOFS); - if (!copy) - return -ENOMEM; - - if (copy_from_user(copy, data, size)) { - rc = -EFAULT; - goto out; - } + copy = memdup_user(data, size); + if (IS_ERR(copy)) + return PTR_ERR(copy); rc = obd_iocontrol(cmd, exp, size, copy, NULL); -out: kfree(copy); return rc; -- cgit v0.10.2 From b788dc51e4255b700f566a5d63a9c5028d631c77 Mon Sep 17 00:00:00 2001 From: James Simmons Date: Mon, 23 May 2016 20:35:08 -0400 Subject: staging: lustre: llite: drop acl from cache Commit b8a7a3a6 change get_acl() for posix xattr to always cache the ACL which increases the reference count. That reference count can be reduced by have ll_get_acl() call forget_cached_acl() which it wasn't. When an inode gets deleted by Lustre the POSIX ACL reference count is tested to ensure its 1 and if not produces an error. Since forget_cached_acl() was not called Lustre started to complain. This patch changes ll_get_acl() to call forget_cached_acl(). Signed-off-by: James Simmons Reviewed-by: Andreas Gruenbacher Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/lustre/lustre/llite/file.c b/drivers/staging/lustre/lustre/llite/file.c index f47f2ac..0191945 100644 --- a/drivers/staging/lustre/lustre/llite/file.c +++ b/drivers/staging/lustre/lustre/llite/file.c @@ -3124,6 +3124,7 @@ struct posix_acl *ll_get_acl(struct inode *inode, int type) spin_lock(&lli->lli_lock); /* VFS' acl_permission_check->check_acl will release the refcount */ acl = posix_acl_dup(lli->lli_posix_acl); + forget_cached_acl(inode, type); spin_unlock(&lli->lli_lock); return acl; -- cgit v0.10.2 From ecd4df4a7a3e4e2c58ce39abb0654b2c3cd1a3c6 Mon Sep 17 00:00:00 2001 From: Jinshan Xiong Date: Sun, 5 Jun 2016 23:28:50 -0400 Subject: staging/lustre/lov: calculate file offset correctly In lov_stripe_pgoff(), it calls lov_stripe_size() to calculate the file size by ost_size, which will be wrong if the stripe_index happens to be stripe aligned. Signed-off-by: Jinshan Xiong Reviewed-on: http://review.whamcloud.com/14462 Intel-bug-id: https://jira.hpdd.intel.com/browse/LU-6482 Reviewed-by: Bobi Jam Reviewed-by: Andreas Dilger Signed-off-by: Oleg Drokin Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/lustre/lustre/lov/lov_offset.c b/drivers/staging/lustre/lustre/lov/lov_offset.c index 9302f06..7636bfa 100644 --- a/drivers/staging/lustre/lustre/lov/lov_offset.c +++ b/drivers/staging/lustre/lustre/lov/lov_offset.c @@ -74,7 +74,7 @@ pgoff_t lov_stripe_pgoff(struct lov_stripe_md *lsm, pgoff_t stripe_index, { loff_t offset; - offset = lov_stripe_size(lsm, stripe_index << PAGE_SHIFT, stripe); + offset = lov_stripe_size(lsm, (stripe_index << PAGE_SHIFT) + 1, stripe); return offset >> PAGE_SHIFT; } -- cgit v0.10.2 From 966c4a8f8029a595a5e1840d51309ac417bb4234 Mon Sep 17 00:00:00 2001 From: Jinshan Xiong Date: Sun, 5 Jun 2016 23:28:51 -0400 Subject: staging/lustre/llite: define per open file cache for ll_cl_context In ll_readpage and ll_write_begin, it needs to find out the cl_env and cl_io, a.k.a ll_cl_context, when the IO is initialized. It used to call cl_env_get() to figure it out but turned out to be contended if multiple threads are doing IO. In this patch, a per open file ll_cl_context cache is created. When IO type of CIT_READ, CIT_WRITE and CIR_FAULT is initialized, it will add a ll_cl_context into the cache maintained in ll_file_data. In this case, the ll_cl_context can be found in ll_readpage and ll_write_begin later. Signed-off-by: Jinshan Xiong Reviewed-on: http://review.whamcloud.com/10503 Intel-bug-id: https://jira.hpdd.intel.com/browse/LU-5108 Reviewed-on: http://review.whamcloud.com/10955 Intel-bug-id: https://jira.hpdd.intel.com/browse/LU-5260 Reviewed-by: Lai Siyao Reviewed-by: Bobi Jam Signed-off-by: Oleg Drokin Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/lustre/lustre/llite/file.c b/drivers/staging/lustre/lustre/llite/file.c index 0191945..bafa0b7 100644 --- a/drivers/staging/lustre/lustre/llite/file.c +++ b/drivers/staging/lustre/lustre/llite/file.c @@ -519,6 +519,11 @@ static int ll_local_open(struct file *file, struct lookup_intent *it, LUSTRE_FPRIVATE(file) = fd; ll_readahead_init(inode, &fd->fd_ras); fd->fd_omode = it->it_flags & (FMODE_READ | FMODE_WRITE | FMODE_EXEC); + + /* ll_cl_context initialize */ + rwlock_init(&fd->fd_lock); + INIT_LIST_HEAD(&fd->fd_lccs); + return 0; } @@ -1178,7 +1183,9 @@ restart: CERROR("Unknown IO type - %u\n", vio->vui_io_subtype); LBUG(); } + ll_cl_add(file, env, io); result = cl_io_loop(env, io); + ll_cl_remove(file, env); if (args->via_io_subtype == IO_NORMAL) up_read(&lli->lli_trunc_sem); if (write_mutex_locked) diff --git a/drivers/staging/lustre/lustre/llite/llite_internal.h b/drivers/staging/lustre/lustre/llite/llite_internal.h index 3f2f30b..7fb949a 100644 --- a/drivers/staging/lustre/lustre/llite/llite_internal.h +++ b/drivers/staging/lustre/lustre/llite/llite_internal.h @@ -640,6 +640,8 @@ struct ll_file_data { * false: unknown failure, should report. */ bool fd_write_failed; + rwlock_t fd_lock; /* protect lcc list */ + struct list_head fd_lccs; /* list of ll_cl_context */ }; struct lov_stripe_md; @@ -715,8 +717,9 @@ void ll_readahead_init(struct inode *inode, struct ll_readahead_state *ras); int ll_readahead(const struct lu_env *env, struct cl_io *io, struct cl_page_list *queue, struct ll_readahead_state *ras, bool hit); -struct ll_cl_context *ll_cl_init(struct file *file, struct page *vmpage); -void ll_cl_fini(struct ll_cl_context *lcc); +struct ll_cl_context *ll_cl_find(struct file *file); +void ll_cl_add(struct file *file, const struct lu_env *env, struct cl_io *io); +void ll_cl_remove(struct file *file, const struct lu_env *env); extern const struct address_space_operations ll_aops; @@ -858,11 +861,11 @@ struct vvp_io_args { }; struct ll_cl_context { + struct list_head lcc_list; void *lcc_cookie; + const struct lu_env *lcc_env; struct cl_io *lcc_io; struct cl_page *lcc_page; - struct lu_env *lcc_env; - int lcc_refcheck; }; struct ll_thread_info { diff --git a/drivers/staging/lustre/lustre/llite/llite_mmap.c b/drivers/staging/lustre/lustre/llite/llite_mmap.c index 88ef1ca..7610799 100644 --- a/drivers/staging/lustre/lustre/llite/llite_mmap.c +++ b/drivers/staging/lustre/lustre/llite/llite_mmap.c @@ -315,8 +315,13 @@ static int ll_fault0(struct vm_area_struct *vma, struct vm_fault *vmf) vio->u.fault.ft_flags = 0; vio->u.fault.ft_flags_valid = false; + /* May call ll_readpage() */ + ll_cl_add(vma->vm_file, env, io); + result = cl_io_loop(env, io); + ll_cl_remove(vma->vm_file, env); + /* ft_flags are only valid if we reached * the call to filemap_fault */ diff --git a/drivers/staging/lustre/lustre/llite/rw.c b/drivers/staging/lustre/lustre/llite/rw.c index 3363977..fa42869 100644 --- a/drivers/staging/lustre/lustre/llite/rw.c +++ b/drivers/staging/lustre/lustre/llite/rw.c @@ -59,84 +59,6 @@ #include "llite_internal.h" #include "../include/linux/lustre_compat25.h" -/** - * Finalizes cl-data before exiting typical address_space operation. Dual to - * ll_cl_init(). - */ -void ll_cl_fini(struct ll_cl_context *lcc) -{ - struct lu_env *env = lcc->lcc_env; - struct cl_io *io = lcc->lcc_io; - struct cl_page *page = lcc->lcc_page; - - LASSERT(lcc->lcc_cookie == current); - LASSERT(env); - - if (page) { - lu_ref_del(&page->cp_reference, "cl_io", io); - cl_page_put(env, page); - } - - cl_env_put(env, &lcc->lcc_refcheck); -} - -/** - * Initializes common cl-data at the typical address_space operation entry - * point. - */ -struct ll_cl_context *ll_cl_init(struct file *file, struct page *vmpage) -{ - struct ll_cl_context *lcc; - struct lu_env *env; - struct cl_io *io; - struct cl_object *clob; - struct vvp_io *vio; - - int refcheck; - int result = 0; - - clob = ll_i2info(file_inode(file))->lli_clob; - LASSERT(clob); - - env = cl_env_get(&refcheck); - if (IS_ERR(env)) - return ERR_CAST(env); - - lcc = &ll_env_info(env)->lti_io_ctx; - memset(lcc, 0, sizeof(*lcc)); - lcc->lcc_env = env; - lcc->lcc_refcheck = refcheck; - lcc->lcc_cookie = current; - - vio = vvp_env_io(env); - io = vio->vui_cl.cis_io; - lcc->lcc_io = io; - if (!io) - result = -EIO; - - if (result == 0 && vmpage) { - struct cl_page *page; - - LASSERT(io->ci_state == CIS_IO_GOING); - LASSERT(vio->vui_fd == LUSTRE_FPRIVATE(file)); - page = cl_page_find(env, clob, vmpage->index, vmpage, - CPT_CACHEABLE); - if (!IS_ERR(page)) { - lcc->lcc_page = page; - lu_ref_add(&page->cp_reference, "cl_io", io); - result = 0; - } else { - result = PTR_ERR(page); - } - } - if (result) { - ll_cl_fini(lcc); - lcc = ERR_PTR(result); - } - - return lcc; -} - static void ll_ra_stats_inc_sbi(struct ll_sb_info *sbi, enum ra_stat which); /** @@ -1112,17 +1034,70 @@ int ll_writepages(struct address_space *mapping, struct writeback_control *wbc) return result; } +struct ll_cl_context *ll_cl_find(struct file *file) +{ + struct ll_file_data *fd = LUSTRE_FPRIVATE(file); + struct ll_cl_context *lcc; + struct ll_cl_context *found = NULL; + + read_lock(&fd->fd_lock); + list_for_each_entry(lcc, &fd->fd_lccs, lcc_list) { + if (lcc->lcc_cookie == current) { + found = lcc; + break; + } + } + read_unlock(&fd->fd_lock); + + return found; +} + +void ll_cl_add(struct file *file, const struct lu_env *env, struct cl_io *io) +{ + struct ll_file_data *fd = LUSTRE_FPRIVATE(file); + struct ll_cl_context *lcc = &ll_env_info(env)->lti_io_ctx; + + memset(lcc, 0, sizeof(*lcc)); + INIT_LIST_HEAD(&lcc->lcc_list); + lcc->lcc_cookie = current; + lcc->lcc_env = env; + lcc->lcc_io = io; + + write_lock(&fd->fd_lock); + list_add(&lcc->lcc_list, &fd->fd_lccs); + write_unlock(&fd->fd_lock); +} + +void ll_cl_remove(struct file *file, const struct lu_env *env) +{ + struct ll_file_data *fd = LUSTRE_FPRIVATE(file); + struct ll_cl_context *lcc = &ll_env_info(env)->lti_io_ctx; + + write_lock(&fd->fd_lock); + list_del_init(&lcc->lcc_list); + write_unlock(&fd->fd_lock); +} + int ll_readpage(struct file *file, struct page *vmpage) { + struct cl_object *clob = ll_i2info(file_inode(file))->lli_clob; struct ll_cl_context *lcc; + const struct lu_env *env; + struct cl_io *io; + struct cl_page *page; int result; - lcc = ll_cl_init(file, vmpage); - if (!IS_ERR(lcc)) { - struct lu_env *env = lcc->lcc_env; - struct cl_io *io = lcc->lcc_io; - struct cl_page *page = lcc->lcc_page; + lcc = ll_cl_find(file); + if (!lcc) { + unlock_page(vmpage); + return -EIO; + } + env = lcc->lcc_env; + io = lcc->lcc_io; + LASSERT(io->ci_state == CIS_IO_GOING); + page = cl_page_find(env, clob, vmpage->index, vmpage, CPT_CACHEABLE); + if (!IS_ERR(page)) { LASSERT(page->cp_type == CPT_CACHEABLE); if (likely(!PageUptodate(vmpage))) { cl_page_assume(env, io, page); @@ -1132,10 +1107,10 @@ int ll_readpage(struct file *file, struct page *vmpage) unlock_page(vmpage); result = 0; } - ll_cl_fini(lcc); + cl_page_put(env, page); } else { unlock_page(vmpage); - result = PTR_ERR(lcc); + result = PTR_ERR(page); } return result; } diff --git a/drivers/staging/lustre/lustre/llite/rw26.c b/drivers/staging/lustre/lustre/llite/rw26.c index c12a048..947a4f5 100644 --- a/drivers/staging/lustre/lustre/llite/rw26.c +++ b/drivers/staging/lustre/lustre/llite/rw26.c @@ -489,7 +489,7 @@ static int ll_write_begin(struct file *file, struct address_space *mapping, struct page **pagep, void **fsdata) { struct ll_cl_context *lcc; - struct lu_env *env; + const struct lu_env *env; struct cl_io *io; struct cl_page *page; struct cl_object *clob = ll_i2info(mapping->host)->lli_clob; @@ -501,9 +501,9 @@ static int ll_write_begin(struct file *file, struct address_space *mapping, CDEBUG(D_VFSTRACE, "Writing %lu of %d to %d bytes\n", index, from, len); - lcc = ll_cl_init(file, NULL); - if (IS_ERR(lcc)) { - result = PTR_ERR(lcc); + lcc = ll_cl_find(file); + if (!lcc) { + result = -EIO; goto out; } @@ -579,8 +579,6 @@ out: unlock_page(vmpage); put_page(vmpage); } - if (!IS_ERR(lcc)) - ll_cl_fini(lcc); } else { *pagep = vmpage; *fsdata = lcc; @@ -593,7 +591,7 @@ static int ll_write_end(struct file *file, struct address_space *mapping, struct page *vmpage, void *fsdata) { struct ll_cl_context *lcc = fsdata; - struct lu_env *env; + const struct lu_env *env; struct cl_io *io; struct vvp_io *vio; struct cl_page *page; @@ -631,6 +629,10 @@ static int ll_write_end(struct file *file, struct address_space *mapping, } else { cl_page_disown(env, io, page); + lcc->lcc_page = NULL; + lu_ref_del(&page->cp_reference, "cl_io", io); + cl_page_put(env, page); + /* page list is not contiguous now, commit it now */ unplug = true; } @@ -639,7 +641,6 @@ static int ll_write_end(struct file *file, struct address_space *mapping, file->f_flags & O_SYNC || IS_SYNC(file_inode(file))) result = vvp_io_write_commit(env, io); - ll_cl_fini(lcc); return result >= 0 ? copied : result; } -- cgit v0.10.2 From d4722fccbe78c2b45a0a534d8944247592eaefe7 Mon Sep 17 00:00:00 2001 From: Oleg Drokin Date: Sun, 5 Jun 2016 23:28:52 -0400 Subject: staging/lustre/osc: Remove ops_temp from osc_page It's no longer used and never set anywhere. Signed-off-by: Oleg Drokin Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/lustre/lustre/osc/osc_cl_internal.h b/drivers/staging/lustre/lustre/osc/osc_cl_internal.h index ae19d39..7359fcb 100644 --- a/drivers/staging/lustre/lustre/osc/osc_cl_internal.h +++ b/drivers/staging/lustre/lustre/osc/osc_cl_internal.h @@ -356,11 +356,6 @@ struct osc_page { */ unsigned ops_transfer_pinned:1, /** - * True for a `temporary page' created by read-ahead code, probably - * outside of any DLM lock. - */ - ops_temp:1, - /** * in LRU? */ ops_in_lru:1, diff --git a/drivers/staging/lustre/lustre/osc/osc_page.c b/drivers/staging/lustre/lustre/osc/osc_page.c index c29c2ea..fc36743 100644 --- a/drivers/staging/lustre/lustre/osc/osc_page.c +++ b/drivers/staging/lustre/lustre/osc/osc_page.c @@ -214,7 +214,7 @@ static void osc_page_delete(const struct lu_env *env, struct osc_object *obj = cl2osc(opg->ops_cl.cpl_obj); int rc; - LINVRNT(opg->ops_temp || osc_page_protected(env, opg, CLM_READ, 1)); + LINVRNT(osc_page_protected(env, opg, CLM_READ, 1)); CDEBUG(D_TRACE, "%p\n", opg); osc_page_transfer_put(env, opg); -- cgit v0.10.2 From d484ed6f10997bb7a89dc7a71d2bf2614053640a Mon Sep 17 00:00:00 2001 From: Oleg Drokin Date: Sun, 5 Jun 2016 23:28:53 -0400 Subject: staging/lustre/osc: Get rid of osc_page_protected() There was a proper debugging function by that name that's long gone. The currently remaining shadow that always returns true is not really useful so it could be dropped along with all the asserts it is part of. Signed-off-by: Oleg Drokin Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/lustre/lustre/osc/osc_page.c b/drivers/staging/lustre/lustre/osc/osc_page.c index fc36743..5a3e694 100644 --- a/drivers/staging/lustre/lustre/osc/osc_page.c +++ b/drivers/staging/lustre/lustre/osc/osc_page.c @@ -52,13 +52,6 @@ static int osc_lru_reserve(const struct lu_env *env, struct osc_object *obj, * @{ */ -static int osc_page_protected(const struct lu_env *env, - const struct osc_page *opg, - enum cl_lock_mode mode, int unref) -{ - return 1; -} - /***************************************************************************** * * Page operations. @@ -110,8 +103,6 @@ int osc_page_cache_add(const struct lu_env *env, struct osc_page *opg = cl2osc_page(slice); int result; - LINVRNT(osc_page_protected(env, opg, CLM_WRITE, 0)); - osc_page_transfer_get(opg, "transfer\0cache"); result = osc_queue_async_io(env, io, opg); if (result != 0) @@ -214,8 +205,6 @@ static void osc_page_delete(const struct lu_env *env, struct osc_object *obj = cl2osc(opg->ops_cl.cpl_obj); int rc; - LINVRNT(osc_page_protected(env, opg, CLM_READ, 1)); - CDEBUG(D_TRACE, "%p\n", opg); osc_page_transfer_put(env, opg); rc = osc_teardown_async_page(env, obj, opg); @@ -254,8 +243,6 @@ static void osc_page_clip(const struct lu_env *env, struct osc_page *opg = cl2osc_page(slice); struct osc_async_page *oap = &opg->ops_oap; - LINVRNT(osc_page_protected(env, opg, CLM_READ, 0)); - opg->ops_from = from; opg->ops_to = to; spin_lock(&oap->oap_lock); @@ -269,8 +256,6 @@ static int osc_page_cancel(const struct lu_env *env, struct osc_page *opg = cl2osc_page(slice); int rc = 0; - LINVRNT(osc_page_protected(env, opg, CLM_READ, 0)); - /* Check if the transferring against this page * is completed, or not even queued. */ @@ -320,10 +305,6 @@ int osc_page_init(const struct lu_env *env, struct cl_object *obj, cl_page_slice_add(page, &opg->ops_cl, obj, index, &osc_page_ops); } - /* - * Cannot assert osc_page_protected() here as read-ahead - * creates temporary pages outside of a lock. - */ /* ops_inflight and ops_lru are the same field, but it doesn't * hurt to initialize it twice :-) */ @@ -382,9 +363,6 @@ void osc_page_submit(const struct lu_env *env, struct osc_page *opg, struct osc_async_page *oap = &opg->ops_oap; struct osc_object *obj = oap->oap_obj; - LINVRNT(osc_page_protected(env, opg, - crt == CRT_WRITE ? CLM_WRITE : CLM_READ, 1)); - LASSERTF(oap->oap_magic == OAP_MAGIC, "Bad oap magic: oap %p, magic 0x%x\n", oap, oap->oap_magic); LASSERT(oap->oap_async_flags & ASYNC_READY); -- cgit v0.10.2 From e3c9078af85dceaa6cda2a573c4bf0be7d978bc4 Mon Sep 17 00:00:00 2001 From: Tobin C Harding Date: Mon, 23 May 2016 20:17:46 +1000 Subject: staging: lustre: set function scope with static A number of function definitions were found to be candidates for static scoping. This patch adds static to these functions. Signed-off-by: Tobin C Harding Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/lustre/lustre/llite/vvp_dev.c b/drivers/staging/lustre/lustre/llite/vvp_dev.c index 47101de..c63def9 100644 --- a/drivers/staging/lustre/lustre/llite/vvp_dev.c +++ b/drivers/staging/lustre/lustre/llite/vvp_dev.c @@ -150,8 +150,8 @@ struct lu_context_key vvp_session_key = { .lct_fini = vvp_session_key_fini }; -void *vvp_thread_key_init(const struct lu_context *ctx, - struct lu_context_key *key) +static void *vvp_thread_key_init(const struct lu_context *ctx, + struct lu_context_key *key) { struct vvp_thread_info *vti; @@ -161,8 +161,8 @@ void *vvp_thread_key_init(const struct lu_context *ctx, return vti; } -void vvp_thread_key_fini(const struct lu_context *ctx, - struct lu_context_key *key, void *data) +static void vvp_thread_key_fini(const struct lu_context *ctx, + struct lu_context_key *key, void *data) { struct vvp_thread_info *vti = data; diff --git a/drivers/staging/lustre/lustre/llite/vvp_io.c b/drivers/staging/lustre/lustre/llite/vvp_io.c index 5bf9592..e26e0f8 100644 --- a/drivers/staging/lustre/lustre/llite/vvp_io.c +++ b/drivers/staging/lustre/lustre/llite/vvp_io.c @@ -47,8 +47,8 @@ #include "llite_internal.h" #include "vvp_internal.h" -struct vvp_io *cl2vvp_io(const struct lu_env *env, - const struct cl_io_slice *slice) +static struct vvp_io *cl2vvp_io(const struct lu_env *env, + const struct cl_io_slice *slice) { struct vvp_io *vio; @@ -1259,7 +1259,7 @@ static int vvp_io_read_page(const struct lu_env *env, return 0; } -void vvp_io_end(const struct lu_env *env, const struct cl_io_slice *ios) +static void vvp_io_end(const struct lu_env *env, const struct cl_io_slice *ios) { CLOBINVRNT(env, ios->cis_io->ci_obj, vvp_object_invariant(ios->cis_io->ci_obj)); diff --git a/drivers/staging/lustre/lustre/llite/vvp_req.c b/drivers/staging/lustre/lustre/llite/vvp_req.c index fb88629..9fe9d6c 100644 --- a/drivers/staging/lustre/lustre/llite/vvp_req.c +++ b/drivers/staging/lustre/lustre/llite/vvp_req.c @@ -60,10 +60,10 @@ static inline struct vvp_req *cl2vvp_req(const struct cl_req_slice *slice) * - o_ioepoch, * */ -void vvp_req_attr_set(const struct lu_env *env, - const struct cl_req_slice *slice, - const struct cl_object *obj, - struct cl_req_attr *attr, u64 flags) +static void vvp_req_attr_set(const struct lu_env *env, + const struct cl_req_slice *slice, + const struct cl_object *obj, + struct cl_req_attr *attr, u64 flags) { struct inode *inode; struct obdo *oa; @@ -87,8 +87,8 @@ void vvp_req_attr_set(const struct lu_env *env, JOBSTATS_JOBID_SIZE); } -void vvp_req_completion(const struct lu_env *env, - const struct cl_req_slice *slice, int ioret) +static void vvp_req_completion(const struct lu_env *env, + const struct cl_req_slice *slice, int ioret) { struct vvp_req *vrq; diff --git a/drivers/staging/lustre/lustre/obdclass/obd_mount.c b/drivers/staging/lustre/lustre/obdclass/obd_mount.c index e0c90ad..bc4e1e4 100644 --- a/drivers/staging/lustre/lustre/obdclass/obd_mount.c +++ b/drivers/staging/lustre/lustre/obdclass/obd_mount.c @@ -192,7 +192,7 @@ static int lustre_start_simple(char *obdname, char *type, char *uuid, return rc; } -DEFINE_MUTEX(mgc_start_lock); +static DEFINE_MUTEX(mgc_start_lock); /** Set up a mgc obd to process startup logs * -- cgit v0.10.2 From 13a9930d15b424ab7d3b906af8ba7ff8c409edfe Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Tue, 31 May 2016 12:56:13 +0200 Subject: staging: ks7010: add driver from Nanonote extra-repository See the TODO for details where this driver came from. Only a few minor changes were made to make the driver suitable for staging: * updated Kconfig help text and dependencies * added TODO * removed two __DATE__ and __TIME__ printouts to allow reproducible builds * added to staging main Kconfig + Makefile Tested on a Renesas Salvator-X board with a Spectec SDW-823 card. I could connect to a WPA-protected network. Signed-off-by: Wolfram Sang Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig index 7c197d1..af94764 100644 --- a/drivers/staging/Kconfig +++ b/drivers/staging/Kconfig @@ -102,4 +102,6 @@ source "drivers/staging/most/Kconfig" source "drivers/staging/i4l/Kconfig" +source "drivers/staging/ks7010/Kconfig" + endif # STAGING diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile index a470c72..9f6009d 100644 --- a/drivers/staging/Makefile +++ b/drivers/staging/Makefile @@ -40,3 +40,4 @@ obj-$(CONFIG_FSL_MC_BUS) += fsl-mc/ obj-$(CONFIG_WILC1000) += wilc1000/ obj-$(CONFIG_MOST) += most/ obj-$(CONFIG_ISDN_I4L) += i4l/ +obj-$(CONFIG_KS7010) += ks7010/ diff --git a/drivers/staging/ks7010/Kconfig b/drivers/staging/ks7010/Kconfig new file mode 100644 index 0000000..dfd4eed --- /dev/null +++ b/drivers/staging/ks7010/Kconfig @@ -0,0 +1,9 @@ +config KS7010 + tristate "KeyStream KS7010 SDIO support" + depends on MMC && WIRELESS + select WIRELESS_EXT + select WEXT_PRIV + help + This is a driver for KeyStream KS7010 based SDIO WIFI cards. It is + found on at least later Spectec SDW-821 (FCC-ID "S2Y-WLAN-11G-K" only, + sadly not FCC-ID "S2Y-WLAN-11B-G") and Spectec SDW-823 microSD cards. diff --git a/drivers/staging/ks7010/Makefile b/drivers/staging/ks7010/Makefile new file mode 100644 index 0000000..68b7ebf --- /dev/null +++ b/drivers/staging/ks7010/Makefile @@ -0,0 +1,5 @@ +obj-$(CONFIG_KS7010) += ks7010.o + +ccflags-y += -D_SDIO_ -DKS_WLAN_DEBUG=0 +ks7010-y := michael_mic.o ks_hostif.o ks_wlan_net.o ks_debug.o \ + ks7010_sdio.o ks7010_config.o diff --git a/drivers/staging/ks7010/TODO b/drivers/staging/ks7010/TODO new file mode 100644 index 0000000..390e821 --- /dev/null +++ b/drivers/staging/ks7010/TODO @@ -0,0 +1,38 @@ +KS7010 Linux driver +=================== + +This driver is based on source code from the Ben Nanonote extra repository [1] +which is based on the original v007 release from Renesas [2]. Some more +background info about the chipset can be found here [3] and here [4]. Thank +you to all which already participated in cleaning up the driver so far! + +[1] http://projects.qi-hardware.com/index.php/p/openwrt-packages/source/tree/master/ks7010/src +[2] http://downloads.qi-hardware.com/software/ks7010_sdio_v007.tar.bz2 +[3] http://en.qi-hardware.com/wiki/Ben_NanoNote_Wi-Fi +[4] https://wikidevi.com/wiki/Renesas + +TODO +---- + +First a few words what not to do (at least not blindly): + +- don't be overly strict with the 80 char limit. Only if it REALLY makes the + code more readable +- No '#if 0/1' removal unless the surrounding code is understood and removal is + really OK. There might be some hints hidden there. + +Now the TODOs: + +- fix codechecker warnings (checkpatch, sparse, smatch). But PLEASE make sure + that you are not only silencing the warning but really fixing code. You + should understand the change you submit. +- drop using a config file and use an upstream technique for configuration +- fix the 'card removal' event when card is inserted when booting +- driver crashes when removing the card +- check what other upstream wireless mechanisms can be used instead of the + custom ones here + +Please send any patches to: +Greg Kroah-Hartman +Wolfram Sang +Linux Driver Project Developer List diff --git a/drivers/staging/ks7010/eap_packet.h b/drivers/staging/ks7010/eap_packet.h new file mode 100644 index 0000000..b664bdd --- /dev/null +++ b/drivers/staging/ks7010/eap_packet.h @@ -0,0 +1,136 @@ +/* + * + * eap_packet.h + * $Id: eap_packet.h 991 2009-09-14 01:38:58Z sekine $ + * + */ +#ifndef EAP_PACKET_H +#define EAP_PACKET_H + +#define WBIT(n) (1 << (n)) + +#ifndef ETH_ALEN +#define ETH_ALEN 6 +#endif + +struct ether_hdr { + unsigned char h_dest[ETH_ALEN]; /* destination eth addr */ + unsigned char h_source[ETH_ALEN]; /* source ether addr */ + unsigned char h_dest_snap; + unsigned char h_source_snap; + unsigned char h_command; + unsigned char h_vendor_id[3]; + unsigned short h_proto; /* packet type ID field */ +#define ETHER_PROTOCOL_TYPE_EAP 0x888e +#define ETHER_PROTOCOL_TYPE_IP 0x0800 +#define ETHER_PROTOCOL_TYPE_ARP 0x0806 + /* followed by length octets of data */ +} __attribute__ ((packed)); + +struct ieee802_1x_hdr { + unsigned char version; + unsigned char type; + unsigned short length; + /* followed by length octets of data */ +} __attribute__ ((packed)); + +#define EAPOL_VERSION 2 + +enum { IEEE802_1X_TYPE_EAP_PACKET = 0, + IEEE802_1X_TYPE_EAPOL_START = 1, + IEEE802_1X_TYPE_EAPOL_LOGOFF = 2, + IEEE802_1X_TYPE_EAPOL_KEY = 3, + IEEE802_1X_TYPE_EAPOL_ENCAPSULATED_ASF_ALERT = 4 +}; + +enum { EAPOL_KEY_TYPE_RC4 = 1, EAPOL_KEY_TYPE_RSN = 2, + EAPOL_KEY_TYPE_WPA = 254 }; + + +#define IEEE8021X_REPLAY_COUNTER_LEN 8 +#define IEEE8021X_KEY_SIGN_LEN 16 +#define IEEE8021X_KEY_IV_LEN 16 + +#define IEEE8021X_KEY_INDEX_FLAG 0x80 +#define IEEE8021X_KEY_INDEX_MASK 0x03 + +struct ieee802_1x_eapol_key { + unsigned char type; + unsigned short key_length; + /* does not repeat within the life of the keying material used to + * encrypt the Key field; 64-bit NTP timestamp MAY be used here */ + unsigned char replay_counter[IEEE8021X_REPLAY_COUNTER_LEN]; + unsigned char key_iv[IEEE8021X_KEY_IV_LEN]; /* cryptographically random number */ + unsigned char key_index; /* key flag in the most significant bit: + * 0 = broadcast (default key), + * 1 = unicast (key mapping key); key index is in the + * 7 least significant bits */ + /* HMAC-MD5 message integrity check computed with MS-MPPE-Send-Key as + * the key */ + unsigned char key_signature[IEEE8021X_KEY_SIGN_LEN]; + + /* followed by key: if packet body length = 44 + key length, then the + * key field (of key_length bytes) contains the key in encrypted form; + * if packet body length = 44, key field is absent and key_length + * represents the number of least significant octets from + * MS-MPPE-Send-Key attribute to be used as the keying material; + * RC4 key used in encryption = Key-IV + MS-MPPE-Recv-Key */ +} __attribute__ ((packed)); + + +#define WPA_NONCE_LEN 32 +#define WPA_REPLAY_COUNTER_LEN 8 + +struct wpa_eapol_key { + unsigned char type; + unsigned short key_info; + unsigned short key_length; + unsigned char replay_counter[WPA_REPLAY_COUNTER_LEN]; + unsigned char key_nonce[WPA_NONCE_LEN]; + unsigned char key_iv[16]; + unsigned char key_rsc[8]; + unsigned char key_id[8]; /* Reserved in IEEE 802.11i/RSN */ + unsigned char key_mic[16]; + unsigned short key_data_length; + /* followed by key_data_length bytes of key_data */ +} __attribute__ ((packed)); + +#define WPA_KEY_INFO_TYPE_MASK (WBIT(0) | WBIT(1) | WBIT(2)) +#define WPA_KEY_INFO_TYPE_HMAC_MD5_RC4 WBIT(0) +#define WPA_KEY_INFO_TYPE_HMAC_SHA1_AES WBIT(1) +#define WPA_KEY_INFO_KEY_TYPE WBIT(3) /* 1 = Pairwise, 0 = Group key */ +/* bit4..5 is used in WPA, but is reserved in IEEE 802.11i/RSN */ +#define WPA_KEY_INFO_KEY_INDEX_MASK (WBIT(4) | WBIT(5)) +#define WPA_KEY_INFO_KEY_INDEX_SHIFT 4 +#define WPA_KEY_INFO_INSTALL WBIT(6) /* pairwise */ +#define WPA_KEY_INFO_TXRX WBIT(6) /* group */ +#define WPA_KEY_INFO_ACK WBIT(7) +#define WPA_KEY_INFO_MIC WBIT(8) +#define WPA_KEY_INFO_SECURE WBIT(9) +#define WPA_KEY_INFO_ERROR WBIT(10) +#define WPA_KEY_INFO_REQUEST WBIT(11) +#define WPA_KEY_INFO_ENCR_KEY_DATA WBIT(12) /* IEEE 802.11i/RSN only */ + +#define WPA_CAPABILITY_PREAUTH WBIT(0) + +#define GENERIC_INFO_ELEM 0xdd +#define RSN_INFO_ELEM 0x30 + +enum { + REASON_UNSPECIFIED = 1, + REASON_DEAUTH_LEAVING = 3, + REASON_INVALID_IE = 13, + REASON_MICHAEL_MIC_FAILURE = 14, + REASON_4WAY_HANDSHAKE_TIMEOUT = 15, + REASON_GROUP_KEY_UPDATE_TIMEOUT = 16, + REASON_IE_IN_4WAY_DIFFERS = 17, + REASON_GROUP_CIPHER_NOT_VALID = 18, + REASON_PAIRWISE_CIPHER_NOT_VALID = 19, + REASON_AKMP_NOT_VALID = 20, + REASON_UNSUPPORTED_RSN_IE_VERSION = 21, + REASON_INVALID_RSN_IE_CAPAB = 22, + REASON_IEEE_802_1X_AUTH_FAILED = 23, + REASON_CIPHER_SUITE_REJECTED = 24 +}; + +#endif /* EAP_PACKET_H */ diff --git a/drivers/staging/ks7010/ks7010_config.c b/drivers/staging/ks7010/ks7010_config.c new file mode 100644 index 0000000..4a80984 --- /dev/null +++ b/drivers/staging/ks7010/ks7010_config.c @@ -0,0 +1,556 @@ +#include +#include + +#include "ks_wlan.h" +#include "ks_hostif.h" +#include "ks_wlan_ioctl.h" +#include "ks_debug.h" + +static int wep_on_off; +#define WEP_OFF 0 +#define WEP_ON_64BIT 1 +#define WEP_ON_128BIT 2 + +static int wep_type; +#define WEP_KEY_CHARACTER 0 +#define WEP_KEY_HEX 1 + +static +void analyze_character_wep_key(struct ks_wlan_parameter *param, int wep_key_index, char *value) +{ + int i; + unsigned char wep_key[26], key_length; + + key_length = (wep_on_off == WEP_ON_64BIT) ? 5 : 13; + /* 64bit key_length = 5; 128bit key_length = 13; */ + + for (i=0; i 3) + return; + + param->wep_key[wep_key_index].size = key_length; + for (i=0; i<(param->wep_key[wep_key_index].size); i++) { + param->wep_key[wep_key_index].val[i] = wep_key[i]; + } +} + +static +void analyze_hex_wep_key(struct ks_wlan_parameter *param, int wep_key_index, char *value) +{ + unsigned char wep_end[26], i, j, key_length; + + key_length = (wep_on_off == WEP_ON_64BIT) ? 10 : 26; + /* 64bit key_length = 10; 128bit key_length = 26; */ + + for (i=0; i 3) + return ; + + param->wep_key[wep_key_index].size = key_length/2; + for (i=0; i<(param->wep_key[wep_key_index].size); i++) { + param->wep_key[wep_key_index].val[i] = wep_end[i]; + } + +} + +static +int rate_set_configuration(ks_wlan_private *priv, char *value) +{ + int rc=0; + + priv->reg.tx_rate = TX_RATE_FIXED; + priv->reg.rate_set.size = 1; + + switch(*value){ + case '1': /* 1M 11M 12M 18M */ + if(*(value+1) == '8'){ + priv->reg.rate_set.body[0] = TX_RATE_18M; + } + else if(*(value+1) == '2'){ + priv->reg.rate_set.body[0] = TX_RATE_12M|BASIC_RATE; + } + else if(*(value+1) == '1'){ + priv->reg.rate_set.body[0] = TX_RATE_11M|BASIC_RATE; + } + else{ + priv->reg.rate_set.body[0] = TX_RATE_1M|BASIC_RATE; + } + break; + case '2': /* 2M 24M */ + if(*(value+1) == '4'){ + priv->reg.rate_set.body[0] = TX_RATE_24M|BASIC_RATE; + } + else{ + priv->reg.rate_set.body[0] = TX_RATE_2M|BASIC_RATE; + } + break; + case '3': /* 36M */ + priv->reg.rate_set.body[0] = TX_RATE_36M; + break; + case '4': /* 48M */ + priv->reg.rate_set.body[0] = TX_RATE_48M; + break; + case '5': /* 5.5M 54M */ + if(*(value+1) == '4'){ + priv->reg.rate_set.body[0] = TX_RATE_54M; + } + else{ + priv->reg.rate_set.body[0] = TX_RATE_5M|BASIC_RATE; + } + break; + case '6': /* 6M */ + priv->reg.rate_set.body[0] = TX_RATE_6M|BASIC_RATE; + break; + case '9': /* 9M */ + priv->reg.rate_set.body[0] = TX_RATE_9M; + break; + case 'K': + priv->reg.rate_set.body[6] = TX_RATE_36M; + priv->reg.rate_set.body[5] = TX_RATE_18M; + priv->reg.rate_set.body[4] = TX_RATE_24M|BASIC_RATE; + priv->reg.rate_set.body[3] = TX_RATE_12M|BASIC_RATE; + priv->reg.rate_set.body[2] = TX_RATE_6M|BASIC_RATE; + priv->reg.rate_set.body[1] = TX_RATE_11M|BASIC_RATE; + priv->reg.rate_set.body[0] = TX_RATE_2M|BASIC_RATE; + priv->reg.tx_rate = TX_RATE_FULL_AUTO; + priv->reg.rate_set.size = 7; + break; + default: + priv->reg.rate_set.body[11] = TX_RATE_54M; + priv->reg.rate_set.body[10] = TX_RATE_48M; + priv->reg.rate_set.body[9] = TX_RATE_36M; + priv->reg.rate_set.body[8] = TX_RATE_18M; + priv->reg.rate_set.body[7] = TX_RATE_9M; + priv->reg.rate_set.body[6] = TX_RATE_24M|BASIC_RATE; + priv->reg.rate_set.body[5] = TX_RATE_12M|BASIC_RATE; + priv->reg.rate_set.body[4] = TX_RATE_6M|BASIC_RATE; + priv->reg.rate_set.body[3] = TX_RATE_11M|BASIC_RATE; + priv->reg.rate_set.body[2] = TX_RATE_5M|BASIC_RATE; + priv->reg.rate_set.body[1] = TX_RATE_2M|BASIC_RATE; + priv->reg.rate_set.body[0] = TX_RATE_1M|BASIC_RATE; + priv->reg.tx_rate = TX_RATE_FULL_AUTO; + priv->reg.rate_set.size = 12; + break; + } + return rc; +} + +#ifndef NO_FIRMWARE_CLASS +#include +#else +#define MAX_CONFIG_FILE_SIZE (1024*10) +#endif +int ks_wlan_read_config_file(ks_wlan_private *priv) +{ + struct { + const int key_len; + const char *key; + const char *val; + } cfg_tbl[] = { + {15,"BeaconLostCount", "20"}, /* 0 */ + {7,"Channel", "1"}, /* 1 */ + {17,"FragmentThreshold","2346"}, /* 2 */ + {13,"OperationMode","Infrastructure"}, /* 3 */ + {19,"PowerManagementMode","ACTIVE"}, /* 4 */ + {12,"RTSThreshold","2347"}, /* 5 */ + {4,"SSID","default"}, /* 6 */ + {6,"TxRate","Auto"}, /* 7 */ + {23,"AuthenticationAlgorithm",""}, /* 8 */ + {12,"WepKeyValue1",""}, /* 9 */ + {12,"WepKeyValue2",""}, /* 10 */ + {12,"WepKeyValue3",""}, /* 11 */ + {12,"WepKeyValue4",""}, /* 12 */ + {8,"WepIndex","1"}, /* 13 */ + {7,"WepType","STRING"}, /* 14 */ + {3,"Wep","OFF"}, /* 15 */ + {13,"PREAMBLE_TYPE","SHORT"}, /* 16 */ + {8,"ScanType","ACTIVE_SCAN"}, /* 17 */ + {8,"ROM_FILE", ROM_FILE}, /* 18 */ + {7,"PhyType", "BG_MODE"}, /* 19 */ + {7,"CtsMode", "FALSE"}, /* 20 */ + {19,"PhyInformationTimer", "0"}, /* 21 */ + {0,"",""}, + }; + +#ifndef NO_FIRMWARE_CLASS + const struct firmware *fw_entry; + struct device *dev = NULL; + int retval; +#else + struct file *srcf; + int nr_read ; + int retval; + char *cfg_buf=NULL; + int orgfsuid, orgfsgid; + mm_segment_t orgfs; +#endif + char cfg_file[]=CFG_FILE; + char *cur_p, *end_p; + char wk_buff[256], *wk_p; + + /* Initialize Variable */ + priv->reg.operation_mode = MODE_INFRASTRUCTURE; /* Infrastructure */ + priv->reg.channel = 10; /* 10 */ + memset(priv->reg.bssid, 0x0, ETH_ALEN); /* BSSID */ + priv->reg.ssid.body[0] = '\0'; /* SSID */ + priv->reg.ssid.size = 0; /* SSID size */ + priv->reg.tx_rate = TX_RATE_AUTO; /* TxRate Fully Auto */ + priv->reg.preamble = SHORT_PREAMBLE; /* Preamble = SHORT */ + priv->reg.powermgt = POWMGT_ACTIVE_MODE; /* POWMGT_ACTIVE_MODE */ + priv->reg.scan_type = ACTIVE_SCAN; /* Active */ + priv->reg.beacon_lost_count = 20; /* Beacon Lost Count */ + priv->reg.rts = 2347UL; /* RTS Threashold */ + priv->reg.fragment = 2346UL; /* Fragmentation Threashold */ + + strcpy(&priv->reg.rom_file[0], ROM_FILE); + + priv->skb = NULL; + + priv->reg.authenticate_type = AUTH_TYPE_OPEN_SYSTEM; /* AuthenticationAlgorithm */ + + priv->reg.privacy_invoked = 0x00; /* WEP */ + priv->reg.wep_index=0; + memset(&priv->reg.wep_key[0],0,sizeof(priv->reg.wep_key[0])); + memset(&priv->reg.wep_key[1],0,sizeof(priv->reg.wep_key[0])); + memset(&priv->reg.wep_key[2],0,sizeof(priv->reg.wep_key[0])); + memset(&priv->reg.wep_key[3],0,sizeof(priv->reg.wep_key[0])); + + priv->reg.phy_type = D_11BG_COMPATIBLE_MODE; + priv->reg.cts_mode = CTS_MODE_FALSE; + priv->reg.phy_info_timer = 0; + priv->reg.rate_set.body[11] = TX_RATE_54M; + priv->reg.rate_set.body[10] = TX_RATE_48M; + priv->reg.rate_set.body[9] = TX_RATE_36M; + priv->reg.rate_set.body[8] = TX_RATE_18M; + priv->reg.rate_set.body[7] = TX_RATE_9M; + priv->reg.rate_set.body[6] = TX_RATE_24M|BASIC_RATE; + priv->reg.rate_set.body[5] = TX_RATE_12M|BASIC_RATE; + priv->reg.rate_set.body[4] = TX_RATE_6M|BASIC_RATE; + priv->reg.rate_set.body[3] = TX_RATE_11M|BASIC_RATE; + priv->reg.rate_set.body[2] = TX_RATE_5M|BASIC_RATE; + priv->reg.rate_set.body[1] = TX_RATE_2M|BASIC_RATE; + priv->reg.rate_set.body[0] = TX_RATE_1M|BASIC_RATE; + priv->reg.tx_rate = TX_RATE_FULL_AUTO; + priv->reg.rate_set.size = 12; + +#ifndef NO_FIRMWARE_CLASS +#if (defined _PCMCIA_) + dev = &priv->ks_wlan_hw.pcmcia_dev->dev; +#elif (defined _PCI_) + dev = &priv->ks_wlan_hw.pci_dev->dev; +#elif (defined _SDIO_) + dev = &priv->ks_wlan_hw.sdio_card->func->dev; +#endif + if((retval = request_firmware(&fw_entry, cfg_file, dev)) !=0 ){ + DPRINTK(1, "error request_firmware() file=%s ret=%d\n", cfg_file, retval); + return 1; + } + + DPRINTK(4, "success request_firmware() file=%s size=%d\n", cfg_file, fw_entry->size); + cur_p = fw_entry->data; + end_p = cur_p + fw_entry->size; +#else + orgfsuid=current->fsuid; + orgfsgid=current->fsgid; + orgfs=get_fs(); + set_fs(KERNEL_DS); + + srcf = filp_open(cfg_file, O_RDONLY, 0); + if (IS_ERR(srcf)) { + printk(KERN_ERR "error %ld opening %s\n", -PTR_ERR(srcf),cfg_file); + goto no_config_file; + } + + if (!(srcf->f_op && srcf->f_op->read)) { + printk(KERN_ERR "%s does not have a read method\n", cfg_file); + goto no_config_file; + } + + cfg_buf = (char *)kzalloc(MAX_CONFIG_FILE_SIZE, GFP_ATOMIC); + if (!cfg_buf) { + printk(KERN_ERR "%s does not read : out of memory \n", cfg_file); + goto no_config_file; + } + + nr_read = srcf->f_op->read(srcf, (unsigned char *)cfg_buf, MAX_CONFIG_FILE_SIZE, &srcf->f_pos); + + DPRINTK(1, "read retval=%d file=%s\n", nr_read, priv->reg.cfg_file); + retval=filp_close(srcf ,NULL); + if (retval) + DPRINTK(1, "error %d closing %s\n", -retval,priv->reg.cfg_file); + + if (nr_read < 1) { + printk(KERN_ERR "%s does not read : file is empty num=%d\n", cfg_file, nr_read); + goto no_config_file; + }else if(nr_read > MAX_CONFIG_FILE_SIZE){ + printk(KERN_ERR "%s does not read : file is too big \n", cfg_file); + goto no_config_file; + } + cur_p = cfg_buf; + end_p = cur_p + nr_read; +#endif + *end_p = '\0'; + + while (cur_p < end_p) { + int i, j, len; + + len = end_p - cur_p; + for (i=0; cfg_tbl[i].key_len != 0; i++) { + if (*cur_p == '#') { + break; + } + if (len < cfg_tbl[i].key_len) { + continue; + } + if (!strncmp(cfg_tbl[i].key, cur_p, cfg_tbl[i].key_len)) { + break; + } + } + if ((*cur_p == '#') || (cfg_tbl[i].key_len == 0)) { + while (*cur_p != '\n') { + if (cur_p >= end_p) { + break; + } + cur_p++; + } + cur_p++; + } else { + cur_p += cfg_tbl[i].key_len; + if (*cur_p != '=') { + while (*cur_p != '\n') { + if (cur_p >= end_p) { + break; + } + cur_p++; + } + continue; + } + cur_p++; + + for (j=0,wk_p=cur_p; *wk_p != '\n' && wk_p < end_p; j++,wk_p++) { + wk_buff[j] = *wk_p; + } + wk_buff[j] = '\0'; + cur_p = wk_p; + DPRINTK(4,"%s=%s\n",cfg_tbl[i].key, wk_buff); + wk_p = wk_buff; + + switch (i) { + case 0: /* "BeaconLostCount", "10" */ + priv->reg.beacon_lost_count = simple_strtol(wk_buff, NULL, 10); + break; + case 1: /* "Channel", "1" */ + priv->reg.channel = simple_strtol(wk_buff, NULL, 10); + break; + case 2: /* "FragmentThreshold","2346" */ + j = simple_strtol(wk_buff, NULL, 10); + priv->reg.fragment = (unsigned long)j; + break; + case 3: /* "OperationMode","Infrastructure" */ + switch (*wk_buff) { + case 'P': + priv->reg.operation_mode = MODE_PSEUDO_ADHOC; + break; + case 'I': + priv->reg.operation_mode = MODE_INFRASTRUCTURE; + break; + case '8': + priv->reg.operation_mode = MODE_ADHOC; + break; + default: + priv->reg.operation_mode = MODE_INFRASTRUCTURE; + } + break; + case 4: /* "PowerManagementMode","POWER_ACTIVE" */ + if (!strncmp(wk_buff, "SAVE1", 5)) { + priv->reg.powermgt = POWMGT_SAVE1_MODE; + } else if (!strncmp(wk_buff, "SAVE2", 5)){ + priv->reg.powermgt = POWMGT_SAVE2_MODE; + } else { + priv->reg.powermgt = POWMGT_ACTIVE_MODE; + } + break; + case 5: /* "RTSThreshold","2347" */ + j = simple_strtol(wk_buff, NULL, 10); + priv->reg.rts = (unsigned long)j; + break; + case 6: /* "SSID","" */ + if (*wk_p != '"') + break; + wk_p++; + for (j=0; *wk_p != '"'; j++) { + if (wk_p == '\0') { + break; + } + priv->reg.ssid.body[j] = *wk_p++; + } + priv->reg.ssid.body[j] = '\0'; + priv->reg.ssid.size = j; + wk_p++; + break; + case 7: /* "TxRate","Auto" */ + rate_set_configuration(priv, wk_p); + break; + case 8: /* "AuthenticationAlgorithm","OPEN_SYSTEM" */ + switch (*wk_p) { + case 'O': /* Authenticate System : Open System */ + priv->reg.authenticate_type = AUTH_TYPE_OPEN_SYSTEM; + break; + case 'S': /* Authenticate System : Shared Key */ + priv->reg.authenticate_type = AUTH_TYPE_SHARED_KEY; + break; + } + break; + case 9: /* "WepKeyValue1","" */ + case 10: /* "WepKeyValue2","" */ + case 11: /* "WepKeyValue3","" */ + case 12: /* "WepKeyValue4","" */ + if (wep_on_off != WEP_OFF) { + switch (wep_type) { + case WEP_KEY_CHARACTER: + analyze_character_wep_key(&priv->reg, (i-9), wk_p); + break; + case WEP_KEY_HEX: + analyze_hex_wep_key(&priv->reg, (i-9), wk_p); + break; + } + } + break; + case 13: /* "WepIndex","1"->0 (So, Zero Origin) */ + priv->reg.wep_index = simple_strtol(wk_buff, NULL, 10) - 1; + break; + case 14: /* "WepType","STRING" */ + if (!strncmp(wk_buff, "STRING", 6)) { + wep_type = WEP_KEY_CHARACTER; + } else { + wep_type = WEP_KEY_HEX; + } + break; + case 15: /* "Wep","OFF" */ + if (!strncmp(wk_buff, "OFF", 3)) { + priv->reg.privacy_invoked = 0x00; + wep_on_off = WEP_OFF; + } else { /* 64bit or 128bit */ + priv->reg.privacy_invoked = 0x01; + if (*wk_buff == '6') { /* 64bit */ + wep_on_off = WEP_ON_64BIT; + } else { /* 128bit */ + wep_on_off = WEP_ON_128BIT; + } + } + break; + case 16: /* "PREAMBLE_TYPE","LONG" */ + if (!strncmp(wk_buff, "SHORT", 5)) { + priv->reg.preamble = SHORT_PREAMBLE; + } else { /* "LONG" */ + priv->reg.preamble = LONG_PREAMBLE; + } + break; + case 17: /* "ScanType","ACTIVE_SCAN" */ + if (!strncmp(wk_buff, "PASSIVE_SCAN", 12)) { + priv->reg.scan_type = PASSIVE_SCAN; + } else { /* "ACTIVE_SCAN" */ + priv->reg.scan_type = ACTIVE_SCAN; + } + break; + case 18: // "ROM_FILE",ROMFILE + if (*wk_p != '"') + break; + wk_p++; + for (j=0; *wk_p != '"'; j++) { + if (wk_p == '\0') { + break; + } + priv->reg.rom_file[j] = *wk_p++; + } + priv->reg.rom_file[j] = '\0'; + wk_p++; + break; + case 19: /*"PhyType", "BG_MODE" */ + if (!strncmp(wk_buff, "B_MODE", 6)) { + priv->reg.phy_type = D_11B_ONLY_MODE; + } else if (!strncmp(wk_buff, "G_MODE", 6)) { + priv->reg.phy_type = D_11G_ONLY_MODE; + } else { + priv->reg.phy_type = D_11BG_COMPATIBLE_MODE; + } + break; + case 20: /* "CtsMode", "FALSE" */ + if (!strncmp(wk_buff, "TRUE", 4)) { + priv->reg.cts_mode = CTS_MODE_TRUE; + } else { + priv->reg.cts_mode = CTS_MODE_FALSE; + } + break; + case 21: /* "PhyInformationTimer", "0" */ + j = simple_strtol(wk_buff, NULL, 10); + priv->reg.phy_info_timer = (uint16_t)j; + break; + default: + break; + } + if (cur_p >= end_p) { + break; + } + cur_p++; + } + + } +#ifndef NO_FIRMWARE_CLASS + release_firmware(fw_entry); +#else +no_config_file: + kfree(cfg_buf); + set_fs(orgfs); + current->fsuid=orgfsuid; + current->fsgid=orgfsgid; +#endif + + DPRINTK(3,"\n operation_mode = %d\n channel = %d\n ssid = %s\n tx_rate = %d\n \ + preamble = %d\n powermgt = %d\n scan_type = %d\n beacon_lost_count = %d\n rts = %d\n \ + fragment = %d\n privacy_invoked = %d\n wep_type = %d\n wep_on_off = %d\n wep_index = %d\n romfile = %s\n", + priv->reg.operation_mode,priv->reg.channel,&priv->reg.ssid.body[0],priv->reg.tx_rate, + priv->reg.preamble,priv->reg.powermgt,priv->reg.scan_type,priv->reg.beacon_lost_count, + priv->reg.rts,priv->reg.fragment,priv->reg.privacy_invoked,wep_type,wep_on_off,priv->reg.wep_index, + &priv->reg.rom_file[0] + ); + DPRINTK(3,"\n phy_type = %d\n cts_mode = %d\n tx_rate = %d\n phy_info_timer = %d\n", + priv->reg.phy_type,priv->reg.cts_mode,priv->reg.tx_rate,priv->reg.phy_info_timer ); + + return(0); +} + diff --git a/drivers/staging/ks7010/ks7010_sdio.c b/drivers/staging/ks7010/ks7010_sdio.c new file mode 100644 index 0000000..7cc49a4 --- /dev/null +++ b/drivers/staging/ks7010/ks7010_sdio.c @@ -0,0 +1,1263 @@ +/* + * Driver for KeyStream, KS7010 based SDIO cards. + * + * ks7010_sdio.c + * $Id: ks7010_sdio.c 996 2009-09-14 02:54:21Z sekine $ + * + * Copyright (C) 2006-2008 KeyStream Corp. + * Copyright (C) 2009 Renesas Technology Corp. + * + * This program is free software; you can redistribute it and/or modify + * it undr the terms of the GNU General Public License version 2 as + * published by the Free Sotware Foundation. + */ + +#include +#include +#include +#include + +#include "ks_wlan.h" +#include "ks_wlan_ioctl.h" +#include "ks_debug.h" +#include "ks_hostif.h" + +#include "ks7010_sdio.h" + +#define KS7010_FUNC_NUM 1 +#define KS7010_IO_BLOCK_SIZE 512 +#define KS7010_MAX_CLOCK 25000000 + +static int reg_net = 0; + +static const struct sdio_device_id if_sdio_ids[] = { + { SDIO_DEVICE(SDIO_VENDOR_ID_KS_CODE_A, SDIO_DEVICE_ID_KS_7010) }, + { SDIO_DEVICE(SDIO_VENDOR_ID_KS_CODE_B, SDIO_DEVICE_ID_KS_7010) }, + { /* all zero */ } +}; + +struct ks_sdio_model { + int model; + const char *firmware; +}; + +static struct ks_sdio_model ks_sdio_models[] = { + { + /* ks7010 */ + .model = 0x10, + .firmware = "ks7010sd.rom", + }, +}; + +static int ks7910_sdio_probe(struct sdio_func *function, const struct sdio_device_id *device); +static void ks7910_sdio_remove(struct sdio_func *function); +static void ks7010_rw_function(struct work_struct *work); +static int ks7010_sdio_read( ks_wlan_private *priv, unsigned int address, + unsigned char *buffer, int length ); +static int ks7010_sdio_write( ks_wlan_private *priv, unsigned int address, + unsigned char *buffer, int length ); +#ifdef NO_FIRMWARE_CLASS +static char *romfile = ROM_FILE; +module_param(romfile, charp, S_IRUGO); +#endif +/* macro */ + +#define inc_txqhead(priv) \ + ( priv->tx_dev.qhead = (priv->tx_dev.qhead + 1) % TX_DEVICE_BUFF_SIZE ) +#define inc_txqtail(priv) \ + ( priv->tx_dev.qtail = (priv->tx_dev.qtail + 1) % TX_DEVICE_BUFF_SIZE ) +#define cnt_txqbody(priv) \ + (((priv->tx_dev.qtail + TX_DEVICE_BUFF_SIZE) - (priv->tx_dev.qhead)) % TX_DEVICE_BUFF_SIZE ) + +#define inc_rxqhead(priv) \ + ( priv->rx_dev.qhead = (priv->rx_dev.qhead + 1) % RX_DEVICE_BUFF_SIZE ) +#define inc_rxqtail(priv) \ + ( priv->rx_dev.qtail = (priv->rx_dev.qtail + 1) % RX_DEVICE_BUFF_SIZE ) +#define cnt_rxqbody(priv) \ + (((priv->rx_dev.qtail + RX_DEVICE_BUFF_SIZE) - (priv->rx_dev.qhead)) % RX_DEVICE_BUFF_SIZE ) + +void ks_wlan_hw_sleep_doze_request(ks_wlan_private *priv) +{ + unsigned char rw_data; + int retval; + + DPRINTK(4, "\n"); + + /* clear request */ + atomic_set(&priv->sleepstatus.doze_request,0); + + if( atomic_read(&priv->sleepstatus.status) == 0){ + rw_data = GCR_B_DOZE; + retval = ks7010_sdio_write(priv, GCR_B, &rw_data, sizeof(rw_data)); + if(retval){ + DPRINTK(1, " error : GCR_B=%02X\n", rw_data); + goto out; + } + DPRINTK(4, "PMG SET!! : GCR_B=%02X\n", rw_data); + DPRINTK(3,"sleep_mode=SLP_SLEEP\n"); + atomic_set(&priv->sleepstatus.status, 1); + priv->last_doze = jiffies; + } + else{ + DPRINTK(1,"sleep_mode=%d\n",priv->sleep_mode); + } + +out: + priv->sleep_mode = atomic_read(&priv->sleepstatus.status); + return; +} + +void ks_wlan_hw_sleep_wakeup_request(ks_wlan_private *priv) +{ + unsigned char rw_data; + int retval; + + DPRINTK(4, "\n"); + + /* clear request */ + atomic_set(&priv->sleepstatus.wakeup_request,0); + + if( atomic_read(&priv->sleepstatus.status) == 1){ + rw_data = WAKEUP_REQ; + retval = ks7010_sdio_write(priv, WAKEUP, &rw_data, sizeof(rw_data)); + if(retval){ + DPRINTK(1, " error : WAKEUP=%02X\n", rw_data); + goto out; + } + DPRINTK(4, "wake up : WAKEUP=%02X\n", rw_data); + atomic_set(&priv->sleepstatus.status, 0); + priv->last_wakeup = jiffies; + ++priv->wakeup_count; + } + else{ + DPRINTK(1,"sleep_mode=%d\n",priv->sleep_mode); + } + +out: + priv->sleep_mode = atomic_read(&priv->sleepstatus.status); + return; +} + + +void ks_wlan_hw_wakeup_request(ks_wlan_private *priv) +{ + unsigned char rw_data; + int retval; + + DPRINTK(4, "\n"); + if(atomic_read(&priv->psstatus.status)==PS_SNOOZE){ + rw_data = WAKEUP_REQ; + retval = ks7010_sdio_write(priv, WAKEUP, &rw_data, sizeof(rw_data)); + if(retval){ + DPRINTK(1, " error : WAKEUP=%02X\n", rw_data); + } + DPRINTK(4, "wake up : WAKEUP=%02X\n", rw_data); + priv->last_wakeup = jiffies; + ++priv->wakeup_count; + } + else{ + DPRINTK(1,"psstatus=%d\n",atomic_read(&priv->psstatus.status)); + } +} + +int _ks_wlan_hw_power_save(ks_wlan_private *priv) +{ + int rc=0; + unsigned char rw_data; + int retval; + + if(priv->reg.powermgt == POWMGT_ACTIVE_MODE) + return rc; + + if(priv->reg.operation_mode == MODE_INFRASTRUCTURE && + (priv->connect_status & CONNECT_STATUS_MASK)== CONNECT_STATUS){ + + //DPRINTK(1,"psstatus.status=%d\n",atomic_read(&priv->psstatus.status)); + if (priv->dev_state == DEVICE_STATE_SLEEP) { + switch(atomic_read(&priv->psstatus.status)){ + case PS_SNOOZE: /* 4 */ + break; + default: + DPRINTK(5,"\n\ + psstatus.status=%d\n\ + psstatus.confirm_wait=%d\n\ + psstatus.snooze_guard=%d\n\ + cnt_txqbody=%d\n", + atomic_read(&priv->psstatus.status), + atomic_read(&priv->psstatus.confirm_wait), + atomic_read(&priv->psstatus.snooze_guard), + cnt_txqbody(priv)); + + if(!atomic_read(&priv->psstatus.confirm_wait)&& + !atomic_read(&priv->psstatus.snooze_guard)&& + !cnt_txqbody(priv)){ + retval = ks7010_sdio_read(priv, INT_PENDING, &rw_data, sizeof(rw_data)); + if(retval){ + DPRINTK(1, " error : INT_PENDING=%02X\n", rw_data); + queue_delayed_work(priv->ks_wlan_hw.ks7010sdio_wq,&priv->ks_wlan_hw.rw_wq, 1); + break; + } + if(!rw_data){ + rw_data = GCR_B_DOZE; + retval = ks7010_sdio_write(priv, GCR_B, &rw_data, sizeof(rw_data)); + if(retval){ + DPRINTK(1, " error : GCR_B=%02X\n", rw_data); + queue_delayed_work(priv->ks_wlan_hw.ks7010sdio_wq,&priv->ks_wlan_hw.rw_wq, 1); + break; + } + DPRINTK(4, "PMG SET!! : GCR_B=%02X\n", rw_data); + atomic_set(&priv->psstatus.status, PS_SNOOZE); + DPRINTK(3,"psstatus.status=PS_SNOOZE\n"); + } + else{ + queue_delayed_work(priv->ks_wlan_hw.ks7010sdio_wq,&priv->ks_wlan_hw.rw_wq, 1); + } + } + else{ + queue_delayed_work(priv->ks_wlan_hw.ks7010sdio_wq,&priv->ks_wlan_hw.rw_wq, 0); + } + break; + } + } + + } + + return rc; +} + +int ks_wlan_hw_power_save(ks_wlan_private *priv) +{ + queue_delayed_work(priv->ks_wlan_hw.ks7010sdio_wq,&priv->ks_wlan_hw.rw_wq, 1); + return 0; +} + +static int ks7010_sdio_read(ks_wlan_private *priv, unsigned int address, + unsigned char *buffer, int length) +{ + int rc = -1; + struct ks_sdio_card *card; + + card = priv->ks_wlan_hw.sdio_card; + + if (length == 1) /* CMD52 */ + *buffer = sdio_readb(card->func, address, &rc); + else /* CMD53 multi-block transfer */ + rc = sdio_memcpy_fromio(card->func, buffer, address, length); + + if(rc != 0){ + printk("sdio error erorr=%d size=%d\n", rc, length); + ++priv->sdio_error_count; + }else{ + priv->sdio_error_count=0; + } + + return rc; +} + +static int ks7010_sdio_write(ks_wlan_private *priv, unsigned int address, + unsigned char *buffer, int length) +{ + int rc = -1; + struct ks_sdio_card *card; + + card = priv->ks_wlan_hw.sdio_card; + + if (length == 1) /* CMD52 */ + sdio_writeb(card->func, *buffer, (unsigned int) address, &rc); + else /* CMD53 */ + rc = sdio_memcpy_toio(card->func, (unsigned int) address, buffer, length); + + if(rc != 0){ + printk("sdio error erorr=%d size=%d\n", rc, length); + ++priv->sdio_error_count; + }else{ + priv->sdio_error_count=0; + } + + return rc; +} + +static int enqueue_txdev(ks_wlan_private *priv, unsigned char *p, unsigned long size, + void (*complete_handler)(void *arg1, void *arg2), + void *arg1, void *arg2 ) +{ + struct tx_device_buffer *sp; + + if (priv->dev_state < DEVICE_STATE_BOOT) { + kfree(p); + if (complete_handler != NULL) + (*complete_handler)(arg1, arg2); + return 1; + } + + if ((TX_DEVICE_BUFF_SIZE - 1) <= cnt_txqbody(priv)) { + /* in case of buffer overflow */ + DPRINTK(1,"tx buffer overflow\n"); + kfree(p); + if (complete_handler != NULL) + (*complete_handler)(arg1, arg2); + return 1; + } + + sp = &priv->tx_dev.tx_dev_buff[priv->tx_dev.qtail]; + sp->sendp = p; + sp->size = size; + sp->complete_handler = complete_handler; + sp->arg1 = arg1; + sp->arg2 = arg2; + inc_txqtail(priv); + + return 0; +} + +/* write data */ +static int write_to_device(ks_wlan_private *priv, unsigned char *buffer, unsigned long size ) +{ + int rc,retval; + unsigned char rw_data; + struct hostif_hdr *hdr; + hdr = (struct hostif_hdr *)buffer; + rc=0; + + DPRINTK(4,"size=%d\n", hdr->size); + if(hdr->event < HIF_DATA_REQ || HIF_REQ_MAX < hdr->event){ + DPRINTK(1,"unknown event=%04X\n",hdr->event); + return 0; + } + + retval = ks7010_sdio_write(priv, DATA_WINDOW, buffer, size); + if(retval){ + DPRINTK(1, " write error : retval=%d\n", retval); + return -4; + } + + rw_data = WRITE_STATUS_BUSY; + retval = ks7010_sdio_write(priv, WRITE_STATUS, &rw_data, sizeof(rw_data)); + if(retval){ + DPRINTK(1, " error : WRITE_STATUS=%02X\n", rw_data); + return -3; + } + + return 0; +} + +static void tx_device_task(void *dev) +{ + ks_wlan_private *priv = (ks_wlan_private *)dev; + struct tx_device_buffer *sp; + int rc = 0; + + DPRINTK(4, "\n"); + if(cnt_txqbody(priv)>0 && atomic_read(&priv->psstatus.status) != PS_SNOOZE){ + sp = &priv->tx_dev.tx_dev_buff[priv->tx_dev.qhead]; + if(priv->dev_state >= DEVICE_STATE_BOOT){ + rc = write_to_device(priv, sp->sendp, sp->size); + if(rc){ + DPRINTK(1, "write_to_device error !!(%d)\n", rc); + queue_delayed_work(priv->ks_wlan_hw.ks7010sdio_wq,&priv->ks_wlan_hw.rw_wq, 1); + return; + } + + } + kfree(sp->sendp); /* allocated memory free */ + if(sp->complete_handler != NULL) /* TX Complete */ + (*sp->complete_handler)(sp->arg1, sp->arg2); + inc_txqhead(priv); + + if(cnt_txqbody(priv)>0){ + queue_delayed_work(priv->ks_wlan_hw.ks7010sdio_wq,&priv->ks_wlan_hw.rw_wq, 0); + } + } + return; +} + +int ks_wlan_hw_tx( ks_wlan_private *priv, void *p, unsigned long size, + void (*complete_handler)(void *arg1, void *arg2), + void *arg1, void *arg2 ) +{ + int result=0; + struct hostif_hdr *hdr; + hdr = (struct hostif_hdr *)p; + + if(hdr->event < HIF_DATA_REQ || HIF_REQ_MAX < hdr->event){ + DPRINTK(1,"unknown event=%04X\n",hdr->event); + return 0; + } + + /* add event to hostt buffer */ + priv->hostt.buff[priv->hostt.qtail] = hdr->event; + priv->hostt.qtail = (priv->hostt.qtail + 1) % SME_EVENT_BUFF_SIZE; + + DPRINTK(4, "event=%04X\n",hdr->event); + spin_lock(&priv->tx_dev.tx_dev_lock); + result = enqueue_txdev(priv, p, size, complete_handler, arg1, arg2); + spin_unlock(&priv->tx_dev.tx_dev_lock); + + if(cnt_txqbody(priv)>0){ + queue_delayed_work(priv->ks_wlan_hw.ks7010sdio_wq,&priv->ks_wlan_hw.rw_wq, 0); + } + return result; +} + +static void rx_event_task(unsigned long dev) +{ + ks_wlan_private *priv = (ks_wlan_private *)dev; + struct rx_device_buffer *rp; + + DPRINTK(4,"\n"); + + if(cnt_rxqbody(priv) > 0 && priv->dev_state >= DEVICE_STATE_BOOT){ + rp = &priv->rx_dev.rx_dev_buff[priv->rx_dev.qhead]; + hostif_receive(priv, rp->data, rp->size); + inc_rxqhead(priv); + + if(cnt_rxqbody(priv) > 0){ + tasklet_schedule(&priv->ks_wlan_hw.rx_bh_task); + } + } + + return; +} + +static void ks_wlan_hw_rx(void *dev, uint16_t size) +{ + ks_wlan_private *priv = (ks_wlan_private *)dev; + int retval; + struct rx_device_buffer *rx_buffer; + struct hostif_hdr *hdr; + unsigned char read_status; + unsigned short event=0; + + DPRINTK(4,"\n"); + + /* receive data */ + if (cnt_rxqbody(priv) >= (RX_DEVICE_BUFF_SIZE-1)) { + /* in case of buffer overflow */ + DPRINTK(1,"rx buffer overflow \n"); + goto error_out; + } + rx_buffer = &priv->rx_dev.rx_dev_buff[priv->rx_dev.qtail]; + + retval = ks7010_sdio_read(priv, DATA_WINDOW, &rx_buffer->data[0], hif_align_size(size)); + if(retval){ + goto error_out; + } + + /* length check */ + if(size > 2046 || size == 0){ + + DPRINTK(5,"-INVAILED DATA dump\n"); + print_buffer(&rx_buffer->data[0],32); + + /* rx_status update */ + read_status = READ_STATUS_IDLE; + retval = ks7010_sdio_write(priv, READ_STATUS, &read_status, sizeof(read_status)); + if(retval){ + DPRINTK(1, " error : READ_STATUS=%02X\n", read_status); + } + goto error_out; + } + + hdr = (struct hostif_hdr *)&rx_buffer->data[0]; + rx_buffer->size = le16_to_cpu(hdr->size) + sizeof(hdr->size); + event = hdr->event; + inc_rxqtail(priv); + + /* read status update */ + read_status = READ_STATUS_IDLE; + retval = ks7010_sdio_write(priv, READ_STATUS, &read_status, sizeof(read_status)); + if(retval){ + DPRINTK(1, " error : READ_STATUS=%02X\n", read_status); + } + DPRINTK(4, "READ_STATUS=%02X\n", read_status); + + if(atomic_read(&priv->psstatus.confirm_wait)){ + if(IS_HIF_CONF(event)){ + DPRINTK(4, "IS_HIF_CONF true !!\n"); + atomic_dec(&priv->psstatus.confirm_wait); + } + } + + /* rx_event_task((void *)priv); */ + tasklet_schedule(&priv->ks_wlan_hw.rx_bh_task); + +error_out: + return; +} + +static void ks7010_rw_function(struct work_struct *work) +{ + struct hw_info_t *hw; + struct ks_wlan_private *priv; + unsigned char rw_data; + int retval; + + hw = container_of(work, struct hw_info_t, rw_wq.work); + priv = container_of(hw, struct ks_wlan_private, ks_wlan_hw); + + DPRINTK(4,"\n"); + + + /* wiat after DOZE */ + if(time_after(priv->last_doze + ((30*HZ)/1000), jiffies )){ + DPRINTK(4, "wait after DOZE \n"); + queue_delayed_work(priv->ks_wlan_hw.ks7010sdio_wq,&priv->ks_wlan_hw.rw_wq, 1); + return; + } + + /* wiat after WAKEUP */ + while(time_after(priv->last_wakeup + ((30*HZ)/1000), jiffies )){ + DPRINTK(4, "wait after WAKEUP \n"); +/* queue_delayed_work(priv->ks_wlan_hw.ks7010sdio_wq,&priv->ks_wlan_hw.rw_wq, + (priv->last_wakeup + ((30*HZ)/1000) - jiffies));*/ + printk("wake: %lu %lu\n", priv->last_wakeup + (30* HZ)/1000, jiffies); + msleep(30); + } + + sdio_claim_host(priv->ks_wlan_hw.sdio_card->func); + + /* power save wakeup */ + if(atomic_read(&priv->psstatus.status)==PS_SNOOZE){ + if(cnt_txqbody(priv)>0){ + ks_wlan_hw_wakeup_request(priv); + queue_delayed_work(priv->ks_wlan_hw.ks7010sdio_wq,&priv->ks_wlan_hw.rw_wq, 1); + } + goto err_out; + } + + /* sleep mode doze */ + if(atomic_read(&priv->sleepstatus.doze_request)==1){ + ks_wlan_hw_sleep_doze_request(priv); + goto err_out; + } + /* sleep mode wakeup */ + if(atomic_read(&priv->sleepstatus.wakeup_request)==1){ + ks_wlan_hw_sleep_wakeup_request(priv); + goto err_out; + } + + /* read (WriteStatus/ReadDataSize FN1:00_0014) */ + retval = ks7010_sdio_read(priv, WSTATUS_RSIZE, &rw_data, sizeof(rw_data)); + if(retval){ + DPRINTK(1, " error : WSTATUS_RSIZE=%02X psstatus=%d\n", rw_data,atomic_read(&priv->psstatus.status)); + goto err_out; + } + DPRINTK(4, "WSTATUS_RSIZE=%02X\n", rw_data); + + if(rw_data&RSIZE_MASK){ /* Read schedule */ + ks_wlan_hw_rx((void *)priv, (uint16_t)(((rw_data&RSIZE_MASK)<<4))); + } + if((rw_data&WSTATUS_MASK)){ + tx_device_task((void *)priv); + } + _ks_wlan_hw_power_save(priv); + +err_out: + sdio_release_host(priv->ks_wlan_hw.sdio_card->func); + + return; +} + + + +static void ks_sdio_interrupt(struct sdio_func *func) +{ + int retval; + struct ks_sdio_card *card; + ks_wlan_private *priv; + unsigned char status, rsize, rw_data; + + card = sdio_get_drvdata(func); + priv = card->priv; + DPRINTK(4, "\n"); + + if(priv->dev_state >= DEVICE_STATE_BOOT){ + retval = ks7010_sdio_read(priv, INT_PENDING, &status, sizeof(status)); + if(retval){ + DPRINTK(1, "read INT_PENDING Failed!!(%d)\n",retval); + goto intr_out; + } + DPRINTK(4, "INT_PENDING=%02X\n", rw_data); + + /* schedule task for interrupt status */ + /* bit7 -> Write General Communication B register */ + /* read (General Communication B register) */ + /* bit5 -> Write Status Idle */ + /* bit2 -> Read Status Busy */ + if(status&INT_GCR_B || atomic_read(&priv->psstatus.status)==PS_SNOOZE){ + retval = ks7010_sdio_read(priv, GCR_B, &rw_data, sizeof(rw_data)); + if(retval){ + DPRINTK(1, " error : GCR_B=%02X\n", rw_data); + goto intr_out; + } + /* DPRINTK(1, "GCR_B=%02X\n", rw_data); */ + if(rw_data == GCR_B_ACTIVE){ + if(atomic_read(&priv->psstatus.status)==PS_SNOOZE){ + atomic_set(&priv->psstatus.status, PS_WAKEUP); + priv->wakeup_count=0; + } + complete(&priv->psstatus.wakeup_wait); + } + + + } + + do{ + /* read (WriteStatus/ReadDataSize FN1:00_0014) */ + retval = ks7010_sdio_read(priv, WSTATUS_RSIZE, &rw_data, sizeof(rw_data)); + if(retval){ + DPRINTK(1, " error : WSTATUS_RSIZE=%02X\n", rw_data); + goto intr_out; + } + DPRINTK(4, "WSTATUS_RSIZE=%02X\n", rw_data); + rsize=rw_data&RSIZE_MASK; + if(rsize){ /* Read schedule */ + ks_wlan_hw_rx((void *)priv, (uint16_t)(((rsize)<<4))); + } + if(rw_data&WSTATUS_MASK){ +#if 0 + if(status&INT_WRITE_STATUS && !cnt_txqbody(priv)){ + /* dummy write for interrupt clear */ + rw_data =0; + retval = ks7010_sdio_write(priv, DATA_WINDOW, &rw_data, sizeof(rw_data)); + if (retval) { + DPRINTK(1, "write DATA_WINDOW Failed!!(%d)\n",retval); + } + status &= ~INT_WRITE_STATUS; + } + else{ +#endif + if(atomic_read(&priv->psstatus.status)==PS_SNOOZE){ + if(cnt_txqbody(priv)){ + ks_wlan_hw_wakeup_request(priv); + queue_delayed_work(priv->ks_wlan_hw.ks7010sdio_wq, &priv->ks_wlan_hw.rw_wq, 1); + return; + } + } + else{ + tx_device_task((void *)priv); + } +// } + } + }while(rsize); + } + +intr_out: + queue_delayed_work(priv->ks_wlan_hw.ks7010sdio_wq,&priv->ks_wlan_hw.rw_wq, 0); + return; +} + +static int trx_device_init( ks_wlan_private *priv ) +{ + /* initialize values (tx) */ + priv->tx_dev.qtail = priv->tx_dev.qhead = 0; + + /* initialize values (rx) */ + priv->rx_dev.qtail = priv->rx_dev.qhead = 0; + + /* initialize spinLock (tx,rx) */ + spin_lock_init(&priv->tx_dev.tx_dev_lock); + spin_lock_init(&priv->rx_dev.rx_dev_lock); + + tasklet_init(&priv->ks_wlan_hw.rx_bh_task, rx_event_task, (unsigned long)priv); + + return 0; +} + +static void trx_device_exit( ks_wlan_private *priv ) +{ + struct tx_device_buffer *sp; + + /* tx buffer clear */ + while (cnt_txqbody(priv)>0) { + sp = &priv->tx_dev.tx_dev_buff[priv->tx_dev.qhead]; + kfree(sp->sendp); /* allocated memory free */ + if (sp->complete_handler != NULL) /* TX Complete */ + (*sp->complete_handler)(sp->arg1, sp->arg2); + inc_txqhead(priv); + } + + tasklet_kill(&priv->ks_wlan_hw.rx_bh_task); + + return; +} +static int ks7010_sdio_update_index(ks_wlan_private *priv, u32 index) +{ + int rc=0; + int retval; + unsigned char *data_buf; + data_buf = NULL; + + data_buf = kmalloc(sizeof(u32), GFP_KERNEL); + if(!data_buf){ rc = 1; goto error_out; } + + memcpy(data_buf, &index, sizeof(index)); + retval = ks7010_sdio_write(priv, WRITE_INDEX, data_buf, sizeof(index)); + if(retval){ rc = 2; goto error_out; } + + retval = ks7010_sdio_write(priv, READ_INDEX, data_buf, sizeof(index)); + if(retval){ rc = 3; goto error_out; } +error_out: + if(data_buf) kfree(data_buf); + return rc; +} + +#define ROM_BUFF_SIZE (64*1024) +static int ks7010_sdio_data_compare(ks_wlan_private *priv, u32 address, + unsigned char *data, unsigned int size) +{ + int rc=0; + int retval; + unsigned char *read_buf; + read_buf = NULL; + read_buf = kmalloc(ROM_BUFF_SIZE, GFP_KERNEL); + if(!read_buf){ rc = 1; goto error_out; } + retval = ks7010_sdio_read(priv, address, read_buf, size); + if(retval){ rc = 2; goto error_out; } + retval = memcmp(data, read_buf, size); + + if(retval){ + DPRINTK(0, "data compare error (%d) \n",retval); rc = 3; goto error_out; + } +error_out: + if(read_buf) kfree(read_buf); + return rc; +} +#ifndef NO_FIRMWARE_CLASS +#include +#endif +static int ks79xx_upload_firmware(ks_wlan_private *priv, struct ks_sdio_card *card) +{ + unsigned int size, offset, n = 0; + unsigned char *rom_buf; + unsigned char rw_data =0; + int retval, rc=0; +#ifndef NO_FIRMWARE_CLASS + int length; + const struct firmware *fw_entry = NULL; +#else + int orgfsuid, orgfsgid; + struct file *srcf; + mm_segment_t orgfs; +#endif + + rom_buf = NULL; + + /* buffer allocate */ + rom_buf = kmalloc(ROM_BUFF_SIZE, GFP_KERNEL); + if(!rom_buf){ rc = 3; goto error_out0; } + + + sdio_claim_host(card->func); + + /* Firmware running ? */ + retval = ks7010_sdio_read(priv, GCR_A, &rw_data, sizeof(rw_data)); + if(rw_data == GCR_A_RUN){ + DPRINTK( 0, "MAC firmware running ...\n"); + rc = 0; + goto error_out0; + } + +#ifndef NO_FIRMWARE_CLASS + if(request_firmware(&fw_entry, priv->reg.rom_file, &priv->ks_wlan_hw.sdio_card->func->dev)!=0){ + DPRINTK(1,"error request_firmware() file=%s\n", priv->reg.rom_file); + return 1; + } + DPRINTK(4,"success request_firmware() file=%s size=%d\n", priv->reg.rom_file, fw_entry->size); + length = fw_entry->size; +#else + orgfsuid=current->fsuid; + orgfsgid=current->fsgid; + current->fsuid=current->fsgid=0; + orgfs=get_fs(); + set_fs(KERNEL_DS); + + srcf = filp_open(romfile, O_RDONLY, 0); + if (IS_ERR(srcf)) { + DPRINTK(1, "error %ld opening %s\n", -PTR_ERR(srcf),romfile); + rc = 1; + goto error_out1; + } + + if (!(srcf->f_op && srcf->f_op->read)) { + DPRINTK(1, "%s does not have a read method\n", romfile); + rc = 2; + goto error_out2; + } +#endif + + /* Load Program */ + n = 0; + do { +#ifndef NO_FIRMWARE_CLASS + if(length >= ROM_BUFF_SIZE){ + size = ROM_BUFF_SIZE; + length = length - ROM_BUFF_SIZE; + } + else{ + size=length; + length=0; + } + DPRINTK(4, "size = %d\n",size); + if(size == 0) break; + memcpy(rom_buf,fw_entry->data+n,size); +#else + /* The object must have a read method */ + size = srcf->f_op->read(srcf, rom_buf, ROM_BUFF_SIZE, &srcf->f_pos); + if (size < 0) { + DPRINTK(1, "Read %s error %d\n", priv->reg.rom_file, -retval); + rc = 5; + goto error_out2; + } + else if (size == 0) break; +#endif + /* Update write index */ + offset = n; + retval = ks7010_sdio_update_index(priv, KS7010_IRAM_ADDRESS+offset); + if(retval){ rc = 6; goto error_out1; } + + /* Write data */ + retval = ks7010_sdio_write(priv, DATA_WINDOW, rom_buf, size); + if(retval){ rc = 8; goto error_out1; } + + /* compare */ + retval = ks7010_sdio_data_compare(priv, DATA_WINDOW, rom_buf, size); + if(retval){ rc = 9; goto error_out1; } + n += size; + + }while(size); + + /* Remap request */ + rw_data = GCR_A_REMAP; + retval = ks7010_sdio_write(priv, GCR_A, &rw_data, sizeof(rw_data)); + if(retval){ + rc = 11; + goto error_out1; + } + DPRINTK( 4, " REMAP Request : GCR_A=%02X\n", rw_data); + + /* Firmware running check */ + for (n = 0; n < 50; ++n) { + mdelay(10);/* wait_ms(10); */ + retval = ks7010_sdio_read(priv, GCR_A, &rw_data, sizeof(rw_data)); + if(retval){ rc = 11; goto error_out1; } + if(rw_data == GCR_A_RUN) break; + } + DPRINTK(4, "firmware wakeup (%d)!!!!\n",n); + if ((50) <= n) { + DPRINTK(1, "firmware can't start\n"); + rc = 12; + goto error_out1; + } + + rc = 0; + +#ifdef NO_FIRMWARE_CLASS + error_out2: + retval=filp_close(srcf ,NULL); + if (retval) + DPRINTK(1, "error %d closing %s\n", -retval,priv->reg.rom_file); + + error_out1: + set_fs(orgfs); + current->fsuid=orgfsuid; + current->fsgid=orgfsgid; +#else + error_out1: + release_firmware(fw_entry); +#endif + error_out0: + sdio_release_host(card->func); + if(rom_buf) + kfree(rom_buf); + return rc; +} + +static void card_init_task(struct work_struct *work) +{ + struct hw_info_t *hw; + struct ks_wlan_private *priv; + + hw = container_of(work, struct hw_info_t, init_task); + priv = container_of(hw, struct ks_wlan_private, ks_wlan_hw); + + DPRINTK(5,"\ncard_init_task()\n"); + + /* init_waitqueue_head(&priv->confirm_wait); */ + init_completion(&priv->confirm_wait); + + DPRINTK(5,"init_completion()\n"); + + /* get mac address & firmware version */ + hostif_sme_enqueue(priv, SME_START); + + DPRINTK(5,"hostif_sme_enqueu()\n"); + + if(!wait_for_completion_interruptible_timeout(&priv->confirm_wait,5*HZ)){ + DPRINTK(1,"wait time out!! SME_START\n"); + } + + if(priv->mac_address_valid && priv->version_size){ + priv->dev_state = DEVICE_STATE_PREINIT; + } + + hostif_sme_enqueue(priv, SME_GET_EEPROM_CKSUM); + + /* load initial wireless parameter */ + hostif_sme_enqueue(priv, SME_STOP_REQUEST); + + hostif_sme_enqueue(priv, SME_RTS_THRESHOLD_REQUEST); + hostif_sme_enqueue(priv, SME_FRAGMENTATION_THRESHOLD_REQUEST); + + hostif_sme_enqueue(priv, SME_WEP_INDEX_REQUEST); + hostif_sme_enqueue(priv, SME_WEP_KEY1_REQUEST); + hostif_sme_enqueue(priv, SME_WEP_KEY2_REQUEST); + hostif_sme_enqueue(priv, SME_WEP_KEY3_REQUEST); + hostif_sme_enqueue(priv, SME_WEP_KEY4_REQUEST); + + hostif_sme_enqueue(priv, SME_WEP_FLAG_REQUEST); + hostif_sme_enqueue(priv, SME_RSN_ENABLED_REQUEST); + hostif_sme_enqueue(priv, SME_MODE_SET_REQUEST); + hostif_sme_enqueue(priv, SME_START_REQUEST); + + if(!wait_for_completion_interruptible_timeout(&priv->confirm_wait,5*HZ)){ + DPRINTK(1,"wait time out!! wireless parameter set\n"); + } + + if(priv->dev_state >= DEVICE_STATE_PREINIT){ + DPRINTK(1, "DEVICE READY!!\n"); + priv->dev_state = DEVICE_STATE_READY; + reg_net = register_netdev (priv->net_dev); + DPRINTK(3, "register_netdev=%d\n",reg_net); + } + else { + DPRINTK(1, "dev_state=%d\n",priv->dev_state); + } +} + +static struct sdio_driver ks7010_sdio_driver = { + .name = "ks7910_sdio", + .id_table = if_sdio_ids, + .probe = ks7910_sdio_probe, + .remove = ks7910_sdio_remove, +}; + + +extern int ks_wlan_net_start(struct net_device *dev); +extern int ks_wlan_net_stop(struct net_device *dev); + +static int ks7910_sdio_probe(struct sdio_func *func, const struct sdio_device_id *device) +{ + ks_wlan_private *priv; + struct ks_sdio_card *card; + struct net_device *netdev; + unsigned char rw_data; + int i=0, ret; + + DPRINTK(5, "ks7910_sdio_probe()\n"); + + priv = NULL; + netdev=NULL; + + + /* initilize ks_sdio_card */ + card = kzalloc(sizeof(struct ks_sdio_card), GFP_KERNEL); + if (!card) + return -ENOMEM; + + card->func = func; + card->model = 0x10; + spin_lock_init(&card->lock); + + /* select model */ + for (i = 0;i < ARRAY_SIZE(ks_sdio_models);i++) { + if (card->model == ks_sdio_models[i].model) + break; + } + + if (i == ARRAY_SIZE(ks_sdio_models)) { + DPRINTK(5, "unkown card model 0x%x\n", card->model); + goto error; + } + + card->firmware = ks_sdio_models[i].firmware; + + + /*** Initialize SDIO ***/ + sdio_claim_host(func); + + /* bus setting */ + /* Issue config request to override clock rate */ + + /* function blocksize set */ + ret = sdio_set_block_size(func, KS7010_IO_BLOCK_SIZE); + DPRINTK(5, "multi_block=%d sdio_set_block_size()=%d %d\n", func->card->cccr.multi_block, func->cur_blksize, ret); + + /* Allocate the slot current */ + + /* function enable */ + ret = sdio_enable_func(func); + DPRINTK(5, "sdio_enable_func() %d\n", ret); + if (ret) + goto error_free_card; + + /* interrupt disable */ + sdio_writeb(func, 0, INT_ENABLE, &ret); + if (ret) + goto error_free_card; + sdio_writeb(func, 0xff, INT_PENDING, &ret); + if (ret) + goto error_disable_func; + + /* setup interrupt handler */ + ret = sdio_claim_irq(func, ks_sdio_interrupt); + if (ret) + goto error_disable_func; + + sdio_release_host(func); + + sdio_set_drvdata(func, card); + + DPRINTK(5, "class = 0x%X, vendor = 0x%X, " + "device = 0x%X\n", + func->class, func->vendor, func->device); + + + /* private memory allocate */ + netdev = alloc_etherdev(sizeof(*priv)); + if (netdev == NULL) { + printk (KERN_ERR "ks79xx : Unable to alloc new net device\n"); + goto error_release_irq; + } + if (dev_alloc_name(netdev, netdev->name) < 0) { + printk (KERN_ERR "ks79xx : Couldn't get name!\n"); + goto error_free_netdev; + } + + priv = netdev_priv(netdev); + + card->priv = priv; + SET_NETDEV_DEV(netdev, &card->func->dev); /* for create sysfs symlinks */ + + /* private memory initialize */ + priv->ks_wlan_hw.sdio_card = card; + init_completion(&priv->ks_wlan_hw.ks7010_sdio_wait); + priv->ks_wlan_hw.read_buf = NULL; + priv->ks_wlan_hw.read_buf = kmalloc(RX_DATA_SIZE, GFP_KERNEL); + if(!priv->ks_wlan_hw.read_buf){ + goto error_free_netdev; + } + priv->dev_state = DEVICE_STATE_PREBOOT; + priv->net_dev = netdev; + priv->firmware_version[0] = '\0'; + priv->version_size = 0; + priv->last_doze = jiffies; /* set current jiffies */ + priv->last_wakeup = jiffies; + memset(&priv->nstats, 0, sizeof(priv->nstats)); + memset(&priv->wstats, 0, sizeof(priv->wstats)); + + /* sleep mode */ + atomic_set(&priv->sleepstatus.doze_request,0); + atomic_set(&priv->sleepstatus.wakeup_request,0); + atomic_set(&priv->sleepstatus.wakeup_request,0); + + trx_device_init(priv); + hostif_init(priv); + ks_wlan_net_start(netdev); + + /* Read config file */ + ret = ks_wlan_read_config_file(priv); + if (ret) { + printk(KERN_ERR "ks79xx: read configuration file failed !! retern code = %d\n", ret); + goto error_free_read_buf; + } + + /* Upload firmware */ + ret = ks79xx_upload_firmware(priv, card); /* firmware load */ + if(ret){ + printk(KERN_ERR "ks79xx: firmware load failed !! retern code = %d\n", ret); + goto error_free_read_buf; + } + + /* interrupt setting */ + /* clear Interrupt status write (ARMtoSD_InterruptPending FN1:00_0024) */ + rw_data = 0xff; + sdio_claim_host(func); + ret = ks7010_sdio_write(priv, INT_PENDING, &rw_data, sizeof(rw_data)); + sdio_release_host(func); + if(ret){ + DPRINTK(1, " error : INT_PENDING=%02X\n", rw_data); + } + DPRINTK(4, " clear Interrupt : INT_PENDING=%02X\n", rw_data); + + + /* enable ks7010sdio interrupt (INT_GCR_B|INT_READ_STATUS|INT_WRITE_STATUS) */ + rw_data = (INT_GCR_B|INT_READ_STATUS|INT_WRITE_STATUS); + sdio_claim_host(func); + ret = ks7010_sdio_write(priv, INT_ENABLE, &rw_data, sizeof(rw_data)); + sdio_release_host(func); + if(ret){ + DPRINTK(1, " error : INT_ENABLE=%02X\n", rw_data); + } + DPRINTK(4, " enable Interrupt : INT_ENABLE=%02X\n", rw_data); + priv->dev_state = DEVICE_STATE_BOOT; + + priv->ks_wlan_hw.ks7010sdio_wq = create_workqueue("ks7010sdio_wq"); + if(!priv->ks_wlan_hw.ks7010sdio_wq){ + DPRINTK(1, "create_workqueue failed !!\n"); + goto error_free_read_buf; + } + + priv->ks_wlan_hw.ks7010sdio_init = create_singlethread_workqueue("ks7010sdio_init"); + if(!priv->ks_wlan_hw.ks7010sdio_init){ + DPRINTK(1, "create_workqueue failed !!\n"); + goto error_free_sdio_wq; + } + + INIT_WORK(&priv->ks_wlan_hw.init_task, card_init_task); + INIT_DELAYED_WORK(&priv->ks_wlan_hw.rw_wq, ks7010_rw_function); + + queue_work(priv->ks_wlan_hw.ks7010sdio_init, &priv->ks_wlan_hw.init_task); + + return 0; + +error_free_sdio_wq: + flush_workqueue(priv->ks_wlan_hw.ks7010sdio_wq); + destroy_workqueue(priv->ks_wlan_hw.ks7010sdio_wq); + priv->ks_wlan_hw.ks7010sdio_wq = NULL; +error_free_read_buf: + kfree(priv->ks_wlan_hw.read_buf); + priv->ks_wlan_hw.read_buf = NULL; +error_free_netdev: + free_netdev(priv->net_dev); + card->priv = NULL; +error_release_irq: + sdio_claim_host(func); + sdio_release_irq(func); +error_disable_func: + sdio_disable_func(func); +error_free_card: + sdio_release_host(func); + sdio_set_drvdata(func, NULL); + kfree(card); +error: + return -ENODEV; +} + +static void ks7910_sdio_remove(struct sdio_func *func) +{ + int ret; + struct ks_sdio_card *card; + struct ks_wlan_private *priv; + struct net_device *netdev; + DPRINTK(1, "ks7910_sdio_remove()\n"); + + card = sdio_get_drvdata(func); + + if(card == NULL) + return; + + DPRINTK(1, "priv = card->priv\n"); + priv = card->priv; + netdev = priv->net_dev; + if(priv){ + ks_wlan_net_stop(netdev); + DPRINTK(1, "ks_wlan_net_stop\n"); + + /* interrupt disable */ + sdio_claim_host(func); + sdio_writeb(func, 0, INT_ENABLE, &ret); + sdio_writeb(func, 0xff, INT_PENDING, &ret); + sdio_release_host(func); + DPRINTK(1, "interrupt disable\n"); + + /* send stop request to MAC */ + { + struct hostif_stop_request_t *pp; + pp = (struct hostif_stop_request_t *)kzalloc(hif_align_size(sizeof(*pp)), GFP_KERNEL ); + if (pp==NULL) { + DPRINTK(3,"allocate memory failed..\n"); + return; /* to do goto ni suru*/ + } + pp->header.size = cpu_to_le16((uint16_t)(sizeof(*pp)-sizeof(pp->header.size))); + pp->header.event = cpu_to_le16((uint16_t)HIF_STOP_REQ); + + sdio_claim_host(func); + write_to_device(priv, (unsigned char *) pp, hif_align_size(sizeof(*pp))); + sdio_release_host(func); + kfree(pp); + } + DPRINTK(1, "STOP Req\n"); + + if(priv->ks_wlan_hw.ks7010sdio_wq){ + flush_workqueue(priv->ks_wlan_hw.ks7010sdio_wq); + destroy_workqueue(priv->ks_wlan_hw.ks7010sdio_wq); + } + DPRINTK(1, "destroy_workqueue(priv->ks_wlan_hw.ks7010sdio_wq);\n"); + + if(priv->ks_wlan_hw.ks7010sdio_init){ + flush_workqueue(priv->ks_wlan_hw.ks7010sdio_init); + destroy_workqueue(priv->ks_wlan_hw.ks7010sdio_init); + } + DPRINTK(1, "destroy_workqueue(priv->ks_wlan_hw.ks7010sdio_init);\n"); + + hostif_exit(priv); + DPRINTK(1, "hostif_exit\n"); + + if(!reg_net) + unregister_netdev(netdev); + DPRINTK(1, "unregister_netdev\n"); + + trx_device_exit(priv); + if(priv->ks_wlan_hw.read_buf){ + kfree(priv->ks_wlan_hw.read_buf); + } + free_netdev(priv->net_dev); + card->priv = NULL; + } + + sdio_claim_host(func); + sdio_release_irq(func); + DPRINTK(1, "sdio_release_irq()\n"); + sdio_disable_func(func); + DPRINTK(1, "sdio_disable_func()\n"); + sdio_release_host(func); + + sdio_set_drvdata(func, NULL); + + kfree(card); + DPRINTK(1, "kfree()\n"); + + + DPRINTK(5," Bye !!\n"); + return; +} + +static int __init ks7010_sdio_init( void ) +{ + int status; + + /* register with bus driver core */ + status = sdio_register_driver(&ks7010_sdio_driver); + if(status != 0){ + DPRINTK(1,"ks79xx_sdio : failed to register with bus driver, %d\n", status ); + } + return status; +} + +static void __exit ks7010_sdio_exit( void ) +{ + DPRINTK(5," \n"); + sdio_unregister_driver(&ks7010_sdio_driver); + return; +} + +module_init(ks7010_sdio_init); +module_exit(ks7010_sdio_exit); + +MODULE_AUTHOR("Qi-Hardware based on KeyStream driver"); +MODULE_DESCRIPTION("Driver for KeyStream, KS7010 based SDIO cards. "); +#ifdef MODULE_LICENSE +MODULE_LICENSE("GPL"); +#endif +MODULE_SUPPORTED_DEVICE("KS7910"); diff --git a/drivers/staging/ks7010/ks7010_sdio.h b/drivers/staging/ks7010/ks7010_sdio.h new file mode 100644 index 0000000..3af742f --- /dev/null +++ b/drivers/staging/ks7010/ks7010_sdio.h @@ -0,0 +1,165 @@ +/* + * + * Driver for KeyStream, KS7010 based SDIO cards. + * + * ks7010_sdio.h + * $Id: ks7010_sdio.h 1019 2009-09-28 05:41:07Z sekine $ + * + * Copyright (C) 2006-2008 KeyStream Corp. + * Copyright (C) 2009 Renesas Technology Corp. + * + * This program is free software; you can redistribute it and/or modify + * it undr the terms of the GNU General Public License version 2 as + * published by the Free Sotware Foundation. + */ +#ifndef _KS7010_SDIO_H +#define _KS7010_SDIO_H + +#ifdef DEVICE_ALIGNMENT +#undef DEVICE_ALIGNMENT +#endif +#define DEVICE_ALIGNMENT 32 + +/* SDIO KeyStream vendor and device */ +#define SDIO_VENDOR_ID_KS_CODE_A 0x005b +#define SDIO_VENDOR_ID_KS_CODE_B 0x0023 +#define SDIO_DEVICE_ID_KS_7010 0x7910 + +/* Read Status Register */ +#define READ_STATUS 0x000000 +#define READ_STATUS_BUSY 0 +#define READ_STATUS_IDLE 1 + +/* Read Index Register */ +#define READ_INDEX 0x000004 + +/* Read Data Size Register */ +#define READ_DATA_SIZE 0x000008 + +/* Write Status Register */ +#define WRITE_STATUS 0x00000C +#define WRITE_STATUS_BUSY 0 +#define WRITE_STATUS_IDLE 1 + +/* Write Index Register */ +#define WRITE_INDEX 0x000010 + +/* Write Status/Read Data Size Register + * for network packet (less than 2048 bytes data) + */ +#define WSTATUS_RSIZE 0x000014 +#define WSTATUS_MASK 0x80 /* Write Status Register value */ +#define RSIZE_MASK 0x7F /* Read Data Size Register value [10:4] */ + +/* ARM to SD interrupt Enable */ +#define INT_ENABLE 0x000020 +/* ARM to SD interrupt Pending */ +#define INT_PENDING 0x000024 + +#define INT_GCR_B (1<<7) +#define INT_GCR_A (1<<6) +#define INT_WRITE_STATUS (1<<5) +#define INT_WRITE_INDEX (1<<4) +#define INT_WRITE_SIZE (1<<3) +#define INT_READ_STATUS (1<<2) +#define INT_READ_INDEX (1<<1) +#define INT_READ_SIZE (1<<0) + +/* General Communication Register A */ +#define GCR_A 0x000028 +#define GCR_A_INIT 0 +#define GCR_A_REMAP 1 +#define GCR_A_RUN 2 + +/* General Communication Register B */ +#define GCR_B 0x00002C +#define GCR_B_ACTIVE 0 +#define GCR_B_DOZE 1 + +/* Wakeup Register */ +/* #define WAKEUP 0x008104 */ +/* #define WAKEUP_REQ 0x00 */ +#define WAKEUP 0x008018 +#define WAKEUP_REQ 0x5a + +/* AHB Data Window 0x010000-0x01FFFF */ +#define DATA_WINDOW 0x010000 +#define WINDOW_SIZE 64*1024 + +#define KS7010_IRAM_ADDRESS 0x06000000 + + +/* + * struct define + */ +struct hw_info_t { + struct ks_sdio_card *sdio_card; + struct completion ks7010_sdio_wait; + struct workqueue_struct *ks7010sdio_wq; + struct workqueue_struct *ks7010sdio_init; + struct work_struct init_task; + struct delayed_work rw_wq; + unsigned char *read_buf; + struct tasklet_struct rx_bh_task; +}; + +struct ks_sdio_packet { + struct ks_sdio_packet *next; + u16 nb; + u8 buffer[0] __attribute__((aligned(4))); +}; + + +struct ks_sdio_card { + struct sdio_func *func; + struct ks_wlan_private *priv; + int model; + const char *firmware; + spinlock_t lock; +}; + + + +/* Tx Device struct */ +#define TX_DEVICE_BUFF_SIZE 1024 + +struct tx_device_buffer { + unsigned char *sendp; /* pointer of send req data */ + unsigned int size; + void (*complete_handler)(void *arg1, void *arg2); + void *arg1; + void *arg2; +}; + +struct tx_device{ + struct tx_device_buffer tx_dev_buff[TX_DEVICE_BUFF_SIZE]; + unsigned int qhead; /* tx buffer queue first pointer */ + unsigned int qtail; /* tx buffer queue last pointer */ + spinlock_t tx_dev_lock; +}; + +/* Rx Device struct */ +#define RX_DATA_SIZE (2 + 2 + 2347 + 1) +#define RX_DEVICE_BUFF_SIZE 32 + +struct rx_device_buffer { + unsigned char data[RX_DATA_SIZE]; + unsigned int size; +}; + +struct rx_device{ + struct rx_device_buffer rx_dev_buff[RX_DEVICE_BUFF_SIZE]; + unsigned int qhead; /* rx buffer queue first pointer */ + unsigned int qtail; /* rx buffer queue last pointer */ + spinlock_t rx_dev_lock; +}; +#ifndef NO_FIRMWARE_CLASS +#define ROM_FILE "ks7010sd.rom" +#define CFG_FILE "ks79xx.cfg" +#else +#define ROM_FILE "/lib/firmware/ks7010sd.rom" +#define CFG_FILE "/lib/firmware/ks79xx.cfg" +#endif +#define KS_WLAN_DRIVER_VERSION_INFO "ks7010 sdio linux 007" + +#endif /* _KS7010_SDIO_H */ diff --git a/drivers/staging/ks7010/ks_debug.c b/drivers/staging/ks7010/ks_debug.c new file mode 100644 index 0000000..009f5f6 --- /dev/null +++ b/drivers/staging/ks7010/ks_debug.c @@ -0,0 +1,30 @@ +/* + * Driver for KeyStream 11b/g wireless LAN cards. + * + * ks_debug.c + * $Id: ks_debug.c 991 2009-09-14 01:38:58Z sekine $ + * + * Copyright (C) 2005-2008 KeyStream Corp. + * Copyright (C) 2009 Renesas Technology Corp. + * + * This program is free software; you can redistribute it and/or modify + * it undr the terms of the GNU General Public License version 2 as + * published by the Free Sotware Foundation. + */ +#include "ks_wlan.h" +#include "ks_debug.h" + +void print_buffer(unsigned char *p, int length) +{ +#ifdef KS_WLAN_DEBUG + int i; +#define HEX_OFFSET "\ + +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +A +B +C +D +E +F" + printk(HEX_OFFSET); + for (i=0; i + + +#ifdef KS_WLAN_DEBUG +#define DPRINTK(n, fmt, args...) \ + if (KS_WLAN_DEBUG>(n)) printk(KERN_NOTICE "%s: "fmt, __FUNCTION__, ## args) +#else +#define DPRINTK(n, fmt, args...) +#endif + +extern void print_buffer(unsigned char *p, int size); + +#endif /* _KS_DEBUG_H */ diff --git a/drivers/staging/ks7010/ks_hostif.c b/drivers/staging/ks7010/ks_hostif.c new file mode 100644 index 0000000..402ddba --- /dev/null +++ b/drivers/staging/ks7010/ks_hostif.c @@ -0,0 +1,2665 @@ +/* + * Driver for KeyStream wireless LAN cards. + * + * ks_hostif.c + * $Id: ks_hostif.c 996 2009-09-14 02:54:21Z sekine $ + * + * Copyright (C) 2005-2008 KeyStream Corp. + * Copyright (C) 2009 Renesas Technology Corp. + * + * This program is free software; you can redistribute it and/or modify + * it undr the terms of the GNU General Public License version 2 as + * published by the Free Sotware Foundation. + */ + +#include "ks_wlan.h" +#include "ks_debug.h" +#include "ks_hostif.h" +#include "eap_packet.h" +#include "michael_mic.h" + +#include +#include + +/* Include Wireless Extension definition and check version */ +#ifndef WIRELESS_EXT +#include +#endif /* WIRELESS_EXT */ +#if WIRELESS_EXT > 12 +#include /* New driver API */ +#endif /* WIRELESS_EXT > 12 */ + +extern int ks_wlan_hw_tx(ks_wlan_private *priv, void *p, unsigned long size, + void (*complete_handler)(void *arg1, void *arg2), + void *arg1, void *arg2 ); +extern void send_packet_complete(void *, void *); + +extern void ks_wlan_hw_wakeup_request(ks_wlan_private *priv); +extern int ks_wlan_hw_power_save(ks_wlan_private *priv); + +/* macro */ +#define inc_smeqhead(priv) \ + ( priv->sme_i.qhead = (priv->sme_i.qhead + 1) % SME_EVENT_BUFF_SIZE ) +#define inc_smeqtail(priv) \ + ( priv->sme_i.qtail = (priv->sme_i.qtail + 1) % SME_EVENT_BUFF_SIZE ) +#define cnt_smeqbody(priv) \ + (((priv->sme_i.qtail + SME_EVENT_BUFF_SIZE) - (priv->sme_i.qhead)) % SME_EVENT_BUFF_SIZE ) + +#define KS_WLAN_MEM_FLAG (GFP_ATOMIC) + +static +inline u8 get_BYTE(ks_wlan_private *priv) +{ + u8 data; + data = *(priv->rxp)++; + /* length check in advance ! */ + --(priv->rx_size); + return data; +} + +static +inline u16 get_WORD(ks_wlan_private *priv) +{ + u16 data; + data = (get_BYTE(priv) & 0xff); + data |= ((get_BYTE(priv) << 8) & 0xff00); + return data; +} + +static +inline u32 get_DWORD(ks_wlan_private *priv) +{ + u32 data; + data = (get_BYTE(priv) & 0xff); + data |= ((get_BYTE(priv) << 8) & 0x0000ff00); + data |= ((get_BYTE(priv) << 16) & 0x00ff0000); + data |= ((get_BYTE(priv) << 24) & 0xff000000); + return data; +} + +void ks_wlan_hw_wakeup_task(struct work_struct *work) +{ + ks_wlan_private *priv = container_of(work, struct ks_wlan_private, ks_wlan_wakeup_task); + int ps_status = atomic_read(&priv->psstatus.status); + + if(ps_status==PS_SNOOZE){ + ks_wlan_hw_wakeup_request(priv); + if(!wait_for_completion_interruptible_timeout(&priv->psstatus.wakeup_wait,HZ/50)){ /* 20ms timeout */ + DPRINTK(1,"wake up timeout !!!\n"); + schedule_work(&priv->ks_wlan_wakeup_task); + return; + } + } + else{ + DPRINTK(1,"ps_status=%d\n",ps_status); + } + + /* power save */ + if(atomic_read(&priv->sme_task.count) > 0){ + DPRINTK(4,"sme task enable.\n"); + tasklet_enable(&priv->sme_task); + } +} + +static +int ks_wlan_do_power_save(ks_wlan_private *priv) +{ + int rc=0; + + DPRINTK(4,"psstatus.status=%d\n",atomic_read(&priv->psstatus.status)); + +#ifdef _SDIO_ + if((priv->connect_status & CONNECT_STATUS_MASK) == CONNECT_STATUS){ + hostif_sme_enqueue(priv, SME_POW_MNGMT_REQUEST); + } + else{ + priv->dev_state = DEVICE_STATE_READY; + } +#else + if((priv->connect_status & CONNECT_STATUS_MASK) == CONNECT_STATUS){ + switch(atomic_read(&priv->psstatus.status)){ + case PS_ACTIVE_SET: + case PS_WAKEUP: + case PS_SAVE_SET: + case PS_SNOOZE: + break; + case PS_CONF_WAIT: + atomic_set(&priv->psstatus.confirm_wait,0); + break; + case PS_NONE: + default: + hostif_sme_enqueue(priv, SME_POW_MNGMT_REQUEST); + break; + } + + } + else{ + switch(atomic_read(&priv->psstatus.status)){ + case PS_ACTIVE_SET: + case PS_WAKEUP: + case PS_SAVE_SET: + break; + case PS_CONF_WAIT: + atomic_set(&priv->psstatus.confirm_wait,0); + atomic_set(&priv->psstatus.status, PS_WAKEUP); + break; + case PS_SNOOZE: + ks_wlan_hw_power_save(priv); + break; + case PS_NONE: + default: + hostif_sme_enqueue(priv, SME_POW_MNGMT_REQUEST); + break; + } + } +#endif + return rc; +} + +static +int get_current_ap(ks_wlan_private *priv, struct link_ap_info_t *ap_info) +{ + struct local_ap_t *ap; +#if WIRELESS_EXT > 13 + union iwreq_data wrqu; + struct net_device *netdev=priv->net_dev; +#endif /* WIRELESS_EXT > 13 */ + int rc=0; + + DPRINTK(3,"\n"); + ap = &(priv->current_ap); + + if((priv->connect_status & CONNECT_STATUS_MASK)== DISCONNECT_STATUS){ + memset(ap,0,sizeof(struct local_ap_t)); + return 1; + } + + /* bssid */ + memcpy(&(ap->bssid[0]),&(ap_info->bssid[0]),ETH_ALEN); + /* essid */ + memcpy(&(ap->ssid.body[0]),&(priv->reg.ssid.body[0]),priv->reg.ssid.size); + ap->ssid.size = priv->reg.ssid.size; + /* rate_set */ + memcpy(&(ap->rate_set.body[0]),&(ap_info->rate_set.body[0]),ap_info->rate_set.size); + ap->rate_set.size = ap_info->rate_set.size; + if(ap_info->ext_rate_set.size){ + /* rate_set */ + memcpy(&(ap->rate_set.body[ap->rate_set.size]), + &(ap_info->ext_rate_set.body[0]), + ap_info->ext_rate_set.size); + ap->rate_set.size += ap_info->ext_rate_set.size; + } + /* channel */ + ap->channel = ap_info->ds_parameter.channel; + /* rssi */ + ap->rssi = ap_info->rssi; + /* sq */ + ap->sq = ap_info->sq; + /* noise */ + ap->noise = ap_info->noise; + /* capability */ + ap->capability = ap_info->capability; + /* rsn */ + if((ap_info->rsn_mode & RSN_MODE_WPA2) && (priv->wpa.version == IW_AUTH_WPA_VERSION_WPA2)){ + ap->rsn_ie.id = 0x30; + if(ap_info->rsn.size <= RSN_IE_BODY_MAX){ + ap->rsn_ie.size = ap_info->rsn.size; + memcpy(&(ap->rsn_ie.body[0]),&(ap_info->rsn.body[0]),ap_info->rsn.size); + } + else{ + ap->rsn_ie.size = RSN_IE_BODY_MAX; + memcpy(&(ap->rsn_ie.body[0]),&(ap_info->rsn.body[0]),RSN_IE_BODY_MAX); + } + } + else if((ap_info->rsn_mode & RSN_MODE_WPA) && (priv->wpa.version == IW_AUTH_WPA_VERSION_WPA)){ + ap->wpa_ie.id = 0xdd; + if(ap_info->rsn.size <= RSN_IE_BODY_MAX){ + ap->wpa_ie.size = ap_info->rsn.size; + memcpy(&(ap->wpa_ie.body[0]),&(ap_info->rsn.body[0]),ap_info->rsn.size); + } + else{ + ap->wpa_ie.size = RSN_IE_BODY_MAX; + memcpy(&(ap->wpa_ie.body[0]),&(ap_info->rsn.body[0]),RSN_IE_BODY_MAX); + } + } + else{ + ap->rsn_ie.id = 0; + ap->rsn_ie.size = 0; + ap->wpa_ie.id = 0; + ap->wpa_ie.size = 0; + } + +#if WIRELESS_EXT > 13 + wrqu.data.length = 0; + wrqu.data.flags = 0; + wrqu.ap_addr.sa_family = ARPHRD_ETHER; + if((priv->connect_status & CONNECT_STATUS_MASK)==CONNECT_STATUS){ + memcpy(wrqu.ap_addr.sa_data, + &(priv->current_ap.bssid[0]), ETH_ALEN); + DPRINTK(3,"IWEVENT: connect bssid=%02x:%02x:%02x:%02x:%02x:%02x\n", + (unsigned char)wrqu.ap_addr.sa_data[0],(unsigned char)wrqu.ap_addr.sa_data[1], + (unsigned char)wrqu.ap_addr.sa_data[2],(unsigned char)wrqu.ap_addr.sa_data[3], + (unsigned char)wrqu.ap_addr.sa_data[4],(unsigned char)wrqu.ap_addr.sa_data[5]); + wireless_send_event(netdev, SIOCGIWAP, &wrqu, NULL); + } +#endif + DPRINTK(4,"\n Link AP\n"); + DPRINTK(4," bssid=%02X:%02X:%02X:%02X:%02X:%02X\n \ + essid=%s\n rate_set=%02X,%02X,%02X,%02X,%02X,%02X,%02X,%02X\n channel=%d\n \ + rssi=%d\n sq=%d\n capability=%04X\n", + ap->bssid[0],ap->bssid[1],ap->bssid[2],ap->bssid[3],ap->bssid[4], + ap->bssid[5],&(ap->ssid.body[0]),ap->rate_set.body[0],ap->rate_set.body[1], + ap->rate_set.body[2],ap->rate_set.body[3],ap->rate_set.body[4], + ap->rate_set.body[5],ap->rate_set.body[6],ap->rate_set.body[7], + ap->channel,ap->rssi,ap->sq,ap->capability); + DPRINTK(4,"\n Link AP\n rsn.mode=%d\n rsn.size=%d\n", + ap_info->rsn_mode,ap_info->rsn.size); + DPRINTK(4,"\n ext_rate_set_size=%d\n rate_set_size=%d\n", + ap_info->ext_rate_set.size,ap_info->rate_set.size); + + + return rc; +} + +static +int get_ap_information(ks_wlan_private *priv, struct ap_info_t *ap_info, struct local_ap_t *ap) +{ + unsigned char *bp; + int bsize,offset; + int rc=0; + + DPRINTK(3,"\n"); + memset(ap,0,sizeof(struct local_ap_t)); + + /* bssid */ + memcpy(&(ap->bssid[0]),&(ap_info->bssid[0]),ETH_ALEN); + /* rssi */ + ap->rssi = ap_info->rssi; + /* sq */ + ap->sq = ap_info->sq; + /* noise */ + ap->noise = ap_info->noise; + /* capability */ + ap->capability = ap_info->capability; + /* channel */ + ap->channel = ap_info->ch_info; + + bp = &(ap_info->body[0]); + bsize = ap_info->body_size; + offset = 0; + + while(bsize > offset){ + /* DPRINTK(4, "Element ID=%d \n",*bp); */ + switch(*bp){ + case 0: /* ssid */ + if(*(bp+1) <= SSID_MAX_SIZE){ + ap->ssid.size = *(bp+1); + } + else { + DPRINTK(1, "size over :: ssid size=%d \n",*(bp+1)); + ap->ssid.size = SSID_MAX_SIZE; + } + memcpy(&(ap->ssid.body[0]),bp+2,ap->ssid.size); + break; + case 1: /* rate */ + case 50: /* ext rate */ + if((*(bp+1) + ap->rate_set.size) <= RATE_SET_MAX_SIZE){ + memcpy(&(ap->rate_set.body[ap->rate_set.size]),bp+2,*(bp+1)); + ap->rate_set.size += *(bp+1); + } + else{ + DPRINTK(1, "size over :: rate size=%d \n", + (*(bp+1) + ap->rate_set.size)); + memcpy(&(ap->rate_set.body[ap->rate_set.size]),bp+2, + RATE_SET_MAX_SIZE - ap->rate_set.size); + ap->rate_set.size += (RATE_SET_MAX_SIZE - ap->rate_set.size); + } + break; + case 3: /* DS parameter */ + break; + case 48: /* RSN(WPA2) */ + ap->rsn_ie.id = *bp; + if(*(bp+1) <= RSN_IE_BODY_MAX){ + ap->rsn_ie.size = *(bp+1); + }else{ + DPRINTK(1, "size over :: rsn size=%d \n",*(bp+1)); + ap->rsn_ie.size = RSN_IE_BODY_MAX; + } + memcpy(&(ap->rsn_ie.body[0]),bp+2,ap->rsn_ie.size); + break; + case 221: /* WPA */ + if(!memcmp(bp+2, "\x00\x50\xf2\x01", 4)){ /* WPA OUI check */ + ap->wpa_ie.id = *bp; + if(*(bp+1) <= RSN_IE_BODY_MAX){ + ap->wpa_ie.size = *(bp+1); + }else{ + DPRINTK(1, "size over :: wpa size=%d \n",*(bp+1)); + ap->wpa_ie.size = RSN_IE_BODY_MAX; + } + memcpy(&(ap->wpa_ie.body[0]),bp+2,ap->wpa_ie.size); + } + break; + + case 2: /* FH parameter */ + case 4: /* CF parameter */ + case 5: /* TIM */ + case 6: /* IBSS parameter */ + case 7: /* Country */ + case 42: /* ERP information */ + case 47: /* Reserve ID 47 Broadcom AP */ + break; + default: + DPRINTK(4, "unknown Element ID=%d \n",*bp); + break; + } + offset += 2; /* id & size field */ + offset += *(bp+1); /* +size offset */ + bp += (*(bp+1) + 2); /* pointer update */ + } + + return rc; +} + +static +void hostif_data_indication(ks_wlan_private *priv) +{ + unsigned int rx_ind_size; /* indicate data size */ + struct sk_buff *skb; + unsigned short auth_type; + unsigned char temp[256]; + + unsigned char RecvMIC[8]; + char buf[128]; + struct ether_hdr *eth_hdr; + unsigned short eth_proto; + unsigned long now; + struct mic_failure_t *mic_failure; + struct ieee802_1x_hdr *aa1x_hdr; + struct wpa_eapol_key *eap_key; + struct michel_mic_t michel_mic; +#if WIRELESS_EXT > 14 + union iwreq_data wrqu; +#endif /* WIRELESS_EXT > 14 */ + + DPRINTK(3,"\n"); + + /* min length check */ + if (priv->rx_size <= ETH_HLEN) { + DPRINTK(3,"rx_size = %d\n", priv->rx_size); + priv->nstats.rx_errors++; + return; + } + + auth_type = get_WORD(priv); /* AuthType */ + get_WORD(priv); /* Reserve Area */ + + eth_hdr = (struct ether_hdr *)(priv->rxp); + eth_proto = ntohs(eth_hdr->h_proto); + DPRINTK(3,"ether protocol = %04X\n", eth_proto); + + /* source address check */ + if (!memcmp(&priv->eth_addr[0],eth_hdr->h_source, ETH_ALEN)){ + DPRINTK(1, "invalid : source is own mac address !!\n"); + DPRINTK(1, "eth_hdrernet->h_dest=%02X:%02X:%02X:%02X:%02X:%02X\n", + eth_hdr->h_source[0],eth_hdr->h_source[1],eth_hdr->h_source[2], + eth_hdr->h_source[3],eth_hdr->h_source[4],eth_hdr->h_source[5]); + priv->nstats.rx_errors++; + return; + } + + /* for WPA */ + if (auth_type != TYPE_DATA && priv->wpa.rsn_enabled){ + if(memcmp(ð_hdr->h_source[0],&priv->eth_addr[0],ETH_ALEN)){ /* source address check */ + if (eth_hdr->h_dest_snap != eth_hdr->h_source_snap){ + DPRINTK(1,"invalid data format\n"); + priv->nstats.rx_errors++; + return; + } + if(((auth_type==TYPE_PMK1 && priv->wpa.pairwise_suite == IW_AUTH_CIPHER_TKIP)|| + (auth_type==TYPE_GMK1 && priv->wpa.group_suite == IW_AUTH_CIPHER_TKIP)|| + (auth_type==TYPE_GMK2 && priv->wpa.group_suite == IW_AUTH_CIPHER_TKIP)) + && priv->wpa.key[auth_type-1].key_len){ + DPRINTK(4,"TKIP: protocol=%04X: size=%u\n", eth_proto, priv->rx_size); + /* MIC save */ + memcpy(&RecvMIC[0], (priv->rxp)+((priv->rx_size)-8), 8); + priv->rx_size = priv->rx_size - 8; + if(auth_type > 0 && auth_type < 4){ /* auth_type check */ + MichaelMICFunction(&michel_mic, + (uint8_t*)priv->wpa.key[auth_type-1].rx_mic_key, + (uint8_t*)priv->rxp, + (int)priv->rx_size, + (uint8_t)0, /* priority */ + (uint8_t*)michel_mic.Result); + } + if(memcmp(michel_mic.Result, RecvMIC, 8)){ + now = jiffies; + mic_failure = &priv->wpa.mic_failure; + /* MIC FAILURE */ + if(mic_failure->last_failure_time && + (now - mic_failure->last_failure_time)/HZ >= 60){ + mic_failure->failure=0; + } + DPRINTK(4,"MIC FAILURE \n"); + if(mic_failure->failure==0){ + mic_failure->failure=1; + mic_failure->counter=0; + }else if(mic_failure->failure==1){ + mic_failure->failure=2; + mic_failure->counter = + (uint16_t)((now - mic_failure->last_failure_time)/HZ); + if(!mic_failure->counter) /* mic_failure counter value range 1-60 */ + mic_failure->counter = 1; + } + priv->wpa.mic_failure.last_failure_time = now; +#if WIRELESS_EXT > 14 + /* needed parameters: count, keyid, key type, TSC */ + sprintf(buf, "MLME-MICHAELMICFAILURE.indication(keyid=%d %scast addr=" + "%02x:%02x:%02x:%02x:%02x:%02x)", + auth_type-1, eth_hdr->h_dest[0] & 0x01 ? "broad" : "uni", + eth_hdr->h_source[0],eth_hdr->h_source[1], + eth_hdr->h_source[2],eth_hdr->h_source[3], + eth_hdr->h_source[4],eth_hdr->h_source[5]); + memset(&wrqu, 0, sizeof(wrqu)); + wrqu.data.length = strlen(buf); + DPRINTK(4,"IWEVENT:MICHAELMICFAILURE\n"); + wireless_send_event(priv->net_dev, IWEVCUSTOM, &wrqu, buf); +#endif /* WIRELESS_EXT > 14 */ + return; + } + } + } + } + + if((priv->connect_status & FORCE_DISCONNECT)|| + priv->wpa.mic_failure.failure==2){ + return; + } + + /* check 13th byte at rx data */ + switch (*(priv->rxp+12)) { + case 0xAA: /* SNAP */ + rx_ind_size = priv->rx_size - 6; + skb = dev_alloc_skb (rx_ind_size); + DPRINTK(4,"SNAP, rx_ind_size = %d\n", rx_ind_size); + + if(skb) { + memcpy(skb_put(skb,12),priv->rxp,12); /* 8802/FDDI MAC copy */ + /* (SNAP+UI..) skip */ + memcpy(skb_put(skb,rx_ind_size-12),priv->rxp+18,rx_ind_size-12); /* copy after Type */ + + aa1x_hdr=(struct ieee802_1x_hdr *)(priv->rxp+20); + if(aa1x_hdr->type == IEEE802_1X_TYPE_EAPOL_KEY && priv->wpa.rsn_enabled){ + eap_key = (struct wpa_eapol_key *)(aa1x_hdr+1); + atomic_set(&priv->psstatus.snooze_guard, 1); + } + + /* rx indication */ + skb->dev = priv->net_dev; + skb->protocol = eth_type_trans (skb, skb->dev); + priv->nstats.rx_packets++; + priv->nstats.rx_bytes += rx_ind_size; + skb->dev->last_rx = jiffies; + netif_rx (skb); + } else { + printk (KERN_WARNING"%s: Memory squeeze, dropping packet.\n",skb->dev->name); + priv->nstats.rx_dropped++; + } + break; + case 0xF0: /* NETBEUI/NetBIOS */ + rx_ind_size = (priv->rx_size + 2); + skb = dev_alloc_skb (rx_ind_size); + DPRINTK(3,"NETBEUI/NetBIOS rx_ind_size=%d\n", rx_ind_size); + + if(skb) { + memcpy(skb_put(skb,12),priv->rxp,12); /* 8802/FDDI MAC copy */ + + temp[0] = (((rx_ind_size-12) >> 8) & 0xff); /* NETBEUI size add */ + temp[1] = ((rx_ind_size-12) & 0xff); + memcpy(skb_put(skb,2),temp,2); + + memcpy(skb_put(skb,rx_ind_size-14),priv->rxp+12,rx_ind_size-14); /* copy after Type */ + + aa1x_hdr=(struct ieee802_1x_hdr *)(priv->rxp+14); + if(aa1x_hdr->type == IEEE802_1X_TYPE_EAPOL_KEY && priv->wpa.rsn_enabled){ + eap_key = (struct wpa_eapol_key *)(aa1x_hdr+1); + atomic_set(&priv->psstatus.snooze_guard, 1); + } + + /* rx indication */ + skb->dev = priv->net_dev; + skb->protocol = eth_type_trans (skb, skb->dev); + priv->nstats.rx_packets++; + priv->nstats.rx_bytes += rx_ind_size; + skb->dev->last_rx = jiffies; + netif_rx (skb); + } else { + printk (KERN_WARNING"%s: Memory squeeze, dropping packet.\n",skb->dev->name); + priv->nstats.rx_dropped++; + } + break; + default: /* other rx data */ + DPRINTK(2,"invalid data format\n"); + priv->nstats.rx_errors++; + } +} + +static +void hostif_mib_get_confirm(ks_wlan_private *priv) +{ + struct net_device *dev=priv->net_dev; + uint32_t mib_status; + uint32_t mib_attribute; + uint16_t mib_val_size; + uint16_t mib_val_type; + + DPRINTK(3, "\n"); + + mib_status = get_DWORD(priv); /* MIB status */ + mib_attribute = get_DWORD(priv); /* MIB atttibute */ + mib_val_size = get_WORD(priv); /* MIB value size */ + mib_val_type = get_WORD(priv); /* MIB value type */ + + if (mib_status != 0) { + /* in case of error */ + DPRINTK(1, "attribute=%08X, status=%08X\n", mib_attribute, mib_status); + return; + } + + switch (mib_attribute) { + case DOT11_MAC_ADDRESS: + /* MAC address */ + DPRINTK(3," mib_attribute=DOT11_MAC_ADDRESS\n"); + hostif_sme_enqueue(priv, SME_GET_MAC_ADDRESS); + memcpy(priv->eth_addr, priv->rxp, ETH_ALEN); + priv->mac_address_valid = 1; + dev->dev_addr[0] = priv->eth_addr[0]; + dev->dev_addr[1] = priv->eth_addr[1]; + dev->dev_addr[2] = priv->eth_addr[2]; + dev->dev_addr[3] = priv->eth_addr[3]; + dev->dev_addr[4] = priv->eth_addr[4]; + dev->dev_addr[5] = priv->eth_addr[5]; + dev->dev_addr[6] = 0x00; + dev->dev_addr[7] = 0x00; + printk(KERN_INFO "ks_wlan: MAC ADDRESS = %02x:%02x:%02x:%02x:%02x:%02x\n", + priv->eth_addr[0],priv->eth_addr[1],priv->eth_addr[2], + priv->eth_addr[3],priv->eth_addr[4],priv->eth_addr[5]); + break; + case DOT11_PRODUCT_VERSION: + /* firmware version */ + DPRINTK(3," mib_attribute=DOT11_PRODUCT_VERSION\n"); + priv->version_size = priv->rx_size; + memcpy(priv->firmware_version, priv->rxp, priv->rx_size); + priv->firmware_version[priv->rx_size] = '\0'; + printk(KERN_INFO "ks_wlan: firmware ver. = %s\n",priv->firmware_version); + hostif_sme_enqueue(priv, SME_GET_PRODUCT_VERSION); + /* wake_up_interruptible_all(&priv->confirm_wait); */ + complete(&priv->confirm_wait); + break; + case LOCAL_GAIN: + memcpy(&priv->gain, priv->rxp, sizeof(priv->gain)); + DPRINTK(3, "TxMode=%d, RxMode=%d, TxGain=%d, RxGain=%d\n", + priv->gain.TxMode, priv->gain.RxMode, priv->gain.TxGain, priv->gain.RxGain); + break; + case LOCAL_EEPROM_SUM: + memcpy(&priv->eeprom_sum, priv->rxp, sizeof(priv->eeprom_sum)); + DPRINTK(1, "eeprom_sum.type=%x, eeprom_sum.result=%x\n", priv->eeprom_sum.type, priv->eeprom_sum.result); + if(priv->eeprom_sum.type == 0){ + priv->eeprom_checksum = EEPROM_CHECKSUM_NONE; + }else if(priv->eeprom_sum.type == 1){ + if(priv->eeprom_sum.result == 0){ + priv->eeprom_checksum = EEPROM_NG; + printk("LOCAL_EEPROM_SUM NG\n"); + }else if(priv->eeprom_sum.result == 1){ + priv->eeprom_checksum = EEPROM_OK; + } + }else{ + printk("LOCAL_EEPROM_SUM error!\n"); + } + break; + default: + DPRINTK(1,"mib_attribute=%08x\n",(unsigned int)mib_attribute); + break; + } +} + +static +void hostif_mib_set_confirm(ks_wlan_private *priv) +{ + uint32_t mib_status; /* +04 MIB Status */ + uint32_t mib_attribute; /* +08 MIB attribute */ + + DPRINTK(3,"\n"); + + mib_status = get_DWORD(priv); /* MIB Status */ + mib_attribute = get_DWORD(priv); /* MIB attribute */ + + if (mib_status != 0) { + /* in case of error */ + DPRINTK(1, "error :: attribute=%08X, status=%08X\n", mib_attribute, mib_status); + } + + switch (mib_attribute) { + case DOT11_RTS_THRESHOLD: + hostif_sme_enqueue(priv, SME_RTS_THRESHOLD_CONFIRM); + break; + case DOT11_FRAGMENTATION_THRESHOLD: + hostif_sme_enqueue(priv, SME_FRAGMENTATION_THRESHOLD_CONFIRM); + break; + case DOT11_WEP_DEFAULT_KEY_ID: + if(!priv->wpa.wpa_enabled) + hostif_sme_enqueue(priv, SME_WEP_INDEX_CONFIRM); + break; + case DOT11_WEP_DEFAULT_KEY_VALUE1: + DPRINTK(2,"DOT11_WEP_DEFAULT_KEY_VALUE1:mib_status=%d\n",(int)mib_status); + if(priv->wpa.rsn_enabled) + hostif_sme_enqueue(priv, SME_SET_PMK_TSC); + else + hostif_sme_enqueue(priv, SME_WEP_KEY1_CONFIRM); + break; + case DOT11_WEP_DEFAULT_KEY_VALUE2: + DPRINTK(2,"DOT11_WEP_DEFAULT_KEY_VALUE2:mib_status=%d\n",(int)mib_status); + if(priv->wpa.rsn_enabled) + hostif_sme_enqueue(priv, SME_SET_GMK1_TSC); + else + hostif_sme_enqueue(priv, SME_WEP_KEY2_CONFIRM); + break; + case DOT11_WEP_DEFAULT_KEY_VALUE3: + DPRINTK(2,"DOT11_WEP_DEFAULT_KEY_VALUE3:mib_status=%d\n",(int)mib_status); + if(priv->wpa.rsn_enabled) + hostif_sme_enqueue(priv, SME_SET_GMK2_TSC); + else + hostif_sme_enqueue(priv, SME_WEP_KEY3_CONFIRM); + break; + case DOT11_WEP_DEFAULT_KEY_VALUE4: + DPRINTK(2,"DOT11_WEP_DEFAULT_KEY_VALUE4:mib_status=%d\n",(int)mib_status); + if(!priv->wpa.rsn_enabled) + hostif_sme_enqueue(priv, SME_WEP_KEY4_CONFIRM); + break; + case DOT11_PRIVACY_INVOKED: + if(!priv->wpa.rsn_enabled) + hostif_sme_enqueue(priv, SME_WEP_FLAG_CONFIRM); + break; + case DOT11_RSN_ENABLED: + DPRINTK(2,"DOT11_RSN_ENABLED:mib_status=%d\n",(int)mib_status); + hostif_sme_enqueue(priv, SME_RSN_ENABLED_CONFIRM); + break; + case LOCAL_RSN_MODE: + hostif_sme_enqueue(priv, SME_RSN_MODE_CONFIRM); + break; + case LOCAL_MULTICAST_ADDRESS: + hostif_sme_enqueue(priv, SME_MULTICAST_REQUEST); + break; + case LOCAL_MULTICAST_FILTER: + hostif_sme_enqueue(priv, SME_MULTICAST_CONFIRM); + break; + case LOCAL_CURRENTADDRESS: + priv->mac_address_valid = 1; + break; + case DOT11_RSN_CONFIG_MULTICAST_CIPHER: + DPRINTK(2,"DOT11_RSN_CONFIG_MULTICAST_CIPHER:mib_status=%d\n",(int)mib_status); + hostif_sme_enqueue(priv, SME_RSN_MCAST_CONFIRM); + break; + case DOT11_RSN_CONFIG_UNICAST_CIPHER: + DPRINTK(2,"DOT11_RSN_CONFIG_UNICAST_CIPHER:mib_status=%d\n",(int)mib_status); + hostif_sme_enqueue(priv, SME_RSN_UCAST_CONFIRM); + break; + case DOT11_RSN_CONFIG_AUTH_SUITE: + DPRINTK(2,"DOT11_RSN_CONFIG_AUTH_SUITE:mib_status=%d\n",(int)mib_status); + hostif_sme_enqueue(priv, SME_RSN_AUTH_CONFIRM); + break; + case DOT11_PMK_TSC: + DPRINTK(2,"DOT11_PMK_TSC:mib_status=%d\n",(int)mib_status); + break; + case DOT11_GMK1_TSC: + DPRINTK(2,"DOT11_GMK1_TSC:mib_status=%d\n",(int)mib_status); + if(atomic_read(&priv->psstatus.snooze_guard)){ + atomic_set(&priv->psstatus.snooze_guard, 0); + } + break; + case DOT11_GMK2_TSC: + DPRINTK(2,"DOT11_GMK2_TSC:mib_status=%d\n",(int)mib_status); + if(atomic_read(&priv->psstatus.snooze_guard)){ + atomic_set(&priv->psstatus.snooze_guard, 0); + } + break; + case LOCAL_PMK: + DPRINTK(2,"LOCAL_PMK:mib_status=%d\n",(int)mib_status); + break; + case LOCAL_GAIN: + DPRINTK(2,"LOCAL_GAIN:mib_status=%d\n",(int)mib_status); + break; +#ifdef WPS + case LOCAL_WPS_ENABLE: + DPRINTK(2,"LOCAL_WPS_ENABLE:mib_status=%d\n",(int)mib_status); + break; + case LOCAL_WPS_PROBE_REQ: + DPRINTK(2,"LOCAL_WPS_PROBE_REQ:mib_status=%d\n",(int)mib_status); + break; +#endif /* WPS */ + case LOCAL_REGION: + DPRINTK(2,"LOCAL_REGION:mib_status=%d\n",(int)mib_status); + default : + break; + } +} + +static +void hostif_power_mngmt_confirm(ks_wlan_private *priv) +{ + DPRINTK(3,"\n"); + + if(priv->reg.powermgt > POWMGT_ACTIVE_MODE && + priv->reg.operation_mode == MODE_INFRASTRUCTURE){ +#if !defined(_SDIO_) + atomic_set(&priv->psstatus.status,PS_SAVE_SET); +#endif + atomic_set(&priv->psstatus.confirm_wait, 0); + priv->dev_state = DEVICE_STATE_SLEEP; + ks_wlan_hw_power_save(priv); + }else{ + priv->dev_state = DEVICE_STATE_READY; +#if !defined(_SDIO_) + atomic_set(&priv->psstatus.status,PS_ACTIVE_SET); +#endif + } + +} + +static +void hostif_sleep_confirm(ks_wlan_private *priv) +{ + DPRINTK(3,"\n"); + + atomic_set(&priv->sleepstatus.doze_request,1); + queue_delayed_work(priv->ks_wlan_hw.ks7010sdio_wq,&priv->ks_wlan_hw.rw_wq, 1); +} + +static +void hostif_start_confirm(ks_wlan_private *priv) +{ +#ifdef WPS + union iwreq_data wrqu; + wrqu.data.length = 0; + wrqu.data.flags = 0; + wrqu.ap_addr.sa_family = ARPHRD_ETHER; + if((priv->connect_status & CONNECT_STATUS_MASK)== CONNECT_STATUS){ + memset(wrqu.ap_addr.sa_data, '\0', ETH_ALEN); + DPRINTK(3,"IWEVENT: disconnect\n"); + wireless_send_event(priv->net_dev, SIOCGIWAP, &wrqu, NULL); + } +#endif + DPRINTK(3," scan_ind_count=%d\n",priv->scan_ind_count); + hostif_sme_enqueue(priv, SME_START_CONFIRM); +} + +static +void hostif_connect_indication(ks_wlan_private *priv) +{ + unsigned short connect_code; + unsigned int tmp=0; + unsigned int old_status=priv->connect_status; + struct net_device *netdev=priv->net_dev; +#if WIRELESS_EXT > 13 + union iwreq_data wrqu0; +#endif /* WIRELESS_EXT > 13 */ + connect_code = get_WORD(priv); + + switch(connect_code){ + case RESULT_CONNECT: /* connect */ + DPRINTK(3,"connect :: scan_ind_count=%d\n",priv->scan_ind_count); + if(!(priv->connect_status & FORCE_DISCONNECT)) + netif_carrier_on(netdev); + tmp = FORCE_DISCONNECT & priv->connect_status; + priv->connect_status = tmp + CONNECT_STATUS; + break; + case RESULT_DISCONNECT: /* disconnect */ + DPRINTK(3,"disconnect :: scan_ind_count=%d\n",priv->scan_ind_count); + netif_carrier_off(netdev); + tmp = FORCE_DISCONNECT & priv->connect_status; + priv->connect_status = tmp + DISCONNECT_STATUS; + break; + default: + DPRINTK(1,"unknown connect_code=%d :: scan_ind_count=%d\n", + connect_code,priv->scan_ind_count); + netif_carrier_off(netdev); + tmp = FORCE_DISCONNECT & priv->connect_status; + priv->connect_status = tmp + DISCONNECT_STATUS; + break; + } + + get_current_ap(priv, (struct link_ap_info_t *)priv->rxp); + if((priv->connect_status & CONNECT_STATUS_MASK)== CONNECT_STATUS && + (old_status & CONNECT_STATUS_MASK)==DISCONNECT_STATUS ){ + /* for power save */ + atomic_set(&priv->psstatus.snooze_guard, 0); + atomic_set(&priv->psstatus.confirm_wait,0); +#if !defined(_SDIO_) + atomic_set(&priv->psstatus.status, PS_NONE); +#endif + } + ks_wlan_do_power_save(priv); + +#if WIRELESS_EXT > 13 + wrqu0.data.length = 0; + wrqu0.data.flags = 0; + wrqu0.ap_addr.sa_family = ARPHRD_ETHER; + if((priv->connect_status & CONNECT_STATUS_MASK)== DISCONNECT_STATUS && + (old_status & CONNECT_STATUS_MASK)==CONNECT_STATUS ){ + memset(wrqu0.ap_addr.sa_data, '\0', ETH_ALEN); + DPRINTK(3,"IWEVENT: disconnect\n"); + DPRINTK(3,"disconnect :: scan_ind_count=%d\n",priv->scan_ind_count); + wireless_send_event(netdev, SIOCGIWAP, &wrqu0, NULL); + } +#endif /* WIRELESS_EXT > 13 */ + priv->scan_ind_count=0; +} + +static +void hostif_scan_indication(ks_wlan_private *priv) +{ + int i; + struct ap_info_t *ap_info; + + DPRINTK(3,"scan_ind_count = %d\n", priv->scan_ind_count); + ap_info = (struct ap_info_t *)(priv->rxp); + + if(priv->scan_ind_count!=0){ + for(i=0;iaplist.size;i++){ /* bssid check */ + if(!memcmp(&(ap_info->bssid[0]),&(priv->aplist.ap[i].bssid[0]),ETH_ALEN)){ + if(ap_info->frame_type == FRAME_TYPE_PROBE_RESP) + get_ap_information(priv,ap_info,&(priv->aplist.ap[i])); + return; + } + } + } + priv->scan_ind_count++; + if(priv->scan_ind_count < LOCAL_APLIST_MAX+1){ + DPRINTK(4," scan_ind_count=%d :: aplist.size=%d\n", priv->scan_ind_count, priv->aplist.size); + get_ap_information(priv,(struct ap_info_t *)(priv->rxp),&(priv->aplist.ap[priv->scan_ind_count-1])); + priv->aplist.size = priv->scan_ind_count; + } + else{ + DPRINTK(4," count over :: scan_ind_count=%d\n", priv->scan_ind_count); + } + + +} + +static +void hostif_stop_confirm(ks_wlan_private *priv) +{ + unsigned int tmp=0; + unsigned int old_status=priv->connect_status; + struct net_device *netdev=priv->net_dev; + union iwreq_data wrqu0; + + DPRINTK(3,"\n"); +#ifdef _SDIO_ + if(priv->dev_state == DEVICE_STATE_SLEEP) + priv->dev_state = DEVICE_STATE_READY; +#endif + + /* disconnect indication */ + if( (priv->connect_status & CONNECT_STATUS_MASK)== CONNECT_STATUS){ + netif_carrier_off(netdev); + tmp = FORCE_DISCONNECT & priv->connect_status; + priv->connect_status = tmp | DISCONNECT_STATUS; + printk("IWEVENT: disconnect\n"); + + wrqu0.data.length = 0; + wrqu0.data.flags = 0; + wrqu0.ap_addr.sa_family = ARPHRD_ETHER; + if((priv->connect_status & CONNECT_STATUS_MASK)== DISCONNECT_STATUS && + (old_status & CONNECT_STATUS_MASK)==CONNECT_STATUS ){ + memset(wrqu0.ap_addr.sa_data, '\0', ETH_ALEN); + DPRINTK(3,"IWEVENT: disconnect\n"); + printk("IWEVENT: disconnect\n"); + DPRINTK(3,"disconnect :: scan_ind_count=%d\n",priv->scan_ind_count); + wireless_send_event(netdev, SIOCGIWAP, &wrqu0, NULL); + } + priv->scan_ind_count=0; + } + + hostif_sme_enqueue(priv, SME_STOP_CONFIRM); +} + +static +void hostif_ps_adhoc_set_confirm(ks_wlan_private *priv) +{ + DPRINTK(3,"\n"); + priv->infra_status = 0; /* infrastructure mode cancel */ + hostif_sme_enqueue(priv, SME_MODE_SET_CONFIRM); + +} + +static +void hostif_infrastructure_set_confirm(ks_wlan_private *priv) +{ + uint16_t result_code; + DPRINTK(3,"\n"); + result_code = get_WORD(priv); + DPRINTK(3,"result code = %d\n",result_code); + priv->infra_status = 1; /* infrastructure mode set */ + hostif_sme_enqueue(priv, SME_MODE_SET_CONFIRM); +} + +static +void hostif_adhoc_set_confirm(ks_wlan_private *priv) +{ + DPRINTK(3,"\n"); + priv->infra_status = 1; /* infrastructure mode set */ + hostif_sme_enqueue(priv, SME_MODE_SET_CONFIRM); +} + +static +void hostif_associate_indication(ks_wlan_private *priv) +{ +#if WIRELESS_EXT > 14 + struct association_request_t *assoc_req; + struct association_response_t *assoc_resp; + unsigned char *pb; + union iwreq_data wrqu; + char buf[IW_CUSTOM_MAX]; + char *pbuf = &buf[0]; + int i; + + static const char associnfo_leader0[] = "ASSOCINFO(ReqIEs="; + static const char associnfo_leader1[] = " RespIEs="; + + DPRINTK(3,"\n"); + assoc_req = (struct association_request_t *)(priv->rxp); + assoc_resp = (struct association_response_t *)(assoc_req+1); + pb = (unsigned char *)(assoc_resp+1); + + memset(&wrqu, 0, sizeof(wrqu)); + memcpy(pbuf,associnfo_leader0,sizeof(associnfo_leader0)-1); + wrqu.data.length += sizeof(associnfo_leader0)-1; + pbuf += sizeof(associnfo_leader0)-1; + + for (i = 0; i < assoc_req->reqIEs_size; i++) + pbuf += sprintf(pbuf, "%02x", *(pb+i)); + wrqu.data.length += (assoc_req->reqIEs_size)*2; + + memcpy(pbuf,associnfo_leader1,sizeof(associnfo_leader1)-1); + wrqu.data.length += sizeof(associnfo_leader1)-1; + pbuf += sizeof(associnfo_leader1)-1; + + pb += assoc_req->reqIEs_size; + for (i = 0; i < assoc_resp->respIEs_size; i++) + pbuf += sprintf(pbuf, "%02x", *(pb+i)); + wrqu.data.length += (assoc_resp->respIEs_size)*2; + + pbuf += sprintf(pbuf, ")"); + wrqu.data.length += 1; + + DPRINTK(3,"IWEVENT:ASSOCINFO\n"); + wireless_send_event(priv->net_dev, IWEVCUSTOM, &wrqu, buf); +#endif /* WIRELESS_EXT > 14 */ +} + +static +void hostif_bss_scan_confirm(ks_wlan_private *priv) +{ + unsigned int result_code; +#if WIRELESS_EXT > 13 + struct net_device *dev = priv->net_dev; + union iwreq_data wrqu; +#endif /* WIRELESS_EXT > 13 */ + result_code = get_DWORD(priv); + DPRINTK(2,"result=%d :: scan_ind_count=%d\n", result_code, priv->scan_ind_count); + + priv->sme_i.sme_flag &= ~SME_AP_SCAN; + hostif_sme_enqueue(priv, SME_BSS_SCAN_CONFIRM); + +#if WIRELESS_EXT > 13 + wrqu.data.length = 0; + wrqu.data.flags = 0; + DPRINTK(3,"IWEVENT: SCAN CONFIRM\n"); + wireless_send_event(dev, SIOCGIWSCAN, &wrqu, NULL); +#endif /* WIRELESS_EXT > 13 */ + priv->scan_ind_count=0; +} + +static +void hostif_phy_information_confirm(ks_wlan_private *priv) +{ + struct iw_statistics *wstats = &priv->wstats; + unsigned char rssi,signal,noise; + unsigned char LinkSpeed; + unsigned int TransmittedFrameCount, ReceivedFragmentCount; + unsigned int FailedCount, FCSErrorCount; + + DPRINTK(3,"\n"); + rssi = get_BYTE(priv); + signal = get_BYTE(priv); + noise = get_BYTE(priv); + LinkSpeed = get_BYTE(priv); + TransmittedFrameCount = get_DWORD(priv); + ReceivedFragmentCount = get_DWORD(priv); + FailedCount = get_DWORD(priv); + FCSErrorCount = get_DWORD(priv); + + DPRINTK(4, "phyinfo confirm rssi=%d signal=%d\n", rssi, signal); + priv->current_rate = (LinkSpeed & RATE_MASK); + wstats->qual.qual = signal; + wstats->qual.level = 256 - rssi; + wstats->qual.noise = 0; /* invalid noise value */ + wstats->qual.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM; + + DPRINTK(3,"\n rssi=%u\n signal=%u\n LinkSpeed=%ux500Kbps\n \ + TransmittedFrameCount=%u\n ReceivedFragmentCount=%u\n FailedCount=%u\n \ + FCSErrorCount=%u\n", + rssi,signal,LinkSpeed,TransmittedFrameCount, + ReceivedFragmentCount,FailedCount,FCSErrorCount); + + /* wake_up_interruptible_all(&priv->confirm_wait); */ + complete(&priv->confirm_wait); +} + +static +void hostif_mic_failure_confirm(ks_wlan_private *priv) +{ + DPRINTK(3,"mic_failure=%u\n",priv->wpa.mic_failure.failure); + hostif_sme_enqueue(priv, SME_MIC_FAILURE_CONFIRM); +} + + +static +void hostif_event_check(ks_wlan_private *priv) +{ + unsigned short event; + + DPRINTK(4, "\n"); + event = get_WORD(priv); /* get event */ + switch (event) { + case HIF_DATA_IND: + hostif_data_indication(priv); + break; + case HIF_MIB_GET_CONF: + hostif_mib_get_confirm(priv); + break; + case HIF_MIB_SET_CONF: + hostif_mib_set_confirm(priv); + break; + case HIF_POWERMGT_CONF: + hostif_power_mngmt_confirm(priv); + break; + case HIF_SLEEP_CONF: + hostif_sleep_confirm(priv); + break; + case HIF_START_CONF: + hostif_start_confirm(priv); + break; + case HIF_CONNECT_IND: + hostif_connect_indication(priv); + break; + case HIF_STOP_CONF: + hostif_stop_confirm(priv); + break; + case HIF_PS_ADH_SET_CONF: + hostif_ps_adhoc_set_confirm(priv); + break; + case HIF_INFRA_SET_CONF: + case HIF_INFRA_SET2_CONF: + hostif_infrastructure_set_confirm(priv); + break; + case HIF_ADH_SET_CONF: + case HIF_ADH_SET2_CONF: + hostif_adhoc_set_confirm(priv); + break; + case HIF_ASSOC_INFO_IND: + hostif_associate_indication(priv); + break; + case HIF_MIC_FAILURE_CONF: + hostif_mic_failure_confirm(priv); + break; + case HIF_SCAN_CONF: + hostif_bss_scan_confirm(priv); + break; + case HIF_PHY_INFO_CONF: + case HIF_PHY_INFO_IND: + hostif_phy_information_confirm(priv); + break; + case HIF_SCAN_IND: + hostif_scan_indication(priv); + break; + case HIF_AP_SET_CONF: + default: + //DPRINTK(1, "undefined event[%04X]\n", event); + printk("undefined event[%04X]\n", event); + /* wake_up_all(&priv->confirm_wait); */ + complete(&priv->confirm_wait); + break; + } + + /* add event to hostt buffer */ + priv->hostt.buff[priv->hostt.qtail] = event; + priv->hostt.qtail = (priv->hostt.qtail + 1) % SME_EVENT_BUFF_SIZE; +} + +#define CHECK_ALINE(size) (size%4 ? (size+(4-(size%4))):size) + +int hostif_data_request(ks_wlan_private *priv, struct sk_buff *packet) +{ + unsigned int packet_len=0; + + unsigned char *buffer=NULL; + unsigned int length=0; + struct hostif_data_request_t *pp; + unsigned char *p; + int result=0; + unsigned short eth_proto; + struct ether_hdr *eth_hdr; + struct michel_mic_t michel_mic; + unsigned short keyinfo=0; + struct ieee802_1x_hdr *aa1x_hdr; + struct wpa_eapol_key *eap_key; + struct ethhdr *eth; + + packet_len = packet->len; + if (packet_len > ETH_FRAME_LEN) { + DPRINTK(1,"bad length packet_len=%d \n", packet_len); + dev_kfree_skb(packet); + return -1; + } + + if(((priv->connect_status & CONNECT_STATUS_MASK)== DISCONNECT_STATUS) || + (priv->connect_status & FORCE_DISCONNECT) || priv->wpa.mic_failure.stop){ + DPRINTK(3," DISCONNECT\n"); + if(netif_queue_stopped(priv->net_dev)) + netif_wake_queue(priv->net_dev); + if(packet) + dev_kfree_skb(packet); + + return 0; + } + + /* for PowerSave */ + if(atomic_read(&priv->psstatus.status)==PS_SNOOZE){ /* power save wakeup */ + if(!netif_queue_stopped(priv->net_dev)) + netif_stop_queue(priv->net_dev); +#if !defined(_SDIO_) + schedule_work(&priv->ks_wlan_wakeup_task); +#endif + } + + DPRINTK(4, "skb_buff length=%d\n", packet_len); + pp = (struct hostif_data_request_t *)kmalloc(hif_align_size(sizeof(*pp)+6+packet_len+8),KS_WLAN_MEM_FLAG ); + + if (pp==NULL) { + DPRINTK(3, "allocate memory failed..\n"); + dev_kfree_skb(packet); + return -2; + } + + p = (unsigned char *)pp->data; + + buffer = packet->data; + length = packet->len; + + /* packet check */ + eth = (struct ethhdr *)packet->data; + if (memcmp(&priv->eth_addr[0],eth->h_source, ETH_ALEN)){ + DPRINTK(1, "invalid mac address !!\n"); + DPRINTK(1, "ethernet->h_source=%02X:%02X:%02X:%02X:%02X:%02X\n", + eth->h_source[0],eth->h_source[1],eth->h_source[2], + eth->h_source[3],eth->h_source[4],eth->h_source[5]); + return -3; + } + + /* MAC address copy */ + memcpy(p, buffer, 12); /* DST/SRC MAC address */ + p += 12; + buffer += 12; + length -= 12; + /* EtherType/Length check */ + if (*(buffer+1) + (*buffer << 8) > 1500) { + /* ProtocolEAP = *(buffer+1) + (*buffer << 8); */ + /* DPRINTK(2, "Send [SNAP]Type %x\n",ProtocolEAP); */ + /* SAP/CTL/OUI(6 byte) add */ + *p++ = 0xAA; /* DSAP */ + *p++ = 0xAA; /* SSAP */ + *p++ = 0x03; /* CTL */ + *p++ = 0x00; /* OUI ("000000") */ + *p++ = 0x00; /* OUI ("000000") */ + *p++ = 0x00; /* OUI ("000000") */ + packet_len += 6; + } else { + DPRINTK(4,"DIX\n"); + /* Length(2 byte) delete */ + buffer += 2; + length -= 2; + packet_len -= 2; + } + + /* pp->data copy */ + memcpy(p, buffer, length); + + p += length; + + /* for WPA */ + eth_hdr = (struct ether_hdr *)&pp->data[0]; + eth_proto = ntohs(eth_hdr->h_proto); + + /* for MIC FAILUER REPORT check */ + if(eth_proto == ETHER_PROTOCOL_TYPE_EAP && priv->wpa.mic_failure.failure>0){ + aa1x_hdr=(struct ieee802_1x_hdr *)(eth_hdr+1); + if(aa1x_hdr->type == IEEE802_1X_TYPE_EAPOL_KEY){ + eap_key = (struct wpa_eapol_key *)(aa1x_hdr+1); + keyinfo=ntohs(eap_key->key_info); + } + } + + if (priv->wpa.rsn_enabled && priv->wpa.key[0].key_len){ + if(eth_proto == ETHER_PROTOCOL_TYPE_EAP && !(priv->wpa.key[1].key_len) && + !(priv->wpa.key[2].key_len) && !(priv->wpa.key[3].key_len)){ + pp->auth_type = cpu_to_le16((uint16_t)TYPE_AUTH); /* no encryption */ + } + else{ + if(priv->wpa.pairwise_suite == IW_AUTH_CIPHER_TKIP){ + MichaelMICFunction( &michel_mic, + (uint8_t*)priv->wpa.key[0].tx_mic_key, + (uint8_t*)&pp->data[0], + (int)packet_len, + (uint8_t)0, /* priority */ + (uint8_t*)michel_mic.Result ); + memcpy(p, michel_mic.Result, 8); + length += 8; + packet_len += 8; + p += 8; + pp->auth_type = cpu_to_le16((uint16_t)TYPE_DATA); + + }else if(priv->wpa.pairwise_suite == IW_AUTH_CIPHER_CCMP){ + pp->auth_type = cpu_to_le16((uint16_t)TYPE_DATA); + } + } + } + else{ + if(eth_proto == ETHER_PROTOCOL_TYPE_EAP) + pp->auth_type = cpu_to_le16((uint16_t)TYPE_AUTH); + else + pp->auth_type = cpu_to_le16((uint16_t)TYPE_DATA); + } + + /* header value set */ + pp->header.size = cpu_to_le16((uint16_t)(sizeof(*pp)-sizeof(pp->header.size)+packet_len)); + pp->header.event = cpu_to_le16((uint16_t)HIF_DATA_REQ); + + /* tx request */ + result = ks_wlan_hw_tx(priv, pp, hif_align_size(sizeof(*pp) + packet_len), + (void *)send_packet_complete, (void *)priv, (void *)packet); + + /* MIC FAILUER REPORT check */ + if(eth_proto == ETHER_PROTOCOL_TYPE_EAP && priv->wpa.mic_failure.failure>0){ + if(keyinfo & WPA_KEY_INFO_ERROR && keyinfo & WPA_KEY_INFO_REQUEST){ + DPRINTK(3," MIC ERROR Report SET : %04X\n", keyinfo); + hostif_sme_enqueue(priv, SME_MIC_FAILURE_REQUEST); + } + if(priv->wpa.mic_failure.failure==2) + priv->wpa.mic_failure.stop=1; + } + + return result; +} + +#if defined(_SPI_) +#define ps_confirm_wait_inc(priv) +#else +#define ps_confirm_wait_inc(priv) do{if(atomic_read(&priv->psstatus.status) > PS_ACTIVE_SET){ \ + atomic_inc(&priv->psstatus.confirm_wait); \ + /* atomic_set(&priv->psstatus.status, PS_CONF_WAIT);*/ \ + } }while(0) +#endif + +static +void hostif_mib_get_request( ks_wlan_private *priv, unsigned long mib_attribute) +{ + struct hostif_mib_get_request_t *pp; + + DPRINTK(3, "\n"); + + /* make primitive */ + pp = (struct hostif_mib_get_request_t *)kmalloc(hif_align_size(sizeof(*pp)), KS_WLAN_MEM_FLAG ); + if (pp==NULL) { + DPRINTK(3,"allocate memory failed..\n"); + return; + } + pp->header.size = cpu_to_le16((uint16_t)(sizeof(*pp)-sizeof(pp->header.size))); + pp->header.event = cpu_to_le16((uint16_t)HIF_MIB_GET_REQ); + pp->mib_attribute = cpu_to_le32((uint32_t)mib_attribute); + + /* send to device request */ + ps_confirm_wait_inc(priv); + ks_wlan_hw_tx( priv, pp, hif_align_size(sizeof(*pp)), NULL, NULL, NULL); +} + +static +void hostif_mib_set_request( ks_wlan_private *priv, unsigned long mib_attribute, + unsigned short size, unsigned short type, + void *vp ) +{ + struct hostif_mib_set_request_t *pp; + + DPRINTK(3,"\n"); + + if (priv->dev_state < DEVICE_STATE_BOOT) { + DPRINTK(3,"DeviceRemove\n"); + return; + } + + /* make primitive */ + pp = (struct hostif_mib_set_request_t *)kmalloc(hif_align_size(sizeof(*pp)+size), KS_WLAN_MEM_FLAG ); + if (pp==NULL) { + DPRINTK(3, "allocate memory failed..\n"); + return; + } + + pp->header.size = cpu_to_le16((uint16_t)(sizeof(*pp)-sizeof(pp->header.size)+size)); + pp->header.event = cpu_to_le16((uint16_t)HIF_MIB_SET_REQ); + pp->mib_attribute = cpu_to_le32((uint32_t)mib_attribute); + pp->mib_value.size = cpu_to_le16((uint16_t)size); + pp->mib_value.type = cpu_to_le16((uint16_t)type); + memcpy(&pp->mib_value.body, vp, size); + + /* send to device request */ + ps_confirm_wait_inc(priv); + ks_wlan_hw_tx(priv, pp, hif_align_size(sizeof(*pp) + size), NULL, NULL, NULL); +} + +static +void hostif_start_request( ks_wlan_private *priv, unsigned char mode ) +{ + struct hostif_start_request_t *pp; + + DPRINTK(3,"\n"); + + /* make primitive */ + pp = (struct hostif_start_request_t *)kmalloc(hif_align_size(sizeof(*pp)), KS_WLAN_MEM_FLAG ); + if (pp==NULL) { + DPRINTK(3, "allocate memory failed..\n"); + return; + } + pp->header.size = cpu_to_le16((uint16_t)(sizeof(*pp)-sizeof(pp->header.size))); + pp->header.event = cpu_to_le16((uint16_t)HIF_START_REQ); + pp->mode = cpu_to_le16((uint16_t)mode); + + /* send to device request */ + ps_confirm_wait_inc(priv); + ks_wlan_hw_tx(priv, pp, hif_align_size(sizeof(*pp)), NULL, NULL, NULL); + + priv->aplist.size = 0; + priv->scan_ind_count=0; +} + +static +void hostif_ps_adhoc_set_request(ks_wlan_private *priv) +{ + struct hostif_ps_adhoc_set_request_t *pp; + uint16_t capability; + + DPRINTK(3,"\n"); + + /* make primitive */ + pp = (struct hostif_ps_adhoc_set_request_t *)kmalloc(hif_align_size(sizeof(*pp)), KS_WLAN_MEM_FLAG ); + if (pp==NULL) { + DPRINTK(3, "allocate memory failed..\n"); + return; + } + memset(pp, 0, sizeof(*pp)); + pp->header.size = cpu_to_le16((uint16_t)(sizeof(*pp)-sizeof(pp->header.size))); + pp->header.event = cpu_to_le16((uint16_t)HIF_PS_ADH_SET_REQ); + pp->phy_type = cpu_to_le16((uint16_t)(priv->reg.phy_type)); + pp->cts_mode = cpu_to_le16((uint16_t)(priv->reg.cts_mode)); + pp->scan_type = cpu_to_le16((uint16_t)(priv->reg.scan_type)); + pp->channel = cpu_to_le16((uint16_t)(priv->reg.channel)); + pp->rate_set.size = priv->reg.rate_set.size; + memcpy(&pp->rate_set.body[0], &priv->reg.rate_set.body[0], priv->reg.rate_set.size); + + capability = 0x0000; + if (priv->reg.preamble==SHORT_PREAMBLE) { + /* short preamble */ + capability |= BSS_CAP_SHORT_PREAMBLE; + } + capability &= ~(BSS_CAP_PBCC); /* pbcc not support */ + if(priv->reg.phy_type != D_11B_ONLY_MODE){ + capability |= BSS_CAP_SHORT_SLOT_TIME; /* ShortSlotTime support */ + capability &= ~(BSS_CAP_DSSS_OFDM); /* DSSS OFDM */ + } + pp->capability = cpu_to_le16((uint16_t)capability); + + /* send to device request */ + ps_confirm_wait_inc(priv); + ks_wlan_hw_tx(priv, pp, hif_align_size(sizeof(*pp)), NULL, NULL, NULL); +} + +static +void hostif_infrastructure_set_request(ks_wlan_private *priv) +{ + struct hostif_infrastructure_set_request_t *pp; + uint16_t capability; + + DPRINTK(3, "ssid.size=%d \n",priv->reg.ssid.size); + + /* make primitive */ + pp = (struct hostif_infrastructure_set_request_t *)kmalloc(hif_align_size(sizeof(*pp)), KS_WLAN_MEM_FLAG ); + if (pp==NULL) { + DPRINTK(3, "allocate memory failed..\n"); + return; + } + pp->header.size = cpu_to_le16((uint16_t)(sizeof(*pp)-sizeof(pp->header.size))); + pp->header.event = cpu_to_le16((uint16_t)HIF_INFRA_SET_REQ); + pp->phy_type = cpu_to_le16((uint16_t)(priv->reg.phy_type)); + pp->cts_mode = cpu_to_le16((uint16_t)(priv->reg.cts_mode)); + pp->scan_type = cpu_to_le16((uint16_t)(priv->reg.scan_type)); + + pp->rate_set.size = priv->reg.rate_set.size; + memcpy(&pp->rate_set.body[0], &priv->reg.rate_set.body[0], priv->reg.rate_set.size); + pp->ssid.size = priv->reg.ssid.size; + memcpy(&pp->ssid.body[0], &priv->reg.ssid.body[0], priv->reg.ssid.size); + + capability = 0x0000; + if (priv->reg.preamble==SHORT_PREAMBLE) { + /* short preamble */ + capability |= BSS_CAP_SHORT_PREAMBLE; + } + capability &= ~(BSS_CAP_PBCC); /* pbcc not support */ + if(priv->reg.phy_type != D_11B_ONLY_MODE){ + capability |= BSS_CAP_SHORT_SLOT_TIME; /* ShortSlotTime support */ + capability &= ~(BSS_CAP_DSSS_OFDM); /* DSSS OFDM not support */ + } + pp->capability = cpu_to_le16((uint16_t)capability); + pp->beacon_lost_count = cpu_to_le16((uint16_t)(priv->reg.beacon_lost_count)); + pp->auth_type = cpu_to_le16((uint16_t)(priv->reg.authenticate_type)); + + pp->channel_list.body[0] = 1; + pp->channel_list.body[1] = 8; + pp->channel_list.body[2] = 2; + pp->channel_list.body[3] = 9; + pp->channel_list.body[4] = 3; + pp->channel_list.body[5] = 10; + pp->channel_list.body[6] = 4; + pp->channel_list.body[7] = 11; + pp->channel_list.body[8] = 5; + pp->channel_list.body[9] = 12; + pp->channel_list.body[10] = 6; + pp->channel_list.body[11] = 13; + pp->channel_list.body[12] = 7; + if(priv->reg.phy_type == D_11G_ONLY_MODE){ + pp->channel_list.size = 13; + }else{ + pp->channel_list.body[13] = 14; + pp->channel_list.size = 14; + } + + /* send to device request */ + ps_confirm_wait_inc(priv); + ks_wlan_hw_tx( priv, pp, hif_align_size(sizeof(*pp)),NULL, NULL, NULL); +} + +void hostif_infrastructure_set2_request(ks_wlan_private *priv) +{ + struct hostif_infrastructure_set2_request_t *pp; + uint16_t capability; + + DPRINTK(2, "ssid.size=%d \n",priv->reg.ssid.size); + + /* make primitive */ + pp = (struct hostif_infrastructure_set2_request_t *)kmalloc(hif_align_size(sizeof(*pp)), KS_WLAN_MEM_FLAG ); + if (pp==NULL) { + DPRINTK(3, "allocate memory failed..\n"); + return; + } + pp->header.size = cpu_to_le16((uint16_t)(sizeof(*pp)-sizeof(pp->header.size))); + pp->header.event = cpu_to_le16((uint16_t)HIF_INFRA_SET2_REQ); + pp->phy_type = cpu_to_le16((uint16_t)(priv->reg.phy_type)); + pp->cts_mode = cpu_to_le16((uint16_t)(priv->reg.cts_mode)); + pp->scan_type = cpu_to_le16((uint16_t)(priv->reg.scan_type)); + + pp->rate_set.size = priv->reg.rate_set.size; + memcpy(&pp->rate_set.body[0], &priv->reg.rate_set.body[0], priv->reg.rate_set.size); + pp->ssid.size = priv->reg.ssid.size; + memcpy(&pp->ssid.body[0], &priv->reg.ssid.body[0], priv->reg.ssid.size); + + capability = 0x0000; + if (priv->reg.preamble==SHORT_PREAMBLE) { + /* short preamble */ + capability |= BSS_CAP_SHORT_PREAMBLE; + } + capability &= ~(BSS_CAP_PBCC); /* pbcc not support */ + if(priv->reg.phy_type != D_11B_ONLY_MODE){ + capability |= BSS_CAP_SHORT_SLOT_TIME; /* ShortSlotTime support */ + capability &= ~(BSS_CAP_DSSS_OFDM); /* DSSS OFDM not support */ + } + pp->capability = cpu_to_le16((uint16_t)capability); + pp->beacon_lost_count = cpu_to_le16((uint16_t)(priv->reg.beacon_lost_count)); + pp->auth_type = cpu_to_le16((uint16_t)(priv->reg.authenticate_type)); + + pp->channel_list.body[0] = 1; + pp->channel_list.body[1] = 8; + pp->channel_list.body[2] = 2; + pp->channel_list.body[3] = 9; + pp->channel_list.body[4] = 3; + pp->channel_list.body[5] = 10; + pp->channel_list.body[6] = 4; + pp->channel_list.body[7] = 11; + pp->channel_list.body[8] = 5; + pp->channel_list.body[9] = 12; + pp->channel_list.body[10] = 6; + pp->channel_list.body[11] = 13; + pp->channel_list.body[12] = 7; + if(priv->reg.phy_type == D_11G_ONLY_MODE){ + pp->channel_list.size = 13; + }else{ + pp->channel_list.body[13] = 14; + pp->channel_list.size = 14; + } + + memcpy(pp->bssid, priv->reg.bssid, ETH_ALEN); + + /* send to device request */ + ps_confirm_wait_inc(priv); + ks_wlan_hw_tx( priv, pp, hif_align_size(sizeof(*pp)),NULL, NULL, NULL); +} + +static +void hostif_adhoc_set_request(ks_wlan_private *priv) +{ + struct hostif_adhoc_set_request_t *pp; + uint16_t capability; + + DPRINTK(3, "\n"); + + /* make primitive */ + pp = (struct hostif_adhoc_set_request_t *)kmalloc(hif_align_size(sizeof(*pp)), KS_WLAN_MEM_FLAG ); + if (pp==NULL) { + DPRINTK(3, "allocate memory failed..\n"); + return; + } + memset(pp, 0, sizeof(*pp)); + pp->header.size = cpu_to_le16((uint16_t)(sizeof(*pp)-sizeof(pp->header.size))); + pp->header.event = cpu_to_le16((uint16_t)HIF_ADH_SET_REQ); + pp->phy_type = cpu_to_le16((uint16_t)(priv->reg.phy_type)); + pp->cts_mode = cpu_to_le16((uint16_t)(priv->reg.cts_mode)); + pp->scan_type = cpu_to_le16((uint16_t)(priv->reg.scan_type)); + pp->channel = cpu_to_le16((uint16_t)(priv->reg.channel)); + pp->rate_set.size = priv->reg.rate_set.size; + memcpy(&pp->rate_set.body[0], &priv->reg.rate_set.body[0], priv->reg.rate_set.size); + pp->ssid.size = priv->reg.ssid.size; + memcpy(&pp->ssid.body[0], &priv->reg.ssid.body[0], priv->reg.ssid.size); + + capability = 0x0000; + if (priv->reg.preamble==SHORT_PREAMBLE) { + /* short preamble */ + capability |= BSS_CAP_SHORT_PREAMBLE; + } + capability &= ~(BSS_CAP_PBCC); /* pbcc not support */ + if(priv->reg.phy_type != D_11B_ONLY_MODE){ + capability |= BSS_CAP_SHORT_SLOT_TIME; /* ShortSlotTime support */ + capability &= ~(BSS_CAP_DSSS_OFDM); /* DSSS OFDM not support */ + } + pp->capability = cpu_to_le16((uint16_t)capability); + + /* send to device request */ + ps_confirm_wait_inc(priv); + ks_wlan_hw_tx( priv, pp, hif_align_size(sizeof(*pp)), NULL, NULL, NULL); +} + +static +void hostif_adhoc_set2_request(ks_wlan_private *priv) +{ + struct hostif_adhoc_set2_request_t *pp; + uint16_t capability; + + DPRINTK(3, "\n"); + + /* make primitive */ + pp = (struct hostif_adhoc_set2_request_t *)kmalloc(hif_align_size(sizeof(*pp)), KS_WLAN_MEM_FLAG ); + if (pp==NULL) { + DPRINTK(3, "allocate memory failed..\n"); + return; + } + memset(pp, 0, sizeof(*pp)); + pp->header.size = cpu_to_le16((uint16_t)(sizeof(*pp)-sizeof(pp->header.size))); + pp->header.event = cpu_to_le16((uint16_t)HIF_ADH_SET_REQ); + pp->phy_type = cpu_to_le16((uint16_t)(priv->reg.phy_type)); + pp->cts_mode = cpu_to_le16((uint16_t)(priv->reg.cts_mode)); + pp->scan_type = cpu_to_le16((uint16_t)(priv->reg.scan_type)); + pp->rate_set.size = priv->reg.rate_set.size; + memcpy(&pp->rate_set.body[0], &priv->reg.rate_set.body[0], priv->reg.rate_set.size); + pp->ssid.size = priv->reg.ssid.size; + memcpy(&pp->ssid.body[0], &priv->reg.ssid.body[0], priv->reg.ssid.size); + + capability = 0x0000; + if (priv->reg.preamble==SHORT_PREAMBLE) { + /* short preamble */ + capability |= BSS_CAP_SHORT_PREAMBLE; + } + capability &= ~(BSS_CAP_PBCC); /* pbcc not support */ + if(priv->reg.phy_type != D_11B_ONLY_MODE){ + capability |= BSS_CAP_SHORT_SLOT_TIME; /* ShortSlotTime support */ + capability &= ~(BSS_CAP_DSSS_OFDM); /* DSSS OFDM not support */ + } + pp->capability = cpu_to_le16((uint16_t)capability); + + pp->channel_list.body[0] = priv->reg.channel; + pp->channel_list.size = 1; + memcpy(pp->bssid, priv->reg.bssid, ETH_ALEN); + + /* send to device request */ + ps_confirm_wait_inc(priv); + ks_wlan_hw_tx( priv, pp, hif_align_size(sizeof(*pp)), NULL, NULL, NULL); +} + +static +void hostif_stop_request( ks_wlan_private *priv ) +{ + struct hostif_stop_request_t *pp; + + DPRINTK(3,"\n"); + + /* make primitive */ + pp = (struct hostif_stop_request_t *)kmalloc(hif_align_size(sizeof(*pp)), KS_WLAN_MEM_FLAG ); + if (pp==NULL) { + DPRINTK(3,"allocate memory failed..\n"); + return; + } + pp->header.size = cpu_to_le16((uint16_t)(sizeof(*pp)-sizeof(pp->header.size))); + pp->header.event = cpu_to_le16((uint16_t)HIF_STOP_REQ); + + /* send to device request */ + ps_confirm_wait_inc(priv); + ks_wlan_hw_tx( priv, pp, hif_align_size(sizeof(*pp)), NULL, NULL, NULL); +} + +static +void hostif_phy_information_request( ks_wlan_private *priv ) +{ + struct hostif_phy_information_request_t *pp; + + DPRINTK(3,"\n"); + + /* make primitive */ + pp = (struct hostif_phy_information_request_t *)kmalloc(hif_align_size(sizeof(*pp)), KS_WLAN_MEM_FLAG ); + if (pp==NULL) { + DPRINTK(3, "allocate memory failed..\n"); + return; + } + pp->header.size = cpu_to_le16((uint16_t)(sizeof(*pp)-sizeof(pp->header.size))); + pp->header.event = cpu_to_le16((uint16_t)HIF_PHY_INFO_REQ); + if(priv->reg.phy_info_timer){ + pp->type = cpu_to_le16((uint16_t)TIME_TYPE); + pp->time = cpu_to_le16((uint16_t)(priv->reg.phy_info_timer)); + }else{ + pp->type = cpu_to_le16((uint16_t)NORMAL_TYPE); + pp->time = cpu_to_le16((uint16_t)0); + } + + /* send to device request */ + ps_confirm_wait_inc(priv); + ks_wlan_hw_tx( priv, pp, hif_align_size(sizeof(*pp)), NULL, NULL, NULL); +} + +static +void hostif_power_mngmt_request( ks_wlan_private *priv, unsigned long mode, + unsigned long wake_up, unsigned long receiveDTIMs ) +{ + struct hostif_power_mngmt_request_t *pp; + + DPRINTK(3,"mode=%lu wake_up=%lu receiveDTIMs=%lu\n",mode,wake_up,receiveDTIMs); + /* make primitive */ + pp = (struct hostif_power_mngmt_request_t *)kmalloc(hif_align_size(sizeof(*pp)), KS_WLAN_MEM_FLAG ); + if (pp==NULL) { + DPRINTK(3,"allocate memory failed..\n"); + return; + } + pp->header.size = cpu_to_le16((uint16_t)(sizeof(*pp)-sizeof(pp->header.size))); + pp->header.event = cpu_to_le16((uint16_t)HIF_POWERMGT_REQ); + pp->mode = cpu_to_le32((uint32_t)mode); + pp->wake_up = cpu_to_le32((uint32_t)wake_up); + pp->receiveDTIMs = cpu_to_le32((uint32_t)receiveDTIMs); + + /* send to device request */ + ps_confirm_wait_inc(priv); + ks_wlan_hw_tx( priv, pp, hif_align_size(sizeof(*pp)), NULL, NULL, NULL); +} + +static +void hostif_sleep_request( ks_wlan_private *priv, unsigned long mode) +{ + struct hostif_sleep_request_t *pp; + + DPRINTK(3,"mode=%lu \n",mode); + + if(mode == SLP_SLEEP){ + /* make primitive */ + pp = (struct hostif_sleep_request_t *)kmalloc(hif_align_size(sizeof(*pp)), KS_WLAN_MEM_FLAG ); + if (pp==NULL) { + DPRINTK(3,"allocate memory failed..\n"); + return; + } + pp->header.size = cpu_to_le16((uint16_t)(sizeof(*pp)-sizeof(pp->header.size))); + pp->header.event = cpu_to_le16((uint16_t)HIF_SLEEP_REQ); + + /* send to device request */ + ps_confirm_wait_inc(priv); + ks_wlan_hw_tx( priv, pp, hif_align_size(sizeof(*pp)), NULL, NULL, NULL); + }else if(mode == SLP_ACTIVE){ + atomic_set(&priv->sleepstatus.wakeup_request,1); + queue_delayed_work(priv->ks_wlan_hw.ks7010sdio_wq,&priv->ks_wlan_hw.rw_wq, 1); + }else{ + DPRINTK(3,"invalid mode %ld \n", mode); + return; + } +} + + +static +void hostif_bss_scan_request( ks_wlan_private *priv, unsigned long scan_type , uint8_t *scan_ssid, uint8_t scan_ssid_len) +{ + struct hostif_bss_scan_request_t *pp; + + DPRINTK(2,"\n"); + /* make primitive */ + pp = (struct hostif_bss_scan_request_t *)kmalloc(hif_align_size(sizeof(*pp)), KS_WLAN_MEM_FLAG ); + if (pp==NULL) { + DPRINTK(3,"allocate memory failed..\n"); + return; + } + pp->header.size = cpu_to_le16((uint16_t)(sizeof(*pp)-sizeof(pp->header.size))); + pp->header.event = cpu_to_le16((uint16_t)HIF_SCAN_REQ); + pp->scan_type = scan_type; + + pp->ch_time_min = cpu_to_le32((uint32_t)110); /* default value */ + pp->ch_time_max = cpu_to_le32((uint32_t)130); /* default value */ + pp->channel_list.body[0] = 1; + pp->channel_list.body[1] = 8; + pp->channel_list.body[2] = 2; + pp->channel_list.body[3] = 9; + pp->channel_list.body[4] = 3; + pp->channel_list.body[5] = 10; + pp->channel_list.body[6] = 4; + pp->channel_list.body[7] = 11; + pp->channel_list.body[8] = 5; + pp->channel_list.body[9] = 12; + pp->channel_list.body[10] = 6; + pp->channel_list.body[11] = 13; + pp->channel_list.body[12] = 7; + if(priv->reg.phy_type == D_11G_ONLY_MODE){ + pp->channel_list.size = 13; + }else{ + pp->channel_list.body[13] = 14; + pp->channel_list.size = 14; + } + pp->ssid.size = 0; + + /* specified SSID SCAN */ + if(scan_ssid_len > 0 && scan_ssid_len <= 32){ + pp->ssid.size = scan_ssid_len; + memcpy(&pp->ssid.body[0], scan_ssid, scan_ssid_len); + } + + + /* send to device request */ + ps_confirm_wait_inc(priv); + ks_wlan_hw_tx( priv, pp, hif_align_size(sizeof(*pp)), NULL, NULL, NULL); + + priv->aplist.size = 0; + priv->scan_ind_count=0; +} + +static +void hostif_mic_failure_request( ks_wlan_private *priv, unsigned short failure_count, + unsigned short timer ) +{ + struct hostif_mic_failure_request_t *pp; + + DPRINTK(3,"count=%d :: timer=%d\n",failure_count,timer); + /* make primitive */ + pp = (struct hostif_mic_failure_request_t *)kmalloc(hif_align_size(sizeof(*pp)), KS_WLAN_MEM_FLAG ); + if (pp==NULL) { + DPRINTK(3,"allocate memory failed..\n"); + return; + } + pp->header.size = cpu_to_le16((uint16_t)(sizeof(*pp)-sizeof(pp->header.size))); + pp->header.event = cpu_to_le16((uint16_t)HIF_MIC_FAILURE_REQ); + pp->failure_count = cpu_to_le16((uint16_t)failure_count); + pp->timer = cpu_to_le16((uint16_t)timer); + + /* send to device request */ + ps_confirm_wait_inc(priv); + ks_wlan_hw_tx( priv, pp, hif_align_size(sizeof(*pp)), NULL, NULL, NULL); +} + +/* Device I/O Recieve indicate */ +static void devio_rec_ind(ks_wlan_private *priv, unsigned char *p, unsigned int size) +{ + if (priv->device_open_status) { + spin_lock(&priv->dev_read_lock); /* request spin lock */ + priv->dev_data[atomic_read(&priv->rec_count)] = p; + priv->dev_size[atomic_read(&priv->rec_count)] = size; + + if (atomic_read(&priv->event_count) != DEVICE_STOCK_COUNT) { + /* rx event count inc */ + atomic_inc(&priv->event_count); + } + atomic_inc(&priv->rec_count); + if (atomic_read(&priv->rec_count)==DEVICE_STOCK_COUNT) + atomic_set(&priv->rec_count, 0); + + wake_up_interruptible_all(&priv->devread_wait); + + /* release spin lock */ + spin_unlock(&priv->dev_read_lock); + } +} + +void hostif_receive( ks_wlan_private *priv, unsigned char *p, unsigned int size ) +{ + DPRINTK(4,"\n"); + + devio_rec_ind(priv, p, size); + + priv->rxp = p; + priv->rx_size = size; + + if (get_WORD(priv) == priv->rx_size) { /* length check !! */ + hostif_event_check(priv); /* event check */ + } +} + + +static +void hostif_sme_set_wep(ks_wlan_private *priv, int type) +{ + uint32_t val; + switch(type){ + case SME_WEP_INDEX_REQUEST: + val = cpu_to_le32((uint32_t)(priv->reg.wep_index)); + hostif_mib_set_request(priv, DOT11_WEP_DEFAULT_KEY_ID, + sizeof(val), MIB_VALUE_TYPE_INT, + &val ); + break; + case SME_WEP_KEY1_REQUEST: + if(!priv->wpa.wpa_enabled) + hostif_mib_set_request(priv, DOT11_WEP_DEFAULT_KEY_VALUE1, + priv->reg.wep_key[0].size, MIB_VALUE_TYPE_OSTRING, + &priv->reg.wep_key[0].val[0] ); + break; + case SME_WEP_KEY2_REQUEST: + if(!priv->wpa.wpa_enabled) + hostif_mib_set_request(priv, DOT11_WEP_DEFAULT_KEY_VALUE2, + priv->reg.wep_key[1].size, MIB_VALUE_TYPE_OSTRING, + &priv->reg.wep_key[1].val[0]); + break; + case SME_WEP_KEY3_REQUEST: + if(!priv->wpa.wpa_enabled) + hostif_mib_set_request(priv, DOT11_WEP_DEFAULT_KEY_VALUE3, + priv->reg.wep_key[2].size, MIB_VALUE_TYPE_OSTRING, + &priv->reg.wep_key[2].val[0] ); + break; + case SME_WEP_KEY4_REQUEST: + if(!priv->wpa.wpa_enabled) + hostif_mib_set_request(priv, DOT11_WEP_DEFAULT_KEY_VALUE4, + priv->reg.wep_key[3].size, MIB_VALUE_TYPE_OSTRING, + &priv->reg.wep_key[3].val[0]); + break; + case SME_WEP_FLAG_REQUEST: + val = cpu_to_le32((uint32_t)(priv->reg.privacy_invoked)); + hostif_mib_set_request(priv, DOT11_PRIVACY_INVOKED, + sizeof(val), MIB_VALUE_TYPE_BOOL, + &val ); + break; + } + + return ; +} + +struct wpa_suite_t { + unsigned short size; + unsigned char suite[4][CIPHER_ID_LEN]; +} __attribute__((packed)); + +struct rsn_mode_t { + uint32_t rsn_mode; + uint16_t rsn_capability; +} __attribute__((packed)); + +static +void hostif_sme_set_rsn(ks_wlan_private *priv, int type) +{ + struct wpa_suite_t wpa_suite; + struct rsn_mode_t rsn_mode; + uint32_t val; + + memset(&wpa_suite,0,sizeof(wpa_suite)); + + switch(type){ + case SME_RSN_UCAST_REQUEST: + wpa_suite.size=cpu_to_le16((uint16_t)1); + switch(priv->wpa.pairwise_suite){ + case IW_AUTH_CIPHER_NONE: + if(priv->wpa.version == IW_AUTH_WPA_VERSION_WPA2) + memcpy(&wpa_suite.suite[0][0],CIPHER_ID_WPA2_NONE,CIPHER_ID_LEN); + else + memcpy(&wpa_suite.suite[0][0],CIPHER_ID_WPA_NONE,CIPHER_ID_LEN); + break; + case IW_AUTH_CIPHER_WEP40: + if(priv->wpa.version == IW_AUTH_WPA_VERSION_WPA2) + memcpy(&wpa_suite.suite[0][0],CIPHER_ID_WPA2_WEP40,CIPHER_ID_LEN); + else + memcpy(&wpa_suite.suite[0][0],CIPHER_ID_WPA_WEP40,CIPHER_ID_LEN); + break; + case IW_AUTH_CIPHER_TKIP: + if(priv->wpa.version == IW_AUTH_WPA_VERSION_WPA2) + memcpy(&wpa_suite.suite[0][0],CIPHER_ID_WPA2_TKIP,CIPHER_ID_LEN); + else + memcpy(&wpa_suite.suite[0][0],CIPHER_ID_WPA_TKIP,CIPHER_ID_LEN); + break; + case IW_AUTH_CIPHER_CCMP: + if(priv->wpa.version == IW_AUTH_WPA_VERSION_WPA2) + memcpy(&wpa_suite.suite[0][0],CIPHER_ID_WPA2_CCMP,CIPHER_ID_LEN); + else + memcpy(&wpa_suite.suite[0][0],CIPHER_ID_WPA_CCMP,CIPHER_ID_LEN); + break; + case IW_AUTH_CIPHER_WEP104: + if(priv->wpa.version == IW_AUTH_WPA_VERSION_WPA2) + memcpy(&wpa_suite.suite[0][0],CIPHER_ID_WPA2_WEP104,CIPHER_ID_LEN); + else + memcpy(&wpa_suite.suite[0][0],CIPHER_ID_WPA_WEP104,CIPHER_ID_LEN); + break; + } + + hostif_mib_set_request(priv, DOT11_RSN_CONFIG_UNICAST_CIPHER, + sizeof(wpa_suite.size)+CIPHER_ID_LEN*wpa_suite.size, + MIB_VALUE_TYPE_OSTRING, &wpa_suite); + break; + case SME_RSN_MCAST_REQUEST: + switch(priv->wpa.group_suite){ + case IW_AUTH_CIPHER_NONE: + if(priv->wpa.version == IW_AUTH_WPA_VERSION_WPA2) + memcpy(&wpa_suite.suite[0][0],CIPHER_ID_WPA2_NONE,CIPHER_ID_LEN); + else + memcpy(&wpa_suite.suite[0][0],CIPHER_ID_WPA_NONE,CIPHER_ID_LEN); + break; + case IW_AUTH_CIPHER_WEP40: + if(priv->wpa.version == IW_AUTH_WPA_VERSION_WPA2) + memcpy(&wpa_suite.suite[0][0],CIPHER_ID_WPA2_WEP40,CIPHER_ID_LEN); + else + memcpy(&wpa_suite.suite[0][0],CIPHER_ID_WPA_WEP40,CIPHER_ID_LEN); + break; + case IW_AUTH_CIPHER_TKIP: + if(priv->wpa.version == IW_AUTH_WPA_VERSION_WPA2) + memcpy(&wpa_suite.suite[0][0],CIPHER_ID_WPA2_TKIP,CIPHER_ID_LEN); + else + memcpy(&wpa_suite.suite[0][0],CIPHER_ID_WPA_TKIP,CIPHER_ID_LEN); + break; + case IW_AUTH_CIPHER_CCMP: + if(priv->wpa.version == IW_AUTH_WPA_VERSION_WPA2) + memcpy(&wpa_suite.suite[0][0],CIPHER_ID_WPA2_CCMP,CIPHER_ID_LEN); + else + memcpy(&wpa_suite.suite[0][0],CIPHER_ID_WPA_CCMP,CIPHER_ID_LEN); + break; + case IW_AUTH_CIPHER_WEP104: + if(priv->wpa.version == IW_AUTH_WPA_VERSION_WPA2) + memcpy(&wpa_suite.suite[0][0],CIPHER_ID_WPA2_WEP104,CIPHER_ID_LEN); + else + memcpy(&wpa_suite.suite[0][0],CIPHER_ID_WPA_WEP104,CIPHER_ID_LEN); + break; + } + + hostif_mib_set_request(priv, DOT11_RSN_CONFIG_MULTICAST_CIPHER, + CIPHER_ID_LEN, MIB_VALUE_TYPE_OSTRING, + &wpa_suite.suite[0][0] ); + break; + case SME_RSN_AUTH_REQUEST: + wpa_suite.size=cpu_to_le16((uint16_t)1); + switch(priv->wpa.key_mgmt_suite){ + case IW_AUTH_KEY_MGMT_802_1X: + if(priv->wpa.version == IW_AUTH_WPA_VERSION_WPA2) + memcpy(&wpa_suite.suite[0][0],KEY_MGMT_ID_WPA2_1X,KEY_MGMT_ID_LEN); + else + memcpy(&wpa_suite.suite[0][0],KEY_MGMT_ID_WPA_1X,KEY_MGMT_ID_LEN); + break; + case IW_AUTH_KEY_MGMT_PSK: + if(priv->wpa.version == IW_AUTH_WPA_VERSION_WPA2) + memcpy(&wpa_suite.suite[0][0],KEY_MGMT_ID_WPA2_PSK,KEY_MGMT_ID_LEN); + else + memcpy(&wpa_suite.suite[0][0],KEY_MGMT_ID_WPA_PSK,KEY_MGMT_ID_LEN); + break; + case 0: + if(priv->wpa.version == IW_AUTH_WPA_VERSION_WPA2) + memcpy(&wpa_suite.suite[0][0],KEY_MGMT_ID_WPA2_NONE,KEY_MGMT_ID_LEN); + else + memcpy(&wpa_suite.suite[0][0],KEY_MGMT_ID_WPA_NONE,KEY_MGMT_ID_LEN); + break; + case 4: + if(priv->wpa.version == IW_AUTH_WPA_VERSION_WPA2) + memcpy(&wpa_suite.suite[0][0],KEY_MGMT_ID_WPA2_WPANONE,KEY_MGMT_ID_LEN); + else + memcpy(&wpa_suite.suite[0][0],KEY_MGMT_ID_WPA_WPANONE,KEY_MGMT_ID_LEN); + break; + } + + hostif_mib_set_request(priv, DOT11_RSN_CONFIG_AUTH_SUITE, + sizeof(wpa_suite.size)+KEY_MGMT_ID_LEN*wpa_suite.size, + MIB_VALUE_TYPE_OSTRING, &wpa_suite); + break; + case SME_RSN_ENABLED_REQUEST: + val = cpu_to_le32((uint32_t)(priv->wpa.rsn_enabled)); + hostif_mib_set_request(priv, DOT11_RSN_ENABLED, + sizeof(val), MIB_VALUE_TYPE_BOOL, + &val ); + break; + case SME_RSN_MODE_REQUEST: + if(priv->wpa.version == IW_AUTH_WPA_VERSION_WPA2){ + rsn_mode.rsn_mode = cpu_to_le32((uint32_t)RSN_MODE_WPA2); + rsn_mode.rsn_capability = cpu_to_le16((uint16_t)0); + } + else if(priv->wpa.version == IW_AUTH_WPA_VERSION_WPA){ + rsn_mode.rsn_mode = cpu_to_le32((uint32_t)RSN_MODE_WPA); + rsn_mode.rsn_capability = cpu_to_le16((uint16_t)0); + } + else{ + rsn_mode.rsn_mode = cpu_to_le32((uint32_t)RSN_MODE_NONE); + rsn_mode.rsn_capability = cpu_to_le16((uint16_t)0); + } + hostif_mib_set_request(priv, LOCAL_RSN_MODE,sizeof(rsn_mode), + MIB_VALUE_TYPE_OSTRING,&rsn_mode ); + break; + + } + return; +} + +static +void hostif_sme_mode_setup(ks_wlan_private *priv) +{ + unsigned char rate_size; + unsigned char rate_octet[RATE_SET_MAX_SIZE]; + int i=0; + + /* rate setting if rate segging is auto for changing phy_type (#94)*/ + if(priv->reg.tx_rate == TX_RATE_FULL_AUTO){ + if(priv->reg.phy_type == D_11B_ONLY_MODE){ + priv->reg.rate_set.body[3] = TX_RATE_11M; + priv->reg.rate_set.body[2] = TX_RATE_5M; + priv->reg.rate_set.body[1] = TX_RATE_2M|BASIC_RATE; + priv->reg.rate_set.body[0] = TX_RATE_1M|BASIC_RATE; + priv->reg.rate_set.size = 4; + }else{ /* D_11G_ONLY_MODE or D_11BG_COMPATIBLE_MODE */ + priv->reg.rate_set.body[11] = TX_RATE_54M; + priv->reg.rate_set.body[10] = TX_RATE_48M; + priv->reg.rate_set.body[9] = TX_RATE_36M; + priv->reg.rate_set.body[8] = TX_RATE_18M; + priv->reg.rate_set.body[7] = TX_RATE_9M; + priv->reg.rate_set.body[6] = TX_RATE_24M|BASIC_RATE; + priv->reg.rate_set.body[5] = TX_RATE_12M|BASIC_RATE; + priv->reg.rate_set.body[4] = TX_RATE_6M|BASIC_RATE; + priv->reg.rate_set.body[3] = TX_RATE_11M|BASIC_RATE; + priv->reg.rate_set.body[2] = TX_RATE_5M|BASIC_RATE; + priv->reg.rate_set.body[1] = TX_RATE_2M|BASIC_RATE; + priv->reg.rate_set.body[0] = TX_RATE_1M|BASIC_RATE; + priv->reg.rate_set.size = 12; + } + } + + /* rate mask by phy setting */ + if(priv->reg.phy_type == D_11B_ONLY_MODE){ + for(i=0;ireg.rate_set.size;i++){ + if(IS_11B_RATE(priv->reg.rate_set.body[i])){ + if((priv->reg.rate_set.body[i] & RATE_MASK) >= TX_RATE_5M) + rate_octet[i] = priv->reg.rate_set.body[i] & RATE_MASK ; + else + rate_octet[i] = priv->reg.rate_set.body[i]; + } + else + break; + } + + }else{ /* D_11G_ONLY_MODE or D_11BG_COMPATIBLE_MODE */ + for(i=0;ireg.rate_set.size;i++){ + if(IS_11BG_RATE(priv->reg.rate_set.body[i])){ + if(IS_OFDM_EXT_RATE(priv->reg.rate_set.body[i])) + rate_octet[i] = priv->reg.rate_set.body[i] & RATE_MASK ; + else + rate_octet[i] = priv->reg.rate_set.body[i]; + } + else + break; + } + } + rate_size = i; + if(rate_size==0){ + if(priv->reg.phy_type == D_11G_ONLY_MODE) + rate_octet[0]=TX_RATE_6M | BASIC_RATE; + else + rate_octet[0]=TX_RATE_2M | BASIC_RATE; + rate_size = 1; + } + + /* rate set update */ + priv->reg.rate_set.size = rate_size; + memcpy(&priv->reg.rate_set.body[0], &rate_octet[0], rate_size); + + switch ( priv->reg.operation_mode ) { + case MODE_PSEUDO_ADHOC: + /* Pseudo Ad-Hoc mode */ + hostif_ps_adhoc_set_request(priv); + break; + case MODE_INFRASTRUCTURE: + /* Infrastructure mode */ + if (!is_valid_ether_addr((u8 *)priv->reg.bssid)) { + hostif_infrastructure_set_request(priv); + } + else { + hostif_infrastructure_set2_request(priv); + DPRINTK(2, "Infra bssid = %02x:%02x:%02x:%02x:%02x:%02x\n", + priv->reg.bssid[0],priv->reg.bssid[1],priv->reg.bssid[2], + priv->reg.bssid[3],priv->reg.bssid[4],priv->reg.bssid[5]); + } + break; + case MODE_ADHOC: + /* IEEE802.11 Ad-Hoc mode */ + if (!is_valid_ether_addr((u8 *)priv->reg.bssid)) { + hostif_adhoc_set_request(priv); + } + else { + hostif_adhoc_set2_request(priv); + DPRINTK(2, "Adhoc bssid = %02x:%02x:%02x:%02x:%02x:%02x\n", + priv->reg.bssid[0],priv->reg.bssid[1],priv->reg.bssid[2], + priv->reg.bssid[3],priv->reg.bssid[4],priv->reg.bssid[5]); + } + break; + default: + break; + } + + return ; +} + +static +void hostif_sme_multicast_set(ks_wlan_private *priv) +{ + + struct net_device *dev = priv->net_dev; + int mc_count; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,35) + struct netdev_hw_addr *ha; +#else + struct dev_mc_list *mclist; +#endif + char set_address[NIC_MAX_MCAST_LIST*ETH_ALEN]; + unsigned long filter_type; + int i; + + DPRINTK(3,"\n"); + + spin_lock(&priv->multicast_spin); + + memset(set_address, 0, NIC_MAX_MCAST_LIST*ETH_ALEN); + + if (dev->flags & IFF_PROMISC ){ + filter_type = cpu_to_le32((uint32_t)MCAST_FILTER_PROMISC); + hostif_mib_set_request(priv, LOCAL_MULTICAST_FILTER, sizeof(filter_type), + MIB_VALUE_TYPE_BOOL, &filter_type); + } + else if ((netdev_mc_count(dev) > NIC_MAX_MCAST_LIST) || (dev->flags & IFF_ALLMULTI)){ + filter_type = cpu_to_le32((uint32_t)MCAST_FILTER_MCASTALL); + hostif_mib_set_request(priv, LOCAL_MULTICAST_FILTER, sizeof(filter_type), + MIB_VALUE_TYPE_BOOL, &filter_type); + } + else { + if (priv->sme_i.sme_flag & SME_MULTICAST){ + mc_count = netdev_mc_count(dev); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,35) + netdev_for_each_mc_addr(ha, dev) { + memcpy(&set_address[i*ETH_ALEN], ha->addr, ETH_ALEN); + } +#else + for (i = 0, mclist = dev->mc_list; mclist && i < mc_count; i++, mclist = mclist->next) + memcpy(&set_address[i*ETH_ALEN], mclist->dmi_addr, ETH_ALEN); +#endif + priv->sme_i.sme_flag &= ~SME_MULTICAST; + hostif_mib_set_request(priv, LOCAL_MULTICAST_ADDRESS, + (ETH_ALEN*mc_count), MIB_VALUE_TYPE_OSTRING, &set_address[0]); + }else { + filter_type = cpu_to_le32((uint32_t)MCAST_FILTER_MCAST); + priv->sme_i.sme_flag |= SME_MULTICAST; + hostif_mib_set_request(priv, LOCAL_MULTICAST_FILTER, sizeof(filter_type), + MIB_VALUE_TYPE_BOOL, &filter_type); + } + } + + spin_unlock(&priv->multicast_spin); + +} + +static +void hostif_sme_powermgt_set(ks_wlan_private *priv) +{ + unsigned long mode,wake_up,receiveDTIMs ; + + DPRINTK(3,"\n"); + switch(priv->reg.powermgt){ + case POWMGT_ACTIVE_MODE: + mode = POWER_ACTIVE; + wake_up = 0; + receiveDTIMs = 0; + break; + case POWMGT_SAVE1_MODE: + if(priv->reg.operation_mode == MODE_INFRASTRUCTURE){ + mode = POWER_SAVE; + wake_up = 0; + receiveDTIMs = 0; + } else { + mode = POWER_ACTIVE; + wake_up = 0; + receiveDTIMs = 0; + } + break; + case POWMGT_SAVE2_MODE: + if(priv->reg.operation_mode == MODE_INFRASTRUCTURE){ + mode = POWER_SAVE; + wake_up = 0; + receiveDTIMs = 1; + } else { + mode = POWER_ACTIVE; + wake_up = 0; + receiveDTIMs = 0; + } + break; + default: + mode = POWER_ACTIVE; + wake_up = 0; + receiveDTIMs = 0; + break; + } + hostif_power_mngmt_request(priv, mode, wake_up, receiveDTIMs); + + return; +} + +static +void hostif_sme_sleep_set(ks_wlan_private *priv) +{ + DPRINTK(3,"\n"); + switch(priv->sleep_mode){ + case SLP_SLEEP: + hostif_sleep_request(priv, priv->sleep_mode); + break; + case SLP_ACTIVE: + hostif_sleep_request(priv, priv->sleep_mode); + break; + default: + break; + } + + return; +} + +static +void hostif_sme_set_key(ks_wlan_private *priv, int type) +{ + uint32_t val; + switch(type){ + case SME_SET_FLAG: + val = cpu_to_le32((uint32_t)(priv->reg.privacy_invoked)); + hostif_mib_set_request(priv, DOT11_PRIVACY_INVOKED, + sizeof(val), MIB_VALUE_TYPE_BOOL, + &val ); + break; + case SME_SET_TXKEY: + val = cpu_to_le32((uint32_t)(priv->wpa.txkey)); + hostif_mib_set_request(priv, DOT11_WEP_DEFAULT_KEY_ID, + sizeof(val), MIB_VALUE_TYPE_INT, + &val ); + break; + case SME_SET_KEY1: + hostif_mib_set_request(priv, DOT11_WEP_DEFAULT_KEY_VALUE1, + priv->wpa.key[0].key_len, MIB_VALUE_TYPE_OSTRING, + &priv->wpa.key[0].key_val[0] ); + break; + case SME_SET_KEY2: + hostif_mib_set_request(priv, DOT11_WEP_DEFAULT_KEY_VALUE2, + priv->wpa.key[1].key_len, MIB_VALUE_TYPE_OSTRING, + &priv->wpa.key[1].key_val[0] ); + break; + case SME_SET_KEY3: + hostif_mib_set_request(priv, DOT11_WEP_DEFAULT_KEY_VALUE3, + priv->wpa.key[2].key_len, MIB_VALUE_TYPE_OSTRING, + &priv->wpa.key[2].key_val[0] ); + break; + case SME_SET_KEY4: + hostif_mib_set_request(priv, DOT11_WEP_DEFAULT_KEY_VALUE4, + priv->wpa.key[3].key_len, MIB_VALUE_TYPE_OSTRING, + &priv->wpa.key[3].key_val[0] ); + break; + case SME_SET_PMK_TSC: + hostif_mib_set_request(priv, DOT11_PMK_TSC, + WPA_RX_SEQ_LEN, MIB_VALUE_TYPE_OSTRING, + &priv->wpa.key[0].rx_seq[0] ); + break; + case SME_SET_GMK1_TSC: + hostif_mib_set_request(priv, DOT11_GMK1_TSC, + WPA_RX_SEQ_LEN, MIB_VALUE_TYPE_OSTRING, + &priv->wpa.key[1].rx_seq[0] ); + break; + case SME_SET_GMK2_TSC: + hostif_mib_set_request(priv, DOT11_GMK2_TSC, + WPA_RX_SEQ_LEN, MIB_VALUE_TYPE_OSTRING, + &priv->wpa.key[2].rx_seq[0] ); + break; + } + return; +} + +static +void hostif_sme_set_pmksa(ks_wlan_private *priv) +{ + struct pmk_cache_t { + uint16_t size; + struct { + uint8_t bssid[ETH_ALEN]; + uint8_t pmkid[IW_PMKID_LEN]; + } __attribute__((packed)) list[PMK_LIST_MAX]; + } __attribute__((packed)) pmkcache; + struct pmk_t *pmk; + struct list_head *ptr; + int i; + + DPRINTK(4,"pmklist.size=%d\n",priv->pmklist.size); + i=0; + list_for_each(ptr, &priv->pmklist.head){ + pmk = list_entry(ptr, struct pmk_t, list); + if(ibssid, ETH_ALEN); + memcpy(pmkcache.list[i].pmkid, pmk->pmkid, IW_PMKID_LEN); + i++; + } + } + pmkcache.size = cpu_to_le16((uint16_t)(priv->pmklist.size)); + hostif_mib_set_request(priv, LOCAL_PMK, + sizeof(priv->pmklist.size)+(ETH_ALEN+IW_PMKID_LEN)*(priv->pmklist.size), + MIB_VALUE_TYPE_OSTRING,&pmkcache ); +} + +/* execute sme */ +static +void hostif_sme_execute(ks_wlan_private *priv, int event) +{ + uint32_t val; + + DPRINTK(3,"event=%d\n",event); + switch (event) { + case SME_START: + if ( priv->dev_state == DEVICE_STATE_BOOT ){ + hostif_mib_get_request(priv, DOT11_MAC_ADDRESS); + } + break; + case SME_MULTICAST_REQUEST: + hostif_sme_multicast_set(priv); + break; + case SME_MACADDRESS_SET_REQUEST: + hostif_mib_set_request(priv, LOCAL_CURRENTADDRESS, ETH_ALEN, + MIB_VALUE_TYPE_OSTRING, &priv->eth_addr[0]); + break; + case SME_BSS_SCAN_REQUEST: + hostif_bss_scan_request(priv, priv->reg.scan_type, priv->scan_ssid, priv->scan_ssid_len); + break; + case SME_POW_MNGMT_REQUEST: + hostif_sme_powermgt_set(priv); + break; + case SME_PHY_INFO_REQUEST: + hostif_phy_information_request(priv); + break; + case SME_MIC_FAILURE_REQUEST: + if(priv->wpa.mic_failure.failure == 1){ + hostif_mic_failure_request(priv, priv->wpa.mic_failure.failure-1, 0); + }else if(priv->wpa.mic_failure.failure == 2){ + hostif_mic_failure_request(priv, priv->wpa.mic_failure.failure-1, + priv->wpa.mic_failure.counter); + }else + DPRINTK(4,"SME_MIC_FAILURE_REQUEST: failure count=%u error?\n", + priv->wpa.mic_failure.failure); + break; + case SME_MIC_FAILURE_CONFIRM: + if(priv->wpa.mic_failure.failure == 2){ + if(priv->wpa.mic_failure.stop) + priv->wpa.mic_failure.stop = 0; + priv->wpa.mic_failure.failure = 0; + hostif_start_request( priv, priv->reg.operation_mode ); + } + break; + case SME_GET_MAC_ADDRESS: + if ( priv->dev_state == DEVICE_STATE_BOOT ){ + hostif_mib_get_request(priv, DOT11_PRODUCT_VERSION); + } + break; + case SME_GET_PRODUCT_VERSION: + if ( priv->dev_state == DEVICE_STATE_BOOT ){ + priv->dev_state = DEVICE_STATE_PREINIT; + } + break; + case SME_STOP_REQUEST: + hostif_stop_request(priv); + break; + case SME_RTS_THRESHOLD_REQUEST: + val = cpu_to_le32((uint32_t)(priv->reg.rts)); + hostif_mib_set_request(priv, DOT11_RTS_THRESHOLD, + sizeof(val), MIB_VALUE_TYPE_INT, + &val ); + break; + case SME_FRAGMENTATION_THRESHOLD_REQUEST: + val = cpu_to_le32((uint32_t)(priv->reg.fragment)); + hostif_mib_set_request(priv, DOT11_FRAGMENTATION_THRESHOLD, + sizeof(val), MIB_VALUE_TYPE_INT, + &val ); + break; + case SME_WEP_INDEX_REQUEST: case SME_WEP_KEY1_REQUEST: + case SME_WEP_KEY2_REQUEST: case SME_WEP_KEY3_REQUEST: + case SME_WEP_KEY4_REQUEST: case SME_WEP_FLAG_REQUEST: + hostif_sme_set_wep(priv,event); + break; + case SME_RSN_UCAST_REQUEST: case SME_RSN_MCAST_REQUEST: + case SME_RSN_AUTH_REQUEST: case SME_RSN_ENABLED_REQUEST: + case SME_RSN_MODE_REQUEST: + hostif_sme_set_rsn(priv,event); + break; + case SME_SET_FLAG: case SME_SET_TXKEY: + case SME_SET_KEY1: case SME_SET_KEY2: + case SME_SET_KEY3: case SME_SET_KEY4: + case SME_SET_PMK_TSC: case SME_SET_GMK1_TSC: + case SME_SET_GMK2_TSC: + hostif_sme_set_key(priv,event); + break; + case SME_SET_PMKSA: + hostif_sme_set_pmksa(priv); + break; +#ifdef WPS + case SME_WPS_ENABLE_REQUEST: + hostif_mib_set_request(priv, LOCAL_WPS_ENABLE, + sizeof(priv->wps.wps_enabled), + MIB_VALUE_TYPE_INT, &priv->wps.wps_enabled ); + break; + case SME_WPS_PROBE_REQUEST: + hostif_mib_set_request(priv, LOCAL_WPS_PROBE_REQ, + priv->wps.ielen, + MIB_VALUE_TYPE_OSTRING, priv->wps.ie); + break; +#endif /* WPS */ + case SME_MODE_SET_REQUEST: + hostif_sme_mode_setup(priv); + break; + case SME_SET_GAIN: + hostif_mib_set_request(priv, LOCAL_GAIN, + sizeof(priv->gain), MIB_VALUE_TYPE_OSTRING, + &priv->gain); + break; + case SME_GET_GAIN: + hostif_mib_get_request(priv, LOCAL_GAIN); + break; + case SME_GET_EEPROM_CKSUM: + priv->eeprom_checksum = EEPROM_FW_NOT_SUPPORT; /* initialize */ + hostif_mib_get_request(priv, LOCAL_EEPROM_SUM); + break; + case SME_START_REQUEST: + hostif_start_request( priv, priv->reg.operation_mode ); + break; + case SME_START_CONFIRM: + /* for power save */ + atomic_set(&priv->psstatus.snooze_guard, 0); + atomic_set(&priv->psstatus.confirm_wait,0); +#if !defined(_SDIO_) + atomic_set(&priv->psstatus.status, PS_NONE); +#endif + if ( priv->dev_state == DEVICE_STATE_PREINIT ){ + priv->dev_state = DEVICE_STATE_INIT; + } + /* wake_up_interruptible_all(&priv->confirm_wait); */ + complete(&priv->confirm_wait); + break; + case SME_SLEEP_REQUEST: + hostif_sme_sleep_set(priv); + break; + case SME_SET_REGION: + val = cpu_to_le32((uint32_t)(priv->region)); + hostif_mib_set_request(priv, LOCAL_REGION, + sizeof(val), MIB_VALUE_TYPE_INT, + &val ); + break; + case SME_MULTICAST_CONFIRM: + case SME_BSS_SCAN_CONFIRM: + case SME_POW_MNGMT_CONFIRM: + case SME_PHY_INFO_CONFIRM: + case SME_STOP_CONFIRM: + case SME_RTS_THRESHOLD_CONFIRM: + case SME_FRAGMENTATION_THRESHOLD_CONFIRM: + case SME_WEP_INDEX_CONFIRM: case SME_WEP_KEY1_CONFIRM: + case SME_WEP_KEY2_CONFIRM: case SME_WEP_KEY3_CONFIRM: + case SME_WEP_KEY4_CONFIRM: case SME_WEP_FLAG_CONFIRM: + case SME_RSN_UCAST_CONFIRM: case SME_RSN_MCAST_CONFIRM: + case SME_RSN_AUTH_CONFIRM: case SME_RSN_ENABLED_CONFIRM: + case SME_RSN_MODE_CONFIRM: + case SME_MODE_SET_CONFIRM: + break; + case SME_TERMINATE: + default: + break; + } +} + +static +void hostif_sme_task( unsigned long dev ) +{ + ks_wlan_private *priv = (ks_wlan_private *)dev; + + DPRINTK(3,"\n"); + + if(priv->dev_state >= DEVICE_STATE_BOOT){ + if (0 < cnt_smeqbody(priv) && priv->dev_state >= DEVICE_STATE_BOOT) { + hostif_sme_execute(priv, priv->sme_i.event_buff[priv->sme_i.qhead]); + inc_smeqhead(priv); + if (0 < cnt_smeqbody(priv)) + tasklet_schedule(&priv->sme_task); + } + } + return; +} + +/* send to Station Management Entity module */ +void hostif_sme_enqueue(ks_wlan_private *priv, unsigned short event) +{ + DPRINTK(3,"\n"); + +#if !defined(_SDIO_) + if(atomic_read(&priv->psstatus.status)==PS_SNOOZE && event < SME_START_CONFIRM){ /* power save wakeup*/ + schedule_work(&priv->ks_wlan_wakeup_task); + if(atomic_read(&priv->sme_task.count) <= 0){ + /* schedule_work(&priv->ks_wlan_wakeup_task); */ + DPRINTK(4,"sme task disable.\n"); + tasklet_disable(&priv->sme_task); + } + } +#endif + + + /* enqueue sme event */ + if (cnt_smeqbody(priv) < (SME_EVENT_BUFF_SIZE - 1)) { + priv->sme_i.event_buff[priv->sme_i.qtail] = event; + inc_smeqtail(priv); + //DPRINTK(3,"inc_smeqtail \n"); +#ifdef KS_WLAN_DEBUG + if (priv->sme_i.max_event_count < cnt_smeqbody(priv)) + priv->sme_i.max_event_count = cnt_smeqbody(priv); +#endif /* KS_WLAN_DEBUG */ + } else { + /* in case of buffer overflow */ + //DPRINTK(2,"sme queue buffer overflow\n"); + printk("sme queue buffer overflow\n"); + } + + tasklet_schedule(&priv->sme_task); + +} + +int hostif_init( ks_wlan_private *priv ) +{ + int rc=0; + int i; + + DPRINTK(3,"\n"); + + priv->aplist.size =0; + for(i=0;iaplist.ap[i]),0,sizeof(struct local_ap_t)); + priv->infra_status = 0; + priv->current_rate = 4; + priv->connect_status = DISCONNECT_STATUS; + + spin_lock_init(&priv->multicast_spin); + + spin_lock_init(&priv->dev_read_lock); + init_waitqueue_head (&priv->devread_wait); + priv->dev_count = 0; + atomic_set(&priv->event_count, 0); + atomic_set(&priv->rec_count, 0); + + /* for power save */ + atomic_set(&priv->psstatus.status, PS_NONE); + atomic_set(&priv->psstatus.confirm_wait, 0); + atomic_set(&priv->psstatus.snooze_guard, 0); + /* init_waitqueue_head(&priv->psstatus.wakeup_wait); */ + init_completion(&priv->psstatus.wakeup_wait); + //INIT_WORK(&priv->ks_wlan_wakeup_task, ks_wlan_hw_wakeup_task, (void *)priv); + INIT_WORK(&priv->ks_wlan_wakeup_task, ks_wlan_hw_wakeup_task); + + /* WPA */ + memset(&(priv->wpa), 0, sizeof(priv->wpa)); + priv->wpa.rsn_enabled = 0; + priv->wpa.mic_failure.failure = 0; + priv->wpa.mic_failure.last_failure_time = 0; + priv->wpa.mic_failure.stop = 0; + memset(&(priv->pmklist), 0, sizeof(priv->pmklist)); + INIT_LIST_HEAD(&priv->pmklist.head); + for(i=0;ipmklist.pmk[i].list); + + priv->sme_i.sme_status = SME_IDLE; + priv->sme_i.qhead = priv->sme_i.qtail = 0; +#ifdef KS_WLAN_DEBUG + priv->sme_i.max_event_count = 0; +#endif + spin_lock_init(&priv->sme_i.sme_spin); + priv->sme_i.sme_flag = 0; + + tasklet_init(&priv->sme_task, hostif_sme_task, (unsigned long)priv); + + return rc; +} + +void hostif_exit( ks_wlan_private *priv ) +{ + tasklet_kill(&priv->sme_task); + return; +} + diff --git a/drivers/staging/ks7010/ks_hostif.h b/drivers/staging/ks7010/ks_hostif.h new file mode 100644 index 0000000..24ebf1d --- /dev/null +++ b/drivers/staging/ks7010/ks_hostif.h @@ -0,0 +1,648 @@ +/* + * Driver for KeyStream wireless LAN + * + * ks_hostif.h + * $Id: ks_hostif.h 994 2009-09-14 01:51:16Z sekine $ + * + * Copyright (c) 2005-2008 KeyStream Corp. + * Copyright (C) 2009 Renesas Technology Corp. + * + * This program is free software; you can redistribute it and/or modify + * it undr the terms of the GNU General Public License version 2 as + * published by the Free Sotware Foundation. + */ + +#ifndef _KS_HOSTIF_H_ +#define _KS_HOSTIF_H_ +/* + * HOST-MAC I/F events + */ +#define HIF_DATA_REQ 0xE001 +#define HIF_DATA_IND 0xE801 +#define HIF_MIB_GET_REQ 0xE002 +#define HIF_MIB_GET_CONF 0xE802 +#define HIF_MIB_SET_REQ 0xE003 +#define HIF_MIB_SET_CONF 0xE803 +#define HIF_POWERMGT_REQ 0xE004 +#define HIF_POWERMGT_CONF 0xE804 +#define HIF_START_REQ 0xE005 +#define HIF_START_CONF 0xE805 +#define HIF_CONNECT_IND 0xE806 +#define HIF_STOP_REQ 0xE006 +#define HIF_STOP_CONF 0xE807 +#define HIF_PS_ADH_SET_REQ 0xE007 +#define HIF_PS_ADH_SET_CONF 0xE808 +#define HIF_INFRA_SET_REQ 0xE008 +#define HIF_INFRA_SET_CONF 0xE809 +#define HIF_ADH_SET_REQ 0xE009 +#define HIF_ADH_SET_CONF 0xE80A +#define HIF_AP_SET_REQ 0xE00A +#define HIF_AP_SET_CONF 0xE80B +#define HIF_ASSOC_INFO_IND 0xE80C +#define HIF_MIC_FAILURE_REQ 0xE00B +#define HIF_MIC_FAILURE_CONF 0xE80D +#define HIF_SCAN_REQ 0xE00C +#define HIF_SCAN_CONF 0xE80E +#define HIF_PHY_INFO_REQ 0xE00D +#define HIF_PHY_INFO_CONF 0xE80F +#define HIF_SLEEP_REQ 0xE00E +#define HIF_SLEEP_CONF 0xE810 +#define HIF_PHY_INFO_IND 0xE811 +#define HIF_SCAN_IND 0xE812 +#define HIF_INFRA_SET2_REQ 0xE00F +#define HIF_INFRA_SET2_CONF 0xE813 +#define HIF_ADH_SET2_REQ 0xE010 +#define HIF_ADH_SET2_CONF 0xE814 + +#define HIF_REQ_MAX 0xE010 + +/* + * HOST-MAC I/F data structure + * Byte alignmet Little Endian + */ + +struct hostif_hdr { + uint16_t size; + uint16_t event; +} __attribute__((packed)); + +struct hostif_data_request_t { + struct hostif_hdr header; + uint16_t auth_type; +#define TYPE_DATA 0x0000 +#define TYPE_AUTH 0x0001 + uint16_t reserved; + uint8_t data[0]; +} __attribute__((packed)); + +struct hostif_data_indication_t { + struct hostif_hdr header; + uint16_t auth_type; +/* #define TYPE_DATA 0x0000 */ +#define TYPE_PMK1 0x0001 +#define TYPE_GMK1 0x0002 +#define TYPE_GMK2 0x0003 + uint16_t reserved; + uint8_t data[0]; +} __attribute__((packed)); + +#define CHANNEL_LIST_MAX_SIZE 14 +struct channel_list_t { + uint8_t size; + uint8_t body[CHANNEL_LIST_MAX_SIZE]; + uint8_t pad; +} __attribute__((packed)); + +/* MIB Attribute */ +#define DOT11_MAC_ADDRESS 0x21010100 /* MAC Address (R) */ +#define DOT11_PRODUCT_VERSION 0x31024100 /* FirmWare Version (R)*/ +#define DOT11_RTS_THRESHOLD 0x21020100 /* RTS Threshold (R/W) */ +#define DOT11_FRAGMENTATION_THRESHOLD 0x21050100 /* Fragment Threshold (R/W) */ +#define DOT11_PRIVACY_INVOKED 0x15010100 /* WEP ON/OFF (W) */ +#define DOT11_WEP_DEFAULT_KEY_ID 0x15020100 /* WEP Index (W) */ +#define DOT11_WEP_DEFAULT_KEY_VALUE1 0x13020101 /* WEP Key#1(TKIP AES: PairwiseTemporalKey) (W) */ +#define DOT11_WEP_DEFAULT_KEY_VALUE2 0x13020102 /* WEP Key#2(TKIP AES: GroupKey1) (W) */ +#define DOT11_WEP_DEFAULT_KEY_VALUE3 0x13020103 /* WEP Key#3(TKIP AES: GroupKey2) (W) */ +#define DOT11_WEP_DEFAULT_KEY_VALUE4 0x13020104 /* WEP Key#4 (W) */ +#define DOT11_WEP_LIST 0x13020100 /* WEP LIST */ +#define DOT11_DESIRED_SSID 0x11090100 /* SSID */ +#define DOT11_CURRENT_CHANNEL 0x45010100 /* channel set */ +#define DOT11_OPERATION_RATE_SET 0x11110100 /* rate set */ + +#define LOCAL_AP_SEARCH_INTEAVAL 0xF1010100 /* AP search interval (R/W) */ +#define LOCAL_CURRENTADDRESS 0xF1050100 /* MAC Adress change (W) */ +#define LOCAL_MULTICAST_ADDRESS 0xF1060100 /* Multicast Adress (W) */ +#define LOCAL_MULTICAST_FILTER 0xF1060200 /* Multicast Adress Filter enable/disable (W) */ +#define LOCAL_SEARCHED_AP_LIST 0xF1030100 /* AP list (R) */ +#define LOCAL_LINK_AP_STATUS 0xF1040100 /* Link AP status (R) */ +#define LOCAL_PACKET_STATISTICS 0xF1020100 /* tx,rx packets statistics */ +#define LOCAL_AP_SCAN_LIST_TYPE_SET 0xF1030200 /* AP_SCAN_LIST_TYPE */ + +#define DOT11_RSN_ENABLED 0x15070100 /* WPA enable/disable (W) */ +#define LOCAL_RSN_MODE 0x56010100 /* RSN mode WPA/WPA2 (W) */ +#define DOT11_RSN_CONFIG_MULTICAST_CIPHER 0x51040100 /* GroupKeyCipherSuite (W) */ +#define DOT11_RSN_CONFIG_UNICAST_CIPHER 0x52020100 /* PairwiseKeyCipherSuite (W) */ +#define DOT11_RSN_CONFIG_AUTH_SUITE 0x53020100 /* AuthenticationKeyManagementSuite (W) */ +#define DOT11_RSN_CONFIG_VERSION 0x51020100 /* RSN version (W) */ +#define LOCAL_RSN_CONFIG_ALL 0x5F010100 /* RSN CONFIG ALL (W) */ +#define DOT11_PMK_TSC 0x55010100 /* PMK_TSC (W) */ +#define DOT11_GMK1_TSC 0x55010101 /* GMK1_TSC (W) */ +#define DOT11_GMK2_TSC 0x55010102 /* GMK2_TSC (W) */ +#define DOT11_GMK3_TSC 0x55010103 /* GMK3_TSC */ +#define LOCAL_PMK 0x58010100 /* Pairwise Master Key cache (W) */ + +#define LOCAL_REGION 0xF10A0100 /* Region setting */ + +#ifdef WPS +#define LOCAL_WPS_ENABLE 0xF10B0100 /* WiFi Protected Setup */ +#define LOCAL_WPS_PROBE_REQ 0xF10C0100 /* WPS Probe Request */ +#endif /* WPS */ + +#define LOCAL_GAIN 0xF10D0100 /* Carrer sense threshold for demo ato show */ +#define LOCAL_EEPROM_SUM 0xF10E0100 /* EEPROM checksum information */ + +struct hostif_mib_get_request_t { + struct hostif_hdr header; + uint32_t mib_attribute; +} __attribute__((packed)); + + +struct hostif_mib_value_t { + uint16_t size; + uint16_t type; +#define MIB_VALUE_TYPE_NULL 0 +#define MIB_VALUE_TYPE_INT 1 +#define MIB_VALUE_TYPE_BOOL 2 +#define MIB_VALUE_TYPE_COUNT32 3 +#define MIB_VALUE_TYPE_OSTRING 4 + uint8_t body[0]; +} __attribute__((packed)); + +struct hostif_mib_get_confirm_t { + struct hostif_hdr header; + uint32_t mib_status; +#define MIB_SUCCESS 0 +#define MIB_INVALID 1 +#define MIB_READ_ONLY 2 +#define MIB_WRITE_ONLY 3 + uint32_t mib_attribute; + struct hostif_mib_value_t mib_value; +} __attribute__((packed)); + +struct hostif_mib_set_request_t { + struct hostif_hdr header; + uint32_t mib_attribute; + struct hostif_mib_value_t mib_value; +} __attribute__((packed)); + +struct hostif_mib_set_confirm_t { + struct hostif_hdr header; + uint32_t mib_status; + uint32_t mib_attribute; +} __attribute__((packed)); + +struct hostif_power_mngmt_request_t { + struct hostif_hdr header; + uint32_t mode; +#define POWER_ACTIVE 1 +#define POWER_SAVE 2 + uint32_t wake_up; +#define SLEEP_FALSE 0 +#define SLEEP_TRUE 1 /* not used */ + uint32_t receiveDTIMs; +#define DTIM_FALSE 0 +#define DTIM_TRUE 1 +} __attribute__((packed)); + +/* power management mode */ +enum { + POWMGT_ACTIVE_MODE=0, + POWMGT_SAVE1_MODE, + POWMGT_SAVE2_MODE +}; + +#define RESULT_SUCCESS 0 +#define RESULT_INVALID_PARAMETERS 1 +#define RESULT_NOT_SUPPORTED 2 +/* #define RESULT_ALREADY_RUNNING 3 */ +#define RESULT_ALREADY_RUNNING 7 + +struct hostif_power_mngmt_confirm_t { + struct hostif_hdr header; + uint16_t result_code; +} __attribute__((packed)); + +struct hostif_start_request_t { + struct hostif_hdr header; + uint16_t mode; +#define MODE_PSEUDO_ADHOC 0 +#define MODE_INFRASTRUCTURE 1 +#define MODE_AP 2 /* not used */ +#define MODE_ADHOC 3 +} __attribute__((packed)); + +struct hostif_start_confirm_t { + struct hostif_hdr header; + uint16_t result_code; +} __attribute__((packed)); + +#define SSID_MAX_SIZE 32 +struct ssid_t { + uint8_t size; + uint8_t body[SSID_MAX_SIZE]; + uint8_t ssid_pad; +} __attribute__((packed)); + +#define RATE_SET_MAX_SIZE 16 +struct rate_set8_t { + uint8_t size; + uint8_t body[8]; + uint8_t rate_pad; +} __attribute__((packed)); + +struct FhParms_t { + uint16_t dwellTime; + uint8_t hopSet; + uint8_t hopPattern; + uint8_t hopIndex; +} __attribute__((packed)); + +struct DsParms_t { + uint8_t channel; +} __attribute__((packed)); + +struct CfParms_t { + uint8_t count; + uint8_t period; + uint16_t maxDuration; + uint16_t durRemaining; +} __attribute__((packed)); + +struct IbssParms_t { + uint16_t atimWindow; +} __attribute__((packed)); + + +struct rsn_t { + uint8_t size; +#define RSN_BODY_SIZE 64 + uint8_t body[RSN_BODY_SIZE]; +} __attribute__((packed)); + +struct ErpParams_t { + uint8_t erp_info; +} __attribute__((packed)); + +struct rate_set16_t{ + uint8_t size; + uint8_t body[16]; + uint8_t rate_pad; +} __attribute__((packed)); + +struct ap_info_t{ + uint8_t bssid[6]; /* +00 */ + uint8_t rssi; /* +06 */ + uint8_t sq; /* +07 */ + uint8_t noise; /* +08 */ + uint8_t pad0; /* +09 */ + uint16_t beacon_period; /* +10 */ + uint16_t capability; /* +12 */ +#define BSS_CAP_ESS (1<<0) +#define BSS_CAP_IBSS (1<<1) +#define BSS_CAP_CF_POLABLE (1<<2) +#define BSS_CAP_CF_POLL_REQ (1<<3) +#define BSS_CAP_PRIVACY (1<<4) +#define BSS_CAP_SHORT_PREAMBLE (1<<5) +#define BSS_CAP_PBCC (1<<6) +#define BSS_CAP_CHANNEL_AGILITY (1<<7) +#define BSS_CAP_SHORT_SLOT_TIME (1<<10) +#define BSS_CAP_DSSS_OFDM (1<<13) + uint8_t frame_type; /* +14 */ + uint8_t ch_info; /* +15 */ +#define FRAME_TYPE_BEACON 0x80 +#define FRAME_TYPE_PROBE_RESP 0x50 + uint16_t body_size; /* +16 */ + uint8_t body[1024]; /* +18 */ + /* +1032 */ +} __attribute__((packed)); + +struct link_ap_info_t{ + uint8_t bssid[6]; /* +00 */ + uint8_t rssi; /* +06 */ + uint8_t sq; /* +07 */ + uint8_t noise; /* +08 */ + uint8_t pad0; /* +09 */ + uint16_t beacon_period; /* +10 */ + uint16_t capability; /* +12 */ + struct rate_set8_t rate_set; /* +14 */ + struct FhParms_t fh_parameter; /* +24 */ + struct DsParms_t ds_parameter; /* +29 */ + struct CfParms_t cf_parameter; /* +30 */ + struct IbssParms_t ibss_parameter; /* +36 */ + struct ErpParams_t erp_parameter; /* +38 */ + uint8_t pad1; /* +39 */ + struct rate_set8_t ext_rate_set; /* +40 */ + uint8_t DTIM_period; /* +50 */ + uint8_t rsn_mode; /* +51 */ +#define RSN_MODE_NONE 0 +#define RSN_MODE_WPA 1 +#define RSN_MODE_WPA2 2 + struct { + uint8_t size; /* +52 */ + uint8_t body[128]; /* +53 */ + } __attribute__((packed)) rsn; +} __attribute__((packed)); + +struct hostif_connect_indication_t { + struct hostif_hdr header; + uint16_t connect_code; +#define RESULT_CONNECT 0 +#define RESULT_DISCONNECT 1 + struct link_ap_info_t link_ap_info; +} __attribute__((packed)); + +struct hostif_stop_request_t { + struct hostif_hdr header; +} __attribute__((packed)); + +struct hostif_stop_confirm_t { + struct hostif_hdr header; + uint16_t result_code; +} __attribute__((packed)); + +struct hostif_ps_adhoc_set_request_t { + struct hostif_hdr header; + uint16_t phy_type; +#define D_11B_ONLY_MODE 0 +#define D_11G_ONLY_MODE 1 +#define D_11BG_COMPATIBLE_MODE 2 +#define D_11A_ONLY_MODE 3 + uint16_t cts_mode; +#define CTS_MODE_FALSE 0 +#define CTS_MODE_TRUE 1 + uint16_t channel; + struct rate_set16_t rate_set; + uint16_t capability; /* bit5:preamble bit6:pbcc pbcc not supported always 0 + * bit10:ShortSlotTime bit13:DSSS-OFDM DSSS-OFDM not supported always 0 */ + uint16_t scan_type; +} __attribute__((packed)); + +struct hostif_ps_adhoc_set_confirm_t { + struct hostif_hdr header; + uint16_t result_code; +} __attribute__((packed)); + +struct hostif_infrastructure_set_request_t { + struct hostif_hdr header; + uint16_t phy_type; + uint16_t cts_mode; + struct rate_set16_t rate_set; + struct ssid_t ssid; + uint16_t capability; /* bit5:preamble bit6:pbcc pbcc not supported always 0 + * bit10:ShortSlotTime bit13:DSSS-OFDM DSSS-OFDM not supported always 0 */ + uint16_t beacon_lost_count; + uint16_t auth_type; +#define AUTH_TYPE_OPEN_SYSTEM 0 +#define AUTH_TYPE_SHARED_KEY 1 + struct channel_list_t channel_list; + uint16_t scan_type; +} __attribute__((packed)); + +struct hostif_infrastructure_set2_request_t { + struct hostif_hdr header; + uint16_t phy_type; + uint16_t cts_mode; + struct rate_set16_t rate_set; + struct ssid_t ssid; + uint16_t capability; /* bit5:preamble bit6:pbcc pbcc not supported always 0 + * bit10:ShortSlotTime bit13:DSSS-OFDM DSSS-OFDM not supported always 0 */ + uint16_t beacon_lost_count; + uint16_t auth_type; +#define AUTH_TYPE_OPEN_SYSTEM 0 +#define AUTH_TYPE_SHARED_KEY 1 + struct channel_list_t channel_list; + uint16_t scan_type; + uint8_t bssid[ETH_ALEN]; +} __attribute__((packed)); + + +struct hostif_infrastructure_set_confirm_t { + struct hostif_hdr header; + uint16_t result_code; +} __attribute__((packed)); + +struct hostif_adhoc_set_request_t { + struct hostif_hdr header; + uint16_t phy_type; + uint16_t cts_mode; + uint16_t channel; + struct rate_set16_t rate_set; + struct ssid_t ssid; + uint16_t capability; /* bit5:preamble bit6:pbcc pbcc not supported always 0 + * bit10:ShortSlotTime bit13:DSSS-OFDM DSSS-OFDM not supported always 0 */ + uint16_t scan_type; +} __attribute__((packed)); + +struct hostif_adhoc_set2_request_t { + struct hostif_hdr header; + uint16_t phy_type; + uint16_t cts_mode; + uint16_t reserved; + struct rate_set16_t rate_set; + struct ssid_t ssid; + uint16_t capability; /* bit5:preamble bit6:pbcc pbcc not supported always 0 + * bit10:ShortSlotTime bit13:DSSS-OFDM DSSS-OFDM not supported always 0 */ + uint16_t scan_type; + struct channel_list_t channel_list; + uint8_t bssid[ETH_ALEN]; +} __attribute__((packed)); + +struct hostif_adhoc_set_confirm_t { + struct hostif_hdr header; + uint16_t result_code; +} __attribute__((packed)); + + +struct last_associate_t { + uint8_t type; + uint8_t status; +} __attribute__((packed)); + +struct association_request_t { + uint8_t type; +#define FRAME_TYPE_ASSOC_REQ 0x00 +#define FRAME_TYPE_REASSOC_REQ 0x20 + uint8_t pad; + uint16_t capability; + uint16_t listen_interval; + uint8_t ap_address[6]; + uint16_t reqIEs_size; +} __attribute__((packed)); + +struct association_response_t { + uint8_t type; +#define FRAME_TYPE_ASSOC_RESP 0x10 +#define FRAME_TYPE_REASSOC_RESP 0x30 + uint8_t pad; + uint16_t capability; + uint16_t status; + uint16_t association_id; + uint16_t respIEs_size; +} __attribute__((packed)); + +struct hostif_associate_indication_t { + struct hostif_hdr header; + struct association_request_t assoc_req; + struct association_response_t assoc_resp; + /* followed by (reqIEs_size + respIEs_size) octets of data */ + /* reqIEs data *//* respIEs data */ +} __attribute__((packed)); + +struct hostif_bss_scan_request_t { + struct hostif_hdr header; + uint8_t scan_type; +#define ACTIVE_SCAN 0 +#define PASSIVE_SCAN 1 + uint8_t pad[3]; + uint32_t ch_time_min; + uint32_t ch_time_max; + struct channel_list_t channel_list; + struct ssid_t ssid; +} __attribute__((packed)); + +struct hostif_bss_scan_confirm_t { + struct hostif_hdr header; + uint16_t result_code; + uint16_t reserved; +} __attribute__((packed)); + +struct hostif_phy_information_request_t { + struct hostif_hdr header; + uint16_t type; +#define NORMAL_TYPE 0 +#define TIME_TYPE 1 + uint16_t time; /* unit 100ms */ +} __attribute__((packed)); + +struct hostif_phy_information_confirm_t { + struct hostif_hdr header; + uint8_t rssi; + uint8_t sq; + uint8_t noise; + uint8_t link_speed; + uint32_t tx_frame; + uint32_t rx_frame; + uint32_t tx_error; + uint32_t rx_error; +} __attribute__((packed)); + +/* sleep mode */ +#define SLP_ACTIVE 0 +#define SLP_SLEEP 1 +struct hostif_sleep_request_t { + struct hostif_hdr header; +} __attribute__((packed)); + +struct hostif_sleep_confirm_t { + struct hostif_hdr header; + uint16_t result_code; +} __attribute__((packed)); + +struct hostif_mic_failure_request_t { + struct hostif_hdr header; + uint16_t failure_count; + uint16_t timer; +} __attribute__((packed)); + +struct hostif_mic_failure_confirm_t { + struct hostif_hdr header; + uint16_t result_code; +} __attribute__((packed)); + +#define BASIC_RATE 0x80 +#define RATE_MASK 0x7F + +#define TX_RATE_AUTO 0xff +#define TX_RATE_1M_FIXED 0 +#define TX_RATE_2M_FIXED 1 +#define TX_RATE_1_2M_AUTO 2 +#define TX_RATE_5M_FIXED 3 +#define TX_RATE_11M_FIXED 4 + +#define TX_RATE_FULL_AUTO 0 +#define TX_RATE_11_AUTO 1 +#define TX_RATE_11B_AUTO 2 +#define TX_RATE_11BG_AUTO 3 +#define TX_RATE_MANUAL_AUTO 4 +#define TX_RATE_FIXED 5 + +/* 11b rate */ +#define TX_RATE_1M (uint8_t)(10/5) /* 11b 11g basic rate */ +#define TX_RATE_2M (uint8_t)(20/5) /* 11b 11g basic rate */ +#define TX_RATE_5M (uint8_t)(55/5) /* 11g basic rate */ +#define TX_RATE_11M (uint8_t)(110/5) /* 11g basic rate */ + +/* 11g rate */ +#define TX_RATE_6M (uint8_t)(60/5) /* 11g basic rate */ +#define TX_RATE_12M (uint8_t)(120/5) /* 11g basic rate */ +#define TX_RATE_24M (uint8_t)(240/5) /* 11g basic rate */ +#define TX_RATE_9M (uint8_t)(90/5) +#define TX_RATE_18M (uint8_t)(180/5) +#define TX_RATE_36M (uint8_t)(360/5) +#define TX_RATE_48M (uint8_t)(480/5) +#define TX_RATE_54M (uint8_t)(540/5) + +#define IS_11B_RATE(A) (((A&RATE_MASK)==TX_RATE_1M)||((A&RATE_MASK)==TX_RATE_2M)||\ + ((A&RATE_MASK)==TX_RATE_5M)||((A&RATE_MASK)==TX_RATE_11M)) + +#define IS_OFDM_RATE(A) (((A&RATE_MASK)==TX_RATE_6M)||((A&RATE_MASK)==TX_RATE_12M)||\ + ((A&RATE_MASK)==TX_RATE_24M)||((A&RATE_MASK)==TX_RATE_9M)||\ + ((A&RATE_MASK)==TX_RATE_18M)||((A&RATE_MASK)==TX_RATE_36M)||\ + ((A&RATE_MASK)==TX_RATE_48M)||((A&RATE_MASK)==TX_RATE_54M)) + +#define IS_11BG_RATE(A) (IS_11B_RATE(A)||IS_OFDM_RATE(A)) + +#define IS_OFDM_EXT_RATE(A) (((A&RATE_MASK)==TX_RATE_9M)||((A&RATE_MASK)==TX_RATE_18M)||\ + ((A&RATE_MASK)==TX_RATE_36M)||((A&RATE_MASK)==TX_RATE_48M)||\ + ((A&RATE_MASK)==TX_RATE_54M)) + +enum { + CONNECT_STATUS=0, + DISCONNECT_STATUS +}; + +/* preamble type */ +enum { + LONG_PREAMBLE=0, + SHORT_PREAMBLE +}; + +/* multicast filter */ +#define MCAST_FILTER_MCAST 0 +#define MCAST_FILTER_MCASTALL 1 +#define MCAST_FILTER_PROMISC 2 + +#define NIC_MAX_MCAST_LIST 32 + +/* macro function */ +#define HIF_EVENT_MASK 0xE800 +#define IS_HIF_IND(_EVENT) ((_EVENT&HIF_EVENT_MASK)==0xE800 && \ + ((_EVENT&~HIF_EVENT_MASK)==0x0001 || \ + (_EVENT&~HIF_EVENT_MASK)==0x0006 || \ + (_EVENT&~HIF_EVENT_MASK)==0x000C || \ + (_EVENT&~HIF_EVENT_MASK)==0x0011 || \ + (_EVENT&~HIF_EVENT_MASK)==0x0012)) + +#define IS_HIF_CONF(_EVENT) ((_EVENT&HIF_EVENT_MASK)==0xE800 && \ + (_EVENT&~HIF_EVENT_MASK)>0x0000 && \ + (_EVENT&~HIF_EVENT_MASK)<0x0012 && \ + !IS_HIF_IND(_EVENT) ) + +#ifdef __KERNEL__ + +#include "ks_wlan.h" + +/* function prototype */ +extern int hostif_data_request( ks_wlan_private *priv, struct sk_buff *packet ); +extern void hostif_receive( ks_wlan_private *priv, unsigned char *p, unsigned int size ); +extern void hostif_sme_enqueue(ks_wlan_private *priv, uint16_t event); +extern int hostif_init( ks_wlan_private *priv ); +extern void hostif_exit( ks_wlan_private *priv ); + +static +inline int hif_align_size(int size) +{ +#ifdef KS_ATOM + if( size < 1024 ) + size = 1024; +#endif +#ifdef DEVICE_ALIGNMENT + return (size%DEVICE_ALIGNMENT) ? size + DEVICE_ALIGNMENT - (size % DEVICE_ALIGNMENT) : size; +#else + return size; +#endif +} + +#endif /* __KERNEL__ */ + +#endif /* _KS_HOSTIF_H_ */ diff --git a/drivers/staging/ks7010/ks_wlan.h b/drivers/staging/ks7010/ks_wlan.h new file mode 100644 index 0000000..c7cbde1 --- /dev/null +++ b/drivers/staging/ks7010/ks_wlan.h @@ -0,0 +1,541 @@ +/* + * Driver for KeyStream IEEE802.11 b/g wireless LAN cards. + * + * ks_wlan.h + * $Id: ks_wlan.h 994 2009-09-14 01:51:16Z sekine $ + * + * Copyright (C) 2006-2008 KeyStream Corp. + * Copyright (C) 2009 Renesas Technology Corp. + * + * This program is free software; you can redistribute it and/or modify + * it undr the terms of the GNU General Public License version 2 as + * published by the Free Sotware Foundation. + */ + +#ifndef _KS_WLAN_H +#define _KS_WLAN_H + +#define WPS + +#include +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)) +#include +#endif +#include +#include +#include + +#include /* spinlock_t */ +#include /* wait_queue_head_t */ +#include /* pid_t */ +#include /* struct net_device_stats, struct sk_buff */ +#include +#include +#include /* struct atmic_t */ +#include /* struct timer_list */ +#include +#include /* struct completion */ + +#include + +/* Workqueue / task queue backwards compatibility stuff */ +#if ((LINUX_VERSION_CODE > KERNEL_VERSION(2,5,41)) || (defined _MVL31_) || (defined _CELF3_)) +#include +#else +#include +#define work_struct tq_struct +#define INIT_WORK INIT_TQUEUE +#define schedule_work schedule_task +#endif + +/* Interrupt handler backwards compatibility stuff */ +/* +#ifndef IRQ_NONE +#define IRQ_NONE +#define IRQ_HANDLED +typedef void irqreturn_t; +#endif +*/ + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,23) +#define free_netdev(x) kfree(x) +#define pci_name(x) x->slot_name +#endif + +#if (defined _PCMCIA_) +#include "pcmcia/ks7010_pcmcia.h" +#elif (defined _PCI_) +#include "pci/ks7010_pci.h" +#elif (defined _SDIO_) +#include "ks7010_sdio.h" +#elif (defined _SPI_) +#include "spi/ks7010_spi.h" +#else +#error not defined bus type ! +#endif + +struct ks_wlan_parameter { + uint8_t operation_mode; /* Operation Mode */ + uint8_t channel; /* Channel */ + uint8_t tx_rate; /* Transmit Rate */ + struct { + uint8_t size; + uint8_t body[16]; + } rate_set; + uint8_t bssid[ETH_ALEN]; /* BSSID */ + struct { + uint8_t size; + uint8_t body[32+1]; + } ssid; /* SSID */ + uint8_t preamble; /* Preamble */ + uint8_t powermgt; /* PowerManagementMode */ + uint32_t scan_type; /* AP List Scan Type */ +#define BEACON_LOST_COUNT_MIN 0 +#define BEACON_LOST_COUNT_MAX 65535 + uint32_t beacon_lost_count; /* Beacon Lost Count */ + uint32_t rts; /* RTS Threashold */ + uint32_t fragment; /* Fragmentation Threashold */ + uint32_t privacy_invoked; + uint32_t wep_index; + struct { + uint8_t size; + uint8_t val[13*2+1]; + } wep_key[4]; + uint16_t authenticate_type; + uint16_t phy_type; /* 11b/11g/11bg mode type*/ + uint16_t cts_mode; /* for 11g/11bg mode cts mode */ + uint16_t phy_info_timer; /* phy information timer */ + char rom_file[256]; +}; + +enum { + DEVICE_STATE_OFF = 0, /* this means hw_unavailable is != 0 */ + DEVICE_STATE_PREBOOT, /* we are in a pre-boot state (empty RAM) */ + DEVICE_STATE_BOOT, /* boot state (fw upload, run fw) */ + DEVICE_STATE_PREINIT, /* pre-init state */ + DEVICE_STATE_INIT, /* init state (restore MIB backup to device) */ + DEVICE_STATE_READY, /* driver&device are in operational state */ + DEVICE_STATE_SLEEP /* device in sleep mode */ +}; + +/* SME flag */ +#define SME_MODE_SET (1<<0) +#define SME_RTS (1<<1) +#define SME_FRAG (1<<2) +#define SME_WEP_FLAG (1<<3) +#define SME_WEP_INDEX (1<<4) +#define SME_WEP_VAL1 (1<<5) +#define SME_WEP_VAL2 (1<<6) +#define SME_WEP_VAL3 (1<<7) +#define SME_WEP_VAL4 (1<<8) +#define SME_WEP_VAL_MASK (SME_WEP_VAL1|SME_WEP_VAL2|SME_WEP_VAL3|SME_WEP_VAL4) +#define SME_RSN (1<<9) +#define SME_RSN_MULTICAST (1<<10) +#define SME_RSN_UNICAST (1<<11) +#define SME_RSN_AUTH (1<<12) + +#define SME_AP_SCAN (1<<13) +#define SME_MULTICAST (1<<14) + +/* SME Event */ +enum { + SME_START, + + SME_MULTICAST_REQUEST, + SME_MACADDRESS_SET_REQUEST, + SME_BSS_SCAN_REQUEST, + SME_SET_FLAG, + SME_SET_TXKEY, + SME_SET_KEY1, + SME_SET_KEY2, + SME_SET_KEY3, + SME_SET_KEY4, + SME_SET_PMK_TSC, + SME_SET_GMK1_TSC, + SME_SET_GMK2_TSC, + SME_SET_GMK3_TSC, + SME_SET_PMKSA, + SME_POW_MNGMT_REQUEST, + SME_PHY_INFO_REQUEST, + SME_MIC_FAILURE_REQUEST, + SME_GET_MAC_ADDRESS, + SME_GET_PRODUCT_VERSION, + SME_STOP_REQUEST, + SME_RTS_THRESHOLD_REQUEST, + SME_FRAGMENTATION_THRESHOLD_REQUEST, + SME_WEP_INDEX_REQUEST, + SME_WEP_KEY1_REQUEST, + SME_WEP_KEY2_REQUEST, + SME_WEP_KEY3_REQUEST, + SME_WEP_KEY4_REQUEST, + SME_WEP_FLAG_REQUEST, + SME_RSN_UCAST_REQUEST, + SME_RSN_MCAST_REQUEST, + SME_RSN_AUTH_REQUEST, + SME_RSN_ENABLED_REQUEST, + SME_RSN_MODE_REQUEST, +#ifdef WPS + SME_WPS_ENABLE_REQUEST, + SME_WPS_PROBE_REQUEST, +#endif + SME_SET_GAIN, + SME_GET_GAIN, + SME_SLEEP_REQUEST, + SME_SET_REGION, + SME_MODE_SET_REQUEST, + SME_START_REQUEST, + SME_GET_EEPROM_CKSUM, + + + SME_MIC_FAILURE_CONFIRM, + SME_START_CONFIRM, + + SME_MULTICAST_CONFIRM, + SME_BSS_SCAN_CONFIRM, + SME_GET_CURRENT_AP, + SME_POW_MNGMT_CONFIRM, + SME_PHY_INFO_CONFIRM, + SME_STOP_CONFIRM, + SME_RTS_THRESHOLD_CONFIRM, + SME_FRAGMENTATION_THRESHOLD_CONFIRM, + SME_WEP_INDEX_CONFIRM, + SME_WEP_KEY1_CONFIRM, + SME_WEP_KEY2_CONFIRM, + SME_WEP_KEY3_CONFIRM, + SME_WEP_KEY4_CONFIRM, + SME_WEP_FLAG_CONFIRM, + SME_RSN_UCAST_CONFIRM, + SME_RSN_MCAST_CONFIRM, + SME_RSN_AUTH_CONFIRM, + SME_RSN_ENABLED_CONFIRM, + SME_RSN_MODE_CONFIRM, + SME_MODE_SET_CONFIRM, + SME_SLEEP_CONFIRM, + + SME_RSN_SET_CONFIRM, + SME_WEP_SET_CONFIRM, + SME_TERMINATE, + + SME_EVENT_SIZE /* end */ +}; + +/* SME Status */ +enum { + SME_IDLE, + SME_SETUP, + SME_DISCONNECT, + SME_CONNECT +}; + +#define SME_EVENT_BUFF_SIZE 128 + +struct sme_info{ + int sme_status; + int event_buff[SME_EVENT_BUFF_SIZE]; + unsigned int qhead; + unsigned int qtail; +#ifdef KS_WLAN_DEBUG + /* for debug */ + unsigned int max_event_count; +#endif + spinlock_t sme_spin; + unsigned long sme_flag; +}; + +struct hostt_t{ + int buff[SME_EVENT_BUFF_SIZE]; + unsigned int qhead; + unsigned int qtail; +}; + +#define RSN_IE_BODY_MAX 64 +struct rsn_ie_t { + uint8_t id; /* 0xdd = WPA or 0x30 = RSN */ + uint8_t size; /* max ? 255 ? */ + uint8_t body[RSN_IE_BODY_MAX]; +} __attribute__((packed)); + +#ifdef WPS +#define WPS_IE_BODY_MAX 255 +struct wps_ie_t { + uint8_t id; /* 221 'dd 00 50 F2 04' */ + uint8_t size; /* max ? 255 ? */ + uint8_t body[WPS_IE_BODY_MAX]; +} __attribute__((packed)); +#endif /* WPS */ + +struct local_ap_t { + uint8_t bssid[6]; + uint8_t rssi; + uint8_t sq; + struct { + uint8_t size; + uint8_t body[32]; + uint8_t ssid_pad; + } ssid; + struct { + uint8_t size; + uint8_t body[16]; + uint8_t rate_pad; + } rate_set; + uint16_t capability; + uint8_t channel; + uint8_t noise; + struct rsn_ie_t wpa_ie; + struct rsn_ie_t rsn_ie; +#ifdef WPS + struct wps_ie_t wps_ie; +#endif /* WPS */ +}; + +#define LOCAL_APLIST_MAX 31 +#define LOCAL_CURRENT_AP LOCAL_APLIST_MAX +struct local_aplist_t { + int size; + struct local_ap_t ap[LOCAL_APLIST_MAX+1]; +}; + +struct local_gain_t{ + uint8_t TxMode; + uint8_t RxMode; + uint8_t TxGain; + uint8_t RxGain; +}; + +struct local_eeprom_sum_t{ + uint8_t type; + uint8_t result; +}; + +enum { + EEPROM_OK, + EEPROM_CHECKSUM_NONE, + EEPROM_FW_NOT_SUPPORT, + EEPROM_NG, +}; + + +/* Power Save Status */ +enum { + PS_NONE, + PS_ACTIVE_SET, + PS_SAVE_SET, + PS_CONF_WAIT, + PS_SNOOZE, + PS_WAKEUP +}; + +struct power_save_status_t { + atomic_t status; /* initialvalue 0 */ + struct completion wakeup_wait; + atomic_t confirm_wait; + atomic_t snooze_guard; +}; + +struct sleep_status_t { + atomic_t status; /* initialvalue 0 */ + atomic_t doze_request; + atomic_t wakeup_request; +}; + +/* WPA */ +struct scan_ext_t { + unsigned int flag; + char ssid[IW_ESSID_MAX_SIZE+1]; +}; + +enum { + CIPHER_NONE, + CIPHER_WEP40, + CIPHER_TKIP, + CIPHER_CCMP, + CIPHER_WEP104 +}; + +#define CIPHER_ID_WPA_NONE "\x00\x50\xf2\x00" +#define CIPHER_ID_WPA_WEP40 "\x00\x50\xf2\x01" +#define CIPHER_ID_WPA_TKIP "\x00\x50\xf2\x02" +#define CIPHER_ID_WPA_CCMP "\x00\x50\xf2\x04" +#define CIPHER_ID_WPA_WEP104 "\x00\x50\xf2\x05" + +#define CIPHER_ID_WPA2_NONE "\x00\x0f\xac\x00" +#define CIPHER_ID_WPA2_WEP40 "\x00\x0f\xac\x01" +#define CIPHER_ID_WPA2_TKIP "\x00\x0f\xac\x02" +#define CIPHER_ID_WPA2_CCMP "\x00\x0f\xac\x04" +#define CIPHER_ID_WPA2_WEP104 "\x00\x0f\xac\x05" + +#define CIPHER_ID_LEN 4 + +enum { + KEY_MGMT_802_1X, + KEY_MGMT_PSK, + KEY_MGMT_WPANONE, +}; + +#define KEY_MGMT_ID_WPA_NONE "\x00\x50\xf2\x00" +#define KEY_MGMT_ID_WPA_1X "\x00\x50\xf2\x01" +#define KEY_MGMT_ID_WPA_PSK "\x00\x50\xf2\x02" +#define KEY_MGMT_ID_WPA_WPANONE "\x00\x50\xf2\xff" + +#define KEY_MGMT_ID_WPA2_NONE "\x00\x0f\xac\x00" +#define KEY_MGMT_ID_WPA2_1X "\x00\x0f\xac\x01" +#define KEY_MGMT_ID_WPA2_PSK "\x00\x0f\xac\x02" +#define KEY_MGMT_ID_WPA2_WPANONE "\x00\x0f\xac\xff" + +#define KEY_MGMT_ID_LEN 4 + +#define MIC_KEY_SIZE 8 + +struct wpa_key_t { + uint32_t ext_flags; /* IW_ENCODE_EXT_xxx */ + uint8_t tx_seq[IW_ENCODE_SEQ_MAX_SIZE]; /* LSB first */ + uint8_t rx_seq[IW_ENCODE_SEQ_MAX_SIZE]; /* LSB first */ + struct sockaddr addr; /* ff:ff:ff:ff:ff:ff for broadcast/multicast + * (group) keys or unicast address for + * individual keys */ + uint16_t alg; + uint16_t key_len; /* WEP: 5 or 13, TKIP: 32, CCMP: 16 */ + uint8_t key_val[IW_ENCODING_TOKEN_MAX]; + uint8_t tx_mic_key[MIC_KEY_SIZE]; + uint8_t rx_mic_key[MIC_KEY_SIZE]; +}; +#define WPA_KEY_INDEX_MAX 4 +#define WPA_RX_SEQ_LEN 6 + +struct mic_failure_t { + uint16_t failure; /* MIC Failure counter 0 or 1 or 2 */ + uint16_t counter; /* 1sec counter 0-60 */ + uint32_t last_failure_time; + int stop; /* stop flag */ +}; + +struct wpa_status_t { + int wpa_enabled; + unsigned int rsn_enabled; + int version; + int pairwise_suite; /* unicast cipher */ + int group_suite; /* multicast cipher */ + int key_mgmt_suite; /* authentication key management suite */ + int auth_alg; + int txkey; + struct wpa_key_t key[WPA_KEY_INDEX_MAX]; + struct scan_ext_t scan_ext; + struct mic_failure_t mic_failure; +}; + +#include +#define PMK_LIST_MAX 8 +struct pmk_list_t { + uint16_t size; + struct list_head head; + struct pmk_t { + struct list_head list; + uint8_t bssid[ETH_ALEN]; + uint8_t pmkid[IW_PMKID_LEN]; + } pmk[PMK_LIST_MAX]; +}; + +#ifdef WPS +struct wps_status_t { + int wps_enabled; + int ielen; + uint8_t ie[255]; +}; +#endif /* WPS */ + +typedef struct ks_wlan_private{ + + struct hw_info_t ks_wlan_hw; /* hardware information */ + + struct net_device *net_dev; + int reg_net; /* register_netdev */ + struct net_device_stats nstats; + struct iw_statistics wstats; + + struct completion confirm_wait; + + /* trx device & sme */ + struct tx_device tx_dev; + struct rx_device rx_dev; + struct sme_info sme_i; + u8 *rxp; + unsigned int rx_size; + struct tasklet_struct sme_task; + struct work_struct ks_wlan_wakeup_task; + int scan_ind_count; + + unsigned char eth_addr[ETH_ALEN]; + + struct local_aplist_t aplist; + struct local_ap_t current_ap; + struct power_save_status_t psstatus; + struct sleep_status_t sleepstatus; + struct wpa_status_t wpa; + struct pmk_list_t pmklist; + /* wireless parameter */ + struct ks_wlan_parameter reg; + uint8_t current_rate; + + char nick[IW_ESSID_MAX_SIZE+1]; + + spinlock_t multicast_spin; + + spinlock_t dev_read_lock; + wait_queue_head_t devread_wait; + + unsigned int need_commit; /* for ioctl */ + + /* DeviceIoControl */ + int device_open_status; + atomic_t event_count; + atomic_t rec_count; + int dev_count; +#define DEVICE_STOCK_COUNT 20 + unsigned char *dev_data[DEVICE_STOCK_COUNT]; + int dev_size[DEVICE_STOCK_COUNT]; + + /* ioctl : IOCTL_FIRMWARE_VERSION */ + unsigned char firmware_version[128+1]; + int version_size; + + int mac_address_valid; /* Mac Address Status */ + + int dev_state; + + struct sk_buff *skb; + unsigned int cur_rx; /* Index into the Rx buffer of next Rx pkt. */ + /* spinlock_t lock; */ +#define FORCE_DISCONNECT 0x80000000 +#define CONNECT_STATUS_MASK 0x7FFFFFFF + uint32_t connect_status; /* connect status */ + int infra_status; /* Infractructure status */ + + uint8_t data_buff[0x1000]; + + uint8_t scan_ssid_len; + uint8_t scan_ssid[IW_ESSID_MAX_SIZE+1]; + struct local_gain_t gain; +#ifdef WPS + struct net_device *l2_dev; + int l2_fd; + struct wps_status_t wps; +#endif /* WPS */ + uint8_t sleep_mode; + + uint8_t region; + struct local_eeprom_sum_t eeprom_sum; + uint8_t eeprom_checksum; + + struct hostt_t hostt; + + unsigned long last_doze; + unsigned long last_wakeup; + + uint sdio_error_count; /* SDIO error */ + uint wakeup_count; /* for detect wakeup loop */ + +} ks_wlan_private; + + + +#endif /* _KS_WLAN_H */ diff --git a/drivers/staging/ks7010/ks_wlan_ioctl.h b/drivers/staging/ks7010/ks_wlan_ioctl.h new file mode 100644 index 0000000..e27f8fb --- /dev/null +++ b/drivers/staging/ks7010/ks_wlan_ioctl.h @@ -0,0 +1,69 @@ +/* + * Driver for KeyStream 11b/g wireless LAN + * + * ks_wlan_ioctl.h + * $Id: ks_wlan_ioctl.h 996 2009-09-14 02:54:21Z sekine $ + * + * Copyright (c) 2005-2008 KeyStream Corp. + * Copyright (C) 2009 Renesas Technology Corp. + * + * This program is free software; you can redistribute it and/or modify + * it undr the terms of the GNU General Public License version 2 as + * published by the Free Sotware Foundation. + */ + +#ifndef _KS_WLAN_IOCTL_H +#define _KS_WLAN_IOCTL_H + +#include +/* The low order bit identify a SET (0) or a GET (1) ioctl. */ + +/* SIOCIWFIRSTPRIV+0 */ +#define KS_WLAN_GET_DRIVER_VERSION SIOCIWFIRSTPRIV+1 +/* SIOCIWFIRSTPRIV+2 */ +#define KS_WLAN_GET_FIRM_VERSION SIOCIWFIRSTPRIV+3 +#ifdef WPS +#define KS_WLAN_SET_WPS_ENABLE SIOCIWFIRSTPRIV+4 +#define KS_WLAN_GET_WPS_ENABLE SIOCIWFIRSTPRIV+5 +#define KS_WLAN_SET_WPS_PROBE_REQ SIOCIWFIRSTPRIV+6 +#endif +#define KS_WLAN_GET_EEPROM_CKSUM SIOCIWFIRSTPRIV+7 +#define KS_WLAN_SET_PREAMBLE SIOCIWFIRSTPRIV+8 +#define KS_WLAN_GET_PREAMBLE SIOCIWFIRSTPRIV+9 +#define KS_WLAN_SET_POWER_SAVE SIOCIWFIRSTPRIV+10 +#define KS_WLAN_GET_POWER_SAVE SIOCIWFIRSTPRIV+11 +#define KS_WLAN_SET_SCAN_TYPE SIOCIWFIRSTPRIV+12 +#define KS_WLAN_GET_SCAN_TYPE SIOCIWFIRSTPRIV+13 +#define KS_WLAN_SET_RX_GAIN SIOCIWFIRSTPRIV+14 +#define KS_WLAN_GET_RX_GAIN SIOCIWFIRSTPRIV+15 +#define KS_WLAN_HOSTT SIOCIWFIRSTPRIV+16 /* unused */ +//#define KS_WLAN_SET_REGION SIOCIWFIRSTPRIV+17 +#define KS_WLAN_SET_BEACON_LOST SIOCIWFIRSTPRIV+18 +#define KS_WLAN_GET_BEACON_LOST SIOCIWFIRSTPRIV+19 + +#define KS_WLAN_SET_TX_GAIN SIOCIWFIRSTPRIV+20 +#define KS_WLAN_GET_TX_GAIN SIOCIWFIRSTPRIV+21 + +/* for KS7010 */ +#define KS_WLAN_SET_PHY_TYPE SIOCIWFIRSTPRIV+22 +#define KS_WLAN_GET_PHY_TYPE SIOCIWFIRSTPRIV+23 +#define KS_WLAN_SET_CTS_MODE SIOCIWFIRSTPRIV+24 +#define KS_WLAN_GET_CTS_MODE SIOCIWFIRSTPRIV+25 +/* SIOCIWFIRSTPRIV+26 */ +/* SIOCIWFIRSTPRIV+27 */ +#define KS_WLAN_SET_SLEEP_MODE SIOCIWFIRSTPRIV+28 /* sleep mode */ +#define KS_WLAN_GET_SLEEP_MODE SIOCIWFIRSTPRIV+29 /* sleep mode */ +/* SIOCIWFIRSTPRIV+30 */ +/* SIOCIWFIRSTPRIV+31 */ + +#ifdef __KERNEL__ + +#include "ks_wlan.h" +#include + +extern int ks_wlan_read_config_file(ks_wlan_private *priv); +extern int ks_wlan_setup_parameter(ks_wlan_private *priv, unsigned int commit_flag); + +#endif /* __KERNEL__ */ + +#endif /* _KS_WLAN_IOCTL_H */ diff --git a/drivers/staging/ks7010/ks_wlan_net.c b/drivers/staging/ks7010/ks_wlan_net.c new file mode 100644 index 0000000..546a256 --- /dev/null +++ b/drivers/staging/ks7010/ks_wlan_net.c @@ -0,0 +1,3157 @@ +/* + * Driver for KeyStream 11b/g wireless LAN + * + * ks_wlan_net.c + * $Id: ks_wlan_net.c 1020 2009-09-28 05:48:31Z sekine $ + * + * Copyright (C) 2005-2008 KeyStream Corp. + * Copyright (C) 2009 Renesas Technology Corp. + * + * This program is free software; you can redistribute it and/or modify + * it undr the terms of the GNU General Public License version 2 as + * published by the Free Sotware Foundation. + */ + +#include +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)) +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static int wep_on_off; +#define WEP_OFF 0 +#define WEP_ON_64BIT 1 +#define WEP_ON_128BIT 2 + +#include "ks_wlan.h" +#include "ks_hostif.h" +#include "ks_wlan_ioctl.h" +#include "ks_debug.h" + +/* Include Wireless Extension definition and check version */ +#include +#define WIRELESS_SPY /* enable iwspy support */ +#include /* New driver API */ + +#ifdef WIRELESS_EXT +/* Frequency list (map channels to frequencies) */ +static const long frequency_list[] = { 2412, 2417, 2422, 2427, 2432, 2437, 2442, + 2447, 2452, 2457, 2462, 2467, 2472, 2484 }; + +/* A few details needed for WEP (Wireless Equivalent Privacy) */ +#define MAX_KEY_SIZE 13 /* 128 (?) bits */ +#define MIN_KEY_SIZE 5 /* 40 bits RC4 - WEP */ +typedef struct wep_key_t { + u16 len; + u8 key[16]; /* 40-bit and 104-bit keys */ +} wep_key_t; + +/* Backward compatibility */ +#ifndef IW_ENCODE_NOKEY +#define IW_ENCODE_NOKEY 0x0800 /* Key is write only, so not present */ +#define IW_ENCODE_MODE (IW_ENCODE_DISABLED | IW_ENCODE_RESTRICTED | IW_ENCODE_OPEN) +#endif /* IW_ENCODE_NOKEY */ + +/* List of Wireless Handlers (new API) */ +static const struct iw_handler_def ks_wlan_handler_def; + +#define KSC_OPNOTSUPP /* Operation Not Support*/ + +#endif /* WIRELESS_EXT */ + +/* + * function prototypes + */ +extern int ks_wlan_hw_tx(ks_wlan_private *priv, void *p, unsigned long size, + void (*complete_handler)(void *arg1, void *arg2), + void *arg1, + void *arg2 ); +static int ks_wlan_open (struct net_device *dev); +static void ks_wlan_tx_timeout (struct net_device *dev); +static int ks_wlan_start_xmit (struct sk_buff *skb, struct net_device *dev); +static int ks_wlan_close (struct net_device *dev); +static void ks_wlan_set_multicast_list (struct net_device *dev); +static struct net_device_stats *ks_wlan_get_stats (struct net_device *dev); +static int ks_wlan_set_mac_address(struct net_device *dev, void *addr); +static int ks_wlan_netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); + +static atomic_t update_phyinfo; +static struct timer_list update_phyinfo_timer; +static +int ks_wlan_update_phy_information(ks_wlan_private *priv) +{ + struct iw_statistics *wstats = &priv->wstats; + + DPRINTK(4, "in_interrupt = %ld\n", in_interrupt()); + + if (priv->dev_state < DEVICE_STATE_READY) { + return -1; /* not finished initialize */ + } + if(atomic_read(&update_phyinfo)) + return 1; + + /* The status */ + wstats->status = priv->reg.operation_mode; /* Operation mode */ + + /* Signal quality and co. But where is the noise level ??? */ + hostif_sme_enqueue(priv, SME_PHY_INFO_REQUEST); + + /* interruptible_sleep_on_timeout(&priv->confirm_wait, HZ/2); */ + if(!wait_for_completion_interruptible_timeout(&priv->confirm_wait,HZ/2)){ + DPRINTK(1,"wait time out!!\n"); + } + + atomic_inc(&update_phyinfo); + update_phyinfo_timer.expires = jiffies + HZ; /* 1sec */ + add_timer(&update_phyinfo_timer); + + return 0; +} + +static +void ks_wlan_update_phyinfo_timeout(unsigned long ptr) +{ + DPRINTK(4, "in_interrupt = %ld\n", in_interrupt()); + atomic_set(&update_phyinfo,0); +} + +int ks_wlan_setup_parameter(ks_wlan_private *priv, unsigned int commit_flag) +{ + DPRINTK(2,"\n"); + + hostif_sme_enqueue(priv, SME_STOP_REQUEST); + + if(commit_flag & SME_RTS) + hostif_sme_enqueue(priv, SME_RTS_THRESHOLD_REQUEST); + if(commit_flag & SME_FRAG) + hostif_sme_enqueue(priv, SME_FRAGMENTATION_THRESHOLD_REQUEST); + + if(commit_flag & SME_WEP_INDEX) + hostif_sme_enqueue(priv, SME_WEP_INDEX_REQUEST); + if(commit_flag & SME_WEP_VAL1) + hostif_sme_enqueue(priv, SME_WEP_KEY1_REQUEST); + if(commit_flag & SME_WEP_VAL2) + hostif_sme_enqueue(priv, SME_WEP_KEY2_REQUEST); + if(commit_flag & SME_WEP_VAL3) + hostif_sme_enqueue(priv, SME_WEP_KEY3_REQUEST); + if(commit_flag & SME_WEP_VAL4) + hostif_sme_enqueue(priv, SME_WEP_KEY4_REQUEST); + if(commit_flag & SME_WEP_FLAG) + hostif_sme_enqueue(priv, SME_WEP_FLAG_REQUEST); + + if(commit_flag & SME_RSN){ + hostif_sme_enqueue(priv, SME_RSN_ENABLED_REQUEST); + hostif_sme_enqueue(priv, SME_RSN_MODE_REQUEST); + } + if(commit_flag & SME_RSN_MULTICAST) + hostif_sme_enqueue(priv, SME_RSN_MCAST_REQUEST); + if(commit_flag & SME_RSN_UNICAST) + hostif_sme_enqueue(priv, SME_RSN_UCAST_REQUEST); + if(commit_flag & SME_RSN_AUTH) + hostif_sme_enqueue(priv, SME_RSN_AUTH_REQUEST); + + hostif_sme_enqueue(priv, SME_MODE_SET_REQUEST); + + hostif_sme_enqueue(priv, SME_START_REQUEST); + + return 0; +} + +#ifdef WIRELESS_EXT +/* + * Initial Wireless Extension code for Ks_Wlannet driver by : + * Jean Tourrilhes - HPL - 17 November 00 + * Conversion to new driver API by : + * Jean Tourrilhes - HPL - 26 March 02 + * Javier also did a good amount of work here, adding some new extensions + * and fixing my code. Let's just say that without him this code just + * would not work at all... - Jean II + */ + +/*------------------------------------------------------------------*/ +/* Wireless Handler : get protocol name */ +static int ks_wlan_get_name(struct net_device *dev, struct iw_request_info *info, + char *cwrq, char *extra) +{ + ks_wlan_private *priv = (ks_wlan_private *) netdev_priv(dev); + + if (priv->sleep_mode == SLP_SLEEP){ return -EPERM; } /* for SLEEP MODE */ + + if (priv->dev_state < DEVICE_STATE_READY) { + strcpy(cwrq, "NOT READY!"); + } + else if(priv->reg.phy_type == D_11B_ONLY_MODE){ + strcpy(cwrq, "IEEE 802.11b"); + } + else if(priv->reg.phy_type == D_11G_ONLY_MODE){ + strcpy(cwrq, "IEEE 802.11g"); + } + else { + strcpy(cwrq, "IEEE 802.11b/g"); + } + + return 0; +} + +/*------------------------------------------------------------------*/ +/* Wireless Handler : set frequency */ +static int ks_wlan_set_freq(struct net_device *dev, struct iw_request_info *info, + struct iw_freq *fwrq, char *extra) +{ + ks_wlan_private *priv = (ks_wlan_private *)netdev_priv(dev); + int rc = -EINPROGRESS; /* Call commit handler */ + + if (priv->sleep_mode == SLP_SLEEP){ return -EPERM; } /* for SLEEP MODE */ + + /* If setting by frequency, convert to a channel */ + if((fwrq->e == 1) && + (fwrq->m >= (int) 2.412e8) && + (fwrq->m <= (int) 2.487e8)) { + int f = fwrq->m / 100000; + int c = 0; + while((c < 14) && (f != frequency_list[c])) + c++; + /* Hack to fall through... */ + fwrq->e = 0; + fwrq->m = c + 1; + } + /* Setting by channel number */ + if((fwrq->m > 1000) || (fwrq->e > 0)) + rc = -EOPNOTSUPP; + else { + int channel = fwrq->m; + /* We should do a better check than that, + * based on the card capability !!! */ + if((channel < 1) || (channel > 14)) { + printk(KERN_DEBUG "%s: New channel value of %d is invalid!\n", dev->name, fwrq->m); + rc = -EINVAL; + } else { + /* Yes ! We can set it !!! */ + priv->reg.channel = (u8)(channel); + priv->need_commit |= SME_MODE_SET; + } + } + + return rc; +} + +/*------------------------------------------------------------------*/ +/* Wireless Handler : get frequency */ +static int ks_wlan_get_freq(struct net_device *dev, struct iw_request_info *info, + struct iw_freq *fwrq, char *extra) +{ + ks_wlan_private *priv = (ks_wlan_private *)netdev_priv(dev); + int f; + + if (priv->sleep_mode == SLP_SLEEP){ return -EPERM; } /* for SLEEP MODE */ + + if((priv->connect_status & CONNECT_STATUS_MASK) == CONNECT_STATUS){ + f = (int)priv->current_ap.channel; + } + else + f = (int)priv->reg.channel; + fwrq->m = frequency_list[f-1] * 100000; + fwrq->e = 1; + + return 0; +} + +/*------------------------------------------------------------------*/ +/* Wireless Handler : set ESSID */ +static int ks_wlan_set_essid(struct net_device *dev, struct iw_request_info *info, + struct iw_point *dwrq, char *extra) +{ + ks_wlan_private *priv = (ks_wlan_private *)netdev_priv(dev); + size_t len; + + DPRINTK(2," %d\n", dwrq->flags); + + if (priv->sleep_mode == SLP_SLEEP){ return -EPERM; } /* for SLEEP MODE */ + + /* Check if we asked for `any' */ + if(dwrq->flags == 0) { + /* Just send an empty SSID list */ + memset(priv->reg.ssid.body, 0, sizeof(priv->reg.ssid.body)); + priv->reg.ssid.size = 0; + } else { +#if 1 + len = dwrq->length; + /* iwconfig uses nul termination in SSID.. */ + if (len > 0 && extra[len - 1] == '\0') + len--; + + /* Check the size of the string */ + if(len > IW_ESSID_MAX_SIZE) { + return -EINVAL; + } +#else + /* Check the size of the string */ + if(dwrq->length > IW_ESSID_MAX_SIZE+1) { + return -E2BIG ; + } +#endif + + /* Set the SSID */ + memset(priv->reg.ssid.body, 0, sizeof(priv->reg.ssid.body)); + +#if 1 + memcpy(priv->reg.ssid.body, extra, len); + priv->reg.ssid.size = len; +#else + memcpy(priv->reg.ssid.body, extra, dwrq->length); + priv->reg.ssid.size = dwrq->length; +#endif + } + /* Write it to the card */ + priv->need_commit |= SME_MODE_SET; + +// return -EINPROGRESS; /* Call commit handler */ + ks_wlan_setup_parameter(priv, priv->need_commit); + priv->need_commit=0; + return 0; +} + +/*------------------------------------------------------------------*/ +/* Wireless Handler : get ESSID */ +static int ks_wlan_get_essid(struct net_device *dev, struct iw_request_info *info, + struct iw_point *dwrq, char *extra) +{ + ks_wlan_private *priv = (ks_wlan_private *)netdev_priv(dev); + + if (priv->sleep_mode == SLP_SLEEP){ return -EPERM; } /* for SLEEP MODE */ + + /* Note : if dwrq->flags != 0, we should + * get the relevant SSID from the SSID list... */ + + if(priv->reg.ssid.size){ + /* Get the current SSID */ + memcpy(extra, priv->reg.ssid.body, priv->reg.ssid.size); +#if 0 + extra[priv->reg.ssid.size] = '\0'; +#endif + /* If none, we may want to get the one that was set */ + + /* Push it out ! */ +#if 1 + dwrq->length = priv->reg.ssid.size; +#else + dwrq->length = priv->reg.ssid.size+1; +#endif + dwrq->flags = 1; /* active */ + }else{ +#if 1 + dwrq->length = 0; +#else + extra[0] = '\0'; + dwrq->length = 1; +#endif + dwrq->flags = 0; /* ANY */ + } + + return 0; +} + +/*------------------------------------------------------------------*/ +/* Wireless Handler : set AP address */ +static int ks_wlan_set_wap(struct net_device *dev, struct iw_request_info *info, + struct sockaddr *ap_addr, char *extra) +{ + ks_wlan_private *priv = (ks_wlan_private *)netdev_priv(dev); + + DPRINTK(2,"\n"); + + if (priv->sleep_mode == SLP_SLEEP){ return -EPERM; } /* for SLEEP MODE */ + + if (priv->reg.operation_mode == MODE_ADHOC || + priv->reg.operation_mode == MODE_INFRASTRUCTURE) { + memcpy(priv->reg.bssid, (u8 *)&ap_addr->sa_data, ETH_ALEN); + + if (is_valid_ether_addr((u8 *)priv->reg.bssid)) { + priv->need_commit |= SME_MODE_SET; + } + } + else { + memset(priv->reg.bssid, 0x0, ETH_ALEN); + return -EOPNOTSUPP; + } + + DPRINTK(2, "bssid = %02x:%02x:%02x:%02x:%02x:%02x\n", + priv->reg.bssid[0],priv->reg.bssid[1],priv->reg.bssid[2], + priv->reg.bssid[3],priv->reg.bssid[4],priv->reg.bssid[5]); + + /* Write it to the card */ + if (priv->need_commit) { + priv->need_commit |= SME_MODE_SET; + return -EINPROGRESS; /* Call commit handler */ + } + return 0; +} + +/*------------------------------------------------------------------*/ +/* Wireless Handler : get AP address */ +static int ks_wlan_get_wap(struct net_device *dev, struct iw_request_info *info, + struct sockaddr *awrq, char *extra) +{ + ks_wlan_private *priv = (ks_wlan_private *)netdev_priv(dev); + + if (priv->sleep_mode == SLP_SLEEP){ return -EPERM; } /* for SLEEP MODE */ + + if((priv->connect_status & CONNECT_STATUS_MASK) == CONNECT_STATUS){ + memcpy(awrq->sa_data, &(priv->current_ap.bssid[0]), ETH_ALEN); + } + else{ + memset(awrq->sa_data, 0, ETH_ALEN); + } + + awrq->sa_family = ARPHRD_ETHER; + + return 0; +} + +/*------------------------------------------------------------------*/ +/* Wireless Handler : set Nickname */ +static int ks_wlan_set_nick(struct net_device *dev, struct iw_request_info *info, + struct iw_point *dwrq, char *extra) +{ + ks_wlan_private *priv = (ks_wlan_private *)netdev_priv(dev); + + if (priv->sleep_mode == SLP_SLEEP){ return -EPERM; } /* for SLEEP MODE */ + + /* Check the size of the string */ + if(dwrq->length > 16 + 1) { + return -E2BIG; + } + memset(priv->nick, 0, sizeof(priv->nick)); + memcpy(priv->nick, extra, dwrq->length); + + return -EINPROGRESS; /* Call commit handler */ +} + +/*------------------------------------------------------------------*/ +/* Wireless Handler : get Nickname */ +static int ks_wlan_get_nick(struct net_device *dev, struct iw_request_info *info, + struct iw_point *dwrq, char *extra) +{ + ks_wlan_private *priv = (ks_wlan_private *)netdev_priv(dev); + + if (priv->sleep_mode == SLP_SLEEP){ return -EPERM; } /* for SLEEP MODE */ + + strncpy(extra, priv->nick, 16); + extra[16] = '\0'; + dwrq->length = strlen(extra) + 1; + + return 0; +} + +/*------------------------------------------------------------------*/ +/* Wireless Handler : set Bit-Rate */ +static int ks_wlan_set_rate(struct net_device *dev, struct iw_request_info *info, + struct iw_param *vwrq, char *extra) +{ + ks_wlan_private *priv = (ks_wlan_private *)netdev_priv(dev); + int i = 0; + + if (priv->sleep_mode == SLP_SLEEP){ return -EPERM; } /* for SLEEP MODE */ + + if(priv->reg.phy_type == D_11B_ONLY_MODE){ + if(vwrq->fixed == 1) { + switch(vwrq->value){ + case 11000000: + case 5500000: + priv->reg.rate_set.body[0] = (uint8_t)(vwrq->value/500000); + break; + case 2000000: + case 1000000: + priv->reg.rate_set.body[0] = ((uint8_t)(vwrq->value/500000))|BASIC_RATE; + break; + default: + return -EINVAL; + } + priv->reg.tx_rate = TX_RATE_FIXED; + priv->reg.rate_set.size = 1; + }else{ /* vwrq->fixed == 0 */ + if(vwrq->value > 0){ + switch(vwrq->value){ + case 11000000: + priv->reg.rate_set.body[3] = TX_RATE_11M; i++; + case 5500000: + priv->reg.rate_set.body[2] = TX_RATE_5M; i++; + case 2000000: + priv->reg.rate_set.body[1] = TX_RATE_2M|BASIC_RATE; i++; + case 1000000: + priv->reg.rate_set.body[0] = TX_RATE_1M|BASIC_RATE; i++; + break; + default: + return -EINVAL; + } + priv->reg.tx_rate = TX_RATE_MANUAL_AUTO; + priv->reg.rate_set.size = i; + }else{ + priv->reg.rate_set.body[3] = TX_RATE_11M; + priv->reg.rate_set.body[2] = TX_RATE_5M; + priv->reg.rate_set.body[1] = TX_RATE_2M|BASIC_RATE; + priv->reg.rate_set.body[0] = TX_RATE_1M|BASIC_RATE; + priv->reg.tx_rate = TX_RATE_FULL_AUTO; + priv->reg.rate_set.size = 4; + } + } + }else{ /* D_11B_ONLY_MODE or D_11BG_COMPATIBLE_MODE */ + if(vwrq->fixed == 1) { + switch(vwrq->value){ + case 54000000: + case 48000000: + case 36000000: + case 18000000: + case 9000000: + priv->reg.rate_set.body[0] = (uint8_t)(vwrq->value/500000); + break; + case 24000000: + case 12000000: + case 11000000: + case 6000000: + case 5500000: + case 2000000: + case 1000000: + priv->reg.rate_set.body[0] = ((uint8_t)(vwrq->value/500000))|BASIC_RATE; + break; + default: + return -EINVAL; + } + priv->reg.tx_rate = TX_RATE_FIXED; + priv->reg.rate_set.size = 1; + }else{ /* vwrq->fixed == 0 */ + if(vwrq->value > 0){ + switch(vwrq->value){ + case 54000000: + priv->reg.rate_set.body[11] = TX_RATE_54M; i++; + case 48000000: + priv->reg.rate_set.body[10] = TX_RATE_48M; i++; + case 36000000: + priv->reg.rate_set.body[9] = TX_RATE_36M; i++; + case 24000000: case 18000000: case 12000000: + case 11000000: case 9000000: case 6000000: + if(vwrq->value == 24000000){ + priv->reg.rate_set.body[8] = TX_RATE_18M; i++; + priv->reg.rate_set.body[7] = TX_RATE_9M; i++; + priv->reg.rate_set.body[6] = TX_RATE_24M|BASIC_RATE; i++; + priv->reg.rate_set.body[5] = TX_RATE_12M|BASIC_RATE; i++; + priv->reg.rate_set.body[4] = TX_RATE_6M|BASIC_RATE; i++; + priv->reg.rate_set.body[3] = TX_RATE_11M|BASIC_RATE; i++; + }else if(vwrq->value == 18000000){ + priv->reg.rate_set.body[7] = TX_RATE_18M; i++; + priv->reg.rate_set.body[6] = TX_RATE_9M; i++; + priv->reg.rate_set.body[5] = TX_RATE_12M|BASIC_RATE; i++; + priv->reg.rate_set.body[4] = TX_RATE_6M|BASIC_RATE; i++; + priv->reg.rate_set.body[3] = TX_RATE_11M|BASIC_RATE; i++; + }else if(vwrq->value == 12000000){ + priv->reg.rate_set.body[6] = TX_RATE_9M; i++; + priv->reg.rate_set.body[5] = TX_RATE_12M|BASIC_RATE; i++; + priv->reg.rate_set.body[4] = TX_RATE_6M|BASIC_RATE; i++; + priv->reg.rate_set.body[3] = TX_RATE_11M|BASIC_RATE; i++; + }else if(vwrq->value == 11000000){ + priv->reg.rate_set.body[5] = TX_RATE_9M; i++; + priv->reg.rate_set.body[4] = TX_RATE_6M|BASIC_RATE; i++; + priv->reg.rate_set.body[3] = TX_RATE_11M|BASIC_RATE; i++; + }else if(vwrq->value == 9000000){ + priv->reg.rate_set.body[4] = TX_RATE_9M; i++; + priv->reg.rate_set.body[3] = TX_RATE_6M|BASIC_RATE; i++; + }else{ /* vwrq->value == 6000000 */ + priv->reg.rate_set.body[3] = TX_RATE_6M|BASIC_RATE; i++; + } + case 5500000: + priv->reg.rate_set.body[2] = TX_RATE_5M|BASIC_RATE; i++; + case 2000000: + priv->reg.rate_set.body[1] = TX_RATE_2M|BASIC_RATE; i++; + case 1000000: + priv->reg.rate_set.body[0] = TX_RATE_1M|BASIC_RATE; i++; + break; + default: + return -EINVAL; + } + priv->reg.tx_rate = TX_RATE_MANUAL_AUTO; + priv->reg.rate_set.size = i; + }else{ + priv->reg.rate_set.body[11] = TX_RATE_54M; + priv->reg.rate_set.body[10] = TX_RATE_48M; + priv->reg.rate_set.body[9] = TX_RATE_36M; + priv->reg.rate_set.body[8] = TX_RATE_18M; + priv->reg.rate_set.body[7] = TX_RATE_9M; + priv->reg.rate_set.body[6] = TX_RATE_24M|BASIC_RATE; + priv->reg.rate_set.body[5] = TX_RATE_12M|BASIC_RATE; + priv->reg.rate_set.body[4] = TX_RATE_6M|BASIC_RATE; + priv->reg.rate_set.body[3] = TX_RATE_11M|BASIC_RATE; + priv->reg.rate_set.body[2] = TX_RATE_5M|BASIC_RATE; + priv->reg.rate_set.body[1] = TX_RATE_2M|BASIC_RATE; + priv->reg.rate_set.body[0] = TX_RATE_1M|BASIC_RATE; + priv->reg.tx_rate = TX_RATE_FULL_AUTO; + priv->reg.rate_set.size = 12; + } + } + } + + priv->need_commit |= SME_MODE_SET; + + return -EINPROGRESS; /* Call commit handler */ +} + +/*------------------------------------------------------------------*/ +/* Wireless Handler : get Bit-Rate */ +static int ks_wlan_get_rate(struct net_device *dev, struct iw_request_info *info, + struct iw_param *vwrq, char *extra) +{ + ks_wlan_private *priv = (ks_wlan_private *)netdev_priv(dev); + + DPRINTK(2, "in_interrupt = %ld update_phyinfo = %d\n", + in_interrupt(),atomic_read(&update_phyinfo)); + + if (priv->sleep_mode == SLP_SLEEP){ return -EPERM; } /* for SLEEP MODE */ + + if(!atomic_read(&update_phyinfo)){ + ks_wlan_update_phy_information(priv); + } + vwrq->value = ((priv->current_rate) & RATE_MASK) * 500000; + if(priv->reg.tx_rate == TX_RATE_FIXED) + vwrq->fixed = 1; + else + vwrq->fixed = 0; + + return 0; +} + +/*------------------------------------------------------------------*/ +/* Wireless Handler : set RTS threshold */ +static int ks_wlan_set_rts(struct net_device *dev, struct iw_request_info *info, + struct iw_param *vwrq, char *extra) +{ + ks_wlan_private *priv = (ks_wlan_private *)netdev_priv(dev); + int rthr = vwrq->value; + + if (priv->sleep_mode == SLP_SLEEP){ return -EPERM; } /* for SLEEP MODE */ + + if(vwrq->disabled) + rthr = 2347; + if((rthr < 0) || (rthr > 2347)) { + return -EINVAL; + } + priv->reg.rts = rthr; + priv->need_commit |= SME_RTS; + + return -EINPROGRESS; /* Call commit handler */ +} + +/*------------------------------------------------------------------*/ +/* Wireless Handler : get RTS threshold */ +static int ks_wlan_get_rts(struct net_device *dev, struct iw_request_info *info, + struct iw_param *vwrq, char *extra) +{ + ks_wlan_private *priv = (ks_wlan_private *)netdev_priv(dev); + + if (priv->sleep_mode == SLP_SLEEP){ return -EPERM; } /* for SLEEP MODE */ + + vwrq->value = priv->reg.rts; + vwrq->disabled = (vwrq->value >= 2347); + vwrq->fixed = 1; + + return 0; +} + +/*------------------------------------------------------------------*/ +/* Wireless Handler : set Fragmentation threshold */ +static int ks_wlan_set_frag(struct net_device *dev, struct iw_request_info *info, + struct iw_param *vwrq, char *extra) +{ + ks_wlan_private *priv = (ks_wlan_private *)netdev_priv(dev); + int fthr = vwrq->value; + + if (priv->sleep_mode == SLP_SLEEP){ return -EPERM; } /* for SLEEP MODE */ + + if(vwrq->disabled) + fthr = 2346; + if((fthr < 256) || (fthr > 2346)) { + return -EINVAL; + } + fthr &= ~0x1; /* Get an even value - is it really needed ??? */ + priv->reg.fragment = fthr; + priv->need_commit |= SME_FRAG; + + return -EINPROGRESS; /* Call commit handler */ +} + +/*------------------------------------------------------------------*/ +/* Wireless Handler : get Fragmentation threshold */ +static int ks_wlan_get_frag(struct net_device *dev, struct iw_request_info *info, + struct iw_param *vwrq, char *extra) +{ + ks_wlan_private *priv = (ks_wlan_private *)netdev_priv(dev); + + if (priv->sleep_mode == SLP_SLEEP){ return -EPERM; } /* for SLEEP MODE */ + + vwrq->value = priv->reg.fragment; + vwrq->disabled = (vwrq->value >= 2346); + vwrq->fixed = 1; + + return 0; +} + +/*------------------------------------------------------------------*/ +/* Wireless Handler : set Mode of Operation */ +static int ks_wlan_set_mode(struct net_device *dev, struct iw_request_info *info, + __u32 *uwrq, char *extra) +{ + ks_wlan_private *priv = (ks_wlan_private *)netdev_priv(dev); + + DPRINTK(2,"mode=%d\n",*uwrq); + + if (priv->sleep_mode == SLP_SLEEP){ return -EPERM; } /* for SLEEP MODE */ + + switch(*uwrq) { + case IW_MODE_ADHOC: + priv->reg.operation_mode = MODE_ADHOC; + priv->need_commit |= SME_MODE_SET; + break; + case IW_MODE_INFRA: + priv->reg.operation_mode = MODE_INFRASTRUCTURE; + priv->need_commit |= SME_MODE_SET; + break; + case IW_MODE_AUTO: + case IW_MODE_MASTER: + case IW_MODE_REPEAT: + case IW_MODE_SECOND: + case IW_MODE_MONITOR: + default: + return -EINVAL; + } + + return -EINPROGRESS; /* Call commit handler */ +} + +/*------------------------------------------------------------------*/ +/* Wireless Handler : get Mode of Operation */ +static int ks_wlan_get_mode(struct net_device *dev, struct iw_request_info *info, + __u32 *uwrq, char *extra) +{ + ks_wlan_private *priv = (ks_wlan_private *)netdev_priv(dev); + + if (priv->sleep_mode == SLP_SLEEP){ return -EPERM; } /* for SLEEP MODE */ + + /* If not managed, assume it's ad-hoc */ + switch (priv->reg.operation_mode) { + case MODE_INFRASTRUCTURE: + *uwrq = IW_MODE_INFRA; + break; + case MODE_ADHOC: + *uwrq = IW_MODE_ADHOC; + break; + default: + *uwrq = IW_MODE_ADHOC; + } + + return 0; +} + +/*------------------------------------------------------------------*/ +/* Wireless Handler : set Encryption Key */ +static int ks_wlan_set_encode(struct net_device *dev, struct iw_request_info *info, + struct iw_point *dwrq, char *extra) +{ + ks_wlan_private *priv = (ks_wlan_private *)netdev_priv(dev); + + wep_key_t key; + int index = (dwrq->flags & IW_ENCODE_INDEX); + int current_index = priv->reg.wep_index; + int i; + + DPRINTK(2,"flags=%04X\n",dwrq->flags); + + if (priv->sleep_mode == SLP_SLEEP){ return -EPERM; } /* for SLEEP MODE */ + + /* index check */ + if((index<0) || (index>4)) + return -EINVAL; + else if (index==0) + index = current_index; + else + index--; + + /* Is WEP supported ? */ + /* Basic checking: do we have a key to set ? */ + if (dwrq->length > 0) { + if (dwrq->length > MAX_KEY_SIZE) { /* Check the size of the key */ + return -EINVAL; + } + if (dwrq->length > MIN_KEY_SIZE) { /* Set the length */ + key.len = MAX_KEY_SIZE; + priv->reg.privacy_invoked = 0x01; + priv->need_commit |= SME_WEP_FLAG; + wep_on_off = WEP_ON_128BIT; + } else { + if (dwrq->length > 0) { + key.len = MIN_KEY_SIZE; + priv->reg.privacy_invoked = 0x01; + priv->need_commit |= SME_WEP_FLAG; + wep_on_off = WEP_ON_64BIT; + } else { /* Disable the key */ + key.len = 0; + } + } + /* Check if the key is not marked as invalid */ + if(!(dwrq->flags & IW_ENCODE_NOKEY)) { + /* Cleanup */ + memset(key.key, 0, MAX_KEY_SIZE); + /* Copy the key in the driver */ + if(copy_from_user(key.key,dwrq->pointer,dwrq->length)) { + key.len = 0; + return -EFAULT; + } + /* Send the key to the card */ + priv->reg.wep_key[index].size = key.len; + for (i=0; i<(priv->reg.wep_key[index].size); i++) { + priv->reg.wep_key[index].val[i] = key.key[i]; + } + priv->need_commit |= (SME_WEP_VAL1<reg.wep_index = index; + priv->need_commit |= SME_WEP_INDEX; + } + } else { + if(dwrq->flags & IW_ENCODE_DISABLED){ + priv->reg.wep_key[0].size = 0; + priv->reg.wep_key[1].size = 0; + priv->reg.wep_key[2].size = 0; + priv->reg.wep_key[3].size = 0; + priv->reg.privacy_invoked = 0x00; + if(priv->reg.authenticate_type == AUTH_TYPE_SHARED_KEY){ + priv->need_commit |= SME_MODE_SET; + } + priv->reg.authenticate_type = AUTH_TYPE_OPEN_SYSTEM; + wep_on_off = WEP_OFF; + priv->need_commit |= SME_WEP_FLAG; + }else{ + /* Do we want to just set the transmit key index ? */ + if ((index>=0) && (index<4)) { + /* set_wep_key(priv, index, 0, 0, 1); xxx */ + if(priv->reg.wep_key[index].size){ + priv->reg.wep_index = index; + priv->need_commit |= SME_WEP_INDEX; + } + else + return -EINVAL; + } + } + } + + /* Commit the changes if needed */ + if(dwrq->flags & IW_ENCODE_MODE) + priv->need_commit |= SME_WEP_FLAG; + + if(dwrq->flags & IW_ENCODE_OPEN) { + if(priv->reg.authenticate_type == AUTH_TYPE_SHARED_KEY){ + priv->need_commit |= SME_MODE_SET; + } + priv->reg.authenticate_type = AUTH_TYPE_OPEN_SYSTEM; + } else if(dwrq->flags & IW_ENCODE_RESTRICTED) { + if(priv->reg.authenticate_type == AUTH_TYPE_OPEN_SYSTEM){ + priv->need_commit |= SME_MODE_SET; + } + priv->reg.authenticate_type = AUTH_TYPE_SHARED_KEY; + } + +// return -EINPROGRESS; /* Call commit handler */ + if(priv->need_commit){ + ks_wlan_setup_parameter(priv, priv->need_commit); + priv->need_commit=0; + } + return 0; +} + +/*------------------------------------------------------------------*/ +/* Wireless Handler : get Encryption Key */ +static int ks_wlan_get_encode(struct net_device *dev, struct iw_request_info *info, + struct iw_point *dwrq, char *extra) +{ + ks_wlan_private *priv = (ks_wlan_private *)netdev_priv(dev); + char zeros[16]; + int index = (dwrq->flags & IW_ENCODE_INDEX) - 1; + + if (priv->sleep_mode == SLP_SLEEP){ return -EPERM; } /* for SLEEP MODE */ + + dwrq->flags = IW_ENCODE_DISABLED; + + /* Check encryption mode */ + switch(priv->reg.authenticate_type) { + case AUTH_TYPE_OPEN_SYSTEM: + dwrq->flags = IW_ENCODE_OPEN; + break; + case AUTH_TYPE_SHARED_KEY: + dwrq->flags = IW_ENCODE_RESTRICTED; + break; + } + + memset(zeros,0, sizeof(zeros)); + + /* Which key do we want ? -1 -> tx index */ + if((index < 0) || (index >= 4)) + index = priv->reg.wep_index; + if (priv->reg.privacy_invoked){ + dwrq->flags &= ~IW_ENCODE_DISABLED; + /* dwrq->flags |= IW_ENCODE_NOKEY; */ + } + dwrq->flags |= index + 1; + DPRINTK(2,"encoding flag = 0x%04X\n",dwrq->flags); + /* Copy the key to the user buffer */ + if((index >= 0) && (index < 4)) + dwrq->length = priv->reg.wep_key[index].size; + if (dwrq->length > 16) { + dwrq->length=0; + } +#if 1 /* IW_ENCODE_NOKEY; */ + if (dwrq->length) { + if((index >= 0) && (index < 4)) + memcpy(extra,priv->reg.wep_key[index].val,dwrq->length); + } else + memcpy(extra,zeros,dwrq->length); +#endif + return 0; +} + +#ifndef KSC_OPNOTSUPP +/*------------------------------------------------------------------*/ +/* Wireless Handler : set Tx-Power */ +static int ks_wlan_set_txpow(struct net_device *dev, struct iw_request_info *info, + struct iw_param *vwrq, char *extra) +{ + return -EOPNOTSUPP; /* Not Support */ +} + +/*------------------------------------------------------------------*/ +/* Wireless Handler : get Tx-Power */ +static int ks_wlan_get_txpow(struct net_device *dev, struct iw_request_info *info, + struct iw_param *vwrq, char *extra) +{ + if (priv->sleep_mode == SLP_SLEEP){ return -EPERM; } /* for SLEEP MODE */ + + /* Not Support */ + vwrq->value = 0; + vwrq->disabled = (vwrq->value == 0); + vwrq->fixed = 1; + return 0; +} + +/*------------------------------------------------------------------*/ +/* Wireless Handler : set Retry limits */ +static int ks_wlan_set_retry(struct net_device *dev, struct iw_request_info *info, + struct iw_param *vwrq, char *extra) +{ + return -EOPNOTSUPP; /* Not Support */ +} + +/*------------------------------------------------------------------*/ +/* Wireless Handler : get Retry limits */ +static int ks_wlan_get_retry(struct net_device *dev, struct iw_request_info *info, + struct iw_param *vwrq, char *extra) +{ + if (priv->sleep_mode == SLP_SLEEP){ return -EPERM; } /* for SLEEP MODE */ + + /* Not Support */ + vwrq->value = 0; + vwrq->disabled = (vwrq->value == 0); + vwrq->fixed = 1; + return 0; +} +#endif /* KSC_OPNOTSUPP */ + +/*------------------------------------------------------------------*/ +/* Wireless Handler : get range info */ +static int ks_wlan_get_range(struct net_device *dev, struct iw_request_info *info, + struct iw_point *dwrq, char *extra) +{ + ks_wlan_private *priv = (ks_wlan_private *)netdev_priv(dev); + struct iw_range *range = (struct iw_range *) extra; + int i,k; + + DPRINTK(2,"\n"); + + if (priv->sleep_mode == SLP_SLEEP){ return -EPERM; } /* for SLEEP MODE */ + + dwrq->length = sizeof(struct iw_range); + memset(range, 0, sizeof(*range)); + range->min_nwid = 0x0000; + range->max_nwid = 0x0000; + range->num_channels = 14; + /* Should be based on cap_rid.country to give only + * what the current card support */ + k = 0; + for(i = 0; i < 13; i++) { /* channel 1 -- 13*/ + range->freq[k].i = i + 1; /* List index */ + range->freq[k].m = frequency_list[i] * 100000; + range->freq[k++].e = 1; /* Values in table in MHz -> * 10^5 * 10 */ + } + range->num_frequency = k; + if(priv->reg.phy_type == D_11B_ONLY_MODE || + priv->reg.phy_type == D_11BG_COMPATIBLE_MODE){ /* channel 14 */ + range->freq[13].i = 14; /* List index */ + range->freq[13].m = frequency_list[13] * 100000; + range->freq[13].e = 1; /* Values in table in MHz -> * 10^5 * 10 */ + range->num_frequency = 14; + } + + /* Hum... Should put the right values there */ + range->max_qual.qual = 100; + range->max_qual.level = 256 - 128; /* 0 dBm? */ + range->max_qual.noise = 256 - 128; + range->sensitivity = 1; + + if(priv->reg.phy_type == D_11B_ONLY_MODE){ + range->bitrate[0] = 1e6; + range->bitrate[1] = 2e6; + range->bitrate[2] = 5.5e6; + range->bitrate[3] = 11e6; + range->num_bitrates = 4; + } + else{ /* D_11G_ONLY_MODE or D_11BG_COMPATIBLE_MODE */ + range->bitrate[0] = 1e6; + range->bitrate[1] = 2e6; + range->bitrate[2] = 5.5e6; + range->bitrate[3] = 11e6; + + range->bitrate[4] = 6e6; + range->bitrate[5] = 9e6; + range->bitrate[6] = 12e6; + if(IW_MAX_BITRATES < 9){ + range->bitrate[7] = 54e6; + range->num_bitrates = 8; + }else{ + range->bitrate[7] = 18e6; + range->bitrate[8] = 24e6; + range->bitrate[9] = 36e6; + range->bitrate[10] = 48e6; + range->bitrate[11] = 54e6; + + range->num_bitrates = 12; + } + } + + /* Set an indication of the max TCP throughput + * in bit/s that we can expect using this interface. + * May be use for QoS stuff... Jean II */ + if(i > 2) + range->throughput = 5000 * 1000; + else + range->throughput = 1500 * 1000; + + range->min_rts = 0; + range->max_rts = 2347; + range->min_frag = 256; + range->max_frag = 2346; + + range->encoding_size[0] = 5; /* WEP: RC4 40 bits */ + range->encoding_size[1] = 13; /* WEP: RC4 ~128 bits */ + range->num_encoding_sizes = 2; + range->max_encoding_tokens = 4; + + /* power management not support */ + range->pmp_flags = IW_POWER_ON; + range->pmt_flags = IW_POWER_ON; + range->pm_capa = 0; + + /* Transmit Power - values are in dBm( or mW) */ + range->txpower[0]=-256; + range->num_txpower = 1; + range->txpower_capa = IW_TXPOW_DBM; + /* range->txpower_capa = IW_TXPOW_MWATT; */ + + range->we_version_source = 21; + range->we_version_compiled = WIRELESS_EXT; + + range->retry_capa = IW_RETRY_ON; + range->retry_flags = IW_RETRY_ON; + range->r_time_flags = IW_RETRY_ON; + + /* Experimental measurements - boundary 11/5.5 Mb/s */ + /* Note : with or without the (local->rssi), results + * are somewhat different. - Jean II */ + range->avg_qual.qual = 50; + range->avg_qual.level = 186; /* -70 dBm */ + range->avg_qual.noise = 0; + +#if defined(WIRELESS_EXT) + /* Event capability (kernel + driver) */ + range->event_capa[0] = (IW_EVENT_CAPA_K_0 | + IW_EVENT_CAPA_MASK(SIOCGIWAP) | + IW_EVENT_CAPA_MASK(SIOCGIWSCAN)); + range->event_capa[1] = IW_EVENT_CAPA_K_1; + range->event_capa[4] = (IW_EVENT_CAPA_MASK(IWEVCUSTOM) | + IW_EVENT_CAPA_MASK(IWEVMICHAELMICFAILURE)); + + /* encode extension (WPA) capability */ + range->enc_capa = (IW_ENC_CAPA_WPA | + IW_ENC_CAPA_WPA2 | + IW_ENC_CAPA_CIPHER_TKIP | + IW_ENC_CAPA_CIPHER_CCMP); +#endif + return 0; +} + + +/*------------------------------------------------------------------*/ +/* Wireless Handler : set Power Management */ +static int ks_wlan_set_power(struct net_device *dev, struct iw_request_info *info, + struct iw_param *vwrq, char *extra) +{ + ks_wlan_private *priv = (ks_wlan_private *)netdev_priv(dev); + short enabled; + + if (priv->sleep_mode == SLP_SLEEP){ return -EPERM; } /* for SLEEP MODE */ + + enabled = vwrq->disabled ? 0 : 1; + if(enabled == 0 ){ /* 0 */ + priv->reg.powermgt = POWMGT_ACTIVE_MODE; + }else if(enabled){ /* 1 */ + if(priv->reg.operation_mode == MODE_INFRASTRUCTURE) + priv->reg.powermgt = POWMGT_SAVE1_MODE; + else + return -EINVAL; + }else if(enabled){ /* 2 */ + if(priv->reg.operation_mode == MODE_INFRASTRUCTURE) + priv->reg.powermgt = POWMGT_SAVE2_MODE; + else + return -EINVAL; + }else + return -EINVAL; + + hostif_sme_enqueue(priv, SME_POW_MNGMT_REQUEST); + + return 0; +} + +/*------------------------------------------------------------------*/ +/* Wireless Handler : get Power Management */ +static int ks_wlan_get_power(struct net_device *dev, struct iw_request_info *info, + struct iw_param *vwrq, char *extra) +{ + ks_wlan_private *priv = (ks_wlan_private *)netdev_priv(dev); + + if (priv->sleep_mode == SLP_SLEEP){ return -EPERM; } /* for SLEEP MODE */ + + if(priv->reg.powermgt > 0) + vwrq->disabled = 0; + else + vwrq->disabled = 1; + + return 0; +} + +/*------------------------------------------------------------------*/ +/* Wireless Handler : get wirless statistics */ +static int ks_wlan_get_iwstats(struct net_device *dev, struct iw_request_info *info, + struct iw_quality *vwrq, char *extra) +{ + ks_wlan_private *priv = (ks_wlan_private *)netdev_priv(dev); + + if (priv->sleep_mode == SLP_SLEEP){ return -EPERM; } /* for SLEEP MODE */ + + vwrq->qual = 0; /* not supported */ + vwrq->level = priv->wstats.qual.level; + vwrq->noise = 0; /* not supported */ + vwrq->updated = 0; + + return 0; +} + +#ifndef KSC_OPNOTSUPP +/*------------------------------------------------------------------*/ +/* Wireless Handler : set Sensitivity */ +static int ks_wlan_set_sens(struct net_device *dev, struct iw_request_info *info, + struct iw_param *vwrq, char *extra) +{ + return -EOPNOTSUPP; /* Not Support */ +} + +/*------------------------------------------------------------------*/ +/* Wireless Handler : get Sensitivity */ +static int ks_wlan_get_sens(struct net_device *dev, struct iw_request_info *info, + struct iw_param *vwrq, char *extra) +{ + /* Not Support */ + vwrq->value = 0; + vwrq->disabled = (vwrq->value == 0); + vwrq->fixed = 1; + return 0; +} +#endif /* KSC_OPNOTSUPP */ + + +/*------------------------------------------------------------------*/ +/* Wireless Handler : get AP List */ +/* Note : this is deprecated in favor of IWSCAN */ +static int ks_wlan_get_aplist(struct net_device *dev, struct iw_request_info *info, + struct iw_point *dwrq, char *extra) +{ + ks_wlan_private *priv = (ks_wlan_private *)netdev_priv(dev); + struct sockaddr *address = (struct sockaddr *) extra; + struct iw_quality qual[LOCAL_APLIST_MAX]; + + int i; + + if (priv->sleep_mode == SLP_SLEEP){ return -EPERM; } /* for SLEEP MODE */ + + for (i = 0; i < priv->aplist.size; i++) { + memcpy(address[i].sa_data, &(priv->aplist.ap[i].bssid[0]), ETH_ALEN); + address[i].sa_family = ARPHRD_ETHER; + qual[i].level = 256 - priv->aplist.ap[i].rssi; + qual[i].qual = priv->aplist.ap[i].sq; + qual[i].noise = 0; /* invalid noise value */ + qual[i].updated = 7; + } + if (i){ + dwrq->flags = 1; /* Should be define'd */ + memcpy(extra + sizeof(struct sockaddr)*i, + &qual, sizeof(struct iw_quality)*i); + } + dwrq->length = i; + + return 0; +} + +#if defined(WIRELESS_EXT) +/*------------------------------------------------------------------*/ +/* Wireless Handler : Initiate Scan */ +static int ks_wlan_set_scan(struct net_device *dev, struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + ks_wlan_private *priv = (ks_wlan_private *)netdev_priv(dev); + struct iw_scan_req *req = NULL; + DPRINTK(2,"\n"); + + if (priv->sleep_mode == SLP_SLEEP){ return -EPERM; } /* for SLEEP MODE */ + + /* specified SSID SCAN */ + if(wrqu->data.length == sizeof(struct iw_scan_req) && wrqu->data.flags & IW_SCAN_THIS_ESSID){ + req = (struct iw_scan_req *) extra; + priv->scan_ssid_len = req->essid_len; + memcpy(priv->scan_ssid, req->essid, priv->scan_ssid_len); + }else{ + priv->scan_ssid_len = 0; + } + + + priv->sme_i.sme_flag |= SME_AP_SCAN; + hostif_sme_enqueue(priv, SME_BSS_SCAN_REQUEST); + + /* At this point, just return to the user. */ + + return 0; +} + +/*------------------------------------------------------------------*/ +/* + * Translate scan data returned from the card to a card independent + * format that the Wireless Tools will understand - Jean II + */ +static inline char *ks_wlan_translate_scan(struct net_device *dev, struct iw_request_info *info, char *current_ev, + char *end_buf, struct local_ap_t *ap) +{ + /* ks_wlan_private *priv = (ks_wlan_private *)dev->priv; */ + struct iw_event iwe; /* Temporary buffer */ + u16 capabilities; + char *current_val; /* For rates */ + int i; + static const char rsn_leader[] = "rsn_ie="; + static const char wpa_leader[] = "wpa_ie="; + char buf0[RSN_IE_BODY_MAX*2 + 30]; + char buf1[RSN_IE_BODY_MAX*2 + 30]; + char *pbuf; + /* First entry *MUST* be the AP MAC address */ + iwe.cmd = SIOCGIWAP; + iwe.u.ap_addr.sa_family = ARPHRD_ETHER; + memcpy(iwe.u.ap_addr.sa_data, ap->bssid, ETH_ALEN); + current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe, IW_EV_ADDR_LEN); + + /* Other entries will be displayed in the order we give them */ + + /* Add the ESSID */ + iwe.u.data.length = ap->ssid.size; + if(iwe.u.data.length > 32) + iwe.u.data.length = 32; + iwe.cmd = SIOCGIWESSID; + iwe.u.data.flags = 1; + current_ev = iwe_stream_add_point(info, current_ev, end_buf, &iwe, &(ap->ssid.body[0])); + + /* Add mode */ + iwe.cmd = SIOCGIWMODE; + capabilities = le16_to_cpu(ap->capability); + if(capabilities & (BSS_CAP_ESS | BSS_CAP_IBSS)) { + if(capabilities & BSS_CAP_ESS) + iwe.u.mode = IW_MODE_INFRA; + else + iwe.u.mode = IW_MODE_ADHOC; + current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe, IW_EV_UINT_LEN); + } + + /* Add frequency */ + iwe.cmd = SIOCGIWFREQ; + iwe.u.freq.m = ap->channel; + iwe.u.freq.m = frequency_list[iwe.u.freq.m-1] * 100000; + iwe.u.freq.e = 1; + current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe, IW_EV_FREQ_LEN); + + /* Add quality statistics */ + iwe.cmd = IWEVQUAL; + iwe.u.qual.level = 256 - ap->rssi; + iwe.u.qual.qual = ap->sq; + iwe.u.qual.noise = 0; /* invalid noise value */ + current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe, IW_EV_QUAL_LEN); + + /* Add encryption capability */ + iwe.cmd = SIOCGIWENCODE; + if(capabilities & BSS_CAP_PRIVACY) + iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY; + else + iwe.u.data.flags = IW_ENCODE_DISABLED; + iwe.u.data.length = 0; + current_ev = iwe_stream_add_point(info, current_ev, end_buf, &iwe, &(ap->ssid.body[0])); + + /* Rate : stuffing multiple values in a single event require a bit + * more of magic - Jean II */ + current_val = current_ev + IW_EV_LCP_LEN; + + iwe.cmd = SIOCGIWRATE; + /* Those two flags are ignored... */ + iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0; + + /* Max 16 values */ + for(i = 0 ; i < 16 ; i++) { + /* NULL terminated */ + if(i >= ap->rate_set.size) + break; + /* Bit rate given in 500 kb/s units (+ 0x80) */ + iwe.u.bitrate.value = ((ap->rate_set.body[i] & 0x7f) * 500000); + /* Add new value to event */ + current_val = iwe_stream_add_value(info, current_ev, current_val, end_buf, &iwe, IW_EV_PARAM_LEN); + } + /* Check if we added any event */ + if((current_val - current_ev) > IW_EV_LCP_LEN) + current_ev = current_val; + +#define GENERIC_INFO_ELEM_ID 0xdd +#define RSN_INFO_ELEM_ID 0x30 + if (ap->rsn_ie.id == RSN_INFO_ELEM_ID && ap->rsn_ie.size != 0) { + pbuf = &buf0[0]; + memset(&iwe, 0, sizeof(iwe)); + iwe.cmd = IWEVCUSTOM; + memcpy(buf0,rsn_leader,sizeof(rsn_leader)-1); + iwe.u.data.length += sizeof(rsn_leader)-1; + pbuf += sizeof(rsn_leader)-1; + + pbuf += sprintf(pbuf, "%02x", ap->rsn_ie.id); + pbuf += sprintf(pbuf, "%02x", ap->rsn_ie.size); + iwe.u.data.length += 4; + + for (i = 0; i < ap->rsn_ie.size; i++) + pbuf += sprintf(pbuf, "%02x", ap->rsn_ie.body[i]); + iwe.u.data.length += (ap->rsn_ie.size)*2; + + DPRINTK(4,"ap->rsn.size=%d\n",ap->rsn_ie.size); + + current_ev = iwe_stream_add_point(info, current_ev, end_buf,&iwe, &buf0[0]); + } + if (ap->wpa_ie.id == GENERIC_INFO_ELEM_ID && ap->wpa_ie.size != 0) { + pbuf = &buf1[0]; + memset(&iwe, 0, sizeof(iwe)); + iwe.cmd = IWEVCUSTOM; + memcpy(buf1,wpa_leader,sizeof(wpa_leader)-1); + iwe.u.data.length += sizeof(wpa_leader)-1; + pbuf += sizeof(wpa_leader)-1; + + pbuf += sprintf(pbuf, "%02x", ap->wpa_ie.id); + pbuf += sprintf(pbuf, "%02x", ap->wpa_ie.size); + iwe.u.data.length += 4; + + for (i = 0; i < ap->wpa_ie.size; i++) + pbuf += sprintf(pbuf, "%02x", ap->wpa_ie.body[i]); + iwe.u.data.length += (ap->wpa_ie.size)*2; + + DPRINTK(4,"ap->rsn.size=%d\n",ap->wpa_ie.size); + DPRINTK(4,"iwe.u.data.length=%d\n",iwe.u.data.length); + + current_ev = iwe_stream_add_point(info, current_ev, end_buf,&iwe, &buf1[0]); + } + + /* The other data in the scan result are not really + * interesting, so for now drop it - Jean II */ + return current_ev; +} + +/*------------------------------------------------------------------*/ +/* Wireless Handler : Read Scan Results */ +static int ks_wlan_get_scan(struct net_device *dev, struct iw_request_info *info, + struct iw_point *dwrq, char *extra) +{ + ks_wlan_private *priv = (ks_wlan_private *)netdev_priv(dev); + int i; + char *current_ev = extra; + DPRINTK(2,"\n"); + + if (priv->sleep_mode == SLP_SLEEP){ return -EPERM; } /* for SLEEP MODE */ + + if(priv->sme_i.sme_flag & SME_AP_SCAN) { +DPRINTK(2,"flag AP_SCAN\n"); + return -EAGAIN; + } + + if(priv->aplist.size == 0) { + /* Client error, no scan results... + * The caller need to restart the scan. */ +DPRINTK(2,"aplist 0\n"); + return -ENODATA; + } +#if 0 + /* current connect ap */ + if((priv->connect_status & CONNECT_STATUS_MASK)== CONNECT_STATUS){ + if ((extra + dwrq->length) - current_ev <= IW_EV_ADDR_LEN) { + dwrq->length = 0; + return -E2BIG; + } + current_ev = ks_wlan_translate_scan(dev, current_ev, +// extra + IW_SCAN_MAX_DATA, + extra + dwrq->length, + &(priv->current_ap)); + } +#endif + /* Read and parse all entries */ + for(i=0; i < priv->aplist.size; i++) { + if ((extra + dwrq->length) - current_ev <= IW_EV_ADDR_LEN) { + dwrq->length = 0; + return -E2BIG; + } + /* Translate to WE format this entry */ + current_ev = ks_wlan_translate_scan(dev, info, current_ev, +// extra + IW_SCAN_MAX_DATA, + extra + dwrq->length, + &(priv->aplist.ap[i])); + } + /* Length of data */ + dwrq->length = (current_ev - extra); + dwrq->flags = 0; + + return 0; +} +#endif /* WIRELESS_EXT */ + +/*------------------------------------------------------------------*/ +/* Commit handler : called after a bunch of SET operations */ +static int ks_wlan_config_commit(struct net_device *dev, struct iw_request_info *info, + void *zwrq, char *extra) +{ + ks_wlan_private *priv = (ks_wlan_private *)netdev_priv(dev); + + if (!priv->need_commit) + return 0; + + ks_wlan_setup_parameter(priv, priv->need_commit); + priv->need_commit=0; + return 0; +} + +#ifdef WIRELESS_EXT +/*------------------------------------------------------------------*/ +/* Wireless handler : set association ie params */ +static int ks_wlan_set_genie(struct net_device *dev, struct iw_request_info *info, + struct iw_point *dwrq, char *extra) +{ + ks_wlan_private *priv = (ks_wlan_private *)netdev_priv(dev); + + DPRINTK(2, "\n"); + + if (priv->sleep_mode == SLP_SLEEP){ return -EPERM; } /* for SLEEP MODE */ + + return 0; +// return -EOPNOTSUPP; +} + +/*------------------------------------------------------------------*/ +/* Wireless handler : set authentication mode params */ +static int ks_wlan_set_auth_mode(struct net_device *dev, struct iw_request_info *info, + struct iw_param *vwrq, char *extra) +{ + ks_wlan_private *priv = (ks_wlan_private *)netdev_priv(dev); + int index = (vwrq->flags & IW_AUTH_INDEX); + int value = vwrq->value; + + DPRINTK(2,"index=%d:value=%08X\n",index,value); + + if (priv->sleep_mode == SLP_SLEEP){ return -EPERM; } /* for SLEEP MODE */ + + switch(index){ + case IW_AUTH_WPA_VERSION: /* 0 */ + switch(value){ + case IW_AUTH_WPA_VERSION_DISABLED: + priv->wpa.version = value; + if(priv->wpa.rsn_enabled){ + priv->wpa.rsn_enabled = 0; + } + priv->need_commit |= SME_RSN; + break; + case IW_AUTH_WPA_VERSION_WPA: + case IW_AUTH_WPA_VERSION_WPA2: + priv->wpa.version = value; + if(!(priv->wpa.rsn_enabled)){ + priv->wpa.rsn_enabled = 1; + } + priv->need_commit |= SME_RSN; + break; + default: + return -EOPNOTSUPP; + } + break; + case IW_AUTH_CIPHER_PAIRWISE: /* 1 */ + switch(value){ + case IW_AUTH_CIPHER_NONE: + if(priv->reg.privacy_invoked){ + priv->reg.privacy_invoked = 0x00; + priv->need_commit |= SME_WEP_FLAG; + } + break; + case IW_AUTH_CIPHER_WEP40: + case IW_AUTH_CIPHER_TKIP: + case IW_AUTH_CIPHER_CCMP: + case IW_AUTH_CIPHER_WEP104: + if(!priv->reg.privacy_invoked){ + priv->reg.privacy_invoked = 0x01; + priv->need_commit |= SME_WEP_FLAG; + } + priv->wpa.pairwise_suite = value; + priv->need_commit |= SME_RSN_UNICAST; + break; + default: + return -EOPNOTSUPP; + } + break; + case IW_AUTH_CIPHER_GROUP: /* 2 */ + switch(value){ + case IW_AUTH_CIPHER_NONE: + if(priv->reg.privacy_invoked){ + priv->reg.privacy_invoked = 0x00; + priv->need_commit |= SME_WEP_FLAG; + } + break; + case IW_AUTH_CIPHER_WEP40: + case IW_AUTH_CIPHER_TKIP: + case IW_AUTH_CIPHER_CCMP: + case IW_AUTH_CIPHER_WEP104: + if(!priv->reg.privacy_invoked){ + priv->reg.privacy_invoked = 0x01; + priv->need_commit |= SME_WEP_FLAG; + } + priv->wpa.group_suite = value; + priv->need_commit |= SME_RSN_MULTICAST; + break; + default: + return -EOPNOTSUPP; + } + break; + case IW_AUTH_KEY_MGMT: /* 3 */ + switch(value){ + case IW_AUTH_KEY_MGMT_802_1X: + case IW_AUTH_KEY_MGMT_PSK: + case 0: /* NONE or 802_1X_NO_WPA */ + case 4: /* WPA_NONE */ + priv->wpa.key_mgmt_suite = value; + priv->need_commit |= SME_RSN_AUTH; + break; + default: + return -EOPNOTSUPP; + } + break; + case IW_AUTH_80211_AUTH_ALG: /* 6 */ + switch(value){ + case IW_AUTH_ALG_OPEN_SYSTEM: + priv->wpa.auth_alg = value; + priv->reg.authenticate_type = AUTH_TYPE_OPEN_SYSTEM; + break; + case IW_AUTH_ALG_SHARED_KEY: + priv->wpa.auth_alg = value; + priv->reg.authenticate_type = AUTH_TYPE_SHARED_KEY; + break; + case IW_AUTH_ALG_LEAP: + default: + return -EOPNOTSUPP; + } + priv->need_commit |= SME_MODE_SET; + break; + case IW_AUTH_WPA_ENABLED: /* 7 */ + priv->wpa.wpa_enabled = value; + break; + case IW_AUTH_PRIVACY_INVOKED: /* 10 */ + if((value && !priv->reg.privacy_invoked)|| + (!value && priv->reg.privacy_invoked)){ + priv->reg.privacy_invoked = value?0x01:0x00; + priv->need_commit |= SME_WEP_FLAG; + } + break; + case IW_AUTH_RX_UNENCRYPTED_EAPOL: /* 4 */ + case IW_AUTH_TKIP_COUNTERMEASURES: /* 5 */ + case IW_AUTH_DROP_UNENCRYPTED: /* 8 */ + case IW_AUTH_ROAMING_CONTROL: /* 9 */ + default: + break; + } + + /* return -EINPROGRESS; */ + if(priv->need_commit){ + ks_wlan_setup_parameter(priv, priv->need_commit); + priv->need_commit=0; + } + return 0; +} + +/*------------------------------------------------------------------*/ +/* Wireless handler : get authentication mode params */ +static int ks_wlan_get_auth_mode(struct net_device *dev, struct iw_request_info *info, + struct iw_param *vwrq, char *extra) +{ + ks_wlan_private *priv = (ks_wlan_private *)netdev_priv(dev); + int index = (vwrq->flags & IW_AUTH_INDEX); + DPRINTK(2,"index=%d\n",index); + + if (priv->sleep_mode == SLP_SLEEP){ return -EPERM; } /* for SLEEP MODE */ + + /* WPA (not used ?? wpa_supplicant) */ + switch(index){ + case IW_AUTH_WPA_VERSION: + vwrq->value = priv->wpa.version; + break; + case IW_AUTH_CIPHER_PAIRWISE: + vwrq->value = priv->wpa.pairwise_suite; + break; + case IW_AUTH_CIPHER_GROUP: + vwrq->value = priv->wpa.group_suite; + break; + case IW_AUTH_KEY_MGMT: + vwrq->value = priv->wpa.key_mgmt_suite; + break; + case IW_AUTH_80211_AUTH_ALG: + vwrq->value = priv->wpa.auth_alg; + break; + case IW_AUTH_WPA_ENABLED: + vwrq->value = priv->wpa.rsn_enabled; + break; + case IW_AUTH_RX_UNENCRYPTED_EAPOL: /* OK??? */ + case IW_AUTH_TKIP_COUNTERMEASURES: + case IW_AUTH_DROP_UNENCRYPTED: + default: + /* return -EOPNOTSUPP; */ + break; + } + return 0; +} + +/*------------------------------------------------------------------*/ +/* Wireless Handler : set encoding token & mode (WPA)*/ +static int ks_wlan_set_encode_ext(struct net_device *dev, struct iw_request_info *info, + struct iw_point *dwrq, char *extra) +{ + ks_wlan_private *priv = (ks_wlan_private *)netdev_priv(dev); + struct iw_encode_ext *enc; + int index = dwrq->flags & IW_ENCODE_INDEX; + unsigned int commit=0; + + enc = (struct iw_encode_ext *)extra; + + DPRINTK(2,"flags=%04X:: ext_flags=%08X\n",dwrq->flags, enc->ext_flags); + + if (priv->sleep_mode == SLP_SLEEP){ return -EPERM; } /* for SLEEP MODE */ + + if(index<1||index>4) + return -EINVAL; + else + index--; + + if(dwrq->flags & IW_ENCODE_DISABLED){ + priv->wpa.key[index].key_len=0; + } + + if(enc){ + priv->wpa.key[index].ext_flags=enc->ext_flags; + if(enc->ext_flags&IW_ENCODE_EXT_SET_TX_KEY){ + priv->wpa.txkey=index; + commit |= SME_WEP_INDEX; + }else if(enc->ext_flags&IW_ENCODE_EXT_RX_SEQ_VALID){ + if(enc->rx_seq) + memcpy(&priv->wpa.key[index].rx_seq[0], + enc->rx_seq, IW_ENCODE_SEQ_MAX_SIZE); + else + return -EINVAL; + } + + memcpy(&priv->wpa.key[index].addr.sa_data[0], + &enc->addr.sa_data[0], ETH_ALEN); + + switch (enc->alg) { + case IW_ENCODE_ALG_NONE: + if(priv->reg.privacy_invoked){ + priv->reg.privacy_invoked = 0x00; + commit |= SME_WEP_FLAG; + } + priv->wpa.key[index].key_len = 0; + + break; + case IW_ENCODE_ALG_WEP: + case IW_ENCODE_ALG_CCMP: + if(!priv->reg.privacy_invoked){ + priv->reg.privacy_invoked = 0x01; + commit |= SME_WEP_FLAG; + } + if(enc->key && enc->key_len){ + memcpy(&priv->wpa.key[index].key_val[0], + &enc->key[0], enc->key_len); + priv->wpa.key[index].key_len = enc->key_len; + commit |= (SME_WEP_VAL1 << index); + } + break; + case IW_ENCODE_ALG_TKIP: + if(!priv->reg.privacy_invoked){ + priv->reg.privacy_invoked = 0x01; + commit |= SME_WEP_FLAG; + } + if(enc->key && enc->key_len == 32){ + memcpy(&priv->wpa.key[index].key_val[0], + &enc->key[0], enc->key_len-16); + priv->wpa.key[index].key_len = enc->key_len-16; + if(priv->wpa.key_mgmt_suite==4){ /* WPA_NONE */ + memcpy(&priv->wpa.key[index].tx_mic_key[0], + &enc->key[16],8); + memcpy(&priv->wpa.key[index].rx_mic_key[0], + &enc->key[16],8); + }else{ + memcpy(&priv->wpa.key[index].tx_mic_key[0], + &enc->key[16],8); + memcpy(&priv->wpa.key[index].rx_mic_key[0], + &enc->key[24],8); + } + commit |= (SME_WEP_VAL1 << index); + } + break; + default: + return -EINVAL; + } + priv->wpa.key[index].alg=enc->alg; + } + else + return -EINVAL; + + if(commit){ + if(commit&SME_WEP_INDEX) + hostif_sme_enqueue(priv, SME_SET_TXKEY); + if(commit&SME_WEP_VAL_MASK) + hostif_sme_enqueue(priv, SME_SET_KEY1+index); + if(commit&SME_WEP_FLAG) + hostif_sme_enqueue(priv, SME_WEP_FLAG_REQUEST); + } + + return 0; +} + +/*------------------------------------------------------------------*/ +/* Wireless Handler : get encoding token & mode (WPA)*/ +static int ks_wlan_get_encode_ext(struct net_device *dev, struct iw_request_info *info, + struct iw_point *dwrq, char *extra) +{ + ks_wlan_private *priv = (ks_wlan_private *)netdev_priv(dev); + + if (priv->sleep_mode == SLP_SLEEP){ return -EPERM; } /* for SLEEP MODE */ + + /* WPA (not used ?? wpa_supplicant) + ks_wlan_private *priv = (ks_wlan_private *)dev->priv; + struct iw_encode_ext *enc; + enc = (struct iw_encode_ext *)extra; + int index = dwrq->flags & IW_ENCODE_INDEX; + WPA (not used ?? wpa_supplicant) */ + return 0; +} + +/*------------------------------------------------------------------*/ +/* Wireless Handler : PMKSA cache operation (WPA2) */ +static int ks_wlan_set_pmksa(struct net_device *dev, struct iw_request_info *info, + struct iw_point *dwrq, char *extra) +{ + ks_wlan_private *priv = (ks_wlan_private *)netdev_priv(dev); + struct iw_pmksa *pmksa ; + int i; + struct pmk_t *pmk; + struct list_head *ptr; + + DPRINTK(2,"\n"); + + if (priv->sleep_mode == SLP_SLEEP){ return -EPERM; } /* for SLEEP MODE */ + + if(!extra){ + return -EINVAL; + } + pmksa = (struct iw_pmksa *)extra; + DPRINTK(2,"cmd=%d\n",pmksa->cmd); + + switch(pmksa->cmd){ + case IW_PMKSA_ADD: + if(list_empty(&priv->pmklist.head)){ /* new list */ + for(i=0;ipmklist.pmk[i]; + if(!memcmp("\x00\x00\x00\x00\x00\x00",pmk->bssid,ETH_ALEN)) + break; + } + memcpy(pmk->bssid, pmksa->bssid.sa_data, ETH_ALEN); + memcpy(pmk->pmkid, pmksa->pmkid, IW_PMKID_LEN); + list_add(&pmk->list,&priv->pmklist.head); + priv->pmklist.size++; + } + else { /* search cache data */ + list_for_each(ptr, &priv->pmklist.head){ + pmk = list_entry(ptr, struct pmk_t, list); + if(!memcmp(pmksa->bssid.sa_data, pmk->bssid, ETH_ALEN)){ /* match address! list move to head. */ + memcpy(pmk->pmkid, pmksa->pmkid, IW_PMKID_LEN); + list_move(&pmk->list, &priv->pmklist.head); + break; + } + } + if(ptr == &priv->pmklist.head){ /* not find address. */ + if(PMK_LIST_MAX > priv->pmklist.size){ /* new cache data */ + for(i=0;ipmklist.pmk[i]; + if(!memcmp("\x00\x00\x00\x00\x00\x00",pmk->bssid,ETH_ALEN)) + break; + } + memcpy(pmk->bssid, pmksa->bssid.sa_data, ETH_ALEN); + memcpy(pmk->pmkid, pmksa->pmkid, IW_PMKID_LEN); + list_add(&pmk->list,&priv->pmklist.head); + priv->pmklist.size++; + } + else{ /* overwrite old cache data */ + pmk = list_entry(priv->pmklist.head.prev, struct pmk_t, list); + memcpy(pmk->bssid, pmksa->bssid.sa_data, ETH_ALEN); + memcpy(pmk->pmkid, pmksa->pmkid, IW_PMKID_LEN); + list_move(&pmk->list,&priv->pmklist.head); + } + } + } + break; + case IW_PMKSA_REMOVE: + if(list_empty(&priv->pmklist.head)){ /* list empty */ + return -EINVAL; + } + else{ /* search cache data */ + list_for_each(ptr, &priv->pmklist.head){ + pmk = list_entry(ptr, struct pmk_t, list); + if(!memcmp(pmksa->bssid.sa_data, pmk->bssid, ETH_ALEN)){ /* match address! list del. */ + memset(pmk->bssid, 0, ETH_ALEN); + memset(pmk->pmkid, 0, IW_PMKID_LEN); + list_del_init(&pmk->list); + break; + } + } + if(ptr == &priv->pmklist.head){ /* not find address. */ + return 0; + } + } + break; + case IW_PMKSA_FLUSH: + memset(&(priv->pmklist), 0, sizeof(priv->pmklist)); + INIT_LIST_HEAD(&priv->pmklist.head); + for(i=0;ipmklist.pmk[i].list); + break; + default: + return -EINVAL; + } + + hostif_sme_enqueue(priv, SME_SET_PMKSA); + return 0; +} + +static struct iw_statistics *ks_get_wireless_stats(struct net_device *dev) +{ + + ks_wlan_private *priv = (ks_wlan_private *) netdev_priv(dev); + struct iw_statistics *wstats = &priv->wstats; + + if(!atomic_read(&update_phyinfo)){ + if (priv->dev_state < DEVICE_STATE_READY) + return NULL; /* not finished initialize */ + else + return wstats; + } + + /* Packets discarded in the wireless adapter due to wireless + * specific problems */ + wstats->discard.nwid = 0; /* Rx invalid nwid */ + wstats->discard.code = 0; /* Rx invalid crypt */ + wstats->discard.fragment = 0; /* Rx invalid frag */ + wstats->discard.retries = 0; /* Tx excessive retries */ + wstats->discard.misc = 0; /* Invalid misc */ + wstats->miss.beacon = 0; /* Missed beacon */ + + return wstats; +} + +/*------------------------------------------------------------------*/ +/* Private handler : set stop request */ +static int ks_wlan_set_stop_request(struct net_device *dev, struct iw_request_info *info, + __u32 *uwrq, char *extra) +{ + ks_wlan_private *priv = (ks_wlan_private *)netdev_priv(dev); + DPRINTK(2,"\n"); + + if (priv->sleep_mode == SLP_SLEEP){ return -EPERM; } /* for SLEEP MODE */ + + if(!(*uwrq)) + return -EINVAL; + + hostif_sme_enqueue(priv, SME_STOP_REQUEST); + return 0; +} + +/*------------------------------------------------------------------*/ +/* Wireless Handler : set MLME */ +#include +static int ks_wlan_set_mlme(struct net_device *dev, struct iw_request_info *info, + struct iw_point *dwrq, char *extra) +{ + ks_wlan_private *priv = (ks_wlan_private *)netdev_priv(dev); + struct iw_mlme *mlme = (struct iw_mlme *)extra; + __u32 mode; + + DPRINTK(2, ":%d :%d\n", mlme->cmd, mlme->reason_code); + + if (priv->sleep_mode == SLP_SLEEP){ return -EPERM; } /* for SLEEP MODE */ + + switch (mlme->cmd) { + case IW_MLME_DEAUTH: + if (mlme->reason_code == WLAN_REASON_MIC_FAILURE) { + return 0; + } + case IW_MLME_DISASSOC: + mode = 1; + return ks_wlan_set_stop_request(dev, NULL, &mode, NULL); + default: + return -EOPNOTSUPP; /* Not Support */ + } +} +#endif /* WIRELESS_EXT */ + +/*------------------------------------------------------------------*/ +/* Private handler : get driver version */ +static int ks_wlan_get_driver_version(struct net_device *dev, struct iw_request_info *info, + struct iw_point *dwrq, char *extra) +{ + strcpy(extra, KS_WLAN_DRIVER_VERSION_INFO); + dwrq->length = strlen(KS_WLAN_DRIVER_VERSION_INFO)+1; + return 0; +} + +/*------------------------------------------------------------------*/ +/* Private handler : get firemware version */ +static int ks_wlan_get_firmware_version(struct net_device *dev, struct iw_request_info *info, + struct iw_point *dwrq, char *extra) +{ + ks_wlan_private *priv = (ks_wlan_private *)netdev_priv(dev); + strcpy(extra, &(priv->firmware_version[0])); + dwrq->length = priv->version_size+1; + return 0; +} + +#if 0 +/*------------------------------------------------------------------*/ +/* Private handler : set force disconnect status */ +static int ks_wlan_set_detach(struct net_device *dev, struct iw_request_info *info, + __u32 *uwrq, char *extra) +{ + ks_wlan_private *priv = (ks_wlan_private *)dev->priv; + + if (priv->sleep_mode == SLP_SLEEP){ return -EPERM; } /* for SLEEP MODE */ + + if(*uwrq == CONNECT_STATUS){ /* 0 */ + priv->connect_status &= ~FORCE_DISCONNECT; + if((priv->connect_status & CONNECT_STATUS_MASK) == CONNECT_STATUS) + netif_carrier_on(dev); + }else if(*uwrq == DISCONNECT_STATUS){ /* 1 */ + priv->connect_status |= FORCE_DISCONNECT; + netif_carrier_off(dev); + }else + return -EINVAL; + return 0; +} + +/*------------------------------------------------------------------*/ +/* Private handler : get force disconnect status */ +static int ks_wlan_get_detach(struct net_device *dev, struct iw_request_info *info, + __u32 *uwrq, char *extra) +{ + ks_wlan_private *priv = (ks_wlan_private *)dev->priv; + + if (priv->sleep_mode == SLP_SLEEP){ return -EPERM; } /* for SLEEP MODE */ + + *uwrq = ((priv->connect_status & FORCE_DISCONNECT) ? 1 : 0 ); + return 0; +} + +/*------------------------------------------------------------------*/ +/* Private handler : get connect status */ +static int ks_wlan_get_connect(struct net_device *dev, struct iw_request_info *info, + __u32 *uwrq, char *extra) +{ + ks_wlan_private *priv = (ks_wlan_private *)dev->priv; + + if (priv->sleep_mode == SLP_SLEEP){ return -EPERM; } /* for SLEEP MODE */ + + *uwrq = (priv->connect_status & CONNECT_STATUS_MASK); + return 0; +} +#endif + +/*------------------------------------------------------------------*/ +/* Private handler : set preamble */ +static int ks_wlan_set_preamble(struct net_device *dev, struct iw_request_info *info, + __u32 *uwrq, char *extra) +{ + ks_wlan_private *priv = (ks_wlan_private *)netdev_priv(dev); + + if (priv->sleep_mode == SLP_SLEEP){ return -EPERM; } /* for SLEEP MODE */ + + if(*uwrq == LONG_PREAMBLE){ /* 0 */ + priv->reg.preamble = LONG_PREAMBLE; + }else if(*uwrq == SHORT_PREAMBLE){ /* 1 */ + priv->reg.preamble = SHORT_PREAMBLE; + }else + return -EINVAL; + + priv->need_commit |= SME_MODE_SET; + return -EINPROGRESS; /* Call commit handler */ + +} + +/*------------------------------------------------------------------*/ +/* Private handler : get preamble */ +static int ks_wlan_get_preamble(struct net_device *dev, struct iw_request_info *info, + __u32 *uwrq, char *extra) +{ + ks_wlan_private *priv = (ks_wlan_private *)netdev_priv(dev); + + if (priv->sleep_mode == SLP_SLEEP){ return -EPERM; } /* for SLEEP MODE */ + + *uwrq = priv->reg.preamble; + return 0; +} + +/*------------------------------------------------------------------*/ +/* Private handler : set power save mode */ +static int ks_wlan_set_powermgt(struct net_device *dev, struct iw_request_info *info, + __u32 *uwrq, char *extra) +{ + ks_wlan_private *priv = (ks_wlan_private *)netdev_priv(dev); + + if (priv->sleep_mode == SLP_SLEEP){ return -EPERM; } /* for SLEEP MODE */ + + if(*uwrq == POWMGT_ACTIVE_MODE){ /* 0 */ + priv->reg.powermgt = POWMGT_ACTIVE_MODE; + }else if(*uwrq == POWMGT_SAVE1_MODE){ /* 1 */ + if(priv->reg.operation_mode == MODE_INFRASTRUCTURE) + priv->reg.powermgt = POWMGT_SAVE1_MODE; + else + return -EINVAL; + }else if(*uwrq == POWMGT_SAVE2_MODE){ /* 2 */ + if(priv->reg.operation_mode == MODE_INFRASTRUCTURE) + priv->reg.powermgt = POWMGT_SAVE2_MODE; + else + return -EINVAL; + }else + return -EINVAL; + + hostif_sme_enqueue(priv, SME_POW_MNGMT_REQUEST); + + return 0; +} + +/*------------------------------------------------------------------*/ +/* Private handler : get power save made */ +static int ks_wlan_get_powermgt(struct net_device *dev, struct iw_request_info *info, + __u32 *uwrq, char *extra) +{ + ks_wlan_private *priv = (ks_wlan_private *)netdev_priv(dev); + + if (priv->sleep_mode == SLP_SLEEP){ return -EPERM; } /* for SLEEP MODE */ + + *uwrq = priv->reg.powermgt; + return 0; +} + +/*------------------------------------------------------------------*/ +/* Private handler : set scan type */ +static int ks_wlan_set_scan_type(struct net_device *dev, struct iw_request_info *info, + __u32 *uwrq, char *extra) +{ + ks_wlan_private *priv = (ks_wlan_private *)netdev_priv(dev); + + if (priv->sleep_mode == SLP_SLEEP){ return -EPERM; } /* for SLEEP MODE */ + + if(*uwrq == ACTIVE_SCAN){ /* 0 */ + priv->reg.scan_type = ACTIVE_SCAN; + }else if(*uwrq == PASSIVE_SCAN){ /* 1 */ + priv->reg.scan_type = PASSIVE_SCAN; + }else + return -EINVAL; + + return 0; +} + +/*------------------------------------------------------------------*/ +/* Private handler : get scan type */ +static int ks_wlan_get_scan_type(struct net_device *dev, struct iw_request_info *info, + __u32 *uwrq, char *extra) +{ + ks_wlan_private *priv = (ks_wlan_private *)netdev_priv(dev); + + if (priv->sleep_mode == SLP_SLEEP){ return -EPERM; } /* for SLEEP MODE */ + + *uwrq = priv->reg.scan_type; + return 0; +} +#if 0 +/*------------------------------------------------------------------*/ +/* Private handler : write raw data to device */ +static int ks_wlan_data_write(struct net_device *dev, struct iw_request_info *info, + struct iw_point *dwrq, char *extra) +{ + ks_wlan_private *priv = (ks_wlan_private *)dev->priv; + unsigned char *wbuff = NULL; + + if (priv->sleep_mode == SLP_SLEEP){ return -EPERM; } /* for SLEEP MODE */ + + wbuff = (unsigned char *)kmalloc(dwrq->length, GFP_ATOMIC); + if(!wbuff) + return -EFAULT; + memcpy(wbuff, extra, dwrq->length); + + /* write to device */ + ks_wlan_hw_tx( priv, wbuff, dwrq->length, NULL, NULL, NULL); + + return 0; +} + +/*------------------------------------------------------------------*/ +/* Private handler : read raw data form device */ +static int ks_wlan_data_read(struct net_device *dev, struct iw_request_info *info, + struct iw_point *dwrq, char *extra) +{ + ks_wlan_private *priv = (ks_wlan_private *)dev->priv; + unsigned short read_length; + + if (priv->sleep_mode == SLP_SLEEP){ return -EPERM; } /* for SLEEP MODE */ + + if(!atomic_read(&priv->event_count)){ + if (priv->dev_state < DEVICE_STATE_BOOT) { /* Remove device */ + read_length = 4; + memset(extra,0xff,read_length); + dwrq->length = read_length; + return 0; + } + read_length = 0; + memset(extra,0,1); + dwrq->length = 0; + return 0; + } + + if(atomic_read(&priv->event_count)>0) + atomic_dec(&priv->event_count); + + spin_lock(&priv->dev_read_lock); /* request spin lock */ + + /* Copy length max size 0x07ff */ + if(priv->dev_size[priv->dev_count] > 2047) + read_length = 2047; + else + read_length = priv->dev_size[priv->dev_count]; + + /* Copy data */ + memcpy(extra, &(priv->dev_data[priv->dev_count][0]), read_length); + + spin_unlock(&priv->dev_read_lock); /* release spin lock */ + + /* Initialize */ + priv->dev_data[priv->dev_count] = 0; + priv->dev_size[priv->dev_count] = 0; + + priv->dev_count++; + if(priv->dev_count == DEVICE_STOCK_COUNT) + priv->dev_count=0; + + /* Set read size */ + dwrq->length = read_length; + + return 0; +} +#endif + +#if 0 +/*------------------------------------------------------------------*/ +/* Private handler : get wep string */ +#define WEP_ASCII_BUFF_SIZE (17+64*4+1) +static int ks_wlan_get_wep_ascii(struct net_device *dev, struct iw_request_info *info, + struct iw_point *dwrq, char *extra) +{ + ks_wlan_private *priv = (ks_wlan_private *)dev->priv; + int i,j,len=0; + char tmp[WEP_ASCII_BUFF_SIZE]; + + if (priv->sleep_mode == SLP_SLEEP){ return -EPERM; } /* for SLEEP MODE */ + + strcpy(tmp," WEP keys ASCII \n"); + len+=strlen(" WEP keys ASCII \n"); + + for(i=0;i<4;i++){ + strcpy(tmp+len,"\t["); + len+=strlen("\t["); + tmp[len] = '1'+i; + len++; + strcpy(tmp+len,"] "); + len+=strlen("] "); + if(priv->reg.wep_key[i].size){ + strcpy(tmp+len,(priv->reg.wep_key[i].size < 6 ? "(40bits) [" : "(104bits) [")); + len+=strlen((priv->reg.wep_key[i].size < 6 ? "(40bits) [" : "(104bits) [")); + for(j=0;jreg.wep_key[i].size;j++,len++) + tmp[len]=(isprint(priv->reg.wep_key[i].val[j]) ? priv->reg.wep_key[i].val[j] : ' '); + + strcpy(tmp+len,"]\n"); + len+=strlen("]\n"); + } + else{ + strcpy(tmp+len,"off\n"); + len+=strlen("off\n"); + } + } + + memcpy(extra, tmp, len); + dwrq->length = len+1; + return 0; +} +#endif + +/*------------------------------------------------------------------*/ +/* Private handler : set beacon lost count */ +static int ks_wlan_set_beacon_lost(struct net_device *dev, struct iw_request_info *info, + __u32 *uwrq, char *extra) +{ + ks_wlan_private *priv = (ks_wlan_private *)netdev_priv(dev); + + if (priv->sleep_mode == SLP_SLEEP){ return -EPERM; } /* for SLEEP MODE */ + + if(*uwrq >= BEACON_LOST_COUNT_MIN && + *uwrq <= BEACON_LOST_COUNT_MAX){ + priv->reg.beacon_lost_count = *uwrq; + }else + return -EINVAL; + + if(priv->reg.operation_mode == MODE_INFRASTRUCTURE){ + priv->need_commit |= SME_MODE_SET; + return -EINPROGRESS; /* Call commit handler */ + } + else + return 0; +} + +/*------------------------------------------------------------------*/ +/* Private handler : get beacon lost count */ +static int ks_wlan_get_beacon_lost(struct net_device *dev, struct iw_request_info *info, + __u32 *uwrq, char *extra) +{ + ks_wlan_private *priv = (ks_wlan_private *)netdev_priv(dev); + + if (priv->sleep_mode == SLP_SLEEP){ return -EPERM; } /* for SLEEP MODE */ + + *uwrq = priv->reg.beacon_lost_count; + return 0; +} + +/*------------------------------------------------------------------*/ +/* Private handler : set phy type */ +static int ks_wlan_set_phy_type(struct net_device *dev, struct iw_request_info *info, + __u32 *uwrq, char *extra) +{ + ks_wlan_private *priv = (ks_wlan_private *)netdev_priv(dev); + + if (priv->sleep_mode == SLP_SLEEP){ return -EPERM; } /* for SLEEP MODE */ + + if(*uwrq == D_11B_ONLY_MODE){ /* 0 */ + priv->reg.phy_type = D_11B_ONLY_MODE; + }else if(*uwrq == D_11G_ONLY_MODE){ /* 1 */ + priv->reg.phy_type = D_11G_ONLY_MODE; + }else if(*uwrq == D_11BG_COMPATIBLE_MODE){ /* 2 */ + priv->reg.phy_type = D_11BG_COMPATIBLE_MODE; + }else + return -EINVAL; + + priv->need_commit |= SME_MODE_SET; + return -EINPROGRESS; /* Call commit handler */ +} + +/*------------------------------------------------------------------*/ +/* Private handler : get phy type */ +static int ks_wlan_get_phy_type(struct net_device *dev, struct iw_request_info *info, + __u32 *uwrq, char *extra) +{ + ks_wlan_private *priv = (ks_wlan_private *)netdev_priv(dev); + + if (priv->sleep_mode == SLP_SLEEP){ return -EPERM; } /* for SLEEP MODE */ + + *uwrq = priv->reg.phy_type; + return 0; +} + +/*------------------------------------------------------------------*/ +/* Private handler : set cts mode */ +static int ks_wlan_set_cts_mode(struct net_device *dev, struct iw_request_info *info, + __u32 *uwrq, char *extra) +{ + ks_wlan_private *priv = (ks_wlan_private *)netdev_priv(dev); + + if (priv->sleep_mode == SLP_SLEEP){ return -EPERM; } /* for SLEEP MODE */ + + if(*uwrq == CTS_MODE_FALSE){ /* 0 */ + priv->reg.cts_mode = CTS_MODE_FALSE; + }else if(*uwrq == CTS_MODE_TRUE){ /* 1 */ + if(priv->reg.phy_type == D_11G_ONLY_MODE || + priv->reg.phy_type == D_11BG_COMPATIBLE_MODE) + priv->reg.cts_mode = CTS_MODE_TRUE; + else + priv->reg.cts_mode = CTS_MODE_FALSE; + }else + return -EINVAL; + + priv->need_commit |= SME_MODE_SET; + return -EINPROGRESS; /* Call commit handler */ +} + +/*------------------------------------------------------------------*/ +/* Private handler : get cts mode */ +static int ks_wlan_get_cts_mode(struct net_device *dev, struct iw_request_info *info, + __u32 *uwrq, char *extra) +{ + ks_wlan_private *priv = (ks_wlan_private *)netdev_priv(dev); + + if (priv->sleep_mode == SLP_SLEEP){ return -EPERM; } /* for SLEEP MODE */ + + *uwrq = priv->reg.cts_mode; + return 0; +} + +/*------------------------------------------------------------------*/ +/* Private handler : set sleep mode */ +static int ks_wlan_set_sleep_mode(struct net_device *dev, + struct iw_request_info *info, + __u32 *uwrq, char *extra) +{ + ks_wlan_private *priv = (ks_wlan_private *)netdev_priv(dev); + + DPRINTK(2,"\n"); + + if(*uwrq == SLP_SLEEP){ + priv->sleep_mode = *uwrq; + printk("SET_SLEEP_MODE %d\n", priv->sleep_mode); + + hostif_sme_enqueue(priv, SME_STOP_REQUEST); + hostif_sme_enqueue(priv, SME_SLEEP_REQUEST); + + }else if(*uwrq == SLP_ACTIVE) { + priv->sleep_mode = *uwrq; + printk("SET_SLEEP_MODE %d\n", priv->sleep_mode); + hostif_sme_enqueue(priv, SME_SLEEP_REQUEST); + }else{ + printk("SET_SLEEP_MODE %d errror\n", *uwrq); + return -EINVAL; + } + + return 0; +} +/*------------------------------------------------------------------*/ +/* Private handler : get sleep mode */ +static int ks_wlan_get_sleep_mode(struct net_device *dev, + struct iw_request_info *info, + __u32 *uwrq, char *extra) +{ + ks_wlan_private *priv = (ks_wlan_private *)netdev_priv(dev); + + DPRINTK(2, "GET_SLEEP_MODE %d\n", priv->sleep_mode); + *uwrq = priv->sleep_mode; + + return 0; +} + +#if 0 +/*------------------------------------------------------------------*/ +/* Private handler : set phy information timer */ +static int ks_wlan_set_phy_information_timer(struct net_device *dev, struct iw_request_info *info, + __u32 *uwrq, char *extra) +{ + ks_wlan_private *priv = (ks_wlan_private *)dev->priv; + + if (priv->sleep_mode == SLP_SLEEP){ return -EPERM; } /* for SLEEP MODE */ + + if(*uwrq >= 0 && *uwrq <= 0xFFFF) /* 0-65535 */ + priv->reg.phy_info_timer = (uint16_t)*uwrq; + else + return -EINVAL; + + hostif_sme_enqueue(priv, SME_PHY_INFO_REQUEST); + + return 0; +} + +/*------------------------------------------------------------------*/ +/* Private handler : get phy information timer */ +static int ks_wlan_get_phy_information_timer(struct net_device *dev, struct iw_request_info *info, + __u32 *uwrq, char *extra) +{ + ks_wlan_private *priv = (ks_wlan_private *)dev->priv; + + if (priv->sleep_mode == SLP_SLEEP){ return -EPERM; } /* for SLEEP MODE */ + + *uwrq = priv->reg.phy_info_timer; + return 0; +} +#endif + +#ifdef WPS +/*------------------------------------------------------------------*/ +/* Private handler : set WPS enable */ +static int ks_wlan_set_wps_enable(struct net_device *dev, struct iw_request_info *info, + __u32 *uwrq, char *extra) +{ + ks_wlan_private *priv = (ks_wlan_private *)netdev_priv(dev); + DPRINTK(2,"\n"); + + if (priv->sleep_mode == SLP_SLEEP){ return -EPERM; } /* for SLEEP MODE */ + + if(*uwrq == 0 || *uwrq == 1) + priv->wps.wps_enabled = *uwrq; + else + return -EINVAL; + + hostif_sme_enqueue(priv, SME_WPS_ENABLE_REQUEST); + + return 0; +} +/*------------------------------------------------------------------*/ +/* Private handler : get WPS enable */ +static int ks_wlan_get_wps_enable(struct net_device *dev, struct iw_request_info *info, + __u32 *uwrq, char *extra) +{ + ks_wlan_private *priv = (ks_wlan_private *)netdev_priv(dev); + DPRINTK(2,"\n"); + + if (priv->sleep_mode == SLP_SLEEP){ return -EPERM; } /* for SLEEP MODE */ + + *uwrq = priv->wps.wps_enabled; + printk("return=%d\n", *uwrq); + + return 0; +} +/*------------------------------------------------------------------*/ +/* Private handler : set WPS probe req */ +static int ks_wlan_set_wps_probe_req(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *dwrq, char *extra) +{ + uint8_t *p = extra; + unsigned char len; + ks_wlan_private *priv = (ks_wlan_private *)netdev_priv(dev); + + DPRINTK(2,"\n"); + + if (priv->sleep_mode == SLP_SLEEP){ return -EPERM; } /* for SLEEP MODE */ + + DPRINTK(2,"dwrq->length=%d\n", dwrq->length); + + /* length check */ + if(p[1] + 2 != dwrq->length || dwrq->length > 256 ){ + return -EINVAL; + } + + priv->wps.ielen = p[1] + 2 + 1; /* IE header + IE + sizeof(len) */ + len = p[1] + 2; /* IE header + IE */ + + memcpy(priv->wps.ie, &len, sizeof(len)); + p = memcpy(priv->wps.ie+1, p, len); + + DPRINTK(2,"%d(%#x): %02X %02X %02X %02X ... %02X %02X %02X\n", + priv->wps.ielen, priv->wps.ielen, p[0], p[1], p[2], p[3], + p[priv->wps.ielen-3], p[priv->wps.ielen-2], p[priv->wps.ielen-1]); + + hostif_sme_enqueue(priv, SME_WPS_PROBE_REQUEST); + + return 0; +} +#if 0 +/*------------------------------------------------------------------*/ +/* Private handler : get WPS probe req */ +static int ks_wlan_get_wps_probe_req(struct net_device *dev, + struct iw_request_info *info, + __u32 *uwrq, char *extra) +{ + ks_wlan_private *priv = (ks_wlan_private *)dev->priv; + DPRINTK(2,"\n"); + + if (priv->sleep_mode == SLP_SLEEP){ return -EPERM; } /* for SLEEP MODE */ + + return 0; +} +#endif +#endif /* WPS */ + +/*------------------------------------------------------------------*/ +/* Private handler : set tx gain control value */ +static int ks_wlan_set_tx_gain(struct net_device *dev, struct iw_request_info *info, + __u32 *uwrq, char *extra) +{ + ks_wlan_private *priv = (ks_wlan_private *)netdev_priv(dev); + + if (priv->sleep_mode == SLP_SLEEP){ return -EPERM; } /* for SLEEP MODE */ + + if(*uwrq >= 0 && *uwrq <= 0xFF) /* 0-255 */ + priv->gain.TxGain = (uint8_t)*uwrq; + else + return -EINVAL; + + if(priv->gain.TxGain < 0xFF) + priv->gain.TxMode = 1; + else + priv->gain.TxMode = 0; + + + hostif_sme_enqueue(priv, SME_SET_GAIN); + return 0; +} + +/*------------------------------------------------------------------*/ +/* Private handler : get tx gain control value */ +static int ks_wlan_get_tx_gain(struct net_device *dev, struct iw_request_info *info, + __u32 *uwrq, char *extra) +{ + ks_wlan_private *priv = (ks_wlan_private *)netdev_priv(dev); + + if (priv->sleep_mode == SLP_SLEEP){ return -EPERM; } /* for SLEEP MODE */ + + *uwrq = priv->gain.TxGain; + hostif_sme_enqueue(priv, SME_GET_GAIN); + return 0; +} + +/*------------------------------------------------------------------*/ +/* Private handler : set rx gain control value */ +static int ks_wlan_set_rx_gain(struct net_device *dev, struct iw_request_info *info, + __u32 *uwrq, char *extra) +{ + ks_wlan_private *priv = (ks_wlan_private *)netdev_priv(dev); + + if (priv->sleep_mode == SLP_SLEEP){ return -EPERM; } /* for SLEEP MODE */ + + if(*uwrq >= 0 && *uwrq <= 0xFF) /* 0-255 */ + priv->gain.RxGain = (uint8_t)*uwrq; + else + return -EINVAL; + + if(priv->gain.RxGain < 0xFF) + priv->gain.RxMode = 1; + else + priv->gain.RxMode = 0; + + hostif_sme_enqueue(priv, SME_SET_GAIN); + return 0; +} + +/*------------------------------------------------------------------*/ +/* Private handler : get rx gain control value */ +static int ks_wlan_get_rx_gain(struct net_device *dev, struct iw_request_info *info, + __u32 *uwrq, char *extra) +{ + ks_wlan_private *priv = (ks_wlan_private *)netdev_priv(dev); + + if (priv->sleep_mode == SLP_SLEEP){ return -EPERM; } /* for SLEEP MODE */ + + *uwrq = priv->gain.RxGain; + hostif_sme_enqueue(priv, SME_GET_GAIN); + return 0; +} +#if 0 +/*------------------------------------------------------------------*/ +/* Private handler : set region value */ +static int ks_wlan_set_region(struct net_device *dev, struct iw_request_info *info, + __u32 *uwrq, char *extra) +{ + ks_wlan_private *priv = (ks_wlan_private *)dev->priv; + + if (priv->sleep_mode == SLP_SLEEP){ return -EPERM; } /* for SLEEP MODE */ + + if(*uwrq >= 0x9 && *uwrq <= 0xF) /* 0x9-0xf */ + priv->region = (uint8_t)*uwrq; + else + return -EINVAL; + + hostif_sme_enqueue(priv, SME_SET_REGION); + return 0; +} +#endif + +/*------------------------------------------------------------------*/ +/* Private handler : get eeprom checksum result */ +static int ks_wlan_get_eeprom_cksum(struct net_device *dev, struct iw_request_info *info, + __u32 *uwrq, char *extra) +{ + ks_wlan_private *priv = (ks_wlan_private *)netdev_priv(dev); + + *uwrq = priv->eeprom_checksum; + return 0; +} + +static void print_hif_event(int event){ + + switch(event){ + case HIF_DATA_REQ : + printk("HIF_DATA_REQ\n"); + break; + case HIF_DATA_IND : + printk("HIF_DATA_IND\n"); + break; + case HIF_MIB_GET_REQ : + printk("HIF_MIB_GET_REQ\n"); + break; + case HIF_MIB_GET_CONF : + printk("HIF_MIB_GET_CONF\n"); + break; + case HIF_MIB_SET_REQ : + printk("HIF_MIB_SET_REQ\n"); + break; + case HIF_MIB_SET_CONF : + printk("HIF_MIB_SET_CONF\n"); + break; + case HIF_POWERMGT_REQ : + printk("HIF_POWERMGT_REQ\n"); + break; + case HIF_POWERMGT_CONF : + printk("HIF_POWERMGT_CONF\n"); + break; + case HIF_START_REQ : + printk("HIF_START_REQ\n"); + break; + case HIF_START_CONF : + printk("HIF_START_CONF\n"); + break; + case HIF_CONNECT_IND : + printk("HIF_CONNECT_IND\n"); + break; + case HIF_STOP_REQ : + printk("HIF_STOP_REQ\n"); + break; + case HIF_STOP_CONF : + printk("HIF_STOP_CONF\n"); + break; + case HIF_PS_ADH_SET_REQ : + printk("HIF_PS_ADH_SET_REQ\n"); + break; + case HIF_PS_ADH_SET_CONF: + printk("HIF_PS_ADH_SET_CONF\n"); + break; + case HIF_INFRA_SET_REQ : + printk("HIF_INFRA_SET_REQ\n"); + break; + case HIF_INFRA_SET_CONF : + printk("HIF_INFRA_SET_CONF\n"); + break; + case HIF_ADH_SET_REQ : + printk("HIF_ADH_SET_REQ\n"); + break; + case HIF_ADH_SET_CONF : + printk("HIF_ADH_SET_CONF\n"); + break; + case HIF_AP_SET_REQ : + printk("HIF_AP_SET_REQ\n"); + break; + case HIF_AP_SET_CONF : + printk("HIF_AP_SET_CONF\n"); + break; + case HIF_ASSOC_INFO_IND : + printk("HIF_ASSOC_INFO_IND\n"); + break; + case HIF_MIC_FAILURE_REQ: + printk("HIF_MIC_FAILURE_REQ\n"); + break; + case HIF_MIC_FAILURE_CONF : + printk("HIF_MIC_FAILURE_CONF\n"); + break; + case HIF_SCAN_REQ : + printk("HIF_SCAN_REQ\n"); + break; + case HIF_SCAN_CONF : + printk("HIF_SCAN_CONF\n"); + break; + case HIF_PHY_INFO_REQ : + printk("HIF_PHY_INFO_REQ\n"); + break; + case HIF_PHY_INFO_CONF : + printk("HIF_PHY_INFO_CONF\n"); + break; + case HIF_SLEEP_REQ : + printk("HIF_SLEEP_REQ\n"); + break; + case HIF_SLEEP_CONF : + printk("HIF_SLEEP_CONF\n"); + break; + case HIF_PHY_INFO_IND : + printk("HIF_PHY_INFO_IND\n"); + break; + case HIF_SCAN_IND : + printk("HIF_SCAN_IND\n"); + break; + case HIF_INFRA_SET2_REQ : + printk("HIF_INFRA_SET2_REQ\n"); + break; + case HIF_INFRA_SET2_CONF: + printk("HIF_INFRA_SET2_CONF\n"); + break; + case HIF_ADH_SET2_REQ : + printk("HIF_ADH_SET2_REQ\n"); + break; + case HIF_ADH_SET2_CONF : + printk("HIF_ADH_SET2_CONF\n"); + } +} + +/*------------------------------------------------------------------*/ +/* Private handler : get host command history */ +static int ks_wlan_hostt(struct net_device *dev, struct iw_request_info *info, + __u32 *uwrq, char *extra) +{ + int i,event; + ks_wlan_private *priv = (ks_wlan_private *)netdev_priv(dev); + + for(i = 63; i >= 0; i--){ + event = priv->hostt.buff[(priv->hostt.qtail -1 -i)%SME_EVENT_BUFF_SIZE] ; + print_hif_event(event); + } + return 0; +} + +/* Structures to export the Wireless Handlers */ + +static const struct iw_priv_args ks_wlan_private_args[] = { +/*{ cmd, set_args, get_args, name[16] } */ + { KS_WLAN_GET_DRIVER_VERSION, IW_PRIV_TYPE_NONE, IW_PRIV_TYPE_CHAR | (128+1), "GetDriverVer" }, + { KS_WLAN_GET_FIRM_VERSION, IW_PRIV_TYPE_NONE, IW_PRIV_TYPE_CHAR | (128+1), "GetFirmwareVer" }, +#ifdef WPS + { KS_WLAN_SET_WPS_ENABLE, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, IW_PRIV_TYPE_NONE, "SetWPSEnable" }, + { KS_WLAN_GET_WPS_ENABLE, IW_PRIV_TYPE_NONE, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "GetW" }, + { KS_WLAN_SET_WPS_PROBE_REQ, IW_PRIV_TYPE_BYTE | 2047, IW_PRIV_TYPE_NONE, "SetWPSProbeReq" }, +#endif /* WPS */ + { KS_WLAN_SET_PREAMBLE, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, IW_PRIV_TYPE_NONE, "SetPreamble" }, + { KS_WLAN_GET_PREAMBLE, IW_PRIV_TYPE_NONE, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "GetPreamble" }, + { KS_WLAN_SET_POWER_SAVE, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, IW_PRIV_TYPE_NONE, "SetPowerSave" }, + { KS_WLAN_GET_POWER_SAVE, IW_PRIV_TYPE_NONE, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "GetPowerSave" }, + { KS_WLAN_SET_SCAN_TYPE, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, IW_PRIV_TYPE_NONE, "SetScanType" }, + { KS_WLAN_GET_SCAN_TYPE, IW_PRIV_TYPE_NONE, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "GetScanType" }, + { KS_WLAN_SET_RX_GAIN, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, IW_PRIV_TYPE_NONE, "SetRxGain" }, + { KS_WLAN_GET_RX_GAIN, IW_PRIV_TYPE_NONE, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "GetRxGain" }, + { KS_WLAN_HOSTT, IW_PRIV_TYPE_NONE, IW_PRIV_TYPE_CHAR | (128+1), "hostt" }, + { KS_WLAN_SET_BEACON_LOST, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, IW_PRIV_TYPE_NONE, "SetBeaconLost" }, + { KS_WLAN_GET_BEACON_LOST, IW_PRIV_TYPE_NONE, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "GetBeaconLost" }, + { KS_WLAN_SET_SLEEP_MODE, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, IW_PRIV_TYPE_NONE, "SetSleepMode" }, + { KS_WLAN_GET_SLEEP_MODE, IW_PRIV_TYPE_NONE, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "GetSleepMode" }, + { KS_WLAN_SET_TX_GAIN, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, IW_PRIV_TYPE_NONE, "SetTxGain" }, + { KS_WLAN_GET_TX_GAIN, IW_PRIV_TYPE_NONE, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "GetTxGain" }, + { KS_WLAN_SET_PHY_TYPE, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, IW_PRIV_TYPE_NONE, "SetPhyType" }, + { KS_WLAN_GET_PHY_TYPE, IW_PRIV_TYPE_NONE, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "GetPhyType" }, + { KS_WLAN_SET_CTS_MODE, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, IW_PRIV_TYPE_NONE, "SetCtsMode" }, + { KS_WLAN_GET_CTS_MODE, IW_PRIV_TYPE_NONE, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "GetCtsMode" }, + { KS_WLAN_GET_EEPROM_CKSUM, IW_PRIV_TYPE_NONE, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "GetChecksum" }, +}; +static const iw_handler ks_wlan_handler[] = +{ + (iw_handler) ks_wlan_config_commit, /* SIOCSIWCOMMIT */ + (iw_handler) ks_wlan_get_name, /* SIOCGIWNAME */ + (iw_handler) NULL, /* SIOCSIWNWID */ + (iw_handler) NULL, /* SIOCGIWNWID */ + (iw_handler) ks_wlan_set_freq, /* SIOCSIWFREQ */ + (iw_handler) ks_wlan_get_freq, /* SIOCGIWFREQ */ + (iw_handler) ks_wlan_set_mode, /* SIOCSIWMODE */ + (iw_handler) ks_wlan_get_mode, /* SIOCGIWMODE */ +#ifndef KSC_OPNOTSUPP + (iw_handler) ks_wlan_set_sens, /* SIOCSIWSENS */ + (iw_handler) ks_wlan_get_sens, /* SIOCGIWSENS */ +#else /* KSC_OPNOTSUPP */ + (iw_handler) NULL, /* SIOCSIWSENS */ + (iw_handler) NULL, /* SIOCGIWSENS */ +#endif /* KSC_OPNOTSUPP */ + (iw_handler) NULL, /* SIOCSIWRANGE */ + (iw_handler) ks_wlan_get_range, /* SIOCGIWRANGE */ + (iw_handler) NULL, /* SIOCSIWPRIV */ + (iw_handler) NULL, /* SIOCGIWPRIV */ + (iw_handler) NULL, /* SIOCSIWSTATS */ + (iw_handler) ks_wlan_get_iwstats, /* SIOCGIWSTATS */ + (iw_handler) NULL, /* SIOCSIWSPY */ + (iw_handler) NULL, /* SIOCGIWSPY */ + (iw_handler) NULL, /* SIOCSIWTHRSPY */ + (iw_handler) NULL, /* SIOCGIWTHRSPY */ + (iw_handler) ks_wlan_set_wap, /* SIOCSIWAP */ + (iw_handler) ks_wlan_get_wap, /* SIOCGIWAP */ +// (iw_handler) NULL, /* SIOCSIWMLME */ + (iw_handler) ks_wlan_set_mlme, /* SIOCSIWMLME */ + (iw_handler) ks_wlan_get_aplist, /* SIOCGIWAPLIST */ + (iw_handler) ks_wlan_set_scan, /* SIOCSIWSCAN */ + (iw_handler) ks_wlan_get_scan, /* SIOCGIWSCAN */ + (iw_handler) ks_wlan_set_essid, /* SIOCSIWESSID */ + (iw_handler) ks_wlan_get_essid, /* SIOCGIWESSID */ + (iw_handler) ks_wlan_set_nick, /* SIOCSIWNICKN */ + (iw_handler) ks_wlan_get_nick, /* SIOCGIWNICKN */ + (iw_handler) NULL, /* -- hole -- */ + (iw_handler) NULL, /* -- hole -- */ + (iw_handler) ks_wlan_set_rate, /* SIOCSIWRATE */ + (iw_handler) ks_wlan_get_rate, /* SIOCGIWRATE */ + (iw_handler) ks_wlan_set_rts, /* SIOCSIWRTS */ + (iw_handler) ks_wlan_get_rts, /* SIOCGIWRTS */ + (iw_handler) ks_wlan_set_frag, /* SIOCSIWFRAG */ + (iw_handler) ks_wlan_get_frag, /* SIOCGIWFRAG */ +#ifndef KSC_OPNOTSUPP + (iw_handler) ks_wlan_set_txpow, /* SIOCSIWTXPOW */ + (iw_handler) ks_wlan_get_txpow, /* SIOCGIWTXPOW */ + (iw_handler) ks_wlan_set_retry, /* SIOCSIWRETRY */ + (iw_handler) ks_wlan_get_retry, /* SIOCGIWRETRY */ +#else /* KSC_OPNOTSUPP */ + (iw_handler) NULL, /* SIOCSIWTXPOW */ + (iw_handler) NULL, /* SIOCGIWTXPOW */ + (iw_handler) NULL, /* SIOCSIWRETRY */ + (iw_handler) NULL, /* SIOCGIWRETRY */ +#endif /* KSC_OPNOTSUPP */ + (iw_handler) ks_wlan_set_encode, /* SIOCSIWENCODE */ + (iw_handler) ks_wlan_get_encode, /* SIOCGIWENCODE */ + (iw_handler) ks_wlan_set_power, /* SIOCSIWPOWER */ + (iw_handler) ks_wlan_get_power, /* SIOCGIWPOWER */ + (iw_handler) NULL, /* -- hole -- */ + (iw_handler) NULL, /* -- hole -- */ +// (iw_handler) NULL, /* SIOCSIWGENIE */ + (iw_handler) ks_wlan_set_genie, /* SIOCSIWGENIE */ + (iw_handler) NULL, /* SIOCGIWGENIE */ + (iw_handler) ks_wlan_set_auth_mode, /* SIOCSIWAUTH */ + (iw_handler) ks_wlan_get_auth_mode, /* SIOCGIWAUTH */ + (iw_handler) ks_wlan_set_encode_ext, /* SIOCSIWENCODEEXT */ + (iw_handler) ks_wlan_get_encode_ext, /* SIOCGIWENCODEEXT */ + (iw_handler) ks_wlan_set_pmksa, /* SIOCSIWPMKSA */ + (iw_handler) NULL, /* -- hole -- */ +}; + +/* private_handler */ +static const iw_handler ks_wlan_private_handler[] = +{ + (iw_handler) NULL, /* 0 */ + (iw_handler) ks_wlan_get_driver_version, /* 1 KS_WLAN_GET_DRIVER_VERSION */ + (iw_handler) NULL, /* 2 */ + (iw_handler) ks_wlan_get_firmware_version, /* 3 KS_WLAN_GET_FIRM_VERSION */ +#ifdef WPS + (iw_handler) ks_wlan_set_wps_enable, /* 4 KS_WLAN_SET_WPS_ENABLE */ + (iw_handler) ks_wlan_get_wps_enable, /* 5 KS_WLAN_GET_WPS_ENABLE */ + (iw_handler) ks_wlan_set_wps_probe_req, /* 6 KS_WLAN_SET_WPS_PROBE_REQ */ +#else + (iw_handler) NULL, /* 4 */ + (iw_handler) NULL, /* 5 */ + (iw_handler) NULL, /* 6 */ +#endif /* WPS */ + + (iw_handler) ks_wlan_get_eeprom_cksum, /* 7 KS_WLAN_GET_CONNECT */ + (iw_handler) ks_wlan_set_preamble, /* 8 KS_WLAN_SET_PREAMBLE */ + (iw_handler) ks_wlan_get_preamble, /* 9 KS_WLAN_GET_PREAMBLE */ + (iw_handler) ks_wlan_set_powermgt, /* 10 KS_WLAN_SET_POWER_SAVE */ + (iw_handler) ks_wlan_get_powermgt, /* 11 KS_WLAN_GET_POWER_SAVE */ + (iw_handler) ks_wlan_set_scan_type, /* 12 KS_WLAN_SET_SCAN_TYPE */ + (iw_handler) ks_wlan_get_scan_type, /* 13 KS_WLAN_GET_SCAN_TYPE */ + (iw_handler) ks_wlan_set_rx_gain, /* 14 KS_WLAN_SET_RX_GAIN */ + (iw_handler) ks_wlan_get_rx_gain, /* 15 KS_WLAN_GET_RX_GAIN */ + (iw_handler) ks_wlan_hostt, /* 16 KS_WLAN_HOSTT */ + (iw_handler) NULL, /* 17 */ + (iw_handler) ks_wlan_set_beacon_lost, /* 18 KS_WLAN_SET_BECAN_LOST */ + (iw_handler) ks_wlan_get_beacon_lost, /* 19 KS_WLAN_GET_BECAN_LOST */ + (iw_handler) ks_wlan_set_tx_gain, /* 20 KS_WLAN_SET_TX_GAIN */ + (iw_handler) ks_wlan_get_tx_gain, /* 21 KS_WLAN_GET_TX_GAIN */ + (iw_handler) ks_wlan_set_phy_type, /* 22 KS_WLAN_SET_PHY_TYPE */ + (iw_handler) ks_wlan_get_phy_type, /* 23 KS_WLAN_GET_PHY_TYPE */ + (iw_handler) ks_wlan_set_cts_mode, /* 24 KS_WLAN_SET_CTS_MODE */ + (iw_handler) ks_wlan_get_cts_mode, /* 25 KS_WLAN_GET_CTS_MODE */ + (iw_handler) NULL, /* 26 */ + (iw_handler) NULL, /* 27 */ + (iw_handler) ks_wlan_set_sleep_mode, /* 28 KS_WLAN_SET_SLEEP_MODE */ + (iw_handler) ks_wlan_get_sleep_mode, /* 29 KS_WLAN_GET_SLEEP_MODE */ + (iw_handler) NULL, /* 30 */ + (iw_handler) NULL, /* 31 */ +}; + +static const struct iw_handler_def ks_wlan_handler_def = +{ + .num_standard = sizeof(ks_wlan_handler)/sizeof(iw_handler), + .num_private = sizeof(ks_wlan_private_handler)/sizeof(iw_handler), + .num_private_args = sizeof(ks_wlan_private_args)/sizeof(struct iw_priv_args), + .standard = (iw_handler *) ks_wlan_handler, + .private = (iw_handler *) ks_wlan_private_handler, + .private_args = (struct iw_priv_args *) ks_wlan_private_args, + .get_wireless_stats = ks_get_wireless_stats, +}; + +#endif /* WIRELESS_EXT */ + +static int ks_wlan_netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) +{ + int rc = 0; +#if defined(WIRELESS_EXT) + struct iwreq *wrq = (struct iwreq *) rq; +#endif /* WIRELESS_EXT */ + switch (cmd) { +#if defined(WIRELESS_EXT) + case SIOCIWFIRSTPRIV+20: /* KS_WLAN_SET_STOP_REQ */ + rc = ks_wlan_set_stop_request(dev, NULL, &(wrq->u.mode), NULL); + break; +#endif /* WIRELESS_EXT >17 */ + // All other calls are currently unsupported + default: + rc = -EOPNOTSUPP; + } + + DPRINTK(5,"return=%d\n",rc); + return rc; +} + + +static +struct net_device_stats *ks_wlan_get_stats(struct net_device *dev) +{ + ks_wlan_private *priv = netdev_priv(dev); + + if (priv->dev_state < DEVICE_STATE_READY) { + return NULL; /* not finished initialize */ + } + + return &priv->nstats; +} + +static +int ks_wlan_set_mac_address(struct net_device *dev, void *addr) +{ + ks_wlan_private *priv = netdev_priv(dev); + struct sockaddr *mac_addr=(struct sockaddr *)addr; + if (netif_running(dev)) + return -EBUSY; + memcpy(dev->dev_addr, mac_addr->sa_data, dev->addr_len); + memcpy(priv->eth_addr, mac_addr->sa_data, ETH_ALEN); + + priv->mac_address_valid = 0; + hostif_sme_enqueue(priv, SME_MACADDRESS_SET_REQUEST); + printk(KERN_INFO "ks_wlan: MAC ADDRESS = %02x:%02x:%02x:%02x:%02x:%02x\n", + priv->eth_addr[0],priv->eth_addr[1],priv->eth_addr[2], + priv->eth_addr[3],priv->eth_addr[4],priv->eth_addr[5]); + return 0; +} + + +static +void ks_wlan_tx_timeout(struct net_device *dev) +{ + ks_wlan_private *priv = netdev_priv(dev); + + DPRINTK(1,"head(%d) tail(%d)!!\n",priv->tx_dev.qhead, priv->tx_dev.qtail); + if(!netif_queue_stopped(dev)){ + netif_stop_queue(dev); + } + priv->nstats.tx_errors++; + netif_wake_queue(dev); + + return; +} + +static +int ks_wlan_start_xmit(struct sk_buff *skb, struct net_device *dev) +{ + ks_wlan_private *priv = netdev_priv(dev); + int rc = 0; + + DPRINTK(3,"in_interrupt()=%ld\n",in_interrupt()); + + if ( skb == NULL ) { + printk( KERN_ERR "ks_wlan: skb == NULL!!!\n" ); + return 0; + } + if (priv->dev_state < DEVICE_STATE_READY) { + dev_kfree_skb(skb); + return 0; /* not finished initialize */ + } + + if(netif_running(dev)) + netif_stop_queue(dev); + + rc = hostif_data_request(priv, skb); + dev->trans_start = jiffies; + + DPRINTK(4,"rc=%d\n",rc); + if (rc){ + rc=0; + } + + return rc; +} + +void send_packet_complete(void *arg1, void *arg2) +{ + ks_wlan_private *priv = (ks_wlan_private *)arg1; + struct sk_buff *packet = (struct sk_buff *)arg2; + + DPRINTK(3,"\n"); + + priv->nstats.tx_bytes += packet->len; + priv->nstats.tx_packets++; + + if(netif_queue_stopped(priv->net_dev)) + netif_wake_queue(priv->net_dev); + + if(packet){ + dev_kfree_skb(packet); + packet=NULL; + } + +} + +/* Set or clear the multicast filter for this adaptor. + This routine is not state sensitive and need not be SMP locked. */ +static +void ks_wlan_set_multicast_list(struct net_device *dev) +{ + ks_wlan_private *priv = netdev_priv(dev); + + DPRINTK(4,"\n"); + if (priv->dev_state < DEVICE_STATE_READY) { + return ; /* not finished initialize */ + } + hostif_sme_enqueue(priv, SME_MULTICAST_REQUEST); + + return; +} + +static +int ks_wlan_open(struct net_device *dev) +{ + ks_wlan_private *priv = netdev_priv(dev); + + priv->cur_rx = 0; + + if(!priv->mac_address_valid){ + printk(KERN_ERR "ks_wlan : %s Not READY !!\n", dev->name); + return -EBUSY; + } + else + netif_start_queue (dev); + + return 0; +} + +static +int ks_wlan_close(struct net_device *dev) +{ + + netif_stop_queue (dev); + + DPRINTK(4, "%s: Shutting down ethercard, status was 0x%4.4x.\n", + dev->name, 0x00); + + return 0; +} + + +/* Operational parameters that usually are not changed. */ +/* Time in jiffies before concluding the transmitter is hung. */ +#define TX_TIMEOUT (3*HZ) +static const unsigned char dummy_addr[] = {0x00,0x0b,0xe3,0x00,0x00,0x00}; + +static const struct net_device_ops ks_wlan_netdev_ops = { + .ndo_start_xmit = ks_wlan_start_xmit, + .ndo_open = ks_wlan_open, + .ndo_stop = ks_wlan_close, + .ndo_do_ioctl = ks_wlan_netdev_ioctl, + .ndo_set_mac_address = ks_wlan_set_mac_address, + .ndo_get_stats = ks_wlan_get_stats, + .ndo_tx_timeout = ks_wlan_tx_timeout, + .ndo_set_rx_mode = ks_wlan_set_multicast_list, +}; + +int ks_wlan_net_start(struct net_device *dev) +{ + ks_wlan_private *priv; + /* int rc; */ + + priv = netdev_priv(dev); + priv->mac_address_valid = 0; + priv->need_commit = 0; + + priv->device_open_status = 1; + + /* phy information update timer */ + atomic_set(&update_phyinfo,0); + init_timer(&update_phyinfo_timer); + update_phyinfo_timer.function=ks_wlan_update_phyinfo_timeout; + update_phyinfo_timer.data = (unsigned long)priv; + + /* dummy address set */ + memcpy(priv->eth_addr, dummy_addr, ETH_ALEN); + dev->dev_addr[0] = priv->eth_addr[0]; + dev->dev_addr[1] = priv->eth_addr[1]; + dev->dev_addr[2] = priv->eth_addr[2]; + dev->dev_addr[3] = priv->eth_addr[3]; + dev->dev_addr[4] = priv->eth_addr[4]; + dev->dev_addr[5] = priv->eth_addr[5]; + dev->dev_addr[6] = 0x00; + dev->dev_addr[7] = 0x00; + + /* The ks_wlan-specific entries in the device structure. */ + dev->netdev_ops = &ks_wlan_netdev_ops; + dev->wireless_handlers = (struct iw_handler_def *)&ks_wlan_handler_def; + dev->watchdog_timeo = TX_TIMEOUT; + + netif_carrier_off(dev); + + return 0; +} + + +int ks_wlan_net_stop(struct net_device *dev) +{ + ks_wlan_private *priv = netdev_priv(dev); + + int ret = 0; + priv->device_open_status = 0; + del_timer_sync(&update_phyinfo_timer); + + if(netif_running(dev)) + netif_stop_queue(dev); + + return ret; +} + +int ks_wlan_reset(struct net_device *dev) +{ + return 0; +} diff --git a/drivers/staging/ks7010/michael_mic.c b/drivers/staging/ks7010/michael_mic.c new file mode 100644 index 0000000..ec8769a --- /dev/null +++ b/drivers/staging/ks7010/michael_mic.c @@ -0,0 +1,143 @@ +/* + * Driver for KeyStream wireless LAN + * + * michael_mic.c + * $Id: michael_mic.c 991 2009-09-14 01:38:58Z sekine $ + * + * Copyright (C) 2005-2008 KeyStream Corp. + * Copyright (C) 2009 Renesas Technology Corp. + * + * This program is free software; you can redistribute it and/or modify + * it undr the terms of the GNU General Public License version 2 as + * published by the Free Sotware Foundation. + */ + +#include +#include +#include "michael_mic.h" + +// Rotation functions on 32 bit values +#define ROL32( A, n ) ( ((A) << (n)) | ( ((A)>>(32-(n))) & ( (1UL << (n)) - 1 ) ) ) +#define ROR32( A, n ) ROL32( (A), 32-(n) ) +// Convert from Byte[] to UInt32 in a portable way +#define getUInt32( A, B ) (uint32_t)(A[B+0] << 0) + (A[B+1] << 8) + (A[B+2] << 16) + (A[B+3] << 24) + +// Convert from UInt32 to Byte[] in a portable way +#define putUInt32( A, B, C ) A[B+0] = (uint8_t) (C & 0xff); \ + A[B+1] = (uint8_t) ((C>>8) & 0xff); \ + A[B+2] = (uint8_t) ((C>>16) & 0xff); \ + A[B+3] = (uint8_t) ((C>>24) & 0xff) + +// Reset the state to the empty message. +#define MichaelClear( A ) A->L = A->K0; \ + A->R = A->K1; \ + A->nBytesInM = 0; + +static +void MichaelInitializeFunction( struct michel_mic_t *Mic, uint8_t *key ) +{ + // Set the key + Mic->K0 = getUInt32( key , 0 ); + Mic->K1 = getUInt32( key , 4 ); + + //clear(); + MichaelClear(Mic); +} + +#define MichaelBlockFunction(L, R) \ +do{ \ + R ^= ROL32( L, 17 ); \ + L += R; \ + R ^= ((L & 0xff00ff00) >> 8) | ((L & 0x00ff00ff) << 8); \ + L += R; \ + R ^= ROL32( L, 3 ); \ + L += R; \ + R ^= ROR32( L, 2 ); \ + L += R; \ +}while(0) + + +static +void MichaelAppend( struct michel_mic_t *Mic, uint8_t *src, int nBytes ) +{ + int addlen ; + if (Mic->nBytesInM) { + addlen = 4 - Mic->nBytesInM; + if (addlen > nBytes) + addlen = nBytes; + memcpy(&Mic->M[Mic->nBytesInM], src, addlen); + Mic->nBytesInM += addlen; + src += addlen; + nBytes -= addlen; + + if (Mic->nBytesInM < 4) + return; + + Mic->L ^= getUInt32(Mic->M,0); + MichaelBlockFunction(Mic->L, Mic->R); + Mic->nBytesInM = 0; + } + + while(nBytes >= 4){ + Mic->L ^= getUInt32(src,0); + MichaelBlockFunction(Mic->L, Mic->R); + src += 4; + nBytes -= 4; + } + + if (nBytes > 0) { + Mic->nBytesInM = nBytes; + memcpy(Mic->M, src, nBytes); + } +} + +static +void MichaelGetMIC( struct michel_mic_t *Mic, uint8_t *dst ) +{ + uint8_t *data = Mic->M; + switch (Mic->nBytesInM) { + case 0: + Mic->L ^= 0x5a; + break; + case 1: + Mic->L ^= data[0] | 0x5a00; + break; + case 2: + Mic->L ^= data[0] | (data[1] << 8) | 0x5a0000; + break; + case 3: + Mic->L ^= data[0] | (data[1] << 8) | (data[2] << 16) | + 0x5a000000; + break; + } + MichaelBlockFunction(Mic->L, Mic->R); + MichaelBlockFunction(Mic->L, Mic->R); + // The appendByte function has already computed the result. + putUInt32( dst, 0, Mic->L ); + putUInt32( dst, 4, Mic->R ); + + // Reset to the empty message. + MichaelClear(Mic); +} + +void MichaelMICFunction( struct michel_mic_t *Mic, uint8_t *Key, + uint8_t *Data, int Len, uint8_t priority, + uint8_t *Result ) +{ + uint8_t pad_data[4] = {priority,0,0,0}; + // Compute the MIC value + /* + * IEEE802.11i page 47 + * Figure 43g TKIP MIC processing format + * +--+--+--------+--+----+--+--+--+--+--+--+--+--+ + * |6 |6 |1 |3 |M |1 |1 |1 |1 |1 |1 |1 |1 | Octet + * +--+--+--------+--+----+--+--+--+--+--+--+--+--+ + * |DA|SA|Priority|0 |Data|M0|M1|M2|M3|M4|M5|M6|M7| + * +--+--+--------+--+----+--+--+--+--+--+--+--+--+ + */ + MichaelInitializeFunction( Mic, Key ) ; + MichaelAppend( Mic, (uint8_t*)Data, 12 ); /* |DA|SA| */ + MichaelAppend( Mic, pad_data, 4 ); /* |Priority|0|0|0| */ + MichaelAppend( Mic, (uint8_t*)(Data+12), Len -12 ); /* |Data| */ + MichaelGetMIC( Mic, Result ) ; +} diff --git a/drivers/staging/ks7010/michael_mic.h b/drivers/staging/ks7010/michael_mic.h new file mode 100644 index 0000000..f14f160 --- /dev/null +++ b/drivers/staging/ks7010/michael_mic.h @@ -0,0 +1,29 @@ +/* + * Driver for KeyStream wireless LAN + * + * michael_mic.h + * $Id: michael_mic.h 991 2009-09-14 01:38:58Z sekine $ + * + * Copyright (C) 2005-2008 KeyStream Corp. + * Copyright (C) 2009 Renesas Technology Corp. + * + * This program is free software; you can redistribute it and/or modify + * it undr the terms of the GNU General Public License version 2 as + * published by the Free Sotware Foundation. + */ + +/* MichelMIC routine define */ +struct michel_mic_t { + uint32_t K0; // Key + uint32_t K1; // Key + uint32_t L; // Current state + uint32_t R; // Current state + uint8_t M[4]; // Message accumulator (single word) + int nBytesInM; // # bytes in M + uint8_t Result[8]; +}; + +extern +void MichaelMICFunction( struct michel_mic_t *Mic, uint8_t *Key, + uint8_t *Data, int Len, uint8_t priority, + uint8_t *Result ); -- cgit v0.10.2 From 021873f650658fb1d8da5f3ee7d31eba40b21a93 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Tue, 31 May 2016 12:56:14 +0200 Subject: staging: ks7010: remove non-SDIO code and #ifdefs I couldn't find any trace of code or even products using ks7010 with something else than SDIO. So, remove the conditionals. Signed-off-by: Wolfram Sang Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/ks7010/Makefile b/drivers/staging/ks7010/Makefile index 68b7ebf..32b0efc7 100644 --- a/drivers/staging/ks7010/Makefile +++ b/drivers/staging/ks7010/Makefile @@ -1,5 +1,5 @@ obj-$(CONFIG_KS7010) += ks7010.o -ccflags-y += -D_SDIO_ -DKS_WLAN_DEBUG=0 +ccflags-y += -DKS_WLAN_DEBUG=0 ks7010-y := michael_mic.o ks_hostif.o ks_wlan_net.o ks_debug.o \ ks7010_sdio.o ks7010_config.o diff --git a/drivers/staging/ks7010/ks7010_config.c b/drivers/staging/ks7010/ks7010_config.c index 4a80984..e8a4207 100644 --- a/drivers/staging/ks7010/ks7010_config.c +++ b/drivers/staging/ks7010/ks7010_config.c @@ -268,13 +268,7 @@ int ks_wlan_read_config_file(ks_wlan_private *priv) priv->reg.rate_set.size = 12; #ifndef NO_FIRMWARE_CLASS -#if (defined _PCMCIA_) - dev = &priv->ks_wlan_hw.pcmcia_dev->dev; -#elif (defined _PCI_) - dev = &priv->ks_wlan_hw.pci_dev->dev; -#elif (defined _SDIO_) dev = &priv->ks_wlan_hw.sdio_card->func->dev; -#endif if((retval = request_firmware(&fw_entry, cfg_file, dev)) !=0 ){ DPRINTK(1, "error request_firmware() file=%s ret=%d\n", cfg_file, retval); return 1; diff --git a/drivers/staging/ks7010/ks_hostif.c b/drivers/staging/ks7010/ks_hostif.c index 402ddba..0295bb4 100644 --- a/drivers/staging/ks7010/ks_hostif.c +++ b/drivers/staging/ks7010/ks_hostif.c @@ -108,51 +108,12 @@ int ks_wlan_do_power_save(ks_wlan_private *priv) DPRINTK(4,"psstatus.status=%d\n",atomic_read(&priv->psstatus.status)); -#ifdef _SDIO_ if((priv->connect_status & CONNECT_STATUS_MASK) == CONNECT_STATUS){ hostif_sme_enqueue(priv, SME_POW_MNGMT_REQUEST); } else{ priv->dev_state = DEVICE_STATE_READY; } -#else - if((priv->connect_status & CONNECT_STATUS_MASK) == CONNECT_STATUS){ - switch(atomic_read(&priv->psstatus.status)){ - case PS_ACTIVE_SET: - case PS_WAKEUP: - case PS_SAVE_SET: - case PS_SNOOZE: - break; - case PS_CONF_WAIT: - atomic_set(&priv->psstatus.confirm_wait,0); - break; - case PS_NONE: - default: - hostif_sme_enqueue(priv, SME_POW_MNGMT_REQUEST); - break; - } - - } - else{ - switch(atomic_read(&priv->psstatus.status)){ - case PS_ACTIVE_SET: - case PS_WAKEUP: - case PS_SAVE_SET: - break; - case PS_CONF_WAIT: - atomic_set(&priv->psstatus.confirm_wait,0); - atomic_set(&priv->psstatus.status, PS_WAKEUP); - break; - case PS_SNOOZE: - ks_wlan_hw_power_save(priv); - break; - case PS_NONE: - default: - hostif_sme_enqueue(priv, SME_POW_MNGMT_REQUEST); - break; - } - } -#endif return rc; } @@ -750,17 +711,11 @@ void hostif_power_mngmt_confirm(ks_wlan_private *priv) if(priv->reg.powermgt > POWMGT_ACTIVE_MODE && priv->reg.operation_mode == MODE_INFRASTRUCTURE){ -#if !defined(_SDIO_) - atomic_set(&priv->psstatus.status,PS_SAVE_SET); -#endif atomic_set(&priv->psstatus.confirm_wait, 0); priv->dev_state = DEVICE_STATE_SLEEP; ks_wlan_hw_power_save(priv); }else{ priv->dev_state = DEVICE_STATE_READY; -#if !defined(_SDIO_) - atomic_set(&priv->psstatus.status,PS_ACTIVE_SET); -#endif } } @@ -833,9 +788,6 @@ void hostif_connect_indication(ks_wlan_private *priv) /* for power save */ atomic_set(&priv->psstatus.snooze_guard, 0); atomic_set(&priv->psstatus.confirm_wait,0); -#if !defined(_SDIO_) - atomic_set(&priv->psstatus.status, PS_NONE); -#endif } ks_wlan_do_power_save(priv); @@ -894,10 +846,8 @@ void hostif_stop_confirm(ks_wlan_private *priv) union iwreq_data wrqu0; DPRINTK(3,"\n"); -#ifdef _SDIO_ if(priv->dev_state == DEVICE_STATE_SLEEP) priv->dev_state = DEVICE_STATE_READY; -#endif /* disconnect indication */ if( (priv->connect_status & CONNECT_STATUS_MASK)== CONNECT_STATUS){ @@ -1178,9 +1128,6 @@ int hostif_data_request(ks_wlan_private *priv, struct sk_buff *packet) if(atomic_read(&priv->psstatus.status)==PS_SNOOZE){ /* power save wakeup */ if(!netif_queue_stopped(priv->net_dev)) netif_stop_queue(priv->net_dev); -#if !defined(_SDIO_) - schedule_work(&priv->ks_wlan_wakeup_task); -#endif } DPRINTK(4, "skb_buff length=%d\n", packet_len); @@ -1302,14 +1249,10 @@ int hostif_data_request(ks_wlan_private *priv, struct sk_buff *packet) return result; } -#if defined(_SPI_) -#define ps_confirm_wait_inc(priv) -#else #define ps_confirm_wait_inc(priv) do{if(atomic_read(&priv->psstatus.status) > PS_ACTIVE_SET){ \ atomic_inc(&priv->psstatus.confirm_wait); \ /* atomic_set(&priv->psstatus.status, PS_CONF_WAIT);*/ \ } }while(0) -#endif static void hostif_mib_get_request( ks_wlan_private *priv, unsigned long mib_attribute) @@ -2509,9 +2452,6 @@ void hostif_sme_execute(ks_wlan_private *priv, int event) /* for power save */ atomic_set(&priv->psstatus.snooze_guard, 0); atomic_set(&priv->psstatus.confirm_wait,0); -#if !defined(_SDIO_) - atomic_set(&priv->psstatus.status, PS_NONE); -#endif if ( priv->dev_state == DEVICE_STATE_PREINIT ){ priv->dev_state = DEVICE_STATE_INIT; } @@ -2571,16 +2511,6 @@ void hostif_sme_enqueue(ks_wlan_private *priv, unsigned short event) { DPRINTK(3,"\n"); -#if !defined(_SDIO_) - if(atomic_read(&priv->psstatus.status)==PS_SNOOZE && event < SME_START_CONFIRM){ /* power save wakeup*/ - schedule_work(&priv->ks_wlan_wakeup_task); - if(atomic_read(&priv->sme_task.count) <= 0){ - /* schedule_work(&priv->ks_wlan_wakeup_task); */ - DPRINTK(4,"sme task disable.\n"); - tasklet_disable(&priv->sme_task); - } - } -#endif /* enqueue sme event */ diff --git a/drivers/staging/ks7010/ks_wlan.h b/drivers/staging/ks7010/ks_wlan.h index c7cbde1..329a062 100644 --- a/drivers/staging/ks7010/ks_wlan.h +++ b/drivers/staging/ks7010/ks_wlan.h @@ -62,17 +62,7 @@ typedef void irqreturn_t; #define pci_name(x) x->slot_name #endif -#if (defined _PCMCIA_) -#include "pcmcia/ks7010_pcmcia.h" -#elif (defined _PCI_) -#include "pci/ks7010_pci.h" -#elif (defined _SDIO_) #include "ks7010_sdio.h" -#elif (defined _SPI_) -#include "spi/ks7010_spi.h" -#else -#error not defined bus type ! -#endif struct ks_wlan_parameter { uint8_t operation_mode; /* Operation Mode */ -- cgit v0.10.2 From c3fe667f0a99712a2f2ba2f936b35598cf806286 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Tue, 31 May 2016 12:56:15 +0200 Subject: staging: ks7010: remove custom firmware loader FW_LOADER works fine, no need for a open coded fallback. Signed-off-by: Wolfram Sang Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/ks7010/Kconfig b/drivers/staging/ks7010/Kconfig index dfd4eed..0b92176 100644 --- a/drivers/staging/ks7010/Kconfig +++ b/drivers/staging/ks7010/Kconfig @@ -3,6 +3,7 @@ config KS7010 depends on MMC && WIRELESS select WIRELESS_EXT select WEXT_PRIV + select FW_LOADER help This is a driver for KeyStream KS7010 based SDIO WIFI cards. It is found on at least later Spectec SDW-821 (FCC-ID "S2Y-WLAN-11G-K" only, diff --git a/drivers/staging/ks7010/ks7010_config.c b/drivers/staging/ks7010/ks7010_config.c index e8a4207..7d33070 100644 --- a/drivers/staging/ks7010/ks7010_config.c +++ b/drivers/staging/ks7010/ks7010_config.c @@ -169,11 +169,7 @@ int rate_set_configuration(ks_wlan_private *priv, char *value) return rc; } -#ifndef NO_FIRMWARE_CLASS #include -#else -#define MAX_CONFIG_FILE_SIZE (1024*10) -#endif int ks_wlan_read_config_file(ks_wlan_private *priv) { struct { @@ -206,18 +202,9 @@ int ks_wlan_read_config_file(ks_wlan_private *priv) {0,"",""}, }; -#ifndef NO_FIRMWARE_CLASS const struct firmware *fw_entry; struct device *dev = NULL; int retval; -#else - struct file *srcf; - int nr_read ; - int retval; - char *cfg_buf=NULL; - int orgfsuid, orgfsgid; - mm_segment_t orgfs; -#endif char cfg_file[]=CFG_FILE; char *cur_p, *end_p; char wk_buff[256], *wk_p; @@ -267,7 +254,6 @@ int ks_wlan_read_config_file(ks_wlan_private *priv) priv->reg.tx_rate = TX_RATE_FULL_AUTO; priv->reg.rate_set.size = 12; -#ifndef NO_FIRMWARE_CLASS dev = &priv->ks_wlan_hw.sdio_card->func->dev; if((retval = request_firmware(&fw_entry, cfg_file, dev)) !=0 ){ DPRINTK(1, "error request_firmware() file=%s ret=%d\n", cfg_file, retval); @@ -277,46 +263,6 @@ int ks_wlan_read_config_file(ks_wlan_private *priv) DPRINTK(4, "success request_firmware() file=%s size=%d\n", cfg_file, fw_entry->size); cur_p = fw_entry->data; end_p = cur_p + fw_entry->size; -#else - orgfsuid=current->fsuid; - orgfsgid=current->fsgid; - orgfs=get_fs(); - set_fs(KERNEL_DS); - - srcf = filp_open(cfg_file, O_RDONLY, 0); - if (IS_ERR(srcf)) { - printk(KERN_ERR "error %ld opening %s\n", -PTR_ERR(srcf),cfg_file); - goto no_config_file; - } - - if (!(srcf->f_op && srcf->f_op->read)) { - printk(KERN_ERR "%s does not have a read method\n", cfg_file); - goto no_config_file; - } - - cfg_buf = (char *)kzalloc(MAX_CONFIG_FILE_SIZE, GFP_ATOMIC); - if (!cfg_buf) { - printk(KERN_ERR "%s does not read : out of memory \n", cfg_file); - goto no_config_file; - } - - nr_read = srcf->f_op->read(srcf, (unsigned char *)cfg_buf, MAX_CONFIG_FILE_SIZE, &srcf->f_pos); - - DPRINTK(1, "read retval=%d file=%s\n", nr_read, priv->reg.cfg_file); - retval=filp_close(srcf ,NULL); - if (retval) - DPRINTK(1, "error %d closing %s\n", -retval,priv->reg.cfg_file); - - if (nr_read < 1) { - printk(KERN_ERR "%s does not read : file is empty num=%d\n", cfg_file, nr_read); - goto no_config_file; - }else if(nr_read > MAX_CONFIG_FILE_SIZE){ - printk(KERN_ERR "%s does not read : file is too big \n", cfg_file); - goto no_config_file; - } - cur_p = cfg_buf; - end_p = cur_p + nr_read; -#endif *end_p = '\0'; while (cur_p < end_p) { @@ -524,15 +470,7 @@ int ks_wlan_read_config_file(ks_wlan_private *priv) } } -#ifndef NO_FIRMWARE_CLASS release_firmware(fw_entry); -#else -no_config_file: - kfree(cfg_buf); - set_fs(orgfs); - current->fsuid=orgfsuid; - current->fsgid=orgfsgid; -#endif DPRINTK(3,"\n operation_mode = %d\n channel = %d\n ssid = %s\n tx_rate = %d\n \ preamble = %d\n powermgt = %d\n scan_type = %d\n beacon_lost_count = %d\n rts = %d\n \ diff --git a/drivers/staging/ks7010/ks7010_sdio.c b/drivers/staging/ks7010/ks7010_sdio.c index 7cc49a4..9300658 100644 --- a/drivers/staging/ks7010/ks7010_sdio.c +++ b/drivers/staging/ks7010/ks7010_sdio.c @@ -56,10 +56,6 @@ static int ks7010_sdio_read( ks_wlan_private *priv, unsigned int address, unsigned char *buffer, int length ); static int ks7010_sdio_write( ks_wlan_private *priv, unsigned int address, unsigned char *buffer, int length ); -#ifdef NO_FIRMWARE_CLASS -static char *romfile = ROM_FILE; -module_param(romfile, charp, S_IRUGO); -#endif /* macro */ #define inc_txqhead(priv) \ @@ -723,23 +719,15 @@ error_out: if(read_buf) kfree(read_buf); return rc; } -#ifndef NO_FIRMWARE_CLASS #include -#endif static int ks79xx_upload_firmware(ks_wlan_private *priv, struct ks_sdio_card *card) { unsigned int size, offset, n = 0; unsigned char *rom_buf; unsigned char rw_data =0; int retval, rc=0; -#ifndef NO_FIRMWARE_CLASS int length; const struct firmware *fw_entry = NULL; -#else - int orgfsuid, orgfsgid; - struct file *srcf; - mm_segment_t orgfs; -#endif rom_buf = NULL; @@ -758,38 +746,16 @@ static int ks79xx_upload_firmware(ks_wlan_private *priv, struct ks_sdio_card *ca goto error_out0; } -#ifndef NO_FIRMWARE_CLASS if(request_firmware(&fw_entry, priv->reg.rom_file, &priv->ks_wlan_hw.sdio_card->func->dev)!=0){ DPRINTK(1,"error request_firmware() file=%s\n", priv->reg.rom_file); return 1; } DPRINTK(4,"success request_firmware() file=%s size=%d\n", priv->reg.rom_file, fw_entry->size); length = fw_entry->size; -#else - orgfsuid=current->fsuid; - orgfsgid=current->fsgid; - current->fsuid=current->fsgid=0; - orgfs=get_fs(); - set_fs(KERNEL_DS); - - srcf = filp_open(romfile, O_RDONLY, 0); - if (IS_ERR(srcf)) { - DPRINTK(1, "error %ld opening %s\n", -PTR_ERR(srcf),romfile); - rc = 1; - goto error_out1; - } - - if (!(srcf->f_op && srcf->f_op->read)) { - DPRINTK(1, "%s does not have a read method\n", romfile); - rc = 2; - goto error_out2; - } -#endif /* Load Program */ n = 0; do { -#ifndef NO_FIRMWARE_CLASS if(length >= ROM_BUFF_SIZE){ size = ROM_BUFF_SIZE; length = length - ROM_BUFF_SIZE; @@ -801,16 +767,6 @@ static int ks79xx_upload_firmware(ks_wlan_private *priv, struct ks_sdio_card *ca DPRINTK(4, "size = %d\n",size); if(size == 0) break; memcpy(rom_buf,fw_entry->data+n,size); -#else - /* The object must have a read method */ - size = srcf->f_op->read(srcf, rom_buf, ROM_BUFF_SIZE, &srcf->f_pos); - if (size < 0) { - DPRINTK(1, "Read %s error %d\n", priv->reg.rom_file, -retval); - rc = 5; - goto error_out2; - } - else if (size == 0) break; -#endif /* Update write index */ offset = n; retval = ks7010_sdio_update_index(priv, KS7010_IRAM_ADDRESS+offset); @@ -852,20 +808,8 @@ static int ks79xx_upload_firmware(ks_wlan_private *priv, struct ks_sdio_card *ca rc = 0; -#ifdef NO_FIRMWARE_CLASS - error_out2: - retval=filp_close(srcf ,NULL); - if (retval) - DPRINTK(1, "error %d closing %s\n", -retval,priv->reg.rom_file); - - error_out1: - set_fs(orgfs); - current->fsuid=orgfsuid; - current->fsgid=orgfsgid; -#else error_out1: release_firmware(fw_entry); -#endif error_out0: sdio_release_host(card->func); if(rom_buf) diff --git a/drivers/staging/ks7010/ks7010_sdio.h b/drivers/staging/ks7010/ks7010_sdio.h index 3af742f..5bf01ab 100644 --- a/drivers/staging/ks7010/ks7010_sdio.h +++ b/drivers/staging/ks7010/ks7010_sdio.h @@ -153,13 +153,8 @@ struct rx_device{ unsigned int qtail; /* rx buffer queue last pointer */ spinlock_t rx_dev_lock; }; -#ifndef NO_FIRMWARE_CLASS #define ROM_FILE "ks7010sd.rom" #define CFG_FILE "ks79xx.cfg" -#else -#define ROM_FILE "/lib/firmware/ks7010sd.rom" -#define CFG_FILE "/lib/firmware/ks79xx.cfg" -#endif #define KS_WLAN_DRIVER_VERSION_INFO "ks7010 sdio linux 007" #endif /* _KS7010_SDIO_H */ -- cgit v0.10.2 From 4ab274017bc31cea220a531358e8c3e2d08d87fc Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Tue, 31 May 2016 12:56:16 +0200 Subject: staging: ks7010: remove checks for WIRELESS_EXT version We are by far newer than that anyhow. Signed-off-by: Wolfram Sang Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/ks7010/ks_hostif.c b/drivers/staging/ks7010/ks_hostif.c index 0295bb4..6bea699 100644 --- a/drivers/staging/ks7010/ks_hostif.c +++ b/drivers/staging/ks7010/ks_hostif.c @@ -22,12 +22,7 @@ #include /* Include Wireless Extension definition and check version */ -#ifndef WIRELESS_EXT -#include -#endif /* WIRELESS_EXT */ -#if WIRELESS_EXT > 12 #include /* New driver API */ -#endif /* WIRELESS_EXT > 12 */ extern int ks_wlan_hw_tx(ks_wlan_private *priv, void *p, unsigned long size, void (*complete_handler)(void *arg1, void *arg2), @@ -121,10 +116,8 @@ static int get_current_ap(ks_wlan_private *priv, struct link_ap_info_t *ap_info) { struct local_ap_t *ap; -#if WIRELESS_EXT > 13 union iwreq_data wrqu; struct net_device *netdev=priv->net_dev; -#endif /* WIRELESS_EXT > 13 */ int rc=0; DPRINTK(3,"\n"); @@ -190,7 +183,6 @@ int get_current_ap(ks_wlan_private *priv, struct link_ap_info_t *ap_info) ap->wpa_ie.size = 0; } -#if WIRELESS_EXT > 13 wrqu.data.length = 0; wrqu.data.flags = 0; wrqu.ap_addr.sa_family = ARPHRD_ETHER; @@ -203,7 +195,6 @@ int get_current_ap(ks_wlan_private *priv, struct link_ap_info_t *ap_info) (unsigned char)wrqu.ap_addr.sa_data[4],(unsigned char)wrqu.ap_addr.sa_data[5]); wireless_send_event(netdev, SIOCGIWAP, &wrqu, NULL); } -#endif DPRINTK(4,"\n Link AP\n"); DPRINTK(4," bssid=%02X:%02X:%02X:%02X:%02X:%02X\n \ essid=%s\n rate_set=%02X,%02X,%02X,%02X,%02X,%02X,%02X,%02X\n channel=%d\n \ @@ -338,9 +329,7 @@ void hostif_data_indication(ks_wlan_private *priv) struct ieee802_1x_hdr *aa1x_hdr; struct wpa_eapol_key *eap_key; struct michel_mic_t michel_mic; -#if WIRELESS_EXT > 14 union iwreq_data wrqu; -#endif /* WIRELESS_EXT > 14 */ DPRINTK(3,"\n"); @@ -412,7 +401,6 @@ void hostif_data_indication(ks_wlan_private *priv) mic_failure->counter = 1; } priv->wpa.mic_failure.last_failure_time = now; -#if WIRELESS_EXT > 14 /* needed parameters: count, keyid, key type, TSC */ sprintf(buf, "MLME-MICHAELMICFAILURE.indication(keyid=%d %scast addr=" "%02x:%02x:%02x:%02x:%02x:%02x)", @@ -424,7 +412,6 @@ void hostif_data_indication(ks_wlan_private *priv) wrqu.data.length = strlen(buf); DPRINTK(4,"IWEVENT:MICHAELMICFAILURE\n"); wireless_send_event(priv->net_dev, IWEVCUSTOM, &wrqu, buf); -#endif /* WIRELESS_EXT > 14 */ return; } } @@ -754,9 +741,7 @@ void hostif_connect_indication(ks_wlan_private *priv) unsigned int tmp=0; unsigned int old_status=priv->connect_status; struct net_device *netdev=priv->net_dev; -#if WIRELESS_EXT > 13 union iwreq_data wrqu0; -#endif /* WIRELESS_EXT > 13 */ connect_code = get_WORD(priv); switch(connect_code){ @@ -791,7 +776,6 @@ void hostif_connect_indication(ks_wlan_private *priv) } ks_wlan_do_power_save(priv); -#if WIRELESS_EXT > 13 wrqu0.data.length = 0; wrqu0.data.flags = 0; wrqu0.ap_addr.sa_family = ARPHRD_ETHER; @@ -802,7 +786,6 @@ void hostif_connect_indication(ks_wlan_private *priv) DPRINTK(3,"disconnect :: scan_ind_count=%d\n",priv->scan_ind_count); wireless_send_event(netdev, SIOCGIWAP, &wrqu0, NULL); } -#endif /* WIRELESS_EXT > 13 */ priv->scan_ind_count=0; } @@ -904,7 +887,6 @@ void hostif_adhoc_set_confirm(ks_wlan_private *priv) static void hostif_associate_indication(ks_wlan_private *priv) { -#if WIRELESS_EXT > 14 struct association_request_t *assoc_req; struct association_response_t *assoc_resp; unsigned char *pb; @@ -944,29 +926,24 @@ void hostif_associate_indication(ks_wlan_private *priv) DPRINTK(3,"IWEVENT:ASSOCINFO\n"); wireless_send_event(priv->net_dev, IWEVCUSTOM, &wrqu, buf); -#endif /* WIRELESS_EXT > 14 */ } static void hostif_bss_scan_confirm(ks_wlan_private *priv) { unsigned int result_code; -#if WIRELESS_EXT > 13 struct net_device *dev = priv->net_dev; union iwreq_data wrqu; -#endif /* WIRELESS_EXT > 13 */ result_code = get_DWORD(priv); DPRINTK(2,"result=%d :: scan_ind_count=%d\n", result_code, priv->scan_ind_count); priv->sme_i.sme_flag &= ~SME_AP_SCAN; hostif_sme_enqueue(priv, SME_BSS_SCAN_CONFIRM); -#if WIRELESS_EXT > 13 wrqu.data.length = 0; wrqu.data.flags = 0; DPRINTK(3,"IWEVENT: SCAN CONFIRM\n"); wireless_send_event(dev, SIOCGIWSCAN, &wrqu, NULL); -#endif /* WIRELESS_EXT > 13 */ priv->scan_ind_count=0; } diff --git a/drivers/staging/ks7010/ks_wlan_net.c b/drivers/staging/ks7010/ks_wlan_net.c index 546a256..185630c 100644 --- a/drivers/staging/ks7010/ks_wlan_net.c +++ b/drivers/staging/ks7010/ks_wlan_net.c @@ -50,7 +50,6 @@ static int wep_on_off; #define WIRELESS_SPY /* enable iwspy support */ #include /* New driver API */ -#ifdef WIRELESS_EXT /* Frequency list (map channels to frequencies) */ static const long frequency_list[] = { 2412, 2417, 2422, 2427, 2432, 2437, 2442, 2447, 2452, 2457, 2462, 2467, 2472, 2484 }; @@ -74,7 +73,6 @@ static const struct iw_handler_def ks_wlan_handler_def; #define KSC_OPNOTSUPP /* Operation Not Support*/ -#endif /* WIRELESS_EXT */ /* * function prototypes @@ -174,7 +172,6 @@ int ks_wlan_setup_parameter(ks_wlan_private *priv, unsigned int commit_flag) return 0; } -#ifdef WIRELESS_EXT /* * Initial Wireless Extension code for Ks_Wlannet driver by : * Jean Tourrilhes - HPL - 17 November 00 @@ -1090,7 +1087,6 @@ static int ks_wlan_get_range(struct net_device *dev, struct iw_request_info *inf range->avg_qual.level = 186; /* -70 dBm */ range->avg_qual.noise = 0; -#if defined(WIRELESS_EXT) /* Event capability (kernel + driver) */ range->event_capa[0] = (IW_EVENT_CAPA_K_0 | IW_EVENT_CAPA_MASK(SIOCGIWAP) | @@ -1104,7 +1100,6 @@ static int ks_wlan_get_range(struct net_device *dev, struct iw_request_info *inf IW_ENC_CAPA_WPA2 | IW_ENC_CAPA_CIPHER_TKIP | IW_ENC_CAPA_CIPHER_CCMP); -#endif return 0; } @@ -1229,7 +1224,6 @@ static int ks_wlan_get_aplist(struct net_device *dev, struct iw_request_info *in return 0; } -#if defined(WIRELESS_EXT) /*------------------------------------------------------------------*/ /* Wireless Handler : Initiate Scan */ static int ks_wlan_set_scan(struct net_device *dev, struct iw_request_info *info, @@ -1452,7 +1446,6 @@ DPRINTK(2,"aplist 0\n"); return 0; } -#endif /* WIRELESS_EXT */ /*------------------------------------------------------------------*/ /* Commit handler : called after a bunch of SET operations */ @@ -1469,7 +1462,6 @@ static int ks_wlan_config_commit(struct net_device *dev, struct iw_request_info return 0; } -#ifdef WIRELESS_EXT /*------------------------------------------------------------------*/ /* Wireless handler : set association ie params */ static int ks_wlan_set_genie(struct net_device *dev, struct iw_request_info *info, @@ -1951,7 +1943,6 @@ static int ks_wlan_set_mlme(struct net_device *dev, struct iw_request_info *info return -EOPNOTSUPP; /* Not Support */ } } -#endif /* WIRELESS_EXT */ /*------------------------------------------------------------------*/ /* Private handler : get driver version */ @@ -2915,20 +2906,15 @@ static const struct iw_handler_def ks_wlan_handler_def = .get_wireless_stats = ks_get_wireless_stats, }; -#endif /* WIRELESS_EXT */ static int ks_wlan_netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { int rc = 0; -#if defined(WIRELESS_EXT) struct iwreq *wrq = (struct iwreq *) rq; -#endif /* WIRELESS_EXT */ switch (cmd) { -#if defined(WIRELESS_EXT) case SIOCIWFIRSTPRIV+20: /* KS_WLAN_SET_STOP_REQ */ rc = ks_wlan_set_stop_request(dev, NULL, &(wrq->u.mode), NULL); break; -#endif /* WIRELESS_EXT >17 */ // All other calls are currently unsupported default: rc = -EOPNOTSUPP; -- cgit v0.10.2 From 72bf750007297c33fe2331d2125118d4885367c2 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Tue, 31 May 2016 12:56:17 +0200 Subject: staging: ks7010: remove code for old kernel versions No need to be backwards compatible. Signed-off-by: Wolfram Sang Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/ks7010/ks_hostif.c b/drivers/staging/ks7010/ks_hostif.c index 6bea699..146a135 100644 --- a/drivers/staging/ks7010/ks_hostif.c +++ b/drivers/staging/ks7010/ks_hostif.c @@ -2103,11 +2103,7 @@ void hostif_sme_multicast_set(ks_wlan_private *priv) struct net_device *dev = priv->net_dev; int mc_count; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,35) struct netdev_hw_addr *ha; -#else - struct dev_mc_list *mclist; -#endif char set_address[NIC_MAX_MCAST_LIST*ETH_ALEN]; unsigned long filter_type; int i; @@ -2131,14 +2127,9 @@ void hostif_sme_multicast_set(ks_wlan_private *priv) else { if (priv->sme_i.sme_flag & SME_MULTICAST){ mc_count = netdev_mc_count(dev); -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,35) netdev_for_each_mc_addr(ha, dev) { memcpy(&set_address[i*ETH_ALEN], ha->addr, ETH_ALEN); } -#else - for (i = 0, mclist = dev->mc_list; mclist && i < mc_count; i++, mclist = mclist->next) - memcpy(&set_address[i*ETH_ALEN], mclist->dmi_addr, ETH_ALEN); -#endif priv->sme_i.sme_flag &= ~SME_MULTICAST; hostif_mib_set_request(priv, LOCAL_MULTICAST_ADDRESS, (ETH_ALEN*mc_count), MIB_VALUE_TYPE_OSTRING, &set_address[0]); diff --git a/drivers/staging/ks7010/ks_wlan.h b/drivers/staging/ks7010/ks_wlan.h index 329a062..6bd01641 100644 --- a/drivers/staging/ks7010/ks_wlan.h +++ b/drivers/staging/ks7010/ks_wlan.h @@ -18,9 +18,6 @@ #define WPS #include -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)) -#include -#endif #include #include #include @@ -35,32 +32,9 @@ #include /* struct timer_list */ #include #include /* struct completion */ - -#include - -/* Workqueue / task queue backwards compatibility stuff */ -#if ((LINUX_VERSION_CODE > KERNEL_VERSION(2,5,41)) || (defined _MVL31_) || (defined _CELF3_)) #include -#else -#include -#define work_struct tq_struct -#define INIT_WORK INIT_TQUEUE -#define schedule_work schedule_task -#endif -/* Interrupt handler backwards compatibility stuff */ -/* -#ifndef IRQ_NONE -#define IRQ_NONE -#define IRQ_HANDLED -typedef void irqreturn_t; -#endif -*/ - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,23) -#define free_netdev(x) kfree(x) -#define pci_name(x) x->slot_name -#endif +#include #include "ks7010_sdio.h" diff --git a/drivers/staging/ks7010/ks_wlan_net.c b/drivers/staging/ks7010/ks_wlan_net.c index 185630c..776a544 100644 --- a/drivers/staging/ks7010/ks_wlan_net.c +++ b/drivers/staging/ks7010/ks_wlan_net.c @@ -13,9 +13,6 @@ */ #include -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)) -#include -#endif #include #include #include -- cgit v0.10.2 From e8593a8abf8cc35073b1c26bb0492f7e361b6ac1 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Tue, 31 May 2016 12:56:18 +0200 Subject: staging: ks7010: avoid workqueue races My Spectec SDW823 card oopsed when it was already inserted during boot. When debugging this, I noticed that the card init was done in a seperate workqueue which was only activated once in probe. After removing the workqueue and calling the card init directly from probe, the OOPS went away. It turned out this is the same OOPS which happened when removing the card, so this seems possible now. Note: There is still a not-understood card-removed event during boot, but at least it doesn't crash anymore and the card will be re-probed right away. Signed-off-by: Wolfram Sang Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/ks7010/TODO b/drivers/staging/ks7010/TODO index 390e821..5cbb4ca 100644 --- a/drivers/staging/ks7010/TODO +++ b/drivers/staging/ks7010/TODO @@ -28,7 +28,6 @@ Now the TODOs: should understand the change you submit. - drop using a config file and use an upstream technique for configuration - fix the 'card removal' event when card is inserted when booting -- driver crashes when removing the card - check what other upstream wireless mechanisms can be used instead of the custom ones here diff --git a/drivers/staging/ks7010/ks7010_sdio.c b/drivers/staging/ks7010/ks7010_sdio.c index 9300658..5b78522 100644 --- a/drivers/staging/ks7010/ks7010_sdio.c +++ b/drivers/staging/ks7010/ks7010_sdio.c @@ -817,14 +817,8 @@ static int ks79xx_upload_firmware(ks_wlan_private *priv, struct ks_sdio_card *ca return rc; } -static void card_init_task(struct work_struct *work) +static void ks7010_card_init(struct ks_wlan_private *priv) { - struct hw_info_t *hw; - struct ks_wlan_private *priv; - - hw = container_of(work, struct hw_info_t, init_task); - priv = container_of(hw, struct ks_wlan_private, ks_wlan_hw); - DPRINTK(5,"\ncard_init_task()\n"); /* init_waitqueue_head(&priv->confirm_wait); */ @@ -1052,23 +1046,11 @@ static int ks7910_sdio_probe(struct sdio_func *func, const struct sdio_device_id goto error_free_read_buf; } - priv->ks_wlan_hw.ks7010sdio_init = create_singlethread_workqueue("ks7010sdio_init"); - if(!priv->ks_wlan_hw.ks7010sdio_init){ - DPRINTK(1, "create_workqueue failed !!\n"); - goto error_free_sdio_wq; - } - - INIT_WORK(&priv->ks_wlan_hw.init_task, card_init_task); INIT_DELAYED_WORK(&priv->ks_wlan_hw.rw_wq, ks7010_rw_function); - - queue_work(priv->ks_wlan_hw.ks7010sdio_init, &priv->ks_wlan_hw.init_task); + ks7010_card_init(priv); return 0; -error_free_sdio_wq: - flush_workqueue(priv->ks_wlan_hw.ks7010sdio_wq); - destroy_workqueue(priv->ks_wlan_hw.ks7010sdio_wq); - priv->ks_wlan_hw.ks7010sdio_wq = NULL; error_free_read_buf: kfree(priv->ks_wlan_hw.read_buf); priv->ks_wlan_hw.read_buf = NULL; @@ -1139,12 +1121,6 @@ static void ks7910_sdio_remove(struct sdio_func *func) } DPRINTK(1, "destroy_workqueue(priv->ks_wlan_hw.ks7010sdio_wq);\n"); - if(priv->ks_wlan_hw.ks7010sdio_init){ - flush_workqueue(priv->ks_wlan_hw.ks7010sdio_init); - destroy_workqueue(priv->ks_wlan_hw.ks7010sdio_init); - } - DPRINTK(1, "destroy_workqueue(priv->ks_wlan_hw.ks7010sdio_init);\n"); - hostif_exit(priv); DPRINTK(1, "hostif_exit\n"); diff --git a/drivers/staging/ks7010/ks7010_sdio.h b/drivers/staging/ks7010/ks7010_sdio.h index 5bf01ab..9382383 100644 --- a/drivers/staging/ks7010/ks7010_sdio.h +++ b/drivers/staging/ks7010/ks7010_sdio.h @@ -96,8 +96,6 @@ struct hw_info_t { struct ks_sdio_card *sdio_card; struct completion ks7010_sdio_wait; struct workqueue_struct *ks7010sdio_wq; - struct workqueue_struct *ks7010sdio_init; - struct work_struct init_task; struct delayed_work rw_wq; unsigned char *read_buf; struct tasklet_struct rx_bh_task; -- cgit v0.10.2 From 19b0832759143896726e69b8d37f078849ccc70a Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Tue, 31 May 2016 12:56:19 +0200 Subject: staging: ks7010: use long preamble as default I had a problem connecting to a network with a short preamble, so let's make the safer option the default. Signed-off-by: Wolfram Sang Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/ks7010/ks7010_config.c b/drivers/staging/ks7010/ks7010_config.c index 7d33070..abe99a5 100644 --- a/drivers/staging/ks7010/ks7010_config.c +++ b/drivers/staging/ks7010/ks7010_config.c @@ -193,7 +193,7 @@ int ks_wlan_read_config_file(ks_wlan_private *priv) {8,"WepIndex","1"}, /* 13 */ {7,"WepType","STRING"}, /* 14 */ {3,"Wep","OFF"}, /* 15 */ - {13,"PREAMBLE_TYPE","SHORT"}, /* 16 */ + {13,"PREAMBLE_TYPE","LONG"}, /* 16 */ {8,"ScanType","ACTIVE_SCAN"}, /* 17 */ {8,"ROM_FILE", ROM_FILE}, /* 18 */ {7,"PhyType", "BG_MODE"}, /* 19 */ @@ -216,7 +216,7 @@ int ks_wlan_read_config_file(ks_wlan_private *priv) priv->reg.ssid.body[0] = '\0'; /* SSID */ priv->reg.ssid.size = 0; /* SSID size */ priv->reg.tx_rate = TX_RATE_AUTO; /* TxRate Fully Auto */ - priv->reg.preamble = SHORT_PREAMBLE; /* Preamble = SHORT */ + priv->reg.preamble = LONG_PREAMBLE; /* Preamble = LONG */ priv->reg.powermgt = POWMGT_ACTIVE_MODE; /* POWMGT_ACTIVE_MODE */ priv->reg.scan_type = ACTIVE_SCAN; /* Active */ priv->reg.beacon_lost_count = 20; /* Beacon Lost Count */ -- cgit v0.10.2 From 3215bb1a4ba4a6f26272497b4789093549b060e7 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Tue, 31 May 2016 12:56:20 +0200 Subject: staging: ks7010: use kernel helper to print buffer No need for an open coded one. Signed-off-by: Wolfram Sang Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/ks7010/Makefile b/drivers/staging/ks7010/Makefile index 32b0efc7..f6a2cc8 100644 --- a/drivers/staging/ks7010/Makefile +++ b/drivers/staging/ks7010/Makefile @@ -1,5 +1,5 @@ obj-$(CONFIG_KS7010) += ks7010.o ccflags-y += -DKS_WLAN_DEBUG=0 -ks7010-y := michael_mic.o ks_hostif.o ks_wlan_net.o ks_debug.o \ +ks7010-y := michael_mic.o ks_hostif.o ks_wlan_net.o \ ks7010_sdio.o ks7010_config.o diff --git a/drivers/staging/ks7010/ks7010_sdio.c b/drivers/staging/ks7010/ks7010_sdio.c index 5b78522..1a1a43f 100644 --- a/drivers/staging/ks7010/ks7010_sdio.c +++ b/drivers/staging/ks7010/ks7010_sdio.c @@ -441,10 +441,11 @@ static void ks_wlan_hw_rx(void *dev, uint16_t size) /* length check */ if(size > 2046 || size == 0){ - - DPRINTK(5,"-INVAILED DATA dump\n"); - print_buffer(&rx_buffer->data[0],32); - +#ifdef KS_WLAN_DEBUG + if (KS_WLAN_DEBUG > 5) + print_hex_dump_bytes("INVALID DATA dump: ", DUMP_PREFIX_OFFSET, + rx_buffer->data, 32); +#endif /* rx_status update */ read_status = READ_STATUS_IDLE; retval = ks7010_sdio_write(priv, READ_STATUS, &read_status, sizeof(read_status)); diff --git a/drivers/staging/ks7010/ks_debug.c b/drivers/staging/ks7010/ks_debug.c deleted file mode 100644 index 009f5f6..0000000 --- a/drivers/staging/ks7010/ks_debug.c +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Driver for KeyStream 11b/g wireless LAN cards. - * - * ks_debug.c - * $Id: ks_debug.c 991 2009-09-14 01:38:58Z sekine $ - * - * Copyright (C) 2005-2008 KeyStream Corp. - * Copyright (C) 2009 Renesas Technology Corp. - * - * This program is free software; you can redistribute it and/or modify - * it undr the terms of the GNU General Public License version 2 as - * published by the Free Sotware Foundation. - */ -#include "ks_wlan.h" -#include "ks_debug.h" - -void print_buffer(unsigned char *p, int length) -{ -#ifdef KS_WLAN_DEBUG - int i; -#define HEX_OFFSET "\ - +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +A +B +C +D +E +F" - printk(HEX_OFFSET); - for (i=0; i Date: Tue, 31 May 2016 12:56:21 +0200 Subject: staging: ks7010: delete seperate debug header Move the one debug macro to the generic wlan header. Signed-off-by: Wolfram Sang Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/ks7010/ks7010_config.c b/drivers/staging/ks7010/ks7010_config.c index abe99a5..7f273da 100644 --- a/drivers/staging/ks7010/ks7010_config.c +++ b/drivers/staging/ks7010/ks7010_config.c @@ -4,7 +4,6 @@ #include "ks_wlan.h" #include "ks_hostif.h" #include "ks_wlan_ioctl.h" -#include "ks_debug.h" static int wep_on_off; #define WEP_OFF 0 diff --git a/drivers/staging/ks7010/ks7010_sdio.c b/drivers/staging/ks7010/ks7010_sdio.c index 1a1a43f..3fb432c 100644 --- a/drivers/staging/ks7010/ks7010_sdio.c +++ b/drivers/staging/ks7010/ks7010_sdio.c @@ -19,7 +19,6 @@ #include "ks_wlan.h" #include "ks_wlan_ioctl.h" -#include "ks_debug.h" #include "ks_hostif.h" #include "ks7010_sdio.h" diff --git a/drivers/staging/ks7010/ks_debug.h b/drivers/staging/ks7010/ks_debug.h deleted file mode 100644 index adad5f9..0000000 --- a/drivers/staging/ks7010/ks_debug.h +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Driver for KeyStream 11b/g wireless LAN cards. - * - * ks_debug.h - * $Id: ks_debug.h 991 2009-09-14 01:38:58Z sekine $ - * - * Copyright (C) 2005-2008 KeyStream Corp. - * Copyright (C) 2009 Renesas Technology Corp. - * - * This program is free software; you can redistribute it and/or modify - * it undr the terms of the GNU General Public License version 2 as - * published by the Free Sotware Foundation. - */ - -#ifndef _KS_DEBUG_H -#define _KS_DEBUG_H - -#include - - -#ifdef KS_WLAN_DEBUG -#define DPRINTK(n, fmt, args...) \ - if (KS_WLAN_DEBUG>(n)) printk(KERN_NOTICE "%s: "fmt, __FUNCTION__, ## args) -#else -#define DPRINTK(n, fmt, args...) -#endif - -#endif /* _KS_DEBUG_H */ diff --git a/drivers/staging/ks7010/ks_hostif.c b/drivers/staging/ks7010/ks_hostif.c index 146a135..367d487 100644 --- a/drivers/staging/ks7010/ks_hostif.c +++ b/drivers/staging/ks7010/ks_hostif.c @@ -13,7 +13,6 @@ */ #include "ks_wlan.h" -#include "ks_debug.h" #include "ks_hostif.h" #include "eap_packet.h" #include "michael_mic.h" diff --git a/drivers/staging/ks7010/ks_wlan.h b/drivers/staging/ks7010/ks_wlan.h index 6bd01641..c460741 100644 --- a/drivers/staging/ks7010/ks_wlan.h +++ b/drivers/staging/ks7010/ks_wlan.h @@ -38,6 +38,13 @@ #include "ks7010_sdio.h" +#ifdef KS_WLAN_DEBUG +#define DPRINTK(n, fmt, args...) \ + if (KS_WLAN_DEBUG>(n)) printk(KERN_NOTICE "%s: "fmt, __FUNCTION__, ## args) +#else +#define DPRINTK(n, fmt, args...) +#endif + struct ks_wlan_parameter { uint8_t operation_mode; /* Operation Mode */ uint8_t channel; /* Channel */ diff --git a/drivers/staging/ks7010/ks_wlan_net.c b/drivers/staging/ks7010/ks_wlan_net.c index 776a544..1da2768 100644 --- a/drivers/staging/ks7010/ks_wlan_net.c +++ b/drivers/staging/ks7010/ks_wlan_net.c @@ -40,7 +40,6 @@ static int wep_on_off; #include "ks_wlan.h" #include "ks_hostif.h" #include "ks_wlan_ioctl.h" -#include "ks_debug.h" /* Include Wireless Extension definition and check version */ #include -- cgit v0.10.2 From f88e6d3317907b93d7e8cbdbc0e26012cc1b1a48 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Tue, 31 May 2016 12:56:22 +0200 Subject: staging: ks7010: really iterate over multicast addresses The loop variable was defined but not really used. Fix this. Signed-off-by: Wolfram Sang Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/ks7010/ks_hostif.c b/drivers/staging/ks7010/ks_hostif.c index 367d487..b0a0a53 100644 --- a/drivers/staging/ks7010/ks_hostif.c +++ b/drivers/staging/ks7010/ks_hostif.c @@ -2105,7 +2105,7 @@ void hostif_sme_multicast_set(ks_wlan_private *priv) struct netdev_hw_addr *ha; char set_address[NIC_MAX_MCAST_LIST*ETH_ALEN]; unsigned long filter_type; - int i; + int i = 0; DPRINTK(3,"\n"); @@ -2128,6 +2128,7 @@ void hostif_sme_multicast_set(ks_wlan_private *priv) mc_count = netdev_mc_count(dev); netdev_for_each_mc_addr(ha, dev) { memcpy(&set_address[i*ETH_ALEN], ha->addr, ETH_ALEN); + i++; } priv->sme_i.sme_flag &= ~SME_MULTICAST; hostif_mib_set_request(priv, LOCAL_MULTICAST_ADDRESS, -- cgit v0.10.2 From 4fdec6ad1cdfa6559c1e1ba868d92a02f9f1e6ae Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Tue, 31 May 2016 12:56:23 +0200 Subject: staging: ks7010: make loading config file optional We have sane defaults, so we don't need to bail out if there is no config file. Note that the config file should go away completely in favour of configuration mechanisms already upstream. Signed-off-by: Wolfram Sang Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/ks7010/ks7010_config.c b/drivers/staging/ks7010/ks7010_config.c index 7f273da..06ff885 100644 --- a/drivers/staging/ks7010/ks7010_config.c +++ b/drivers/staging/ks7010/ks7010_config.c @@ -203,7 +203,6 @@ int ks_wlan_read_config_file(ks_wlan_private *priv) const struct firmware *fw_entry; struct device *dev = NULL; - int retval; char cfg_file[]=CFG_FILE; char *cur_p, *end_p; char wk_buff[256], *wk_p; @@ -254,10 +253,9 @@ int ks_wlan_read_config_file(ks_wlan_private *priv) priv->reg.rate_set.size = 12; dev = &priv->ks_wlan_hw.sdio_card->func->dev; - if((retval = request_firmware(&fw_entry, cfg_file, dev)) !=0 ){ - DPRINTK(1, "error request_firmware() file=%s ret=%d\n", cfg_file, retval); - return 1; - } + /* If no cfg file, stay with the defaults */ + if (request_firmware_direct(&fw_entry, cfg_file, dev)) + return 0; DPRINTK(4, "success request_firmware() file=%s size=%d\n", cfg_file, fw_entry->size); cur_p = fw_entry->data; -- cgit v0.10.2 From f8d72df83ca4d3b80517d721bef6d124393a35e7 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Tue, 31 May 2016 12:56:24 +0200 Subject: staging: ks7010: fix printk format warnings Use proper type for size_t. Signed-off-by: Wolfram Sang Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/ks7010/ks7010_config.c b/drivers/staging/ks7010/ks7010_config.c index 06ff885..4b00d25 100644 --- a/drivers/staging/ks7010/ks7010_config.c +++ b/drivers/staging/ks7010/ks7010_config.c @@ -257,7 +257,7 @@ int ks_wlan_read_config_file(ks_wlan_private *priv) if (request_firmware_direct(&fw_entry, cfg_file, dev)) return 0; - DPRINTK(4, "success request_firmware() file=%s size=%d\n", cfg_file, fw_entry->size); + DPRINTK(4, "success request_firmware() file=%s size=%zu\n", cfg_file, fw_entry->size); cur_p = fw_entry->data; end_p = cur_p + fw_entry->size; *end_p = '\0'; diff --git a/drivers/staging/ks7010/ks7010_sdio.c b/drivers/staging/ks7010/ks7010_sdio.c index 3fb432c..5036490 100644 --- a/drivers/staging/ks7010/ks7010_sdio.c +++ b/drivers/staging/ks7010/ks7010_sdio.c @@ -750,7 +750,7 @@ static int ks79xx_upload_firmware(ks_wlan_private *priv, struct ks_sdio_card *ca DPRINTK(1,"error request_firmware() file=%s\n", priv->reg.rom_file); return 1; } - DPRINTK(4,"success request_firmware() file=%s size=%d\n", priv->reg.rom_file, fw_entry->size); + DPRINTK(4,"success request_firmware() file=%s size=%zu\n", priv->reg.rom_file, fw_entry->size); length = fw_entry->size; /* Load Program */ -- cgit v0.10.2 From acd15986df6aa3fa2c56201693c3b1d245f88630 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Tue, 31 May 2016 12:56:25 +0200 Subject: staging: ks7010: add example cfg file as a reference We want to remove it, but to do so properly, it is good to have a working example. Needs to be copied to /lib/firmware in order to be used. Signed-off-by: Wolfram Sang Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/ks7010/ks79xx.cfg b/drivers/staging/ks7010/ks79xx.cfg new file mode 100644 index 0000000..0f2d24d --- /dev/null +++ b/drivers/staging/ks7010/ks79xx.cfg @@ -0,0 +1,116 @@ +#ks79xx.cfg +#KS79xx configuration file +# + +# +#BeaconLostCount default 20 +BeaconLostCount=20 +# + +# +#Ap List Scan Type default ACTIVE_SCAN ACTIVE_SCAN or PASSIVE_SCAN +ScanType=ACTIVE_SCAN +# + +# +#Channel default 10 min 1 max 14 +Channel=10 +# + +# +#FragmentThreshold default 2346 min 256 max 2346 +FragmentThreshold=2346 +# + +# +#OperationMode default Infrastructure Pseudo-Ad-Hoc or 802.11-Ad-Hoc or Infrastructure +OperationMode=Infrastructure +# + +# +#PowerManagementMode default ACTIVE ACTIVE or SAVE1 or SAVE2 +PowerManagementMode=ACTIVE +# + +# +#RTSThreshold default 2347 min 0 max 2347 +RTSThreshold=2347 +# + +# +#SSID default "" max 32 character +SSID="default" +# + +# +#TxRate default Auto 1, 2, 5.5, 11 ex. TxRate=1,2 TxRate=11 TxRate=Auto ... +TxRate=Auto +# + +# +#Wep default OFF OFF or 64bit or 128bit +Wep=OFF +# + +# +#WepType default STRING STRING or HEX +WepType=STRING +# + +# +#WepIndex=1 +# + +# +#WepKeyValue1 +# character_wep_key:64bit key_length = 5; 128bit key_length = 13 +# hex_wep_key:64bit key_length = 10; 128bit key_length = 26 +# + +# +#WepKeyValue2 +# character_wep_key:64bit key_length = 5; 128bit key_length = 13 +# hex_wep_key:64bit key_length = 10; 128bit key_length = 26 +# + +# +#WepKeyValue3 +# character_wep_key:64bit key_length = 5; 128bit key_length = 13 +# hex_wep_key:64bit key_length = 10; 128bit key_length = 26 +# + +# +#WepKeyValue4 +# character_wep_key:64bit key_length = 5; 128bit key_length = 13 +# hex_wep_key:64bit key_length = 10; 128bit key_length = 26 +# + +# +#AuthenticationAlgorithm default OPEN_SYSTEM OPEN_SYSTEM or SHARED_KEY +AuthenticationAlgorithm=OPEN_SYSTEM +# + +# +#PREAMBLE_TYPE default LONG LONG or SHORT +PREAMBLE_TYPE=SHORT +# + +# +# PhyType default BG_MODE B_MODE, G_MODE or BG_MODE +PhyType=BG_MODE +# + +# +# CtsMode defalut FALSE TURE or FALSE +CtsMode=FALSE +# + +# +# PhyInformationTimer defalut 0 uint 100msec +PhyInformationTimer=0 +# + +# +#ROM_FILE default "ks7010sd.rom" +ROM_FILE="ks7010sd.rom" +# -- cgit v0.10.2 From feedcf1a5f3d4fc964d9f7b4d755fc0992378abf Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Tue, 31 May 2016 12:56:26 +0200 Subject: staging: ks7010: remove unecessary typedef Let's simply specify the struct to keep in sync with kernel coding style. Signed-off-by: Wolfram Sang Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/ks7010/ks7010_config.c b/drivers/staging/ks7010/ks7010_config.c index 4b00d25..48809bc 100644 --- a/drivers/staging/ks7010/ks7010_config.c +++ b/drivers/staging/ks7010/ks7010_config.c @@ -87,7 +87,7 @@ void analyze_hex_wep_key(struct ks_wlan_parameter *param, int wep_key_index, cha } static -int rate_set_configuration(ks_wlan_private *priv, char *value) +int rate_set_configuration(struct ks_wlan_private *priv, char *value) { int rc=0; @@ -169,7 +169,7 @@ int rate_set_configuration(ks_wlan_private *priv, char *value) } #include -int ks_wlan_read_config_file(ks_wlan_private *priv) +int ks_wlan_read_config_file(struct ks_wlan_private *priv) { struct { const int key_len; diff --git a/drivers/staging/ks7010/ks7010_sdio.c b/drivers/staging/ks7010/ks7010_sdio.c index 5036490..fb9f0b5 100644 --- a/drivers/staging/ks7010/ks7010_sdio.c +++ b/drivers/staging/ks7010/ks7010_sdio.c @@ -51,9 +51,9 @@ static struct ks_sdio_model ks_sdio_models[] = { static int ks7910_sdio_probe(struct sdio_func *function, const struct sdio_device_id *device); static void ks7910_sdio_remove(struct sdio_func *function); static void ks7010_rw_function(struct work_struct *work); -static int ks7010_sdio_read( ks_wlan_private *priv, unsigned int address, +static int ks7010_sdio_read( struct ks_wlan_private *priv, unsigned int address, unsigned char *buffer, int length ); -static int ks7010_sdio_write( ks_wlan_private *priv, unsigned int address, +static int ks7010_sdio_write( struct ks_wlan_private *priv, unsigned int address, unsigned char *buffer, int length ); /* macro */ @@ -71,7 +71,7 @@ static int ks7010_sdio_write( ks_wlan_private *priv, unsigned int address, #define cnt_rxqbody(priv) \ (((priv->rx_dev.qtail + RX_DEVICE_BUFF_SIZE) - (priv->rx_dev.qhead)) % RX_DEVICE_BUFF_SIZE ) -void ks_wlan_hw_sleep_doze_request(ks_wlan_private *priv) +void ks_wlan_hw_sleep_doze_request(struct ks_wlan_private *priv) { unsigned char rw_data; int retval; @@ -102,7 +102,7 @@ out: return; } -void ks_wlan_hw_sleep_wakeup_request(ks_wlan_private *priv) +void ks_wlan_hw_sleep_wakeup_request(struct ks_wlan_private *priv) { unsigned char rw_data; int retval; @@ -134,7 +134,7 @@ out: } -void ks_wlan_hw_wakeup_request(ks_wlan_private *priv) +void ks_wlan_hw_wakeup_request(struct ks_wlan_private *priv) { unsigned char rw_data; int retval; @@ -155,7 +155,7 @@ void ks_wlan_hw_wakeup_request(ks_wlan_private *priv) } } -int _ks_wlan_hw_power_save(ks_wlan_private *priv) +int _ks_wlan_hw_power_save(struct ks_wlan_private *priv) { int rc=0; unsigned char rw_data; @@ -220,13 +220,13 @@ int _ks_wlan_hw_power_save(ks_wlan_private *priv) return rc; } -int ks_wlan_hw_power_save(ks_wlan_private *priv) +int ks_wlan_hw_power_save(struct ks_wlan_private *priv) { queue_delayed_work(priv->ks_wlan_hw.ks7010sdio_wq,&priv->ks_wlan_hw.rw_wq, 1); return 0; } -static int ks7010_sdio_read(ks_wlan_private *priv, unsigned int address, +static int ks7010_sdio_read(struct ks_wlan_private *priv, unsigned int address, unsigned char *buffer, int length) { int rc = -1; @@ -249,7 +249,7 @@ static int ks7010_sdio_read(ks_wlan_private *priv, unsigned int address, return rc; } -static int ks7010_sdio_write(ks_wlan_private *priv, unsigned int address, +static int ks7010_sdio_write(struct ks_wlan_private *priv, unsigned int address, unsigned char *buffer, int length) { int rc = -1; @@ -272,7 +272,7 @@ static int ks7010_sdio_write(ks_wlan_private *priv, unsigned int address, return rc; } -static int enqueue_txdev(ks_wlan_private *priv, unsigned char *p, unsigned long size, +static int enqueue_txdev(struct ks_wlan_private *priv, unsigned char *p, unsigned long size, void (*complete_handler)(void *arg1, void *arg2), void *arg1, void *arg2 ) { @@ -306,7 +306,7 @@ static int enqueue_txdev(ks_wlan_private *priv, unsigned char *p, unsigned long } /* write data */ -static int write_to_device(ks_wlan_private *priv, unsigned char *buffer, unsigned long size ) +static int write_to_device(struct ks_wlan_private *priv, unsigned char *buffer, unsigned long size ) { int rc,retval; unsigned char rw_data; @@ -338,7 +338,7 @@ static int write_to_device(ks_wlan_private *priv, unsigned char *buffer, unsigne static void tx_device_task(void *dev) { - ks_wlan_private *priv = (ks_wlan_private *)dev; + struct ks_wlan_private *priv = (struct ks_wlan_private *)dev; struct tx_device_buffer *sp; int rc = 0; @@ -366,7 +366,7 @@ static void tx_device_task(void *dev) return; } -int ks_wlan_hw_tx( ks_wlan_private *priv, void *p, unsigned long size, +int ks_wlan_hw_tx( struct ks_wlan_private *priv, void *p, unsigned long size, void (*complete_handler)(void *arg1, void *arg2), void *arg1, void *arg2 ) { @@ -396,7 +396,7 @@ int ks_wlan_hw_tx( ks_wlan_private *priv, void *p, unsigned long size, static void rx_event_task(unsigned long dev) { - ks_wlan_private *priv = (ks_wlan_private *)dev; + struct ks_wlan_private *priv = (struct ks_wlan_private *)dev; struct rx_device_buffer *rp; DPRINTK(4,"\n"); @@ -416,7 +416,7 @@ static void rx_event_task(unsigned long dev) static void ks_wlan_hw_rx(void *dev, uint16_t size) { - ks_wlan_private *priv = (ks_wlan_private *)dev; + struct ks_wlan_private *priv = (struct ks_wlan_private *)dev; int retval; struct rx_device_buffer *rx_buffer; struct hostif_hdr *hdr; @@ -560,7 +560,7 @@ static void ks_sdio_interrupt(struct sdio_func *func) { int retval; struct ks_sdio_card *card; - ks_wlan_private *priv; + struct ks_wlan_private *priv; unsigned char status, rsize, rw_data; card = sdio_get_drvdata(func); @@ -643,7 +643,7 @@ intr_out: return; } -static int trx_device_init( ks_wlan_private *priv ) +static int trx_device_init( struct ks_wlan_private *priv ) { /* initialize values (tx) */ priv->tx_dev.qtail = priv->tx_dev.qhead = 0; @@ -660,7 +660,7 @@ static int trx_device_init( ks_wlan_private *priv ) return 0; } -static void trx_device_exit( ks_wlan_private *priv ) +static void trx_device_exit( struct ks_wlan_private *priv ) { struct tx_device_buffer *sp; @@ -677,7 +677,7 @@ static void trx_device_exit( ks_wlan_private *priv ) return; } -static int ks7010_sdio_update_index(ks_wlan_private *priv, u32 index) +static int ks7010_sdio_update_index(struct ks_wlan_private *priv, u32 index) { int rc=0; int retval; @@ -699,7 +699,7 @@ error_out: } #define ROM_BUFF_SIZE (64*1024) -static int ks7010_sdio_data_compare(ks_wlan_private *priv, u32 address, +static int ks7010_sdio_data_compare(struct ks_wlan_private *priv, u32 address, unsigned char *data, unsigned int size) { int rc=0; @@ -720,7 +720,7 @@ error_out: return rc; } #include -static int ks79xx_upload_firmware(ks_wlan_private *priv, struct ks_sdio_card *card) +static int ks79xx_upload_firmware(struct ks_wlan_private *priv, struct ks_sdio_card *card) { unsigned int size, offset, n = 0; unsigned char *rom_buf; @@ -886,7 +886,7 @@ extern int ks_wlan_net_stop(struct net_device *dev); static int ks7910_sdio_probe(struct sdio_func *func, const struct sdio_device_id *device) { - ks_wlan_private *priv; + struct ks_wlan_private *priv; struct ks_sdio_card *card; struct net_device *netdev; unsigned char rw_data; diff --git a/drivers/staging/ks7010/ks7010_sdio.h b/drivers/staging/ks7010/ks7010_sdio.h index 9382383..1d16673 100644 --- a/drivers/staging/ks7010/ks7010_sdio.h +++ b/drivers/staging/ks7010/ks7010_sdio.h @@ -110,7 +110,7 @@ struct ks_sdio_packet { struct ks_sdio_card { struct sdio_func *func; - struct ks_wlan_private *priv; + struct ks_wlan_private *priv; int model; const char *firmware; spinlock_t lock; diff --git a/drivers/staging/ks7010/ks_hostif.c b/drivers/staging/ks7010/ks_hostif.c index b0a0a53..497b8aa 100644 --- a/drivers/staging/ks7010/ks_hostif.c +++ b/drivers/staging/ks7010/ks_hostif.c @@ -23,13 +23,13 @@ /* Include Wireless Extension definition and check version */ #include /* New driver API */ -extern int ks_wlan_hw_tx(ks_wlan_private *priv, void *p, unsigned long size, +extern int ks_wlan_hw_tx(struct ks_wlan_private *priv, void *p, unsigned long size, void (*complete_handler)(void *arg1, void *arg2), void *arg1, void *arg2 ); extern void send_packet_complete(void *, void *); -extern void ks_wlan_hw_wakeup_request(ks_wlan_private *priv); -extern int ks_wlan_hw_power_save(ks_wlan_private *priv); +extern void ks_wlan_hw_wakeup_request(struct ks_wlan_private *priv); +extern int ks_wlan_hw_power_save(struct ks_wlan_private *priv); /* macro */ #define inc_smeqhead(priv) \ @@ -42,7 +42,7 @@ extern int ks_wlan_hw_power_save(ks_wlan_private *priv); #define KS_WLAN_MEM_FLAG (GFP_ATOMIC) static -inline u8 get_BYTE(ks_wlan_private *priv) +inline u8 get_BYTE(struct ks_wlan_private *priv) { u8 data; data = *(priv->rxp)++; @@ -52,7 +52,7 @@ inline u8 get_BYTE(ks_wlan_private *priv) } static -inline u16 get_WORD(ks_wlan_private *priv) +inline u16 get_WORD(struct ks_wlan_private *priv) { u16 data; data = (get_BYTE(priv) & 0xff); @@ -61,7 +61,7 @@ inline u16 get_WORD(ks_wlan_private *priv) } static -inline u32 get_DWORD(ks_wlan_private *priv) +inline u32 get_DWORD(struct ks_wlan_private *priv) { u32 data; data = (get_BYTE(priv) & 0xff); @@ -73,7 +73,7 @@ inline u32 get_DWORD(ks_wlan_private *priv) void ks_wlan_hw_wakeup_task(struct work_struct *work) { - ks_wlan_private *priv = container_of(work, struct ks_wlan_private, ks_wlan_wakeup_task); + struct ks_wlan_private *priv = container_of(work, struct ks_wlan_private, ks_wlan_wakeup_task); int ps_status = atomic_read(&priv->psstatus.status); if(ps_status==PS_SNOOZE){ @@ -96,7 +96,7 @@ void ks_wlan_hw_wakeup_task(struct work_struct *work) } static -int ks_wlan_do_power_save(ks_wlan_private *priv) +int ks_wlan_do_power_save(struct ks_wlan_private *priv) { int rc=0; @@ -112,7 +112,7 @@ int ks_wlan_do_power_save(ks_wlan_private *priv) } static -int get_current_ap(ks_wlan_private *priv, struct link_ap_info_t *ap_info) +int get_current_ap(struct ks_wlan_private *priv, struct link_ap_info_t *ap_info) { struct local_ap_t *ap; union iwreq_data wrqu; @@ -213,7 +213,7 @@ int get_current_ap(ks_wlan_private *priv, struct link_ap_info_t *ap_info) } static -int get_ap_information(ks_wlan_private *priv, struct ap_info_t *ap_info, struct local_ap_t *ap) +int get_ap_information(struct ks_wlan_private *priv, struct ap_info_t *ap_info, struct local_ap_t *ap) { unsigned char *bp; int bsize,offset; @@ -312,7 +312,7 @@ int get_ap_information(ks_wlan_private *priv, struct ap_info_t *ap_info, struct } static -void hostif_data_indication(ks_wlan_private *priv) +void hostif_data_indication(struct ks_wlan_private *priv) { unsigned int rx_ind_size; /* indicate data size */ struct sk_buff *skb; @@ -491,7 +491,7 @@ void hostif_data_indication(ks_wlan_private *priv) } static -void hostif_mib_get_confirm(ks_wlan_private *priv) +void hostif_mib_get_confirm(struct ks_wlan_private *priv) { struct net_device *dev=priv->net_dev; uint32_t mib_status; @@ -570,7 +570,7 @@ void hostif_mib_get_confirm(ks_wlan_private *priv) } static -void hostif_mib_set_confirm(ks_wlan_private *priv) +void hostif_mib_set_confirm(struct ks_wlan_private *priv) { uint32_t mib_status; /* +04 MIB Status */ uint32_t mib_attribute; /* +08 MIB attribute */ @@ -691,7 +691,7 @@ void hostif_mib_set_confirm(ks_wlan_private *priv) } static -void hostif_power_mngmt_confirm(ks_wlan_private *priv) +void hostif_power_mngmt_confirm(struct ks_wlan_private *priv) { DPRINTK(3,"\n"); @@ -707,7 +707,7 @@ void hostif_power_mngmt_confirm(ks_wlan_private *priv) } static -void hostif_sleep_confirm(ks_wlan_private *priv) +void hostif_sleep_confirm(struct ks_wlan_private *priv) { DPRINTK(3,"\n"); @@ -716,7 +716,7 @@ void hostif_sleep_confirm(ks_wlan_private *priv) } static -void hostif_start_confirm(ks_wlan_private *priv) +void hostif_start_confirm(struct ks_wlan_private *priv) { #ifdef WPS union iwreq_data wrqu; @@ -734,7 +734,7 @@ void hostif_start_confirm(ks_wlan_private *priv) } static -void hostif_connect_indication(ks_wlan_private *priv) +void hostif_connect_indication(struct ks_wlan_private *priv) { unsigned short connect_code; unsigned int tmp=0; @@ -789,7 +789,7 @@ void hostif_connect_indication(ks_wlan_private *priv) } static -void hostif_scan_indication(ks_wlan_private *priv) +void hostif_scan_indication(struct ks_wlan_private *priv) { int i; struct ap_info_t *ap_info; @@ -820,7 +820,7 @@ void hostif_scan_indication(ks_wlan_private *priv) } static -void hostif_stop_confirm(ks_wlan_private *priv) +void hostif_stop_confirm(struct ks_wlan_private *priv) { unsigned int tmp=0; unsigned int old_status=priv->connect_status; @@ -856,7 +856,7 @@ void hostif_stop_confirm(ks_wlan_private *priv) } static -void hostif_ps_adhoc_set_confirm(ks_wlan_private *priv) +void hostif_ps_adhoc_set_confirm(struct ks_wlan_private *priv) { DPRINTK(3,"\n"); priv->infra_status = 0; /* infrastructure mode cancel */ @@ -865,7 +865,7 @@ void hostif_ps_adhoc_set_confirm(ks_wlan_private *priv) } static -void hostif_infrastructure_set_confirm(ks_wlan_private *priv) +void hostif_infrastructure_set_confirm(struct ks_wlan_private *priv) { uint16_t result_code; DPRINTK(3,"\n"); @@ -876,7 +876,7 @@ void hostif_infrastructure_set_confirm(ks_wlan_private *priv) } static -void hostif_adhoc_set_confirm(ks_wlan_private *priv) +void hostif_adhoc_set_confirm(struct ks_wlan_private *priv) { DPRINTK(3,"\n"); priv->infra_status = 1; /* infrastructure mode set */ @@ -884,7 +884,7 @@ void hostif_adhoc_set_confirm(ks_wlan_private *priv) } static -void hostif_associate_indication(ks_wlan_private *priv) +void hostif_associate_indication(struct ks_wlan_private *priv) { struct association_request_t *assoc_req; struct association_response_t *assoc_resp; @@ -928,7 +928,7 @@ void hostif_associate_indication(ks_wlan_private *priv) } static -void hostif_bss_scan_confirm(ks_wlan_private *priv) +void hostif_bss_scan_confirm(struct ks_wlan_private *priv) { unsigned int result_code; struct net_device *dev = priv->net_dev; @@ -947,7 +947,7 @@ void hostif_bss_scan_confirm(ks_wlan_private *priv) } static -void hostif_phy_information_confirm(ks_wlan_private *priv) +void hostif_phy_information_confirm(struct ks_wlan_private *priv) { struct iw_statistics *wstats = &priv->wstats; unsigned char rssi,signal,noise; @@ -983,7 +983,7 @@ void hostif_phy_information_confirm(ks_wlan_private *priv) } static -void hostif_mic_failure_confirm(ks_wlan_private *priv) +void hostif_mic_failure_confirm(struct ks_wlan_private *priv) { DPRINTK(3,"mic_failure=%u\n",priv->wpa.mic_failure.failure); hostif_sme_enqueue(priv, SME_MIC_FAILURE_CONFIRM); @@ -991,7 +991,7 @@ void hostif_mic_failure_confirm(ks_wlan_private *priv) static -void hostif_event_check(ks_wlan_private *priv) +void hostif_event_check(struct ks_wlan_private *priv) { unsigned short event; @@ -1065,7 +1065,7 @@ void hostif_event_check(ks_wlan_private *priv) #define CHECK_ALINE(size) (size%4 ? (size+(4-(size%4))):size) -int hostif_data_request(ks_wlan_private *priv, struct sk_buff *packet) +int hostif_data_request(struct ks_wlan_private *priv, struct sk_buff *packet) { unsigned int packet_len=0; @@ -1231,7 +1231,7 @@ int hostif_data_request(ks_wlan_private *priv, struct sk_buff *packet) } }while(0) static -void hostif_mib_get_request( ks_wlan_private *priv, unsigned long mib_attribute) +void hostif_mib_get_request( struct ks_wlan_private *priv, unsigned long mib_attribute) { struct hostif_mib_get_request_t *pp; @@ -1253,7 +1253,7 @@ void hostif_mib_get_request( ks_wlan_private *priv, unsigned long mib_attribute) } static -void hostif_mib_set_request( ks_wlan_private *priv, unsigned long mib_attribute, +void hostif_mib_set_request( struct ks_wlan_private *priv, unsigned long mib_attribute, unsigned short size, unsigned short type, void *vp ) { @@ -1286,7 +1286,7 @@ void hostif_mib_set_request( ks_wlan_private *priv, unsigned long mib_attribute, } static -void hostif_start_request( ks_wlan_private *priv, unsigned char mode ) +void hostif_start_request( struct ks_wlan_private *priv, unsigned char mode ) { struct hostif_start_request_t *pp; @@ -1311,7 +1311,7 @@ void hostif_start_request( ks_wlan_private *priv, unsigned char mode ) } static -void hostif_ps_adhoc_set_request(ks_wlan_private *priv) +void hostif_ps_adhoc_set_request(struct ks_wlan_private *priv) { struct hostif_ps_adhoc_set_request_t *pp; uint16_t capability; @@ -1352,7 +1352,7 @@ void hostif_ps_adhoc_set_request(ks_wlan_private *priv) } static -void hostif_infrastructure_set_request(ks_wlan_private *priv) +void hostif_infrastructure_set_request(struct ks_wlan_private *priv) { struct hostif_infrastructure_set_request_t *pp; uint16_t capability; @@ -1415,7 +1415,7 @@ void hostif_infrastructure_set_request(ks_wlan_private *priv) ks_wlan_hw_tx( priv, pp, hif_align_size(sizeof(*pp)),NULL, NULL, NULL); } -void hostif_infrastructure_set2_request(ks_wlan_private *priv) +void hostif_infrastructure_set2_request(struct ks_wlan_private *priv) { struct hostif_infrastructure_set2_request_t *pp; uint16_t capability; @@ -1481,7 +1481,7 @@ void hostif_infrastructure_set2_request(ks_wlan_private *priv) } static -void hostif_adhoc_set_request(ks_wlan_private *priv) +void hostif_adhoc_set_request(struct ks_wlan_private *priv) { struct hostif_adhoc_set_request_t *pp; uint16_t capability; @@ -1524,7 +1524,7 @@ void hostif_adhoc_set_request(ks_wlan_private *priv) } static -void hostif_adhoc_set2_request(ks_wlan_private *priv) +void hostif_adhoc_set2_request(struct ks_wlan_private *priv) { struct hostif_adhoc_set2_request_t *pp; uint16_t capability; @@ -1570,7 +1570,7 @@ void hostif_adhoc_set2_request(ks_wlan_private *priv) } static -void hostif_stop_request( ks_wlan_private *priv ) +void hostif_stop_request( struct ks_wlan_private *priv ) { struct hostif_stop_request_t *pp; @@ -1591,7 +1591,7 @@ void hostif_stop_request( ks_wlan_private *priv ) } static -void hostif_phy_information_request( ks_wlan_private *priv ) +void hostif_phy_information_request( struct ks_wlan_private *priv ) { struct hostif_phy_information_request_t *pp; @@ -1619,7 +1619,7 @@ void hostif_phy_information_request( ks_wlan_private *priv ) } static -void hostif_power_mngmt_request( ks_wlan_private *priv, unsigned long mode, +void hostif_power_mngmt_request( struct ks_wlan_private *priv, unsigned long mode, unsigned long wake_up, unsigned long receiveDTIMs ) { struct hostif_power_mngmt_request_t *pp; @@ -1643,7 +1643,7 @@ void hostif_power_mngmt_request( ks_wlan_private *priv, unsigned long mode, } static -void hostif_sleep_request( ks_wlan_private *priv, unsigned long mode) +void hostif_sleep_request( struct ks_wlan_private *priv, unsigned long mode) { struct hostif_sleep_request_t *pp; @@ -1673,7 +1673,7 @@ void hostif_sleep_request( ks_wlan_private *priv, unsigned long mode) static -void hostif_bss_scan_request( ks_wlan_private *priv, unsigned long scan_type , uint8_t *scan_ssid, uint8_t scan_ssid_len) +void hostif_bss_scan_request( struct ks_wlan_private *priv, unsigned long scan_type , uint8_t *scan_ssid, uint8_t scan_ssid_len) { struct hostif_bss_scan_request_t *pp; @@ -1727,7 +1727,7 @@ void hostif_bss_scan_request( ks_wlan_private *priv, unsigned long scan_type , u } static -void hostif_mic_failure_request( ks_wlan_private *priv, unsigned short failure_count, +void hostif_mic_failure_request( struct ks_wlan_private *priv, unsigned short failure_count, unsigned short timer ) { struct hostif_mic_failure_request_t *pp; @@ -1750,7 +1750,7 @@ void hostif_mic_failure_request( ks_wlan_private *priv, unsigned short failure_c } /* Device I/O Recieve indicate */ -static void devio_rec_ind(ks_wlan_private *priv, unsigned char *p, unsigned int size) +static void devio_rec_ind(struct ks_wlan_private *priv, unsigned char *p, unsigned int size) { if (priv->device_open_status) { spin_lock(&priv->dev_read_lock); /* request spin lock */ @@ -1772,7 +1772,7 @@ static void devio_rec_ind(ks_wlan_private *priv, unsigned char *p, unsigned int } } -void hostif_receive( ks_wlan_private *priv, unsigned char *p, unsigned int size ) +void hostif_receive( struct ks_wlan_private *priv, unsigned char *p, unsigned int size ) { DPRINTK(4,"\n"); @@ -1788,7 +1788,7 @@ void hostif_receive( ks_wlan_private *priv, unsigned char *p, unsigned int size static -void hostif_sme_set_wep(ks_wlan_private *priv, int type) +void hostif_sme_set_wep(struct ks_wlan_private *priv, int type) { uint32_t val; switch(type){ @@ -1844,7 +1844,7 @@ struct rsn_mode_t { } __attribute__((packed)); static -void hostif_sme_set_rsn(ks_wlan_private *priv, int type) +void hostif_sme_set_rsn(struct ks_wlan_private *priv, int type) { struct wpa_suite_t wpa_suite; struct rsn_mode_t rsn_mode; @@ -1991,7 +1991,7 @@ void hostif_sme_set_rsn(ks_wlan_private *priv, int type) } static -void hostif_sme_mode_setup(ks_wlan_private *priv) +void hostif_sme_mode_setup(struct ks_wlan_private *priv) { unsigned char rate_size; unsigned char rate_octet[RATE_SET_MAX_SIZE]; @@ -2097,7 +2097,7 @@ void hostif_sme_mode_setup(ks_wlan_private *priv) } static -void hostif_sme_multicast_set(ks_wlan_private *priv) +void hostif_sme_multicast_set(struct ks_wlan_private *priv) { struct net_device *dev = priv->net_dev; @@ -2146,7 +2146,7 @@ void hostif_sme_multicast_set(ks_wlan_private *priv) } static -void hostif_sme_powermgt_set(ks_wlan_private *priv) +void hostif_sme_powermgt_set(struct ks_wlan_private *priv) { unsigned long mode,wake_up,receiveDTIMs ; @@ -2191,7 +2191,7 @@ void hostif_sme_powermgt_set(ks_wlan_private *priv) } static -void hostif_sme_sleep_set(ks_wlan_private *priv) +void hostif_sme_sleep_set(struct ks_wlan_private *priv) { DPRINTK(3,"\n"); switch(priv->sleep_mode){ @@ -2209,7 +2209,7 @@ void hostif_sme_sleep_set(ks_wlan_private *priv) } static -void hostif_sme_set_key(ks_wlan_private *priv, int type) +void hostif_sme_set_key(struct ks_wlan_private *priv, int type) { uint32_t val; switch(type){ @@ -2265,7 +2265,7 @@ void hostif_sme_set_key(ks_wlan_private *priv, int type) } static -void hostif_sme_set_pmksa(ks_wlan_private *priv) +void hostif_sme_set_pmksa(struct ks_wlan_private *priv) { struct pmk_cache_t { uint16_t size; @@ -2296,7 +2296,7 @@ void hostif_sme_set_pmksa(ks_wlan_private *priv) /* execute sme */ static -void hostif_sme_execute(ks_wlan_private *priv, int event) +void hostif_sme_execute(struct ks_wlan_private *priv, int event) { uint32_t val; @@ -2459,7 +2459,7 @@ void hostif_sme_execute(ks_wlan_private *priv, int event) static void hostif_sme_task( unsigned long dev ) { - ks_wlan_private *priv = (ks_wlan_private *)dev; + struct ks_wlan_private *priv = (struct ks_wlan_private *)dev; DPRINTK(3,"\n"); @@ -2475,7 +2475,7 @@ void hostif_sme_task( unsigned long dev ) } /* send to Station Management Entity module */ -void hostif_sme_enqueue(ks_wlan_private *priv, unsigned short event) +void hostif_sme_enqueue(struct ks_wlan_private *priv, unsigned short event) { DPRINTK(3,"\n"); @@ -2500,7 +2500,7 @@ void hostif_sme_enqueue(ks_wlan_private *priv, unsigned short event) } -int hostif_init( ks_wlan_private *priv ) +int hostif_init( struct ks_wlan_private *priv ) { int rc=0; int i; @@ -2555,7 +2555,7 @@ int hostif_init( ks_wlan_private *priv ) return rc; } -void hostif_exit( ks_wlan_private *priv ) +void hostif_exit( struct ks_wlan_private *priv ) { tasklet_kill(&priv->sme_task); return; diff --git a/drivers/staging/ks7010/ks_hostif.h b/drivers/staging/ks7010/ks_hostif.h index 24ebf1d..c333ce1 100644 --- a/drivers/staging/ks7010/ks_hostif.h +++ b/drivers/staging/ks7010/ks_hostif.h @@ -623,11 +623,11 @@ enum { #include "ks_wlan.h" /* function prototype */ -extern int hostif_data_request( ks_wlan_private *priv, struct sk_buff *packet ); -extern void hostif_receive( ks_wlan_private *priv, unsigned char *p, unsigned int size ); -extern void hostif_sme_enqueue(ks_wlan_private *priv, uint16_t event); -extern int hostif_init( ks_wlan_private *priv ); -extern void hostif_exit( ks_wlan_private *priv ); +extern int hostif_data_request( struct ks_wlan_private *priv, struct sk_buff *packet ); +extern void hostif_receive( struct ks_wlan_private *priv, unsigned char *p, unsigned int size ); +extern void hostif_sme_enqueue(struct ks_wlan_private *priv, uint16_t event); +extern int hostif_init( struct ks_wlan_private *priv ); +extern void hostif_exit( struct ks_wlan_private *priv ); static inline int hif_align_size(int size) diff --git a/drivers/staging/ks7010/ks_wlan.h b/drivers/staging/ks7010/ks_wlan.h index c460741..58e3a5a 100644 --- a/drivers/staging/ks7010/ks_wlan.h +++ b/drivers/staging/ks7010/ks_wlan.h @@ -414,7 +414,7 @@ struct wps_status_t { }; #endif /* WPS */ -typedef struct ks_wlan_private{ +struct ks_wlan_private { struct hw_info_t ks_wlan_hw; /* hardware information */ @@ -505,7 +505,7 @@ typedef struct ks_wlan_private{ uint sdio_error_count; /* SDIO error */ uint wakeup_count; /* for detect wakeup loop */ -} ks_wlan_private; +}; diff --git a/drivers/staging/ks7010/ks_wlan_ioctl.h b/drivers/staging/ks7010/ks_wlan_ioctl.h index e27f8fb..e7469f7 100644 --- a/drivers/staging/ks7010/ks_wlan_ioctl.h +++ b/drivers/staging/ks7010/ks_wlan_ioctl.h @@ -61,8 +61,8 @@ #include "ks_wlan.h" #include -extern int ks_wlan_read_config_file(ks_wlan_private *priv); -extern int ks_wlan_setup_parameter(ks_wlan_private *priv, unsigned int commit_flag); +extern int ks_wlan_read_config_file(struct ks_wlan_private *priv); +extern int ks_wlan_setup_parameter(struct ks_wlan_private *priv, unsigned int commit_flag); #endif /* __KERNEL__ */ diff --git a/drivers/staging/ks7010/ks_wlan_net.c b/drivers/staging/ks7010/ks_wlan_net.c index 1da2768..ec5c452 100644 --- a/drivers/staging/ks7010/ks_wlan_net.c +++ b/drivers/staging/ks7010/ks_wlan_net.c @@ -73,7 +73,7 @@ static const struct iw_handler_def ks_wlan_handler_def; /* * function prototypes */ -extern int ks_wlan_hw_tx(ks_wlan_private *priv, void *p, unsigned long size, +extern int ks_wlan_hw_tx(struct ks_wlan_private *priv, void *p, unsigned long size, void (*complete_handler)(void *arg1, void *arg2), void *arg1, void *arg2 ); @@ -89,7 +89,7 @@ static int ks_wlan_netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cm static atomic_t update_phyinfo; static struct timer_list update_phyinfo_timer; static -int ks_wlan_update_phy_information(ks_wlan_private *priv) +int ks_wlan_update_phy_information(struct ks_wlan_private *priv) { struct iw_statistics *wstats = &priv->wstats; @@ -126,7 +126,7 @@ void ks_wlan_update_phyinfo_timeout(unsigned long ptr) atomic_set(&update_phyinfo,0); } -int ks_wlan_setup_parameter(ks_wlan_private *priv, unsigned int commit_flag) +int ks_wlan_setup_parameter(struct ks_wlan_private *priv, unsigned int commit_flag) { DPRINTK(2,"\n"); @@ -183,7 +183,7 @@ int ks_wlan_setup_parameter(ks_wlan_private *priv, unsigned int commit_flag) static int ks_wlan_get_name(struct net_device *dev, struct iw_request_info *info, char *cwrq, char *extra) { - ks_wlan_private *priv = (ks_wlan_private *) netdev_priv(dev); + struct ks_wlan_private *priv = (struct ks_wlan_private *) netdev_priv(dev); if (priv->sleep_mode == SLP_SLEEP){ return -EPERM; } /* for SLEEP MODE */ @@ -208,7 +208,7 @@ static int ks_wlan_get_name(struct net_device *dev, struct iw_request_info *info static int ks_wlan_set_freq(struct net_device *dev, struct iw_request_info *info, struct iw_freq *fwrq, char *extra) { - ks_wlan_private *priv = (ks_wlan_private *)netdev_priv(dev); + struct ks_wlan_private *priv = (struct ks_wlan_private *)netdev_priv(dev); int rc = -EINPROGRESS; /* Call commit handler */ if (priv->sleep_mode == SLP_SLEEP){ return -EPERM; } /* for SLEEP MODE */ @@ -250,7 +250,7 @@ static int ks_wlan_set_freq(struct net_device *dev, struct iw_request_info *info static int ks_wlan_get_freq(struct net_device *dev, struct iw_request_info *info, struct iw_freq *fwrq, char *extra) { - ks_wlan_private *priv = (ks_wlan_private *)netdev_priv(dev); + struct ks_wlan_private *priv = (struct ks_wlan_private *)netdev_priv(dev); int f; if (priv->sleep_mode == SLP_SLEEP){ return -EPERM; } /* for SLEEP MODE */ @@ -271,7 +271,7 @@ static int ks_wlan_get_freq(struct net_device *dev, struct iw_request_info *info static int ks_wlan_set_essid(struct net_device *dev, struct iw_request_info *info, struct iw_point *dwrq, char *extra) { - ks_wlan_private *priv = (ks_wlan_private *)netdev_priv(dev); + struct ks_wlan_private *priv = (struct ks_wlan_private *)netdev_priv(dev); size_t len; DPRINTK(2," %d\n", dwrq->flags); @@ -326,7 +326,7 @@ static int ks_wlan_set_essid(struct net_device *dev, struct iw_request_info *inf static int ks_wlan_get_essid(struct net_device *dev, struct iw_request_info *info, struct iw_point *dwrq, char *extra) { - ks_wlan_private *priv = (ks_wlan_private *)netdev_priv(dev); + struct ks_wlan_private *priv = (struct ks_wlan_private *)netdev_priv(dev); if (priv->sleep_mode == SLP_SLEEP){ return -EPERM; } /* for SLEEP MODE */ @@ -366,7 +366,7 @@ static int ks_wlan_get_essid(struct net_device *dev, struct iw_request_info *inf static int ks_wlan_set_wap(struct net_device *dev, struct iw_request_info *info, struct sockaddr *ap_addr, char *extra) { - ks_wlan_private *priv = (ks_wlan_private *)netdev_priv(dev); + struct ks_wlan_private *priv = (struct ks_wlan_private *)netdev_priv(dev); DPRINTK(2,"\n"); @@ -402,7 +402,7 @@ static int ks_wlan_set_wap(struct net_device *dev, struct iw_request_info *info, static int ks_wlan_get_wap(struct net_device *dev, struct iw_request_info *info, struct sockaddr *awrq, char *extra) { - ks_wlan_private *priv = (ks_wlan_private *)netdev_priv(dev); + struct ks_wlan_private *priv = (struct ks_wlan_private *)netdev_priv(dev); if (priv->sleep_mode == SLP_SLEEP){ return -EPERM; } /* for SLEEP MODE */ @@ -423,7 +423,7 @@ static int ks_wlan_get_wap(struct net_device *dev, struct iw_request_info *info, static int ks_wlan_set_nick(struct net_device *dev, struct iw_request_info *info, struct iw_point *dwrq, char *extra) { - ks_wlan_private *priv = (ks_wlan_private *)netdev_priv(dev); + struct ks_wlan_private *priv = (struct ks_wlan_private *)netdev_priv(dev); if (priv->sleep_mode == SLP_SLEEP){ return -EPERM; } /* for SLEEP MODE */ @@ -442,7 +442,7 @@ static int ks_wlan_set_nick(struct net_device *dev, struct iw_request_info *info static int ks_wlan_get_nick(struct net_device *dev, struct iw_request_info *info, struct iw_point *dwrq, char *extra) { - ks_wlan_private *priv = (ks_wlan_private *)netdev_priv(dev); + struct ks_wlan_private *priv = (struct ks_wlan_private *)netdev_priv(dev); if (priv->sleep_mode == SLP_SLEEP){ return -EPERM; } /* for SLEEP MODE */ @@ -458,7 +458,7 @@ static int ks_wlan_get_nick(struct net_device *dev, struct iw_request_info *info static int ks_wlan_set_rate(struct net_device *dev, struct iw_request_info *info, struct iw_param *vwrq, char *extra) { - ks_wlan_private *priv = (ks_wlan_private *)netdev_priv(dev); + struct ks_wlan_private *priv = (struct ks_wlan_private *)netdev_priv(dev); int i = 0; if (priv->sleep_mode == SLP_SLEEP){ return -EPERM; } /* for SLEEP MODE */ @@ -609,7 +609,7 @@ static int ks_wlan_set_rate(struct net_device *dev, struct iw_request_info *info static int ks_wlan_get_rate(struct net_device *dev, struct iw_request_info *info, struct iw_param *vwrq, char *extra) { - ks_wlan_private *priv = (ks_wlan_private *)netdev_priv(dev); + struct ks_wlan_private *priv = (struct ks_wlan_private *)netdev_priv(dev); DPRINTK(2, "in_interrupt = %ld update_phyinfo = %d\n", in_interrupt(),atomic_read(&update_phyinfo)); @@ -633,7 +633,7 @@ static int ks_wlan_get_rate(struct net_device *dev, struct iw_request_info *info static int ks_wlan_set_rts(struct net_device *dev, struct iw_request_info *info, struct iw_param *vwrq, char *extra) { - ks_wlan_private *priv = (ks_wlan_private *)netdev_priv(dev); + struct ks_wlan_private *priv = (struct ks_wlan_private *)netdev_priv(dev); int rthr = vwrq->value; if (priv->sleep_mode == SLP_SLEEP){ return -EPERM; } /* for SLEEP MODE */ @@ -654,7 +654,7 @@ static int ks_wlan_set_rts(struct net_device *dev, struct iw_request_info *info, static int ks_wlan_get_rts(struct net_device *dev, struct iw_request_info *info, struct iw_param *vwrq, char *extra) { - ks_wlan_private *priv = (ks_wlan_private *)netdev_priv(dev); + struct ks_wlan_private *priv = (struct ks_wlan_private *)netdev_priv(dev); if (priv->sleep_mode == SLP_SLEEP){ return -EPERM; } /* for SLEEP MODE */ @@ -670,7 +670,7 @@ static int ks_wlan_get_rts(struct net_device *dev, struct iw_request_info *info, static int ks_wlan_set_frag(struct net_device *dev, struct iw_request_info *info, struct iw_param *vwrq, char *extra) { - ks_wlan_private *priv = (ks_wlan_private *)netdev_priv(dev); + struct ks_wlan_private *priv = (struct ks_wlan_private *)netdev_priv(dev); int fthr = vwrq->value; if (priv->sleep_mode == SLP_SLEEP){ return -EPERM; } /* for SLEEP MODE */ @@ -692,7 +692,7 @@ static int ks_wlan_set_frag(struct net_device *dev, struct iw_request_info *info static int ks_wlan_get_frag(struct net_device *dev, struct iw_request_info *info, struct iw_param *vwrq, char *extra) { - ks_wlan_private *priv = (ks_wlan_private *)netdev_priv(dev); + struct ks_wlan_private *priv = (struct ks_wlan_private *)netdev_priv(dev); if (priv->sleep_mode == SLP_SLEEP){ return -EPERM; } /* for SLEEP MODE */ @@ -708,7 +708,7 @@ static int ks_wlan_get_frag(struct net_device *dev, struct iw_request_info *info static int ks_wlan_set_mode(struct net_device *dev, struct iw_request_info *info, __u32 *uwrq, char *extra) { - ks_wlan_private *priv = (ks_wlan_private *)netdev_priv(dev); + struct ks_wlan_private *priv = (struct ks_wlan_private *)netdev_priv(dev); DPRINTK(2,"mode=%d\n",*uwrq); @@ -740,7 +740,7 @@ static int ks_wlan_set_mode(struct net_device *dev, struct iw_request_info *info static int ks_wlan_get_mode(struct net_device *dev, struct iw_request_info *info, __u32 *uwrq, char *extra) { - ks_wlan_private *priv = (ks_wlan_private *)netdev_priv(dev); + struct ks_wlan_private *priv = (struct ks_wlan_private *)netdev_priv(dev); if (priv->sleep_mode == SLP_SLEEP){ return -EPERM; } /* for SLEEP MODE */ @@ -764,7 +764,7 @@ static int ks_wlan_get_mode(struct net_device *dev, struct iw_request_info *info static int ks_wlan_set_encode(struct net_device *dev, struct iw_request_info *info, struct iw_point *dwrq, char *extra) { - ks_wlan_private *priv = (ks_wlan_private *)netdev_priv(dev); + struct ks_wlan_private *priv = (struct ks_wlan_private *)netdev_priv(dev); wep_key_t key; int index = (dwrq->flags & IW_ENCODE_INDEX); @@ -878,7 +878,7 @@ static int ks_wlan_set_encode(struct net_device *dev, struct iw_request_info *in static int ks_wlan_get_encode(struct net_device *dev, struct iw_request_info *info, struct iw_point *dwrq, char *extra) { - ks_wlan_private *priv = (ks_wlan_private *)netdev_priv(dev); + struct ks_wlan_private *priv = (struct ks_wlan_private *)netdev_priv(dev); char zeros[16]; int index = (dwrq->flags & IW_ENCODE_INDEX) - 1; @@ -974,7 +974,7 @@ static int ks_wlan_get_retry(struct net_device *dev, struct iw_request_info *inf static int ks_wlan_get_range(struct net_device *dev, struct iw_request_info *info, struct iw_point *dwrq, char *extra) { - ks_wlan_private *priv = (ks_wlan_private *)netdev_priv(dev); + struct ks_wlan_private *priv = (struct ks_wlan_private *)netdev_priv(dev); struct iw_range *range = (struct iw_range *) extra; int i,k; @@ -1105,7 +1105,7 @@ static int ks_wlan_get_range(struct net_device *dev, struct iw_request_info *inf static int ks_wlan_set_power(struct net_device *dev, struct iw_request_info *info, struct iw_param *vwrq, char *extra) { - ks_wlan_private *priv = (ks_wlan_private *)netdev_priv(dev); + struct ks_wlan_private *priv = (struct ks_wlan_private *)netdev_priv(dev); short enabled; if (priv->sleep_mode == SLP_SLEEP){ return -EPERM; } /* for SLEEP MODE */ @@ -1136,7 +1136,7 @@ static int ks_wlan_set_power(struct net_device *dev, struct iw_request_info *inf static int ks_wlan_get_power(struct net_device *dev, struct iw_request_info *info, struct iw_param *vwrq, char *extra) { - ks_wlan_private *priv = (ks_wlan_private *)netdev_priv(dev); + struct ks_wlan_private *priv = (struct ks_wlan_private *)netdev_priv(dev); if (priv->sleep_mode == SLP_SLEEP){ return -EPERM; } /* for SLEEP MODE */ @@ -1153,7 +1153,7 @@ static int ks_wlan_get_power(struct net_device *dev, struct iw_request_info *inf static int ks_wlan_get_iwstats(struct net_device *dev, struct iw_request_info *info, struct iw_quality *vwrq, char *extra) { - ks_wlan_private *priv = (ks_wlan_private *)netdev_priv(dev); + struct ks_wlan_private *priv = (struct ks_wlan_private *)netdev_priv(dev); if (priv->sleep_mode == SLP_SLEEP){ return -EPERM; } /* for SLEEP MODE */ @@ -1194,7 +1194,7 @@ static int ks_wlan_get_sens(struct net_device *dev, struct iw_request_info *info static int ks_wlan_get_aplist(struct net_device *dev, struct iw_request_info *info, struct iw_point *dwrq, char *extra) { - ks_wlan_private *priv = (ks_wlan_private *)netdev_priv(dev); + struct ks_wlan_private *priv = (struct ks_wlan_private *)netdev_priv(dev); struct sockaddr *address = (struct sockaddr *) extra; struct iw_quality qual[LOCAL_APLIST_MAX]; @@ -1225,7 +1225,7 @@ static int ks_wlan_get_aplist(struct net_device *dev, struct iw_request_info *in static int ks_wlan_set_scan(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - ks_wlan_private *priv = (ks_wlan_private *)netdev_priv(dev); + struct ks_wlan_private *priv = (struct ks_wlan_private *)netdev_priv(dev); struct iw_scan_req *req = NULL; DPRINTK(2,"\n"); @@ -1257,7 +1257,7 @@ static int ks_wlan_set_scan(struct net_device *dev, struct iw_request_info *info static inline char *ks_wlan_translate_scan(struct net_device *dev, struct iw_request_info *info, char *current_ev, char *end_buf, struct local_ap_t *ap) { - /* ks_wlan_private *priv = (ks_wlan_private *)dev->priv; */ + /* struct ks_wlan_private *priv = (struct ks_wlan_private *)dev->priv; */ struct iw_event iwe; /* Temporary buffer */ u16 capabilities; char *current_val; /* For rates */ @@ -1393,7 +1393,7 @@ static inline char *ks_wlan_translate_scan(struct net_device *dev, struct iw_req static int ks_wlan_get_scan(struct net_device *dev, struct iw_request_info *info, struct iw_point *dwrq, char *extra) { - ks_wlan_private *priv = (ks_wlan_private *)netdev_priv(dev); + struct ks_wlan_private *priv = (struct ks_wlan_private *)netdev_priv(dev); int i; char *current_ev = extra; DPRINTK(2,"\n"); @@ -1448,7 +1448,7 @@ DPRINTK(2,"aplist 0\n"); static int ks_wlan_config_commit(struct net_device *dev, struct iw_request_info *info, void *zwrq, char *extra) { - ks_wlan_private *priv = (ks_wlan_private *)netdev_priv(dev); + struct ks_wlan_private *priv = (struct ks_wlan_private *)netdev_priv(dev); if (!priv->need_commit) return 0; @@ -1463,7 +1463,7 @@ static int ks_wlan_config_commit(struct net_device *dev, struct iw_request_info static int ks_wlan_set_genie(struct net_device *dev, struct iw_request_info *info, struct iw_point *dwrq, char *extra) { - ks_wlan_private *priv = (ks_wlan_private *)netdev_priv(dev); + struct ks_wlan_private *priv = (struct ks_wlan_private *)netdev_priv(dev); DPRINTK(2, "\n"); @@ -1478,7 +1478,7 @@ static int ks_wlan_set_genie(struct net_device *dev, struct iw_request_info *inf static int ks_wlan_set_auth_mode(struct net_device *dev, struct iw_request_info *info, struct iw_param *vwrq, char *extra) { - ks_wlan_private *priv = (ks_wlan_private *)netdev_priv(dev); + struct ks_wlan_private *priv = (struct ks_wlan_private *)netdev_priv(dev); int index = (vwrq->flags & IW_AUTH_INDEX); int value = vwrq->value; @@ -1614,7 +1614,7 @@ static int ks_wlan_set_auth_mode(struct net_device *dev, struct iw_request_info static int ks_wlan_get_auth_mode(struct net_device *dev, struct iw_request_info *info, struct iw_param *vwrq, char *extra) { - ks_wlan_private *priv = (ks_wlan_private *)netdev_priv(dev); + struct ks_wlan_private *priv = (struct ks_wlan_private *)netdev_priv(dev); int index = (vwrq->flags & IW_AUTH_INDEX); DPRINTK(2,"index=%d\n",index); @@ -1655,7 +1655,7 @@ static int ks_wlan_get_auth_mode(struct net_device *dev, struct iw_request_info static int ks_wlan_set_encode_ext(struct net_device *dev, struct iw_request_info *info, struct iw_point *dwrq, char *extra) { - ks_wlan_private *priv = (ks_wlan_private *)netdev_priv(dev); + struct ks_wlan_private *priv = (struct ks_wlan_private *)netdev_priv(dev); struct iw_encode_ext *enc; int index = dwrq->flags & IW_ENCODE_INDEX; unsigned int commit=0; @@ -1761,12 +1761,12 @@ static int ks_wlan_set_encode_ext(struct net_device *dev, struct iw_request_info static int ks_wlan_get_encode_ext(struct net_device *dev, struct iw_request_info *info, struct iw_point *dwrq, char *extra) { - ks_wlan_private *priv = (ks_wlan_private *)netdev_priv(dev); + struct ks_wlan_private *priv = (struct ks_wlan_private *)netdev_priv(dev); if (priv->sleep_mode == SLP_SLEEP){ return -EPERM; } /* for SLEEP MODE */ /* WPA (not used ?? wpa_supplicant) - ks_wlan_private *priv = (ks_wlan_private *)dev->priv; + struct ks_wlan_private *priv = (struct ks_wlan_private *)dev->priv; struct iw_encode_ext *enc; enc = (struct iw_encode_ext *)extra; int index = dwrq->flags & IW_ENCODE_INDEX; @@ -1779,7 +1779,7 @@ static int ks_wlan_get_encode_ext(struct net_device *dev, struct iw_request_info static int ks_wlan_set_pmksa(struct net_device *dev, struct iw_request_info *info, struct iw_point *dwrq, char *extra) { - ks_wlan_private *priv = (ks_wlan_private *)netdev_priv(dev); + struct ks_wlan_private *priv = (struct ks_wlan_private *)netdev_priv(dev); struct iw_pmksa *pmksa ; int i; struct pmk_t *pmk; @@ -1874,7 +1874,7 @@ static int ks_wlan_set_pmksa(struct net_device *dev, struct iw_request_info *inf static struct iw_statistics *ks_get_wireless_stats(struct net_device *dev) { - ks_wlan_private *priv = (ks_wlan_private *) netdev_priv(dev); + struct ks_wlan_private *priv = (struct ks_wlan_private *) netdev_priv(dev); struct iw_statistics *wstats = &priv->wstats; if(!atomic_read(&update_phyinfo)){ @@ -1901,7 +1901,7 @@ static struct iw_statistics *ks_get_wireless_stats(struct net_device *dev) static int ks_wlan_set_stop_request(struct net_device *dev, struct iw_request_info *info, __u32 *uwrq, char *extra) { - ks_wlan_private *priv = (ks_wlan_private *)netdev_priv(dev); + struct ks_wlan_private *priv = (struct ks_wlan_private *)netdev_priv(dev); DPRINTK(2,"\n"); if (priv->sleep_mode == SLP_SLEEP){ return -EPERM; } /* for SLEEP MODE */ @@ -1919,7 +1919,7 @@ static int ks_wlan_set_stop_request(struct net_device *dev, struct iw_request_in static int ks_wlan_set_mlme(struct net_device *dev, struct iw_request_info *info, struct iw_point *dwrq, char *extra) { - ks_wlan_private *priv = (ks_wlan_private *)netdev_priv(dev); + struct ks_wlan_private *priv = (struct ks_wlan_private *)netdev_priv(dev); struct iw_mlme *mlme = (struct iw_mlme *)extra; __u32 mode; @@ -1955,7 +1955,7 @@ static int ks_wlan_get_driver_version(struct net_device *dev, struct iw_request_ static int ks_wlan_get_firmware_version(struct net_device *dev, struct iw_request_info *info, struct iw_point *dwrq, char *extra) { - ks_wlan_private *priv = (ks_wlan_private *)netdev_priv(dev); + struct ks_wlan_private *priv = (struct ks_wlan_private *)netdev_priv(dev); strcpy(extra, &(priv->firmware_version[0])); dwrq->length = priv->version_size+1; return 0; @@ -1967,7 +1967,7 @@ static int ks_wlan_get_firmware_version(struct net_device *dev, struct iw_reques static int ks_wlan_set_detach(struct net_device *dev, struct iw_request_info *info, __u32 *uwrq, char *extra) { - ks_wlan_private *priv = (ks_wlan_private *)dev->priv; + struct ks_wlan_private *priv = (struct ks_wlan_private *)dev->priv; if (priv->sleep_mode == SLP_SLEEP){ return -EPERM; } /* for SLEEP MODE */ @@ -1988,7 +1988,7 @@ static int ks_wlan_set_detach(struct net_device *dev, struct iw_request_info *in static int ks_wlan_get_detach(struct net_device *dev, struct iw_request_info *info, __u32 *uwrq, char *extra) { - ks_wlan_private *priv = (ks_wlan_private *)dev->priv; + struct ks_wlan_private *priv = (struct ks_wlan_private *)dev->priv; if (priv->sleep_mode == SLP_SLEEP){ return -EPERM; } /* for SLEEP MODE */ @@ -2001,7 +2001,7 @@ static int ks_wlan_get_detach(struct net_device *dev, struct iw_request_info *in static int ks_wlan_get_connect(struct net_device *dev, struct iw_request_info *info, __u32 *uwrq, char *extra) { - ks_wlan_private *priv = (ks_wlan_private *)dev->priv; + struct ks_wlan_private *priv = (struct ks_wlan_private *)dev->priv; if (priv->sleep_mode == SLP_SLEEP){ return -EPERM; } /* for SLEEP MODE */ @@ -2015,7 +2015,7 @@ static int ks_wlan_get_connect(struct net_device *dev, struct iw_request_info *i static int ks_wlan_set_preamble(struct net_device *dev, struct iw_request_info *info, __u32 *uwrq, char *extra) { - ks_wlan_private *priv = (ks_wlan_private *)netdev_priv(dev); + struct ks_wlan_private *priv = (struct ks_wlan_private *)netdev_priv(dev); if (priv->sleep_mode == SLP_SLEEP){ return -EPERM; } /* for SLEEP MODE */ @@ -2036,7 +2036,7 @@ static int ks_wlan_set_preamble(struct net_device *dev, struct iw_request_info * static int ks_wlan_get_preamble(struct net_device *dev, struct iw_request_info *info, __u32 *uwrq, char *extra) { - ks_wlan_private *priv = (ks_wlan_private *)netdev_priv(dev); + struct ks_wlan_private *priv = (struct ks_wlan_private *)netdev_priv(dev); if (priv->sleep_mode == SLP_SLEEP){ return -EPERM; } /* for SLEEP MODE */ @@ -2049,7 +2049,7 @@ static int ks_wlan_get_preamble(struct net_device *dev, struct iw_request_info * static int ks_wlan_set_powermgt(struct net_device *dev, struct iw_request_info *info, __u32 *uwrq, char *extra) { - ks_wlan_private *priv = (ks_wlan_private *)netdev_priv(dev); + struct ks_wlan_private *priv = (struct ks_wlan_private *)netdev_priv(dev); if (priv->sleep_mode == SLP_SLEEP){ return -EPERM; } /* for SLEEP MODE */ @@ -2078,7 +2078,7 @@ static int ks_wlan_set_powermgt(struct net_device *dev, struct iw_request_info * static int ks_wlan_get_powermgt(struct net_device *dev, struct iw_request_info *info, __u32 *uwrq, char *extra) { - ks_wlan_private *priv = (ks_wlan_private *)netdev_priv(dev); + struct ks_wlan_private *priv = (struct ks_wlan_private *)netdev_priv(dev); if (priv->sleep_mode == SLP_SLEEP){ return -EPERM; } /* for SLEEP MODE */ @@ -2091,7 +2091,7 @@ static int ks_wlan_get_powermgt(struct net_device *dev, struct iw_request_info * static int ks_wlan_set_scan_type(struct net_device *dev, struct iw_request_info *info, __u32 *uwrq, char *extra) { - ks_wlan_private *priv = (ks_wlan_private *)netdev_priv(dev); + struct ks_wlan_private *priv = (struct ks_wlan_private *)netdev_priv(dev); if (priv->sleep_mode == SLP_SLEEP){ return -EPERM; } /* for SLEEP MODE */ @@ -2110,7 +2110,7 @@ static int ks_wlan_set_scan_type(struct net_device *dev, struct iw_request_info static int ks_wlan_get_scan_type(struct net_device *dev, struct iw_request_info *info, __u32 *uwrq, char *extra) { - ks_wlan_private *priv = (ks_wlan_private *)netdev_priv(dev); + struct ks_wlan_private *priv = (struct ks_wlan_private *)netdev_priv(dev); if (priv->sleep_mode == SLP_SLEEP){ return -EPERM; } /* for SLEEP MODE */ @@ -2123,7 +2123,7 @@ static int ks_wlan_get_scan_type(struct net_device *dev, struct iw_request_info static int ks_wlan_data_write(struct net_device *dev, struct iw_request_info *info, struct iw_point *dwrq, char *extra) { - ks_wlan_private *priv = (ks_wlan_private *)dev->priv; + struct ks_wlan_private *priv = (struct ks_wlan_private *)dev->priv; unsigned char *wbuff = NULL; if (priv->sleep_mode == SLP_SLEEP){ return -EPERM; } /* for SLEEP MODE */ @@ -2144,7 +2144,7 @@ static int ks_wlan_data_write(struct net_device *dev, struct iw_request_info *in static int ks_wlan_data_read(struct net_device *dev, struct iw_request_info *info, struct iw_point *dwrq, char *extra) { - ks_wlan_private *priv = (ks_wlan_private *)dev->priv; + struct ks_wlan_private *priv = (struct ks_wlan_private *)dev->priv; unsigned short read_length; if (priv->sleep_mode == SLP_SLEEP){ return -EPERM; } /* for SLEEP MODE */ @@ -2200,7 +2200,7 @@ static int ks_wlan_data_read(struct net_device *dev, struct iw_request_info *inf static int ks_wlan_get_wep_ascii(struct net_device *dev, struct iw_request_info *info, struct iw_point *dwrq, char *extra) { - ks_wlan_private *priv = (ks_wlan_private *)dev->priv; + struct ks_wlan_private *priv = (struct ks_wlan_private *)dev->priv; int i,j,len=0; char tmp[WEP_ASCII_BUFF_SIZE]; @@ -2242,7 +2242,7 @@ static int ks_wlan_get_wep_ascii(struct net_device *dev, struct iw_request_info static int ks_wlan_set_beacon_lost(struct net_device *dev, struct iw_request_info *info, __u32 *uwrq, char *extra) { - ks_wlan_private *priv = (ks_wlan_private *)netdev_priv(dev); + struct ks_wlan_private *priv = (struct ks_wlan_private *)netdev_priv(dev); if (priv->sleep_mode == SLP_SLEEP){ return -EPERM; } /* for SLEEP MODE */ @@ -2265,7 +2265,7 @@ static int ks_wlan_set_beacon_lost(struct net_device *dev, struct iw_request_inf static int ks_wlan_get_beacon_lost(struct net_device *dev, struct iw_request_info *info, __u32 *uwrq, char *extra) { - ks_wlan_private *priv = (ks_wlan_private *)netdev_priv(dev); + struct ks_wlan_private *priv = (struct ks_wlan_private *)netdev_priv(dev); if (priv->sleep_mode == SLP_SLEEP){ return -EPERM; } /* for SLEEP MODE */ @@ -2278,7 +2278,7 @@ static int ks_wlan_get_beacon_lost(struct net_device *dev, struct iw_request_inf static int ks_wlan_set_phy_type(struct net_device *dev, struct iw_request_info *info, __u32 *uwrq, char *extra) { - ks_wlan_private *priv = (ks_wlan_private *)netdev_priv(dev); + struct ks_wlan_private *priv = (struct ks_wlan_private *)netdev_priv(dev); if (priv->sleep_mode == SLP_SLEEP){ return -EPERM; } /* for SLEEP MODE */ @@ -2300,7 +2300,7 @@ static int ks_wlan_set_phy_type(struct net_device *dev, struct iw_request_info * static int ks_wlan_get_phy_type(struct net_device *dev, struct iw_request_info *info, __u32 *uwrq, char *extra) { - ks_wlan_private *priv = (ks_wlan_private *)netdev_priv(dev); + struct ks_wlan_private *priv = (struct ks_wlan_private *)netdev_priv(dev); if (priv->sleep_mode == SLP_SLEEP){ return -EPERM; } /* for SLEEP MODE */ @@ -2313,7 +2313,7 @@ static int ks_wlan_get_phy_type(struct net_device *dev, struct iw_request_info * static int ks_wlan_set_cts_mode(struct net_device *dev, struct iw_request_info *info, __u32 *uwrq, char *extra) { - ks_wlan_private *priv = (ks_wlan_private *)netdev_priv(dev); + struct ks_wlan_private *priv = (struct ks_wlan_private *)netdev_priv(dev); if (priv->sleep_mode == SLP_SLEEP){ return -EPERM; } /* for SLEEP MODE */ @@ -2337,7 +2337,7 @@ static int ks_wlan_set_cts_mode(struct net_device *dev, struct iw_request_info * static int ks_wlan_get_cts_mode(struct net_device *dev, struct iw_request_info *info, __u32 *uwrq, char *extra) { - ks_wlan_private *priv = (ks_wlan_private *)netdev_priv(dev); + struct ks_wlan_private *priv = (struct ks_wlan_private *)netdev_priv(dev); if (priv->sleep_mode == SLP_SLEEP){ return -EPERM; } /* for SLEEP MODE */ @@ -2351,7 +2351,7 @@ static int ks_wlan_set_sleep_mode(struct net_device *dev, struct iw_request_info *info, __u32 *uwrq, char *extra) { - ks_wlan_private *priv = (ks_wlan_private *)netdev_priv(dev); + struct ks_wlan_private *priv = (struct ks_wlan_private *)netdev_priv(dev); DPRINTK(2,"\n"); @@ -2379,7 +2379,7 @@ static int ks_wlan_get_sleep_mode(struct net_device *dev, struct iw_request_info *info, __u32 *uwrq, char *extra) { - ks_wlan_private *priv = (ks_wlan_private *)netdev_priv(dev); + struct ks_wlan_private *priv = (struct ks_wlan_private *)netdev_priv(dev); DPRINTK(2, "GET_SLEEP_MODE %d\n", priv->sleep_mode); *uwrq = priv->sleep_mode; @@ -2393,7 +2393,7 @@ static int ks_wlan_get_sleep_mode(struct net_device *dev, static int ks_wlan_set_phy_information_timer(struct net_device *dev, struct iw_request_info *info, __u32 *uwrq, char *extra) { - ks_wlan_private *priv = (ks_wlan_private *)dev->priv; + struct ks_wlan_private *priv = (struct ks_wlan_private *)dev->priv; if (priv->sleep_mode == SLP_SLEEP){ return -EPERM; } /* for SLEEP MODE */ @@ -2412,7 +2412,7 @@ static int ks_wlan_set_phy_information_timer(struct net_device *dev, struct iw_r static int ks_wlan_get_phy_information_timer(struct net_device *dev, struct iw_request_info *info, __u32 *uwrq, char *extra) { - ks_wlan_private *priv = (ks_wlan_private *)dev->priv; + struct ks_wlan_private *priv = (struct ks_wlan_private *)dev->priv; if (priv->sleep_mode == SLP_SLEEP){ return -EPERM; } /* for SLEEP MODE */ @@ -2427,7 +2427,7 @@ static int ks_wlan_get_phy_information_timer(struct net_device *dev, struct iw_r static int ks_wlan_set_wps_enable(struct net_device *dev, struct iw_request_info *info, __u32 *uwrq, char *extra) { - ks_wlan_private *priv = (ks_wlan_private *)netdev_priv(dev); + struct ks_wlan_private *priv = (struct ks_wlan_private *)netdev_priv(dev); DPRINTK(2,"\n"); if (priv->sleep_mode == SLP_SLEEP){ return -EPERM; } /* for SLEEP MODE */ @@ -2446,7 +2446,7 @@ static int ks_wlan_set_wps_enable(struct net_device *dev, struct iw_request_info static int ks_wlan_get_wps_enable(struct net_device *dev, struct iw_request_info *info, __u32 *uwrq, char *extra) { - ks_wlan_private *priv = (ks_wlan_private *)netdev_priv(dev); + struct ks_wlan_private *priv = (struct ks_wlan_private *)netdev_priv(dev); DPRINTK(2,"\n"); if (priv->sleep_mode == SLP_SLEEP){ return -EPERM; } /* for SLEEP MODE */ @@ -2464,7 +2464,7 @@ static int ks_wlan_set_wps_probe_req(struct net_device *dev, { uint8_t *p = extra; unsigned char len; - ks_wlan_private *priv = (ks_wlan_private *)netdev_priv(dev); + struct ks_wlan_private *priv = (struct ks_wlan_private *)netdev_priv(dev); DPRINTK(2,"\n"); @@ -2498,7 +2498,7 @@ static int ks_wlan_get_wps_probe_req(struct net_device *dev, struct iw_request_info *info, __u32 *uwrq, char *extra) { - ks_wlan_private *priv = (ks_wlan_private *)dev->priv; + struct ks_wlan_private *priv = (struct ks_wlan_private *)dev->priv; DPRINTK(2,"\n"); if (priv->sleep_mode == SLP_SLEEP){ return -EPERM; } /* for SLEEP MODE */ @@ -2513,7 +2513,7 @@ static int ks_wlan_get_wps_probe_req(struct net_device *dev, static int ks_wlan_set_tx_gain(struct net_device *dev, struct iw_request_info *info, __u32 *uwrq, char *extra) { - ks_wlan_private *priv = (ks_wlan_private *)netdev_priv(dev); + struct ks_wlan_private *priv = (struct ks_wlan_private *)netdev_priv(dev); if (priv->sleep_mode == SLP_SLEEP){ return -EPERM; } /* for SLEEP MODE */ @@ -2537,7 +2537,7 @@ static int ks_wlan_set_tx_gain(struct net_device *dev, struct iw_request_info *i static int ks_wlan_get_tx_gain(struct net_device *dev, struct iw_request_info *info, __u32 *uwrq, char *extra) { - ks_wlan_private *priv = (ks_wlan_private *)netdev_priv(dev); + struct ks_wlan_private *priv = (struct ks_wlan_private *)netdev_priv(dev); if (priv->sleep_mode == SLP_SLEEP){ return -EPERM; } /* for SLEEP MODE */ @@ -2551,7 +2551,7 @@ static int ks_wlan_get_tx_gain(struct net_device *dev, struct iw_request_info *i static int ks_wlan_set_rx_gain(struct net_device *dev, struct iw_request_info *info, __u32 *uwrq, char *extra) { - ks_wlan_private *priv = (ks_wlan_private *)netdev_priv(dev); + struct ks_wlan_private *priv = (struct ks_wlan_private *)netdev_priv(dev); if (priv->sleep_mode == SLP_SLEEP){ return -EPERM; } /* for SLEEP MODE */ @@ -2574,7 +2574,7 @@ static int ks_wlan_set_rx_gain(struct net_device *dev, struct iw_request_info *i static int ks_wlan_get_rx_gain(struct net_device *dev, struct iw_request_info *info, __u32 *uwrq, char *extra) { - ks_wlan_private *priv = (ks_wlan_private *)netdev_priv(dev); + struct ks_wlan_private *priv = (struct ks_wlan_private *)netdev_priv(dev); if (priv->sleep_mode == SLP_SLEEP){ return -EPERM; } /* for SLEEP MODE */ @@ -2588,7 +2588,7 @@ static int ks_wlan_get_rx_gain(struct net_device *dev, struct iw_request_info *i static int ks_wlan_set_region(struct net_device *dev, struct iw_request_info *info, __u32 *uwrq, char *extra) { - ks_wlan_private *priv = (ks_wlan_private *)dev->priv; + struct ks_wlan_private *priv = (struct ks_wlan_private *)dev->priv; if (priv->sleep_mode == SLP_SLEEP){ return -EPERM; } /* for SLEEP MODE */ @@ -2607,7 +2607,7 @@ static int ks_wlan_set_region(struct net_device *dev, struct iw_request_info *in static int ks_wlan_get_eeprom_cksum(struct net_device *dev, struct iw_request_info *info, __u32 *uwrq, char *extra) { - ks_wlan_private *priv = (ks_wlan_private *)netdev_priv(dev); + struct ks_wlan_private *priv = (struct ks_wlan_private *)netdev_priv(dev); *uwrq = priv->eeprom_checksum; return 0; @@ -2732,7 +2732,7 @@ static int ks_wlan_hostt(struct net_device *dev, struct iw_request_info *info, __u32 *uwrq, char *extra) { int i,event; - ks_wlan_private *priv = (ks_wlan_private *)netdev_priv(dev); + struct ks_wlan_private *priv = (struct ks_wlan_private *)netdev_priv(dev); for(i = 63; i >= 0; i--){ event = priv->hostt.buff[(priv->hostt.qtail -1 -i)%SME_EVENT_BUFF_SIZE] ; @@ -2924,7 +2924,7 @@ static int ks_wlan_netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cm static struct net_device_stats *ks_wlan_get_stats(struct net_device *dev) { - ks_wlan_private *priv = netdev_priv(dev); + struct ks_wlan_private *priv = netdev_priv(dev); if (priv->dev_state < DEVICE_STATE_READY) { return NULL; /* not finished initialize */ @@ -2936,7 +2936,7 @@ struct net_device_stats *ks_wlan_get_stats(struct net_device *dev) static int ks_wlan_set_mac_address(struct net_device *dev, void *addr) { - ks_wlan_private *priv = netdev_priv(dev); + struct ks_wlan_private *priv = netdev_priv(dev); struct sockaddr *mac_addr=(struct sockaddr *)addr; if (netif_running(dev)) return -EBUSY; @@ -2955,7 +2955,7 @@ int ks_wlan_set_mac_address(struct net_device *dev, void *addr) static void ks_wlan_tx_timeout(struct net_device *dev) { - ks_wlan_private *priv = netdev_priv(dev); + struct ks_wlan_private *priv = netdev_priv(dev); DPRINTK(1,"head(%d) tail(%d)!!\n",priv->tx_dev.qhead, priv->tx_dev.qtail); if(!netif_queue_stopped(dev)){ @@ -2970,7 +2970,7 @@ void ks_wlan_tx_timeout(struct net_device *dev) static int ks_wlan_start_xmit(struct sk_buff *skb, struct net_device *dev) { - ks_wlan_private *priv = netdev_priv(dev); + struct ks_wlan_private *priv = netdev_priv(dev); int rc = 0; DPRINTK(3,"in_interrupt()=%ld\n",in_interrupt()); @@ -3000,7 +3000,7 @@ int ks_wlan_start_xmit(struct sk_buff *skb, struct net_device *dev) void send_packet_complete(void *arg1, void *arg2) { - ks_wlan_private *priv = (ks_wlan_private *)arg1; + struct ks_wlan_private *priv = (struct ks_wlan_private *)arg1; struct sk_buff *packet = (struct sk_buff *)arg2; DPRINTK(3,"\n"); @@ -3023,7 +3023,7 @@ void send_packet_complete(void *arg1, void *arg2) static void ks_wlan_set_multicast_list(struct net_device *dev) { - ks_wlan_private *priv = netdev_priv(dev); + struct ks_wlan_private *priv = netdev_priv(dev); DPRINTK(4,"\n"); if (priv->dev_state < DEVICE_STATE_READY) { @@ -3037,7 +3037,7 @@ void ks_wlan_set_multicast_list(struct net_device *dev) static int ks_wlan_open(struct net_device *dev) { - ks_wlan_private *priv = netdev_priv(dev); + struct ks_wlan_private *priv = netdev_priv(dev); priv->cur_rx = 0; @@ -3082,7 +3082,7 @@ static const struct net_device_ops ks_wlan_netdev_ops = { int ks_wlan_net_start(struct net_device *dev) { - ks_wlan_private *priv; + struct ks_wlan_private *priv; /* int rc; */ priv = netdev_priv(dev); @@ -3121,7 +3121,7 @@ int ks_wlan_net_start(struct net_device *dev) int ks_wlan_net_stop(struct net_device *dev) { - ks_wlan_private *priv = netdev_priv(dev); + struct ks_wlan_private *priv = netdev_priv(dev); int ret = 0; priv->device_open_status = 0; -- cgit v0.10.2 From 5d7696bcce37010400412bbff53996b242556923 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Tue, 31 May 2016 12:56:27 +0200 Subject: staging: ks7010: indent eap_packet.h Signed-off-by: Wolfram Sang Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/ks7010/eap_packet.h b/drivers/staging/ks7010/eap_packet.h index b664bdd..88384fb 100644 --- a/drivers/staging/ks7010/eap_packet.h +++ b/drivers/staging/ks7010/eap_packet.h @@ -14,13 +14,13 @@ #endif struct ether_hdr { - unsigned char h_dest[ETH_ALEN]; /* destination eth addr */ - unsigned char h_source[ETH_ALEN]; /* source ether addr */ - unsigned char h_dest_snap; - unsigned char h_source_snap; - unsigned char h_command; - unsigned char h_vendor_id[3]; - unsigned short h_proto; /* packet type ID field */ + unsigned char h_dest[ETH_ALEN]; /* destination eth addr */ + unsigned char h_source[ETH_ALEN]; /* source ether addr */ + unsigned char h_dest_snap; + unsigned char h_source_snap; + unsigned char h_command; + unsigned char h_vendor_id[3]; + unsigned short h_proto; /* packet type ID field */ #define ETHER_PROTOCOL_TYPE_EAP 0x888e #define ETHER_PROTOCOL_TYPE_IP 0x0800 #define ETHER_PROTOCOL_TYPE_ARP 0x0806 @@ -37,15 +37,15 @@ struct ieee802_1x_hdr { #define EAPOL_VERSION 2 enum { IEEE802_1X_TYPE_EAP_PACKET = 0, - IEEE802_1X_TYPE_EAPOL_START = 1, - IEEE802_1X_TYPE_EAPOL_LOGOFF = 2, - IEEE802_1X_TYPE_EAPOL_KEY = 3, - IEEE802_1X_TYPE_EAPOL_ENCAPSULATED_ASF_ALERT = 4 + IEEE802_1X_TYPE_EAPOL_START = 1, + IEEE802_1X_TYPE_EAPOL_LOGOFF = 2, + IEEE802_1X_TYPE_EAPOL_KEY = 3, + IEEE802_1X_TYPE_EAPOL_ENCAPSULATED_ASF_ALERT = 4 }; enum { EAPOL_KEY_TYPE_RC4 = 1, EAPOL_KEY_TYPE_RSN = 2, - EAPOL_KEY_TYPE_WPA = 254 }; - + EAPOL_KEY_TYPE_WPA = 254 +}; #define IEEE8021X_REPLAY_COUNTER_LEN 8 #define IEEE8021X_KEY_SIGN_LEN 16 @@ -60,11 +60,11 @@ struct ieee802_1x_eapol_key { /* does not repeat within the life of the keying material used to * encrypt the Key field; 64-bit NTP timestamp MAY be used here */ unsigned char replay_counter[IEEE8021X_REPLAY_COUNTER_LEN]; - unsigned char key_iv[IEEE8021X_KEY_IV_LEN]; /* cryptographically random number */ - unsigned char key_index; /* key flag in the most significant bit: - * 0 = broadcast (default key), - * 1 = unicast (key mapping key); key index is in the - * 7 least significant bits */ + unsigned char key_iv[IEEE8021X_KEY_IV_LEN]; /* cryptographically random number */ + unsigned char key_index; /* key flag in the most significant bit: + * 0 = broadcast (default key), + * 1 = unicast (key mapping key); key index is in the + * 7 least significant bits */ /* HMAC-MD5 message integrity check computed with MS-MPPE-Send-Key as * the key */ unsigned char key_signature[IEEE8021X_KEY_SIGN_LEN]; @@ -77,19 +77,18 @@ struct ieee802_1x_eapol_key { * RC4 key used in encryption = Key-IV + MS-MPPE-Recv-Key */ } __attribute__ ((packed)); - #define WPA_NONCE_LEN 32 #define WPA_REPLAY_COUNTER_LEN 8 struct wpa_eapol_key { unsigned char type; - unsigned short key_info; + unsigned short key_info; unsigned short key_length; unsigned char replay_counter[WPA_REPLAY_COUNTER_LEN]; unsigned char key_nonce[WPA_NONCE_LEN]; unsigned char key_iv[16]; unsigned char key_rsc[8]; - unsigned char key_id[8]; /* Reserved in IEEE 802.11i/RSN */ + unsigned char key_id[8]; /* Reserved in IEEE 802.11i/RSN */ unsigned char key_mic[16]; unsigned short key_data_length; /* followed by key_data_length bytes of key_data */ @@ -98,18 +97,18 @@ struct wpa_eapol_key { #define WPA_KEY_INFO_TYPE_MASK (WBIT(0) | WBIT(1) | WBIT(2)) #define WPA_KEY_INFO_TYPE_HMAC_MD5_RC4 WBIT(0) #define WPA_KEY_INFO_TYPE_HMAC_SHA1_AES WBIT(1) -#define WPA_KEY_INFO_KEY_TYPE WBIT(3) /* 1 = Pairwise, 0 = Group key */ +#define WPA_KEY_INFO_KEY_TYPE WBIT(3) /* 1 = Pairwise, 0 = Group key */ /* bit4..5 is used in WPA, but is reserved in IEEE 802.11i/RSN */ #define WPA_KEY_INFO_KEY_INDEX_MASK (WBIT(4) | WBIT(5)) #define WPA_KEY_INFO_KEY_INDEX_SHIFT 4 -#define WPA_KEY_INFO_INSTALL WBIT(6) /* pairwise */ -#define WPA_KEY_INFO_TXRX WBIT(6) /* group */ +#define WPA_KEY_INFO_INSTALL WBIT(6) /* pairwise */ +#define WPA_KEY_INFO_TXRX WBIT(6) /* group */ #define WPA_KEY_INFO_ACK WBIT(7) #define WPA_KEY_INFO_MIC WBIT(8) #define WPA_KEY_INFO_SECURE WBIT(9) #define WPA_KEY_INFO_ERROR WBIT(10) #define WPA_KEY_INFO_REQUEST WBIT(11) -#define WPA_KEY_INFO_ENCR_KEY_DATA WBIT(12) /* IEEE 802.11i/RSN only */ +#define WPA_KEY_INFO_ENCR_KEY_DATA WBIT(12) /* IEEE 802.11i/RSN only */ #define WPA_CAPABILITY_PREAUTH WBIT(0) -- cgit v0.10.2 From 84e18a94b992d3a3bcc81259dda87657fec3bf58 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Tue, 31 May 2016 12:56:28 +0200 Subject: staging: ks7010: indent ks7010_config.c Signed-off-by: Wolfram Sang Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/ks7010/ks7010_config.c b/drivers/staging/ks7010/ks7010_config.c index 48809bc..4b495cb 100644 --- a/drivers/staging/ks7010/ks7010_config.c +++ b/drivers/staging/ks7010/ks7010_config.c @@ -15,7 +15,8 @@ static int wep_type; #define WEP_KEY_HEX 1 static -void analyze_character_wep_key(struct ks_wlan_parameter *param, int wep_key_index, char *value) +void analyze_character_wep_key(struct ks_wlan_parameter *param, + int wep_key_index, char *value) { int i; unsigned char wep_key[26], key_length; @@ -23,64 +24,69 @@ void analyze_character_wep_key(struct ks_wlan_parameter *param, int wep_key_inde key_length = (wep_on_off == WEP_ON_64BIT) ? 5 : 13; /* 64bit key_length = 5; 128bit key_length = 13; */ - for (i=0; i 3) + if (wep_key_index < 0 || wep_key_index > 3) return; param->wep_key[wep_key_index].size = key_length; - for (i=0; i<(param->wep_key[wep_key_index].size); i++) { + for (i = 0; i < (param->wep_key[wep_key_index].size); i++) { param->wep_key[wep_key_index].val[i] = wep_key[i]; } } static -void analyze_hex_wep_key(struct ks_wlan_parameter *param, int wep_key_index, char *value) +void analyze_hex_wep_key(struct ks_wlan_parameter *param, int wep_key_index, + char *value) { unsigned char wep_end[26], i, j, key_length; key_length = (wep_on_off == WEP_ON_64BIT) ? 10 : 26; /* 64bit key_length = 10; 128bit key_length = 26; */ - for (i=0; i 3) - return ; + if (wep_key_index < 0 || wep_key_index > 3) + return; - param->wep_key[wep_key_index].size = key_length/2; - for (i=0; i<(param->wep_key[wep_key_index].size); i++) { + param->wep_key[wep_key_index].size = key_length / 2; + for (i = 0; i < (param->wep_key[wep_key_index].size); i++) { param->wep_key[wep_key_index].val[i] = wep_end[i]; } @@ -89,62 +95,57 @@ void analyze_hex_wep_key(struct ks_wlan_parameter *param, int wep_key_index, cha static int rate_set_configuration(struct ks_wlan_private *priv, char *value) { - int rc=0; + int rc = 0; priv->reg.tx_rate = TX_RATE_FIXED; priv->reg.rate_set.size = 1; - switch(*value){ - case '1': /* 1M 11M 12M 18M */ - if(*(value+1) == '8'){ + switch (*value) { + case '1': /* 1M 11M 12M 18M */ + if (*(value + 1) == '8') { priv->reg.rate_set.body[0] = TX_RATE_18M; - } - else if(*(value+1) == '2'){ - priv->reg.rate_set.body[0] = TX_RATE_12M|BASIC_RATE; - } - else if(*(value+1) == '1'){ - priv->reg.rate_set.body[0] = TX_RATE_11M|BASIC_RATE; - } - else{ - priv->reg.rate_set.body[0] = TX_RATE_1M|BASIC_RATE; + } else if (*(value + 1) == '2') { + priv->reg.rate_set.body[0] = TX_RATE_12M | BASIC_RATE; + } else if (*(value + 1) == '1') { + priv->reg.rate_set.body[0] = TX_RATE_11M | BASIC_RATE; + } else { + priv->reg.rate_set.body[0] = TX_RATE_1M | BASIC_RATE; } break; - case '2': /* 2M 24M */ - if(*(value+1) == '4'){ - priv->reg.rate_set.body[0] = TX_RATE_24M|BASIC_RATE; - } - else{ - priv->reg.rate_set.body[0] = TX_RATE_2M|BASIC_RATE; + case '2': /* 2M 24M */ + if (*(value + 1) == '4') { + priv->reg.rate_set.body[0] = TX_RATE_24M | BASIC_RATE; + } else { + priv->reg.rate_set.body[0] = TX_RATE_2M | BASIC_RATE; } break; - case '3': /* 36M */ + case '3': /* 36M */ priv->reg.rate_set.body[0] = TX_RATE_36M; break; - case '4': /* 48M */ + case '4': /* 48M */ priv->reg.rate_set.body[0] = TX_RATE_48M; break; - case '5': /* 5.5M 54M */ - if(*(value+1) == '4'){ + case '5': /* 5.5M 54M */ + if (*(value + 1) == '4') { priv->reg.rate_set.body[0] = TX_RATE_54M; - } - else{ - priv->reg.rate_set.body[0] = TX_RATE_5M|BASIC_RATE; + } else { + priv->reg.rate_set.body[0] = TX_RATE_5M | BASIC_RATE; } break; - case '6': /* 6M */ - priv->reg.rate_set.body[0] = TX_RATE_6M|BASIC_RATE; + case '6': /* 6M */ + priv->reg.rate_set.body[0] = TX_RATE_6M | BASIC_RATE; break; - case '9': /* 9M */ + case '9': /* 9M */ priv->reg.rate_set.body[0] = TX_RATE_9M; break; case 'K': priv->reg.rate_set.body[6] = TX_RATE_36M; priv->reg.rate_set.body[5] = TX_RATE_18M; - priv->reg.rate_set.body[4] = TX_RATE_24M|BASIC_RATE; - priv->reg.rate_set.body[3] = TX_RATE_12M|BASIC_RATE; - priv->reg.rate_set.body[2] = TX_RATE_6M|BASIC_RATE; - priv->reg.rate_set.body[1] = TX_RATE_11M|BASIC_RATE; - priv->reg.rate_set.body[0] = TX_RATE_2M|BASIC_RATE; + priv->reg.rate_set.body[4] = TX_RATE_24M | BASIC_RATE; + priv->reg.rate_set.body[3] = TX_RATE_12M | BASIC_RATE; + priv->reg.rate_set.body[2] = TX_RATE_6M | BASIC_RATE; + priv->reg.rate_set.body[1] = TX_RATE_11M | BASIC_RATE; + priv->reg.rate_set.body[0] = TX_RATE_2M | BASIC_RATE; priv->reg.tx_rate = TX_RATE_FULL_AUTO; priv->reg.rate_set.size = 7; break; @@ -154,13 +155,13 @@ int rate_set_configuration(struct ks_wlan_private *priv, char *value) priv->reg.rate_set.body[9] = TX_RATE_36M; priv->reg.rate_set.body[8] = TX_RATE_18M; priv->reg.rate_set.body[7] = TX_RATE_9M; - priv->reg.rate_set.body[6] = TX_RATE_24M|BASIC_RATE; - priv->reg.rate_set.body[5] = TX_RATE_12M|BASIC_RATE; - priv->reg.rate_set.body[4] = TX_RATE_6M|BASIC_RATE; - priv->reg.rate_set.body[3] = TX_RATE_11M|BASIC_RATE; - priv->reg.rate_set.body[2] = TX_RATE_5M|BASIC_RATE; - priv->reg.rate_set.body[1] = TX_RATE_2M|BASIC_RATE; - priv->reg.rate_set.body[0] = TX_RATE_1M|BASIC_RATE; + priv->reg.rate_set.body[6] = TX_RATE_24M | BASIC_RATE; + priv->reg.rate_set.body[5] = TX_RATE_12M | BASIC_RATE; + priv->reg.rate_set.body[4] = TX_RATE_6M | BASIC_RATE; + priv->reg.rate_set.body[3] = TX_RATE_11M | BASIC_RATE; + priv->reg.rate_set.body[2] = TX_RATE_5M | BASIC_RATE; + priv->reg.rate_set.body[1] = TX_RATE_2M | BASIC_RATE; + priv->reg.rate_set.body[0] = TX_RATE_1M | BASIC_RATE; priv->reg.tx_rate = TX_RATE_FULL_AUTO; priv->reg.rate_set.size = 12; break; @@ -176,63 +177,63 @@ int ks_wlan_read_config_file(struct ks_wlan_private *priv) const char *key; const char *val; } cfg_tbl[] = { - {15,"BeaconLostCount", "20"}, /* 0 */ - {7,"Channel", "1"}, /* 1 */ - {17,"FragmentThreshold","2346"}, /* 2 */ - {13,"OperationMode","Infrastructure"}, /* 3 */ - {19,"PowerManagementMode","ACTIVE"}, /* 4 */ - {12,"RTSThreshold","2347"}, /* 5 */ - {4,"SSID","default"}, /* 6 */ - {6,"TxRate","Auto"}, /* 7 */ - {23,"AuthenticationAlgorithm",""}, /* 8 */ - {12,"WepKeyValue1",""}, /* 9 */ - {12,"WepKeyValue2",""}, /* 10 */ - {12,"WepKeyValue3",""}, /* 11 */ - {12,"WepKeyValue4",""}, /* 12 */ - {8,"WepIndex","1"}, /* 13 */ - {7,"WepType","STRING"}, /* 14 */ - {3,"Wep","OFF"}, /* 15 */ - {13,"PREAMBLE_TYPE","LONG"}, /* 16 */ - {8,"ScanType","ACTIVE_SCAN"}, /* 17 */ - {8,"ROM_FILE", ROM_FILE}, /* 18 */ - {7,"PhyType", "BG_MODE"}, /* 19 */ - {7,"CtsMode", "FALSE"}, /* 20 */ - {19,"PhyInformationTimer", "0"}, /* 21 */ - {0,"",""}, + {15, "BeaconLostCount", "20"}, /* 0 */ + {7, "Channel", "1"}, /* 1 */ + {17, "FragmentThreshold", "2346"}, /* 2 */ + {13, "OperationMode", "Infrastructure"}, /* 3 */ + {19, "PowerManagementMode", "ACTIVE"}, /* 4 */ + {12, "RTSThreshold", "2347"}, /* 5 */ + {4, "SSID", "default"}, /* 6 */ + {6, "TxRate", "Auto"}, /* 7 */ + {23, "AuthenticationAlgorithm", ""}, /* 8 */ + {12, "WepKeyValue1", ""}, /* 9 */ + {12, "WepKeyValue2", ""}, /* 10 */ + {12, "WepKeyValue3", ""}, /* 11 */ + {12, "WepKeyValue4", ""}, /* 12 */ + {8, "WepIndex", "1"}, /* 13 */ + {7, "WepType", "STRING"}, /* 14 */ + {3, "Wep", "OFF"}, /* 15 */ + {13, "PREAMBLE_TYPE", "LONG"}, /* 16 */ + {8, "ScanType", "ACTIVE_SCAN"}, /* 17 */ + {8, "ROM_FILE", ROM_FILE}, /* 18 */ + {7, "PhyType", "BG_MODE"}, /* 19 */ + {7, "CtsMode", "FALSE"}, /* 20 */ + {19, "PhyInformationTimer", "0"}, /* 21 */ + {0, "", ""}, }; const struct firmware *fw_entry; struct device *dev = NULL; - char cfg_file[]=CFG_FILE; + char cfg_file[] = CFG_FILE; char *cur_p, *end_p; char wk_buff[256], *wk_p; /* Initialize Variable */ priv->reg.operation_mode = MODE_INFRASTRUCTURE; /* Infrastructure */ - priv->reg.channel = 10; /* 10 */ - memset(priv->reg.bssid, 0x0, ETH_ALEN); /* BSSID */ - priv->reg.ssid.body[0] = '\0'; /* SSID */ - priv->reg.ssid.size = 0; /* SSID size */ - priv->reg.tx_rate = TX_RATE_AUTO; /* TxRate Fully Auto */ - priv->reg.preamble = LONG_PREAMBLE; /* Preamble = LONG */ - priv->reg.powermgt = POWMGT_ACTIVE_MODE; /* POWMGT_ACTIVE_MODE */ - priv->reg.scan_type = ACTIVE_SCAN; /* Active */ - priv->reg.beacon_lost_count = 20; /* Beacon Lost Count */ - priv->reg.rts = 2347UL; /* RTS Threashold */ - priv->reg.fragment = 2346UL; /* Fragmentation Threashold */ + priv->reg.channel = 10; /* 10 */ + memset(priv->reg.bssid, 0x0, ETH_ALEN); /* BSSID */ + priv->reg.ssid.body[0] = '\0'; /* SSID */ + priv->reg.ssid.size = 0; /* SSID size */ + priv->reg.tx_rate = TX_RATE_AUTO; /* TxRate Fully Auto */ + priv->reg.preamble = LONG_PREAMBLE; /* Preamble = LONG */ + priv->reg.powermgt = POWMGT_ACTIVE_MODE; /* POWMGT_ACTIVE_MODE */ + priv->reg.scan_type = ACTIVE_SCAN; /* Active */ + priv->reg.beacon_lost_count = 20; /* Beacon Lost Count */ + priv->reg.rts = 2347UL; /* RTS Threashold */ + priv->reg.fragment = 2346UL; /* Fragmentation Threashold */ strcpy(&priv->reg.rom_file[0], ROM_FILE); priv->skb = NULL; - priv->reg.authenticate_type = AUTH_TYPE_OPEN_SYSTEM; /* AuthenticationAlgorithm */ + priv->reg.authenticate_type = AUTH_TYPE_OPEN_SYSTEM; /* AuthenticationAlgorithm */ - priv->reg.privacy_invoked = 0x00; /* WEP */ - priv->reg.wep_index=0; - memset(&priv->reg.wep_key[0],0,sizeof(priv->reg.wep_key[0])); - memset(&priv->reg.wep_key[1],0,sizeof(priv->reg.wep_key[0])); - memset(&priv->reg.wep_key[2],0,sizeof(priv->reg.wep_key[0])); - memset(&priv->reg.wep_key[3],0,sizeof(priv->reg.wep_key[0])); + priv->reg.privacy_invoked = 0x00; /* WEP */ + priv->reg.wep_index = 0; + memset(&priv->reg.wep_key[0], 0, sizeof(priv->reg.wep_key[0])); + memset(&priv->reg.wep_key[1], 0, sizeof(priv->reg.wep_key[0])); + memset(&priv->reg.wep_key[2], 0, sizeof(priv->reg.wep_key[0])); + memset(&priv->reg.wep_key[3], 0, sizeof(priv->reg.wep_key[0])); priv->reg.phy_type = D_11BG_COMPATIBLE_MODE; priv->reg.cts_mode = CTS_MODE_FALSE; @@ -242,13 +243,13 @@ int ks_wlan_read_config_file(struct ks_wlan_private *priv) priv->reg.rate_set.body[9] = TX_RATE_36M; priv->reg.rate_set.body[8] = TX_RATE_18M; priv->reg.rate_set.body[7] = TX_RATE_9M; - priv->reg.rate_set.body[6] = TX_RATE_24M|BASIC_RATE; - priv->reg.rate_set.body[5] = TX_RATE_12M|BASIC_RATE; - priv->reg.rate_set.body[4] = TX_RATE_6M|BASIC_RATE; - priv->reg.rate_set.body[3] = TX_RATE_11M|BASIC_RATE; - priv->reg.rate_set.body[2] = TX_RATE_5M|BASIC_RATE; - priv->reg.rate_set.body[1] = TX_RATE_2M|BASIC_RATE; - priv->reg.rate_set.body[0] = TX_RATE_1M|BASIC_RATE; + priv->reg.rate_set.body[6] = TX_RATE_24M | BASIC_RATE; + priv->reg.rate_set.body[5] = TX_RATE_12M | BASIC_RATE; + priv->reg.rate_set.body[4] = TX_RATE_6M | BASIC_RATE; + priv->reg.rate_set.body[3] = TX_RATE_11M | BASIC_RATE; + priv->reg.rate_set.body[2] = TX_RATE_5M | BASIC_RATE; + priv->reg.rate_set.body[1] = TX_RATE_2M | BASIC_RATE; + priv->reg.rate_set.body[0] = TX_RATE_1M | BASIC_RATE; priv->reg.tx_rate = TX_RATE_FULL_AUTO; priv->reg.rate_set.size = 12; @@ -257,7 +258,8 @@ int ks_wlan_read_config_file(struct ks_wlan_private *priv) if (request_firmware_direct(&fw_entry, cfg_file, dev)) return 0; - DPRINTK(4, "success request_firmware() file=%s size=%zu\n", cfg_file, fw_entry->size); + DPRINTK(4, "success request_firmware() file=%s size=%zu\n", cfg_file, + fw_entry->size); cur_p = fw_entry->data; end_p = cur_p + fw_entry->size; *end_p = '\0'; @@ -266,7 +268,7 @@ int ks_wlan_read_config_file(struct ks_wlan_private *priv) int i, j, len; len = end_p - cur_p; - for (i=0; cfg_tbl[i].key_len != 0; i++) { + for (i = 0; cfg_tbl[i].key_len != 0; i++) { if (*cur_p == '#') { break; } @@ -298,58 +300,64 @@ int ks_wlan_read_config_file(struct ks_wlan_private *priv) } cur_p++; - for (j=0,wk_p=cur_p; *wk_p != '\n' && wk_p < end_p; j++,wk_p++) { + for (j = 0, wk_p = cur_p; *wk_p != '\n' && wk_p < end_p; + j++, wk_p++) { wk_buff[j] = *wk_p; } wk_buff[j] = '\0'; cur_p = wk_p; - DPRINTK(4,"%s=%s\n",cfg_tbl[i].key, wk_buff); + DPRINTK(4, "%s=%s\n", cfg_tbl[i].key, wk_buff); wk_p = wk_buff; switch (i) { - case 0: /* "BeaconLostCount", "10" */ - priv->reg.beacon_lost_count = simple_strtol(wk_buff, NULL, 10); + case 0: /* "BeaconLostCount", "10" */ + priv->reg.beacon_lost_count = + simple_strtol(wk_buff, NULL, 10); break; - case 1: /* "Channel", "1" */ - priv->reg.channel = simple_strtol(wk_buff, NULL, 10); + case 1: /* "Channel", "1" */ + priv->reg.channel = + simple_strtol(wk_buff, NULL, 10); break; - case 2: /* "FragmentThreshold","2346" */ + case 2: /* "FragmentThreshold","2346" */ j = simple_strtol(wk_buff, NULL, 10); priv->reg.fragment = (unsigned long)j; break; - case 3: /* "OperationMode","Infrastructure" */ + case 3: /* "OperationMode","Infrastructure" */ switch (*wk_buff) { case 'P': - priv->reg.operation_mode = MODE_PSEUDO_ADHOC; + priv->reg.operation_mode = + MODE_PSEUDO_ADHOC; break; case 'I': - priv->reg.operation_mode = MODE_INFRASTRUCTURE; + priv->reg.operation_mode = + MODE_INFRASTRUCTURE; break; case '8': priv->reg.operation_mode = MODE_ADHOC; break; default: - priv->reg.operation_mode = MODE_INFRASTRUCTURE; + priv->reg.operation_mode = + MODE_INFRASTRUCTURE; } break; - case 4: /* "PowerManagementMode","POWER_ACTIVE" */ + case 4: /* "PowerManagementMode","POWER_ACTIVE" */ if (!strncmp(wk_buff, "SAVE1", 5)) { priv->reg.powermgt = POWMGT_SAVE1_MODE; - } else if (!strncmp(wk_buff, "SAVE2", 5)){ + } else if (!strncmp(wk_buff, "SAVE2", 5)) { priv->reg.powermgt = POWMGT_SAVE2_MODE; } else { priv->reg.powermgt = POWMGT_ACTIVE_MODE; } break; - case 5: /* "RTSThreshold","2347" */ + case 5: /* "RTSThreshold","2347" */ j = simple_strtol(wk_buff, NULL, 10); priv->reg.rts = (unsigned long)j; break; - case 6: /* "SSID","" */ + case 6: /* "SSID","" */ if (*wk_p != '"') break; wk_p++; - for (j=0; *wk_p != '"'; j++) { + for (j = 0; *wk_p != '"'; j++) { if (wk_p == '\0') { break; } @@ -359,45 +367,51 @@ int ks_wlan_read_config_file(struct ks_wlan_private *priv) priv->reg.ssid.size = j; wk_p++; break; - case 7: /* "TxRate","Auto" */ + case 7: /* "TxRate","Auto" */ rate_set_configuration(priv, wk_p); break; - case 8: /* "AuthenticationAlgorithm","OPEN_SYSTEM" */ + case 8: /* "AuthenticationAlgorithm","OPEN_SYSTEM" */ switch (*wk_p) { - case 'O': /* Authenticate System : Open System */ - priv->reg.authenticate_type = AUTH_TYPE_OPEN_SYSTEM; + case 'O': /* Authenticate System : Open System */ + priv->reg.authenticate_type = + AUTH_TYPE_OPEN_SYSTEM; break; - case 'S': /* Authenticate System : Shared Key */ - priv->reg.authenticate_type = AUTH_TYPE_SHARED_KEY; + case 'S': /* Authenticate System : Shared Key */ + priv->reg.authenticate_type = + AUTH_TYPE_SHARED_KEY; break; } break; - case 9: /* "WepKeyValue1","" */ - case 10: /* "WepKeyValue2","" */ - case 11: /* "WepKeyValue3","" */ - case 12: /* "WepKeyValue4","" */ + case 9: /* "WepKeyValue1","" */ + case 10: /* "WepKeyValue2","" */ + case 11: /* "WepKeyValue3","" */ + case 12: /* "WepKeyValue4","" */ if (wep_on_off != WEP_OFF) { switch (wep_type) { case WEP_KEY_CHARACTER: - analyze_character_wep_key(&priv->reg, (i-9), wk_p); + analyze_character_wep_key + (&priv->reg, (i - 9), wk_p); break; case WEP_KEY_HEX: - analyze_hex_wep_key(&priv->reg, (i-9), wk_p); + analyze_hex_wep_key(&priv->reg, + (i - 9), + wk_p); break; } } break; - case 13: /* "WepIndex","1"->0 (So, Zero Origin) */ - priv->reg.wep_index = simple_strtol(wk_buff, NULL, 10) - 1; + case 13: /* "WepIndex","1"->0 (So, Zero Origin) */ + priv->reg.wep_index = + simple_strtol(wk_buff, NULL, 10) - 1; break; - case 14: /* "WepType","STRING" */ + case 14: /* "WepType","STRING" */ if (!strncmp(wk_buff, "STRING", 6)) { wep_type = WEP_KEY_CHARACTER; } else { wep_type = WEP_KEY_HEX; } break; - case 15: /* "Wep","OFF" */ + case 15: /* "Wep","OFF" */ if (!strncmp(wk_buff, "OFF", 3)) { priv->reg.privacy_invoked = 0x00; wep_on_off = WEP_OFF; @@ -405,30 +419,30 @@ int ks_wlan_read_config_file(struct ks_wlan_private *priv) priv->reg.privacy_invoked = 0x01; if (*wk_buff == '6') { /* 64bit */ wep_on_off = WEP_ON_64BIT; - } else { /* 128bit */ + } else { /* 128bit */ wep_on_off = WEP_ON_128BIT; } } break; - case 16: /* "PREAMBLE_TYPE","LONG" */ + case 16: /* "PREAMBLE_TYPE","LONG" */ if (!strncmp(wk_buff, "SHORT", 5)) { priv->reg.preamble = SHORT_PREAMBLE; - } else { /* "LONG" */ + } else { /* "LONG" */ priv->reg.preamble = LONG_PREAMBLE; } break; - case 17: /* "ScanType","ACTIVE_SCAN" */ + case 17: /* "ScanType","ACTIVE_SCAN" */ if (!strncmp(wk_buff, "PASSIVE_SCAN", 12)) { priv->reg.scan_type = PASSIVE_SCAN; - } else { /* "ACTIVE_SCAN" */ + } else { /* "ACTIVE_SCAN" */ priv->reg.scan_type = ACTIVE_SCAN; } break; - case 18: // "ROM_FILE",ROMFILE + case 18: // "ROM_FILE",ROMFILE if (*wk_p != '"') break; wk_p++; - for (j=0; *wk_p != '"'; j++) { + for (j = 0; *wk_p != '"'; j++) { if (wk_p == '\0') { break; } @@ -437,25 +451,26 @@ int ks_wlan_read_config_file(struct ks_wlan_private *priv) priv->reg.rom_file[j] = '\0'; wk_p++; break; - case 19: /*"PhyType", "BG_MODE" */ + case 19: /*"PhyType", "BG_MODE" */ if (!strncmp(wk_buff, "B_MODE", 6)) { priv->reg.phy_type = D_11B_ONLY_MODE; } else if (!strncmp(wk_buff, "G_MODE", 6)) { priv->reg.phy_type = D_11G_ONLY_MODE; } else { - priv->reg.phy_type = D_11BG_COMPATIBLE_MODE; + priv->reg.phy_type = + D_11BG_COMPATIBLE_MODE; } break; - case 20: /* "CtsMode", "FALSE" */ + case 20: /* "CtsMode", "FALSE" */ if (!strncmp(wk_buff, "TRUE", 4)) { priv->reg.cts_mode = CTS_MODE_TRUE; } else { priv->reg.cts_mode = CTS_MODE_FALSE; } break; - case 21: /* "PhyInformationTimer", "0" */ + case 21: /* "PhyInformationTimer", "0" */ j = simple_strtol(wk_buff, NULL, 10); - priv->reg.phy_info_timer = (uint16_t)j; + priv->reg.phy_info_timer = (uint16_t) j; break; default: break; @@ -469,17 +484,17 @@ int ks_wlan_read_config_file(struct ks_wlan_private *priv) } release_firmware(fw_entry); - DPRINTK(3,"\n operation_mode = %d\n channel = %d\n ssid = %s\n tx_rate = %d\n \ + DPRINTK(3, + "\n operation_mode = %d\n channel = %d\n ssid = %s\n tx_rate = %d\n \ preamble = %d\n powermgt = %d\n scan_type = %d\n beacon_lost_count = %d\n rts = %d\n \ fragment = %d\n privacy_invoked = %d\n wep_type = %d\n wep_on_off = %d\n wep_index = %d\n romfile = %s\n", - priv->reg.operation_mode,priv->reg.channel,&priv->reg.ssid.body[0],priv->reg.tx_rate, - priv->reg.preamble,priv->reg.powermgt,priv->reg.scan_type,priv->reg.beacon_lost_count, - priv->reg.rts,priv->reg.fragment,priv->reg.privacy_invoked,wep_type,wep_on_off,priv->reg.wep_index, - &priv->reg.rom_file[0] - ); - DPRINTK(3,"\n phy_type = %d\n cts_mode = %d\n tx_rate = %d\n phy_info_timer = %d\n", - priv->reg.phy_type,priv->reg.cts_mode,priv->reg.tx_rate,priv->reg.phy_info_timer ); - - return(0); + priv->reg.operation_mode, priv->reg.channel, &priv->reg.ssid.body[0], priv->reg.tx_rate, priv->reg.preamble, priv->reg.powermgt, priv->reg.scan_type, priv->reg.beacon_lost_count, priv->reg.rts, priv->reg.fragment, priv->reg.privacy_invoked, wep_type, wep_on_off, + priv->reg.wep_index, &priv->reg.rom_file[0] + ); + DPRINTK(3, + "\n phy_type = %d\n cts_mode = %d\n tx_rate = %d\n phy_info_timer = %d\n", + priv->reg.phy_type, priv->reg.cts_mode, priv->reg.tx_rate, + priv->reg.phy_info_timer); + + return (0); } - -- cgit v0.10.2 From 4a3e75483dfadd5164f482bc1af9c4a7e3ee67b0 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Tue, 31 May 2016 12:56:29 +0200 Subject: staging: ks7010: indent ks7010_sdio.h Signed-off-by: Wolfram Sang Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/ks7010/ks7010_sdio.h b/drivers/staging/ks7010/ks7010_sdio.h index 1d16673..aea3727 100644 --- a/drivers/staging/ks7010/ks7010_sdio.h +++ b/drivers/staging/ks7010/ks7010_sdio.h @@ -21,7 +21,7 @@ #define DEVICE_ALIGNMENT 32 /* SDIO KeyStream vendor and device */ -#define SDIO_VENDOR_ID_KS_CODE_A 0x005b +#define SDIO_VENDOR_ID_KS_CODE_A 0x005b #define SDIO_VENDOR_ID_KS_CODE_B 0x0023 #define SDIO_DEVICE_ID_KS_7010 0x7910 @@ -48,8 +48,8 @@ * for network packet (less than 2048 bytes data) */ #define WSTATUS_RSIZE 0x000014 -#define WSTATUS_MASK 0x80 /* Write Status Register value */ -#define RSIZE_MASK 0x7F /* Read Data Size Register value [10:4] */ +#define WSTATUS_MASK 0x80 /* Write Status Register value */ +#define RSIZE_MASK 0x7F /* Read Data Size Register value [10:4] */ /* ARM to SD interrupt Enable */ #define INT_ENABLE 0x000020 @@ -88,52 +88,48 @@ #define KS7010_IRAM_ADDRESS 0x06000000 - /* * struct define */ struct hw_info_t { - struct ks_sdio_card *sdio_card; + struct ks_sdio_card *sdio_card; struct completion ks7010_sdio_wait; struct workqueue_struct *ks7010sdio_wq; struct delayed_work rw_wq; - unsigned char *read_buf; + unsigned char *read_buf; struct tasklet_struct rx_bh_task; }; struct ks_sdio_packet { - struct ks_sdio_packet *next; - u16 nb; - u8 buffer[0] __attribute__((aligned(4))); + struct ks_sdio_packet *next; + u16 nb; + u8 buffer[0] __attribute__ ((aligned(4))); }; - struct ks_sdio_card { - struct sdio_func *func; + struct sdio_func *func; struct ks_wlan_private *priv; - int model; - const char *firmware; - spinlock_t lock; + int model; + const char *firmware; + spinlock_t lock; }; - - /* Tx Device struct */ -#define TX_DEVICE_BUFF_SIZE 1024 +#define TX_DEVICE_BUFF_SIZE 1024 struct tx_device_buffer { - unsigned char *sendp; /* pointer of send req data */ - unsigned int size; - void (*complete_handler)(void *arg1, void *arg2); - void *arg1; - void *arg2; + unsigned char *sendp; /* pointer of send req data */ + unsigned int size; + void (*complete_handler) (void *arg1, void *arg2); + void *arg1; + void *arg2; }; -struct tx_device{ - struct tx_device_buffer tx_dev_buff[TX_DEVICE_BUFF_SIZE]; - unsigned int qhead; /* tx buffer queue first pointer */ - unsigned int qtail; /* tx buffer queue last pointer */ - spinlock_t tx_dev_lock; +struct tx_device { + struct tx_device_buffer tx_dev_buff[TX_DEVICE_BUFF_SIZE]; + unsigned int qhead; /* tx buffer queue first pointer */ + unsigned int qtail; /* tx buffer queue last pointer */ + spinlock_t tx_dev_lock; }; /* Rx Device struct */ @@ -141,15 +137,15 @@ struct tx_device{ #define RX_DEVICE_BUFF_SIZE 32 struct rx_device_buffer { - unsigned char data[RX_DATA_SIZE]; - unsigned int size; + unsigned char data[RX_DATA_SIZE]; + unsigned int size; }; -struct rx_device{ - struct rx_device_buffer rx_dev_buff[RX_DEVICE_BUFF_SIZE]; - unsigned int qhead; /* rx buffer queue first pointer */ - unsigned int qtail; /* rx buffer queue last pointer */ - spinlock_t rx_dev_lock; +struct rx_device { + struct rx_device_buffer rx_dev_buff[RX_DEVICE_BUFF_SIZE]; + unsigned int qhead; /* rx buffer queue first pointer */ + unsigned int qtail; /* rx buffer queue last pointer */ + spinlock_t rx_dev_lock; }; #define ROM_FILE "ks7010sd.rom" #define CFG_FILE "ks79xx.cfg" -- cgit v0.10.2 From 20c4f9c52e619a12e0a63eea708f0225b248e788 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Tue, 31 May 2016 12:56:30 +0200 Subject: staging: ks7010: indent ks_hostif.c Signed-off-by: Wolfram Sang Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/ks7010/ks_hostif.c b/drivers/staging/ks7010/ks_hostif.c index 497b8aa..f2a65c0 100644 --- a/drivers/staging/ks7010/ks_hostif.c +++ b/drivers/staging/ks7010/ks_hostif.c @@ -23,9 +23,10 @@ /* Include Wireless Extension definition and check version */ #include /* New driver API */ -extern int ks_wlan_hw_tx(struct ks_wlan_private *priv, void *p, unsigned long size, - void (*complete_handler)(void *arg1, void *arg2), - void *arg1, void *arg2 ); +extern int ks_wlan_hw_tx(struct ks_wlan_private *priv, void *p, + unsigned long size, + void (*complete_handler) (void *arg1, void *arg2), + void *arg1, void *arg2); extern void send_packet_complete(void *, void *); extern void ks_wlan_hw_wakeup_request(struct ks_wlan_private *priv); @@ -55,7 +56,7 @@ static inline u16 get_WORD(struct ks_wlan_private *priv) { u16 data; - data = (get_BYTE(priv) & 0xff); + data = (get_BYTE(priv) & 0xff); data |= ((get_BYTE(priv) << 8) & 0xff00); return data; } @@ -64,7 +65,7 @@ static inline u32 get_DWORD(struct ks_wlan_private *priv) { u32 data; - data = (get_BYTE(priv) & 0xff); + data = (get_BYTE(priv) & 0xff); data |= ((get_BYTE(priv) << 8) & 0x0000ff00); data |= ((get_BYTE(priv) << 16) & 0x00ff0000); data |= ((get_BYTE(priv) << 24) & 0xff000000); @@ -73,24 +74,24 @@ inline u32 get_DWORD(struct ks_wlan_private *priv) void ks_wlan_hw_wakeup_task(struct work_struct *work) { - struct ks_wlan_private *priv = container_of(work, struct ks_wlan_private, ks_wlan_wakeup_task); + struct ks_wlan_private *priv = + container_of(work, struct ks_wlan_private, ks_wlan_wakeup_task); int ps_status = atomic_read(&priv->psstatus.status); - if(ps_status==PS_SNOOZE){ + if (ps_status == PS_SNOOZE) { ks_wlan_hw_wakeup_request(priv); - if(!wait_for_completion_interruptible_timeout(&priv->psstatus.wakeup_wait,HZ/50)){ /* 20ms timeout */ - DPRINTK(1,"wake up timeout !!!\n"); + if (!wait_for_completion_interruptible_timeout(&priv->psstatus.wakeup_wait, HZ / 50)) { /* 20ms timeout */ + DPRINTK(1, "wake up timeout !!!\n"); schedule_work(&priv->ks_wlan_wakeup_task); return; } - } - else{ - DPRINTK(1,"ps_status=%d\n",ps_status); + } else { + DPRINTK(1, "ps_status=%d\n", ps_status); } /* power save */ - if(atomic_read(&priv->sme_task.count) > 0){ - DPRINTK(4,"sme task enable.\n"); + if (atomic_read(&priv->sme_task.count) > 0) { + DPRINTK(4, "sme task enable.\n"); tasklet_enable(&priv->sme_task); } } @@ -98,14 +99,13 @@ void ks_wlan_hw_wakeup_task(struct work_struct *work) static int ks_wlan_do_power_save(struct ks_wlan_private *priv) { - int rc=0; + int rc = 0; - DPRINTK(4,"psstatus.status=%d\n",atomic_read(&priv->psstatus.status)); + DPRINTK(4, "psstatus.status=%d\n", atomic_read(&priv->psstatus.status)); - if((priv->connect_status & CONNECT_STATUS_MASK) == CONNECT_STATUS){ + if ((priv->connect_status & CONNECT_STATUS_MASK) == CONNECT_STATUS) { hostif_sme_enqueue(priv, SME_POW_MNGMT_REQUEST); - } - else{ + } else { priv->dev_state = DEVICE_STATE_READY; } return rc; @@ -116,26 +116,28 @@ int get_current_ap(struct ks_wlan_private *priv, struct link_ap_info_t *ap_info) { struct local_ap_t *ap; union iwreq_data wrqu; - struct net_device *netdev=priv->net_dev; - int rc=0; + struct net_device *netdev = priv->net_dev; + int rc = 0; - DPRINTK(3,"\n"); + DPRINTK(3, "\n"); ap = &(priv->current_ap); - if((priv->connect_status & CONNECT_STATUS_MASK)== DISCONNECT_STATUS){ - memset(ap,0,sizeof(struct local_ap_t)); + if ((priv->connect_status & CONNECT_STATUS_MASK) == DISCONNECT_STATUS) { + memset(ap, 0, sizeof(struct local_ap_t)); return 1; } /* bssid */ - memcpy(&(ap->bssid[0]),&(ap_info->bssid[0]),ETH_ALEN); + memcpy(&(ap->bssid[0]), &(ap_info->bssid[0]), ETH_ALEN); /* essid */ - memcpy(&(ap->ssid.body[0]),&(priv->reg.ssid.body[0]),priv->reg.ssid.size); + memcpy(&(ap->ssid.body[0]), &(priv->reg.ssid.body[0]), + priv->reg.ssid.size); ap->ssid.size = priv->reg.ssid.size; /* rate_set */ - memcpy(&(ap->rate_set.body[0]),&(ap_info->rate_set.body[0]),ap_info->rate_set.size); + memcpy(&(ap->rate_set.body[0]), &(ap_info->rate_set.body[0]), + ap_info->rate_set.size); ap->rate_set.size = ap_info->rate_set.size; - if(ap_info->ext_rate_set.size){ + if (ap_info->ext_rate_set.size) { /* rate_set */ memcpy(&(ap->rate_set.body[ap->rate_set.size]), &(ap_info->ext_rate_set.body[0]), @@ -153,29 +155,31 @@ int get_current_ap(struct ks_wlan_private *priv, struct link_ap_info_t *ap_info) /* capability */ ap->capability = ap_info->capability; /* rsn */ - if((ap_info->rsn_mode & RSN_MODE_WPA2) && (priv->wpa.version == IW_AUTH_WPA_VERSION_WPA2)){ + if ((ap_info->rsn_mode & RSN_MODE_WPA2) + && (priv->wpa.version == IW_AUTH_WPA_VERSION_WPA2)) { ap->rsn_ie.id = 0x30; - if(ap_info->rsn.size <= RSN_IE_BODY_MAX){ + if (ap_info->rsn.size <= RSN_IE_BODY_MAX) { ap->rsn_ie.size = ap_info->rsn.size; - memcpy(&(ap->rsn_ie.body[0]),&(ap_info->rsn.body[0]),ap_info->rsn.size); - } - else{ + memcpy(&(ap->rsn_ie.body[0]), &(ap_info->rsn.body[0]), + ap_info->rsn.size); + } else { ap->rsn_ie.size = RSN_IE_BODY_MAX; - memcpy(&(ap->rsn_ie.body[0]),&(ap_info->rsn.body[0]),RSN_IE_BODY_MAX); + memcpy(&(ap->rsn_ie.body[0]), &(ap_info->rsn.body[0]), + RSN_IE_BODY_MAX); } - } - else if((ap_info->rsn_mode & RSN_MODE_WPA) && (priv->wpa.version == IW_AUTH_WPA_VERSION_WPA)){ + } else if ((ap_info->rsn_mode & RSN_MODE_WPA) + && (priv->wpa.version == IW_AUTH_WPA_VERSION_WPA)) { ap->wpa_ie.id = 0xdd; - if(ap_info->rsn.size <= RSN_IE_BODY_MAX){ + if (ap_info->rsn.size <= RSN_IE_BODY_MAX) { ap->wpa_ie.size = ap_info->rsn.size; - memcpy(&(ap->wpa_ie.body[0]),&(ap_info->rsn.body[0]),ap_info->rsn.size); - } - else{ + memcpy(&(ap->wpa_ie.body[0]), &(ap_info->rsn.body[0]), + ap_info->rsn.size); + } else { ap->wpa_ie.size = RSN_IE_BODY_MAX; - memcpy(&(ap->wpa_ie.body[0]),&(ap_info->rsn.body[0]),RSN_IE_BODY_MAX); + memcpy(&(ap->wpa_ie.body[0]), &(ap_info->rsn.body[0]), + RSN_IE_BODY_MAX); } - } - else{ + } else { ap->rsn_ie.id = 0; ap->rsn_ie.size = 0; ap->wpa_ie.id = 0; @@ -185,45 +189,44 @@ int get_current_ap(struct ks_wlan_private *priv, struct link_ap_info_t *ap_info) wrqu.data.length = 0; wrqu.data.flags = 0; wrqu.ap_addr.sa_family = ARPHRD_ETHER; - if((priv->connect_status & CONNECT_STATUS_MASK)==CONNECT_STATUS){ + if ((priv->connect_status & CONNECT_STATUS_MASK) == CONNECT_STATUS) { memcpy(wrqu.ap_addr.sa_data, &(priv->current_ap.bssid[0]), ETH_ALEN); - DPRINTK(3,"IWEVENT: connect bssid=%02x:%02x:%02x:%02x:%02x:%02x\n", - (unsigned char)wrqu.ap_addr.sa_data[0],(unsigned char)wrqu.ap_addr.sa_data[1], - (unsigned char)wrqu.ap_addr.sa_data[2],(unsigned char)wrqu.ap_addr.sa_data[3], - (unsigned char)wrqu.ap_addr.sa_data[4],(unsigned char)wrqu.ap_addr.sa_data[5]); + DPRINTK(3, + "IWEVENT: connect bssid=%02x:%02x:%02x:%02x:%02x:%02x\n", + (unsigned char)wrqu.ap_addr.sa_data[0], + (unsigned char)wrqu.ap_addr.sa_data[1], + (unsigned char)wrqu.ap_addr.sa_data[2], + (unsigned char)wrqu.ap_addr.sa_data[3], + (unsigned char)wrqu.ap_addr.sa_data[4], + (unsigned char)wrqu.ap_addr.sa_data[5]); wireless_send_event(netdev, SIOCGIWAP, &wrqu, NULL); } - DPRINTK(4,"\n Link AP\n"); - DPRINTK(4," bssid=%02X:%02X:%02X:%02X:%02X:%02X\n \ + DPRINTK(4, "\n Link AP\n"); + DPRINTK(4, " bssid=%02X:%02X:%02X:%02X:%02X:%02X\n \ essid=%s\n rate_set=%02X,%02X,%02X,%02X,%02X,%02X,%02X,%02X\n channel=%d\n \ - rssi=%d\n sq=%d\n capability=%04X\n", - ap->bssid[0],ap->bssid[1],ap->bssid[2],ap->bssid[3],ap->bssid[4], - ap->bssid[5],&(ap->ssid.body[0]),ap->rate_set.body[0],ap->rate_set.body[1], - ap->rate_set.body[2],ap->rate_set.body[3],ap->rate_set.body[4], - ap->rate_set.body[5],ap->rate_set.body[6],ap->rate_set.body[7], - ap->channel,ap->rssi,ap->sq,ap->capability); - DPRINTK(4,"\n Link AP\n rsn.mode=%d\n rsn.size=%d\n", - ap_info->rsn_mode,ap_info->rsn.size); - DPRINTK(4,"\n ext_rate_set_size=%d\n rate_set_size=%d\n", - ap_info->ext_rate_set.size,ap_info->rate_set.size); - + rssi=%d\n sq=%d\n capability=%04X\n", ap->bssid[0], ap->bssid[1], ap->bssid[2], ap->bssid[3], ap->bssid[4], ap->bssid[5], &(ap->ssid.body[0]), ap->rate_set.body[0], ap->rate_set.body[1], ap->rate_set.body[2], ap->rate_set.body[3], ap->rate_set.body[4], ap->rate_set.body[5], ap->rate_set.body[6], ap->rate_set.body[7], ap->channel, ap->rssi, ap->sq, ap->capability); + DPRINTK(4, "\n Link AP\n rsn.mode=%d\n rsn.size=%d\n", + ap_info->rsn_mode, ap_info->rsn.size); + DPRINTK(4, "\n ext_rate_set_size=%d\n rate_set_size=%d\n", + ap_info->ext_rate_set.size, ap_info->rate_set.size); return rc; } static -int get_ap_information(struct ks_wlan_private *priv, struct ap_info_t *ap_info, struct local_ap_t *ap) +int get_ap_information(struct ks_wlan_private *priv, struct ap_info_t *ap_info, + struct local_ap_t *ap) { unsigned char *bp; - int bsize,offset; - int rc=0; + int bsize, offset; + int rc = 0; - DPRINTK(3,"\n"); - memset(ap,0,sizeof(struct local_ap_t)); + DPRINTK(3, "\n"); + memset(ap, 0, sizeof(struct local_ap_t)); /* bssid */ - memcpy(&(ap->bssid[0]),&(ap_info->bssid[0]),ETH_ALEN); + memcpy(&(ap->bssid[0]), &(ap_info->bssid[0]), ETH_ALEN); /* rssi */ ap->rssi = ap_info->rssi; /* sq */ @@ -239,73 +242,80 @@ int get_ap_information(struct ks_wlan_private *priv, struct ap_info_t *ap_info, bsize = ap_info->body_size; offset = 0; - while(bsize > offset){ + while (bsize > offset) { /* DPRINTK(4, "Element ID=%d \n",*bp); */ - switch(*bp){ - case 0: /* ssid */ - if(*(bp+1) <= SSID_MAX_SIZE){ - ap->ssid.size = *(bp+1); - } - else { - DPRINTK(1, "size over :: ssid size=%d \n",*(bp+1)); + switch (*bp) { + case 0: /* ssid */ + if (*(bp + 1) <= SSID_MAX_SIZE) { + ap->ssid.size = *(bp + 1); + } else { + DPRINTK(1, "size over :: ssid size=%d \n", + *(bp + 1)); ap->ssid.size = SSID_MAX_SIZE; } - memcpy(&(ap->ssid.body[0]),bp+2,ap->ssid.size); + memcpy(&(ap->ssid.body[0]), bp + 2, ap->ssid.size); break; - case 1: /* rate */ - case 50: /* ext rate */ - if((*(bp+1) + ap->rate_set.size) <= RATE_SET_MAX_SIZE){ - memcpy(&(ap->rate_set.body[ap->rate_set.size]),bp+2,*(bp+1)); - ap->rate_set.size += *(bp+1); - } - else{ + case 1: /* rate */ + case 50: /* ext rate */ + if ((*(bp + 1) + ap->rate_set.size) <= + RATE_SET_MAX_SIZE) { + memcpy(&(ap->rate_set.body[ap->rate_set.size]), + bp + 2, *(bp + 1)); + ap->rate_set.size += *(bp + 1); + } else { DPRINTK(1, "size over :: rate size=%d \n", - (*(bp+1) + ap->rate_set.size)); - memcpy(&(ap->rate_set.body[ap->rate_set.size]),bp+2, + (*(bp + 1) + ap->rate_set.size)); + memcpy(&(ap->rate_set.body[ap->rate_set.size]), + bp + 2, RATE_SET_MAX_SIZE - ap->rate_set.size); - ap->rate_set.size += (RATE_SET_MAX_SIZE - ap->rate_set.size); + ap->rate_set.size += + (RATE_SET_MAX_SIZE - ap->rate_set.size); } break; - case 3: /* DS parameter */ + case 3: /* DS parameter */ break; - case 48: /* RSN(WPA2) */ + case 48: /* RSN(WPA2) */ ap->rsn_ie.id = *bp; - if(*(bp+1) <= RSN_IE_BODY_MAX){ - ap->rsn_ie.size = *(bp+1); - }else{ - DPRINTK(1, "size over :: rsn size=%d \n",*(bp+1)); + if (*(bp + 1) <= RSN_IE_BODY_MAX) { + ap->rsn_ie.size = *(bp + 1); + } else { + DPRINTK(1, "size over :: rsn size=%d \n", + *(bp + 1)); ap->rsn_ie.size = RSN_IE_BODY_MAX; } - memcpy(&(ap->rsn_ie.body[0]),bp+2,ap->rsn_ie.size); + memcpy(&(ap->rsn_ie.body[0]), bp + 2, ap->rsn_ie.size); break; - case 221: /* WPA */ - if(!memcmp(bp+2, "\x00\x50\xf2\x01", 4)){ /* WPA OUI check */ + case 221: /* WPA */ + if (!memcmp(bp + 2, "\x00\x50\xf2\x01", 4)) { /* WPA OUI check */ ap->wpa_ie.id = *bp; - if(*(bp+1) <= RSN_IE_BODY_MAX){ - ap->wpa_ie.size = *(bp+1); - }else{ - DPRINTK(1, "size over :: wpa size=%d \n",*(bp+1)); + if (*(bp + 1) <= RSN_IE_BODY_MAX) { + ap->wpa_ie.size = *(bp + 1); + } else { + DPRINTK(1, + "size over :: wpa size=%d \n", + *(bp + 1)); ap->wpa_ie.size = RSN_IE_BODY_MAX; } - memcpy(&(ap->wpa_ie.body[0]),bp+2,ap->wpa_ie.size); + memcpy(&(ap->wpa_ie.body[0]), bp + 2, + ap->wpa_ie.size); } break; - case 2: /* FH parameter */ - case 4: /* CF parameter */ - case 5: /* TIM */ - case 6: /* IBSS parameter */ - case 7: /* Country */ - case 42: /* ERP information */ - case 47: /* Reserve ID 47 Broadcom AP */ + case 2: /* FH parameter */ + case 4: /* CF parameter */ + case 5: /* TIM */ + case 6: /* IBSS parameter */ + case 7: /* Country */ + case 42: /* ERP information */ + case 47: /* Reserve ID 47 Broadcom AP */ break; default: - DPRINTK(4, "unknown Element ID=%d \n",*bp); + DPRINTK(4, "unknown Element ID=%d \n", *bp); break; } - offset += 2; /* id & size field */ - offset += *(bp+1); /* +size offset */ - bp += (*(bp+1) + 2); /* pointer update */ + offset += 2; /* id & size field */ + offset += *(bp + 1); /* +size offset */ + bp += (*(bp + 1) + 2); /* pointer update */ } return rc; @@ -314,12 +324,12 @@ int get_ap_information(struct ks_wlan_private *priv, struct ap_info_t *ap_info, static void hostif_data_indication(struct ks_wlan_private *priv) { - unsigned int rx_ind_size; /* indicate data size */ + unsigned int rx_ind_size; /* indicate data size */ struct sk_buff *skb; - unsigned short auth_type; - unsigned char temp[256]; + unsigned short auth_type; + unsigned char temp[256]; - unsigned char RecvMIC[8]; + unsigned char RecvMIC[8]; char buf[128]; struct ether_hdr *eth_hdr; unsigned short eth_proto; @@ -330,162 +340,193 @@ void hostif_data_indication(struct ks_wlan_private *priv) struct michel_mic_t michel_mic; union iwreq_data wrqu; - DPRINTK(3,"\n"); + DPRINTK(3, "\n"); /* min length check */ if (priv->rx_size <= ETH_HLEN) { - DPRINTK(3,"rx_size = %d\n", priv->rx_size); + DPRINTK(3, "rx_size = %d\n", priv->rx_size); priv->nstats.rx_errors++; return; } - auth_type = get_WORD(priv); /* AuthType */ - get_WORD(priv); /* Reserve Area */ + auth_type = get_WORD(priv); /* AuthType */ + get_WORD(priv); /* Reserve Area */ eth_hdr = (struct ether_hdr *)(priv->rxp); eth_proto = ntohs(eth_hdr->h_proto); - DPRINTK(3,"ether protocol = %04X\n", eth_proto); + DPRINTK(3, "ether protocol = %04X\n", eth_proto); /* source address check */ - if (!memcmp(&priv->eth_addr[0],eth_hdr->h_source, ETH_ALEN)){ + if (!memcmp(&priv->eth_addr[0], eth_hdr->h_source, ETH_ALEN)) { DPRINTK(1, "invalid : source is own mac address !!\n"); - DPRINTK(1, "eth_hdrernet->h_dest=%02X:%02X:%02X:%02X:%02X:%02X\n", - eth_hdr->h_source[0],eth_hdr->h_source[1],eth_hdr->h_source[2], - eth_hdr->h_source[3],eth_hdr->h_source[4],eth_hdr->h_source[5]); + DPRINTK(1, + "eth_hdrernet->h_dest=%02X:%02X:%02X:%02X:%02X:%02X\n", + eth_hdr->h_source[0], eth_hdr->h_source[1], + eth_hdr->h_source[2], eth_hdr->h_source[3], + eth_hdr->h_source[4], eth_hdr->h_source[5]); priv->nstats.rx_errors++; return; } /* for WPA */ - if (auth_type != TYPE_DATA && priv->wpa.rsn_enabled){ - if(memcmp(ð_hdr->h_source[0],&priv->eth_addr[0],ETH_ALEN)){ /* source address check */ - if (eth_hdr->h_dest_snap != eth_hdr->h_source_snap){ - DPRINTK(1,"invalid data format\n"); + if (auth_type != TYPE_DATA && priv->wpa.rsn_enabled) { + if (memcmp(ð_hdr->h_source[0], &priv->eth_addr[0], ETH_ALEN)) { /* source address check */ + if (eth_hdr->h_dest_snap != eth_hdr->h_source_snap) { + DPRINTK(1, "invalid data format\n"); priv->nstats.rx_errors++; return; } - if(((auth_type==TYPE_PMK1 && priv->wpa.pairwise_suite == IW_AUTH_CIPHER_TKIP)|| - (auth_type==TYPE_GMK1 && priv->wpa.group_suite == IW_AUTH_CIPHER_TKIP)|| - (auth_type==TYPE_GMK2 && priv->wpa.group_suite == IW_AUTH_CIPHER_TKIP)) - && priv->wpa.key[auth_type-1].key_len){ - DPRINTK(4,"TKIP: protocol=%04X: size=%u\n", eth_proto, priv->rx_size); + if (((auth_type == TYPE_PMK1 + && priv->wpa.pairwise_suite == + IW_AUTH_CIPHER_TKIP) || (auth_type == TYPE_GMK1 + && priv->wpa. + group_suite == + IW_AUTH_CIPHER_TKIP) + || (auth_type == TYPE_GMK2 + && priv->wpa.group_suite == + IW_AUTH_CIPHER_TKIP)) + && priv->wpa.key[auth_type - 1].key_len) { + DPRINTK(4, "TKIP: protocol=%04X: size=%u\n", + eth_proto, priv->rx_size); /* MIC save */ - memcpy(&RecvMIC[0], (priv->rxp)+((priv->rx_size)-8), 8); + memcpy(&RecvMIC[0], + (priv->rxp) + ((priv->rx_size) - 8), 8); priv->rx_size = priv->rx_size - 8; - if(auth_type > 0 && auth_type < 4){ /* auth_type check */ - MichaelMICFunction(&michel_mic, - (uint8_t*)priv->wpa.key[auth_type-1].rx_mic_key, - (uint8_t*)priv->rxp, - (int)priv->rx_size, - (uint8_t)0, /* priority */ - (uint8_t*)michel_mic.Result); + if (auth_type > 0 && auth_type < 4) { /* auth_type check */ + MichaelMICFunction(&michel_mic, (uint8_t *) priv->wpa.key[auth_type - 1].rx_mic_key, (uint8_t *) priv->rxp, (int)priv->rx_size, (uint8_t) 0, /* priority */ + (uint8_t *) + michel_mic.Result); } - if(memcmp(michel_mic.Result, RecvMIC, 8)){ + if (memcmp(michel_mic.Result, RecvMIC, 8)) { now = jiffies; mic_failure = &priv->wpa.mic_failure; /* MIC FAILURE */ - if(mic_failure->last_failure_time && - (now - mic_failure->last_failure_time)/HZ >= 60){ - mic_failure->failure=0; + if (mic_failure->last_failure_time && + (now - + mic_failure->last_failure_time) / + HZ >= 60) { + mic_failure->failure = 0; } - DPRINTK(4,"MIC FAILURE \n"); - if(mic_failure->failure==0){ - mic_failure->failure=1; - mic_failure->counter=0; - }else if(mic_failure->failure==1){ - mic_failure->failure=2; + DPRINTK(4, "MIC FAILURE \n"); + if (mic_failure->failure == 0) { + mic_failure->failure = 1; + mic_failure->counter = 0; + } else if (mic_failure->failure == 1) { + mic_failure->failure = 2; mic_failure->counter = - (uint16_t)((now - mic_failure->last_failure_time)/HZ); - if(!mic_failure->counter) /* mic_failure counter value range 1-60 */ - mic_failure->counter = 1; + (uint16_t) ((now - + mic_failure-> + last_failure_time) + / HZ); + if (!mic_failure->counter) /* mic_failure counter value range 1-60 */ + mic_failure->counter = + 1; } - priv->wpa.mic_failure.last_failure_time = now; + priv->wpa.mic_failure. + last_failure_time = now; /* needed parameters: count, keyid, key type, TSC */ - sprintf(buf, "MLME-MICHAELMICFAILURE.indication(keyid=%d %scast addr=" + sprintf(buf, + "MLME-MICHAELMICFAILURE.indication(keyid=%d %scast addr=" "%02x:%02x:%02x:%02x:%02x:%02x)", - auth_type-1, eth_hdr->h_dest[0] & 0x01 ? "broad" : "uni", - eth_hdr->h_source[0],eth_hdr->h_source[1], - eth_hdr->h_source[2],eth_hdr->h_source[3], - eth_hdr->h_source[4],eth_hdr->h_source[5]); + auth_type - 1, + eth_hdr-> + h_dest[0] & 0x01 ? "broad" : + "uni", eth_hdr->h_source[0], + eth_hdr->h_source[1], + eth_hdr->h_source[2], + eth_hdr->h_source[3], + eth_hdr->h_source[4], + eth_hdr->h_source[5]); memset(&wrqu, 0, sizeof(wrqu)); wrqu.data.length = strlen(buf); - DPRINTK(4,"IWEVENT:MICHAELMICFAILURE\n"); - wireless_send_event(priv->net_dev, IWEVCUSTOM, &wrqu, buf); + DPRINTK(4, + "IWEVENT:MICHAELMICFAILURE\n"); + wireless_send_event(priv->net_dev, + IWEVCUSTOM, &wrqu, + buf); return; } } } } - if((priv->connect_status & FORCE_DISCONNECT)|| - priv->wpa.mic_failure.failure==2){ + if ((priv->connect_status & FORCE_DISCONNECT) || + priv->wpa.mic_failure.failure == 2) { return; } /* check 13th byte at rx data */ - switch (*(priv->rxp+12)) { - case 0xAA: /* SNAP */ + switch (*(priv->rxp + 12)) { + case 0xAA: /* SNAP */ rx_ind_size = priv->rx_size - 6; - skb = dev_alloc_skb (rx_ind_size); - DPRINTK(4,"SNAP, rx_ind_size = %d\n", rx_ind_size); - - if(skb) { - memcpy(skb_put(skb,12),priv->rxp,12); /* 8802/FDDI MAC copy */ - /* (SNAP+UI..) skip */ - memcpy(skb_put(skb,rx_ind_size-12),priv->rxp+18,rx_ind_size-12); /* copy after Type */ - - aa1x_hdr=(struct ieee802_1x_hdr *)(priv->rxp+20); - if(aa1x_hdr->type == IEEE802_1X_TYPE_EAPOL_KEY && priv->wpa.rsn_enabled){ - eap_key = (struct wpa_eapol_key *)(aa1x_hdr+1); + skb = dev_alloc_skb(rx_ind_size); + DPRINTK(4, "SNAP, rx_ind_size = %d\n", rx_ind_size); + + if (skb) { + memcpy(skb_put(skb, 12), priv->rxp, 12); /* 8802/FDDI MAC copy */ + /* (SNAP+UI..) skip */ + memcpy(skb_put(skb, rx_ind_size - 12), priv->rxp + 18, rx_ind_size - 12); /* copy after Type */ + + aa1x_hdr = (struct ieee802_1x_hdr *)(priv->rxp + 20); + if (aa1x_hdr->type == IEEE802_1X_TYPE_EAPOL_KEY + && priv->wpa.rsn_enabled) { + eap_key = + (struct wpa_eapol_key *)(aa1x_hdr + 1); atomic_set(&priv->psstatus.snooze_guard, 1); } /* rx indication */ skb->dev = priv->net_dev; - skb->protocol = eth_type_trans (skb, skb->dev); + skb->protocol = eth_type_trans(skb, skb->dev); priv->nstats.rx_packets++; priv->nstats.rx_bytes += rx_ind_size; skb->dev->last_rx = jiffies; - netif_rx (skb); + netif_rx(skb); } else { - printk (KERN_WARNING"%s: Memory squeeze, dropping packet.\n",skb->dev->name); + printk(KERN_WARNING + "%s: Memory squeeze, dropping packet.\n", + skb->dev->name); priv->nstats.rx_dropped++; } break; - case 0xF0: /* NETBEUI/NetBIOS */ + case 0xF0: /* NETBEUI/NetBIOS */ rx_ind_size = (priv->rx_size + 2); - skb = dev_alloc_skb (rx_ind_size); - DPRINTK(3,"NETBEUI/NetBIOS rx_ind_size=%d\n", rx_ind_size); + skb = dev_alloc_skb(rx_ind_size); + DPRINTK(3, "NETBEUI/NetBIOS rx_ind_size=%d\n", rx_ind_size); - if(skb) { - memcpy(skb_put(skb,12),priv->rxp,12); /* 8802/FDDI MAC copy */ + if (skb) { + memcpy(skb_put(skb, 12), priv->rxp, 12); /* 8802/FDDI MAC copy */ - temp[0] = (((rx_ind_size-12) >> 8) & 0xff); /* NETBEUI size add */ - temp[1] = ((rx_ind_size-12) & 0xff); - memcpy(skb_put(skb,2),temp,2); + temp[0] = (((rx_ind_size - 12) >> 8) & 0xff); /* NETBEUI size add */ + temp[1] = ((rx_ind_size - 12) & 0xff); + memcpy(skb_put(skb, 2), temp, 2); - memcpy(skb_put(skb,rx_ind_size-14),priv->rxp+12,rx_ind_size-14); /* copy after Type */ + memcpy(skb_put(skb, rx_ind_size - 14), priv->rxp + 12, rx_ind_size - 14); /* copy after Type */ - aa1x_hdr=(struct ieee802_1x_hdr *)(priv->rxp+14); - if(aa1x_hdr->type == IEEE802_1X_TYPE_EAPOL_KEY && priv->wpa.rsn_enabled){ - eap_key = (struct wpa_eapol_key *)(aa1x_hdr+1); + aa1x_hdr = (struct ieee802_1x_hdr *)(priv->rxp + 14); + if (aa1x_hdr->type == IEEE802_1X_TYPE_EAPOL_KEY + && priv->wpa.rsn_enabled) { + eap_key = + (struct wpa_eapol_key *)(aa1x_hdr + 1); atomic_set(&priv->psstatus.snooze_guard, 1); } /* rx indication */ skb->dev = priv->net_dev; - skb->protocol = eth_type_trans (skb, skb->dev); + skb->protocol = eth_type_trans(skb, skb->dev); priv->nstats.rx_packets++; priv->nstats.rx_bytes += rx_ind_size; skb->dev->last_rx = jiffies; - netif_rx (skb); + netif_rx(skb); } else { - printk (KERN_WARNING"%s: Memory squeeze, dropping packet.\n",skb->dev->name); + printk(KERN_WARNING + "%s: Memory squeeze, dropping packet.\n", + skb->dev->name); priv->nstats.rx_dropped++; } break; - default: /* other rx data */ - DPRINTK(2,"invalid data format\n"); + default: /* other rx data */ + DPRINTK(2, "invalid data format\n"); priv->nstats.rx_errors++; } } @@ -493,29 +534,30 @@ void hostif_data_indication(struct ks_wlan_private *priv) static void hostif_mib_get_confirm(struct ks_wlan_private *priv) { - struct net_device *dev=priv->net_dev; - uint32_t mib_status; - uint32_t mib_attribute; - uint16_t mib_val_size; - uint16_t mib_val_type; + struct net_device *dev = priv->net_dev; + uint32_t mib_status; + uint32_t mib_attribute; + uint16_t mib_val_size; + uint16_t mib_val_type; DPRINTK(3, "\n"); - mib_status = get_DWORD(priv); /* MIB status */ - mib_attribute = get_DWORD(priv); /* MIB atttibute */ - mib_val_size = get_WORD(priv); /* MIB value size */ - mib_val_type = get_WORD(priv); /* MIB value type */ + mib_status = get_DWORD(priv); /* MIB status */ + mib_attribute = get_DWORD(priv); /* MIB atttibute */ + mib_val_size = get_WORD(priv); /* MIB value size */ + mib_val_type = get_WORD(priv); /* MIB value type */ if (mib_status != 0) { /* in case of error */ - DPRINTK(1, "attribute=%08X, status=%08X\n", mib_attribute, mib_status); + DPRINTK(1, "attribute=%08X, status=%08X\n", mib_attribute, + mib_status); return; } switch (mib_attribute) { case DOT11_MAC_ADDRESS: /* MAC address */ - DPRINTK(3," mib_attribute=DOT11_MAC_ADDRESS\n"); + DPRINTK(3, " mib_attribute=DOT11_MAC_ADDRESS\n"); hostif_sme_enqueue(priv, SME_GET_MAC_ADDRESS); memcpy(priv->eth_addr, priv->rxp, ETH_ALEN); priv->mac_address_valid = 1; @@ -527,44 +569,48 @@ void hostif_mib_get_confirm(struct ks_wlan_private *priv) dev->dev_addr[5] = priv->eth_addr[5]; dev->dev_addr[6] = 0x00; dev->dev_addr[7] = 0x00; - printk(KERN_INFO "ks_wlan: MAC ADDRESS = %02x:%02x:%02x:%02x:%02x:%02x\n", - priv->eth_addr[0],priv->eth_addr[1],priv->eth_addr[2], - priv->eth_addr[3],priv->eth_addr[4],priv->eth_addr[5]); + printk(KERN_INFO + "ks_wlan: MAC ADDRESS = %02x:%02x:%02x:%02x:%02x:%02x\n", + priv->eth_addr[0], priv->eth_addr[1], priv->eth_addr[2], + priv->eth_addr[3], priv->eth_addr[4], priv->eth_addr[5]); break; case DOT11_PRODUCT_VERSION: /* firmware version */ - DPRINTK(3," mib_attribute=DOT11_PRODUCT_VERSION\n"); + DPRINTK(3, " mib_attribute=DOT11_PRODUCT_VERSION\n"); priv->version_size = priv->rx_size; memcpy(priv->firmware_version, priv->rxp, priv->rx_size); priv->firmware_version[priv->rx_size] = '\0'; - printk(KERN_INFO "ks_wlan: firmware ver. = %s\n",priv->firmware_version); + printk(KERN_INFO "ks_wlan: firmware ver. = %s\n", + priv->firmware_version); hostif_sme_enqueue(priv, SME_GET_PRODUCT_VERSION); /* wake_up_interruptible_all(&priv->confirm_wait); */ complete(&priv->confirm_wait); break; case LOCAL_GAIN: memcpy(&priv->gain, priv->rxp, sizeof(priv->gain)); - DPRINTK(3, "TxMode=%d, RxMode=%d, TxGain=%d, RxGain=%d\n", - priv->gain.TxMode, priv->gain.RxMode, priv->gain.TxGain, priv->gain.RxGain); + DPRINTK(3, "TxMode=%d, RxMode=%d, TxGain=%d, RxGain=%d\n", + priv->gain.TxMode, priv->gain.RxMode, priv->gain.TxGain, + priv->gain.RxGain); break; case LOCAL_EEPROM_SUM: memcpy(&priv->eeprom_sum, priv->rxp, sizeof(priv->eeprom_sum)); - DPRINTK(1, "eeprom_sum.type=%x, eeprom_sum.result=%x\n", priv->eeprom_sum.type, priv->eeprom_sum.result); - if(priv->eeprom_sum.type == 0){ + DPRINTK(1, "eeprom_sum.type=%x, eeprom_sum.result=%x\n", + priv->eeprom_sum.type, priv->eeprom_sum.result); + if (priv->eeprom_sum.type == 0) { priv->eeprom_checksum = EEPROM_CHECKSUM_NONE; - }else if(priv->eeprom_sum.type == 1){ - if(priv->eeprom_sum.result == 0){ + } else if (priv->eeprom_sum.type == 1) { + if (priv->eeprom_sum.result == 0) { priv->eeprom_checksum = EEPROM_NG; printk("LOCAL_EEPROM_SUM NG\n"); - }else if(priv->eeprom_sum.result == 1){ + } else if (priv->eeprom_sum.result == 1) { priv->eeprom_checksum = EEPROM_OK; } - }else{ + } else { printk("LOCAL_EEPROM_SUM error!\n"); } break; default: - DPRINTK(1,"mib_attribute=%08x\n",(unsigned int)mib_attribute); + DPRINTK(1, "mib_attribute=%08x\n", (unsigned int)mib_attribute); break; } } @@ -572,17 +618,18 @@ void hostif_mib_get_confirm(struct ks_wlan_private *priv) static void hostif_mib_set_confirm(struct ks_wlan_private *priv) { - uint32_t mib_status; /* +04 MIB Status */ - uint32_t mib_attribute; /* +08 MIB attribute */ + uint32_t mib_status; /* +04 MIB Status */ + uint32_t mib_attribute; /* +08 MIB attribute */ - DPRINTK(3,"\n"); + DPRINTK(3, "\n"); - mib_status = get_DWORD(priv); /* MIB Status */ - mib_attribute = get_DWORD(priv); /* MIB attribute */ + mib_status = get_DWORD(priv); /* MIB Status */ + mib_attribute = get_DWORD(priv); /* MIB attribute */ if (mib_status != 0) { /* in case of error */ - DPRINTK(1, "error :: attribute=%08X, status=%08X\n", mib_attribute, mib_status); + DPRINTK(1, "error :: attribute=%08X, status=%08X\n", + mib_attribute, mib_status); } switch (mib_attribute) { @@ -593,41 +640,46 @@ void hostif_mib_set_confirm(struct ks_wlan_private *priv) hostif_sme_enqueue(priv, SME_FRAGMENTATION_THRESHOLD_CONFIRM); break; case DOT11_WEP_DEFAULT_KEY_ID: - if(!priv->wpa.wpa_enabled) + if (!priv->wpa.wpa_enabled) hostif_sme_enqueue(priv, SME_WEP_INDEX_CONFIRM); break; case DOT11_WEP_DEFAULT_KEY_VALUE1: - DPRINTK(2,"DOT11_WEP_DEFAULT_KEY_VALUE1:mib_status=%d\n",(int)mib_status); - if(priv->wpa.rsn_enabled) + DPRINTK(2, "DOT11_WEP_DEFAULT_KEY_VALUE1:mib_status=%d\n", + (int)mib_status); + if (priv->wpa.rsn_enabled) hostif_sme_enqueue(priv, SME_SET_PMK_TSC); else hostif_sme_enqueue(priv, SME_WEP_KEY1_CONFIRM); break; case DOT11_WEP_DEFAULT_KEY_VALUE2: - DPRINTK(2,"DOT11_WEP_DEFAULT_KEY_VALUE2:mib_status=%d\n",(int)mib_status); - if(priv->wpa.rsn_enabled) + DPRINTK(2, "DOT11_WEP_DEFAULT_KEY_VALUE2:mib_status=%d\n", + (int)mib_status); + if (priv->wpa.rsn_enabled) hostif_sme_enqueue(priv, SME_SET_GMK1_TSC); else hostif_sme_enqueue(priv, SME_WEP_KEY2_CONFIRM); break; case DOT11_WEP_DEFAULT_KEY_VALUE3: - DPRINTK(2,"DOT11_WEP_DEFAULT_KEY_VALUE3:mib_status=%d\n",(int)mib_status); - if(priv->wpa.rsn_enabled) + DPRINTK(2, "DOT11_WEP_DEFAULT_KEY_VALUE3:mib_status=%d\n", + (int)mib_status); + if (priv->wpa.rsn_enabled) hostif_sme_enqueue(priv, SME_SET_GMK2_TSC); else hostif_sme_enqueue(priv, SME_WEP_KEY3_CONFIRM); break; case DOT11_WEP_DEFAULT_KEY_VALUE4: - DPRINTK(2,"DOT11_WEP_DEFAULT_KEY_VALUE4:mib_status=%d\n",(int)mib_status); - if(!priv->wpa.rsn_enabled) + DPRINTK(2, "DOT11_WEP_DEFAULT_KEY_VALUE4:mib_status=%d\n", + (int)mib_status); + if (!priv->wpa.rsn_enabled) hostif_sme_enqueue(priv, SME_WEP_KEY4_CONFIRM); break; case DOT11_PRIVACY_INVOKED: - if(!priv->wpa.rsn_enabled) + if (!priv->wpa.rsn_enabled) hostif_sme_enqueue(priv, SME_WEP_FLAG_CONFIRM); break; case DOT11_RSN_ENABLED: - DPRINTK(2,"DOT11_RSN_ENABLED:mib_status=%d\n",(int)mib_status); + DPRINTK(2, "DOT11_RSN_ENABLED:mib_status=%d\n", + (int)mib_status); hostif_sme_enqueue(priv, SME_RSN_ENABLED_CONFIRM); break; case LOCAL_RSN_MODE: @@ -643,49 +695,53 @@ void hostif_mib_set_confirm(struct ks_wlan_private *priv) priv->mac_address_valid = 1; break; case DOT11_RSN_CONFIG_MULTICAST_CIPHER: - DPRINTK(2,"DOT11_RSN_CONFIG_MULTICAST_CIPHER:mib_status=%d\n",(int)mib_status); + DPRINTK(2, "DOT11_RSN_CONFIG_MULTICAST_CIPHER:mib_status=%d\n", + (int)mib_status); hostif_sme_enqueue(priv, SME_RSN_MCAST_CONFIRM); break; case DOT11_RSN_CONFIG_UNICAST_CIPHER: - DPRINTK(2,"DOT11_RSN_CONFIG_UNICAST_CIPHER:mib_status=%d\n",(int)mib_status); + DPRINTK(2, "DOT11_RSN_CONFIG_UNICAST_CIPHER:mib_status=%d\n", + (int)mib_status); hostif_sme_enqueue(priv, SME_RSN_UCAST_CONFIRM); break; case DOT11_RSN_CONFIG_AUTH_SUITE: - DPRINTK(2,"DOT11_RSN_CONFIG_AUTH_SUITE:mib_status=%d\n",(int)mib_status); + DPRINTK(2, "DOT11_RSN_CONFIG_AUTH_SUITE:mib_status=%d\n", + (int)mib_status); hostif_sme_enqueue(priv, SME_RSN_AUTH_CONFIRM); break; case DOT11_PMK_TSC: - DPRINTK(2,"DOT11_PMK_TSC:mib_status=%d\n",(int)mib_status); + DPRINTK(2, "DOT11_PMK_TSC:mib_status=%d\n", (int)mib_status); break; case DOT11_GMK1_TSC: - DPRINTK(2,"DOT11_GMK1_TSC:mib_status=%d\n",(int)mib_status); - if(atomic_read(&priv->psstatus.snooze_guard)){ + DPRINTK(2, "DOT11_GMK1_TSC:mib_status=%d\n", (int)mib_status); + if (atomic_read(&priv->psstatus.snooze_guard)) { atomic_set(&priv->psstatus.snooze_guard, 0); } break; case DOT11_GMK2_TSC: - DPRINTK(2,"DOT11_GMK2_TSC:mib_status=%d\n",(int)mib_status); - if(atomic_read(&priv->psstatus.snooze_guard)){ + DPRINTK(2, "DOT11_GMK2_TSC:mib_status=%d\n", (int)mib_status); + if (atomic_read(&priv->psstatus.snooze_guard)) { atomic_set(&priv->psstatus.snooze_guard, 0); } break; case LOCAL_PMK: - DPRINTK(2,"LOCAL_PMK:mib_status=%d\n",(int)mib_status); + DPRINTK(2, "LOCAL_PMK:mib_status=%d\n", (int)mib_status); break; case LOCAL_GAIN: - DPRINTK(2,"LOCAL_GAIN:mib_status=%d\n",(int)mib_status); + DPRINTK(2, "LOCAL_GAIN:mib_status=%d\n", (int)mib_status); break; #ifdef WPS case LOCAL_WPS_ENABLE: - DPRINTK(2,"LOCAL_WPS_ENABLE:mib_status=%d\n",(int)mib_status); + DPRINTK(2, "LOCAL_WPS_ENABLE:mib_status=%d\n", (int)mib_status); break; case LOCAL_WPS_PROBE_REQ: - DPRINTK(2,"LOCAL_WPS_PROBE_REQ:mib_status=%d\n",(int)mib_status); + DPRINTK(2, "LOCAL_WPS_PROBE_REQ:mib_status=%d\n", + (int)mib_status); break; #endif /* WPS */ case LOCAL_REGION: - DPRINTK(2,"LOCAL_REGION:mib_status=%d\n",(int)mib_status); - default : + DPRINTK(2, "LOCAL_REGION:mib_status=%d\n", (int)mib_status); + default: break; } } @@ -693,14 +749,14 @@ void hostif_mib_set_confirm(struct ks_wlan_private *priv) static void hostif_power_mngmt_confirm(struct ks_wlan_private *priv) { - DPRINTK(3,"\n"); + DPRINTK(3, "\n"); - if(priv->reg.powermgt > POWMGT_ACTIVE_MODE && - priv->reg.operation_mode == MODE_INFRASTRUCTURE){ + if (priv->reg.powermgt > POWMGT_ACTIVE_MODE && + priv->reg.operation_mode == MODE_INFRASTRUCTURE) { atomic_set(&priv->psstatus.confirm_wait, 0); priv->dev_state = DEVICE_STATE_SLEEP; ks_wlan_hw_power_save(priv); - }else{ + } else { priv->dev_state = DEVICE_STATE_READY; } @@ -709,27 +765,28 @@ void hostif_power_mngmt_confirm(struct ks_wlan_private *priv) static void hostif_sleep_confirm(struct ks_wlan_private *priv) { - DPRINTK(3,"\n"); + DPRINTK(3, "\n"); - atomic_set(&priv->sleepstatus.doze_request,1); - queue_delayed_work(priv->ks_wlan_hw.ks7010sdio_wq,&priv->ks_wlan_hw.rw_wq, 1); + atomic_set(&priv->sleepstatus.doze_request, 1); + queue_delayed_work(priv->ks_wlan_hw.ks7010sdio_wq, + &priv->ks_wlan_hw.rw_wq, 1); } static void hostif_start_confirm(struct ks_wlan_private *priv) { #ifdef WPS - union iwreq_data wrqu; - wrqu.data.length = 0; - wrqu.data.flags = 0; - wrqu.ap_addr.sa_family = ARPHRD_ETHER; - if((priv->connect_status & CONNECT_STATUS_MASK)== CONNECT_STATUS){ - memset(wrqu.ap_addr.sa_data, '\0', ETH_ALEN); - DPRINTK(3,"IWEVENT: disconnect\n"); - wireless_send_event(priv->net_dev, SIOCGIWAP, &wrqu, NULL); - } + union iwreq_data wrqu; + wrqu.data.length = 0; + wrqu.data.flags = 0; + wrqu.ap_addr.sa_family = ARPHRD_ETHER; + if ((priv->connect_status & CONNECT_STATUS_MASK) == CONNECT_STATUS) { + memset(wrqu.ap_addr.sa_data, '\0', ETH_ALEN); + DPRINTK(3, "IWEVENT: disconnect\n"); + wireless_send_event(priv->net_dev, SIOCGIWAP, &wrqu, NULL); + } #endif - DPRINTK(3," scan_ind_count=%d\n",priv->scan_ind_count); + DPRINTK(3, " scan_ind_count=%d\n", priv->scan_ind_count); hostif_sme_enqueue(priv, SME_START_CONFIRM); } @@ -737,29 +794,31 @@ static void hostif_connect_indication(struct ks_wlan_private *priv) { unsigned short connect_code; - unsigned int tmp=0; - unsigned int old_status=priv->connect_status; - struct net_device *netdev=priv->net_dev; + unsigned int tmp = 0; + unsigned int old_status = priv->connect_status; + struct net_device *netdev = priv->net_dev; union iwreq_data wrqu0; connect_code = get_WORD(priv); - switch(connect_code){ - case RESULT_CONNECT: /* connect */ - DPRINTK(3,"connect :: scan_ind_count=%d\n",priv->scan_ind_count); - if(!(priv->connect_status & FORCE_DISCONNECT)) + switch (connect_code) { + case RESULT_CONNECT: /* connect */ + DPRINTK(3, "connect :: scan_ind_count=%d\n", + priv->scan_ind_count); + if (!(priv->connect_status & FORCE_DISCONNECT)) netif_carrier_on(netdev); tmp = FORCE_DISCONNECT & priv->connect_status; priv->connect_status = tmp + CONNECT_STATUS; break; - case RESULT_DISCONNECT: /* disconnect */ - DPRINTK(3,"disconnect :: scan_ind_count=%d\n",priv->scan_ind_count); + case RESULT_DISCONNECT: /* disconnect */ + DPRINTK(3, "disconnect :: scan_ind_count=%d\n", + priv->scan_ind_count); netif_carrier_off(netdev); tmp = FORCE_DISCONNECT & priv->connect_status; priv->connect_status = tmp + DISCONNECT_STATUS; break; default: - DPRINTK(1,"unknown connect_code=%d :: scan_ind_count=%d\n", - connect_code,priv->scan_ind_count); + DPRINTK(1, "unknown connect_code=%d :: scan_ind_count=%d\n", + connect_code, priv->scan_ind_count); netif_carrier_off(netdev); tmp = FORCE_DISCONNECT & priv->connect_status; priv->connect_status = tmp + DISCONNECT_STATUS; @@ -767,25 +826,26 @@ void hostif_connect_indication(struct ks_wlan_private *priv) } get_current_ap(priv, (struct link_ap_info_t *)priv->rxp); - if((priv->connect_status & CONNECT_STATUS_MASK)== CONNECT_STATUS && - (old_status & CONNECT_STATUS_MASK)==DISCONNECT_STATUS ){ + if ((priv->connect_status & CONNECT_STATUS_MASK) == CONNECT_STATUS && + (old_status & CONNECT_STATUS_MASK) == DISCONNECT_STATUS) { /* for power save */ atomic_set(&priv->psstatus.snooze_guard, 0); - atomic_set(&priv->psstatus.confirm_wait,0); + atomic_set(&priv->psstatus.confirm_wait, 0); } ks_wlan_do_power_save(priv); wrqu0.data.length = 0; wrqu0.data.flags = 0; wrqu0.ap_addr.sa_family = ARPHRD_ETHER; - if((priv->connect_status & CONNECT_STATUS_MASK)== DISCONNECT_STATUS && - (old_status & CONNECT_STATUS_MASK)==CONNECT_STATUS ){ + if ((priv->connect_status & CONNECT_STATUS_MASK) == DISCONNECT_STATUS && + (old_status & CONNECT_STATUS_MASK) == CONNECT_STATUS) { memset(wrqu0.ap_addr.sa_data, '\0', ETH_ALEN); - DPRINTK(3,"IWEVENT: disconnect\n"); - DPRINTK(3,"disconnect :: scan_ind_count=%d\n",priv->scan_ind_count); + DPRINTK(3, "IWEVENT: disconnect\n"); + DPRINTK(3, "disconnect :: scan_ind_count=%d\n", + priv->scan_ind_count); wireless_send_event(netdev, SIOCGIWAP, &wrqu0, NULL); } - priv->scan_ind_count=0; + priv->scan_ind_count = 0; } static @@ -794,45 +854,52 @@ void hostif_scan_indication(struct ks_wlan_private *priv) int i; struct ap_info_t *ap_info; - DPRINTK(3,"scan_ind_count = %d\n", priv->scan_ind_count); + DPRINTK(3, "scan_ind_count = %d\n", priv->scan_ind_count); ap_info = (struct ap_info_t *)(priv->rxp); - if(priv->scan_ind_count!=0){ - for(i=0;iaplist.size;i++){ /* bssid check */ - if(!memcmp(&(ap_info->bssid[0]),&(priv->aplist.ap[i].bssid[0]),ETH_ALEN)){ - if(ap_info->frame_type == FRAME_TYPE_PROBE_RESP) - get_ap_information(priv,ap_info,&(priv->aplist.ap[i])); + if (priv->scan_ind_count != 0) { + for (i = 0; i < priv->aplist.size; i++) { /* bssid check */ + if (!memcmp + (&(ap_info->bssid[0]), + &(priv->aplist.ap[i].bssid[0]), ETH_ALEN)) { + if (ap_info->frame_type == + FRAME_TYPE_PROBE_RESP) + get_ap_information(priv, ap_info, + &(priv->aplist. + ap[i])); return; } } } priv->scan_ind_count++; - if(priv->scan_ind_count < LOCAL_APLIST_MAX+1){ - DPRINTK(4," scan_ind_count=%d :: aplist.size=%d\n", priv->scan_ind_count, priv->aplist.size); - get_ap_information(priv,(struct ap_info_t *)(priv->rxp),&(priv->aplist.ap[priv->scan_ind_count-1])); + if (priv->scan_ind_count < LOCAL_APLIST_MAX + 1) { + DPRINTK(4, " scan_ind_count=%d :: aplist.size=%d\n", + priv->scan_ind_count, priv->aplist.size); + get_ap_information(priv, (struct ap_info_t *)(priv->rxp), + &(priv->aplist. + ap[priv->scan_ind_count - 1])); priv->aplist.size = priv->scan_ind_count; + } else { + DPRINTK(4, " count over :: scan_ind_count=%d\n", + priv->scan_ind_count); } - else{ - DPRINTK(4," count over :: scan_ind_count=%d\n", priv->scan_ind_count); - } - } static void hostif_stop_confirm(struct ks_wlan_private *priv) { - unsigned int tmp=0; - unsigned int old_status=priv->connect_status; - struct net_device *netdev=priv->net_dev; + unsigned int tmp = 0; + unsigned int old_status = priv->connect_status; + struct net_device *netdev = priv->net_dev; union iwreq_data wrqu0; - DPRINTK(3,"\n"); - if(priv->dev_state == DEVICE_STATE_SLEEP) + DPRINTK(3, "\n"); + if (priv->dev_state == DEVICE_STATE_SLEEP) priv->dev_state = DEVICE_STATE_READY; /* disconnect indication */ - if( (priv->connect_status & CONNECT_STATUS_MASK)== CONNECT_STATUS){ + if ((priv->connect_status & CONNECT_STATUS_MASK) == CONNECT_STATUS) { netif_carrier_off(netdev); tmp = FORCE_DISCONNECT & priv->connect_status; priv->connect_status = tmp | DISCONNECT_STATUS; @@ -841,15 +908,17 @@ void hostif_stop_confirm(struct ks_wlan_private *priv) wrqu0.data.length = 0; wrqu0.data.flags = 0; wrqu0.ap_addr.sa_family = ARPHRD_ETHER; - if((priv->connect_status & CONNECT_STATUS_MASK)== DISCONNECT_STATUS && - (old_status & CONNECT_STATUS_MASK)==CONNECT_STATUS ){ + if ((priv->connect_status & CONNECT_STATUS_MASK) == + DISCONNECT_STATUS + && (old_status & CONNECT_STATUS_MASK) == CONNECT_STATUS) { memset(wrqu0.ap_addr.sa_data, '\0', ETH_ALEN); - DPRINTK(3,"IWEVENT: disconnect\n"); + DPRINTK(3, "IWEVENT: disconnect\n"); printk("IWEVENT: disconnect\n"); - DPRINTK(3,"disconnect :: scan_ind_count=%d\n",priv->scan_ind_count); + DPRINTK(3, "disconnect :: scan_ind_count=%d\n", + priv->scan_ind_count); wireless_send_event(netdev, SIOCGIWAP, &wrqu0, NULL); } - priv->scan_ind_count=0; + priv->scan_ind_count = 0; } hostif_sme_enqueue(priv, SME_STOP_CONFIRM); @@ -858,8 +927,8 @@ void hostif_stop_confirm(struct ks_wlan_private *priv) static void hostif_ps_adhoc_set_confirm(struct ks_wlan_private *priv) { - DPRINTK(3,"\n"); - priv->infra_status = 0; /* infrastructure mode cancel */ + DPRINTK(3, "\n"); + priv->infra_status = 0; /* infrastructure mode cancel */ hostif_sme_enqueue(priv, SME_MODE_SET_CONFIRM); } @@ -868,18 +937,18 @@ static void hostif_infrastructure_set_confirm(struct ks_wlan_private *priv) { uint16_t result_code; - DPRINTK(3,"\n"); + DPRINTK(3, "\n"); result_code = get_WORD(priv); - DPRINTK(3,"result code = %d\n",result_code); - priv->infra_status = 1; /* infrastructure mode set */ + DPRINTK(3, "result code = %d\n", result_code); + priv->infra_status = 1; /* infrastructure mode set */ hostif_sme_enqueue(priv, SME_MODE_SET_CONFIRM); } static void hostif_adhoc_set_confirm(struct ks_wlan_private *priv) { - DPRINTK(3,"\n"); - priv->infra_status = 1; /* infrastructure mode set */ + DPRINTK(3, "\n"); + priv->infra_status = 1; /* infrastructure mode set */ hostif_sme_enqueue(priv, SME_MODE_SET_CONFIRM); } @@ -897,33 +966,33 @@ void hostif_associate_indication(struct ks_wlan_private *priv) static const char associnfo_leader0[] = "ASSOCINFO(ReqIEs="; static const char associnfo_leader1[] = " RespIEs="; - DPRINTK(3,"\n"); + DPRINTK(3, "\n"); assoc_req = (struct association_request_t *)(priv->rxp); - assoc_resp = (struct association_response_t *)(assoc_req+1); - pb = (unsigned char *)(assoc_resp+1); + assoc_resp = (struct association_response_t *)(assoc_req + 1); + pb = (unsigned char *)(assoc_resp + 1); memset(&wrqu, 0, sizeof(wrqu)); - memcpy(pbuf,associnfo_leader0,sizeof(associnfo_leader0)-1); - wrqu.data.length += sizeof(associnfo_leader0)-1; - pbuf += sizeof(associnfo_leader0)-1; + memcpy(pbuf, associnfo_leader0, sizeof(associnfo_leader0) - 1); + wrqu.data.length += sizeof(associnfo_leader0) - 1; + pbuf += sizeof(associnfo_leader0) - 1; for (i = 0; i < assoc_req->reqIEs_size; i++) - pbuf += sprintf(pbuf, "%02x", *(pb+i)); - wrqu.data.length += (assoc_req->reqIEs_size)*2; + pbuf += sprintf(pbuf, "%02x", *(pb + i)); + wrqu.data.length += (assoc_req->reqIEs_size) * 2; - memcpy(pbuf,associnfo_leader1,sizeof(associnfo_leader1)-1); - wrqu.data.length += sizeof(associnfo_leader1)-1; - pbuf += sizeof(associnfo_leader1)-1; + memcpy(pbuf, associnfo_leader1, sizeof(associnfo_leader1) - 1); + wrqu.data.length += sizeof(associnfo_leader1) - 1; + pbuf += sizeof(associnfo_leader1) - 1; pb += assoc_req->reqIEs_size; for (i = 0; i < assoc_resp->respIEs_size; i++) - pbuf += sprintf(pbuf, "%02x", *(pb+i)); - wrqu.data.length += (assoc_resp->respIEs_size)*2; + pbuf += sprintf(pbuf, "%02x", *(pb + i)); + wrqu.data.length += (assoc_resp->respIEs_size) * 2; pbuf += sprintf(pbuf, ")"); wrqu.data.length += 1; - DPRINTK(3,"IWEVENT:ASSOCINFO\n"); + DPRINTK(3, "IWEVENT:ASSOCINFO\n"); wireless_send_event(priv->net_dev, IWEVCUSTOM, &wrqu, buf); } @@ -934,28 +1003,29 @@ void hostif_bss_scan_confirm(struct ks_wlan_private *priv) struct net_device *dev = priv->net_dev; union iwreq_data wrqu; result_code = get_DWORD(priv); - DPRINTK(2,"result=%d :: scan_ind_count=%d\n", result_code, priv->scan_ind_count); + DPRINTK(2, "result=%d :: scan_ind_count=%d\n", result_code, + priv->scan_ind_count); priv->sme_i.sme_flag &= ~SME_AP_SCAN; hostif_sme_enqueue(priv, SME_BSS_SCAN_CONFIRM); wrqu.data.length = 0; wrqu.data.flags = 0; - DPRINTK(3,"IWEVENT: SCAN CONFIRM\n"); + DPRINTK(3, "IWEVENT: SCAN CONFIRM\n"); wireless_send_event(dev, SIOCGIWSCAN, &wrqu, NULL); - priv->scan_ind_count=0; + priv->scan_ind_count = 0; } static void hostif_phy_information_confirm(struct ks_wlan_private *priv) { struct iw_statistics *wstats = &priv->wstats; - unsigned char rssi,signal,noise; + unsigned char rssi, signal, noise; unsigned char LinkSpeed; unsigned int TransmittedFrameCount, ReceivedFragmentCount; unsigned int FailedCount, FCSErrorCount; - DPRINTK(3,"\n"); + DPRINTK(3, "\n"); rssi = get_BYTE(priv); signal = get_BYTE(priv); noise = get_BYTE(priv); @@ -969,14 +1039,12 @@ void hostif_phy_information_confirm(struct ks_wlan_private *priv) priv->current_rate = (LinkSpeed & RATE_MASK); wstats->qual.qual = signal; wstats->qual.level = 256 - rssi; - wstats->qual.noise = 0; /* invalid noise value */ + wstats->qual.noise = 0; /* invalid noise value */ wstats->qual.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM; - DPRINTK(3,"\n rssi=%u\n signal=%u\n LinkSpeed=%ux500Kbps\n \ + DPRINTK(3, "\n rssi=%u\n signal=%u\n LinkSpeed=%ux500Kbps\n \ TransmittedFrameCount=%u\n ReceivedFragmentCount=%u\n FailedCount=%u\n \ - FCSErrorCount=%u\n", - rssi,signal,LinkSpeed,TransmittedFrameCount, - ReceivedFragmentCount,FailedCount,FCSErrorCount); + FCSErrorCount=%u\n", rssi, signal, LinkSpeed, TransmittedFrameCount, ReceivedFragmentCount, FailedCount, FCSErrorCount); /* wake_up_interruptible_all(&priv->confirm_wait); */ complete(&priv->confirm_wait); @@ -985,18 +1053,17 @@ void hostif_phy_information_confirm(struct ks_wlan_private *priv) static void hostif_mic_failure_confirm(struct ks_wlan_private *priv) { - DPRINTK(3,"mic_failure=%u\n",priv->wpa.mic_failure.failure); + DPRINTK(3, "mic_failure=%u\n", priv->wpa.mic_failure.failure); hostif_sme_enqueue(priv, SME_MIC_FAILURE_CONFIRM); } - static void hostif_event_check(struct ks_wlan_private *priv) { unsigned short event; DPRINTK(4, "\n"); - event = get_WORD(priv); /* get event */ + event = get_WORD(priv); /* get event */ switch (event) { case HIF_DATA_IND: hostif_data_indication(priv); @@ -1060,56 +1127,59 @@ void hostif_event_check(struct ks_wlan_private *priv) /* add event to hostt buffer */ priv->hostt.buff[priv->hostt.qtail] = event; - priv->hostt.qtail = (priv->hostt.qtail + 1) % SME_EVENT_BUFF_SIZE; + priv->hostt.qtail = (priv->hostt.qtail + 1) % SME_EVENT_BUFF_SIZE; } #define CHECK_ALINE(size) (size%4 ? (size+(4-(size%4))):size) int hostif_data_request(struct ks_wlan_private *priv, struct sk_buff *packet) { - unsigned int packet_len=0; + unsigned int packet_len = 0; - unsigned char *buffer=NULL; - unsigned int length=0; + unsigned char *buffer = NULL; + unsigned int length = 0; struct hostif_data_request_t *pp; - unsigned char *p; - int result=0; + unsigned char *p; + int result = 0; unsigned short eth_proto; struct ether_hdr *eth_hdr; struct michel_mic_t michel_mic; - unsigned short keyinfo=0; + unsigned short keyinfo = 0; struct ieee802_1x_hdr *aa1x_hdr; struct wpa_eapol_key *eap_key; struct ethhdr *eth; packet_len = packet->len; if (packet_len > ETH_FRAME_LEN) { - DPRINTK(1,"bad length packet_len=%d \n", packet_len); + DPRINTK(1, "bad length packet_len=%d \n", packet_len); dev_kfree_skb(packet); return -1; } - if(((priv->connect_status & CONNECT_STATUS_MASK)== DISCONNECT_STATUS) || - (priv->connect_status & FORCE_DISCONNECT) || priv->wpa.mic_failure.stop){ - DPRINTK(3," DISCONNECT\n"); - if(netif_queue_stopped(priv->net_dev)) + if (((priv->connect_status & CONNECT_STATUS_MASK) == DISCONNECT_STATUS) + || (priv->connect_status & FORCE_DISCONNECT) + || priv->wpa.mic_failure.stop) { + DPRINTK(3, " DISCONNECT\n"); + if (netif_queue_stopped(priv->net_dev)) netif_wake_queue(priv->net_dev); - if(packet) + if (packet) dev_kfree_skb(packet); return 0; } /* for PowerSave */ - if(atomic_read(&priv->psstatus.status)==PS_SNOOZE){ /* power save wakeup */ - if(!netif_queue_stopped(priv->net_dev)) + if (atomic_read(&priv->psstatus.status) == PS_SNOOZE) { /* power save wakeup */ + if (!netif_queue_stopped(priv->net_dev)) netif_stop_queue(priv->net_dev); } DPRINTK(4, "skb_buff length=%d\n", packet_len); - pp = (struct hostif_data_request_t *)kmalloc(hif_align_size(sizeof(*pp)+6+packet_len+8),KS_WLAN_MEM_FLAG ); + pp = (struct hostif_data_request_t *) + kmalloc(hif_align_size(sizeof(*pp) + 6 + packet_len + 8), + KS_WLAN_MEM_FLAG); - if (pp==NULL) { + if (pp == NULL) { DPRINTK(3, "allocate memory failed..\n"); dev_kfree_skb(packet); return -2; @@ -1122,34 +1192,34 @@ int hostif_data_request(struct ks_wlan_private *priv, struct sk_buff *packet) /* packet check */ eth = (struct ethhdr *)packet->data; - if (memcmp(&priv->eth_addr[0],eth->h_source, ETH_ALEN)){ + if (memcmp(&priv->eth_addr[0], eth->h_source, ETH_ALEN)) { DPRINTK(1, "invalid mac address !!\n"); DPRINTK(1, "ethernet->h_source=%02X:%02X:%02X:%02X:%02X:%02X\n", - eth->h_source[0],eth->h_source[1],eth->h_source[2], - eth->h_source[3],eth->h_source[4],eth->h_source[5]); + eth->h_source[0], eth->h_source[1], eth->h_source[2], + eth->h_source[3], eth->h_source[4], eth->h_source[5]); return -3; } /* MAC address copy */ - memcpy(p, buffer, 12); /* DST/SRC MAC address */ + memcpy(p, buffer, 12); /* DST/SRC MAC address */ p += 12; buffer += 12; length -= 12; /* EtherType/Length check */ - if (*(buffer+1) + (*buffer << 8) > 1500) { + if (*(buffer + 1) + (*buffer << 8) > 1500) { /* ProtocolEAP = *(buffer+1) + (*buffer << 8); */ - /* DPRINTK(2, "Send [SNAP]Type %x\n",ProtocolEAP); */ + /* DPRINTK(2, "Send [SNAP]Type %x\n",ProtocolEAP); */ /* SAP/CTL/OUI(6 byte) add */ - *p++ = 0xAA; /* DSAP */ - *p++ = 0xAA; /* SSAP */ - *p++ = 0x03; /* CTL */ - *p++ = 0x00; /* OUI ("000000") */ - *p++ = 0x00; /* OUI ("000000") */ - *p++ = 0x00; /* OUI ("000000") */ + *p++ = 0xAA; /* DSAP */ + *p++ = 0xAA; /* SSAP */ + *p++ = 0x03; /* CTL */ + *p++ = 0x00; /* OUI ("000000") */ + *p++ = 0x00; /* OUI ("000000") */ + *p++ = 0x00; /* OUI ("000000") */ packet_len += 6; } else { - DPRINTK(4,"DIX\n"); - /* Length(2 byte) delete */ + DPRINTK(4, "DIX\n"); + /* Length(2 byte) delete */ buffer += 2; length -= 2; packet_len -= 2; @@ -1165,61 +1235,68 @@ int hostif_data_request(struct ks_wlan_private *priv, struct sk_buff *packet) eth_proto = ntohs(eth_hdr->h_proto); /* for MIC FAILUER REPORT check */ - if(eth_proto == ETHER_PROTOCOL_TYPE_EAP && priv->wpa.mic_failure.failure>0){ - aa1x_hdr=(struct ieee802_1x_hdr *)(eth_hdr+1); - if(aa1x_hdr->type == IEEE802_1X_TYPE_EAPOL_KEY){ - eap_key = (struct wpa_eapol_key *)(aa1x_hdr+1); - keyinfo=ntohs(eap_key->key_info); + if (eth_proto == ETHER_PROTOCOL_TYPE_EAP + && priv->wpa.mic_failure.failure > 0) { + aa1x_hdr = (struct ieee802_1x_hdr *)(eth_hdr + 1); + if (aa1x_hdr->type == IEEE802_1X_TYPE_EAPOL_KEY) { + eap_key = (struct wpa_eapol_key *)(aa1x_hdr + 1); + keyinfo = ntohs(eap_key->key_info); } } - if (priv->wpa.rsn_enabled && priv->wpa.key[0].key_len){ - if(eth_proto == ETHER_PROTOCOL_TYPE_EAP && !(priv->wpa.key[1].key_len) && - !(priv->wpa.key[2].key_len) && !(priv->wpa.key[3].key_len)){ - pp->auth_type = cpu_to_le16((uint16_t)TYPE_AUTH); /* no encryption */ - } - else{ - if(priv->wpa.pairwise_suite == IW_AUTH_CIPHER_TKIP){ - MichaelMICFunction( &michel_mic, - (uint8_t*)priv->wpa.key[0].tx_mic_key, - (uint8_t*)&pp->data[0], - (int)packet_len, - (uint8_t)0, /* priority */ - (uint8_t*)michel_mic.Result ); + if (priv->wpa.rsn_enabled && priv->wpa.key[0].key_len) { + if (eth_proto == ETHER_PROTOCOL_TYPE_EAP + && !(priv->wpa.key[1].key_len) + && !(priv->wpa.key[2].key_len) + && !(priv->wpa.key[3].key_len)) { + pp->auth_type = cpu_to_le16((uint16_t) TYPE_AUTH); /* no encryption */ + } else { + if (priv->wpa.pairwise_suite == IW_AUTH_CIPHER_TKIP) { + MichaelMICFunction(&michel_mic, (uint8_t *) priv->wpa.key[0].tx_mic_key, (uint8_t *) & pp->data[0], (int)packet_len, (uint8_t) 0, /* priority */ + (uint8_t *) michel_mic. + Result); memcpy(p, michel_mic.Result, 8); length += 8; packet_len += 8; p += 8; - pp->auth_type = cpu_to_le16((uint16_t)TYPE_DATA); + pp->auth_type = + cpu_to_le16((uint16_t) TYPE_DATA); - }else if(priv->wpa.pairwise_suite == IW_AUTH_CIPHER_CCMP){ - pp->auth_type = cpu_to_le16((uint16_t)TYPE_DATA); + } else if (priv->wpa.pairwise_suite == + IW_AUTH_CIPHER_CCMP) { + pp->auth_type = + cpu_to_le16((uint16_t) TYPE_DATA); } } - } - else{ - if(eth_proto == ETHER_PROTOCOL_TYPE_EAP) - pp->auth_type = cpu_to_le16((uint16_t)TYPE_AUTH); + } else { + if (eth_proto == ETHER_PROTOCOL_TYPE_EAP) + pp->auth_type = cpu_to_le16((uint16_t) TYPE_AUTH); else - pp->auth_type = cpu_to_le16((uint16_t)TYPE_DATA); + pp->auth_type = cpu_to_le16((uint16_t) TYPE_DATA); } /* header value set */ - pp->header.size = cpu_to_le16((uint16_t)(sizeof(*pp)-sizeof(pp->header.size)+packet_len)); - pp->header.event = cpu_to_le16((uint16_t)HIF_DATA_REQ); + pp->header.size = + cpu_to_le16((uint16_t) + (sizeof(*pp) - sizeof(pp->header.size) + packet_len)); + pp->header.event = cpu_to_le16((uint16_t) HIF_DATA_REQ); /* tx request */ - result = ks_wlan_hw_tx(priv, pp, hif_align_size(sizeof(*pp) + packet_len), - (void *)send_packet_complete, (void *)priv, (void *)packet); + result = + ks_wlan_hw_tx(priv, pp, hif_align_size(sizeof(*pp) + packet_len), + (void *)send_packet_complete, (void *)priv, + (void *)packet); /* MIC FAILUER REPORT check */ - if(eth_proto == ETHER_PROTOCOL_TYPE_EAP && priv->wpa.mic_failure.failure>0){ - if(keyinfo & WPA_KEY_INFO_ERROR && keyinfo & WPA_KEY_INFO_REQUEST){ - DPRINTK(3," MIC ERROR Report SET : %04X\n", keyinfo); + if (eth_proto == ETHER_PROTOCOL_TYPE_EAP + && priv->wpa.mic_failure.failure > 0) { + if (keyinfo & WPA_KEY_INFO_ERROR + && keyinfo & WPA_KEY_INFO_REQUEST) { + DPRINTK(3, " MIC ERROR Report SET : %04X\n", keyinfo); hostif_sme_enqueue(priv, SME_MIC_FAILURE_REQUEST); } - if(priv->wpa.mic_failure.failure==2) - priv->wpa.mic_failure.stop=1; + if (priv->wpa.mic_failure.failure == 2) + priv->wpa.mic_failure.stop = 1; } return result; @@ -1231,83 +1308,92 @@ int hostif_data_request(struct ks_wlan_private *priv, struct sk_buff *packet) } }while(0) static -void hostif_mib_get_request( struct ks_wlan_private *priv, unsigned long mib_attribute) +void hostif_mib_get_request(struct ks_wlan_private *priv, + unsigned long mib_attribute) { struct hostif_mib_get_request_t *pp; DPRINTK(3, "\n"); /* make primitive */ - pp = (struct hostif_mib_get_request_t *)kmalloc(hif_align_size(sizeof(*pp)), KS_WLAN_MEM_FLAG ); - if (pp==NULL) { - DPRINTK(3,"allocate memory failed..\n"); + pp = (struct hostif_mib_get_request_t *) + kmalloc(hif_align_size(sizeof(*pp)), KS_WLAN_MEM_FLAG); + if (pp == NULL) { + DPRINTK(3, "allocate memory failed..\n"); return; } - pp->header.size = cpu_to_le16((uint16_t)(sizeof(*pp)-sizeof(pp->header.size))); - pp->header.event = cpu_to_le16((uint16_t)HIF_MIB_GET_REQ); - pp->mib_attribute = cpu_to_le32((uint32_t)mib_attribute); + pp->header.size = + cpu_to_le16((uint16_t) (sizeof(*pp) - sizeof(pp->header.size))); + pp->header.event = cpu_to_le16((uint16_t) HIF_MIB_GET_REQ); + pp->mib_attribute = cpu_to_le32((uint32_t) mib_attribute); /* send to device request */ ps_confirm_wait_inc(priv); - ks_wlan_hw_tx( priv, pp, hif_align_size(sizeof(*pp)), NULL, NULL, NULL); + ks_wlan_hw_tx(priv, pp, hif_align_size(sizeof(*pp)), NULL, NULL, NULL); } static -void hostif_mib_set_request( struct ks_wlan_private *priv, unsigned long mib_attribute, - unsigned short size, unsigned short type, - void *vp ) +void hostif_mib_set_request(struct ks_wlan_private *priv, + unsigned long mib_attribute, unsigned short size, + unsigned short type, void *vp) { struct hostif_mib_set_request_t *pp; - DPRINTK(3,"\n"); + DPRINTK(3, "\n"); if (priv->dev_state < DEVICE_STATE_BOOT) { - DPRINTK(3,"DeviceRemove\n"); + DPRINTK(3, "DeviceRemove\n"); return; } /* make primitive */ - pp = (struct hostif_mib_set_request_t *)kmalloc(hif_align_size(sizeof(*pp)+size), KS_WLAN_MEM_FLAG ); - if (pp==NULL) { + pp = (struct hostif_mib_set_request_t *) + kmalloc(hif_align_size(sizeof(*pp) + size), KS_WLAN_MEM_FLAG); + if (pp == NULL) { DPRINTK(3, "allocate memory failed..\n"); return; } - pp->header.size = cpu_to_le16((uint16_t)(sizeof(*pp)-sizeof(pp->header.size)+size)); - pp->header.event = cpu_to_le16((uint16_t)HIF_MIB_SET_REQ); - pp->mib_attribute = cpu_to_le32((uint32_t)mib_attribute); - pp->mib_value.size = cpu_to_le16((uint16_t)size); - pp->mib_value.type = cpu_to_le16((uint16_t)type); + pp->header.size = + cpu_to_le16((uint16_t) + (sizeof(*pp) - sizeof(pp->header.size) + size)); + pp->header.event = cpu_to_le16((uint16_t) HIF_MIB_SET_REQ); + pp->mib_attribute = cpu_to_le32((uint32_t) mib_attribute); + pp->mib_value.size = cpu_to_le16((uint16_t) size); + pp->mib_value.type = cpu_to_le16((uint16_t) type); memcpy(&pp->mib_value.body, vp, size); /* send to device request */ ps_confirm_wait_inc(priv); - ks_wlan_hw_tx(priv, pp, hif_align_size(sizeof(*pp) + size), NULL, NULL, NULL); + ks_wlan_hw_tx(priv, pp, hif_align_size(sizeof(*pp) + size), NULL, NULL, + NULL); } static -void hostif_start_request( struct ks_wlan_private *priv, unsigned char mode ) +void hostif_start_request(struct ks_wlan_private *priv, unsigned char mode) { struct hostif_start_request_t *pp; - DPRINTK(3,"\n"); + DPRINTK(3, "\n"); /* make primitive */ - pp = (struct hostif_start_request_t *)kmalloc(hif_align_size(sizeof(*pp)), KS_WLAN_MEM_FLAG ); - if (pp==NULL) { + pp = (struct hostif_start_request_t *) + kmalloc(hif_align_size(sizeof(*pp)), KS_WLAN_MEM_FLAG); + if (pp == NULL) { DPRINTK(3, "allocate memory failed..\n"); return; } - pp->header.size = cpu_to_le16((uint16_t)(sizeof(*pp)-sizeof(pp->header.size))); - pp->header.event = cpu_to_le16((uint16_t)HIF_START_REQ); - pp->mode = cpu_to_le16((uint16_t)mode); + pp->header.size = + cpu_to_le16((uint16_t) (sizeof(*pp) - sizeof(pp->header.size))); + pp->header.event = cpu_to_le16((uint16_t) HIF_START_REQ); + pp->mode = cpu_to_le16((uint16_t) mode); /* send to device request */ ps_confirm_wait_inc(priv); ks_wlan_hw_tx(priv, pp, hif_align_size(sizeof(*pp)), NULL, NULL, NULL); priv->aplist.size = 0; - priv->scan_ind_count=0; + priv->scan_ind_count = 0; } static @@ -1316,35 +1402,38 @@ void hostif_ps_adhoc_set_request(struct ks_wlan_private *priv) struct hostif_ps_adhoc_set_request_t *pp; uint16_t capability; - DPRINTK(3,"\n"); + DPRINTK(3, "\n"); /* make primitive */ - pp = (struct hostif_ps_adhoc_set_request_t *)kmalloc(hif_align_size(sizeof(*pp)), KS_WLAN_MEM_FLAG ); - if (pp==NULL) { + pp = (struct hostif_ps_adhoc_set_request_t *) + kmalloc(hif_align_size(sizeof(*pp)), KS_WLAN_MEM_FLAG); + if (pp == NULL) { DPRINTK(3, "allocate memory failed..\n"); return; } memset(pp, 0, sizeof(*pp)); - pp->header.size = cpu_to_le16((uint16_t)(sizeof(*pp)-sizeof(pp->header.size))); - pp->header.event = cpu_to_le16((uint16_t)HIF_PS_ADH_SET_REQ); - pp->phy_type = cpu_to_le16((uint16_t)(priv->reg.phy_type)); - pp->cts_mode = cpu_to_le16((uint16_t)(priv->reg.cts_mode)); - pp->scan_type = cpu_to_le16((uint16_t)(priv->reg.scan_type)); - pp->channel = cpu_to_le16((uint16_t)(priv->reg.channel)); + pp->header.size = + cpu_to_le16((uint16_t) (sizeof(*pp) - sizeof(pp->header.size))); + pp->header.event = cpu_to_le16((uint16_t) HIF_PS_ADH_SET_REQ); + pp->phy_type = cpu_to_le16((uint16_t) (priv->reg.phy_type)); + pp->cts_mode = cpu_to_le16((uint16_t) (priv->reg.cts_mode)); + pp->scan_type = cpu_to_le16((uint16_t) (priv->reg.scan_type)); + pp->channel = cpu_to_le16((uint16_t) (priv->reg.channel)); pp->rate_set.size = priv->reg.rate_set.size; - memcpy(&pp->rate_set.body[0], &priv->reg.rate_set.body[0], priv->reg.rate_set.size); + memcpy(&pp->rate_set.body[0], &priv->reg.rate_set.body[0], + priv->reg.rate_set.size); capability = 0x0000; - if (priv->reg.preamble==SHORT_PREAMBLE) { + if (priv->reg.preamble == SHORT_PREAMBLE) { /* short preamble */ capability |= BSS_CAP_SHORT_PREAMBLE; } - capability &= ~(BSS_CAP_PBCC); /* pbcc not support */ - if(priv->reg.phy_type != D_11B_ONLY_MODE){ - capability |= BSS_CAP_SHORT_SLOT_TIME; /* ShortSlotTime support */ - capability &= ~(BSS_CAP_DSSS_OFDM); /* DSSS OFDM */ + capability &= ~(BSS_CAP_PBCC); /* pbcc not support */ + if (priv->reg.phy_type != D_11B_ONLY_MODE) { + capability |= BSS_CAP_SHORT_SLOT_TIME; /* ShortSlotTime support */ + capability &= ~(BSS_CAP_DSSS_OFDM); /* DSSS OFDM */ } - pp->capability = cpu_to_le16((uint16_t)capability); + pp->capability = cpu_to_le16((uint16_t) capability); /* send to device request */ ps_confirm_wait_inc(priv); @@ -1357,38 +1446,42 @@ void hostif_infrastructure_set_request(struct ks_wlan_private *priv) struct hostif_infrastructure_set_request_t *pp; uint16_t capability; - DPRINTK(3, "ssid.size=%d \n",priv->reg.ssid.size); + DPRINTK(3, "ssid.size=%d \n", priv->reg.ssid.size); /* make primitive */ - pp = (struct hostif_infrastructure_set_request_t *)kmalloc(hif_align_size(sizeof(*pp)), KS_WLAN_MEM_FLAG ); - if (pp==NULL) { + pp = (struct hostif_infrastructure_set_request_t *) + kmalloc(hif_align_size(sizeof(*pp)), KS_WLAN_MEM_FLAG); + if (pp == NULL) { DPRINTK(3, "allocate memory failed..\n"); return; } - pp->header.size = cpu_to_le16((uint16_t)(sizeof(*pp)-sizeof(pp->header.size))); - pp->header.event = cpu_to_le16((uint16_t)HIF_INFRA_SET_REQ); - pp->phy_type = cpu_to_le16((uint16_t)(priv->reg.phy_type)); - pp->cts_mode = cpu_to_le16((uint16_t)(priv->reg.cts_mode)); - pp->scan_type = cpu_to_le16((uint16_t)(priv->reg.scan_type)); + pp->header.size = + cpu_to_le16((uint16_t) (sizeof(*pp) - sizeof(pp->header.size))); + pp->header.event = cpu_to_le16((uint16_t) HIF_INFRA_SET_REQ); + pp->phy_type = cpu_to_le16((uint16_t) (priv->reg.phy_type)); + pp->cts_mode = cpu_to_le16((uint16_t) (priv->reg.cts_mode)); + pp->scan_type = cpu_to_le16((uint16_t) (priv->reg.scan_type)); pp->rate_set.size = priv->reg.rate_set.size; - memcpy(&pp->rate_set.body[0], &priv->reg.rate_set.body[0], priv->reg.rate_set.size); + memcpy(&pp->rate_set.body[0], &priv->reg.rate_set.body[0], + priv->reg.rate_set.size); pp->ssid.size = priv->reg.ssid.size; memcpy(&pp->ssid.body[0], &priv->reg.ssid.body[0], priv->reg.ssid.size); capability = 0x0000; - if (priv->reg.preamble==SHORT_PREAMBLE) { + if (priv->reg.preamble == SHORT_PREAMBLE) { /* short preamble */ capability |= BSS_CAP_SHORT_PREAMBLE; } - capability &= ~(BSS_CAP_PBCC); /* pbcc not support */ - if(priv->reg.phy_type != D_11B_ONLY_MODE){ - capability |= BSS_CAP_SHORT_SLOT_TIME; /* ShortSlotTime support */ - capability &= ~(BSS_CAP_DSSS_OFDM); /* DSSS OFDM not support */ + capability &= ~(BSS_CAP_PBCC); /* pbcc not support */ + if (priv->reg.phy_type != D_11B_ONLY_MODE) { + capability |= BSS_CAP_SHORT_SLOT_TIME; /* ShortSlotTime support */ + capability &= ~(BSS_CAP_DSSS_OFDM); /* DSSS OFDM not support */ } - pp->capability = cpu_to_le16((uint16_t)capability); - pp->beacon_lost_count = cpu_to_le16((uint16_t)(priv->reg.beacon_lost_count)); - pp->auth_type = cpu_to_le16((uint16_t)(priv->reg.authenticate_type)); + pp->capability = cpu_to_le16((uint16_t) capability); + pp->beacon_lost_count = + cpu_to_le16((uint16_t) (priv->reg.beacon_lost_count)); + pp->auth_type = cpu_to_le16((uint16_t) (priv->reg.authenticate_type)); pp->channel_list.body[0] = 1; pp->channel_list.body[1] = 8; @@ -1403,16 +1496,16 @@ void hostif_infrastructure_set_request(struct ks_wlan_private *priv) pp->channel_list.body[10] = 6; pp->channel_list.body[11] = 13; pp->channel_list.body[12] = 7; - if(priv->reg.phy_type == D_11G_ONLY_MODE){ + if (priv->reg.phy_type == D_11G_ONLY_MODE) { pp->channel_list.size = 13; - }else{ + } else { pp->channel_list.body[13] = 14; pp->channel_list.size = 14; } /* send to device request */ ps_confirm_wait_inc(priv); - ks_wlan_hw_tx( priv, pp, hif_align_size(sizeof(*pp)),NULL, NULL, NULL); + ks_wlan_hw_tx(priv, pp, hif_align_size(sizeof(*pp)), NULL, NULL, NULL); } void hostif_infrastructure_set2_request(struct ks_wlan_private *priv) @@ -1420,38 +1513,42 @@ void hostif_infrastructure_set2_request(struct ks_wlan_private *priv) struct hostif_infrastructure_set2_request_t *pp; uint16_t capability; - DPRINTK(2, "ssid.size=%d \n",priv->reg.ssid.size); + DPRINTK(2, "ssid.size=%d \n", priv->reg.ssid.size); /* make primitive */ - pp = (struct hostif_infrastructure_set2_request_t *)kmalloc(hif_align_size(sizeof(*pp)), KS_WLAN_MEM_FLAG ); - if (pp==NULL) { + pp = (struct hostif_infrastructure_set2_request_t *) + kmalloc(hif_align_size(sizeof(*pp)), KS_WLAN_MEM_FLAG); + if (pp == NULL) { DPRINTK(3, "allocate memory failed..\n"); return; } - pp->header.size = cpu_to_le16((uint16_t)(sizeof(*pp)-sizeof(pp->header.size))); - pp->header.event = cpu_to_le16((uint16_t)HIF_INFRA_SET2_REQ); - pp->phy_type = cpu_to_le16((uint16_t)(priv->reg.phy_type)); - pp->cts_mode = cpu_to_le16((uint16_t)(priv->reg.cts_mode)); - pp->scan_type = cpu_to_le16((uint16_t)(priv->reg.scan_type)); + pp->header.size = + cpu_to_le16((uint16_t) (sizeof(*pp) - sizeof(pp->header.size))); + pp->header.event = cpu_to_le16((uint16_t) HIF_INFRA_SET2_REQ); + pp->phy_type = cpu_to_le16((uint16_t) (priv->reg.phy_type)); + pp->cts_mode = cpu_to_le16((uint16_t) (priv->reg.cts_mode)); + pp->scan_type = cpu_to_le16((uint16_t) (priv->reg.scan_type)); pp->rate_set.size = priv->reg.rate_set.size; - memcpy(&pp->rate_set.body[0], &priv->reg.rate_set.body[0], priv->reg.rate_set.size); + memcpy(&pp->rate_set.body[0], &priv->reg.rate_set.body[0], + priv->reg.rate_set.size); pp->ssid.size = priv->reg.ssid.size; memcpy(&pp->ssid.body[0], &priv->reg.ssid.body[0], priv->reg.ssid.size); capability = 0x0000; - if (priv->reg.preamble==SHORT_PREAMBLE) { + if (priv->reg.preamble == SHORT_PREAMBLE) { /* short preamble */ capability |= BSS_CAP_SHORT_PREAMBLE; } - capability &= ~(BSS_CAP_PBCC); /* pbcc not support */ - if(priv->reg.phy_type != D_11B_ONLY_MODE){ - capability |= BSS_CAP_SHORT_SLOT_TIME; /* ShortSlotTime support */ - capability &= ~(BSS_CAP_DSSS_OFDM); /* DSSS OFDM not support */ + capability &= ~(BSS_CAP_PBCC); /* pbcc not support */ + if (priv->reg.phy_type != D_11B_ONLY_MODE) { + capability |= BSS_CAP_SHORT_SLOT_TIME; /* ShortSlotTime support */ + capability &= ~(BSS_CAP_DSSS_OFDM); /* DSSS OFDM not support */ } - pp->capability = cpu_to_le16((uint16_t)capability); - pp->beacon_lost_count = cpu_to_le16((uint16_t)(priv->reg.beacon_lost_count)); - pp->auth_type = cpu_to_le16((uint16_t)(priv->reg.authenticate_type)); + pp->capability = cpu_to_le16((uint16_t) capability); + pp->beacon_lost_count = + cpu_to_le16((uint16_t) (priv->reg.beacon_lost_count)); + pp->auth_type = cpu_to_le16((uint16_t) (priv->reg.authenticate_type)); pp->channel_list.body[0] = 1; pp->channel_list.body[1] = 8; @@ -1466,9 +1563,9 @@ void hostif_infrastructure_set2_request(struct ks_wlan_private *priv) pp->channel_list.body[10] = 6; pp->channel_list.body[11] = 13; pp->channel_list.body[12] = 7; - if(priv->reg.phy_type == D_11G_ONLY_MODE){ + if (priv->reg.phy_type == D_11G_ONLY_MODE) { pp->channel_list.size = 13; - }else{ + } else { pp->channel_list.body[13] = 14; pp->channel_list.size = 14; } @@ -1477,7 +1574,7 @@ void hostif_infrastructure_set2_request(struct ks_wlan_private *priv) /* send to device request */ ps_confirm_wait_inc(priv); - ks_wlan_hw_tx( priv, pp, hif_align_size(sizeof(*pp)),NULL, NULL, NULL); + ks_wlan_hw_tx(priv, pp, hif_align_size(sizeof(*pp)), NULL, NULL, NULL); } static @@ -1489,38 +1586,41 @@ void hostif_adhoc_set_request(struct ks_wlan_private *priv) DPRINTK(3, "\n"); /* make primitive */ - pp = (struct hostif_adhoc_set_request_t *)kmalloc(hif_align_size(sizeof(*pp)), KS_WLAN_MEM_FLAG ); - if (pp==NULL) { + pp = (struct hostif_adhoc_set_request_t *) + kmalloc(hif_align_size(sizeof(*pp)), KS_WLAN_MEM_FLAG); + if (pp == NULL) { DPRINTK(3, "allocate memory failed..\n"); return; } memset(pp, 0, sizeof(*pp)); - pp->header.size = cpu_to_le16((uint16_t)(sizeof(*pp)-sizeof(pp->header.size))); - pp->header.event = cpu_to_le16((uint16_t)HIF_ADH_SET_REQ); - pp->phy_type = cpu_to_le16((uint16_t)(priv->reg.phy_type)); - pp->cts_mode = cpu_to_le16((uint16_t)(priv->reg.cts_mode)); - pp->scan_type = cpu_to_le16((uint16_t)(priv->reg.scan_type)); - pp->channel = cpu_to_le16((uint16_t)(priv->reg.channel)); + pp->header.size = + cpu_to_le16((uint16_t) (sizeof(*pp) - sizeof(pp->header.size))); + pp->header.event = cpu_to_le16((uint16_t) HIF_ADH_SET_REQ); + pp->phy_type = cpu_to_le16((uint16_t) (priv->reg.phy_type)); + pp->cts_mode = cpu_to_le16((uint16_t) (priv->reg.cts_mode)); + pp->scan_type = cpu_to_le16((uint16_t) (priv->reg.scan_type)); + pp->channel = cpu_to_le16((uint16_t) (priv->reg.channel)); pp->rate_set.size = priv->reg.rate_set.size; - memcpy(&pp->rate_set.body[0], &priv->reg.rate_set.body[0], priv->reg.rate_set.size); + memcpy(&pp->rate_set.body[0], &priv->reg.rate_set.body[0], + priv->reg.rate_set.size); pp->ssid.size = priv->reg.ssid.size; memcpy(&pp->ssid.body[0], &priv->reg.ssid.body[0], priv->reg.ssid.size); capability = 0x0000; - if (priv->reg.preamble==SHORT_PREAMBLE) { + if (priv->reg.preamble == SHORT_PREAMBLE) { /* short preamble */ capability |= BSS_CAP_SHORT_PREAMBLE; } - capability &= ~(BSS_CAP_PBCC); /* pbcc not support */ - if(priv->reg.phy_type != D_11B_ONLY_MODE){ - capability |= BSS_CAP_SHORT_SLOT_TIME; /* ShortSlotTime support */ - capability &= ~(BSS_CAP_DSSS_OFDM); /* DSSS OFDM not support */ + capability &= ~(BSS_CAP_PBCC); /* pbcc not support */ + if (priv->reg.phy_type != D_11B_ONLY_MODE) { + capability |= BSS_CAP_SHORT_SLOT_TIME; /* ShortSlotTime support */ + capability &= ~(BSS_CAP_DSSS_OFDM); /* DSSS OFDM not support */ } - pp->capability = cpu_to_le16((uint16_t)capability); + pp->capability = cpu_to_le16((uint16_t) capability); /* send to device request */ ps_confirm_wait_inc(priv); - ks_wlan_hw_tx( priv, pp, hif_align_size(sizeof(*pp)), NULL, NULL, NULL); + ks_wlan_hw_tx(priv, pp, hif_align_size(sizeof(*pp)), NULL, NULL, NULL); } static @@ -1532,33 +1632,36 @@ void hostif_adhoc_set2_request(struct ks_wlan_private *priv) DPRINTK(3, "\n"); /* make primitive */ - pp = (struct hostif_adhoc_set2_request_t *)kmalloc(hif_align_size(sizeof(*pp)), KS_WLAN_MEM_FLAG ); - if (pp==NULL) { + pp = (struct hostif_adhoc_set2_request_t *) + kmalloc(hif_align_size(sizeof(*pp)), KS_WLAN_MEM_FLAG); + if (pp == NULL) { DPRINTK(3, "allocate memory failed..\n"); return; } memset(pp, 0, sizeof(*pp)); - pp->header.size = cpu_to_le16((uint16_t)(sizeof(*pp)-sizeof(pp->header.size))); - pp->header.event = cpu_to_le16((uint16_t)HIF_ADH_SET_REQ); - pp->phy_type = cpu_to_le16((uint16_t)(priv->reg.phy_type)); - pp->cts_mode = cpu_to_le16((uint16_t)(priv->reg.cts_mode)); - pp->scan_type = cpu_to_le16((uint16_t)(priv->reg.scan_type)); + pp->header.size = + cpu_to_le16((uint16_t) (sizeof(*pp) - sizeof(pp->header.size))); + pp->header.event = cpu_to_le16((uint16_t) HIF_ADH_SET_REQ); + pp->phy_type = cpu_to_le16((uint16_t) (priv->reg.phy_type)); + pp->cts_mode = cpu_to_le16((uint16_t) (priv->reg.cts_mode)); + pp->scan_type = cpu_to_le16((uint16_t) (priv->reg.scan_type)); pp->rate_set.size = priv->reg.rate_set.size; - memcpy(&pp->rate_set.body[0], &priv->reg.rate_set.body[0], priv->reg.rate_set.size); + memcpy(&pp->rate_set.body[0], &priv->reg.rate_set.body[0], + priv->reg.rate_set.size); pp->ssid.size = priv->reg.ssid.size; memcpy(&pp->ssid.body[0], &priv->reg.ssid.body[0], priv->reg.ssid.size); capability = 0x0000; - if (priv->reg.preamble==SHORT_PREAMBLE) { + if (priv->reg.preamble == SHORT_PREAMBLE) { /* short preamble */ capability |= BSS_CAP_SHORT_PREAMBLE; } - capability &= ~(BSS_CAP_PBCC); /* pbcc not support */ - if(priv->reg.phy_type != D_11B_ONLY_MODE){ - capability |= BSS_CAP_SHORT_SLOT_TIME; /* ShortSlotTime support */ - capability &= ~(BSS_CAP_DSSS_OFDM); /* DSSS OFDM not support */ + capability &= ~(BSS_CAP_PBCC); /* pbcc not support */ + if (priv->reg.phy_type != D_11B_ONLY_MODE) { + capability |= BSS_CAP_SHORT_SLOT_TIME; /* ShortSlotTime support */ + capability &= ~(BSS_CAP_DSSS_OFDM); /* DSSS OFDM not support */ } - pp->capability = cpu_to_le16((uint16_t)capability); + pp->capability = cpu_to_le16((uint16_t) capability); pp->channel_list.body[0] = priv->reg.channel; pp->channel_list.size = 1; @@ -1566,130 +1669,146 @@ void hostif_adhoc_set2_request(struct ks_wlan_private *priv) /* send to device request */ ps_confirm_wait_inc(priv); - ks_wlan_hw_tx( priv, pp, hif_align_size(sizeof(*pp)), NULL, NULL, NULL); + ks_wlan_hw_tx(priv, pp, hif_align_size(sizeof(*pp)), NULL, NULL, NULL); } static -void hostif_stop_request( struct ks_wlan_private *priv ) +void hostif_stop_request(struct ks_wlan_private *priv) { struct hostif_stop_request_t *pp; - DPRINTK(3,"\n"); + DPRINTK(3, "\n"); /* make primitive */ - pp = (struct hostif_stop_request_t *)kmalloc(hif_align_size(sizeof(*pp)), KS_WLAN_MEM_FLAG ); - if (pp==NULL) { - DPRINTK(3,"allocate memory failed..\n"); + pp = (struct hostif_stop_request_t *) + kmalloc(hif_align_size(sizeof(*pp)), KS_WLAN_MEM_FLAG); + if (pp == NULL) { + DPRINTK(3, "allocate memory failed..\n"); return; } - pp->header.size = cpu_to_le16((uint16_t)(sizeof(*pp)-sizeof(pp->header.size))); - pp->header.event = cpu_to_le16((uint16_t)HIF_STOP_REQ); + pp->header.size = + cpu_to_le16((uint16_t) (sizeof(*pp) - sizeof(pp->header.size))); + pp->header.event = cpu_to_le16((uint16_t) HIF_STOP_REQ); /* send to device request */ ps_confirm_wait_inc(priv); - ks_wlan_hw_tx( priv, pp, hif_align_size(sizeof(*pp)), NULL, NULL, NULL); + ks_wlan_hw_tx(priv, pp, hif_align_size(sizeof(*pp)), NULL, NULL, NULL); } static -void hostif_phy_information_request( struct ks_wlan_private *priv ) +void hostif_phy_information_request(struct ks_wlan_private *priv) { struct hostif_phy_information_request_t *pp; - DPRINTK(3,"\n"); + DPRINTK(3, "\n"); /* make primitive */ - pp = (struct hostif_phy_information_request_t *)kmalloc(hif_align_size(sizeof(*pp)), KS_WLAN_MEM_FLAG ); - if (pp==NULL) { + pp = (struct hostif_phy_information_request_t *) + kmalloc(hif_align_size(sizeof(*pp)), KS_WLAN_MEM_FLAG); + if (pp == NULL) { DPRINTK(3, "allocate memory failed..\n"); return; } - pp->header.size = cpu_to_le16((uint16_t)(sizeof(*pp)-sizeof(pp->header.size))); - pp->header.event = cpu_to_le16((uint16_t)HIF_PHY_INFO_REQ); - if(priv->reg.phy_info_timer){ - pp->type = cpu_to_le16((uint16_t)TIME_TYPE); - pp->time = cpu_to_le16((uint16_t)(priv->reg.phy_info_timer)); - }else{ - pp->type = cpu_to_le16((uint16_t)NORMAL_TYPE); - pp->time = cpu_to_le16((uint16_t)0); + pp->header.size = + cpu_to_le16((uint16_t) (sizeof(*pp) - sizeof(pp->header.size))); + pp->header.event = cpu_to_le16((uint16_t) HIF_PHY_INFO_REQ); + if (priv->reg.phy_info_timer) { + pp->type = cpu_to_le16((uint16_t) TIME_TYPE); + pp->time = cpu_to_le16((uint16_t) (priv->reg.phy_info_timer)); + } else { + pp->type = cpu_to_le16((uint16_t) NORMAL_TYPE); + pp->time = cpu_to_le16((uint16_t) 0); } /* send to device request */ ps_confirm_wait_inc(priv); - ks_wlan_hw_tx( priv, pp, hif_align_size(sizeof(*pp)), NULL, NULL, NULL); + ks_wlan_hw_tx(priv, pp, hif_align_size(sizeof(*pp)), NULL, NULL, NULL); } static -void hostif_power_mngmt_request( struct ks_wlan_private *priv, unsigned long mode, - unsigned long wake_up, unsigned long receiveDTIMs ) +void hostif_power_mngmt_request(struct ks_wlan_private *priv, + unsigned long mode, unsigned long wake_up, + unsigned long receiveDTIMs) { struct hostif_power_mngmt_request_t *pp; - DPRINTK(3,"mode=%lu wake_up=%lu receiveDTIMs=%lu\n",mode,wake_up,receiveDTIMs); + DPRINTK(3, "mode=%lu wake_up=%lu receiveDTIMs=%lu\n", mode, wake_up, + receiveDTIMs); /* make primitive */ - pp = (struct hostif_power_mngmt_request_t *)kmalloc(hif_align_size(sizeof(*pp)), KS_WLAN_MEM_FLAG ); - if (pp==NULL) { - DPRINTK(3,"allocate memory failed..\n"); + pp = (struct hostif_power_mngmt_request_t *) + kmalloc(hif_align_size(sizeof(*pp)), KS_WLAN_MEM_FLAG); + if (pp == NULL) { + DPRINTK(3, "allocate memory failed..\n"); return; } - pp->header.size = cpu_to_le16((uint16_t)(sizeof(*pp)-sizeof(pp->header.size))); - pp->header.event = cpu_to_le16((uint16_t)HIF_POWERMGT_REQ); - pp->mode = cpu_to_le32((uint32_t)mode); - pp->wake_up = cpu_to_le32((uint32_t)wake_up); - pp->receiveDTIMs = cpu_to_le32((uint32_t)receiveDTIMs); + pp->header.size = + cpu_to_le16((uint16_t) (sizeof(*pp) - sizeof(pp->header.size))); + pp->header.event = cpu_to_le16((uint16_t) HIF_POWERMGT_REQ); + pp->mode = cpu_to_le32((uint32_t) mode); + pp->wake_up = cpu_to_le32((uint32_t) wake_up); + pp->receiveDTIMs = cpu_to_le32((uint32_t) receiveDTIMs); /* send to device request */ ps_confirm_wait_inc(priv); - ks_wlan_hw_tx( priv, pp, hif_align_size(sizeof(*pp)), NULL, NULL, NULL); + ks_wlan_hw_tx(priv, pp, hif_align_size(sizeof(*pp)), NULL, NULL, NULL); } static -void hostif_sleep_request( struct ks_wlan_private *priv, unsigned long mode) +void hostif_sleep_request(struct ks_wlan_private *priv, unsigned long mode) { struct hostif_sleep_request_t *pp; - DPRINTK(3,"mode=%lu \n",mode); + DPRINTK(3, "mode=%lu \n", mode); - if(mode == SLP_SLEEP){ + if (mode == SLP_SLEEP) { /* make primitive */ - pp = (struct hostif_sleep_request_t *)kmalloc(hif_align_size(sizeof(*pp)), KS_WLAN_MEM_FLAG ); - if (pp==NULL) { - DPRINTK(3,"allocate memory failed..\n"); + pp = (struct hostif_sleep_request_t *) + kmalloc(hif_align_size(sizeof(*pp)), KS_WLAN_MEM_FLAG); + if (pp == NULL) { + DPRINTK(3, "allocate memory failed..\n"); return; } - pp->header.size = cpu_to_le16((uint16_t)(sizeof(*pp)-sizeof(pp->header.size))); - pp->header.event = cpu_to_le16((uint16_t)HIF_SLEEP_REQ); + pp->header.size = + cpu_to_le16((uint16_t) + (sizeof(*pp) - sizeof(pp->header.size))); + pp->header.event = cpu_to_le16((uint16_t) HIF_SLEEP_REQ); /* send to device request */ ps_confirm_wait_inc(priv); - ks_wlan_hw_tx( priv, pp, hif_align_size(sizeof(*pp)), NULL, NULL, NULL); - }else if(mode == SLP_ACTIVE){ - atomic_set(&priv->sleepstatus.wakeup_request,1); - queue_delayed_work(priv->ks_wlan_hw.ks7010sdio_wq,&priv->ks_wlan_hw.rw_wq, 1); - }else{ - DPRINTK(3,"invalid mode %ld \n", mode); + ks_wlan_hw_tx(priv, pp, hif_align_size(sizeof(*pp)), NULL, NULL, + NULL); + } else if (mode == SLP_ACTIVE) { + atomic_set(&priv->sleepstatus.wakeup_request, 1); + queue_delayed_work(priv->ks_wlan_hw.ks7010sdio_wq, + &priv->ks_wlan_hw.rw_wq, 1); + } else { + DPRINTK(3, "invalid mode %ld \n", mode); return; } } - static -void hostif_bss_scan_request( struct ks_wlan_private *priv, unsigned long scan_type , uint8_t *scan_ssid, uint8_t scan_ssid_len) +void hostif_bss_scan_request(struct ks_wlan_private *priv, + unsigned long scan_type, uint8_t * scan_ssid, + uint8_t scan_ssid_len) { struct hostif_bss_scan_request_t *pp; - DPRINTK(2,"\n"); + DPRINTK(2, "\n"); /* make primitive */ - pp = (struct hostif_bss_scan_request_t *)kmalloc(hif_align_size(sizeof(*pp)), KS_WLAN_MEM_FLAG ); - if (pp==NULL) { - DPRINTK(3,"allocate memory failed..\n"); + pp = (struct hostif_bss_scan_request_t *) + kmalloc(hif_align_size(sizeof(*pp)), KS_WLAN_MEM_FLAG); + if (pp == NULL) { + DPRINTK(3, "allocate memory failed..\n"); return; } - pp->header.size = cpu_to_le16((uint16_t)(sizeof(*pp)-sizeof(pp->header.size))); - pp->header.event = cpu_to_le16((uint16_t)HIF_SCAN_REQ); + pp->header.size = + cpu_to_le16((uint16_t) (sizeof(*pp) - sizeof(pp->header.size))); + pp->header.event = cpu_to_le16((uint16_t) HIF_SCAN_REQ); pp->scan_type = scan_type; - pp->ch_time_min = cpu_to_le32((uint32_t)110); /* default value */ - pp->ch_time_max = cpu_to_le32((uint32_t)130); /* default value */ + pp->ch_time_min = cpu_to_le32((uint32_t) 110); /* default value */ + pp->ch_time_max = cpu_to_le32((uint32_t) 130); /* default value */ pp->channel_list.body[0] = 1; pp->channel_list.body[1] = 8; pp->channel_list.body[2] = 2; @@ -1703,57 +1822,60 @@ void hostif_bss_scan_request( struct ks_wlan_private *priv, unsigned long scan_t pp->channel_list.body[10] = 6; pp->channel_list.body[11] = 13; pp->channel_list.body[12] = 7; - if(priv->reg.phy_type == D_11G_ONLY_MODE){ + if (priv->reg.phy_type == D_11G_ONLY_MODE) { pp->channel_list.size = 13; - }else{ + } else { pp->channel_list.body[13] = 14; pp->channel_list.size = 14; } pp->ssid.size = 0; /* specified SSID SCAN */ - if(scan_ssid_len > 0 && scan_ssid_len <= 32){ + if (scan_ssid_len > 0 && scan_ssid_len <= 32) { pp->ssid.size = scan_ssid_len; memcpy(&pp->ssid.body[0], scan_ssid, scan_ssid_len); } - /* send to device request */ ps_confirm_wait_inc(priv); - ks_wlan_hw_tx( priv, pp, hif_align_size(sizeof(*pp)), NULL, NULL, NULL); + ks_wlan_hw_tx(priv, pp, hif_align_size(sizeof(*pp)), NULL, NULL, NULL); priv->aplist.size = 0; - priv->scan_ind_count=0; + priv->scan_ind_count = 0; } static -void hostif_mic_failure_request( struct ks_wlan_private *priv, unsigned short failure_count, - unsigned short timer ) +void hostif_mic_failure_request(struct ks_wlan_private *priv, + unsigned short failure_count, + unsigned short timer) { struct hostif_mic_failure_request_t *pp; - DPRINTK(3,"count=%d :: timer=%d\n",failure_count,timer); + DPRINTK(3, "count=%d :: timer=%d\n", failure_count, timer); /* make primitive */ - pp = (struct hostif_mic_failure_request_t *)kmalloc(hif_align_size(sizeof(*pp)), KS_WLAN_MEM_FLAG ); - if (pp==NULL) { - DPRINTK(3,"allocate memory failed..\n"); + pp = (struct hostif_mic_failure_request_t *) + kmalloc(hif_align_size(sizeof(*pp)), KS_WLAN_MEM_FLAG); + if (pp == NULL) { + DPRINTK(3, "allocate memory failed..\n"); return; } - pp->header.size = cpu_to_le16((uint16_t)(sizeof(*pp)-sizeof(pp->header.size))); - pp->header.event = cpu_to_le16((uint16_t)HIF_MIC_FAILURE_REQ); - pp->failure_count = cpu_to_le16((uint16_t)failure_count); - pp->timer = cpu_to_le16((uint16_t)timer); + pp->header.size = + cpu_to_le16((uint16_t) (sizeof(*pp) - sizeof(pp->header.size))); + pp->header.event = cpu_to_le16((uint16_t) HIF_MIC_FAILURE_REQ); + pp->failure_count = cpu_to_le16((uint16_t) failure_count); + pp->timer = cpu_to_le16((uint16_t) timer); /* send to device request */ ps_confirm_wait_inc(priv); - ks_wlan_hw_tx( priv, pp, hif_align_size(sizeof(*pp)), NULL, NULL, NULL); + ks_wlan_hw_tx(priv, pp, hif_align_size(sizeof(*pp)), NULL, NULL, NULL); } /* Device I/O Recieve indicate */ -static void devio_rec_ind(struct ks_wlan_private *priv, unsigned char *p, unsigned int size) +static void devio_rec_ind(struct ks_wlan_private *priv, unsigned char *p, + unsigned int size) { if (priv->device_open_status) { - spin_lock(&priv->dev_read_lock); /* request spin lock */ + spin_lock(&priv->dev_read_lock); /* request spin lock */ priv->dev_data[atomic_read(&priv->rec_count)] = p; priv->dev_size[atomic_read(&priv->rec_count)] = size; @@ -1762,86 +1884,92 @@ static void devio_rec_ind(struct ks_wlan_private *priv, unsigned char *p, unsign atomic_inc(&priv->event_count); } atomic_inc(&priv->rec_count); - if (atomic_read(&priv->rec_count)==DEVICE_STOCK_COUNT) + if (atomic_read(&priv->rec_count) == DEVICE_STOCK_COUNT) atomic_set(&priv->rec_count, 0); - wake_up_interruptible_all(&priv->devread_wait); + wake_up_interruptible_all(&priv->devread_wait); /* release spin lock */ spin_unlock(&priv->dev_read_lock); } } -void hostif_receive( struct ks_wlan_private *priv, unsigned char *p, unsigned int size ) +void hostif_receive(struct ks_wlan_private *priv, unsigned char *p, + unsigned int size) { - DPRINTK(4,"\n"); + DPRINTK(4, "\n"); devio_rec_ind(priv, p, size); priv->rxp = p; priv->rx_size = size; - if (get_WORD(priv) == priv->rx_size) { /* length check !! */ - hostif_event_check(priv); /* event check */ + if (get_WORD(priv) == priv->rx_size) { /* length check !! */ + hostif_event_check(priv); /* event check */ } } - static void hostif_sme_set_wep(struct ks_wlan_private *priv, int type) { uint32_t val; - switch(type){ + switch (type) { case SME_WEP_INDEX_REQUEST: - val = cpu_to_le32((uint32_t)(priv->reg.wep_index)); + val = cpu_to_le32((uint32_t) (priv->reg.wep_index)); hostif_mib_set_request(priv, DOT11_WEP_DEFAULT_KEY_ID, - sizeof(val), MIB_VALUE_TYPE_INT, - &val ); + sizeof(val), MIB_VALUE_TYPE_INT, &val); break; case SME_WEP_KEY1_REQUEST: - if(!priv->wpa.wpa_enabled) - hostif_mib_set_request(priv, DOT11_WEP_DEFAULT_KEY_VALUE1, - priv->reg.wep_key[0].size, MIB_VALUE_TYPE_OSTRING, - &priv->reg.wep_key[0].val[0] ); + if (!priv->wpa.wpa_enabled) + hostif_mib_set_request(priv, + DOT11_WEP_DEFAULT_KEY_VALUE1, + priv->reg.wep_key[0].size, + MIB_VALUE_TYPE_OSTRING, + &priv->reg.wep_key[0].val[0]); break; case SME_WEP_KEY2_REQUEST: - if(!priv->wpa.wpa_enabled) - hostif_mib_set_request(priv, DOT11_WEP_DEFAULT_KEY_VALUE2, - priv->reg.wep_key[1].size, MIB_VALUE_TYPE_OSTRING, + if (!priv->wpa.wpa_enabled) + hostif_mib_set_request(priv, + DOT11_WEP_DEFAULT_KEY_VALUE2, + priv->reg.wep_key[1].size, + MIB_VALUE_TYPE_OSTRING, &priv->reg.wep_key[1].val[0]); break; case SME_WEP_KEY3_REQUEST: - if(!priv->wpa.wpa_enabled) - hostif_mib_set_request(priv, DOT11_WEP_DEFAULT_KEY_VALUE3, - priv->reg.wep_key[2].size, MIB_VALUE_TYPE_OSTRING, - &priv->reg.wep_key[2].val[0] ); + if (!priv->wpa.wpa_enabled) + hostif_mib_set_request(priv, + DOT11_WEP_DEFAULT_KEY_VALUE3, + priv->reg.wep_key[2].size, + MIB_VALUE_TYPE_OSTRING, + &priv->reg.wep_key[2].val[0]); break; case SME_WEP_KEY4_REQUEST: - if(!priv->wpa.wpa_enabled) - hostif_mib_set_request(priv, DOT11_WEP_DEFAULT_KEY_VALUE4, - priv->reg.wep_key[3].size, MIB_VALUE_TYPE_OSTRING, + if (!priv->wpa.wpa_enabled) + hostif_mib_set_request(priv, + DOT11_WEP_DEFAULT_KEY_VALUE4, + priv->reg.wep_key[3].size, + MIB_VALUE_TYPE_OSTRING, &priv->reg.wep_key[3].val[0]); break; case SME_WEP_FLAG_REQUEST: - val = cpu_to_le32((uint32_t)(priv->reg.privacy_invoked)); + val = cpu_to_le32((uint32_t) (priv->reg.privacy_invoked)); hostif_mib_set_request(priv, DOT11_PRIVACY_INVOKED, - sizeof(val), MIB_VALUE_TYPE_BOOL, - &val ); + sizeof(val), MIB_VALUE_TYPE_BOOL, &val); break; } - return ; + return; } struct wpa_suite_t { unsigned short size; unsigned char suite[4][CIPHER_ID_LEN]; -} __attribute__((packed)); +} __attribute__ ((packed)); struct rsn_mode_t { uint32_t rsn_mode; uint16_t rsn_capability; -} __attribute__((packed)); +} __attribute__ ((packed)); static void hostif_sme_set_rsn(struct ks_wlan_private *priv, int type) @@ -1850,140 +1978,172 @@ void hostif_sme_set_rsn(struct ks_wlan_private *priv, int type) struct rsn_mode_t rsn_mode; uint32_t val; - memset(&wpa_suite,0,sizeof(wpa_suite)); + memset(&wpa_suite, 0, sizeof(wpa_suite)); - switch(type){ + switch (type) { case SME_RSN_UCAST_REQUEST: - wpa_suite.size=cpu_to_le16((uint16_t)1); - switch(priv->wpa.pairwise_suite){ + wpa_suite.size = cpu_to_le16((uint16_t) 1); + switch (priv->wpa.pairwise_suite) { case IW_AUTH_CIPHER_NONE: - if(priv->wpa.version == IW_AUTH_WPA_VERSION_WPA2) - memcpy(&wpa_suite.suite[0][0],CIPHER_ID_WPA2_NONE,CIPHER_ID_LEN); + if (priv->wpa.version == IW_AUTH_WPA_VERSION_WPA2) + memcpy(&wpa_suite.suite[0][0], + CIPHER_ID_WPA2_NONE, CIPHER_ID_LEN); else - memcpy(&wpa_suite.suite[0][0],CIPHER_ID_WPA_NONE,CIPHER_ID_LEN); + memcpy(&wpa_suite.suite[0][0], + CIPHER_ID_WPA_NONE, CIPHER_ID_LEN); break; case IW_AUTH_CIPHER_WEP40: - if(priv->wpa.version == IW_AUTH_WPA_VERSION_WPA2) - memcpy(&wpa_suite.suite[0][0],CIPHER_ID_WPA2_WEP40,CIPHER_ID_LEN); + if (priv->wpa.version == IW_AUTH_WPA_VERSION_WPA2) + memcpy(&wpa_suite.suite[0][0], + CIPHER_ID_WPA2_WEP40, CIPHER_ID_LEN); else - memcpy(&wpa_suite.suite[0][0],CIPHER_ID_WPA_WEP40,CIPHER_ID_LEN); + memcpy(&wpa_suite.suite[0][0], + CIPHER_ID_WPA_WEP40, CIPHER_ID_LEN); break; case IW_AUTH_CIPHER_TKIP: - if(priv->wpa.version == IW_AUTH_WPA_VERSION_WPA2) - memcpy(&wpa_suite.suite[0][0],CIPHER_ID_WPA2_TKIP,CIPHER_ID_LEN); + if (priv->wpa.version == IW_AUTH_WPA_VERSION_WPA2) + memcpy(&wpa_suite.suite[0][0], + CIPHER_ID_WPA2_TKIP, CIPHER_ID_LEN); else - memcpy(&wpa_suite.suite[0][0],CIPHER_ID_WPA_TKIP,CIPHER_ID_LEN); + memcpy(&wpa_suite.suite[0][0], + CIPHER_ID_WPA_TKIP, CIPHER_ID_LEN); break; case IW_AUTH_CIPHER_CCMP: - if(priv->wpa.version == IW_AUTH_WPA_VERSION_WPA2) - memcpy(&wpa_suite.suite[0][0],CIPHER_ID_WPA2_CCMP,CIPHER_ID_LEN); + if (priv->wpa.version == IW_AUTH_WPA_VERSION_WPA2) + memcpy(&wpa_suite.suite[0][0], + CIPHER_ID_WPA2_CCMP, CIPHER_ID_LEN); else - memcpy(&wpa_suite.suite[0][0],CIPHER_ID_WPA_CCMP,CIPHER_ID_LEN); + memcpy(&wpa_suite.suite[0][0], + CIPHER_ID_WPA_CCMP, CIPHER_ID_LEN); break; case IW_AUTH_CIPHER_WEP104: - if(priv->wpa.version == IW_AUTH_WPA_VERSION_WPA2) - memcpy(&wpa_suite.suite[0][0],CIPHER_ID_WPA2_WEP104,CIPHER_ID_LEN); + if (priv->wpa.version == IW_AUTH_WPA_VERSION_WPA2) + memcpy(&wpa_suite.suite[0][0], + CIPHER_ID_WPA2_WEP104, CIPHER_ID_LEN); else - memcpy(&wpa_suite.suite[0][0],CIPHER_ID_WPA_WEP104,CIPHER_ID_LEN); + memcpy(&wpa_suite.suite[0][0], + CIPHER_ID_WPA_WEP104, CIPHER_ID_LEN); break; } hostif_mib_set_request(priv, DOT11_RSN_CONFIG_UNICAST_CIPHER, - sizeof(wpa_suite.size)+CIPHER_ID_LEN*wpa_suite.size, + sizeof(wpa_suite.size) + + CIPHER_ID_LEN * wpa_suite.size, MIB_VALUE_TYPE_OSTRING, &wpa_suite); break; case SME_RSN_MCAST_REQUEST: - switch(priv->wpa.group_suite){ + switch (priv->wpa.group_suite) { case IW_AUTH_CIPHER_NONE: - if(priv->wpa.version == IW_AUTH_WPA_VERSION_WPA2) - memcpy(&wpa_suite.suite[0][0],CIPHER_ID_WPA2_NONE,CIPHER_ID_LEN); + if (priv->wpa.version == IW_AUTH_WPA_VERSION_WPA2) + memcpy(&wpa_suite.suite[0][0], + CIPHER_ID_WPA2_NONE, CIPHER_ID_LEN); else - memcpy(&wpa_suite.suite[0][0],CIPHER_ID_WPA_NONE,CIPHER_ID_LEN); + memcpy(&wpa_suite.suite[0][0], + CIPHER_ID_WPA_NONE, CIPHER_ID_LEN); break; case IW_AUTH_CIPHER_WEP40: - if(priv->wpa.version == IW_AUTH_WPA_VERSION_WPA2) - memcpy(&wpa_suite.suite[0][0],CIPHER_ID_WPA2_WEP40,CIPHER_ID_LEN); + if (priv->wpa.version == IW_AUTH_WPA_VERSION_WPA2) + memcpy(&wpa_suite.suite[0][0], + CIPHER_ID_WPA2_WEP40, CIPHER_ID_LEN); else - memcpy(&wpa_suite.suite[0][0],CIPHER_ID_WPA_WEP40,CIPHER_ID_LEN); + memcpy(&wpa_suite.suite[0][0], + CIPHER_ID_WPA_WEP40, CIPHER_ID_LEN); break; case IW_AUTH_CIPHER_TKIP: - if(priv->wpa.version == IW_AUTH_WPA_VERSION_WPA2) - memcpy(&wpa_suite.suite[0][0],CIPHER_ID_WPA2_TKIP,CIPHER_ID_LEN); + if (priv->wpa.version == IW_AUTH_WPA_VERSION_WPA2) + memcpy(&wpa_suite.suite[0][0], + CIPHER_ID_WPA2_TKIP, CIPHER_ID_LEN); else - memcpy(&wpa_suite.suite[0][0],CIPHER_ID_WPA_TKIP,CIPHER_ID_LEN); + memcpy(&wpa_suite.suite[0][0], + CIPHER_ID_WPA_TKIP, CIPHER_ID_LEN); break; case IW_AUTH_CIPHER_CCMP: - if(priv->wpa.version == IW_AUTH_WPA_VERSION_WPA2) - memcpy(&wpa_suite.suite[0][0],CIPHER_ID_WPA2_CCMP,CIPHER_ID_LEN); + if (priv->wpa.version == IW_AUTH_WPA_VERSION_WPA2) + memcpy(&wpa_suite.suite[0][0], + CIPHER_ID_WPA2_CCMP, CIPHER_ID_LEN); else - memcpy(&wpa_suite.suite[0][0],CIPHER_ID_WPA_CCMP,CIPHER_ID_LEN); + memcpy(&wpa_suite.suite[0][0], + CIPHER_ID_WPA_CCMP, CIPHER_ID_LEN); break; case IW_AUTH_CIPHER_WEP104: - if(priv->wpa.version == IW_AUTH_WPA_VERSION_WPA2) - memcpy(&wpa_suite.suite[0][0],CIPHER_ID_WPA2_WEP104,CIPHER_ID_LEN); + if (priv->wpa.version == IW_AUTH_WPA_VERSION_WPA2) + memcpy(&wpa_suite.suite[0][0], + CIPHER_ID_WPA2_WEP104, CIPHER_ID_LEN); else - memcpy(&wpa_suite.suite[0][0],CIPHER_ID_WPA_WEP104,CIPHER_ID_LEN); + memcpy(&wpa_suite.suite[0][0], + CIPHER_ID_WPA_WEP104, CIPHER_ID_LEN); break; } hostif_mib_set_request(priv, DOT11_RSN_CONFIG_MULTICAST_CIPHER, CIPHER_ID_LEN, MIB_VALUE_TYPE_OSTRING, - &wpa_suite.suite[0][0] ); + &wpa_suite.suite[0][0]); break; case SME_RSN_AUTH_REQUEST: - wpa_suite.size=cpu_to_le16((uint16_t)1); - switch(priv->wpa.key_mgmt_suite){ + wpa_suite.size = cpu_to_le16((uint16_t) 1); + switch (priv->wpa.key_mgmt_suite) { case IW_AUTH_KEY_MGMT_802_1X: - if(priv->wpa.version == IW_AUTH_WPA_VERSION_WPA2) - memcpy(&wpa_suite.suite[0][0],KEY_MGMT_ID_WPA2_1X,KEY_MGMT_ID_LEN); + if (priv->wpa.version == IW_AUTH_WPA_VERSION_WPA2) + memcpy(&wpa_suite.suite[0][0], + KEY_MGMT_ID_WPA2_1X, KEY_MGMT_ID_LEN); else - memcpy(&wpa_suite.suite[0][0],KEY_MGMT_ID_WPA_1X,KEY_MGMT_ID_LEN); + memcpy(&wpa_suite.suite[0][0], + KEY_MGMT_ID_WPA_1X, KEY_MGMT_ID_LEN); break; case IW_AUTH_KEY_MGMT_PSK: - if(priv->wpa.version == IW_AUTH_WPA_VERSION_WPA2) - memcpy(&wpa_suite.suite[0][0],KEY_MGMT_ID_WPA2_PSK,KEY_MGMT_ID_LEN); + if (priv->wpa.version == IW_AUTH_WPA_VERSION_WPA2) + memcpy(&wpa_suite.suite[0][0], + KEY_MGMT_ID_WPA2_PSK, KEY_MGMT_ID_LEN); else - memcpy(&wpa_suite.suite[0][0],KEY_MGMT_ID_WPA_PSK,KEY_MGMT_ID_LEN); + memcpy(&wpa_suite.suite[0][0], + KEY_MGMT_ID_WPA_PSK, KEY_MGMT_ID_LEN); break; case 0: - if(priv->wpa.version == IW_AUTH_WPA_VERSION_WPA2) - memcpy(&wpa_suite.suite[0][0],KEY_MGMT_ID_WPA2_NONE,KEY_MGMT_ID_LEN); + if (priv->wpa.version == IW_AUTH_WPA_VERSION_WPA2) + memcpy(&wpa_suite.suite[0][0], + KEY_MGMT_ID_WPA2_NONE, KEY_MGMT_ID_LEN); else - memcpy(&wpa_suite.suite[0][0],KEY_MGMT_ID_WPA_NONE,KEY_MGMT_ID_LEN); + memcpy(&wpa_suite.suite[0][0], + KEY_MGMT_ID_WPA_NONE, KEY_MGMT_ID_LEN); break; case 4: - if(priv->wpa.version == IW_AUTH_WPA_VERSION_WPA2) - memcpy(&wpa_suite.suite[0][0],KEY_MGMT_ID_WPA2_WPANONE,KEY_MGMT_ID_LEN); + if (priv->wpa.version == IW_AUTH_WPA_VERSION_WPA2) + memcpy(&wpa_suite.suite[0][0], + KEY_MGMT_ID_WPA2_WPANONE, + KEY_MGMT_ID_LEN); else - memcpy(&wpa_suite.suite[0][0],KEY_MGMT_ID_WPA_WPANONE,KEY_MGMT_ID_LEN); + memcpy(&wpa_suite.suite[0][0], + KEY_MGMT_ID_WPA_WPANONE, + KEY_MGMT_ID_LEN); break; } hostif_mib_set_request(priv, DOT11_RSN_CONFIG_AUTH_SUITE, - sizeof(wpa_suite.size)+KEY_MGMT_ID_LEN*wpa_suite.size, + sizeof(wpa_suite.size) + + KEY_MGMT_ID_LEN * wpa_suite.size, MIB_VALUE_TYPE_OSTRING, &wpa_suite); break; case SME_RSN_ENABLED_REQUEST: - val = cpu_to_le32((uint32_t)(priv->wpa.rsn_enabled)); + val = cpu_to_le32((uint32_t) (priv->wpa.rsn_enabled)); hostif_mib_set_request(priv, DOT11_RSN_ENABLED, - sizeof(val), MIB_VALUE_TYPE_BOOL, - &val ); + sizeof(val), MIB_VALUE_TYPE_BOOL, &val); break; case SME_RSN_MODE_REQUEST: - if(priv->wpa.version == IW_AUTH_WPA_VERSION_WPA2){ - rsn_mode.rsn_mode = cpu_to_le32((uint32_t)RSN_MODE_WPA2); - rsn_mode.rsn_capability = cpu_to_le16((uint16_t)0); - } - else if(priv->wpa.version == IW_AUTH_WPA_VERSION_WPA){ - rsn_mode.rsn_mode = cpu_to_le32((uint32_t)RSN_MODE_WPA); - rsn_mode.rsn_capability = cpu_to_le16((uint16_t)0); - } - else{ - rsn_mode.rsn_mode = cpu_to_le32((uint32_t)RSN_MODE_NONE); - rsn_mode.rsn_capability = cpu_to_le16((uint16_t)0); + if (priv->wpa.version == IW_AUTH_WPA_VERSION_WPA2) { + rsn_mode.rsn_mode = + cpu_to_le32((uint32_t) RSN_MODE_WPA2); + rsn_mode.rsn_capability = cpu_to_le16((uint16_t) 0); + } else if (priv->wpa.version == IW_AUTH_WPA_VERSION_WPA) { + rsn_mode.rsn_mode = + cpu_to_le32((uint32_t) RSN_MODE_WPA); + rsn_mode.rsn_capability = cpu_to_le16((uint16_t) 0); + } else { + rsn_mode.rsn_mode = + cpu_to_le32((uint32_t) RSN_MODE_NONE); + rsn_mode.rsn_capability = cpu_to_le16((uint16_t) 0); } - hostif_mib_set_request(priv, LOCAL_RSN_MODE,sizeof(rsn_mode), - MIB_VALUE_TYPE_OSTRING,&rsn_mode ); + hostif_mib_set_request(priv, LOCAL_RSN_MODE, sizeof(rsn_mode), + MIB_VALUE_TYPE_OSTRING, &rsn_mode); break; } @@ -1995,64 +2155,70 @@ void hostif_sme_mode_setup(struct ks_wlan_private *priv) { unsigned char rate_size; unsigned char rate_octet[RATE_SET_MAX_SIZE]; - int i=0; + int i = 0; - /* rate setting if rate segging is auto for changing phy_type (#94)*/ - if(priv->reg.tx_rate == TX_RATE_FULL_AUTO){ - if(priv->reg.phy_type == D_11B_ONLY_MODE){ + /* rate setting if rate segging is auto for changing phy_type (#94) */ + if (priv->reg.tx_rate == TX_RATE_FULL_AUTO) { + if (priv->reg.phy_type == D_11B_ONLY_MODE) { priv->reg.rate_set.body[3] = TX_RATE_11M; priv->reg.rate_set.body[2] = TX_RATE_5M; - priv->reg.rate_set.body[1] = TX_RATE_2M|BASIC_RATE; - priv->reg.rate_set.body[0] = TX_RATE_1M|BASIC_RATE; + priv->reg.rate_set.body[1] = TX_RATE_2M | BASIC_RATE; + priv->reg.rate_set.body[0] = TX_RATE_1M | BASIC_RATE; priv->reg.rate_set.size = 4; - }else{ /* D_11G_ONLY_MODE or D_11BG_COMPATIBLE_MODE */ + } else { /* D_11G_ONLY_MODE or D_11BG_COMPATIBLE_MODE */ priv->reg.rate_set.body[11] = TX_RATE_54M; priv->reg.rate_set.body[10] = TX_RATE_48M; priv->reg.rate_set.body[9] = TX_RATE_36M; priv->reg.rate_set.body[8] = TX_RATE_18M; priv->reg.rate_set.body[7] = TX_RATE_9M; - priv->reg.rate_set.body[6] = TX_RATE_24M|BASIC_RATE; - priv->reg.rate_set.body[5] = TX_RATE_12M|BASIC_RATE; - priv->reg.rate_set.body[4] = TX_RATE_6M|BASIC_RATE; - priv->reg.rate_set.body[3] = TX_RATE_11M|BASIC_RATE; - priv->reg.rate_set.body[2] = TX_RATE_5M|BASIC_RATE; - priv->reg.rate_set.body[1] = TX_RATE_2M|BASIC_RATE; - priv->reg.rate_set.body[0] = TX_RATE_1M|BASIC_RATE; + priv->reg.rate_set.body[6] = TX_RATE_24M | BASIC_RATE; + priv->reg.rate_set.body[5] = TX_RATE_12M | BASIC_RATE; + priv->reg.rate_set.body[4] = TX_RATE_6M | BASIC_RATE; + priv->reg.rate_set.body[3] = TX_RATE_11M | BASIC_RATE; + priv->reg.rate_set.body[2] = TX_RATE_5M | BASIC_RATE; + priv->reg.rate_set.body[1] = TX_RATE_2M | BASIC_RATE; + priv->reg.rate_set.body[0] = TX_RATE_1M | BASIC_RATE; priv->reg.rate_set.size = 12; } } /* rate mask by phy setting */ - if(priv->reg.phy_type == D_11B_ONLY_MODE){ - for(i=0;ireg.rate_set.size;i++){ - if(IS_11B_RATE(priv->reg.rate_set.body[i])){ - if((priv->reg.rate_set.body[i] & RATE_MASK) >= TX_RATE_5M) - rate_octet[i] = priv->reg.rate_set.body[i] & RATE_MASK ; + if (priv->reg.phy_type == D_11B_ONLY_MODE) { + for (i = 0; i < priv->reg.rate_set.size; i++) { + if (IS_11B_RATE(priv->reg.rate_set.body[i])) { + if ((priv->reg.rate_set.body[i] & RATE_MASK) >= + TX_RATE_5M) + rate_octet[i] = + priv->reg.rate_set. + body[i] & RATE_MASK; else - rate_octet[i] = priv->reg.rate_set.body[i]; - } - else + rate_octet[i] = + priv->reg.rate_set.body[i]; + } else break; } - }else{ /* D_11G_ONLY_MODE or D_11BG_COMPATIBLE_MODE */ - for(i=0;ireg.rate_set.size;i++){ - if(IS_11BG_RATE(priv->reg.rate_set.body[i])){ - if(IS_OFDM_EXT_RATE(priv->reg.rate_set.body[i])) - rate_octet[i] = priv->reg.rate_set.body[i] & RATE_MASK ; + } else { /* D_11G_ONLY_MODE or D_11BG_COMPATIBLE_MODE */ + for (i = 0; i < priv->reg.rate_set.size; i++) { + if (IS_11BG_RATE(priv->reg.rate_set.body[i])) { + if (IS_OFDM_EXT_RATE + (priv->reg.rate_set.body[i])) + rate_octet[i] = + priv->reg.rate_set. + body[i] & RATE_MASK; else - rate_octet[i] = priv->reg.rate_set.body[i]; - } - else + rate_octet[i] = + priv->reg.rate_set.body[i]; + } else break; } } rate_size = i; - if(rate_size==0){ - if(priv->reg.phy_type == D_11G_ONLY_MODE) - rate_octet[0]=TX_RATE_6M | BASIC_RATE; + if (rate_size == 0) { + if (priv->reg.phy_type == D_11G_ONLY_MODE) + rate_octet[0] = TX_RATE_6M | BASIC_RATE; else - rate_octet[0]=TX_RATE_2M | BASIC_RATE; + rate_octet[0] = TX_RATE_2M | BASIC_RATE; rate_size = 1; } @@ -2060,84 +2226,93 @@ void hostif_sme_mode_setup(struct ks_wlan_private *priv) priv->reg.rate_set.size = rate_size; memcpy(&priv->reg.rate_set.body[0], &rate_octet[0], rate_size); - switch ( priv->reg.operation_mode ) { + switch (priv->reg.operation_mode) { case MODE_PSEUDO_ADHOC: /* Pseudo Ad-Hoc mode */ hostif_ps_adhoc_set_request(priv); break; case MODE_INFRASTRUCTURE: /* Infrastructure mode */ - if (!is_valid_ether_addr((u8 *)priv->reg.bssid)) { + if (!is_valid_ether_addr((u8 *) priv->reg.bssid)) { hostif_infrastructure_set_request(priv); - } - else { + } else { hostif_infrastructure_set2_request(priv); - DPRINTK(2, "Infra bssid = %02x:%02x:%02x:%02x:%02x:%02x\n", - priv->reg.bssid[0],priv->reg.bssid[1],priv->reg.bssid[2], - priv->reg.bssid[3],priv->reg.bssid[4],priv->reg.bssid[5]); + DPRINTK(2, + "Infra bssid = %02x:%02x:%02x:%02x:%02x:%02x\n", + priv->reg.bssid[0], priv->reg.bssid[1], + priv->reg.bssid[2], priv->reg.bssid[3], + priv->reg.bssid[4], priv->reg.bssid[5]); } break; case MODE_ADHOC: /* IEEE802.11 Ad-Hoc mode */ - if (!is_valid_ether_addr((u8 *)priv->reg.bssid)) { + if (!is_valid_ether_addr((u8 *) priv->reg.bssid)) { hostif_adhoc_set_request(priv); - } - else { + } else { hostif_adhoc_set2_request(priv); - DPRINTK(2, "Adhoc bssid = %02x:%02x:%02x:%02x:%02x:%02x\n", - priv->reg.bssid[0],priv->reg.bssid[1],priv->reg.bssid[2], - priv->reg.bssid[3],priv->reg.bssid[4],priv->reg.bssid[5]); + DPRINTK(2, + "Adhoc bssid = %02x:%02x:%02x:%02x:%02x:%02x\n", + priv->reg.bssid[0], priv->reg.bssid[1], + priv->reg.bssid[2], priv->reg.bssid[3], + priv->reg.bssid[4], priv->reg.bssid[5]); } break; default: break; } - return ; + return; } static void hostif_sme_multicast_set(struct ks_wlan_private *priv) { - struct net_device *dev = priv->net_dev; + struct net_device *dev = priv->net_dev; int mc_count; struct netdev_hw_addr *ha; - char set_address[NIC_MAX_MCAST_LIST*ETH_ALEN]; + char set_address[NIC_MAX_MCAST_LIST * ETH_ALEN]; unsigned long filter_type; int i = 0; - DPRINTK(3,"\n"); + DPRINTK(3, "\n"); spin_lock(&priv->multicast_spin); - memset(set_address, 0, NIC_MAX_MCAST_LIST*ETH_ALEN); - - if (dev->flags & IFF_PROMISC ){ - filter_type = cpu_to_le32((uint32_t)MCAST_FILTER_PROMISC); - hostif_mib_set_request(priv, LOCAL_MULTICAST_FILTER, sizeof(filter_type), - MIB_VALUE_TYPE_BOOL, &filter_type); - } - else if ((netdev_mc_count(dev) > NIC_MAX_MCAST_LIST) || (dev->flags & IFF_ALLMULTI)){ - filter_type = cpu_to_le32((uint32_t)MCAST_FILTER_MCASTALL); - hostif_mib_set_request(priv, LOCAL_MULTICAST_FILTER, sizeof(filter_type), - MIB_VALUE_TYPE_BOOL, &filter_type); - } - else { - if (priv->sme_i.sme_flag & SME_MULTICAST){ + memset(set_address, 0, NIC_MAX_MCAST_LIST * ETH_ALEN); + + if (dev->flags & IFF_PROMISC) { + filter_type = cpu_to_le32((uint32_t) MCAST_FILTER_PROMISC); + hostif_mib_set_request(priv, LOCAL_MULTICAST_FILTER, + sizeof(filter_type), MIB_VALUE_TYPE_BOOL, + &filter_type); + } else if ((netdev_mc_count(dev) > NIC_MAX_MCAST_LIST) + || (dev->flags & IFF_ALLMULTI)) { + filter_type = cpu_to_le32((uint32_t) MCAST_FILTER_MCASTALL); + hostif_mib_set_request(priv, LOCAL_MULTICAST_FILTER, + sizeof(filter_type), MIB_VALUE_TYPE_BOOL, + &filter_type); + } else { + if (priv->sme_i.sme_flag & SME_MULTICAST) { mc_count = netdev_mc_count(dev); netdev_for_each_mc_addr(ha, dev) { - memcpy(&set_address[i*ETH_ALEN], ha->addr, ETH_ALEN); + memcpy(&set_address[i * ETH_ALEN], ha->addr, + ETH_ALEN); i++; } priv->sme_i.sme_flag &= ~SME_MULTICAST; hostif_mib_set_request(priv, LOCAL_MULTICAST_ADDRESS, - (ETH_ALEN*mc_count), MIB_VALUE_TYPE_OSTRING, &set_address[0]); - }else { - filter_type = cpu_to_le32((uint32_t)MCAST_FILTER_MCAST); + (ETH_ALEN * mc_count), + MIB_VALUE_TYPE_OSTRING, + &set_address[0]); + } else { + filter_type = + cpu_to_le32((uint32_t) MCAST_FILTER_MCAST); priv->sme_i.sme_flag |= SME_MULTICAST; - hostif_mib_set_request(priv, LOCAL_MULTICAST_FILTER, sizeof(filter_type), - MIB_VALUE_TYPE_BOOL, &filter_type); + hostif_mib_set_request(priv, LOCAL_MULTICAST_FILTER, + sizeof(filter_type), + MIB_VALUE_TYPE_BOOL, + &filter_type); } } @@ -2148,17 +2323,17 @@ void hostif_sme_multicast_set(struct ks_wlan_private *priv) static void hostif_sme_powermgt_set(struct ks_wlan_private *priv) { - unsigned long mode,wake_up,receiveDTIMs ; + unsigned long mode, wake_up, receiveDTIMs; - DPRINTK(3,"\n"); - switch(priv->reg.powermgt){ + DPRINTK(3, "\n"); + switch (priv->reg.powermgt) { case POWMGT_ACTIVE_MODE: mode = POWER_ACTIVE; wake_up = 0; receiveDTIMs = 0; break; case POWMGT_SAVE1_MODE: - if(priv->reg.operation_mode == MODE_INFRASTRUCTURE){ + if (priv->reg.operation_mode == MODE_INFRASTRUCTURE) { mode = POWER_SAVE; wake_up = 0; receiveDTIMs = 0; @@ -2169,7 +2344,7 @@ void hostif_sme_powermgt_set(struct ks_wlan_private *priv) } break; case POWMGT_SAVE2_MODE: - if(priv->reg.operation_mode == MODE_INFRASTRUCTURE){ + if (priv->reg.operation_mode == MODE_INFRASTRUCTURE) { mode = POWER_SAVE; wake_up = 0; receiveDTIMs = 1; @@ -2193,8 +2368,8 @@ void hostif_sme_powermgt_set(struct ks_wlan_private *priv) static void hostif_sme_sleep_set(struct ks_wlan_private *priv) { - DPRINTK(3,"\n"); - switch(priv->sleep_mode){ + DPRINTK(3, "\n"); + switch (priv->sleep_mode) { case SLP_SLEEP: hostif_sleep_request(priv, priv->sleep_mode); break; @@ -2212,53 +2387,55 @@ static void hostif_sme_set_key(struct ks_wlan_private *priv, int type) { uint32_t val; - switch(type){ + switch (type) { case SME_SET_FLAG: - val = cpu_to_le32((uint32_t)(priv->reg.privacy_invoked)); + val = cpu_to_le32((uint32_t) (priv->reg.privacy_invoked)); hostif_mib_set_request(priv, DOT11_PRIVACY_INVOKED, - sizeof(val), MIB_VALUE_TYPE_BOOL, - &val ); + sizeof(val), MIB_VALUE_TYPE_BOOL, &val); break; case SME_SET_TXKEY: - val = cpu_to_le32((uint32_t)(priv->wpa.txkey)); + val = cpu_to_le32((uint32_t) (priv->wpa.txkey)); hostif_mib_set_request(priv, DOT11_WEP_DEFAULT_KEY_ID, - sizeof(val), MIB_VALUE_TYPE_INT, - &val ); + sizeof(val), MIB_VALUE_TYPE_INT, &val); break; case SME_SET_KEY1: hostif_mib_set_request(priv, DOT11_WEP_DEFAULT_KEY_VALUE1, - priv->wpa.key[0].key_len, MIB_VALUE_TYPE_OSTRING, - &priv->wpa.key[0].key_val[0] ); + priv->wpa.key[0].key_len, + MIB_VALUE_TYPE_OSTRING, + &priv->wpa.key[0].key_val[0]); break; case SME_SET_KEY2: hostif_mib_set_request(priv, DOT11_WEP_DEFAULT_KEY_VALUE2, - priv->wpa.key[1].key_len, MIB_VALUE_TYPE_OSTRING, - &priv->wpa.key[1].key_val[0] ); + priv->wpa.key[1].key_len, + MIB_VALUE_TYPE_OSTRING, + &priv->wpa.key[1].key_val[0]); break; case SME_SET_KEY3: hostif_mib_set_request(priv, DOT11_WEP_DEFAULT_KEY_VALUE3, - priv->wpa.key[2].key_len, MIB_VALUE_TYPE_OSTRING, - &priv->wpa.key[2].key_val[0] ); + priv->wpa.key[2].key_len, + MIB_VALUE_TYPE_OSTRING, + &priv->wpa.key[2].key_val[0]); break; case SME_SET_KEY4: hostif_mib_set_request(priv, DOT11_WEP_DEFAULT_KEY_VALUE4, - priv->wpa.key[3].key_len, MIB_VALUE_TYPE_OSTRING, - &priv->wpa.key[3].key_val[0] ); + priv->wpa.key[3].key_len, + MIB_VALUE_TYPE_OSTRING, + &priv->wpa.key[3].key_val[0]); break; case SME_SET_PMK_TSC: hostif_mib_set_request(priv, DOT11_PMK_TSC, WPA_RX_SEQ_LEN, MIB_VALUE_TYPE_OSTRING, - &priv->wpa.key[0].rx_seq[0] ); + &priv->wpa.key[0].rx_seq[0]); break; case SME_SET_GMK1_TSC: hostif_mib_set_request(priv, DOT11_GMK1_TSC, WPA_RX_SEQ_LEN, MIB_VALUE_TYPE_OSTRING, - &priv->wpa.key[1].rx_seq[0] ); + &priv->wpa.key[1].rx_seq[0]); break; case SME_SET_GMK2_TSC: hostif_mib_set_request(priv, DOT11_GMK2_TSC, WPA_RX_SEQ_LEN, MIB_VALUE_TYPE_OSTRING, - &priv->wpa.key[2].rx_seq[0] ); + &priv->wpa.key[2].rx_seq[0]); break; } return; @@ -2270,28 +2447,31 @@ void hostif_sme_set_pmksa(struct ks_wlan_private *priv) struct pmk_cache_t { uint16_t size; struct { - uint8_t bssid[ETH_ALEN]; - uint8_t pmkid[IW_PMKID_LEN]; - } __attribute__((packed)) list[PMK_LIST_MAX]; - } __attribute__((packed)) pmkcache; + uint8_t bssid[ETH_ALEN]; + uint8_t pmkid[IW_PMKID_LEN]; + } __attribute__ ((packed)) list[PMK_LIST_MAX]; + } __attribute__ ((packed)) pmkcache; struct pmk_t *pmk; struct list_head *ptr; int i; - DPRINTK(4,"pmklist.size=%d\n",priv->pmklist.size); - i=0; - list_for_each(ptr, &priv->pmklist.head){ + DPRINTK(4, "pmklist.size=%d\n", priv->pmklist.size); + i = 0; + list_for_each(ptr, &priv->pmklist.head) { pmk = list_entry(ptr, struct pmk_t, list); - if(ibssid, ETH_ALEN); - memcpy(pmkcache.list[i].pmkid, pmk->pmkid, IW_PMKID_LEN); + memcpy(pmkcache.list[i].pmkid, pmk->pmkid, + IW_PMKID_LEN); i++; } } - pmkcache.size = cpu_to_le16((uint16_t)(priv->pmklist.size)); + pmkcache.size = cpu_to_le16((uint16_t) (priv->pmklist.size)); hostif_mib_set_request(priv, LOCAL_PMK, - sizeof(priv->pmklist.size)+(ETH_ALEN+IW_PMKID_LEN)*(priv->pmklist.size), - MIB_VALUE_TYPE_OSTRING,&pmkcache ); + sizeof(priv->pmklist.size) + (ETH_ALEN + + IW_PMKID_LEN) * + (priv->pmklist.size), MIB_VALUE_TYPE_OSTRING, + &pmkcache); } /* execute sme */ @@ -2300,10 +2480,10 @@ void hostif_sme_execute(struct ks_wlan_private *priv, int event) { uint32_t val; - DPRINTK(3,"event=%d\n",event); + DPRINTK(3, "event=%d\n", event); switch (event) { case SME_START: - if ( priv->dev_state == DEVICE_STATE_BOOT ){ + if (priv->dev_state == DEVICE_STATE_BOOT) { hostif_mib_get_request(priv, DOT11_MAC_ADDRESS); } break; @@ -2312,10 +2492,12 @@ void hostif_sme_execute(struct ks_wlan_private *priv, int event) break; case SME_MACADDRESS_SET_REQUEST: hostif_mib_set_request(priv, LOCAL_CURRENTADDRESS, ETH_ALEN, - MIB_VALUE_TYPE_OSTRING, &priv->eth_addr[0]); + MIB_VALUE_TYPE_OSTRING, + &priv->eth_addr[0]); break; case SME_BSS_SCAN_REQUEST: - hostif_bss_scan_request(priv, priv->reg.scan_type, priv->scan_ssid, priv->scan_ssid_len); + hostif_bss_scan_request(priv, priv->reg.scan_type, + priv->scan_ssid, priv->scan_ssid_len); break; case SME_POW_MNGMT_REQUEST: hostif_sme_powermgt_set(priv); @@ -2324,30 +2506,36 @@ void hostif_sme_execute(struct ks_wlan_private *priv, int event) hostif_phy_information_request(priv); break; case SME_MIC_FAILURE_REQUEST: - if(priv->wpa.mic_failure.failure == 1){ - hostif_mic_failure_request(priv, priv->wpa.mic_failure.failure-1, 0); - }else if(priv->wpa.mic_failure.failure == 2){ - hostif_mic_failure_request(priv, priv->wpa.mic_failure.failure-1, - priv->wpa.mic_failure.counter); - }else - DPRINTK(4,"SME_MIC_FAILURE_REQUEST: failure count=%u error?\n", + if (priv->wpa.mic_failure.failure == 1) { + hostif_mic_failure_request(priv, + priv->wpa.mic_failure. + failure - 1, 0); + } else if (priv->wpa.mic_failure.failure == 2) { + hostif_mic_failure_request(priv, + priv->wpa.mic_failure. + failure - 1, + priv->wpa.mic_failure. + counter); + } else + DPRINTK(4, + "SME_MIC_FAILURE_REQUEST: failure count=%u error?\n", priv->wpa.mic_failure.failure); break; case SME_MIC_FAILURE_CONFIRM: - if(priv->wpa.mic_failure.failure == 2){ - if(priv->wpa.mic_failure.stop) + if (priv->wpa.mic_failure.failure == 2) { + if (priv->wpa.mic_failure.stop) priv->wpa.mic_failure.stop = 0; priv->wpa.mic_failure.failure = 0; - hostif_start_request( priv, priv->reg.operation_mode ); + hostif_start_request(priv, priv->reg.operation_mode); } break; case SME_GET_MAC_ADDRESS: - if ( priv->dev_state == DEVICE_STATE_BOOT ){ + if (priv->dev_state == DEVICE_STATE_BOOT) { hostif_mib_get_request(priv, DOT11_PRODUCT_VERSION); } break; case SME_GET_PRODUCT_VERSION: - if ( priv->dev_state == DEVICE_STATE_BOOT ){ + if (priv->dev_state == DEVICE_STATE_BOOT) { priv->dev_state = DEVICE_STATE_PREINIT; } break; @@ -2355,33 +2543,40 @@ void hostif_sme_execute(struct ks_wlan_private *priv, int event) hostif_stop_request(priv); break; case SME_RTS_THRESHOLD_REQUEST: - val = cpu_to_le32((uint32_t)(priv->reg.rts)); + val = cpu_to_le32((uint32_t) (priv->reg.rts)); hostif_mib_set_request(priv, DOT11_RTS_THRESHOLD, - sizeof(val), MIB_VALUE_TYPE_INT, - &val ); + sizeof(val), MIB_VALUE_TYPE_INT, &val); break; case SME_FRAGMENTATION_THRESHOLD_REQUEST: - val = cpu_to_le32((uint32_t)(priv->reg.fragment)); + val = cpu_to_le32((uint32_t) (priv->reg.fragment)); hostif_mib_set_request(priv, DOT11_FRAGMENTATION_THRESHOLD, - sizeof(val), MIB_VALUE_TYPE_INT, - &val ); + sizeof(val), MIB_VALUE_TYPE_INT, &val); break; - case SME_WEP_INDEX_REQUEST: case SME_WEP_KEY1_REQUEST: - case SME_WEP_KEY2_REQUEST: case SME_WEP_KEY3_REQUEST: - case SME_WEP_KEY4_REQUEST: case SME_WEP_FLAG_REQUEST: - hostif_sme_set_wep(priv,event); + case SME_WEP_INDEX_REQUEST: + case SME_WEP_KEY1_REQUEST: + case SME_WEP_KEY2_REQUEST: + case SME_WEP_KEY3_REQUEST: + case SME_WEP_KEY4_REQUEST: + case SME_WEP_FLAG_REQUEST: + hostif_sme_set_wep(priv, event); break; - case SME_RSN_UCAST_REQUEST: case SME_RSN_MCAST_REQUEST: - case SME_RSN_AUTH_REQUEST: case SME_RSN_ENABLED_REQUEST: + case SME_RSN_UCAST_REQUEST: + case SME_RSN_MCAST_REQUEST: + case SME_RSN_AUTH_REQUEST: + case SME_RSN_ENABLED_REQUEST: case SME_RSN_MODE_REQUEST: - hostif_sme_set_rsn(priv,event); + hostif_sme_set_rsn(priv, event); break; - case SME_SET_FLAG: case SME_SET_TXKEY: - case SME_SET_KEY1: case SME_SET_KEY2: - case SME_SET_KEY3: case SME_SET_KEY4: - case SME_SET_PMK_TSC: case SME_SET_GMK1_TSC: + case SME_SET_FLAG: + case SME_SET_TXKEY: + case SME_SET_KEY1: + case SME_SET_KEY2: + case SME_SET_KEY3: + case SME_SET_KEY4: + case SME_SET_PMK_TSC: + case SME_SET_GMK1_TSC: case SME_SET_GMK2_TSC: - hostif_sme_set_key(priv,event); + hostif_sme_set_key(priv, event); break; case SME_SET_PMKSA: hostif_sme_set_pmksa(priv); @@ -2390,7 +2585,8 @@ void hostif_sme_execute(struct ks_wlan_private *priv, int event) case SME_WPS_ENABLE_REQUEST: hostif_mib_set_request(priv, LOCAL_WPS_ENABLE, sizeof(priv->wps.wps_enabled), - MIB_VALUE_TYPE_INT, &priv->wps.wps_enabled ); + MIB_VALUE_TYPE_INT, + &priv->wps.wps_enabled); break; case SME_WPS_PROBE_REQUEST: hostif_mib_set_request(priv, LOCAL_WPS_PROBE_REQ, @@ -2403,8 +2599,8 @@ void hostif_sme_execute(struct ks_wlan_private *priv, int event) break; case SME_SET_GAIN: hostif_mib_set_request(priv, LOCAL_GAIN, - sizeof(priv->gain), MIB_VALUE_TYPE_OSTRING, - &priv->gain); + sizeof(priv->gain), + MIB_VALUE_TYPE_OSTRING, &priv->gain); break; case SME_GET_GAIN: hostif_mib_get_request(priv, LOCAL_GAIN); @@ -2414,13 +2610,13 @@ void hostif_sme_execute(struct ks_wlan_private *priv, int event) hostif_mib_get_request(priv, LOCAL_EEPROM_SUM); break; case SME_START_REQUEST: - hostif_start_request( priv, priv->reg.operation_mode ); + hostif_start_request(priv, priv->reg.operation_mode); break; case SME_START_CONFIRM: /* for power save */ atomic_set(&priv->psstatus.snooze_guard, 0); - atomic_set(&priv->psstatus.confirm_wait,0); - if ( priv->dev_state == DEVICE_STATE_PREINIT ){ + atomic_set(&priv->psstatus.confirm_wait, 0); + if (priv->dev_state == DEVICE_STATE_PREINIT) { priv->dev_state = DEVICE_STATE_INIT; } /* wake_up_interruptible_all(&priv->confirm_wait); */ @@ -2430,10 +2626,9 @@ void hostif_sme_execute(struct ks_wlan_private *priv, int event) hostif_sme_sleep_set(priv); break; case SME_SET_REGION: - val = cpu_to_le32((uint32_t)(priv->region)); + val = cpu_to_le32((uint32_t) (priv->region)); hostif_mib_set_request(priv, LOCAL_REGION, - sizeof(val), MIB_VALUE_TYPE_INT, - &val ); + sizeof(val), MIB_VALUE_TYPE_INT, &val); break; case SME_MULTICAST_CONFIRM: case SME_BSS_SCAN_CONFIRM: @@ -2442,11 +2637,16 @@ void hostif_sme_execute(struct ks_wlan_private *priv, int event) case SME_STOP_CONFIRM: case SME_RTS_THRESHOLD_CONFIRM: case SME_FRAGMENTATION_THRESHOLD_CONFIRM: - case SME_WEP_INDEX_CONFIRM: case SME_WEP_KEY1_CONFIRM: - case SME_WEP_KEY2_CONFIRM: case SME_WEP_KEY3_CONFIRM: - case SME_WEP_KEY4_CONFIRM: case SME_WEP_FLAG_CONFIRM: - case SME_RSN_UCAST_CONFIRM: case SME_RSN_MCAST_CONFIRM: - case SME_RSN_AUTH_CONFIRM: case SME_RSN_ENABLED_CONFIRM: + case SME_WEP_INDEX_CONFIRM: + case SME_WEP_KEY1_CONFIRM: + case SME_WEP_KEY2_CONFIRM: + case SME_WEP_KEY3_CONFIRM: + case SME_WEP_KEY4_CONFIRM: + case SME_WEP_FLAG_CONFIRM: + case SME_RSN_UCAST_CONFIRM: + case SME_RSN_MCAST_CONFIRM: + case SME_RSN_AUTH_CONFIRM: + case SME_RSN_ENABLED_CONFIRM: case SME_RSN_MODE_CONFIRM: case SME_MODE_SET_CONFIRM: break; @@ -2457,18 +2657,21 @@ void hostif_sme_execute(struct ks_wlan_private *priv, int event) } static -void hostif_sme_task( unsigned long dev ) +void hostif_sme_task(unsigned long dev) { struct ks_wlan_private *priv = (struct ks_wlan_private *)dev; - DPRINTK(3,"\n"); + DPRINTK(3, "\n"); - if(priv->dev_state >= DEVICE_STATE_BOOT){ - if (0 < cnt_smeqbody(priv) && priv->dev_state >= DEVICE_STATE_BOOT) { - hostif_sme_execute(priv, priv->sme_i.event_buff[priv->sme_i.qhead]); + if (priv->dev_state >= DEVICE_STATE_BOOT) { + if (0 < cnt_smeqbody(priv) + && priv->dev_state >= DEVICE_STATE_BOOT) { + hostif_sme_execute(priv, + priv->sme_i.event_buff[priv->sme_i. + qhead]); inc_smeqhead(priv); if (0 < cnt_smeqbody(priv)) - tasklet_schedule(&priv->sme_task); + tasklet_schedule(&priv->sme_task); } } return; @@ -2477,9 +2680,7 @@ void hostif_sme_task( unsigned long dev ) /* send to Station Management Entity module */ void hostif_sme_enqueue(struct ks_wlan_private *priv, unsigned short event) { - DPRINTK(3,"\n"); - - + DPRINTK(3, "\n"); /* enqueue sme event */ if (cnt_smeqbody(priv) < (SME_EVENT_BUFF_SIZE - 1)) { @@ -2500,16 +2701,16 @@ void hostif_sme_enqueue(struct ks_wlan_private *priv, unsigned short event) } -int hostif_init( struct ks_wlan_private *priv ) +int hostif_init(struct ks_wlan_private *priv) { - int rc=0; + int rc = 0; int i; - DPRINTK(3,"\n"); + DPRINTK(3, "\n"); - priv->aplist.size =0; - for(i=0;iaplist.ap[i]),0,sizeof(struct local_ap_t)); + priv->aplist.size = 0; + for (i = 0; i < LOCAL_APLIST_MAX; i++) + memset(&(priv->aplist.ap[i]), 0, sizeof(struct local_ap_t)); priv->infra_status = 0; priv->current_rate = 4; priv->connect_status = DISCONNECT_STATUS; @@ -2517,7 +2718,7 @@ int hostif_init( struct ks_wlan_private *priv ) spin_lock_init(&priv->multicast_spin); spin_lock_init(&priv->dev_read_lock); - init_waitqueue_head (&priv->devread_wait); + init_waitqueue_head(&priv->devread_wait); priv->dev_count = 0; atomic_set(&priv->event_count, 0); atomic_set(&priv->rec_count, 0); @@ -2539,7 +2740,7 @@ int hostif_init( struct ks_wlan_private *priv ) priv->wpa.mic_failure.stop = 0; memset(&(priv->pmklist), 0, sizeof(priv->pmklist)); INIT_LIST_HEAD(&priv->pmklist.head); - for(i=0;ipmklist.pmk[i].list); priv->sme_i.sme_status = SME_IDLE; @@ -2547,7 +2748,7 @@ int hostif_init( struct ks_wlan_private *priv ) #ifdef KS_WLAN_DEBUG priv->sme_i.max_event_count = 0; #endif - spin_lock_init(&priv->sme_i.sme_spin); + spin_lock_init(&priv->sme_i.sme_spin); priv->sme_i.sme_flag = 0; tasklet_init(&priv->sme_task, hostif_sme_task, (unsigned long)priv); @@ -2555,9 +2756,8 @@ int hostif_init( struct ks_wlan_private *priv ) return rc; } -void hostif_exit( struct ks_wlan_private *priv ) +void hostif_exit(struct ks_wlan_private *priv) { tasklet_kill(&priv->sme_task); return; } - -- cgit v0.10.2 From e3d7482607befe01c08cf0030c91d4f15a44db1d Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Tue, 31 May 2016 12:56:31 +0200 Subject: staging: ks7010: indent ks_hostif.h Signed-off-by: Wolfram Sang Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/ks7010/ks_hostif.h b/drivers/staging/ks7010/ks_hostif.h index c333ce1..01de478 100644 --- a/drivers/staging/ks7010/ks_hostif.h +++ b/drivers/staging/ks7010/ks_hostif.h @@ -62,141 +62,140 @@ */ struct hostif_hdr { - uint16_t size; - uint16_t event; -} __attribute__((packed)); + uint16_t size; + uint16_t event; +} __attribute__ ((packed)); struct hostif_data_request_t { struct hostif_hdr header; - uint16_t auth_type; + uint16_t auth_type; #define TYPE_DATA 0x0000 #define TYPE_AUTH 0x0001 - uint16_t reserved; - uint8_t data[0]; -} __attribute__((packed)); + uint16_t reserved; + uint8_t data[0]; +} __attribute__ ((packed)); struct hostif_data_indication_t { struct hostif_hdr header; - uint16_t auth_type; + uint16_t auth_type; /* #define TYPE_DATA 0x0000 */ #define TYPE_PMK1 0x0001 #define TYPE_GMK1 0x0002 #define TYPE_GMK2 0x0003 - uint16_t reserved; - uint8_t data[0]; -} __attribute__((packed)); + uint16_t reserved; + uint8_t data[0]; +} __attribute__ ((packed)); #define CHANNEL_LIST_MAX_SIZE 14 struct channel_list_t { - uint8_t size; - uint8_t body[CHANNEL_LIST_MAX_SIZE]; - uint8_t pad; -} __attribute__((packed)); + uint8_t size; + uint8_t body[CHANNEL_LIST_MAX_SIZE]; + uint8_t pad; +} __attribute__ ((packed)); /* MIB Attribute */ -#define DOT11_MAC_ADDRESS 0x21010100 /* MAC Address (R) */ -#define DOT11_PRODUCT_VERSION 0x31024100 /* FirmWare Version (R)*/ -#define DOT11_RTS_THRESHOLD 0x21020100 /* RTS Threshold (R/W) */ -#define DOT11_FRAGMENTATION_THRESHOLD 0x21050100 /* Fragment Threshold (R/W) */ -#define DOT11_PRIVACY_INVOKED 0x15010100 /* WEP ON/OFF (W) */ -#define DOT11_WEP_DEFAULT_KEY_ID 0x15020100 /* WEP Index (W) */ -#define DOT11_WEP_DEFAULT_KEY_VALUE1 0x13020101 /* WEP Key#1(TKIP AES: PairwiseTemporalKey) (W) */ -#define DOT11_WEP_DEFAULT_KEY_VALUE2 0x13020102 /* WEP Key#2(TKIP AES: GroupKey1) (W) */ -#define DOT11_WEP_DEFAULT_KEY_VALUE3 0x13020103 /* WEP Key#3(TKIP AES: GroupKey2) (W) */ -#define DOT11_WEP_DEFAULT_KEY_VALUE4 0x13020104 /* WEP Key#4 (W) */ -#define DOT11_WEP_LIST 0x13020100 /* WEP LIST */ -#define DOT11_DESIRED_SSID 0x11090100 /* SSID */ -#define DOT11_CURRENT_CHANNEL 0x45010100 /* channel set */ -#define DOT11_OPERATION_RATE_SET 0x11110100 /* rate set */ - -#define LOCAL_AP_SEARCH_INTEAVAL 0xF1010100 /* AP search interval (R/W) */ -#define LOCAL_CURRENTADDRESS 0xF1050100 /* MAC Adress change (W) */ -#define LOCAL_MULTICAST_ADDRESS 0xF1060100 /* Multicast Adress (W) */ -#define LOCAL_MULTICAST_FILTER 0xF1060200 /* Multicast Adress Filter enable/disable (W) */ -#define LOCAL_SEARCHED_AP_LIST 0xF1030100 /* AP list (R) */ -#define LOCAL_LINK_AP_STATUS 0xF1040100 /* Link AP status (R) */ -#define LOCAL_PACKET_STATISTICS 0xF1020100 /* tx,rx packets statistics */ -#define LOCAL_AP_SCAN_LIST_TYPE_SET 0xF1030200 /* AP_SCAN_LIST_TYPE */ - -#define DOT11_RSN_ENABLED 0x15070100 /* WPA enable/disable (W) */ -#define LOCAL_RSN_MODE 0x56010100 /* RSN mode WPA/WPA2 (W) */ -#define DOT11_RSN_CONFIG_MULTICAST_CIPHER 0x51040100 /* GroupKeyCipherSuite (W) */ -#define DOT11_RSN_CONFIG_UNICAST_CIPHER 0x52020100 /* PairwiseKeyCipherSuite (W) */ -#define DOT11_RSN_CONFIG_AUTH_SUITE 0x53020100 /* AuthenticationKeyManagementSuite (W) */ -#define DOT11_RSN_CONFIG_VERSION 0x51020100 /* RSN version (W) */ -#define LOCAL_RSN_CONFIG_ALL 0x5F010100 /* RSN CONFIG ALL (W) */ -#define DOT11_PMK_TSC 0x55010100 /* PMK_TSC (W) */ -#define DOT11_GMK1_TSC 0x55010101 /* GMK1_TSC (W) */ -#define DOT11_GMK2_TSC 0x55010102 /* GMK2_TSC (W) */ -#define DOT11_GMK3_TSC 0x55010103 /* GMK3_TSC */ -#define LOCAL_PMK 0x58010100 /* Pairwise Master Key cache (W) */ - -#define LOCAL_REGION 0xF10A0100 /* Region setting */ +#define DOT11_MAC_ADDRESS 0x21010100 /* MAC Address (R) */ +#define DOT11_PRODUCT_VERSION 0x31024100 /* FirmWare Version (R) */ +#define DOT11_RTS_THRESHOLD 0x21020100 /* RTS Threshold (R/W) */ +#define DOT11_FRAGMENTATION_THRESHOLD 0x21050100 /* Fragment Threshold (R/W) */ +#define DOT11_PRIVACY_INVOKED 0x15010100 /* WEP ON/OFF (W) */ +#define DOT11_WEP_DEFAULT_KEY_ID 0x15020100 /* WEP Index (W) */ +#define DOT11_WEP_DEFAULT_KEY_VALUE1 0x13020101 /* WEP Key#1(TKIP AES: PairwiseTemporalKey) (W) */ +#define DOT11_WEP_DEFAULT_KEY_VALUE2 0x13020102 /* WEP Key#2(TKIP AES: GroupKey1) (W) */ +#define DOT11_WEP_DEFAULT_KEY_VALUE3 0x13020103 /* WEP Key#3(TKIP AES: GroupKey2) (W) */ +#define DOT11_WEP_DEFAULT_KEY_VALUE4 0x13020104 /* WEP Key#4 (W) */ +#define DOT11_WEP_LIST 0x13020100 /* WEP LIST */ +#define DOT11_DESIRED_SSID 0x11090100 /* SSID */ +#define DOT11_CURRENT_CHANNEL 0x45010100 /* channel set */ +#define DOT11_OPERATION_RATE_SET 0x11110100 /* rate set */ + +#define LOCAL_AP_SEARCH_INTEAVAL 0xF1010100 /* AP search interval (R/W) */ +#define LOCAL_CURRENTADDRESS 0xF1050100 /* MAC Adress change (W) */ +#define LOCAL_MULTICAST_ADDRESS 0xF1060100 /* Multicast Adress (W) */ +#define LOCAL_MULTICAST_FILTER 0xF1060200 /* Multicast Adress Filter enable/disable (W) */ +#define LOCAL_SEARCHED_AP_LIST 0xF1030100 /* AP list (R) */ +#define LOCAL_LINK_AP_STATUS 0xF1040100 /* Link AP status (R) */ +#define LOCAL_PACKET_STATISTICS 0xF1020100 /* tx,rx packets statistics */ +#define LOCAL_AP_SCAN_LIST_TYPE_SET 0xF1030200 /* AP_SCAN_LIST_TYPE */ + +#define DOT11_RSN_ENABLED 0x15070100 /* WPA enable/disable (W) */ +#define LOCAL_RSN_MODE 0x56010100 /* RSN mode WPA/WPA2 (W) */ +#define DOT11_RSN_CONFIG_MULTICAST_CIPHER 0x51040100 /* GroupKeyCipherSuite (W) */ +#define DOT11_RSN_CONFIG_UNICAST_CIPHER 0x52020100 /* PairwiseKeyCipherSuite (W) */ +#define DOT11_RSN_CONFIG_AUTH_SUITE 0x53020100 /* AuthenticationKeyManagementSuite (W) */ +#define DOT11_RSN_CONFIG_VERSION 0x51020100 /* RSN version (W) */ +#define LOCAL_RSN_CONFIG_ALL 0x5F010100 /* RSN CONFIG ALL (W) */ +#define DOT11_PMK_TSC 0x55010100 /* PMK_TSC (W) */ +#define DOT11_GMK1_TSC 0x55010101 /* GMK1_TSC (W) */ +#define DOT11_GMK2_TSC 0x55010102 /* GMK2_TSC (W) */ +#define DOT11_GMK3_TSC 0x55010103 /* GMK3_TSC */ +#define LOCAL_PMK 0x58010100 /* Pairwise Master Key cache (W) */ + +#define LOCAL_REGION 0xF10A0100 /* Region setting */ #ifdef WPS -#define LOCAL_WPS_ENABLE 0xF10B0100 /* WiFi Protected Setup */ -#define LOCAL_WPS_PROBE_REQ 0xF10C0100 /* WPS Probe Request */ +#define LOCAL_WPS_ENABLE 0xF10B0100 /* WiFi Protected Setup */ +#define LOCAL_WPS_PROBE_REQ 0xF10C0100 /* WPS Probe Request */ #endif /* WPS */ -#define LOCAL_GAIN 0xF10D0100 /* Carrer sense threshold for demo ato show */ -#define LOCAL_EEPROM_SUM 0xF10E0100 /* EEPROM checksum information */ +#define LOCAL_GAIN 0xF10D0100 /* Carrer sense threshold for demo ato show */ +#define LOCAL_EEPROM_SUM 0xF10E0100 /* EEPROM checksum information */ struct hostif_mib_get_request_t { struct hostif_hdr header; - uint32_t mib_attribute; -} __attribute__((packed)); - + uint32_t mib_attribute; +} __attribute__ ((packed)); struct hostif_mib_value_t { - uint16_t size; - uint16_t type; + uint16_t size; + uint16_t type; #define MIB_VALUE_TYPE_NULL 0 #define MIB_VALUE_TYPE_INT 1 #define MIB_VALUE_TYPE_BOOL 2 #define MIB_VALUE_TYPE_COUNT32 3 #define MIB_VALUE_TYPE_OSTRING 4 - uint8_t body[0]; -} __attribute__((packed)); + uint8_t body[0]; +} __attribute__ ((packed)); struct hostif_mib_get_confirm_t { struct hostif_hdr header; - uint32_t mib_status; + uint32_t mib_status; #define MIB_SUCCESS 0 #define MIB_INVALID 1 #define MIB_READ_ONLY 2 #define MIB_WRITE_ONLY 3 - uint32_t mib_attribute; + uint32_t mib_attribute; struct hostif_mib_value_t mib_value; -} __attribute__((packed)); +} __attribute__ ((packed)); struct hostif_mib_set_request_t { struct hostif_hdr header; - uint32_t mib_attribute; + uint32_t mib_attribute; struct hostif_mib_value_t mib_value; -} __attribute__((packed)); +} __attribute__ ((packed)); struct hostif_mib_set_confirm_t { struct hostif_hdr header; - uint32_t mib_status; - uint32_t mib_attribute; -} __attribute__((packed)); + uint32_t mib_status; + uint32_t mib_attribute; +} __attribute__ ((packed)); struct hostif_power_mngmt_request_t { struct hostif_hdr header; - uint32_t mode; + uint32_t mode; #define POWER_ACTIVE 1 #define POWER_SAVE 2 - uint32_t wake_up; + uint32_t wake_up; #define SLEEP_FALSE 0 -#define SLEEP_TRUE 1 /* not used */ - uint32_t receiveDTIMs; +#define SLEEP_TRUE 1 /* not used */ + uint32_t receiveDTIMs; #define DTIM_FALSE 0 #define DTIM_TRUE 1 -} __attribute__((packed)); +} __attribute__ ((packed)); /* power management mode */ enum { - POWMGT_ACTIVE_MODE=0, + POWMGT_ACTIVE_MODE = 0, POWMGT_SAVE1_MODE, POWMGT_SAVE2_MODE }; @@ -209,84 +208,83 @@ enum { struct hostif_power_mngmt_confirm_t { struct hostif_hdr header; - uint16_t result_code; -} __attribute__((packed)); + uint16_t result_code; +} __attribute__ ((packed)); struct hostif_start_request_t { struct hostif_hdr header; - uint16_t mode; + uint16_t mode; #define MODE_PSEUDO_ADHOC 0 #define MODE_INFRASTRUCTURE 1 -#define MODE_AP 2 /* not used */ +#define MODE_AP 2 /* not used */ #define MODE_ADHOC 3 -} __attribute__((packed)); +} __attribute__ ((packed)); struct hostif_start_confirm_t { struct hostif_hdr header; - uint16_t result_code; -} __attribute__((packed)); + uint16_t result_code; +} __attribute__ ((packed)); #define SSID_MAX_SIZE 32 struct ssid_t { - uint8_t size; - uint8_t body[SSID_MAX_SIZE]; - uint8_t ssid_pad; -} __attribute__((packed)); + uint8_t size; + uint8_t body[SSID_MAX_SIZE]; + uint8_t ssid_pad; +} __attribute__ ((packed)); #define RATE_SET_MAX_SIZE 16 struct rate_set8_t { - uint8_t size; - uint8_t body[8]; - uint8_t rate_pad; -} __attribute__((packed)); + uint8_t size; + uint8_t body[8]; + uint8_t rate_pad; +} __attribute__ ((packed)); struct FhParms_t { - uint16_t dwellTime; - uint8_t hopSet; - uint8_t hopPattern; - uint8_t hopIndex; -} __attribute__((packed)); + uint16_t dwellTime; + uint8_t hopSet; + uint8_t hopPattern; + uint8_t hopIndex; +} __attribute__ ((packed)); struct DsParms_t { - uint8_t channel; -} __attribute__((packed)); + uint8_t channel; +} __attribute__ ((packed)); struct CfParms_t { - uint8_t count; - uint8_t period; - uint16_t maxDuration; - uint16_t durRemaining; -} __attribute__((packed)); + uint8_t count; + uint8_t period; + uint16_t maxDuration; + uint16_t durRemaining; +} __attribute__ ((packed)); struct IbssParms_t { - uint16_t atimWindow; -} __attribute__((packed)); - + uint16_t atimWindow; +} __attribute__ ((packed)); struct rsn_t { - uint8_t size; + uint8_t size; #define RSN_BODY_SIZE 64 - uint8_t body[RSN_BODY_SIZE]; -} __attribute__((packed)); + uint8_t body[RSN_BODY_SIZE]; +} __attribute__ ((packed)); struct ErpParams_t { uint8_t erp_info; -} __attribute__((packed)); - -struct rate_set16_t{ - uint8_t size; - uint8_t body[16]; - uint8_t rate_pad; -} __attribute__((packed)); - -struct ap_info_t{ - uint8_t bssid[6]; /* +00 */ - uint8_t rssi; /* +06 */ - uint8_t sq; /* +07 */ - uint8_t noise; /* +08 */ - uint8_t pad0; /* +09 */ - uint16_t beacon_period; /* +10 */ - uint16_t capability; /* +12 */ +} __attribute__ ((packed)); + +struct rate_set16_t { + uint8_t size; + uint8_t body[16]; + uint8_t rate_pad; +} __attribute__ ((packed)); + +struct ap_info_t { + uint8_t bssid[6]; /* +00 */ + uint8_t rssi; /* +06 */ + uint8_t sq; /* +07 */ + uint8_t noise; /* +08 */ + uint8_t pad0; /* +09 */ + uint16_t beacon_period; /* +10 */ + uint16_t capability; /* +12 */ #define BSS_CAP_ESS (1<<0) #define BSS_CAP_IBSS (1<<1) #define BSS_CAP_CF_POLABLE (1<<2) @@ -297,178 +295,176 @@ struct ap_info_t{ #define BSS_CAP_CHANNEL_AGILITY (1<<7) #define BSS_CAP_SHORT_SLOT_TIME (1<<10) #define BSS_CAP_DSSS_OFDM (1<<13) - uint8_t frame_type; /* +14 */ - uint8_t ch_info; /* +15 */ + uint8_t frame_type; /* +14 */ + uint8_t ch_info; /* +15 */ #define FRAME_TYPE_BEACON 0x80 #define FRAME_TYPE_PROBE_RESP 0x50 - uint16_t body_size; /* +16 */ - uint8_t body[1024]; /* +18 */ - /* +1032 */ -} __attribute__((packed)); - -struct link_ap_info_t{ - uint8_t bssid[6]; /* +00 */ - uint8_t rssi; /* +06 */ - uint8_t sq; /* +07 */ - uint8_t noise; /* +08 */ - uint8_t pad0; /* +09 */ - uint16_t beacon_period; /* +10 */ - uint16_t capability; /* +12 */ - struct rate_set8_t rate_set; /* +14 */ - struct FhParms_t fh_parameter; /* +24 */ - struct DsParms_t ds_parameter; /* +29 */ - struct CfParms_t cf_parameter; /* +30 */ + uint16_t body_size; /* +16 */ + uint8_t body[1024]; /* +18 */ + /* +1032 */ +} __attribute__ ((packed)); + +struct link_ap_info_t { + uint8_t bssid[6]; /* +00 */ + uint8_t rssi; /* +06 */ + uint8_t sq; /* +07 */ + uint8_t noise; /* +08 */ + uint8_t pad0; /* +09 */ + uint16_t beacon_period; /* +10 */ + uint16_t capability; /* +12 */ + struct rate_set8_t rate_set; /* +14 */ + struct FhParms_t fh_parameter; /* +24 */ + struct DsParms_t ds_parameter; /* +29 */ + struct CfParms_t cf_parameter; /* +30 */ struct IbssParms_t ibss_parameter; /* +36 */ struct ErpParams_t erp_parameter; /* +38 */ - uint8_t pad1; /* +39 */ - struct rate_set8_t ext_rate_set; /* +40 */ - uint8_t DTIM_period; /* +50 */ - uint8_t rsn_mode; /* +51 */ + uint8_t pad1; /* +39 */ + struct rate_set8_t ext_rate_set; /* +40 */ + uint8_t DTIM_period; /* +50 */ + uint8_t rsn_mode; /* +51 */ #define RSN_MODE_NONE 0 #define RSN_MODE_WPA 1 #define RSN_MODE_WPA2 2 struct { - uint8_t size; /* +52 */ - uint8_t body[128]; /* +53 */ - } __attribute__((packed)) rsn; -} __attribute__((packed)); + uint8_t size; /* +52 */ + uint8_t body[128]; /* +53 */ + } __attribute__ ((packed)) rsn; +} __attribute__ ((packed)); struct hostif_connect_indication_t { struct hostif_hdr header; - uint16_t connect_code; + uint16_t connect_code; #define RESULT_CONNECT 0 #define RESULT_DISCONNECT 1 struct link_ap_info_t link_ap_info; -} __attribute__((packed)); +} __attribute__ ((packed)); struct hostif_stop_request_t { struct hostif_hdr header; -} __attribute__((packed)); +} __attribute__ ((packed)); struct hostif_stop_confirm_t { struct hostif_hdr header; - uint16_t result_code; -} __attribute__((packed)); + uint16_t result_code; +} __attribute__ ((packed)); struct hostif_ps_adhoc_set_request_t { struct hostif_hdr header; - uint16_t phy_type; + uint16_t phy_type; #define D_11B_ONLY_MODE 0 #define D_11G_ONLY_MODE 1 #define D_11BG_COMPATIBLE_MODE 2 #define D_11A_ONLY_MODE 3 - uint16_t cts_mode; + uint16_t cts_mode; #define CTS_MODE_FALSE 0 #define CTS_MODE_TRUE 1 - uint16_t channel; + uint16_t channel; struct rate_set16_t rate_set; - uint16_t capability; /* bit5:preamble bit6:pbcc pbcc not supported always 0 - * bit10:ShortSlotTime bit13:DSSS-OFDM DSSS-OFDM not supported always 0 */ - uint16_t scan_type; -} __attribute__((packed)); + uint16_t capability; /* bit5:preamble bit6:pbcc pbcc not supported always 0 + * bit10:ShortSlotTime bit13:DSSS-OFDM DSSS-OFDM not supported always 0 */ + uint16_t scan_type; +} __attribute__ ((packed)); struct hostif_ps_adhoc_set_confirm_t { struct hostif_hdr header; - uint16_t result_code; -} __attribute__((packed)); + uint16_t result_code; +} __attribute__ ((packed)); struct hostif_infrastructure_set_request_t { struct hostif_hdr header; - uint16_t phy_type; - uint16_t cts_mode; + uint16_t phy_type; + uint16_t cts_mode; struct rate_set16_t rate_set; struct ssid_t ssid; - uint16_t capability; /* bit5:preamble bit6:pbcc pbcc not supported always 0 - * bit10:ShortSlotTime bit13:DSSS-OFDM DSSS-OFDM not supported always 0 */ - uint16_t beacon_lost_count; - uint16_t auth_type; + uint16_t capability; /* bit5:preamble bit6:pbcc pbcc not supported always 0 + * bit10:ShortSlotTime bit13:DSSS-OFDM DSSS-OFDM not supported always 0 */ + uint16_t beacon_lost_count; + uint16_t auth_type; #define AUTH_TYPE_OPEN_SYSTEM 0 #define AUTH_TYPE_SHARED_KEY 1 struct channel_list_t channel_list; - uint16_t scan_type; -} __attribute__((packed)); + uint16_t scan_type; +} __attribute__ ((packed)); struct hostif_infrastructure_set2_request_t { struct hostif_hdr header; - uint16_t phy_type; - uint16_t cts_mode; + uint16_t phy_type; + uint16_t cts_mode; struct rate_set16_t rate_set; struct ssid_t ssid; - uint16_t capability; /* bit5:preamble bit6:pbcc pbcc not supported always 0 - * bit10:ShortSlotTime bit13:DSSS-OFDM DSSS-OFDM not supported always 0 */ - uint16_t beacon_lost_count; - uint16_t auth_type; + uint16_t capability; /* bit5:preamble bit6:pbcc pbcc not supported always 0 + * bit10:ShortSlotTime bit13:DSSS-OFDM DSSS-OFDM not supported always 0 */ + uint16_t beacon_lost_count; + uint16_t auth_type; #define AUTH_TYPE_OPEN_SYSTEM 0 #define AUTH_TYPE_SHARED_KEY 1 struct channel_list_t channel_list; - uint16_t scan_type; - uint8_t bssid[ETH_ALEN]; -} __attribute__((packed)); - + uint16_t scan_type; + uint8_t bssid[ETH_ALEN]; +} __attribute__ ((packed)); struct hostif_infrastructure_set_confirm_t { struct hostif_hdr header; - uint16_t result_code; -} __attribute__((packed)); + uint16_t result_code; +} __attribute__ ((packed)); struct hostif_adhoc_set_request_t { struct hostif_hdr header; - uint16_t phy_type; - uint16_t cts_mode; - uint16_t channel; + uint16_t phy_type; + uint16_t cts_mode; + uint16_t channel; struct rate_set16_t rate_set; struct ssid_t ssid; - uint16_t capability; /* bit5:preamble bit6:pbcc pbcc not supported always 0 - * bit10:ShortSlotTime bit13:DSSS-OFDM DSSS-OFDM not supported always 0 */ - uint16_t scan_type; -} __attribute__((packed)); + uint16_t capability; /* bit5:preamble bit6:pbcc pbcc not supported always 0 + * bit10:ShortSlotTime bit13:DSSS-OFDM DSSS-OFDM not supported always 0 */ + uint16_t scan_type; +} __attribute__ ((packed)); struct hostif_adhoc_set2_request_t { struct hostif_hdr header; - uint16_t phy_type; - uint16_t cts_mode; - uint16_t reserved; + uint16_t phy_type; + uint16_t cts_mode; + uint16_t reserved; struct rate_set16_t rate_set; struct ssid_t ssid; - uint16_t capability; /* bit5:preamble bit6:pbcc pbcc not supported always 0 - * bit10:ShortSlotTime bit13:DSSS-OFDM DSSS-OFDM not supported always 0 */ - uint16_t scan_type; + uint16_t capability; /* bit5:preamble bit6:pbcc pbcc not supported always 0 + * bit10:ShortSlotTime bit13:DSSS-OFDM DSSS-OFDM not supported always 0 */ + uint16_t scan_type; struct channel_list_t channel_list; - uint8_t bssid[ETH_ALEN]; -} __attribute__((packed)); + uint8_t bssid[ETH_ALEN]; +} __attribute__ ((packed)); struct hostif_adhoc_set_confirm_t { struct hostif_hdr header; - uint16_t result_code; -} __attribute__((packed)); - + uint16_t result_code; +} __attribute__ ((packed)); struct last_associate_t { - uint8_t type; - uint8_t status; -} __attribute__((packed)); + uint8_t type; + uint8_t status; +} __attribute__ ((packed)); struct association_request_t { - uint8_t type; + uint8_t type; #define FRAME_TYPE_ASSOC_REQ 0x00 #define FRAME_TYPE_REASSOC_REQ 0x20 - uint8_t pad; - uint16_t capability; - uint16_t listen_interval; - uint8_t ap_address[6]; - uint16_t reqIEs_size; -} __attribute__((packed)); + uint8_t pad; + uint16_t capability; + uint16_t listen_interval; + uint8_t ap_address[6]; + uint16_t reqIEs_size; +} __attribute__ ((packed)); struct association_response_t { - uint8_t type; + uint8_t type; #define FRAME_TYPE_ASSOC_RESP 0x10 #define FRAME_TYPE_REASSOC_RESP 0x30 - uint8_t pad; - uint16_t capability; - uint16_t status; - uint16_t association_id; - uint16_t respIEs_size; -} __attribute__((packed)); + uint8_t pad; + uint16_t capability; + uint16_t status; + uint16_t association_id; + uint16_t respIEs_size; +} __attribute__ ((packed)); struct hostif_associate_indication_t { struct hostif_hdr header; @@ -476,68 +472,68 @@ struct hostif_associate_indication_t { struct association_response_t assoc_resp; /* followed by (reqIEs_size + respIEs_size) octets of data */ /* reqIEs data *//* respIEs data */ -} __attribute__((packed)); +} __attribute__ ((packed)); struct hostif_bss_scan_request_t { struct hostif_hdr header; - uint8_t scan_type; + uint8_t scan_type; #define ACTIVE_SCAN 0 #define PASSIVE_SCAN 1 - uint8_t pad[3]; + uint8_t pad[3]; uint32_t ch_time_min; uint32_t ch_time_max; struct channel_list_t channel_list; struct ssid_t ssid; -} __attribute__((packed)); +} __attribute__ ((packed)); struct hostif_bss_scan_confirm_t { struct hostif_hdr header; - uint16_t result_code; - uint16_t reserved; -} __attribute__((packed)); + uint16_t result_code; + uint16_t reserved; +} __attribute__ ((packed)); struct hostif_phy_information_request_t { struct hostif_hdr header; - uint16_t type; + uint16_t type; #define NORMAL_TYPE 0 #define TIME_TYPE 1 - uint16_t time; /* unit 100ms */ -} __attribute__((packed)); + uint16_t time; /* unit 100ms */ +} __attribute__ ((packed)); struct hostif_phy_information_confirm_t { struct hostif_hdr header; - uint8_t rssi; - uint8_t sq; - uint8_t noise; - uint8_t link_speed; - uint32_t tx_frame; - uint32_t rx_frame; - uint32_t tx_error; - uint32_t rx_error; -} __attribute__((packed)); + uint8_t rssi; + uint8_t sq; + uint8_t noise; + uint8_t link_speed; + uint32_t tx_frame; + uint32_t rx_frame; + uint32_t tx_error; + uint32_t rx_error; +} __attribute__ ((packed)); /* sleep mode */ #define SLP_ACTIVE 0 #define SLP_SLEEP 1 struct hostif_sleep_request_t { struct hostif_hdr header; -} __attribute__((packed)); +} __attribute__ ((packed)); struct hostif_sleep_confirm_t { struct hostif_hdr header; - uint16_t result_code; -} __attribute__((packed)); + uint16_t result_code; +} __attribute__ ((packed)); struct hostif_mic_failure_request_t { struct hostif_hdr header; - uint16_t failure_count; - uint16_t timer; -} __attribute__((packed)); + uint16_t failure_count; + uint16_t timer; +} __attribute__ ((packed)); struct hostif_mic_failure_confirm_t { struct hostif_hdr header; - uint16_t result_code; -} __attribute__((packed)); + uint16_t result_code; +} __attribute__ ((packed)); #define BASIC_RATE 0x80 #define RATE_MASK 0x7F @@ -557,13 +553,13 @@ struct hostif_mic_failure_confirm_t { #define TX_RATE_FIXED 5 /* 11b rate */ -#define TX_RATE_1M (uint8_t)(10/5) /* 11b 11g basic rate */ -#define TX_RATE_2M (uint8_t)(20/5) /* 11b 11g basic rate */ -#define TX_RATE_5M (uint8_t)(55/5) /* 11g basic rate */ +#define TX_RATE_1M (uint8_t)(10/5) /* 11b 11g basic rate */ +#define TX_RATE_2M (uint8_t)(20/5) /* 11b 11g basic rate */ +#define TX_RATE_5M (uint8_t)(55/5) /* 11g basic rate */ #define TX_RATE_11M (uint8_t)(110/5) /* 11g basic rate */ /* 11g rate */ -#define TX_RATE_6M (uint8_t)(60/5) /* 11g basic rate */ +#define TX_RATE_6M (uint8_t)(60/5) /* 11g basic rate */ #define TX_RATE_12M (uint8_t)(120/5) /* 11g basic rate */ #define TX_RATE_24M (uint8_t)(240/5) /* 11g basic rate */ #define TX_RATE_9M (uint8_t)(90/5) @@ -587,13 +583,13 @@ struct hostif_mic_failure_confirm_t { ((A&RATE_MASK)==TX_RATE_54M)) enum { - CONNECT_STATUS=0, + CONNECT_STATUS = 0, DISCONNECT_STATUS }; /* preamble type */ enum { - LONG_PREAMBLE=0, + LONG_PREAMBLE = 0, SHORT_PREAMBLE }; @@ -623,26 +619,29 @@ enum { #include "ks_wlan.h" /* function prototype */ -extern int hostif_data_request( struct ks_wlan_private *priv, struct sk_buff *packet ); -extern void hostif_receive( struct ks_wlan_private *priv, unsigned char *p, unsigned int size ); +extern int hostif_data_request(struct ks_wlan_private *priv, + struct sk_buff *packet); +extern void hostif_receive(struct ks_wlan_private *priv, unsigned char *p, + unsigned int size); extern void hostif_sme_enqueue(struct ks_wlan_private *priv, uint16_t event); -extern int hostif_init( struct ks_wlan_private *priv ); -extern void hostif_exit( struct ks_wlan_private *priv ); +extern int hostif_init(struct ks_wlan_private *priv); +extern void hostif_exit(struct ks_wlan_private *priv); static inline int hif_align_size(int size) { #ifdef KS_ATOM - if( size < 1024 ) + if (size < 1024) size = 1024; #endif #ifdef DEVICE_ALIGNMENT - return (size%DEVICE_ALIGNMENT) ? size + DEVICE_ALIGNMENT - (size % DEVICE_ALIGNMENT) : size; + return (size % DEVICE_ALIGNMENT) ? size + DEVICE_ALIGNMENT - + (size % DEVICE_ALIGNMENT) : size; #else return size; #endif } -#endif /* __KERNEL__ */ +#endif /* __KERNEL__ */ #endif /* _KS_HOSTIF_H_ */ -- cgit v0.10.2 From d6e25e7048eb6a9f086f3cbf4a42a7a6a5b66bae Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Tue, 31 May 2016 12:56:32 +0200 Subject: staging: ks7010: indent ks_wlan.h Signed-off-by: Wolfram Sang Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/ks7010/ks_wlan.h b/drivers/staging/ks7010/ks_wlan.h index 58e3a5a..f0f9f8e 100644 --- a/drivers/staging/ks7010/ks_wlan.h +++ b/drivers/staging/ks7010/ks_wlan.h @@ -22,16 +22,16 @@ #include #include -#include /* spinlock_t */ -#include /* wait_queue_head_t */ -#include /* pid_t */ -#include /* struct net_device_stats, struct sk_buff */ +#include /* spinlock_t */ +#include /* wait_queue_head_t */ +#include /* pid_t */ +#include /* struct net_device_stats, struct sk_buff */ #include #include -#include /* struct atmic_t */ +#include /* struct atmic_t */ #include /* struct timer_list */ #include -#include /* struct completion */ +#include /* struct completion */ #include #include @@ -46,37 +46,37 @@ #endif struct ks_wlan_parameter { - uint8_t operation_mode; /* Operation Mode */ - uint8_t channel; /* Channel */ - uint8_t tx_rate; /* Transmit Rate */ + uint8_t operation_mode; /* Operation Mode */ + uint8_t channel; /* Channel */ + uint8_t tx_rate; /* Transmit Rate */ struct { uint8_t size; uint8_t body[16]; } rate_set; - uint8_t bssid[ETH_ALEN]; /* BSSID */ + uint8_t bssid[ETH_ALEN]; /* BSSID */ struct { uint8_t size; - uint8_t body[32+1]; - } ssid; /* SSID */ - uint8_t preamble; /* Preamble */ - uint8_t powermgt; /* PowerManagementMode */ - uint32_t scan_type; /* AP List Scan Type */ + uint8_t body[32 + 1]; + } ssid; /* SSID */ + uint8_t preamble; /* Preamble */ + uint8_t powermgt; /* PowerManagementMode */ + uint32_t scan_type; /* AP List Scan Type */ #define BEACON_LOST_COUNT_MIN 0 #define BEACON_LOST_COUNT_MAX 65535 - uint32_t beacon_lost_count; /* Beacon Lost Count */ - uint32_t rts; /* RTS Threashold */ - uint32_t fragment; /* Fragmentation Threashold */ - uint32_t privacy_invoked; - uint32_t wep_index; + uint32_t beacon_lost_count; /* Beacon Lost Count */ + uint32_t rts; /* RTS Threashold */ + uint32_t fragment; /* Fragmentation Threashold */ + uint32_t privacy_invoked; + uint32_t wep_index; struct { uint8_t size; - uint8_t val[13*2+1]; + uint8_t val[13 * 2 + 1]; } wep_key[4]; - uint16_t authenticate_type; - uint16_t phy_type; /* 11b/11g/11bg mode type*/ - uint16_t cts_mode; /* for 11g/11bg mode cts mode */ - uint16_t phy_info_timer; /* phy information timer */ - char rom_file[256]; + uint16_t authenticate_type; + uint16_t phy_type; /* 11b/11g/11bg mode type */ + uint16_t cts_mode; /* for 11g/11bg mode cts mode */ + uint16_t phy_info_timer; /* phy information timer */ + char rom_file[256]; }; enum { @@ -157,7 +157,6 @@ enum { SME_START_REQUEST, SME_GET_EEPROM_CKSUM, - SME_MIC_FAILURE_CONFIRM, SME_START_CONFIRM, @@ -187,7 +186,7 @@ enum { SME_WEP_SET_CONFIRM, SME_TERMINATE, - SME_EVENT_SIZE /* end */ + SME_EVENT_SIZE /* end */ }; /* SME Status */ @@ -200,58 +199,58 @@ enum { #define SME_EVENT_BUFF_SIZE 128 -struct sme_info{ - int sme_status; - int event_buff[SME_EVENT_BUFF_SIZE]; - unsigned int qhead; - unsigned int qtail; +struct sme_info { + int sme_status; + int event_buff[SME_EVENT_BUFF_SIZE]; + unsigned int qhead; + unsigned int qtail; #ifdef KS_WLAN_DEBUG - /* for debug */ + /* for debug */ unsigned int max_event_count; #endif - spinlock_t sme_spin; + spinlock_t sme_spin; unsigned long sme_flag; }; -struct hostt_t{ - int buff[SME_EVENT_BUFF_SIZE]; - unsigned int qhead; - unsigned int qtail; +struct hostt_t { + int buff[SME_EVENT_BUFF_SIZE]; + unsigned int qhead; + unsigned int qtail; }; #define RSN_IE_BODY_MAX 64 struct rsn_ie_t { - uint8_t id; /* 0xdd = WPA or 0x30 = RSN */ - uint8_t size; /* max ? 255 ? */ - uint8_t body[RSN_IE_BODY_MAX]; -} __attribute__((packed)); + uint8_t id; /* 0xdd = WPA or 0x30 = RSN */ + uint8_t size; /* max ? 255 ? */ + uint8_t body[RSN_IE_BODY_MAX]; +} __attribute__ ((packed)); #ifdef WPS #define WPS_IE_BODY_MAX 255 struct wps_ie_t { - uint8_t id; /* 221 'dd 00 50 F2 04' */ - uint8_t size; /* max ? 255 ? */ + uint8_t id; /* 221 'dd 00 50 F2 04' */ + uint8_t size; /* max ? 255 ? */ uint8_t body[WPS_IE_BODY_MAX]; -} __attribute__((packed)); +} __attribute__ ((packed)); #endif /* WPS */ struct local_ap_t { - uint8_t bssid[6]; - uint8_t rssi; - uint8_t sq; + uint8_t bssid[6]; + uint8_t rssi; + uint8_t sq; struct { - uint8_t size; - uint8_t body[32]; - uint8_t ssid_pad; + uint8_t size; + uint8_t body[32]; + uint8_t ssid_pad; } ssid; struct { - uint8_t size; - uint8_t body[16]; - uint8_t rate_pad; + uint8_t size; + uint8_t body[16]; + uint8_t rate_pad; } rate_set; - uint16_t capability; - uint8_t channel; - uint8_t noise; + uint16_t capability; + uint8_t channel; + uint8_t noise; struct rsn_ie_t wpa_ie; struct rsn_ie_t rsn_ie; #ifdef WPS @@ -263,19 +262,19 @@ struct local_ap_t { #define LOCAL_CURRENT_AP LOCAL_APLIST_MAX struct local_aplist_t { int size; - struct local_ap_t ap[LOCAL_APLIST_MAX+1]; + struct local_ap_t ap[LOCAL_APLIST_MAX + 1]; }; -struct local_gain_t{ - uint8_t TxMode; - uint8_t RxMode; - uint8_t TxGain; - uint8_t RxGain; +struct local_gain_t { + uint8_t TxMode; + uint8_t RxMode; + uint8_t TxGain; + uint8_t RxGain; }; -struct local_eeprom_sum_t{ - uint8_t type; - uint8_t result; +struct local_eeprom_sum_t { + uint8_t type; + uint8_t result; }; enum { @@ -285,7 +284,6 @@ enum { EEPROM_NG, }; - /* Power Save Status */ enum { PS_NONE, @@ -297,22 +295,22 @@ enum { }; struct power_save_status_t { - atomic_t status; /* initialvalue 0 */ + atomic_t status; /* initialvalue 0 */ struct completion wakeup_wait; - atomic_t confirm_wait; - atomic_t snooze_guard; + atomic_t confirm_wait; + atomic_t snooze_guard; }; struct sleep_status_t { - atomic_t status; /* initialvalue 0 */ - atomic_t doze_request; - atomic_t wakeup_request; + atomic_t status; /* initialvalue 0 */ + atomic_t doze_request; + atomic_t wakeup_request; }; /* WPA */ struct scan_ext_t { unsigned int flag; - char ssid[IW_ESSID_MAX_SIZE+1]; + char ssid[IW_ESSID_MAX_SIZE + 1]; }; enum { @@ -337,7 +335,7 @@ enum { #define CIPHER_ID_LEN 4 -enum { +enum { KEY_MGMT_802_1X, KEY_MGMT_PSK, KEY_MGMT_WPANONE, @@ -358,26 +356,26 @@ enum { #define MIC_KEY_SIZE 8 struct wpa_key_t { - uint32_t ext_flags; /* IW_ENCODE_EXT_xxx */ - uint8_t tx_seq[IW_ENCODE_SEQ_MAX_SIZE]; /* LSB first */ - uint8_t rx_seq[IW_ENCODE_SEQ_MAX_SIZE]; /* LSB first */ - struct sockaddr addr; /* ff:ff:ff:ff:ff:ff for broadcast/multicast - * (group) keys or unicast address for - * individual keys */ - uint16_t alg; - uint16_t key_len; /* WEP: 5 or 13, TKIP: 32, CCMP: 16 */ - uint8_t key_val[IW_ENCODING_TOKEN_MAX]; - uint8_t tx_mic_key[MIC_KEY_SIZE]; - uint8_t rx_mic_key[MIC_KEY_SIZE]; + uint32_t ext_flags; /* IW_ENCODE_EXT_xxx */ + uint8_t tx_seq[IW_ENCODE_SEQ_MAX_SIZE]; /* LSB first */ + uint8_t rx_seq[IW_ENCODE_SEQ_MAX_SIZE]; /* LSB first */ + struct sockaddr addr; /* ff:ff:ff:ff:ff:ff for broadcast/multicast + * (group) keys or unicast address for + * individual keys */ + uint16_t alg; + uint16_t key_len; /* WEP: 5 or 13, TKIP: 32, CCMP: 16 */ + uint8_t key_val[IW_ENCODING_TOKEN_MAX]; + uint8_t tx_mic_key[MIC_KEY_SIZE]; + uint8_t rx_mic_key[MIC_KEY_SIZE]; }; #define WPA_KEY_INDEX_MAX 4 #define WPA_RX_SEQ_LEN 6 struct mic_failure_t { - uint16_t failure; /* MIC Failure counter 0 or 1 or 2 */ - uint16_t counter; /* 1sec counter 0-60 */ - uint32_t last_failure_time; - int stop; /* stop flag */ + uint16_t failure; /* MIC Failure counter 0 or 1 or 2 */ + uint16_t counter; /* 1sec counter 0-60 */ + uint32_t last_failure_time; + int stop; /* stop flag */ }; struct wpa_status_t { @@ -401,36 +399,36 @@ struct pmk_list_t { struct list_head head; struct pmk_t { struct list_head list; - uint8_t bssid[ETH_ALEN]; - uint8_t pmkid[IW_PMKID_LEN]; + uint8_t bssid[ETH_ALEN]; + uint8_t pmkid[IW_PMKID_LEN]; } pmk[PMK_LIST_MAX]; }; #ifdef WPS struct wps_status_t { - int wps_enabled; - int ielen; - uint8_t ie[255]; + int wps_enabled; + int ielen; + uint8_t ie[255]; }; #endif /* WPS */ struct ks_wlan_private { - struct hw_info_t ks_wlan_hw; /* hardware information */ + struct hw_info_t ks_wlan_hw; /* hardware information */ struct net_device *net_dev; - int reg_net; /* register_netdev */ + int reg_net; /* register_netdev */ struct net_device_stats nstats; struct iw_statistics wstats; struct completion confirm_wait; - /* trx device & sme */ + /* trx device & sme */ struct tx_device tx_dev; struct rx_device rx_dev; - struct sme_info sme_i; + struct sme_info sme_i; u8 *rxp; - unsigned int rx_size; + unsigned int rx_size; struct tasklet_struct sme_task; struct work_struct ks_wlan_wakeup_task; int scan_ind_count; @@ -443,33 +441,33 @@ struct ks_wlan_private { struct sleep_status_t sleepstatus; struct wpa_status_t wpa; struct pmk_list_t pmklist; - /* wireless parameter */ + /* wireless parameter */ struct ks_wlan_parameter reg; uint8_t current_rate; - char nick[IW_ESSID_MAX_SIZE+1]; - - spinlock_t multicast_spin; + char nick[IW_ESSID_MAX_SIZE + 1]; + + spinlock_t multicast_spin; spinlock_t dev_read_lock; - wait_queue_head_t devread_wait; + wait_queue_head_t devread_wait; - unsigned int need_commit; /* for ioctl */ + unsigned int need_commit; /* for ioctl */ - /* DeviceIoControl */ + /* DeviceIoControl */ int device_open_status; atomic_t event_count; - atomic_t rec_count; - int dev_count; + atomic_t rec_count; + int dev_count; #define DEVICE_STOCK_COUNT 20 unsigned char *dev_data[DEVICE_STOCK_COUNT]; int dev_size[DEVICE_STOCK_COUNT]; - /* ioctl : IOCTL_FIRMWARE_VERSION */ - unsigned char firmware_version[128+1]; + /* ioctl : IOCTL_FIRMWARE_VERSION */ + unsigned char firmware_version[128 + 1]; int version_size; - int mac_address_valid; /* Mac Address Status */ + int mac_address_valid; /* Mac Address Status */ int dev_state; @@ -478,35 +476,33 @@ struct ks_wlan_private { /* spinlock_t lock; */ #define FORCE_DISCONNECT 0x80000000 #define CONNECT_STATUS_MASK 0x7FFFFFFF - uint32_t connect_status; /* connect status */ - int infra_status; /* Infractructure status */ + uint32_t connect_status; /* connect status */ + int infra_status; /* Infractructure status */ - uint8_t data_buff[0x1000]; + uint8_t data_buff[0x1000]; uint8_t scan_ssid_len; - uint8_t scan_ssid[IW_ESSID_MAX_SIZE+1]; + uint8_t scan_ssid[IW_ESSID_MAX_SIZE + 1]; struct local_gain_t gain; #ifdef WPS struct net_device *l2_dev; - int l2_fd; + int l2_fd; struct wps_status_t wps; #endif /* WPS */ - uint8_t sleep_mode; + uint8_t sleep_mode; uint8_t region; struct local_eeprom_sum_t eeprom_sum; uint8_t eeprom_checksum; - struct hostt_t hostt; + struct hostt_t hostt; unsigned long last_doze; unsigned long last_wakeup; - uint sdio_error_count; /* SDIO error */ - uint wakeup_count; /* for detect wakeup loop */ - -}; - + uint sdio_error_count; /* SDIO error */ + uint wakeup_count; /* for detect wakeup loop */ +}; #endif /* _KS_WLAN_H */ -- cgit v0.10.2 From 2086ffac7b91dfeac1d9ddf44ce6ab547df58499 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Tue, 31 May 2016 12:56:33 +0200 Subject: staging: ks7010: indent ks_wlan_ioctl.h Signed-off-by: Wolfram Sang Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/ks7010/ks_wlan_ioctl.h b/drivers/staging/ks7010/ks_wlan_ioctl.h index e7469f7..cc4669e 100644 --- a/drivers/staging/ks7010/ks_wlan_ioctl.h +++ b/drivers/staging/ks7010/ks_wlan_ioctl.h @@ -36,8 +36,8 @@ #define KS_WLAN_GET_SCAN_TYPE SIOCIWFIRSTPRIV+13 #define KS_WLAN_SET_RX_GAIN SIOCIWFIRSTPRIV+14 #define KS_WLAN_GET_RX_GAIN SIOCIWFIRSTPRIV+15 -#define KS_WLAN_HOSTT SIOCIWFIRSTPRIV+16 /* unused */ -//#define KS_WLAN_SET_REGION SIOCIWFIRSTPRIV+17 +#define KS_WLAN_HOSTT SIOCIWFIRSTPRIV+16 /* unused */ +//#define KS_WLAN_SET_REGION SIOCIWFIRSTPRIV+17 #define KS_WLAN_SET_BEACON_LOST SIOCIWFIRSTPRIV+18 #define KS_WLAN_GET_BEACON_LOST SIOCIWFIRSTPRIV+19 @@ -51,8 +51,8 @@ #define KS_WLAN_GET_CTS_MODE SIOCIWFIRSTPRIV+25 /* SIOCIWFIRSTPRIV+26 */ /* SIOCIWFIRSTPRIV+27 */ -#define KS_WLAN_SET_SLEEP_MODE SIOCIWFIRSTPRIV+28 /* sleep mode */ -#define KS_WLAN_GET_SLEEP_MODE SIOCIWFIRSTPRIV+29 /* sleep mode */ +#define KS_WLAN_SET_SLEEP_MODE SIOCIWFIRSTPRIV+28 /* sleep mode */ +#define KS_WLAN_GET_SLEEP_MODE SIOCIWFIRSTPRIV+29 /* sleep mode */ /* SIOCIWFIRSTPRIV+30 */ /* SIOCIWFIRSTPRIV+31 */ @@ -62,7 +62,8 @@ #include extern int ks_wlan_read_config_file(struct ks_wlan_private *priv); -extern int ks_wlan_setup_parameter(struct ks_wlan_private *priv, unsigned int commit_flag); +extern int ks_wlan_setup_parameter(struct ks_wlan_private *priv, + unsigned int commit_flag); #endif /* __KERNEL__ */ -- cgit v0.10.2 From 1df655478eeb909192bd6f2eafe62d46d83a25e0 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Tue, 31 May 2016 12:56:34 +0200 Subject: staging: ks7010: indent ks_wlan_net.c Signed-off-by: Wolfram Sang Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/ks7010/ks_wlan_net.c b/drivers/staging/ks7010/ks_wlan_net.c index ec5c452..3e28283 100644 --- a/drivers/staging/ks7010/ks_wlan_net.c +++ b/drivers/staging/ks7010/ks_wlan_net.c @@ -43,62 +43,63 @@ static int wep_on_off; /* Include Wireless Extension definition and check version */ #include -#define WIRELESS_SPY /* enable iwspy support */ +#define WIRELESS_SPY /* enable iwspy support */ #include /* New driver API */ /* Frequency list (map channels to frequencies) */ static const long frequency_list[] = { 2412, 2417, 2422, 2427, 2432, 2437, 2442, - 2447, 2452, 2457, 2462, 2467, 2472, 2484 }; + 2447, 2452, 2457, 2462, 2467, 2472, 2484 +}; /* A few details needed for WEP (Wireless Equivalent Privacy) */ #define MAX_KEY_SIZE 13 /* 128 (?) bits */ #define MIN_KEY_SIZE 5 /* 40 bits RC4 - WEP */ typedef struct wep_key_t { - u16 len; - u8 key[16]; /* 40-bit and 104-bit keys */ + u16 len; + u8 key[16]; /* 40-bit and 104-bit keys */ } wep_key_t; /* Backward compatibility */ #ifndef IW_ENCODE_NOKEY -#define IW_ENCODE_NOKEY 0x0800 /* Key is write only, so not present */ +#define IW_ENCODE_NOKEY 0x0800 /* Key is write only, so not present */ #define IW_ENCODE_MODE (IW_ENCODE_DISABLED | IW_ENCODE_RESTRICTED | IW_ENCODE_OPEN) #endif /* IW_ENCODE_NOKEY */ /* List of Wireless Handlers (new API) */ -static const struct iw_handler_def ks_wlan_handler_def; - -#define KSC_OPNOTSUPP /* Operation Not Support*/ +static const struct iw_handler_def ks_wlan_handler_def; +#define KSC_OPNOTSUPP /* Operation Not Support */ /* * function prototypes */ -extern int ks_wlan_hw_tx(struct ks_wlan_private *priv, void *p, unsigned long size, - void (*complete_handler)(void *arg1, void *arg2), - void *arg1, - void *arg2 ); -static int ks_wlan_open (struct net_device *dev); -static void ks_wlan_tx_timeout (struct net_device *dev); -static int ks_wlan_start_xmit (struct sk_buff *skb, struct net_device *dev); -static int ks_wlan_close (struct net_device *dev); -static void ks_wlan_set_multicast_list (struct net_device *dev); -static struct net_device_stats *ks_wlan_get_stats (struct net_device *dev); +extern int ks_wlan_hw_tx(struct ks_wlan_private *priv, void *p, + unsigned long size, + void (*complete_handler) (void *arg1, void *arg2), + void *arg1, void *arg2); +static int ks_wlan_open(struct net_device *dev); +static void ks_wlan_tx_timeout(struct net_device *dev); +static int ks_wlan_start_xmit(struct sk_buff *skb, struct net_device *dev); +static int ks_wlan_close(struct net_device *dev); +static void ks_wlan_set_multicast_list(struct net_device *dev); +static struct net_device_stats *ks_wlan_get_stats(struct net_device *dev); static int ks_wlan_set_mac_address(struct net_device *dev, void *addr); -static int ks_wlan_netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); +static int ks_wlan_netdev_ioctl(struct net_device *dev, struct ifreq *rq, + int cmd); static atomic_t update_phyinfo; static struct timer_list update_phyinfo_timer; static int ks_wlan_update_phy_information(struct ks_wlan_private *priv) { - struct iw_statistics *wstats = &priv->wstats; + struct iw_statistics *wstats = &priv->wstats; DPRINTK(4, "in_interrupt = %ld\n", in_interrupt()); if (priv->dev_state < DEVICE_STATE_READY) { - return -1; /* not finished initialize */ - } - if(atomic_read(&update_phyinfo)) + return -1; /* not finished initialize */ + } + if (atomic_read(&update_phyinfo)) return 1; /* The status */ @@ -108,12 +109,13 @@ int ks_wlan_update_phy_information(struct ks_wlan_private *priv) hostif_sme_enqueue(priv, SME_PHY_INFO_REQUEST); /* interruptible_sleep_on_timeout(&priv->confirm_wait, HZ/2); */ - if(!wait_for_completion_interruptible_timeout(&priv->confirm_wait,HZ/2)){ - DPRINTK(1,"wait time out!!\n"); + if (!wait_for_completion_interruptible_timeout + (&priv->confirm_wait, HZ / 2)) { + DPRINTK(1, "wait time out!!\n"); } atomic_inc(&update_phyinfo); - update_phyinfo_timer.expires = jiffies + HZ; /* 1sec */ + update_phyinfo_timer.expires = jiffies + HZ; /* 1sec */ add_timer(&update_phyinfo_timer); return 0; @@ -123,42 +125,43 @@ static void ks_wlan_update_phyinfo_timeout(unsigned long ptr) { DPRINTK(4, "in_interrupt = %ld\n", in_interrupt()); - atomic_set(&update_phyinfo,0); + atomic_set(&update_phyinfo, 0); } -int ks_wlan_setup_parameter(struct ks_wlan_private *priv, unsigned int commit_flag) +int ks_wlan_setup_parameter(struct ks_wlan_private *priv, + unsigned int commit_flag) { - DPRINTK(2,"\n"); + DPRINTK(2, "\n"); hostif_sme_enqueue(priv, SME_STOP_REQUEST); - if(commit_flag & SME_RTS) + if (commit_flag & SME_RTS) hostif_sme_enqueue(priv, SME_RTS_THRESHOLD_REQUEST); - if(commit_flag & SME_FRAG) + if (commit_flag & SME_FRAG) hostif_sme_enqueue(priv, SME_FRAGMENTATION_THRESHOLD_REQUEST); - if(commit_flag & SME_WEP_INDEX) + if (commit_flag & SME_WEP_INDEX) hostif_sme_enqueue(priv, SME_WEP_INDEX_REQUEST); - if(commit_flag & SME_WEP_VAL1) + if (commit_flag & SME_WEP_VAL1) hostif_sme_enqueue(priv, SME_WEP_KEY1_REQUEST); - if(commit_flag & SME_WEP_VAL2) + if (commit_flag & SME_WEP_VAL2) hostif_sme_enqueue(priv, SME_WEP_KEY2_REQUEST); - if(commit_flag & SME_WEP_VAL3) + if (commit_flag & SME_WEP_VAL3) hostif_sme_enqueue(priv, SME_WEP_KEY3_REQUEST); - if(commit_flag & SME_WEP_VAL4) + if (commit_flag & SME_WEP_VAL4) hostif_sme_enqueue(priv, SME_WEP_KEY4_REQUEST); - if(commit_flag & SME_WEP_FLAG) + if (commit_flag & SME_WEP_FLAG) hostif_sme_enqueue(priv, SME_WEP_FLAG_REQUEST); - if(commit_flag & SME_RSN){ + if (commit_flag & SME_RSN) { hostif_sme_enqueue(priv, SME_RSN_ENABLED_REQUEST); hostif_sme_enqueue(priv, SME_RSN_MODE_REQUEST); } - if(commit_flag & SME_RSN_MULTICAST) + if (commit_flag & SME_RSN_MULTICAST) hostif_sme_enqueue(priv, SME_RSN_MCAST_REQUEST); - if(commit_flag & SME_RSN_UNICAST) + if (commit_flag & SME_RSN_UNICAST) hostif_sme_enqueue(priv, SME_RSN_UCAST_REQUEST); - if(commit_flag & SME_RSN_AUTH) + if (commit_flag & SME_RSN_AUTH) hostif_sme_enqueue(priv, SME_RSN_AUTH_REQUEST); hostif_sme_enqueue(priv, SME_MODE_SET_REQUEST); @@ -180,23 +183,24 @@ int ks_wlan_setup_parameter(struct ks_wlan_private *priv, unsigned int commit_fl /*------------------------------------------------------------------*/ /* Wireless Handler : get protocol name */ -static int ks_wlan_get_name(struct net_device *dev, struct iw_request_info *info, - char *cwrq, char *extra) +static int ks_wlan_get_name(struct net_device *dev, + struct iw_request_info *info, char *cwrq, + char *extra) { - struct ks_wlan_private *priv = (struct ks_wlan_private *) netdev_priv(dev); - - if (priv->sleep_mode == SLP_SLEEP){ return -EPERM; } /* for SLEEP MODE */ + struct ks_wlan_private *priv = + (struct ks_wlan_private *)netdev_priv(dev); + if (priv->sleep_mode == SLP_SLEEP) { + return -EPERM; + } + /* for SLEEP MODE */ if (priv->dev_state < DEVICE_STATE_READY) { strcpy(cwrq, "NOT READY!"); - } - else if(priv->reg.phy_type == D_11B_ONLY_MODE){ + } else if (priv->reg.phy_type == D_11B_ONLY_MODE) { strcpy(cwrq, "IEEE 802.11b"); - } - else if(priv->reg.phy_type == D_11G_ONLY_MODE){ + } else if (priv->reg.phy_type == D_11G_ONLY_MODE) { strcpy(cwrq, "IEEE 802.11g"); - } - else { + } else { strcpy(cwrq, "IEEE 802.11b/g"); } @@ -205,39 +209,45 @@ static int ks_wlan_get_name(struct net_device *dev, struct iw_request_info *info /*------------------------------------------------------------------*/ /* Wireless Handler : set frequency */ -static int ks_wlan_set_freq(struct net_device *dev, struct iw_request_info *info, - struct iw_freq *fwrq, char *extra) +static int ks_wlan_set_freq(struct net_device *dev, + struct iw_request_info *info, struct iw_freq *fwrq, + char *extra) { - struct ks_wlan_private *priv = (struct ks_wlan_private *)netdev_priv(dev); - int rc = -EINPROGRESS; /* Call commit handler */ + struct ks_wlan_private *priv = + (struct ks_wlan_private *)netdev_priv(dev); + int rc = -EINPROGRESS; /* Call commit handler */ - if (priv->sleep_mode == SLP_SLEEP){ return -EPERM; } /* for SLEEP MODE */ + if (priv->sleep_mode == SLP_SLEEP) { + return -EPERM; + } + /* for SLEEP MODE */ /* If setting by frequency, convert to a channel */ - if((fwrq->e == 1) && - (fwrq->m >= (int) 2.412e8) && - (fwrq->m <= (int) 2.487e8)) { + if ((fwrq->e == 1) && + (fwrq->m >= (int)2.412e8) && (fwrq->m <= (int)2.487e8)) { int f = fwrq->m / 100000; int c = 0; - while((c < 14) && (f != frequency_list[c])) + while ((c < 14) && (f != frequency_list[c])) c++; /* Hack to fall through... */ fwrq->e = 0; fwrq->m = c + 1; } /* Setting by channel number */ - if((fwrq->m > 1000) || (fwrq->e > 0)) + if ((fwrq->m > 1000) || (fwrq->e > 0)) rc = -EOPNOTSUPP; else { int channel = fwrq->m; /* We should do a better check than that, * based on the card capability !!! */ - if((channel < 1) || (channel > 14)) { - printk(KERN_DEBUG "%s: New channel value of %d is invalid!\n", dev->name, fwrq->m); + if ((channel < 1) || (channel > 14)) { + printk(KERN_DEBUG + "%s: New channel value of %d is invalid!\n", + dev->name, fwrq->m); rc = -EINVAL; } else { /* Yes ! We can set it !!! */ - priv->reg.channel = (u8)(channel); + priv->reg.channel = (u8) (channel); priv->need_commit |= SME_MODE_SET; } } @@ -247,20 +257,23 @@ static int ks_wlan_set_freq(struct net_device *dev, struct iw_request_info *info /*------------------------------------------------------------------*/ /* Wireless Handler : get frequency */ -static int ks_wlan_get_freq(struct net_device *dev, struct iw_request_info *info, - struct iw_freq *fwrq, char *extra) +static int ks_wlan_get_freq(struct net_device *dev, + struct iw_request_info *info, struct iw_freq *fwrq, + char *extra) { - struct ks_wlan_private *priv = (struct ks_wlan_private *)netdev_priv(dev); + struct ks_wlan_private *priv = + (struct ks_wlan_private *)netdev_priv(dev); int f; - if (priv->sleep_mode == SLP_SLEEP){ return -EPERM; } /* for SLEEP MODE */ - - if((priv->connect_status & CONNECT_STATUS_MASK) == CONNECT_STATUS){ - f = (int)priv->current_ap.channel; + if (priv->sleep_mode == SLP_SLEEP) { + return -EPERM; } - else + /* for SLEEP MODE */ + if ((priv->connect_status & CONNECT_STATUS_MASK) == CONNECT_STATUS) { + f = (int)priv->current_ap.channel; + } else f = (int)priv->reg.channel; - fwrq->m = frequency_list[f-1] * 100000; + fwrq->m = frequency_list[f - 1] * 100000; fwrq->e = 1; return 0; @@ -268,18 +281,23 @@ static int ks_wlan_get_freq(struct net_device *dev, struct iw_request_info *info /*------------------------------------------------------------------*/ /* Wireless Handler : set ESSID */ -static int ks_wlan_set_essid(struct net_device *dev, struct iw_request_info *info, - struct iw_point *dwrq, char *extra) +static int ks_wlan_set_essid(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *dwrq, char *extra) { - struct ks_wlan_private *priv = (struct ks_wlan_private *)netdev_priv(dev); + struct ks_wlan_private *priv = + (struct ks_wlan_private *)netdev_priv(dev); size_t len; - DPRINTK(2," %d\n", dwrq->flags); + DPRINTK(2, " %d\n", dwrq->flags); - if (priv->sleep_mode == SLP_SLEEP){ return -EPERM; } /* for SLEEP MODE */ + if (priv->sleep_mode == SLP_SLEEP) { + return -EPERM; + } + /* for SLEEP MODE */ /* Check if we asked for `any' */ - if(dwrq->flags == 0) { + if (dwrq->flags == 0) { /* Just send an empty SSID list */ memset(priv->reg.ssid.body, 0, sizeof(priv->reg.ssid.body)); priv->reg.ssid.size = 0; @@ -291,13 +309,13 @@ static int ks_wlan_set_essid(struct net_device *dev, struct iw_request_info *inf len--; /* Check the size of the string */ - if(len > IW_ESSID_MAX_SIZE) { + if (len > IW_ESSID_MAX_SIZE) { return -EINVAL; } #else /* Check the size of the string */ - if(dwrq->length > IW_ESSID_MAX_SIZE+1) { - return -E2BIG ; + if (dwrq->length > IW_ESSID_MAX_SIZE + 1) { + return -E2BIG; } #endif @@ -315,25 +333,29 @@ static int ks_wlan_set_essid(struct net_device *dev, struct iw_request_info *inf /* Write it to the card */ priv->need_commit |= SME_MODE_SET; -// return -EINPROGRESS; /* Call commit handler */ +// return -EINPROGRESS; /* Call commit handler */ ks_wlan_setup_parameter(priv, priv->need_commit); - priv->need_commit=0; - return 0; + priv->need_commit = 0; + return 0; } /*------------------------------------------------------------------*/ /* Wireless Handler : get ESSID */ -static int ks_wlan_get_essid(struct net_device *dev, struct iw_request_info *info, - struct iw_point *dwrq, char *extra) +static int ks_wlan_get_essid(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *dwrq, char *extra) { - struct ks_wlan_private *priv = (struct ks_wlan_private *)netdev_priv(dev); + struct ks_wlan_private *priv = + (struct ks_wlan_private *)netdev_priv(dev); - if (priv->sleep_mode == SLP_SLEEP){ return -EPERM; } /* for SLEEP MODE */ + if (priv->sleep_mode == SLP_SLEEP) { + return -EPERM; + } + /* for SLEEP MODE */ /* Note : if dwrq->flags != 0, we should * get the relevant SSID from the SSID list... */ - - if(priv->reg.ssid.size){ + if (priv->reg.ssid.size) { /* Get the current SSID */ memcpy(extra, priv->reg.ssid.body, priv->reg.ssid.size); #if 0 @@ -345,17 +367,17 @@ static int ks_wlan_get_essid(struct net_device *dev, struct iw_request_info *inf #if 1 dwrq->length = priv->reg.ssid.size; #else - dwrq->length = priv->reg.ssid.size+1; + dwrq->length = priv->reg.ssid.size + 1; #endif - dwrq->flags = 1; /* active */ - }else{ + dwrq->flags = 1; /* active */ + } else { #if 1 dwrq->length = 0; #else extra[0] = '\0'; dwrq->length = 1; #endif - dwrq->flags = 0; /* ANY */ + dwrq->flags = 0; /* ANY */ } return 0; @@ -366,33 +388,35 @@ static int ks_wlan_get_essid(struct net_device *dev, struct iw_request_info *inf static int ks_wlan_set_wap(struct net_device *dev, struct iw_request_info *info, struct sockaddr *ap_addr, char *extra) { - struct ks_wlan_private *priv = (struct ks_wlan_private *)netdev_priv(dev); + struct ks_wlan_private *priv = + (struct ks_wlan_private *)netdev_priv(dev); - DPRINTK(2,"\n"); - - if (priv->sleep_mode == SLP_SLEEP){ return -EPERM; } /* for SLEEP MODE */ + DPRINTK(2, "\n"); + if (priv->sleep_mode == SLP_SLEEP) { + return -EPERM; + } + /* for SLEEP MODE */ if (priv->reg.operation_mode == MODE_ADHOC || - priv->reg.operation_mode == MODE_INFRASTRUCTURE) { - memcpy(priv->reg.bssid, (u8 *)&ap_addr->sa_data, ETH_ALEN); + priv->reg.operation_mode == MODE_INFRASTRUCTURE) { + memcpy(priv->reg.bssid, (u8 *) & ap_addr->sa_data, ETH_ALEN); - if (is_valid_ether_addr((u8 *)priv->reg.bssid)) { + if (is_valid_ether_addr((u8 *) priv->reg.bssid)) { priv->need_commit |= SME_MODE_SET; } - } - else { + } else { memset(priv->reg.bssid, 0x0, ETH_ALEN); return -EOPNOTSUPP; } DPRINTK(2, "bssid = %02x:%02x:%02x:%02x:%02x:%02x\n", - priv->reg.bssid[0],priv->reg.bssid[1],priv->reg.bssid[2], - priv->reg.bssid[3],priv->reg.bssid[4],priv->reg.bssid[5]); + priv->reg.bssid[0], priv->reg.bssid[1], priv->reg.bssid[2], + priv->reg.bssid[3], priv->reg.bssid[4], priv->reg.bssid[5]); /* Write it to the card */ if (priv->need_commit) { priv->need_commit |= SME_MODE_SET; - return -EINPROGRESS; /* Call commit handler */ + return -EINPROGRESS; /* Call commit handler */ } return 0; } @@ -402,14 +426,16 @@ static int ks_wlan_set_wap(struct net_device *dev, struct iw_request_info *info, static int ks_wlan_get_wap(struct net_device *dev, struct iw_request_info *info, struct sockaddr *awrq, char *extra) { - struct ks_wlan_private *priv = (struct ks_wlan_private *)netdev_priv(dev); + struct ks_wlan_private *priv = + (struct ks_wlan_private *)netdev_priv(dev); - if (priv->sleep_mode == SLP_SLEEP){ return -EPERM; } /* for SLEEP MODE */ - - if((priv->connect_status & CONNECT_STATUS_MASK) == CONNECT_STATUS){ - memcpy(awrq->sa_data, &(priv->current_ap.bssid[0]), ETH_ALEN); + if (priv->sleep_mode == SLP_SLEEP) { + return -EPERM; } - else{ + /* for SLEEP MODE */ + if ((priv->connect_status & CONNECT_STATUS_MASK) == CONNECT_STATUS) { + memcpy(awrq->sa_data, &(priv->current_ap.bssid[0]), ETH_ALEN); + } else { memset(awrq->sa_data, 0, ETH_ALEN); } @@ -420,15 +446,20 @@ static int ks_wlan_get_wap(struct net_device *dev, struct iw_request_info *info, /*------------------------------------------------------------------*/ /* Wireless Handler : set Nickname */ -static int ks_wlan_set_nick(struct net_device *dev, struct iw_request_info *info, - struct iw_point *dwrq, char *extra) +static int ks_wlan_set_nick(struct net_device *dev, + struct iw_request_info *info, struct iw_point *dwrq, + char *extra) { - struct ks_wlan_private *priv = (struct ks_wlan_private *)netdev_priv(dev); + struct ks_wlan_private *priv = + (struct ks_wlan_private *)netdev_priv(dev); - if (priv->sleep_mode == SLP_SLEEP){ return -EPERM; } /* for SLEEP MODE */ + if (priv->sleep_mode == SLP_SLEEP) { + return -EPERM; + } + /* for SLEEP MODE */ /* Check the size of the string */ - if(dwrq->length > 16 + 1) { + if (dwrq->length > 16 + 1) { return -E2BIG; } memset(priv->nick, 0, sizeof(priv->nick)); @@ -439,13 +470,17 @@ static int ks_wlan_set_nick(struct net_device *dev, struct iw_request_info *info /*------------------------------------------------------------------*/ /* Wireless Handler : get Nickname */ -static int ks_wlan_get_nick(struct net_device *dev, struct iw_request_info *info, - struct iw_point *dwrq, char *extra) +static int ks_wlan_get_nick(struct net_device *dev, + struct iw_request_info *info, struct iw_point *dwrq, + char *extra) { - struct ks_wlan_private *priv = (struct ks_wlan_private *)netdev_priv(dev); - - if (priv->sleep_mode == SLP_SLEEP){ return -EPERM; } /* for SLEEP MODE */ + struct ks_wlan_private *priv = + (struct ks_wlan_private *)netdev_priv(dev); + if (priv->sleep_mode == SLP_SLEEP) { + return -EPERM; + } + /* for SLEEP MODE */ strncpy(extra, priv->nick, 16); extra[16] = '\0'; dwrq->length = strlen(extra) + 1; @@ -455,144 +490,228 @@ static int ks_wlan_get_nick(struct net_device *dev, struct iw_request_info *info /*------------------------------------------------------------------*/ /* Wireless Handler : set Bit-Rate */ -static int ks_wlan_set_rate(struct net_device *dev, struct iw_request_info *info, - struct iw_param *vwrq, char *extra) +static int ks_wlan_set_rate(struct net_device *dev, + struct iw_request_info *info, struct iw_param *vwrq, + char *extra) { - struct ks_wlan_private *priv = (struct ks_wlan_private *)netdev_priv(dev); + struct ks_wlan_private *priv = + (struct ks_wlan_private *)netdev_priv(dev); int i = 0; - if (priv->sleep_mode == SLP_SLEEP){ return -EPERM; } /* for SLEEP MODE */ - - if(priv->reg.phy_type == D_11B_ONLY_MODE){ - if(vwrq->fixed == 1) { - switch(vwrq->value){ + if (priv->sleep_mode == SLP_SLEEP) { + return -EPERM; + } + /* for SLEEP MODE */ + if (priv->reg.phy_type == D_11B_ONLY_MODE) { + if (vwrq->fixed == 1) { + switch (vwrq->value) { case 11000000: - case 5500000: - priv->reg.rate_set.body[0] = (uint8_t)(vwrq->value/500000); + case 5500000: + priv->reg.rate_set.body[0] = + (uint8_t) (vwrq->value / 500000); break; - case 2000000: - case 1000000: - priv->reg.rate_set.body[0] = ((uint8_t)(vwrq->value/500000))|BASIC_RATE; + case 2000000: + case 1000000: + priv->reg.rate_set.body[0] = + ((uint8_t) (vwrq->value / 500000)) | + BASIC_RATE; break; default: return -EINVAL; } priv->reg.tx_rate = TX_RATE_FIXED; priv->reg.rate_set.size = 1; - }else{ /* vwrq->fixed == 0 */ - if(vwrq->value > 0){ - switch(vwrq->value){ + } else { /* vwrq->fixed == 0 */ + if (vwrq->value > 0) { + switch (vwrq->value) { case 11000000: - priv->reg.rate_set.body[3] = TX_RATE_11M; i++; - case 5500000: - priv->reg.rate_set.body[2] = TX_RATE_5M; i++; - case 2000000: - priv->reg.rate_set.body[1] = TX_RATE_2M|BASIC_RATE; i++; - case 1000000: - priv->reg.rate_set.body[0] = TX_RATE_1M|BASIC_RATE; i++; + priv->reg.rate_set.body[3] = + TX_RATE_11M; + i++; + case 5500000: + priv->reg.rate_set.body[2] = TX_RATE_5M; + i++; + case 2000000: + priv->reg.rate_set.body[1] = + TX_RATE_2M | BASIC_RATE; + i++; + case 1000000: + priv->reg.rate_set.body[0] = + TX_RATE_1M | BASIC_RATE; + i++; break; default: return -EINVAL; } priv->reg.tx_rate = TX_RATE_MANUAL_AUTO; priv->reg.rate_set.size = i; - }else{ + } else { priv->reg.rate_set.body[3] = TX_RATE_11M; priv->reg.rate_set.body[2] = TX_RATE_5M; - priv->reg.rate_set.body[1] = TX_RATE_2M|BASIC_RATE; - priv->reg.rate_set.body[0] = TX_RATE_1M|BASIC_RATE; + priv->reg.rate_set.body[1] = + TX_RATE_2M | BASIC_RATE; + priv->reg.rate_set.body[0] = + TX_RATE_1M | BASIC_RATE; priv->reg.tx_rate = TX_RATE_FULL_AUTO; priv->reg.rate_set.size = 4; } } - }else{ /* D_11B_ONLY_MODE or D_11BG_COMPATIBLE_MODE */ - if(vwrq->fixed == 1) { - switch(vwrq->value){ + } else { /* D_11B_ONLY_MODE or D_11BG_COMPATIBLE_MODE */ + if (vwrq->fixed == 1) { + switch (vwrq->value) { case 54000000: case 48000000: case 36000000: case 18000000: - case 9000000: - priv->reg.rate_set.body[0] = (uint8_t)(vwrq->value/500000); + case 9000000: + priv->reg.rate_set.body[0] = + (uint8_t) (vwrq->value / 500000); break; case 24000000: case 12000000: case 11000000: - case 6000000: - case 5500000: - case 2000000: - case 1000000: - priv->reg.rate_set.body[0] = ((uint8_t)(vwrq->value/500000))|BASIC_RATE; + case 6000000: + case 5500000: + case 2000000: + case 1000000: + priv->reg.rate_set.body[0] = + ((uint8_t) (vwrq->value / 500000)) | + BASIC_RATE; break; default: return -EINVAL; } priv->reg.tx_rate = TX_RATE_FIXED; priv->reg.rate_set.size = 1; - }else{ /* vwrq->fixed == 0 */ - if(vwrq->value > 0){ - switch(vwrq->value){ + } else { /* vwrq->fixed == 0 */ + if (vwrq->value > 0) { + switch (vwrq->value) { case 54000000: - priv->reg.rate_set.body[11] = TX_RATE_54M; i++; + priv->reg.rate_set.body[11] = + TX_RATE_54M; + i++; case 48000000: - priv->reg.rate_set.body[10] = TX_RATE_48M; i++; + priv->reg.rate_set.body[10] = + TX_RATE_48M; + i++; case 36000000: - priv->reg.rate_set.body[9] = TX_RATE_36M; i++; - case 24000000: case 18000000: case 12000000: - case 11000000: case 9000000: case 6000000: - if(vwrq->value == 24000000){ - priv->reg.rate_set.body[8] = TX_RATE_18M; i++; - priv->reg.rate_set.body[7] = TX_RATE_9M; i++; - priv->reg.rate_set.body[6] = TX_RATE_24M|BASIC_RATE; i++; - priv->reg.rate_set.body[5] = TX_RATE_12M|BASIC_RATE; i++; - priv->reg.rate_set.body[4] = TX_RATE_6M|BASIC_RATE; i++; - priv->reg.rate_set.body[3] = TX_RATE_11M|BASIC_RATE; i++; - }else if(vwrq->value == 18000000){ - priv->reg.rate_set.body[7] = TX_RATE_18M; i++; - priv->reg.rate_set.body[6] = TX_RATE_9M; i++; - priv->reg.rate_set.body[5] = TX_RATE_12M|BASIC_RATE; i++; - priv->reg.rate_set.body[4] = TX_RATE_6M|BASIC_RATE; i++; - priv->reg.rate_set.body[3] = TX_RATE_11M|BASIC_RATE; i++; - }else if(vwrq->value == 12000000){ - priv->reg.rate_set.body[6] = TX_RATE_9M; i++; - priv->reg.rate_set.body[5] = TX_RATE_12M|BASIC_RATE; i++; - priv->reg.rate_set.body[4] = TX_RATE_6M|BASIC_RATE; i++; - priv->reg.rate_set.body[3] = TX_RATE_11M|BASIC_RATE; i++; - }else if(vwrq->value == 11000000){ - priv->reg.rate_set.body[5] = TX_RATE_9M; i++; - priv->reg.rate_set.body[4] = TX_RATE_6M|BASIC_RATE; i++; - priv->reg.rate_set.body[3] = TX_RATE_11M|BASIC_RATE; i++; - }else if(vwrq->value == 9000000){ - priv->reg.rate_set.body[4] = TX_RATE_9M; i++; - priv->reg.rate_set.body[3] = TX_RATE_6M|BASIC_RATE; i++; - }else{ /* vwrq->value == 6000000 */ - priv->reg.rate_set.body[3] = TX_RATE_6M|BASIC_RATE; i++; + priv->reg.rate_set.body[9] = + TX_RATE_36M; + i++; + case 24000000: + case 18000000: + case 12000000: + case 11000000: + case 9000000: + case 6000000: + if (vwrq->value == 24000000) { + priv->reg.rate_set.body[8] = + TX_RATE_18M; + i++; + priv->reg.rate_set.body[7] = + TX_RATE_9M; + i++; + priv->reg.rate_set.body[6] = + TX_RATE_24M | BASIC_RATE; + i++; + priv->reg.rate_set.body[5] = + TX_RATE_12M | BASIC_RATE; + i++; + priv->reg.rate_set.body[4] = + TX_RATE_6M | BASIC_RATE; + i++; + priv->reg.rate_set.body[3] = + TX_RATE_11M | BASIC_RATE; + i++; + } else if (vwrq->value == 18000000) { + priv->reg.rate_set.body[7] = + TX_RATE_18M; + i++; + priv->reg.rate_set.body[6] = + TX_RATE_9M; + i++; + priv->reg.rate_set.body[5] = + TX_RATE_12M | BASIC_RATE; + i++; + priv->reg.rate_set.body[4] = + TX_RATE_6M | BASIC_RATE; + i++; + priv->reg.rate_set.body[3] = + TX_RATE_11M | BASIC_RATE; + i++; + } else if (vwrq->value == 12000000) { + priv->reg.rate_set.body[6] = + TX_RATE_9M; + i++; + priv->reg.rate_set.body[5] = + TX_RATE_12M | BASIC_RATE; + i++; + priv->reg.rate_set.body[4] = + TX_RATE_6M | BASIC_RATE; + i++; + priv->reg.rate_set.body[3] = + TX_RATE_11M | BASIC_RATE; + i++; + } else if (vwrq->value == 11000000) { + priv->reg.rate_set.body[5] = + TX_RATE_9M; + i++; + priv->reg.rate_set.body[4] = + TX_RATE_6M | BASIC_RATE; + i++; + priv->reg.rate_set.body[3] = + TX_RATE_11M | BASIC_RATE; + i++; + } else if (vwrq->value == 9000000) { + priv->reg.rate_set.body[4] = + TX_RATE_9M; + i++; + priv->reg.rate_set.body[3] = + TX_RATE_6M | BASIC_RATE; + i++; + } else { /* vwrq->value == 6000000 */ + priv->reg.rate_set.body[3] = + TX_RATE_6M | BASIC_RATE; + i++; } - case 5500000: - priv->reg.rate_set.body[2] = TX_RATE_5M|BASIC_RATE; i++; - case 2000000: - priv->reg.rate_set.body[1] = TX_RATE_2M|BASIC_RATE; i++; - case 1000000: - priv->reg.rate_set.body[0] = TX_RATE_1M|BASIC_RATE; i++; + case 5500000: + priv->reg.rate_set.body[2] = + TX_RATE_5M | BASIC_RATE; + i++; + case 2000000: + priv->reg.rate_set.body[1] = + TX_RATE_2M | BASIC_RATE; + i++; + case 1000000: + priv->reg.rate_set.body[0] = + TX_RATE_1M | BASIC_RATE; + i++; break; default: return -EINVAL; } priv->reg.tx_rate = TX_RATE_MANUAL_AUTO; priv->reg.rate_set.size = i; - }else{ + } else { priv->reg.rate_set.body[11] = TX_RATE_54M; priv->reg.rate_set.body[10] = TX_RATE_48M; priv->reg.rate_set.body[9] = TX_RATE_36M; priv->reg.rate_set.body[8] = TX_RATE_18M; priv->reg.rate_set.body[7] = TX_RATE_9M; - priv->reg.rate_set.body[6] = TX_RATE_24M|BASIC_RATE; - priv->reg.rate_set.body[5] = TX_RATE_12M|BASIC_RATE; - priv->reg.rate_set.body[4] = TX_RATE_6M|BASIC_RATE; - priv->reg.rate_set.body[3] = TX_RATE_11M|BASIC_RATE; - priv->reg.rate_set.body[2] = TX_RATE_5M|BASIC_RATE; - priv->reg.rate_set.body[1] = TX_RATE_2M|BASIC_RATE; - priv->reg.rate_set.body[0] = TX_RATE_1M|BASIC_RATE; + priv->reg.rate_set.body[6] = + TX_RATE_24M | BASIC_RATE; + priv->reg.rate_set.body[5] = + TX_RATE_12M | BASIC_RATE; + priv->reg.rate_set.body[4] = + TX_RATE_6M | BASIC_RATE; + priv->reg.rate_set.body[3] = + TX_RATE_11M | BASIC_RATE; + priv->reg.rate_set.body[2] = + TX_RATE_5M | BASIC_RATE; + priv->reg.rate_set.body[1] = + TX_RATE_2M | BASIC_RATE; + priv->reg.rate_set.body[0] = + TX_RATE_1M | BASIC_RATE; priv->reg.tx_rate = TX_RATE_FULL_AUTO; priv->reg.rate_set.size = 12; } @@ -606,21 +725,25 @@ static int ks_wlan_set_rate(struct net_device *dev, struct iw_request_info *info /*------------------------------------------------------------------*/ /* Wireless Handler : get Bit-Rate */ -static int ks_wlan_get_rate(struct net_device *dev, struct iw_request_info *info, - struct iw_param *vwrq, char *extra) +static int ks_wlan_get_rate(struct net_device *dev, + struct iw_request_info *info, struct iw_param *vwrq, + char *extra) { - struct ks_wlan_private *priv = (struct ks_wlan_private *)netdev_priv(dev); + struct ks_wlan_private *priv = + (struct ks_wlan_private *)netdev_priv(dev); DPRINTK(2, "in_interrupt = %ld update_phyinfo = %d\n", - in_interrupt(),atomic_read(&update_phyinfo)); - - if (priv->sleep_mode == SLP_SLEEP){ return -EPERM; } /* for SLEEP MODE */ + in_interrupt(), atomic_read(&update_phyinfo)); - if(!atomic_read(&update_phyinfo)){ + if (priv->sleep_mode == SLP_SLEEP) { + return -EPERM; + } + /* for SLEEP MODE */ + if (!atomic_read(&update_phyinfo)) { ks_wlan_update_phy_information(priv); } vwrq->value = ((priv->current_rate) & RATE_MASK) * 500000; - if(priv->reg.tx_rate == TX_RATE_FIXED) + if (priv->reg.tx_rate == TX_RATE_FIXED) vwrq->fixed = 1; else vwrq->fixed = 0; @@ -633,14 +756,17 @@ static int ks_wlan_get_rate(struct net_device *dev, struct iw_request_info *info static int ks_wlan_set_rts(struct net_device *dev, struct iw_request_info *info, struct iw_param *vwrq, char *extra) { - struct ks_wlan_private *priv = (struct ks_wlan_private *)netdev_priv(dev); + struct ks_wlan_private *priv = + (struct ks_wlan_private *)netdev_priv(dev); int rthr = vwrq->value; - if (priv->sleep_mode == SLP_SLEEP){ return -EPERM; } /* for SLEEP MODE */ - - if(vwrq->disabled) + if (priv->sleep_mode == SLP_SLEEP) { + return -EPERM; + } + /* for SLEEP MODE */ + if (vwrq->disabled) rthr = 2347; - if((rthr < 0) || (rthr > 2347)) { + if ((rthr < 0) || (rthr > 2347)) { return -EINVAL; } priv->reg.rts = rthr; @@ -654,10 +780,13 @@ static int ks_wlan_set_rts(struct net_device *dev, struct iw_request_info *info, static int ks_wlan_get_rts(struct net_device *dev, struct iw_request_info *info, struct iw_param *vwrq, char *extra) { - struct ks_wlan_private *priv = (struct ks_wlan_private *)netdev_priv(dev); - - if (priv->sleep_mode == SLP_SLEEP){ return -EPERM; } /* for SLEEP MODE */ + struct ks_wlan_private *priv = + (struct ks_wlan_private *)netdev_priv(dev); + if (priv->sleep_mode == SLP_SLEEP) { + return -EPERM; + } + /* for SLEEP MODE */ vwrq->value = priv->reg.rts; vwrq->disabled = (vwrq->value >= 2347); vwrq->fixed = 1; @@ -667,17 +796,21 @@ static int ks_wlan_get_rts(struct net_device *dev, struct iw_request_info *info, /*------------------------------------------------------------------*/ /* Wireless Handler : set Fragmentation threshold */ -static int ks_wlan_set_frag(struct net_device *dev, struct iw_request_info *info, - struct iw_param *vwrq, char *extra) +static int ks_wlan_set_frag(struct net_device *dev, + struct iw_request_info *info, struct iw_param *vwrq, + char *extra) { - struct ks_wlan_private *priv = (struct ks_wlan_private *)netdev_priv(dev); + struct ks_wlan_private *priv = + (struct ks_wlan_private *)netdev_priv(dev); int fthr = vwrq->value; - if (priv->sleep_mode == SLP_SLEEP){ return -EPERM; } /* for SLEEP MODE */ - - if(vwrq->disabled) + if (priv->sleep_mode == SLP_SLEEP) { + return -EPERM; + } + /* for SLEEP MODE */ + if (vwrq->disabled) fthr = 2346; - if((fthr < 256) || (fthr > 2346)) { + if ((fthr < 256) || (fthr > 2346)) { return -EINVAL; } fthr &= ~0x1; /* Get an even value - is it really needed ??? */ @@ -689,13 +822,17 @@ static int ks_wlan_set_frag(struct net_device *dev, struct iw_request_info *info /*------------------------------------------------------------------*/ /* Wireless Handler : get Fragmentation threshold */ -static int ks_wlan_get_frag(struct net_device *dev, struct iw_request_info *info, - struct iw_param *vwrq, char *extra) +static int ks_wlan_get_frag(struct net_device *dev, + struct iw_request_info *info, struct iw_param *vwrq, + char *extra) { - struct ks_wlan_private *priv = (struct ks_wlan_private *)netdev_priv(dev); - - if (priv->sleep_mode == SLP_SLEEP){ return -EPERM; } /* for SLEEP MODE */ + struct ks_wlan_private *priv = + (struct ks_wlan_private *)netdev_priv(dev); + if (priv->sleep_mode == SLP_SLEEP) { + return -EPERM; + } + /* for SLEEP MODE */ vwrq->value = priv->reg.fragment; vwrq->disabled = (vwrq->value >= 2346); vwrq->fixed = 1; @@ -705,16 +842,20 @@ static int ks_wlan_get_frag(struct net_device *dev, struct iw_request_info *info /*------------------------------------------------------------------*/ /* Wireless Handler : set Mode of Operation */ -static int ks_wlan_set_mode(struct net_device *dev, struct iw_request_info *info, - __u32 *uwrq, char *extra) +static int ks_wlan_set_mode(struct net_device *dev, + struct iw_request_info *info, __u32 * uwrq, + char *extra) { - struct ks_wlan_private *priv = (struct ks_wlan_private *)netdev_priv(dev); + struct ks_wlan_private *priv = + (struct ks_wlan_private *)netdev_priv(dev); - DPRINTK(2,"mode=%d\n",*uwrq); + DPRINTK(2, "mode=%d\n", *uwrq); - if (priv->sleep_mode == SLP_SLEEP){ return -EPERM; } /* for SLEEP MODE */ - - switch(*uwrq) { + if (priv->sleep_mode == SLP_SLEEP) { + return -EPERM; + } + /* for SLEEP MODE */ + switch (*uwrq) { case IW_MODE_ADHOC: priv->reg.operation_mode = MODE_ADHOC; priv->need_commit |= SME_MODE_SET; @@ -732,28 +873,33 @@ static int ks_wlan_set_mode(struct net_device *dev, struct iw_request_info *info return -EINVAL; } - return -EINPROGRESS; /* Call commit handler */ + return -EINPROGRESS; /* Call commit handler */ } /*------------------------------------------------------------------*/ /* Wireless Handler : get Mode of Operation */ -static int ks_wlan_get_mode(struct net_device *dev, struct iw_request_info *info, - __u32 *uwrq, char *extra) +static int ks_wlan_get_mode(struct net_device *dev, + struct iw_request_info *info, __u32 * uwrq, + char *extra) { - struct ks_wlan_private *priv = (struct ks_wlan_private *)netdev_priv(dev); + struct ks_wlan_private *priv = + (struct ks_wlan_private *)netdev_priv(dev); - if (priv->sleep_mode == SLP_SLEEP){ return -EPERM; } /* for SLEEP MODE */ + if (priv->sleep_mode == SLP_SLEEP) { + return -EPERM; + } + /* for SLEEP MODE */ /* If not managed, assume it's ad-hoc */ switch (priv->reg.operation_mode) { - case MODE_INFRASTRUCTURE: - *uwrq = IW_MODE_INFRA; - break; - case MODE_ADHOC: - *uwrq = IW_MODE_ADHOC; - break; - default: - *uwrq = IW_MODE_ADHOC; + case MODE_INFRASTRUCTURE: + *uwrq = IW_MODE_INFRA; + break; + case MODE_ADHOC: + *uwrq = IW_MODE_ADHOC; + break; + default: + *uwrq = IW_MODE_ADHOC; } return 0; @@ -761,24 +907,29 @@ static int ks_wlan_get_mode(struct net_device *dev, struct iw_request_info *info /*------------------------------------------------------------------*/ /* Wireless Handler : set Encryption Key */ -static int ks_wlan_set_encode(struct net_device *dev, struct iw_request_info *info, - struct iw_point *dwrq, char *extra) +static int ks_wlan_set_encode(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *dwrq, char *extra) { - struct ks_wlan_private *priv = (struct ks_wlan_private *)netdev_priv(dev); + struct ks_wlan_private *priv = + (struct ks_wlan_private *)netdev_priv(dev); wep_key_t key; int index = (dwrq->flags & IW_ENCODE_INDEX); int current_index = priv->reg.wep_index; int i; - DPRINTK(2,"flags=%04X\n",dwrq->flags); + DPRINTK(2, "flags=%04X\n", dwrq->flags); - if (priv->sleep_mode == SLP_SLEEP){ return -EPERM; } /* for SLEEP MODE */ + if (priv->sleep_mode == SLP_SLEEP) { + return -EPERM; + } + /* for SLEEP MODE */ /* index check */ - if((index<0) || (index>4)) + if ((index < 0) || (index > 4)) return -EINVAL; - else if (index==0) + else if (index == 0) index = current_index; else index--; @@ -786,10 +937,10 @@ static int ks_wlan_set_encode(struct net_device *dev, struct iw_request_info *in /* Is WEP supported ? */ /* Basic checking: do we have a key to set ? */ if (dwrq->length > 0) { - if (dwrq->length > MAX_KEY_SIZE) { /* Check the size of the key */ + if (dwrq->length > MAX_KEY_SIZE) { /* Check the size of the key */ return -EINVAL; } - if (dwrq->length > MIN_KEY_SIZE) { /* Set the length */ + if (dwrq->length > MIN_KEY_SIZE) { /* Set the length */ key.len = MAX_KEY_SIZE; priv->reg.privacy_invoked = 0x01; priv->need_commit |= SME_WEP_FLAG; @@ -800,94 +951,97 @@ static int ks_wlan_set_encode(struct net_device *dev, struct iw_request_info *in priv->reg.privacy_invoked = 0x01; priv->need_commit |= SME_WEP_FLAG; wep_on_off = WEP_ON_64BIT; - } else { /* Disable the key */ + } else { /* Disable the key */ key.len = 0; } } /* Check if the key is not marked as invalid */ - if(!(dwrq->flags & IW_ENCODE_NOKEY)) { + if (!(dwrq->flags & IW_ENCODE_NOKEY)) { /* Cleanup */ memset(key.key, 0, MAX_KEY_SIZE); /* Copy the key in the driver */ - if(copy_from_user(key.key,dwrq->pointer,dwrq->length)) { + if (copy_from_user + (key.key, dwrq->pointer, dwrq->length)) { key.len = 0; return -EFAULT; } /* Send the key to the card */ priv->reg.wep_key[index].size = key.len; - for (i=0; i<(priv->reg.wep_key[index].size); i++) { + for (i = 0; i < (priv->reg.wep_key[index].size); i++) { priv->reg.wep_key[index].val[i] = key.key[i]; } - priv->need_commit |= (SME_WEP_VAL1<need_commit |= (SME_WEP_VAL1 << index); priv->reg.wep_index = index; priv->need_commit |= SME_WEP_INDEX; } } else { - if(dwrq->flags & IW_ENCODE_DISABLED){ + if (dwrq->flags & IW_ENCODE_DISABLED) { priv->reg.wep_key[0].size = 0; priv->reg.wep_key[1].size = 0; priv->reg.wep_key[2].size = 0; priv->reg.wep_key[3].size = 0; priv->reg.privacy_invoked = 0x00; - if(priv->reg.authenticate_type == AUTH_TYPE_SHARED_KEY){ + if (priv->reg.authenticate_type == AUTH_TYPE_SHARED_KEY) { priv->need_commit |= SME_MODE_SET; } priv->reg.authenticate_type = AUTH_TYPE_OPEN_SYSTEM; wep_on_off = WEP_OFF; priv->need_commit |= SME_WEP_FLAG; - }else{ + } else { /* Do we want to just set the transmit key index ? */ - if ((index>=0) && (index<4)) { - /* set_wep_key(priv, index, 0, 0, 1); xxx */ - if(priv->reg.wep_key[index].size){ + if ((index >= 0) && (index < 4)) { + /* set_wep_key(priv, index, 0, 0, 1); xxx */ + if (priv->reg.wep_key[index].size) { priv->reg.wep_index = index; priv->need_commit |= SME_WEP_INDEX; - } - else + } else return -EINVAL; } } } /* Commit the changes if needed */ - if(dwrq->flags & IW_ENCODE_MODE) + if (dwrq->flags & IW_ENCODE_MODE) priv->need_commit |= SME_WEP_FLAG; - if(dwrq->flags & IW_ENCODE_OPEN) { - if(priv->reg.authenticate_type == AUTH_TYPE_SHARED_KEY){ + if (dwrq->flags & IW_ENCODE_OPEN) { + if (priv->reg.authenticate_type == AUTH_TYPE_SHARED_KEY) { priv->need_commit |= SME_MODE_SET; } priv->reg.authenticate_type = AUTH_TYPE_OPEN_SYSTEM; - } else if(dwrq->flags & IW_ENCODE_RESTRICTED) { - if(priv->reg.authenticate_type == AUTH_TYPE_OPEN_SYSTEM){ + } else if (dwrq->flags & IW_ENCODE_RESTRICTED) { + if (priv->reg.authenticate_type == AUTH_TYPE_OPEN_SYSTEM) { priv->need_commit |= SME_MODE_SET; } priv->reg.authenticate_type = AUTH_TYPE_SHARED_KEY; } - -// return -EINPROGRESS; /* Call commit handler */ - if(priv->need_commit){ +// return -EINPROGRESS; /* Call commit handler */ + if (priv->need_commit) { ks_wlan_setup_parameter(priv, priv->need_commit); - priv->need_commit=0; + priv->need_commit = 0; } return 0; } /*------------------------------------------------------------------*/ /* Wireless Handler : get Encryption Key */ -static int ks_wlan_get_encode(struct net_device *dev, struct iw_request_info *info, - struct iw_point *dwrq, char *extra) +static int ks_wlan_get_encode(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *dwrq, char *extra) { - struct ks_wlan_private *priv = (struct ks_wlan_private *)netdev_priv(dev); + struct ks_wlan_private *priv = + (struct ks_wlan_private *)netdev_priv(dev); char zeros[16]; int index = (dwrq->flags & IW_ENCODE_INDEX) - 1; - if (priv->sleep_mode == SLP_SLEEP){ return -EPERM; } /* for SLEEP MODE */ - + if (priv->sleep_mode == SLP_SLEEP) { + return -EPERM; + } + /* for SLEEP MODE */ dwrq->flags = IW_ENCODE_DISABLED; /* Check encryption mode */ - switch(priv->reg.authenticate_type) { + switch (priv->reg.authenticate_type) { case AUTH_TYPE_OPEN_SYSTEM: dwrq->flags = IW_ENCODE_OPEN; break; @@ -896,29 +1050,30 @@ static int ks_wlan_get_encode(struct net_device *dev, struct iw_request_info *in break; } - memset(zeros,0, sizeof(zeros)); + memset(zeros, 0, sizeof(zeros)); /* Which key do we want ? -1 -> tx index */ - if((index < 0) || (index >= 4)) + if ((index < 0) || (index >= 4)) index = priv->reg.wep_index; - if (priv->reg.privacy_invoked){ + if (priv->reg.privacy_invoked) { dwrq->flags &= ~IW_ENCODE_DISABLED; /* dwrq->flags |= IW_ENCODE_NOKEY; */ } dwrq->flags |= index + 1; - DPRINTK(2,"encoding flag = 0x%04X\n",dwrq->flags); + DPRINTK(2, "encoding flag = 0x%04X\n", dwrq->flags); /* Copy the key to the user buffer */ - if((index >= 0) && (index < 4)) + if ((index >= 0) && (index < 4)) dwrq->length = priv->reg.wep_key[index].size; if (dwrq->length > 16) { - dwrq->length=0; + dwrq->length = 0; } -#if 1 /* IW_ENCODE_NOKEY; */ +#if 1 /* IW_ENCODE_NOKEY; */ if (dwrq->length) { - if((index >= 0) && (index < 4)) - memcpy(extra,priv->reg.wep_key[index].val,dwrq->length); + if ((index >= 0) && (index < 4)) + memcpy(extra, priv->reg.wep_key[index].val, + dwrq->length); } else - memcpy(extra,zeros,dwrq->length); + memcpy(extra, zeros, dwrq->length); #endif return 0; } @@ -926,19 +1081,24 @@ static int ks_wlan_get_encode(struct net_device *dev, struct iw_request_info *in #ifndef KSC_OPNOTSUPP /*------------------------------------------------------------------*/ /* Wireless Handler : set Tx-Power */ -static int ks_wlan_set_txpow(struct net_device *dev, struct iw_request_info *info, - struct iw_param *vwrq, char *extra) +static int ks_wlan_set_txpow(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *vwrq, char *extra) { - return -EOPNOTSUPP; /* Not Support */ + return -EOPNOTSUPP; /* Not Support */ } /*------------------------------------------------------------------*/ /* Wireless Handler : get Tx-Power */ -static int ks_wlan_get_txpow(struct net_device *dev, struct iw_request_info *info, - struct iw_param *vwrq, char *extra) +static int ks_wlan_get_txpow(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *vwrq, char *extra) { - if (priv->sleep_mode == SLP_SLEEP){ return -EPERM; } /* for SLEEP MODE */ + if (priv->sleep_mode == SLP_SLEEP) { + return -EPERM; + } + /* for SLEEP MODE */ /* Not Support */ vwrq->value = 0; vwrq->disabled = (vwrq->value == 0); @@ -948,19 +1108,24 @@ static int ks_wlan_get_txpow(struct net_device *dev, struct iw_request_info *inf /*------------------------------------------------------------------*/ /* Wireless Handler : set Retry limits */ -static int ks_wlan_set_retry(struct net_device *dev, struct iw_request_info *info, - struct iw_param *vwrq, char *extra) +static int ks_wlan_set_retry(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *vwrq, char *extra) { - return -EOPNOTSUPP; /* Not Support */ + return -EOPNOTSUPP; /* Not Support */ } /*------------------------------------------------------------------*/ /* Wireless Handler : get Retry limits */ -static int ks_wlan_get_retry(struct net_device *dev, struct iw_request_info *info, - struct iw_param *vwrq, char *extra) +static int ks_wlan_get_retry(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *vwrq, char *extra) { - if (priv->sleep_mode == SLP_SLEEP){ return -EPERM; } /* for SLEEP MODE */ + if (priv->sleep_mode == SLP_SLEEP) { + return -EPERM; + } + /* for SLEEP MODE */ /* Not Support */ vwrq->value = 0; vwrq->disabled = (vwrq->value == 0); @@ -971,17 +1136,21 @@ static int ks_wlan_get_retry(struct net_device *dev, struct iw_request_info *inf /*------------------------------------------------------------------*/ /* Wireless Handler : get range info */ -static int ks_wlan_get_range(struct net_device *dev, struct iw_request_info *info, - struct iw_point *dwrq, char *extra) +static int ks_wlan_get_range(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *dwrq, char *extra) { - struct ks_wlan_private *priv = (struct ks_wlan_private *)netdev_priv(dev); - struct iw_range *range = (struct iw_range *) extra; - int i,k; - - DPRINTK(2,"\n"); + struct ks_wlan_private *priv = + (struct ks_wlan_private *)netdev_priv(dev); + struct iw_range *range = (struct iw_range *)extra; + int i, k; - if (priv->sleep_mode == SLP_SLEEP){ return -EPERM; } /* for SLEEP MODE */ + DPRINTK(2, "\n"); + if (priv->sleep_mode == SLP_SLEEP) { + return -EPERM; + } + /* for SLEEP MODE */ dwrq->length = sizeof(struct iw_range); memset(range, 0, sizeof(*range)); range->min_nwid = 0x0000; @@ -990,15 +1159,14 @@ static int ks_wlan_get_range(struct net_device *dev, struct iw_request_info *inf /* Should be based on cap_rid.country to give only * what the current card support */ k = 0; - for(i = 0; i < 13; i++) { /* channel 1 -- 13*/ - range->freq[k].i = i + 1; /* List index */ + for (i = 0; i < 13; i++) { /* channel 1 -- 13 */ + range->freq[k].i = i + 1; /* List index */ range->freq[k].m = frequency_list[i] * 100000; range->freq[k++].e = 1; /* Values in table in MHz -> * 10^5 * 10 */ } range->num_frequency = k; - if(priv->reg.phy_type == D_11B_ONLY_MODE || - priv->reg.phy_type == D_11BG_COMPATIBLE_MODE){ /* channel 14 */ - range->freq[13].i = 14; /* List index */ + if (priv->reg.phy_type == D_11B_ONLY_MODE || priv->reg.phy_type == D_11BG_COMPATIBLE_MODE) { /* channel 14 */ + range->freq[13].i = 14; /* List index */ range->freq[13].m = frequency_list[13] * 100000; range->freq[13].e = 1; /* Values in table in MHz -> * 10^5 * 10 */ range->num_frequency = 14; @@ -1008,16 +1176,15 @@ static int ks_wlan_get_range(struct net_device *dev, struct iw_request_info *inf range->max_qual.qual = 100; range->max_qual.level = 256 - 128; /* 0 dBm? */ range->max_qual.noise = 256 - 128; - range->sensitivity = 1; + range->sensitivity = 1; - if(priv->reg.phy_type == D_11B_ONLY_MODE){ + if (priv->reg.phy_type == D_11B_ONLY_MODE) { range->bitrate[0] = 1e6; range->bitrate[1] = 2e6; range->bitrate[2] = 5.5e6; range->bitrate[3] = 11e6; range->num_bitrates = 4; - } - else{ /* D_11G_ONLY_MODE or D_11BG_COMPATIBLE_MODE */ + } else { /* D_11G_ONLY_MODE or D_11BG_COMPATIBLE_MODE */ range->bitrate[0] = 1e6; range->bitrate[1] = 2e6; range->bitrate[2] = 5.5e6; @@ -1026,10 +1193,10 @@ static int ks_wlan_get_range(struct net_device *dev, struct iw_request_info *inf range->bitrate[4] = 6e6; range->bitrate[5] = 9e6; range->bitrate[6] = 12e6; - if(IW_MAX_BITRATES < 9){ + if (IW_MAX_BITRATES < 9) { range->bitrate[7] = 54e6; range->num_bitrates = 8; - }else{ + } else { range->bitrate[7] = 18e6; range->bitrate[8] = 24e6; range->bitrate[9] = 36e6; @@ -1043,7 +1210,7 @@ static int ks_wlan_get_range(struct net_device *dev, struct iw_request_info *inf /* Set an indication of the max TCP throughput * in bit/s that we can expect using this interface. * May be use for QoS stuff... Jean II */ - if(i > 2) + if (i > 2) range->throughput = 5000 * 1000; else range->throughput = 1500 * 1000; @@ -1053,9 +1220,9 @@ static int ks_wlan_get_range(struct net_device *dev, struct iw_request_info *inf range->min_frag = 256; range->max_frag = 2346; - range->encoding_size[0] = 5; /* WEP: RC4 40 bits */ - range->encoding_size[1] = 13; /* WEP: RC4 ~128 bits */ - range->num_encoding_sizes = 2; + range->encoding_size[0] = 5; /* WEP: RC4 40 bits */ + range->encoding_size[1] = 13; /* WEP: RC4 ~128 bits */ + range->num_encoding_sizes = 2; range->max_encoding_tokens = 4; /* power management not support */ @@ -1064,7 +1231,7 @@ static int ks_wlan_get_range(struct net_device *dev, struct iw_request_info *inf range->pm_capa = 0; /* Transmit Power - values are in dBm( or mW) */ - range->txpower[0]=-256; + range->txpower[0] = -256; range->num_txpower = 1; range->txpower_capa = IW_TXPOW_DBM; /* range->txpower_capa = IW_TXPOW_MWATT; */ @@ -1073,8 +1240,8 @@ static int ks_wlan_get_range(struct net_device *dev, struct iw_request_info *inf range->we_version_compiled = WIRELESS_EXT; range->retry_capa = IW_RETRY_ON; - range->retry_flags = IW_RETRY_ON; - range->r_time_flags = IW_RETRY_ON; + range->retry_flags = IW_RETRY_ON; + range->r_time_flags = IW_RETRY_ON; /* Experimental measurements - boundary 11/5.5 Mb/s */ /* Note : with or without the (local->rssi), results @@ -1092,39 +1259,41 @@ static int ks_wlan_get_range(struct net_device *dev, struct iw_request_info *inf IW_EVENT_CAPA_MASK(IWEVMICHAELMICFAILURE)); /* encode extension (WPA) capability */ - range->enc_capa = (IW_ENC_CAPA_WPA | + range->enc_capa = (IW_ENC_CAPA_WPA | IW_ENC_CAPA_WPA2 | - IW_ENC_CAPA_CIPHER_TKIP | - IW_ENC_CAPA_CIPHER_CCMP); + IW_ENC_CAPA_CIPHER_TKIP | IW_ENC_CAPA_CIPHER_CCMP); return 0; } - /*------------------------------------------------------------------*/ /* Wireless Handler : set Power Management */ -static int ks_wlan_set_power(struct net_device *dev, struct iw_request_info *info, - struct iw_param *vwrq, char *extra) +static int ks_wlan_set_power(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *vwrq, char *extra) { - struct ks_wlan_private *priv = (struct ks_wlan_private *)netdev_priv(dev); + struct ks_wlan_private *priv = + (struct ks_wlan_private *)netdev_priv(dev); short enabled; - if (priv->sleep_mode == SLP_SLEEP){ return -EPERM; } /* for SLEEP MODE */ - + if (priv->sleep_mode == SLP_SLEEP) { + return -EPERM; + } + /* for SLEEP MODE */ enabled = vwrq->disabled ? 0 : 1; - if(enabled == 0 ){ /* 0 */ + if (enabled == 0) { /* 0 */ priv->reg.powermgt = POWMGT_ACTIVE_MODE; - }else if(enabled){ /* 1 */ - if(priv->reg.operation_mode == MODE_INFRASTRUCTURE) - priv->reg.powermgt = POWMGT_SAVE1_MODE; - else - return -EINVAL; - }else if(enabled){ /* 2 */ - if(priv->reg.operation_mode == MODE_INFRASTRUCTURE) + } else if (enabled) { /* 1 */ + if (priv->reg.operation_mode == MODE_INFRASTRUCTURE) + priv->reg.powermgt = POWMGT_SAVE1_MODE; + else + return -EINVAL; + } else if (enabled) { /* 2 */ + if (priv->reg.operation_mode == MODE_INFRASTRUCTURE) priv->reg.powermgt = POWMGT_SAVE2_MODE; else return -EINVAL; - }else - return -EINVAL; + } else + return -EINVAL; hostif_sme_enqueue(priv, SME_POW_MNGMT_REQUEST); @@ -1133,33 +1302,41 @@ static int ks_wlan_set_power(struct net_device *dev, struct iw_request_info *inf /*------------------------------------------------------------------*/ /* Wireless Handler : get Power Management */ -static int ks_wlan_get_power(struct net_device *dev, struct iw_request_info *info, - struct iw_param *vwrq, char *extra) +static int ks_wlan_get_power(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *vwrq, char *extra) { - struct ks_wlan_private *priv = (struct ks_wlan_private *)netdev_priv(dev); - - if (priv->sleep_mode == SLP_SLEEP){ return -EPERM; } /* for SLEEP MODE */ + struct ks_wlan_private *priv = + (struct ks_wlan_private *)netdev_priv(dev); - if(priv->reg.powermgt > 0) - vwrq->disabled = 0; + if (priv->sleep_mode == SLP_SLEEP) { + return -EPERM; + } + /* for SLEEP MODE */ + if (priv->reg.powermgt > 0) + vwrq->disabled = 0; else - vwrq->disabled = 1; + vwrq->disabled = 1; return 0; } /*------------------------------------------------------------------*/ /* Wireless Handler : get wirless statistics */ -static int ks_wlan_get_iwstats(struct net_device *dev, struct iw_request_info *info, - struct iw_quality *vwrq, char *extra) +static int ks_wlan_get_iwstats(struct net_device *dev, + struct iw_request_info *info, + struct iw_quality *vwrq, char *extra) { - struct ks_wlan_private *priv = (struct ks_wlan_private *)netdev_priv(dev); - - if (priv->sleep_mode == SLP_SLEEP){ return -EPERM; } /* for SLEEP MODE */ + struct ks_wlan_private *priv = + (struct ks_wlan_private *)netdev_priv(dev); - vwrq->qual = 0; /* not supported */ - vwrq->level = priv->wstats.qual.level; - vwrq->noise = 0; /* not supported */ + if (priv->sleep_mode == SLP_SLEEP) { + return -EPERM; + } + /* for SLEEP MODE */ + vwrq->qual = 0; /* not supported */ + vwrq->level = priv->wstats.qual.level; + vwrq->noise = 0; /* not supported */ vwrq->updated = 0; return 0; @@ -1168,16 +1345,18 @@ static int ks_wlan_get_iwstats(struct net_device *dev, struct iw_request_info *i #ifndef KSC_OPNOTSUPP /*------------------------------------------------------------------*/ /* Wireless Handler : set Sensitivity */ -static int ks_wlan_set_sens(struct net_device *dev, struct iw_request_info *info, - struct iw_param *vwrq, char *extra) +static int ks_wlan_set_sens(struct net_device *dev, + struct iw_request_info *info, struct iw_param *vwrq, + char *extra) { - return -EOPNOTSUPP; /* Not Support */ + return -EOPNOTSUPP; /* Not Support */ } /*------------------------------------------------------------------*/ /* Wireless Handler : get Sensitivity */ -static int ks_wlan_get_sens(struct net_device *dev, struct iw_request_info *info, - struct iw_param *vwrq, char *extra) +static int ks_wlan_get_sens(struct net_device *dev, + struct iw_request_info *info, struct iw_param *vwrq, + char *extra) { /* Not Support */ vwrq->value = 0; @@ -1187,33 +1366,37 @@ static int ks_wlan_get_sens(struct net_device *dev, struct iw_request_info *info } #endif /* KSC_OPNOTSUPP */ - /*------------------------------------------------------------------*/ /* Wireless Handler : get AP List */ /* Note : this is deprecated in favor of IWSCAN */ -static int ks_wlan_get_aplist(struct net_device *dev, struct iw_request_info *info, - struct iw_point *dwrq, char *extra) +static int ks_wlan_get_aplist(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *dwrq, char *extra) { - struct ks_wlan_private *priv = (struct ks_wlan_private *)netdev_priv(dev); - struct sockaddr *address = (struct sockaddr *) extra; + struct ks_wlan_private *priv = + (struct ks_wlan_private *)netdev_priv(dev); + struct sockaddr *address = (struct sockaddr *)extra; struct iw_quality qual[LOCAL_APLIST_MAX]; int i; - if (priv->sleep_mode == SLP_SLEEP){ return -EPERM; } /* for SLEEP MODE */ - + if (priv->sleep_mode == SLP_SLEEP) { + return -EPERM; + } + /* for SLEEP MODE */ for (i = 0; i < priv->aplist.size; i++) { - memcpy(address[i].sa_data, &(priv->aplist.ap[i].bssid[0]), ETH_ALEN); + memcpy(address[i].sa_data, &(priv->aplist.ap[i].bssid[0]), + ETH_ALEN); address[i].sa_family = ARPHRD_ETHER; qual[i].level = 256 - priv->aplist.ap[i].rssi; qual[i].qual = priv->aplist.ap[i].sq; - qual[i].noise = 0; /* invalid noise value */ + qual[i].noise = 0; /* invalid noise value */ qual[i].updated = 7; } - if (i){ - dwrq->flags = 1; /* Should be define'd */ - memcpy(extra + sizeof(struct sockaddr)*i, - &qual, sizeof(struct iw_quality)*i); + if (i) { + dwrq->flags = 1; /* Should be define'd */ + memcpy(extra + sizeof(struct sockaddr) * i, + &qual, sizeof(struct iw_quality) * i); } dwrq->length = i; @@ -1222,25 +1405,30 @@ static int ks_wlan_get_aplist(struct net_device *dev, struct iw_request_info *in /*------------------------------------------------------------------*/ /* Wireless Handler : Initiate Scan */ -static int ks_wlan_set_scan(struct net_device *dev, struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) +static int ks_wlan_set_scan(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) { - struct ks_wlan_private *priv = (struct ks_wlan_private *)netdev_priv(dev); + struct ks_wlan_private *priv = + (struct ks_wlan_private *)netdev_priv(dev); struct iw_scan_req *req = NULL; - DPRINTK(2,"\n"); + DPRINTK(2, "\n"); - if (priv->sleep_mode == SLP_SLEEP){ return -EPERM; } /* for SLEEP MODE */ + if (priv->sleep_mode == SLP_SLEEP) { + return -EPERM; + } + /* for SLEEP MODE */ /* specified SSID SCAN */ - if(wrqu->data.length == sizeof(struct iw_scan_req) && wrqu->data.flags & IW_SCAN_THIS_ESSID){ - req = (struct iw_scan_req *) extra; + if (wrqu->data.length == sizeof(struct iw_scan_req) + && wrqu->data.flags & IW_SCAN_THIS_ESSID) { + req = (struct iw_scan_req *)extra; priv->scan_ssid_len = req->essid_len; memcpy(priv->scan_ssid, req->essid, priv->scan_ssid_len); - }else{ + } else { priv->scan_ssid_len = 0; } - priv->sme_i.sme_flag |= SME_AP_SCAN; hostif_sme_enqueue(priv, SME_BSS_SCAN_REQUEST); @@ -1254,68 +1442,82 @@ static int ks_wlan_set_scan(struct net_device *dev, struct iw_request_info *info * Translate scan data returned from the card to a card independent * format that the Wireless Tools will understand - Jean II */ -static inline char *ks_wlan_translate_scan(struct net_device *dev, struct iw_request_info *info, char *current_ev, - char *end_buf, struct local_ap_t *ap) +static inline char *ks_wlan_translate_scan(struct net_device *dev, + struct iw_request_info *info, + char *current_ev, char *end_buf, + struct local_ap_t *ap) { /* struct ks_wlan_private *priv = (struct ks_wlan_private *)dev->priv; */ - struct iw_event iwe; /* Temporary buffer */ + struct iw_event iwe; /* Temporary buffer */ u16 capabilities; char *current_val; /* For rates */ int i; static const char rsn_leader[] = "rsn_ie="; static const char wpa_leader[] = "wpa_ie="; - char buf0[RSN_IE_BODY_MAX*2 + 30]; - char buf1[RSN_IE_BODY_MAX*2 + 30]; + char buf0[RSN_IE_BODY_MAX * 2 + 30]; + char buf1[RSN_IE_BODY_MAX * 2 + 30]; char *pbuf; /* First entry *MUST* be the AP MAC address */ iwe.cmd = SIOCGIWAP; iwe.u.ap_addr.sa_family = ARPHRD_ETHER; memcpy(iwe.u.ap_addr.sa_data, ap->bssid, ETH_ALEN); - current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe, IW_EV_ADDR_LEN); + current_ev = + iwe_stream_add_event(info, current_ev, end_buf, &iwe, + IW_EV_ADDR_LEN); /* Other entries will be displayed in the order we give them */ /* Add the ESSID */ iwe.u.data.length = ap->ssid.size; - if(iwe.u.data.length > 32) + if (iwe.u.data.length > 32) iwe.u.data.length = 32; iwe.cmd = SIOCGIWESSID; iwe.u.data.flags = 1; - current_ev = iwe_stream_add_point(info, current_ev, end_buf, &iwe, &(ap->ssid.body[0])); + current_ev = + iwe_stream_add_point(info, current_ev, end_buf, &iwe, + &(ap->ssid.body[0])); /* Add mode */ iwe.cmd = SIOCGIWMODE; capabilities = le16_to_cpu(ap->capability); - if(capabilities & (BSS_CAP_ESS | BSS_CAP_IBSS)) { - if(capabilities & BSS_CAP_ESS) + if (capabilities & (BSS_CAP_ESS | BSS_CAP_IBSS)) { + if (capabilities & BSS_CAP_ESS) iwe.u.mode = IW_MODE_INFRA; else iwe.u.mode = IW_MODE_ADHOC; - current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe, IW_EV_UINT_LEN); + current_ev = + iwe_stream_add_event(info, current_ev, end_buf, &iwe, + IW_EV_UINT_LEN); } /* Add frequency */ iwe.cmd = SIOCGIWFREQ; iwe.u.freq.m = ap->channel; - iwe.u.freq.m = frequency_list[iwe.u.freq.m-1] * 100000; + iwe.u.freq.m = frequency_list[iwe.u.freq.m - 1] * 100000; iwe.u.freq.e = 1; - current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe, IW_EV_FREQ_LEN); + current_ev = + iwe_stream_add_event(info, current_ev, end_buf, &iwe, + IW_EV_FREQ_LEN); /* Add quality statistics */ iwe.cmd = IWEVQUAL; iwe.u.qual.level = 256 - ap->rssi; iwe.u.qual.qual = ap->sq; - iwe.u.qual.noise = 0; /* invalid noise value */ - current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe, IW_EV_QUAL_LEN); + iwe.u.qual.noise = 0; /* invalid noise value */ + current_ev = + iwe_stream_add_event(info, current_ev, end_buf, &iwe, + IW_EV_QUAL_LEN); /* Add encryption capability */ iwe.cmd = SIOCGIWENCODE; - if(capabilities & BSS_CAP_PRIVACY) + if (capabilities & BSS_CAP_PRIVACY) iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY; else iwe.u.data.flags = IW_ENCODE_DISABLED; iwe.u.data.length = 0; - current_ev = iwe_stream_add_point(info, current_ev, end_buf, &iwe, &(ap->ssid.body[0])); + current_ev = + iwe_stream_add_point(info, current_ev, end_buf, &iwe, + &(ap->ssid.body[0])); /* Rate : stuffing multiple values in a single event require a bit * more of magic - Jean II */ @@ -1326,62 +1528,68 @@ static inline char *ks_wlan_translate_scan(struct net_device *dev, struct iw_req iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0; /* Max 16 values */ - for(i = 0 ; i < 16 ; i++) { + for (i = 0; i < 16; i++) { /* NULL terminated */ - if(i >= ap->rate_set.size) + if (i >= ap->rate_set.size) break; /* Bit rate given in 500 kb/s units (+ 0x80) */ iwe.u.bitrate.value = ((ap->rate_set.body[i] & 0x7f) * 500000); /* Add new value to event */ - current_val = iwe_stream_add_value(info, current_ev, current_val, end_buf, &iwe, IW_EV_PARAM_LEN); + current_val = + iwe_stream_add_value(info, current_ev, current_val, end_buf, + &iwe, IW_EV_PARAM_LEN); } /* Check if we added any event */ - if((current_val - current_ev) > IW_EV_LCP_LEN) + if ((current_val - current_ev) > IW_EV_LCP_LEN) current_ev = current_val; #define GENERIC_INFO_ELEM_ID 0xdd #define RSN_INFO_ELEM_ID 0x30 - if (ap->rsn_ie.id == RSN_INFO_ELEM_ID && ap->rsn_ie.size != 0) { - pbuf = &buf0[0]; - memset(&iwe, 0, sizeof(iwe)); - iwe.cmd = IWEVCUSTOM; - memcpy(buf0,rsn_leader,sizeof(rsn_leader)-1); - iwe.u.data.length += sizeof(rsn_leader)-1; - pbuf += sizeof(rsn_leader)-1; + if (ap->rsn_ie.id == RSN_INFO_ELEM_ID && ap->rsn_ie.size != 0) { + pbuf = &buf0[0]; + memset(&iwe, 0, sizeof(iwe)); + iwe.cmd = IWEVCUSTOM; + memcpy(buf0, rsn_leader, sizeof(rsn_leader) - 1); + iwe.u.data.length += sizeof(rsn_leader) - 1; + pbuf += sizeof(rsn_leader) - 1; - pbuf += sprintf(pbuf, "%02x", ap->rsn_ie.id); - pbuf += sprintf(pbuf, "%02x", ap->rsn_ie.size); - iwe.u.data.length += 4; + pbuf += sprintf(pbuf, "%02x", ap->rsn_ie.id); + pbuf += sprintf(pbuf, "%02x", ap->rsn_ie.size); + iwe.u.data.length += 4; - for (i = 0; i < ap->rsn_ie.size; i++) - pbuf += sprintf(pbuf, "%02x", ap->rsn_ie.body[i]); - iwe.u.data.length += (ap->rsn_ie.size)*2; + for (i = 0; i < ap->rsn_ie.size; i++) + pbuf += sprintf(pbuf, "%02x", ap->rsn_ie.body[i]); + iwe.u.data.length += (ap->rsn_ie.size) * 2; - DPRINTK(4,"ap->rsn.size=%d\n",ap->rsn_ie.size); + DPRINTK(4, "ap->rsn.size=%d\n", ap->rsn_ie.size); - current_ev = iwe_stream_add_point(info, current_ev, end_buf,&iwe, &buf0[0]); - } - if (ap->wpa_ie.id == GENERIC_INFO_ELEM_ID && ap->wpa_ie.size != 0) { - pbuf = &buf1[0]; - memset(&iwe, 0, sizeof(iwe)); - iwe.cmd = IWEVCUSTOM; - memcpy(buf1,wpa_leader,sizeof(wpa_leader)-1); - iwe.u.data.length += sizeof(wpa_leader)-1; - pbuf += sizeof(wpa_leader)-1; - - pbuf += sprintf(pbuf, "%02x", ap->wpa_ie.id); - pbuf += sprintf(pbuf, "%02x", ap->wpa_ie.size); - iwe.u.data.length += 4; - - for (i = 0; i < ap->wpa_ie.size; i++) - pbuf += sprintf(pbuf, "%02x", ap->wpa_ie.body[i]); - iwe.u.data.length += (ap->wpa_ie.size)*2; - - DPRINTK(4,"ap->rsn.size=%d\n",ap->wpa_ie.size); - DPRINTK(4,"iwe.u.data.length=%d\n",iwe.u.data.length); - - current_ev = iwe_stream_add_point(info, current_ev, end_buf,&iwe, &buf1[0]); - } + current_ev = + iwe_stream_add_point(info, current_ev, end_buf, &iwe, + &buf0[0]); + } + if (ap->wpa_ie.id == GENERIC_INFO_ELEM_ID && ap->wpa_ie.size != 0) { + pbuf = &buf1[0]; + memset(&iwe, 0, sizeof(iwe)); + iwe.cmd = IWEVCUSTOM; + memcpy(buf1, wpa_leader, sizeof(wpa_leader) - 1); + iwe.u.data.length += sizeof(wpa_leader) - 1; + pbuf += sizeof(wpa_leader) - 1; + + pbuf += sprintf(pbuf, "%02x", ap->wpa_ie.id); + pbuf += sprintf(pbuf, "%02x", ap->wpa_ie.size); + iwe.u.data.length += 4; + + for (i = 0; i < ap->wpa_ie.size; i++) + pbuf += sprintf(pbuf, "%02x", ap->wpa_ie.body[i]); + iwe.u.data.length += (ap->wpa_ie.size) * 2; + + DPRINTK(4, "ap->rsn.size=%d\n", ap->wpa_ie.size); + DPRINTK(4, "iwe.u.data.length=%d\n", iwe.u.data.length); + + current_ev = + iwe_stream_add_point(info, current_ev, end_buf, &iwe, + &buf1[0]); + } /* The other data in the scan result are not really * interesting, so for now drop it - Jean II */ @@ -1390,49 +1598,53 @@ static inline char *ks_wlan_translate_scan(struct net_device *dev, struct iw_req /*------------------------------------------------------------------*/ /* Wireless Handler : Read Scan Results */ -static int ks_wlan_get_scan(struct net_device *dev, struct iw_request_info *info, - struct iw_point *dwrq, char *extra) +static int ks_wlan_get_scan(struct net_device *dev, + struct iw_request_info *info, struct iw_point *dwrq, + char *extra) { - struct ks_wlan_private *priv = (struct ks_wlan_private *)netdev_priv(dev); + struct ks_wlan_private *priv = + (struct ks_wlan_private *)netdev_priv(dev); int i; char *current_ev = extra; - DPRINTK(2,"\n"); - - if (priv->sleep_mode == SLP_SLEEP){ return -EPERM; } /* for SLEEP MODE */ + DPRINTK(2, "\n"); - if(priv->sme_i.sme_flag & SME_AP_SCAN) { -DPRINTK(2,"flag AP_SCAN\n"); + if (priv->sleep_mode == SLP_SLEEP) { + return -EPERM; + } + /* for SLEEP MODE */ + if (priv->sme_i.sme_flag & SME_AP_SCAN) { + DPRINTK(2, "flag AP_SCAN\n"); return -EAGAIN; } - if(priv->aplist.size == 0) { + if (priv->aplist.size == 0) { /* Client error, no scan results... * The caller need to restart the scan. */ -DPRINTK(2,"aplist 0\n"); + DPRINTK(2, "aplist 0\n"); return -ENODATA; } #if 0 /* current connect ap */ - if((priv->connect_status & CONNECT_STATUS_MASK)== CONNECT_STATUS){ + if ((priv->connect_status & CONNECT_STATUS_MASK) == CONNECT_STATUS) { if ((extra + dwrq->length) - current_ev <= IW_EV_ADDR_LEN) { dwrq->length = 0; return -E2BIG; } current_ev = ks_wlan_translate_scan(dev, current_ev, -// extra + IW_SCAN_MAX_DATA, +// extra + IW_SCAN_MAX_DATA, extra + dwrq->length, &(priv->current_ap)); } #endif /* Read and parse all entries */ - for(i=0; i < priv->aplist.size; i++) { + for (i = 0; i < priv->aplist.size; i++) { if ((extra + dwrq->length) - current_ev <= IW_EV_ADDR_LEN) { dwrq->length = 0; return -E2BIG; } /* Translate to WE format this entry */ current_ev = ks_wlan_translate_scan(dev, info, current_ev, -// extra + IW_SCAN_MAX_DATA, +// extra + IW_SCAN_MAX_DATA, extra + dwrq->length, &(priv->aplist.ap[i])); } @@ -1445,53 +1657,63 @@ DPRINTK(2,"aplist 0\n"); /*------------------------------------------------------------------*/ /* Commit handler : called after a bunch of SET operations */ -static int ks_wlan_config_commit(struct net_device *dev, struct iw_request_info *info, - void *zwrq, char *extra) +static int ks_wlan_config_commit(struct net_device *dev, + struct iw_request_info *info, void *zwrq, + char *extra) { - struct ks_wlan_private *priv = (struct ks_wlan_private *)netdev_priv(dev); + struct ks_wlan_private *priv = + (struct ks_wlan_private *)netdev_priv(dev); if (!priv->need_commit) return 0; ks_wlan_setup_parameter(priv, priv->need_commit); - priv->need_commit=0; + priv->need_commit = 0; return 0; } /*------------------------------------------------------------------*/ /* Wireless handler : set association ie params */ -static int ks_wlan_set_genie(struct net_device *dev, struct iw_request_info *info, - struct iw_point *dwrq, char *extra) +static int ks_wlan_set_genie(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *dwrq, char *extra) { - struct ks_wlan_private *priv = (struct ks_wlan_private *)netdev_priv(dev); + struct ks_wlan_private *priv = + (struct ks_wlan_private *)netdev_priv(dev); DPRINTK(2, "\n"); - if (priv->sleep_mode == SLP_SLEEP){ return -EPERM; } /* for SLEEP MODE */ - + if (priv->sleep_mode == SLP_SLEEP) { + return -EPERM; + } + /* for SLEEP MODE */ return 0; -// return -EOPNOTSUPP; +// return -EOPNOTSUPP; } /*------------------------------------------------------------------*/ /* Wireless handler : set authentication mode params */ -static int ks_wlan_set_auth_mode(struct net_device *dev, struct iw_request_info *info, +static int ks_wlan_set_auth_mode(struct net_device *dev, + struct iw_request_info *info, struct iw_param *vwrq, char *extra) { - struct ks_wlan_private *priv = (struct ks_wlan_private *)netdev_priv(dev); + struct ks_wlan_private *priv = + (struct ks_wlan_private *)netdev_priv(dev); int index = (vwrq->flags & IW_AUTH_INDEX); int value = vwrq->value; - DPRINTK(2,"index=%d:value=%08X\n",index,value); + DPRINTK(2, "index=%d:value=%08X\n", index, value); - if (priv->sleep_mode == SLP_SLEEP){ return -EPERM; } /* for SLEEP MODE */ - - switch(index){ - case IW_AUTH_WPA_VERSION: /* 0 */ - switch(value){ + if (priv->sleep_mode == SLP_SLEEP) { + return -EPERM; + } + /* for SLEEP MODE */ + switch (index) { + case IW_AUTH_WPA_VERSION: /* 0 */ + switch (value) { case IW_AUTH_WPA_VERSION_DISABLED: priv->wpa.version = value; - if(priv->wpa.rsn_enabled){ + if (priv->wpa.rsn_enabled) { priv->wpa.rsn_enabled = 0; } priv->need_commit |= SME_RSN; @@ -1499,7 +1721,7 @@ static int ks_wlan_set_auth_mode(struct net_device *dev, struct iw_request_info case IW_AUTH_WPA_VERSION_WPA: case IW_AUTH_WPA_VERSION_WPA2: priv->wpa.version = value; - if(!(priv->wpa.rsn_enabled)){ + if (!(priv->wpa.rsn_enabled)) { priv->wpa.rsn_enabled = 1; } priv->need_commit |= SME_RSN; @@ -1508,10 +1730,10 @@ static int ks_wlan_set_auth_mode(struct net_device *dev, struct iw_request_info return -EOPNOTSUPP; } break; - case IW_AUTH_CIPHER_PAIRWISE: /* 1 */ - switch(value){ + case IW_AUTH_CIPHER_PAIRWISE: /* 1 */ + switch (value) { case IW_AUTH_CIPHER_NONE: - if(priv->reg.privacy_invoked){ + if (priv->reg.privacy_invoked) { priv->reg.privacy_invoked = 0x00; priv->need_commit |= SME_WEP_FLAG; } @@ -1520,7 +1742,7 @@ static int ks_wlan_set_auth_mode(struct net_device *dev, struct iw_request_info case IW_AUTH_CIPHER_TKIP: case IW_AUTH_CIPHER_CCMP: case IW_AUTH_CIPHER_WEP104: - if(!priv->reg.privacy_invoked){ + if (!priv->reg.privacy_invoked) { priv->reg.privacy_invoked = 0x01; priv->need_commit |= SME_WEP_FLAG; } @@ -1531,10 +1753,10 @@ static int ks_wlan_set_auth_mode(struct net_device *dev, struct iw_request_info return -EOPNOTSUPP; } break; - case IW_AUTH_CIPHER_GROUP: /* 2 */ - switch(value){ + case IW_AUTH_CIPHER_GROUP: /* 2 */ + switch (value) { case IW_AUTH_CIPHER_NONE: - if(priv->reg.privacy_invoked){ + if (priv->reg.privacy_invoked) { priv->reg.privacy_invoked = 0x00; priv->need_commit |= SME_WEP_FLAG; } @@ -1543,7 +1765,7 @@ static int ks_wlan_set_auth_mode(struct net_device *dev, struct iw_request_info case IW_AUTH_CIPHER_TKIP: case IW_AUTH_CIPHER_CCMP: case IW_AUTH_CIPHER_WEP104: - if(!priv->reg.privacy_invoked){ + if (!priv->reg.privacy_invoked) { priv->reg.privacy_invoked = 0x01; priv->need_commit |= SME_WEP_FLAG; } @@ -1554,12 +1776,12 @@ static int ks_wlan_set_auth_mode(struct net_device *dev, struct iw_request_info return -EOPNOTSUPP; } break; - case IW_AUTH_KEY_MGMT: /* 3 */ - switch(value){ + case IW_AUTH_KEY_MGMT: /* 3 */ + switch (value) { case IW_AUTH_KEY_MGMT_802_1X: case IW_AUTH_KEY_MGMT_PSK: - case 0: /* NONE or 802_1X_NO_WPA */ - case 4: /* WPA_NONE */ + case 0: /* NONE or 802_1X_NO_WPA */ + case 4: /* WPA_NONE */ priv->wpa.key_mgmt_suite = value; priv->need_commit |= SME_RSN_AUTH; break; @@ -1567,8 +1789,8 @@ static int ks_wlan_set_auth_mode(struct net_device *dev, struct iw_request_info return -EOPNOTSUPP; } break; - case IW_AUTH_80211_AUTH_ALG: /* 6 */ - switch(value){ + case IW_AUTH_80211_AUTH_ALG: /* 6 */ + switch (value) { case IW_AUTH_ALG_OPEN_SYSTEM: priv->wpa.auth_alg = value; priv->reg.authenticate_type = AUTH_TYPE_OPEN_SYSTEM; @@ -1583,45 +1805,50 @@ static int ks_wlan_set_auth_mode(struct net_device *dev, struct iw_request_info } priv->need_commit |= SME_MODE_SET; break; - case IW_AUTH_WPA_ENABLED: /* 7 */ + case IW_AUTH_WPA_ENABLED: /* 7 */ priv->wpa.wpa_enabled = value; break; - case IW_AUTH_PRIVACY_INVOKED: /* 10 */ - if((value && !priv->reg.privacy_invoked)|| - (!value && priv->reg.privacy_invoked)){ - priv->reg.privacy_invoked = value?0x01:0x00; + case IW_AUTH_PRIVACY_INVOKED: /* 10 */ + if ((value && !priv->reg.privacy_invoked) || + (!value && priv->reg.privacy_invoked)) { + priv->reg.privacy_invoked = value ? 0x01 : 0x00; priv->need_commit |= SME_WEP_FLAG; } break; - case IW_AUTH_RX_UNENCRYPTED_EAPOL: /* 4 */ - case IW_AUTH_TKIP_COUNTERMEASURES: /* 5 */ - case IW_AUTH_DROP_UNENCRYPTED: /* 8 */ - case IW_AUTH_ROAMING_CONTROL: /* 9 */ + case IW_AUTH_RX_UNENCRYPTED_EAPOL: /* 4 */ + case IW_AUTH_TKIP_COUNTERMEASURES: /* 5 */ + case IW_AUTH_DROP_UNENCRYPTED: /* 8 */ + case IW_AUTH_ROAMING_CONTROL: /* 9 */ default: break; } /* return -EINPROGRESS; */ - if(priv->need_commit){ + if (priv->need_commit) { ks_wlan_setup_parameter(priv, priv->need_commit); - priv->need_commit=0; + priv->need_commit = 0; } return 0; } /*------------------------------------------------------------------*/ /* Wireless handler : get authentication mode params */ -static int ks_wlan_get_auth_mode(struct net_device *dev, struct iw_request_info *info, +static int ks_wlan_get_auth_mode(struct net_device *dev, + struct iw_request_info *info, struct iw_param *vwrq, char *extra) { - struct ks_wlan_private *priv = (struct ks_wlan_private *)netdev_priv(dev); + struct ks_wlan_private *priv = + (struct ks_wlan_private *)netdev_priv(dev); int index = (vwrq->flags & IW_AUTH_INDEX); - DPRINTK(2,"index=%d\n",index); + DPRINTK(2, "index=%d\n", index); - if (priv->sleep_mode == SLP_SLEEP){ return -EPERM; } /* for SLEEP MODE */ + if (priv->sleep_mode == SLP_SLEEP) { + return -EPERM; + } + /* for SLEEP MODE */ /* WPA (not used ?? wpa_supplicant) */ - switch(index){ + switch (index) { case IW_AUTH_WPA_VERSION: vwrq->value = priv->wpa.version; break; @@ -1640,7 +1867,7 @@ static int ks_wlan_get_auth_mode(struct net_device *dev, struct iw_request_info case IW_AUTH_WPA_ENABLED: vwrq->value = priv->wpa.rsn_enabled; break; - case IW_AUTH_RX_UNENCRYPTED_EAPOL: /* OK??? */ + case IW_AUTH_RX_UNENCRYPTED_EAPOL: /* OK??? */ case IW_AUTH_TKIP_COUNTERMEASURES: case IW_AUTH_DROP_UNENCRYPTED: default: @@ -1652,36 +1879,41 @@ static int ks_wlan_get_auth_mode(struct net_device *dev, struct iw_request_info /*------------------------------------------------------------------*/ /* Wireless Handler : set encoding token & mode (WPA)*/ -static int ks_wlan_set_encode_ext(struct net_device *dev, struct iw_request_info *info, +static int ks_wlan_set_encode_ext(struct net_device *dev, + struct iw_request_info *info, struct iw_point *dwrq, char *extra) { - struct ks_wlan_private *priv = (struct ks_wlan_private *)netdev_priv(dev); + struct ks_wlan_private *priv = + (struct ks_wlan_private *)netdev_priv(dev); struct iw_encode_ext *enc; int index = dwrq->flags & IW_ENCODE_INDEX; - unsigned int commit=0; + unsigned int commit = 0; enc = (struct iw_encode_ext *)extra; - DPRINTK(2,"flags=%04X:: ext_flags=%08X\n",dwrq->flags, enc->ext_flags); - - if (priv->sleep_mode == SLP_SLEEP){ return -EPERM; } /* for SLEEP MODE */ + DPRINTK(2, "flags=%04X:: ext_flags=%08X\n", dwrq->flags, + enc->ext_flags); - if(index<1||index>4) + if (priv->sleep_mode == SLP_SLEEP) { + return -EPERM; + } + /* for SLEEP MODE */ + if (index < 1 || index > 4) return -EINVAL; else index--; - if(dwrq->flags & IW_ENCODE_DISABLED){ - priv->wpa.key[index].key_len=0; + if (dwrq->flags & IW_ENCODE_DISABLED) { + priv->wpa.key[index].key_len = 0; } - if(enc){ - priv->wpa.key[index].ext_flags=enc->ext_flags; - if(enc->ext_flags&IW_ENCODE_EXT_SET_TX_KEY){ - priv->wpa.txkey=index; + if (enc) { + priv->wpa.key[index].ext_flags = enc->ext_flags; + if (enc->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) { + priv->wpa.txkey = index; commit |= SME_WEP_INDEX; - }else if(enc->ext_flags&IW_ENCODE_EXT_RX_SEQ_VALID){ - if(enc->rx_seq) + } else if (enc->ext_flags & IW_ENCODE_EXT_RX_SEQ_VALID) { + if (enc->rx_seq) memcpy(&priv->wpa.key[index].rx_seq[0], enc->rx_seq, IW_ENCODE_SEQ_MAX_SIZE); else @@ -1689,11 +1921,11 @@ static int ks_wlan_set_encode_ext(struct net_device *dev, struct iw_request_info } memcpy(&priv->wpa.key[index].addr.sa_data[0], - &enc->addr.sa_data[0], ETH_ALEN); + &enc->addr.sa_data[0], ETH_ALEN); switch (enc->alg) { case IW_ENCODE_ALG_NONE: - if(priv->reg.privacy_invoked){ + if (priv->reg.privacy_invoked) { priv->reg.privacy_invoked = 0x00; commit |= SME_WEP_FLAG; } @@ -1702,11 +1934,11 @@ static int ks_wlan_set_encode_ext(struct net_device *dev, struct iw_request_info break; case IW_ENCODE_ALG_WEP: case IW_ENCODE_ALG_CCMP: - if(!priv->reg.privacy_invoked){ + if (!priv->reg.privacy_invoked) { priv->reg.privacy_invoked = 0x01; commit |= SME_WEP_FLAG; } - if(enc->key && enc->key_len){ + if (enc->key && enc->key_len) { memcpy(&priv->wpa.key[index].key_val[0], &enc->key[0], enc->key_len); priv->wpa.key[index].key_len = enc->key_len; @@ -1714,24 +1946,25 @@ static int ks_wlan_set_encode_ext(struct net_device *dev, struct iw_request_info } break; case IW_ENCODE_ALG_TKIP: - if(!priv->reg.privacy_invoked){ + if (!priv->reg.privacy_invoked) { priv->reg.privacy_invoked = 0x01; commit |= SME_WEP_FLAG; } - if(enc->key && enc->key_len == 32){ + if (enc->key && enc->key_len == 32) { memcpy(&priv->wpa.key[index].key_val[0], - &enc->key[0], enc->key_len-16); - priv->wpa.key[index].key_len = enc->key_len-16; - if(priv->wpa.key_mgmt_suite==4){ /* WPA_NONE */ - memcpy(&priv->wpa.key[index].tx_mic_key[0], - &enc->key[16],8); - memcpy(&priv->wpa.key[index].rx_mic_key[0], - &enc->key[16],8); - }else{ - memcpy(&priv->wpa.key[index].tx_mic_key[0], - &enc->key[16],8); - memcpy(&priv->wpa.key[index].rx_mic_key[0], - &enc->key[24],8); + &enc->key[0], enc->key_len - 16); + priv->wpa.key[index].key_len = + enc->key_len - 16; + if (priv->wpa.key_mgmt_suite == 4) { /* WPA_NONE */ + memcpy(&priv->wpa.key[index]. + tx_mic_key[0], &enc->key[16], 8); + memcpy(&priv->wpa.key[index]. + rx_mic_key[0], &enc->key[16], 8); + } else { + memcpy(&priv->wpa.key[index]. + tx_mic_key[0], &enc->key[16], 8); + memcpy(&priv->wpa.key[index]. + rx_mic_key[0], &enc->key[24], 8); } commit |= (SME_WEP_VAL1 << index); } @@ -1739,17 +1972,16 @@ static int ks_wlan_set_encode_ext(struct net_device *dev, struct iw_request_info default: return -EINVAL; } - priv->wpa.key[index].alg=enc->alg; - } - else + priv->wpa.key[index].alg = enc->alg; + } else return -EINVAL; - if(commit){ - if(commit&SME_WEP_INDEX) + if (commit) { + if (commit & SME_WEP_INDEX) hostif_sme_enqueue(priv, SME_SET_TXKEY); - if(commit&SME_WEP_VAL_MASK) - hostif_sme_enqueue(priv, SME_SET_KEY1+index); - if(commit&SME_WEP_FLAG) + if (commit & SME_WEP_VAL_MASK) + hostif_sme_enqueue(priv, SME_SET_KEY1 + index); + if (commit & SME_WEP_FLAG) hostif_sme_enqueue(priv, SME_WEP_FLAG_REQUEST); } @@ -1758,101 +1990,121 @@ static int ks_wlan_set_encode_ext(struct net_device *dev, struct iw_request_info /*------------------------------------------------------------------*/ /* Wireless Handler : get encoding token & mode (WPA)*/ -static int ks_wlan_get_encode_ext(struct net_device *dev, struct iw_request_info *info, +static int ks_wlan_get_encode_ext(struct net_device *dev, + struct iw_request_info *info, struct iw_point *dwrq, char *extra) { - struct ks_wlan_private *priv = (struct ks_wlan_private *)netdev_priv(dev); + struct ks_wlan_private *priv = + (struct ks_wlan_private *)netdev_priv(dev); - if (priv->sleep_mode == SLP_SLEEP){ return -EPERM; } /* for SLEEP MODE */ + if (priv->sleep_mode == SLP_SLEEP) { + return -EPERM; + } + /* for SLEEP MODE */ /* WPA (not used ?? wpa_supplicant) - struct ks_wlan_private *priv = (struct ks_wlan_private *)dev->priv; - struct iw_encode_ext *enc; - enc = (struct iw_encode_ext *)extra; - int index = dwrq->flags & IW_ENCODE_INDEX; - WPA (not used ?? wpa_supplicant) */ + struct ks_wlan_private *priv = (struct ks_wlan_private *)dev->priv; + struct iw_encode_ext *enc; + enc = (struct iw_encode_ext *)extra; + int index = dwrq->flags & IW_ENCODE_INDEX; + WPA (not used ?? wpa_supplicant) */ return 0; } /*------------------------------------------------------------------*/ /* Wireless Handler : PMKSA cache operation (WPA2) */ -static int ks_wlan_set_pmksa(struct net_device *dev, struct iw_request_info *info, - struct iw_point *dwrq, char *extra) +static int ks_wlan_set_pmksa(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *dwrq, char *extra) { - struct ks_wlan_private *priv = (struct ks_wlan_private *)netdev_priv(dev); - struct iw_pmksa *pmksa ; + struct ks_wlan_private *priv = + (struct ks_wlan_private *)netdev_priv(dev); + struct iw_pmksa *pmksa; int i; struct pmk_t *pmk; struct list_head *ptr; - DPRINTK(2,"\n"); - - if (priv->sleep_mode == SLP_SLEEP){ return -EPERM; } /* for SLEEP MODE */ + DPRINTK(2, "\n"); - if(!extra){ + if (priv->sleep_mode == SLP_SLEEP) { + return -EPERM; + } + /* for SLEEP MODE */ + if (!extra) { return -EINVAL; } pmksa = (struct iw_pmksa *)extra; - DPRINTK(2,"cmd=%d\n",pmksa->cmd); + DPRINTK(2, "cmd=%d\n", pmksa->cmd); - switch(pmksa->cmd){ + switch (pmksa->cmd) { case IW_PMKSA_ADD: - if(list_empty(&priv->pmklist.head)){ /* new list */ - for(i=0;ipmklist.head)) { /* new list */ + for (i = 0; i < PMK_LIST_MAX; i++) { pmk = &priv->pmklist.pmk[i]; - if(!memcmp("\x00\x00\x00\x00\x00\x00",pmk->bssid,ETH_ALEN)) + if (!memcmp + ("\x00\x00\x00\x00\x00\x00", pmk->bssid, + ETH_ALEN)) break; } memcpy(pmk->bssid, pmksa->bssid.sa_data, ETH_ALEN); memcpy(pmk->pmkid, pmksa->pmkid, IW_PMKID_LEN); - list_add(&pmk->list,&priv->pmklist.head); + list_add(&pmk->list, &priv->pmklist.head); priv->pmklist.size++; - } - else { /* search cache data */ - list_for_each(ptr, &priv->pmklist.head){ + } else { /* search cache data */ + list_for_each(ptr, &priv->pmklist.head) { pmk = list_entry(ptr, struct pmk_t, list); - if(!memcmp(pmksa->bssid.sa_data, pmk->bssid, ETH_ALEN)){ /* match address! list move to head. */ - memcpy(pmk->pmkid, pmksa->pmkid, IW_PMKID_LEN); - list_move(&pmk->list, &priv->pmklist.head); + if (!memcmp(pmksa->bssid.sa_data, pmk->bssid, ETH_ALEN)) { /* match address! list move to head. */ + memcpy(pmk->pmkid, pmksa->pmkid, + IW_PMKID_LEN); + list_move(&pmk->list, + &priv->pmklist.head); break; } } - if(ptr == &priv->pmklist.head){ /* not find address. */ - if(PMK_LIST_MAX > priv->pmklist.size){ /* new cache data */ - for(i=0;ipmklist.head) { /* not find address. */ + if (PMK_LIST_MAX > priv->pmklist.size) { /* new cache data */ + for (i = 0; i < PMK_LIST_MAX; i++) { pmk = &priv->pmklist.pmk[i]; - if(!memcmp("\x00\x00\x00\x00\x00\x00",pmk->bssid,ETH_ALEN)) + if (!memcmp + ("\x00\x00\x00\x00\x00\x00", + pmk->bssid, ETH_ALEN)) break; } - memcpy(pmk->bssid, pmksa->bssid.sa_data, ETH_ALEN); - memcpy(pmk->pmkid, pmksa->pmkid, IW_PMKID_LEN); - list_add(&pmk->list,&priv->pmklist.head); + memcpy(pmk->bssid, pmksa->bssid.sa_data, + ETH_ALEN); + memcpy(pmk->pmkid, pmksa->pmkid, + IW_PMKID_LEN); + list_add(&pmk->list, + &priv->pmklist.head); priv->pmklist.size++; - } - else{ /* overwrite old cache data */ - pmk = list_entry(priv->pmklist.head.prev, struct pmk_t, list); - memcpy(pmk->bssid, pmksa->bssid.sa_data, ETH_ALEN); - memcpy(pmk->pmkid, pmksa->pmkid, IW_PMKID_LEN); - list_move(&pmk->list,&priv->pmklist.head); + } else { /* overwrite old cache data */ + pmk = + list_entry(priv->pmklist.head.prev, + struct pmk_t, list); + memcpy(pmk->bssid, pmksa->bssid.sa_data, + ETH_ALEN); + memcpy(pmk->pmkid, pmksa->pmkid, + IW_PMKID_LEN); + list_move(&pmk->list, + &priv->pmklist.head); } } } break; case IW_PMKSA_REMOVE: - if(list_empty(&priv->pmklist.head)){ /* list empty */ + if (list_empty(&priv->pmklist.head)) { /* list empty */ return -EINVAL; - } - else{ /* search cache data */ - list_for_each(ptr, &priv->pmklist.head){ + } else { /* search cache data */ + list_for_each(ptr, &priv->pmklist.head) { pmk = list_entry(ptr, struct pmk_t, list); - if(!memcmp(pmksa->bssid.sa_data, pmk->bssid, ETH_ALEN)){ /* match address! list del. */ + if (!memcmp(pmksa->bssid.sa_data, pmk->bssid, ETH_ALEN)) { /* match address! list del. */ memset(pmk->bssid, 0, ETH_ALEN); memset(pmk->pmkid, 0, IW_PMKID_LEN); list_del_init(&pmk->list); break; } } - if(ptr == &priv->pmklist.head){ /* not find address. */ + if (ptr == &priv->pmklist.head) { /* not find address. */ return 0; } } @@ -1860,7 +2112,7 @@ static int ks_wlan_set_pmksa(struct net_device *dev, struct iw_request_info *inf case IW_PMKSA_FLUSH: memset(&(priv->pmklist), 0, sizeof(priv->pmklist)); INIT_LIST_HEAD(&priv->pmklist.head); - for(i=0;ipmklist.pmk[i].list); break; default: @@ -1874,40 +2126,45 @@ static int ks_wlan_set_pmksa(struct net_device *dev, struct iw_request_info *inf static struct iw_statistics *ks_get_wireless_stats(struct net_device *dev) { - struct ks_wlan_private *priv = (struct ks_wlan_private *) netdev_priv(dev); - struct iw_statistics *wstats = &priv->wstats; + struct ks_wlan_private *priv = + (struct ks_wlan_private *)netdev_priv(dev); + struct iw_statistics *wstats = &priv->wstats; - if(!atomic_read(&update_phyinfo)){ + if (!atomic_read(&update_phyinfo)) { if (priv->dev_state < DEVICE_STATE_READY) - return NULL; /* not finished initialize */ + return NULL; /* not finished initialize */ else return wstats; } /* Packets discarded in the wireless adapter due to wireless * specific problems */ - wstats->discard.nwid = 0; /* Rx invalid nwid */ - wstats->discard.code = 0; /* Rx invalid crypt */ - wstats->discard.fragment = 0; /* Rx invalid frag */ - wstats->discard.retries = 0; /* Tx excessive retries */ - wstats->discard.misc = 0; /* Invalid misc */ - wstats->miss.beacon = 0; /* Missed beacon */ + wstats->discard.nwid = 0; /* Rx invalid nwid */ + wstats->discard.code = 0; /* Rx invalid crypt */ + wstats->discard.fragment = 0; /* Rx invalid frag */ + wstats->discard.retries = 0; /* Tx excessive retries */ + wstats->discard.misc = 0; /* Invalid misc */ + wstats->miss.beacon = 0; /* Missed beacon */ - return wstats; + return wstats; } /*------------------------------------------------------------------*/ /* Private handler : set stop request */ -static int ks_wlan_set_stop_request(struct net_device *dev, struct iw_request_info *info, - __u32 *uwrq, char *extra) +static int ks_wlan_set_stop_request(struct net_device *dev, + struct iw_request_info *info, __u32 * uwrq, + char *extra) { - struct ks_wlan_private *priv = (struct ks_wlan_private *)netdev_priv(dev); - DPRINTK(2,"\n"); - - if (priv->sleep_mode == SLP_SLEEP){ return -EPERM; } /* for SLEEP MODE */ + struct ks_wlan_private *priv = + (struct ks_wlan_private *)netdev_priv(dev); + DPRINTK(2, "\n"); - if(!(*uwrq)) - return -EINVAL; + if (priv->sleep_mode == SLP_SLEEP) { + return -EPERM; + } + /* for SLEEP MODE */ + if (!(*uwrq)) + return -EINVAL; hostif_sme_enqueue(priv, SME_STOP_REQUEST); return 0; @@ -1916,17 +2173,21 @@ static int ks_wlan_set_stop_request(struct net_device *dev, struct iw_request_in /*------------------------------------------------------------------*/ /* Wireless Handler : set MLME */ #include -static int ks_wlan_set_mlme(struct net_device *dev, struct iw_request_info *info, - struct iw_point *dwrq, char *extra) +static int ks_wlan_set_mlme(struct net_device *dev, + struct iw_request_info *info, struct iw_point *dwrq, + char *extra) { - struct ks_wlan_private *priv = (struct ks_wlan_private *)netdev_priv(dev); + struct ks_wlan_private *priv = + (struct ks_wlan_private *)netdev_priv(dev); struct iw_mlme *mlme = (struct iw_mlme *)extra; __u32 mode; DPRINTK(2, ":%d :%d\n", mlme->cmd, mlme->reason_code); - if (priv->sleep_mode == SLP_SLEEP){ return -EPERM; } /* for SLEEP MODE */ - + if (priv->sleep_mode == SLP_SLEEP) { + return -EPERM; + } + /* for SLEEP MODE */ switch (mlme->cmd) { case IW_MLME_DEAUTH: if (mlme->reason_code == WLAN_REASON_MIC_FAILURE) { @@ -1936,75 +2197,88 @@ static int ks_wlan_set_mlme(struct net_device *dev, struct iw_request_info *info mode = 1; return ks_wlan_set_stop_request(dev, NULL, &mode, NULL); default: - return -EOPNOTSUPP; /* Not Support */ + return -EOPNOTSUPP; /* Not Support */ } } /*------------------------------------------------------------------*/ /* Private handler : get driver version */ -static int ks_wlan_get_driver_version(struct net_device *dev, struct iw_request_info *info, +static int ks_wlan_get_driver_version(struct net_device *dev, + struct iw_request_info *info, struct iw_point *dwrq, char *extra) { strcpy(extra, KS_WLAN_DRIVER_VERSION_INFO); - dwrq->length = strlen(KS_WLAN_DRIVER_VERSION_INFO)+1; + dwrq->length = strlen(KS_WLAN_DRIVER_VERSION_INFO) + 1; return 0; } /*------------------------------------------------------------------*/ /* Private handler : get firemware version */ -static int ks_wlan_get_firmware_version(struct net_device *dev, struct iw_request_info *info, +static int ks_wlan_get_firmware_version(struct net_device *dev, + struct iw_request_info *info, struct iw_point *dwrq, char *extra) { - struct ks_wlan_private *priv = (struct ks_wlan_private *)netdev_priv(dev); + struct ks_wlan_private *priv = + (struct ks_wlan_private *)netdev_priv(dev); strcpy(extra, &(priv->firmware_version[0])); - dwrq->length = priv->version_size+1; + dwrq->length = priv->version_size + 1; return 0; } #if 0 /*------------------------------------------------------------------*/ /* Private handler : set force disconnect status */ -static int ks_wlan_set_detach(struct net_device *dev, struct iw_request_info *info, - __u32 *uwrq, char *extra) +static int ks_wlan_set_detach(struct net_device *dev, + struct iw_request_info *info, __u32 * uwrq, + char *extra) { struct ks_wlan_private *priv = (struct ks_wlan_private *)dev->priv; - if (priv->sleep_mode == SLP_SLEEP){ return -EPERM; } /* for SLEEP MODE */ - - if(*uwrq == CONNECT_STATUS){ /* 0 */ + if (priv->sleep_mode == SLP_SLEEP) { + return -EPERM; + } + /* for SLEEP MODE */ + if (*uwrq == CONNECT_STATUS) { /* 0 */ priv->connect_status &= ~FORCE_DISCONNECT; - if((priv->connect_status & CONNECT_STATUS_MASK) == CONNECT_STATUS) + if ((priv->connect_status & CONNECT_STATUS_MASK) == + CONNECT_STATUS) netif_carrier_on(dev); - }else if(*uwrq == DISCONNECT_STATUS){ /* 1 */ + } else if (*uwrq == DISCONNECT_STATUS) { /* 1 */ priv->connect_status |= FORCE_DISCONNECT; netif_carrier_off(dev); - }else - return -EINVAL; + } else + return -EINVAL; return 0; } /*------------------------------------------------------------------*/ /* Private handler : get force disconnect status */ -static int ks_wlan_get_detach(struct net_device *dev, struct iw_request_info *info, - __u32 *uwrq, char *extra) +static int ks_wlan_get_detach(struct net_device *dev, + struct iw_request_info *info, __u32 * uwrq, + char *extra) { struct ks_wlan_private *priv = (struct ks_wlan_private *)dev->priv; - if (priv->sleep_mode == SLP_SLEEP){ return -EPERM; } /* for SLEEP MODE */ - - *uwrq = ((priv->connect_status & FORCE_DISCONNECT) ? 1 : 0 ); + if (priv->sleep_mode == SLP_SLEEP) { + return -EPERM; + } + /* for SLEEP MODE */ + *uwrq = ((priv->connect_status & FORCE_DISCONNECT) ? 1 : 0); return 0; } /*------------------------------------------------------------------*/ /* Private handler : get connect status */ -static int ks_wlan_get_connect(struct net_device *dev, struct iw_request_info *info, - __u32 *uwrq, char *extra) +static int ks_wlan_get_connect(struct net_device *dev, + struct iw_request_info *info, __u32 * uwrq, + char *extra) { struct ks_wlan_private *priv = (struct ks_wlan_private *)dev->priv; - if (priv->sleep_mode == SLP_SLEEP){ return -EPERM; } /* for SLEEP MODE */ - + if (priv->sleep_mode == SLP_SLEEP) { + return -EPERM; + } + /* for SLEEP MODE */ *uwrq = (priv->connect_status & CONNECT_STATUS_MASK); return 0; } @@ -2012,61 +2286,73 @@ static int ks_wlan_get_connect(struct net_device *dev, struct iw_request_info *i /*------------------------------------------------------------------*/ /* Private handler : set preamble */ -static int ks_wlan_set_preamble(struct net_device *dev, struct iw_request_info *info, - __u32 *uwrq, char *extra) +static int ks_wlan_set_preamble(struct net_device *dev, + struct iw_request_info *info, __u32 * uwrq, + char *extra) { - struct ks_wlan_private *priv = (struct ks_wlan_private *)netdev_priv(dev); - - if (priv->sleep_mode == SLP_SLEEP){ return -EPERM; } /* for SLEEP MODE */ + struct ks_wlan_private *priv = + (struct ks_wlan_private *)netdev_priv(dev); - if(*uwrq == LONG_PREAMBLE){ /* 0 */ + if (priv->sleep_mode == SLP_SLEEP) { + return -EPERM; + } + /* for SLEEP MODE */ + if (*uwrq == LONG_PREAMBLE) { /* 0 */ priv->reg.preamble = LONG_PREAMBLE; - }else if(*uwrq == SHORT_PREAMBLE){ /* 1 */ + } else if (*uwrq == SHORT_PREAMBLE) { /* 1 */ priv->reg.preamble = SHORT_PREAMBLE; - }else - return -EINVAL; + } else + return -EINVAL; priv->need_commit |= SME_MODE_SET; - return -EINPROGRESS; /* Call commit handler */ + return -EINPROGRESS; /* Call commit handler */ } /*------------------------------------------------------------------*/ /* Private handler : get preamble */ -static int ks_wlan_get_preamble(struct net_device *dev, struct iw_request_info *info, - __u32 *uwrq, char *extra) +static int ks_wlan_get_preamble(struct net_device *dev, + struct iw_request_info *info, __u32 * uwrq, + char *extra) { - struct ks_wlan_private *priv = (struct ks_wlan_private *)netdev_priv(dev); - - if (priv->sleep_mode == SLP_SLEEP){ return -EPERM; } /* for SLEEP MODE */ + struct ks_wlan_private *priv = + (struct ks_wlan_private *)netdev_priv(dev); + if (priv->sleep_mode == SLP_SLEEP) { + return -EPERM; + } + /* for SLEEP MODE */ *uwrq = priv->reg.preamble; return 0; } /*------------------------------------------------------------------*/ /* Private handler : set power save mode */ -static int ks_wlan_set_powermgt(struct net_device *dev, struct iw_request_info *info, - __u32 *uwrq, char *extra) +static int ks_wlan_set_powermgt(struct net_device *dev, + struct iw_request_info *info, __u32 * uwrq, + char *extra) { - struct ks_wlan_private *priv = (struct ks_wlan_private *)netdev_priv(dev); - - if (priv->sleep_mode == SLP_SLEEP){ return -EPERM; } /* for SLEEP MODE */ + struct ks_wlan_private *priv = + (struct ks_wlan_private *)netdev_priv(dev); - if(*uwrq == POWMGT_ACTIVE_MODE){ /* 0 */ + if (priv->sleep_mode == SLP_SLEEP) { + return -EPERM; + } + /* for SLEEP MODE */ + if (*uwrq == POWMGT_ACTIVE_MODE) { /* 0 */ priv->reg.powermgt = POWMGT_ACTIVE_MODE; - }else if(*uwrq == POWMGT_SAVE1_MODE){ /* 1 */ - if(priv->reg.operation_mode == MODE_INFRASTRUCTURE) - priv->reg.powermgt = POWMGT_SAVE1_MODE; - else - return -EINVAL; - }else if(*uwrq == POWMGT_SAVE2_MODE){ /* 2 */ - if(priv->reg.operation_mode == MODE_INFRASTRUCTURE) + } else if (*uwrq == POWMGT_SAVE1_MODE) { /* 1 */ + if (priv->reg.operation_mode == MODE_INFRASTRUCTURE) + priv->reg.powermgt = POWMGT_SAVE1_MODE; + else + return -EINVAL; + } else if (*uwrq == POWMGT_SAVE2_MODE) { /* 2 */ + if (priv->reg.operation_mode == MODE_INFRASTRUCTURE) priv->reg.powermgt = POWMGT_SAVE2_MODE; else return -EINVAL; - }else - return -EINVAL; + } else + return -EINVAL; hostif_sme_enqueue(priv, SME_POW_MNGMT_REQUEST); @@ -2075,100 +2361,119 @@ static int ks_wlan_set_powermgt(struct net_device *dev, struct iw_request_info * /*------------------------------------------------------------------*/ /* Private handler : get power save made */ -static int ks_wlan_get_powermgt(struct net_device *dev, struct iw_request_info *info, - __u32 *uwrq, char *extra) +static int ks_wlan_get_powermgt(struct net_device *dev, + struct iw_request_info *info, __u32 * uwrq, + char *extra) { - struct ks_wlan_private *priv = (struct ks_wlan_private *)netdev_priv(dev); - - if (priv->sleep_mode == SLP_SLEEP){ return -EPERM; } /* for SLEEP MODE */ + struct ks_wlan_private *priv = + (struct ks_wlan_private *)netdev_priv(dev); + if (priv->sleep_mode == SLP_SLEEP) { + return -EPERM; + } + /* for SLEEP MODE */ *uwrq = priv->reg.powermgt; return 0; } /*------------------------------------------------------------------*/ /* Private handler : set scan type */ -static int ks_wlan_set_scan_type(struct net_device *dev, struct iw_request_info *info, - __u32 *uwrq, char *extra) +static int ks_wlan_set_scan_type(struct net_device *dev, + struct iw_request_info *info, __u32 * uwrq, + char *extra) { - struct ks_wlan_private *priv = (struct ks_wlan_private *)netdev_priv(dev); - - if (priv->sleep_mode == SLP_SLEEP){ return -EPERM; } /* for SLEEP MODE */ + struct ks_wlan_private *priv = + (struct ks_wlan_private *)netdev_priv(dev); - if(*uwrq == ACTIVE_SCAN){ /* 0 */ + if (priv->sleep_mode == SLP_SLEEP) { + return -EPERM; + } + /* for SLEEP MODE */ + if (*uwrq == ACTIVE_SCAN) { /* 0 */ priv->reg.scan_type = ACTIVE_SCAN; - }else if(*uwrq == PASSIVE_SCAN){ /* 1 */ + } else if (*uwrq == PASSIVE_SCAN) { /* 1 */ priv->reg.scan_type = PASSIVE_SCAN; - }else - return -EINVAL; + } else + return -EINVAL; return 0; } /*------------------------------------------------------------------*/ /* Private handler : get scan type */ -static int ks_wlan_get_scan_type(struct net_device *dev, struct iw_request_info *info, - __u32 *uwrq, char *extra) +static int ks_wlan_get_scan_type(struct net_device *dev, + struct iw_request_info *info, __u32 * uwrq, + char *extra) { - struct ks_wlan_private *priv = (struct ks_wlan_private *)netdev_priv(dev); - - if (priv->sleep_mode == SLP_SLEEP){ return -EPERM; } /* for SLEEP MODE */ + struct ks_wlan_private *priv = + (struct ks_wlan_private *)netdev_priv(dev); + if (priv->sleep_mode == SLP_SLEEP) { + return -EPERM; + } + /* for SLEEP MODE */ *uwrq = priv->reg.scan_type; return 0; } + #if 0 /*------------------------------------------------------------------*/ /* Private handler : write raw data to device */ -static int ks_wlan_data_write(struct net_device *dev, struct iw_request_info *info, - struct iw_point *dwrq, char *extra) +static int ks_wlan_data_write(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *dwrq, char *extra) { struct ks_wlan_private *priv = (struct ks_wlan_private *)dev->priv; unsigned char *wbuff = NULL; - if (priv->sleep_mode == SLP_SLEEP){ return -EPERM; } /* for SLEEP MODE */ - + if (priv->sleep_mode == SLP_SLEEP) { + return -EPERM; + } + /* for SLEEP MODE */ wbuff = (unsigned char *)kmalloc(dwrq->length, GFP_ATOMIC); - if(!wbuff) - return -EFAULT; + if (!wbuff) + return -EFAULT; memcpy(wbuff, extra, dwrq->length); /* write to device */ - ks_wlan_hw_tx( priv, wbuff, dwrq->length, NULL, NULL, NULL); + ks_wlan_hw_tx(priv, wbuff, dwrq->length, NULL, NULL, NULL); return 0; } /*------------------------------------------------------------------*/ /* Private handler : read raw data form device */ -static int ks_wlan_data_read(struct net_device *dev, struct iw_request_info *info, - struct iw_point *dwrq, char *extra) +static int ks_wlan_data_read(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *dwrq, char *extra) { struct ks_wlan_private *priv = (struct ks_wlan_private *)dev->priv; unsigned short read_length; - if (priv->sleep_mode == SLP_SLEEP){ return -EPERM; } /* for SLEEP MODE */ - - if(!atomic_read(&priv->event_count)){ - if (priv->dev_state < DEVICE_STATE_BOOT) { /* Remove device */ - read_length = 4; - memset(extra,0xff,read_length); + if (priv->sleep_mode == SLP_SLEEP) { + return -EPERM; + } + /* for SLEEP MODE */ + if (!atomic_read(&priv->event_count)) { + if (priv->dev_state < DEVICE_STATE_BOOT) { /* Remove device */ + read_length = 4; + memset(extra, 0xff, read_length); dwrq->length = read_length; return 0; } read_length = 0; - memset(extra,0,1); + memset(extra, 0, 1); dwrq->length = 0; return 0; } - if(atomic_read(&priv->event_count)>0) - atomic_dec(&priv->event_count); + if (atomic_read(&priv->event_count) > 0) + atomic_dec(&priv->event_count); spin_lock(&priv->dev_read_lock); /* request spin lock */ - /* Copy length max size 0x07ff */ - if(priv->dev_size[priv->dev_count] > 2047) + /* Copy length max size 0x07ff */ + if (priv->dev_size[priv->dev_count] > 2047) read_length = 2047; else read_length = priv->dev_size[priv->dev_count]; @@ -2176,15 +2481,15 @@ static int ks_wlan_data_read(struct net_device *dev, struct iw_request_info *inf /* Copy data */ memcpy(extra, &(priv->dev_data[priv->dev_count][0]), read_length); - spin_unlock(&priv->dev_read_lock); /* release spin lock */ + spin_unlock(&priv->dev_read_lock); /* release spin lock */ /* Initialize */ priv->dev_data[priv->dev_count] = 0; priv->dev_size[priv->dev_count] = 0; priv->dev_count++; - if(priv->dev_count == DEVICE_STOCK_COUNT) - priv->dev_count=0; + if (priv->dev_count == DEVICE_STOCK_COUNT) + priv->dev_count = 0; /* Set read size */ dwrq->length = read_length; @@ -2197,150 +2502,180 @@ static int ks_wlan_data_read(struct net_device *dev, struct iw_request_info *inf /*------------------------------------------------------------------*/ /* Private handler : get wep string */ #define WEP_ASCII_BUFF_SIZE (17+64*4+1) -static int ks_wlan_get_wep_ascii(struct net_device *dev, struct iw_request_info *info, +static int ks_wlan_get_wep_ascii(struct net_device *dev, + struct iw_request_info *info, struct iw_point *dwrq, char *extra) { struct ks_wlan_private *priv = (struct ks_wlan_private *)dev->priv; - int i,j,len=0; + int i, j, len = 0; char tmp[WEP_ASCII_BUFF_SIZE]; - if (priv->sleep_mode == SLP_SLEEP){ return -EPERM; } /* for SLEEP MODE */ - - strcpy(tmp," WEP keys ASCII \n"); - len+=strlen(" WEP keys ASCII \n"); + if (priv->sleep_mode == SLP_SLEEP) { + return -EPERM; + } + /* for SLEEP MODE */ + strcpy(tmp, " WEP keys ASCII \n"); + len += strlen(" WEP keys ASCII \n"); - for(i=0;i<4;i++){ - strcpy(tmp+len,"\t["); - len+=strlen("\t["); - tmp[len] = '1'+i; + for (i = 0; i < 4; i++) { + strcpy(tmp + len, "\t["); + len += strlen("\t["); + tmp[len] = '1' + i; len++; - strcpy(tmp+len,"] "); - len+=strlen("] "); - if(priv->reg.wep_key[i].size){ - strcpy(tmp+len,(priv->reg.wep_key[i].size < 6 ? "(40bits) [" : "(104bits) [")); - len+=strlen((priv->reg.wep_key[i].size < 6 ? "(40bits) [" : "(104bits) [")); - for(j=0;jreg.wep_key[i].size;j++,len++) - tmp[len]=(isprint(priv->reg.wep_key[i].val[j]) ? priv->reg.wep_key[i].val[j] : ' '); - - strcpy(tmp+len,"]\n"); - len+=strlen("]\n"); - } - else{ - strcpy(tmp+len,"off\n"); - len+=strlen("off\n"); + strcpy(tmp + len, "] "); + len += strlen("] "); + if (priv->reg.wep_key[i].size) { + strcpy(tmp + len, + (priv->reg.wep_key[i].size < + 6 ? "(40bits) [" : "(104bits) [")); + len += + strlen((priv->reg.wep_key[i].size < + 6 ? "(40bits) [" : "(104bits) [")); + for (j = 0; j < priv->reg.wep_key[i].size; j++, len++) + tmp[len] = + (isprint(priv->reg.wep_key[i].val[j]) ? + priv->reg.wep_key[i].val[j] : ' '); + + strcpy(tmp + len, "]\n"); + len += strlen("]\n"); + } else { + strcpy(tmp + len, "off\n"); + len += strlen("off\n"); } } memcpy(extra, tmp, len); - dwrq->length = len+1; + dwrq->length = len + 1; return 0; } #endif /*------------------------------------------------------------------*/ /* Private handler : set beacon lost count */ -static int ks_wlan_set_beacon_lost(struct net_device *dev, struct iw_request_info *info, - __u32 *uwrq, char *extra) +static int ks_wlan_set_beacon_lost(struct net_device *dev, + struct iw_request_info *info, __u32 * uwrq, + char *extra) { - struct ks_wlan_private *priv = (struct ks_wlan_private *)netdev_priv(dev); + struct ks_wlan_private *priv = + (struct ks_wlan_private *)netdev_priv(dev); - if (priv->sleep_mode == SLP_SLEEP){ return -EPERM; } /* for SLEEP MODE */ - - if(*uwrq >= BEACON_LOST_COUNT_MIN && - *uwrq <= BEACON_LOST_COUNT_MAX){ + if (priv->sleep_mode == SLP_SLEEP) { + return -EPERM; + } + /* for SLEEP MODE */ + if (*uwrq >= BEACON_LOST_COUNT_MIN && *uwrq <= BEACON_LOST_COUNT_MAX) { priv->reg.beacon_lost_count = *uwrq; - }else - return -EINVAL; + } else + return -EINVAL; - if(priv->reg.operation_mode == MODE_INFRASTRUCTURE){ + if (priv->reg.operation_mode == MODE_INFRASTRUCTURE) { priv->need_commit |= SME_MODE_SET; - return -EINPROGRESS; /* Call commit handler */ - } - else + return -EINPROGRESS; /* Call commit handler */ + } else return 0; } /*------------------------------------------------------------------*/ /* Private handler : get beacon lost count */ -static int ks_wlan_get_beacon_lost(struct net_device *dev, struct iw_request_info *info, - __u32 *uwrq, char *extra) +static int ks_wlan_get_beacon_lost(struct net_device *dev, + struct iw_request_info *info, __u32 * uwrq, + char *extra) { - struct ks_wlan_private *priv = (struct ks_wlan_private *)netdev_priv(dev); - - if (priv->sleep_mode == SLP_SLEEP){ return -EPERM; } /* for SLEEP MODE */ + struct ks_wlan_private *priv = + (struct ks_wlan_private *)netdev_priv(dev); + if (priv->sleep_mode == SLP_SLEEP) { + return -EPERM; + } + /* for SLEEP MODE */ *uwrq = priv->reg.beacon_lost_count; return 0; } /*------------------------------------------------------------------*/ /* Private handler : set phy type */ -static int ks_wlan_set_phy_type(struct net_device *dev, struct iw_request_info *info, - __u32 *uwrq, char *extra) +static int ks_wlan_set_phy_type(struct net_device *dev, + struct iw_request_info *info, __u32 * uwrq, + char *extra) { - struct ks_wlan_private *priv = (struct ks_wlan_private *)netdev_priv(dev); + struct ks_wlan_private *priv = + (struct ks_wlan_private *)netdev_priv(dev); - if (priv->sleep_mode == SLP_SLEEP){ return -EPERM; } /* for SLEEP MODE */ - - if(*uwrq == D_11B_ONLY_MODE){ /* 0 */ + if (priv->sleep_mode == SLP_SLEEP) { + return -EPERM; + } + /* for SLEEP MODE */ + if (*uwrq == D_11B_ONLY_MODE) { /* 0 */ priv->reg.phy_type = D_11B_ONLY_MODE; - }else if(*uwrq == D_11G_ONLY_MODE){ /* 1 */ + } else if (*uwrq == D_11G_ONLY_MODE) { /* 1 */ priv->reg.phy_type = D_11G_ONLY_MODE; - }else if(*uwrq == D_11BG_COMPATIBLE_MODE){ /* 2 */ + } else if (*uwrq == D_11BG_COMPATIBLE_MODE) { /* 2 */ priv->reg.phy_type = D_11BG_COMPATIBLE_MODE; - }else - return -EINVAL; + } else + return -EINVAL; priv->need_commit |= SME_MODE_SET; - return -EINPROGRESS; /* Call commit handler */ + return -EINPROGRESS; /* Call commit handler */ } /*------------------------------------------------------------------*/ /* Private handler : get phy type */ -static int ks_wlan_get_phy_type(struct net_device *dev, struct iw_request_info *info, - __u32 *uwrq, char *extra) +static int ks_wlan_get_phy_type(struct net_device *dev, + struct iw_request_info *info, __u32 * uwrq, + char *extra) { - struct ks_wlan_private *priv = (struct ks_wlan_private *)netdev_priv(dev); - - if (priv->sleep_mode == SLP_SLEEP){ return -EPERM; } /* for SLEEP MODE */ + struct ks_wlan_private *priv = + (struct ks_wlan_private *)netdev_priv(dev); + if (priv->sleep_mode == SLP_SLEEP) { + return -EPERM; + } + /* for SLEEP MODE */ *uwrq = priv->reg.phy_type; return 0; } /*------------------------------------------------------------------*/ /* Private handler : set cts mode */ -static int ks_wlan_set_cts_mode(struct net_device *dev, struct iw_request_info *info, - __u32 *uwrq, char *extra) +static int ks_wlan_set_cts_mode(struct net_device *dev, + struct iw_request_info *info, __u32 * uwrq, + char *extra) { - struct ks_wlan_private *priv = (struct ks_wlan_private *)netdev_priv(dev); - - if (priv->sleep_mode == SLP_SLEEP){ return -EPERM; } /* for SLEEP MODE */ + struct ks_wlan_private *priv = + (struct ks_wlan_private *)netdev_priv(dev); - if(*uwrq == CTS_MODE_FALSE){ /* 0 */ + if (priv->sleep_mode == SLP_SLEEP) { + return -EPERM; + } + /* for SLEEP MODE */ + if (*uwrq == CTS_MODE_FALSE) { /* 0 */ priv->reg.cts_mode = CTS_MODE_FALSE; - }else if(*uwrq == CTS_MODE_TRUE){ /* 1 */ - if(priv->reg.phy_type == D_11G_ONLY_MODE || - priv->reg.phy_type == D_11BG_COMPATIBLE_MODE) + } else if (*uwrq == CTS_MODE_TRUE) { /* 1 */ + if (priv->reg.phy_type == D_11G_ONLY_MODE || + priv->reg.phy_type == D_11BG_COMPATIBLE_MODE) priv->reg.cts_mode = CTS_MODE_TRUE; else priv->reg.cts_mode = CTS_MODE_FALSE; - }else - return -EINVAL; + } else + return -EINVAL; priv->need_commit |= SME_MODE_SET; - return -EINPROGRESS; /* Call commit handler */ + return -EINPROGRESS; /* Call commit handler */ } /*------------------------------------------------------------------*/ /* Private handler : get cts mode */ -static int ks_wlan_get_cts_mode(struct net_device *dev, struct iw_request_info *info, - __u32 *uwrq, char *extra) +static int ks_wlan_get_cts_mode(struct net_device *dev, + struct iw_request_info *info, __u32 * uwrq, + char *extra) { - struct ks_wlan_private *priv = (struct ks_wlan_private *)netdev_priv(dev); - - if (priv->sleep_mode == SLP_SLEEP){ return -EPERM; } /* for SLEEP MODE */ + struct ks_wlan_private *priv = + (struct ks_wlan_private *)netdev_priv(dev); + if (priv->sleep_mode == SLP_SLEEP) { + return -EPERM; + } + /* for SLEEP MODE */ *uwrq = priv->reg.cts_mode; return 0; } @@ -2348,38 +2683,41 @@ static int ks_wlan_get_cts_mode(struct net_device *dev, struct iw_request_info * /*------------------------------------------------------------------*/ /* Private handler : set sleep mode */ static int ks_wlan_set_sleep_mode(struct net_device *dev, - struct iw_request_info *info, - __u32 *uwrq, char *extra) + struct iw_request_info *info, + __u32 * uwrq, char *extra) { - struct ks_wlan_private *priv = (struct ks_wlan_private *)netdev_priv(dev); + struct ks_wlan_private *priv = + (struct ks_wlan_private *)netdev_priv(dev); - DPRINTK(2,"\n"); + DPRINTK(2, "\n"); - if(*uwrq == SLP_SLEEP){ + if (*uwrq == SLP_SLEEP) { priv->sleep_mode = *uwrq; printk("SET_SLEEP_MODE %d\n", priv->sleep_mode); hostif_sme_enqueue(priv, SME_STOP_REQUEST); hostif_sme_enqueue(priv, SME_SLEEP_REQUEST); - }else if(*uwrq == SLP_ACTIVE) { + } else if (*uwrq == SLP_ACTIVE) { priv->sleep_mode = *uwrq; printk("SET_SLEEP_MODE %d\n", priv->sleep_mode); hostif_sme_enqueue(priv, SME_SLEEP_REQUEST); - }else{ + } else { printk("SET_SLEEP_MODE %d errror\n", *uwrq); - return -EINVAL; + return -EINVAL; } return 0; } + /*------------------------------------------------------------------*/ /* Private handler : get sleep mode */ static int ks_wlan_get_sleep_mode(struct net_device *dev, - struct iw_request_info *info, - __u32 *uwrq, char *extra) + struct iw_request_info *info, + __u32 * uwrq, char *extra) { - struct ks_wlan_private *priv = (struct ks_wlan_private *)netdev_priv(dev); + struct ks_wlan_private *priv = + (struct ks_wlan_private *)netdev_priv(dev); DPRINTK(2, "GET_SLEEP_MODE %d\n", priv->sleep_mode); *uwrq = priv->sleep_mode; @@ -2390,17 +2728,20 @@ static int ks_wlan_get_sleep_mode(struct net_device *dev, #if 0 /*------------------------------------------------------------------*/ /* Private handler : set phy information timer */ -static int ks_wlan_set_phy_information_timer(struct net_device *dev, struct iw_request_info *info, - __u32 *uwrq, char *extra) +static int ks_wlan_set_phy_information_timer(struct net_device *dev, + struct iw_request_info *info, + __u32 * uwrq, char *extra) { struct ks_wlan_private *priv = (struct ks_wlan_private *)dev->priv; - if (priv->sleep_mode == SLP_SLEEP){ return -EPERM; } /* for SLEEP MODE */ - - if(*uwrq >= 0 && *uwrq <= 0xFFFF) /* 0-65535 */ - priv->reg.phy_info_timer = (uint16_t)*uwrq; + if (priv->sleep_mode == SLP_SLEEP) { + return -EPERM; + } + /* for SLEEP MODE */ + if (*uwrq >= 0 && *uwrq <= 0xFFFF) /* 0-65535 */ + priv->reg.phy_info_timer = (uint16_t) * uwrq; else - return -EINVAL; + return -EINVAL; hostif_sme_enqueue(priv, SME_PHY_INFO_REQUEST); @@ -2409,13 +2750,16 @@ static int ks_wlan_set_phy_information_timer(struct net_device *dev, struct iw_r /*------------------------------------------------------------------*/ /* Private handler : get phy information timer */ -static int ks_wlan_get_phy_information_timer(struct net_device *dev, struct iw_request_info *info, - __u32 *uwrq, char *extra) +static int ks_wlan_get_phy_information_timer(struct net_device *dev, + struct iw_request_info *info, + __u32 * uwrq, char *extra) { struct ks_wlan_private *priv = (struct ks_wlan_private *)dev->priv; - if (priv->sleep_mode == SLP_SLEEP){ return -EPERM; } /* for SLEEP MODE */ - + if (priv->sleep_mode == SLP_SLEEP) { + return -EPERM; + } + /* for SLEEP MODE */ *uwrq = priv->reg.phy_info_timer; return 0; } @@ -2424,38 +2768,48 @@ static int ks_wlan_get_phy_information_timer(struct net_device *dev, struct iw_r #ifdef WPS /*------------------------------------------------------------------*/ /* Private handler : set WPS enable */ -static int ks_wlan_set_wps_enable(struct net_device *dev, struct iw_request_info *info, - __u32 *uwrq, char *extra) +static int ks_wlan_set_wps_enable(struct net_device *dev, + struct iw_request_info *info, __u32 * uwrq, + char *extra) { - struct ks_wlan_private *priv = (struct ks_wlan_private *)netdev_priv(dev); - DPRINTK(2,"\n"); - - if (priv->sleep_mode == SLP_SLEEP){ return -EPERM; } /* for SLEEP MODE */ + struct ks_wlan_private *priv = + (struct ks_wlan_private *)netdev_priv(dev); + DPRINTK(2, "\n"); - if(*uwrq == 0 || *uwrq == 1) + if (priv->sleep_mode == SLP_SLEEP) { + return -EPERM; + } + /* for SLEEP MODE */ + if (*uwrq == 0 || *uwrq == 1) priv->wps.wps_enabled = *uwrq; else - return -EINVAL; + return -EINVAL; hostif_sme_enqueue(priv, SME_WPS_ENABLE_REQUEST); return 0; } + /*------------------------------------------------------------------*/ /* Private handler : get WPS enable */ -static int ks_wlan_get_wps_enable(struct net_device *dev, struct iw_request_info *info, - __u32 *uwrq, char *extra) +static int ks_wlan_get_wps_enable(struct net_device *dev, + struct iw_request_info *info, __u32 * uwrq, + char *extra) { - struct ks_wlan_private *priv = (struct ks_wlan_private *)netdev_priv(dev); - DPRINTK(2,"\n"); - - if (priv->sleep_mode == SLP_SLEEP){ return -EPERM; } /* for SLEEP MODE */ + struct ks_wlan_private *priv = + (struct ks_wlan_private *)netdev_priv(dev); + DPRINTK(2, "\n"); + if (priv->sleep_mode == SLP_SLEEP) { + return -EPERM; + } + /* for SLEEP MODE */ *uwrq = priv->wps.wps_enabled; printk("return=%d\n", *uwrq); return 0; } + /*------------------------------------------------------------------*/ /* Private handler : set WPS probe req */ static int ks_wlan_set_wps_probe_req(struct net_device *dev, @@ -2464,45 +2818,52 @@ static int ks_wlan_set_wps_probe_req(struct net_device *dev, { uint8_t *p = extra; unsigned char len; - struct ks_wlan_private *priv = (struct ks_wlan_private *)netdev_priv(dev); - - DPRINTK(2,"\n"); + struct ks_wlan_private *priv = + (struct ks_wlan_private *)netdev_priv(dev); - if (priv->sleep_mode == SLP_SLEEP){ return -EPERM; } /* for SLEEP MODE */ + DPRINTK(2, "\n"); - DPRINTK(2,"dwrq->length=%d\n", dwrq->length); + if (priv->sleep_mode == SLP_SLEEP) { + return -EPERM; + } + /* for SLEEP MODE */ + DPRINTK(2, "dwrq->length=%d\n", dwrq->length); /* length check */ - if(p[1] + 2 != dwrq->length || dwrq->length > 256 ){ + if (p[1] + 2 != dwrq->length || dwrq->length > 256) { return -EINVAL; } - priv->wps.ielen = p[1] + 2 + 1; /* IE header + IE + sizeof(len) */ - len = p[1] + 2; /* IE header + IE */ + priv->wps.ielen = p[1] + 2 + 1; /* IE header + IE + sizeof(len) */ + len = p[1] + 2; /* IE header + IE */ memcpy(priv->wps.ie, &len, sizeof(len)); - p = memcpy(priv->wps.ie+1, p, len); + p = memcpy(priv->wps.ie + 1, p, len); - DPRINTK(2,"%d(%#x): %02X %02X %02X %02X ... %02X %02X %02X\n", + DPRINTK(2, "%d(%#x): %02X %02X %02X %02X ... %02X %02X %02X\n", priv->wps.ielen, priv->wps.ielen, p[0], p[1], p[2], p[3], - p[priv->wps.ielen-3], p[priv->wps.ielen-2], p[priv->wps.ielen-1]); + p[priv->wps.ielen - 3], p[priv->wps.ielen - 2], + p[priv->wps.ielen - 1]); hostif_sme_enqueue(priv, SME_WPS_PROBE_REQUEST); return 0; } + #if 0 /*------------------------------------------------------------------*/ /* Private handler : get WPS probe req */ static int ks_wlan_get_wps_probe_req(struct net_device *dev, struct iw_request_info *info, - __u32 *uwrq, char *extra) + __u32 * uwrq, char *extra) { struct ks_wlan_private *priv = (struct ks_wlan_private *)dev->priv; - DPRINTK(2,"\n"); - - if (priv->sleep_mode == SLP_SLEEP){ return -EPERM; } /* for SLEEP MODE */ + DPRINTK(2, "\n"); + if (priv->sleep_mode == SLP_SLEEP) { + return -EPERM; + } + /* for SLEEP MODE */ return 0; } #endif @@ -2510,37 +2871,44 @@ static int ks_wlan_get_wps_probe_req(struct net_device *dev, /*------------------------------------------------------------------*/ /* Private handler : set tx gain control value */ -static int ks_wlan_set_tx_gain(struct net_device *dev, struct iw_request_info *info, - __u32 *uwrq, char *extra) +static int ks_wlan_set_tx_gain(struct net_device *dev, + struct iw_request_info *info, __u32 * uwrq, + char *extra) { - struct ks_wlan_private *priv = (struct ks_wlan_private *)netdev_priv(dev); + struct ks_wlan_private *priv = + (struct ks_wlan_private *)netdev_priv(dev); - if (priv->sleep_mode == SLP_SLEEP){ return -EPERM; } /* for SLEEP MODE */ - - if(*uwrq >= 0 && *uwrq <= 0xFF) /* 0-255 */ - priv->gain.TxGain = (uint8_t)*uwrq; + if (priv->sleep_mode == SLP_SLEEP) { + return -EPERM; + } + /* for SLEEP MODE */ + if (*uwrq >= 0 && *uwrq <= 0xFF) /* 0-255 */ + priv->gain.TxGain = (uint8_t) * uwrq; else - return -EINVAL; + return -EINVAL; - if(priv->gain.TxGain < 0xFF) + if (priv->gain.TxGain < 0xFF) priv->gain.TxMode = 1; else priv->gain.TxMode = 0; - hostif_sme_enqueue(priv, SME_SET_GAIN); - return 0; + return 0; } /*------------------------------------------------------------------*/ /* Private handler : get tx gain control value */ -static int ks_wlan_get_tx_gain(struct net_device *dev, struct iw_request_info *info, - __u32 *uwrq, char *extra) +static int ks_wlan_get_tx_gain(struct net_device *dev, + struct iw_request_info *info, __u32 * uwrq, + char *extra) { - struct ks_wlan_private *priv = (struct ks_wlan_private *)netdev_priv(dev); - - if (priv->sleep_mode == SLP_SLEEP){ return -EPERM; } /* for SLEEP MODE */ + struct ks_wlan_private *priv = + (struct ks_wlan_private *)netdev_priv(dev); + if (priv->sleep_mode == SLP_SLEEP) { + return -EPERM; + } + /* for SLEEP MODE */ *uwrq = priv->gain.TxGain; hostif_sme_enqueue(priv, SME_GET_GAIN); return 0; @@ -2548,180 +2916,195 @@ static int ks_wlan_get_tx_gain(struct net_device *dev, struct iw_request_info *i /*------------------------------------------------------------------*/ /* Private handler : set rx gain control value */ -static int ks_wlan_set_rx_gain(struct net_device *dev, struct iw_request_info *info, - __u32 *uwrq, char *extra) +static int ks_wlan_set_rx_gain(struct net_device *dev, + struct iw_request_info *info, __u32 * uwrq, + char *extra) { - struct ks_wlan_private *priv = (struct ks_wlan_private *)netdev_priv(dev); + struct ks_wlan_private *priv = + (struct ks_wlan_private *)netdev_priv(dev); - if (priv->sleep_mode == SLP_SLEEP){ return -EPERM; } /* for SLEEP MODE */ - - if(*uwrq >= 0 && *uwrq <= 0xFF) /* 0-255 */ - priv->gain.RxGain = (uint8_t)*uwrq; + if (priv->sleep_mode == SLP_SLEEP) { + return -EPERM; + } + /* for SLEEP MODE */ + if (*uwrq >= 0 && *uwrq <= 0xFF) /* 0-255 */ + priv->gain.RxGain = (uint8_t) * uwrq; else - return -EINVAL; + return -EINVAL; - if(priv->gain.RxGain < 0xFF) + if (priv->gain.RxGain < 0xFF) priv->gain.RxMode = 1; else priv->gain.RxMode = 0; hostif_sme_enqueue(priv, SME_SET_GAIN); - return 0; + return 0; } /*------------------------------------------------------------------*/ /* Private handler : get rx gain control value */ -static int ks_wlan_get_rx_gain(struct net_device *dev, struct iw_request_info *info, - __u32 *uwrq, char *extra) +static int ks_wlan_get_rx_gain(struct net_device *dev, + struct iw_request_info *info, __u32 * uwrq, + char *extra) { - struct ks_wlan_private *priv = (struct ks_wlan_private *)netdev_priv(dev); - - if (priv->sleep_mode == SLP_SLEEP){ return -EPERM; } /* for SLEEP MODE */ + struct ks_wlan_private *priv = + (struct ks_wlan_private *)netdev_priv(dev); + if (priv->sleep_mode == SLP_SLEEP) { + return -EPERM; + } + /* for SLEEP MODE */ *uwrq = priv->gain.RxGain; hostif_sme_enqueue(priv, SME_GET_GAIN); return 0; } + #if 0 /*------------------------------------------------------------------*/ /* Private handler : set region value */ -static int ks_wlan_set_region(struct net_device *dev, struct iw_request_info *info, - __u32 *uwrq, char *extra) +static int ks_wlan_set_region(struct net_device *dev, + struct iw_request_info *info, __u32 * uwrq, + char *extra) { struct ks_wlan_private *priv = (struct ks_wlan_private *)dev->priv; - if (priv->sleep_mode == SLP_SLEEP){ return -EPERM; } /* for SLEEP MODE */ - - if(*uwrq >= 0x9 && *uwrq <= 0xF) /* 0x9-0xf */ - priv->region = (uint8_t)*uwrq; + if (priv->sleep_mode == SLP_SLEEP) { + return -EPERM; + } + /* for SLEEP MODE */ + if (*uwrq >= 0x9 && *uwrq <= 0xF) /* 0x9-0xf */ + priv->region = (uint8_t) * uwrq; else - return -EINVAL; + return -EINVAL; hostif_sme_enqueue(priv, SME_SET_REGION); - return 0; + return 0; } #endif /*------------------------------------------------------------------*/ /* Private handler : get eeprom checksum result */ -static int ks_wlan_get_eeprom_cksum(struct net_device *dev, struct iw_request_info *info, - __u32 *uwrq, char *extra) +static int ks_wlan_get_eeprom_cksum(struct net_device *dev, + struct iw_request_info *info, __u32 * uwrq, + char *extra) { - struct ks_wlan_private *priv = (struct ks_wlan_private *)netdev_priv(dev); + struct ks_wlan_private *priv = + (struct ks_wlan_private *)netdev_priv(dev); *uwrq = priv->eeprom_checksum; return 0; } -static void print_hif_event(int event){ +static void print_hif_event(int event) +{ - switch(event){ - case HIF_DATA_REQ : + switch (event) { + case HIF_DATA_REQ: printk("HIF_DATA_REQ\n"); break; - case HIF_DATA_IND : + case HIF_DATA_IND: printk("HIF_DATA_IND\n"); break; - case HIF_MIB_GET_REQ : + case HIF_MIB_GET_REQ: printk("HIF_MIB_GET_REQ\n"); break; - case HIF_MIB_GET_CONF : + case HIF_MIB_GET_CONF: printk("HIF_MIB_GET_CONF\n"); break; - case HIF_MIB_SET_REQ : + case HIF_MIB_SET_REQ: printk("HIF_MIB_SET_REQ\n"); break; - case HIF_MIB_SET_CONF : + case HIF_MIB_SET_CONF: printk("HIF_MIB_SET_CONF\n"); break; - case HIF_POWERMGT_REQ : + case HIF_POWERMGT_REQ: printk("HIF_POWERMGT_REQ\n"); break; - case HIF_POWERMGT_CONF : + case HIF_POWERMGT_CONF: printk("HIF_POWERMGT_CONF\n"); break; - case HIF_START_REQ : + case HIF_START_REQ: printk("HIF_START_REQ\n"); break; - case HIF_START_CONF : + case HIF_START_CONF: printk("HIF_START_CONF\n"); break; - case HIF_CONNECT_IND : + case HIF_CONNECT_IND: printk("HIF_CONNECT_IND\n"); break; - case HIF_STOP_REQ : + case HIF_STOP_REQ: printk("HIF_STOP_REQ\n"); break; - case HIF_STOP_CONF : + case HIF_STOP_CONF: printk("HIF_STOP_CONF\n"); break; - case HIF_PS_ADH_SET_REQ : + case HIF_PS_ADH_SET_REQ: printk("HIF_PS_ADH_SET_REQ\n"); break; case HIF_PS_ADH_SET_CONF: printk("HIF_PS_ADH_SET_CONF\n"); break; - case HIF_INFRA_SET_REQ : + case HIF_INFRA_SET_REQ: printk("HIF_INFRA_SET_REQ\n"); break; - case HIF_INFRA_SET_CONF : + case HIF_INFRA_SET_CONF: printk("HIF_INFRA_SET_CONF\n"); break; - case HIF_ADH_SET_REQ : + case HIF_ADH_SET_REQ: printk("HIF_ADH_SET_REQ\n"); break; - case HIF_ADH_SET_CONF : + case HIF_ADH_SET_CONF: printk("HIF_ADH_SET_CONF\n"); break; - case HIF_AP_SET_REQ : + case HIF_AP_SET_REQ: printk("HIF_AP_SET_REQ\n"); break; - case HIF_AP_SET_CONF : + case HIF_AP_SET_CONF: printk("HIF_AP_SET_CONF\n"); break; - case HIF_ASSOC_INFO_IND : + case HIF_ASSOC_INFO_IND: printk("HIF_ASSOC_INFO_IND\n"); break; case HIF_MIC_FAILURE_REQ: printk("HIF_MIC_FAILURE_REQ\n"); break; - case HIF_MIC_FAILURE_CONF : + case HIF_MIC_FAILURE_CONF: printk("HIF_MIC_FAILURE_CONF\n"); break; - case HIF_SCAN_REQ : + case HIF_SCAN_REQ: printk("HIF_SCAN_REQ\n"); break; - case HIF_SCAN_CONF : + case HIF_SCAN_CONF: printk("HIF_SCAN_CONF\n"); break; - case HIF_PHY_INFO_REQ : + case HIF_PHY_INFO_REQ: printk("HIF_PHY_INFO_REQ\n"); break; - case HIF_PHY_INFO_CONF : + case HIF_PHY_INFO_CONF: printk("HIF_PHY_INFO_CONF\n"); break; - case HIF_SLEEP_REQ : + case HIF_SLEEP_REQ: printk("HIF_SLEEP_REQ\n"); break; - case HIF_SLEEP_CONF : + case HIF_SLEEP_CONF: printk("HIF_SLEEP_CONF\n"); break; - case HIF_PHY_INFO_IND : + case HIF_PHY_INFO_IND: printk("HIF_PHY_INFO_IND\n"); break; - case HIF_SCAN_IND : + case HIF_SCAN_IND: printk("HIF_SCAN_IND\n"); break; - case HIF_INFRA_SET2_REQ : + case HIF_INFRA_SET2_REQ: printk("HIF_INFRA_SET2_REQ\n"); break; case HIF_INFRA_SET2_CONF: printk("HIF_INFRA_SET2_CONF\n"); break; - case HIF_ADH_SET2_REQ : + case HIF_ADH_SET2_REQ: printk("HIF_ADH_SET2_REQ\n"); break; - case HIF_ADH_SET2_CONF : + case HIF_ADH_SET2_CONF: printk("HIF_ADH_SET2_CONF\n"); } } @@ -2729,13 +3112,16 @@ static void print_hif_event(int event){ /*------------------------------------------------------------------*/ /* Private handler : get host command history */ static int ks_wlan_hostt(struct net_device *dev, struct iw_request_info *info, - __u32 *uwrq, char *extra) + __u32 * uwrq, char *extra) { - int i,event; - struct ks_wlan_private *priv = (struct ks_wlan_private *)netdev_priv(dev); + int i, event; + struct ks_wlan_private *priv = + (struct ks_wlan_private *)netdev_priv(dev); - for(i = 63; i >= 0; i--){ - event = priv->hostt.buff[(priv->hostt.qtail -1 -i)%SME_EVENT_BUFF_SIZE] ; + for (i = 63; i >= 0; i--) { + event = + priv->hostt.buff[(priv->hostt.qtail - 1 - i) % + SME_EVENT_BUFF_SIZE]; print_hif_event(event); } return 0; @@ -2745,190 +3131,213 @@ static int ks_wlan_hostt(struct net_device *dev, struct iw_request_info *info, static const struct iw_priv_args ks_wlan_private_args[] = { /*{ cmd, set_args, get_args, name[16] } */ - { KS_WLAN_GET_DRIVER_VERSION, IW_PRIV_TYPE_NONE, IW_PRIV_TYPE_CHAR | (128+1), "GetDriverVer" }, - { KS_WLAN_GET_FIRM_VERSION, IW_PRIV_TYPE_NONE, IW_PRIV_TYPE_CHAR | (128+1), "GetFirmwareVer" }, + {KS_WLAN_GET_DRIVER_VERSION, IW_PRIV_TYPE_NONE, + IW_PRIV_TYPE_CHAR | (128 + 1), "GetDriverVer"}, + {KS_WLAN_GET_FIRM_VERSION, IW_PRIV_TYPE_NONE, + IW_PRIV_TYPE_CHAR | (128 + 1), "GetFirmwareVer"}, #ifdef WPS - { KS_WLAN_SET_WPS_ENABLE, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, IW_PRIV_TYPE_NONE, "SetWPSEnable" }, - { KS_WLAN_GET_WPS_ENABLE, IW_PRIV_TYPE_NONE, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "GetW" }, - { KS_WLAN_SET_WPS_PROBE_REQ, IW_PRIV_TYPE_BYTE | 2047, IW_PRIV_TYPE_NONE, "SetWPSProbeReq" }, + {KS_WLAN_SET_WPS_ENABLE, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + IW_PRIV_TYPE_NONE, "SetWPSEnable"}, + {KS_WLAN_GET_WPS_ENABLE, IW_PRIV_TYPE_NONE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "GetW"}, + {KS_WLAN_SET_WPS_PROBE_REQ, IW_PRIV_TYPE_BYTE | 2047, IW_PRIV_TYPE_NONE, + "SetWPSProbeReq"}, #endif /* WPS */ - { KS_WLAN_SET_PREAMBLE, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, IW_PRIV_TYPE_NONE, "SetPreamble" }, - { KS_WLAN_GET_PREAMBLE, IW_PRIV_TYPE_NONE, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "GetPreamble" }, - { KS_WLAN_SET_POWER_SAVE, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, IW_PRIV_TYPE_NONE, "SetPowerSave" }, - { KS_WLAN_GET_POWER_SAVE, IW_PRIV_TYPE_NONE, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "GetPowerSave" }, - { KS_WLAN_SET_SCAN_TYPE, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, IW_PRIV_TYPE_NONE, "SetScanType" }, - { KS_WLAN_GET_SCAN_TYPE, IW_PRIV_TYPE_NONE, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "GetScanType" }, - { KS_WLAN_SET_RX_GAIN, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, IW_PRIV_TYPE_NONE, "SetRxGain" }, - { KS_WLAN_GET_RX_GAIN, IW_PRIV_TYPE_NONE, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "GetRxGain" }, - { KS_WLAN_HOSTT, IW_PRIV_TYPE_NONE, IW_PRIV_TYPE_CHAR | (128+1), "hostt" }, - { KS_WLAN_SET_BEACON_LOST, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, IW_PRIV_TYPE_NONE, "SetBeaconLost" }, - { KS_WLAN_GET_BEACON_LOST, IW_PRIV_TYPE_NONE, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "GetBeaconLost" }, - { KS_WLAN_SET_SLEEP_MODE, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, IW_PRIV_TYPE_NONE, "SetSleepMode" }, - { KS_WLAN_GET_SLEEP_MODE, IW_PRIV_TYPE_NONE, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "GetSleepMode" }, - { KS_WLAN_SET_TX_GAIN, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, IW_PRIV_TYPE_NONE, "SetTxGain" }, - { KS_WLAN_GET_TX_GAIN, IW_PRIV_TYPE_NONE, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "GetTxGain" }, - { KS_WLAN_SET_PHY_TYPE, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, IW_PRIV_TYPE_NONE, "SetPhyType" }, - { KS_WLAN_GET_PHY_TYPE, IW_PRIV_TYPE_NONE, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "GetPhyType" }, - { KS_WLAN_SET_CTS_MODE, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, IW_PRIV_TYPE_NONE, "SetCtsMode" }, - { KS_WLAN_GET_CTS_MODE, IW_PRIV_TYPE_NONE, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "GetCtsMode" }, - { KS_WLAN_GET_EEPROM_CKSUM, IW_PRIV_TYPE_NONE, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "GetChecksum" }, + {KS_WLAN_SET_PREAMBLE, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + IW_PRIV_TYPE_NONE, "SetPreamble"}, + {KS_WLAN_GET_PREAMBLE, IW_PRIV_TYPE_NONE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "GetPreamble"}, + {KS_WLAN_SET_POWER_SAVE, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + IW_PRIV_TYPE_NONE, "SetPowerSave"}, + {KS_WLAN_GET_POWER_SAVE, IW_PRIV_TYPE_NONE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "GetPowerSave"}, + {KS_WLAN_SET_SCAN_TYPE, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + IW_PRIV_TYPE_NONE, "SetScanType"}, + {KS_WLAN_GET_SCAN_TYPE, IW_PRIV_TYPE_NONE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "GetScanType"}, + {KS_WLAN_SET_RX_GAIN, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + IW_PRIV_TYPE_NONE, "SetRxGain"}, + {KS_WLAN_GET_RX_GAIN, IW_PRIV_TYPE_NONE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "GetRxGain"}, + {KS_WLAN_HOSTT, IW_PRIV_TYPE_NONE, IW_PRIV_TYPE_CHAR | (128 + 1), + "hostt"}, + {KS_WLAN_SET_BEACON_LOST, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + IW_PRIV_TYPE_NONE, "SetBeaconLost"}, + {KS_WLAN_GET_BEACON_LOST, IW_PRIV_TYPE_NONE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "GetBeaconLost"}, + {KS_WLAN_SET_SLEEP_MODE, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + IW_PRIV_TYPE_NONE, "SetSleepMode"}, + {KS_WLAN_GET_SLEEP_MODE, IW_PRIV_TYPE_NONE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "GetSleepMode"}, + {KS_WLAN_SET_TX_GAIN, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + IW_PRIV_TYPE_NONE, "SetTxGain"}, + {KS_WLAN_GET_TX_GAIN, IW_PRIV_TYPE_NONE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "GetTxGain"}, + {KS_WLAN_SET_PHY_TYPE, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + IW_PRIV_TYPE_NONE, "SetPhyType"}, + {KS_WLAN_GET_PHY_TYPE, IW_PRIV_TYPE_NONE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "GetPhyType"}, + {KS_WLAN_SET_CTS_MODE, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + IW_PRIV_TYPE_NONE, "SetCtsMode"}, + {KS_WLAN_GET_CTS_MODE, IW_PRIV_TYPE_NONE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "GetCtsMode"}, + {KS_WLAN_GET_EEPROM_CKSUM, IW_PRIV_TYPE_NONE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "GetChecksum"}, }; -static const iw_handler ks_wlan_handler[] = -{ + +static const iw_handler ks_wlan_handler[] = { (iw_handler) ks_wlan_config_commit, /* SIOCSIWCOMMIT */ - (iw_handler) ks_wlan_get_name, /* SIOCGIWNAME */ - (iw_handler) NULL, /* SIOCSIWNWID */ - (iw_handler) NULL, /* SIOCGIWNWID */ - (iw_handler) ks_wlan_set_freq, /* SIOCSIWFREQ */ - (iw_handler) ks_wlan_get_freq, /* SIOCGIWFREQ */ - (iw_handler) ks_wlan_set_mode, /* SIOCSIWMODE */ - (iw_handler) ks_wlan_get_mode, /* SIOCGIWMODE */ + (iw_handler) ks_wlan_get_name, /* SIOCGIWNAME */ + (iw_handler) NULL, /* SIOCSIWNWID */ + (iw_handler) NULL, /* SIOCGIWNWID */ + (iw_handler) ks_wlan_set_freq, /* SIOCSIWFREQ */ + (iw_handler) ks_wlan_get_freq, /* SIOCGIWFREQ */ + (iw_handler) ks_wlan_set_mode, /* SIOCSIWMODE */ + (iw_handler) ks_wlan_get_mode, /* SIOCGIWMODE */ #ifndef KSC_OPNOTSUPP - (iw_handler) ks_wlan_set_sens, /* SIOCSIWSENS */ - (iw_handler) ks_wlan_get_sens, /* SIOCGIWSENS */ + (iw_handler) ks_wlan_set_sens, /* SIOCSIWSENS */ + (iw_handler) ks_wlan_get_sens, /* SIOCGIWSENS */ #else /* KSC_OPNOTSUPP */ - (iw_handler) NULL, /* SIOCSIWSENS */ - (iw_handler) NULL, /* SIOCGIWSENS */ + (iw_handler) NULL, /* SIOCSIWSENS */ + (iw_handler) NULL, /* SIOCGIWSENS */ #endif /* KSC_OPNOTSUPP */ - (iw_handler) NULL, /* SIOCSIWRANGE */ - (iw_handler) ks_wlan_get_range, /* SIOCGIWRANGE */ - (iw_handler) NULL, /* SIOCSIWPRIV */ - (iw_handler) NULL, /* SIOCGIWPRIV */ - (iw_handler) NULL, /* SIOCSIWSTATS */ + (iw_handler) NULL, /* SIOCSIWRANGE */ + (iw_handler) ks_wlan_get_range, /* SIOCGIWRANGE */ + (iw_handler) NULL, /* SIOCSIWPRIV */ + (iw_handler) NULL, /* SIOCGIWPRIV */ + (iw_handler) NULL, /* SIOCSIWSTATS */ (iw_handler) ks_wlan_get_iwstats, /* SIOCGIWSTATS */ - (iw_handler) NULL, /* SIOCSIWSPY */ - (iw_handler) NULL, /* SIOCGIWSPY */ - (iw_handler) NULL, /* SIOCSIWTHRSPY */ - (iw_handler) NULL, /* SIOCGIWTHRSPY */ - (iw_handler) ks_wlan_set_wap, /* SIOCSIWAP */ - (iw_handler) ks_wlan_get_wap, /* SIOCGIWAP */ -// (iw_handler) NULL, /* SIOCSIWMLME */ - (iw_handler) ks_wlan_set_mlme, /* SIOCSIWMLME */ + (iw_handler) NULL, /* SIOCSIWSPY */ + (iw_handler) NULL, /* SIOCGIWSPY */ + (iw_handler) NULL, /* SIOCSIWTHRSPY */ + (iw_handler) NULL, /* SIOCGIWTHRSPY */ + (iw_handler) ks_wlan_set_wap, /* SIOCSIWAP */ + (iw_handler) ks_wlan_get_wap, /* SIOCGIWAP */ +// (iw_handler) NULL, /* SIOCSIWMLME */ + (iw_handler) ks_wlan_set_mlme, /* SIOCSIWMLME */ (iw_handler) ks_wlan_get_aplist, /* SIOCGIWAPLIST */ - (iw_handler) ks_wlan_set_scan, /* SIOCSIWSCAN */ - (iw_handler) ks_wlan_get_scan, /* SIOCGIWSCAN */ - (iw_handler) ks_wlan_set_essid, /* SIOCSIWESSID */ - (iw_handler) ks_wlan_get_essid, /* SIOCGIWESSID */ - (iw_handler) ks_wlan_set_nick, /* SIOCSIWNICKN */ - (iw_handler) ks_wlan_get_nick, /* SIOCGIWNICKN */ - (iw_handler) NULL, /* -- hole -- */ - (iw_handler) NULL, /* -- hole -- */ - (iw_handler) ks_wlan_set_rate, /* SIOCSIWRATE */ - (iw_handler) ks_wlan_get_rate, /* SIOCGIWRATE */ - (iw_handler) ks_wlan_set_rts, /* SIOCSIWRTS */ - (iw_handler) ks_wlan_get_rts, /* SIOCGIWRTS */ - (iw_handler) ks_wlan_set_frag, /* SIOCSIWFRAG */ - (iw_handler) ks_wlan_get_frag, /* SIOCGIWFRAG */ + (iw_handler) ks_wlan_set_scan, /* SIOCSIWSCAN */ + (iw_handler) ks_wlan_get_scan, /* SIOCGIWSCAN */ + (iw_handler) ks_wlan_set_essid, /* SIOCSIWESSID */ + (iw_handler) ks_wlan_get_essid, /* SIOCGIWESSID */ + (iw_handler) ks_wlan_set_nick, /* SIOCSIWNICKN */ + (iw_handler) ks_wlan_get_nick, /* SIOCGIWNICKN */ + (iw_handler) NULL, /* -- hole -- */ + (iw_handler) NULL, /* -- hole -- */ + (iw_handler) ks_wlan_set_rate, /* SIOCSIWRATE */ + (iw_handler) ks_wlan_get_rate, /* SIOCGIWRATE */ + (iw_handler) ks_wlan_set_rts, /* SIOCSIWRTS */ + (iw_handler) ks_wlan_get_rts, /* SIOCGIWRTS */ + (iw_handler) ks_wlan_set_frag, /* SIOCSIWFRAG */ + (iw_handler) ks_wlan_get_frag, /* SIOCGIWFRAG */ #ifndef KSC_OPNOTSUPP - (iw_handler) ks_wlan_set_txpow, /* SIOCSIWTXPOW */ - (iw_handler) ks_wlan_get_txpow, /* SIOCGIWTXPOW */ - (iw_handler) ks_wlan_set_retry, /* SIOCSIWRETRY */ - (iw_handler) ks_wlan_get_retry, /* SIOCGIWRETRY */ + (iw_handler) ks_wlan_set_txpow, /* SIOCSIWTXPOW */ + (iw_handler) ks_wlan_get_txpow, /* SIOCGIWTXPOW */ + (iw_handler) ks_wlan_set_retry, /* SIOCSIWRETRY */ + (iw_handler) ks_wlan_get_retry, /* SIOCGIWRETRY */ #else /* KSC_OPNOTSUPP */ - (iw_handler) NULL, /* SIOCSIWTXPOW */ - (iw_handler) NULL, /* SIOCGIWTXPOW */ - (iw_handler) NULL, /* SIOCSIWRETRY */ - (iw_handler) NULL, /* SIOCGIWRETRY */ + (iw_handler) NULL, /* SIOCSIWTXPOW */ + (iw_handler) NULL, /* SIOCGIWTXPOW */ + (iw_handler) NULL, /* SIOCSIWRETRY */ + (iw_handler) NULL, /* SIOCGIWRETRY */ #endif /* KSC_OPNOTSUPP */ (iw_handler) ks_wlan_set_encode, /* SIOCSIWENCODE */ (iw_handler) ks_wlan_get_encode, /* SIOCGIWENCODE */ - (iw_handler) ks_wlan_set_power, /* SIOCSIWPOWER */ - (iw_handler) ks_wlan_get_power, /* SIOCGIWPOWER */ - (iw_handler) NULL, /* -- hole -- */ - (iw_handler) NULL, /* -- hole -- */ -// (iw_handler) NULL, /* SIOCSIWGENIE */ - (iw_handler) ks_wlan_set_genie, /* SIOCSIWGENIE */ - (iw_handler) NULL, /* SIOCGIWGENIE */ + (iw_handler) ks_wlan_set_power, /* SIOCSIWPOWER */ + (iw_handler) ks_wlan_get_power, /* SIOCGIWPOWER */ + (iw_handler) NULL, /* -- hole -- */ + (iw_handler) NULL, /* -- hole -- */ +// (iw_handler) NULL, /* SIOCSIWGENIE */ + (iw_handler) ks_wlan_set_genie, /* SIOCSIWGENIE */ + (iw_handler) NULL, /* SIOCGIWGENIE */ (iw_handler) ks_wlan_set_auth_mode, /* SIOCSIWAUTH */ (iw_handler) ks_wlan_get_auth_mode, /* SIOCGIWAUTH */ (iw_handler) ks_wlan_set_encode_ext, /* SIOCSIWENCODEEXT */ (iw_handler) ks_wlan_get_encode_ext, /* SIOCGIWENCODEEXT */ - (iw_handler) ks_wlan_set_pmksa, /* SIOCSIWPMKSA */ - (iw_handler) NULL, /* -- hole -- */ + (iw_handler) ks_wlan_set_pmksa, /* SIOCSIWPMKSA */ + (iw_handler) NULL, /* -- hole -- */ }; /* private_handler */ -static const iw_handler ks_wlan_private_handler[] = -{ - (iw_handler) NULL, /* 0 */ +static const iw_handler ks_wlan_private_handler[] = { + (iw_handler) NULL, /* 0 */ (iw_handler) ks_wlan_get_driver_version, /* 1 KS_WLAN_GET_DRIVER_VERSION */ - (iw_handler) NULL, /* 2 */ + (iw_handler) NULL, /* 2 */ (iw_handler) ks_wlan_get_firmware_version, /* 3 KS_WLAN_GET_FIRM_VERSION */ #ifdef WPS - (iw_handler) ks_wlan_set_wps_enable, /* 4 KS_WLAN_SET_WPS_ENABLE */ - (iw_handler) ks_wlan_get_wps_enable, /* 5 KS_WLAN_GET_WPS_ENABLE */ - (iw_handler) ks_wlan_set_wps_probe_req, /* 6 KS_WLAN_SET_WPS_PROBE_REQ */ + (iw_handler) ks_wlan_set_wps_enable, /* 4 KS_WLAN_SET_WPS_ENABLE */ + (iw_handler) ks_wlan_get_wps_enable, /* 5 KS_WLAN_GET_WPS_ENABLE */ + (iw_handler) ks_wlan_set_wps_probe_req, /* 6 KS_WLAN_SET_WPS_PROBE_REQ */ #else - (iw_handler) NULL, /* 4 */ - (iw_handler) NULL, /* 5 */ - (iw_handler) NULL, /* 6 */ + (iw_handler) NULL, /* 4 */ + (iw_handler) NULL, /* 5 */ + (iw_handler) NULL, /* 6 */ #endif /* WPS */ - (iw_handler) ks_wlan_get_eeprom_cksum, /* 7 KS_WLAN_GET_CONNECT */ - (iw_handler) ks_wlan_set_preamble, /* 8 KS_WLAN_SET_PREAMBLE */ - (iw_handler) ks_wlan_get_preamble, /* 9 KS_WLAN_GET_PREAMBLE */ - (iw_handler) ks_wlan_set_powermgt, /* 10 KS_WLAN_SET_POWER_SAVE */ - (iw_handler) ks_wlan_get_powermgt, /* 11 KS_WLAN_GET_POWER_SAVE */ - (iw_handler) ks_wlan_set_scan_type, /* 12 KS_WLAN_SET_SCAN_TYPE */ - (iw_handler) ks_wlan_get_scan_type, /* 13 KS_WLAN_GET_SCAN_TYPE */ - (iw_handler) ks_wlan_set_rx_gain, /* 14 KS_WLAN_SET_RX_GAIN */ - (iw_handler) ks_wlan_get_rx_gain, /* 15 KS_WLAN_GET_RX_GAIN */ - (iw_handler) ks_wlan_hostt, /* 16 KS_WLAN_HOSTT */ - (iw_handler) NULL, /* 17 */ - (iw_handler) ks_wlan_set_beacon_lost, /* 18 KS_WLAN_SET_BECAN_LOST */ - (iw_handler) ks_wlan_get_beacon_lost, /* 19 KS_WLAN_GET_BECAN_LOST */ - (iw_handler) ks_wlan_set_tx_gain, /* 20 KS_WLAN_SET_TX_GAIN */ - (iw_handler) ks_wlan_get_tx_gain, /* 21 KS_WLAN_GET_TX_GAIN */ - (iw_handler) ks_wlan_set_phy_type, /* 22 KS_WLAN_SET_PHY_TYPE */ - (iw_handler) ks_wlan_get_phy_type, /* 23 KS_WLAN_GET_PHY_TYPE */ - (iw_handler) ks_wlan_set_cts_mode, /* 24 KS_WLAN_SET_CTS_MODE */ - (iw_handler) ks_wlan_get_cts_mode, /* 25 KS_WLAN_GET_CTS_MODE */ - (iw_handler) NULL, /* 26 */ - (iw_handler) NULL, /* 27 */ - (iw_handler) ks_wlan_set_sleep_mode, /* 28 KS_WLAN_SET_SLEEP_MODE */ - (iw_handler) ks_wlan_get_sleep_mode, /* 29 KS_WLAN_GET_SLEEP_MODE */ - (iw_handler) NULL, /* 30 */ - (iw_handler) NULL, /* 31 */ + (iw_handler) ks_wlan_get_eeprom_cksum, /* 7 KS_WLAN_GET_CONNECT */ + (iw_handler) ks_wlan_set_preamble, /* 8 KS_WLAN_SET_PREAMBLE */ + (iw_handler) ks_wlan_get_preamble, /* 9 KS_WLAN_GET_PREAMBLE */ + (iw_handler) ks_wlan_set_powermgt, /* 10 KS_WLAN_SET_POWER_SAVE */ + (iw_handler) ks_wlan_get_powermgt, /* 11 KS_WLAN_GET_POWER_SAVE */ + (iw_handler) ks_wlan_set_scan_type, /* 12 KS_WLAN_SET_SCAN_TYPE */ + (iw_handler) ks_wlan_get_scan_type, /* 13 KS_WLAN_GET_SCAN_TYPE */ + (iw_handler) ks_wlan_set_rx_gain, /* 14 KS_WLAN_SET_RX_GAIN */ + (iw_handler) ks_wlan_get_rx_gain, /* 15 KS_WLAN_GET_RX_GAIN */ + (iw_handler) ks_wlan_hostt, /* 16 KS_WLAN_HOSTT */ + (iw_handler) NULL, /* 17 */ + (iw_handler) ks_wlan_set_beacon_lost, /* 18 KS_WLAN_SET_BECAN_LOST */ + (iw_handler) ks_wlan_get_beacon_lost, /* 19 KS_WLAN_GET_BECAN_LOST */ + (iw_handler) ks_wlan_set_tx_gain, /* 20 KS_WLAN_SET_TX_GAIN */ + (iw_handler) ks_wlan_get_tx_gain, /* 21 KS_WLAN_GET_TX_GAIN */ + (iw_handler) ks_wlan_set_phy_type, /* 22 KS_WLAN_SET_PHY_TYPE */ + (iw_handler) ks_wlan_get_phy_type, /* 23 KS_WLAN_GET_PHY_TYPE */ + (iw_handler) ks_wlan_set_cts_mode, /* 24 KS_WLAN_SET_CTS_MODE */ + (iw_handler) ks_wlan_get_cts_mode, /* 25 KS_WLAN_GET_CTS_MODE */ + (iw_handler) NULL, /* 26 */ + (iw_handler) NULL, /* 27 */ + (iw_handler) ks_wlan_set_sleep_mode, /* 28 KS_WLAN_SET_SLEEP_MODE */ + (iw_handler) ks_wlan_get_sleep_mode, /* 29 KS_WLAN_GET_SLEEP_MODE */ + (iw_handler) NULL, /* 30 */ + (iw_handler) NULL, /* 31 */ }; -static const struct iw_handler_def ks_wlan_handler_def = -{ - .num_standard = sizeof(ks_wlan_handler)/sizeof(iw_handler), - .num_private = sizeof(ks_wlan_private_handler)/sizeof(iw_handler), - .num_private_args = sizeof(ks_wlan_private_args)/sizeof(struct iw_priv_args), - .standard = (iw_handler *) ks_wlan_handler, - .private = (iw_handler *) ks_wlan_private_handler, - .private_args = (struct iw_priv_args *) ks_wlan_private_args, +static const struct iw_handler_def ks_wlan_handler_def = { + .num_standard = sizeof(ks_wlan_handler) / sizeof(iw_handler), + .num_private = sizeof(ks_wlan_private_handler) / sizeof(iw_handler), + .num_private_args = + sizeof(ks_wlan_private_args) / sizeof(struct iw_priv_args), + .standard = (iw_handler *) ks_wlan_handler, + .private = (iw_handler *) ks_wlan_private_handler, + .private_args = (struct iw_priv_args *)ks_wlan_private_args, .get_wireless_stats = ks_get_wireless_stats, }; - -static int ks_wlan_netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) +static int ks_wlan_netdev_ioctl(struct net_device *dev, struct ifreq *rq, + int cmd) { int rc = 0; - struct iwreq *wrq = (struct iwreq *) rq; + struct iwreq *wrq = (struct iwreq *)rq; switch (cmd) { - case SIOCIWFIRSTPRIV+20: /* KS_WLAN_SET_STOP_REQ */ + case SIOCIWFIRSTPRIV + 20: /* KS_WLAN_SET_STOP_REQ */ rc = ks_wlan_set_stop_request(dev, NULL, &(wrq->u.mode), NULL); break; - // All other calls are currently unsupported + // All other calls are currently unsupported default: rc = -EOPNOTSUPP; } - DPRINTK(5,"return=%d\n",rc); + DPRINTK(5, "return=%d\n", rc); return rc; } - static struct net_device_stats *ks_wlan_get_stats(struct net_device *dev) { struct ks_wlan_private *priv = netdev_priv(dev); if (priv->dev_state < DEVICE_STATE_READY) { - return NULL; /* not finished initialize */ - } + return NULL; /* not finished initialize */ + } return &priv->nstats; } @@ -2937,7 +3346,7 @@ static int ks_wlan_set_mac_address(struct net_device *dev, void *addr) { struct ks_wlan_private *priv = netdev_priv(dev); - struct sockaddr *mac_addr=(struct sockaddr *)addr; + struct sockaddr *mac_addr = (struct sockaddr *)addr; if (netif_running(dev)) return -EBUSY; memcpy(dev->dev_addr, mac_addr->sa_data, dev->addr_len); @@ -2945,20 +3354,21 @@ int ks_wlan_set_mac_address(struct net_device *dev, void *addr) priv->mac_address_valid = 0; hostif_sme_enqueue(priv, SME_MACADDRESS_SET_REQUEST); - printk(KERN_INFO "ks_wlan: MAC ADDRESS = %02x:%02x:%02x:%02x:%02x:%02x\n", - priv->eth_addr[0],priv->eth_addr[1],priv->eth_addr[2], - priv->eth_addr[3],priv->eth_addr[4],priv->eth_addr[5]); + printk(KERN_INFO + "ks_wlan: MAC ADDRESS = %02x:%02x:%02x:%02x:%02x:%02x\n", + priv->eth_addr[0], priv->eth_addr[1], priv->eth_addr[2], + priv->eth_addr[3], priv->eth_addr[4], priv->eth_addr[5]); return 0; } - static void ks_wlan_tx_timeout(struct net_device *dev) { - struct ks_wlan_private *priv = netdev_priv(dev); + struct ks_wlan_private *priv = netdev_priv(dev); - DPRINTK(1,"head(%d) tail(%d)!!\n",priv->tx_dev.qhead, priv->tx_dev.qtail); - if(!netif_queue_stopped(dev)){ + DPRINTK(1, "head(%d) tail(%d)!!\n", priv->tx_dev.qhead, + priv->tx_dev.qtail); + if (!netif_queue_stopped(dev)) { netif_stop_queue(dev); } priv->nstats.tx_errors++; @@ -2973,26 +3383,26 @@ int ks_wlan_start_xmit(struct sk_buff *skb, struct net_device *dev) struct ks_wlan_private *priv = netdev_priv(dev); int rc = 0; - DPRINTK(3,"in_interrupt()=%ld\n",in_interrupt()); + DPRINTK(3, "in_interrupt()=%ld\n", in_interrupt()); - if ( skb == NULL ) { - printk( KERN_ERR "ks_wlan: skb == NULL!!!\n" ); + if (skb == NULL) { + printk(KERN_ERR "ks_wlan: skb == NULL!!!\n"); return 0; } if (priv->dev_state < DEVICE_STATE_READY) { dev_kfree_skb(skb); - return 0; /* not finished initialize */ - } + return 0; /* not finished initialize */ + } - if(netif_running(dev)) + if (netif_running(dev)) netif_stop_queue(dev); rc = hostif_data_request(priv, skb); dev->trans_start = jiffies; - DPRINTK(4,"rc=%d\n",rc); - if (rc){ - rc=0; + DPRINTK(4, "rc=%d\n", rc); + if (rc) { + rc = 0; } return rc; @@ -3003,17 +3413,17 @@ void send_packet_complete(void *arg1, void *arg2) struct ks_wlan_private *priv = (struct ks_wlan_private *)arg1; struct sk_buff *packet = (struct sk_buff *)arg2; - DPRINTK(3,"\n"); + DPRINTK(3, "\n"); - priv->nstats.tx_bytes += packet->len; + priv->nstats.tx_bytes += packet->len; priv->nstats.tx_packets++; - if(netif_queue_stopped(priv->net_dev)) - netif_wake_queue(priv->net_dev); + if (netif_queue_stopped(priv->net_dev)) + netif_wake_queue(priv->net_dev); - if(packet){ + if (packet) { dev_kfree_skb(packet); - packet=NULL; + packet = NULL; } } @@ -3025,9 +3435,9 @@ void ks_wlan_set_multicast_list(struct net_device *dev) { struct ks_wlan_private *priv = netdev_priv(dev); - DPRINTK(4,"\n"); + DPRINTK(4, "\n"); if (priv->dev_state < DEVICE_STATE_READY) { - return ; /* not finished initialize */ + return; /* not finished initialize */ } hostif_sme_enqueue(priv, SME_MULTICAST_REQUEST); @@ -3041,12 +3451,11 @@ int ks_wlan_open(struct net_device *dev) priv->cur_rx = 0; - if(!priv->mac_address_valid){ + if (!priv->mac_address_valid) { printk(KERN_ERR "ks_wlan : %s Not READY !!\n", dev->name); return -EBUSY; - } - else - netif_start_queue (dev); + } else + netif_start_queue(dev); return 0; } @@ -3055,7 +3464,7 @@ static int ks_wlan_close(struct net_device *dev) { - netif_stop_queue (dev); + netif_stop_queue(dev); DPRINTK(4, "%s: Shutting down ethercard, status was 0x%4.4x.\n", dev->name, 0x00); @@ -3063,21 +3472,21 @@ int ks_wlan_close(struct net_device *dev) return 0; } - /* Operational parameters that usually are not changed. */ /* Time in jiffies before concluding the transmitter is hung. */ #define TX_TIMEOUT (3*HZ) -static const unsigned char dummy_addr[] = {0x00,0x0b,0xe3,0x00,0x00,0x00}; +static const unsigned char dummy_addr[] = + { 0x00, 0x0b, 0xe3, 0x00, 0x00, 0x00 }; static const struct net_device_ops ks_wlan_netdev_ops = { - .ndo_start_xmit = ks_wlan_start_xmit, - .ndo_open = ks_wlan_open, - .ndo_stop = ks_wlan_close, - .ndo_do_ioctl = ks_wlan_netdev_ioctl, - .ndo_set_mac_address = ks_wlan_set_mac_address, - .ndo_get_stats = ks_wlan_get_stats, - .ndo_tx_timeout = ks_wlan_tx_timeout, - .ndo_set_rx_mode = ks_wlan_set_multicast_list, + .ndo_start_xmit = ks_wlan_start_xmit, + .ndo_open = ks_wlan_open, + .ndo_stop = ks_wlan_close, + .ndo_do_ioctl = ks_wlan_netdev_ioctl, + .ndo_set_mac_address = ks_wlan_set_mac_address, + .ndo_get_stats = ks_wlan_get_stats, + .ndo_tx_timeout = ks_wlan_tx_timeout, + .ndo_set_rx_mode = ks_wlan_set_multicast_list, }; int ks_wlan_net_start(struct net_device *dev) @@ -3092,9 +3501,9 @@ int ks_wlan_net_start(struct net_device *dev) priv->device_open_status = 1; /* phy information update timer */ - atomic_set(&update_phyinfo,0); + atomic_set(&update_phyinfo, 0); init_timer(&update_phyinfo_timer); - update_phyinfo_timer.function=ks_wlan_update_phyinfo_timeout; + update_phyinfo_timer.function = ks_wlan_update_phyinfo_timeout; update_phyinfo_timer.data = (unsigned long)priv; /* dummy address set */ @@ -3118,7 +3527,6 @@ int ks_wlan_net_start(struct net_device *dev) return 0; } - int ks_wlan_net_stop(struct net_device *dev) { struct ks_wlan_private *priv = netdev_priv(dev); @@ -3127,7 +3535,7 @@ int ks_wlan_net_stop(struct net_device *dev) priv->device_open_status = 0; del_timer_sync(&update_phyinfo_timer); - if(netif_running(dev)) + if (netif_running(dev)) netif_stop_queue(dev); return ret; -- cgit v0.10.2 From cab898fbb0065c4252261e5a20328d5af5afaa8c Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Tue, 31 May 2016 12:56:35 +0200 Subject: staging: ks7010: indent michael_mic.c Signed-off-by: Wolfram Sang Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/ks7010/michael_mic.c b/drivers/staging/ks7010/michael_mic.c index ec8769a..adb17df 100644 --- a/drivers/staging/ks7010/michael_mic.c +++ b/drivers/staging/ks7010/michael_mic.c @@ -34,11 +34,11 @@ A->nBytesInM = 0; static -void MichaelInitializeFunction( struct michel_mic_t *Mic, uint8_t *key ) +void MichaelInitializeFunction(struct michel_mic_t *Mic, uint8_t * key) { // Set the key - Mic->K0 = getUInt32( key , 0 ); - Mic->K1 = getUInt32( key , 4 ); + Mic->K0 = getUInt32(key, 0); + Mic->K1 = getUInt32(key, 4); //clear(); MichaelClear(Mic); @@ -56,11 +56,10 @@ do{ \ L += R; \ }while(0) - static -void MichaelAppend( struct michel_mic_t *Mic, uint8_t *src, int nBytes ) +void MichaelAppend(struct michel_mic_t *Mic, uint8_t * src, int nBytes) { - int addlen ; + int addlen; if (Mic->nBytesInM) { addlen = 4 - Mic->nBytesInM; if (addlen > nBytes) @@ -73,13 +72,13 @@ void MichaelAppend( struct michel_mic_t *Mic, uint8_t *src, int nBytes ) if (Mic->nBytesInM < 4) return; - Mic->L ^= getUInt32(Mic->M,0); + Mic->L ^= getUInt32(Mic->M, 0); MichaelBlockFunction(Mic->L, Mic->R); Mic->nBytesInM = 0; } - while(nBytes >= 4){ - Mic->L ^= getUInt32(src,0); + while (nBytes >= 4) { + Mic->L ^= getUInt32(src, 0); MichaelBlockFunction(Mic->L, Mic->R); src += 4; nBytes -= 4; @@ -92,7 +91,7 @@ void MichaelAppend( struct michel_mic_t *Mic, uint8_t *src, int nBytes ) } static -void MichaelGetMIC( struct michel_mic_t *Mic, uint8_t *dst ) +void MichaelGetMIC(struct michel_mic_t *Mic, uint8_t * dst) { uint8_t *data = Mic->M; switch (Mic->nBytesInM) { @@ -107,24 +106,24 @@ void MichaelGetMIC( struct michel_mic_t *Mic, uint8_t *dst ) break; case 3: Mic->L ^= data[0] | (data[1] << 8) | (data[2] << 16) | - 0x5a000000; + 0x5a000000; break; } MichaelBlockFunction(Mic->L, Mic->R); MichaelBlockFunction(Mic->L, Mic->R); // The appendByte function has already computed the result. - putUInt32( dst, 0, Mic->L ); - putUInt32( dst, 4, Mic->R ); + putUInt32(dst, 0, Mic->L); + putUInt32(dst, 4, Mic->R); // Reset to the empty message. MichaelClear(Mic); } -void MichaelMICFunction( struct michel_mic_t *Mic, uint8_t *Key, - uint8_t *Data, int Len, uint8_t priority, - uint8_t *Result ) +void MichaelMICFunction(struct michel_mic_t *Mic, uint8_t * Key, + uint8_t * Data, int Len, uint8_t priority, + uint8_t * Result) { - uint8_t pad_data[4] = {priority,0,0,0}; + uint8_t pad_data[4] = { priority, 0, 0, 0 }; // Compute the MIC value /* * IEEE802.11i page 47 @@ -135,9 +134,9 @@ void MichaelMICFunction( struct michel_mic_t *Mic, uint8_t *Key, * |DA|SA|Priority|0 |Data|M0|M1|M2|M3|M4|M5|M6|M7| * +--+--+--------+--+----+--+--+--+--+--+--+--+--+ */ - MichaelInitializeFunction( Mic, Key ) ; - MichaelAppend( Mic, (uint8_t*)Data, 12 ); /* |DA|SA| */ - MichaelAppend( Mic, pad_data, 4 ); /* |Priority|0|0|0| */ - MichaelAppend( Mic, (uint8_t*)(Data+12), Len -12 ); /* |Data| */ - MichaelGetMIC( Mic, Result ) ; + MichaelInitializeFunction(Mic, Key); + MichaelAppend(Mic, (uint8_t *) Data, 12); /* |DA|SA| */ + MichaelAppend(Mic, pad_data, 4); /* |Priority|0|0|0| */ + MichaelAppend(Mic, (uint8_t *) (Data + 12), Len - 12); /* |Data| */ + MichaelGetMIC(Mic, Result); } -- cgit v0.10.2 From 79c2df5866a14fcac4235332fddb4d5a2d99d76d Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Tue, 31 May 2016 12:56:36 +0200 Subject: staging: ks7010: indent michael_mic.h Signed-off-by: Wolfram Sang Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/ks7010/michael_mic.h b/drivers/staging/ks7010/michael_mic.h index f14f160..57ecbe3 100644 --- a/drivers/staging/ks7010/michael_mic.h +++ b/drivers/staging/ks7010/michael_mic.h @@ -16,14 +16,14 @@ struct michel_mic_t { uint32_t K0; // Key uint32_t K1; // Key - uint32_t L; // Current state - uint32_t R; // Current state - uint8_t M[4]; // Message accumulator (single word) - int nBytesInM; // # bytes in M - uint8_t Result[8]; + uint32_t L; // Current state + uint32_t R; // Current state + uint8_t M[4]; // Message accumulator (single word) + int nBytesInM; // # bytes in M + uint8_t Result[8]; }; extern -void MichaelMICFunction( struct michel_mic_t *Mic, uint8_t *Key, - uint8_t *Data, int Len, uint8_t priority, - uint8_t *Result ); +void MichaelMICFunction(struct michel_mic_t *Mic, uint8_t * Key, + uint8_t * Data, int Len, uint8_t priority, + uint8_t * Result); -- cgit v0.10.2 From cdf6ecc5eed103190f1df9cdd09659ef2cc7d23a Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Tue, 31 May 2016 12:56:37 +0200 Subject: staging: ks7010: indent ks7010_sdio.c Unlike the previous patches which are plain indent outcomes, this has some manual fixups to be not overly strict with the 80 char limit. Signed-off-by: Wolfram Sang Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/ks7010/ks7010_sdio.c b/drivers/staging/ks7010/ks7010_sdio.c index fb9f0b5..ed4d579 100644 --- a/drivers/staging/ks7010/ks7010_sdio.c +++ b/drivers/staging/ks7010/ks7010_sdio.c @@ -30,31 +30,32 @@ static int reg_net = 0; static const struct sdio_device_id if_sdio_ids[] = { - { SDIO_DEVICE(SDIO_VENDOR_ID_KS_CODE_A, SDIO_DEVICE_ID_KS_7010) }, - { SDIO_DEVICE(SDIO_VENDOR_ID_KS_CODE_B, SDIO_DEVICE_ID_KS_7010) }, + {SDIO_DEVICE(SDIO_VENDOR_ID_KS_CODE_A, SDIO_DEVICE_ID_KS_7010)}, + {SDIO_DEVICE(SDIO_VENDOR_ID_KS_CODE_B, SDIO_DEVICE_ID_KS_7010)}, { /* all zero */ } }; struct ks_sdio_model { - int model; - const char *firmware; + int model; + const char *firmware; }; static struct ks_sdio_model ks_sdio_models[] = { - { - /* ks7010 */ - .model = 0x10, - .firmware = "ks7010sd.rom", - }, + { + /* ks7010 */ + .model = 0x10, + .firmware = "ks7010sd.rom", + }, }; -static int ks7910_sdio_probe(struct sdio_func *function, const struct sdio_device_id *device); +static int ks7910_sdio_probe(struct sdio_func *function, + const struct sdio_device_id *device); static void ks7910_sdio_remove(struct sdio_func *function); static void ks7010_rw_function(struct work_struct *work); -static int ks7010_sdio_read( struct ks_wlan_private *priv, unsigned int address, - unsigned char *buffer, int length ); -static int ks7010_sdio_write( struct ks_wlan_private *priv, unsigned int address, - unsigned char *buffer, int length ); +static int ks7010_sdio_read(struct ks_wlan_private *priv, unsigned int address, + unsigned char *buffer, int length); +static int ks7010_sdio_write(struct ks_wlan_private *priv, unsigned int address, + unsigned char *buffer, int length); /* macro */ #define inc_txqhead(priv) \ @@ -79,25 +80,25 @@ void ks_wlan_hw_sleep_doze_request(struct ks_wlan_private *priv) DPRINTK(4, "\n"); /* clear request */ - atomic_set(&priv->sleepstatus.doze_request,0); + atomic_set(&priv->sleepstatus.doze_request, 0); - if( atomic_read(&priv->sleepstatus.status) == 0){ + if (atomic_read(&priv->sleepstatus.status) == 0) { rw_data = GCR_B_DOZE; - retval = ks7010_sdio_write(priv, GCR_B, &rw_data, sizeof(rw_data)); - if(retval){ + retval = + ks7010_sdio_write(priv, GCR_B, &rw_data, sizeof(rw_data)); + if (retval) { DPRINTK(1, " error : GCR_B=%02X\n", rw_data); goto out; } DPRINTK(4, "PMG SET!! : GCR_B=%02X\n", rw_data); - DPRINTK(3,"sleep_mode=SLP_SLEEP\n"); + DPRINTK(3, "sleep_mode=SLP_SLEEP\n"); atomic_set(&priv->sleepstatus.status, 1); - priv->last_doze = jiffies; - } - else{ - DPRINTK(1,"sleep_mode=%d\n",priv->sleep_mode); + priv->last_doze = jiffies; + } else { + DPRINTK(1, "sleep_mode=%d\n", priv->sleep_mode); } -out: + out: priv->sleep_mode = atomic_read(&priv->sleepstatus.status); return; } @@ -110,110 +111,126 @@ void ks_wlan_hw_sleep_wakeup_request(struct ks_wlan_private *priv) DPRINTK(4, "\n"); /* clear request */ - atomic_set(&priv->sleepstatus.wakeup_request,0); + atomic_set(&priv->sleepstatus.wakeup_request, 0); - if( atomic_read(&priv->sleepstatus.status) == 1){ + if (atomic_read(&priv->sleepstatus.status) == 1) { rw_data = WAKEUP_REQ; - retval = ks7010_sdio_write(priv, WAKEUP, &rw_data, sizeof(rw_data)); - if(retval){ + retval = + ks7010_sdio_write(priv, WAKEUP, &rw_data, sizeof(rw_data)); + if (retval) { DPRINTK(1, " error : WAKEUP=%02X\n", rw_data); goto out; } DPRINTK(4, "wake up : WAKEUP=%02X\n", rw_data); atomic_set(&priv->sleepstatus.status, 0); - priv->last_wakeup = jiffies; + priv->last_wakeup = jiffies; ++priv->wakeup_count; - } - else{ - DPRINTK(1,"sleep_mode=%d\n",priv->sleep_mode); + } else { + DPRINTK(1, "sleep_mode=%d\n", priv->sleep_mode); } -out: + out: priv->sleep_mode = atomic_read(&priv->sleepstatus.status); return; } - void ks_wlan_hw_wakeup_request(struct ks_wlan_private *priv) { unsigned char rw_data; int retval; DPRINTK(4, "\n"); - if(atomic_read(&priv->psstatus.status)==PS_SNOOZE){ + if (atomic_read(&priv->psstatus.status) == PS_SNOOZE) { rw_data = WAKEUP_REQ; - retval = ks7010_sdio_write(priv, WAKEUP, &rw_data, sizeof(rw_data)); - if(retval){ + retval = + ks7010_sdio_write(priv, WAKEUP, &rw_data, sizeof(rw_data)); + if (retval) { DPRINTK(1, " error : WAKEUP=%02X\n", rw_data); } DPRINTK(4, "wake up : WAKEUP=%02X\n", rw_data); - priv->last_wakeup = jiffies; + priv->last_wakeup = jiffies; ++priv->wakeup_count; - } - else{ - DPRINTK(1,"psstatus=%d\n",atomic_read(&priv->psstatus.status)); + } else { + DPRINTK(1, "psstatus=%d\n", + atomic_read(&priv->psstatus.status)); } } int _ks_wlan_hw_power_save(struct ks_wlan_private *priv) { - int rc=0; + int rc = 0; unsigned char rw_data; int retval; - if(priv->reg.powermgt == POWMGT_ACTIVE_MODE) + if (priv->reg.powermgt == POWMGT_ACTIVE_MODE) return rc; - if(priv->reg.operation_mode == MODE_INFRASTRUCTURE && - (priv->connect_status & CONNECT_STATUS_MASK)== CONNECT_STATUS){ + if (priv->reg.operation_mode == MODE_INFRASTRUCTURE && + (priv->connect_status & CONNECT_STATUS_MASK) == CONNECT_STATUS) { //DPRINTK(1,"psstatus.status=%d\n",atomic_read(&priv->psstatus.status)); - if (priv->dev_state == DEVICE_STATE_SLEEP) { - switch(atomic_read(&priv->psstatus.status)){ - case PS_SNOOZE: /* 4 */ - break; - default: - DPRINTK(5,"\n\ - psstatus.status=%d\n\ - psstatus.confirm_wait=%d\n\ - psstatus.snooze_guard=%d\n\ - cnt_txqbody=%d\n", - atomic_read(&priv->psstatus.status), - atomic_read(&priv->psstatus.confirm_wait), - atomic_read(&priv->psstatus.snooze_guard), - cnt_txqbody(priv)); - - if(!atomic_read(&priv->psstatus.confirm_wait)&& - !atomic_read(&priv->psstatus.snooze_guard)&& - !cnt_txqbody(priv)){ - retval = ks7010_sdio_read(priv, INT_PENDING, &rw_data, sizeof(rw_data)); - if(retval){ - DPRINTK(1, " error : INT_PENDING=%02X\n", rw_data); - queue_delayed_work(priv->ks_wlan_hw.ks7010sdio_wq,&priv->ks_wlan_hw.rw_wq, 1); - break; - } - if(!rw_data){ - rw_data = GCR_B_DOZE; - retval = ks7010_sdio_write(priv, GCR_B, &rw_data, sizeof(rw_data)); - if(retval){ - DPRINTK(1, " error : GCR_B=%02X\n", rw_data); - queue_delayed_work(priv->ks_wlan_hw.ks7010sdio_wq,&priv->ks_wlan_hw.rw_wq, 1); + if (priv->dev_state == DEVICE_STATE_SLEEP) { + switch (atomic_read(&priv->psstatus.status)) { + case PS_SNOOZE: /* 4 */ + break; + default: + DPRINTK(5, "\npsstatus.status=%d\npsstatus.confirm_wait=%d\npsstatus.snooze_guard=%d\ncnt_txqbody=%d\n", + atomic_read(&priv->psstatus.status), + atomic_read(&priv->psstatus.confirm_wait), + atomic_read(&priv->psstatus.snooze_guard), + cnt_txqbody(priv)); + + if (!atomic_read(&priv->psstatus.confirm_wait) + && !atomic_read(&priv->psstatus.snooze_guard) + && !cnt_txqbody(priv)) { + retval = + ks7010_sdio_read(priv, INT_PENDING, + &rw_data, + sizeof(rw_data)); + if (retval) { + DPRINTK(1, + " error : INT_PENDING=%02X\n", + rw_data); + queue_delayed_work(priv->ks_wlan_hw.ks7010sdio_wq, + &priv->ks_wlan_hw.rw_wq, 1); break; } - DPRINTK(4, "PMG SET!! : GCR_B=%02X\n", rw_data); - atomic_set(&priv->psstatus.status, PS_SNOOZE); - DPRINTK(3,"psstatus.status=PS_SNOOZE\n"); - } - else{ - queue_delayed_work(priv->ks_wlan_hw.ks7010sdio_wq,&priv->ks_wlan_hw.rw_wq, 1); + if (!rw_data) { + rw_data = GCR_B_DOZE; + retval = + ks7010_sdio_write(priv, + GCR_B, + &rw_data, + sizeof(rw_data)); + if (retval) { + DPRINTK(1, + " error : GCR_B=%02X\n", + rw_data); + queue_delayed_work + (priv->ks_wlan_hw.ks7010sdio_wq, + &priv->ks_wlan_hw.rw_wq, 1); + break; + } + DPRINTK(4, + "PMG SET!! : GCR_B=%02X\n", + rw_data); + atomic_set(&priv->psstatus. + status, PS_SNOOZE); + DPRINTK(3, + "psstatus.status=PS_SNOOZE\n"); + } else { + queue_delayed_work(priv->ks_wlan_hw.ks7010sdio_wq, + &priv->ks_wlan_hw.rw_wq, 1); + } + } else { + queue_delayed_work(priv->ks_wlan_hw. + ks7010sdio_wq, + &priv->ks_wlan_hw.rw_wq, + 0); } + break; } - else{ - queue_delayed_work(priv->ks_wlan_hw.ks7010sdio_wq,&priv->ks_wlan_hw.rw_wq, 0); - } - break; } - } } @@ -222,7 +239,8 @@ int _ks_wlan_hw_power_save(struct ks_wlan_private *priv) int ks_wlan_hw_power_save(struct ks_wlan_private *priv) { - queue_delayed_work(priv->ks_wlan_hw.ks7010sdio_wq,&priv->ks_wlan_hw.rw_wq, 1); + queue_delayed_work(priv->ks_wlan_hw.ks7010sdio_wq, + &priv->ks_wlan_hw.rw_wq, 1); return 0; } @@ -234,16 +252,16 @@ static int ks7010_sdio_read(struct ks_wlan_private *priv, unsigned int address, card = priv->ks_wlan_hw.sdio_card; - if (length == 1) /* CMD52 */ + if (length == 1) /* CMD52 */ *buffer = sdio_readb(card->func, address, &rc); - else /* CMD53 multi-block transfer */ + else /* CMD53 multi-block transfer */ rc = sdio_memcpy_fromio(card->func, buffer, address, length); - if(rc != 0){ + if (rc != 0) { printk("sdio error erorr=%d size=%d\n", rc, length); ++priv->sdio_error_count; - }else{ - priv->sdio_error_count=0; + } else { + priv->sdio_error_count = 0; } return rc; @@ -257,40 +275,42 @@ static int ks7010_sdio_write(struct ks_wlan_private *priv, unsigned int address, card = priv->ks_wlan_hw.sdio_card; - if (length == 1) /* CMD52 */ - sdio_writeb(card->func, *buffer, (unsigned int) address, &rc); - else /* CMD53 */ - rc = sdio_memcpy_toio(card->func, (unsigned int) address, buffer, length); + if (length == 1) /* CMD52 */ + sdio_writeb(card->func, *buffer, (unsigned int)address, &rc); + else /* CMD53 */ + rc = sdio_memcpy_toio(card->func, (unsigned int)address, buffer, + length); - if(rc != 0){ + if (rc != 0) { printk("sdio error erorr=%d size=%d\n", rc, length); ++priv->sdio_error_count; - }else{ - priv->sdio_error_count=0; + } else { + priv->sdio_error_count = 0; } return rc; } -static int enqueue_txdev(struct ks_wlan_private *priv, unsigned char *p, unsigned long size, - void (*complete_handler)(void *arg1, void *arg2), - void *arg1, void *arg2 ) +static int enqueue_txdev(struct ks_wlan_private *priv, unsigned char *p, + unsigned long size, + void (*complete_handler) (void *arg1, void *arg2), + void *arg1, void *arg2) { struct tx_device_buffer *sp; if (priv->dev_state < DEVICE_STATE_BOOT) { kfree(p); if (complete_handler != NULL) - (*complete_handler)(arg1, arg2); + (*complete_handler) (arg1, arg2); return 1; } - if ((TX_DEVICE_BUFF_SIZE - 1) <= cnt_txqbody(priv)) { + if ((TX_DEVICE_BUFF_SIZE - 1) <= cnt_txqbody(priv)) { /* in case of buffer overflow */ - DPRINTK(1,"tx buffer overflow\n"); + DPRINTK(1, "tx buffer overflow\n"); kfree(p); if (complete_handler != NULL) - (*complete_handler)(arg1, arg2); + (*complete_handler) (arg1, arg2); return 1; } @@ -306,29 +326,31 @@ static int enqueue_txdev(struct ks_wlan_private *priv, unsigned char *p, unsigne } /* write data */ -static int write_to_device(struct ks_wlan_private *priv, unsigned char *buffer, unsigned long size ) +static int write_to_device(struct ks_wlan_private *priv, unsigned char *buffer, + unsigned long size) { - int rc,retval; + int rc, retval; unsigned char rw_data; struct hostif_hdr *hdr; hdr = (struct hostif_hdr *)buffer; - rc=0; + rc = 0; - DPRINTK(4,"size=%d\n", hdr->size); - if(hdr->event < HIF_DATA_REQ || HIF_REQ_MAX < hdr->event){ - DPRINTK(1,"unknown event=%04X\n",hdr->event); + DPRINTK(4, "size=%d\n", hdr->size); + if (hdr->event < HIF_DATA_REQ || HIF_REQ_MAX < hdr->event) { + DPRINTK(1, "unknown event=%04X\n", hdr->event); return 0; } retval = ks7010_sdio_write(priv, DATA_WINDOW, buffer, size); - if(retval){ + if (retval) { DPRINTK(1, " write error : retval=%d\n", retval); return -4; } rw_data = WRITE_STATUS_BUSY; - retval = ks7010_sdio_write(priv, WRITE_STATUS, &rw_data, sizeof(rw_data)); - if(retval){ + retval = + ks7010_sdio_write(priv, WRITE_STATUS, &rw_data, sizeof(rw_data)); + if (retval) { DPRINTK(1, " error : WRITE_STATUS=%02X\n", rw_data); return -3; } @@ -339,74 +361,80 @@ static int write_to_device(struct ks_wlan_private *priv, unsigned char *buffer, static void tx_device_task(void *dev) { struct ks_wlan_private *priv = (struct ks_wlan_private *)dev; - struct tx_device_buffer *sp; + struct tx_device_buffer *sp; int rc = 0; DPRINTK(4, "\n"); - if(cnt_txqbody(priv)>0 && atomic_read(&priv->psstatus.status) != PS_SNOOZE){ + if (cnt_txqbody(priv) > 0 + && atomic_read(&priv->psstatus.status) != PS_SNOOZE) { sp = &priv->tx_dev.tx_dev_buff[priv->tx_dev.qhead]; - if(priv->dev_state >= DEVICE_STATE_BOOT){ + if (priv->dev_state >= DEVICE_STATE_BOOT) { rc = write_to_device(priv, sp->sendp, sp->size); - if(rc){ - DPRINTK(1, "write_to_device error !!(%d)\n", rc); - queue_delayed_work(priv->ks_wlan_hw.ks7010sdio_wq,&priv->ks_wlan_hw.rw_wq, 1); + if (rc) { + DPRINTK(1, "write_to_device error !!(%d)\n", + rc); + queue_delayed_work(priv->ks_wlan_hw. + ks7010sdio_wq, + &priv->ks_wlan_hw.rw_wq, 1); return; } } - kfree(sp->sendp); /* allocated memory free */ - if(sp->complete_handler != NULL) /* TX Complete */ - (*sp->complete_handler)(sp->arg1, sp->arg2); + kfree(sp->sendp); /* allocated memory free */ + if (sp->complete_handler != NULL) /* TX Complete */ + (*sp->complete_handler) (sp->arg1, sp->arg2); inc_txqhead(priv); - if(cnt_txqbody(priv)>0){ - queue_delayed_work(priv->ks_wlan_hw.ks7010sdio_wq,&priv->ks_wlan_hw.rw_wq, 0); + if (cnt_txqbody(priv) > 0) { + queue_delayed_work(priv->ks_wlan_hw.ks7010sdio_wq, + &priv->ks_wlan_hw.rw_wq, 0); } } return; } -int ks_wlan_hw_tx( struct ks_wlan_private *priv, void *p, unsigned long size, - void (*complete_handler)(void *arg1, void *arg2), - void *arg1, void *arg2 ) +int ks_wlan_hw_tx(struct ks_wlan_private *priv, void *p, unsigned long size, + void (*complete_handler) (void *arg1, void *arg2), + void *arg1, void *arg2) { - int result=0; + int result = 0; struct hostif_hdr *hdr; hdr = (struct hostif_hdr *)p; - if(hdr->event < HIF_DATA_REQ || HIF_REQ_MAX < hdr->event){ - DPRINTK(1,"unknown event=%04X\n",hdr->event); + if (hdr->event < HIF_DATA_REQ || HIF_REQ_MAX < hdr->event) { + DPRINTK(1, "unknown event=%04X\n", hdr->event); return 0; } /* add event to hostt buffer */ priv->hostt.buff[priv->hostt.qtail] = hdr->event; - priv->hostt.qtail = (priv->hostt.qtail + 1) % SME_EVENT_BUFF_SIZE; + priv->hostt.qtail = (priv->hostt.qtail + 1) % SME_EVENT_BUFF_SIZE; - DPRINTK(4, "event=%04X\n",hdr->event); + DPRINTK(4, "event=%04X\n", hdr->event); spin_lock(&priv->tx_dev.tx_dev_lock); result = enqueue_txdev(priv, p, size, complete_handler, arg1, arg2); spin_unlock(&priv->tx_dev.tx_dev_lock); - if(cnt_txqbody(priv)>0){ - queue_delayed_work(priv->ks_wlan_hw.ks7010sdio_wq,&priv->ks_wlan_hw.rw_wq, 0); + if (cnt_txqbody(priv) > 0) { + queue_delayed_work(priv->ks_wlan_hw.ks7010sdio_wq, + &priv->ks_wlan_hw.rw_wq, 0); } return result; } static void rx_event_task(unsigned long dev) { - struct ks_wlan_private *priv = (struct ks_wlan_private *)dev; - struct rx_device_buffer *rp; + struct ks_wlan_private *priv = (struct ks_wlan_private *)dev; + struct rx_device_buffer *rp; - DPRINTK(4,"\n"); + DPRINTK(4, "\n"); - if(cnt_rxqbody(priv) > 0 && priv->dev_state >= DEVICE_STATE_BOOT){ + if (cnt_rxqbody(priv) > 0 && priv->dev_state >= DEVICE_STATE_BOOT) { rp = &priv->rx_dev.rx_dev_buff[priv->rx_dev.qhead]; hostif_receive(priv, rp->data, rp->size); inc_rxqhead(priv); - if(cnt_rxqbody(priv) > 0){ + if (cnt_rxqbody(priv) > 0) { tasklet_schedule(&priv->ks_wlan_hw.rx_bh_task); } } @@ -420,35 +448,40 @@ static void ks_wlan_hw_rx(void *dev, uint16_t size) int retval; struct rx_device_buffer *rx_buffer; struct hostif_hdr *hdr; - unsigned char read_status; - unsigned short event=0; + unsigned char read_status; + unsigned short event = 0; - DPRINTK(4,"\n"); + DPRINTK(4, "\n"); /* receive data */ - if (cnt_rxqbody(priv) >= (RX_DEVICE_BUFF_SIZE-1)) { + if (cnt_rxqbody(priv) >= (RX_DEVICE_BUFF_SIZE - 1)) { /* in case of buffer overflow */ - DPRINTK(1,"rx buffer overflow \n"); + DPRINTK(1, "rx buffer overflow \n"); goto error_out; } rx_buffer = &priv->rx_dev.rx_dev_buff[priv->rx_dev.qtail]; - retval = ks7010_sdio_read(priv, DATA_WINDOW, &rx_buffer->data[0], hif_align_size(size)); - if(retval){ + retval = + ks7010_sdio_read(priv, DATA_WINDOW, &rx_buffer->data[0], + hif_align_size(size)); + if (retval) { goto error_out; } /* length check */ - if(size > 2046 || size == 0){ + if (size > 2046 || size == 0) { #ifdef KS_WLAN_DEBUG if (KS_WLAN_DEBUG > 5) - print_hex_dump_bytes("INVALID DATA dump: ", DUMP_PREFIX_OFFSET, + print_hex_dump_bytes("INVALID DATA dump: ", + DUMP_PREFIX_OFFSET, rx_buffer->data, 32); #endif /* rx_status update */ read_status = READ_STATUS_IDLE; - retval = ks7010_sdio_write(priv, READ_STATUS, &read_status, sizeof(read_status)); - if(retval){ + retval = + ks7010_sdio_write(priv, READ_STATUS, &read_status, + sizeof(read_status)); + if (retval) { DPRINTK(1, " error : READ_STATUS=%02X\n", read_status); } goto error_out; @@ -461,14 +494,16 @@ static void ks_wlan_hw_rx(void *dev, uint16_t size) /* read status update */ read_status = READ_STATUS_IDLE; - retval = ks7010_sdio_write(priv, READ_STATUS, &read_status, sizeof(read_status)); - if(retval){ + retval = + ks7010_sdio_write(priv, READ_STATUS, &read_status, + sizeof(read_status)); + if (retval) { DPRINTK(1, " error : READ_STATUS=%02X\n", read_status); } DPRINTK(4, "READ_STATUS=%02X\n", read_status); - if(atomic_read(&priv->psstatus.confirm_wait)){ - if(IS_HIF_CONF(event)){ + if (atomic_read(&priv->psstatus.confirm_wait)) { + if (IS_HIF_CONF(event)) { DPRINTK(4, "IS_HIF_CONF true !!\n"); atomic_dec(&priv->psstatus.confirm_wait); } @@ -477,7 +512,7 @@ static void ks_wlan_hw_rx(void *dev, uint16_t size) /* rx_event_task((void *)priv); */ tasklet_schedule(&priv->ks_wlan_hw.rx_bh_task); -error_out: + error_out: return; } @@ -491,71 +526,74 @@ static void ks7010_rw_function(struct work_struct *work) hw = container_of(work, struct hw_info_t, rw_wq.work); priv = container_of(hw, struct ks_wlan_private, ks_wlan_hw); - DPRINTK(4,"\n"); - + DPRINTK(4, "\n"); - /* wiat after DOZE */ - if(time_after(priv->last_doze + ((30*HZ)/1000), jiffies )){ - DPRINTK(4, "wait after DOZE \n"); - queue_delayed_work(priv->ks_wlan_hw.ks7010sdio_wq,&priv->ks_wlan_hw.rw_wq, 1); + /* wiat after DOZE */ + if (time_after(priv->last_doze + ((30 * HZ) / 1000), jiffies)) { + DPRINTK(4, "wait after DOZE \n"); + queue_delayed_work(priv->ks_wlan_hw.ks7010sdio_wq, + &priv->ks_wlan_hw.rw_wq, 1); return; } /* wiat after WAKEUP */ - while(time_after(priv->last_wakeup + ((30*HZ)/1000), jiffies )){ + while (time_after(priv->last_wakeup + ((30 * HZ) / 1000), jiffies)) { DPRINTK(4, "wait after WAKEUP \n"); /* queue_delayed_work(priv->ks_wlan_hw.ks7010sdio_wq,&priv->ks_wlan_hw.rw_wq, (priv->last_wakeup + ((30*HZ)/1000) - jiffies));*/ - printk("wake: %lu %lu\n", priv->last_wakeup + (30* HZ)/1000, jiffies); + printk("wake: %lu %lu\n", priv->last_wakeup + (30 * HZ) / 1000, + jiffies); msleep(30); } sdio_claim_host(priv->ks_wlan_hw.sdio_card->func); /* power save wakeup */ - if(atomic_read(&priv->psstatus.status)==PS_SNOOZE){ - if(cnt_txqbody(priv)>0){ + if (atomic_read(&priv->psstatus.status) == PS_SNOOZE) { + if (cnt_txqbody(priv) > 0) { ks_wlan_hw_wakeup_request(priv); - queue_delayed_work(priv->ks_wlan_hw.ks7010sdio_wq,&priv->ks_wlan_hw.rw_wq, 1); + queue_delayed_work(priv->ks_wlan_hw.ks7010sdio_wq, + &priv->ks_wlan_hw.rw_wq, 1); } goto err_out; } /* sleep mode doze */ - if(atomic_read(&priv->sleepstatus.doze_request)==1){ + if (atomic_read(&priv->sleepstatus.doze_request) == 1) { ks_wlan_hw_sleep_doze_request(priv); goto err_out; } /* sleep mode wakeup */ - if(atomic_read(&priv->sleepstatus.wakeup_request)==1){ + if (atomic_read(&priv->sleepstatus.wakeup_request) == 1) { ks_wlan_hw_sleep_wakeup_request(priv); goto err_out; } /* read (WriteStatus/ReadDataSize FN1:00_0014) */ - retval = ks7010_sdio_read(priv, WSTATUS_RSIZE, &rw_data, sizeof(rw_data)); - if(retval){ - DPRINTK(1, " error : WSTATUS_RSIZE=%02X psstatus=%d\n", rw_data,atomic_read(&priv->psstatus.status)); + retval = + ks7010_sdio_read(priv, WSTATUS_RSIZE, &rw_data, sizeof(rw_data)); + if (retval) { + DPRINTK(1, " error : WSTATUS_RSIZE=%02X psstatus=%d\n", rw_data, + atomic_read(&priv->psstatus.status)); goto err_out; } DPRINTK(4, "WSTATUS_RSIZE=%02X\n", rw_data); - if(rw_data&RSIZE_MASK){ /* Read schedule */ - ks_wlan_hw_rx((void *)priv, (uint16_t)(((rw_data&RSIZE_MASK)<<4))); + if (rw_data & RSIZE_MASK) { /* Read schedule */ + ks_wlan_hw_rx((void *)priv, + (uint16_t) (((rw_data & RSIZE_MASK) << 4))); } - if((rw_data&WSTATUS_MASK)){ + if ((rw_data & WSTATUS_MASK)) { tx_device_task((void *)priv); } _ks_wlan_hw_power_save(priv); -err_out: + err_out: sdio_release_host(priv->ks_wlan_hw.sdio_card->func); return; } - - static void ks_sdio_interrupt(struct sdio_func *func) { int retval; @@ -567,10 +605,12 @@ static void ks_sdio_interrupt(struct sdio_func *func) priv = card->priv; DPRINTK(4, "\n"); - if(priv->dev_state >= DEVICE_STATE_BOOT){ - retval = ks7010_sdio_read(priv, INT_PENDING, &status, sizeof(status)); - if(retval){ - DPRINTK(1, "read INT_PENDING Failed!!(%d)\n",retval); + if (priv->dev_state >= DEVICE_STATE_BOOT) { + retval = + ks7010_sdio_read(priv, INT_PENDING, &status, + sizeof(status)); + if (retval) { + DPRINTK(1, "read INT_PENDING Failed!!(%d)\n", retval); goto intr_out; } DPRINTK(4, "INT_PENDING=%02X\n", rw_data); @@ -580,70 +620,89 @@ static void ks_sdio_interrupt(struct sdio_func *func) /* read (General Communication B register) */ /* bit5 -> Write Status Idle */ /* bit2 -> Read Status Busy */ - if(status&INT_GCR_B || atomic_read(&priv->psstatus.status)==PS_SNOOZE){ - retval = ks7010_sdio_read(priv, GCR_B, &rw_data, sizeof(rw_data)); - if(retval){ + if (status & INT_GCR_B + || atomic_read(&priv->psstatus.status) == PS_SNOOZE) { + retval = + ks7010_sdio_read(priv, GCR_B, &rw_data, + sizeof(rw_data)); + if (retval) { DPRINTK(1, " error : GCR_B=%02X\n", rw_data); goto intr_out; } /* DPRINTK(1, "GCR_B=%02X\n", rw_data); */ - if(rw_data == GCR_B_ACTIVE){ - if(atomic_read(&priv->psstatus.status)==PS_SNOOZE){ - atomic_set(&priv->psstatus.status, PS_WAKEUP); - priv->wakeup_count=0; + if (rw_data == GCR_B_ACTIVE) { + if (atomic_read(&priv->psstatus.status) == + PS_SNOOZE) { + atomic_set(&priv->psstatus.status, + PS_WAKEUP); + priv->wakeup_count = 0; } complete(&priv->psstatus.wakeup_wait); } - } - do{ + do { /* read (WriteStatus/ReadDataSize FN1:00_0014) */ - retval = ks7010_sdio_read(priv, WSTATUS_RSIZE, &rw_data, sizeof(rw_data)); - if(retval){ - DPRINTK(1, " error : WSTATUS_RSIZE=%02X\n", rw_data); + retval = + ks7010_sdio_read(priv, WSTATUS_RSIZE, &rw_data, + sizeof(rw_data)); + if (retval) { + DPRINTK(1, " error : WSTATUS_RSIZE=%02X\n", + rw_data); goto intr_out; } DPRINTK(4, "WSTATUS_RSIZE=%02X\n", rw_data); - rsize=rw_data&RSIZE_MASK; - if(rsize){ /* Read schedule */ - ks_wlan_hw_rx((void *)priv, (uint16_t)(((rsize)<<4))); + rsize = rw_data & RSIZE_MASK; + if (rsize) { /* Read schedule */ + ks_wlan_hw_rx((void *)priv, + (uint16_t) (((rsize) << 4))); } - if(rw_data&WSTATUS_MASK){ + if (rw_data & WSTATUS_MASK) { #if 0 - if(status&INT_WRITE_STATUS && !cnt_txqbody(priv)){ + if (status & INT_WRITE_STATUS + && !cnt_txqbody(priv)) { /* dummy write for interrupt clear */ - rw_data =0; - retval = ks7010_sdio_write(priv, DATA_WINDOW, &rw_data, sizeof(rw_data)); + rw_data = 0; + retval = + ks7010_sdio_write(priv, DATA_WINDOW, + &rw_data, + sizeof(rw_data)); if (retval) { - DPRINTK(1, "write DATA_WINDOW Failed!!(%d)\n",retval); + DPRINTK(1, + "write DATA_WINDOW Failed!!(%d)\n", + retval); } status &= ~INT_WRITE_STATUS; - } - else{ + } else { #endif - if(atomic_read(&priv->psstatus.status)==PS_SNOOZE){ - if(cnt_txqbody(priv)){ + if (atomic_read(&priv->psstatus.status) == PS_SNOOZE) { + if (cnt_txqbody(priv)) { ks_wlan_hw_wakeup_request(priv); - queue_delayed_work(priv->ks_wlan_hw.ks7010sdio_wq, &priv->ks_wlan_hw.rw_wq, 1); + queue_delayed_work + (priv->ks_wlan_hw. + ks7010sdio_wq, + &priv->ks_wlan_hw. + rw_wq, 1); return; } - } - else{ + } else { tx_device_task((void *)priv); } -// } +#if 0 + } +#endif } - }while(rsize); + } while (rsize); } -intr_out: - queue_delayed_work(priv->ks_wlan_hw.ks7010sdio_wq,&priv->ks_wlan_hw.rw_wq, 0); + intr_out: + queue_delayed_work(priv->ks_wlan_hw.ks7010sdio_wq, + &priv->ks_wlan_hw.rw_wq, 0); return; } -static int trx_device_init( struct ks_wlan_private *priv ) +static int trx_device_init(struct ks_wlan_private *priv) { /* initialize values (tx) */ priv->tx_dev.qtail = priv->tx_dev.qhead = 0; @@ -655,21 +714,22 @@ static int trx_device_init( struct ks_wlan_private *priv ) spin_lock_init(&priv->tx_dev.tx_dev_lock); spin_lock_init(&priv->rx_dev.rx_dev_lock); - tasklet_init(&priv->ks_wlan_hw.rx_bh_task, rx_event_task, (unsigned long)priv); + tasklet_init(&priv->ks_wlan_hw.rx_bh_task, rx_event_task, + (unsigned long)priv); return 0; } -static void trx_device_exit( struct ks_wlan_private *priv ) +static void trx_device_exit(struct ks_wlan_private *priv) { - struct tx_device_buffer *sp; + struct tx_device_buffer *sp; /* tx buffer clear */ - while (cnt_txqbody(priv)>0) { + while (cnt_txqbody(priv) > 0) { sp = &priv->tx_dev.tx_dev_buff[priv->tx_dev.qhead]; - kfree(sp->sendp); /* allocated memory free */ - if (sp->complete_handler != NULL) /* TX Complete */ - (*sp->complete_handler)(sp->arg1, sp->arg2); + kfree(sp->sendp); /* allocated memory free */ + if (sp->complete_handler != NULL) /* TX Complete */ + (*sp->complete_handler) (sp->arg1, sp->arg2); inc_txqhead(priv); } @@ -677,24 +737,35 @@ static void trx_device_exit( struct ks_wlan_private *priv ) return; } + static int ks7010_sdio_update_index(struct ks_wlan_private *priv, u32 index) { - int rc=0; + int rc = 0; int retval; unsigned char *data_buf; data_buf = NULL; data_buf = kmalloc(sizeof(u32), GFP_KERNEL); - if(!data_buf){ rc = 1; goto error_out; } + if (!data_buf) { + rc = 1; + goto error_out; + } memcpy(data_buf, &index, sizeof(index)); retval = ks7010_sdio_write(priv, WRITE_INDEX, data_buf, sizeof(index)); - if(retval){ rc = 2; goto error_out; } + if (retval) { + rc = 2; + goto error_out; + } retval = ks7010_sdio_write(priv, READ_INDEX, data_buf, sizeof(index)); - if(retval){ rc = 3; goto error_out; } -error_out: - if(data_buf) kfree(data_buf); + if (retval) { + rc = 3; + goto error_out; + } + error_out: + if (data_buf) + kfree(data_buf); return rc; } @@ -702,30 +773,41 @@ error_out: static int ks7010_sdio_data_compare(struct ks_wlan_private *priv, u32 address, unsigned char *data, unsigned int size) { - int rc=0; + int rc = 0; int retval; unsigned char *read_buf; read_buf = NULL; read_buf = kmalloc(ROM_BUFF_SIZE, GFP_KERNEL); - if(!read_buf){ rc = 1; goto error_out; } + if (!read_buf) { + rc = 1; + goto error_out; + } retval = ks7010_sdio_read(priv, address, read_buf, size); - if(retval){ rc = 2; goto error_out; } + if (retval) { + rc = 2; + goto error_out; + } retval = memcmp(data, read_buf, size); - if(retval){ - DPRINTK(0, "data compare error (%d) \n",retval); rc = 3; goto error_out; + if (retval) { + DPRINTK(0, "data compare error (%d) \n", retval); + rc = 3; + goto error_out; } -error_out: - if(read_buf) kfree(read_buf); + error_out: + if (read_buf) + kfree(read_buf); return rc; } + #include -static int ks79xx_upload_firmware(struct ks_wlan_private *priv, struct ks_sdio_card *card) +static int ks79xx_upload_firmware(struct ks_wlan_private *priv, + struct ks_sdio_card *card) { - unsigned int size, offset, n = 0; - unsigned char *rom_buf; - unsigned char rw_data =0; - int retval, rc=0; + unsigned int size, offset, n = 0; + unsigned char *rom_buf; + unsigned char rw_data = 0; + int retval, rc = 0; int length; const struct firmware *fw_entry = NULL; @@ -733,76 +815,99 @@ static int ks79xx_upload_firmware(struct ks_wlan_private *priv, struct ks_sdio_c /* buffer allocate */ rom_buf = kmalloc(ROM_BUFF_SIZE, GFP_KERNEL); - if(!rom_buf){ rc = 3; goto error_out0; } - + if (!rom_buf) { + rc = 3; + goto error_out0; + } sdio_claim_host(card->func); /* Firmware running ? */ retval = ks7010_sdio_read(priv, GCR_A, &rw_data, sizeof(rw_data)); - if(rw_data == GCR_A_RUN){ - DPRINTK( 0, "MAC firmware running ...\n"); + if (rw_data == GCR_A_RUN) { + DPRINTK(0, "MAC firmware running ...\n"); rc = 0; goto error_out0; } - if(request_firmware(&fw_entry, priv->reg.rom_file, &priv->ks_wlan_hw.sdio_card->func->dev)!=0){ - DPRINTK(1,"error request_firmware() file=%s\n", priv->reg.rom_file); + if (request_firmware + (&fw_entry, priv->reg.rom_file, + &priv->ks_wlan_hw.sdio_card->func->dev) != 0) { + DPRINTK(1, "error request_firmware() file=%s\n", + priv->reg.rom_file); return 1; } - DPRINTK(4,"success request_firmware() file=%s size=%zu\n", priv->reg.rom_file, fw_entry->size); + DPRINTK(4, "success request_firmware() file=%s size=%zu\n", + priv->reg.rom_file, fw_entry->size); length = fw_entry->size; /* Load Program */ n = 0; - do { - if(length >= ROM_BUFF_SIZE){ + do { + if (length >= ROM_BUFF_SIZE) { size = ROM_BUFF_SIZE; length = length - ROM_BUFF_SIZE; + } else { + size = length; + length = 0; } - else{ - size=length; - length=0; - } - DPRINTK(4, "size = %d\n",size); - if(size == 0) break; - memcpy(rom_buf,fw_entry->data+n,size); + DPRINTK(4, "size = %d\n", size); + if (size == 0) + break; + memcpy(rom_buf, fw_entry->data + n, size); /* Update write index */ offset = n; - retval = ks7010_sdio_update_index(priv, KS7010_IRAM_ADDRESS+offset); - if(retval){ rc = 6; goto error_out1; } + retval = + ks7010_sdio_update_index(priv, + KS7010_IRAM_ADDRESS + offset); + if (retval) { + rc = 6; + goto error_out1; + } /* Write data */ retval = ks7010_sdio_write(priv, DATA_WINDOW, rom_buf, size); - if(retval){ rc = 8; goto error_out1; } + if (retval) { + rc = 8; + goto error_out1; + } /* compare */ - retval = ks7010_sdio_data_compare(priv, DATA_WINDOW, rom_buf, size); - if(retval){ rc = 9; goto error_out1; } + retval = + ks7010_sdio_data_compare(priv, DATA_WINDOW, rom_buf, size); + if (retval) { + rc = 9; + goto error_out1; + } n += size; - }while(size); + } while (size); /* Remap request */ rw_data = GCR_A_REMAP; retval = ks7010_sdio_write(priv, GCR_A, &rw_data, sizeof(rw_data)); - if(retval){ + if (retval) { rc = 11; goto error_out1; } - DPRINTK( 4, " REMAP Request : GCR_A=%02X\n", rw_data); + DPRINTK(4, " REMAP Request : GCR_A=%02X\n", rw_data); /* Firmware running check */ for (n = 0; n < 50; ++n) { - mdelay(10);/* wait_ms(10); */ - retval = ks7010_sdio_read(priv, GCR_A, &rw_data, sizeof(rw_data)); - if(retval){ rc = 11; goto error_out1; } - if(rw_data == GCR_A_RUN) break; + mdelay(10); /* wait_ms(10); */ + retval = + ks7010_sdio_read(priv, GCR_A, &rw_data, sizeof(rw_data)); + if (retval) { + rc = 11; + goto error_out1; + } + if (rw_data == GCR_A_RUN) + break; } - DPRINTK(4, "firmware wakeup (%d)!!!!\n",n); + DPRINTK(4, "firmware wakeup (%d)!!!!\n", n); if ((50) <= n) { DPRINTK(1, "firmware can't start\n"); - rc = 12; + rc = 12; goto error_out1; } @@ -812,30 +917,31 @@ static int ks79xx_upload_firmware(struct ks_wlan_private *priv, struct ks_sdio_c release_firmware(fw_entry); error_out0: sdio_release_host(card->func); - if(rom_buf) + if (rom_buf) kfree(rom_buf); return rc; } static void ks7010_card_init(struct ks_wlan_private *priv) { - DPRINTK(5,"\ncard_init_task()\n"); + DPRINTK(5, "\ncard_init_task()\n"); /* init_waitqueue_head(&priv->confirm_wait); */ init_completion(&priv->confirm_wait); - DPRINTK(5,"init_completion()\n"); + DPRINTK(5, "init_completion()\n"); /* get mac address & firmware version */ hostif_sme_enqueue(priv, SME_START); - DPRINTK(5,"hostif_sme_enqueu()\n"); + DPRINTK(5, "hostif_sme_enqueu()\n"); - if(!wait_for_completion_interruptible_timeout(&priv->confirm_wait,5*HZ)){ - DPRINTK(1,"wait time out!! SME_START\n"); + if (!wait_for_completion_interruptible_timeout + (&priv->confirm_wait, 5 * HZ)) { + DPRINTK(1, "wait time out!! SME_START\n"); } - if(priv->mac_address_valid && priv->version_size){ + if (priv->mac_address_valid && priv->version_size) { priv->dev_state = DEVICE_STATE_PREINIT; } @@ -858,57 +964,56 @@ static void ks7010_card_init(struct ks_wlan_private *priv) hostif_sme_enqueue(priv, SME_MODE_SET_REQUEST); hostif_sme_enqueue(priv, SME_START_REQUEST); - if(!wait_for_completion_interruptible_timeout(&priv->confirm_wait,5*HZ)){ - DPRINTK(1,"wait time out!! wireless parameter set\n"); + if (!wait_for_completion_interruptible_timeout + (&priv->confirm_wait, 5 * HZ)) { + DPRINTK(1, "wait time out!! wireless parameter set\n"); } - if(priv->dev_state >= DEVICE_STATE_PREINIT){ + if (priv->dev_state >= DEVICE_STATE_PREINIT) { DPRINTK(1, "DEVICE READY!!\n"); priv->dev_state = DEVICE_STATE_READY; - reg_net = register_netdev (priv->net_dev); - DPRINTK(3, "register_netdev=%d\n",reg_net); - } - else { - DPRINTK(1, "dev_state=%d\n",priv->dev_state); + reg_net = register_netdev(priv->net_dev); + DPRINTK(3, "register_netdev=%d\n", reg_net); + } else { + DPRINTK(1, "dev_state=%d\n", priv->dev_state); } } static struct sdio_driver ks7010_sdio_driver = { - .name = "ks7910_sdio", - .id_table = if_sdio_ids, - .probe = ks7910_sdio_probe, - .remove = ks7910_sdio_remove, + .name = "ks7910_sdio", + .id_table = if_sdio_ids, + .probe = ks7910_sdio_probe, + .remove = ks7910_sdio_remove, }; - extern int ks_wlan_net_start(struct net_device *dev); extern int ks_wlan_net_stop(struct net_device *dev); -static int ks7910_sdio_probe(struct sdio_func *func, const struct sdio_device_id *device) +static int ks7910_sdio_probe(struct sdio_func *func, + const struct sdio_device_id *device) { struct ks_wlan_private *priv; struct ks_sdio_card *card; struct net_device *netdev; unsigned char rw_data; - int i=0, ret; + int i = 0, ret; DPRINTK(5, "ks7910_sdio_probe()\n"); priv = NULL; - netdev=NULL; - + netdev = NULL; /* initilize ks_sdio_card */ card = kzalloc(sizeof(struct ks_sdio_card), GFP_KERNEL); if (!card) return -ENOMEM; - card->func = func; + card->func = func; card->model = 0x10; spin_lock_init(&card->lock); /* select model */ - for (i = 0;i < ARRAY_SIZE(ks_sdio_models);i++) { + for (i = 0; i < ARRAY_SIZE(ks_sdio_models); i++) { if (card->model == ks_sdio_models[i].model) break; } @@ -920,7 +1025,6 @@ static int ks7910_sdio_probe(struct sdio_func *func, const struct sdio_device_id card->firmware = ks_sdio_models[i].firmware; - /*** Initialize SDIO ***/ sdio_claim_host(func); @@ -929,7 +1033,8 @@ static int ks7910_sdio_probe(struct sdio_func *func, const struct sdio_device_id /* function blocksize set */ ret = sdio_set_block_size(func, KS7010_IO_BLOCK_SIZE); - DPRINTK(5, "multi_block=%d sdio_set_block_size()=%d %d\n", func->card->cccr.multi_block, func->cur_blksize, ret); + DPRINTK(5, "multi_block=%d sdio_set_block_size()=%d %d\n", + func->card->cccr.multi_block, func->cur_blksize, ret); /* Allocate the slot current */ @@ -940,10 +1045,10 @@ static int ks7910_sdio_probe(struct sdio_func *func, const struct sdio_device_id goto error_free_card; /* interrupt disable */ - sdio_writeb(func, 0, INT_ENABLE, &ret); + sdio_writeb(func, 0, INT_ENABLE, &ret); if (ret) goto error_free_card; - sdio_writeb(func, 0xff, INT_PENDING, &ret); + sdio_writeb(func, 0xff, INT_PENDING, &ret); if (ret) goto error_disable_func; @@ -957,18 +1062,16 @@ static int ks7910_sdio_probe(struct sdio_func *func, const struct sdio_device_id sdio_set_drvdata(func, card); DPRINTK(5, "class = 0x%X, vendor = 0x%X, " - "device = 0x%X\n", - func->class, func->vendor, func->device); - + "device = 0x%X\n", func->class, func->vendor, func->device); /* private memory allocate */ netdev = alloc_etherdev(sizeof(*priv)); if (netdev == NULL) { - printk (KERN_ERR "ks79xx : Unable to alloc new net device\n"); + printk(KERN_ERR "ks79xx : Unable to alloc new net device\n"); goto error_release_irq; } if (dev_alloc_name(netdev, netdev->name) < 0) { - printk (KERN_ERR "ks79xx : Couldn't get name!\n"); + printk(KERN_ERR "ks79xx : Couldn't get name!\n"); goto error_free_netdev; } @@ -982,7 +1085,7 @@ static int ks7910_sdio_probe(struct sdio_func *func, const struct sdio_device_id init_completion(&priv->ks_wlan_hw.ks7010_sdio_wait); priv->ks_wlan_hw.read_buf = NULL; priv->ks_wlan_hw.read_buf = kmalloc(RX_DATA_SIZE, GFP_KERNEL); - if(!priv->ks_wlan_hw.read_buf){ + if (!priv->ks_wlan_hw.read_buf) { goto error_free_netdev; } priv->dev_state = DEVICE_STATE_PREBOOT; @@ -995,25 +1098,29 @@ static int ks7910_sdio_probe(struct sdio_func *func, const struct sdio_device_id memset(&priv->wstats, 0, sizeof(priv->wstats)); /* sleep mode */ - atomic_set(&priv->sleepstatus.doze_request,0); - atomic_set(&priv->sleepstatus.wakeup_request,0); - atomic_set(&priv->sleepstatus.wakeup_request,0); + atomic_set(&priv->sleepstatus.doze_request, 0); + atomic_set(&priv->sleepstatus.wakeup_request, 0); + atomic_set(&priv->sleepstatus.wakeup_request, 0); trx_device_init(priv); hostif_init(priv); - ks_wlan_net_start(netdev); + ks_wlan_net_start(netdev); /* Read config file */ ret = ks_wlan_read_config_file(priv); if (ret) { - printk(KERN_ERR "ks79xx: read configuration file failed !! retern code = %d\n", ret); + printk(KERN_ERR + "ks79xx: read configuration file failed !! retern code = %d\n", + ret); goto error_free_read_buf; } /* Upload firmware */ - ret = ks79xx_upload_firmware(priv, card); /* firmware load */ - if(ret){ - printk(KERN_ERR "ks79xx: firmware load failed !! retern code = %d\n", ret); + ret = ks79xx_upload_firmware(priv, card); /* firmware load */ + if (ret) { + printk(KERN_ERR + "ks79xx: firmware load failed !! retern code = %d\n", + ret); goto error_free_read_buf; } @@ -1023,25 +1130,24 @@ static int ks7910_sdio_probe(struct sdio_func *func, const struct sdio_device_id sdio_claim_host(func); ret = ks7010_sdio_write(priv, INT_PENDING, &rw_data, sizeof(rw_data)); sdio_release_host(func); - if(ret){ + if (ret) { DPRINTK(1, " error : INT_PENDING=%02X\n", rw_data); } DPRINTK(4, " clear Interrupt : INT_PENDING=%02X\n", rw_data); - /* enable ks7010sdio interrupt (INT_GCR_B|INT_READ_STATUS|INT_WRITE_STATUS) */ - rw_data = (INT_GCR_B|INT_READ_STATUS|INT_WRITE_STATUS); + rw_data = (INT_GCR_B | INT_READ_STATUS | INT_WRITE_STATUS); sdio_claim_host(func); ret = ks7010_sdio_write(priv, INT_ENABLE, &rw_data, sizeof(rw_data)); sdio_release_host(func); - if(ret){ + if (ret) { DPRINTK(1, " error : INT_ENABLE=%02X\n", rw_data); } DPRINTK(4, " enable Interrupt : INT_ENABLE=%02X\n", rw_data); priv->dev_state = DEVICE_STATE_BOOT; priv->ks_wlan_hw.ks7010sdio_wq = create_workqueue("ks7010sdio_wq"); - if(!priv->ks_wlan_hw.ks7010sdio_wq){ + if (!priv->ks_wlan_hw.ks7010sdio_wq) { DPRINTK(1, "create_workqueue failed !!\n"); goto error_free_read_buf; } @@ -1051,22 +1157,22 @@ static int ks7910_sdio_probe(struct sdio_func *func, const struct sdio_device_id return 0; -error_free_read_buf: + error_free_read_buf: kfree(priv->ks_wlan_hw.read_buf); priv->ks_wlan_hw.read_buf = NULL; -error_free_netdev: + error_free_netdev: free_netdev(priv->net_dev); card->priv = NULL; -error_release_irq: + error_release_irq: sdio_claim_host(func); sdio_release_irq(func); -error_disable_func: + error_disable_func: sdio_disable_func(func); -error_free_card: + error_free_card: sdio_release_host(func); sdio_set_drvdata(func, NULL); kfree(card); -error: + error: return -ENODEV; } @@ -1080,56 +1186,62 @@ static void ks7910_sdio_remove(struct sdio_func *func) card = sdio_get_drvdata(func); - if(card == NULL) + if (card == NULL) return; DPRINTK(1, "priv = card->priv\n"); priv = card->priv; netdev = priv->net_dev; - if(priv){ + if (priv) { ks_wlan_net_stop(netdev); DPRINTK(1, "ks_wlan_net_stop\n"); /* interrupt disable */ sdio_claim_host(func); - sdio_writeb(func, 0, INT_ENABLE, &ret); - sdio_writeb(func, 0xff, INT_PENDING, &ret); + sdio_writeb(func, 0, INT_ENABLE, &ret); + sdio_writeb(func, 0xff, INT_PENDING, &ret); sdio_release_host(func); DPRINTK(1, "interrupt disable\n"); /* send stop request to MAC */ { struct hostif_stop_request_t *pp; - pp = (struct hostif_stop_request_t *)kzalloc(hif_align_size(sizeof(*pp)), GFP_KERNEL ); - if (pp==NULL) { - DPRINTK(3,"allocate memory failed..\n"); - return; /* to do goto ni suru*/ + pp = (struct hostif_stop_request_t *) + kzalloc(hif_align_size(sizeof(*pp)), GFP_KERNEL); + if (pp == NULL) { + DPRINTK(3, "allocate memory failed..\n"); + return; /* to do goto ni suru */ } - pp->header.size = cpu_to_le16((uint16_t)(sizeof(*pp)-sizeof(pp->header.size))); - pp->header.event = cpu_to_le16((uint16_t)HIF_STOP_REQ); + pp->header.size = + cpu_to_le16((uint16_t) + (sizeof(*pp) - + sizeof(pp->header.size))); + pp->header.event = cpu_to_le16((uint16_t) HIF_STOP_REQ); sdio_claim_host(func); - write_to_device(priv, (unsigned char *) pp, hif_align_size(sizeof(*pp))); + write_to_device(priv, (unsigned char *)pp, + hif_align_size(sizeof(*pp))); sdio_release_host(func); kfree(pp); } DPRINTK(1, "STOP Req\n"); - if(priv->ks_wlan_hw.ks7010sdio_wq){ + if (priv->ks_wlan_hw.ks7010sdio_wq) { flush_workqueue(priv->ks_wlan_hw.ks7010sdio_wq); destroy_workqueue(priv->ks_wlan_hw.ks7010sdio_wq); } - DPRINTK(1, "destroy_workqueue(priv->ks_wlan_hw.ks7010sdio_wq);\n"); + DPRINTK(1, + "destroy_workqueue(priv->ks_wlan_hw.ks7010sdio_wq);\n"); hostif_exit(priv); DPRINTK(1, "hostif_exit\n"); - if(!reg_net) + if (!reg_net) unregister_netdev(netdev); DPRINTK(1, "unregister_netdev\n"); trx_device_exit(priv); - if(priv->ks_wlan_hw.read_buf){ + if (priv->ks_wlan_hw.read_buf) { kfree(priv->ks_wlan_hw.read_buf); } free_netdev(priv->net_dev); @@ -1148,26 +1260,27 @@ static void ks7910_sdio_remove(struct sdio_func *func) kfree(card); DPRINTK(1, "kfree()\n"); - - DPRINTK(5," Bye !!\n"); + DPRINTK(5, " Bye !!\n"); return; } -static int __init ks7010_sdio_init( void ) +static int __init ks7010_sdio_init(void) { int status; /* register with bus driver core */ status = sdio_register_driver(&ks7010_sdio_driver); - if(status != 0){ - DPRINTK(1,"ks79xx_sdio : failed to register with bus driver, %d\n", status ); + if (status != 0) { + DPRINTK(1, + "ks79xx_sdio : failed to register with bus driver, %d\n", + status); } return status; } -static void __exit ks7010_sdio_exit( void ) +static void __exit ks7010_sdio_exit(void) { - DPRINTK(5," \n"); + DPRINTK(5, " \n"); sdio_unregister_driver(&ks7010_sdio_driver); return; } -- cgit v0.10.2 From 2801d7a289bd435ae4920a792c5497a6450686ef Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Tue, 31 May 2016 12:56:38 +0200 Subject: staging: ks7010: remove supported card table with one element There is only this card supported, no need to iterate over the table. The resulting firmware filename wasn't used anyway, but came from the config file or hardcoded default. Signed-off-by: Wolfram Sang Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/ks7010/ks7010_sdio.c b/drivers/staging/ks7010/ks7010_sdio.c index ed4d579..8e8476b 100644 --- a/drivers/staging/ks7010/ks7010_sdio.c +++ b/drivers/staging/ks7010/ks7010_sdio.c @@ -35,19 +35,6 @@ static const struct sdio_device_id if_sdio_ids[] = { { /* all zero */ } }; -struct ks_sdio_model { - int model; - const char *firmware; -}; - -static struct ks_sdio_model ks_sdio_models[] = { - { - /* ks7010 */ - .model = 0x10, - .firmware = "ks7010sd.rom", - }, -}; - static int ks7910_sdio_probe(struct sdio_func *function, const struct sdio_device_id *device); static void ks7910_sdio_remove(struct sdio_func *function); @@ -996,7 +983,7 @@ static int ks7910_sdio_probe(struct sdio_func *func, struct ks_sdio_card *card; struct net_device *netdev; unsigned char rw_data; - int i = 0, ret; + int ret; DPRINTK(5, "ks7910_sdio_probe()\n"); @@ -1009,22 +996,8 @@ static int ks7910_sdio_probe(struct sdio_func *func, return -ENOMEM; card->func = func; - card->model = 0x10; spin_lock_init(&card->lock); - /* select model */ - for (i = 0; i < ARRAY_SIZE(ks_sdio_models); i++) { - if (card->model == ks_sdio_models[i].model) - break; - } - - if (i == ARRAY_SIZE(ks_sdio_models)) { - DPRINTK(5, "unkown card model 0x%x\n", card->model); - goto error; - } - - card->firmware = ks_sdio_models[i].firmware; - /*** Initialize SDIO ***/ sdio_claim_host(func); @@ -1172,7 +1145,7 @@ static int ks7910_sdio_probe(struct sdio_func *func, sdio_release_host(func); sdio_set_drvdata(func, NULL); kfree(card); - error: + return -ENODEV; } diff --git a/drivers/staging/ks7010/ks7010_sdio.h b/drivers/staging/ks7010/ks7010_sdio.h index aea3727..2d7be5d 100644 --- a/drivers/staging/ks7010/ks7010_sdio.h +++ b/drivers/staging/ks7010/ks7010_sdio.h @@ -109,8 +109,6 @@ struct ks_sdio_packet { struct ks_sdio_card { struct sdio_func *func; struct ks_wlan_private *priv; - int model; - const char *firmware; spinlock_t lock; }; -- cgit v0.10.2 From e1240140f9e9a749eb938e7a6866355a6ed1b8d1 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Tue, 31 May 2016 12:56:39 +0200 Subject: staging: ks7010: fix module annotations List all authors, beautify description, match license to what is stated in file headers, add firmware information. Signed-off-by: Wolfram Sang Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/ks7010/ks7010_sdio.c b/drivers/staging/ks7010/ks7010_sdio.c index 8e8476b..8c0d1bb 100644 --- a/drivers/staging/ks7010/ks7010_sdio.c +++ b/drivers/staging/ks7010/ks7010_sdio.c @@ -1261,9 +1261,7 @@ static void __exit ks7010_sdio_exit(void) module_init(ks7010_sdio_init); module_exit(ks7010_sdio_exit); -MODULE_AUTHOR("Qi-Hardware based on KeyStream driver"); -MODULE_DESCRIPTION("Driver for KeyStream, KS7010 based SDIO cards. "); -#ifdef MODULE_LICENSE -MODULE_LICENSE("GPL"); -#endif -MODULE_SUPPORTED_DEVICE("KS7910"); +MODULE_AUTHOR("Sang Engineering, Qi-Hardware, KeyStream"); +MODULE_DESCRIPTION("Driver for KeyStream KS7010 based SDIO cards"); +MODULE_LICENSE("GPL v2"); +MODULE_FIRMWARE(ROM_FILE); -- cgit v0.10.2 From 4e66308e7dc43e15237cedb4079b830858a597aa Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Tue, 31 May 2016 12:56:40 +0200 Subject: staging: ks7010: adapt to new trans_start handling trans_start is gone from netdevice, so use the new helper function to set the mark. Signed-off-by: Wolfram Sang Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/ks7010/ks_wlan_net.c b/drivers/staging/ks7010/ks_wlan_net.c index 3e28283..ac3354b 100644 --- a/drivers/staging/ks7010/ks_wlan_net.c +++ b/drivers/staging/ks7010/ks_wlan_net.c @@ -3398,7 +3398,7 @@ int ks_wlan_start_xmit(struct sk_buff *skb, struct net_device *dev) netif_stop_queue(dev); rc = hostif_data_request(priv, skb); - dev->trans_start = jiffies; + netif_trans_update(dev); DPRINTK(4, "rc=%d\n", rc); if (rc) { -- cgit v0.10.2 From 6b0cb0b02ec8c03a16d1bdff4ae79b27874138e1 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Tue, 31 May 2016 12:56:41 +0200 Subject: staging: ks7010: simplify module_init/exit The printouts are not needed, the driver core has enough debug output for this if wanted. So, use a helper to save boilerplate code. Signed-off-by: Wolfram Sang Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/ks7010/ks7010_sdio.c b/drivers/staging/ks7010/ks7010_sdio.c index 8c0d1bb..a8a14f9 100644 --- a/drivers/staging/ks7010/ks7010_sdio.c +++ b/drivers/staging/ks7010/ks7010_sdio.c @@ -1237,30 +1237,7 @@ static void ks7910_sdio_remove(struct sdio_func *func) return; } -static int __init ks7010_sdio_init(void) -{ - int status; - - /* register with bus driver core */ - status = sdio_register_driver(&ks7010_sdio_driver); - if (status != 0) { - DPRINTK(1, - "ks79xx_sdio : failed to register with bus driver, %d\n", - status); - } - return status; -} - -static void __exit ks7010_sdio_exit(void) -{ - DPRINTK(5, " \n"); - sdio_unregister_driver(&ks7010_sdio_driver); - return; -} - -module_init(ks7010_sdio_init); -module_exit(ks7010_sdio_exit); - +module_driver(ks7010_sdio_driver, sdio_register_driver, sdio_unregister_driver); MODULE_AUTHOR("Sang Engineering, Qi-Hardware, KeyStream"); MODULE_DESCRIPTION("Driver for KeyStream KS7010 based SDIO cards"); MODULE_LICENSE("GPL v2"); -- cgit v0.10.2 From 9adca34b7eea096db6757ee7263fbc002e64c5eb Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Tue, 31 May 2016 12:56:42 +0200 Subject: staging: ks7010: drop counting sd errors They were counted but never really used anywhere. Also change the printk to a debug print, since it mostly shows on the expected -ENOMEDIUM on card removal. Signed-off-by: Wolfram Sang Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/ks7010/ks7010_sdio.c b/drivers/staging/ks7010/ks7010_sdio.c index a8a14f9..c166022 100644 --- a/drivers/staging/ks7010/ks7010_sdio.c +++ b/drivers/staging/ks7010/ks7010_sdio.c @@ -234,8 +234,8 @@ int ks_wlan_hw_power_save(struct ks_wlan_private *priv) static int ks7010_sdio_read(struct ks_wlan_private *priv, unsigned int address, unsigned char *buffer, int length) { - int rc = -1; struct ks_sdio_card *card; + int rc; card = priv->ks_wlan_hw.sdio_card; @@ -244,12 +244,8 @@ static int ks7010_sdio_read(struct ks_wlan_private *priv, unsigned int address, else /* CMD53 multi-block transfer */ rc = sdio_memcpy_fromio(card->func, buffer, address, length); - if (rc != 0) { - printk("sdio error erorr=%d size=%d\n", rc, length); - ++priv->sdio_error_count; - } else { - priv->sdio_error_count = 0; - } + if (rc != 0) + DPRINTK(1, "sdio error=%d size=%d\n", rc, length); return rc; } @@ -257,8 +253,8 @@ static int ks7010_sdio_read(struct ks_wlan_private *priv, unsigned int address, static int ks7010_sdio_write(struct ks_wlan_private *priv, unsigned int address, unsigned char *buffer, int length) { - int rc = -1; struct ks_sdio_card *card; + int rc; card = priv->ks_wlan_hw.sdio_card; @@ -268,12 +264,8 @@ static int ks7010_sdio_write(struct ks_wlan_private *priv, unsigned int address, rc = sdio_memcpy_toio(card->func, (unsigned int)address, buffer, length); - if (rc != 0) { - printk("sdio error erorr=%d size=%d\n", rc, length); - ++priv->sdio_error_count; - } else { - priv->sdio_error_count = 0; - } + if (rc != 0) + DPRINTK(1, "sdio error=%d size=%d\n", rc, length); return rc; } diff --git a/drivers/staging/ks7010/ks_wlan.h b/drivers/staging/ks7010/ks_wlan.h index f0f9f8e..a2126c2 100644 --- a/drivers/staging/ks7010/ks_wlan.h +++ b/drivers/staging/ks7010/ks_wlan.h @@ -500,9 +500,7 @@ struct ks_wlan_private { unsigned long last_doze; unsigned long last_wakeup; - uint sdio_error_count; /* SDIO error */ uint wakeup_count; /* for detect wakeup loop */ - }; #endif /* _KS_WLAN_H */ -- cgit v0.10.2 From c5d9a03031a645a8c63fdaa6a650113f8bd55b2b Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Tue, 31 May 2016 12:56:43 +0200 Subject: staging: ks7010: cleanup file headers Remove svn-ids and fix typos in the licence declaration. Add my copyright to the sdio code which I worked on mainly. Signed-off-by: Wolfram Sang Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/ks7010/eap_packet.h b/drivers/staging/ks7010/eap_packet.h index 88384fb..16a392a 100644 --- a/drivers/staging/ks7010/eap_packet.h +++ b/drivers/staging/ks7010/eap_packet.h @@ -1,9 +1,3 @@ -/* - * - * eap_packet.h - * $Id: eap_packet.h 991 2009-09-14 01:38:58Z sekine $ - * - */ #ifndef EAP_PACKET_H #define EAP_PACKET_H diff --git a/drivers/staging/ks7010/ks7010_sdio.c b/drivers/staging/ks7010/ks7010_sdio.c index c166022..c340254 100644 --- a/drivers/staging/ks7010/ks7010_sdio.c +++ b/drivers/staging/ks7010/ks7010_sdio.c @@ -1,15 +1,13 @@ /* * Driver for KeyStream, KS7010 based SDIO cards. * - * ks7010_sdio.c - * $Id: ks7010_sdio.c 996 2009-09-14 02:54:21Z sekine $ - * * Copyright (C) 2006-2008 KeyStream Corp. * Copyright (C) 2009 Renesas Technology Corp. + * Copyright (C) 2016 Sang Engineering, Wolfram Sang * * This program is free software; you can redistribute it and/or modify - * it undr the terms of the GNU General Public License version 2 as - * published by the Free Sotware Foundation. + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. */ #include diff --git a/drivers/staging/ks7010/ks7010_sdio.h b/drivers/staging/ks7010/ks7010_sdio.h index 2d7be5d..987cfa7 100644 --- a/drivers/staging/ks7010/ks7010_sdio.h +++ b/drivers/staging/ks7010/ks7010_sdio.h @@ -1,16 +1,12 @@ /* - * * Driver for KeyStream, KS7010 based SDIO cards. - * - * ks7010_sdio.h - * $Id: ks7010_sdio.h 1019 2009-09-28 05:41:07Z sekine $ * * Copyright (C) 2006-2008 KeyStream Corp. * Copyright (C) 2009 Renesas Technology Corp. * * This program is free software; you can redistribute it and/or modify - * it undr the terms of the GNU General Public License version 2 as - * published by the Free Sotware Foundation. + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. */ #ifndef _KS7010_SDIO_H #define _KS7010_SDIO_H diff --git a/drivers/staging/ks7010/ks_hostif.c b/drivers/staging/ks7010/ks_hostif.c index f2a65c0..a8822fe 100644 --- a/drivers/staging/ks7010/ks_hostif.c +++ b/drivers/staging/ks7010/ks_hostif.c @@ -1,15 +1,12 @@ /* * Driver for KeyStream wireless LAN cards. * - * ks_hostif.c - * $Id: ks_hostif.c 996 2009-09-14 02:54:21Z sekine $ - * * Copyright (C) 2005-2008 KeyStream Corp. * Copyright (C) 2009 Renesas Technology Corp. * * This program is free software; you can redistribute it and/or modify - * it undr the terms of the GNU General Public License version 2 as - * published by the Free Sotware Foundation. + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. */ #include "ks_wlan.h" diff --git a/drivers/staging/ks7010/ks_hostif.h b/drivers/staging/ks7010/ks_hostif.h index 01de478..dc806b5b 100644 --- a/drivers/staging/ks7010/ks_hostif.h +++ b/drivers/staging/ks7010/ks_hostif.h @@ -1,15 +1,12 @@ /* * Driver for KeyStream wireless LAN * - * ks_hostif.h - * $Id: ks_hostif.h 994 2009-09-14 01:51:16Z sekine $ - * * Copyright (c) 2005-2008 KeyStream Corp. * Copyright (C) 2009 Renesas Technology Corp. * * This program is free software; you can redistribute it and/or modify - * it undr the terms of the GNU General Public License version 2 as - * published by the Free Sotware Foundation. + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. */ #ifndef _KS_HOSTIF_H_ diff --git a/drivers/staging/ks7010/ks_wlan.h b/drivers/staging/ks7010/ks_wlan.h index a2126c2..c42d99c 100644 --- a/drivers/staging/ks7010/ks_wlan.h +++ b/drivers/staging/ks7010/ks_wlan.h @@ -1,15 +1,12 @@ /* * Driver for KeyStream IEEE802.11 b/g wireless LAN cards. - * - * ks_wlan.h - * $Id: ks_wlan.h 994 2009-09-14 01:51:16Z sekine $ * * Copyright (C) 2006-2008 KeyStream Corp. * Copyright (C) 2009 Renesas Technology Corp. * * This program is free software; you can redistribute it and/or modify - * it undr the terms of the GNU General Public License version 2 as - * published by the Free Sotware Foundation. + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. */ #ifndef _KS_WLAN_H diff --git a/drivers/staging/ks7010/ks_wlan_ioctl.h b/drivers/staging/ks7010/ks_wlan_ioctl.h index cc4669e..f1fb2dd 100644 --- a/drivers/staging/ks7010/ks_wlan_ioctl.h +++ b/drivers/staging/ks7010/ks_wlan_ioctl.h @@ -1,15 +1,12 @@ /* * Driver for KeyStream 11b/g wireless LAN * - * ks_wlan_ioctl.h - * $Id: ks_wlan_ioctl.h 996 2009-09-14 02:54:21Z sekine $ - * * Copyright (c) 2005-2008 KeyStream Corp. * Copyright (C) 2009 Renesas Technology Corp. * * This program is free software; you can redistribute it and/or modify - * it undr the terms of the GNU General Public License version 2 as - * published by the Free Sotware Foundation. + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. */ #ifndef _KS_WLAN_IOCTL_H diff --git a/drivers/staging/ks7010/ks_wlan_net.c b/drivers/staging/ks7010/ks_wlan_net.c index ac3354b..8ef0f11 100644 --- a/drivers/staging/ks7010/ks_wlan_net.c +++ b/drivers/staging/ks7010/ks_wlan_net.c @@ -1,15 +1,12 @@ /* * Driver for KeyStream 11b/g wireless LAN * - * ks_wlan_net.c - * $Id: ks_wlan_net.c 1020 2009-09-28 05:48:31Z sekine $ - * * Copyright (C) 2005-2008 KeyStream Corp. * Copyright (C) 2009 Renesas Technology Corp. * * This program is free software; you can redistribute it and/or modify - * it undr the terms of the GNU General Public License version 2 as - * published by the Free Sotware Foundation. + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. */ #include diff --git a/drivers/staging/ks7010/michael_mic.c b/drivers/staging/ks7010/michael_mic.c index adb17df..e14c109 100644 --- a/drivers/staging/ks7010/michael_mic.c +++ b/drivers/staging/ks7010/michael_mic.c @@ -1,15 +1,12 @@ /* * Driver for KeyStream wireless LAN * - * michael_mic.c - * $Id: michael_mic.c 991 2009-09-14 01:38:58Z sekine $ - * * Copyright (C) 2005-2008 KeyStream Corp. * Copyright (C) 2009 Renesas Technology Corp. * * This program is free software; you can redistribute it and/or modify - * it undr the terms of the GNU General Public License version 2 as - * published by the Free Sotware Foundation. + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. */ #include diff --git a/drivers/staging/ks7010/michael_mic.h b/drivers/staging/ks7010/michael_mic.h index 57ecbe3..c7e4eb2 100644 --- a/drivers/staging/ks7010/michael_mic.h +++ b/drivers/staging/ks7010/michael_mic.h @@ -1,15 +1,12 @@ /* * Driver for KeyStream wireless LAN - * - * michael_mic.h - * $Id: michael_mic.h 991 2009-09-14 01:38:58Z sekine $ * * Copyright (C) 2005-2008 KeyStream Corp. * Copyright (C) 2009 Renesas Technology Corp. * * This program is free software; you can redistribute it and/or modify - * it undr the terms of the GNU General Public License version 2 as - * published by the Free Sotware Foundation. + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. */ /* MichelMIC routine define */ -- cgit v0.10.2 From 9c4dfdaa256715b08ef907c3533288f606fe78a0 Mon Sep 17 00:00:00 2001 From: Tim Sell Date: Thu, 12 May 2016 09:14:40 -0400 Subject: staging: unisys: visorhba: delete processing of vdiskmgmt commands We never issue SCSI commands of type CMD_VDISKMGMT_TYPE, so there is no need to have code that processes their completions. Signed-off-by: Tim Sell Signed-off-by: David Kershner Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/unisys/visorhba/visorhba_main.c b/drivers/staging/unisys/visorhba/visorhba_main.c index 6a4570d..085d782 100644 --- a/drivers/staging/unisys/visorhba/visorhba_main.c +++ b/drivers/staging/unisys/visorhba/visorhba_main.c @@ -706,13 +706,6 @@ static void visorhba_serverdown_complete(struct visorhba_devdata *devdata) wake_up_all((wait_queue_head_t *) cmdrsp->scsitaskmgmt.notify_handle); break; - case CMD_VDISKMGMT_TYPE: - cmdrsp = pendingdel->sent; - cmdrsp->vdiskmgmt.notifyresult_handle - = VDISK_MGMT_FAILED; - wake_up_all((wait_queue_head_t *) - cmdrsp->vdiskmgmt.notify_handle); - break; default: break; } @@ -878,16 +871,6 @@ complete_scsi_command(struct uiscmdrsp *cmdrsp, struct scsi_cmnd *scsicmd) scsicmd->scsi_done(scsicmd); } -/* DELETE VDISK TASK MGMT COMMANDS */ -static inline void complete_vdiskmgmt_command(struct uiscmdrsp *cmdrsp) -{ - /* copy the result of the taskmgmt and - * wake up the error handler that is waiting for this - */ - cmdrsp->vdiskmgmt.notifyresult_handle = cmdrsp->vdiskmgmt.result; - wake_up_all((wait_queue_head_t *)cmdrsp->vdiskmgmt.notify_handle); -} - /** * complete_taskmgmt_command - complete task management * @cmdrsp: Response from the IOVM @@ -1003,11 +986,6 @@ drain_queue(struct uiscmdrsp *cmdrsp, struct visorhba_devdata *devdata) */ cmdrsp->disknotify.v_hba = NULL; process_disk_notify(shost, cmdrsp); - } else if (cmdrsp->cmdtype == CMD_VDISKMGMT_TYPE) { - if (!del_scsipending_ent(devdata, - cmdrsp->vdiskmgmt.handle)) - break; - complete_vdiskmgmt_command(cmdrsp); } /* cmdrsp is now available for resuse */ } -- cgit v0.10.2 From a7d656063e55f8227a54fad99270b26472719ff1 Mon Sep 17 00:00:00 2001 From: Tim Sell Date: Thu, 12 May 2016 09:14:41 -0400 Subject: staging: unisys: visorhba: correct scsi task mgmt completion handling This patch is necessary to enable ANY task mgmt command to complete successfully via visorhba. When issuing a task mgmt command (CMD_SCSITASKMGMT_TYPE) to the IO partition (back-end), forward_taskmgmt_command() includes pointers within the command area that will be used to wake up the issuing process and provide the result when the command completes: cmdrsp->scsitaskmgmt.notify_handle = (u64)¬ifyevent; cmdrsp->scsitaskmgmt.notifyresult_handle = (u64)¬ifyresult; 'notify_handle' is a pointer to a 'wait_queue_head_t' variable, and 'notifyresult' is a pointer to an int. Both of these are just local stack variables in the issuing process. The way it's supposed to happen is that when the IO partition completes the command, in our completion handling we get copies of those pointers back from the IO partition, where we stash the result of the command at '*notifyresult' (which should not be 0xffff, because that is the initial value that the caller is looking to see a change in), and wake up the wait queue at '*notify_handle'. There are several places we do that dance, but prior to this patch, we always do it WRONG, like: cmdrsp->scsitaskmgmt.notifyresult_handle = TASK_MGMT_FAILED; wake_up_all((wait_queue_head_t *)cmdrsp->scsitaskmgmt.notify_handle); The wake_up_all() part is correct (albeit with the help of the sloppy pointer casting, but that's irrelevant to the bug), but the assignment of 'notifyresult_handle' is WRONG, and SHOULD read: *(int *)(cmdrsp->scsitaskmgmt.notifyresult_handle) = TASK_MGMT_FAILED; Without this change, the caller is NEVER going to notice a change in his local value of 'notifyresult' when he does the: if (!wait_event_timeout(notifyevent, notifyresult != 0xffff, msecs_to_jiffies(45000))) and hence will be timing out EVERY taskmgmt command. This patch also eliminates the need for sloppy casting of pointers back-and-forth between u64 values, with the help of idr_alloc() to provide handles for us. It is the generated int handles we pass to the IO partition to denote our completion context, and these are validated and converted back to the required pointers when the task mgmt commands are returned back to us by the IO partition. == Testing == You must enable dynamic debugging in visorhba (build kernel with 'CONFIG_DYNAMIC_DEBUG=y', provide kernel parameter 'visorhba.dyndbg=+p') to see kernel messages involved with visorhba scsi task mgmt commands, which were added in this patch in the form of a few dev_dbg() / pr_debug() messages. In order to inject faults necessary to get visorhba to actully issue scsi task mgmt commands, you will need to compile a kernel with CONFIG_FAIL_IO_TIMEOUT and friends, in the "Kernel hacking" section: * Enable "Fault-injection framework" * Enable "Fault-injection capability for disk IO" * Enable "Fault-injection capability for faking disk interrupts" * Enable "Debugfs entries for fault-injection capabilities" When running a kernel with those options, you can manually inject a fault that will force a scsi task mgmt command to be issued like this: # mount -t debugfs nodev /sys/kernel/debug # cd /sys/kernel/debug/fail_io_timeout # cat interval 1 # cat probability 0 # cat times 1 # echo 100 >probability # cd /sys/block/sda # l | grep fail -rw-r--r-- 1 root root 4096 May 5 10:53 io-timeout-fail -rw-r--r-- 1 root root 4096 May 5 10:54 make-it-fail # echo 1 >io-timeout-fail # echo 1 >make-it-fail To test this patch, after performing the above steps, I did something to force a block device i/o, then shortly afterwards examined the kernel log. There I found evidence that visorhba had successfully issued a task mgmt command, and that it completed successfully: [ 333.352612] FAULT_INJECTION: forcing a failure. name fail_io_timeout, interval 1, probability 100, space 0, times 1 [ 333.352617] CPU: 0 PID: 295 Comm: vhba_incoming Tainted: G C 4.6.0-rc3-ARCH+ #2 [ 333.352619] Hardware name: Dell Inc. PowerEdge T110/ , BIOS 1.23 12/15/2009 [ 333.352620] 0000000000000000 ffff88001d1a7dd0 ffffffff8125beeb ffffffff818507c0 [ 333.352623] 0000000000000064 ffff88001d1a7df0 ffffffff8128047a ffff8800113462b0 [ 333.352625] ffff88000e523000 ffff88001d1a7e00 ffffffff81241c79 ffff88001d1a7e18 [ 333.352627] Call Trace: [ 333.352634] [] dump_stack+0x4d/0x72 [ 333.352637] [] should_fail+0x11a/0x120 [ 333.352641] [] blk_should_fake_timeout+0x29/0x30 [ 333.352643] [] blk_complete_request+0x16/0x30 [ 333.352654] [] scsi_done+0x26/0x80 [scsi_mod] [ 333.352657] [] process_incoming_rsps+0x2bc/0x770 [visorhba] [ 333.352661] [] ? wait_woken+0x80/0x80 [ 333.352663] [] ? add_scsipending_entry+0x100/0x100 [visorhba] [ 333.352666] [] kthread+0xc9/0xe0 [ 333.352669] [] ret_from_fork+0x22/0x40 [ 333.352671] [] ? kthread_create_on_node+0x180/0x180 [ 364.025672] sd 0:0:1:1: visorhba: initiating type=1 taskmgmt command [ 364.029721] visorhba: notifying initiator with result=0x1 [ 364.029726] sd 0:0:1:1: visorhba: taskmgmt type=1 success; result=0x1 Signed-off-by: Tim Sell Signed-off-by: David Kershner Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/unisys/visorhba/visorhba_main.c b/drivers/staging/unisys/visorhba/visorhba_main.c index 085d782..c4a9f32 100644 --- a/drivers/staging/unisys/visorhba/visorhba_main.c +++ b/drivers/staging/unisys/visorhba/visorhba_main.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -133,6 +134,12 @@ struct visorhba_devdata { int devnum; struct task_struct *thread; int thread_wait_ms; + + /* + * allows us to pass int handles back-and-forth between us and + * iovm, instead of raw pointers + */ + struct idr idr; }; struct visorhba_devices_open { @@ -269,6 +276,62 @@ static struct uiscmdrsp *get_scsipending_cmdrsp(struct visorhba_devdata *ddata, } /** + * simple_idr_get - associate a provided pointer with an int value + * 1 <= value <= INT_MAX, and return this int value; + * the pointer value can be obtained later by passing + * this int value to idr_find() + * @idrtable: the data object maintaining the pointer<-->int mappings + * @p: the pointer value to be remembered + * @lock: a spinlock used when exclusive access to idrtable is needed + */ +static unsigned int simple_idr_get(struct idr *idrtable, void *p, + spinlock_t *lock) +{ + int id; + unsigned long flags; + + idr_preload(GFP_KERNEL); + spin_lock_irqsave(lock, flags); + id = idr_alloc(idrtable, p, 1, INT_MAX, GFP_NOWAIT); + spin_unlock_irqrestore(lock, flags); + idr_preload_end(); + if (id < 0) + return 0; /* failure */ + return (unsigned int)(id); /* idr_alloc() guarantees > 0 */ +} + +/** + * setup_scsitaskmgmt_handles - stash the necessary handles so that the + * completion processing logic for a taskmgmt + * cmd will be able to find who to wake up + * and where to stash the result + */ +static void setup_scsitaskmgmt_handles(struct idr *idrtable, spinlock_t *lock, + struct uiscmdrsp *cmdrsp, + wait_queue_head_t *event, int *result) +{ + /* specify the event that has to be triggered when this */ + /* cmd is complete */ + cmdrsp->scsitaskmgmt.notify_handle = + simple_idr_get(idrtable, event, lock); + cmdrsp->scsitaskmgmt.notifyresult_handle = + simple_idr_get(idrtable, result, lock); +} + +/** + * cleanup_scsitaskmgmt_handles - forget handles created by + * setup_scsitaskmgmt_handles() + */ +static void cleanup_scsitaskmgmt_handles(struct idr *idrtable, + struct uiscmdrsp *cmdrsp) +{ + if (cmdrsp->scsitaskmgmt.notify_handle) + idr_remove(idrtable, cmdrsp->scsitaskmgmt.notify_handle); + if (cmdrsp->scsitaskmgmt.notifyresult_handle) + idr_remove(idrtable, cmdrsp->scsitaskmgmt.notifyresult_handle); +} + +/** * forward_taskmgmt_command - send taskmegmt command to the Service * Partition * @tasktype: Type of taskmgmt command @@ -303,10 +366,8 @@ static int forward_taskmgmt_command(enum task_mgmt_types tasktype, /* issue TASK_MGMT_ABORT_TASK */ cmdrsp->cmdtype = CMD_SCSITASKMGMT_TYPE; - /* specify the event that has to be triggered when this */ - /* cmd is complete */ - cmdrsp->scsitaskmgmt.notify_handle = (u64)¬ifyevent; - cmdrsp->scsitaskmgmt.notifyresult_handle = (u64)¬ifyresult; + setup_scsitaskmgmt_handles(&devdata->idr, &devdata->privlock, cmdrsp, + ¬ifyevent, ¬ifyresult); /* save destination */ cmdrsp->scsitaskmgmt.tasktype = tasktype; @@ -315,6 +376,8 @@ static int forward_taskmgmt_command(enum task_mgmt_types tasktype, cmdrsp->scsitaskmgmt.vdest.lun = scsidev->lun; cmdrsp->scsitaskmgmt.handle = scsicmd_id; + dev_dbg(&scsidev->sdev_gendev, + "visorhba: initiating type=%d taskmgmt command\n", tasktype); if (!visorchannel_signalinsert(devdata->dev->visorchannel, IOCHAN_TO_IOPART, cmdrsp)) @@ -327,17 +390,23 @@ static int forward_taskmgmt_command(enum task_mgmt_types tasktype, msecs_to_jiffies(45000))) goto err_del_scsipending_ent; + dev_dbg(&scsidev->sdev_gendev, + "visorhba: taskmgmt type=%d success; result=0x%x\n", + tasktype, notifyresult); if (tasktype == TASK_MGMT_ABORT_TASK) scsicmd->result = DID_ABORT << 16; else scsicmd->result = DID_RESET << 16; scsicmd->scsi_done(scsicmd); - + cleanup_scsitaskmgmt_handles(&devdata->idr, cmdrsp); return SUCCESS; err_del_scsipending_ent: + dev_dbg(&scsidev->sdev_gendev, + "visorhba: taskmgmt type=%d not executed\n", tasktype); del_scsipending_ent(devdata, scsicmd_id); + cleanup_scsitaskmgmt_handles(&devdata->idr, cmdrsp); return FAILED; } @@ -667,6 +736,35 @@ static ssize_t info_debugfs_read(struct file *file, char __user *buf, } /** + * complete_taskmgmt_command - complete task management + * @cmdrsp: Response from the IOVM + * + * Service Partition returned the result of the task management + * command. Wake up anyone waiting for it. + * Returns void + */ +static inline void complete_taskmgmt_command +(struct idr *idrtable, struct uiscmdrsp *cmdrsp, int result) +{ + wait_queue_head_t *wq = + idr_find(idrtable, cmdrsp->scsitaskmgmt.notify_handle); + int *scsi_result_ptr = + idr_find(idrtable, cmdrsp->scsitaskmgmt.notifyresult_handle); + + if (unlikely(!(wq && scsi_result_ptr))) { + pr_err("visorhba: no completion context; cmd will time out\n"); + return; + } + + /* copy the result of the taskmgmt and + * wake up the error handler that is waiting for this + */ + pr_debug("visorhba: notifying initiator with result=0x%x\n", result); + *scsi_result_ptr = result; + wake_up_all(wq); +} + +/** * visorhba_serverdown_complete - Called when we are done cleaning up * from serverdown * @work: work structure for this serverdown request @@ -701,10 +799,8 @@ static void visorhba_serverdown_complete(struct visorhba_devdata *devdata) break; case CMD_SCSITASKMGMT_TYPE: cmdrsp = pendingdel->sent; - cmdrsp->scsitaskmgmt.notifyresult_handle - = TASK_MGMT_FAILED; - wake_up_all((wait_queue_head_t *) - cmdrsp->scsitaskmgmt.notify_handle); + complete_taskmgmt_command(&devdata->idr, cmdrsp, + TASK_MGMT_FAILED); break; default: break; @@ -871,23 +967,6 @@ complete_scsi_command(struct uiscmdrsp *cmdrsp, struct scsi_cmnd *scsicmd) scsicmd->scsi_done(scsicmd); } -/** - * complete_taskmgmt_command - complete task management - * @cmdrsp: Response from the IOVM - * - * Service Partition returned the result of the task management - * command. Wake up anyone waiting for it. - * Returns void - */ -static inline void complete_taskmgmt_command(struct uiscmdrsp *cmdrsp) -{ - /* copy the result of the taskgmgt and - * wake up the error handler that is waiting for this - */ - cmdrsp->vdiskmgmt.notifyresult_handle = cmdrsp->vdiskmgmt.result; - wake_up_all((wait_queue_head_t *)cmdrsp->scsitaskmgmt.notify_handle); -} - static struct work_struct dar_work_queue; static struct diskaddremove *dar_work_queue_head; static spinlock_t dar_work_queue_lock; /* Lock to protet dar_work_queue_head */ @@ -978,7 +1057,8 @@ drain_queue(struct uiscmdrsp *cmdrsp, struct visorhba_devdata *devdata) if (!del_scsipending_ent(devdata, cmdrsp->scsitaskmgmt.handle)) break; - complete_taskmgmt_command(cmdrsp); + complete_taskmgmt_command(&devdata->idr, cmdrsp, + cmdrsp->scsitaskmgmt.result); } else if (cmdrsp->cmdtype == CMD_NOTIFYGUEST_TYPE) { /* The vHba pointer has no meaning in a * guest partition. Let's be safe and set it @@ -1140,6 +1220,8 @@ static int visorhba_probe(struct visor_device *dev) if (err) goto err_scsi_remove_host; + idr_init(&devdata->idr); + devdata->thread_wait_ms = 2; devdata->thread = visor_thread_start(process_incoming_rsps, devdata, "vhba_incoming"); @@ -1176,6 +1258,8 @@ static void visorhba_remove(struct visor_device *dev) scsi_remove_host(scsihost); scsi_host_put(scsihost); + idr_destroy(&devdata->idr); + dev_set_drvdata(&dev->device, NULL); } -- cgit v0.10.2 From bf817f2f40d79dd0dfd7d800e174d8bac5257935 Mon Sep 17 00:00:00 2001 From: Tim Sell Date: Thu, 12 May 2016 09:14:42 -0400 Subject: staging: unisys: visorhba: remove unused (and broken) logic The handling of CMD_NOTIFYGUEST_TYPE messages from the IO partition appears to be only partially implemented, but fortunately it is never used in our current environment. This patch deletes the unused code. Signed-off-by: Tim Sell Signed-off-by: David Kershner Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/unisys/visorhba/visorhba_main.c b/drivers/staging/unisys/visorhba/visorhba_main.c index c4a9f32..5ea6bb2 100644 --- a/drivers/staging/unisys/visorhba/visorhba_main.c +++ b/drivers/staging/unisys/visorhba/visorhba_main.c @@ -100,14 +100,6 @@ struct scsipending { char cmdtype; /* Type of pointer that is being stored */ }; -/* Work Data for dar_work_queue */ -struct diskaddremove { - u8 add; /* 0-remove, 1-add */ - struct Scsi_Host *shost; /* Scsi Host for this visorhba instance */ - u32 channel, id, lun; /* Disk Path */ - struct diskaddremove *next; -}; - /* Each scsi_host has a host_data area that contains this struct. */ struct visorhba_devdata { struct Scsi_Host *scsihost; @@ -967,62 +959,6 @@ complete_scsi_command(struct uiscmdrsp *cmdrsp, struct scsi_cmnd *scsicmd) scsicmd->scsi_done(scsicmd); } -static struct work_struct dar_work_queue; -static struct diskaddremove *dar_work_queue_head; -static spinlock_t dar_work_queue_lock; /* Lock to protet dar_work_queue_head */ -static unsigned short dar_work_queue_sched; - -/** - * queue_disk_add_remove - IOSP has sent us a add/remove request - * @dar: disk add/remove request - * - * Queue the work needed to add/remove a disk. - * Returns void - */ -static inline void queue_disk_add_remove(struct diskaddremove *dar) -{ - unsigned long flags; - - spin_lock_irqsave(&dar_work_queue_lock, flags); - if (!dar_work_queue_head) { - dar_work_queue_head = dar; - dar->next = NULL; - } else { - dar->next = dar_work_queue_head; - dar_work_queue_head = dar; - } - if (!dar_work_queue_sched) { - schedule_work(&dar_work_queue); - dar_work_queue_sched = 1; - } - spin_unlock_irqrestore(&dar_work_queue_lock, flags); -} - -/** - * process_disk_notify - IOSP has sent a process disk notify event - * @shost: Scsi hot - * @cmdrsp: Response from the IOSP - * - * Queue it to the work queue. - * Return void. - */ -static void process_disk_notify(struct Scsi_Host *shost, - struct uiscmdrsp *cmdrsp) -{ - struct diskaddremove *dar; - - dar = kzalloc(sizeof(*dar), GFP_ATOMIC); - if (!dar) - return; - - dar->add = cmdrsp->disknotify.add; - dar->shost = shost; - dar->channel = cmdrsp->disknotify.channel; - dar->id = cmdrsp->disknotify.id; - dar->lun = cmdrsp->disknotify.lun; - queue_disk_add_remove(dar); -} - /** * drain_queue - pull responses out of iochannel * @cmdrsp: Response from the IOSP @@ -1035,7 +971,6 @@ static void drain_queue(struct uiscmdrsp *cmdrsp, struct visorhba_devdata *devdata) { struct scsi_cmnd *scsicmd; - struct Scsi_Host *shost = devdata->scsihost; while (1) { if (!visorchannel_signalremove(devdata->dev->visorchannel, @@ -1059,15 +994,10 @@ drain_queue(struct uiscmdrsp *cmdrsp, struct visorhba_devdata *devdata) break; complete_taskmgmt_command(&devdata->idr, cmdrsp, cmdrsp->scsitaskmgmt.result); - } else if (cmdrsp->cmdtype == CMD_NOTIFYGUEST_TYPE) { - /* The vHba pointer has no meaning in a - * guest partition. Let's be safe and set it - * to NULL now. Do not use it here! - */ - cmdrsp->disknotify.v_hba = NULL; - process_disk_notify(shost, cmdrsp); - } - /* cmdrsp is now available for resuse */ + } else if (cmdrsp->cmdtype == CMD_NOTIFYGUEST_TYPE) + dev_err_once(&devdata->dev->device, + "ignoring unsupported NOTIFYGUEST\n"); + /* cmdrsp is now available for re-use */ } } -- cgit v0.10.2 From 5e1073d3f4017980f256b06725229014829b821d Mon Sep 17 00:00:00 2001 From: Tim Sell Date: Thu, 12 May 2016 09:14:43 -0400 Subject: staging: unisys: visorhba: simplify and enhance debugfs interface debugfs info for each visorhba device is now presented by a file named of the following form within the debugfs tree: visorhba/vbus:dev/info where is the vbus number, and is the relative device number. Also, the debugfs presentation function was converted to use the seq_file interface, so that it could access the device context without resorting to a global array. This also simplified the function. Signed-off-by: Tim Sell Signed-off-by: David Kershner Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/unisys/visorhba/visorhba_main.c b/drivers/staging/unisys/visorhba/visorhba_main.c index 5ea6bb2..6a21514 100644 --- a/drivers/staging/unisys/visorhba/visorhba_main.c +++ b/drivers/staging/unisys/visorhba/visorhba_main.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -51,14 +52,7 @@ static int visorhba_pause(struct visor_device *dev, static int visorhba_resume(struct visor_device *dev, visorbus_state_complete_func complete_func); -static ssize_t info_debugfs_read(struct file *file, char __user *buf, - size_t len, loff_t *offset); -static int set_no_disk_inquiry_result(unsigned char *buf, - size_t len, bool is_lun0); static struct dentry *visorhba_debugfs_dir; -static const struct file_operations debugfs_info_fops = { - .read = info_debugfs_read, -}; /* GUIDS for HBA channel type supported by this driver */ static struct visor_channeltype_descriptor visorhba_channel_types[] = { @@ -132,6 +126,9 @@ struct visorhba_devdata { * iovm, instead of raw pointers */ struct idr idr; + + struct dentry *debugfs_dir; + struct dentry *debugfs_info; }; struct visorhba_devices_open { @@ -667,66 +664,49 @@ static struct scsi_host_template visorhba_driver_template = { }; /** - * info_debugfs_read - debugfs interface to dump visorhba states - * @file: Debug file - * @buf: buffer to send back to user - * @len: len that can be written to buf - * @offset: offset into buf + * info_debugfs_show - debugfs interface to dump visorhba states * - * Dumps information about the visorhba driver and devices - * TODO: Make this per vhba - * Returns bytes_read + * This presents a file in the debugfs tree named: + * /visorhba/vbus:dev/info */ -static ssize_t info_debugfs_read(struct file *file, char __user *buf, - size_t len, loff_t *offset) +static int info_debugfs_show(struct seq_file *seq, void *v) { - ssize_t bytes_read = 0; - int str_pos = 0; - u64 phys_flags_addr; - int i; - struct visorhba_devdata *devdata; - char *vbuf; - - if (len > MAX_BUF) - len = MAX_BUF; - vbuf = kzalloc(len, GFP_KERNEL); - if (!vbuf) - return -ENOMEM; - - for (i = 0; i < VISORHBA_OPEN_MAX; i++) { - if (!visorhbas_open[i].devdata) - continue; - - devdata = visorhbas_open[i].devdata; - - str_pos += scnprintf(vbuf + str_pos, - len - str_pos, "max_buff_len:%u\n", - devdata->max_buff_len); - - str_pos += scnprintf(vbuf + str_pos, len - str_pos, - "\ninterrupts_rcvd = %llu, interrupts_disabled = %llu\n", - devdata->interrupts_rcvd, - devdata->interrupts_disabled); - str_pos += scnprintf(vbuf + str_pos, - len - str_pos, "\ninterrupts_notme = %llu,\n", - devdata->interrupts_notme); - phys_flags_addr = virt_to_phys((__force void *) - devdata->flags_addr); - str_pos += scnprintf(vbuf + str_pos, len - str_pos, - "flags_addr = %p, phys_flags_addr=0x%016llx, FeatureFlags=%llu\n", - devdata->flags_addr, phys_flags_addr, - (__le64)readq(devdata->flags_addr)); - str_pos += scnprintf(vbuf + str_pos, - len - str_pos, "acquire_failed_cnt:%llu\n", - devdata->acquire_failed_cnt); - str_pos += scnprintf(vbuf + str_pos, len - str_pos, "\n"); + struct visorhba_devdata *devdata = seq->private; + + seq_printf(seq, "max_buff_len = %u\n", devdata->max_buff_len); + seq_printf(seq, "interrupts_rcvd = %llu\n", devdata->interrupts_rcvd); + seq_printf(seq, "interrupts_disabled = %llu\n", + devdata->interrupts_disabled); + seq_printf(seq, "interrupts_notme = %llu\n", + devdata->interrupts_notme); + seq_printf(seq, "flags_addr = %p\n", devdata->flags_addr); + if (devdata->flags_addr) { + u64 phys_flags_addr = + virt_to_phys((__force void *)devdata->flags_addr); + seq_printf(seq, "phys_flags_addr = 0x%016llx\n", + phys_flags_addr); + seq_printf(seq, "FeatureFlags = %llu\n", + (__le64)readq(devdata->flags_addr)); } + seq_printf(seq, "acquire_failed_cnt = %llu\n", + devdata->acquire_failed_cnt); - bytes_read = simple_read_from_buffer(buf, len, offset, vbuf, str_pos); - kfree(vbuf); - return bytes_read; + return 0; } +static int info_debugfs_open(struct inode *inode, struct file *file) +{ + return single_open(file, info_debugfs_show, inode->i_private); +} + +static const struct file_operations info_debugfs_fops = { + .owner = THIS_MODULE, + .open = info_debugfs_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + /** * complete_taskmgmt_command - complete task management * @cmdrsp: Response from the IOVM @@ -1134,6 +1114,21 @@ static int visorhba_probe(struct visor_device *dev) devdata->dev = dev; dev_set_drvdata(&dev->device, devdata); + devdata->debugfs_dir = debugfs_create_dir(dev_name(&dev->device), + visorhba_debugfs_dir); + if (!devdata->debugfs_dir) { + err = -ENOMEM; + goto err_scsi_remove_host; + } + devdata->debugfs_info = + debugfs_create_file("info", S_IRUSR | S_IRGRP, + devdata->debugfs_dir, devdata, + &info_debugfs_fops); + if (!devdata->debugfs_info) { + err = -ENOMEM; + goto err_debugfs_dir; + } + init_waitqueue_head(&devdata->rsp_queue); spin_lock_init(&devdata->privlock); devdata->serverdown = false; @@ -1144,11 +1139,11 @@ static int visorhba_probe(struct visor_device *dev) channel_header.features); err = visorbus_read_channel(dev, channel_offset, &features, 8); if (err) - goto err_scsi_remove_host; + goto err_debugfs_info; features |= ULTRA_IO_CHANNEL_IS_POLLING; err = visorbus_write_channel(dev, channel_offset, &features, 8); if (err) - goto err_scsi_remove_host; + goto err_debugfs_info; idr_init(&devdata->idr); @@ -1160,6 +1155,12 @@ static int visorhba_probe(struct visor_device *dev) return 0; +err_debugfs_info: + debugfs_remove(devdata->debugfs_info); + +err_debugfs_dir: + debugfs_remove_recursive(devdata->debugfs_dir); + err_scsi_remove_host: scsi_remove_host(scsihost); @@ -1191,6 +1192,8 @@ static void visorhba_remove(struct visor_device *dev) idr_destroy(&devdata->idr); dev_set_drvdata(&dev->device, NULL); + debugfs_remove(devdata->debugfs_info); + debugfs_remove_recursive(devdata->debugfs_dir); } /** @@ -1201,21 +1204,12 @@ static void visorhba_remove(struct visor_device *dev) */ static int visorhba_init(void) { - struct dentry *ret; int rc = -ENOMEM; visorhba_debugfs_dir = debugfs_create_dir("visorhba", NULL); if (!visorhba_debugfs_dir) return -ENOMEM; - ret = debugfs_create_file("info", S_IRUSR, visorhba_debugfs_dir, NULL, - &debugfs_info_fops); - - if (!ret) { - rc = -EIO; - goto cleanup_debugfs; - } - rc = visorbus_register_visor_driver(&visorhba_driver); if (rc) goto cleanup_debugfs; -- cgit v0.10.2 From d91184a9c6824205eb6072227bfc1f0beee2ade5 Mon Sep 17 00:00:00 2001 From: Tim Sell Date: Thu, 12 May 2016 09:14:44 -0400 Subject: staging: unisys: visorhba: visorhbas_open[] no longer used, so deleted The prior patch which simplified the visorhba debugfs interface made it so visorhbas_open[] and VISORHBA_OPEN_MAX were no longer needed, so they have now been deleted. Signed-off-by: Tim Sell Signed-off-by: David Kershner Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/unisys/visorhba/visorhba_main.c b/drivers/staging/unisys/visorhba/visorhba_main.c index 6a21514..11985bb 100644 --- a/drivers/staging/unisys/visorhba/visorhba_main.c +++ b/drivers/staging/unisys/visorhba/visorhba_main.c @@ -35,7 +35,6 @@ #define MAX_BUF 8192 #define MAX_PENDING_REQUESTS (MIN_NUMSIGNALS * 2) #define VISORHBA_ERROR_COUNT 30 -#define VISORHBA_OPEN_MAX 1 static int visorhba_queue_command_lck(struct scsi_cmnd *scsicmd, void (*visorhba_cmnd_done) @@ -135,8 +134,6 @@ struct visorhba_devices_open { struct visorhba_devdata *devdata; }; -static struct visorhba_devices_open visorhbas_open[VISORHBA_OPEN_MAX]; - #define for_each_vdisk_match(iter, list, match) \ for (iter = &list->head; iter->next; iter = iter->next) \ if ((iter->channel == match->channel) && \ @@ -1075,7 +1072,7 @@ static int visorhba_probe(struct visor_device *dev) struct Scsi_Host *scsihost; struct vhba_config_max max; struct visorhba_devdata *devdata = NULL; - int i, err, channel_offset; + int err, channel_offset; u64 features; scsihost = scsi_host_alloc(&visorhba_driver_template, @@ -1104,13 +1101,6 @@ static int visorhba_probe(struct visor_device *dev) goto err_scsi_host_put; devdata = (struct visorhba_devdata *)scsihost->hostdata; - for (i = 0; i < VISORHBA_OPEN_MAX; i++) { - if (!visorhbas_open[i].devdata) { - visorhbas_open[i].devdata = devdata; - break; - } - } - devdata->dev = dev; dev_set_drvdata(&dev->device, devdata); -- cgit v0.10.2 From 6d8c96cbc161168726480ab01ad5c53fd6b2e04a Mon Sep 17 00:00:00 2001 From: David Binder Date: Thu, 12 May 2016 09:14:45 -0400 Subject: staging: unisys: visornic: simplify visornic if statements Changes the conditional logic by looking for the absence of work to do, instead of the opposite. Signed-off-by: David Binder Reviewed-by: Tim Sell Signed-off-by: David Kershner Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/unisys/visornic/visornic_main.c b/drivers/staging/unisys/visornic/visornic_main.c index fd7c9a6..992543a 100644 --- a/drivers/staging/unisys/visornic/visornic_main.c +++ b/drivers/staging/unisys/visornic/visornic_main.c @@ -1000,25 +1000,28 @@ visornic_set_multi(struct net_device *netdev) struct uiscmdrsp *cmdrsp; struct visornic_devdata *devdata = netdev_priv(netdev); - /* any filtering changes */ - if (devdata->old_flags != netdev->flags) { - if ((netdev->flags & IFF_PROMISC) != - (devdata->old_flags & IFF_PROMISC)) { - cmdrsp = kmalloc(SIZEOF_CMDRSP, GFP_ATOMIC); - if (!cmdrsp) - return; - cmdrsp->cmdtype = CMD_NET_TYPE; - cmdrsp->net.type = NET_RCV_PROMISC; - cmdrsp->net.enbdis.context = netdev; - cmdrsp->net.enbdis.enable = - netdev->flags & IFF_PROMISC; - visorchannel_signalinsert(devdata->dev->visorchannel, - IOCHAN_TO_IOPART, - cmdrsp); - kfree(cmdrsp); - } - devdata->old_flags = netdev->flags; - } + if (devdata->old_flags == netdev->flags) + return; + + if ((netdev->flags & IFF_PROMISC) == + (devdata->old_flags & IFF_PROMISC)) + goto out_save_flags; + + cmdrsp = kmalloc(SIZEOF_CMDRSP, GFP_ATOMIC); + if (!cmdrsp) + return; + cmdrsp->cmdtype = CMD_NET_TYPE; + cmdrsp->net.type = NET_RCV_PROMISC; + cmdrsp->net.enbdis.context = netdev; + cmdrsp->net.enbdis.enable = + netdev->flags & IFF_PROMISC; + visorchannel_signalinsert(devdata->dev->visorchannel, + IOCHAN_TO_IOPART, + cmdrsp); + kfree(cmdrsp); + +out_save_flags: + devdata->old_flags = netdev->flags; } /** -- cgit v0.10.2 From d12324e37d4f384b93df65d5188a1875ee80ed4c Mon Sep 17 00:00:00 2001 From: David Binder Date: Thu, 12 May 2016 09:14:46 -0400 Subject: staging: unisys: visornic: cleanup error handling Adjusts goto labels to prevent attempts to free unallocated resources. Signed-off-by: David Binder Signed-off-by: David Kershner Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/unisys/visornic/visornic_main.c b/drivers/staging/unisys/visornic/visornic_main.c index 992543a..f556100 100644 --- a/drivers/staging/unisys/visornic/visornic_main.c +++ b/drivers/staging/unisys/visornic/visornic_main.c @@ -1796,7 +1796,7 @@ static int visornic_probe(struct visor_device *dev) sizeof(struct sk_buff *), GFP_KERNEL); if (!devdata->rcvbuf) { err = -ENOMEM; - goto cleanup_rcvbuf; + goto cleanup_netdev; } /* set the net_xmit outstanding threshold */ @@ -1817,12 +1817,12 @@ static int visornic_probe(struct visor_device *dev) devdata->cmdrsp_rcv = kmalloc(SIZEOF_CMDRSP, GFP_ATOMIC); if (!devdata->cmdrsp_rcv) { err = -ENOMEM; - goto cleanup_cmdrsp_rcv; + goto cleanup_rcvbuf; } devdata->xmit_cmdrsp = kmalloc(SIZEOF_CMDRSP, GFP_ATOMIC); if (!devdata->xmit_cmdrsp) { err = -ENOMEM; - goto cleanup_xmit_cmdrsp; + goto cleanup_cmdrsp_rcv; } INIT_WORK(&devdata->timeout_reset, visornic_timeout_reset); devdata->server_down = false; -- cgit v0.10.2 From ab2c3d75451819b4d28ec6dececd299ac03d39ec Mon Sep 17 00:00:00 2001 From: David Binder Date: Thu, 12 May 2016 09:14:47 -0400 Subject: staging: unisys: visorhba: return 0 literal Returns 0 instead of variable rc in visorhba_init(). Signed-off-by: David Binder Signed-off-by: David Kershner Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/unisys/visorhba/visorhba_main.c b/drivers/staging/unisys/visorhba/visorhba_main.c index 11985bb..5ef1d30 100644 --- a/drivers/staging/unisys/visorhba/visorhba_main.c +++ b/drivers/staging/unisys/visorhba/visorhba_main.c @@ -1204,7 +1204,7 @@ static int visorhba_init(void) if (rc) goto cleanup_debugfs; - return rc; + return 0; cleanup_debugfs: debugfs_remove_recursive(visorhba_debugfs_dir); -- cgit v0.10.2 From 186896fdf0fd7d4617435986ed79f817eecd3c0f Mon Sep 17 00:00:00 2001 From: David Binder Date: Thu, 12 May 2016 09:14:48 -0400 Subject: staging: unisys: visornic: check for error instead of success Changes the conditional logic to check for an error code instead of a success code. Signed-off-by: David Binder Signed-off-by: David Kershner Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/unisys/visornic/visornic_main.c b/drivers/staging/unisys/visornic/visornic_main.c index f556100..af81d31 100644 --- a/drivers/staging/unisys/visornic/visornic_main.c +++ b/drivers/staging/unisys/visornic/visornic_main.c @@ -2091,8 +2091,10 @@ static int visornic_init(void) goto cleanup_debugfs; err = visorbus_register_visor_driver(&visornic_driver); - if (!err) - return 0; + if (err) + goto cleanup_debugfs; + + return 0; cleanup_debugfs: debugfs_remove_recursive(visornic_debugfs_dir); -- cgit v0.10.2 From e1834bd0f6e2e00b04dc992d15051fb43790814e Mon Sep 17 00:00:00 2001 From: David Binder Date: Fri, 13 May 2016 23:17:15 -0400 Subject: staging: unisys: visornic: remove extraneous error check Removes an extraneous error check in devdata_initialize(), and updates the function comment accordingly. Signed-off-by: David Binder Reviewed-by: Tim Sell Signed-off-by: David Kershner Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/unisys/visornic/visornic_main.c b/drivers/staging/unisys/visornic/visornic_main.c index af81d31..4e3e67c 100644 --- a/drivers/staging/unisys/visornic/visornic_main.c +++ b/drivers/staging/unisys/visornic/visornic_main.c @@ -1342,13 +1342,11 @@ visornic_rx(struct uiscmdrsp *cmdrsp) * * Setup initial values for the visornic based on channel and default * values. - * Returns a pointer to the devdata if successful, else NULL + * Returns a pointer to the devdata structure */ static struct visornic_devdata * devdata_initialize(struct visornic_devdata *devdata, struct visor_device *dev) { - if (!devdata) - return NULL; devdata->dev = dev; devdata->incarnation_id = get_jiffies_64(); return devdata; -- cgit v0.10.2 From 403ecd636424f98fa08440c6d8d1d95d66d2ad10 Mon Sep 17 00:00:00 2001 From: Tim Sell Date: Fri, 13 May 2016 23:17:16 -0400 Subject: staging: unisys: visorhba: "Prefer 'unsigned int'" checkpatch warnings This patch fixes a few checkpatch warnings in visorhba: WARNING: Prefer 'unsigned int' to bare use of 'unsigned' Signed-off-by: Tim Sell Signed-off-by: David Kershner Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/unisys/visorhba/visorhba_main.c b/drivers/staging/unisys/visorhba/visorhba_main.c index 5ef1d30..48551fe 100644 --- a/drivers/staging/unisys/visorhba/visorhba_main.c +++ b/drivers/staging/unisys/visorhba/visorhba_main.c @@ -1087,9 +1087,9 @@ static int visorhba_probe(struct visor_device *dev) if (err < 0) goto err_scsi_host_put; - scsihost->max_id = (unsigned)max.max_id; - scsihost->max_lun = (unsigned)max.max_lun; - scsihost->cmd_per_lun = (unsigned)max.cmd_per_lun; + scsihost->max_id = (unsigned int)max.max_id; + scsihost->max_lun = (unsigned int)max.max_lun; + scsihost->cmd_per_lun = (unsigned int)max.cmd_per_lun; scsihost->max_sectors = (unsigned short)(max.max_io_size >> 9); scsihost->sg_tablesize = -- cgit v0.10.2 From 2efffad3148838842ce4ddbcb719bd1d07905d0c Mon Sep 17 00:00:00 2001 From: Erik Arfvidson Date: Fri, 13 May 2016 23:17:17 -0400 Subject: staging: unisys: visorinput change -1 return value This patch changes the vague -1 return value to -EINVAL Signed-off-by: Erik Arfvidson Signed-off-by: David Kershner Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/unisys/visorinput/visorinput.c b/drivers/staging/unisys/visorinput/visorinput.c index 12a3570..d67cd763 100644 --- a/drivers/staging/unisys/visorinput/visorinput.c +++ b/drivers/staging/unisys/visorinput/visorinput.c @@ -506,7 +506,7 @@ calc_button(int x) case 3: return BTN_RIGHT; default: - return -1; + return -EINVAL; } } -- cgit v0.10.2 From ba78c4707c8757ef8aacee7f26002c38c49caa8f Mon Sep 17 00:00:00 2001 From: Erik Arfvidson Date: Fri, 13 May 2016 23:17:18 -0400 Subject: staging: unisys: visorhba change -1 return value This patch changes the vague -1 return value to -EBUSY Signed-off-by: Erik Arfvidson Signed-off-by: David Kershner Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/unisys/visorhba/visorhba_main.c b/drivers/staging/unisys/visorhba/visorhba_main.c index 48551fe..120ba20 100644 --- a/drivers/staging/unisys/visorhba/visorhba_main.c +++ b/drivers/staging/unisys/visorhba/visorhba_main.c @@ -184,7 +184,7 @@ static void visor_thread_stop(struct task_struct *task) * Partition so that it can be handled when it completes. If new is * NULL it is assumed the entry refers only to the cmdrsp. * Returns insert_location where entry was added, - * SCSI_MLQUEUE_DEVICE_BUSY if it can't + * -EBUSY if it can't */ static int add_scsipending_entry(struct visorhba_devdata *devdata, char cmdtype, void *new) @@ -199,7 +199,7 @@ static int add_scsipending_entry(struct visorhba_devdata *devdata, insert_location = (insert_location + 1) % MAX_PENDING_REQUESTS; if (insert_location == (int)devdata->nextinsert) { spin_unlock_irqrestore(&devdata->privlock, flags); - return -1; + return -EBUSY; } } -- cgit v0.10.2 From c294ea31aa785afe2144fc933fd59106506c1c53 Mon Sep 17 00:00:00 2001 From: Erik Arfvidson Date: Fri, 13 May 2016 23:17:19 -0400 Subject: staging: unisys: visorbus change -1 return values This patch changes the vague -1 return values to -EFAULT since it would be the most appropriate, given that this error would only occur in an unexpected bad offset field. Resulting in a bad address. Signed-off-by: Erik Arfvidson Signed-off-by: David Kershner Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/unisys/visorbus/visorbus_main.c b/drivers/staging/unisys/visorbus/visorbus_main.c index 3a147db..d32b898 100644 --- a/drivers/staging/unisys/visorbus/visorbus_main.c +++ b/drivers/staging/unisys/visorbus/visorbus_main.c @@ -876,10 +876,10 @@ write_vbus_chp_info(struct visorchannel *chan, int off = sizeof(struct channel_header) + hdr_info->chp_info_offset; if (hdr_info->chp_info_offset == 0) - return -1; + return -EFAULT; if (visorchannel_write(chan, off, info, sizeof(*info)) < 0) - return -1; + return -EFAULT; return 0; } @@ -895,10 +895,10 @@ write_vbus_bus_info(struct visorchannel *chan, int off = sizeof(struct channel_header) + hdr_info->bus_info_offset; if (hdr_info->bus_info_offset == 0) - return -1; + return -EFAULT; if (visorchannel_write(chan, off, info, sizeof(*info)) < 0) - return -1; + return -EFAULT; return 0; } @@ -915,10 +915,10 @@ write_vbus_dev_info(struct visorchannel *chan, (hdr_info->device_info_struct_bytes * devix); if (hdr_info->dev_info_offset == 0) - return -1; + return -EFAULT; if (visorchannel_write(chan, off, info, sizeof(*info)) < 0) - return -1; + return -EFAULT; return 0; } -- cgit v0.10.2 From 119296eaa8a5dd8c3dbd5051202a06ae9a1d04fc Mon Sep 17 00:00:00 2001 From: Erik Arfvidson Date: Fri, 13 May 2016 23:17:20 -0400 Subject: staging: unisys: visorchipset change -1 return value This patch changes the vague -1 return value to -EINVAL Signed-off-by: Erik Arfvidson Signed-off-by: David Kershner Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/unisys/visorbus/visorchipset.c b/drivers/staging/unisys/visorbus/visorchipset.c index 5ba5936..d248c94 100644 --- a/drivers/staging/unisys/visorbus/visorchipset.c +++ b/drivers/staging/unisys/visorbus/visorchipset.c @@ -1613,7 +1613,7 @@ parahotplug_request_complete(int id, u16 active) } spin_unlock(¶hotplug_request_list_lock); - return -1; + return -EINVAL; } /* -- cgit v0.10.2 From 35b214155601cdbb97bc2d97524b5f0df176348d Mon Sep 17 00:00:00 2001 From: Erik Arfvidson Date: Fri, 13 May 2016 23:17:21 -0400 Subject: staging: unisys: iovmcall_gnuc.h change -1 return values This patch changes the vague -1 return values to -EPERM. This operation is not supported is a good alternative to -1 because the return is basically telling the caller that the processor doesn't support vmcall operations. Signed-off-by: Erik Arfvidson Signed-off-by: David Kershner Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/unisys/visorbus/iovmcall_gnuc.h b/drivers/staging/unisys/visorbus/iovmcall_gnuc.h index b08b6ec..98ea7f3 100644 --- a/drivers/staging/unisys/visorbus/iovmcall_gnuc.h +++ b/drivers/staging/unisys/visorbus/iovmcall_gnuc.h @@ -22,7 +22,7 @@ __unisys_vmcall_gnuc(unsigned long tuple, unsigned long reg_ebx, cpuid(0x00000001, &cpuid_eax, &cpuid_ebx, &cpuid_ecx, &cpuid_edx); if (!(cpuid_ecx & 0x80000000)) - return -1; + return -EPERM; __asm__ __volatile__(".byte 0x00f, 0x001, 0x0c1" : "=a"(result) : "a"(tuple), "b"(reg_ebx), "c"(reg_ecx)); @@ -40,7 +40,7 @@ __unisys_extended_vmcall_gnuc(unsigned long long tuple, cpuid(0x00000001, &cpuid_eax, &cpuid_ebx, &cpuid_ecx, &cpuid_edx); if (!(cpuid_ecx & 0x80000000)) - return -1; + return -EPERM; __asm__ __volatile__(".byte 0x00f, 0x001, 0x0c1" : "=a"(result) : "a"(tuple), "b"(reg_ebx), "c"(reg_ecx), "d"(reg_edx)); -- cgit v0.10.2 From 73e81350ad7a45117c17fb3ec433a266b3fa7d78 Mon Sep 17 00:00:00 2001 From: David Binder Date: Fri, 13 May 2016 23:17:22 -0400 Subject: staging: unisys: visornic: change return statements Changes return statements in visornic_rx() to use literals instead of a variable. Also changes function description to reflect the correct return type. Signed-off-by: David Binder Signed-off-by: David Kershner Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/unisys/visornic/visornic_main.c b/drivers/staging/unisys/visornic/visornic_main.c index 4e3e67c..a28388d 100644 --- a/drivers/staging/unisys/visornic/visornic_main.c +++ b/drivers/staging/unisys/visornic/visornic_main.c @@ -1137,7 +1137,7 @@ repost_return(struct uiscmdrsp *cmdrsp, struct visornic_devdata *devdata, * * Got a receive packet back from the IO Part, handle it and send * it up the stack. - * Returns void + * Returns 1 iff an skb was receieved, otherwise 0 */ static int visornic_rx(struct uiscmdrsp *cmdrsp) @@ -1148,7 +1148,6 @@ visornic_rx(struct uiscmdrsp *cmdrsp) int cc, currsize, off; struct ethhdr *eth; unsigned long flags; - int rx_count = 0; /* post new rcv buf to the other end using the cmdrsp we have at hand * post it without holding lock - but we'll use the signal lock to @@ -1180,7 +1179,7 @@ visornic_rx(struct uiscmdrsp *cmdrsp) */ spin_unlock_irqrestore(&devdata->priv_lock, flags); repost_return(cmdrsp, devdata, skb, netdev); - return rx_count; + return 0; } spin_unlock_irqrestore(&devdata->priv_lock, flags); @@ -1199,7 +1198,7 @@ visornic_rx(struct uiscmdrsp *cmdrsp) if (repost_return(cmdrsp, devdata, skb, netdev) < 0) dev_err(&devdata->netdev->dev, "repost_return failed"); - return rx_count; + return 0; } /* length rcvd is greater than firstfrag in this skb rcv buf */ skb->tail += RCVPOST_BUF_SIZE; /* amount in skb->data */ @@ -1215,7 +1214,7 @@ visornic_rx(struct uiscmdrsp *cmdrsp) if (repost_return(cmdrsp, devdata, skb, netdev) < 0) dev_err(&devdata->netdev->dev, "repost_return failed"); - return rx_count; + return 0; } skb->tail += skb->len; skb->data_len = 0; /* nothing rcvd in frag_list */ @@ -1234,7 +1233,7 @@ visornic_rx(struct uiscmdrsp *cmdrsp) if (cmdrsp->net.rcv.rcvbuf[0] != skb) { if (repost_return(cmdrsp, devdata, skb, netdev) < 0) dev_err(&devdata->netdev->dev, "repost_return failed"); - return rx_count; + return 0; } if (cmdrsp->net.rcv.numrcvbufs > 1) { @@ -1316,10 +1315,9 @@ visornic_rx(struct uiscmdrsp *cmdrsp) /* drop packet - don't forward it up to OS */ devdata->n_rcv_packets_not_accepted++; repost_return(cmdrsp, devdata, skb, netdev); - return rx_count; + return 0; } while (0); - rx_count++; netif_receive_skb(skb); /* netif_rx returns various values, but "in practice most drivers * ignore the return value @@ -1332,7 +1330,7 @@ visornic_rx(struct uiscmdrsp *cmdrsp) * new rcv buffer. */ repost_return(cmdrsp, devdata, skb, netdev); - return rx_count; + return 1; } /** -- cgit v0.10.2 From a4f144ebbdf6f7807c477bce8e136047ed27321f Mon Sep 17 00:00:00 2001 From: David Carrillo-Cisneros Date: Wed, 1 Jun 2016 12:33:05 -0700 Subject: perf/core: Fix crash due to account/unaccount_sb_event() inconsistency unaccount_pmu_sb_event() did not check for attributes in event->attr before calling detach_sb_event(), while account_pmu_event() did. This caused NULL pointer reference in cgroup events that did not have any of the attributes checked by account_pmu_event(). To trigger the bug just wait for a cgroup event to terminate, e.g.: $ mkdir /dev/cgroup/devices/test $ perf stat -e cycles -a -G test sleep 0 ... see crash ... Signed-off-by: David Carrillo-Cisneros Reviewed-by: Stephane Eranian Cc: Alexander Shishkin Cc: Arnaldo Carvalho de Melo Cc: Jiri Olsa Cc: Kan Liang Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: Zheng Link: http://lkml.kernel.org/r/1464809585-66072-1-git-send-email-davidcc@google.com Signed-off-by: Ingo Molnar diff --git a/kernel/events/core.c b/kernel/events/core.c index 5d48306..ae081a1 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c @@ -3682,15 +3682,28 @@ static void detach_sb_event(struct perf_event *event) raw_spin_unlock(&pel->lock); } -static void unaccount_pmu_sb_event(struct perf_event *event) +static bool is_sb_event(struct perf_event *event) { + struct perf_event_attr *attr = &event->attr; + if (event->parent) - return; + return false; if (event->attach_state & PERF_ATTACH_TASK) - return; + return false; - detach_sb_event(event); + if (attr->mmap || attr->mmap_data || attr->mmap2 || + attr->comm || attr->comm_exec || + attr->task || + attr->context_switch) + return true; + return false; +} + +static void unaccount_pmu_sb_event(struct perf_event *event) +{ + if (is_sb_event(event)) + detach_sb_event(event); } static void unaccount_event_cpu(struct perf_event *event, int cpu) @@ -8666,18 +8679,7 @@ static void attach_sb_event(struct perf_event *event) */ static void account_pmu_sb_event(struct perf_event *event) { - struct perf_event_attr *attr = &event->attr; - - if (event->parent) - return; - - if (event->attach_state & PERF_ATTACH_TASK) - return; - - if (attr->mmap || attr->mmap_data || attr->mmap2 || - attr->comm || attr->comm_exec || - attr->task || - attr->context_switch) + if (is_sb_event(event)) attach_sb_event(event); } -- cgit v0.10.2 From ef5f9f47d4ec4cf42bac48c7c4dafacc1b9f0630 Mon Sep 17 00:00:00 2001 From: Dave Hansen Date: Thu, 2 Jun 2016 17:19:29 -0700 Subject: perf/x86/intel: Use Intel family macros for core perf events Use the new model number macros instead of spelling things out in the comments. Note that this is missing a Nehalem model that is mentioned in intel_idle which is fixed up in a later patch. The resulting binary (arch/x86/events/intel/core.o) is exactly the same with and without this patch modulo some harmless changes to restoring %esi in the return path of functions, even those untouched by this patch. Signed-off-by: Dave Hansen Cc: Alexander Shishkin Cc: Andy Lutomirski Cc: Arnaldo Carvalho de Melo Cc: Borislav Petkov Cc: Brian Gerst Cc: Dave Hansen Cc: Denys Vlasenko Cc: H. Peter Anvin Cc: Jiri Olsa Cc: Kan Liang Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Thomas Gleixner Cc: Vince Weaver Cc: jacob.jun.pan@intel.com Link: http://lkml.kernel.org/r/20160603001929.C5F1C079@viggo.jf.intel.com Signed-off-by: Ingo Molnar diff --git a/arch/x86/events/intel/core.c b/arch/x86/events/intel/core.c index 5081b4c..3ed528c 100644 --- a/arch/x86/events/intel/core.c +++ b/arch/x86/events/intel/core.c @@ -16,6 +16,7 @@ #include #include +#include #include #include "../perf_event.h" @@ -3319,11 +3320,11 @@ static int intel_snb_pebs_broken(int cpu) u32 rev = UINT_MAX; /* default to broken for unknown models */ switch (cpu_data(cpu).x86_model) { - case 42: /* SNB */ + case INTEL_FAM6_SANDYBRIDGE: rev = 0x28; break; - case 45: /* SNB-EP */ + case INTEL_FAM6_SANDYBRIDGE_X: switch (cpu_data(cpu).x86_mask) { case 6: rev = 0x618; break; case 7: rev = 0x70c; break; @@ -3573,15 +3574,15 @@ __init int intel_pmu_init(void) * Install the hw-cache-events table: */ switch (boot_cpu_data.x86_model) { - case 14: /* 65nm Core "Yonah" */ + case INTEL_FAM6_CORE_YONAH: pr_cont("Core events, "); break; - case 15: /* 65nm Core2 "Merom" */ + case INTEL_FAM6_CORE2_MEROM: x86_add_quirk(intel_clovertown_quirk); - case 22: /* 65nm Core2 "Merom-L" */ - case 23: /* 45nm Core2 "Penryn" */ - case 29: /* 45nm Core2 "Dunnington (MP) */ + case INTEL_FAM6_CORE2_MEROM_L: + case INTEL_FAM6_CORE2_PENRYN: + case INTEL_FAM6_CORE2_DUNNINGTON: memcpy(hw_cache_event_ids, core2_hw_cache_event_ids, sizeof(hw_cache_event_ids)); @@ -3592,9 +3593,9 @@ __init int intel_pmu_init(void) pr_cont("Core2 events, "); break; - case 30: /* 45nm Nehalem */ - case 26: /* 45nm Nehalem-EP */ - case 46: /* 45nm Nehalem-EX */ + case INTEL_FAM6_NEHALEM: + case INTEL_FAM6_NEHALEM_EP: + case INTEL_FAM6_NEHALEM_EX: memcpy(hw_cache_event_ids, nehalem_hw_cache_event_ids, sizeof(hw_cache_event_ids)); memcpy(hw_cache_extra_regs, nehalem_hw_cache_extra_regs, @@ -3622,11 +3623,11 @@ __init int intel_pmu_init(void) pr_cont("Nehalem events, "); break; - case 28: /* 45nm Atom "Pineview" */ - case 38: /* 45nm Atom "Lincroft" */ - case 39: /* 32nm Atom "Penwell" */ - case 53: /* 32nm Atom "Cloverview" */ - case 54: /* 32nm Atom "Cedarview" */ + case INTEL_FAM6_ATOM_PINEVIEW: + case INTEL_FAM6_ATOM_LINCROFT: + case INTEL_FAM6_ATOM_PENWELL: + case INTEL_FAM6_ATOM_CLOVERVIEW: + case INTEL_FAM6_ATOM_CEDARVIEW: memcpy(hw_cache_event_ids, atom_hw_cache_event_ids, sizeof(hw_cache_event_ids)); @@ -3638,9 +3639,9 @@ __init int intel_pmu_init(void) pr_cont("Atom events, "); break; - case 55: /* 22nm Atom "Silvermont" */ - case 76: /* 14nm Atom "Airmont" */ - case 77: /* 22nm Atom "Silvermont Avoton/Rangely" */ + case INTEL_FAM6_ATOM_SILVERMONT1: + case INTEL_FAM6_ATOM_SILVERMONT2: + case INTEL_FAM6_ATOM_AIRMONT: memcpy(hw_cache_event_ids, slm_hw_cache_event_ids, sizeof(hw_cache_event_ids)); memcpy(hw_cache_extra_regs, slm_hw_cache_extra_regs, @@ -3656,8 +3657,8 @@ __init int intel_pmu_init(void) pr_cont("Silvermont events, "); break; - case 92: /* 14nm Atom "Goldmont" */ - case 95: /* 14nm Atom "Goldmont Denverton" */ + case INTEL_FAM6_ATOM_GOLDMONT: + case INTEL_FAM6_ATOM_DENVERTON: memcpy(hw_cache_event_ids, glm_hw_cache_event_ids, sizeof(hw_cache_event_ids)); memcpy(hw_cache_extra_regs, glm_hw_cache_extra_regs, @@ -3680,9 +3681,9 @@ __init int intel_pmu_init(void) pr_cont("Goldmont events, "); break; - case 37: /* 32nm Westmere */ - case 44: /* 32nm Westmere-EP */ - case 47: /* 32nm Westmere-EX */ + case INTEL_FAM6_WESTMERE: + case INTEL_FAM6_WESTMERE_EP: + case INTEL_FAM6_WESTMERE_EX: memcpy(hw_cache_event_ids, westmere_hw_cache_event_ids, sizeof(hw_cache_event_ids)); memcpy(hw_cache_extra_regs, nehalem_hw_cache_extra_regs, @@ -3709,8 +3710,8 @@ __init int intel_pmu_init(void) pr_cont("Westmere events, "); break; - case 42: /* 32nm SandyBridge */ - case 45: /* 32nm SandyBridge-E/EN/EP */ + case INTEL_FAM6_SANDYBRIDGE: + case INTEL_FAM6_SANDYBRIDGE_X: x86_add_quirk(intel_sandybridge_quirk); x86_add_quirk(intel_ht_bug); memcpy(hw_cache_event_ids, snb_hw_cache_event_ids, @@ -3723,7 +3724,7 @@ __init int intel_pmu_init(void) x86_pmu.event_constraints = intel_snb_event_constraints; x86_pmu.pebs_constraints = intel_snb_pebs_event_constraints; x86_pmu.pebs_aliases = intel_pebs_aliases_snb; - if (boot_cpu_data.x86_model == 45) + if (boot_cpu_data.x86_model == INTEL_FAM6_SANDYBRIDGE_X) x86_pmu.extra_regs = intel_snbep_extra_regs; else x86_pmu.extra_regs = intel_snb_extra_regs; @@ -3745,8 +3746,8 @@ __init int intel_pmu_init(void) pr_cont("SandyBridge events, "); break; - case 58: /* 22nm IvyBridge */ - case 62: /* 22nm IvyBridge-EP/EX */ + case INTEL_FAM6_IVYBRIDGE: + case INTEL_FAM6_IVYBRIDGE_X: x86_add_quirk(intel_ht_bug); memcpy(hw_cache_event_ids, snb_hw_cache_event_ids, sizeof(hw_cache_event_ids)); @@ -3762,7 +3763,7 @@ __init int intel_pmu_init(void) x86_pmu.pebs_constraints = intel_ivb_pebs_event_constraints; x86_pmu.pebs_aliases = intel_pebs_aliases_ivb; x86_pmu.pebs_prec_dist = true; - if (boot_cpu_data.x86_model == 62) + if (boot_cpu_data.x86_model == INTEL_FAM6_IVYBRIDGE_X) x86_pmu.extra_regs = intel_snbep_extra_regs; else x86_pmu.extra_regs = intel_snb_extra_regs; @@ -3780,10 +3781,10 @@ __init int intel_pmu_init(void) break; - case 60: /* 22nm Haswell Core */ - case 63: /* 22nm Haswell Server */ - case 69: /* 22nm Haswell ULT */ - case 70: /* 22nm Haswell + GT3e (Intel Iris Pro graphics) */ + case INTEL_FAM6_HASWELL_CORE: + case INTEL_FAM6_HASWELL_X: + case INTEL_FAM6_HASWELL_ULT: + case INTEL_FAM6_HASWELL_GT3E: x86_add_quirk(intel_ht_bug); x86_pmu.late_ack = true; memcpy(hw_cache_event_ids, hsw_hw_cache_event_ids, sizeof(hw_cache_event_ids)); @@ -3807,10 +3808,10 @@ __init int intel_pmu_init(void) pr_cont("Haswell events, "); break; - case 61: /* 14nm Broadwell Core-M */ - case 86: /* 14nm Broadwell Xeon D */ - case 71: /* 14nm Broadwell + GT3e (Intel Iris Pro graphics) */ - case 79: /* 14nm Broadwell Server */ + case INTEL_FAM6_BROADWELL_CORE: + case INTEL_FAM6_BROADWELL_XEON_D: + case INTEL_FAM6_BROADWELL_GT3E: + case INTEL_FAM6_BROADWELL_X: x86_pmu.late_ack = true; memcpy(hw_cache_event_ids, hsw_hw_cache_event_ids, sizeof(hw_cache_event_ids)); memcpy(hw_cache_extra_regs, hsw_hw_cache_extra_regs, sizeof(hw_cache_extra_regs)); @@ -3843,7 +3844,7 @@ __init int intel_pmu_init(void) pr_cont("Broadwell events, "); break; - case 87: /* Knights Landing Xeon Phi */ + case INTEL_FAM6_XEON_PHI_KNL: memcpy(hw_cache_event_ids, slm_hw_cache_event_ids, sizeof(hw_cache_event_ids)); memcpy(hw_cache_extra_regs, @@ -3861,11 +3862,11 @@ __init int intel_pmu_init(void) pr_cont("Knights Landing events, "); break; - case 142: /* 14nm Kabylake Mobile */ - case 158: /* 14nm Kabylake Desktop */ - case 78: /* 14nm Skylake Mobile */ - case 94: /* 14nm Skylake Desktop */ - case 85: /* 14nm Skylake Server */ + case INTEL_FAM6_SKYLAKE_MOBILE: + case INTEL_FAM6_SKYLAKE_DESKTOP: + case INTEL_FAM6_SKYLAKE_X: + case INTEL_FAM6_KABYLAKE_MOBILE: + case INTEL_FAM6_KABYLAKE_DESKTOP: x86_pmu.late_ack = true; memcpy(hw_cache_event_ids, skl_hw_cache_event_ids, sizeof(hw_cache_event_ids)); memcpy(hw_cache_extra_regs, skl_hw_cache_extra_regs, sizeof(hw_cache_extra_regs)); -- cgit v0.10.2 From 7f2236d0bf9a33bb539551b653ae842430654240 Mon Sep 17 00:00:00 2001 From: Dave Hansen Date: Thu, 2 Jun 2016 17:19:30 -0700 Subject: perf/x86/rapl: Use Intel family macros for RAPL Use the new INTEL_FAM6_* macros for rapl.c. Note that this is missing at least one Westmere model and Skylake Server which will we fixed later in this series. The resulting binary structure 'rapl_cpu_match' is the same before and after this patch. Signed-off-by: Dave Hansen Cc: Alexander Shishkin Cc: Andy Lutomirski Cc: Arnaldo Carvalho de Melo Cc: Borislav Petkov Cc: Brian Gerst Cc: Dave Hansen Cc: Denys Vlasenko Cc: H. Peter Anvin Cc: Jiri Olsa Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Srinivas Pandruvada Cc: Stephane Eranian Cc: Thomas Gleixner Cc: Vince Weaver Cc: jacob.jun.pan@intel.com Link: http://lkml.kernel.org/r/20160603001930.6AC50BE3@viggo.jf.intel.com Signed-off-by: Ingo Molnar diff --git a/arch/x86/events/intel/rapl.c b/arch/x86/events/intel/rapl.c index e30eef4..8012fe6 100644 --- a/arch/x86/events/intel/rapl.c +++ b/arch/x86/events/intel/rapl.c @@ -55,6 +55,7 @@ #include #include #include +#include #include "../perf_event.h" MODULE_LICENSE("GPL"); @@ -786,26 +787,26 @@ static const struct intel_rapl_init_fun skl_rapl_init __initconst = { }; static const struct x86_cpu_id rapl_cpu_match[] __initconst = { - X86_RAPL_MODEL_MATCH(42, snb_rapl_init), /* Sandy Bridge */ - X86_RAPL_MODEL_MATCH(45, snbep_rapl_init), /* Sandy Bridge-EP */ + X86_RAPL_MODEL_MATCH(INTEL_FAM6_SANDYBRIDGE, snb_rapl_init), + X86_RAPL_MODEL_MATCH(INTEL_FAM6_SANDYBRIDGE_X, snbep_rapl_init), - X86_RAPL_MODEL_MATCH(58, snb_rapl_init), /* Ivy Bridge */ - X86_RAPL_MODEL_MATCH(62, snbep_rapl_init), /* IvyTown */ + X86_RAPL_MODEL_MATCH(INTEL_FAM6_IVYBRIDGE, snb_rapl_init), + X86_RAPL_MODEL_MATCH(INTEL_FAM6_IVYBRIDGE_X, snbep_rapl_init), - X86_RAPL_MODEL_MATCH(60, hsw_rapl_init), /* Haswell */ - X86_RAPL_MODEL_MATCH(63, hsx_rapl_init), /* Haswell-Server */ - X86_RAPL_MODEL_MATCH(69, hsw_rapl_init), /* Haswell-Celeron */ - X86_RAPL_MODEL_MATCH(70, hsw_rapl_init), /* Haswell GT3e */ + X86_RAPL_MODEL_MATCH(INTEL_FAM6_HASWELL_CORE, hsw_rapl_init), + X86_RAPL_MODEL_MATCH(INTEL_FAM6_HASWELL_X, hsw_rapl_init), + X86_RAPL_MODEL_MATCH(INTEL_FAM6_HASWELL_ULT, hsw_rapl_init), + X86_RAPL_MODEL_MATCH(INTEL_FAM6_HASWELL_GT3E, hsw_rapl_init), - X86_RAPL_MODEL_MATCH(61, hsw_rapl_init), /* Broadwell */ - X86_RAPL_MODEL_MATCH(71, hsw_rapl_init), /* Broadwell-H */ - X86_RAPL_MODEL_MATCH(79, hsx_rapl_init), /* Broadwell-Server */ - X86_RAPL_MODEL_MATCH(86, hsx_rapl_init), /* Broadwell Xeon D */ + X86_RAPL_MODEL_MATCH(INTEL_FAM6_BROADWELL_CORE, hsw_rapl_init), + X86_RAPL_MODEL_MATCH(INTEL_FAM6_BROADWELL_GT3E, hsw_rapl_init), + X86_RAPL_MODEL_MATCH(INTEL_FAM6_BROADWELL_X, hsw_rapl_init), + X86_RAPL_MODEL_MATCH(INTEL_FAM6_BROADWELL_XEON_D, hsw_rapl_init), - X86_RAPL_MODEL_MATCH(87, knl_rapl_init), /* Knights Landing */ + X86_RAPL_MODEL_MATCH(INTEL_FAM6_XEON_PHI_KNL, knl_rapl_init), - X86_RAPL_MODEL_MATCH(78, skl_rapl_init), /* Skylake */ - X86_RAPL_MODEL_MATCH(94, skl_rapl_init), /* Skylake H/S */ + X86_RAPL_MODEL_MATCH(INTEL_FAM6_SKYLAKE_MOBILE, skl_rapl_init), + X86_RAPL_MODEL_MATCH(INTEL_FAM6_SKYLAKE_DESKTOP, skl_rapl_init), {}, }; -- cgit v0.10.2 From 353bf605a771e3c86b21de017e9525aba7d64770 Mon Sep 17 00:00:00 2001 From: Dave Hansen Date: Thu, 2 Jun 2016 17:19:33 -0700 Subject: perf/x86/msr: Use Intel family macros for MSR events code Use the new INTEL_MODEL_* macros for arch/x86/events/msr.c. This code appears to be missing handling for "WESTMERE2" and "SKYLAKE_X". Signed-off-by: Dave Hansen Cc: Alexander Shishkin Cc: Andy Lutomirski Cc: Andy Lutomirski Cc: Arnaldo Carvalho de Melo Cc: Borislav Petkov Cc: Brian Gerst Cc: Dave Hansen Cc: Denys Vlasenko Cc: H. Peter Anvin Cc: Jiri Olsa Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Thomas Gleixner Cc: Vince Weaver Cc: jacob.jun.pan@intel.com Link: http://lkml.kernel.org/r/20160603001933.99A402B0@viggo.jf.intel.com Signed-off-by: Ingo Molnar diff --git a/arch/x86/events/msr.c b/arch/x86/events/msr.c index 85ef3c2..83cf13e 100644 --- a/arch/x86/events/msr.c +++ b/arch/x86/events/msr.c @@ -1,4 +1,5 @@ #include +#include enum perf_msr_id { PERF_MSR_TSC = 0, @@ -34,39 +35,39 @@ static bool test_intel(int idx) return false; switch (boot_cpu_data.x86_model) { - case 30: /* 45nm Nehalem */ - case 26: /* 45nm Nehalem-EP */ - case 46: /* 45nm Nehalem-EX */ + case INTEL_FAM6_NEHALEM: + case INTEL_FAM6_NEHALEM_EP: + case INTEL_FAM6_NEHALEM_EX: - case 37: /* 32nm Westmere */ - case 44: /* 32nm Westmere-EP */ - case 47: /* 32nm Westmere-EX */ + case INTEL_FAM6_WESTMERE: + case INTEL_FAM6_WESTMERE_EP: + case INTEL_FAM6_WESTMERE_EX: - case 42: /* 32nm SandyBridge */ - case 45: /* 32nm SandyBridge-E/EN/EP */ + case INTEL_FAM6_SANDYBRIDGE: + case INTEL_FAM6_SANDYBRIDGE_X: - case 58: /* 22nm IvyBridge */ - case 62: /* 22nm IvyBridge-EP/EX */ + case INTEL_FAM6_IVYBRIDGE: + case INTEL_FAM6_IVYBRIDGE_X: - case 60: /* 22nm Haswell Core */ - case 63: /* 22nm Haswell Server */ - case 69: /* 22nm Haswell ULT */ - case 70: /* 22nm Haswell + GT3e (Intel Iris Pro graphics) */ + case INTEL_FAM6_HASWELL_CORE: + case INTEL_FAM6_HASWELL_X: + case INTEL_FAM6_HASWELL_ULT: + case INTEL_FAM6_HASWELL_GT3E: - case 61: /* 14nm Broadwell Core-M */ - case 86: /* 14nm Broadwell Xeon D */ - case 71: /* 14nm Broadwell + GT3e (Intel Iris Pro graphics) */ - case 79: /* 14nm Broadwell Server */ + case INTEL_FAM6_BROADWELL_CORE: + case INTEL_FAM6_BROADWELL_XEON_D: + case INTEL_FAM6_BROADWELL_GT3E: + case INTEL_FAM6_BROADWELL_X: - case 55: /* 22nm Atom "Silvermont" */ - case 77: /* 22nm Atom "Silvermont Avoton/Rangely" */ - case 76: /* 14nm Atom "Airmont" */ + case INTEL_FAM6_ATOM_SILVERMONT1: + case INTEL_FAM6_ATOM_SILVERMONT2: + case INTEL_FAM6_ATOM_AIRMONT: if (idx == PERF_MSR_SMI) return true; break; - case 78: /* 14nm Skylake Mobile */ - case 94: /* 14nm Skylake Desktop */ + case INTEL_FAM6_SKYLAKE_MOBILE: + case INTEL_FAM6_SKYLAKE_DESKTOP: if (idx == PERF_MSR_SMI || idx == PERF_MSR_PPERF) return true; break; -- cgit v0.10.2 From 5134596caee9e834d2486edc45efad4c9e6effc3 Mon Sep 17 00:00:00 2001 From: Dave Hansen Date: Thu, 2 Jun 2016 17:19:35 -0700 Subject: perf/x86/msr: Add missing Intel models This patch presumes that Kabylake and Skylake Server will be the same as the existing Skylake parts and adds them to the MSR events code. Also add handling for "WESTMERE2". Signed-off-by: Dave Hansen Cc: Alexander Shishkin Cc: Andy Lutomirski Cc: Arnaldo Carvalho de Melo Cc: Borislav Petkov Cc: Brian Gerst Cc: Dave Hansen Cc: Denys Vlasenko Cc: H. Peter Anvin Cc: Jiri Olsa Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Thomas Gleixner Cc: Vince Weaver Cc: jacob.jun.pan@intel.com Link: http://lkml.kernel.org/r/20160603001935.FE6B3847@viggo.jf.intel.com Signed-off-by: Ingo Molnar diff --git a/arch/x86/events/msr.c b/arch/x86/events/msr.c index 83cf13e..50b3a05 100644 --- a/arch/x86/events/msr.c +++ b/arch/x86/events/msr.c @@ -40,6 +40,7 @@ static bool test_intel(int idx) case INTEL_FAM6_NEHALEM_EX: case INTEL_FAM6_WESTMERE: + case INTEL_FAM6_WESTMERE2: case INTEL_FAM6_WESTMERE_EP: case INTEL_FAM6_WESTMERE_EX: @@ -68,6 +69,9 @@ static bool test_intel(int idx) case INTEL_FAM6_SKYLAKE_MOBILE: case INTEL_FAM6_SKYLAKE_DESKTOP: + case INTEL_FAM6_SKYLAKE_X: + case INTEL_FAM6_KABYLAKE_MOBILE: + case INTEL_FAM6_KABYLAKE_DESKTOP: if (idx == PERF_MSR_SMI || idx == PERF_MSR_PPERF) return true; break; -- cgit v0.10.2 From bf4ad54199333d10c212499b57f26ffeb8222c81 Mon Sep 17 00:00:00 2001 From: Dave Hansen Date: Thu, 2 Jun 2016 17:19:40 -0700 Subject: perf/x86/cstate: Use Intel Model name macros This should be getting old by now. Use the new macros intead of open-coded magic numbers. Signed-off-by: Dave Hansen Cc: Alexander Shishkin Cc: Andy Lutomirski Cc: Arnaldo Carvalho de Melo Cc: Borislav Petkov Cc: Brian Gerst Cc: Dave Hansen Cc: Denys Vlasenko Cc: H. Peter Anvin Cc: Jiri Olsa Cc: Kan Liang Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Thomas Gleixner Cc: Vince Weaver Cc: jacob.jun.pan@intel.com Link: http://lkml.kernel.org/r/20160603001940.FE69D646@viggo.jf.intel.com Signed-off-by: Ingo Molnar diff --git a/arch/x86/events/intel/cstate.c b/arch/x86/events/intel/cstate.c index 9ba4e41..4c7638b 100644 --- a/arch/x86/events/intel/cstate.c +++ b/arch/x86/events/intel/cstate.c @@ -89,6 +89,7 @@ #include #include #include +#include #include "../perf_event.h" MODULE_LICENSE("GPL"); @@ -511,37 +512,37 @@ static const struct cstate_model slm_cstates __initconst = { { X86_VENDOR_INTEL, 6, model, X86_FEATURE_ANY, (unsigned long) &(states) } static const struct x86_cpu_id intel_cstates_match[] __initconst = { - X86_CSTATES_MODEL(30, nhm_cstates), /* 45nm Nehalem */ - X86_CSTATES_MODEL(26, nhm_cstates), /* 45nm Nehalem-EP */ - X86_CSTATES_MODEL(46, nhm_cstates), /* 45nm Nehalem-EX */ + X86_CSTATES_MODEL(INTEL_FAM6_NEHALEM, nhm_cstates), + X86_CSTATES_MODEL(INTEL_FAM6_NEHALEM_EP, nhm_cstates), + X86_CSTATES_MODEL(INTEL_FAM6_NEHALEM_EX, nhm_cstates), - X86_CSTATES_MODEL(37, nhm_cstates), /* 32nm Westmere */ - X86_CSTATES_MODEL(44, nhm_cstates), /* 32nm Westmere-EP */ - X86_CSTATES_MODEL(47, nhm_cstates), /* 32nm Westmere-EX */ + X86_CSTATES_MODEL(INTEL_FAM6_WESTMERE, nhm_cstates), + X86_CSTATES_MODEL(INTEL_FAM6_WESTMERE_EP, nhm_cstates), + X86_CSTATES_MODEL(INTEL_FAM6_WESTMERE_EX, nhm_cstates), - X86_CSTATES_MODEL(42, snb_cstates), /* 32nm SandyBridge */ - X86_CSTATES_MODEL(45, snb_cstates), /* 32nm SandyBridge-E/EN/EP */ + X86_CSTATES_MODEL(INTEL_FAM6_SANDYBRIDGE, snb_cstates), + X86_CSTATES_MODEL(INTEL_FAM6_SANDYBRIDGE_X, snb_cstates), - X86_CSTATES_MODEL(58, snb_cstates), /* 22nm IvyBridge */ - X86_CSTATES_MODEL(62, snb_cstates), /* 22nm IvyBridge-EP/EX */ + X86_CSTATES_MODEL(INTEL_FAM6_IVYBRIDGE, snb_cstates), + X86_CSTATES_MODEL(INTEL_FAM6_IVYBRIDGE_X, snb_cstates), - X86_CSTATES_MODEL(60, snb_cstates), /* 22nm Haswell Core */ - X86_CSTATES_MODEL(63, snb_cstates), /* 22nm Haswell Server */ - X86_CSTATES_MODEL(70, snb_cstates), /* 22nm Haswell + GT3e */ + X86_CSTATES_MODEL(INTEL_FAM6_HASWELL_CORE, snb_cstates), + X86_CSTATES_MODEL(INTEL_FAM6_HASWELL_X, snb_cstates), + X86_CSTATES_MODEL(INTEL_FAM6_HASWELL_GT3E, snb_cstates), - X86_CSTATES_MODEL(69, hswult_cstates), /* 22nm Haswell ULT */ + X86_CSTATES_MODEL(INTEL_FAM6_HASWELL_ULT, hswult_cstates), - X86_CSTATES_MODEL(55, slm_cstates), /* 22nm Atom Silvermont */ - X86_CSTATES_MODEL(77, slm_cstates), /* 22nm Atom Avoton/Rangely */ - X86_CSTATES_MODEL(76, slm_cstates), /* 22nm Atom Airmont */ + X86_CSTATES_MODEL(INTEL_FAM6_ATOM_SILVERMONT1, slm_cstates), + X86_CSTATES_MODEL(INTEL_FAM6_ATOM_SILVERMONT2, slm_cstates), + X86_CSTATES_MODEL(INTEL_FAM6_ATOM_AIRMONT, slm_cstates), - X86_CSTATES_MODEL(61, snb_cstates), /* 14nm Broadwell Core-M */ - X86_CSTATES_MODEL(86, snb_cstates), /* 14nm Broadwell Xeon D */ - X86_CSTATES_MODEL(71, snb_cstates), /* 14nm Broadwell + GT3e */ - X86_CSTATES_MODEL(79, snb_cstates), /* 14nm Broadwell Server */ + X86_CSTATES_MODEL(INTEL_FAM6_BROADWELL_CORE, snb_cstates), + X86_CSTATES_MODEL(INTEL_FAM6_BROADWELL_XEON_D, snb_cstates), + X86_CSTATES_MODEL(INTEL_FAM6_BROADWELL_GT3E, snb_cstates), + X86_CSTATES_MODEL(INTEL_FAM6_BROADWELL_X, snb_cstates), - X86_CSTATES_MODEL(78, snb_cstates), /* 14nm Skylake Mobile */ - X86_CSTATES_MODEL(94, snb_cstates), /* 14nm Skylake Desktop */ + X86_CSTATES_MODEL(INTEL_FAM6_SKYLAKE_MOBILE, snb_cstates), + X86_CSTATES_MODEL(INTEL_FAM6_SKYLAKE_DESKTOP, snb_cstates), { }, }; MODULE_DEVICE_TABLE(x86cpu, intel_cstates_match); -- cgit v0.10.2 From a07301ab3dabd1e31696c1bf1775aba24eb7573d Mon Sep 17 00:00:00 2001 From: Dave Hansen Date: Thu, 2 Jun 2016 17:19:42 -0700 Subject: perf/x86/uncore: Use Intel family name macros for uncore Another straightforward replacement of magic numbers Signed-off-by: Dave Hansen Cc: Alexander Shishkin Cc: Andy Lutomirski Cc: Arnaldo Carvalho de Melo Cc: Borislav Petkov Cc: Brian Gerst Cc: Dave Hansen Cc: Denys Vlasenko Cc: H. Peter Anvin Cc: Jiri Olsa Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Thomas Gleixner Cc: Vince Weaver Cc: jacob.jun.pan@intel.com Link: http://lkml.kernel.org/r/20160603001942.537570B6@viggo.jf.intel.com Signed-off-by: Ingo Molnar diff --git a/arch/x86/events/intel/uncore.c b/arch/x86/events/intel/uncore.c index 6549058..4e70d27 100644 --- a/arch/x86/events/intel/uncore.c +++ b/arch/x86/events/intel/uncore.c @@ -1,4 +1,5 @@ #include +#include #include "uncore.h" static struct intel_uncore_type *empty_uncore[] = { NULL, }; @@ -1382,26 +1383,26 @@ static const struct intel_uncore_init_fun skl_uncore_init __initconst = { }; static const struct x86_cpu_id intel_uncore_match[] __initconst = { - X86_UNCORE_MODEL_MATCH(26, nhm_uncore_init), /* Nehalem */ - X86_UNCORE_MODEL_MATCH(30, nhm_uncore_init), - X86_UNCORE_MODEL_MATCH(37, nhm_uncore_init), /* Westmere */ - X86_UNCORE_MODEL_MATCH(44, nhm_uncore_init), - X86_UNCORE_MODEL_MATCH(42, snb_uncore_init), /* Sandy Bridge */ - X86_UNCORE_MODEL_MATCH(58, ivb_uncore_init), /* Ivy Bridge */ - X86_UNCORE_MODEL_MATCH(60, hsw_uncore_init), /* Haswell */ - X86_UNCORE_MODEL_MATCH(69, hsw_uncore_init), /* Haswell Celeron */ - X86_UNCORE_MODEL_MATCH(70, hsw_uncore_init), /* Haswell */ - X86_UNCORE_MODEL_MATCH(61, bdw_uncore_init), /* Broadwell */ - X86_UNCORE_MODEL_MATCH(71, bdw_uncore_init), /* Broadwell */ - X86_UNCORE_MODEL_MATCH(45, snbep_uncore_init), /* Sandy Bridge-EP */ - X86_UNCORE_MODEL_MATCH(46, nhmex_uncore_init), /* Nehalem-EX */ - X86_UNCORE_MODEL_MATCH(47, nhmex_uncore_init), /* Westmere-EX aka. Xeon E7 */ - X86_UNCORE_MODEL_MATCH(62, ivbep_uncore_init), /* Ivy Bridge-EP */ - X86_UNCORE_MODEL_MATCH(63, hswep_uncore_init), /* Haswell-EP */ - X86_UNCORE_MODEL_MATCH(79, bdx_uncore_init), /* BDX-EP */ - X86_UNCORE_MODEL_MATCH(86, bdx_uncore_init), /* BDX-DE */ - X86_UNCORE_MODEL_MATCH(87, knl_uncore_init), /* Knights Landing */ - X86_UNCORE_MODEL_MATCH(94, skl_uncore_init), /* SkyLake */ + X86_UNCORE_MODEL_MATCH(INTEL_FAM6_NEHALEM_EP, nhm_uncore_init), + X86_UNCORE_MODEL_MATCH(INTEL_FAM6_NEHALEM, nhm_uncore_init), + X86_UNCORE_MODEL_MATCH(INTEL_FAM6_WESTMERE, nhm_uncore_init), + X86_UNCORE_MODEL_MATCH(INTEL_FAM6_WESTMERE_EP, nhm_uncore_init), + X86_UNCORE_MODEL_MATCH(INTEL_FAM6_SANDYBRIDGE, snb_uncore_init), + X86_UNCORE_MODEL_MATCH(INTEL_FAM6_IVYBRIDGE, ivb_uncore_init), + X86_UNCORE_MODEL_MATCH(INTEL_FAM6_HASWELL_CORE, hsw_uncore_init), + X86_UNCORE_MODEL_MATCH(INTEL_FAM6_HASWELL_ULT, hsw_uncore_init), + X86_UNCORE_MODEL_MATCH(INTEL_FAM6_HASWELL_GT3E, hsw_uncore_init), + X86_UNCORE_MODEL_MATCH(INTEL_FAM6_BROADWELL_CORE, bdw_uncore_init), + X86_UNCORE_MODEL_MATCH(INTEL_FAM6_BROADWELL_GT3E, bdw_uncore_init), + X86_UNCORE_MODEL_MATCH(INTEL_FAM6_SANDYBRIDGE_X, snbep_uncore_init), + X86_UNCORE_MODEL_MATCH(INTEL_FAM6_NEHALEM_EX, nhmex_uncore_init), + X86_UNCORE_MODEL_MATCH(INTEL_FAM6_WESTMERE_EX, nhmex_uncore_init), + X86_UNCORE_MODEL_MATCH(INTEL_FAM6_IVYBRIDGE_X, ivbep_uncore_init), + X86_UNCORE_MODEL_MATCH(INTEL_FAM6_HASWELL_X, hswep_uncore_init), + X86_UNCORE_MODEL_MATCH(INTEL_FAM6_BROADWELL_X, bdx_uncore_init), + X86_UNCORE_MODEL_MATCH(INTEL_FAM6_BROADWELL_XEON_D, bdx_uncore_init), + X86_UNCORE_MODEL_MATCH(INTEL_FAM6_XEON_PHI_KNL, knl_uncore_init), + X86_UNCORE_MODEL_MATCH(INTEL_FAM6_SKYLAKE_DESKTOP,skl_uncore_init), {}, }; -- cgit v0.10.2 From 348c5ac6c7dc117e1de095bf07c86c31101d56f3 Mon Sep 17 00:00:00 2001 From: Jacob Pan Date: Thu, 2 Jun 2016 17:19:53 -0700 Subject: perf/x86/rapl: Add Skylake server model detection SKX uses similar RAPL interface as Broadwell server. Signed-off-by: Jacob Pan Signed-off-by: Dave Hansen Cc: Alexander Shishkin Cc: Andy Lutomirski Cc: Arnaldo Carvalho de Melo Cc: Borislav Petkov Cc: Brian Gerst Cc: Dave Hansen Cc: Denys Vlasenko Cc: H. Peter Anvin Cc: Jiri Olsa Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Thomas Gleixner Cc: Vince Weaver Cc: jacob.jun.pan@intel.com Link: http://lkml.kernel.org/r/20160603001953.38848836@viggo.jf.intel.com Signed-off-by: Ingo Molnar diff --git a/arch/x86/events/intel/rapl.c b/arch/x86/events/intel/rapl.c index 8012fe6..d0c58b3 100644 --- a/arch/x86/events/intel/rapl.c +++ b/arch/x86/events/intel/rapl.c @@ -807,6 +807,7 @@ static const struct x86_cpu_id rapl_cpu_match[] __initconst = { X86_RAPL_MODEL_MATCH(INTEL_FAM6_SKYLAKE_MOBILE, skl_rapl_init), X86_RAPL_MODEL_MATCH(INTEL_FAM6_SKYLAKE_DESKTOP, skl_rapl_init), + X86_RAPL_MODEL_MATCH(INTEL_FAM6_SKYLAKE_X, hsx_rapl_init), {}, }; -- cgit v0.10.2 From 70e0d117f2502f19517be03a64b3c513f31b3cdb Mon Sep 17 00:00:00 2001 From: Dave Hansen Date: Thu, 2 Jun 2016 17:19:49 -0700 Subject: x86/pmc_core: Use Intel family name macros for pmc_core driver Another straightforward replacement of magic numbers. Signed-off-by: Dave Hansen Acked-by: Darren Hart Cc: Andy Lutomirski Cc: Borislav Petkov Cc: Brian Gerst Cc: Dave Hansen Cc: Denys Vlasenko Cc: H. Peter Anvin Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Rajneesh Bhardwaj Cc: Thomas Gleixner Cc: Vishwanath Somayaji Cc: jacob.jun.pan@intel.com Cc: platform-driver-x86@vger.kernel.org Link: http://lkml.kernel.org/r/20160603001949.7D5B9534@viggo.jf.intel.com Signed-off-by: Ingo Molnar diff --git a/drivers/platform/x86/intel_pmc_core.c b/drivers/platform/x86/intel_pmc_core.c index 2776bec..e57f923 100644 --- a/drivers/platform/x86/intel_pmc_core.c +++ b/drivers/platform/x86/intel_pmc_core.c @@ -26,6 +26,7 @@ #include #include +#include #include #include "intel_pmc_core.h" @@ -138,10 +139,10 @@ static inline void pmc_core_dbgfs_unregister(struct pmc_dev *pmcdev) #endif /* CONFIG_DEBUG_FS */ static const struct x86_cpu_id intel_pmc_core_ids[] = { - { X86_VENDOR_INTEL, 6, 0x4e, X86_FEATURE_MWAIT, - (kernel_ulong_t)NULL}, /* Skylake CPUID Signature */ - { X86_VENDOR_INTEL, 6, 0x5e, X86_FEATURE_MWAIT, - (kernel_ulong_t)NULL}, /* Skylake CPUID Signature */ + { X86_VENDOR_INTEL, 6, INTEL_FAM6_SKYLAKE_MOBILE, X86_FEATURE_MWAIT, + (kernel_ulong_t)NULL}, + { X86_VENDOR_INTEL, 6, INTEL_FAM6_SKYLAKE_DESKTOP, X86_FEATURE_MWAIT, + (kernel_ulong_t)NULL}, {} }; -- cgit v0.10.2 From 62d167330679994ec816a4fe6be22f589fcfdf76 Mon Sep 17 00:00:00 2001 From: Dave Hansen Date: Thu, 2 Jun 2016 17:19:36 -0700 Subject: x86, powercap, rapl: Use Intel model macros intead of open-coding Use the new macros to remove another large set of open-coded values. Signed-off-by: Dave Hansen Acked-by: Rafael J. Wysocki Cc: Andy Lutomirski Cc: Borislav Petkov Cc: Brian Gerst Cc: Dave Hansen Cc: Denys Vlasenko Cc: H. Peter Anvin Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: jacob.jun.pan@intel.com Cc: linux-pm@vger.kernel.org Link: http://lkml.kernel.org/r/20160603001936.F474F9D8@viggo.jf.intel.com Signed-off-by: Ingo Molnar diff --git a/drivers/powercap/intel_rapl.c b/drivers/powercap/intel_rapl.c index b2766b8..defa8d6 100644 --- a/drivers/powercap/intel_rapl.c +++ b/drivers/powercap/intel_rapl.c @@ -33,6 +33,7 @@ #include #include +#include /* Local defines */ #define MSR_PLATFORM_POWER_LIMIT 0x0000065C @@ -1096,27 +1097,27 @@ static const struct rapl_defaults rapl_defaults_cht = { } static const struct x86_cpu_id rapl_ids[] __initconst = { - RAPL_CPU(0x2a, rapl_defaults_core),/* Sandy Bridge */ - RAPL_CPU(0x2d, rapl_defaults_core),/* Sandy Bridge EP */ - RAPL_CPU(0x37, rapl_defaults_byt),/* Valleyview */ - RAPL_CPU(0x3a, rapl_defaults_core),/* Ivy Bridge */ - RAPL_CPU(0x3c, rapl_defaults_core),/* Haswell */ - RAPL_CPU(0x3d, rapl_defaults_core),/* Broadwell */ - RAPL_CPU(0x3f, rapl_defaults_hsw_server),/* Haswell servers */ - RAPL_CPU(0x4f, rapl_defaults_hsw_server),/* Broadwell servers */ - RAPL_CPU(0x45, rapl_defaults_core),/* Haswell ULT */ - RAPL_CPU(0x46, rapl_defaults_core),/* Haswell */ - RAPL_CPU(0x47, rapl_defaults_core),/* Broadwell-H */ - RAPL_CPU(0x4E, rapl_defaults_core),/* Skylake */ - RAPL_CPU(0x4C, rapl_defaults_cht),/* Braswell/Cherryview */ - RAPL_CPU(0x4A, rapl_defaults_tng),/* Tangier */ - RAPL_CPU(0x56, rapl_defaults_core),/* Future Xeon */ - RAPL_CPU(0x5A, rapl_defaults_ann),/* Annidale */ - RAPL_CPU(0X5C, rapl_defaults_core),/* Broxton */ - RAPL_CPU(0x5E, rapl_defaults_core),/* Skylake-H/S */ - RAPL_CPU(0x57, rapl_defaults_hsw_server),/* Knights Landing */ - RAPL_CPU(0x8E, rapl_defaults_core),/* Kabylake */ - RAPL_CPU(0x9E, rapl_defaults_core),/* Kabylake */ + RAPL_CPU(INTEL_FAM6_SANDYBRIDGE, rapl_defaults_core), + RAPL_CPU(INTEL_FAM6_SANDYBRIDGE_X, rapl_defaults_core), + RAPL_CPU(INTEL_FAM6_ATOM_SILVERMONT1, rapl_defaults_byt), + RAPL_CPU(INTEL_FAM6_IVYBRIDGE, rapl_defaults_core), + RAPL_CPU(INTEL_FAM6_HASWELL_CORE, rapl_defaults_core), + RAPL_CPU(INTEL_FAM6_BROADWELL_CORE, rapl_defaults_core), + RAPL_CPU(INTEL_FAM6_HASWELL_X, rapl_defaults_hsw_server), + RAPL_CPU(INTEL_FAM6_BROADWELL_X, rapl_defaults_hsw_server), + RAPL_CPU(INTEL_FAM6_HASWELL_ULT, rapl_defaults_core), + RAPL_CPU(INTEL_FAM6_HASWELL_GT3E, rapl_defaults_core), + RAPL_CPU(INTEL_FAM6_BROADWELL_GT3E, rapl_defaults_core), + RAPL_CPU(INTEL_FAM6_SKYLAKE_MOBILE, rapl_defaults_core), + RAPL_CPU(INTEL_FAM6_ATOM_AIRMONT, rapl_defaults_cht), + RAPL_CPU(INTEL_FAM6_ATOM_MERRIFIELD1, rapl_defaults_tng), + RAPL_CPU(INTEL_FAM6_BROADWELL_XEON_D, rapl_defaults_core), + RAPL_CPU(INTEL_FAM6_ATOM_MERRIFIELD2, rapl_defaults_ann), + RAPL_CPU(INTEL_FAM6_ATOM_GOLDMONT, rapl_defaults_core), + RAPL_CPU(INTEL_FAM6_SKYLAKE_DESKTOP, rapl_defaults_core), + RAPL_CPU(INTEL_FAM6_XEON_PHI_KNL, rapl_defaults_hsw_server), + RAPL_CPU(INTEL_FAM6_KABYLAKE_MOBILE, rapl_defaults_core), + RAPL_CPU(INTEL_FAM6_KABYLAKE_DESKTOP, rapl_defaults_core), {} }; MODULE_DEVICE_TABLE(x86cpu, rapl_ids); -- cgit v0.10.2 From 0bb04b5f2c2452fdf4e1e376421de6bb34485fbb Mon Sep 17 00:00:00 2001 From: Dave Hansen Date: Thu, 2 Jun 2016 17:19:37 -0700 Subject: x86, powercap, rapl: Reorder CPU detection table Let's make an effort to group these things by microarchitecture name. It makes it easier to see if something got missed. Signed-off-by: Dave Hansen Acked-by: Rafael J. Wysocki Cc: Andy Lutomirski Cc: Borislav Petkov Cc: Brian Gerst Cc: Dave Hansen Cc: Denys Vlasenko Cc: H. Peter Anvin Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: jacob.jun.pan@intel.com Cc: linux-pm@vger.kernel.org Link: http://lkml.kernel.org/r/20160603001937.B53A383A@viggo.jf.intel.com Signed-off-by: Ingo Molnar diff --git a/drivers/powercap/intel_rapl.c b/drivers/powercap/intel_rapl.c index defa8d6..f4f8532 100644 --- a/drivers/powercap/intel_rapl.c +++ b/drivers/powercap/intel_rapl.c @@ -1099,25 +1099,31 @@ static const struct rapl_defaults rapl_defaults_cht = { static const struct x86_cpu_id rapl_ids[] __initconst = { RAPL_CPU(INTEL_FAM6_SANDYBRIDGE, rapl_defaults_core), RAPL_CPU(INTEL_FAM6_SANDYBRIDGE_X, rapl_defaults_core), - RAPL_CPU(INTEL_FAM6_ATOM_SILVERMONT1, rapl_defaults_byt), + RAPL_CPU(INTEL_FAM6_IVYBRIDGE, rapl_defaults_core), + RAPL_CPU(INTEL_FAM6_HASWELL_CORE, rapl_defaults_core), - RAPL_CPU(INTEL_FAM6_BROADWELL_CORE, rapl_defaults_core), - RAPL_CPU(INTEL_FAM6_HASWELL_X, rapl_defaults_hsw_server), - RAPL_CPU(INTEL_FAM6_BROADWELL_X, rapl_defaults_hsw_server), RAPL_CPU(INTEL_FAM6_HASWELL_ULT, rapl_defaults_core), RAPL_CPU(INTEL_FAM6_HASWELL_GT3E, rapl_defaults_core), + RAPL_CPU(INTEL_FAM6_HASWELL_X, rapl_defaults_hsw_server), + + RAPL_CPU(INTEL_FAM6_BROADWELL_CORE, rapl_defaults_core), RAPL_CPU(INTEL_FAM6_BROADWELL_GT3E, rapl_defaults_core), + RAPL_CPU(INTEL_FAM6_BROADWELL_XEON_D, rapl_defaults_core), + RAPL_CPU(INTEL_FAM6_BROADWELL_X, rapl_defaults_hsw_server), + + RAPL_CPU(INTEL_FAM6_SKYLAKE_DESKTOP, rapl_defaults_core), RAPL_CPU(INTEL_FAM6_SKYLAKE_MOBILE, rapl_defaults_core), + RAPL_CPU(INTEL_FAM6_KABYLAKE_MOBILE, rapl_defaults_core), + RAPL_CPU(INTEL_FAM6_KABYLAKE_DESKTOP, rapl_defaults_core), + + RAPL_CPU(INTEL_FAM6_ATOM_SILVERMONT1, rapl_defaults_byt), RAPL_CPU(INTEL_FAM6_ATOM_AIRMONT, rapl_defaults_cht), RAPL_CPU(INTEL_FAM6_ATOM_MERRIFIELD1, rapl_defaults_tng), - RAPL_CPU(INTEL_FAM6_BROADWELL_XEON_D, rapl_defaults_core), RAPL_CPU(INTEL_FAM6_ATOM_MERRIFIELD2, rapl_defaults_ann), RAPL_CPU(INTEL_FAM6_ATOM_GOLDMONT, rapl_defaults_core), - RAPL_CPU(INTEL_FAM6_SKYLAKE_DESKTOP, rapl_defaults_core), + RAPL_CPU(INTEL_FAM6_XEON_PHI_KNL, rapl_defaults_hsw_server), - RAPL_CPU(INTEL_FAM6_KABYLAKE_MOBILE, rapl_defaults_core), - RAPL_CPU(INTEL_FAM6_KABYLAKE_DESKTOP, rapl_defaults_core), {} }; MODULE_DEVICE_TABLE(x86cpu, rapl_ids); -- cgit v0.10.2 From d40671e30cb46e834651e0ce3d4590c915171414 Mon Sep 17 00:00:00 2001 From: Dave Hansen Date: Thu, 2 Jun 2016 17:19:55 -0700 Subject: x86, powercap, rapl: Add Skylake Server model number SKX uses similar RAPL interface as Broadwell server according to Jacob Pan. Signed-off-by: Dave Hansen Cc: Andy Lutomirski Cc: Borislav Petkov Cc: Brian Gerst Cc: Dave Hansen Cc: Denys Vlasenko Cc: H. Peter Anvin Cc: Jacob Pan Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Rafael J. Wysocki Cc: Thomas Gleixner Cc: jacob.jun.pan@intel.com Cc: linux-pm@vger.kernel.org Link: http://lkml.kernel.org/r/20160603001955.38E1E684@viggo.jf.intel.com Signed-off-by: Ingo Molnar diff --git a/drivers/powercap/intel_rapl.c b/drivers/powercap/intel_rapl.c index f4f8532..2e8f2be 100644 --- a/drivers/powercap/intel_rapl.c +++ b/drivers/powercap/intel_rapl.c @@ -1114,6 +1114,7 @@ static const struct x86_cpu_id rapl_ids[] __initconst = { RAPL_CPU(INTEL_FAM6_SKYLAKE_DESKTOP, rapl_defaults_core), RAPL_CPU(INTEL_FAM6_SKYLAKE_MOBILE, rapl_defaults_core), + RAPL_CPU(INTEL_FAM6_SKYLAKE_X, rapl_defaults_hsw_server), RAPL_CPU(INTEL_FAM6_KABYLAKE_MOBILE, rapl_defaults_core), RAPL_CPU(INTEL_FAM6_KABYLAKE_DESKTOP, rapl_defaults_core), -- cgit v0.10.2 From db73c5a8c80decbb6ddf208e58f3865b4df5384d Mon Sep 17 00:00:00 2001 From: Dave Hansen Date: Thu, 2 Jun 2016 17:19:32 -0700 Subject: x86/intel_idle: Use Intel family macros for intel_idle Use the new INTEL_FAM6_* macros for intel_idle.c. Also fix up some of the macros to be consistent with how some of the intel_idle code refers to the model. There's on oddity here: model 0x1F is uniquely referred to here and nowhere else that I could find. 0x1E/0x1F are just spelled out as "Intel Core i7 and i5 Processors" in the SDM or as "Intel processors based on the Nehalem, Westmere microarchitectures" in the RDPMC section. Comments between tables 19-19 and 19-20 in the SDM seem to point to 0x1F being some kind of Westmere, so let's call it "WESTMERE2". Signed-off-by: Dave Hansen Acked-by: Rafael J. Wysocki Cc: Andy Lutomirski Cc: Borislav Petkov Cc: Brian Gerst Cc: Dave Hansen Cc: Denys Vlasenko Cc: H. Peter Anvin Cc: Len Brown Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: jacob.jun.pan@intel.com Cc: linux-pm@vger.kernel.org Link: http://lkml.kernel.org/r/20160603001932.EE978EB9@viggo.jf.intel.com Signed-off-by: Ingo Molnar diff --git a/drivers/idle/intel_idle.c b/drivers/idle/intel_idle.c index c966492..b5dd41d 100644 --- a/drivers/idle/intel_idle.c +++ b/drivers/idle/intel_idle.c @@ -62,6 +62,7 @@ #include #include #include +#include #include #include @@ -1020,38 +1021,38 @@ static const struct idle_cpu idle_cpu_bxt = { { X86_VENDOR_INTEL, 6, model, X86_FEATURE_MWAIT, (unsigned long)&cpu } static const struct x86_cpu_id intel_idle_ids[] __initconst = { - ICPU(0x1a, idle_cpu_nehalem), - ICPU(0x1e, idle_cpu_nehalem), - ICPU(0x1f, idle_cpu_nehalem), - ICPU(0x25, idle_cpu_nehalem), - ICPU(0x2c, idle_cpu_nehalem), - ICPU(0x2e, idle_cpu_nehalem), - ICPU(0x1c, idle_cpu_atom), - ICPU(0x26, idle_cpu_lincroft), - ICPU(0x2f, idle_cpu_nehalem), - ICPU(0x2a, idle_cpu_snb), - ICPU(0x2d, idle_cpu_snb), - ICPU(0x36, idle_cpu_atom), - ICPU(0x37, idle_cpu_byt), - ICPU(0x4c, idle_cpu_cht), - ICPU(0x3a, idle_cpu_ivb), - ICPU(0x3e, idle_cpu_ivt), - ICPU(0x3c, idle_cpu_hsw), - ICPU(0x3f, idle_cpu_hsw), - ICPU(0x45, idle_cpu_hsw), - ICPU(0x46, idle_cpu_hsw), - ICPU(0x4d, idle_cpu_avn), - ICPU(0x3d, idle_cpu_bdw), - ICPU(0x47, idle_cpu_bdw), - ICPU(0x4f, idle_cpu_bdw), - ICPU(0x56, idle_cpu_bdw), - ICPU(0x4e, idle_cpu_skl), - ICPU(0x5e, idle_cpu_skl), - ICPU(0x8e, idle_cpu_skl), - ICPU(0x9e, idle_cpu_skl), - ICPU(0x55, idle_cpu_skx), - ICPU(0x57, idle_cpu_knl), - ICPU(0x5c, idle_cpu_bxt), + ICPU(INTEL_FAM6_NEHALEM_EP, idle_cpu_nehalem), + ICPU(INTEL_FAM6_NEHALEM, idle_cpu_nehalem), + ICPU(INTEL_FAM6_WESTMERE2, idle_cpu_nehalem), + ICPU(INTEL_FAM6_WESTMERE, idle_cpu_nehalem), + ICPU(INTEL_FAM6_WESTMERE_EP, idle_cpu_nehalem), + ICPU(INTEL_FAM6_NEHALEM_EX, idle_cpu_nehalem), + ICPU(INTEL_FAM6_ATOM_PINEVIEW, idle_cpu_atom), + ICPU(INTEL_FAM6_ATOM_LINCROFT, idle_cpu_lincroft), + ICPU(INTEL_FAM6_WESTMERE_EX, idle_cpu_nehalem), + ICPU(INTEL_FAM6_SANDYBRIDGE, idle_cpu_snb), + ICPU(INTEL_FAM6_SANDYBRIDGE_X, idle_cpu_snb), + ICPU(INTEL_FAM6_ATOM_CEDARVIEW, idle_cpu_atom), + ICPU(INTEL_FAM6_ATOM_SILVERMONT1, idle_cpu_byt), + ICPU(INTEL_FAM6_ATOM_AIRMONT, idle_cpu_cht), + ICPU(INTEL_FAM6_IVYBRIDGE, idle_cpu_ivb), + ICPU(INTEL_FAM6_IVYBRIDGE_X, idle_cpu_ivt), + ICPU(INTEL_FAM6_HASWELL_CORE, idle_cpu_hsw), + ICPU(INTEL_FAM6_HASWELL_X, idle_cpu_hsw), + ICPU(INTEL_FAM6_HASWELL_ULT, idle_cpu_hsw), + ICPU(INTEL_FAM6_HASWELL_GT3E, idle_cpu_hsw), + ICPU(INTEL_FAM6_ATOM_SILVERMONT2, idle_cpu_avn), + ICPU(INTEL_FAM6_BROADWELL_CORE, idle_cpu_bdw), + ICPU(INTEL_FAM6_BROADWELL_GT3E, idle_cpu_bdw), + ICPU(INTEL_FAM6_BROADWELL_X, idle_cpu_bdw), + ICPU(INTEL_FAM6_BROADWELL_XEON_D, idle_cpu_bdw), + ICPU(INTEL_FAM6_SKYLAKE_MOBILE, idle_cpu_skl), + ICPU(INTEL_FAM6_SKYLAKE_DESKTOP, idle_cpu_skl), + ICPU(INTEL_FAM6_KABYLAKE_MOBILE, idle_cpu_skl), + ICPU(INTEL_FAM6_KABYLAKE_DESKTOP, idle_cpu_skl), + ICPU(INTEL_FAM6_SKYLAKE_X, idle_cpu_skx), + ICPU(INTEL_FAM6_XEON_PHI_KNL, idle_cpu_knl), + ICPU(INTEL_FAM6_ATOM_GOLDMONT, idle_cpu_bxt), {} }; MODULE_DEVICE_TABLE(x86cpu, intel_idle_ids); @@ -1261,13 +1262,13 @@ static void intel_idle_state_table_update(void) { switch (boot_cpu_data.x86_model) { - case 0x3e: /* IVT */ + case INTEL_FAM6_IVYBRIDGE_X: ivt_idle_state_table_update(); break; - case 0x5c: /* BXT */ + case INTEL_FAM6_ATOM_GOLDMONT: bxt_idle_state_table_update(); break; - case 0x5e: /* SKL-H */ + case INTEL_FAM6_SKYLAKE_DESKTOP: sklh_idle_state_table_update(); break; } -- cgit v0.10.2 From d5e0c89a8ccde900c3245474915ea0f518abdb79 Mon Sep 17 00:00:00 2001 From: Dave Hansen Date: Thu, 2 Jun 2016 17:19:39 -0700 Subject: x86/platform: Use new Intel model number macros Remove the open-coded model numbers. Signed-off-by: Dave Hansen Cc: Andy Lutomirski Cc: Borislav Petkov Cc: Brian Gerst Cc: Dave Hansen Cc: Denys Vlasenko Cc: H. Peter Anvin Cc: Jacob Pan Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Rafael J. Wysocki Cc: Srinivas Pandruvada Cc: Thomas Gleixner Cc: jacob.jun.pan@intel.com Link: http://lkml.kernel.org/r/20160603001939.D1D7FC2F@viggo.jf.intel.com Signed-off-by: Ingo Molnar diff --git a/arch/x86/platform/atom/punit_atom_debug.c b/arch/x86/platform/atom/punit_atom_debug.c index 81c769e..1097829 100644 --- a/arch/x86/platform/atom/punit_atom_debug.c +++ b/arch/x86/platform/atom/punit_atom_debug.c @@ -23,6 +23,7 @@ #include #include #include +#include #include /* Power gate status reg */ @@ -143,8 +144,8 @@ static void punit_dbgfs_unregister(void) (kernel_ulong_t)&drv_data } static const struct x86_cpu_id intel_punit_cpu_ids[] = { - ICPU(55, punit_device_byt), /* Valleyview, Bay Trail */ - ICPU(76, punit_device_cht), /* Braswell, Cherry Trail */ + ICPU(INTEL_FAM6_ATOM_SILVERMONT1, punit_device_byt), + ICPU(INTEL_FAM6_ATOM_AIRMONT, punit_device_cht), {} }; -- cgit v0.10.2 From 5b20c944882ce35da0074b9eabe41a172aea030b Mon Sep 17 00:00:00 2001 From: Dave Hansen Date: Thu, 2 Jun 2016 17:19:45 -0700 Subject: x86/cpufreq: Use Intel family name macros for the intel_pstate cpufreq driver Another straightforward replacement of magic numbers. Signed-off-by: Dave Hansen Acked-by: Rafael J. Wysocki Cc: Andy Lutomirski Cc: Borislav Petkov Cc: Brian Gerst Cc: Dave Hansen Cc: Denys Vlasenko Cc: H. Peter Anvin Cc: Len Brown Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Srinivas Pandruvada Cc: Thomas Gleixner Cc: Viresh Kumar Cc: jacob.jun.pan@intel.com Cc: linux-pm@vger.kernel.org Link: http://lkml.kernel.org/r/20160603001945.0F5D02AA@viggo.jf.intel.com Signed-off-by: Ingo Molnar diff --git a/drivers/cpufreq/intel_pstate.c b/drivers/cpufreq/intel_pstate.c index 0d159b5..9b1f5d7 100644 --- a/drivers/cpufreq/intel_pstate.c +++ b/drivers/cpufreq/intel_pstate.c @@ -35,6 +35,7 @@ #include #include #include +#include #define ATOM_RATIOS 0x66a #define ATOM_VIDS 0x66b @@ -1352,29 +1353,29 @@ static void intel_pstate_update_util(struct update_util_data *data, u64 time, (unsigned long)&policy } static const struct x86_cpu_id intel_pstate_cpu_ids[] = { - ICPU(0x2a, core_params), - ICPU(0x2d, core_params), - ICPU(0x37, silvermont_params), - ICPU(0x3a, core_params), - ICPU(0x3c, core_params), - ICPU(0x3d, core_params), - ICPU(0x3e, core_params), - ICPU(0x3f, core_params), - ICPU(0x45, core_params), - ICPU(0x46, core_params), - ICPU(0x47, core_params), - ICPU(0x4c, airmont_params), - ICPU(0x4e, core_params), - ICPU(0x4f, core_params), - ICPU(0x5e, core_params), - ICPU(0x56, core_params), - ICPU(0x57, knl_params), + ICPU(INTEL_FAM6_SANDYBRIDGE, core_params), + ICPU(INTEL_FAM6_SANDYBRIDGE_X, core_params), + ICPU(INTEL_FAM6_ATOM_SILVERMONT1, silvermont_params), + ICPU(INTEL_FAM6_IVYBRIDGE, core_params), + ICPU(INTEL_FAM6_HASWELL_CORE, core_params), + ICPU(INTEL_FAM6_BROADWELL_CORE, core_params), + ICPU(INTEL_FAM6_IVYBRIDGE_X, core_params), + ICPU(INTEL_FAM6_HASWELL_X, core_params), + ICPU(INTEL_FAM6_HASWELL_ULT, core_params), + ICPU(INTEL_FAM6_HASWELL_GT3E, core_params), + ICPU(INTEL_FAM6_BROADWELL_GT3E, core_params), + ICPU(INTEL_FAM6_ATOM_AIRMONT, airmont_params), + ICPU(INTEL_FAM6_SKYLAKE_MOBILE, core_params), + ICPU(INTEL_FAM6_BROADWELL_X, core_params), + ICPU(INTEL_FAM6_SKYLAKE_DESKTOP, core_params), + ICPU(INTEL_FAM6_BROADWELL_XEON_D, core_params), + ICPU(INTEL_FAM6_XEON_PHI_KNL, knl_params), {} }; MODULE_DEVICE_TABLE(x86cpu, intel_pstate_cpu_ids); static const struct x86_cpu_id intel_pstate_cpu_oob_ids[] = { - ICPU(0x56, core_params), + ICPU(INTEL_FAM6_BROADWELL_XEON_D, core_params), {} }; -- cgit v0.10.2 From 4626d840a1e0044e6f23d226ea8a5b96bd167636 Mon Sep 17 00:00:00 2001 From: Dave Hansen Date: Thu, 2 Jun 2016 17:19:46 -0700 Subject: x86/acpi/lss: Use Intel family name macros for the acpi_lpss driver Another straightforward replacement of magic numbers. Signed-off-by: Dave Hansen Acked-by: Rafael J. Wysocki Cc: Andy Lutomirski Cc: Borislav Petkov Cc: Brian Gerst Cc: Dave Hansen Cc: Denys Vlasenko Cc: H. Peter Anvin Cc: Len Brown Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: jacob.jun.pan@intel.com Cc: linux-acpi@vger.kernel.org Link: http://lkml.kernel.org/r/20160603001946.264CE704@viggo.jf.intel.com Signed-off-by: Ingo Molnar diff --git a/drivers/acpi/acpi_lpss.c b/drivers/acpi/acpi_lpss.c index 0872d5f..357a0b8 100644 --- a/drivers/acpi/acpi_lpss.c +++ b/drivers/acpi/acpi_lpss.c @@ -29,6 +29,7 @@ ACPI_MODULE_NAME("acpi_lpss"); #ifdef CONFIG_X86_INTEL_LPSS #include +#include #include #include @@ -229,8 +230,8 @@ static const struct lpss_device_desc bsw_spi_dev_desc = { #define ICPU(model) { X86_VENDOR_INTEL, 6, model, X86_FEATURE_ANY, } static const struct x86_cpu_id lpss_cpu_ids[] = { - ICPU(0x37), /* Valleyview, Bay Trail */ - ICPU(0x4c), /* Braswell, Cherry Trail */ + ICPU(INTEL_FAM6_ATOM_SILVERMONT1), /* Valleyview, Bay Trail */ + ICPU(INTEL_FAM6_ATOM_AIRMONT), /* Braswell, Cherry Trail */ {} }; -- cgit v0.10.2 From 678dec00a4753b74df8ad6fc5167429b614d1139 Mon Sep 17 00:00:00 2001 From: Dave Hansen Date: Thu, 2 Jun 2016 17:19:47 -0700 Subject: x86/intel_telemetry: Use Intel family name macros for telemetry driver Another straightforward replacement of magic numbers. Signed-off-by: Dave Hansen Acked-by: Darren Hart Cc: Andy Lutomirski Cc: Borislav Petkov Cc: Brian Gerst Cc: Dave Hansen Cc: Denys Vlasenko Cc: H. Peter Anvin Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Souvik Kumar Chakravarty Cc: Thomas Gleixner Cc: jacob.jun.pan@intel.com Cc: platform-driver-x86@vger.kernel.org Link: http://lkml.kernel.org/r/20160603001947.05102C3E@viggo.jf.intel.com Signed-off-by: Ingo Molnar diff --git a/drivers/platform/x86/intel_telemetry_debugfs.c b/drivers/platform/x86/intel_telemetry_debugfs.c index f5134ac..815a7c5 100644 --- a/drivers/platform/x86/intel_telemetry_debugfs.c +++ b/drivers/platform/x86/intel_telemetry_debugfs.c @@ -32,6 +32,7 @@ #include #include +#include #include #include #include @@ -331,7 +332,7 @@ static struct telemetry_debugfs_conf telem_apl_debugfs_conf = { }; static const struct x86_cpu_id telemetry_debugfs_cpu_ids[] = { - TELEM_DEBUGFS_CPU(0x5c, telem_apl_debugfs_conf), + TELEM_DEBUGFS_CPU(INTEL_FAM6_ATOM_GOLDMONT, telem_apl_debugfs_conf), {} }; diff --git a/drivers/platform/x86/intel_telemetry_pltdrv.c b/drivers/platform/x86/intel_telemetry_pltdrv.c index 09c84a2..6d884f7 100644 --- a/drivers/platform/x86/intel_telemetry_pltdrv.c +++ b/drivers/platform/x86/intel_telemetry_pltdrv.c @@ -28,6 +28,7 @@ #include #include +#include #include #include #include @@ -163,7 +164,7 @@ static struct telemetry_plt_config telem_apl_config = { }; static const struct x86_cpu_id telemetry_cpu_ids[] = { - TELEM_CPU(0x5c, telem_apl_config), + TELEM_CPU(INTEL_FAM6_ATOM_GOLDMONT, telem_apl_config), {} }; -- cgit v0.10.2 From 8ba4cb53129c3089f248f1ebeb25128d93c8b5c5 Mon Sep 17 00:00:00 2001 From: Dave Hansen Date: Thu, 2 Jun 2016 17:19:51 -0700 Subject: x86, mmc: Use Intel family name macros for mmc driver Another straightforward replacement of magic numbers. Signed-off-by: Dave Hansen Acked-by: Adrian Hunter Cc: Andy Lutomirski Cc: Borislav Petkov Cc: Brian Gerst Cc: Dave Hansen Cc: Denys Vlasenko Cc: H. Peter Anvin Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: Ulf Hansson Cc: jacob.jun.pan@intel.com Cc: linux-mmc@vger.kernel.org Link: http://lkml.kernel.org/r/20160603001951.9EEA53D8@viggo.jf.intel.com Signed-off-by: Ingo Molnar diff --git a/drivers/mmc/host/sdhci-acpi.c b/drivers/mmc/host/sdhci-acpi.c index 458ffb7..008709c 100644 --- a/drivers/mmc/host/sdhci-acpi.c +++ b/drivers/mmc/host/sdhci-acpi.c @@ -43,6 +43,7 @@ #ifdef CONFIG_X86 #include +#include #include #endif @@ -126,7 +127,7 @@ static const struct sdhci_acpi_chip sdhci_acpi_chip_int = { static bool sdhci_acpi_byt(void) { static const struct x86_cpu_id byt[] = { - { X86_VENDOR_INTEL, 6, 0x37 }, + { X86_VENDOR_INTEL, 6, INTEL_FAM6_ATOM_SILVERMONT1 }, {} }; -- cgit v0.10.2 From ce53da02ebfbe93ec58dd6150b28b4606330ead5 Mon Sep 17 00:00:00 2001 From: Dave Hansen Date: Thu, 2 Jun 2016 17:19:52 -0700 Subject: x86, thermal: Clean up and fix CPU model detection for intel_soc_dts_thermal The X86_FAMILY_ANY in here is bogus. "BYT" and model 0x37 are family-6 only. Signed-off-by: Dave Hansen Cc: Andy Lutomirski Cc: Borislav Petkov Cc: Brian Gerst Cc: Dave Hansen Cc: Denys Vlasenko Cc: Eduardo Valentin Cc: H. Peter Anvin Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: Zhang Rui Cc: jacob.jun.pan@intel.com Cc: linux-pm@vger.kernel.org Link: http://lkml.kernel.org/r/20160603001952.9B6E114D@viggo.jf.intel.com Signed-off-by: Ingo Molnar diff --git a/drivers/thermal/intel_soc_dts_thermal.c b/drivers/thermal/intel_soc_dts_thermal.c index 4ebb31a3..b2bbaa1 100644 --- a/drivers/thermal/intel_soc_dts_thermal.c +++ b/drivers/thermal/intel_soc_dts_thermal.c @@ -18,6 +18,7 @@ #include #include #include +#include #include "intel_soc_dts_iosf.h" #define CRITICAL_OFFSET_FROM_TJ_MAX 5000 @@ -42,7 +43,8 @@ static irqreturn_t soc_irq_thread_fn(int irq, void *dev_data) } static const struct x86_cpu_id soc_thermal_ids[] = { - { X86_VENDOR_INTEL, X86_FAMILY_ANY, 0x37, 0, BYT_SOC_DTS_APIC_IRQ}, + { X86_VENDOR_INTEL, 6, INTEL_FAM6_ATOM_SILVERMONT1, 0, + BYT_SOC_DTS_APIC_IRQ}, {} }; MODULE_DEVICE_TABLE(x86cpu, soc_thermal_ids); -- cgit v0.10.2 From d1898b733619bd46194bd25aa6452d238ff2dc4e Mon Sep 17 00:00:00 2001 From: Dave Hansen Date: Wed, 1 Jun 2016 10:42:20 -0700 Subject: x86/fpu: Add tracepoints to dump FPU state at key points I've been carrying this patch around for a bit and it's helped me solve at least a couple FPU-related bugs. In addition to using it for debugging, I also drug it out because using AVX (and AVX2/AVX-512) can have serious power consequences for a modern core. It's very important to be able to figure out who is using it. It's also insanely useful to go out and see who is using a given feature, like MPX or Memory Protection Keys. If you, for instance, want to find all processes using protection keys, you can do: echo 'xfeatures & 0x200' > filter Since 0x200 is the protection keys feature bit. Note that this touches the KVM code. KVM did a CREATE_TRACE_POINTS and then included a bunch of random headers. If anyone one of those included other tracepoints, it would have defined the *OTHER* tracepoints. That's bogus, so move it to the right place. Signed-off-by: Dave Hansen Cc: Andy Lutomirski Cc: Borislav Petkov Cc: Brian Gerst Cc: Dave Hansen Cc: Denys Vlasenko Cc: Fenghua Yu Cc: H. Peter Anvin Cc: Linus Torvalds Cc: Oleg Nesterov Cc: Peter Zijlstra Cc: Quentin Casasnovas Cc: Steven Rostedt Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/20160601174220.3CDFB90E@viggo.jf.intel.com Signed-off-by: Ingo Molnar diff --git a/arch/x86/include/asm/fpu/internal.h b/arch/x86/include/asm/fpu/internal.h index 31ac8e6..116b583 100644 --- a/arch/x86/include/asm/fpu/internal.h +++ b/arch/x86/include/asm/fpu/internal.h @@ -18,6 +18,7 @@ #include #include #include +#include /* * High level FPU state handling functions: @@ -524,6 +525,7 @@ static inline void __fpregs_deactivate(struct fpu *fpu) fpu->fpregs_active = 0; this_cpu_write(fpu_fpregs_owner_ctx, NULL); + trace_x86_fpu_regs_deactivated(fpu); } /* Must be paired with a 'clts' (fpregs_activate_hw()) before! */ @@ -533,6 +535,7 @@ static inline void __fpregs_activate(struct fpu *fpu) fpu->fpregs_active = 1; this_cpu_write(fpu_fpregs_owner_ctx, fpu); + trace_x86_fpu_regs_activated(fpu); } /* @@ -604,11 +607,13 @@ switch_fpu_prepare(struct fpu *old_fpu, struct fpu *new_fpu, int cpu) /* But leave fpu_fpregs_owner_ctx! */ old_fpu->fpregs_active = 0; + trace_x86_fpu_regs_deactivated(old_fpu); /* Don't change CR0.TS if we just switch! */ if (fpu.preload) { new_fpu->counter++; __fpregs_activate(new_fpu); + trace_x86_fpu_regs_activated(new_fpu); prefetch(&new_fpu->state); } else { __fpregs_deactivate_hw(); diff --git a/arch/x86/include/asm/trace/fpu.h b/arch/x86/include/asm/trace/fpu.h new file mode 100644 index 0000000..9217ab1 --- /dev/null +++ b/arch/x86/include/asm/trace/fpu.h @@ -0,0 +1,119 @@ +#undef TRACE_SYSTEM +#define TRACE_SYSTEM x86_fpu + +#if !defined(_TRACE_FPU_H) || defined(TRACE_HEADER_MULTI_READ) +#define _TRACE_FPU_H + +#include + +DECLARE_EVENT_CLASS(x86_fpu, + TP_PROTO(struct fpu *fpu), + TP_ARGS(fpu), + + TP_STRUCT__entry( + __field(struct fpu *, fpu) + __field(bool, fpregs_active) + __field(bool, fpstate_active) + __field(int, counter) + __field(u64, xfeatures) + __field(u64, xcomp_bv) + ), + + TP_fast_assign( + __entry->fpu = fpu; + __entry->fpregs_active = fpu->fpregs_active; + __entry->fpstate_active = fpu->fpstate_active; + __entry->counter = fpu->counter; + if (boot_cpu_has(X86_FEATURE_OSXSAVE)) { + __entry->xfeatures = fpu->state.xsave.header.xfeatures; + __entry->xcomp_bv = fpu->state.xsave.header.xcomp_bv; + } + ), + TP_printk("x86/fpu: %p fpregs_active: %d fpstate_active: %d counter: %d xfeatures: %llx xcomp_bv: %llx", + __entry->fpu, + __entry->fpregs_active, + __entry->fpstate_active, + __entry->counter, + __entry->xfeatures, + __entry->xcomp_bv + ) +); + +DEFINE_EVENT(x86_fpu, x86_fpu_state, + TP_PROTO(struct fpu *fpu), + TP_ARGS(fpu) +); + +DEFINE_EVENT(x86_fpu, x86_fpu_before_save, + TP_PROTO(struct fpu *fpu), + TP_ARGS(fpu) +); + +DEFINE_EVENT(x86_fpu, x86_fpu_after_save, + TP_PROTO(struct fpu *fpu), + TP_ARGS(fpu) +); + +DEFINE_EVENT(x86_fpu, x86_fpu_before_restore, + TP_PROTO(struct fpu *fpu), + TP_ARGS(fpu) +); + +DEFINE_EVENT(x86_fpu, x86_fpu_after_restore, + TP_PROTO(struct fpu *fpu), + TP_ARGS(fpu) +); + +DEFINE_EVENT(x86_fpu, x86_fpu_regs_activated, + TP_PROTO(struct fpu *fpu), + TP_ARGS(fpu) +); + +DEFINE_EVENT(x86_fpu, x86_fpu_regs_deactivated, + TP_PROTO(struct fpu *fpu), + TP_ARGS(fpu) +); + +DEFINE_EVENT(x86_fpu, x86_fpu_activate_state, + TP_PROTO(struct fpu *fpu), + TP_ARGS(fpu) +); + +DEFINE_EVENT(x86_fpu, x86_fpu_deactivate_state, + TP_PROTO(struct fpu *fpu), + TP_ARGS(fpu) +); + +DEFINE_EVENT(x86_fpu, x86_fpu_init_state, + TP_PROTO(struct fpu *fpu), + TP_ARGS(fpu) +); + +DEFINE_EVENT(x86_fpu, x86_fpu_dropped, + TP_PROTO(struct fpu *fpu), + TP_ARGS(fpu) +); + +DEFINE_EVENT(x86_fpu, x86_fpu_copy_src, + TP_PROTO(struct fpu *fpu), + TP_ARGS(fpu) +); + +DEFINE_EVENT(x86_fpu, x86_fpu_copy_dst, + TP_PROTO(struct fpu *fpu), + TP_ARGS(fpu) +); + +DEFINE_EVENT(x86_fpu, x86_fpu_xstate_check_failed, + TP_PROTO(struct fpu *fpu), + TP_ARGS(fpu) +); + +#undef TRACE_INCLUDE_PATH +#define TRACE_INCLUDE_PATH asm/trace/ +#undef TRACE_INCLUDE_FILE +#define TRACE_INCLUDE_FILE fpu +#endif /* _TRACE_FPU_H */ + +/* This part must be outside protection */ +#include diff --git a/arch/x86/kernel/fpu/core.c b/arch/x86/kernel/fpu/core.c index 9702754..7d56474 100644 --- a/arch/x86/kernel/fpu/core.c +++ b/arch/x86/kernel/fpu/core.c @@ -12,6 +12,9 @@ #include +#define CREATE_TRACE_POINTS +#include + /* * Represents the initial FPU state. It's mostly (but not completely) zeroes, * depending on the FPU hardware format: @@ -192,6 +195,7 @@ void fpu__save(struct fpu *fpu) WARN_ON_FPU(fpu != ¤t->thread.fpu); preempt_disable(); + trace_x86_fpu_before_save(fpu); if (fpu->fpregs_active) { if (!copy_fpregs_to_fpstate(fpu)) { if (use_eager_fpu()) @@ -200,6 +204,7 @@ void fpu__save(struct fpu *fpu) fpregs_deactivate(fpu); } } + trace_x86_fpu_after_save(fpu); preempt_enable(); } EXPORT_SYMBOL_GPL(fpu__save); @@ -275,6 +280,9 @@ int fpu__copy(struct fpu *dst_fpu, struct fpu *src_fpu) } preempt_enable(); + trace_x86_fpu_copy_src(src_fpu); + trace_x86_fpu_copy_dst(dst_fpu); + return 0; } @@ -288,7 +296,9 @@ void fpu__activate_curr(struct fpu *fpu) if (!fpu->fpstate_active) { fpstate_init(&fpu->state); + trace_x86_fpu_init_state(fpu); + trace_x86_fpu_activate_state(fpu); /* Safe to do for the current task: */ fpu->fpstate_active = 1; } @@ -314,7 +324,9 @@ void fpu__activate_fpstate_read(struct fpu *fpu) } else { if (!fpu->fpstate_active) { fpstate_init(&fpu->state); + trace_x86_fpu_init_state(fpu); + trace_x86_fpu_activate_state(fpu); /* Safe to do for current and for stopped child tasks: */ fpu->fpstate_active = 1; } @@ -347,7 +359,9 @@ void fpu__activate_fpstate_write(struct fpu *fpu) fpu->last_cpu = -1; } else { fpstate_init(&fpu->state); + trace_x86_fpu_init_state(fpu); + trace_x86_fpu_activate_state(fpu); /* Safe to do for stopped child tasks: */ fpu->fpstate_active = 1; } @@ -432,9 +446,11 @@ void fpu__restore(struct fpu *fpu) /* Avoid __kernel_fpu_begin() right after fpregs_activate() */ kernel_fpu_disable(); + trace_x86_fpu_before_restore(fpu); fpregs_activate(fpu); copy_kernel_to_fpregs(&fpu->state); fpu->counter++; + trace_x86_fpu_after_restore(fpu); kernel_fpu_enable(); } EXPORT_SYMBOL_GPL(fpu__restore); @@ -463,6 +479,8 @@ void fpu__drop(struct fpu *fpu) fpu->fpstate_active = 0; + trace_x86_fpu_dropped(fpu); + preempt_enable(); } diff --git a/arch/x86/kernel/fpu/signal.c b/arch/x86/kernel/fpu/signal.c index 31c6a60..c6f2a3c 100644 --- a/arch/x86/kernel/fpu/signal.c +++ b/arch/x86/kernel/fpu/signal.c @@ -10,6 +10,7 @@ #include #include +#include static struct _fpx_sw_bytes fx_sw_reserved, fx_sw_reserved_ia32; @@ -282,6 +283,7 @@ static int __fpu__restore_sig(void __user *buf, void __user *buf_fx, int size) */ state_size = sizeof(struct fxregs_state); fx_only = 1; + trace_x86_fpu_xstate_check_failed(fpu); } else { state_size = fx_sw_user.xstate_size; xfeatures = fx_sw_user.xfeatures; @@ -311,6 +313,7 @@ static int __fpu__restore_sig(void __user *buf, void __user *buf_fx, int size) if (__copy_from_user(&fpu->state.xsave, buf_fx, state_size) || __copy_from_user(&env, buf, sizeof(env))) { fpstate_init(&fpu->state); + trace_x86_fpu_init_state(fpu); err = -1; } else { sanitize_restored_xstate(tsk, &env, xfeatures, fx_only); diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 902d9da..1ba3b7d 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -55,9 +55,6 @@ #include #include -#define CREATE_TRACE_POINTS -#include "trace.h" - #include #include #include @@ -68,6 +65,9 @@ #include #include +#define CREATE_TRACE_POINTS +#include "trace.h" + #define MAX_IO_MSRS 256 #define KVM_MAX_MCE_BANKS 32 #define KVM_MCE_CAP_SUPPORTED (MCG_CTL_P | MCG_SER_P) -- cgit v0.10.2 From dfaaf3fa01d65cf6e2072965bb0b7aaa7285344f Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Mon, 30 May 2016 18:31:33 +0200 Subject: locking/lockdep: Use __jhash_mix() for iterate_chain_key() Use __jhash_mix() to mix the class_idx into the class_key. This function provides better mixing than the previously used, home grown mix function. Leave hashing to the professionals :-) Suggested-by: George Spelvin Signed-off-by: Peter Zijlstra (Intel) Cc: Andrew Morton Cc: Linus Torvalds Cc: Paul E. McKenney Cc: Peter Zijlstra Cc: Thomas Gleixner Signed-off-by: Ingo Molnar diff --git a/kernel/locking/lockdep.c b/kernel/locking/lockdep.c index 81f1a71..589d763 100644 --- a/kernel/locking/lockdep.c +++ b/kernel/locking/lockdep.c @@ -46,6 +46,7 @@ #include #include #include +#include #include @@ -309,10 +310,14 @@ static struct hlist_head chainhash_table[CHAINHASH_SIZE]; * It's a 64-bit hash, because it's important for the keys to be * unique. */ -#define iterate_chain_key(key1, key2) \ - (((key1) << MAX_LOCKDEP_KEYS_BITS) ^ \ - ((key1) >> (64-MAX_LOCKDEP_KEYS_BITS)) ^ \ - (key2)) +static inline u64 iterate_chain_key(u64 key, u32 idx) +{ + u32 k0 = key, k1 = key >> 32; + + __jhash_mix(idx, k0, k1); /* Macro that modifies arguments! */ + + return k0 | (u64)k1 << 32; +} void lockdep_off(void) { -- cgit v0.10.2 From a461d58792d4a46b8b10ae50973ec9b2763b694e Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Fri, 27 May 2016 15:47:18 +0200 Subject: locking/rtmutex: Only warn once on a trylock from bad context One warning should be enough to get one motivated to fix this. It is possible that this happens more than once and that starts flooding the output. Later the prints will be suppressed so we only get half of it. Depending on the console system used it might not be helpful. Signed-off-by: Sebastian Andrzej Siewior Signed-off-by: Peter Zijlstra (Intel) Cc: Andrew Morton Cc: Linus Torvalds Cc: Paul E. McKenney Cc: Peter Zijlstra Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/1464356838-1755-1-git-send-email-bigeasy@linutronix.de Signed-off-by: Ingo Molnar diff --git a/kernel/locking/rtmutex.c b/kernel/locking/rtmutex.c index 3e74660..1ec0f48 100644 --- a/kernel/locking/rtmutex.c +++ b/kernel/locking/rtmutex.c @@ -1478,7 +1478,7 @@ EXPORT_SYMBOL_GPL(rt_mutex_timed_lock); */ int __sched rt_mutex_trylock(struct rt_mutex *lock) { - if (WARN_ON(in_irq() || in_nmi() || in_serving_softirq())) + if (WARN_ON_ONCE(in_irq() || in_nmi() || in_serving_softirq())) return 0; return rt_mutex_fasttrylock(lock, rt_mutex_slowtrylock); -- cgit v0.10.2 From 331b6d8c7afc2e5b900b9dcd850c265e1ba8d8e7 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Sun, 22 May 2016 12:48:27 +0200 Subject: locking/barriers: Validate lockless_dereference() is used on a pointer type Use the type to validate the argument @p is indeed a pointer type. Signed-off-by: Peter Zijlstra (Intel) Cc: Alexey Dobriyan Cc: Andrew Morton Cc: Linus Torvalds Cc: Paul E. McKenney Cc: Paul McKenney Cc: Peter Zijlstra Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/20160522104827.GP3193@twins.programming.kicks-ass.net Signed-off-by: Ingo Molnar diff --git a/include/linux/compiler.h b/include/linux/compiler.h index 793c082..06f27fd 100644 --- a/include/linux/compiler.h +++ b/include/linux/compiler.h @@ -545,10 +545,14 @@ static __always_inline void __write_once_size(volatile void *p, void *res, int s * Similar to rcu_dereference(), but for situations where the pointed-to * object's lifetime is managed by something other than RCU. That * "something other" might be reference counting or simple immortality. + * + * The seemingly unused void * variable is to validate @p is indeed a pointer + * type. All pointer types silently cast to void *. */ #define lockless_dereference(p) \ ({ \ typeof(p) _________p1 = READ_ONCE(p); \ + __maybe_unused const void * const _________p2 = _________p1; \ smp_read_barrier_depends(); /* Dependency order vs. p above. */ \ (_________p1); \ }) -- cgit v0.10.2 From 03c041c5bf6ed584dff36b7cd509e0146a124277 Mon Sep 17 00:00:00 2001 From: Josh Poimboeuf Date: Fri, 3 Jun 2016 17:58:41 -0500 Subject: sched/debug: Always show 'nr_migrations' The nr_migrations field is updated independently of CONFIG_SCHEDSTATS, so it can be displayed regardless. Signed-off-by: Josh Poimboeuf Signed-off-by: Peter Zijlstra (Intel) Acked-by: Mel Gorman Cc: Linus Torvalds Cc: Matt Fleming Cc: Peter Zijlstra Cc: Srikar Dronamraju Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/5b1b04057ae2b14d73c2d03f56582c1d38cfe066.1464994423.git.jpoimboe@redhat.com Signed-off-by: Ingo Molnar diff --git a/kernel/sched/debug.c b/kernel/sched/debug.c index 0368c39..2a0a999 100644 --- a/kernel/sched/debug.c +++ b/kernel/sched/debug.c @@ -879,9 +879,9 @@ void proc_sched_show_task(struct task_struct *p, struct seq_file *m) nr_switches = p->nvcsw + p->nivcsw; -#ifdef CONFIG_SCHEDSTATS P(se.nr_migrations); +#ifdef CONFIG_SCHEDSTATS if (schedstat_enabled()) { u64 avg_atom, avg_per_cpu; -- cgit v0.10.2 From 8d53fa19041ae65c484d81d75179b4a577e6d8e4 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Wed, 8 Jun 2016 09:12:30 +0200 Subject: locking/qspinlock: Clarify xchg_tail() ordering While going over the code I noticed that xchg_tail() is a RELEASE but had no obvious pairing commented. It pairs with a somewhat unique address dependency through decode_tail(). So the store-release of xchg_tail() is paired by the address dependency of the load of xchg_tail followed by the dereference from the pointer computed from that load. The @old -> @prev transformation itself is pure, and therefore does not depend on external state, so that is immaterial wrt. ordering. Signed-off-by: Peter Zijlstra (Intel) Cc: Boqun Feng Cc: Davidlohr Bueso Cc: Linus Torvalds Cc: Pan Xinhui Cc: Paul E. McKenney Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: Waiman Long Cc: Will Deacon Cc: linux-kernel@vger.kernel.org Signed-off-by: Ingo Molnar diff --git a/kernel/locking/qspinlock.c b/kernel/locking/qspinlock.c index 5fc8c31..ee7deb0 100644 --- a/kernel/locking/qspinlock.c +++ b/kernel/locking/qspinlock.c @@ -90,7 +90,7 @@ static DEFINE_PER_CPU_ALIGNED(struct mcs_spinlock, mcs_nodes[MAX_NODES]); * therefore increment the cpu number by one. */ -static inline u32 encode_tail(int cpu, int idx) +static inline __pure u32 encode_tail(int cpu, int idx) { u32 tail; @@ -103,7 +103,7 @@ static inline u32 encode_tail(int cpu, int idx) return tail; } -static inline struct mcs_spinlock *decode_tail(u32 tail) +static inline __pure struct mcs_spinlock *decode_tail(u32 tail) { int cpu = (tail >> _Q_TAIL_CPU_OFFSET) - 1; int idx = (tail & _Q_TAIL_IDX_MASK) >> _Q_TAIL_IDX_OFFSET; @@ -455,6 +455,8 @@ queue: * pending stuff. * * p,*,* -> n,*,* + * + * RELEASE, such that the stores to @node must be complete. */ old = xchg_tail(lock, tail); next = NULL; @@ -465,6 +467,15 @@ queue: */ if (old & _Q_TAIL_MASK) { prev = decode_tail(old); + /* + * The above xchg_tail() is also a load of @lock which generates, + * through decode_tail(), a pointer. + * + * The address dependency matches the RELEASE of xchg_tail() + * such that the access to @prev must happen after. + */ + smp_read_barrier_depends(); + WRITE_ONCE(prev->next, node); pv_wait_node(node, prev); -- cgit v0.10.2 From 055ce0fd1b86c204430cbc0887165599d6e15090 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Wed, 8 Jun 2016 10:36:53 +0200 Subject: locking/qspinlock: Add comments I figured we need to document the spin_is_locked() and spin_unlock_wait() constraints somwehere. Ideally 'someone' would rewrite Documentation/atomic_ops.txt and we could find a place in there. But currently that document is stale to the point of hardly being useful. Signed-off-by: Peter Zijlstra (Intel) Cc: Andrew Morton Cc: Boqun Feng Cc: Davidlohr Bueso Cc: Linus Torvalds Cc: Pan Xinhui Cc: Paul E. McKenney Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: Waiman Long Cc: Will Deacon Cc: linux-kernel@vger.kernel.org Signed-off-by: Ingo Molnar diff --git a/kernel/locking/qspinlock.c b/kernel/locking/qspinlock.c index ee7deb0..2f9153b 100644 --- a/kernel/locking/qspinlock.c +++ b/kernel/locking/qspinlock.c @@ -268,6 +268,63 @@ static __always_inline u32 __pv_wait_head_or_lock(struct qspinlock *lock, #endif /* + * Various notes on spin_is_locked() and spin_unlock_wait(), which are + * 'interesting' functions: + * + * PROBLEM: some architectures have an interesting issue with atomic ACQUIRE + * operations in that the ACQUIRE applies to the LOAD _not_ the STORE (ARM64, + * PPC). Also qspinlock has a similar issue per construction, the setting of + * the locked byte can be unordered acquiring the lock proper. + * + * This gets to be 'interesting' in the following cases, where the /should/s + * end up false because of this issue. + * + * + * CASE 1: + * + * So the spin_is_locked() correctness issue comes from something like: + * + * CPU0 CPU1 + * + * global_lock(); local_lock(i) + * spin_lock(&G) spin_lock(&L[i]) + * for (i) if (!spin_is_locked(&G)) { + * spin_unlock_wait(&L[i]); smp_acquire__after_ctrl_dep(); + * return; + * } + * // deal with fail + * + * Where it is important CPU1 sees G locked or CPU0 sees L[i] locked such + * that there is exclusion between the two critical sections. + * + * The load from spin_is_locked(&G) /should/ be constrained by the ACQUIRE from + * spin_lock(&L[i]), and similarly the load(s) from spin_unlock_wait(&L[i]) + * /should/ be constrained by the ACQUIRE from spin_lock(&G). + * + * Similarly, later stuff is constrained by the ACQUIRE from CTRL+RMB. + * + * + * CASE 2: + * + * For spin_unlock_wait() there is a second correctness issue, namely: + * + * CPU0 CPU1 + * + * flag = set; + * smp_mb(); spin_lock(&l) + * spin_unlock_wait(&l); if (!flag) + * // add to lockless list + * spin_unlock(&l); + * // iterate lockless list + * + * Which wants to ensure that CPU1 will stop adding bits to the list and CPU0 + * will observe the last entry on the list (if spin_unlock_wait() had ACQUIRE + * semantics etc..) + * + * Where flag /should/ be ordered against the locked store of l. + */ + +/* * queued_spin_lock_slowpath() can (load-)ACQUIRE the lock before * issuing an _unordered_ store to set _Q_LOCKED_VAL. * -- cgit v0.10.2 From f5967101e9de12addcda4510dfbac66d7c5779c3 Mon Sep 17 00:00:00 2001 From: Borislav Petkov Date: Mon, 30 May 2016 12:56:27 +0200 Subject: x86/hweight: Get rid of the special calling convention People complained about ARCH_HWEIGHT_CFLAGS and how it throws a wrench into kcov, lto, etc, experimentations. Add asm versions for __sw_hweight{32,64}() and do explicit saving and restoring of clobbered registers. This gets rid of the special calling convention. We get to call those functions on !X86_FEATURE_POPCNT CPUs. We still need to hardcode POPCNT and register operands as some old gas versions which we support, do not know about POPCNT. Btw, remove redundant REX prefix from 32-bit POPCNT because alternatives can do padding now. Suggested-by: H. Peter Anvin Signed-off-by: Borislav Petkov Acked-by: Peter Zijlstra (Intel) Cc: Andy Lutomirski Cc: Borislav Petkov Cc: Brian Gerst Cc: Denys Vlasenko Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/1464605787-20603-1-git-send-email-bp@alien8.de Signed-off-by: Ingo Molnar diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 0a7b885..729d41d 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -294,11 +294,6 @@ config X86_32_LAZY_GS def_bool y depends on X86_32 && !CC_STACKPROTECTOR -config ARCH_HWEIGHT_CFLAGS - string - default "-fcall-saved-ecx -fcall-saved-edx" if X86_32 - default "-fcall-saved-rdi -fcall-saved-rsi -fcall-saved-rdx -fcall-saved-rcx -fcall-saved-r8 -fcall-saved-r9 -fcall-saved-r10 -fcall-saved-r11" if X86_64 - config ARCH_SUPPORTS_UPROBES def_bool y diff --git a/arch/x86/include/asm/arch_hweight.h b/arch/x86/include/asm/arch_hweight.h index 02e799f..e7cd631 100644 --- a/arch/x86/include/asm/arch_hweight.h +++ b/arch/x86/include/asm/arch_hweight.h @@ -4,8 +4,8 @@ #include #ifdef CONFIG_64BIT -/* popcnt %edi, %eax -- redundant REX prefix for alignment */ -#define POPCNT32 ".byte 0xf3,0x40,0x0f,0xb8,0xc7" +/* popcnt %edi, %eax */ +#define POPCNT32 ".byte 0xf3,0x0f,0xb8,0xc7" /* popcnt %rdi, %rax */ #define POPCNT64 ".byte 0xf3,0x48,0x0f,0xb8,0xc7" #define REG_IN "D" @@ -17,19 +17,15 @@ #define REG_OUT "a" #endif -/* - * __sw_hweightXX are called from within the alternatives below - * and callee-clobbered registers need to be taken care of. See - * ARCH_HWEIGHT_CFLAGS in for the respective - * compiler switches. - */ +#define __HAVE_ARCH_SW_HWEIGHT + static __always_inline unsigned int __arch_hweight32(unsigned int w) { - unsigned int res = 0; + unsigned int res; asm (ALTERNATIVE("call __sw_hweight32", POPCNT32, X86_FEATURE_POPCNT) - : "="REG_OUT (res) - : REG_IN (w)); + : "="REG_OUT (res) + : REG_IN (w)); return res; } @@ -53,11 +49,11 @@ static inline unsigned long __arch_hweight64(__u64 w) #else static __always_inline unsigned long __arch_hweight64(__u64 w) { - unsigned long res = 0; + unsigned long res; asm (ALTERNATIVE("call __sw_hweight64", POPCNT64, X86_FEATURE_POPCNT) - : "="REG_OUT (res) - : REG_IN (w)); + : "="REG_OUT (res) + : REG_IN (w)); return res; } diff --git a/arch/x86/kernel/i386_ksyms_32.c b/arch/x86/kernel/i386_ksyms_32.c index 64341aa..d40ee8a 100644 --- a/arch/x86/kernel/i386_ksyms_32.c +++ b/arch/x86/kernel/i386_ksyms_32.c @@ -42,3 +42,5 @@ EXPORT_SYMBOL(empty_zero_page); EXPORT_SYMBOL(___preempt_schedule); EXPORT_SYMBOL(___preempt_schedule_notrace); #endif + +EXPORT_SYMBOL(__sw_hweight32); diff --git a/arch/x86/kernel/x8664_ksyms_64.c b/arch/x86/kernel/x8664_ksyms_64.c index cd05942..f1aebfb 100644 --- a/arch/x86/kernel/x8664_ksyms_64.c +++ b/arch/x86/kernel/x8664_ksyms_64.c @@ -44,6 +44,9 @@ EXPORT_SYMBOL(clear_page); EXPORT_SYMBOL(csum_partial); +EXPORT_SYMBOL(__sw_hweight32); +EXPORT_SYMBOL(__sw_hweight64); + /* * Export string functions. We normally rely on gcc builtin for most of these, * but gcc sometimes decides not to inline them. diff --git a/arch/x86/lib/Makefile b/arch/x86/lib/Makefile index 72a5767..ec969cc 100644 --- a/arch/x86/lib/Makefile +++ b/arch/x86/lib/Makefile @@ -25,7 +25,7 @@ lib-y += memcpy_$(BITS).o lib-$(CONFIG_RWSEM_XCHGADD_ALGORITHM) += rwsem.o lib-$(CONFIG_INSTRUCTION_DECODER) += insn.o inat.o -obj-y += msr.o msr-reg.o msr-reg-export.o +obj-y += msr.o msr-reg.o msr-reg-export.o hweight.o ifeq ($(CONFIG_X86_32),y) obj-y += atomic64_32.o diff --git a/arch/x86/lib/hweight.S b/arch/x86/lib/hweight.S new file mode 100644 index 0000000..02de3d7 --- /dev/null +++ b/arch/x86/lib/hweight.S @@ -0,0 +1,77 @@ +#include + +#include + +/* + * unsigned int __sw_hweight32(unsigned int w) + * %rdi: w + */ +ENTRY(__sw_hweight32) + +#ifdef CONFIG_X86_64 + movl %edi, %eax # w +#endif + __ASM_SIZE(push,) %__ASM_REG(dx) + movl %eax, %edx # w -> t + shrl %edx # t >>= 1 + andl $0x55555555, %edx # t &= 0x55555555 + subl %edx, %eax # w -= t + + movl %eax, %edx # w -> t + shrl $2, %eax # w_tmp >>= 2 + andl $0x33333333, %edx # t &= 0x33333333 + andl $0x33333333, %eax # w_tmp &= 0x33333333 + addl %edx, %eax # w = w_tmp + t + + movl %eax, %edx # w -> t + shrl $4, %edx # t >>= 4 + addl %edx, %eax # w_tmp += t + andl $0x0f0f0f0f, %eax # w_tmp &= 0x0f0f0f0f + imull $0x01010101, %eax, %eax # w_tmp *= 0x01010101 + shrl $24, %eax # w = w_tmp >> 24 + __ASM_SIZE(pop,) %__ASM_REG(dx) + ret +ENDPROC(__sw_hweight32) + +ENTRY(__sw_hweight64) +#ifdef CONFIG_X86_64 + pushq %rdx + + movq %rdi, %rdx # w -> t + movabsq $0x5555555555555555, %rax + shrq %rdx # t >>= 1 + andq %rdx, %rax # t &= 0x5555555555555555 + movabsq $0x3333333333333333, %rdx + subq %rax, %rdi # w -= t + + movq %rdi, %rax # w -> t + shrq $2, %rdi # w_tmp >>= 2 + andq %rdx, %rax # t &= 0x3333333333333333 + andq %rdi, %rdx # w_tmp &= 0x3333333333333333 + addq %rdx, %rax # w = w_tmp + t + + movq %rax, %rdx # w -> t + shrq $4, %rdx # t >>= 4 + addq %rdx, %rax # w_tmp += t + movabsq $0x0f0f0f0f0f0f0f0f, %rdx + andq %rdx, %rax # w_tmp &= 0x0f0f0f0f0f0f0f0f + movabsq $0x0101010101010101, %rdx + imulq %rdx, %rax # w_tmp *= 0x0101010101010101 + shrq $56, %rax # w = w_tmp >> 56 + + popq %rdx + ret +#else /* CONFIG_X86_32 */ + /* We're getting an u64 arg in (%eax,%edx): unsigned long hweight64(__u64 w) */ + pushl %ecx + + call __sw_hweight32 + movl %eax, %ecx # stash away result + movl %edx, %eax # second part of input + call __sw_hweight32 + addl %ecx, %eax # result + + popl %ecx + ret +#endif +ENDPROC(__sw_hweight64) diff --git a/lib/Makefile b/lib/Makefile index ff6a7a6..07d06a8 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -15,9 +15,6 @@ KCOV_INSTRUMENT_rbtree.o := n KCOV_INSTRUMENT_list_debug.o := n KCOV_INSTRUMENT_debugobjects.o := n KCOV_INSTRUMENT_dynamic_debug.o := n -# Kernel does not boot if we instrument this file as it uses custom calling -# convention (see CONFIG_ARCH_HWEIGHT_CFLAGS). -KCOV_INSTRUMENT_hweight.o := n lib-y := ctype.o string.o vsprintf.o cmdline.o \ rbtree.o radix-tree.o dump_stack.o timerqueue.o\ @@ -74,8 +71,6 @@ obj-$(CONFIG_HAS_IOMEM) += iomap_copy.o devres.o obj-$(CONFIG_CHECK_SIGNATURE) += check_signature.o obj-$(CONFIG_DEBUG_LOCKING_API_SELFTESTS) += locking-selftest.o -GCOV_PROFILE_hweight.o := n -CFLAGS_hweight.o = $(subst $(quote),,$(CONFIG_ARCH_HWEIGHT_CFLAGS)) obj-$(CONFIG_GENERIC_HWEIGHT) += hweight.o obj-$(CONFIG_BTREE) += btree.o diff --git a/lib/hweight.c b/lib/hweight.c index 9a5c1f2..43273a7 100644 --- a/lib/hweight.c +++ b/lib/hweight.c @@ -9,6 +9,7 @@ * The Hamming Weight of a number is the total number of bits set in it. */ +#ifndef __HAVE_ARCH_SW_HWEIGHT unsigned int __sw_hweight32(unsigned int w) { #ifdef CONFIG_ARCH_HAS_FAST_MULTIPLIER @@ -25,6 +26,7 @@ unsigned int __sw_hweight32(unsigned int w) #endif } EXPORT_SYMBOL(__sw_hweight32); +#endif unsigned int __sw_hweight16(unsigned int w) { @@ -43,6 +45,7 @@ unsigned int __sw_hweight8(unsigned int w) } EXPORT_SYMBOL(__sw_hweight8); +#ifndef __HAVE_ARCH_SW_HWEIGHT unsigned long __sw_hweight64(__u64 w) { #if BITS_PER_LONG == 32 @@ -65,3 +68,4 @@ unsigned long __sw_hweight64(__u64 w) #endif } EXPORT_SYMBOL(__sw_hweight64); +#endif -- cgit v0.10.2 From 8ee62b1870be8e630158701632a533d0378e15b8 Mon Sep 17 00:00:00 2001 From: Jason Low Date: Fri, 3 Jun 2016 22:26:02 -0700 Subject: locking/rwsem: Convert sem->count to 'atomic_long_t' Convert the rwsem count variable to an atomic_long_t since we use it as an atomic variable. This also allows us to remove the rwsem_atomic_{add,update}() "abstraction" which would now be an unnecesary level of indirection. In follow up patches, we also remove the rwsem_atomic_{add,update}() definitions across the various architectures. Suggested-by: Peter Zijlstra Signed-off-by: Jason Low [ Build warning fixes on various architectures. ] Signed-off-by: Peter Zijlstra (Intel) Cc: Andrew Morton Cc: Davidlohr Bueso Cc: Fenghua Yu Cc: Heiko Carstens Cc: Jason Low Cc: Linus Torvalds Cc: Martin Schwidefsky Cc: Paul E. McKenney Cc: Peter Hurley Cc: Terry Rudd Cc: Thomas Gleixner Cc: Tim Chen Cc: Tony Luck Cc: Waiman Long Link: http://lkml.kernel.org/r/1465017963-4839-2-git-send-email-jason.low2@hpe.com Signed-off-by: Ingo Molnar diff --git a/arch/alpha/include/asm/rwsem.h b/arch/alpha/include/asm/rwsem.h index 0131a70..b40021a 100644 --- a/arch/alpha/include/asm/rwsem.h +++ b/arch/alpha/include/asm/rwsem.h @@ -25,8 +25,8 @@ static inline void __down_read(struct rw_semaphore *sem) { long oldcount; #ifndef CONFIG_SMP - oldcount = sem->count; - sem->count += RWSEM_ACTIVE_READ_BIAS; + oldcount = sem->count.counter; + sem->count.counter += RWSEM_ACTIVE_READ_BIAS; #else long temp; __asm__ __volatile__( @@ -52,13 +52,13 @@ static inline int __down_read_trylock(struct rw_semaphore *sem) { long old, new, res; - res = sem->count; + res = atomic_long_read(&sem->count); do { new = res + RWSEM_ACTIVE_READ_BIAS; if (new <= 0) break; old = res; - res = cmpxchg(&sem->count, old, new); + res = atomic_long_cmpxchg(&sem->count, old, new); } while (res != old); return res >= 0 ? 1 : 0; } @@ -67,8 +67,8 @@ static inline long ___down_write(struct rw_semaphore *sem) { long oldcount; #ifndef CONFIG_SMP - oldcount = sem->count; - sem->count += RWSEM_ACTIVE_WRITE_BIAS; + oldcount = sem->count.counter; + sem->count.counter += RWSEM_ACTIVE_WRITE_BIAS; #else long temp; __asm__ __volatile__( @@ -106,7 +106,7 @@ static inline int __down_write_killable(struct rw_semaphore *sem) */ static inline int __down_write_trylock(struct rw_semaphore *sem) { - long ret = cmpxchg(&sem->count, RWSEM_UNLOCKED_VALUE, + long ret = atomic_long_cmpxchg(&sem->count, RWSEM_UNLOCKED_VALUE, RWSEM_ACTIVE_WRITE_BIAS); if (ret == RWSEM_UNLOCKED_VALUE) return 1; @@ -117,8 +117,8 @@ static inline void __up_read(struct rw_semaphore *sem) { long oldcount; #ifndef CONFIG_SMP - oldcount = sem->count; - sem->count -= RWSEM_ACTIVE_READ_BIAS; + oldcount = sem->count.counter; + sem->count.counter -= RWSEM_ACTIVE_READ_BIAS; #else long temp; __asm__ __volatile__( @@ -142,8 +142,8 @@ static inline void __up_write(struct rw_semaphore *sem) { long count; #ifndef CONFIG_SMP - sem->count -= RWSEM_ACTIVE_WRITE_BIAS; - count = sem->count; + sem->count.counter -= RWSEM_ACTIVE_WRITE_BIAS; + count = sem->count.counter; #else long temp; __asm__ __volatile__( @@ -171,8 +171,8 @@ static inline void __downgrade_write(struct rw_semaphore *sem) { long oldcount; #ifndef CONFIG_SMP - oldcount = sem->count; - sem->count -= RWSEM_WAITING_BIAS; + oldcount = sem->count.counter; + sem->count.counter -= RWSEM_WAITING_BIAS; #else long temp; __asm__ __volatile__( diff --git a/arch/ia64/include/asm/rwsem.h b/arch/ia64/include/asm/rwsem.h index 8b23e07..c5d544f 100644 --- a/arch/ia64/include/asm/rwsem.h +++ b/arch/ia64/include/asm/rwsem.h @@ -40,7 +40,7 @@ static inline void __down_read (struct rw_semaphore *sem) { - long result = ia64_fetchadd8_acq((unsigned long *)&sem->count, 1); + long result = ia64_fetchadd8_acq((unsigned long *)&sem->count.counter, 1); if (result < 0) rwsem_down_read_failed(sem); @@ -55,9 +55,9 @@ ___down_write (struct rw_semaphore *sem) long old, new; do { - old = sem->count; + old = atomic_long_read(&sem->count); new = old + RWSEM_ACTIVE_WRITE_BIAS; - } while (cmpxchg_acq(&sem->count, old, new) != old); + } while (atomic_long_cmpxchg_acquire(&sem->count, old, new) != old); return old; } @@ -85,7 +85,7 @@ __down_write_killable (struct rw_semaphore *sem) static inline void __up_read (struct rw_semaphore *sem) { - long result = ia64_fetchadd8_rel((unsigned long *)&sem->count, -1); + long result = ia64_fetchadd8_rel((unsigned long *)&sem->count.counter, -1); if (result < 0 && (--result & RWSEM_ACTIVE_MASK) == 0) rwsem_wake(sem); @@ -100,9 +100,9 @@ __up_write (struct rw_semaphore *sem) long old, new; do { - old = sem->count; + old = atomic_long_read(&sem->count); new = old - RWSEM_ACTIVE_WRITE_BIAS; - } while (cmpxchg_rel(&sem->count, old, new) != old); + } while (atomic_long_cmpxchg_release(&sem->count, old, new) != old); if (new < 0 && (new & RWSEM_ACTIVE_MASK) == 0) rwsem_wake(sem); @@ -115,8 +115,8 @@ static inline int __down_read_trylock (struct rw_semaphore *sem) { long tmp; - while ((tmp = sem->count) >= 0) { - if (tmp == cmpxchg_acq(&sem->count, tmp, tmp+1)) { + while ((tmp = atomic_long_read(&sem->count)) >= 0) { + if (tmp == atomic_long_cmpxchg_acquire(&sem->count, tmp, tmp+1)) { return 1; } } @@ -129,8 +129,8 @@ __down_read_trylock (struct rw_semaphore *sem) static inline int __down_write_trylock (struct rw_semaphore *sem) { - long tmp = cmpxchg_acq(&sem->count, RWSEM_UNLOCKED_VALUE, - RWSEM_ACTIVE_WRITE_BIAS); + long tmp = atomic_long_cmpxchg_acquire(&sem->count, + RWSEM_UNLOCKED_VALUE, RWSEM_ACTIVE_WRITE_BIAS); return tmp == RWSEM_UNLOCKED_VALUE; } @@ -143,9 +143,9 @@ __downgrade_write (struct rw_semaphore *sem) long old, new; do { - old = sem->count; + old = atomic_long_read(&sem->count); new = old - RWSEM_WAITING_BIAS; - } while (cmpxchg_rel(&sem->count, old, new) != old); + } while (atomic_long_cmpxchg_release(&sem->count, old, new) != old); if (old < 0) rwsem_downgrade_wake(sem); diff --git a/include/asm-generic/rwsem.h b/include/asm-generic/rwsem.h index 3fc94a0..a3a93ec 100644 --- a/include/asm-generic/rwsem.h +++ b/include/asm-generic/rwsem.h @@ -41,8 +41,8 @@ static inline int __down_read_trylock(struct rw_semaphore *sem) { long tmp; - while ((tmp = sem->count) >= 0) { - if (tmp == cmpxchg_acquire(&sem->count, tmp, + while ((tmp = atomic_long_read(&sem->count)) >= 0) { + if (tmp == atomic_long_cmpxchg_acquire(&sem->count, tmp, tmp + RWSEM_ACTIVE_READ_BIAS)) { return 1; } @@ -79,7 +79,7 @@ static inline int __down_write_trylock(struct rw_semaphore *sem) { long tmp; - tmp = cmpxchg_acquire(&sem->count, RWSEM_UNLOCKED_VALUE, + tmp = atomic_long_cmpxchg_acquire(&sem->count, RWSEM_UNLOCKED_VALUE, RWSEM_ACTIVE_WRITE_BIAS); return tmp == RWSEM_UNLOCKED_VALUE; } diff --git a/include/linux/rwsem.h b/include/linux/rwsem.h index d37fbb3..dd1d142 100644 --- a/include/linux/rwsem.h +++ b/include/linux/rwsem.h @@ -23,10 +23,11 @@ struct rw_semaphore; #ifdef CONFIG_RWSEM_GENERIC_SPINLOCK #include /* use a generic implementation */ +#define __RWSEM_INIT_COUNT(name) .count = RWSEM_UNLOCKED_VALUE #else /* All arch specific implementations share the same struct */ struct rw_semaphore { - long count; + atomic_long_t count; struct list_head wait_list; raw_spinlock_t wait_lock; #ifdef CONFIG_RWSEM_SPIN_ON_OWNER @@ -54,9 +55,10 @@ extern struct rw_semaphore *rwsem_downgrade_wake(struct rw_semaphore *sem); /* In all implementations count != 0 means locked */ static inline int rwsem_is_locked(struct rw_semaphore *sem) { - return sem->count != 0; + return atomic_long_read(&sem->count) != 0; } +#define __RWSEM_INIT_COUNT(name) .count = ATOMIC_LONG_INIT(RWSEM_UNLOCKED_VALUE) #endif /* Common initializer macros and functions */ @@ -74,7 +76,7 @@ static inline int rwsem_is_locked(struct rw_semaphore *sem) #endif #define __RWSEM_INITIALIZER(name) \ - { .count = RWSEM_UNLOCKED_VALUE, \ + { __RWSEM_INIT_COUNT(name), \ .wait_list = LIST_HEAD_INIT((name).wait_list), \ .wait_lock = __RAW_SPIN_LOCK_UNLOCKED(name.wait_lock) \ __RWSEM_OPT_INIT(name) \ diff --git a/kernel/locking/rwsem-xadd.c b/kernel/locking/rwsem-xadd.c index b957da7..63b40a5 100644 --- a/kernel/locking/rwsem-xadd.c +++ b/kernel/locking/rwsem-xadd.c @@ -80,7 +80,7 @@ void __init_rwsem(struct rw_semaphore *sem, const char *name, debug_check_no_locks_freed((void *)sem, sizeof(*sem)); lockdep_init_map(&sem->dep_map, name, key, 0); #endif - sem->count = RWSEM_UNLOCKED_VALUE; + atomic_long_set(&sem->count, RWSEM_UNLOCKED_VALUE); raw_spin_lock_init(&sem->wait_lock); INIT_LIST_HEAD(&sem->wait_list); #ifdef CONFIG_RWSEM_SPIN_ON_OWNER @@ -153,10 +153,11 @@ __rwsem_mark_wake(struct rw_semaphore *sem, if (wake_type != RWSEM_WAKE_READ_OWNED) { adjustment = RWSEM_ACTIVE_READ_BIAS; try_reader_grant: - oldcount = rwsem_atomic_update(adjustment, sem) - adjustment; + oldcount = atomic_long_add_return(adjustment, &sem->count) - adjustment; + if (unlikely(oldcount < RWSEM_WAITING_BIAS)) { /* A writer stole the lock. Undo our reader grant. */ - if (rwsem_atomic_update(-adjustment, sem) & + if (atomic_long_sub_return(adjustment, &sem->count) & RWSEM_ACTIVE_MASK) goto out; /* Last active locker left. Retry waking readers. */ @@ -186,7 +187,7 @@ __rwsem_mark_wake(struct rw_semaphore *sem, adjustment -= RWSEM_WAITING_BIAS; if (adjustment) - rwsem_atomic_add(adjustment, sem); + atomic_long_add(adjustment, &sem->count); next = sem->wait_list.next; loop = woken; @@ -233,7 +234,7 @@ struct rw_semaphore __sched *rwsem_down_read_failed(struct rw_semaphore *sem) list_add_tail(&waiter.list, &sem->wait_list); /* we're now waiting on the lock, but no longer actively locking */ - count = rwsem_atomic_update(adjustment, sem); + count = atomic_long_add_return(adjustment, &sem->count); /* If there are no active locks, wake the front queued process(es). * @@ -282,7 +283,8 @@ static inline bool rwsem_try_write_lock(long count, struct rw_semaphore *sem) RWSEM_ACTIVE_WRITE_BIAS : RWSEM_ACTIVE_WRITE_BIAS + RWSEM_WAITING_BIAS; - if (cmpxchg_acquire(&sem->count, RWSEM_WAITING_BIAS, count) == RWSEM_WAITING_BIAS) { + if (atomic_long_cmpxchg_acquire(&sem->count, RWSEM_WAITING_BIAS, count) + == RWSEM_WAITING_BIAS) { rwsem_set_owner(sem); return true; } @@ -296,13 +298,13 @@ static inline bool rwsem_try_write_lock(long count, struct rw_semaphore *sem) */ static inline bool rwsem_try_write_lock_unqueued(struct rw_semaphore *sem) { - long old, count = READ_ONCE(sem->count); + long old, count = atomic_long_read(&sem->count); while (true) { if (!(count == 0 || count == RWSEM_WAITING_BIAS)) return false; - old = cmpxchg_acquire(&sem->count, count, + old = atomic_long_cmpxchg_acquire(&sem->count, count, count + RWSEM_ACTIVE_WRITE_BIAS); if (old == count) { rwsem_set_owner(sem); @@ -324,7 +326,7 @@ static inline bool rwsem_can_spin_on_owner(struct rw_semaphore *sem) rcu_read_lock(); owner = READ_ONCE(sem->owner); if (!owner) { - long count = READ_ONCE(sem->count); + long count = atomic_long_read(&sem->count); /* * If sem->owner is not set, yet we have just recently entered the * slowpath with the lock being active, then there is a possibility @@ -375,7 +377,7 @@ bool rwsem_spin_on_owner(struct rw_semaphore *sem, struct task_struct *owner) * held by readers. Check the counter to verify the * state. */ - count = READ_ONCE(sem->count); + count = atomic_long_read(&sem->count); return (count == 0 || count == RWSEM_WAITING_BIAS); } @@ -460,7 +462,7 @@ __rwsem_down_write_failed_common(struct rw_semaphore *sem, int state) WAKE_Q(wake_q); /* undo write bias from down_write operation, stop active locking */ - count = rwsem_atomic_update(-RWSEM_ACTIVE_WRITE_BIAS, sem); + count = atomic_long_sub_return(RWSEM_ACTIVE_WRITE_BIAS, &sem->count); /* do optimistic spinning and steal lock if possible */ if (rwsem_optimistic_spin(sem)) @@ -483,7 +485,7 @@ __rwsem_down_write_failed_common(struct rw_semaphore *sem, int state) /* we're now waiting on the lock, but no longer actively locking */ if (waiting) { - count = READ_ONCE(sem->count); + count = atomic_long_read(&sem->count); /* * If there were already threads queued before us and there are @@ -505,7 +507,7 @@ __rwsem_down_write_failed_common(struct rw_semaphore *sem, int state) } } else - count = rwsem_atomic_update(RWSEM_WAITING_BIAS, sem); + count = atomic_long_add_return(RWSEM_WAITING_BIAS, &sem->count); /* wait until we successfully acquire the lock */ set_current_state(state); @@ -521,7 +523,7 @@ __rwsem_down_write_failed_common(struct rw_semaphore *sem, int state) schedule(); set_current_state(state); - } while ((count = sem->count) & RWSEM_ACTIVE_MASK); + } while ((count = atomic_long_read(&sem->count)) & RWSEM_ACTIVE_MASK); raw_spin_lock_irq(&sem->wait_lock); } @@ -536,7 +538,7 @@ out_nolock: raw_spin_lock_irq(&sem->wait_lock); list_del(&waiter.list); if (list_empty(&sem->wait_list)) - rwsem_atomic_update(-RWSEM_WAITING_BIAS, sem); + atomic_long_add(-RWSEM_WAITING_BIAS, &sem->count); else __rwsem_mark_wake(sem, RWSEM_WAKE_ANY, &wake_q); raw_spin_unlock_irq(&sem->wait_lock); -- cgit v0.10.2 From d157bd860f1c828593730dca594d0ce51956833b Mon Sep 17 00:00:00 2001 From: Jason Low Date: Mon, 16 May 2016 17:38:02 -0700 Subject: locking/rwsem: Remove rwsem_atomic_add() and rwsem_atomic_update() The rwsem-xadd count has been converted to an atomic variable and the rwsem code now directly uses atomic_long_add() and atomic_long_add_return(), so we can remove the arch implementations of rwsem_atomic_add() and rwsem_atomic_update(). Signed-off-by: Jason Low Signed-off-by: Peter Zijlstra (Intel) Cc: Andrew Morton Cc: Arnd Bergmann Cc: Christoph Lameter Cc: Davidlohr Bueso Cc: Fenghua Yu Cc: Heiko Carstens Cc: Ivan Kokshaysky Cc: Jason Low Cc: Linus Torvalds Cc: Martin Schwidefsky Cc: Matt Turner Cc: Paul E. McKenney Cc: Peter Hurley Cc: Peter Zijlstra Cc: Richard Henderson Cc: Terry Rudd Cc: Thomas Gleixner Cc: Tim Chen Cc: Tony Luck Cc: Waiman Long Cc: linux-kernel@vger.kernel.org Signed-off-by: Ingo Molnar diff --git a/arch/alpha/include/asm/rwsem.h b/arch/alpha/include/asm/rwsem.h index b40021a..77873d0 100644 --- a/arch/alpha/include/asm/rwsem.h +++ b/arch/alpha/include/asm/rwsem.h @@ -191,47 +191,5 @@ static inline void __downgrade_write(struct rw_semaphore *sem) rwsem_downgrade_wake(sem); } -static inline void rwsem_atomic_add(long val, struct rw_semaphore *sem) -{ -#ifndef CONFIG_SMP - sem->count += val; -#else - long temp; - __asm__ __volatile__( - "1: ldq_l %0,%1\n" - " addq %0,%2,%0\n" - " stq_c %0,%1\n" - " beq %0,2f\n" - ".subsection 2\n" - "2: br 1b\n" - ".previous" - :"=&r" (temp), "=m" (sem->count) - :"Ir" (val), "m" (sem->count)); -#endif -} - -static inline long rwsem_atomic_update(long val, struct rw_semaphore *sem) -{ -#ifndef CONFIG_SMP - sem->count += val; - return sem->count; -#else - long ret, temp; - __asm__ __volatile__( - "1: ldq_l %0,%1\n" - " addq %0,%3,%2\n" - " addq %0,%3,%0\n" - " stq_c %2,%1\n" - " beq %2,2f\n" - ".subsection 2\n" - "2: br 1b\n" - ".previous" - :"=&r" (ret), "=m" (sem->count), "=&r" (temp) - :"Ir" (val), "m" (sem->count)); - - return ret; -#endif -} - #endif /* __KERNEL__ */ #endif /* _ALPHA_RWSEM_H */ diff --git a/arch/ia64/include/asm/rwsem.h b/arch/ia64/include/asm/rwsem.h index c5d544f..8fa98dd 100644 --- a/arch/ia64/include/asm/rwsem.h +++ b/arch/ia64/include/asm/rwsem.h @@ -151,11 +151,4 @@ __downgrade_write (struct rw_semaphore *sem) rwsem_downgrade_wake(sem); } -/* - * Implement atomic add functionality. These used to be "inline" functions, but GCC v3.1 - * doesn't quite optimize this stuff right and ends up with bad calls to fetchandadd. - */ -#define rwsem_atomic_add(delta, sem) atomic64_add(delta, (atomic64_t *)(&(sem)->count)) -#define rwsem_atomic_update(delta, sem) atomic64_add_return(delta, (atomic64_t *)(&(sem)->count)) - #endif /* _ASM_IA64_RWSEM_H */ diff --git a/arch/s390/include/asm/rwsem.h b/arch/s390/include/asm/rwsem.h index c75e447..597e7e9 100644 --- a/arch/s390/include/asm/rwsem.h +++ b/arch/s390/include/asm/rwsem.h @@ -207,41 +207,4 @@ static inline void __downgrade_write(struct rw_semaphore *sem) rwsem_downgrade_wake(sem); } -/* - * implement atomic add functionality - */ -static inline void rwsem_atomic_add(long delta, struct rw_semaphore *sem) -{ - signed long old, new; - - asm volatile( - " lg %0,%2\n" - "0: lgr %1,%0\n" - " agr %1,%4\n" - " csg %0,%1,%2\n" - " jl 0b" - : "=&d" (old), "=&d" (new), "=Q" (sem->count) - : "Q" (sem->count), "d" (delta) - : "cc", "memory"); -} - -/* - * implement exchange and add functionality - */ -static inline long rwsem_atomic_update(long delta, struct rw_semaphore *sem) -{ - signed long old, new; - - asm volatile( - " lg %0,%2\n" - "0: lgr %1,%0\n" - " agr %1,%4\n" - " csg %0,%1,%2\n" - " jl 0b" - : "=&d" (old), "=&d" (new), "=Q" (sem->count) - : "Q" (sem->count), "d" (delta) - : "cc", "memory"); - return new; -} - #endif /* _S390_RWSEM_H */ diff --git a/arch/x86/include/asm/rwsem.h b/arch/x86/include/asm/rwsem.h index 453744c..089ced4 100644 --- a/arch/x86/include/asm/rwsem.h +++ b/arch/x86/include/asm/rwsem.h @@ -213,23 +213,5 @@ static inline void __downgrade_write(struct rw_semaphore *sem) : "memory", "cc"); } -/* - * implement atomic add functionality - */ -static inline void rwsem_atomic_add(long delta, struct rw_semaphore *sem) -{ - asm volatile(LOCK_PREFIX _ASM_ADD "%1,%0" - : "+m" (sem->count) - : "er" (delta)); -} - -/* - * implement exchange and add functionality - */ -static inline long rwsem_atomic_update(long delta, struct rw_semaphore *sem) -{ - return delta + xadd(&sem->count, delta); -} - #endif /* __KERNEL__ */ #endif /* _ASM_X86_RWSEM_H */ diff --git a/include/asm-generic/rwsem.h b/include/asm-generic/rwsem.h index a3a93ec..5be122e 100644 --- a/include/asm-generic/rwsem.h +++ b/include/asm-generic/rwsem.h @@ -107,14 +107,6 @@ static inline void __up_write(struct rw_semaphore *sem) } /* - * implement atomic add functionality - */ -static inline void rwsem_atomic_add(long delta, struct rw_semaphore *sem) -{ - atomic_long_add(delta, (atomic_long_t *)&sem->count); -} - -/* * downgrade write lock to read lock */ static inline void __downgrade_write(struct rw_semaphore *sem) @@ -134,13 +126,5 @@ static inline void __downgrade_write(struct rw_semaphore *sem) rwsem_downgrade_wake(sem); } -/* - * implement exchange and add functionality - */ -static inline long rwsem_atomic_update(long delta, struct rw_semaphore *sem) -{ - return atomic_long_add_return(delta, (atomic_long_t *)&sem->count); -} - #endif /* __KERNEL__ */ #endif /* _ASM_GENERIC_RWSEM_H */ -- cgit v0.10.2 From 19c5d690e41697fcdd19379ab9d10d8d37818414 Mon Sep 17 00:00:00 2001 From: Waiman Long Date: Tue, 17 May 2016 21:26:19 -0400 Subject: locking/rwsem: Add reader-owned state to the owner field Currently, it is not possible to determine for sure if a reader owns a rwsem by looking at the content of the rwsem data structure. This patch adds a new state RWSEM_READER_OWNED to the owner field to indicate that readers currently own the lock. This enables us to address the following 2 issues in the rwsem optimistic spinning code: 1) rwsem_can_spin_on_owner() will disallow optimistic spinning if the owner field is NULL which can mean either the readers own the lock or the owning writer hasn't set the owner field yet. In the latter case, we miss the chance to do optimistic spinning. 2) While a writer is waiting in the OSQ and a reader takes the lock, the writer will continue to spin when out of the OSQ in the main rwsem_optimistic_spin() loop as the owner field is NULL wasting CPU cycles if some of readers are sleeping. Adding the new state will allow optimistic spinning to go forward as long as the owner field is not RWSEM_READER_OWNED and the owner is running, if set, but stop immediately when that state has been reached. On a 4-socket Haswell machine running on a 4.6-rc1 based kernel, the fio test with multithreaded randrw and randwrite tests on the same file on a XFS partition on top of a NVDIMM were run, the aggregated bandwidths before and after the patch were as follows: Test BW before patch BW after patch % change ---- --------------- -------------- -------- randrw 988 MB/s 1192 MB/s +21% randwrite 1513 MB/s 1623 MB/s +7.3% The perf profile of the rwsem_down_write_failed() function in randrw before and after the patch were: 19.95% 5.88% fio [kernel.vmlinux] [k] rwsem_down_write_failed 14.20% 1.52% fio [kernel.vmlinux] [k] rwsem_down_write_failed The actual CPU cycles spend in rwsem_down_write_failed() dropped from 5.88% to 1.52% after the patch. The xfstests was also run and no regression was observed. Signed-off-by: Waiman Long Signed-off-by: Peter Zijlstra (Intel) Acked-by: Jason Low Acked-by: Davidlohr Bueso Cc: Andrew Morton Cc: Dave Chinner Cc: Douglas Hatch Cc: Linus Torvalds Cc: Paul E. McKenney Cc: Peter Hurley Cc: Peter Zijlstra Cc: Scott J Norton Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/1463534783-38814-2-git-send-email-Waiman.Long@hpe.com Signed-off-by: Ingo Molnar diff --git a/kernel/locking/rwsem-xadd.c b/kernel/locking/rwsem-xadd.c index 63b40a5..6b0d060 100644 --- a/kernel/locking/rwsem-xadd.c +++ b/kernel/locking/rwsem-xadd.c @@ -163,6 +163,12 @@ __rwsem_mark_wake(struct rw_semaphore *sem, /* Last active locker left. Retry waking readers. */ goto try_reader_grant; } + /* + * It is not really necessary to set it to reader-owned here, + * but it gives the spinners an early indication that the + * readers now have the lock. + */ + rwsem_set_reader_owned(sem); } /* Grant an infinite number of read locks to the readers at the front @@ -325,16 +331,11 @@ static inline bool rwsem_can_spin_on_owner(struct rw_semaphore *sem) rcu_read_lock(); owner = READ_ONCE(sem->owner); - if (!owner) { - long count = atomic_long_read(&sem->count); + if (!rwsem_owner_is_writer(owner)) { /* - * If sem->owner is not set, yet we have just recently entered the - * slowpath with the lock being active, then there is a possibility - * reader(s) may have the lock. To be safe, bail spinning in these - * situations. + * Don't spin if the rwsem is readers owned. */ - if (count & RWSEM_ACTIVE_MASK) - ret = false; + ret = !rwsem_owner_is_reader(owner); goto done; } @@ -347,8 +348,6 @@ done: static noinline bool rwsem_spin_on_owner(struct rw_semaphore *sem, struct task_struct *owner) { - long count; - rcu_read_lock(); while (sem->owner == owner) { /* @@ -369,16 +368,11 @@ bool rwsem_spin_on_owner(struct rw_semaphore *sem, struct task_struct *owner) } rcu_read_unlock(); - if (READ_ONCE(sem->owner)) - return true; /* new owner, continue spinning */ - /* - * When the owner is not set, the lock could be free or - * held by readers. Check the counter to verify the - * state. + * If there is a new owner or the owner is not set, we continue + * spinning. */ - count = atomic_long_read(&sem->count); - return (count == 0 || count == RWSEM_WAITING_BIAS); + return !rwsem_owner_is_reader(READ_ONCE(sem->owner)); } static bool rwsem_optimistic_spin(struct rw_semaphore *sem) @@ -397,7 +391,16 @@ static bool rwsem_optimistic_spin(struct rw_semaphore *sem) while (true) { owner = READ_ONCE(sem->owner); - if (owner && !rwsem_spin_on_owner(sem, owner)) + /* + * Don't spin if + * 1) the owner is a reader as we we can't determine if the + * reader is actively running or not. + * 2) The rwsem_spin_on_owner() returns false which means + * the owner isn't running. + */ + if (rwsem_owner_is_reader(owner) || + (rwsem_owner_is_writer(owner) && + !rwsem_spin_on_owner(sem, owner))) break; /* wait_lock will be acquired if write_lock is obtained */ diff --git a/kernel/locking/rwsem.c b/kernel/locking/rwsem.c index 2e853ad..45ba475 100644 --- a/kernel/locking/rwsem.c +++ b/kernel/locking/rwsem.c @@ -22,6 +22,7 @@ void __sched down_read(struct rw_semaphore *sem) rwsem_acquire_read(&sem->dep_map, 0, 0, _RET_IP_); LOCK_CONTENDED(sem, __down_read_trylock, __down_read); + rwsem_set_reader_owned(sem); } EXPORT_SYMBOL(down_read); @@ -33,8 +34,10 @@ int down_read_trylock(struct rw_semaphore *sem) { int ret = __down_read_trylock(sem); - if (ret == 1) + if (ret == 1) { rwsem_acquire_read(&sem->dep_map, 0, 1, _RET_IP_); + rwsem_set_reader_owned(sem); + } return ret; } @@ -124,7 +127,7 @@ void downgrade_write(struct rw_semaphore *sem) * lockdep: a downgraded write will live on as a write * dependency. */ - rwsem_clear_owner(sem); + rwsem_set_reader_owned(sem); __downgrade_write(sem); } @@ -138,6 +141,7 @@ void down_read_nested(struct rw_semaphore *sem, int subclass) rwsem_acquire_read(&sem->dep_map, subclass, 0, _RET_IP_); LOCK_CONTENDED(sem, __down_read_trylock, __down_read); + rwsem_set_reader_owned(sem); } EXPORT_SYMBOL(down_read_nested); diff --git a/kernel/locking/rwsem.h b/kernel/locking/rwsem.h index 870ed9a..8f43ba2 100644 --- a/kernel/locking/rwsem.h +++ b/kernel/locking/rwsem.h @@ -1,3 +1,20 @@ +/* + * The owner field of the rw_semaphore structure will be set to + * RWSEM_READ_OWNED when a reader grabs the lock. A writer will clear + * the owner field when it unlocks. A reader, on the other hand, will + * not touch the owner field when it unlocks. + * + * In essence, the owner field now has the following 3 states: + * 1) 0 + * - lock is free or the owner hasn't set the field yet + * 2) RWSEM_READER_OWNED + * - lock is currently or previously owned by readers (lock is free + * or not set by owner yet) + * 3) Other non-zero value + * - a writer owns the lock + */ +#define RWSEM_READER_OWNED ((struct task_struct *)1UL) + #ifdef CONFIG_RWSEM_SPIN_ON_OWNER static inline void rwsem_set_owner(struct rw_semaphore *sem) { @@ -9,6 +26,26 @@ static inline void rwsem_clear_owner(struct rw_semaphore *sem) sem->owner = NULL; } +static inline void rwsem_set_reader_owned(struct rw_semaphore *sem) +{ + /* + * We check the owner value first to make sure that we will only + * do a write to the rwsem cacheline when it is really necessary + * to minimize cacheline contention. + */ + if (sem->owner != RWSEM_READER_OWNED) + sem->owner = RWSEM_READER_OWNED; +} + +static inline bool rwsem_owner_is_writer(struct task_struct *owner) +{ + return owner && owner != RWSEM_READER_OWNED; +} + +static inline bool rwsem_owner_is_reader(struct task_struct *owner) +{ + return owner == RWSEM_READER_OWNED; +} #else static inline void rwsem_set_owner(struct rw_semaphore *sem) { @@ -17,4 +54,8 @@ static inline void rwsem_set_owner(struct rw_semaphore *sem) static inline void rwsem_clear_owner(struct rw_semaphore *sem) { } + +static inline void rwsem_set_reader_owned(struct rw_semaphore *sem) +{ +} #endif -- cgit v0.10.2 From fb6a44f33be542fd81575ff93a4e8118d6a58592 Mon Sep 17 00:00:00 2001 From: Waiman Long Date: Tue, 17 May 2016 21:26:20 -0400 Subject: locking/rwsem: Protect all writes to owner by WRITE_ONCE() Without using WRITE_ONCE(), the compiler can potentially break a write into multiple smaller ones (store tearing). So a read from the same data by another task concurrently may return a partial result. This can result in a kernel crash if the data is a memory address that is being dereferenced. This patch changes all write to rwsem->owner to use WRITE_ONCE() to make sure that store tearing will not happen. READ_ONCE() may not be needed for rwsem->owner as long as the value is only used for comparison and not dereferencing. Signed-off-by: Waiman Long Signed-off-by: Peter Zijlstra (Intel) Cc: Andrew Morton Cc: Dave Chinner Cc: Davidlohr Bueso Cc: Douglas Hatch Cc: Jason Low Cc: Linus Torvalds Cc: Paul E. McKenney Cc: Peter Hurley Cc: Peter Zijlstra Cc: Scott J Norton Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/1463534783-38814-3-git-send-email-Waiman.Long@hpe.com Signed-off-by: Ingo Molnar diff --git a/kernel/locking/rwsem.h b/kernel/locking/rwsem.h index 8f43ba2..a699f40 100644 --- a/kernel/locking/rwsem.h +++ b/kernel/locking/rwsem.h @@ -16,14 +16,21 @@ #define RWSEM_READER_OWNED ((struct task_struct *)1UL) #ifdef CONFIG_RWSEM_SPIN_ON_OWNER +/* + * All writes to owner are protected by WRITE_ONCE() to make sure that + * store tearing can't happen as optimistic spinners may read and use + * the owner value concurrently without lock. Read from owner, however, + * may not need READ_ONCE() as long as the pointer value is only used + * for comparison and isn't being dereferenced. + */ static inline void rwsem_set_owner(struct rw_semaphore *sem) { - sem->owner = current; + WRITE_ONCE(sem->owner, current); } static inline void rwsem_clear_owner(struct rw_semaphore *sem) { - sem->owner = NULL; + WRITE_ONCE(sem->owner, NULL); } static inline void rwsem_set_reader_owned(struct rw_semaphore *sem) @@ -34,7 +41,7 @@ static inline void rwsem_set_reader_owned(struct rw_semaphore *sem) * to minimize cacheline contention. */ if (sem->owner != RWSEM_READER_OWNED) - sem->owner = RWSEM_READER_OWNED; + WRITE_ONCE(sem->owner, RWSEM_READER_OWNED); } static inline bool rwsem_owner_is_writer(struct task_struct *owner) -- cgit v0.10.2 From bf7b4c472db44413251bcef79ca1f6bf1ec81475 Mon Sep 17 00:00:00 2001 From: Waiman Long Date: Tue, 17 May 2016 21:26:22 -0400 Subject: locking/rwsem: Improve reader wakeup code In __rwsem_do_wake(), the reader wakeup code will assume a writer has stolen the lock if the active reader/writer count is not 0. However, this is not as reliable an indicator as the original "< RWSEM_WAITING_BIAS" check. If another reader is present, the code will still break out and exit even if the writer is gone. This patch changes it to check the same "< RWSEM_WAITING_BIAS" condition to reduce the chance of false positive. Signed-off-by: Waiman Long Signed-off-by: Peter Zijlstra (Intel) Reviewed-by: Peter Hurley Cc: Andrew Morton Cc: Dave Chinner Cc: Davidlohr Bueso Cc: Douglas Hatch Cc: Jason Low Cc: Linus Torvalds Cc: Paul E. McKenney Cc: Peter Zijlstra Cc: Scott J Norton Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/1463534783-38814-5-git-send-email-Waiman.Long@hpe.com Signed-off-by: Ingo Molnar diff --git a/kernel/locking/rwsem-xadd.c b/kernel/locking/rwsem-xadd.c index 6b0d060..4f1daf5 100644 --- a/kernel/locking/rwsem-xadd.c +++ b/kernel/locking/rwsem-xadd.c @@ -156,9 +156,14 @@ __rwsem_mark_wake(struct rw_semaphore *sem, oldcount = atomic_long_add_return(adjustment, &sem->count) - adjustment; if (unlikely(oldcount < RWSEM_WAITING_BIAS)) { - /* A writer stole the lock. Undo our reader grant. */ - if (atomic_long_sub_return(adjustment, &sem->count) & - RWSEM_ACTIVE_MASK) + /* + * If the count is still less than RWSEM_WAITING_BIAS + * after removing the adjustment, it is assumed that + * a writer has stolen the lock. We have to undo our + * reader grant. + */ + if (atomic_long_add_return(-adjustment, &sem->count) < + RWSEM_WAITING_BIAS) goto out; /* Last active locker left. Retry waking readers. */ goto try_reader_grant; -- cgit v0.10.2 From ddd0fa73c2b71c35de4fe7ae60a5f1a6cddc2cf0 Mon Sep 17 00:00:00 2001 From: Waiman Long Date: Tue, 17 May 2016 21:26:23 -0400 Subject: locking/rwsem: Streamline the rwsem_optimistic_spin() code This patch moves the owner loading and checking code entirely inside of rwsem_spin_on_owner() to simplify the logic of rwsem_optimistic_spin() loop. Suggested-by: Peter Hurley Signed-off-by: Waiman Long Signed-off-by: Peter Zijlstra (Intel) Reviewed-by: Peter Hurley Cc: Andrew Morton Cc: Dave Chinner Cc: Davidlohr Bueso Cc: Douglas Hatch Cc: Jason Low Cc: Linus Torvalds Cc: Paul E. McKenney Cc: Peter Zijlstra Cc: Scott J Norton Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/1463534783-38814-6-git-send-email-Waiman.Long@hpe.com Signed-off-by: Ingo Molnar diff --git a/kernel/locking/rwsem-xadd.c b/kernel/locking/rwsem-xadd.c index 4f1daf5..2031281 100644 --- a/kernel/locking/rwsem-xadd.c +++ b/kernel/locking/rwsem-xadd.c @@ -350,9 +350,16 @@ done: return ret; } -static noinline -bool rwsem_spin_on_owner(struct rw_semaphore *sem, struct task_struct *owner) +/* + * Return true only if we can still spin on the owner field of the rwsem. + */ +static noinline bool rwsem_spin_on_owner(struct rw_semaphore *sem) { + struct task_struct *owner = READ_ONCE(sem->owner); + + if (!rwsem_owner_is_writer(owner)) + goto out; + rcu_read_lock(); while (sem->owner == owner) { /* @@ -372,7 +379,7 @@ bool rwsem_spin_on_owner(struct rw_semaphore *sem, struct task_struct *owner) cpu_relax_lowlatency(); } rcu_read_unlock(); - +out: /* * If there is a new owner or the owner is not set, we continue * spinning. @@ -382,7 +389,6 @@ bool rwsem_spin_on_owner(struct rw_semaphore *sem, struct task_struct *owner) static bool rwsem_optimistic_spin(struct rw_semaphore *sem) { - struct task_struct *owner; bool taken = false; preempt_disable(); @@ -394,21 +400,17 @@ static bool rwsem_optimistic_spin(struct rw_semaphore *sem) if (!osq_lock(&sem->osq)) goto done; - while (true) { - owner = READ_ONCE(sem->owner); + /* + * Optimistically spin on the owner field and attempt to acquire the + * lock whenever the owner changes. Spinning will be stopped when: + * 1) the owning writer isn't running; or + * 2) readers own the lock as we can't determine if they are + * actively running or not. + */ + while (rwsem_spin_on_owner(sem)) { /* - * Don't spin if - * 1) the owner is a reader as we we can't determine if the - * reader is actively running or not. - * 2) The rwsem_spin_on_owner() returns false which means - * the owner isn't running. + * Try to acquire the lock */ - if (rwsem_owner_is_reader(owner) || - (rwsem_owner_is_writer(owner) && - !rwsem_spin_on_owner(sem, owner))) - break; - - /* wait_lock will be acquired if write_lock is obtained */ if (rwsem_try_write_lock_unqueued(sem)) { taken = true; break; @@ -420,7 +422,7 @@ static bool rwsem_optimistic_spin(struct rw_semaphore *sem) * we're an RT task that will live-lock because we won't let * the owner complete. */ - if (!owner && (need_resched() || rt_task(current))) + if (!sem->owner && (need_resched() || rt_task(current))) break; /* -- cgit v0.10.2 From 6428671bae97caa7040e24e79e969fd87908f4f3 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Wed, 1 Jun 2016 20:58:15 +0200 Subject: locking/mutex: Optimize mutex_trylock() fast-path A while back Viro posted a number of 'interesting' mutex_is_locked() users on IRC, one of those was RCU. RCU seems to use mutex_is_locked() to avoid doing mutex_trylock(), the regular load before modify pattern. While the use isn't wrong per se, its curious in that its needed at all, mutex_trylock() should be good enough on its own to avoid the pointless cacheline bounces. So fix those and remove the mutex_is_locked() (ab)use from RCU. Reported-by: Al Viro Signed-off-by: Peter Zijlstra (Intel) Acked-by: Paul McKenney Acked-by: Davidlohr Bueso Cc: Andrew Morton Cc: Linus Torvalds Cc: Paul E. McKenney Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: Waiman Long Link: http://lkml.kernel.org/r/20160601185815.GW3190@twins.programming.kicks-ass.net Signed-off-by: Ingo Molnar diff --git a/arch/ia64/include/asm/mutex.h b/arch/ia64/include/asm/mutex.h index f41e66d..28cb819 100644 --- a/arch/ia64/include/asm/mutex.h +++ b/arch/ia64/include/asm/mutex.h @@ -82,7 +82,7 @@ __mutex_fastpath_unlock(atomic_t *count, void (*fail_fn)(atomic_t *)) static inline int __mutex_fastpath_trylock(atomic_t *count, int (*fail_fn)(atomic_t *)) { - if (cmpxchg_acq(count, 1, 0) == 1) + if (atomic_read(count) == 1 && cmpxchg_acq(count, 1, 0) == 1) return 1; return 0; } diff --git a/arch/powerpc/include/asm/mutex.h b/arch/powerpc/include/asm/mutex.h index 127ab23..078155f 100644 --- a/arch/powerpc/include/asm/mutex.h +++ b/arch/powerpc/include/asm/mutex.h @@ -124,7 +124,7 @@ __mutex_fastpath_unlock(atomic_t *count, void (*fail_fn)(atomic_t *)) static inline int __mutex_fastpath_trylock(atomic_t *count, int (*fail_fn)(atomic_t *)) { - if (likely(__mutex_cmpxchg_lock(count, 1, 0) == 1)) + if (likely(atomic_read(count) == 1 && __mutex_cmpxchg_lock(count, 1, 0) == 1)) return 1; return 0; } diff --git a/arch/x86/include/asm/mutex_32.h b/arch/x86/include/asm/mutex_32.h index 85e6cda..e9355a8 100644 --- a/arch/x86/include/asm/mutex_32.h +++ b/arch/x86/include/asm/mutex_32.h @@ -101,7 +101,7 @@ static inline int __mutex_fastpath_trylock(atomic_t *count, int (*fail_fn)(atomic_t *)) { /* cmpxchg because it never induces a false contention state. */ - if (likely(atomic_cmpxchg(count, 1, 0) == 1)) + if (likely(atomic_read(count) == 1 && atomic_cmpxchg(count, 1, 0) == 1)) return 1; return 0; diff --git a/arch/x86/include/asm/mutex_64.h b/arch/x86/include/asm/mutex_64.h index 07537a4..d985075 100644 --- a/arch/x86/include/asm/mutex_64.h +++ b/arch/x86/include/asm/mutex_64.h @@ -118,10 +118,10 @@ do { \ static inline int __mutex_fastpath_trylock(atomic_t *count, int (*fail_fn)(atomic_t *)) { - if (likely(atomic_cmpxchg(count, 1, 0) == 1)) + if (likely(atomic_read(count) == 1 && atomic_cmpxchg(count, 1, 0) == 1)) return 1; - else - return 0; + + return 0; } #endif /* _ASM_X86_MUTEX_64_H */ diff --git a/include/asm-generic/mutex-dec.h b/include/asm-generic/mutex-dec.h index fd694cf..c54829d 100644 --- a/include/asm-generic/mutex-dec.h +++ b/include/asm-generic/mutex-dec.h @@ -80,7 +80,7 @@ __mutex_fastpath_unlock(atomic_t *count, void (*fail_fn)(atomic_t *)) static inline int __mutex_fastpath_trylock(atomic_t *count, int (*fail_fn)(atomic_t *)) { - if (likely(atomic_cmpxchg_acquire(count, 1, 0) == 1)) + if (likely(atomic_read(count) == 1 && atomic_cmpxchg_acquire(count, 1, 0) == 1)) return 1; return 0; } diff --git a/include/asm-generic/mutex-xchg.h b/include/asm-generic/mutex-xchg.h index a6b4a7b..3269ec4 100644 --- a/include/asm-generic/mutex-xchg.h +++ b/include/asm-generic/mutex-xchg.h @@ -91,8 +91,12 @@ __mutex_fastpath_unlock(atomic_t *count, void (*fail_fn)(atomic_t *)) static inline int __mutex_fastpath_trylock(atomic_t *count, int (*fail_fn)(atomic_t *)) { - int prev = atomic_xchg_acquire(count, 0); + int prev; + if (atomic_read(count) != 1) + return 0; + + prev = atomic_xchg_acquire(count, 0); if (unlikely(prev < 0)) { /* * The lock was marked contended so we must restore that diff --git a/kernel/rcu/tree.c b/kernel/rcu/tree.c index c7f1bc4..b732689 100644 --- a/kernel/rcu/tree.c +++ b/kernel/rcu/tree.c @@ -3681,7 +3681,6 @@ static bool exp_funnel_lock(struct rcu_state *rsp, unsigned long s) if (ULONG_CMP_LT(READ_ONCE(rnp->exp_seq_rq), s) && (rnp == rnp_root || ULONG_CMP_LT(READ_ONCE(rnp_root->exp_seq_rq), s)) && - !mutex_is_locked(&rsp->exp_mutex) && mutex_trylock(&rsp->exp_mutex)) goto fastpath; -- cgit v0.10.2 From ca50e426f96c905e7d14a9c7a6bd4e0330516047 Mon Sep 17 00:00:00 2001 From: Pan Xinhui Date: Fri, 3 Jun 2016 16:38:14 +0800 Subject: locking/qspinlock: Use atomic_sub_return_release() in queued_spin_unlock() The existing version uses a heavy barrier while only release semantics is required. So use atomic_sub_return_release() instead. Suggested-by: Peter Zijlstra (Intel) Signed-off-by: Pan Xinhui Signed-off-by: Peter Zijlstra (Intel) Cc: Andrew Morton Cc: Linus Torvalds Cc: Paul E. McKenney Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: arnd@arndb.de Cc: waiman.long@hp.com Link: http://lkml.kernel.org/r/1464943094-3129-1-git-send-email-xinhui.pan@linux.vnet.ibm.com Signed-off-by: Ingo Molnar diff --git a/include/asm-generic/qspinlock.h b/include/asm-generic/qspinlock.h index 05f05f1..9f0681b 100644 --- a/include/asm-generic/qspinlock.h +++ b/include/asm-generic/qspinlock.h @@ -111,10 +111,9 @@ static __always_inline void queued_spin_lock(struct qspinlock *lock) static __always_inline void queued_spin_unlock(struct qspinlock *lock) { /* - * smp_mb__before_atomic() in order to guarantee release semantics + * unlock() needs release semantics: */ - smp_mb__before_atomic(); - atomic_sub(_Q_LOCKED_VAL, &lock->val); + (void)atomic_sub_return_release(_Q_LOCKED_VAL, &lock->val); } #endif -- cgit v0.10.2 From 76d15c8fba655c9b2d60cf01834858f2c44483dc Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Wed, 8 Jun 2016 18:54:40 +0200 Subject: ehci-platform: Add support for shared reset controllers Add support for shared platform controllers by using devm_reset_control_get_shared_by_index instead of of_reset_control_get_by_index. Note we use the devm function because there is no of_reset_control_get_shared_by_index, this also leads to a nice cleanup of the cleanup code. This brings the ehci-platform reset handling code inline with ohci-platform. Signed-off-by: Hans de Goede Acked-by: Alan Stern Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/host/ehci-platform.c b/drivers/usb/host/ehci-platform.c index bc33f45..6816b8c 100644 --- a/drivers/usb/host/ehci-platform.c +++ b/drivers/usb/host/ehci-platform.c @@ -236,8 +236,8 @@ static int ehci_platform_probe(struct platform_device *dev) } for (rst = 0; rst < EHCI_MAX_RSTS; rst++) { - priv->rsts[rst] = of_reset_control_get_by_index( - dev->dev.of_node, rst); + priv->rsts[rst] = devm_reset_control_get_shared_by_index( + &dev->dev, rst); if (IS_ERR(priv->rsts[rst])) { err = PTR_ERR(priv->rsts[rst]); if (err == -EPROBE_DEFER) @@ -247,10 +247,8 @@ static int ehci_platform_probe(struct platform_device *dev) } err = reset_control_deassert(priv->rsts[rst]); - if (err) { - reset_control_put(priv->rsts[rst]); + if (err) goto err_reset; - } } if (pdata->big_endian_desc) @@ -307,10 +305,8 @@ err_power: if (pdata->power_off) pdata->power_off(dev); err_reset: - while (--rst >= 0) { + while (--rst >= 0) reset_control_assert(priv->rsts[rst]); - reset_control_put(priv->rsts[rst]); - } err_put_clks: while (--clk >= 0) clk_put(priv->clks[clk]); @@ -335,10 +331,8 @@ static int ehci_platform_remove(struct platform_device *dev) if (pdata->power_off) pdata->power_off(dev); - for (rst = 0; rst < EHCI_MAX_RSTS && priv->rsts[rst]; rst++) { + for (rst = 0; rst < EHCI_MAX_RSTS && priv->rsts[rst]; rst++) reset_control_assert(priv->rsts[rst]); - reset_control_put(priv->rsts[rst]); - } for (clk = 0; clk < EHCI_MAX_CLKS && priv->clks[clk]; clk++) clk_put(priv->clks[clk]); -- cgit v0.10.2 From 2823d4da5d8a0c222747b24eceb65f5b30717d02 Mon Sep 17 00:00:00 2001 From: "H. Peter Anvin" Date: Wed, 8 Jun 2016 12:38:37 -0700 Subject: x86, bitops: remove use of "sbb" to return CF Use SETC instead of SBB to return the value of CF from assembly. Using SETcc enables uniformity with other flags-returning pieces of assembly code. Signed-off-by: H. Peter Anvin Link: http://lkml.kernel.org/r/1465414726-197858-2-git-send-email-hpa@linux.intel.com Reviewed-by: Andy Lutomirski Reviewed-by: Borislav Petkov Acked-by: Peter Zijlstra (Intel) diff --git a/arch/x86/include/asm/bitops.h b/arch/x86/include/asm/bitops.h index 7766d1c..b2b797d 100644 --- a/arch/x86/include/asm/bitops.h +++ b/arch/x86/include/asm/bitops.h @@ -230,11 +230,11 @@ test_and_set_bit_lock(long nr, volatile unsigned long *addr) */ static __always_inline int __test_and_set_bit(long nr, volatile unsigned long *addr) { - int oldbit; + unsigned char oldbit; asm("bts %2,%1\n\t" - "sbb %0,%0" - : "=r" (oldbit), ADDR + "setc %0" + : "=qm" (oldbit), ADDR : "Ir" (nr)); return oldbit; } @@ -270,11 +270,11 @@ static __always_inline int test_and_clear_bit(long nr, volatile unsigned long *a */ static __always_inline int __test_and_clear_bit(long nr, volatile unsigned long *addr) { - int oldbit; + unsigned char oldbit; asm volatile("btr %2,%1\n\t" - "sbb %0,%0" - : "=r" (oldbit), ADDR + "setc %0" + : "=qm" (oldbit), ADDR : "Ir" (nr)); return oldbit; } @@ -282,11 +282,11 @@ static __always_inline int __test_and_clear_bit(long nr, volatile unsigned long /* WARNING: non atomic and it can be reordered! */ static __always_inline int __test_and_change_bit(long nr, volatile unsigned long *addr) { - int oldbit; + unsigned char oldbit; asm volatile("btc %2,%1\n\t" - "sbb %0,%0" - : "=r" (oldbit), ADDR + "setc %0" + : "=qm" (oldbit), ADDR : "Ir" (nr) : "memory"); return oldbit; @@ -313,11 +313,11 @@ static __always_inline int constant_test_bit(long nr, const volatile unsigned lo static __always_inline int variable_test_bit(long nr, volatile const unsigned long *addr) { - int oldbit; + unsigned char oldbit; asm volatile("bt %2,%1\n\t" - "sbb %0,%0" - : "=r" (oldbit) + "setc %0" + : "=qm" (oldbit) : "m" (*(unsigned long *)addr), "Ir" (nr)); return oldbit; diff --git a/arch/x86/include/asm/percpu.h b/arch/x86/include/asm/percpu.h index e0ba66c..65039e9 100644 --- a/arch/x86/include/asm/percpu.h +++ b/arch/x86/include/asm/percpu.h @@ -510,9 +510,9 @@ do { \ /* This is not atomic against other CPUs -- CPU preemption needs to be off */ #define x86_test_and_clear_bit_percpu(bit, var) \ ({ \ - int old__; \ - asm volatile("btr %2,"__percpu_arg(1)"\n\tsbbl %0,%0" \ - : "=r" (old__), "+m" (var) \ + unsigned char old__; \ + asm volatile("btr %2,"__percpu_arg(1)"\n\tsetc %0" \ + : "=qm" (old__), "+m" (var) \ : "dIr" (bit)); \ old__; \ }) @@ -532,11 +532,11 @@ static __always_inline int x86_this_cpu_constant_test_bit(unsigned int nr, static inline int x86_this_cpu_variable_test_bit(int nr, const unsigned long __percpu *addr) { - int oldbit; + unsigned char oldbit; asm volatile("bt "__percpu_arg(2)",%1\n\t" - "sbb %0,%0" - : "=r" (oldbit) + "setc %0" + : "=qm" (oldbit) : "m" (*(unsigned long *)addr), "Ir" (nr)); return oldbit; diff --git a/arch/x86/include/asm/signal.h b/arch/x86/include/asm/signal.h index 2138c9a..dd1e7d6 100644 --- a/arch/x86/include/asm/signal.h +++ b/arch/x86/include/asm/signal.h @@ -81,9 +81,9 @@ static inline int __const_sigismember(sigset_t *set, int _sig) static inline int __gen_sigismember(sigset_t *set, int _sig) { - int ret; - asm("btl %2,%1\n\tsbbl %0,%0" - : "=r"(ret) : "m"(*set), "Ir"(_sig-1) : "cc"); + unsigned char ret; + asm("btl %2,%1\n\tsetc %0" + : "=qm"(ret) : "m"(*set), "Ir"(_sig-1) : "cc"); return ret; } diff --git a/arch/x86/include/asm/sync_bitops.h b/arch/x86/include/asm/sync_bitops.h index f28a24b..cbf8847 100644 --- a/arch/x86/include/asm/sync_bitops.h +++ b/arch/x86/include/asm/sync_bitops.h @@ -79,10 +79,10 @@ static inline void sync_change_bit(long nr, volatile unsigned long *addr) */ static inline int sync_test_and_set_bit(long nr, volatile unsigned long *addr) { - int oldbit; + unsigned char oldbit; - asm volatile("lock; bts %2,%1\n\tsbbl %0,%0" - : "=r" (oldbit), "+m" (ADDR) + asm volatile("lock; bts %2,%1\n\tsetc %0" + : "=qm" (oldbit), "+m" (ADDR) : "Ir" (nr) : "memory"); return oldbit; } @@ -97,10 +97,10 @@ static inline int sync_test_and_set_bit(long nr, volatile unsigned long *addr) */ static inline int sync_test_and_clear_bit(long nr, volatile unsigned long *addr) { - int oldbit; + unsigned char oldbit; - asm volatile("lock; btr %2,%1\n\tsbbl %0,%0" - : "=r" (oldbit), "+m" (ADDR) + asm volatile("lock; btr %2,%1\n\tsetc %0" + : "=qm" (oldbit), "+m" (ADDR) : "Ir" (nr) : "memory"); return oldbit; } @@ -115,10 +115,10 @@ static inline int sync_test_and_clear_bit(long nr, volatile unsigned long *addr) */ static inline int sync_test_and_change_bit(long nr, volatile unsigned long *addr) { - int oldbit; + unsigned char oldbit; - asm volatile("lock; btc %2,%1\n\tsbbl %0,%0" - : "=r" (oldbit), "+m" (ADDR) + asm volatile("lock; btc %2,%1\n\tsetc %0" + : "=qm" (oldbit), "+m" (ADDR) : "Ir" (nr) : "memory"); return oldbit; } diff --git a/arch/x86/kernel/vm86_32.c b/arch/x86/kernel/vm86_32.c index 3dce1ca..01f30e5 100644 --- a/arch/x86/kernel/vm86_32.c +++ b/arch/x86/kernel/vm86_32.c @@ -440,10 +440,7 @@ static inline unsigned long get_vflags(struct kernel_vm86_regs *regs) static inline int is_revectored(int nr, struct revectored_struct *bitmap) { - __asm__ __volatile__("btl %2,%1\n\tsbbl %0,%0" - :"=r" (nr) - :"m" (*bitmap), "r" (nr)); - return nr; + return test_bit(nr, bitmap->__map); } #define val_byte(val, n) (((__u8 *)&val)[n]) -- cgit v0.10.2 From 117780eef7740729e803bdcc0d5f2f48137ea8e3 Mon Sep 17 00:00:00 2001 From: "H. Peter Anvin" Date: Wed, 8 Jun 2016 12:38:38 -0700 Subject: x86, asm: use bool for bitops and other assembly outputs The gcc people have confirmed that using "bool" when combined with inline assembly always is treated as a byte-sized operand that can be assumed to be 0 or 1, which is exactly what the SET instruction emits. Change the output types and intermediate variables of as many operations as practical to "bool". Signed-off-by: H. Peter Anvin Link: http://lkml.kernel.org/r/1465414726-197858-3-git-send-email-hpa@linux.intel.com Reviewed-by: Andy Lutomirski Reviewed-by: Borislav Petkov Acked-by: Peter Zijlstra (Intel) diff --git a/arch/x86/boot/bitops.h b/arch/x86/boot/bitops.h index 878e4b9..0d41d68 100644 --- a/arch/x86/boot/bitops.h +++ b/arch/x86/boot/bitops.h @@ -16,14 +16,16 @@ #define BOOT_BITOPS_H #define _LINUX_BITOPS_H /* Inhibit inclusion of */ -static inline int constant_test_bit(int nr, const void *addr) +#include + +static inline bool constant_test_bit(int nr, const void *addr) { const u32 *p = (const u32 *)addr; return ((1UL << (nr & 31)) & (p[nr >> 5])) != 0; } -static inline int variable_test_bit(int nr, const void *addr) +static inline bool variable_test_bit(int nr, const void *addr) { - u8 v; + bool v; const u32 *p = (const u32 *)addr; asm("btl %2,%1; setc %0" : "=qm" (v) : "m" (*p), "Ir" (nr)); diff --git a/arch/x86/boot/boot.h b/arch/x86/boot/boot.h index 9011a88..2edb2d5 100644 --- a/arch/x86/boot/boot.h +++ b/arch/x86/boot/boot.h @@ -176,16 +176,16 @@ static inline void wrgs32(u32 v, addr_t addr) } /* Note: these only return true/false, not a signed return value! */ -static inline int memcmp_fs(const void *s1, addr_t s2, size_t len) +static inline bool memcmp_fs(const void *s1, addr_t s2, size_t len) { - u8 diff; + bool diff; asm volatile("fs; repe; cmpsb; setnz %0" : "=qm" (diff), "+D" (s1), "+S" (s2), "+c" (len)); return diff; } -static inline int memcmp_gs(const void *s1, addr_t s2, size_t len) +static inline bool memcmp_gs(const void *s1, addr_t s2, size_t len) { - u8 diff; + bool diff; asm volatile("gs; repe; cmpsb; setnz %0" : "=qm" (diff), "+D" (s1), "+S" (s2), "+c" (len)); return diff; diff --git a/arch/x86/boot/string.c b/arch/x86/boot/string.c index 318b846..cc3bd58 100644 --- a/arch/x86/boot/string.c +++ b/arch/x86/boot/string.c @@ -17,7 +17,7 @@ int memcmp(const void *s1, const void *s2, size_t len) { - u8 diff; + bool diff; asm("repe; cmpsb; setnz %0" : "=qm" (diff), "+D" (s1), "+S" (s2), "+c" (len)); return diff; diff --git a/arch/x86/include/asm/apm.h b/arch/x86/include/asm/apm.h index 20370c6..93eebc63 100644 --- a/arch/x86/include/asm/apm.h +++ b/arch/x86/include/asm/apm.h @@ -45,11 +45,11 @@ static inline void apm_bios_call_asm(u32 func, u32 ebx_in, u32 ecx_in, : "memory", "cc"); } -static inline u8 apm_bios_call_simple_asm(u32 func, u32 ebx_in, - u32 ecx_in, u32 *eax) +static inline bool apm_bios_call_simple_asm(u32 func, u32 ebx_in, + u32 ecx_in, u32 *eax) { int cx, dx, si; - u8 error; + bool error; /* * N.B. We do NOT need a cld after the BIOS call diff --git a/arch/x86/include/asm/archrandom.h b/arch/x86/include/asm/archrandom.h index 69f1366..ab6f599 100644 --- a/arch/x86/include/asm/archrandom.h +++ b/arch/x86/include/asm/archrandom.h @@ -43,7 +43,7 @@ #ifdef CONFIG_ARCH_RANDOM /* Instead of arch_get_random_long() when alternatives haven't run. */ -static inline int rdrand_long(unsigned long *v) +static inline bool rdrand_long(unsigned long *v) { int ok; asm volatile("1: " RDRAND_LONG "\n\t" @@ -53,13 +53,13 @@ static inline int rdrand_long(unsigned long *v) "2:" : "=r" (ok), "=a" (*v) : "0" (RDRAND_RETRY_LOOPS)); - return ok; + return !!ok; } /* A single attempt at RDSEED */ static inline bool rdseed_long(unsigned long *v) { - unsigned char ok; + bool ok; asm volatile(RDSEED_LONG "\n\t" "setc %0" : "=qm" (ok), "=a" (*v)); @@ -67,7 +67,7 @@ static inline bool rdseed_long(unsigned long *v) } #define GET_RANDOM(name, type, rdrand, nop) \ -static inline int name(type *v) \ +static inline bool name(type *v) \ { \ int ok; \ alternative_io("movl $0, %0\n\t" \ @@ -80,13 +80,13 @@ static inline int name(type *v) \ X86_FEATURE_RDRAND, \ ASM_OUTPUT2("=r" (ok), "=a" (*v)), \ "0" (RDRAND_RETRY_LOOPS)); \ - return ok; \ + return !!ok; \ } #define GET_SEED(name, type, rdseed, nop) \ -static inline int name(type *v) \ +static inline bool name(type *v) \ { \ - unsigned char ok; \ + bool ok; \ alternative_io("movb $0, %0\n\t" \ nop, \ rdseed "\n\t" \ @@ -119,7 +119,7 @@ GET_SEED(arch_get_random_seed_int, unsigned int, RDSEED_INT, ASM_NOP4); #else -static inline int rdrand_long(unsigned long *v) +static inline bool rdrand_long(unsigned long *v) { return 0; } diff --git a/arch/x86/include/asm/atomic.h b/arch/x86/include/asm/atomic.h index 3e86742..17d8812 100644 --- a/arch/x86/include/asm/atomic.h +++ b/arch/x86/include/asm/atomic.h @@ -75,7 +75,7 @@ static __always_inline void atomic_sub(int i, atomic_t *v) * true if the result is zero, or false for all * other cases. */ -static __always_inline int atomic_sub_and_test(int i, atomic_t *v) +static __always_inline bool atomic_sub_and_test(int i, atomic_t *v) { GEN_BINARY_RMWcc(LOCK_PREFIX "subl", v->counter, "er", i, "%0", "e"); } @@ -112,7 +112,7 @@ static __always_inline void atomic_dec(atomic_t *v) * returns true if the result is 0, or false for all other * cases. */ -static __always_inline int atomic_dec_and_test(atomic_t *v) +static __always_inline bool atomic_dec_and_test(atomic_t *v) { GEN_UNARY_RMWcc(LOCK_PREFIX "decl", v->counter, "%0", "e"); } @@ -125,7 +125,7 @@ static __always_inline int atomic_dec_and_test(atomic_t *v) * and returns true if the result is zero, or false for all * other cases. */ -static __always_inline int atomic_inc_and_test(atomic_t *v) +static __always_inline bool atomic_inc_and_test(atomic_t *v) { GEN_UNARY_RMWcc(LOCK_PREFIX "incl", v->counter, "%0", "e"); } @@ -139,7 +139,7 @@ static __always_inline int atomic_inc_and_test(atomic_t *v) * if the result is negative, or false when * result is greater than or equal to zero. */ -static __always_inline int atomic_add_negative(int i, atomic_t *v) +static __always_inline bool atomic_add_negative(int i, atomic_t *v) { GEN_BINARY_RMWcc(LOCK_PREFIX "addl", v->counter, "er", i, "%0", "s"); } diff --git a/arch/x86/include/asm/atomic64_64.h b/arch/x86/include/asm/atomic64_64.h index 0373510..4f881d7 100644 --- a/arch/x86/include/asm/atomic64_64.h +++ b/arch/x86/include/asm/atomic64_64.h @@ -70,7 +70,7 @@ static inline void atomic64_sub(long i, atomic64_t *v) * true if the result is zero, or false for all * other cases. */ -static inline int atomic64_sub_and_test(long i, atomic64_t *v) +static inline bool atomic64_sub_and_test(long i, atomic64_t *v) { GEN_BINARY_RMWcc(LOCK_PREFIX "subq", v->counter, "er", i, "%0", "e"); } @@ -109,7 +109,7 @@ static __always_inline void atomic64_dec(atomic64_t *v) * returns true if the result is 0, or false for all other * cases. */ -static inline int atomic64_dec_and_test(atomic64_t *v) +static inline bool atomic64_dec_and_test(atomic64_t *v) { GEN_UNARY_RMWcc(LOCK_PREFIX "decq", v->counter, "%0", "e"); } @@ -122,7 +122,7 @@ static inline int atomic64_dec_and_test(atomic64_t *v) * and returns true if the result is zero, or false for all * other cases. */ -static inline int atomic64_inc_and_test(atomic64_t *v) +static inline bool atomic64_inc_and_test(atomic64_t *v) { GEN_UNARY_RMWcc(LOCK_PREFIX "incq", v->counter, "%0", "e"); } @@ -136,7 +136,7 @@ static inline int atomic64_inc_and_test(atomic64_t *v) * if the result is negative, or false when * result is greater than or equal to zero. */ -static inline int atomic64_add_negative(long i, atomic64_t *v) +static inline bool atomic64_add_negative(long i, atomic64_t *v) { GEN_BINARY_RMWcc(LOCK_PREFIX "addq", v->counter, "er", i, "%0", "s"); } @@ -180,7 +180,7 @@ static inline long atomic64_xchg(atomic64_t *v, long new) * Atomically adds @a to @v, so long as it was not @u. * Returns the old value of @v. */ -static inline int atomic64_add_unless(atomic64_t *v, long a, long u) +static inline bool atomic64_add_unless(atomic64_t *v, long a, long u) { long c, old; c = atomic64_read(v); diff --git a/arch/x86/include/asm/bitops.h b/arch/x86/include/asm/bitops.h index b2b797d..8cbb7f4 100644 --- a/arch/x86/include/asm/bitops.h +++ b/arch/x86/include/asm/bitops.h @@ -201,7 +201,7 @@ static __always_inline void change_bit(long nr, volatile unsigned long *addr) * This operation is atomic and cannot be reordered. * It also implies a memory barrier. */ -static __always_inline int test_and_set_bit(long nr, volatile unsigned long *addr) +static __always_inline bool test_and_set_bit(long nr, volatile unsigned long *addr) { GEN_BINARY_RMWcc(LOCK_PREFIX "bts", *addr, "Ir", nr, "%0", "c"); } @@ -213,7 +213,7 @@ static __always_inline int test_and_set_bit(long nr, volatile unsigned long *add * * This is the same as test_and_set_bit on x86. */ -static __always_inline int +static __always_inline bool test_and_set_bit_lock(long nr, volatile unsigned long *addr) { return test_and_set_bit(nr, addr); @@ -228,9 +228,9 @@ test_and_set_bit_lock(long nr, volatile unsigned long *addr) * If two examples of this operation race, one can appear to succeed * but actually fail. You must protect multiple accesses with a lock. */ -static __always_inline int __test_and_set_bit(long nr, volatile unsigned long *addr) +static __always_inline bool __test_and_set_bit(long nr, volatile unsigned long *addr) { - unsigned char oldbit; + bool oldbit; asm("bts %2,%1\n\t" "setc %0" @@ -247,7 +247,7 @@ static __always_inline int __test_and_set_bit(long nr, volatile unsigned long *a * This operation is atomic and cannot be reordered. * It also implies a memory barrier. */ -static __always_inline int test_and_clear_bit(long nr, volatile unsigned long *addr) +static __always_inline bool test_and_clear_bit(long nr, volatile unsigned long *addr) { GEN_BINARY_RMWcc(LOCK_PREFIX "btr", *addr, "Ir", nr, "%0", "c"); } @@ -268,9 +268,9 @@ static __always_inline int test_and_clear_bit(long nr, volatile unsigned long *a * accessed from a hypervisor on the same CPU if running in a VM: don't change * this without also updating arch/x86/kernel/kvm.c */ -static __always_inline int __test_and_clear_bit(long nr, volatile unsigned long *addr) +static __always_inline bool __test_and_clear_bit(long nr, volatile unsigned long *addr) { - unsigned char oldbit; + bool oldbit; asm volatile("btr %2,%1\n\t" "setc %0" @@ -280,9 +280,9 @@ static __always_inline int __test_and_clear_bit(long nr, volatile unsigned long } /* WARNING: non atomic and it can be reordered! */ -static __always_inline int __test_and_change_bit(long nr, volatile unsigned long *addr) +static __always_inline bool __test_and_change_bit(long nr, volatile unsigned long *addr) { - unsigned char oldbit; + bool oldbit; asm volatile("btc %2,%1\n\t" "setc %0" @@ -300,20 +300,20 @@ static __always_inline int __test_and_change_bit(long nr, volatile unsigned long * This operation is atomic and cannot be reordered. * It also implies a memory barrier. */ -static __always_inline int test_and_change_bit(long nr, volatile unsigned long *addr) +static __always_inline bool test_and_change_bit(long nr, volatile unsigned long *addr) { GEN_BINARY_RMWcc(LOCK_PREFIX "btc", *addr, "Ir", nr, "%0", "c"); } -static __always_inline int constant_test_bit(long nr, const volatile unsigned long *addr) +static __always_inline bool constant_test_bit(long nr, const volatile unsigned long *addr) { return ((1UL << (nr & (BITS_PER_LONG-1))) & (addr[nr >> _BITOPS_LONG_SHIFT])) != 0; } -static __always_inline int variable_test_bit(long nr, volatile const unsigned long *addr) +static __always_inline bool variable_test_bit(long nr, volatile const unsigned long *addr) { - unsigned char oldbit; + bool oldbit; asm volatile("bt %2,%1\n\t" "setc %0" @@ -329,7 +329,7 @@ static __always_inline int variable_test_bit(long nr, volatile const unsigned lo * @nr: bit number to test * @addr: Address to start counting from */ -static int test_bit(int nr, const volatile unsigned long *addr); +static bool test_bit(int nr, const volatile unsigned long *addr); #endif #define test_bit(nr, addr) \ diff --git a/arch/x86/include/asm/local.h b/arch/x86/include/asm/local.h index 4ad6560..0cdc65b 100644 --- a/arch/x86/include/asm/local.h +++ b/arch/x86/include/asm/local.h @@ -50,7 +50,7 @@ static inline void local_sub(long i, local_t *l) * true if the result is zero, or false for all * other cases. */ -static inline int local_sub_and_test(long i, local_t *l) +static inline bool local_sub_and_test(long i, local_t *l) { GEN_BINARY_RMWcc(_ASM_SUB, l->a.counter, "er", i, "%0", "e"); } @@ -63,7 +63,7 @@ static inline int local_sub_and_test(long i, local_t *l) * returns true if the result is 0, or false for all other * cases. */ -static inline int local_dec_and_test(local_t *l) +static inline bool local_dec_and_test(local_t *l) { GEN_UNARY_RMWcc(_ASM_DEC, l->a.counter, "%0", "e"); } @@ -76,7 +76,7 @@ static inline int local_dec_and_test(local_t *l) * and returns true if the result is zero, or false for all * other cases. */ -static inline int local_inc_and_test(local_t *l) +static inline bool local_inc_and_test(local_t *l) { GEN_UNARY_RMWcc(_ASM_INC, l->a.counter, "%0", "e"); } @@ -90,7 +90,7 @@ static inline int local_inc_and_test(local_t *l) * if the result is negative, or false when * result is greater than or equal to zero. */ -static inline int local_add_negative(long i, local_t *l) +static inline bool local_add_negative(long i, local_t *l) { GEN_BINARY_RMWcc(_ASM_ADD, l->a.counter, "er", i, "%0", "s"); } diff --git a/arch/x86/include/asm/percpu.h b/arch/x86/include/asm/percpu.h index 65039e9..184d7f3 100644 --- a/arch/x86/include/asm/percpu.h +++ b/arch/x86/include/asm/percpu.h @@ -510,14 +510,14 @@ do { \ /* This is not atomic against other CPUs -- CPU preemption needs to be off */ #define x86_test_and_clear_bit_percpu(bit, var) \ ({ \ - unsigned char old__; \ + bool old__; \ asm volatile("btr %2,"__percpu_arg(1)"\n\tsetc %0" \ : "=qm" (old__), "+m" (var) \ : "dIr" (bit)); \ old__; \ }) -static __always_inline int x86_this_cpu_constant_test_bit(unsigned int nr, +static __always_inline bool x86_this_cpu_constant_test_bit(unsigned int nr, const unsigned long __percpu *addr) { unsigned long __percpu *a = (unsigned long *)addr + nr / BITS_PER_LONG; @@ -529,10 +529,10 @@ static __always_inline int x86_this_cpu_constant_test_bit(unsigned int nr, #endif } -static inline int x86_this_cpu_variable_test_bit(int nr, +static inline bool x86_this_cpu_variable_test_bit(int nr, const unsigned long __percpu *addr) { - unsigned char oldbit; + bool oldbit; asm volatile("bt "__percpu_arg(2)",%1\n\t" "setc %0" diff --git a/arch/x86/include/asm/rmwcc.h b/arch/x86/include/asm/rmwcc.h index 8f7866a..a15b73d 100644 --- a/arch/x86/include/asm/rmwcc.h +++ b/arch/x86/include/asm/rmwcc.h @@ -23,11 +23,11 @@ cc_label: \ #define __GEN_RMWcc(fullop, var, cc, ...) \ do { \ - char c; \ + bool c; \ asm volatile (fullop "; set" cc " %1" \ : "+m" (var), "=qm" (c) \ : __VA_ARGS__ : "memory"); \ - return c != 0; \ + return c; \ } while (0) #define GEN_UNARY_RMWcc(op, var, arg0, cc) \ diff --git a/arch/x86/include/asm/rwsem.h b/arch/x86/include/asm/rwsem.h index 453744c..c508770 100644 --- a/arch/x86/include/asm/rwsem.h +++ b/arch/x86/include/asm/rwsem.h @@ -77,7 +77,7 @@ static inline void __down_read(struct rw_semaphore *sem) /* * trylock for reading -- returns 1 if successful, 0 if contention */ -static inline int __down_read_trylock(struct rw_semaphore *sem) +static inline bool __down_read_trylock(struct rw_semaphore *sem) { long result, tmp; asm volatile("# beginning __down_read_trylock\n\t" @@ -93,7 +93,7 @@ static inline int __down_read_trylock(struct rw_semaphore *sem) : "+m" (sem->count), "=&a" (result), "=&r" (tmp) : "i" (RWSEM_ACTIVE_READ_BIAS) : "memory", "cc"); - return result >= 0 ? 1 : 0; + return result >= 0; } /* @@ -134,9 +134,10 @@ static inline int __down_write_killable(struct rw_semaphore *sem) /* * trylock for writing -- returns 1 if successful, 0 if contention */ -static inline int __down_write_trylock(struct rw_semaphore *sem) +static inline bool __down_write_trylock(struct rw_semaphore *sem) { - long result, tmp; + bool result; + long tmp0, tmp1; asm volatile("# beginning __down_write_trylock\n\t" " mov %0,%1\n\t" "1:\n\t" @@ -144,14 +145,14 @@ static inline int __down_write_trylock(struct rw_semaphore *sem) /* was the active mask 0 before? */ " jnz 2f\n\t" " mov %1,%2\n\t" - " add %3,%2\n\t" + " add %4,%2\n\t" LOCK_PREFIX " cmpxchg %2,%0\n\t" " jnz 1b\n\t" "2:\n\t" - " sete %b1\n\t" - " movzbl %b1, %k1\n\t" + " sete %3\n\t" "# ending __down_write_trylock\n\t" - : "+m" (sem->count), "=&a" (result), "=&r" (tmp) + : "+m" (sem->count), "=&a" (tmp0), "=&r" (tmp1), + "=qm" (result) : "er" (RWSEM_ACTIVE_WRITE_BIAS) : "memory", "cc"); return result; diff --git a/include/linux/random.h b/include/linux/random.h index e47e533..3d6e981 100644 --- a/include/linux/random.h +++ b/include/linux/random.h @@ -95,27 +95,27 @@ static inline void prandom_seed_state(struct rnd_state *state, u64 seed) #ifdef CONFIG_ARCH_RANDOM # include #else -static inline int arch_get_random_long(unsigned long *v) +static inline bool arch_get_random_long(unsigned long *v) { return 0; } -static inline int arch_get_random_int(unsigned int *v) +static inline bool arch_get_random_int(unsigned int *v) { return 0; } -static inline int arch_has_random(void) +static inline bool arch_has_random(void) { return 0; } -static inline int arch_get_random_seed_long(unsigned long *v) +static inline bool arch_get_random_seed_long(unsigned long *v) { return 0; } -static inline int arch_get_random_seed_int(unsigned int *v) +static inline bool arch_get_random_seed_int(unsigned int *v) { return 0; } -static inline int arch_has_random_seed(void) +static inline bool arch_has_random_seed(void) { return 0; } -- cgit v0.10.2 From 18fe58229d80c7f4f138a07e84ba608e1ebd232b Mon Sep 17 00:00:00 2001 From: "H. Peter Anvin" Date: Wed, 8 Jun 2016 12:38:39 -0700 Subject: x86, asm: change the GEN_*_RMWcc() macros to not quote the condition Change the lexical defintion of the GEN_*_RMWcc() macros to not take the condition code as a quoted string. This will help support changing them to use the new __GCC_ASM_FLAG_OUTPUTS__ feature in a subsequent patch. Signed-off-by: H. Peter Anvin Link: http://lkml.kernel.org/r/1465414726-197858-4-git-send-email-hpa@linux.intel.com Reviewed-by: Andy Lutomirski Reviewed-by: Borislav Petkov Acked-by: Peter Zijlstra (Intel) diff --git a/arch/x86/include/asm/atomic.h b/arch/x86/include/asm/atomic.h index 17d8812..7322c15 100644 --- a/arch/x86/include/asm/atomic.h +++ b/arch/x86/include/asm/atomic.h @@ -77,7 +77,7 @@ static __always_inline void atomic_sub(int i, atomic_t *v) */ static __always_inline bool atomic_sub_and_test(int i, atomic_t *v) { - GEN_BINARY_RMWcc(LOCK_PREFIX "subl", v->counter, "er", i, "%0", "e"); + GEN_BINARY_RMWcc(LOCK_PREFIX "subl", v->counter, "er", i, "%0", e); } /** @@ -114,7 +114,7 @@ static __always_inline void atomic_dec(atomic_t *v) */ static __always_inline bool atomic_dec_and_test(atomic_t *v) { - GEN_UNARY_RMWcc(LOCK_PREFIX "decl", v->counter, "%0", "e"); + GEN_UNARY_RMWcc(LOCK_PREFIX "decl", v->counter, "%0", e); } /** @@ -127,7 +127,7 @@ static __always_inline bool atomic_dec_and_test(atomic_t *v) */ static __always_inline bool atomic_inc_and_test(atomic_t *v) { - GEN_UNARY_RMWcc(LOCK_PREFIX "incl", v->counter, "%0", "e"); + GEN_UNARY_RMWcc(LOCK_PREFIX "incl", v->counter, "%0", e); } /** @@ -141,7 +141,7 @@ static __always_inline bool atomic_inc_and_test(atomic_t *v) */ static __always_inline bool atomic_add_negative(int i, atomic_t *v) { - GEN_BINARY_RMWcc(LOCK_PREFIX "addl", v->counter, "er", i, "%0", "s"); + GEN_BINARY_RMWcc(LOCK_PREFIX "addl", v->counter, "er", i, "%0", s); } /** diff --git a/arch/x86/include/asm/atomic64_64.h b/arch/x86/include/asm/atomic64_64.h index 4f881d7..57bf925 100644 --- a/arch/x86/include/asm/atomic64_64.h +++ b/arch/x86/include/asm/atomic64_64.h @@ -72,7 +72,7 @@ static inline void atomic64_sub(long i, atomic64_t *v) */ static inline bool atomic64_sub_and_test(long i, atomic64_t *v) { - GEN_BINARY_RMWcc(LOCK_PREFIX "subq", v->counter, "er", i, "%0", "e"); + GEN_BINARY_RMWcc(LOCK_PREFIX "subq", v->counter, "er", i, "%0", e); } /** @@ -111,7 +111,7 @@ static __always_inline void atomic64_dec(atomic64_t *v) */ static inline bool atomic64_dec_and_test(atomic64_t *v) { - GEN_UNARY_RMWcc(LOCK_PREFIX "decq", v->counter, "%0", "e"); + GEN_UNARY_RMWcc(LOCK_PREFIX "decq", v->counter, "%0", e); } /** @@ -124,7 +124,7 @@ static inline bool atomic64_dec_and_test(atomic64_t *v) */ static inline bool atomic64_inc_and_test(atomic64_t *v) { - GEN_UNARY_RMWcc(LOCK_PREFIX "incq", v->counter, "%0", "e"); + GEN_UNARY_RMWcc(LOCK_PREFIX "incq", v->counter, "%0", e); } /** @@ -138,7 +138,7 @@ static inline bool atomic64_inc_and_test(atomic64_t *v) */ static inline bool atomic64_add_negative(long i, atomic64_t *v) { - GEN_BINARY_RMWcc(LOCK_PREFIX "addq", v->counter, "er", i, "%0", "s"); + GEN_BINARY_RMWcc(LOCK_PREFIX "addq", v->counter, "er", i, "%0", s); } /** diff --git a/arch/x86/include/asm/bitops.h b/arch/x86/include/asm/bitops.h index 8cbb7f4..ed8f485 100644 --- a/arch/x86/include/asm/bitops.h +++ b/arch/x86/include/asm/bitops.h @@ -203,7 +203,7 @@ static __always_inline void change_bit(long nr, volatile unsigned long *addr) */ static __always_inline bool test_and_set_bit(long nr, volatile unsigned long *addr) { - GEN_BINARY_RMWcc(LOCK_PREFIX "bts", *addr, "Ir", nr, "%0", "c"); + GEN_BINARY_RMWcc(LOCK_PREFIX "bts", *addr, "Ir", nr, "%0", c); } /** @@ -249,7 +249,7 @@ static __always_inline bool __test_and_set_bit(long nr, volatile unsigned long * */ static __always_inline bool test_and_clear_bit(long nr, volatile unsigned long *addr) { - GEN_BINARY_RMWcc(LOCK_PREFIX "btr", *addr, "Ir", nr, "%0", "c"); + GEN_BINARY_RMWcc(LOCK_PREFIX "btr", *addr, "Ir", nr, "%0", c); } /** @@ -302,7 +302,7 @@ static __always_inline bool __test_and_change_bit(long nr, volatile unsigned lon */ static __always_inline bool test_and_change_bit(long nr, volatile unsigned long *addr) { - GEN_BINARY_RMWcc(LOCK_PREFIX "btc", *addr, "Ir", nr, "%0", "c"); + GEN_BINARY_RMWcc(LOCK_PREFIX "btc", *addr, "Ir", nr, "%0", c); } static __always_inline bool constant_test_bit(long nr, const volatile unsigned long *addr) diff --git a/arch/x86/include/asm/local.h b/arch/x86/include/asm/local.h index 0cdc65b..7511978 100644 --- a/arch/x86/include/asm/local.h +++ b/arch/x86/include/asm/local.h @@ -52,7 +52,7 @@ static inline void local_sub(long i, local_t *l) */ static inline bool local_sub_and_test(long i, local_t *l) { - GEN_BINARY_RMWcc(_ASM_SUB, l->a.counter, "er", i, "%0", "e"); + GEN_BINARY_RMWcc(_ASM_SUB, l->a.counter, "er", i, "%0", e); } /** @@ -65,7 +65,7 @@ static inline bool local_sub_and_test(long i, local_t *l) */ static inline bool local_dec_and_test(local_t *l) { - GEN_UNARY_RMWcc(_ASM_DEC, l->a.counter, "%0", "e"); + GEN_UNARY_RMWcc(_ASM_DEC, l->a.counter, "%0", e); } /** @@ -78,7 +78,7 @@ static inline bool local_dec_and_test(local_t *l) */ static inline bool local_inc_and_test(local_t *l) { - GEN_UNARY_RMWcc(_ASM_INC, l->a.counter, "%0", "e"); + GEN_UNARY_RMWcc(_ASM_INC, l->a.counter, "%0", e); } /** @@ -92,7 +92,7 @@ static inline bool local_inc_and_test(local_t *l) */ static inline bool local_add_negative(long i, local_t *l) { - GEN_BINARY_RMWcc(_ASM_ADD, l->a.counter, "er", i, "%0", "s"); + GEN_BINARY_RMWcc(_ASM_ADD, l->a.counter, "er", i, "%0", s); } /** diff --git a/arch/x86/include/asm/preempt.h b/arch/x86/include/asm/preempt.h index d397deb..17f2186 100644 --- a/arch/x86/include/asm/preempt.h +++ b/arch/x86/include/asm/preempt.h @@ -81,7 +81,7 @@ static __always_inline void __preempt_count_sub(int val) */ static __always_inline bool __preempt_count_dec_and_test(void) { - GEN_UNARY_RMWcc("decl", __preempt_count, __percpu_arg(0), "e"); + GEN_UNARY_RMWcc("decl", __preempt_count, __percpu_arg(0), e); } /* diff --git a/arch/x86/include/asm/rmwcc.h b/arch/x86/include/asm/rmwcc.h index a15b73d..e3264c4 100644 --- a/arch/x86/include/asm/rmwcc.h +++ b/arch/x86/include/asm/rmwcc.h @@ -5,7 +5,7 @@ #define __GEN_RMWcc(fullop, var, cc, ...) \ do { \ - asm_volatile_goto (fullop "; j" cc " %l[cc_label]" \ + asm_volatile_goto (fullop "; j" #cc " %l[cc_label]" \ : : "m" (var), ## __VA_ARGS__ \ : "memory" : cc_label); \ return 0; \ @@ -24,7 +24,7 @@ cc_label: \ #define __GEN_RMWcc(fullop, var, cc, ...) \ do { \ bool c; \ - asm volatile (fullop "; set" cc " %1" \ + asm volatile (fullop "; set" #cc " %1" \ : "+m" (var), "=qm" (c) \ : __VA_ARGS__ : "memory"); \ return c; \ -- cgit v0.10.2 From ff3554b409b82d349f71e9d7082648b7b0a1a5bb Mon Sep 17 00:00:00 2001 From: "H. Peter Anvin" Date: Wed, 8 Jun 2016 12:38:40 -0700 Subject: x86, asm: define CC_SET() and CC_OUT() macros The CC_SET() and CC_OUT() macros can be used together to take advantage of the new __GCC_ASM_FLAG_OUTPUTS__ feature in gcc 6+ while remaining backwards compatible. CC_SET() generates a SET instruction on older compilers; CC_OUT() makes sure the output is received in the correct variable. Signed-off-by: H. Peter Anvin Link: http://lkml.kernel.org/r/1465414726-197858-5-git-send-email-hpa@linux.intel.com Reviewed-by: Andy Lutomirski Reviewed-by: Borislav Petkov Acked-by: Peter Zijlstra (Intel) diff --git a/arch/x86/include/asm/asm.h b/arch/x86/include/asm/asm.h index f5063b6..7acb51c 100644 --- a/arch/x86/include/asm/asm.h +++ b/arch/x86/include/asm/asm.h @@ -42,6 +42,18 @@ #define _ASM_SI __ASM_REG(si) #define _ASM_DI __ASM_REG(di) +/* + * Macros to generate condition code outputs from inline assembly, + * The output operand must be type "bool". + */ +#ifdef __GCC_ASM_FLAG_OUTPUTS__ +# define CC_SET(c) "\n\t/* output condition code " #c "*/\n" +# define CC_OUT(c) "=@cc" #c +#else +# define CC_SET(c) "\n\tset" #c " %[_cc_" #c "]\n" +# define CC_OUT(c) [_cc_ ## c] "=qm" +#endif + /* Exception table entry */ #ifdef __ASSEMBLY__ # define _ASM_EXTABLE_HANDLE(from, to, handler) \ -- cgit v0.10.2 From ba741e356c49bfce0adcfa851080666870867f6b Mon Sep 17 00:00:00 2001 From: "H. Peter Anvin" Date: Wed, 8 Jun 2016 12:38:41 -0700 Subject: x86, asm: change GEN_*_RMWcc() to use CC_SET()/CC_OUT() Change the GEN_*_RMWcc() macros to use the CC_SET()/CC_OUT() macros defined in , and disable the use of asm goto if __GCC_ASM_FLAG_OUTPUTS__ is enabled. This allows gcc to receive the flags output directly in gcc 6+. Signed-off-by: H. Peter Anvin Link: http://lkml.kernel.org/r/1465414726-197858-6-git-send-email-hpa@linux.intel.com Reviewed-by: Andy Lutomirski Reviewed-by: Borislav Petkov Acked-by: Peter Zijlstra (Intel) diff --git a/arch/x86/include/asm/rmwcc.h b/arch/x86/include/asm/rmwcc.h index e3264c4..661dd30 100644 --- a/arch/x86/include/asm/rmwcc.h +++ b/arch/x86/include/asm/rmwcc.h @@ -1,7 +1,9 @@ #ifndef _ASM_X86_RMWcc #define _ASM_X86_RMWcc -#ifdef CC_HAVE_ASM_GOTO +#if !defined(__GCC_ASM_FLAG_OUTPUTS__) && defined(CC_HAVE_ASM_GOTO) + +/* Use asm goto */ #define __GEN_RMWcc(fullop, var, cc, ...) \ do { \ @@ -19,13 +21,15 @@ cc_label: \ #define GEN_BINARY_RMWcc(op, var, vcon, val, arg0, cc) \ __GEN_RMWcc(op " %1, " arg0, var, cc, vcon (val)) -#else /* !CC_HAVE_ASM_GOTO */ +#else /* defined(__GCC_ASM_FLAG_OUTPUTS__) || !defined(CC_HAVE_ASM_GOTO) */ + +/* Use flags output or a set instruction */ #define __GEN_RMWcc(fullop, var, cc, ...) \ do { \ bool c; \ - asm volatile (fullop "; set" #cc " %1" \ - : "+m" (var), "=qm" (c) \ + asm volatile (fullop ";" CC_SET(cc) \ + : "+m" (var), CC_OUT(cc) (c) \ : __VA_ARGS__ : "memory"); \ return c; \ } while (0) @@ -36,6 +40,6 @@ do { \ #define GEN_BINARY_RMWcc(op, var, vcon, val, arg0, cc) \ __GEN_RMWcc(op " %2, " arg0, var, cc, vcon (val)) -#endif /* CC_HAVE_ASM_GOTO */ +#endif /* defined(__GCC_ASM_FLAG_OUTPUTS__) || !defined(CC_HAVE_ASM_GOTO) */ #endif /* _ASM_X86_RMWcc */ -- cgit v0.10.2 From 86b61240d4c233b440cd29daf0baa440daf4a148 Mon Sep 17 00:00:00 2001 From: "H. Peter Anvin" Date: Wed, 8 Jun 2016 12:38:42 -0700 Subject: x86, asm: Use CC_SET()/CC_OUT() in Remove open-coded uses of set instructions to use CC_SET()/CC_OUT() in . Signed-off-by: H. Peter Anvin Link: http://lkml.kernel.org/r/1465414726-197858-7-git-send-email-hpa@linux.intel.com Reviewed-by: Andy Lutomirski Reviewed-by: Borislav Petkov Acked-by: Peter Zijlstra (Intel) diff --git a/arch/x86/include/asm/bitops.h b/arch/x86/include/asm/bitops.h index ed8f485..68557f52 100644 --- a/arch/x86/include/asm/bitops.h +++ b/arch/x86/include/asm/bitops.h @@ -233,8 +233,8 @@ static __always_inline bool __test_and_set_bit(long nr, volatile unsigned long * bool oldbit; asm("bts %2,%1\n\t" - "setc %0" - : "=qm" (oldbit), ADDR + CC_SET(c) + : CC_OUT(c) (oldbit), ADDR : "Ir" (nr)); return oldbit; } @@ -273,8 +273,8 @@ static __always_inline bool __test_and_clear_bit(long nr, volatile unsigned long bool oldbit; asm volatile("btr %2,%1\n\t" - "setc %0" - : "=qm" (oldbit), ADDR + CC_SET(c) + : CC_OUT(c) (oldbit), ADDR : "Ir" (nr)); return oldbit; } @@ -285,8 +285,8 @@ static __always_inline bool __test_and_change_bit(long nr, volatile unsigned lon bool oldbit; asm volatile("btc %2,%1\n\t" - "setc %0" - : "=qm" (oldbit), ADDR + CC_SET(c) + : CC_OUT(c) (oldbit), ADDR : "Ir" (nr) : "memory"); return oldbit; @@ -316,8 +316,8 @@ static __always_inline bool variable_test_bit(long nr, volatile const unsigned l bool oldbit; asm volatile("bt %2,%1\n\t" - "setc %0" - : "=qm" (oldbit) + CC_SET(c) + : CC_OUT(c) (oldbit) : "m" (*(unsigned long *)addr), "Ir" (nr)); return oldbit; -- cgit v0.10.2 From 64be6d36f5674f3424d1901772f76e21874f4954 Mon Sep 17 00:00:00 2001 From: "H. Peter Anvin" Date: Wed, 8 Jun 2016 12:38:43 -0700 Subject: x86, asm: Use CC_SET()/CC_OUT() in Remove open-coded uses of set instructions to use CC_SET()/CC_OUT() in . Signed-off-by: H. Peter Anvin Link: http://lkml.kernel.org/r/1465414726-197858-8-git-send-email-hpa@linux.intel.com Reviewed-by: Andy Lutomirski Reviewed-by: Borislav Petkov Acked-by: Peter Zijlstra (Intel) diff --git a/arch/x86/include/asm/percpu.h b/arch/x86/include/asm/percpu.h index 184d7f3..e02e3f8 100644 --- a/arch/x86/include/asm/percpu.h +++ b/arch/x86/include/asm/percpu.h @@ -511,8 +511,9 @@ do { \ #define x86_test_and_clear_bit_percpu(bit, var) \ ({ \ bool old__; \ - asm volatile("btr %2,"__percpu_arg(1)"\n\tsetc %0" \ - : "=qm" (old__), "+m" (var) \ + asm volatile("btr %2,"__percpu_arg(1)"\n\t" \ + CC_SET(c) \ + : CC_OUT(c) (old__), "+m" (var) \ : "dIr" (bit)); \ old__; \ }) @@ -535,8 +536,8 @@ static inline bool x86_this_cpu_variable_test_bit(int nr, bool oldbit; asm volatile("bt "__percpu_arg(2)",%1\n\t" - "setc %0" - : "=qm" (oldbit) + CC_SET(c) + : CC_OUT(c) (oldbit) : "m" (*(unsigned long *)addr), "Ir" (nr)); return oldbit; -- cgit v0.10.2 From 35ccfb7114e2f0f454f264c049b03c31f4c6bbc0 Mon Sep 17 00:00:00 2001 From: "H. Peter Anvin" Date: Wed, 8 Jun 2016 12:38:44 -0700 Subject: x86, asm: Use CC_SET()/CC_OUT() in Remove open-coded uses of set instructions to use CC_SET()/CC_OUT() in . Signed-off-by: H. Peter Anvin Link: http://lkml.kernel.org/r/1465414726-197858-9-git-send-email-hpa@linux.intel.com Reviewed-by: Andy Lutomirski Reviewed-by: Borislav Petkov Acked-by: Peter Zijlstra (Intel) diff --git a/arch/x86/include/asm/rwsem.h b/arch/x86/include/asm/rwsem.h index c508770..1e8be26 100644 --- a/arch/x86/include/asm/rwsem.h +++ b/arch/x86/include/asm/rwsem.h @@ -149,10 +149,10 @@ static inline bool __down_write_trylock(struct rw_semaphore *sem) LOCK_PREFIX " cmpxchg %2,%0\n\t" " jnz 1b\n\t" "2:\n\t" - " sete %3\n\t" + CC_SET(e) "# ending __down_write_trylock\n\t" : "+m" (sem->count), "=&a" (tmp0), "=&r" (tmp1), - "=qm" (result) + CC_OUT(e) (result) : "er" (RWSEM_ACTIVE_WRITE_BIAS) : "memory", "cc"); return result; -- cgit v0.10.2 From 66928b4eb92dfb6d87c204238057b9278b36452b Mon Sep 17 00:00:00 2001 From: "H. Peter Anvin" Date: Wed, 8 Jun 2016 12:38:45 -0700 Subject: x86, asm, boot: Use CC_SET()/CC_OUT() in arch/x86/boot/boot.h Remove open-coded uses of set instructions to use CC_SET()/CC_OUT() in arch/x86/boot/boot.h. Signed-off-by: H. Peter Anvin Link: http://lkml.kernel.org/r/1465414726-197858-10-git-send-email-hpa@linux.intel.com Reviewed-by: Andy Lutomirski Reviewed-by: Borislav Petkov Acked-by: Peter Zijlstra (Intel) diff --git a/arch/x86/boot/boot.h b/arch/x86/boot/boot.h index 2edb2d5..7c1495f 100644 --- a/arch/x86/boot/boot.h +++ b/arch/x86/boot/boot.h @@ -24,6 +24,7 @@ #include #include #include +#include #include "bitops.h" #include "ctype.h" #include "cpuflags.h" @@ -179,15 +180,15 @@ static inline void wrgs32(u32 v, addr_t addr) static inline bool memcmp_fs(const void *s1, addr_t s2, size_t len) { bool diff; - asm volatile("fs; repe; cmpsb; setnz %0" - : "=qm" (diff), "+D" (s1), "+S" (s2), "+c" (len)); + asm volatile("fs; repe; cmpsb" CC_SET(nz) + : CC_OUT(nz) (diff), "+D" (s1), "+S" (s2), "+c" (len)); return diff; } static inline bool memcmp_gs(const void *s1, addr_t s2, size_t len) { bool diff; - asm volatile("gs; repe; cmpsb; setnz %0" - : "=qm" (diff), "+D" (s1), "+S" (s2), "+c" (len)); + asm volatile("gs; repe; cmpsb" CC_SET(nz) + : CC_OUT(nz) (diff), "+D" (s1), "+S" (s2), "+c" (len)); return diff; } -- cgit v0.10.2 From 3b290398638ee4e57f1fb2e35c02005cba9a737f Mon Sep 17 00:00:00 2001 From: "H. Peter Anvin" Date: Wed, 8 Jun 2016 12:38:46 -0700 Subject: x86, asm: Use CC_SET()/CC_OUT() and static_cpu_has() in archrandom.h Use CC_SET()/CC_OUT() and static_cpu_has(). This produces code good enough to eliminate ad hoc use of alternatives in , greatly simplifying the code. While we are at it, make x86_init_rdrand() compile out completely if we don't need it. Signed-off-by: H. Peter Anvin Link: http://lkml.kernel.org/r/1465414726-197858-11-git-send-email-hpa@linux.intel.com v2: fix a conflict between and discovered by Ingo Molnar. There are a few places in x86-specific code where we need all of even when CONFIG_ARCH_RANDOM is disabled, so does not suffice. diff --git a/arch/x86/include/asm/archrandom.h b/arch/x86/include/asm/archrandom.h index ab6f599..5b0579a 100644 --- a/arch/x86/include/asm/archrandom.h +++ b/arch/x86/include/asm/archrandom.h @@ -25,8 +25,6 @@ #include #include -#include -#include #define RDRAND_RETRY_LOOPS 10 @@ -40,97 +38,91 @@ # define RDSEED_LONG RDSEED_INT #endif -#ifdef CONFIG_ARCH_RANDOM +/* Unconditional execution of RDRAND and RDSEED */ -/* Instead of arch_get_random_long() when alternatives haven't run. */ static inline bool rdrand_long(unsigned long *v) { - int ok; - asm volatile("1: " RDRAND_LONG "\n\t" - "jc 2f\n\t" - "decl %0\n\t" - "jnz 1b\n\t" - "2:" - : "=r" (ok), "=a" (*v) - : "0" (RDRAND_RETRY_LOOPS)); - return !!ok; + bool ok; + unsigned int retry = RDRAND_RETRY_LOOPS; + do { + asm volatile(RDRAND_LONG "\n\t" + CC_SET(c) + : CC_OUT(c) (ok), "=a" (*v)); + if (ok) + return true; + } while (--retry); + return false; +} + +static inline bool rdrand_int(unsigned int *v) +{ + bool ok; + unsigned int retry = RDRAND_RETRY_LOOPS; + do { + asm volatile(RDRAND_INT "\n\t" + CC_SET(c) + : CC_OUT(c) (ok), "=a" (*v)); + if (ok) + return true; + } while (--retry); + return false; } -/* A single attempt at RDSEED */ static inline bool rdseed_long(unsigned long *v) { bool ok; asm volatile(RDSEED_LONG "\n\t" - "setc %0" - : "=qm" (ok), "=a" (*v)); + CC_SET(c) + : CC_OUT(c) (ok), "=a" (*v)); return ok; } -#define GET_RANDOM(name, type, rdrand, nop) \ -static inline bool name(type *v) \ -{ \ - int ok; \ - alternative_io("movl $0, %0\n\t" \ - nop, \ - "\n1: " rdrand "\n\t" \ - "jc 2f\n\t" \ - "decl %0\n\t" \ - "jnz 1b\n\t" \ - "2:", \ - X86_FEATURE_RDRAND, \ - ASM_OUTPUT2("=r" (ok), "=a" (*v)), \ - "0" (RDRAND_RETRY_LOOPS)); \ - return !!ok; \ -} - -#define GET_SEED(name, type, rdseed, nop) \ -static inline bool name(type *v) \ -{ \ - bool ok; \ - alternative_io("movb $0, %0\n\t" \ - nop, \ - rdseed "\n\t" \ - "setc %0", \ - X86_FEATURE_RDSEED, \ - ASM_OUTPUT2("=q" (ok), "=a" (*v))); \ - return ok; \ +static inline bool rdseed_int(unsigned int *v) +{ + bool ok; + asm volatile(RDSEED_INT "\n\t" + CC_SET(c) + : CC_OUT(c) (ok), "=a" (*v)); + return ok; } -#ifdef CONFIG_X86_64 - -GET_RANDOM(arch_get_random_long, unsigned long, RDRAND_LONG, ASM_NOP5); -GET_RANDOM(arch_get_random_int, unsigned int, RDRAND_INT, ASM_NOP4); - -GET_SEED(arch_get_random_seed_long, unsigned long, RDSEED_LONG, ASM_NOP5); -GET_SEED(arch_get_random_seed_int, unsigned int, RDSEED_INT, ASM_NOP4); - -#else - -GET_RANDOM(arch_get_random_long, unsigned long, RDRAND_LONG, ASM_NOP3); -GET_RANDOM(arch_get_random_int, unsigned int, RDRAND_INT, ASM_NOP3); - -GET_SEED(arch_get_random_seed_long, unsigned long, RDSEED_LONG, ASM_NOP4); -GET_SEED(arch_get_random_seed_int, unsigned int, RDSEED_INT, ASM_NOP4); - -#endif /* CONFIG_X86_64 */ - +/* Conditional execution based on CPU type */ #define arch_has_random() static_cpu_has(X86_FEATURE_RDRAND) #define arch_has_random_seed() static_cpu_has(X86_FEATURE_RDSEED) -#else +/* + * These are the generic interfaces; they must not be declared if the + * stubs in are to be invoked, + * i.e. CONFIG_ARCH_RANDOM is not defined. + */ +#ifdef CONFIG_ARCH_RANDOM -static inline bool rdrand_long(unsigned long *v) +static inline bool arch_get_random_long(unsigned long *v) { - return 0; + return arch_has_random() ? rdrand_long(v) : false; } -static inline bool rdseed_long(unsigned long *v) +static inline bool arch_get_random_int(unsigned int *v) { - return 0; + return arch_has_random() ? rdrand_int(v) : false; } -#endif /* CONFIG_ARCH_RANDOM */ +static inline bool arch_get_random_seed_long(unsigned long *v) +{ + return arch_has_random_seed() ? rdseed_long(v) : false; +} + +static inline bool arch_get_random_seed_int(unsigned int *v) +{ + return arch_has_random_seed() ? rdseed_int(v) : false; +} extern void x86_init_rdrand(struct cpuinfo_x86 *c); +#else /* !CONFIG_ARCH_RANDOM */ + +static inline void x86_init_rdrand(struct cpuinfo_x86 *c) { } + +#endif /* !CONFIG_ARCH_RANDOM */ + #endif /* ASM_X86_ARCHRANDOM_H */ diff --git a/arch/x86/kernel/cpu/rdrand.c b/arch/x86/kernel/cpu/rdrand.c index f6f50c4..cfa97ff 100644 --- a/arch/x86/kernel/cpu/rdrand.c +++ b/arch/x86/kernel/cpu/rdrand.c @@ -39,9 +39,9 @@ __setup("nordrand", x86_rdrand_setup); */ #define SANITY_CHECK_LOOPS 8 +#ifdef CONFIG_ARCH_RANDOM void x86_init_rdrand(struct cpuinfo_x86 *c) { -#ifdef CONFIG_ARCH_RANDOM unsigned long tmp; int i; @@ -55,5 +55,5 @@ void x86_init_rdrand(struct cpuinfo_x86 *c) return; } } -#endif } +#endif -- cgit v0.10.2 From d4c3be70ca0e7a1ae308bedd3462900c61e97b11 Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Thu, 9 Jun 2016 12:20:25 +0200 Subject: MAINTAINERS: Update locking tree description and file patterns Update the file patterns, the Git tree URI and also widen the scope from 'LOCKDEP and LOCKSTAT' to 'LOCKING PRIMITIVES'. Signed-off-by: Ingo Molnar Cc: Peter Zijlstra Cc: Linus Torvalds Cc: Andrew Morton Cc: Thomas Gleixner Cc: Paul E. McKenney Cc: linux-kernel@vger.kernel.org diff --git a/MAINTAINERS b/MAINTAINERS index ed42cb6..daa85ac 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -7006,15 +7006,23 @@ Q: http://patchwork.linuxtv.org/project/linux-media/list/ S: Maintained F: drivers/media/usb/dvb-usb-v2/lmedm04* -LOCKDEP AND LOCKSTAT +LOCKING PRIMITIVES M: Peter Zijlstra M: Ingo Molnar L: linux-kernel@vger.kernel.org -T: git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git core/locking +T: git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git locking/core S: Maintained -F: Documentation/locking/lockdep*.txt -F: Documentation/locking/lockstat.txt +F: Documentation/locking/ F: include/linux/lockdep.h +F: include/linux/spinlock*.h +F: arch/*/include/asm/spinlock*.h +F: include/linux/rwlock*.h +F: include/linux/mutex*.h +F: arch/*/include/asm/mutex*.h +F: include/linux/rwsem*.h +F: arch/*/include/asm/rwsem.h +F: include/linux/seqlock.h +F: lib/locking*.[ch] F: kernel/locking/ LOGICAL DISK MANAGER SUPPORT (LDM, Windows 2000/XP/Vista Dynamic Disks) -- cgit v0.10.2 From 2895a5e5b3ae78d9923a91fce405d4a2f32c4309 Mon Sep 17 00:00:00 2001 From: Eric Caruso Date: Wed, 8 Jun 2016 16:08:59 -0700 Subject: timerfd: Reject ALARM timerfds without CAP_WAKE_ALARM timerfd gives processes a way to set wake alarms, but unlike timers made using timer_create, timerfds don't check whether the process has CAP_WAKE_ALARM before setting alarm-time timers. CAP_WAKE_ALARM is supposed to gate this behavior and so it makes sense that we should deny permission to create such timerfds if the process doesn't have this capability. Signed-off-by: Eric Caruso Cc: Todd Poynor Link: http://lkml.kernel.org/r/1465427339-96209-1-git-send-email-ejcaruso@chromium.org Signed-off-by: Thomas Gleixner diff --git a/fs/timerfd.c b/fs/timerfd.c index 053818d..9ae4abb 100644 --- a/fs/timerfd.c +++ b/fs/timerfd.c @@ -390,6 +390,11 @@ SYSCALL_DEFINE2(timerfd_create, int, clockid, int, flags) clockid != CLOCK_BOOTTIME_ALARM)) return -EINVAL; + if (!capable(CAP_WAKE_ALARM) && + (clockid == CLOCK_REALTIME_ALARM || + clockid == CLOCK_BOOTTIME_ALARM)) + return -EPERM; + ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); if (!ctx) return -ENOMEM; @@ -433,6 +438,11 @@ static int do_timerfd_settime(int ufd, int flags, return ret; ctx = f.file->private_data; + if (!capable(CAP_WAKE_ALARM) && isalarm(ctx)) { + fdput(f); + return -EPERM; + } + timerfd_setup_cancel(ctx, flags); /* -- cgit v0.10.2 From b5227d03b7191a9a44bf75a4c228a6a9ddbe781b Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Tue, 31 May 2016 16:23:02 -0500 Subject: timers: Clarify usleep_range() function comment Update the usleep_range() function comment to make it clear that it can only be used in non-atomic context. Previously we claimed usleep_range() was a drop-in replacement for udelay() where wakeup is flexible. But that's only true in non-atomic contexts, where it's possible to sleep instead of delay. Signed-off-by: Bjorn Helgaas Cc: John Stultz Link: http://lkml.kernel.org/r/20160531212302.28502.44995.stgit@bhelgaas-glaptop2.roam.corp.google.com Signed-off-by: Thomas Gleixner diff --git a/kernel/time/timer.c b/kernel/time/timer.c index 3a95f97..67dd610 100644 --- a/kernel/time/timer.c +++ b/kernel/time/timer.c @@ -1702,9 +1702,15 @@ static void __sched do_usleep_range(unsigned long min, unsigned long max) } /** - * usleep_range - Drop in replacement for udelay where wakeup is flexible + * usleep_range - Sleep for an approximate time * @min: Minimum time in usecs to sleep * @max: Maximum time in usecs to sleep + * + * In non-atomic context where the exact wakeup time is flexible, use + * usleep_range() instead of udelay(). The sleep improves responsiveness + * by avoiding the CPU-hogging busy-wait of udelay(), and the range reduces + * power usage by allowing hrtimers to take advantage of an already- + * scheduled interrupt instead of scheduling a new one just for this sleep. */ void __sched usleep_range(unsigned long min, unsigned long max) { -- cgit v0.10.2 From 0145071b33142cbccffb51486b1ce921677b1d2d Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Thu, 2 Jun 2016 14:20:18 +0200 Subject: x86: Do away with ARCH_[WANT_OPTIONAL|REQUIRE]_GPIOLIB MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This replaces: - "select ARCH_REQUIRE_GPIOLIB" with "select GPIOLIB" as this can now be selected directly. - "select ARCH_WANT_OPTIONAL_GPIOLIB" with no dependency: GPIOLIB is now selectable by everyone, so we need not declare our intent to select it. When ordering the symbols the following rationale was used: if the selects were in alphabetical order, I moved select GPIOLIB to be in alphabetical order, but if the selects were not maintained in alphabetical order, I just replaced "select ARCH_REQUIRE_GPIOLIB" with "select GPIOLIB". Signed-off-by: Linus Walleij Cc: Michael Büsch Link: http://lkml.kernel.org/r/1464870018-8281-1-git-send-email-linus.walleij@linaro.org Signed-off-by: Thomas Gleixner diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 0a7b885..607382b 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -49,7 +49,6 @@ config X86 select ARCH_WANTS_DYNAMIC_TASK_STRUCT select ARCH_WANT_FRAME_POINTERS select ARCH_WANT_IPC_PARSE_VERSION if X86_32 - select ARCH_WANT_OPTIONAL_GPIOLIB select BUILDTIME_EXTABLE_SORT select CLKEVT_I8253 select CLKSRC_I8253 if X86_32 @@ -643,7 +642,7 @@ config STA2X11 select X86_DMA_REMAP select SWIOTLB select MFD_STA2X11 - select ARCH_REQUIRE_GPIOLIB + select GPIOLIB default n ---help--- This adds support for boards based on the STA2X11 IO-Hub, -- cgit v0.10.2 From 67b1a24e883c8ca716ca3524b2ca1ca5579a48be Mon Sep 17 00:00:00 2001 From: James Simmons Date: Wed, 8 Jun 2016 18:50:12 -0400 Subject: staging: lustre: llite: remove lloop device The lloop device was original developed to work around the lack of direct I/O for the default loop back device. Also the lloop device greatly out performed the default loop back device. The lloop hasn't been worked on for some time and now it no longer out performs the loop device and loop now supports direct I/O. Since this is the case we can delete this device. Signed-off-by: James Simmons Reviewed-by: Andreas Dilger Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/lustre/lustre/Kconfig b/drivers/staging/lustre/lustre/Kconfig index 8ac7cd4..9f5d75f 100644 --- a/drivers/staging/lustre/lustre/Kconfig +++ b/drivers/staging/lustre/lustre/Kconfig @@ -54,9 +54,3 @@ config LUSTRE_TRANSLATE_ERRNOS bool depends on LUSTRE_FS && !X86 default y - -config LUSTRE_LLITE_LLOOP - tristate "Lustre virtual block device" - depends on LUSTRE_FS && BLOCK - depends on !PPC_64K_PAGES && !ARM64_64K_PAGES && !MICROBLAZE_64K_PAGES && !PAGE_SIZE_64KB && !IA64_PAGE_SIZE_64KB && !PARISC_PAGE_SIZE_64KB - default m diff --git a/drivers/staging/lustre/lustre/llite/Makefile b/drivers/staging/lustre/lustre/llite/Makefile index 2ce10ff..19701e7 100644 --- a/drivers/staging/lustre/lustre/llite/Makefile +++ b/drivers/staging/lustre/lustre/llite/Makefile @@ -1,5 +1,4 @@ obj-$(CONFIG_LUSTRE_FS) += lustre.o -obj-$(CONFIG_LUSTRE_LLITE_LLOOP) += llite_lloop.o lustre-y := dcache.o dir.o file.o llite_close.o llite_lib.o llite_nfs.o \ rw.o namei.o symlink.o llite_mmap.o \ xattr.o xattr_cache.o remote_perm.o llite_rmtacl.o \ @@ -7,5 +6,3 @@ lustre-y := dcache.o dir.o file.o llite_close.o llite_lib.o llite_nfs.o \ glimpse.o lcommon_cl.o lcommon_misc.o \ vvp_dev.o vvp_page.o vvp_lock.o vvp_io.o vvp_object.o vvp_req.o \ lproc_llite.o - -llite_lloop-y := lloop.o diff --git a/drivers/staging/lustre/lustre/llite/lloop.c b/drivers/staging/lustre/lustre/llite/lloop.c deleted file mode 100644 index 813a9a3..0000000 --- a/drivers/staging/lustre/lustre/llite/lloop.c +++ /dev/null @@ -1,883 +0,0 @@ -/* - * GPL HEADER START - * - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 only, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License version 2 for more details (a copy is included - * in the LICENSE file that accompanied this code). - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf - * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * - * GPL HEADER END - */ -/* - * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. - * Use is subject to license terms. - * - * Copyright (c) 2011, 2012, Intel Corporation. - */ -/* - * This file is part of Lustre, http://www.lustre.org/ - * Lustre is a trademark of Sun Microsystems, Inc. - */ - -/* - * linux/drivers/block/loop.c - * - * Written by Theodore Ts'o, 3/29/93 - * - * Copyright 1993 by Theodore Ts'o. Redistribution of this file is - * permitted under the GNU General Public License. - * - * Modularized and updated for 1.1.16 kernel - Mitch Dsouza 28th May 1994 - * Adapted for 1.3.59 kernel - Andries Brouwer, 1 Feb 1996 - * - * Fixed do_loop_request() re-entrancy - Vincent.Renardias@waw.com Mar 20, 1997 - * - * Added devfs support - Richard Gooch 16-Jan-1998 - * - * Handle sparse backing files correctly - Kenn Humborg, Jun 28, 1998 - * - * Loadable modules and other fixes by AK, 1998 - * - * Maximum number of loop devices now dynamic via max_loop module parameter. - * Russell Kroll 19990701 - * - * Maximum number of loop devices when compiled-in now selectable by passing - * max_loop=<1-255> to the kernel on boot. - * Erik I. Bols?, , Oct 31, 1999 - * - * Completely rewrite request handling to be make_request_fn style and - * non blocking, pushing work to a helper thread. Lots of fixes from - * Al Viro too. - * Jens Axboe , Nov 2000 - * - * Support up to 256 loop devices - * Heinz Mauelshagen , Feb 2002 - * - * Support for falling back on the write file operation when the address space - * operations prepare_write and/or commit_write are not available on the - * backing filesystem. - * Anton Altaparmakov, 16 Feb 2005 - * - * Still To Fix: - * - Advisory locking is ignored here. - * - Should use an own CAP_* category instead of CAP_SYS_ADMIN - * - */ - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include /* for invalidate_bdev() */ -#include -#include -#include -#include -#include - -#include "../include/lustre_lib.h" -#include "../include/lustre_lite.h" -#include "llite_internal.h" - -#define LLOOP_MAX_SEGMENTS LNET_MAX_IOV - -/* Possible states of device */ -enum { - LLOOP_UNBOUND, - LLOOP_BOUND, - LLOOP_RUNDOWN, -}; - -struct lloop_device { - int lo_number; - int lo_refcnt; - loff_t lo_offset; - loff_t lo_sizelimit; - int lo_flags; - struct file *lo_backing_file; - struct block_device *lo_device; - unsigned lo_blocksize; - - gfp_t old_gfp_mask; - - spinlock_t lo_lock; - struct bio *lo_bio; - struct bio *lo_biotail; - int lo_state; - struct semaphore lo_sem; - struct mutex lo_ctl_mutex; - atomic_t lo_pending; - wait_queue_head_t lo_bh_wait; - - struct request_queue *lo_queue; - - const struct lu_env *lo_env; - struct cl_io lo_io; - struct ll_dio_pages lo_pvec; - - /* data to handle bio for lustre. */ - struct lo_request_data { - struct page *lrd_pages[LLOOP_MAX_SEGMENTS]; - loff_t lrd_offsets[LLOOP_MAX_SEGMENTS]; - } lo_requests[1]; -}; - -/* - * Loop flags - */ -enum { - LO_FLAGS_READ_ONLY = 1, -}; - -static int lloop_major; -#define MAX_LOOP_DEFAULT 16 -static int max_loop = MAX_LOOP_DEFAULT; -static struct lloop_device *loop_dev; -static struct gendisk **disks; -static struct mutex lloop_mutex; -static void *ll_iocontrol_magic; - -static loff_t get_loop_size(struct lloop_device *lo, struct file *file) -{ - loff_t size, offset, loopsize; - - /* Compute loopsize in bytes */ - size = i_size_read(file->f_mapping->host); - offset = lo->lo_offset; - loopsize = size - offset; - if (lo->lo_sizelimit > 0 && lo->lo_sizelimit < loopsize) - loopsize = lo->lo_sizelimit; - - /* - * Unfortunately, if we want to do I/O on the device, - * the number of 512-byte sectors has to fit into a sector_t. - */ - return loopsize >> 9; -} - -static int do_bio_lustrebacked(struct lloop_device *lo, struct bio *head) -{ - const struct lu_env *env = lo->lo_env; - struct cl_io *io = &lo->lo_io; - struct inode *inode = file_inode(lo->lo_backing_file); - struct cl_object *obj = ll_i2info(inode)->lli_clob; - pgoff_t offset; - int ret; - int rw; - u32 page_count = 0; - struct bio_vec bvec; - struct bvec_iter iter; - struct bio *bio; - ssize_t bytes; - - struct ll_dio_pages *pvec = &lo->lo_pvec; - struct page **pages = pvec->ldp_pages; - loff_t *offsets = pvec->ldp_offsets; - - truncate_inode_pages(inode->i_mapping, 0); - - /* initialize the IO */ - memset(io, 0, sizeof(*io)); - io->ci_obj = obj; - ret = cl_io_init(env, io, CIT_MISC, obj); - if (ret) - return io->ci_result; - io->ci_lockreq = CILR_NEVER; - - rw = head->bi_rw; - for (bio = head; bio ; bio = bio->bi_next) { - LASSERT(rw == bio->bi_rw); - - offset = (pgoff_t)(bio->bi_iter.bi_sector << 9) + lo->lo_offset; - bio_for_each_segment(bvec, bio, iter) { - BUG_ON(bvec.bv_offset != 0); - BUG_ON(bvec.bv_len != PAGE_SIZE); - - pages[page_count] = bvec.bv_page; - offsets[page_count] = offset; - page_count++; - offset += bvec.bv_len; - } - LASSERT(page_count <= LLOOP_MAX_SEGMENTS); - } - - ll_stats_ops_tally(ll_i2sbi(inode), - (rw == WRITE) ? LPROC_LL_BRW_WRITE : LPROC_LL_BRW_READ, - page_count); - - pvec->ldp_size = page_count << PAGE_SHIFT; - pvec->ldp_nr = page_count; - - /* FIXME: in ll_direct_rw_pages, it has to allocate many cl_page{}s to - * write those pages into OST. Even worse case is that more pages - * would be asked to write out to swap space, and then finally get here - * again. - * Unfortunately this is NOT easy to fix. - * Thoughts on solution: - * 0. Define a reserved pool for cl_pages, which could be a list of - * pre-allocated cl_pages; - * 1. Define a new operation in cl_object_operations{}, says clo_depth, - * which measures how many layers for this lustre object. Generally - * speaking, the depth would be 2, one for llite, and one for lovsub. - * However, for SNS, there will be more since we need additional page - * to store parity; - * 2. Reserve the # of (page_count * depth) cl_pages from the reserved - * pool. Afterwards, the clio would allocate the pages from reserved - * pool, this guarantees we needn't allocate the cl_pages from - * generic cl_page slab cache. - * Of course, if there is NOT enough pages in the pool, we might - * be asked to write less pages once, this purely depends on - * implementation. Anyway, we should be careful to avoid deadlocking. - */ - inode_lock(inode); - bytes = ll_direct_rw_pages(env, io, rw, inode, pvec); - inode_unlock(inode); - cl_io_fini(env, io); - return (bytes == pvec->ldp_size) ? 0 : (int)bytes; -} - -/* - * Add bio to back of pending list - */ -static void loop_add_bio(struct lloop_device *lo, struct bio *bio) -{ - unsigned long flags; - - spin_lock_irqsave(&lo->lo_lock, flags); - if (lo->lo_biotail) { - lo->lo_biotail->bi_next = bio; - lo->lo_biotail = bio; - } else { - lo->lo_bio = lo->lo_biotail = bio; - } - spin_unlock_irqrestore(&lo->lo_lock, flags); - - atomic_inc(&lo->lo_pending); - if (waitqueue_active(&lo->lo_bh_wait)) - wake_up(&lo->lo_bh_wait); -} - -/* - * Grab first pending buffer - */ -static unsigned int loop_get_bio(struct lloop_device *lo, struct bio **req) -{ - struct bio *first; - struct bio **bio; - unsigned int count = 0; - unsigned int page_count = 0; - int rw; - - spin_lock_irq(&lo->lo_lock); - first = lo->lo_bio; - if (unlikely(!first)) { - spin_unlock_irq(&lo->lo_lock); - return 0; - } - - /* TODO: need to split the bio, too bad. */ - LASSERT(first->bi_vcnt <= LLOOP_MAX_SEGMENTS); - - rw = first->bi_rw; - bio = &lo->lo_bio; - while (*bio && (*bio)->bi_rw == rw) { - CDEBUG(D_INFO, "bio sector %llu size %u count %u vcnt%u\n", - (unsigned long long)(*bio)->bi_iter.bi_sector, - (*bio)->bi_iter.bi_size, - page_count, (*bio)->bi_vcnt); - if (page_count + (*bio)->bi_vcnt > LLOOP_MAX_SEGMENTS) - break; - - page_count += (*bio)->bi_vcnt; - count++; - bio = &(*bio)->bi_next; - } - if (*bio) { - /* Some of bios can't be mergeable. */ - lo->lo_bio = *bio; - *bio = NULL; - } else { - /* Hit the end of queue */ - lo->lo_biotail = NULL; - lo->lo_bio = NULL; - } - *req = first; - spin_unlock_irq(&lo->lo_lock); - return count; -} - -static blk_qc_t loop_make_request(struct request_queue *q, struct bio *old_bio) -{ - struct lloop_device *lo = q->queuedata; - int rw = bio_rw(old_bio); - int inactive; - - blk_queue_split(q, &old_bio, q->bio_split); - - if (!lo) - goto err; - - CDEBUG(D_INFO, "submit bio sector %llu size %u\n", - (unsigned long long)old_bio->bi_iter.bi_sector, - old_bio->bi_iter.bi_size); - - spin_lock_irq(&lo->lo_lock); - inactive = lo->lo_state != LLOOP_BOUND; - spin_unlock_irq(&lo->lo_lock); - if (inactive) - goto err; - - if (rw == WRITE) { - if (lo->lo_flags & LO_FLAGS_READ_ONLY) - goto err; - } else if (rw == READA) { - rw = READ; - } else if (rw != READ) { - CERROR("lloop: unknown command (%x)\n", rw); - goto err; - } - loop_add_bio(lo, old_bio); - return BLK_QC_T_NONE; -err: - bio_io_error(old_bio); - return BLK_QC_T_NONE; -} - -static inline void loop_handle_bio(struct lloop_device *lo, struct bio *bio) -{ - int ret; - - ret = do_bio_lustrebacked(lo, bio); - while (bio) { - struct bio *tmp = bio->bi_next; - - bio->bi_next = NULL; - bio->bi_error = ret; - bio_endio(bio); - bio = tmp; - } -} - -static inline int loop_active(struct lloop_device *lo) -{ - return atomic_read(&lo->lo_pending) || - (lo->lo_state == LLOOP_RUNDOWN); -} - -/* - * worker thread that handles reads/writes to file backed loop devices, - * to avoid blocking in our make_request_fn. - */ -static int loop_thread(void *data) -{ - struct lloop_device *lo = data; - struct bio *bio; - unsigned int count; - unsigned long times = 0; - unsigned long total_count = 0; - - struct lu_env *env; - int refcheck; - int ret = 0; - - set_user_nice(current, MIN_NICE); - - lo->lo_state = LLOOP_BOUND; - - env = cl_env_get(&refcheck); - if (IS_ERR(env)) { - ret = PTR_ERR(env); - goto out; - } - - lo->lo_env = env; - memset(&lo->lo_pvec, 0, sizeof(lo->lo_pvec)); - lo->lo_pvec.ldp_pages = lo->lo_requests[0].lrd_pages; - lo->lo_pvec.ldp_offsets = lo->lo_requests[0].lrd_offsets; - - /* - * up sem, we are running - */ - up(&lo->lo_sem); - - for (;;) { - wait_event(lo->lo_bh_wait, loop_active(lo)); - if (!atomic_read(&lo->lo_pending)) { - int exiting = 0; - - spin_lock_irq(&lo->lo_lock); - exiting = (lo->lo_state == LLOOP_RUNDOWN); - spin_unlock_irq(&lo->lo_lock); - if (exiting) - break; - } - - bio = NULL; - count = loop_get_bio(lo, &bio); - if (!count) { - CWARN("lloop(minor: %d): missing bio\n", lo->lo_number); - continue; - } - - total_count += count; - if (total_count < count) { /* overflow */ - total_count = count; - times = 1; - } else { - times++; - } - if ((times & 127) == 0) { - CDEBUG(D_INFO, "total: %lu, count: %lu, avg: %lu\n", - total_count, times, total_count / times); - } - - LASSERT(bio); - LASSERT(count <= atomic_read(&lo->lo_pending)); - loop_handle_bio(lo, bio); - atomic_sub(count, &lo->lo_pending); - } - cl_env_put(env, &refcheck); - -out: - up(&lo->lo_sem); - return ret; -} - -static int loop_set_fd(struct lloop_device *lo, struct file *unused, - struct block_device *bdev, struct file *file) -{ - struct inode *inode; - struct address_space *mapping; - int lo_flags = 0; - int error; - loff_t size; - - if (!try_module_get(THIS_MODULE)) - return -ENODEV; - - error = -EBUSY; - if (lo->lo_state != LLOOP_UNBOUND) - goto out; - - mapping = file->f_mapping; - inode = mapping->host; - - error = -EINVAL; - if (!S_ISREG(inode->i_mode) || inode->i_sb->s_magic != LL_SUPER_MAGIC) - goto out; - - if (!(file->f_mode & FMODE_WRITE)) - lo_flags |= LO_FLAGS_READ_ONLY; - - size = get_loop_size(lo, file); - - if ((loff_t)(sector_t)size != size) { - error = -EFBIG; - goto out; - } - - /* remove all pages in cache so as dirty pages not to be existent. */ - truncate_inode_pages(mapping, 0); - - set_device_ro(bdev, (lo_flags & LO_FLAGS_READ_ONLY) != 0); - - lo->lo_blocksize = PAGE_SIZE; - lo->lo_device = bdev; - lo->lo_flags = lo_flags; - lo->lo_backing_file = file; - lo->lo_sizelimit = 0; - lo->old_gfp_mask = mapping_gfp_mask(mapping); - mapping_set_gfp_mask(mapping, lo->old_gfp_mask & ~(__GFP_IO|__GFP_FS)); - - lo->lo_bio = lo->lo_biotail = NULL; - - /* - * set queue make_request_fn, and add limits based on lower level - * device - */ - blk_queue_make_request(lo->lo_queue, loop_make_request); - lo->lo_queue->queuedata = lo; - - /* queue parameters */ - CLASSERT(PAGE_SIZE < (1 << (sizeof(unsigned short) * 8))); - blk_queue_logical_block_size(lo->lo_queue, - (unsigned short)PAGE_SIZE); - blk_queue_max_hw_sectors(lo->lo_queue, - LLOOP_MAX_SEGMENTS << (PAGE_SHIFT - 9)); - blk_queue_max_segments(lo->lo_queue, LLOOP_MAX_SEGMENTS); - - set_capacity(disks[lo->lo_number], size); - bd_set_size(bdev, size << 9); - - set_blocksize(bdev, lo->lo_blocksize); - - kthread_run(loop_thread, lo, "lloop%d", lo->lo_number); - down(&lo->lo_sem); - return 0; - -out: - /* This is safe: open() is still holding a reference. */ - module_put(THIS_MODULE); - return error; -} - -static int loop_clr_fd(struct lloop_device *lo, struct block_device *bdev, - int count) -{ - struct file *filp = lo->lo_backing_file; - gfp_t gfp = lo->old_gfp_mask; - - if (lo->lo_state != LLOOP_BOUND) - return -ENXIO; - - if (lo->lo_refcnt > count) /* we needed one fd for the ioctl */ - return -EBUSY; - - if (!filp) - return -EINVAL; - - spin_lock_irq(&lo->lo_lock); - lo->lo_state = LLOOP_RUNDOWN; - spin_unlock_irq(&lo->lo_lock); - wake_up(&lo->lo_bh_wait); - - down(&lo->lo_sem); - lo->lo_backing_file = NULL; - lo->lo_device = NULL; - lo->lo_offset = 0; - lo->lo_sizelimit = 0; - lo->lo_flags = 0; - invalidate_bdev(bdev); - set_capacity(disks[lo->lo_number], 0); - bd_set_size(bdev, 0); - mapping_set_gfp_mask(filp->f_mapping, gfp); - lo->lo_state = LLOOP_UNBOUND; - fput(filp); - /* This is safe: open() is still holding a reference. */ - module_put(THIS_MODULE); - return 0; -} - -static int lo_open(struct block_device *bdev, fmode_t mode) -{ - struct lloop_device *lo = bdev->bd_disk->private_data; - - mutex_lock(&lo->lo_ctl_mutex); - lo->lo_refcnt++; - mutex_unlock(&lo->lo_ctl_mutex); - - return 0; -} - -static void lo_release(struct gendisk *disk, fmode_t mode) -{ - struct lloop_device *lo = disk->private_data; - - mutex_lock(&lo->lo_ctl_mutex); - --lo->lo_refcnt; - mutex_unlock(&lo->lo_ctl_mutex); -} - -/* lloop device node's ioctl function. */ -static int lo_ioctl(struct block_device *bdev, fmode_t mode, - unsigned int cmd, unsigned long arg) -{ - struct lloop_device *lo = bdev->bd_disk->private_data; - struct inode *inode = NULL; - int err = 0; - - mutex_lock(&lloop_mutex); - switch (cmd) { - case LL_IOC_LLOOP_DETACH: { - err = loop_clr_fd(lo, bdev, 2); - if (err == 0) - blkdev_put(bdev, 0); /* grabbed in LLOOP_ATTACH */ - break; - } - - case LL_IOC_LLOOP_INFO: { - struct lu_fid fid; - - if (!lo->lo_backing_file) { - err = -ENOENT; - break; - } - if (!inode) - inode = file_inode(lo->lo_backing_file); - if (lo->lo_state == LLOOP_BOUND) - fid = ll_i2info(inode)->lli_fid; - else - fid_zero(&fid); - - if (copy_to_user((void __user *)arg, &fid, sizeof(fid))) - err = -EFAULT; - break; - } - - default: - err = -EINVAL; - break; - } - mutex_unlock(&lloop_mutex); - - return err; -} - -static struct block_device_operations lo_fops = { - .owner = THIS_MODULE, - .open = lo_open, - .release = lo_release, - .ioctl = lo_ioctl, -}; - -/* dynamic iocontrol callback. - * This callback is registered in lloop_init and will be called by - * ll_iocontrol_call. - * - * This is a llite regular file ioctl function. It takes the responsibility - * of attaching or detaching a file by a lloop's device number. - */ -static enum llioc_iter lloop_ioctl(struct inode *unused, struct file *file, - unsigned int cmd, unsigned long arg, - void *magic, int *rcp) -{ - struct lloop_device *lo = NULL; - struct block_device *bdev = NULL; - int err = 0; - dev_t dev; - - if (magic != ll_iocontrol_magic) - return LLIOC_CONT; - - if (!disks) { - err = -ENODEV; - goto out1; - } - - CWARN("Enter llop_ioctl\n"); - - mutex_lock(&lloop_mutex); - switch (cmd) { - case LL_IOC_LLOOP_ATTACH: { - struct lloop_device *lo_free = NULL; - int i; - - for (i = 0; i < max_loop; i++, lo = NULL) { - lo = &loop_dev[i]; - if (lo->lo_state == LLOOP_UNBOUND) { - if (!lo_free) - lo_free = lo; - continue; - } - if (file_inode(lo->lo_backing_file) == file_inode(file)) - break; - } - if (lo || !lo_free) { - err = -EBUSY; - goto out; - } - - lo = lo_free; - dev = MKDEV(lloop_major, lo->lo_number); - - /* quit if the used pointer is writable */ - if (put_user((long)old_encode_dev(dev), (long __user *)arg)) { - err = -EFAULT; - goto out; - } - - bdev = blkdev_get_by_dev(dev, file->f_mode, NULL); - if (IS_ERR(bdev)) { - err = PTR_ERR(bdev); - goto out; - } - - get_file(file); - err = loop_set_fd(lo, NULL, bdev, file); - if (err) { - fput(file); - blkdev_put(bdev, 0); - } - - break; - } - - case LL_IOC_LLOOP_DETACH_BYDEV: { - int minor; - - dev = old_decode_dev(arg); - if (MAJOR(dev) != lloop_major) { - err = -EINVAL; - goto out; - } - - minor = MINOR(dev); - if (minor > max_loop - 1) { - err = -EINVAL; - goto out; - } - - lo = &loop_dev[minor]; - if (lo->lo_state != LLOOP_BOUND) { - err = -EINVAL; - goto out; - } - - bdev = lo->lo_device; - err = loop_clr_fd(lo, bdev, 1); - if (err == 0) - blkdev_put(bdev, 0); /* grabbed in LLOOP_ATTACH */ - - break; - } - - default: - err = -EINVAL; - break; - } - -out: - mutex_unlock(&lloop_mutex); -out1: - if (rcp) - *rcp = err; - return LLIOC_STOP; -} - -static int __init lloop_init(void) -{ - int i; - unsigned int cmdlist[] = { - LL_IOC_LLOOP_ATTACH, - LL_IOC_LLOOP_DETACH_BYDEV, - }; - - if (max_loop < 1 || max_loop > 256) { - max_loop = MAX_LOOP_DEFAULT; - CWARN("lloop: invalid max_loop (must be between 1 and 256), using default (%u)\n", - max_loop); - } - - lloop_major = register_blkdev(0, "lloop"); - if (lloop_major < 0) - return -EIO; - - CDEBUG(D_CONFIG, "registered lloop major %d with %u minors\n", - lloop_major, max_loop); - - ll_iocontrol_magic = ll_iocontrol_register(lloop_ioctl, 2, cmdlist); - if (!ll_iocontrol_magic) - goto out_mem1; - - loop_dev = kcalloc(max_loop, sizeof(*loop_dev), GFP_KERNEL); - if (!loop_dev) - goto out_mem1; - - disks = kcalloc(max_loop, sizeof(*disks), GFP_KERNEL); - if (!disks) - goto out_mem2; - - for (i = 0; i < max_loop; i++) { - disks[i] = alloc_disk(1); - if (!disks[i]) - goto out_mem3; - } - - mutex_init(&lloop_mutex); - - for (i = 0; i < max_loop; i++) { - struct lloop_device *lo = &loop_dev[i]; - struct gendisk *disk = disks[i]; - - lo->lo_queue = blk_alloc_queue(GFP_KERNEL); - if (!lo->lo_queue) - goto out_mem4; - - mutex_init(&lo->lo_ctl_mutex); - sema_init(&lo->lo_sem, 0); - init_waitqueue_head(&lo->lo_bh_wait); - lo->lo_number = i; - spin_lock_init(&lo->lo_lock); - disk->major = lloop_major; - disk->first_minor = i; - disk->fops = &lo_fops; - sprintf(disk->disk_name, "lloop%d", i); - disk->private_data = lo; - disk->queue = lo->lo_queue; - } - - /* We cannot fail after we call this, so another loop!*/ - for (i = 0; i < max_loop; i++) - add_disk(disks[i]); - return 0; - -out_mem4: - while (i--) - blk_cleanup_queue(loop_dev[i].lo_queue); - i = max_loop; -out_mem3: - while (i--) - put_disk(disks[i]); - kfree(disks); -out_mem2: - kfree(loop_dev); -out_mem1: - unregister_blkdev(lloop_major, "lloop"); - ll_iocontrol_unregister(ll_iocontrol_magic); - CERROR("lloop: ran out of memory\n"); - return -ENOMEM; -} - -static void lloop_exit(void) -{ - int i; - - ll_iocontrol_unregister(ll_iocontrol_magic); - for (i = 0; i < max_loop; i++) { - del_gendisk(disks[i]); - blk_cleanup_queue(loop_dev[i].lo_queue); - put_disk(disks[i]); - } - - unregister_blkdev(lloop_major, "lloop"); - - kfree(disks); - kfree(loop_dev); -} - -module_param(max_loop, int, 0444); -MODULE_PARM_DESC(max_loop, "maximum of lloop_device"); -MODULE_AUTHOR("OpenSFS, Inc. "); -MODULE_DESCRIPTION("Lustre virtual block device"); -MODULE_VERSION(LUSTRE_VERSION_STRING); -MODULE_LICENSE("GPL"); - -module_init(lloop_init); -module_exit(lloop_exit); -- cgit v0.10.2 From 21ca52bb749e66cf755a8b8d6345a8fbbc17ce91 Mon Sep 17 00:00:00 2001 From: Binoy Jayan Date: Wed, 8 Jun 2016 13:20:42 +0530 Subject: staging: lustre: lnet: Replace semaphore ln_rc_signal with completion The semaphore ln_rc_signal is used as completion, so convert it to struct completion. Semaphores are going away in the future. Signed-off-by: Binoy Jayan Acked-by: James Simmons Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/lustre/include/linux/lnet/lib-types.h b/drivers/staging/lustre/include/linux/lnet/lib-types.h index 24c4a08..7967b01 100644 --- a/drivers/staging/lustre/include/linux/lnet/lib-types.h +++ b/drivers/staging/lustre/include/linux/lnet/lib-types.h @@ -38,6 +38,7 @@ #include #include #include +#include #include "types.h" #include "lnetctl.h" @@ -610,7 +611,7 @@ typedef struct { /* rcd ready for free */ struct list_head ln_rcd_zombie; /* serialise startup/shutdown */ - struct semaphore ln_rc_signal; + struct completion ln_rc_signal; struct mutex ln_api_mutex; struct mutex ln_lnd_mutex; diff --git a/drivers/staging/lustre/lnet/lnet/router.c b/drivers/staging/lustre/lnet/lnet/router.c index b01dc42..0635432 100644 --- a/drivers/staging/lustre/lnet/lnet/router.c +++ b/drivers/staging/lustre/lnet/lnet/router.c @@ -18,6 +18,7 @@ */ #define DEBUG_SUBSYSTEM S_LNET +#include #include "../../include/linux/lnet/lib-lnet.h" #define LNET_NRB_TINY_MIN 512 /* min value for each CPT */ @@ -1065,7 +1066,7 @@ lnet_router_checker_start(void) return -EINVAL; } - sema_init(&the_lnet.ln_rc_signal, 0); + init_completion(&the_lnet.ln_rc_signal); rc = LNetEQAlloc(0, lnet_router_checker_event, &the_lnet.ln_rc_eqh); if (rc) { @@ -1079,7 +1080,7 @@ lnet_router_checker_start(void) rc = PTR_ERR(task); CERROR("Can't start router checker thread: %d\n", rc); /* block until event callback signals exit */ - down(&the_lnet.ln_rc_signal); + wait_for_completion(&the_lnet.ln_rc_signal); rc = LNetEQFree(the_lnet.ln_rc_eqh); LASSERT(!rc); the_lnet.ln_rc_state = LNET_RC_STATE_SHUTDOWN; @@ -1112,7 +1113,7 @@ lnet_router_checker_stop(void) wake_up(&the_lnet.ln_rc_waitq); /* block until event callback signals exit */ - down(&the_lnet.ln_rc_signal); + wait_for_completion(&the_lnet.ln_rc_signal); LASSERT(the_lnet.ln_rc_state == LNET_RC_STATE_SHUTDOWN); rc = LNetEQFree(the_lnet.ln_rc_eqh); @@ -1295,7 +1296,7 @@ rescan: lnet_prune_rc_data(1); /* wait for UNLINK */ the_lnet.ln_rc_state = LNET_RC_STATE_SHUTDOWN; - up(&the_lnet.ln_rc_signal); + complete(&the_lnet.ln_rc_signal); /* The unlink event callback will signal final completion */ return 0; } -- cgit v0.10.2 From b396cff519da6ab9094d5d9cd95e2849701ef9de Mon Sep 17 00:00:00 2001 From: Chanwoo Choi Date: Mon, 21 Mar 2016 10:36:26 +0900 Subject: power: axp288_charger: Replace deprecatd API of extcon This patch removes the deprecated notifier API of extcon framework and then use the new extcon API[2] with the unique id[1] to indicate the each external connector. Alter deprecated API as following: - extcon_register_interest() -> extcon_register_notifier() - extcon_unregister_interest() -> extcon_unregister_notifier() - extcon_get_cable_state() -> extcon_get_cable_state_() And, extcon alters the name of USB charger connector in patch[3] as following: - EXTCON_CHG_USB_SDP /* Standard Downstream Port */ - EXTCON_CHG_USB_DCP /* Dedicated Charging Port */ - EXTCON_CHG_USB_CDP /* Charging Downstream Port */ - EXTCON_CHG_USB_ACA /* Accessory Charger Adapter */ [1] Commit 2a9de9c0f08d61 - ("extcon: Use the unique id for external connector instead of string) [2] Commit 046050f6e623e4 - ("extcon: Update the prototype of extcon_register_notifier() with enum extcon [3] Commit 11eecf910bd81d - ("extcon: Modify the id and name of external connector") Signed-off-by: Chanwoo Choi Acked-By: Sebastian Reichel diff --git a/drivers/power/axp288_charger.c b/drivers/power/axp288_charger.c index e4d569f..4030eeb 100644 --- a/drivers/power/axp288_charger.c +++ b/drivers/power/axp288_charger.c @@ -129,10 +129,6 @@ #define AXP288_EXTCON_DEV_NAME "axp288_extcon" -#define AXP288_EXTCON_SLOW_CHARGER "SLOW-CHARGER" -#define AXP288_EXTCON_DOWNSTREAM_CHARGER "CHARGE-DOWNSTREAM" -#define AXP288_EXTCON_FAST_CHARGER "FAST-CHARGER" - enum { VBUS_OV_IRQ = 0, CHARGE_DONE_IRQ, @@ -158,7 +154,7 @@ struct axp288_chrg_info { /* OTG/Host mode */ struct { struct work_struct work; - struct extcon_specific_cable_nb cable; + struct extcon_dev *cable; struct notifier_block id_nb; bool id_short; } otg; @@ -586,17 +582,15 @@ static void axp288_charger_extcon_evt_worker(struct work_struct *work) bool old_connected = info->cable.connected; /* Determine cable/charger type */ - if (extcon_get_cable_state(edev, AXP288_EXTCON_SLOW_CHARGER) > 0) { + if (extcon_get_cable_state_(edev, EXTCON_CHG_USB_SDP) > 0) { dev_dbg(&info->pdev->dev, "USB SDP charger is connected"); info->cable.connected = true; info->cable.chg_type = POWER_SUPPLY_TYPE_USB; - } else if (extcon_get_cable_state(edev, - AXP288_EXTCON_DOWNSTREAM_CHARGER) > 0) { + } else if (extcon_get_cable_state_(edev, EXTCON_CHG_USB_CDP) > 0) { dev_dbg(&info->pdev->dev, "USB CDP charger is connected"); info->cable.connected = true; info->cable.chg_type = POWER_SUPPLY_TYPE_USB_CDP; - } else if (extcon_get_cable_state(edev, - AXP288_EXTCON_FAST_CHARGER) > 0) { + } else if (extcon_get_cable_state_(edev, EXTCON_CHG_USB_DCP) > 0) { dev_dbg(&info->pdev->dev, "USB DCP charger is connected"); info->cable.connected = true; info->cable.chg_type = POWER_SUPPLY_TYPE_USB_DCP; @@ -692,8 +686,8 @@ static int axp288_charger_handle_otg_evt(struct notifier_block *nb, { struct axp288_chrg_info *info = container_of(nb, struct axp288_chrg_info, otg.id_nb); - struct extcon_dev *edev = param; - int usb_host = extcon_get_cable_state(edev, "USB-Host"); + struct extcon_dev *edev = info->otg.cable; + int usb_host = extcon_get_cable_state_(edev, EXTCON_USB_HOST); dev_dbg(&info->pdev->dev, "external connector USB-Host is %s\n", usb_host ? "attached" : "detached"); @@ -848,10 +842,33 @@ static int axp288_charger_probe(struct platform_device *pdev) /* Register for extcon notification */ INIT_WORK(&info->cable.work, axp288_charger_extcon_evt_worker); info->cable.nb.notifier_call = axp288_charger_handle_cable_evt; - ret = extcon_register_notifier(info->cable.edev, EXTCON_NONE, &info->cable.nb); + ret = extcon_register_notifier(info->cable.edev, EXTCON_CHG_USB_SDP, + &info->cable.nb); + if (ret) { + dev_err(&info->pdev->dev, + "failed to register extcon notifier for SDP %d\n", ret); + return ret; + } + + ret = extcon_register_notifier(info->cable.edev, EXTCON_CHG_USB_CDP, + &info->cable.nb); + if (ret) { + dev_err(&info->pdev->dev, + "failed to register extcon notifier for CDP %d\n", ret); + extcon_unregister_notifier(info->cable.edev, + EXTCON_CHG_USB_SDP, &info->cable.nb); + return ret; + } + + ret = extcon_register_notifier(info->cable.edev, EXTCON_CHG_USB_DCP, + &info->cable.nb); if (ret) { dev_err(&info->pdev->dev, - "failed to register extcon notifier %d\n", ret); + "failed to register extcon notifier for DCP %d\n", ret); + extcon_unregister_notifier(info->cable.edev, + EXTCON_CHG_USB_SDP, &info->cable.nb); + extcon_unregister_notifier(info->cable.edev, + EXTCON_CHG_USB_CDP, &info->cable.nb); return ret; } @@ -871,14 +888,14 @@ static int axp288_charger_probe(struct platform_device *pdev) /* Register for OTG notification */ INIT_WORK(&info->otg.work, axp288_charger_otg_evt_worker); info->otg.id_nb.notifier_call = axp288_charger_handle_otg_evt; - ret = extcon_register_interest(&info->otg.cable, NULL, "USB-Host", + ret = extcon_register_notifier(info->otg.cable, EXTCON_USB_HOST, &info->otg.id_nb); if (ret) dev_warn(&pdev->dev, "failed to register otg notifier\n"); - if (info->otg.cable.edev) - info->otg.id_short = extcon_get_cable_state( - info->otg.cable.edev, "USB-Host"); + if (info->otg.cable) + info->otg.id_short = extcon_get_cable_state_( + info->otg.cable, EXTCON_USB_HOST); /* Register charger interrupts */ for (i = 0; i < CHRG_INTR_END; i++) { @@ -905,11 +922,17 @@ static int axp288_charger_probe(struct platform_device *pdev) return 0; intr_reg_failed: - if (info->otg.cable.edev) - extcon_unregister_interest(&info->otg.cable); + if (info->otg.cable) + extcon_unregister_notifier(info->otg.cable, EXTCON_USB_HOST, + &info->otg.id_nb); power_supply_unregister(info->psy_usb); psy_reg_failed: - extcon_unregister_notifier(info->cable.edev, EXTCON_NONE, &info->cable.nb); + extcon_unregister_notifier(info->cable.edev, EXTCON_CHG_USB_SDP, + &info->cable.nb); + extcon_unregister_notifier(info->cable.edev, EXTCON_CHG_USB_CDP, + &info->cable.nb); + extcon_unregister_notifier(info->cable.edev, EXTCON_CHG_USB_DCP, + &info->cable.nb); return ret; } @@ -917,10 +940,16 @@ static int axp288_charger_remove(struct platform_device *pdev) { struct axp288_chrg_info *info = dev_get_drvdata(&pdev->dev); - if (info->otg.cable.edev) - extcon_unregister_interest(&info->otg.cable); + if (info->otg.cable) + extcon_unregister_notifier(info->otg.cable, EXTCON_USB_HOST, + &info->otg.id_nb); - extcon_unregister_notifier(info->cable.edev, EXTCON_NONE, &info->cable.nb); + extcon_unregister_notifier(info->cable.edev, EXTCON_CHG_USB_SDP, + &info->cable.nb); + extcon_unregister_notifier(info->cable.edev, EXTCON_CHG_USB_CDP, + &info->cable.nb); + extcon_unregister_notifier(info->cable.edev, EXTCON_CHG_USB_DCP, + &info->cable.nb); power_supply_unregister(info->psy_usb); return 0; -- cgit v0.10.2 From 830ae442202e314c2bdf7cb4c7cc64d76db0e197 Mon Sep 17 00:00:00 2001 From: Chanwoo Choi Date: Tue, 31 May 2016 17:32:30 +0900 Subject: extcon: Remove the deprecated extcon functions This patch removes the deprecated extcon functions using string type to identify the type of external connector. The Commit 2a9de9c0f08d61 ("extcon: Use the unique id for external connector instead of string) uses the unique id to separate the type of external connector instead of string name. - extcon_register_interest() - extcon_unregister_interest() - extcon_set_cable_state() - extcon_get_cable_state() And, extcon_register_interest() finds the first extcon device to include the requested external connector from extcon client device and then register the notifier if extcon device argument is NULL. Instead, extcon_register_notifier() supports this feature. But, this patch remains the deprecatd function definition to prevent the build break. Signed-off-by: Chanwoo Choi diff --git a/drivers/extcon/extcon.c b/drivers/extcon/extcon.c index 21a123c..4fef9ab 100644 --- a/drivers/extcon/extcon.c +++ b/drivers/extcon/extcon.c @@ -127,38 +127,6 @@ static int find_cable_index_by_id(struct extcon_dev *edev, const unsigned int id return -EINVAL; } -static int find_cable_id_by_name(struct extcon_dev *edev, const char *name) -{ - int id = -EINVAL; - int i = 0; - - /* Find the id of extcon cable */ - while (extcon_name[i]) { - if (!strncmp(extcon_name[i], name, CABLE_NAME_MAX)) { - id = i; - break; - } - i++; - } - - return id; -} - -static int find_cable_index_by_name(struct extcon_dev *edev, const char *name) -{ - int id; - - if (edev->max_supported == 0) - return -EINVAL; - - /* Find the the number of extcon cable */ - id = find_cable_id_by_name(edev, name); - if (id < 0) - return id; - - return find_cable_index_by_id(edev, id); -} - static bool is_extcon_changed(u32 prev, u32 new, int idx, bool *attached) { if (((prev >> idx) & 0x1) != ((new >> idx) & 0x1)) { @@ -374,25 +342,6 @@ int extcon_get_cable_state_(struct extcon_dev *edev, const unsigned int id) EXPORT_SYMBOL_GPL(extcon_get_cable_state_); /** - * extcon_get_cable_state() - Get the status of a specific cable. - * @edev: the extcon device that has the cable. - * @cable_name: cable name. - * - * Note that this is slower than extcon_get_cable_state_. - */ -int extcon_get_cable_state(struct extcon_dev *edev, const char *cable_name) -{ - int id; - - id = find_cable_id_by_name(edev, cable_name); - if (id < 0) - return id; - - return extcon_get_cable_state_(edev, id); -} -EXPORT_SYMBOL_GPL(extcon_get_cable_state); - -/** * extcon_set_cable_state_() - Set the status of a specific cable. * @edev: the extcon device that has the cable. * @id: the unique id of each external connector @@ -422,28 +371,6 @@ int extcon_set_cable_state_(struct extcon_dev *edev, unsigned int id, EXPORT_SYMBOL_GPL(extcon_set_cable_state_); /** - * extcon_set_cable_state() - Set the status of a specific cable. - * @edev: the extcon device that has the cable. - * @cable_name: cable name. - * @cable_state: the new cable status. The default semantics is - * true: attached / false: detached. - * - * Note that this is slower than extcon_set_cable_state_. - */ -int extcon_set_cable_state(struct extcon_dev *edev, - const char *cable_name, bool cable_state) -{ - int id; - - id = find_cable_id_by_name(edev, cable_name); - if (id < 0) - return id; - - return extcon_set_cable_state_(edev, id, cable_state); -} -EXPORT_SYMBOL_GPL(extcon_set_cable_state); - -/** * extcon_get_extcon_dev() - Get the extcon device instance from the name * @extcon_name: The extcon name provided with extcon_dev_register() */ @@ -467,105 +394,6 @@ out: EXPORT_SYMBOL_GPL(extcon_get_extcon_dev); /** - * extcon_register_interest() - Register a notifier for a state change of a - * specific cable, not an entier set of cables of a - * extcon device. - * @obj: an empty extcon_specific_cable_nb object to be returned. - * @extcon_name: the name of extcon device. - * if NULL, extcon_register_interest will register - * every cable with the target cable_name given. - * @cable_name: the target cable name. - * @nb: the notifier block to get notified. - * - * Provide an empty extcon_specific_cable_nb. extcon_register_interest() sets - * the struct for you. - * - * extcon_register_interest is a helper function for those who want to get - * notification for a single specific cable's status change. If a user wants - * to get notification for any changes of all cables of a extcon device, - * he/she should use the general extcon_register_notifier(). - * - * Note that the second parameter given to the callback of nb (val) is - * "old_state", not the current state. The current state can be retrieved - * by looking at the third pameter (edev pointer)'s state value. - */ -int extcon_register_interest(struct extcon_specific_cable_nb *obj, - const char *extcon_name, const char *cable_name, - struct notifier_block *nb) -{ - unsigned long flags; - int ret; - - if (!obj || !cable_name || !nb) - return -EINVAL; - - if (extcon_name) { - obj->edev = extcon_get_extcon_dev(extcon_name); - if (!obj->edev) - return -ENODEV; - - obj->cable_index = find_cable_index_by_name(obj->edev, - cable_name); - if (obj->cable_index < 0) - return obj->cable_index; - - obj->user_nb = nb; - - spin_lock_irqsave(&obj->edev->lock, flags); - ret = raw_notifier_chain_register( - &obj->edev->nh[obj->cable_index], - obj->user_nb); - spin_unlock_irqrestore(&obj->edev->lock, flags); - } else { - struct class_dev_iter iter; - struct extcon_dev *extd; - struct device *dev; - - if (!extcon_class) - return -ENODEV; - class_dev_iter_init(&iter, extcon_class, NULL, NULL); - while ((dev = class_dev_iter_next(&iter))) { - extd = dev_get_drvdata(dev); - - if (find_cable_index_by_name(extd, cable_name) < 0) - continue; - - class_dev_iter_exit(&iter); - return extcon_register_interest(obj, extd->name, - cable_name, nb); - } - - ret = -ENODEV; - } - - return ret; -} -EXPORT_SYMBOL_GPL(extcon_register_interest); - -/** - * extcon_unregister_interest() - Unregister the notifier registered by - * extcon_register_interest(). - * @obj: the extcon_specific_cable_nb object returned by - * extcon_register_interest(). - */ -int extcon_unregister_interest(struct extcon_specific_cable_nb *obj) -{ - unsigned long flags; - int ret; - - if (!obj) - return -EINVAL; - - spin_lock_irqsave(&obj->edev->lock, flags); - ret = raw_notifier_chain_unregister( - &obj->edev->nh[obj->cable_index], obj->user_nb); - spin_unlock_irqrestore(&obj->edev->lock, flags); - - return ret; -} -EXPORT_SYMBOL_GPL(extcon_unregister_interest); - -/** * extcon_register_notifier() - Register a notifiee to get notified by * any attach status changes from the extcon. * @edev: the extcon device that has the external connecotr. @@ -582,14 +410,33 @@ int extcon_register_notifier(struct extcon_dev *edev, unsigned int id, unsigned long flags; int ret, idx; - if (!edev || !nb) + if (!nb) return -EINVAL; - idx = find_cable_index_by_id(edev, id); + if (edev) { + idx = find_cable_index_by_id(edev, id); - spin_lock_irqsave(&edev->lock, flags); - ret = raw_notifier_chain_register(&edev->nh[idx], nb); - spin_unlock_irqrestore(&edev->lock, flags); + spin_lock_irqsave(&edev->lock, flags); + ret = raw_notifier_chain_register(&edev->nh[idx], nb); + spin_unlock_irqrestore(&edev->lock, flags); + } else { + struct extcon_dev *extd; + + mutex_lock(&extcon_dev_list_lock); + list_for_each_entry(extd, &extcon_dev_list, entry) { + idx = find_cable_index_by_id(extd, id); + if (idx >= 0) + break; + } + mutex_unlock(&extcon_dev_list_lock); + + if (idx >= 0) { + edev = extd; + return extcon_register_notifier(extd, id, nb); + } else { + ret = -ENODEV; + } + } return ret; } diff --git a/include/linux/extcon.h b/include/linux/extcon.h index 7abf674..cec5c54 100644 --- a/include/linux/extcon.h +++ b/include/linux/extcon.h @@ -146,22 +146,6 @@ struct extcon_cable { struct attribute *attrs[3]; /* to be fed to attr_g.attrs */ }; -/** - * struct extcon_specific_cable_nb - An internal data for - * extcon_register_interest(). - * @user_nb: user provided notifier block for events from - * a specific cable. - * @cable_index: the target cable. - * @edev: the target extcon device. - * @previous_value: the saved previous event value. - */ -struct extcon_specific_cable_nb { - struct notifier_block *user_nb; - int cable_index; - struct extcon_dev *edev; - unsigned long previous_value; -}; - #if IS_ENABLED(CONFIG_EXTCON) /* @@ -207,23 +191,6 @@ extern int extcon_get_cable_state_(struct extcon_dev *edev, unsigned int id); extern int extcon_set_cable_state_(struct extcon_dev *edev, unsigned int id, bool cable_state); -extern int extcon_get_cable_state(struct extcon_dev *edev, - const char *cable_name); -extern int extcon_set_cable_state(struct extcon_dev *edev, - const char *cable_name, bool cable_state); - -/* - * Following APIs are for notifiees (those who want to be notified) - * to register a callback for events from a specific cable of the extcon. - * Notifiees are the connected device drivers wanting to get notified by - * a specific external port of a connection device. - */ -extern int extcon_register_interest(struct extcon_specific_cable_nb *obj, - const char *extcon_name, - const char *cable_name, - struct notifier_block *nb); -extern int extcon_unregister_interest(struct extcon_specific_cable_nb *nb); - /* * Following APIs are to monitor every action of a notifier. * Registrar gets notified for every external port of a connection device. @@ -246,6 +213,7 @@ extern struct extcon_dev *extcon_get_edev_by_phandle(struct device *dev, /* Following API to get information of extcon device */ extern const char *extcon_get_edev_name(struct extcon_dev *edev); + #else /* CONFIG_EXTCON */ static inline int extcon_dev_register(struct extcon_dev *edev) { @@ -306,18 +274,6 @@ static inline int extcon_set_cable_state_(struct extcon_dev *edev, return 0; } -static inline int extcon_get_cable_state(struct extcon_dev *edev, - const char *cable_name) -{ - return 0; -} - -static inline int extcon_set_cable_state(struct extcon_dev *edev, - const char *cable_name, int state) -{ - return 0; -} - static inline struct extcon_dev *extcon_get_extcon_dev(const char *extcon_name) { return NULL; @@ -337,24 +293,34 @@ static inline int extcon_unregister_notifier(struct extcon_dev *edev, return 0; } -static inline int extcon_register_interest(struct extcon_specific_cable_nb *obj, - const char *extcon_name, - const char *cable_name, - struct notifier_block *nb) +static inline struct extcon_dev *extcon_get_edev_by_phandle(struct device *dev, + int index) { - return 0; + return ERR_PTR(-ENODEV); } +#endif /* CONFIG_EXTCON */ -static inline int extcon_unregister_interest(struct extcon_specific_cable_nb - *obj) +/* + * Following structure and API are deprecated. EXTCON remains the function + * definition to prevent the build break. + */ +struct extcon_specific_cable_nb { + struct notifier_block *user_nb; + int cable_index; + struct extcon_dev *edev; + unsigned long previous_value; +}; + +static inline int extcon_register_interest(struct extcon_specific_cable_nb *obj, + const char *extcon_name, const char *cable_name, + struct notifier_block *nb) { - return 0; + return -EINVAL; } -static inline struct extcon_dev *extcon_get_edev_by_phandle(struct device *dev, - int index) +static inline int extcon_unregister_interest(struct extcon_specific_cable_nb + *obj) { - return ERR_PTR(-ENODEV); + return -EINVAL; } -#endif /* CONFIG_EXTCON */ #endif /* __LINUX_EXTCON_H__ */ -- cgit v0.10.2 From 86721ab63b61ef1dd7305308e4049f644703decf Mon Sep 17 00:00:00 2001 From: Pratyush Patel Date: Tue, 1 Mar 2016 22:58:49 +0530 Subject: hrtimer: Remove redundant #ifdef block Only need CONFIG_NO_HZ_COMMON as this block is already in a CONFIG_SMP block. Signed-off-by: Pratyush Patel Link: http://lkml.kernel.org/r/20160301172849.GA18152@cyborg Signed-off-by: Thomas Gleixner diff --git a/kernel/time/hrtimer.c b/kernel/time/hrtimer.c index e99df0f..d13c9ae 100644 --- a/kernel/time/hrtimer.c +++ b/kernel/time/hrtimer.c @@ -177,7 +177,7 @@ hrtimer_check_target(struct hrtimer *timer, struct hrtimer_clock_base *new_base) #endif } -#if defined(CONFIG_SMP) && defined(CONFIG_NO_HZ_COMMON) +#ifdef CONFIG_NO_HZ_COMMON static inline struct hrtimer_cpu_base *get_target_base(struct hrtimer_cpu_base *base, int pinned) -- cgit v0.10.2 From 7faf90ef995ea470f32f43810266ece8ac8ba6c7 Mon Sep 17 00:00:00 2001 From: Paul Bolle Date: Thu, 3 Mar 2016 13:01:40 +0100 Subject: lguest: Read length of device_cap later Read the length of the capability with type VIRTIO_PCI_CAP_DEVICE_CFG only when we're sure we're going to need it. Which is just before the check whether the virtio console actually has an emerg_wr field. Signed-off-by: Paul Bolle Cc: Rusty Russell Cc: lguest@lists.ozlabs.org Link: http://lkml.kernel.org/r/1457006501-5377-2-git-send-email-pebolle@tiscali.nl Signed-off-by: Thomas Gleixner diff --git a/arch/x86/lguest/boot.c b/arch/x86/lguest/boot.c index 3847e73..146d11c 100644 --- a/arch/x86/lguest/boot.c +++ b/arch/x86/lguest/boot.c @@ -1258,7 +1258,7 @@ static void probe_pci_console(void) u8 vndr = read_pci_config_byte(0, 1, 0, cap); if (vndr == PCI_CAP_ID_VNDR) { u8 type, bar; - u32 offset, length; + u32 offset; type = read_pci_config_byte(0, 1, 0, cap + offsetof(struct virtio_pci_cap, cfg_type)); @@ -1266,15 +1266,12 @@ static void probe_pci_console(void) cap + offsetof(struct virtio_pci_cap, bar)); offset = read_pci_config(0, 1, 0, cap + offsetof(struct virtio_pci_cap, offset)); - length = read_pci_config(0, 1, 0, - cap + offsetof(struct virtio_pci_cap, length)); switch (type) { case VIRTIO_PCI_CAP_DEVICE_CFG: if (bar == 0) { device_cap = cap; device_offset = offset; - device_len = length; } break; case VIRTIO_PCI_CAP_PCI_CFG: @@ -1297,6 +1294,8 @@ static void probe_pci_console(void) * emerg_wr. If it doesn't support VIRTIO_CONSOLE_F_EMERG_WRITE * it should ignore the access. */ + device_len = read_pci_config(0, 1, 0, + device_cap + offsetof(struct virtio_pci_cap, length)); if (device_len < (offsetof(struct virtio_console_config, emerg_wr) + sizeof(u32))) { printk(KERN_ERR "lguest: console missing emerg_wr field\n"); -- cgit v0.10.2 From cf2cf0f50c14e86e04cda2c684357eed77922666 Mon Sep 17 00:00:00 2001 From: Paul Bolle Date: Thu, 3 Mar 2016 13:01:41 +0100 Subject: lguest: Read offset of device_cap later Read the offset of the capability with type VIRTIO_PCI_CAP_DEVICE_CFG only when we're sure we're going to need it. Which is when all checks have passed and we know we have a virtio console with an emerg_wr field. Signed-off-by: Paul Bolle Cc: Rusty Russell Cc: lguest@lists.ozlabs.org Link: http://lkml.kernel.org/r/1457006501-5377-3-git-send-email-pebolle@tiscali.nl Signed-off-by: Thomas Gleixner diff --git a/arch/x86/lguest/boot.c b/arch/x86/lguest/boot.c index 146d11c..25da5bc8 100644 --- a/arch/x86/lguest/boot.c +++ b/arch/x86/lguest/boot.c @@ -1233,8 +1233,6 @@ static void write_bar_via_cfg(u32 cfg_offset, u32 off, u32 val) static void probe_pci_console(void) { u8 cap, common_cap = 0, device_cap = 0; - /* Offset within BAR0 */ - u32 device_offset; u32 device_len; /* Avoid recursive printk into here. */ @@ -1258,21 +1256,16 @@ static void probe_pci_console(void) u8 vndr = read_pci_config_byte(0, 1, 0, cap); if (vndr == PCI_CAP_ID_VNDR) { u8 type, bar; - u32 offset; type = read_pci_config_byte(0, 1, 0, cap + offsetof(struct virtio_pci_cap, cfg_type)); bar = read_pci_config_byte(0, 1, 0, cap + offsetof(struct virtio_pci_cap, bar)); - offset = read_pci_config(0, 1, 0, - cap + offsetof(struct virtio_pci_cap, offset)); switch (type) { case VIRTIO_PCI_CAP_DEVICE_CFG: - if (bar == 0) { + if (bar == 0) device_cap = cap; - device_offset = offset; - } break; case VIRTIO_PCI_CAP_PCI_CFG: console_access_cap = cap; @@ -1302,7 +1295,8 @@ static void probe_pci_console(void) return; } - console_cfg_offset = device_offset; + console_cfg_offset = read_pci_config(0, 1, 0, + device_cap + offsetof(struct virtio_pci_cap, offset)); printk(KERN_INFO "lguest: Console via virtio-pci emerg_wr\n"); } -- cgit v0.10.2 From 4de2d58bc973caa8988b44ddd11787e57051c843 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Wed, 11 May 2016 20:57:44 +0200 Subject: clk: sunxi: tcon-ch1: Do not return a negative error in get_parent get_parent is supposed to return an unsigned 8 bit integer, so returning -EINVAL is a bad idea. Remove it. Reported-by: Dan Carpenter Acked-by: Chen-Yu Tsai Signed-off-by: Maxime Ripard diff --git a/drivers/clk/sunxi/clk-sun4i-tcon-ch1.c b/drivers/clk/sunxi/clk-sun4i-tcon-ch1.c index 98a4582..2485852 100644 --- a/drivers/clk/sunxi/clk-sun4i-tcon-ch1.c +++ b/drivers/clk/sunxi/clk-sun4i-tcon-ch1.c @@ -85,9 +85,6 @@ static u8 tcon_ch1_get_parent(struct clk_hw *hw) reg = readl(tclk->reg) >> TCON_CH1_SCLK2_MUX_SHIFT; reg &= reg >> TCON_CH1_SCLK2_MUX_MASK; - if (reg >= num_parents) - return -EINVAL; - return reg; } -- cgit v0.10.2 From 07ea0b4d9a0abde8d252738079a8a811c5132a94 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Sat, 2 Apr 2016 12:28:31 +0200 Subject: clk: sunxi: display: Add per-clock flags The TCON channel 0 clock that is the parent clock of our pixel clock is expected to change its rate depending on the resolution we want to output in our display engine. However, since it's only a mux, the only way it can do that is by changing its parents rate. Allow to give flags in our display clocks description, and add the CLK_SET_RATE_PARENT flag for the TCON channel 0 flag. Fixes: a3b4956ee6d9 ("clk: sunxi: display: Add per-clock flags") Acked-by: Chen-Yu Tsai Signed-off-by: Maxime Ripard diff --git a/drivers/clk/sunxi/clk-sun4i-display.c b/drivers/clk/sunxi/clk-sun4i-display.c index 445a749..9780fac 100644 --- a/drivers/clk/sunxi/clk-sun4i-display.c +++ b/drivers/clk/sunxi/clk-sun4i-display.c @@ -33,6 +33,8 @@ struct sun4i_a10_display_clk_data { u8 width_div; u8 width_mux; + + u32 flags; }; struct reset_data { @@ -166,7 +168,7 @@ static void __init sun4i_a10_display_init(struct device_node *node, data->has_div ? &div->hw : NULL, data->has_div ? &clk_divider_ops : NULL, &gate->hw, &clk_gate_ops, - 0); + data->flags); if (IS_ERR(clk)) { pr_err("%s: Couldn't register the clock\n", clk_name); goto free_div; @@ -232,6 +234,7 @@ static const struct sun4i_a10_display_clk_data sun4i_a10_tcon_ch0_data __initcon .offset_rst = 29, .offset_mux = 24, .width_mux = 2, + .flags = CLK_SET_RATE_PARENT, }; static void __init sun4i_a10_tcon_ch0_setup(struct device_node *node) -- cgit v0.10.2 From 36e4ad0316c017d5b271378ed9a1c9a4b77fab5f Mon Sep 17 00:00:00 2001 From: Bob Peterson Date: Thu, 9 Jun 2016 14:24:07 -0500 Subject: GFS2: don't set rgrp gl_object until it's inserted into rgrp tree Before this patch, function read_rindex_entry would set a rgrp glock's gl_object pointer to itself before inserting the rgrp into the rgrp rbtree. The problem is: if another process was also reading the rgrp in, and had already inserted its newly created rgrp, then the second call to read_rindex_entry would overwrite that value, then return a bad return code to the caller. Later, other functions would reference the now-freed rgrp memory by way of gl_object. In some cases, that could result in gfs2_rgrp_brelse being called twice for the same rgrp: once for the failed attempt and once for the "real" rgrp release. Eventually the kernel would panic. There are also a number of other things that could go wrong when a kernel module is accessing freed storage. For example, this could result in rgrp corruption because the fake rgrp would point to a fake bitmap in memory too, causing gfs2_inplace_reserve to search some random memory for free blocks, and find some, since we were never setting rgd->rd_bits to NULL before freeing it. This patch fixes the problem by not setting gl_object until we have successfully inserted the rgrp into the rbtree. Also, it sets rd_bits to NULL as it frees them, which will ensure any accidental access to the wrong rgrp will result in a kernel panic rather than file system corruption, which is preferred. Signed-off-by: Bob Peterson diff --git a/fs/gfs2/rgrp.c b/fs/gfs2/rgrp.c index 5bd2169..960aaf4 100644 --- a/fs/gfs2/rgrp.c +++ b/fs/gfs2/rgrp.c @@ -722,6 +722,7 @@ void gfs2_clear_rgrpd(struct gfs2_sbd *sdp) gfs2_free_clones(rgd); kfree(rgd->rd_bits); + rgd->rd_bits = NULL; return_all_reservations(rgd); kmem_cache_free(gfs2_rgrpd_cachep, rgd); } @@ -916,9 +917,6 @@ static int read_rindex_entry(struct gfs2_inode *ip) if (error) goto fail; - rgd->rd_gl->gl_object = rgd; - rgd->rd_gl->gl_vm.start = (rgd->rd_addr * bsize) & PAGE_MASK; - rgd->rd_gl->gl_vm.end = PAGE_ALIGN((rgd->rd_addr + rgd->rd_length) * bsize) - 1; rgd->rd_rgl = (struct gfs2_rgrp_lvb *)rgd->rd_gl->gl_lksb.sb_lvbptr; rgd->rd_flags &= ~(GFS2_RDF_UPTODATE | GFS2_RDF_PREFERRED); if (rgd->rd_data > sdp->sd_max_rg_data) @@ -926,14 +924,20 @@ static int read_rindex_entry(struct gfs2_inode *ip) spin_lock(&sdp->sd_rindex_spin); error = rgd_insert(rgd); spin_unlock(&sdp->sd_rindex_spin); - if (!error) + if (!error) { + rgd->rd_gl->gl_object = rgd; + rgd->rd_gl->gl_vm.start = (rgd->rd_addr * bsize) & PAGE_MASK; + rgd->rd_gl->gl_vm.end = PAGE_ALIGN((rgd->rd_addr + + rgd->rd_length) * bsize) - 1; return 0; + } error = 0; /* someone else read in the rgrp; free it and ignore it */ gfs2_glock_put(rgd->rd_gl); fail: kfree(rgd->rd_bits); + rgd->rd_bits = NULL; kmem_cache_free(gfs2_rgrpd_cachep, rgd); return error; } -- cgit v0.10.2 From 4855531eb8582a98cb905d2baf86021254d7a675 Mon Sep 17 00:00:00 2001 From: Rui Wang Date: Wed, 8 Jun 2016 14:59:53 +0800 Subject: x86/ioapic: Simplify ioapic_setup_resources() Optimize the function by removing the variable 'num'. Signed-off-by: Rui Wang Signed-off-by: Thomas Gleixner Cc: tony.luck@intel.com Cc: linux-pci@vger.kernel.org Cc: rjw@rjwysocki.net Cc: linux-acpi@vger.kernel.org Cc: bhelgaas@google.com Link: http://lkml.kernel.org/r/1465369193-4816-4-git-send-email-rui.y.wang@intel.com Signed-off-by: Ingo Molnar diff --git a/arch/x86/kernel/apic/io_apic.c b/arch/x86/kernel/apic/io_apic.c index 446702e..e587295 100644 --- a/arch/x86/kernel/apic/io_apic.c +++ b/arch/x86/kernel/apic/io_apic.c @@ -2567,29 +2567,25 @@ static struct resource * __init ioapic_setup_resources(void) unsigned long n; struct resource *res; char *mem; - int i, num = 0; + int i; - for_each_ioapic(i) - num++; - if (num == 0) + if (nr_ioapics == 0) return NULL; n = IOAPIC_RESOURCE_NAME_SIZE + sizeof(struct resource); - n *= num; + n *= nr_ioapics; mem = alloc_bootmem(n); res = (void *)mem; - mem += sizeof(struct resource) * num; + mem += sizeof(struct resource) * nr_ioapics; - num = 0; for_each_ioapic(i) { - res[num].name = mem; - res[num].flags = IORESOURCE_MEM | IORESOURCE_BUSY; + res[i].name = mem; + res[i].flags = IORESOURCE_MEM | IORESOURCE_BUSY; snprintf(mem, IOAPIC_RESOURCE_NAME_SIZE, "IOAPIC %u", i); mem += IOAPIC_RESOURCE_NAME_SIZE; - ioapics[i].iomem_res = &res[num]; - num++; + ioapics[i].iomem_res = &res[i]; } ioapic_resources = res; -- cgit v0.10.2 From 3c8fad9183ab7b3b3471fd2bb3d604104dd447cb Mon Sep 17 00:00:00 2001 From: Claudio Fontana Date: Thu, 9 Jun 2016 12:31:58 +0200 Subject: x86/apic: Fix misspelled APIC Signed-off-by: Claudio Fontana Signed-off-by: Thomas Gleixner Cc: trivial@kernel.org Link: http://lkml.kernel.org/r/1465468318-19867-1-git-send-email-hw.claudio@gmail.com Signed-off-by: Ingo Molnar diff --git a/arch/x86/kernel/apic/apic.c b/arch/x86/kernel/apic/apic.c index 60078a6..f943d2f 100644 --- a/arch/x86/kernel/apic/apic.c +++ b/arch/x86/kernel/apic/apic.c @@ -2045,7 +2045,7 @@ int generic_processor_info(int apicid, int version) int thiscpu = max + disabled_cpus - 1; pr_warning( - "ACPI: NR_CPUS/possible_cpus limit of %i almost" + "APIC: NR_CPUS/possible_cpus limit of %i almost" " reached. Keeping one slot for boot cpu." " Processor %d/0x%x ignored.\n", max, thiscpu, apicid); @@ -2057,7 +2057,7 @@ int generic_processor_info(int apicid, int version) int thiscpu = max + disabled_cpus; pr_warning( - "ACPI: NR_CPUS/possible_cpus limit of %i reached." + "APIC: NR_CPUS/possible_cpus limit of %i reached." " Processor %d/0x%x ignored.\n", max, thiscpu, apicid); disabled_cpus++; @@ -2085,7 +2085,7 @@ int generic_processor_info(int apicid, int version) if (topology_update_package_map(apicid, cpu) < 0) { int thiscpu = max + disabled_cpus; - pr_warning("ACPI: Package limit reached. Processor %d/0x%x ignored.\n", + pr_warning("APIC: Package limit reached. Processor %d/0x%x ignored.\n", thiscpu, apicid); disabled_cpus++; return -ENOSPC; -- cgit v0.10.2 From fe3464ca8710012a247bb4586dde21b080f88514 Mon Sep 17 00:00:00 2001 From: Jianyu Zhan Date: Sat, 19 Mar 2016 21:59:19 +0800 Subject: genirq: Remove redundant NULL check of irq_desc for_each_irq_desc() macro has already skipped NULL irq_desc, don't bother to check it again. Signed-off-by: Jianyu Zhan Cc: mingo@kernel.org Cc: yhlu.kernel@gmail.com Link: http://lkml.kernel.org/r/1458395959-7046-1-git-send-email-nasa4836@gmail.com Signed-off-by: Thomas Gleixner diff --git a/kernel/irq/proc.c b/kernel/irq/proc.c index 4e1b947..50a8f28 100644 --- a/kernel/irq/proc.c +++ b/kernel/irq/proc.c @@ -421,12 +421,8 @@ void init_irq_proc(void) /* * Create entries for all existing IRQs. */ - for_each_irq_desc(irq, desc) { - if (!desc) - continue; - + for_each_irq_desc(irq, desc) register_irq_proc(irq, desc); - } } #ifdef CONFIG_GENERIC_IRQ_SHOW -- cgit v0.10.2 From ff5b706f5189fe8d2a6fd576b491b769ec1d29d3 Mon Sep 17 00:00:00 2001 From: Weongyo Jeong Date: Thu, 31 Mar 2016 12:15:03 -0700 Subject: genirq: Remove unnecessary memset() calls sprintf() and snprintf() implementation of kernel guarantees that its result is terminated with null byte if size is larger than 0. So we don't need to call memset() at all. Signed-off-by: Weongyo Jeong Link: http://lkml.kernel.org/r/1459451703-5744-1-git-send-email-weongyo.linux@gmail.com Signed-off-by: Thomas Gleixner diff --git a/kernel/irq/proc.c b/kernel/irq/proc.c index 50a8f28..f30425d 100644 --- a/kernel/irq/proc.c +++ b/kernel/irq/proc.c @@ -311,7 +311,6 @@ void register_handler_proc(unsigned int irq, struct irqaction *action) !name_unique(irq, action)) return; - memset(name, 0, MAX_NAMELEN); snprintf(name, MAX_NAMELEN, "%s", action->name); /* create /proc/irq/1234/handler/ */ @@ -340,7 +339,6 @@ void register_irq_proc(unsigned int irq, struct irq_desc *desc) if (desc->dir) goto out_unlock; - memset(name, 0, MAX_NAMELEN); sprintf(name, "%d", irq); /* create /proc/irq/1234 */ @@ -386,7 +384,6 @@ void unregister_irq_proc(unsigned int irq, struct irq_desc *desc) #endif remove_proc_entry("spurious", desc->dir); - memset(name, 0, MAX_NAMELEN); sprintf(name, "%u", irq); remove_proc_entry(name, root_irq_dir); } -- cgit v0.10.2 From 9e197e2f894c0270ffabd314d73c7730b09ac63c Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Mon, 22 Feb 2016 14:05:44 -0800 Subject: lkdtm: split build into multiple source files Kbuild lacks a way to do in-place objcopy or other modifications of built targets, so in order to move functions into non-text sections without renaming the kernel module, the build of lkdtm must be split into separate source files. This renames lkdtm.c to lkdtm_core.c in preparation for adding the source file for the .rodata section. Signed-off-by: Kees Cook diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index b2fb6dbf..c3cb6ad 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -57,3 +57,5 @@ obj-$(CONFIG_ECHO) += echo/ obj-$(CONFIG_VEXPRESS_SYSCFG) += vexpress-syscfg.o obj-$(CONFIG_CXL_BASE) += cxl/ obj-$(CONFIG_PANEL) += panel.o + +lkdtm-$(CONFIG_LKDTM) += lkdtm_core.o diff --git a/drivers/misc/lkdtm.c b/drivers/misc/lkdtm.c deleted file mode 100644 index 0a5cbbe..0000000 --- a/drivers/misc/lkdtm.c +++ /dev/null @@ -1,1023 +0,0 @@ -/* - * Kprobe module for testing crash dumps - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - * Copyright (C) IBM Corporation, 2006 - * - * Author: Ankita Garg - * - * This module induces system failures at predefined crashpoints to - * evaluate the reliability of crash dumps obtained using different dumping - * solutions. - * - * It is adapted from the Linux Kernel Dump Test Tool by - * Fernando Luis Vazquez Cao - * - * Debugfs support added by Simon Kagstrom - * - * See Documentation/fault-injection/provoke-crashes.txt for instructions - */ -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef CONFIG_IDE -#include -#endif - -/* - * Make sure our attempts to over run the kernel stack doesn't trigger - * a compiler warning when CONFIG_FRAME_WARN is set. Then make sure we - * recurse past the end of THREAD_SIZE by default. - */ -#if defined(CONFIG_FRAME_WARN) && (CONFIG_FRAME_WARN > 0) -#define REC_STACK_SIZE (CONFIG_FRAME_WARN / 2) -#else -#define REC_STACK_SIZE (THREAD_SIZE / 8) -#endif -#define REC_NUM_DEFAULT ((THREAD_SIZE / REC_STACK_SIZE) * 2) - -#define DEFAULT_COUNT 10 -#define EXEC_SIZE 64 - -enum cname { - CN_INVALID, - CN_INT_HARDWARE_ENTRY, - CN_INT_HW_IRQ_EN, - CN_INT_TASKLET_ENTRY, - CN_FS_DEVRW, - CN_MEM_SWAPOUT, - CN_TIMERADD, - CN_SCSI_DISPATCH_CMD, - CN_IDE_CORE_CP, - CN_DIRECT, -}; - -enum ctype { - CT_NONE, - CT_PANIC, - CT_BUG, - CT_WARNING, - CT_EXCEPTION, - CT_LOOP, - CT_OVERFLOW, - CT_CORRUPT_STACK, - CT_UNALIGNED_LOAD_STORE_WRITE, - CT_OVERWRITE_ALLOCATION, - CT_WRITE_AFTER_FREE, - CT_READ_AFTER_FREE, - CT_WRITE_BUDDY_AFTER_FREE, - CT_READ_BUDDY_AFTER_FREE, - CT_SOFTLOCKUP, - CT_HARDLOCKUP, - CT_SPINLOCKUP, - CT_HUNG_TASK, - CT_EXEC_DATA, - CT_EXEC_STACK, - CT_EXEC_KMALLOC, - CT_EXEC_VMALLOC, - CT_EXEC_USERSPACE, - CT_ACCESS_USERSPACE, - CT_WRITE_RO, - CT_WRITE_RO_AFTER_INIT, - CT_WRITE_KERN, - CT_WRAP_ATOMIC -}; - -static char* cp_name[] = { - "INT_HARDWARE_ENTRY", - "INT_HW_IRQ_EN", - "INT_TASKLET_ENTRY", - "FS_DEVRW", - "MEM_SWAPOUT", - "TIMERADD", - "SCSI_DISPATCH_CMD", - "IDE_CORE_CP", - "DIRECT", -}; - -static char* cp_type[] = { - "PANIC", - "BUG", - "WARNING", - "EXCEPTION", - "LOOP", - "OVERFLOW", - "CORRUPT_STACK", - "UNALIGNED_LOAD_STORE_WRITE", - "OVERWRITE_ALLOCATION", - "WRITE_AFTER_FREE", - "READ_AFTER_FREE", - "WRITE_BUDDY_AFTER_FREE", - "READ_BUDDY_AFTER_FREE", - "SOFTLOCKUP", - "HARDLOCKUP", - "SPINLOCKUP", - "HUNG_TASK", - "EXEC_DATA", - "EXEC_STACK", - "EXEC_KMALLOC", - "EXEC_VMALLOC", - "EXEC_USERSPACE", - "ACCESS_USERSPACE", - "WRITE_RO", - "WRITE_RO_AFTER_INIT", - "WRITE_KERN", - "WRAP_ATOMIC" -}; - -static struct jprobe lkdtm; - -static int lkdtm_parse_commandline(void); -static void lkdtm_handler(void); - -static char* cpoint_name; -static char* cpoint_type; -static int cpoint_count = DEFAULT_COUNT; -static int recur_count = REC_NUM_DEFAULT; - -static enum cname cpoint = CN_INVALID; -static enum ctype cptype = CT_NONE; -static int count = DEFAULT_COUNT; -static DEFINE_SPINLOCK(count_lock); -static DEFINE_SPINLOCK(lock_me_up); - -static u8 data_area[EXEC_SIZE]; - -static const unsigned long rodata = 0xAA55AA55; -static unsigned long ro_after_init __ro_after_init = 0x55AA5500; - -module_param(recur_count, int, 0644); -MODULE_PARM_DESC(recur_count, " Recursion level for the stack overflow test"); -module_param(cpoint_name, charp, 0444); -MODULE_PARM_DESC(cpoint_name, " Crash Point, where kernel is to be crashed"); -module_param(cpoint_type, charp, 0444); -MODULE_PARM_DESC(cpoint_type, " Crash Point Type, action to be taken on "\ - "hitting the crash point"); -module_param(cpoint_count, int, 0644); -MODULE_PARM_DESC(cpoint_count, " Crash Point Count, number of times the "\ - "crash point is to be hit to trigger action"); - -static unsigned int jp_do_irq(unsigned int irq) -{ - lkdtm_handler(); - jprobe_return(); - return 0; -} - -static irqreturn_t jp_handle_irq_event(unsigned int irq, - struct irqaction *action) -{ - lkdtm_handler(); - jprobe_return(); - return 0; -} - -static void jp_tasklet_action(struct softirq_action *a) -{ - lkdtm_handler(); - jprobe_return(); -} - -static void jp_ll_rw_block(int rw, int nr, struct buffer_head *bhs[]) -{ - lkdtm_handler(); - jprobe_return(); -} - -struct scan_control; - -static unsigned long jp_shrink_inactive_list(unsigned long max_scan, - struct zone *zone, - struct scan_control *sc) -{ - lkdtm_handler(); - jprobe_return(); - return 0; -} - -static int jp_hrtimer_start(struct hrtimer *timer, ktime_t tim, - const enum hrtimer_mode mode) -{ - lkdtm_handler(); - jprobe_return(); - return 0; -} - -static int jp_scsi_dispatch_cmd(struct scsi_cmnd *cmd) -{ - lkdtm_handler(); - jprobe_return(); - return 0; -} - -#ifdef CONFIG_IDE -static int jp_generic_ide_ioctl(ide_drive_t *drive, struct file *file, - struct block_device *bdev, unsigned int cmd, - unsigned long arg) -{ - lkdtm_handler(); - jprobe_return(); - return 0; -} -#endif - -/* Return the crashpoint number or NONE if the name is invalid */ -static enum ctype parse_cp_type(const char *what, size_t count) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(cp_type); i++) { - if (!strcmp(what, cp_type[i])) - return i + 1; - } - - return CT_NONE; -} - -static const char *cp_type_to_str(enum ctype type) -{ - if (type == CT_NONE || type < 0 || type > ARRAY_SIZE(cp_type)) - return "None"; - - return cp_type[type - 1]; -} - -static const char *cp_name_to_str(enum cname name) -{ - if (name == CN_INVALID || name < 0 || name > ARRAY_SIZE(cp_name)) - return "INVALID"; - - return cp_name[name - 1]; -} - - -static int lkdtm_parse_commandline(void) -{ - int i; - unsigned long flags; - - if (cpoint_count < 1 || recur_count < 1) - return -EINVAL; - - spin_lock_irqsave(&count_lock, flags); - count = cpoint_count; - spin_unlock_irqrestore(&count_lock, flags); - - /* No special parameters */ - if (!cpoint_type && !cpoint_name) - return 0; - - /* Neither or both of these need to be set */ - if (!cpoint_type || !cpoint_name) - return -EINVAL; - - cptype = parse_cp_type(cpoint_type, strlen(cpoint_type)); - if (cptype == CT_NONE) - return -EINVAL; - - for (i = 0; i < ARRAY_SIZE(cp_name); i++) { - if (!strcmp(cpoint_name, cp_name[i])) { - cpoint = i + 1; - return 0; - } - } - - /* Could not find a valid crash point */ - return -EINVAL; -} - -static int recursive_loop(int remaining) -{ - char buf[REC_STACK_SIZE]; - - /* Make sure compiler does not optimize this away. */ - memset(buf, (remaining & 0xff) | 0x1, REC_STACK_SIZE); - if (!remaining) - return 0; - else - return recursive_loop(remaining - 1); -} - -static void do_nothing(void) -{ - return; -} - -/* Must immediately follow do_nothing for size calculuations to work out. */ -static void do_overwritten(void) -{ - pr_info("do_overwritten wasn't overwritten!\n"); - return; -} - -static noinline void corrupt_stack(void) -{ - /* Use default char array length that triggers stack protection. */ - char data[8]; - - memset((void *)data, 0, 64); -} - -static void noinline execute_location(void *dst) -{ - void (*func)(void) = dst; - - pr_info("attempting ok execution at %p\n", do_nothing); - do_nothing(); - - memcpy(dst, do_nothing, EXEC_SIZE); - flush_icache_range((unsigned long)dst, (unsigned long)dst + EXEC_SIZE); - pr_info("attempting bad execution at %p\n", func); - func(); -} - -static void execute_user_location(void *dst) -{ - /* Intentionally crossing kernel/user memory boundary. */ - void (*func)(void) = dst; - - pr_info("attempting ok execution at %p\n", do_nothing); - do_nothing(); - - if (copy_to_user((void __user *)dst, do_nothing, EXEC_SIZE)) - return; - flush_icache_range((unsigned long)dst, (unsigned long)dst + EXEC_SIZE); - pr_info("attempting bad execution at %p\n", func); - func(); -} - -static void lkdtm_do_action(enum ctype which) -{ - switch (which) { - case CT_PANIC: - panic("dumptest"); - break; - case CT_BUG: - BUG(); - break; - case CT_WARNING: - WARN_ON(1); - break; - case CT_EXCEPTION: - *((int *) 0) = 0; - break; - case CT_LOOP: - for (;;) - ; - break; - case CT_OVERFLOW: - (void) recursive_loop(recur_count); - break; - case CT_CORRUPT_STACK: - corrupt_stack(); - break; - case CT_UNALIGNED_LOAD_STORE_WRITE: { - static u8 data[5] __attribute__((aligned(4))) = {1, 2, - 3, 4, 5}; - u32 *p; - u32 val = 0x12345678; - - p = (u32 *)(data + 1); - if (*p == 0) - val = 0x87654321; - *p = val; - break; - } - case CT_OVERWRITE_ALLOCATION: { - size_t len = 1020; - u32 *data = kmalloc(len, GFP_KERNEL); - - data[1024 / sizeof(u32)] = 0x12345678; - kfree(data); - break; - } - case CT_WRITE_AFTER_FREE: { - int *base, *again; - size_t len = 1024; - /* - * The slub allocator uses the first word to store the free - * pointer in some configurations. Use the middle of the - * allocation to avoid running into the freelist - */ - size_t offset = (len / sizeof(*base)) / 2; - - base = kmalloc(len, GFP_KERNEL); - pr_info("Allocated memory %p-%p\n", base, &base[offset * 2]); - pr_info("Attempting bad write to freed memory at %p\n", - &base[offset]); - kfree(base); - base[offset] = 0x0abcdef0; - /* Attempt to notice the overwrite. */ - again = kmalloc(len, GFP_KERNEL); - kfree(again); - if (again != base) - pr_info("Hmm, didn't get the same memory range.\n"); - - break; - } - case CT_READ_AFTER_FREE: { - int *base, *val, saw; - size_t len = 1024; - /* - * The slub allocator uses the first word to store the free - * pointer in some configurations. Use the middle of the - * allocation to avoid running into the freelist - */ - size_t offset = (len / sizeof(*base)) / 2; - - base = kmalloc(len, GFP_KERNEL); - if (!base) - break; - - val = kmalloc(len, GFP_KERNEL); - if (!val) { - kfree(base); - break; - } - - *val = 0x12345678; - base[offset] = *val; - pr_info("Value in memory before free: %x\n", base[offset]); - - kfree(base); - - pr_info("Attempting bad read from freed memory\n"); - saw = base[offset]; - if (saw != *val) { - /* Good! Poisoning happened, so declare a win. */ - pr_info("Memory correctly poisoned (%x)\n", saw); - BUG(); - } - pr_info("Memory was not poisoned\n"); - - kfree(val); - break; - } - case CT_WRITE_BUDDY_AFTER_FREE: { - unsigned long p = __get_free_page(GFP_KERNEL); - if (!p) - break; - pr_info("Writing to the buddy page before free\n"); - memset((void *)p, 0x3, PAGE_SIZE); - free_page(p); - schedule(); - pr_info("Attempting bad write to the buddy page after free\n"); - memset((void *)p, 0x78, PAGE_SIZE); - /* Attempt to notice the overwrite. */ - p = __get_free_page(GFP_KERNEL); - free_page(p); - schedule(); - - break; - } - case CT_READ_BUDDY_AFTER_FREE: { - unsigned long p = __get_free_page(GFP_KERNEL); - int saw, *val; - int *base; - - if (!p) - break; - - val = kmalloc(1024, GFP_KERNEL); - if (!val) { - free_page(p); - break; - } - - base = (int *)p; - - *val = 0x12345678; - base[0] = *val; - pr_info("Value in memory before free: %x\n", base[0]); - free_page(p); - pr_info("Attempting to read from freed memory\n"); - saw = base[0]; - if (saw != *val) { - /* Good! Poisoning happened, so declare a win. */ - pr_info("Memory correctly poisoned (%x)\n", saw); - BUG(); - } - pr_info("Buddy page was not poisoned\n"); - - kfree(val); - break; - } - case CT_SOFTLOCKUP: - preempt_disable(); - for (;;) - cpu_relax(); - break; - case CT_HARDLOCKUP: - local_irq_disable(); - for (;;) - cpu_relax(); - break; - case CT_SPINLOCKUP: - /* Must be called twice to trigger. */ - spin_lock(&lock_me_up); - /* Let sparse know we intended to exit holding the lock. */ - __release(&lock_me_up); - break; - case CT_HUNG_TASK: - set_current_state(TASK_UNINTERRUPTIBLE); - schedule(); - break; - case CT_EXEC_DATA: - execute_location(data_area); - break; - case CT_EXEC_STACK: { - u8 stack_area[EXEC_SIZE]; - execute_location(stack_area); - break; - } - case CT_EXEC_KMALLOC: { - u32 *kmalloc_area = kmalloc(EXEC_SIZE, GFP_KERNEL); - execute_location(kmalloc_area); - kfree(kmalloc_area); - break; - } - case CT_EXEC_VMALLOC: { - u32 *vmalloc_area = vmalloc(EXEC_SIZE); - execute_location(vmalloc_area); - vfree(vmalloc_area); - break; - } - case CT_EXEC_USERSPACE: { - unsigned long user_addr; - - user_addr = vm_mmap(NULL, 0, PAGE_SIZE, - PROT_READ | PROT_WRITE | PROT_EXEC, - MAP_ANONYMOUS | MAP_PRIVATE, 0); - if (user_addr >= TASK_SIZE) { - pr_warn("Failed to allocate user memory\n"); - return; - } - execute_user_location((void *)user_addr); - vm_munmap(user_addr, PAGE_SIZE); - break; - } - case CT_ACCESS_USERSPACE: { - unsigned long user_addr, tmp = 0; - unsigned long *ptr; - - user_addr = vm_mmap(NULL, 0, PAGE_SIZE, - PROT_READ | PROT_WRITE | PROT_EXEC, - MAP_ANONYMOUS | MAP_PRIVATE, 0); - if (user_addr >= TASK_SIZE) { - pr_warn("Failed to allocate user memory\n"); - return; - } - - if (copy_to_user((void __user *)user_addr, &tmp, sizeof(tmp))) { - pr_warn("copy_to_user failed\n"); - vm_munmap(user_addr, PAGE_SIZE); - return; - } - - ptr = (unsigned long *)user_addr; - - pr_info("attempting bad read at %p\n", ptr); - tmp = *ptr; - tmp += 0xc0dec0de; - - pr_info("attempting bad write at %p\n", ptr); - *ptr = tmp; - - vm_munmap(user_addr, PAGE_SIZE); - - break; - } - case CT_WRITE_RO: { - /* Explicitly cast away "const" for the test. */ - unsigned long *ptr = (unsigned long *)&rodata; - - pr_info("attempting bad rodata write at %p\n", ptr); - *ptr ^= 0xabcd1234; - - break; - } - case CT_WRITE_RO_AFTER_INIT: { - unsigned long *ptr = &ro_after_init; - - /* - * Verify we were written to during init. Since an Oops - * is considered a "success", a failure is to just skip the - * real test. - */ - if ((*ptr & 0xAA) != 0xAA) { - pr_info("%p was NOT written during init!?\n", ptr); - break; - } - - pr_info("attempting bad ro_after_init write at %p\n", ptr); - *ptr ^= 0xabcd1234; - - break; - } - case CT_WRITE_KERN: { - size_t size; - unsigned char *ptr; - - size = (unsigned long)do_overwritten - - (unsigned long)do_nothing; - ptr = (unsigned char *)do_overwritten; - - pr_info("attempting bad %zu byte write at %p\n", size, ptr); - memcpy(ptr, (unsigned char *)do_nothing, size); - flush_icache_range((unsigned long)ptr, - (unsigned long)(ptr + size)); - - do_overwritten(); - break; - } - case CT_WRAP_ATOMIC: { - atomic_t under = ATOMIC_INIT(INT_MIN); - atomic_t over = ATOMIC_INIT(INT_MAX); - - pr_info("attempting atomic underflow\n"); - atomic_dec(&under); - pr_info("attempting atomic overflow\n"); - atomic_inc(&over); - - return; - } - case CT_NONE: - default: - break; - } - -} - -static void lkdtm_handler(void) -{ - unsigned long flags; - bool do_it = false; - - spin_lock_irqsave(&count_lock, flags); - count--; - pr_info("Crash point %s of type %s hit, trigger in %d rounds\n", - cp_name_to_str(cpoint), cp_type_to_str(cptype), count); - - if (count == 0) { - do_it = true; - count = cpoint_count; - } - spin_unlock_irqrestore(&count_lock, flags); - - if (do_it) - lkdtm_do_action(cptype); -} - -static int lkdtm_register_cpoint(enum cname which) -{ - int ret; - - cpoint = CN_INVALID; - if (lkdtm.entry != NULL) - unregister_jprobe(&lkdtm); - - switch (which) { - case CN_DIRECT: - lkdtm_do_action(cptype); - return 0; - case CN_INT_HARDWARE_ENTRY: - lkdtm.kp.symbol_name = "do_IRQ"; - lkdtm.entry = (kprobe_opcode_t*) jp_do_irq; - break; - case CN_INT_HW_IRQ_EN: - lkdtm.kp.symbol_name = "handle_IRQ_event"; - lkdtm.entry = (kprobe_opcode_t*) jp_handle_irq_event; - break; - case CN_INT_TASKLET_ENTRY: - lkdtm.kp.symbol_name = "tasklet_action"; - lkdtm.entry = (kprobe_opcode_t*) jp_tasklet_action; - break; - case CN_FS_DEVRW: - lkdtm.kp.symbol_name = "ll_rw_block"; - lkdtm.entry = (kprobe_opcode_t*) jp_ll_rw_block; - break; - case CN_MEM_SWAPOUT: - lkdtm.kp.symbol_name = "shrink_inactive_list"; - lkdtm.entry = (kprobe_opcode_t*) jp_shrink_inactive_list; - break; - case CN_TIMERADD: - lkdtm.kp.symbol_name = "hrtimer_start"; - lkdtm.entry = (kprobe_opcode_t*) jp_hrtimer_start; - break; - case CN_SCSI_DISPATCH_CMD: - lkdtm.kp.symbol_name = "scsi_dispatch_cmd"; - lkdtm.entry = (kprobe_opcode_t*) jp_scsi_dispatch_cmd; - break; - case CN_IDE_CORE_CP: -#ifdef CONFIG_IDE - lkdtm.kp.symbol_name = "generic_ide_ioctl"; - lkdtm.entry = (kprobe_opcode_t*) jp_generic_ide_ioctl; -#else - pr_info("Crash point not available\n"); - return -EINVAL; -#endif - break; - default: - pr_info("Invalid Crash Point\n"); - return -EINVAL; - } - - cpoint = which; - if ((ret = register_jprobe(&lkdtm)) < 0) { - pr_info("Couldn't register jprobe\n"); - cpoint = CN_INVALID; - } - - return ret; -} - -static ssize_t do_register_entry(enum cname which, struct file *f, - const char __user *user_buf, size_t count, loff_t *off) -{ - char *buf; - int err; - - if (count >= PAGE_SIZE) - return -EINVAL; - - buf = (char *)__get_free_page(GFP_KERNEL); - if (!buf) - return -ENOMEM; - if (copy_from_user(buf, user_buf, count)) { - free_page((unsigned long) buf); - return -EFAULT; - } - /* NULL-terminate and remove enter */ - buf[count] = '\0'; - strim(buf); - - cptype = parse_cp_type(buf, count); - free_page((unsigned long) buf); - - if (cptype == CT_NONE) - return -EINVAL; - - err = lkdtm_register_cpoint(which); - if (err < 0) - return err; - - *off += count; - - return count; -} - -/* Generic read callback that just prints out the available crash types */ -static ssize_t lkdtm_debugfs_read(struct file *f, char __user *user_buf, - size_t count, loff_t *off) -{ - char *buf; - int i, n, out; - - buf = (char *)__get_free_page(GFP_KERNEL); - if (buf == NULL) - return -ENOMEM; - - n = snprintf(buf, PAGE_SIZE, "Available crash types:\n"); - for (i = 0; i < ARRAY_SIZE(cp_type); i++) - n += snprintf(buf + n, PAGE_SIZE - n, "%s\n", cp_type[i]); - buf[n] = '\0'; - - out = simple_read_from_buffer(user_buf, count, off, - buf, n); - free_page((unsigned long) buf); - - return out; -} - -static int lkdtm_debugfs_open(struct inode *inode, struct file *file) -{ - return 0; -} - - -static ssize_t int_hardware_entry(struct file *f, const char __user *buf, - size_t count, loff_t *off) -{ - return do_register_entry(CN_INT_HARDWARE_ENTRY, f, buf, count, off); -} - -static ssize_t int_hw_irq_en(struct file *f, const char __user *buf, - size_t count, loff_t *off) -{ - return do_register_entry(CN_INT_HW_IRQ_EN, f, buf, count, off); -} - -static ssize_t int_tasklet_entry(struct file *f, const char __user *buf, - size_t count, loff_t *off) -{ - return do_register_entry(CN_INT_TASKLET_ENTRY, f, buf, count, off); -} - -static ssize_t fs_devrw_entry(struct file *f, const char __user *buf, - size_t count, loff_t *off) -{ - return do_register_entry(CN_FS_DEVRW, f, buf, count, off); -} - -static ssize_t mem_swapout_entry(struct file *f, const char __user *buf, - size_t count, loff_t *off) -{ - return do_register_entry(CN_MEM_SWAPOUT, f, buf, count, off); -} - -static ssize_t timeradd_entry(struct file *f, const char __user *buf, - size_t count, loff_t *off) -{ - return do_register_entry(CN_TIMERADD, f, buf, count, off); -} - -static ssize_t scsi_dispatch_cmd_entry(struct file *f, - const char __user *buf, size_t count, loff_t *off) -{ - return do_register_entry(CN_SCSI_DISPATCH_CMD, f, buf, count, off); -} - -static ssize_t ide_core_cp_entry(struct file *f, const char __user *buf, - size_t count, loff_t *off) -{ - return do_register_entry(CN_IDE_CORE_CP, f, buf, count, off); -} - -/* Special entry to just crash directly. Available without KPROBEs */ -static ssize_t direct_entry(struct file *f, const char __user *user_buf, - size_t count, loff_t *off) -{ - enum ctype type; - char *buf; - - if (count >= PAGE_SIZE) - return -EINVAL; - if (count < 1) - return -EINVAL; - - buf = (char *)__get_free_page(GFP_KERNEL); - if (!buf) - return -ENOMEM; - if (copy_from_user(buf, user_buf, count)) { - free_page((unsigned long) buf); - return -EFAULT; - } - /* NULL-terminate and remove enter */ - buf[count] = '\0'; - strim(buf); - - type = parse_cp_type(buf, count); - free_page((unsigned long) buf); - if (type == CT_NONE) - return -EINVAL; - - pr_info("Performing direct entry %s\n", cp_type_to_str(type)); - lkdtm_do_action(type); - *off += count; - - return count; -} - -struct crash_entry { - const char *name; - const struct file_operations fops; -}; - -static const struct crash_entry crash_entries[] = { - {"DIRECT", {.read = lkdtm_debugfs_read, - .llseek = generic_file_llseek, - .open = lkdtm_debugfs_open, - .write = direct_entry} }, - {"INT_HARDWARE_ENTRY", {.read = lkdtm_debugfs_read, - .llseek = generic_file_llseek, - .open = lkdtm_debugfs_open, - .write = int_hardware_entry} }, - {"INT_HW_IRQ_EN", {.read = lkdtm_debugfs_read, - .llseek = generic_file_llseek, - .open = lkdtm_debugfs_open, - .write = int_hw_irq_en} }, - {"INT_TASKLET_ENTRY", {.read = lkdtm_debugfs_read, - .llseek = generic_file_llseek, - .open = lkdtm_debugfs_open, - .write = int_tasklet_entry} }, - {"FS_DEVRW", {.read = lkdtm_debugfs_read, - .llseek = generic_file_llseek, - .open = lkdtm_debugfs_open, - .write = fs_devrw_entry} }, - {"MEM_SWAPOUT", {.read = lkdtm_debugfs_read, - .llseek = generic_file_llseek, - .open = lkdtm_debugfs_open, - .write = mem_swapout_entry} }, - {"TIMERADD", {.read = lkdtm_debugfs_read, - .llseek = generic_file_llseek, - .open = lkdtm_debugfs_open, - .write = timeradd_entry} }, - {"SCSI_DISPATCH_CMD", {.read = lkdtm_debugfs_read, - .llseek = generic_file_llseek, - .open = lkdtm_debugfs_open, - .write = scsi_dispatch_cmd_entry} }, - {"IDE_CORE_CP", {.read = lkdtm_debugfs_read, - .llseek = generic_file_llseek, - .open = lkdtm_debugfs_open, - .write = ide_core_cp_entry} }, -}; - -static struct dentry *lkdtm_debugfs_root; - -static int __init lkdtm_module_init(void) -{ - int ret = -EINVAL; - int n_debugfs_entries = 1; /* Assume only the direct entry */ - int i; - - /* Make sure we can write to __ro_after_init values during __init */ - ro_after_init |= 0xAA; - - /* Register debugfs interface */ - lkdtm_debugfs_root = debugfs_create_dir("provoke-crash", NULL); - if (!lkdtm_debugfs_root) { - pr_err("creating root dir failed\n"); - return -ENODEV; - } - -#ifdef CONFIG_KPROBES - n_debugfs_entries = ARRAY_SIZE(crash_entries); -#endif - - for (i = 0; i < n_debugfs_entries; i++) { - const struct crash_entry *cur = &crash_entries[i]; - struct dentry *de; - - de = debugfs_create_file(cur->name, 0644, lkdtm_debugfs_root, - NULL, &cur->fops); - if (de == NULL) { - pr_err("could not create %s\n", cur->name); - goto out_err; - } - } - - if (lkdtm_parse_commandline() == -EINVAL) { - pr_info("Invalid command\n"); - goto out_err; - } - - if (cpoint != CN_INVALID && cptype != CT_NONE) { - ret = lkdtm_register_cpoint(cpoint); - if (ret < 0) { - pr_info("Invalid crash point %d\n", cpoint); - goto out_err; - } - pr_info("Crash point %s of type %s registered\n", - cpoint_name, cpoint_type); - } else { - pr_info("No crash points registered, enable through debugfs\n"); - } - - return 0; - -out_err: - debugfs_remove_recursive(lkdtm_debugfs_root); - return ret; -} - -static void __exit lkdtm_module_exit(void) -{ - debugfs_remove_recursive(lkdtm_debugfs_root); - - unregister_jprobe(&lkdtm); - pr_info("Crash point unregistered\n"); -} - -module_init(lkdtm_module_init); -module_exit(lkdtm_module_exit); - -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("Kprobe module for testing crash dumps"); diff --git a/drivers/misc/lkdtm_core.c b/drivers/misc/lkdtm_core.c new file mode 100644 index 0000000..0a5cbbe --- /dev/null +++ b/drivers/misc/lkdtm_core.c @@ -0,0 +1,1023 @@ +/* + * Kprobe module for testing crash dumps + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * Copyright (C) IBM Corporation, 2006 + * + * Author: Ankita Garg + * + * This module induces system failures at predefined crashpoints to + * evaluate the reliability of crash dumps obtained using different dumping + * solutions. + * + * It is adapted from the Linux Kernel Dump Test Tool by + * Fernando Luis Vazquez Cao + * + * Debugfs support added by Simon Kagstrom + * + * See Documentation/fault-injection/provoke-crashes.txt for instructions + */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_IDE +#include +#endif + +/* + * Make sure our attempts to over run the kernel stack doesn't trigger + * a compiler warning when CONFIG_FRAME_WARN is set. Then make sure we + * recurse past the end of THREAD_SIZE by default. + */ +#if defined(CONFIG_FRAME_WARN) && (CONFIG_FRAME_WARN > 0) +#define REC_STACK_SIZE (CONFIG_FRAME_WARN / 2) +#else +#define REC_STACK_SIZE (THREAD_SIZE / 8) +#endif +#define REC_NUM_DEFAULT ((THREAD_SIZE / REC_STACK_SIZE) * 2) + +#define DEFAULT_COUNT 10 +#define EXEC_SIZE 64 + +enum cname { + CN_INVALID, + CN_INT_HARDWARE_ENTRY, + CN_INT_HW_IRQ_EN, + CN_INT_TASKLET_ENTRY, + CN_FS_DEVRW, + CN_MEM_SWAPOUT, + CN_TIMERADD, + CN_SCSI_DISPATCH_CMD, + CN_IDE_CORE_CP, + CN_DIRECT, +}; + +enum ctype { + CT_NONE, + CT_PANIC, + CT_BUG, + CT_WARNING, + CT_EXCEPTION, + CT_LOOP, + CT_OVERFLOW, + CT_CORRUPT_STACK, + CT_UNALIGNED_LOAD_STORE_WRITE, + CT_OVERWRITE_ALLOCATION, + CT_WRITE_AFTER_FREE, + CT_READ_AFTER_FREE, + CT_WRITE_BUDDY_AFTER_FREE, + CT_READ_BUDDY_AFTER_FREE, + CT_SOFTLOCKUP, + CT_HARDLOCKUP, + CT_SPINLOCKUP, + CT_HUNG_TASK, + CT_EXEC_DATA, + CT_EXEC_STACK, + CT_EXEC_KMALLOC, + CT_EXEC_VMALLOC, + CT_EXEC_USERSPACE, + CT_ACCESS_USERSPACE, + CT_WRITE_RO, + CT_WRITE_RO_AFTER_INIT, + CT_WRITE_KERN, + CT_WRAP_ATOMIC +}; + +static char* cp_name[] = { + "INT_HARDWARE_ENTRY", + "INT_HW_IRQ_EN", + "INT_TASKLET_ENTRY", + "FS_DEVRW", + "MEM_SWAPOUT", + "TIMERADD", + "SCSI_DISPATCH_CMD", + "IDE_CORE_CP", + "DIRECT", +}; + +static char* cp_type[] = { + "PANIC", + "BUG", + "WARNING", + "EXCEPTION", + "LOOP", + "OVERFLOW", + "CORRUPT_STACK", + "UNALIGNED_LOAD_STORE_WRITE", + "OVERWRITE_ALLOCATION", + "WRITE_AFTER_FREE", + "READ_AFTER_FREE", + "WRITE_BUDDY_AFTER_FREE", + "READ_BUDDY_AFTER_FREE", + "SOFTLOCKUP", + "HARDLOCKUP", + "SPINLOCKUP", + "HUNG_TASK", + "EXEC_DATA", + "EXEC_STACK", + "EXEC_KMALLOC", + "EXEC_VMALLOC", + "EXEC_USERSPACE", + "ACCESS_USERSPACE", + "WRITE_RO", + "WRITE_RO_AFTER_INIT", + "WRITE_KERN", + "WRAP_ATOMIC" +}; + +static struct jprobe lkdtm; + +static int lkdtm_parse_commandline(void); +static void lkdtm_handler(void); + +static char* cpoint_name; +static char* cpoint_type; +static int cpoint_count = DEFAULT_COUNT; +static int recur_count = REC_NUM_DEFAULT; + +static enum cname cpoint = CN_INVALID; +static enum ctype cptype = CT_NONE; +static int count = DEFAULT_COUNT; +static DEFINE_SPINLOCK(count_lock); +static DEFINE_SPINLOCK(lock_me_up); + +static u8 data_area[EXEC_SIZE]; + +static const unsigned long rodata = 0xAA55AA55; +static unsigned long ro_after_init __ro_after_init = 0x55AA5500; + +module_param(recur_count, int, 0644); +MODULE_PARM_DESC(recur_count, " Recursion level for the stack overflow test"); +module_param(cpoint_name, charp, 0444); +MODULE_PARM_DESC(cpoint_name, " Crash Point, where kernel is to be crashed"); +module_param(cpoint_type, charp, 0444); +MODULE_PARM_DESC(cpoint_type, " Crash Point Type, action to be taken on "\ + "hitting the crash point"); +module_param(cpoint_count, int, 0644); +MODULE_PARM_DESC(cpoint_count, " Crash Point Count, number of times the "\ + "crash point is to be hit to trigger action"); + +static unsigned int jp_do_irq(unsigned int irq) +{ + lkdtm_handler(); + jprobe_return(); + return 0; +} + +static irqreturn_t jp_handle_irq_event(unsigned int irq, + struct irqaction *action) +{ + lkdtm_handler(); + jprobe_return(); + return 0; +} + +static void jp_tasklet_action(struct softirq_action *a) +{ + lkdtm_handler(); + jprobe_return(); +} + +static void jp_ll_rw_block(int rw, int nr, struct buffer_head *bhs[]) +{ + lkdtm_handler(); + jprobe_return(); +} + +struct scan_control; + +static unsigned long jp_shrink_inactive_list(unsigned long max_scan, + struct zone *zone, + struct scan_control *sc) +{ + lkdtm_handler(); + jprobe_return(); + return 0; +} + +static int jp_hrtimer_start(struct hrtimer *timer, ktime_t tim, + const enum hrtimer_mode mode) +{ + lkdtm_handler(); + jprobe_return(); + return 0; +} + +static int jp_scsi_dispatch_cmd(struct scsi_cmnd *cmd) +{ + lkdtm_handler(); + jprobe_return(); + return 0; +} + +#ifdef CONFIG_IDE +static int jp_generic_ide_ioctl(ide_drive_t *drive, struct file *file, + struct block_device *bdev, unsigned int cmd, + unsigned long arg) +{ + lkdtm_handler(); + jprobe_return(); + return 0; +} +#endif + +/* Return the crashpoint number or NONE if the name is invalid */ +static enum ctype parse_cp_type(const char *what, size_t count) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(cp_type); i++) { + if (!strcmp(what, cp_type[i])) + return i + 1; + } + + return CT_NONE; +} + +static const char *cp_type_to_str(enum ctype type) +{ + if (type == CT_NONE || type < 0 || type > ARRAY_SIZE(cp_type)) + return "None"; + + return cp_type[type - 1]; +} + +static const char *cp_name_to_str(enum cname name) +{ + if (name == CN_INVALID || name < 0 || name > ARRAY_SIZE(cp_name)) + return "INVALID"; + + return cp_name[name - 1]; +} + + +static int lkdtm_parse_commandline(void) +{ + int i; + unsigned long flags; + + if (cpoint_count < 1 || recur_count < 1) + return -EINVAL; + + spin_lock_irqsave(&count_lock, flags); + count = cpoint_count; + spin_unlock_irqrestore(&count_lock, flags); + + /* No special parameters */ + if (!cpoint_type && !cpoint_name) + return 0; + + /* Neither or both of these need to be set */ + if (!cpoint_type || !cpoint_name) + return -EINVAL; + + cptype = parse_cp_type(cpoint_type, strlen(cpoint_type)); + if (cptype == CT_NONE) + return -EINVAL; + + for (i = 0; i < ARRAY_SIZE(cp_name); i++) { + if (!strcmp(cpoint_name, cp_name[i])) { + cpoint = i + 1; + return 0; + } + } + + /* Could not find a valid crash point */ + return -EINVAL; +} + +static int recursive_loop(int remaining) +{ + char buf[REC_STACK_SIZE]; + + /* Make sure compiler does not optimize this away. */ + memset(buf, (remaining & 0xff) | 0x1, REC_STACK_SIZE); + if (!remaining) + return 0; + else + return recursive_loop(remaining - 1); +} + +static void do_nothing(void) +{ + return; +} + +/* Must immediately follow do_nothing for size calculuations to work out. */ +static void do_overwritten(void) +{ + pr_info("do_overwritten wasn't overwritten!\n"); + return; +} + +static noinline void corrupt_stack(void) +{ + /* Use default char array length that triggers stack protection. */ + char data[8]; + + memset((void *)data, 0, 64); +} + +static void noinline execute_location(void *dst) +{ + void (*func)(void) = dst; + + pr_info("attempting ok execution at %p\n", do_nothing); + do_nothing(); + + memcpy(dst, do_nothing, EXEC_SIZE); + flush_icache_range((unsigned long)dst, (unsigned long)dst + EXEC_SIZE); + pr_info("attempting bad execution at %p\n", func); + func(); +} + +static void execute_user_location(void *dst) +{ + /* Intentionally crossing kernel/user memory boundary. */ + void (*func)(void) = dst; + + pr_info("attempting ok execution at %p\n", do_nothing); + do_nothing(); + + if (copy_to_user((void __user *)dst, do_nothing, EXEC_SIZE)) + return; + flush_icache_range((unsigned long)dst, (unsigned long)dst + EXEC_SIZE); + pr_info("attempting bad execution at %p\n", func); + func(); +} + +static void lkdtm_do_action(enum ctype which) +{ + switch (which) { + case CT_PANIC: + panic("dumptest"); + break; + case CT_BUG: + BUG(); + break; + case CT_WARNING: + WARN_ON(1); + break; + case CT_EXCEPTION: + *((int *) 0) = 0; + break; + case CT_LOOP: + for (;;) + ; + break; + case CT_OVERFLOW: + (void) recursive_loop(recur_count); + break; + case CT_CORRUPT_STACK: + corrupt_stack(); + break; + case CT_UNALIGNED_LOAD_STORE_WRITE: { + static u8 data[5] __attribute__((aligned(4))) = {1, 2, + 3, 4, 5}; + u32 *p; + u32 val = 0x12345678; + + p = (u32 *)(data + 1); + if (*p == 0) + val = 0x87654321; + *p = val; + break; + } + case CT_OVERWRITE_ALLOCATION: { + size_t len = 1020; + u32 *data = kmalloc(len, GFP_KERNEL); + + data[1024 / sizeof(u32)] = 0x12345678; + kfree(data); + break; + } + case CT_WRITE_AFTER_FREE: { + int *base, *again; + size_t len = 1024; + /* + * The slub allocator uses the first word to store the free + * pointer in some configurations. Use the middle of the + * allocation to avoid running into the freelist + */ + size_t offset = (len / sizeof(*base)) / 2; + + base = kmalloc(len, GFP_KERNEL); + pr_info("Allocated memory %p-%p\n", base, &base[offset * 2]); + pr_info("Attempting bad write to freed memory at %p\n", + &base[offset]); + kfree(base); + base[offset] = 0x0abcdef0; + /* Attempt to notice the overwrite. */ + again = kmalloc(len, GFP_KERNEL); + kfree(again); + if (again != base) + pr_info("Hmm, didn't get the same memory range.\n"); + + break; + } + case CT_READ_AFTER_FREE: { + int *base, *val, saw; + size_t len = 1024; + /* + * The slub allocator uses the first word to store the free + * pointer in some configurations. Use the middle of the + * allocation to avoid running into the freelist + */ + size_t offset = (len / sizeof(*base)) / 2; + + base = kmalloc(len, GFP_KERNEL); + if (!base) + break; + + val = kmalloc(len, GFP_KERNEL); + if (!val) { + kfree(base); + break; + } + + *val = 0x12345678; + base[offset] = *val; + pr_info("Value in memory before free: %x\n", base[offset]); + + kfree(base); + + pr_info("Attempting bad read from freed memory\n"); + saw = base[offset]; + if (saw != *val) { + /* Good! Poisoning happened, so declare a win. */ + pr_info("Memory correctly poisoned (%x)\n", saw); + BUG(); + } + pr_info("Memory was not poisoned\n"); + + kfree(val); + break; + } + case CT_WRITE_BUDDY_AFTER_FREE: { + unsigned long p = __get_free_page(GFP_KERNEL); + if (!p) + break; + pr_info("Writing to the buddy page before free\n"); + memset((void *)p, 0x3, PAGE_SIZE); + free_page(p); + schedule(); + pr_info("Attempting bad write to the buddy page after free\n"); + memset((void *)p, 0x78, PAGE_SIZE); + /* Attempt to notice the overwrite. */ + p = __get_free_page(GFP_KERNEL); + free_page(p); + schedule(); + + break; + } + case CT_READ_BUDDY_AFTER_FREE: { + unsigned long p = __get_free_page(GFP_KERNEL); + int saw, *val; + int *base; + + if (!p) + break; + + val = kmalloc(1024, GFP_KERNEL); + if (!val) { + free_page(p); + break; + } + + base = (int *)p; + + *val = 0x12345678; + base[0] = *val; + pr_info("Value in memory before free: %x\n", base[0]); + free_page(p); + pr_info("Attempting to read from freed memory\n"); + saw = base[0]; + if (saw != *val) { + /* Good! Poisoning happened, so declare a win. */ + pr_info("Memory correctly poisoned (%x)\n", saw); + BUG(); + } + pr_info("Buddy page was not poisoned\n"); + + kfree(val); + break; + } + case CT_SOFTLOCKUP: + preempt_disable(); + for (;;) + cpu_relax(); + break; + case CT_HARDLOCKUP: + local_irq_disable(); + for (;;) + cpu_relax(); + break; + case CT_SPINLOCKUP: + /* Must be called twice to trigger. */ + spin_lock(&lock_me_up); + /* Let sparse know we intended to exit holding the lock. */ + __release(&lock_me_up); + break; + case CT_HUNG_TASK: + set_current_state(TASK_UNINTERRUPTIBLE); + schedule(); + break; + case CT_EXEC_DATA: + execute_location(data_area); + break; + case CT_EXEC_STACK: { + u8 stack_area[EXEC_SIZE]; + execute_location(stack_area); + break; + } + case CT_EXEC_KMALLOC: { + u32 *kmalloc_area = kmalloc(EXEC_SIZE, GFP_KERNEL); + execute_location(kmalloc_area); + kfree(kmalloc_area); + break; + } + case CT_EXEC_VMALLOC: { + u32 *vmalloc_area = vmalloc(EXEC_SIZE); + execute_location(vmalloc_area); + vfree(vmalloc_area); + break; + } + case CT_EXEC_USERSPACE: { + unsigned long user_addr; + + user_addr = vm_mmap(NULL, 0, PAGE_SIZE, + PROT_READ | PROT_WRITE | PROT_EXEC, + MAP_ANONYMOUS | MAP_PRIVATE, 0); + if (user_addr >= TASK_SIZE) { + pr_warn("Failed to allocate user memory\n"); + return; + } + execute_user_location((void *)user_addr); + vm_munmap(user_addr, PAGE_SIZE); + break; + } + case CT_ACCESS_USERSPACE: { + unsigned long user_addr, tmp = 0; + unsigned long *ptr; + + user_addr = vm_mmap(NULL, 0, PAGE_SIZE, + PROT_READ | PROT_WRITE | PROT_EXEC, + MAP_ANONYMOUS | MAP_PRIVATE, 0); + if (user_addr >= TASK_SIZE) { + pr_warn("Failed to allocate user memory\n"); + return; + } + + if (copy_to_user((void __user *)user_addr, &tmp, sizeof(tmp))) { + pr_warn("copy_to_user failed\n"); + vm_munmap(user_addr, PAGE_SIZE); + return; + } + + ptr = (unsigned long *)user_addr; + + pr_info("attempting bad read at %p\n", ptr); + tmp = *ptr; + tmp += 0xc0dec0de; + + pr_info("attempting bad write at %p\n", ptr); + *ptr = tmp; + + vm_munmap(user_addr, PAGE_SIZE); + + break; + } + case CT_WRITE_RO: { + /* Explicitly cast away "const" for the test. */ + unsigned long *ptr = (unsigned long *)&rodata; + + pr_info("attempting bad rodata write at %p\n", ptr); + *ptr ^= 0xabcd1234; + + break; + } + case CT_WRITE_RO_AFTER_INIT: { + unsigned long *ptr = &ro_after_init; + + /* + * Verify we were written to during init. Since an Oops + * is considered a "success", a failure is to just skip the + * real test. + */ + if ((*ptr & 0xAA) != 0xAA) { + pr_info("%p was NOT written during init!?\n", ptr); + break; + } + + pr_info("attempting bad ro_after_init write at %p\n", ptr); + *ptr ^= 0xabcd1234; + + break; + } + case CT_WRITE_KERN: { + size_t size; + unsigned char *ptr; + + size = (unsigned long)do_overwritten - + (unsigned long)do_nothing; + ptr = (unsigned char *)do_overwritten; + + pr_info("attempting bad %zu byte write at %p\n", size, ptr); + memcpy(ptr, (unsigned char *)do_nothing, size); + flush_icache_range((unsigned long)ptr, + (unsigned long)(ptr + size)); + + do_overwritten(); + break; + } + case CT_WRAP_ATOMIC: { + atomic_t under = ATOMIC_INIT(INT_MIN); + atomic_t over = ATOMIC_INIT(INT_MAX); + + pr_info("attempting atomic underflow\n"); + atomic_dec(&under); + pr_info("attempting atomic overflow\n"); + atomic_inc(&over); + + return; + } + case CT_NONE: + default: + break; + } + +} + +static void lkdtm_handler(void) +{ + unsigned long flags; + bool do_it = false; + + spin_lock_irqsave(&count_lock, flags); + count--; + pr_info("Crash point %s of type %s hit, trigger in %d rounds\n", + cp_name_to_str(cpoint), cp_type_to_str(cptype), count); + + if (count == 0) { + do_it = true; + count = cpoint_count; + } + spin_unlock_irqrestore(&count_lock, flags); + + if (do_it) + lkdtm_do_action(cptype); +} + +static int lkdtm_register_cpoint(enum cname which) +{ + int ret; + + cpoint = CN_INVALID; + if (lkdtm.entry != NULL) + unregister_jprobe(&lkdtm); + + switch (which) { + case CN_DIRECT: + lkdtm_do_action(cptype); + return 0; + case CN_INT_HARDWARE_ENTRY: + lkdtm.kp.symbol_name = "do_IRQ"; + lkdtm.entry = (kprobe_opcode_t*) jp_do_irq; + break; + case CN_INT_HW_IRQ_EN: + lkdtm.kp.symbol_name = "handle_IRQ_event"; + lkdtm.entry = (kprobe_opcode_t*) jp_handle_irq_event; + break; + case CN_INT_TASKLET_ENTRY: + lkdtm.kp.symbol_name = "tasklet_action"; + lkdtm.entry = (kprobe_opcode_t*) jp_tasklet_action; + break; + case CN_FS_DEVRW: + lkdtm.kp.symbol_name = "ll_rw_block"; + lkdtm.entry = (kprobe_opcode_t*) jp_ll_rw_block; + break; + case CN_MEM_SWAPOUT: + lkdtm.kp.symbol_name = "shrink_inactive_list"; + lkdtm.entry = (kprobe_opcode_t*) jp_shrink_inactive_list; + break; + case CN_TIMERADD: + lkdtm.kp.symbol_name = "hrtimer_start"; + lkdtm.entry = (kprobe_opcode_t*) jp_hrtimer_start; + break; + case CN_SCSI_DISPATCH_CMD: + lkdtm.kp.symbol_name = "scsi_dispatch_cmd"; + lkdtm.entry = (kprobe_opcode_t*) jp_scsi_dispatch_cmd; + break; + case CN_IDE_CORE_CP: +#ifdef CONFIG_IDE + lkdtm.kp.symbol_name = "generic_ide_ioctl"; + lkdtm.entry = (kprobe_opcode_t*) jp_generic_ide_ioctl; +#else + pr_info("Crash point not available\n"); + return -EINVAL; +#endif + break; + default: + pr_info("Invalid Crash Point\n"); + return -EINVAL; + } + + cpoint = which; + if ((ret = register_jprobe(&lkdtm)) < 0) { + pr_info("Couldn't register jprobe\n"); + cpoint = CN_INVALID; + } + + return ret; +} + +static ssize_t do_register_entry(enum cname which, struct file *f, + const char __user *user_buf, size_t count, loff_t *off) +{ + char *buf; + int err; + + if (count >= PAGE_SIZE) + return -EINVAL; + + buf = (char *)__get_free_page(GFP_KERNEL); + if (!buf) + return -ENOMEM; + if (copy_from_user(buf, user_buf, count)) { + free_page((unsigned long) buf); + return -EFAULT; + } + /* NULL-terminate and remove enter */ + buf[count] = '\0'; + strim(buf); + + cptype = parse_cp_type(buf, count); + free_page((unsigned long) buf); + + if (cptype == CT_NONE) + return -EINVAL; + + err = lkdtm_register_cpoint(which); + if (err < 0) + return err; + + *off += count; + + return count; +} + +/* Generic read callback that just prints out the available crash types */ +static ssize_t lkdtm_debugfs_read(struct file *f, char __user *user_buf, + size_t count, loff_t *off) +{ + char *buf; + int i, n, out; + + buf = (char *)__get_free_page(GFP_KERNEL); + if (buf == NULL) + return -ENOMEM; + + n = snprintf(buf, PAGE_SIZE, "Available crash types:\n"); + for (i = 0; i < ARRAY_SIZE(cp_type); i++) + n += snprintf(buf + n, PAGE_SIZE - n, "%s\n", cp_type[i]); + buf[n] = '\0'; + + out = simple_read_from_buffer(user_buf, count, off, + buf, n); + free_page((unsigned long) buf); + + return out; +} + +static int lkdtm_debugfs_open(struct inode *inode, struct file *file) +{ + return 0; +} + + +static ssize_t int_hardware_entry(struct file *f, const char __user *buf, + size_t count, loff_t *off) +{ + return do_register_entry(CN_INT_HARDWARE_ENTRY, f, buf, count, off); +} + +static ssize_t int_hw_irq_en(struct file *f, const char __user *buf, + size_t count, loff_t *off) +{ + return do_register_entry(CN_INT_HW_IRQ_EN, f, buf, count, off); +} + +static ssize_t int_tasklet_entry(struct file *f, const char __user *buf, + size_t count, loff_t *off) +{ + return do_register_entry(CN_INT_TASKLET_ENTRY, f, buf, count, off); +} + +static ssize_t fs_devrw_entry(struct file *f, const char __user *buf, + size_t count, loff_t *off) +{ + return do_register_entry(CN_FS_DEVRW, f, buf, count, off); +} + +static ssize_t mem_swapout_entry(struct file *f, const char __user *buf, + size_t count, loff_t *off) +{ + return do_register_entry(CN_MEM_SWAPOUT, f, buf, count, off); +} + +static ssize_t timeradd_entry(struct file *f, const char __user *buf, + size_t count, loff_t *off) +{ + return do_register_entry(CN_TIMERADD, f, buf, count, off); +} + +static ssize_t scsi_dispatch_cmd_entry(struct file *f, + const char __user *buf, size_t count, loff_t *off) +{ + return do_register_entry(CN_SCSI_DISPATCH_CMD, f, buf, count, off); +} + +static ssize_t ide_core_cp_entry(struct file *f, const char __user *buf, + size_t count, loff_t *off) +{ + return do_register_entry(CN_IDE_CORE_CP, f, buf, count, off); +} + +/* Special entry to just crash directly. Available without KPROBEs */ +static ssize_t direct_entry(struct file *f, const char __user *user_buf, + size_t count, loff_t *off) +{ + enum ctype type; + char *buf; + + if (count >= PAGE_SIZE) + return -EINVAL; + if (count < 1) + return -EINVAL; + + buf = (char *)__get_free_page(GFP_KERNEL); + if (!buf) + return -ENOMEM; + if (copy_from_user(buf, user_buf, count)) { + free_page((unsigned long) buf); + return -EFAULT; + } + /* NULL-terminate and remove enter */ + buf[count] = '\0'; + strim(buf); + + type = parse_cp_type(buf, count); + free_page((unsigned long) buf); + if (type == CT_NONE) + return -EINVAL; + + pr_info("Performing direct entry %s\n", cp_type_to_str(type)); + lkdtm_do_action(type); + *off += count; + + return count; +} + +struct crash_entry { + const char *name; + const struct file_operations fops; +}; + +static const struct crash_entry crash_entries[] = { + {"DIRECT", {.read = lkdtm_debugfs_read, + .llseek = generic_file_llseek, + .open = lkdtm_debugfs_open, + .write = direct_entry} }, + {"INT_HARDWARE_ENTRY", {.read = lkdtm_debugfs_read, + .llseek = generic_file_llseek, + .open = lkdtm_debugfs_open, + .write = int_hardware_entry} }, + {"INT_HW_IRQ_EN", {.read = lkdtm_debugfs_read, + .llseek = generic_file_llseek, + .open = lkdtm_debugfs_open, + .write = int_hw_irq_en} }, + {"INT_TASKLET_ENTRY", {.read = lkdtm_debugfs_read, + .llseek = generic_file_llseek, + .open = lkdtm_debugfs_open, + .write = int_tasklet_entry} }, + {"FS_DEVRW", {.read = lkdtm_debugfs_read, + .llseek = generic_file_llseek, + .open = lkdtm_debugfs_open, + .write = fs_devrw_entry} }, + {"MEM_SWAPOUT", {.read = lkdtm_debugfs_read, + .llseek = generic_file_llseek, + .open = lkdtm_debugfs_open, + .write = mem_swapout_entry} }, + {"TIMERADD", {.read = lkdtm_debugfs_read, + .llseek = generic_file_llseek, + .open = lkdtm_debugfs_open, + .write = timeradd_entry} }, + {"SCSI_DISPATCH_CMD", {.read = lkdtm_debugfs_read, + .llseek = generic_file_llseek, + .open = lkdtm_debugfs_open, + .write = scsi_dispatch_cmd_entry} }, + {"IDE_CORE_CP", {.read = lkdtm_debugfs_read, + .llseek = generic_file_llseek, + .open = lkdtm_debugfs_open, + .write = ide_core_cp_entry} }, +}; + +static struct dentry *lkdtm_debugfs_root; + +static int __init lkdtm_module_init(void) +{ + int ret = -EINVAL; + int n_debugfs_entries = 1; /* Assume only the direct entry */ + int i; + + /* Make sure we can write to __ro_after_init values during __init */ + ro_after_init |= 0xAA; + + /* Register debugfs interface */ + lkdtm_debugfs_root = debugfs_create_dir("provoke-crash", NULL); + if (!lkdtm_debugfs_root) { + pr_err("creating root dir failed\n"); + return -ENODEV; + } + +#ifdef CONFIG_KPROBES + n_debugfs_entries = ARRAY_SIZE(crash_entries); +#endif + + for (i = 0; i < n_debugfs_entries; i++) { + const struct crash_entry *cur = &crash_entries[i]; + struct dentry *de; + + de = debugfs_create_file(cur->name, 0644, lkdtm_debugfs_root, + NULL, &cur->fops); + if (de == NULL) { + pr_err("could not create %s\n", cur->name); + goto out_err; + } + } + + if (lkdtm_parse_commandline() == -EINVAL) { + pr_info("Invalid command\n"); + goto out_err; + } + + if (cpoint != CN_INVALID && cptype != CT_NONE) { + ret = lkdtm_register_cpoint(cpoint); + if (ret < 0) { + pr_info("Invalid crash point %d\n", cpoint); + goto out_err; + } + pr_info("Crash point %s of type %s registered\n", + cpoint_name, cpoint_type); + } else { + pr_info("No crash points registered, enable through debugfs\n"); + } + + return 0; + +out_err: + debugfs_remove_recursive(lkdtm_debugfs_root); + return ret; +} + +static void __exit lkdtm_module_exit(void) +{ + debugfs_remove_recursive(lkdtm_debugfs_root); + + unregister_jprobe(&lkdtm); + pr_info("Crash point unregistered\n"); +} + +module_init(lkdtm_module_init); +module_exit(lkdtm_module_exit); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Kprobe module for testing crash dumps"); -- cgit v0.10.2 From 426f3a53d4a1ffbe228f268e5c4af148686b7346 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Fri, 3 Jun 2016 11:16:32 -0700 Subject: lkdtm: clean up after rename This cleans up comments a bit to improve readability, adjusts the name of the module after the source file renaming, and corrects the MAINTAINERS for the upcoming lkdtm files. Signed-off-by: Kees Cook diff --git a/MAINTAINERS b/MAINTAINERS index 2ebe195..977504e 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -6954,7 +6954,7 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/jikos/livepatching.git LINUX KERNEL DUMP TEST MODULE (LKDTM) M: Kees Cook S: Maintained -F: drivers/misc/lkdtm.c +F: drivers/misc/lkdtm* LLC (802.2) M: Arnaldo Carvalho de Melo diff --git a/drivers/misc/lkdtm_core.c b/drivers/misc/lkdtm_core.c index 0a5cbbe..605050c 100644 --- a/drivers/misc/lkdtm_core.c +++ b/drivers/misc/lkdtm_core.c @@ -1,5 +1,9 @@ /* - * Kprobe module for testing crash dumps + * Linux Kernel Dump Test Module for testing kernel crashes conditions: + * induces system failures at predefined crashpoints and under predefined + * operational conditions in order to evaluate the reliability of kernel + * sanity checking and crash dumps obtained using different dumping + * solutions. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -19,10 +23,6 @@ * * Author: Ankita Garg * - * This module induces system failures at predefined crashpoints to - * evaluate the reliability of crash dumps obtained using different dumping - * solutions. - * * It is adapted from the Linux Kernel Dump Test Tool by * Fernando Luis Vazquez Cao * @@ -30,7 +30,7 @@ * * See Documentation/fault-injection/provoke-crashes.txt for instructions */ -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +#define pr_fmt(fmt) "lkdtm: " fmt #include #include -- cgit v0.10.2 From 9a49a528dcf3c2022ff89f700d5d0345b9abf288 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Mon, 22 Feb 2016 14:09:29 -0800 Subject: lkdtm: add function for testing .rodata section This adds a function that lives in the .rodata section. The section flags are corrected using objcopy since there is no way with gcc to declare section flags in an architecture-agnostic way. Signed-off-by: Kees Cook diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index c3cb6ad..7d45ed4 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -59,3 +59,11 @@ obj-$(CONFIG_CXL_BASE) += cxl/ obj-$(CONFIG_PANEL) += panel.o lkdtm-$(CONFIG_LKDTM) += lkdtm_core.o +lkdtm-$(CONFIG_LKDTM) += lkdtm_rodata_objcopy.o + +OBJCOPYFLAGS := +OBJCOPYFLAGS_lkdtm_rodata_objcopy.o := \ + --set-section-flags .text=alloc,readonly \ + --rename-section .text=.rodata +$(obj)/lkdtm_rodata_objcopy.o: $(obj)/lkdtm_rodata.o + $(call if_changed,objcopy) diff --git a/drivers/misc/lkdtm.h b/drivers/misc/lkdtm.h new file mode 100644 index 0000000..9531fa3 --- /dev/null +++ b/drivers/misc/lkdtm.h @@ -0,0 +1,6 @@ +#ifndef __LKDTM_H +#define __LKDTM_H + +void lkdtm_rodata_do_nothing(void); + +#endif diff --git a/drivers/misc/lkdtm_core.c b/drivers/misc/lkdtm_core.c index 605050c..187cd9b 100644 --- a/drivers/misc/lkdtm_core.c +++ b/drivers/misc/lkdtm_core.c @@ -52,6 +52,8 @@ #include #endif +#include "lkdtm.h" + /* * Make sure our attempts to over run the kernel stack doesn't trigger * a compiler warning when CONFIG_FRAME_WARN is set. Then make sure we @@ -103,6 +105,7 @@ enum ctype { CT_EXEC_STACK, CT_EXEC_KMALLOC, CT_EXEC_VMALLOC, + CT_EXEC_RODATA, CT_EXEC_USERSPACE, CT_ACCESS_USERSPACE, CT_WRITE_RO, @@ -145,6 +148,7 @@ static char* cp_type[] = { "EXEC_STACK", "EXEC_KMALLOC", "EXEC_VMALLOC", + "EXEC_RODATA", "EXEC_USERSPACE", "ACCESS_USERSPACE", "WRITE_RO", @@ -346,15 +350,18 @@ static noinline void corrupt_stack(void) memset((void *)data, 0, 64); } -static void noinline execute_location(void *dst) +static noinline void execute_location(void *dst, bool write) { void (*func)(void) = dst; pr_info("attempting ok execution at %p\n", do_nothing); do_nothing(); - memcpy(dst, do_nothing, EXEC_SIZE); - flush_icache_range((unsigned long)dst, (unsigned long)dst + EXEC_SIZE); + if (write) { + memcpy(dst, do_nothing, EXEC_SIZE); + flush_icache_range((unsigned long)dst, + (unsigned long)dst + EXEC_SIZE); + } pr_info("attempting bad execution at %p\n", func); func(); } @@ -551,25 +558,28 @@ static void lkdtm_do_action(enum ctype which) schedule(); break; case CT_EXEC_DATA: - execute_location(data_area); + execute_location(data_area, true); break; case CT_EXEC_STACK: { u8 stack_area[EXEC_SIZE]; - execute_location(stack_area); + execute_location(stack_area, true); break; } case CT_EXEC_KMALLOC: { u32 *kmalloc_area = kmalloc(EXEC_SIZE, GFP_KERNEL); - execute_location(kmalloc_area); + execute_location(kmalloc_area, true); kfree(kmalloc_area); break; } case CT_EXEC_VMALLOC: { u32 *vmalloc_area = vmalloc(EXEC_SIZE); - execute_location(vmalloc_area); + execute_location(vmalloc_area, true); vfree(vmalloc_area); break; } + case CT_EXEC_RODATA: + execute_location(lkdtm_rodata_do_nothing, false); + break; case CT_EXEC_USERSPACE: { unsigned long user_addr; diff --git a/drivers/misc/lkdtm_rodata.c b/drivers/misc/lkdtm_rodata.c new file mode 100644 index 0000000..4d0d851 --- /dev/null +++ b/drivers/misc/lkdtm_rodata.c @@ -0,0 +1,10 @@ +/* + * This includes functions that are meant to live entirely in .rodata + * (via objcopy tricks), to validate the non-executability of .rodata. + */ +#include + +void lkdtm_rodata_do_nothing(void) +{ + /* Does nothing. We just want an architecture agnostic "return". */ +} -- cgit v0.10.2 From aa981a665d587a19be869ce7f3cb7232f8588dd8 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Fri, 3 Jun 2016 12:06:52 -0700 Subject: lkdtm: add usercopy tests This adds test to detect copy_to_user/copy_from_user problems that are protected by PAX_USERCOPY (and will be protected by HARDENED_USERCOPY). Explicitly tests both "to" and "from" directions of heap object size problems, heap object markings and, stack frame misalignment. Signed-off-by: Kees Cook diff --git a/drivers/misc/lkdtm_core.c b/drivers/misc/lkdtm_core.c index 187cd9b..3fe4b5d 100644 --- a/drivers/misc/lkdtm_core.c +++ b/drivers/misc/lkdtm_core.c @@ -111,7 +111,14 @@ enum ctype { CT_WRITE_RO, CT_WRITE_RO_AFTER_INIT, CT_WRITE_KERN, - CT_WRAP_ATOMIC + CT_WRAP_ATOMIC, + CT_USERCOPY_HEAP_SIZE_TO, + CT_USERCOPY_HEAP_SIZE_FROM, + CT_USERCOPY_HEAP_FLAG_TO, + CT_USERCOPY_HEAP_FLAG_FROM, + CT_USERCOPY_STACK_FRAME_TO, + CT_USERCOPY_STACK_FRAME_FROM, + CT_USERCOPY_STACK_BEYOND, }; static char* cp_name[] = { @@ -154,7 +161,14 @@ static char* cp_type[] = { "WRITE_RO", "WRITE_RO_AFTER_INIT", "WRITE_KERN", - "WRAP_ATOMIC" + "WRAP_ATOMIC", + "USERCOPY_HEAP_SIZE_TO", + "USERCOPY_HEAP_SIZE_FROM", + "USERCOPY_HEAP_FLAG_TO", + "USERCOPY_HEAP_FLAG_FROM", + "USERCOPY_STACK_FRAME_TO", + "USERCOPY_STACK_FRAME_FROM", + "USERCOPY_STACK_BEYOND", }; static struct jprobe lkdtm; @@ -166,6 +180,8 @@ static char* cpoint_name; static char* cpoint_type; static int cpoint_count = DEFAULT_COUNT; static int recur_count = REC_NUM_DEFAULT; +static int alloc_size = 1024; +static size_t cache_size; static enum cname cpoint = CN_INVALID; static enum ctype cptype = CT_NONE; @@ -174,7 +190,9 @@ static DEFINE_SPINLOCK(count_lock); static DEFINE_SPINLOCK(lock_me_up); static u8 data_area[EXEC_SIZE]; +static struct kmem_cache *bad_cache; +static const unsigned char test_text[] = "This is a test.\n"; static const unsigned long rodata = 0xAA55AA55; static unsigned long ro_after_init __ro_after_init = 0x55AA5500; @@ -188,6 +206,9 @@ MODULE_PARM_DESC(cpoint_type, " Crash Point Type, action to be taken on "\ module_param(cpoint_count, int, 0644); MODULE_PARM_DESC(cpoint_count, " Crash Point Count, number of times the "\ "crash point is to be hit to trigger action"); +module_param(alloc_size, int, 0644); +MODULE_PARM_DESC(alloc_size, " Size of allocation for user copy tests "\ + "(from 1 to PAGE_SIZE)"); static unsigned int jp_do_irq(unsigned int irq) { @@ -381,6 +402,228 @@ static void execute_user_location(void *dst) func(); } +/* + * Instead of adding -Wno-return-local-addr, just pass the stack address + * through a function to obfuscate it from the compiler. + */ +static noinline unsigned char *trick_compiler(unsigned char *stack) +{ + return stack + 0; +} + +static noinline unsigned char *do_usercopy_stack_callee(int value) +{ + unsigned char buf[32]; + int i; + + /* Exercise stack to avoid everything living in registers. */ + for (i = 0; i < sizeof(buf); i++) { + buf[i] = value & 0xff; + } + + return trick_compiler(buf); +} + +static noinline void do_usercopy_stack(bool to_user, bool bad_frame) +{ + unsigned long user_addr; + unsigned char good_stack[32]; + unsigned char *bad_stack; + int i; + + /* Exercise stack to avoid everything living in registers. */ + for (i = 0; i < sizeof(good_stack); i++) + good_stack[i] = test_text[i % sizeof(test_text)]; + + /* This is a pointer to outside our current stack frame. */ + if (bad_frame) { + bad_stack = do_usercopy_stack_callee(alloc_size); + } else { + /* Put start address just inside stack. */ + bad_stack = task_stack_page(current) + THREAD_SIZE; + bad_stack -= sizeof(unsigned long); + } + + user_addr = vm_mmap(NULL, 0, PAGE_SIZE, + PROT_READ | PROT_WRITE | PROT_EXEC, + MAP_ANONYMOUS | MAP_PRIVATE, 0); + if (user_addr >= TASK_SIZE) { + pr_warn("Failed to allocate user memory\n"); + return; + } + + if (to_user) { + pr_info("attempting good copy_to_user of local stack\n"); + if (copy_to_user((void __user *)user_addr, good_stack, + sizeof(good_stack))) { + pr_warn("copy_to_user failed unexpectedly?!\n"); + goto free_user; + } + + pr_info("attempting bad copy_to_user of distant stack\n"); + if (copy_to_user((void __user *)user_addr, bad_stack, + sizeof(good_stack))) { + pr_warn("copy_to_user failed, but lacked Oops\n"); + goto free_user; + } + } else { + /* + * There isn't a safe way to not be protected by usercopy + * if we're going to write to another thread's stack. + */ + if (!bad_frame) + goto free_user; + + pr_info("attempting good copy_from_user of local stack\n"); + if (copy_from_user(good_stack, (void __user *)user_addr, + sizeof(good_stack))) { + pr_warn("copy_from_user failed unexpectedly?!\n"); + goto free_user; + } + + pr_info("attempting bad copy_from_user of distant stack\n"); + if (copy_from_user(bad_stack, (void __user *)user_addr, + sizeof(good_stack))) { + pr_warn("copy_from_user failed, but lacked Oops\n"); + goto free_user; + } + } + +free_user: + vm_munmap(user_addr, PAGE_SIZE); +} + +static void do_usercopy_heap_size(bool to_user) +{ + unsigned long user_addr; + unsigned char *one, *two; + size_t size = clamp_t(int, alloc_size, 1, PAGE_SIZE); + + one = kmalloc(size, GFP_KERNEL); + two = kmalloc(size, GFP_KERNEL); + if (!one || !two) { + pr_warn("Failed to allocate kernel memory\n"); + goto free_kernel; + } + + user_addr = vm_mmap(NULL, 0, PAGE_SIZE, + PROT_READ | PROT_WRITE | PROT_EXEC, + MAP_ANONYMOUS | MAP_PRIVATE, 0); + if (user_addr >= TASK_SIZE) { + pr_warn("Failed to allocate user memory\n"); + goto free_kernel; + } + + memset(one, 'A', size); + memset(two, 'B', size); + + if (to_user) { + pr_info("attempting good copy_to_user of correct size\n"); + if (copy_to_user((void __user *)user_addr, one, size)) { + pr_warn("copy_to_user failed unexpectedly?!\n"); + goto free_user; + } + + pr_info("attempting bad copy_to_user of too large size\n"); + if (copy_to_user((void __user *)user_addr, one, 2 * size)) { + pr_warn("copy_to_user failed, but lacked Oops\n"); + goto free_user; + } + } else { + pr_info("attempting good copy_from_user of correct size\n"); + if (copy_from_user(one, (void __user *)user_addr, + size)) { + pr_warn("copy_from_user failed unexpectedly?!\n"); + goto free_user; + } + + pr_info("attempting bad copy_from_user of too large size\n"); + if (copy_from_user(one, (void __user *)user_addr, 2 * size)) { + pr_warn("copy_from_user failed, but lacked Oops\n"); + goto free_user; + } + } + +free_user: + vm_munmap(user_addr, PAGE_SIZE); +free_kernel: + kfree(one); + kfree(two); +} + +static void do_usercopy_heap_flag(bool to_user) +{ + unsigned long user_addr; + unsigned char *good_buf = NULL; + unsigned char *bad_buf = NULL; + + /* Make sure cache was prepared. */ + if (!bad_cache) { + pr_warn("Failed to allocate kernel cache\n"); + return; + } + + /* + * Allocate one buffer from each cache (kmalloc will have the + * SLAB_USERCOPY flag already, but "bad_cache" won't). + */ + good_buf = kmalloc(cache_size, GFP_KERNEL); + bad_buf = kmem_cache_alloc(bad_cache, GFP_KERNEL); + if (!good_buf || !bad_buf) { + pr_warn("Failed to allocate buffers from caches\n"); + goto free_alloc; + } + + /* Allocate user memory we'll poke at. */ + user_addr = vm_mmap(NULL, 0, PAGE_SIZE, + PROT_READ | PROT_WRITE | PROT_EXEC, + MAP_ANONYMOUS | MAP_PRIVATE, 0); + if (user_addr >= TASK_SIZE) { + pr_warn("Failed to allocate user memory\n"); + goto free_alloc; + } + + memset(good_buf, 'A', cache_size); + memset(bad_buf, 'B', cache_size); + + if (to_user) { + pr_info("attempting good copy_to_user with SLAB_USERCOPY\n"); + if (copy_to_user((void __user *)user_addr, good_buf, + cache_size)) { + pr_warn("copy_to_user failed unexpectedly?!\n"); + goto free_user; + } + + pr_info("attempting bad copy_to_user w/o SLAB_USERCOPY\n"); + if (copy_to_user((void __user *)user_addr, bad_buf, + cache_size)) { + pr_warn("copy_to_user failed, but lacked Oops\n"); + goto free_user; + } + } else { + pr_info("attempting good copy_from_user with SLAB_USERCOPY\n"); + if (copy_from_user(good_buf, (void __user *)user_addr, + cache_size)) { + pr_warn("copy_from_user failed unexpectedly?!\n"); + goto free_user; + } + + pr_info("attempting bad copy_from_user w/o SLAB_USERCOPY\n"); + if (copy_from_user(bad_buf, (void __user *)user_addr, + cache_size)) { + pr_warn("copy_from_user failed, but lacked Oops\n"); + goto free_user; + } + } + +free_user: + vm_munmap(user_addr, PAGE_SIZE); +free_alloc: + if (bad_buf) + kmem_cache_free(bad_cache, bad_buf); + kfree(good_buf); +} + static void lkdtm_do_action(enum ctype which) { switch (which) { @@ -679,6 +922,27 @@ static void lkdtm_do_action(enum ctype which) return; } + case CT_USERCOPY_HEAP_SIZE_TO: + do_usercopy_heap_size(true); + break; + case CT_USERCOPY_HEAP_SIZE_FROM: + do_usercopy_heap_size(false); + break; + case CT_USERCOPY_HEAP_FLAG_TO: + do_usercopy_heap_flag(true); + break; + case CT_USERCOPY_HEAP_FLAG_FROM: + do_usercopy_heap_flag(false); + break; + case CT_USERCOPY_STACK_FRAME_TO: + do_usercopy_stack(true, true); + break; + case CT_USERCOPY_STACK_FRAME_FROM: + do_usercopy_stack(false, true); + break; + case CT_USERCOPY_STACK_BEYOND: + do_usercopy_stack(true, false); + break; case CT_NONE: default: break; @@ -971,6 +1235,11 @@ static int __init lkdtm_module_init(void) /* Make sure we can write to __ro_after_init values during __init */ ro_after_init |= 0xAA; + /* Prepare cache that lacks SLAB_USERCOPY flag. */ + cache_size = clamp_t(int, alloc_size, 1, PAGE_SIZE); + bad_cache = kmem_cache_create("lkdtm-no-usercopy", cache_size, 0, + 0, NULL); + /* Register debugfs interface */ lkdtm_debugfs_root = debugfs_create_dir("provoke-crash", NULL); if (!lkdtm_debugfs_root) { @@ -1022,6 +1291,8 @@ static void __exit lkdtm_module_exit(void) { debugfs_remove_recursive(lkdtm_debugfs_root); + kmem_cache_destroy(bad_cache); + unregister_jprobe(&lkdtm); pr_info("Crash point unregistered\n"); } -- cgit v0.10.2 From b54845276a969b72daa2dee1afe379847a639478 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Tue, 7 Jun 2016 14:27:02 -0700 Subject: lkdtm: split atomic test into over and underflow Each direction of the atomic wrapping should be individually testable. Signed-off-by: Kees Cook diff --git a/drivers/misc/lkdtm_core.c b/drivers/misc/lkdtm_core.c index 3fe4b5d..a595a6f 100644 --- a/drivers/misc/lkdtm_core.c +++ b/drivers/misc/lkdtm_core.c @@ -111,7 +111,8 @@ enum ctype { CT_WRITE_RO, CT_WRITE_RO_AFTER_INIT, CT_WRITE_KERN, - CT_WRAP_ATOMIC, + CT_ATOMIC_UNDERFLOW, + CT_ATOMIC_OVERFLOW, CT_USERCOPY_HEAP_SIZE_TO, CT_USERCOPY_HEAP_SIZE_FROM, CT_USERCOPY_HEAP_FLAG_TO, @@ -161,7 +162,8 @@ static char* cp_type[] = { "WRITE_RO", "WRITE_RO_AFTER_INIT", "WRITE_KERN", - "WRAP_ATOMIC", + "ATOMIC_UNDERFLOW", + "ATOMIC_OVERFLOW", "USERCOPY_HEAP_SIZE_TO", "USERCOPY_HEAP_SIZE_FROM", "USERCOPY_HEAP_FLAG_TO", @@ -911,13 +913,25 @@ static void lkdtm_do_action(enum ctype which) do_overwritten(); break; } - case CT_WRAP_ATOMIC: { + case CT_ATOMIC_UNDERFLOW: { atomic_t under = ATOMIC_INIT(INT_MIN); - atomic_t over = ATOMIC_INIT(INT_MAX); - pr_info("attempting atomic underflow\n"); + pr_info("attempting good atomic increment\n"); + atomic_inc(&under); + atomic_dec(&under); + + pr_info("attempting bad atomic underflow\n"); atomic_dec(&under); - pr_info("attempting atomic overflow\n"); + break; + } + case CT_ATOMIC_OVERFLOW: { + atomic_t over = ATOMIC_INIT(INT_MAX); + + pr_info("attempting good atomic decrement\n"); + atomic_dec(&over); + atomic_inc(&over); + + pr_info("attempting bad atomic overflow\n"); atomic_inc(&over); return; -- cgit v0.10.2 From c0ff9019ee64101fda8f19338da799fda8217e14 Mon Sep 17 00:00:00 2001 From: Alexander Usyskin Date: Mon, 9 May 2016 00:07:47 -0400 Subject: mei: drop wr_msg from the mei_dev structure The control messages are usually small, around 8 bytes, and can be allocated on the stack. Using on stack allocation allows us to drop 'wr_msg' a rather large buffer reserved in the mei_dev structure and relax contention of this device global buffer. Signed-off-by: Alexander Usyskin Signed-off-by: Tomas Winkler Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/misc/mei/hbm.c b/drivers/misc/mei/hbm.c index 5aa606c..085f3aa 100644 --- a/drivers/misc/mei/hbm.c +++ b/drivers/misc/mei/hbm.c @@ -132,6 +132,7 @@ static inline void mei_hbm_hdr(struct mei_msg_hdr *hdr, size_t length) hdr->length = length; hdr->msg_complete = 1; hdr->reserved = 0; + hdr->internal = 0; } /** @@ -165,15 +166,15 @@ void mei_hbm_cl_hdr(struct mei_cl *cl, u8 hbm_cmd, void *buf, size_t len) * Return: 0 on success, <0 on failure. */ static inline -int mei_hbm_cl_write(struct mei_device *dev, - struct mei_cl *cl, u8 hbm_cmd, size_t len) +int mei_hbm_cl_write(struct mei_device *dev, struct mei_cl *cl, + u8 hbm_cmd, u8 *buf, size_t len) { - struct mei_msg_hdr *mei_hdr = &dev->wr_msg.hdr; + struct mei_msg_hdr mei_hdr; - mei_hbm_hdr(mei_hdr, len); - mei_hbm_cl_hdr(cl, hbm_cmd, dev->wr_msg.data, len); + mei_hbm_hdr(&mei_hdr, len); + mei_hbm_cl_hdr(cl, hbm_cmd, buf, len); - return mei_write_message(dev, mei_hdr, dev->wr_msg.data); + return mei_write_message(dev, &mei_hdr, buf); } /** @@ -250,24 +251,23 @@ int mei_hbm_start_wait(struct mei_device *dev) */ int mei_hbm_start_req(struct mei_device *dev) { - struct mei_msg_hdr *mei_hdr = &dev->wr_msg.hdr; - struct hbm_host_version_request *start_req; + struct mei_msg_hdr mei_hdr; + struct hbm_host_version_request start_req; const size_t len = sizeof(struct hbm_host_version_request); int ret; mei_hbm_reset(dev); - mei_hbm_hdr(mei_hdr, len); + mei_hbm_hdr(&mei_hdr, len); /* host start message */ - start_req = (struct hbm_host_version_request *)dev->wr_msg.data; - memset(start_req, 0, len); - start_req->hbm_cmd = HOST_START_REQ_CMD; - start_req->host_version.major_version = HBM_MAJOR_VERSION; - start_req->host_version.minor_version = HBM_MINOR_VERSION; + memset(&start_req, 0, len); + start_req.hbm_cmd = HOST_START_REQ_CMD; + start_req.host_version.major_version = HBM_MAJOR_VERSION; + start_req.host_version.minor_version = HBM_MINOR_VERSION; dev->hbm_state = MEI_HBM_IDLE; - ret = mei_write_message(dev, mei_hdr, dev->wr_msg.data); + ret = mei_write_message(dev, &mei_hdr, &start_req); if (ret) { dev_err(dev->dev, "version message write failed: ret = %d\n", ret); @@ -288,23 +288,22 @@ int mei_hbm_start_req(struct mei_device *dev) */ static int mei_hbm_enum_clients_req(struct mei_device *dev) { - struct mei_msg_hdr *mei_hdr = &dev->wr_msg.hdr; - struct hbm_host_enum_request *enum_req; + struct mei_msg_hdr mei_hdr; + struct hbm_host_enum_request enum_req; const size_t len = sizeof(struct hbm_host_enum_request); int ret; /* enumerate clients */ - mei_hbm_hdr(mei_hdr, len); + mei_hbm_hdr(&mei_hdr, len); - enum_req = (struct hbm_host_enum_request *)dev->wr_msg.data; - memset(enum_req, 0, len); - enum_req->hbm_cmd = HOST_ENUM_REQ_CMD; - enum_req->flags |= dev->hbm_f_dc_supported ? - MEI_HBM_ENUM_F_ALLOW_ADD : 0; - enum_req->flags |= dev->hbm_f_ie_supported ? - MEI_HBM_ENUM_F_IMMEDIATE_ENUM : 0; + memset(&enum_req, 0, len); + enum_req.hbm_cmd = HOST_ENUM_REQ_CMD; + enum_req.flags |= dev->hbm_f_dc_supported ? + MEI_HBM_ENUM_F_ALLOW_ADD : 0; + enum_req.flags |= dev->hbm_f_ie_supported ? + MEI_HBM_ENUM_F_IMMEDIATE_ENUM : 0; - ret = mei_write_message(dev, mei_hdr, dev->wr_msg.data); + ret = mei_write_message(dev, &mei_hdr, &enum_req); if (ret) { dev_err(dev->dev, "enumeration request write failed: ret = %d.\n", ret); @@ -358,23 +357,21 @@ static int mei_hbm_me_cl_add(struct mei_device *dev, */ static int mei_hbm_add_cl_resp(struct mei_device *dev, u8 addr, u8 status) { - struct mei_msg_hdr *mei_hdr = &dev->wr_msg.hdr; - struct hbm_add_client_response *resp; + struct mei_msg_hdr mei_hdr; + struct hbm_add_client_response resp; const size_t len = sizeof(struct hbm_add_client_response); int ret; dev_dbg(dev->dev, "adding client response\n"); - resp = (struct hbm_add_client_response *)dev->wr_msg.data; + mei_hbm_hdr(&mei_hdr, len); - mei_hbm_hdr(mei_hdr, len); - memset(resp, 0, sizeof(struct hbm_add_client_response)); + memset(&resp, 0, sizeof(struct hbm_add_client_response)); + resp.hbm_cmd = MEI_HBM_ADD_CLIENT_RES_CMD; + resp.me_addr = addr; + resp.status = status; - resp->hbm_cmd = MEI_HBM_ADD_CLIENT_RES_CMD; - resp->me_addr = addr; - resp->status = status; - - ret = mei_write_message(dev, mei_hdr, dev->wr_msg.data); + ret = mei_write_message(dev, &mei_hdr, &resp); if (ret) dev_err(dev->dev, "add client response write failed: ret = %d\n", ret); @@ -421,18 +418,17 @@ int mei_hbm_cl_notify_req(struct mei_device *dev, struct mei_cl *cl, u8 start) { - struct mei_msg_hdr *mei_hdr = &dev->wr_msg.hdr; - struct hbm_notification_request *req; + struct mei_msg_hdr mei_hdr; + struct hbm_notification_request req; const size_t len = sizeof(struct hbm_notification_request); int ret; - mei_hbm_hdr(mei_hdr, len); - mei_hbm_cl_hdr(cl, MEI_HBM_NOTIFY_REQ_CMD, dev->wr_msg.data, len); + mei_hbm_hdr(&mei_hdr, len); + mei_hbm_cl_hdr(cl, MEI_HBM_NOTIFY_REQ_CMD, &req, len); - req = (struct hbm_notification_request *)dev->wr_msg.data; - req->start = start; + req.start = start; - ret = mei_write_message(dev, mei_hdr, dev->wr_msg.data); + ret = mei_write_message(dev, &mei_hdr, &req); if (ret) dev_err(dev->dev, "notify request failed: ret = %d\n", ret); @@ -534,8 +530,8 @@ static void mei_hbm_cl_notify(struct mei_device *dev, */ static int mei_hbm_prop_req(struct mei_device *dev, unsigned long start_idx) { - struct mei_msg_hdr *mei_hdr = &dev->wr_msg.hdr; - struct hbm_props_request *prop_req; + struct mei_msg_hdr mei_hdr; + struct hbm_props_request prop_req; const size_t len = sizeof(struct hbm_props_request); unsigned long addr; int ret; @@ -550,15 +546,14 @@ static int mei_hbm_prop_req(struct mei_device *dev, unsigned long start_idx) return 0; } - mei_hbm_hdr(mei_hdr, len); - prop_req = (struct hbm_props_request *)dev->wr_msg.data; + mei_hbm_hdr(&mei_hdr, len); - memset(prop_req, 0, sizeof(struct hbm_props_request)); + memset(&prop_req, 0, sizeof(struct hbm_props_request)); - prop_req->hbm_cmd = HOST_CLIENT_PROPERTIES_REQ_CMD; - prop_req->me_addr = addr; + prop_req.hbm_cmd = HOST_CLIENT_PROPERTIES_REQ_CMD; + prop_req.me_addr = addr; - ret = mei_write_message(dev, mei_hdr, dev->wr_msg.data); + ret = mei_write_message(dev, &mei_hdr, &prop_req); if (ret) { dev_err(dev->dev, "properties request write failed: ret = %d\n", ret); @@ -581,21 +576,20 @@ static int mei_hbm_prop_req(struct mei_device *dev, unsigned long start_idx) */ int mei_hbm_pg(struct mei_device *dev, u8 pg_cmd) { - struct mei_msg_hdr *mei_hdr = &dev->wr_msg.hdr; - struct hbm_power_gate *req; + struct mei_msg_hdr mei_hdr; + struct hbm_power_gate req; const size_t len = sizeof(struct hbm_power_gate); int ret; if (!dev->hbm_f_pg_supported) return -EOPNOTSUPP; - mei_hbm_hdr(mei_hdr, len); + mei_hbm_hdr(&mei_hdr, len); - req = (struct hbm_power_gate *)dev->wr_msg.data; - memset(req, 0, len); - req->hbm_cmd = pg_cmd; + memset(&req, 0, len); + req.hbm_cmd = pg_cmd; - ret = mei_write_message(dev, mei_hdr, dev->wr_msg.data); + ret = mei_write_message(dev, &mei_hdr, &req); if (ret) dev_err(dev->dev, "power gate command write failed.\n"); return ret; @@ -611,18 +605,17 @@ EXPORT_SYMBOL_GPL(mei_hbm_pg); */ static int mei_hbm_stop_req(struct mei_device *dev) { - struct mei_msg_hdr *mei_hdr = &dev->wr_msg.hdr; - struct hbm_host_stop_request *req = - (struct hbm_host_stop_request *)dev->wr_msg.data; + struct mei_msg_hdr mei_hdr; + struct hbm_host_stop_request req; const size_t len = sizeof(struct hbm_host_stop_request); - mei_hbm_hdr(mei_hdr, len); + mei_hbm_hdr(&mei_hdr, len); - memset(req, 0, len); - req->hbm_cmd = HOST_STOP_REQ_CMD; - req->reason = DRIVER_STOP_REQUEST; + memset(&req, 0, len); + req.hbm_cmd = HOST_STOP_REQ_CMD; + req.reason = DRIVER_STOP_REQUEST; - return mei_write_message(dev, mei_hdr, dev->wr_msg.data); + return mei_write_message(dev, &mei_hdr, &req); } /** @@ -636,9 +629,10 @@ static int mei_hbm_stop_req(struct mei_device *dev) int mei_hbm_cl_flow_control_req(struct mei_device *dev, struct mei_cl *cl) { const size_t len = sizeof(struct hbm_flow_control); + u8 buf[len]; cl_dbg(dev, cl, "sending flow control\n"); - return mei_hbm_cl_write(dev, cl, MEI_FLOW_CONTROL_CMD, len); + return mei_hbm_cl_write(dev, cl, MEI_FLOW_CONTROL_CMD, buf, len); } /** @@ -714,8 +708,9 @@ static void mei_hbm_cl_flow_control_res(struct mei_device *dev, int mei_hbm_cl_disconnect_req(struct mei_device *dev, struct mei_cl *cl) { const size_t len = sizeof(struct hbm_client_connect_request); + u8 buf[len]; - return mei_hbm_cl_write(dev, cl, CLIENT_DISCONNECT_REQ_CMD, len); + return mei_hbm_cl_write(dev, cl, CLIENT_DISCONNECT_REQ_CMD, buf, len); } /** @@ -729,8 +724,9 @@ int mei_hbm_cl_disconnect_req(struct mei_device *dev, struct mei_cl *cl) int mei_hbm_cl_disconnect_rsp(struct mei_device *dev, struct mei_cl *cl) { const size_t len = sizeof(struct hbm_client_connect_response); + u8 buf[len]; - return mei_hbm_cl_write(dev, cl, CLIENT_DISCONNECT_RES_CMD, len); + return mei_hbm_cl_write(dev, cl, CLIENT_DISCONNECT_RES_CMD, buf, len); } /** @@ -765,8 +761,9 @@ static void mei_hbm_cl_disconnect_res(struct mei_device *dev, struct mei_cl *cl, int mei_hbm_cl_connect_req(struct mei_device *dev, struct mei_cl *cl) { const size_t len = sizeof(struct hbm_client_connect_request); + u8 buf[len]; - return mei_hbm_cl_write(dev, cl, CLIENT_CONNECT_REQ_CMD, len); + return mei_hbm_cl_write(dev, cl, CLIENT_CONNECT_REQ_CMD, buf, len); } /** diff --git a/drivers/misc/mei/mei_dev.h b/drivers/misc/mei/mei_dev.h index c9e0102..e5e3250 100644 --- a/drivers/misc/mei/mei_dev.h +++ b/drivers/misc/mei/mei_dev.h @@ -382,7 +382,6 @@ const char *mei_pg_state_str(enum mei_pg_state state); * * @hbuf_depth : depth of hardware host/write buffer is slots * @hbuf_is_ready : query if the host host/write buffer is ready - * @wr_msg : the buffer for hbm control messages * * @version : HBM protocol version in use * @hbm_f_pg_supported : hbm feature pgi protocol @@ -467,12 +466,6 @@ struct mei_device { u8 hbuf_depth; bool hbuf_is_ready; - /* used for control messages */ - struct { - struct mei_msg_hdr hdr; - unsigned char data[128]; - } wr_msg; - struct hbm_version version; unsigned int hbm_f_pg_supported:1; unsigned int hbm_f_dc_supported:1; @@ -670,8 +663,7 @@ static inline size_t mei_hbuf_max_len(const struct mei_device *dev) } static inline int mei_write_message(struct mei_device *dev, - struct mei_msg_hdr *hdr, - unsigned char *buf) + struct mei_msg_hdr *hdr, void *buf) { return dev->ops->write(dev, hdr, buf); } -- cgit v0.10.2 From 99158f10e91768d34c5004c40c42f802b719bcae Mon Sep 17 00:00:00 2001 From: Andy Lutomirski Date: Tue, 24 May 2016 15:48:38 -0700 Subject: x86/xen: Simplify set_aliased_prot() A year ago, via the following commit: aa1acff356bb ("x86/xen: Probe target addresses in set_aliased_prot() before the hypercall") I added an explicit probe to work around a hypercall issue. The code can be simplified by using probe_kernel_read(). No change in functionality. Signed-off-by: Andy Lutomirski Reviewed-by: Andrew Cooper Acked-by: David Vrabel Cc: Andy Lutomirski Cc: Boris Ostrovsky Cc: Borislav Petkov Cc: Brian Gerst Cc: David Vrabel Cc: Denys Vlasenko Cc: H. Peter Anvin Cc: Jan Beulich Cc: Kees Cook Cc: Konrad Rzeszutek Wilk Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: xen-devel Link: http://lkml.kernel.org/r/0706f1a2538e481194514197298cca6b5e3f2638.1464129798.git.luto@kernel.org Signed-off-by: Ingo Molnar diff --git a/arch/x86/xen/enlighten.c b/arch/x86/xen/enlighten.c index 760789a..0f87db2 100644 --- a/arch/x86/xen/enlighten.c +++ b/arch/x86/xen/enlighten.c @@ -521,9 +521,7 @@ static void set_aliased_prot(void *v, pgprot_t prot) preempt_disable(); - pagefault_disable(); /* Avoid warnings due to being atomic. */ - __get_user(dummy, (unsigned char __user __force *)v); - pagefault_enable(); + probe_kernel_read(&dummy, v, 1); if (HYPERVISOR_update_va_mapping((unsigned long)v, pte, 0)) BUG(); -- cgit v0.10.2 From 9e18265443d3a76462eafc3a0863c217aeaf62ac Mon Sep 17 00:00:00 2001 From: Matt Ranostay Date: Tue, 7 Jun 2016 21:18:04 -0700 Subject: iio: proximity: lidar: switch to iio_device_claim_*_mode helpers Switch from using indio_dev->mlock to the iio_device_claim_*_mode helper functions. Signed-off-by: Matt Ranostay Signed-off-by: Jonathan Cameron diff --git a/drivers/iio/proximity/pulsedlight-lidar-lite-v2.c b/drivers/iio/proximity/pulsedlight-lidar-lite-v2.c index 4f502386..c0b0e82 100644 --- a/drivers/iio/proximity/pulsedlight-lidar-lite-v2.c +++ b/drivers/iio/proximity/pulsedlight-lidar-lite-v2.c @@ -203,22 +203,19 @@ static int lidar_read_raw(struct iio_dev *indio_dev, struct lidar_data *data = iio_priv(indio_dev); int ret = -EINVAL; - mutex_lock(&indio_dev->mlock); - - if (iio_buffer_enabled(indio_dev) && mask == IIO_CHAN_INFO_RAW) { - ret = -EBUSY; - goto error_busy; - } - switch (mask) { case IIO_CHAN_INFO_RAW: { u16 reg; + if (iio_device_claim_direct_mode(indio_dev)) + return -EBUSY; + ret = lidar_get_measurement(data, ®); if (!ret) { *val = reg; ret = IIO_VAL_INT; } + iio_device_release_direct_mode(indio_dev); break; } case IIO_CHAN_INFO_SCALE: @@ -228,9 +225,6 @@ static int lidar_read_raw(struct iio_dev *indio_dev, break; } -error_busy: - mutex_unlock(&indio_dev->mlock); - return ret; } -- cgit v0.10.2 From b67869791084662e7428e4598129651c29c93667 Mon Sep 17 00:00:00 2001 From: Alison Schofield Date: Mon, 6 Jun 2016 22:09:21 -0700 Subject: iio: light: tcs3414: use iio helper function to guarantee direct mode Replace the code that guarantees the device stays in direct mode with iio_device_claim_direct_mode() which does same. This allows removal of an unused lock in the device private global data. Also prevents a possible race around a buffer being enabled whilst a read is going on. Signed-off-by: Alison Schofield Cc: Daniel Baluta Acked-by: Peter Meerwald-Stadler Signed-off-by: Jonathan Cameron diff --git a/drivers/iio/light/tcs3414.c b/drivers/iio/light/tcs3414.c index f90f8c5..8a15fb5 100644 --- a/drivers/iio/light/tcs3414.c +++ b/drivers/iio/light/tcs3414.c @@ -53,7 +53,6 @@ struct tcs3414_data { struct i2c_client *client; - struct mutex lock; u8 control; u8 gain; u8 timing; @@ -134,16 +133,16 @@ static int tcs3414_read_raw(struct iio_dev *indio_dev, switch (mask) { case IIO_CHAN_INFO_RAW: - if (iio_buffer_enabled(indio_dev)) - return -EBUSY; - mutex_lock(&data->lock); + ret = iio_device_claim_direct_mode(indio_dev); + if (ret) + return ret; ret = tcs3414_req_data(data); if (ret < 0) { - mutex_unlock(&data->lock); + iio_device_release_direct_mode(indio_dev); return ret; } ret = i2c_smbus_read_word_data(data->client, chan->address); - mutex_unlock(&data->lock); + iio_device_release_direct_mode(indio_dev); if (ret < 0) return ret; *val = ret; @@ -288,7 +287,6 @@ static int tcs3414_probe(struct i2c_client *client, data = iio_priv(indio_dev); i2c_set_clientdata(client, indio_dev); data->client = client; - mutex_init(&data->lock); indio_dev->dev.parent = &client->dev; indio_dev->info = &tcs3414_info; -- cgit v0.10.2 From 95bd363bbc0bc22d9c14945e307fc30484c57166 Mon Sep 17 00:00:00 2001 From: Alison Schofield Date: Mon, 6 Jun 2016 22:10:23 -0700 Subject: iio: light: tcs3472: use iio helper function to guarantee direct mode Replace the code that guarantees the device stays in direct mode with iio_device_claim_direct_mode() which does same. This allows removal of an unused lock in the device private global data. Also prevents a previous race condition when a buffer is enabled whilst a raw read is going on. Signed-off-by: Alison Schofield Cc: Daniel Baluta Acked-by: Peter Meerwald-Stadler Signed-off-by: Jonathan Cameron diff --git a/drivers/iio/light/tcs3472.c b/drivers/iio/light/tcs3472.c index 1b530bf..b29312f 100644 --- a/drivers/iio/light/tcs3472.c +++ b/drivers/iio/light/tcs3472.c @@ -52,7 +52,6 @@ struct tcs3472_data { struct i2c_client *client; - struct mutex lock; u8 enable; u8 control; u8 atime; @@ -117,17 +116,16 @@ static int tcs3472_read_raw(struct iio_dev *indio_dev, switch (mask) { case IIO_CHAN_INFO_RAW: - if (iio_buffer_enabled(indio_dev)) - return -EBUSY; - - mutex_lock(&data->lock); + ret = iio_device_claim_direct_mode(indio_dev); + if (ret) + return ret; ret = tcs3472_req_data(data); if (ret < 0) { - mutex_unlock(&data->lock); + iio_device_release_direct_mode(indio_dev); return ret; } ret = i2c_smbus_read_word_data(data->client, chan->address); - mutex_unlock(&data->lock); + iio_device_release_direct_mode(indio_dev); if (ret < 0) return ret; *val = ret; @@ -263,7 +261,6 @@ static int tcs3472_probe(struct i2c_client *client, data = iio_priv(indio_dev); i2c_set_clientdata(client, indio_dev); data->client = client; - mutex_init(&data->lock); indio_dev->dev.parent = &client->dev; indio_dev->info = &tcs3472_info; -- cgit v0.10.2 From ae148e51071455519d52051ad8ee5e5776e17966 Mon Sep 17 00:00:00 2001 From: Alison Schofield Date: Mon, 6 Jun 2016 22:08:33 -0700 Subject: iio: light: isl29125: use iio helper function to guarantee direct mode Replace the code that guarantees the device stays in direct mode with iio_device_claim_direct_mode() which does same. This allows removal of an unused lock in the device private global data. Signed-off-by: Alison Schofield Cc: Daniel Baluta Acked-by: Peter Meerwald-Stadler Signed-off-by: Jonathan Cameron diff --git a/drivers/iio/light/isl29125.c b/drivers/iio/light/isl29125.c index e2945a2..a6b9d66 100644 --- a/drivers/iio/light/isl29125.c +++ b/drivers/iio/light/isl29125.c @@ -50,7 +50,6 @@ struct isl29125_data { struct i2c_client *client; - struct mutex lock; u8 conf1; u16 buffer[8]; /* 3x 16-bit, padding, 8 bytes timestamp */ }; @@ -128,11 +127,11 @@ static int isl29125_read_raw(struct iio_dev *indio_dev, switch (mask) { case IIO_CHAN_INFO_RAW: - if (iio_buffer_enabled(indio_dev)) - return -EBUSY; - mutex_lock(&data->lock); + ret = iio_device_claim_direct_mode(indio_dev); + if (ret) + return ret; ret = isl29125_read_data(data, chan->scan_index); - mutex_unlock(&data->lock); + iio_device_release_direct_mode(indio_dev); if (ret < 0) return ret; *val = ret; @@ -259,7 +258,6 @@ static int isl29125_probe(struct i2c_client *client, data = iio_priv(indio_dev); i2c_set_clientdata(client, indio_dev); data->client = client; - mutex_init(&data->lock); indio_dev->dev.parent = &client->dev; indio_dev->info = &isl29125_info; -- cgit v0.10.2 From dfc07df0f91a4eabfd3d974e5b1b6b4cfde99e6f Mon Sep 17 00:00:00 2001 From: Alison Schofield Date: Tue, 7 Jun 2016 17:19:05 -0700 Subject: iio: light: gp2ap020a00f: use iio helper function to lock direct mode Replace the code that guarantees the device stays in direct mode with iio_device_claim_direct_mode() which does same. Includes a tiny bit of refactoring (single case -> if) and simplified return flow. Also prevents a theoretical race condition by effectively taking the lock a little earlier than before. Signed-off-by: Alison Schofield Cc: Daniel Baluta Acked-by: Jacek Anaszewski Signed-off-by: Jonathan Cameron diff --git a/drivers/iio/light/gp2ap020a00f.c b/drivers/iio/light/gp2ap020a00f.c index 6d41086..af73af3 100644 --- a/drivers/iio/light/gp2ap020a00f.c +++ b/drivers/iio/light/gp2ap020a00f.c @@ -1287,22 +1287,14 @@ static int gp2ap020a00f_read_raw(struct iio_dev *indio_dev, struct gp2ap020a00f_data *data = iio_priv(indio_dev); int err = -EINVAL; - mutex_lock(&data->lock); - - switch (mask) { - case IIO_CHAN_INFO_RAW: - if (iio_buffer_enabled(indio_dev)) { - err = -EBUSY; - goto error_unlock; - } + if (mask == IIO_CHAN_INFO_RAW) { + err = iio_device_claim_direct_mode(indio_dev); + if (err) + return err; err = gp2ap020a00f_read_channel(data, chan, val); - break; + iio_device_release_direct_mode(indio_dev); } - -error_unlock: - mutex_unlock(&data->lock); - return err < 0 ? err : IIO_VAL_INT; } -- cgit v0.10.2 From 40836bc3d791fda0ac930879a2f1b5b4238fd80e Mon Sep 17 00:00:00 2001 From: Martin Kepplinger Date: Fri, 3 Jun 2016 14:51:50 +0200 Subject: iio: mma8452: update contact information for Martin Kepplinger Signed-off-by: Martin Kepplinger Signed-off-by: Jonathan Cameron diff --git a/drivers/iio/accel/mma8452.c b/drivers/iio/accel/mma8452.c index 458c827..9e679af 100644 --- a/drivers/iio/accel/mma8452.c +++ b/drivers/iio/accel/mma8452.c @@ -8,7 +8,7 @@ * MMA8653FC (10 bit) * FXLS8471Q (14 bit) * - * Copyright 2015 Martin Kepplinger + * Copyright 2015 Martin Kepplinger * Copyright 2014 Peter Meerwald * * This file is subject to the terms and conditions of version 2 of -- cgit v0.10.2 From 16df666a99b9518980d0b6be3c3ffdcce6b28bf1 Mon Sep 17 00:00:00 2001 From: Martin Kepplinger Date: Fri, 3 Jun 2016 14:51:51 +0200 Subject: iio: mma8452: update device description in header comments Signed-off-by: Martin Kepplinger Signed-off-by: Jonathan Cameron diff --git a/drivers/iio/accel/mma8452.c b/drivers/iio/accel/mma8452.c index 9e679af..4be2a18 100644 --- a/drivers/iio/accel/mma8452.c +++ b/drivers/iio/accel/mma8452.c @@ -1,12 +1,14 @@ /* * mma8452.c - Support for following Freescale 3-axis accelerometers: * - * MMA8451Q (14 bit) - * MMA8452Q (12 bit) - * MMA8453Q (10 bit) - * MMA8652FC (12 bit) - * MMA8653FC (10 bit) - * FXLS8471Q (14 bit) + * device name digital output 7-bit I2C slave address (pin selectable) + * --------------------------------------------------------------------- + * MMA8451Q 14 bit 0x1c / 0x1d + * MMA8452Q 12 bit 0x1c / 0x1d + * MMA8453Q 10 bit 0x1c / 0x1d + * MMA8652FC 12 bit 0x1d + * MMA8653FC 10 bit 0x1d + * FXLS8471Q 14 bit 0x1e / 0x1d / 0x1c / 0x1f * * Copyright 2015 Martin Kepplinger * Copyright 2014 Peter Meerwald @@ -15,8 +17,6 @@ * the GNU General Public License. See the file COPYING in the main * directory of this archive for more details. * - * 7-bit I2C slave address 0x1c/0x1d (pin selectable) - * * TODO: orientation events */ -- cgit v0.10.2 From f26ab1aad53bdc2c2fedb506fc2e1d2333a8680b Mon Sep 17 00:00:00 2001 From: Martin Kepplinger Date: Fri, 3 Jun 2016 14:51:52 +0200 Subject: iio: mma8452: update Freescale company information NXP took over Freescale, so add NXP to the driver descriptions Signed-off-by: Martin Kepplinger Signed-off-by: Jonathan Cameron diff --git a/drivers/iio/accel/Kconfig b/drivers/iio/accel/Kconfig index 3132587..89d7820 100644 --- a/drivers/iio/accel/Kconfig +++ b/drivers/iio/accel/Kconfig @@ -157,12 +157,12 @@ config MMA7660 will be called mma7660. config MMA8452 - tristate "Freescale MMA8452Q and similar Accelerometers Driver" + tristate "Freescale / NXP MMA8452Q and similar Accelerometers Driver" depends on I2C select IIO_BUFFER select IIO_TRIGGERED_BUFFER help - Say yes here to build support for the following Freescale 3-axis + Say yes here to build support for the following Freescale / NXP 3-axis accelerometers: MMA8451Q, MMA8452Q, MMA8453Q, MMA8652FC, MMA8653FC, FXLS8471Q. diff --git a/drivers/iio/accel/mma8452.c b/drivers/iio/accel/mma8452.c index 4be2a18..799fe64 100644 --- a/drivers/iio/accel/mma8452.c +++ b/drivers/iio/accel/mma8452.c @@ -1,5 +1,5 @@ /* - * mma8452.c - Support for following Freescale 3-axis accelerometers: + * mma8452.c - Support for following Freescale / NXP 3-axis accelerometers: * * device name digital output 7-bit I2C slave address (pin selectable) * --------------------------------------------------------------------- @@ -108,7 +108,7 @@ struct mma8452_data { }; /** - * struct mma_chip_info - chip specific data for Freescale's accelerometers + * struct mma_chip_info - chip specific data * @chip_id: WHO_AM_I register's value * @channels: struct iio_chan_spec matching the device's * capabilities @@ -1693,5 +1693,5 @@ static struct i2c_driver mma8452_driver = { module_i2c_driver(mma8452_driver); MODULE_AUTHOR("Peter Meerwald "); -MODULE_DESCRIPTION("Freescale MMA8452 accelerometer driver"); +MODULE_DESCRIPTION("Freescale / NXP MMA8452 accelerometer driver"); MODULE_LICENSE("GPL"); -- cgit v0.10.2 From 47146eb837863be27e162d9fbbe2af6bb5560499 Mon Sep 17 00:00:00 2001 From: "Markezana, William" Date: Mon, 6 Jun 2016 08:12:11 +0000 Subject: iio: ms5637 Add Measurement Specialties explicit MS5805 and MS5837 support Signed-off-by: William Markezana Signed-off-by: Jonathan Cameron diff --git a/drivers/iio/pressure/ms5637.c b/drivers/iio/pressure/ms5637.c index 8fb6f7a..953ffbc 100644 --- a/drivers/iio/pressure/ms5637.c +++ b/drivers/iio/pressure/ms5637.c @@ -1,6 +1,6 @@ /* - * ms5637.c - Support for Measurement-Specialties ms5637 and ms8607 - * pressure & temperature sensor + * ms5637.c - Support for Measurement-Specialties MS5637, MS5805 + * MS5837 and MS8607 pressure & temperature sensor * * Copyright (c) 2015 Measurement-Specialties * @@ -11,6 +11,10 @@ * Datasheet: * http://www.meas-spec.com/downloads/MS5637-02BA03.pdf * Datasheet: + * http://www.meas-spec.com/downloads/MS5805-02BA01.pdf + * Datasheet: + * http://www.meas-spec.com/downloads/MS5837-30BA.pdf + * Datasheet: * http://www.meas-spec.com/downloads/MS8607-02BA01.pdf */ @@ -170,7 +174,9 @@ static int ms5637_probe(struct i2c_client *client, static const struct i2c_device_id ms5637_id[] = { {"ms5637", 0}, - {"ms8607-temppressure", 1}, + {"ms5805", 0}, + {"ms5837", 0}, + {"ms8607-temppressure", 0}, {} }; MODULE_DEVICE_TABLE(i2c, ms5637_id); -- cgit v0.10.2 From 6c55c418f071dc7df2dfeb66398d009139cc5ef1 Mon Sep 17 00:00:00 2001 From: Adriana Reus Date: Mon, 6 Jun 2016 13:02:41 +0300 Subject: mailmap: update Adriana Reus email address Set current email address instead of previous employers email address. Signed-off-by: Adriana Reus Signed-off-by: Jonathan Cameron diff --git a/.mailmap b/.mailmap index 7e6c533..fd011ff 100644 --- a/.mailmap +++ b/.mailmap @@ -11,6 +11,7 @@ Aaron Durbin Adam Oldham Adam Radford Adrian Bunk +Adriana Reus Alan Cox Alan Cox Aleksey Gorelov -- cgit v0.10.2 From b9155073ff5de8ca6f1c40b64abca702a237c4d1 Mon Sep 17 00:00:00 2001 From: Matt Ranostay Date: Sun, 5 Jun 2016 20:37:57 -0700 Subject: mailmap: update Matt Ranostay email address Set current email address to replace previous employers email addresses. Cc: Jonathan Cameron Cc: Daniel Baluta Cc: linux-iio@vger.kernel.org Signed-off-by: Matt Ranostay Signed-off-by: Jonathan Cameron diff --git a/.mailmap b/.mailmap index fd011ff..2b81945 100644 --- a/.mailmap +++ b/.mailmap @@ -84,6 +84,8 @@ Leonid I Ananiev Linas Vepstas Mark Brown Matthieu CASTET +Matt Ranostay Matthew Ranostay +Matt Ranostay Mayuresh Janorkar Michael Buesch Michel Dänzer -- cgit v0.10.2 From deb4d1fdcb5af079896f7ca5e8067e69485f6bdd Mon Sep 17 00:00:00 2001 From: Crestez Dan Leonard Date: Fri, 3 Jun 2016 21:56:29 +0300 Subject: iio: generic_buffer: Fix --trigger-num option Initialize trig_num to -1 and handle trig_num=0 as a valid id. Fixes: 7c7e9dad (iio: iio_generic_buffer: Add --trigger-num option) Signed-off-by: Crestez Dan Leonard Signed-off-by: Jonathan Cameron diff --git a/tools/iio/iio_generic_buffer.c b/tools/iio/iio_generic_buffer.c index e8c3052..0e8a1f7 100644 --- a/tools/iio/iio_generic_buffer.c +++ b/tools/iio/iio_generic_buffer.c @@ -341,7 +341,7 @@ int main(int argc, char **argv) char *data = NULL; ssize_t read_size; - int dev_num = -1, trig_num; + int dev_num = -1, trig_num = -1; char *buffer_access = NULL; int scan_size; int noevents = 0; @@ -456,7 +456,7 @@ int main(int argc, char **argv) if (notrigger) { printf("trigger-less mode selected\n"); - } if (trig_num > 0) { + } if (trig_num >= 0) { char *trig_dev_name; ret = asprintf(&trig_dev_name, "%strigger%d", iio_dir, trig_num); if (ret < 0) { -- cgit v0.10.2 From 4a3691ccb3ce627874b93c000a9cdd86784e06cb Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Tue, 7 Jun 2016 13:18:30 +0100 Subject: irqchip/sirfsoc: Fix sparse warnings on __iomem Fix warnings from sparse about casting to __iomem from non anotated variable: drivers/irqchip/irq-sirfsoc.c:56:47: warning: incorrect type in initializer (different address spaces) drivers/irqchip/irq-sirfsoc.c:56:47: expected void [noderef] *base drivers/irqchip/irq-sirfsoc.c:56:47: got void *host_data drivers/irqchip/irq-sirfsoc.c:97:47: warning: incorrect type in initializer (different address spaces) drivers/irqchip/irq-sirfsoc.c:97:47: expected void [noderef] *base drivers/irqchip/irq-sirfsoc.c:97:47: got void *host_data drivers/irqchip/irq-sirfsoc.c:109:47: warning: incorrect type in initializer (different address spaces) drivers/irqchip/irq-sirfsoc.c:109:47: expected void [noderef] *base drivers/irqchip/irq-sirfsoc.c:109:47: got void *host_data Signed-off-by: Ben Dooks Link: https://lkml.kernel.org/r/1465301910-2308-1-git-send-email-ben.dooks@codethink.co.uk Signed-off-by: Jason Cooper diff --git a/drivers/irqchip/irq-sirfsoc.c b/drivers/irqchip/irq-sirfsoc.c index 10cb21b..e133684 100644 --- a/drivers/irqchip/irq-sirfsoc.c +++ b/drivers/irqchip/irq-sirfsoc.c @@ -29,6 +29,11 @@ static struct irq_domain *sirfsoc_irqdomain; +static void __iomem *sirfsoc_irq_get_regbase(void) +{ + return (void __iomem __force *)sirfsoc_irqdomain->host_data; +} + static __init void sirfsoc_alloc_gc(void __iomem *base) { unsigned int clr = IRQ_NOREQUEST | IRQ_NOPROBE | IRQ_NOAUTOEN; @@ -53,7 +58,7 @@ static __init void sirfsoc_alloc_gc(void __iomem *base) static void __exception_irq_entry sirfsoc_handle_irq(struct pt_regs *regs) { - void __iomem *base = sirfsoc_irqdomain->host_data; + void __iomem *base = sirfsoc_irq_get_regbase(); u32 irqstat; irqstat = readl_relaxed(base + SIRFSOC_INIT_IRQ_ID); @@ -94,7 +99,7 @@ static struct sirfsoc_irq_status sirfsoc_irq_st; static int sirfsoc_irq_suspend(void) { - void __iomem *base = sirfsoc_irqdomain->host_data; + void __iomem *base = sirfsoc_irq_get_regbase(); sirfsoc_irq_st.mask0 = readl_relaxed(base + SIRFSOC_INT_RISC_MASK0); sirfsoc_irq_st.mask1 = readl_relaxed(base + SIRFSOC_INT_RISC_MASK1); @@ -106,7 +111,7 @@ static int sirfsoc_irq_suspend(void) static void sirfsoc_irq_resume(void) { - void __iomem *base = sirfsoc_irqdomain->host_data; + void __iomem *base = sirfsoc_irq_get_regbase(); writel_relaxed(sirfsoc_irq_st.mask0, base + SIRFSOC_INT_RISC_MASK0); writel_relaxed(sirfsoc_irq_st.mask1, base + SIRFSOC_INT_RISC_MASK1); -- cgit v0.10.2 From f6fbaaa4c0fc5a304458a06996dc3efa96e3714b Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Tue, 7 Jun 2016 13:24:52 +0100 Subject: irqchip/tegra: Fix sparse warnings on __iomem Fix the following warnings from sparse due to casting to/from __iomem annotated variables: drivers/irqchip/irq-tegra.c:93:31: warning: incorrect type in initializer (different address spaces) drivers/irqchip/irq-tegra.c:93:31: expected void [noderef] *base drivers/irqchip/irq-tegra.c:93:31: got void *chip_data drivers/irqchip/irq-tegra.c:93:31: warning: incorrect type in initializer (different address spaces) drivers/irqchip/irq-tegra.c:93:31: expected void [noderef] *base drivers/irqchip/irq-tegra.c:93:31: got void *chip_data drivers/irqchip/irq-tegra.c:93:31: warning: incorrect type in initializer (different address spaces) drivers/irqchip/irq-tegra.c:93:31: expected void [noderef] *base drivers/irqchip/irq-tegra.c:93:31: got void *chip_data drivers/irqchip/irq-tegra.c:93:31: warning: incorrect type in initializer (different address spaces) drivers/irqchip/irq-tegra.c:93:31: expected void [noderef] *base drivers/irqchip/irq-tegra.c:93:31: got void *chip_data drivers/irqchip/irq-tegra.c:269:57: warning: incorrect type in argument 5 (different address spaces) drivers/irqchip/irq-tegra.c:269:57: expected void *chip_data drivers/irqchip/irq-tegra.c:269:57: got void [noderef] * Signed-off-by: Ben Dooks Acked-by: Thierry Reding Link: https://lkml.kernel.org/r/1465302292-4840-1-git-send-email-ben.dooks@codethink.co.uk Signed-off-by: Jason Cooper diff --git a/drivers/irqchip/irq-tegra.c b/drivers/irqchip/irq-tegra.c index e902f08..3973a14 100644 --- a/drivers/irqchip/irq-tegra.c +++ b/drivers/irqchip/irq-tegra.c @@ -90,7 +90,7 @@ static struct tegra_ictlr_info *lic; static inline void tegra_ictlr_write_mask(struct irq_data *d, unsigned long reg) { - void __iomem *base = d->chip_data; + void __iomem *base = (void __iomem __force *)d->chip_data; u32 mask; mask = BIT(d->hwirq % 32); @@ -266,7 +266,7 @@ static int tegra_ictlr_domain_alloc(struct irq_domain *domain, irq_domain_set_hwirq_and_chip(domain, virq + i, hwirq + i, &tegra_ictlr_chip, - info->base[ictlr]); + (void __force *)info->base[ictlr]); } parent_fwspec = *fwspec; -- cgit v0.10.2 From 6c880902419e6e2188fbd1e418ce82410f079a8d Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Wed, 8 Jun 2016 18:55:33 +0100 Subject: irqchip/armada-370-xp: Make syscore_ops static The armada_370_xp_mpic_syscore_ops structure is not exported or declared anywhere. Fix the following warning by making it static: drivers/irqchip/irq-armada-370-xp.c:544:20: warning: symbol 'armada_370_xp_mpic_syscore_ops' was not declared. Should it be static? Signed-off-by: Ben Dooks Link: https://lkml.kernel.org/r/1465408533-13906-1-git-send-email-ben.dooks@codethink.co.uk Signed-off-by: Jason Cooper diff --git a/drivers/irqchip/irq-armada-370-xp.c b/drivers/irqchip/irq-armada-370-xp.c index e7dc6cb..7c42b1d 100644 --- a/drivers/irqchip/irq-armada-370-xp.c +++ b/drivers/irqchip/irq-armada-370-xp.c @@ -541,7 +541,7 @@ static void armada_370_xp_mpic_resume(void) writel(1, per_cpu_int_base + ARMADA_370_XP_INT_CLEAR_MASK_OFFS); } -struct syscore_ops armada_370_xp_mpic_syscore_ops = { +static struct syscore_ops armada_370_xp_mpic_syscore_ops = { .suspend = armada_370_xp_mpic_suspend, .resume = armada_370_xp_mpic_resume, }; -- cgit v0.10.2 From 1eeb67362d93ab6099ed536641dac68df0f2e18d Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Wed, 8 Jun 2016 18:41:37 +0100 Subject: irqchip/bcm2836: Make bcm2836_smp_boot_secondary static The bcm2836_smp_boot_secondary() is not declared or used elsewhere so make it static to fix the following warning: drivers/irqchip/irq-bcm2836.c:227:12: warning: symbol 'bcm2836_smp_boot_secondary' was not declared. Should it be static? Signed-off-by: Ben Dooks Link: https://lkml.kernel.org/r/1465407697-8116-1-git-send-email-ben.dooks@codethink.co.uk Signed-off-by: Jason Cooper diff --git a/drivers/irqchip/irq-bcm2836.c b/drivers/irqchip/irq-bcm2836.c index 72ff1d5..6c72e60 100644 --- a/drivers/irqchip/irq-bcm2836.c +++ b/drivers/irqchip/irq-bcm2836.c @@ -224,8 +224,8 @@ static struct notifier_block bcm2836_arm_irqchip_cpu_notifier = { }; #ifdef CONFIG_ARM -int __init bcm2836_smp_boot_secondary(unsigned int cpu, - struct task_struct *idle) +static int __init bcm2836_smp_boot_secondary(unsigned int cpu, + struct task_struct *idle) { unsigned long secondary_startup_phys = (unsigned long)virt_to_phys((void *)secondary_startup); -- cgit v0.10.2 From dde7e6d1abdc874e6b26e9478b7ffc43cd5e3ee7 Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Wed, 8 Jun 2016 18:59:58 +0100 Subject: irqchip/bcm7120-l2: Make probe functions static The probe functions in this driver are not exported or declared for use elsewhere, so make them static to fix the warnings: drivers/irqchip/irq-bcm7120-l2.c:218:12: warning: symbol 'bcm7120_l2_intc_probe' was not declared. Should it be static? drivers/irqchip/irq-bcm7120-l2.c:342:12: warning: symbol 'bcm7120_l2_intc_probe_7120' was not declared. Should it be static? drivers/irqchip/irq-bcm7120-l2.c:349:12: warning: symbol 'bcm7120_l2_intc_probe_3380' was not declared. Should it be static? Signed-off-by: Ben Dooks Link: https://lkml.kernel.org/r/1465408798-16201-1-git-send-email-ben.dooks@codethink.co.uk Signed-off-by: Jason Cooper diff --git a/drivers/irqchip/irq-bcm7120-l2.c b/drivers/irqchip/irq-bcm7120-l2.c index 61b18ab..0ec9263 100644 --- a/drivers/irqchip/irq-bcm7120-l2.c +++ b/drivers/irqchip/irq-bcm7120-l2.c @@ -215,7 +215,7 @@ static int __init bcm7120_l2_intc_iomap_3380(struct device_node *dn, return 0; } -int __init bcm7120_l2_intc_probe(struct device_node *dn, +static int __init bcm7120_l2_intc_probe(struct device_node *dn, struct device_node *parent, int (*iomap_regs_fn)(struct device_node *, struct bcm7120_l2_intc_data *), @@ -339,15 +339,15 @@ out_unmap: return ret; } -int __init bcm7120_l2_intc_probe_7120(struct device_node *dn, - struct device_node *parent) +static int __init bcm7120_l2_intc_probe_7120(struct device_node *dn, + struct device_node *parent) { return bcm7120_l2_intc_probe(dn, parent, bcm7120_l2_intc_iomap_7120, "BCM7120 L2"); } -int __init bcm7120_l2_intc_probe_3380(struct device_node *dn, - struct device_node *parent) +static int __init bcm7120_l2_intc_probe_3380(struct device_node *dn, + struct device_node *parent) { return bcm7120_l2_intc_probe(dn, parent, bcm7120_l2_intc_iomap_3380, "BCM3380 L2"); -- cgit v0.10.2 From 2ae9add9d82df7a8cb130c9b0f8a797515ed72ef Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Wed, 8 Jun 2016 19:02:20 +0100 Subject: irqchip/brcmstb-l2: Make of probe function static The probe functions in this driver is not exported or declared so make it static to fix the following warning: drivers/irqchip/irq-brcmstb-l2.c:115:12: warning: symbol 'brcmstb_l2_intc_of_init' was not declared. Should it be static? Signed-off-by: Ben Dooks Link: https://lkml.kernel.org/r/1465408940-16414-1-git-send-email-ben.dooks@codethink.co.uk Signed-off-by: Jason Cooper diff --git a/drivers/irqchip/irq-brcmstb-l2.c b/drivers/irqchip/irq-brcmstb-l2.c index 65cd341..1d4a5b4 100644 --- a/drivers/irqchip/irq-brcmstb-l2.c +++ b/drivers/irqchip/irq-brcmstb-l2.c @@ -112,8 +112,8 @@ static void brcmstb_l2_intc_resume(struct irq_data *d) irq_gc_unlock(gc); } -int __init brcmstb_l2_intc_of_init(struct device_node *np, - struct device_node *parent) +static int __init brcmstb_l2_intc_of_init(struct device_node *np, + struct device_node *parent) { unsigned int clr = IRQ_NOREQUEST | IRQ_NOPROBE | IRQ_NOAUTOEN; struct brcmstb_l2_intc_data *data; -- cgit v0.10.2 From 7c034f1699735ddee2df60920fe5e5e78b8c940a Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Wed, 8 Jun 2016 18:53:34 +0100 Subject: irqchip/gic-v2m: Fix missing include of Fix the missing declaration of gicv2m_init() by including the file which defines it. Fixes the warning: drivers/irqchip/irq-gic-v2m.c:517:12: warning: symbol 'gicv2m_init' was not declared. Should it be static? Signed-off-by: Ben Dooks Link: https://lkml.kernel.org/r/1465408414-13698-1-git-send-email-ben.dooks@codethink.co.uk Signed-off-by: Jason Cooper diff --git a/drivers/irqchip/irq-gic-v2m.c b/drivers/irqchip/irq-gic-v2m.c index ad0d296..35eb7ac 100644 --- a/drivers/irqchip/irq-gic-v2m.c +++ b/drivers/irqchip/irq-gic-v2m.c @@ -24,6 +24,7 @@ #include #include #include +#include /* * MSI_TYPER: -- cgit v0.10.2 From f3142635de32cba695149a00efa9980958d5afdc Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Wed, 8 Jun 2016 18:44:32 +0100 Subject: irqchip/omap-intc: Fix missing include Fix the missing include of which declares all the missing functions from the following warnings: drivers/irqchip/irq-omap-intc.c:84:6: warning: symbol 'omap_intc_save_context' was not declared. Should it be static? drivers/irqchip/irq-omap-intc.c:105:6: warning: symbol 'omap_intc_restore_context' was not declared. Should it be static? drivers/irqchip/irq-omap-intc.c:124:6: warning: symbol 'omap3_intc_prepare_idle' was not declared. Should it be static? drivers/irqchip/irq-omap-intc.c:134:6: warning: symbol 'omap3_intc_resume_idle' was not declared. Should it be static? drivers/irqchip/irq-omap-intc.c:173:5: warning: symbol 'omap_irq_pending' was not declared. Should it be static? drivers/irqchip/irq-omap-intc.c:183:6: warning: symbol 'omap3_intc_suspend' was not declared. Should it be static? drivers/irqchip/irq-omap-intc.c:365:13: warning: symbol 'omap3_init_irq' was not declared. Should it be static? Signed-off-by: Ben Dooks Link: https://lkml.kernel.org/r/1465407872-10299-1-git-send-email-ben.dooks@codethink.co.uk Signed-off-by: Jason Cooper diff --git a/drivers/irqchip/irq-omap-intc.c b/drivers/irqchip/irq-omap-intc.c index 9d1bcfc..b04a8ac 100644 --- a/drivers/irqchip/irq-omap-intc.c +++ b/drivers/irqchip/irq-omap-intc.c @@ -23,6 +23,8 @@ #include #include +#include + /* Define these here for now until we drop all board-files */ #define OMAP24XX_IC_BASE 0x480fe000 #define OMAP34XX_IC_BASE 0x48200000 -- cgit v0.10.2 From df042a5f4ce4d930fe8c28653479e25595c08549 Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Thu, 9 Jun 2016 11:30:12 +0100 Subject: irqchip/vic: Make vic_syscore_ops and vic_of_init static The vic_syscore_ops and vic_of_init functions are not exported outside the driver, so make them static to remove the following warnings: drivers/irqchip/irq-vic.c:170:20: warning: symbol 'vic_syscore_ops' was not declared. Should it be static? drivers/irqchip/irq-vic.c:520:12: warning: symbol 'vic_of_init' was not declared. Should it be static? Signed-off-by: Ben Dooks Link: https://lkml.kernel.org/r/1465468212-2937-1-git-send-email-ben.dooks@codethink.co.uk Signed-off-by: Jason Cooper diff --git a/drivers/irqchip/irq-vic.c b/drivers/irqchip/irq-vic.c index b956dff..f811a7d 100644 --- a/drivers/irqchip/irq-vic.c +++ b/drivers/irqchip/irq-vic.c @@ -167,7 +167,7 @@ static int vic_suspend(void) return 0; } -struct syscore_ops vic_syscore_ops = { +static struct syscore_ops vic_syscore_ops = { .suspend = vic_suspend, .resume = vic_resume, }; @@ -517,7 +517,8 @@ int __init vic_init_cascaded(void __iomem *base, unsigned int parent_irq, EXPORT_SYMBOL_GPL(vic_init_cascaded); #ifdef CONFIG_OF -int __init vic_of_init(struct device_node *node, struct device_node *parent) +static int __init vic_of_init(struct device_node *node, + struct device_node *parent) { void __iomem *regs; u32 interrupt_mask = ~0; -- cgit v0.10.2 From b62b2cf5759b0c2206ddff92226f1eb8ac8f9f13 Mon Sep 17 00:00:00 2001 From: Jon Hunter Date: Tue, 7 Jun 2016 16:12:26 +0100 Subject: irqdomain: Fix handling of type settings for existing mappings When mapping an IRQ, it is possible that a mapping for the IRQ already exists. If mapping does exist then there are the following issues with regard to the handling of the IRQ type settings ... 1. If the domain is part of a hierarchy, then: a. We do not check that the type settings for the existing mapping match those of the new mapping. b. We do not check to see if the type settings have been programmed yet (and they might not have been) and so we may never set the type. 2. If the domain is NOT part of a hierarchy, we will overwrite the current type settings programmed if they are different from the previous mapping. Please note that irq_create_mapping() calls irq_find_mapping() to check if a mapping already exists. Although, it may be unlikely that the type settings for a shared interrupt would not match, nonetheless we should check for this. Therefore, to fix this check if a mapping exists (regardless of whether the domain is part of a hierarchy or not) and if it does then: 1. Return the IRQ number if the type settings match or are not specified. 2. Program the type settings and return the IRQ number if the type settings have not been programmed yet. 3. Otherwise if the type setting do not match, then print a warning and don't return the IRQ number. Furthermore, add a warning if the type return by irq_domain_translate() has bits outside the sense mask set and then clear these bits. If these bits are not cleared then this will cause the comparision of the type settings for an existing mapping to fail with that of the new mapping even if the sense bit themselves match. The reason being is that the existing type settings are read by calling irq_get_trigger_type() which will clear any bits outside the sense mask. This will allow us to detect irqchips that are not correctly clearing these bits and fix them. Signed-off-by: Jon Hunter Reviewed-by: Marc Zyngier Signed-off-by: Marc Zyngier diff --git a/kernel/irq/irqdomain.c b/kernel/irq/irqdomain.c index 8798b6c..f3ff1eb 100644 --- a/kernel/irq/irqdomain.c +++ b/kernel/irq/irqdomain.c @@ -588,15 +588,42 @@ unsigned int irq_create_fwspec_mapping(struct irq_fwspec *fwspec) if (irq_domain_translate(domain, fwspec, &hwirq, &type)) return 0; - if (irq_domain_is_hierarchy(domain)) { + /* + * WARN if the irqchip returns a type with bits + * outside the sense mask set and clear these bits. + */ + if (WARN_ON(type & ~IRQ_TYPE_SENSE_MASK)) + type &= IRQ_TYPE_SENSE_MASK; + + /* + * If we've already configured this interrupt, + * don't do it again, or hell will break loose. + */ + virq = irq_find_mapping(domain, hwirq); + if (virq) { /* - * If we've already configured this interrupt, - * don't do it again, or hell will break loose. + * If the trigger type is not specified or matches the + * current trigger type then we are done so return the + * interrupt number. */ - virq = irq_find_mapping(domain, hwirq); - if (virq) + if (type == IRQ_TYPE_NONE || type == irq_get_trigger_type(virq)) return virq; + /* + * If the trigger type has not been set yet, then set + * it now and return the interrupt number. + */ + if (irq_get_trigger_type(virq) == IRQ_TYPE_NONE) { + irq_set_irq_type(virq, type); + return virq; + } + + pr_warn("type mismatch, failed to map hwirq-%lu for %s!\n", + hwirq, of_node_full_name(to_of_node(fwspec->fwnode))); + return 0; + } + + if (irq_domain_is_hierarchy(domain)) { virq = irq_domain_alloc_irqs(domain, 1, NUMA_NO_NODE, fwspec); if (virq <= 0) return 0; -- cgit v0.10.2 From 4b357daed698c95d6b5eacc1c3c4afa206071ba2 Mon Sep 17 00:00:00 2001 From: Jon Hunter Date: Tue, 7 Jun 2016 16:12:27 +0100 Subject: genirq: Look-up trigger type if not specified by caller For some devices the IRQ trigger type for a device is read from firmware, such as device-tree. The IRQ trigger type is typically read when the mapping for IRQ is created, which is before the IRQ is requested. Hence, the IRQ trigger type is programmed when mapping the IRQ and not when requesting the IRQ. Although this works for most cases, in order to support IRQ chips which require runtime power management, which may not be accessible prior to requesting the IRQ, it is desirable to look-up the IRQ trigger type when it is requested. Therefore, if the IRQ trigger type is not specified when __setup_irq() is called, look-up the saved IRQ trigger type. This will allow us to defer the programming of the trigger type from when the IRQ is mapped to when it is actually requested. Signed-off-by: Jon Hunter Reviewed-by: Marc Zyngier Signed-off-by: Marc Zyngier diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c index ef0bc02..eaedeb7 100644 --- a/kernel/irq/manage.c +++ b/kernel/irq/manage.c @@ -1117,6 +1117,13 @@ __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new) new->irq = irq; /* + * If the trigger type is not specified by the caller, + * then use the default for this interrupt. + */ + if (!(new->flags & IRQF_TRIGGER_MASK)) + new->flags |= irqd_get_trigger_type(&desc->irq_data); + + /* * Check whether the interrupt nests into another interrupt * thread. */ -- cgit v0.10.2 From f35ad083783e8ed6ac030f5feb209f864875b413 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Mon, 13 Jun 2016 10:39:44 +0100 Subject: genirq: Look-up percpu trigger type if not specified by caller As we now do for non-percpu interrupt, perform a lookup of the interrupt trigger if the user doesn't supply one. The difference here is that we can only do it at enable time (trigger configuration can be per-cpu as well). Signed-off-by: Marc Zyngier diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c index eaedeb7..f78b084 100644 --- a/kernel/irq/manage.c +++ b/kernel/irq/manage.c @@ -1737,7 +1737,14 @@ void enable_percpu_irq(unsigned int irq, unsigned int type) if (!desc) return; + /* + * If the trigger type is not specified by the caller, then + * use the default for this interrupt. + */ type &= IRQ_TYPE_SENSE_MASK; + if (type == IRQ_TYPE_NONE) + type = irqd_get_trigger_type(&desc->irq_data); + if (type != IRQ_TYPE_NONE) { int ret; -- cgit v0.10.2 From 1e2a7d78499ec8859d2b469051b7b80bad3b08aa Mon Sep 17 00:00:00 2001 From: Jon Hunter Date: Tue, 7 Jun 2016 16:12:28 +0100 Subject: irqdomain: Don't set type when mapping an IRQ Some IRQ chips, such as GPIO controllers or secondary level interrupt controllers, may require require additional runtime power management control to ensure they are accessible. For such IRQ chips, it makes sense to enable the IRQ chip when interrupts are requested and disabled them again once all interrupts have been freed. When mapping an IRQ, the IRQ type settings are read and then programmed. The mapping of the IRQ happens before the IRQ is requested and so the programming of the type settings occurs before the IRQ is requested. This is a problem for IRQ chips that require additional power management control because they may not be accessible yet. Therefore, when mapping the IRQ, don't program the type settings, just save them and then program these saved settings when the IRQ is requested (so long as if they are not overridden via the call to request the IRQ). Add a stub function for irq_domain_free_irqs() to avoid any compilation errors when CONFIG_IRQ_DOMAIN_HIERARCHY is not selected. Signed-off-by: Jon Hunter Reviewed-by: Marc Zyngier Signed-off-by: Marc Zyngier diff --git a/include/linux/irqdomain.h b/include/linux/irqdomain.h index f1f36e0..3175037 100644 --- a/include/linux/irqdomain.h +++ b/include/linux/irqdomain.h @@ -452,6 +452,9 @@ static inline int irq_domain_alloc_irqs(struct irq_domain *domain, return -1; } +static inline void irq_domain_free_irqs(unsigned int virq, + unsigned int nr_irqs) { } + static inline bool irq_domain_is_hierarchy(struct irq_domain *domain) { return false; diff --git a/kernel/irq/irqdomain.c b/kernel/irq/irqdomain.c index f3ff1eb..caa6a63 100644 --- a/kernel/irq/irqdomain.c +++ b/kernel/irq/irqdomain.c @@ -567,6 +567,7 @@ static void of_phandle_args_to_fwspec(struct of_phandle_args *irq_data, unsigned int irq_create_fwspec_mapping(struct irq_fwspec *fwspec) { struct irq_domain *domain; + struct irq_data *irq_data; irq_hw_number_t hwirq; unsigned int type = IRQ_TYPE_NONE; int virq; @@ -614,7 +615,11 @@ unsigned int irq_create_fwspec_mapping(struct irq_fwspec *fwspec) * it now and return the interrupt number. */ if (irq_get_trigger_type(virq) == IRQ_TYPE_NONE) { - irq_set_irq_type(virq, type); + irq_data = irq_get_irq_data(virq); + if (!irq_data) + return 0; + + irqd_set_trigger_type(irq_data, type); return virq; } @@ -634,10 +639,18 @@ unsigned int irq_create_fwspec_mapping(struct irq_fwspec *fwspec) return virq; } - /* Set type if specified and different than the current one */ - if (type != IRQ_TYPE_NONE && - type != irq_get_trigger_type(virq)) - irq_set_irq_type(virq, type); + irq_data = irq_get_irq_data(virq); + if (!irq_data) { + if (irq_domain_is_hierarchy(domain)) + irq_domain_free_irqs(virq, 1); + else + irq_dispose_mapping(virq); + return 0; + } + + /* Store trigger type */ + irqd_set_trigger_type(irq_data, type); + return virq; } EXPORT_SYMBOL_GPL(irq_create_fwspec_mapping); -- cgit v0.10.2 From be45beb2df6909d42a6b3b0052601b3eef878fc0 Mon Sep 17 00:00:00 2001 From: Jon Hunter Date: Tue, 7 Jun 2016 16:12:29 +0100 Subject: genirq: Add runtime power management support for IRQ chips Some IRQ chips may be located in a power domain outside of the CPU subsystem and hence will require device specific runtime power management. In order to support such IRQ chips, add a pointer for a device structure to the irq_chip structure, and if this pointer is populated by the IRQ chip driver and CONFIG_PM is selected in the kernel configuration, then the pm_runtime_get/put APIs for this chip will be called when an IRQ is requested/freed, respectively. Reviewed-by: Kevin Hilman Signed-off-by: Jon Hunter Signed-off-by: Marc Zyngier diff --git a/include/linux/irq.h b/include/linux/irq.h index 4d758a7..6c92a84 100644 --- a/include/linux/irq.h +++ b/include/linux/irq.h @@ -315,6 +315,7 @@ static inline irq_hw_number_t irqd_to_hwirq(struct irq_data *d) /** * struct irq_chip - hardware interrupt chip descriptor * + * @parent_device: pointer to parent device for irqchip * @name: name for /proc/interrupts * @irq_startup: start up the interrupt (defaults to ->enable if NULL) * @irq_shutdown: shut down the interrupt (defaults to ->disable if NULL) @@ -354,6 +355,7 @@ static inline irq_hw_number_t irqd_to_hwirq(struct irq_data *d) * @flags: chip specific flags */ struct irq_chip { + struct device *parent_device; const char *name; unsigned int (*irq_startup)(struct irq_data *data); void (*irq_shutdown)(struct irq_data *data); @@ -488,6 +490,8 @@ extern void handle_bad_irq(struct irq_desc *desc); extern void handle_nested_irq(unsigned int irq); extern int irq_chip_compose_msi_msg(struct irq_data *data, struct msi_msg *msg); +extern int irq_chip_pm_get(struct irq_data *data); +extern int irq_chip_pm_put(struct irq_data *data); #ifdef CONFIG_IRQ_DOMAIN_HIERARCHY extern void irq_chip_enable_parent(struct irq_data *data); extern void irq_chip_disable_parent(struct irq_data *data); diff --git a/kernel/irq/chip.c b/kernel/irq/chip.c index 2f9f2b0..ad81314 100644 --- a/kernel/irq/chip.c +++ b/kernel/irq/chip.c @@ -1093,3 +1093,43 @@ int irq_chip_compose_msi_msg(struct irq_data *data, struct msi_msg *msg) return 0; } + +/** + * irq_chip_pm_get - Enable power for an IRQ chip + * @data: Pointer to interrupt specific data + * + * Enable the power to the IRQ chip referenced by the interrupt data + * structure. + */ +int irq_chip_pm_get(struct irq_data *data) +{ + int retval; + + if (IS_ENABLED(CONFIG_PM) && data->chip->parent_device) { + retval = pm_runtime_get_sync(data->chip->parent_device); + if (retval < 0) { + pm_runtime_put_noidle(data->chip->parent_device); + return retval; + } + } + + return 0; +} + +/** + * irq_chip_pm_put - Disable power for an IRQ chip + * @data: Pointer to interrupt specific data + * + * Disable the power to the IRQ chip referenced by the interrupt data + * structure, belongs. Note that power will only be disabled, once this + * function has been called for all IRQs that have called irq_chip_pm_get(). + */ +int irq_chip_pm_put(struct irq_data *data) +{ + int retval = 0; + + if (IS_ENABLED(CONFIG_PM) && data->chip->parent_device) + retval = pm_runtime_put(data->chip->parent_device); + + return (retval < 0) ? retval : 0; +} diff --git a/kernel/irq/internals.h b/kernel/irq/internals.h index 09be2c9..d5edcdc 100644 --- a/kernel/irq/internals.h +++ b/kernel/irq/internals.h @@ -7,6 +7,7 @@ */ #include #include +#include #ifdef CONFIG_SPARSE_IRQ # define IRQ_BITMAP_BITS (NR_IRQS + 8196) diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c index f78b084..00cfc85 100644 --- a/kernel/irq/manage.c +++ b/kernel/irq/manage.c @@ -1416,10 +1416,18 @@ int setup_irq(unsigned int irq, struct irqaction *act) if (!desc || WARN_ON(irq_settings_is_per_cpu_devid(desc))) return -EINVAL; + + retval = irq_chip_pm_get(&desc->irq_data); + if (retval < 0) + return retval; + chip_bus_lock(desc); retval = __setup_irq(irq, desc, act); chip_bus_sync_unlock(desc); + if (retval) + irq_chip_pm_put(&desc->irq_data); + return retval; } EXPORT_SYMBOL_GPL(setup_irq); @@ -1513,6 +1521,7 @@ static struct irqaction *__free_irq(unsigned int irq, void *dev_id) } } + irq_chip_pm_put(&desc->irq_data); module_put(desc->owner); kfree(action->secondary); return action; @@ -1655,11 +1664,16 @@ int request_threaded_irq(unsigned int irq, irq_handler_t handler, action->name = devname; action->dev_id = dev_id; + retval = irq_chip_pm_get(&desc->irq_data); + if (retval < 0) + return retval; + chip_bus_lock(desc); retval = __setup_irq(irq, desc, action); chip_bus_sync_unlock(desc); if (retval) { + irq_chip_pm_put(&desc->irq_data); kfree(action->secondary); kfree(action); } @@ -1836,6 +1850,7 @@ static struct irqaction *__free_percpu_irq(unsigned int irq, void __percpu *dev_ unregister_handler_proc(irq, action); + irq_chip_pm_put(&desc->irq_data); module_put(desc->owner); return action; @@ -1898,10 +1913,18 @@ int setup_percpu_irq(unsigned int irq, struct irqaction *act) if (!desc || !irq_settings_is_per_cpu_devid(desc)) return -EINVAL; + + retval = irq_chip_pm_get(&desc->irq_data); + if (retval < 0) + return retval; + chip_bus_lock(desc); retval = __setup_irq(irq, desc, act); chip_bus_sync_unlock(desc); + if (retval) + irq_chip_pm_put(&desc->irq_data); + return retval; } @@ -1945,12 +1968,18 @@ int request_percpu_irq(unsigned int irq, irq_handler_t handler, action->name = devname; action->percpu_dev_id = dev_id; + retval = irq_chip_pm_get(&desc->irq_data); + if (retval < 0) + return retval; + chip_bus_lock(desc); retval = __setup_irq(irq, desc, action); chip_bus_sync_unlock(desc); - if (retval) + if (retval) { + irq_chip_pm_put(&desc->irq_data); kfree(action); + } return retval; } -- cgit v0.10.2 From d6ce564cea0c9f8fe7e1b400026482f4e61d38ad Mon Sep 17 00:00:00 2001 From: Jon Hunter Date: Tue, 7 Jun 2016 16:12:30 +0100 Subject: irqchip/gic: Isolate early GIC initialisation code To re-use the code that initialises the GIC (found in __gic_init_bases()), from within a platform driver, it is necessary to move the code from the __init section so that it is always present and not removed. Unfortunately, it is not possible to simply drop the __init from the function declaration for __gic_init_bases() because it contains calls to set_smp_cross_call() and set_handle_irq() which are both located in the __init section. Fortunately, these calls are only required for the root controller and because the initial platform driver will only support non-root controllers that can be initialised later in the boot process, we can move these calls to another function. Move the bulk of the code from __gic_init_bases() to a new function called gic_init_bases() which is not located in the __init section and can be used by the platform driver. Update __gic_init_bases() to call gic_init_bases() and if necessary, set_smp_cross_call() and set_handle_irq(). Signed-off-by: Jon Hunter Signed-off-by: Marc Zyngier diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c index fbc4ae2..fa0dd98 100644 --- a/drivers/irqchip/irq-gic.c +++ b/drivers/irqchip/irq-gic.c @@ -1032,14 +1032,11 @@ static const struct irq_domain_ops gic_irq_domain_ops = { .unmap = gic_irq_domain_unmap, }; -static int __init __gic_init_bases(struct gic_chip_data *gic, int irq_start, - struct fwnode_handle *handle) +static int gic_init_bases(struct gic_chip_data *gic, int irq_start, + struct fwnode_handle *handle) { irq_hw_number_t hwirq_base; - int gic_irqs, irq_base, i, ret; - - if (WARN_ON(!gic || gic->domain)) - return -EINVAL; + int gic_irqs, irq_base, ret; /* Initialize irq_chip */ gic->chip = gic_chip; @@ -1138,23 +1135,6 @@ static int __init __gic_init_bases(struct gic_chip_data *gic, int irq_start, goto error; } - if (gic == &gic_data[0]) { - /* - * Initialize the CPU interface map to all CPUs. - * It will be refined as each CPU probes its ID. - * This is only necessary for the primary GIC. - */ - for (i = 0; i < NR_GIC_CPU_IF; i++) - gic_cpu_map[i] = 0xff; -#ifdef CONFIG_SMP - set_smp_cross_call(gic_raise_softirq); - register_cpu_notifier(&gic_cpu_notifier); -#endif - set_handle_irq(gic_handle_irq); - if (static_key_true(&supports_deactivate)) - pr_info("GIC: Using split EOI/Deactivate mode\n"); - } - gic_dist_init(gic); ret = gic_cpu_init(gic); if (ret) @@ -1177,6 +1157,35 @@ error: return ret; } +static int __init __gic_init_bases(struct gic_chip_data *gic, + int irq_start, + struct fwnode_handle *handle) +{ + int i; + + if (WARN_ON(!gic || gic->domain)) + return -EINVAL; + + if (gic == &gic_data[0]) { + /* + * Initialize the CPU interface map to all CPUs. + * It will be refined as each CPU probes its ID. + * This is only necessary for the primary GIC. + */ + for (i = 0; i < NR_GIC_CPU_IF; i++) + gic_cpu_map[i] = 0xff; +#ifdef CONFIG_SMP + set_smp_cross_call(gic_raise_softirq); + register_cpu_notifier(&gic_cpu_notifier); +#endif + set_handle_irq(gic_handle_irq); + if (static_key_true(&supports_deactivate)) + pr_info("GIC: Using split EOI/Deactivate mode\n"); + } + + return gic_init_bases(gic, irq_start, handle); +} + void __init gic_init(unsigned int gic_nr, int irq_start, void __iomem *dist_base, void __iomem *cpu_base) { -- cgit v0.10.2 From faea645585de88303a74171321a9188fd3dd7df5 Mon Sep 17 00:00:00 2001 From: Jon Hunter Date: Tue, 7 Jun 2016 16:12:31 +0100 Subject: irqchip/gic: Add helper function for chip initialisation For GICs that require runtime power-management it is necessary to populate the 'parent_device' member of the irqchip structure. In preparation for supporting such GICs, move the code that initialises the irqchip structure for a GIC into its own function called gic_init_chip() where the parent device pointer is also set. Instead of calling gic_init_chip() from within gic_init_bases(), move the calls to outside of this function, so that in the future we can avoid having to pass additional parameters to gic_init_bases() in order set the parent device pointer or set the name to a specific string. Signed-off-by: Jon Hunter Signed-off-by: Marc Zyngier diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c index fa0dd98..94eab6e 100644 --- a/drivers/irqchip/irq-gic.c +++ b/drivers/irqchip/irq-gic.c @@ -1032,29 +1032,31 @@ static const struct irq_domain_ops gic_irq_domain_ops = { .unmap = gic_irq_domain_unmap, }; -static int gic_init_bases(struct gic_chip_data *gic, int irq_start, - struct fwnode_handle *handle) +static void gic_init_chip(struct gic_chip_data *gic, struct device *dev, + const char *name, bool use_eoimode1) { - irq_hw_number_t hwirq_base; - int gic_irqs, irq_base, ret; - /* Initialize irq_chip */ gic->chip = gic_chip; + gic->chip.name = name; + gic->chip.parent_device = dev; - if (static_key_true(&supports_deactivate) && gic == &gic_data[0]) { + if (use_eoimode1) { gic->chip.irq_mask = gic_eoimode1_mask_irq; gic->chip.irq_eoi = gic_eoimode1_eoi_irq; gic->chip.irq_set_vcpu_affinity = gic_irq_set_vcpu_affinity; - gic->chip.name = kasprintf(GFP_KERNEL, "GICv2"); - } else { - gic->chip.name = kasprintf(GFP_KERNEL, "GIC-%d", - (int)(gic - &gic_data[0])); } #ifdef CONFIG_SMP if (gic == &gic_data[0]) gic->chip.irq_set_affinity = gic_set_affinity; #endif +} + +static int gic_init_bases(struct gic_chip_data *gic, int irq_start, + struct fwnode_handle *handle) +{ + irq_hw_number_t hwirq_base; + int gic_irqs, irq_base, ret; if (IS_ENABLED(CONFIG_GIC_NON_BANKED) && gic->percpu_offset) { /* Frankein-GIC without banked registers... */ @@ -1152,8 +1154,6 @@ error: free_percpu(gic->cpu_base.percpu_base); } - kfree(gic->chip.name); - return ret; } @@ -1161,7 +1161,8 @@ static int __init __gic_init_bases(struct gic_chip_data *gic, int irq_start, struct fwnode_handle *handle) { - int i; + char *name; + int i, ret; if (WARN_ON(!gic || gic->domain)) return -EINVAL; @@ -1183,7 +1184,19 @@ static int __init __gic_init_bases(struct gic_chip_data *gic, pr_info("GIC: Using split EOI/Deactivate mode\n"); } - return gic_init_bases(gic, irq_start, handle); + if (static_key_true(&supports_deactivate) && gic == &gic_data[0]) { + name = kasprintf(GFP_KERNEL, "GICv2"); + gic_init_chip(gic, NULL, name, true); + } else { + name = kasprintf(GFP_KERNEL, "GIC-%d", (int)(gic-&gic_data[0])); + gic_init_chip(gic, NULL, name, false); + } + + ret = gic_init_bases(gic, irq_start, handle); + if (ret) + kfree(name); + + return ret; } void __init gic_init(unsigned int gic_nr, int irq_start, -- cgit v0.10.2 From cdbb813db6925f9dcd352841d8ba28f2edd83ff8 Mon Sep 17 00:00:00 2001 From: Jon Hunter Date: Tue, 7 Jun 2016 16:12:32 +0100 Subject: irqchip/gic: Prepare for adding platform driver To support GICs that require runtime power management, it is necessary to add a platform driver, so that the probing of the chip can be deferred if resources, such as a power-domain, is not yet available. To prepare for adding a platform driver: 1. Drop the __init section from the gic_dist_config() so this can be re-used by the platform driver. 2. Add prototypes for functions required by the platform driver to the GIC header file so they can be re-used. Signed-off-by: Jon Hunter Signed-off-by: Marc Zyngier diff --git a/drivers/irqchip/irq-gic-common.c b/drivers/irqchip/irq-gic-common.c index 89e7423..9ae7180 100644 --- a/drivers/irqchip/irq-gic-common.c +++ b/drivers/irqchip/irq-gic-common.c @@ -90,8 +90,8 @@ int gic_configure_irq(unsigned int irq, unsigned int type, return ret; } -void __init gic_dist_config(void __iomem *base, int gic_irqs, - void (*sync_access)(void)) +void gic_dist_config(void __iomem *base, int gic_irqs, + void (*sync_access)(void)) { unsigned int i; diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c index 94eab6e..141ea58 100644 --- a/drivers/irqchip/irq-gic.c +++ b/drivers/irqchip/irq-gic.c @@ -449,7 +449,7 @@ static void gic_cpu_if_up(struct gic_chip_data *gic) } -static void __init gic_dist_init(struct gic_chip_data *gic) +static void gic_dist_init(struct gic_chip_data *gic) { unsigned int i; u32 cpumask; @@ -535,7 +535,7 @@ int gic_cpu_if_down(unsigned int gic_nr) * this function, no interrupts will be delivered by the GIC, and another * platform-specific wakeup source must be enabled. */ -static void gic_dist_save(struct gic_chip_data *gic) +void gic_dist_save(struct gic_chip_data *gic) { unsigned int gic_irqs; void __iomem *dist_base; @@ -574,7 +574,7 @@ static void gic_dist_save(struct gic_chip_data *gic) * handled normally, but any edge interrupts that occured will not be seen by * the GIC and need to be handled by the platform-specific wakeup source. */ -static void gic_dist_restore(struct gic_chip_data *gic) +void gic_dist_restore(struct gic_chip_data *gic) { unsigned int gic_irqs; unsigned int i; @@ -620,7 +620,7 @@ static void gic_dist_restore(struct gic_chip_data *gic) writel_relaxed(GICD_ENABLE, dist_base + GIC_DIST_CTRL); } -static void gic_cpu_save(struct gic_chip_data *gic) +void gic_cpu_save(struct gic_chip_data *gic) { int i; u32 *ptr; @@ -650,7 +650,7 @@ static void gic_cpu_save(struct gic_chip_data *gic) } -static void gic_cpu_restore(struct gic_chip_data *gic) +void gic_cpu_restore(struct gic_chip_data *gic) { int i; u32 *ptr; @@ -727,7 +727,7 @@ static struct notifier_block gic_notifier_block = { .notifier_call = gic_notifier, }; -static int __init gic_pm_init(struct gic_chip_data *gic) +static int gic_pm_init(struct gic_chip_data *gic) { gic->saved_ppi_enable = __alloc_percpu(DIV_ROUND_UP(32, 32) * 4, sizeof(u32)); @@ -757,7 +757,7 @@ free_ppi_enable: return -ENOMEM; } #else -static int __init gic_pm_init(struct gic_chip_data *gic) +static int gic_pm_init(struct gic_chip_data *gic) { return 0; } diff --git a/include/linux/irqchip/arm-gic.h b/include/linux/irqchip/arm-gic.h index fd05185..ffcbd8b 100644 --- a/include/linux/irqchip/arm-gic.h +++ b/include/linux/irqchip/arm-gic.h @@ -101,9 +101,14 @@ #include struct device_node; +struct gic_chip_data; void gic_cascade_irq(unsigned int gic_nr, unsigned int irq); int gic_cpu_if_down(unsigned int gic_nr); +void gic_cpu_save(struct gic_chip_data *gic); +void gic_cpu_restore(struct gic_chip_data *gic); +void gic_dist_save(struct gic_chip_data *gic); +void gic_dist_restore(struct gic_chip_data *gic); /* * Subdrivers that need some preparatory work can initialize their -- cgit v0.10.2 From 39f8f23d13666c4c5644e5add7d9598d9e798f22 Mon Sep 17 00:00:00 2001 From: Jon Hunter Date: Tue, 7 Jun 2016 16:12:33 +0100 Subject: dt-bindings: arm-gic: Add documentation for Tegra210 AGIC The Tegra AGIC interrupt controller is compatible with the ARM GIC-400 interrupt controller. Add the compatible string and clock information for the AGIC to the GIC device-tree binding documentation. Signed-off-by: Jon Hunter Acked-by: Rob Herring Signed-off-by: Marc Zyngier diff --git a/Documentation/devicetree/bindings/interrupt-controller/arm,gic.txt b/Documentation/devicetree/bindings/interrupt-controller/arm,gic.txt index 793c20f..5393e2a 100644 --- a/Documentation/devicetree/bindings/interrupt-controller/arm,gic.txt +++ b/Documentation/devicetree/bindings/interrupt-controller/arm,gic.txt @@ -21,6 +21,7 @@ Main node required properties: "arm,pl390" "arm,tc11mp-gic" "brcm,brahma-b15-gic" + "nvidia,tegra210-agic" "qcom,msm-8660-qgic" "qcom,msm-qgic2" - interrupt-controller : Identifies the node as an interrupt controller @@ -68,7 +69,7 @@ Optional "ic_clk" (for "arm,arm11mp-gic") "PERIPHCLKEN" (for "arm,cortex-a15-gic") "PERIPHCLK", "PERIPHCLKEN" (for "arm,cortex-a9-gic") - "clk" (for "arm,gic-400") + "clk" (for "arm,gic-400" and "nvidia,tegra210") "gclk" (for "arm,pl390") - power-domains : A phandle and PM domain specifier as defined by bindings of -- cgit v0.10.2 From 9c8edddfc9924cb473a7570c37ca466db70728f8 Mon Sep 17 00:00:00 2001 From: Jon Hunter Date: Tue, 7 Jun 2016 16:12:34 +0100 Subject: irqchip/gic: Add platform driver for non-root GICs that require RPM Add a platform driver to support non-root GICs that require runtime power-management. Currently, only non-root GICs are supported because the functions, smp_cross_call() and set_handle_irq(), that need to be called for a root controller are located in the __init section and so cannot be called by the platform driver. The GIC platform driver re-uses many functions from the existing GIC driver including some functions to save and restore the GIC context during power transitions. The functions for saving and restoring the GIC context are currently only defined if CONFIG_CPU_PM is enabled and to ensure that these functions are always defined when the platform driver is enabled, a dependency on CONFIG_ARM_GIC_PM (which selects the platform driver) has been added. In order to re-use the private GIC initialisation code, a new public function, gic_of_init_child(), has been added which calls various private functions to initialise the GIC. This is different from the existing gic_of_init() because it only supports non-root GICs (ie. does not call smp_cross_call() is set_handle_irq()) and is not located in the __init section (so can be used by platform drivers). Furthermore, gic_of_init_child() dynamically allocates memory for the GIC chip data which is also different from gic_of_init(). There is no specific suspend handling for GICs registered as platform devices. Non-wakeup interrupts will be disabled by the kernel during late suspend, however, this alone will not power down the GIC if interrupts have been requested and not freed. Therefore, requestors of non-wakeup interrupts will need to free them on entering suspend in order to power-down the GIC. Signed-off-by: Jon Hunter Signed-off-by: Marc Zyngier diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig index fa33c50..5495a5b 100644 --- a/drivers/irqchip/Kconfig +++ b/drivers/irqchip/Kconfig @@ -8,6 +8,12 @@ config ARM_GIC select IRQ_DOMAIN_HIERARCHY select MULTI_IRQ_HANDLER +config ARM_GIC_PM + bool + depends on PM + select ARM_GIC + select PM_CLK + config ARM_GIC_MAX_NR int default 2 if ARCH_REALVIEW diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile index 38853a1..bd0257e 100644 --- a/drivers/irqchip/Makefile +++ b/drivers/irqchip/Makefile @@ -24,6 +24,7 @@ obj-$(CONFIG_ARCH_SUNXI) += irq-sun4i.o obj-$(CONFIG_ARCH_SUNXI) += irq-sunxi-nmi.o obj-$(CONFIG_ARCH_SPEAR3XX) += spear-shirq.o obj-$(CONFIG_ARM_GIC) += irq-gic.o irq-gic-common.o +obj-$(CONFIG_ARM_GIC_PM) += irq-gic-pm.o obj-$(CONFIG_REALVIEW_DT) += irq-gic-realview.o obj-$(CONFIG_ARM_GIC_V2M) += irq-gic-v2m.o obj-$(CONFIG_ARM_GIC_V3) += irq-gic-v3.o irq-gic-common.o diff --git a/drivers/irqchip/irq-gic-pm.c b/drivers/irqchip/irq-gic-pm.c new file mode 100644 index 0000000..4cbffba --- /dev/null +++ b/drivers/irqchip/irq-gic-pm.c @@ -0,0 +1,184 @@ +/* + * Copyright (C) 2016 NVIDIA CORPORATION, All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct gic_clk_data { + unsigned int num_clocks; + const char *const *clocks; +}; + +static int gic_runtime_resume(struct device *dev) +{ + struct gic_chip_data *gic = dev_get_drvdata(dev); + int ret; + + ret = pm_clk_resume(dev); + if (ret) + return ret; + + /* + * On the very first resume, the pointer to the driver data + * will be NULL and this is intentional, because we do not + * want to restore the GIC on the very first resume. So if + * the pointer is not valid just return. + */ + if (!gic) + return 0; + + gic_dist_restore(gic); + gic_cpu_restore(gic); + + return 0; +} + +static int gic_runtime_suspend(struct device *dev) +{ + struct gic_chip_data *gic = dev_get_drvdata(dev); + + gic_dist_save(gic); + gic_cpu_save(gic); + + return pm_clk_suspend(dev); +} + +static int gic_get_clocks(struct device *dev, const struct gic_clk_data *data) +{ + struct clk *clk; + unsigned int i; + int ret; + + if (!dev || !data) + return -EINVAL; + + ret = pm_clk_create(dev); + if (ret) + return ret; + + for (i = 0; i < data->num_clocks; i++) { + clk = of_clk_get_by_name(dev->of_node, data->clocks[i]); + if (IS_ERR(clk)) { + dev_err(dev, "failed to get clock %s\n", + data->clocks[i]); + ret = PTR_ERR(clk); + goto error; + } + + ret = pm_clk_add_clk(dev, clk); + if (ret) { + dev_err(dev, "failed to add clock at index %d\n", i); + clk_put(clk); + goto error; + } + } + + return 0; + +error: + pm_clk_destroy(dev); + + return ret; +} + +static int gic_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + const struct gic_clk_data *data; + struct gic_chip_data *gic; + int ret, irq; + + data = of_device_get_match_data(&pdev->dev); + if (!data) { + dev_err(&pdev->dev, "no device match found\n"); + return -ENODEV; + } + + irq = irq_of_parse_and_map(dev->of_node, 0); + if (!irq) { + dev_err(dev, "no parent interrupt found!\n"); + return -EINVAL; + } + + ret = gic_get_clocks(dev, data); + if (ret) + goto irq_dispose; + + pm_runtime_enable(dev); + + ret = pm_runtime_get_sync(dev); + if (ret < 0) + goto rpm_disable; + + ret = gic_of_init_child(dev, &gic, irq); + if (ret) + goto rpm_put; + + platform_set_drvdata(pdev, gic); + + pm_runtime_put(dev); + + dev_info(dev, "GIC IRQ controller registered\n"); + + return 0; + +rpm_put: + pm_runtime_put_sync(dev); +rpm_disable: + pm_runtime_disable(dev); + pm_clk_destroy(dev); +irq_dispose: + irq_dispose_mapping(irq); + + return ret; +} + +static const struct dev_pm_ops gic_pm_ops = { + SET_RUNTIME_PM_OPS(gic_runtime_suspend, + gic_runtime_resume, NULL) +}; + +static const char * const gic400_clocks[] = { + "clk", +}; + +static const struct gic_clk_data gic400_data = { + .num_clocks = ARRAY_SIZE(gic400_clocks), + .clocks = gic400_clocks, +}; + +static const struct of_device_id gic_match[] = { + { .compatible = "nvidia,tegra210-agic", .data = &gic400_data }, + {}, +}; +MODULE_DEVICE_TABLE(of, gic_match); + +static struct platform_driver gic_driver = { + .probe = gic_probe, + .driver = { + .name = "gic", + .of_match_table = gic_match, + .pm = &gic_pm_ops, + } +}; + +builtin_platform_driver(gic_driver); diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c index 141ea58..1de07eb 100644 --- a/drivers/irqchip/irq-gic.c +++ b/drivers/irqchip/irq-gic.c @@ -75,7 +75,7 @@ struct gic_chip_data { void __iomem *raw_dist_base; void __iomem *raw_cpu_base; u32 percpu_offset; -#ifdef CONFIG_CPU_PM +#if defined(CONFIG_CPU_PM) || defined(CONFIG_ARM_GIC_PM) u32 saved_spi_enable[DIV_ROUND_UP(1020, 32)]; u32 saved_spi_active[DIV_ROUND_UP(1020, 32)]; u32 saved_spi_conf[DIV_ROUND_UP(1020, 16)]; @@ -528,7 +528,7 @@ int gic_cpu_if_down(unsigned int gic_nr) return 0; } -#ifdef CONFIG_CPU_PM +#if defined(CONFIG_CPU_PM) || defined(CONFIG_ARM_GIC_PM) /* * Saves the GIC distributor registers during suspend or idle. Must be called * with interrupts disabled but before powering down the GIC. After calling @@ -1272,7 +1272,7 @@ static bool gic_check_eoimode(struct device_node *node, void __iomem **base) return true; } -static int __init gic_of_setup(struct gic_chip_data *gic, struct device_node *node) +static int gic_of_setup(struct gic_chip_data *gic, struct device_node *node) { if (!gic || !node) return -EINVAL; @@ -1296,6 +1296,34 @@ error: return -ENOMEM; } +int gic_of_init_child(struct device *dev, struct gic_chip_data **gic, int irq) +{ + int ret; + + if (!dev || !dev->of_node || !gic || !irq) + return -EINVAL; + + *gic = devm_kzalloc(dev, sizeof(**gic), GFP_KERNEL); + if (!*gic) + return -ENOMEM; + + gic_init_chip(*gic, dev, dev->of_node->name, false); + + ret = gic_of_setup(*gic, dev->of_node); + if (ret) + return ret; + + ret = gic_init_bases(*gic, -1, &dev->of_node->fwnode); + if (ret) { + gic_teardown(*gic); + return ret; + } + + irq_set_chained_handler_and_data(irq, gic_handle_cascade_irq, *gic); + + return 0; +} + static void __init gic_of_setup_kvm_info(struct device_node *node) { int ret; @@ -1375,7 +1403,11 @@ IRQCHIP_DECLARE(cortex_a7_gic, "arm,cortex-a7-gic", gic_of_init); IRQCHIP_DECLARE(msm_8660_qgic, "qcom,msm-8660-qgic", gic_of_init); IRQCHIP_DECLARE(msm_qgic2, "qcom,msm-qgic2", gic_of_init); IRQCHIP_DECLARE(pl390, "arm,pl390", gic_of_init); - +#else +int gic_of_init_child(struct device *dev, struct gic_chip_data **gic, int irq) +{ + return -ENOTSUPP; +} #endif #ifdef CONFIG_ACPI diff --git a/include/linux/irqchip/arm-gic.h b/include/linux/irqchip/arm-gic.h index ffcbd8b..eafc965 100644 --- a/include/linux/irqchip/arm-gic.h +++ b/include/linux/irqchip/arm-gic.h @@ -117,6 +117,12 @@ void gic_dist_restore(struct gic_chip_data *gic); int gic_of_init(struct device_node *node, struct device_node *parent); /* + * Initialises and registers a non-root or child GIC chip. Memory for + * the gic_chip_data structure is dynamically allocated. + */ +int gic_of_init_child(struct device *dev, struct gic_chip_data **gic, int irq); + +/* * Legacy platforms not converted to DT yet must use this to init * their GIC */ -- cgit v0.10.2 From 2d81d425b6d5cc2262912cce9f9ec7f706a3ea65 Mon Sep 17 00:00:00 2001 From: Shanker Donthineni Date: Mon, 6 Jun 2016 18:17:28 -0500 Subject: irqchip/gicv3-its: Introduce two helper functions for accessing BASERn This patch adds the two handy helper functions for reading and writing ITS BASERn register. Signed-off-by: Shanker Donthineni [Marc: Folded its_write_baser_cache into its_write_baser] Signed-off-by: Marc Zyngier diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c index 5eb1f9e..a8a1144 100644 --- a/drivers/irqchip/irq-gic-v3-its.c +++ b/drivers/irqchip/irq-gic-v3-its.c @@ -824,6 +824,22 @@ static const char *its_base_type_string[] = { [GITS_BASER_TYPE_RESERVED7] = "Reserved (7)", }; +static u64 its_read_baser(struct its_node *its, struct its_baser *baser) +{ + u32 idx = baser - its->tables; + + return readq_relaxed(its->base + GITS_BASER + (idx << 3)); +} + +static void its_write_baser(struct its_node *its, struct its_baser *baser, + u64 val) +{ + u32 idx = baser - its->tables; + + writeq_relaxed(val, its->base + GITS_BASER + (idx << 3)); + baser->val = its_read_baser(its, baser); +} + static void its_free_tables(struct its_node *its) { int i; @@ -863,7 +879,8 @@ static int its_alloc_tables(const char *node_name, struct its_node *its) its->device_ids = ids; for (i = 0; i < GITS_BASER_NR_REGS; i++) { - u64 val = readq_relaxed(its->base + GITS_BASER + i * 8); + struct its_baser *baser = its->tables + i; + u64 val = its_read_baser(its, baser); u64 type = GITS_BASER_TYPE(val); u64 entry_size = GITS_BASER_ENTRY_SIZE(val); int order = get_order(psz); @@ -937,10 +954,9 @@ retry_baser: } val |= alloc_pages - 1; - its->tables[i].val = val; - writeq_relaxed(val, its->base + GITS_BASER + i * 8); - tmp = readq_relaxed(its->base + GITS_BASER + i * 8); + its_write_baser_cache(its, baser, val); + tmp = baser->val; if ((val ^ tmp) & GITS_BASER_SHAREABILITY_MASK) { /* -- cgit v0.10.2 From 4b75c4598b5b8312b8e3d37b6486729cf333dbf5 Mon Sep 17 00:00:00 2001 From: Shanker Donthineni Date: Mon, 6 Jun 2016 18:17:29 -0500 Subject: irqchip/gicv3-its: Add a new function for parsing device table BASERn Only the device table BASERn needs to be handled differently as compared to all other tables. So, adding a separate function for easy code maintenance and improved code readability. Signed-off-by: Shanker Donthineni Signed-off-by: Marc Zyngier diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c index a8a1144..5cfa299 100644 --- a/drivers/irqchip/irq-gic-v3-its.c +++ b/drivers/irqchip/irq-gic-v3-its.c @@ -840,6 +840,30 @@ static void its_write_baser(struct its_node *its, struct its_baser *baser, baser->val = its_read_baser(its, baser); } +static void its_parse_baser_device(struct its_node *its, struct its_baser *baser, + u32 *order) +{ + u64 esz = GITS_BASER_ENTRY_SIZE(its_read_baser(its, baser)); + u32 ids = its->device_ids; + u32 new_order = *order; + + /* + * Allocate as many entries as required to fit the + * range of device IDs that the ITS can grok... The ID + * space being incredibly sparse, this results in a + * massive waste of memory. + */ + new_order = max_t(u32, get_order(esz << ids), new_order); + if (new_order >= MAX_ORDER) { + new_order = MAX_ORDER - 1; + ids = ilog2(PAGE_ORDER_TO_SIZE(new_order) / esz); + pr_warn("ITS@%pa: Device Table too large, reduce ids %u->%u\n", + &its->phys_base, its->device_ids, ids); + } + + *order = new_order; +} + static void its_free_tables(struct its_node *its) { int i; @@ -891,29 +915,8 @@ static int its_alloc_tables(const char *node_name, struct its_node *its) if (type == GITS_BASER_TYPE_NONE) continue; - /* - * Allocate as many entries as required to fit the - * range of device IDs that the ITS can grok... The ID - * space being incredibly sparse, this results in a - * massive waste of memory. - * - * For other tables, only allocate a single page. - */ - if (type == GITS_BASER_TYPE_DEVICE) { - /* - * 'order' was initialized earlier to the default page - * granule of the the ITS. We can't have an allocation - * smaller than that. If the requested allocation - * is smaller, round up to the default page granule. - */ - order = max(get_order((1UL << ids) * entry_size), - order); - if (order >= MAX_ORDER) { - order = MAX_ORDER - 1; - pr_warn("%s: Device Table too large, reduce its page order to %u\n", - node_name, order); - } - } + if (type == GITS_BASER_TYPE_DEVICE) + its_parse_baser_device(its, baser, &order); retry_alloc_baser: alloc_pages = (PAGE_ORDER_TO_SIZE(order) / psz); -- cgit v0.10.2 From 9347359ad0aeeed16bf8c2d4576a2c40edaa9c85 Mon Sep 17 00:00:00 2001 From: Shanker Donthineni Date: Mon, 6 Jun 2016 18:17:30 -0500 Subject: irqchip/gicv3-its: Split its_alloc_tables() into two functions The function is getting out of control, it has too many goto statements and would be too complicated for adding a feature two-level device table. So, it is time for us to cleanup and move some of the logic to a separate function without affecting the existing functionality. Signed-off-by: Shanker Donthineni Signed-off-by: Marc Zyngier diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c index 5cfa299..146189b 100644 --- a/drivers/irqchip/irq-gic-v3-its.c +++ b/drivers/irqchip/irq-gic-v3-its.c @@ -56,13 +56,14 @@ struct its_collection { }; /* - * The ITS_BASER structure - contains memory information and cached - * value of BASER register configuration. + * The ITS_BASER structure - contains memory information, cached + * value of BASER register configuration and ITS page size. */ struct its_baser { void *base; u64 val; u32 order; + u32 psz; }; /* @@ -840,6 +841,110 @@ static void its_write_baser(struct its_node *its, struct its_baser *baser, baser->val = its_read_baser(its, baser); } +static int its_setup_baser(struct its_node *its, struct its_baser *baser, + u64 cache, u64 shr, u32 psz, u32 order) +{ + u64 val = its_read_baser(its, baser); + u64 esz = GITS_BASER_ENTRY_SIZE(val); + u64 type = GITS_BASER_TYPE(val); + u32 alloc_pages; + void *base; + u64 tmp; + +retry_alloc_baser: + alloc_pages = (PAGE_ORDER_TO_SIZE(order) / psz); + if (alloc_pages > GITS_BASER_PAGES_MAX) { + pr_warn("ITS@%pa: %s too large, reduce ITS pages %u->%u\n", + &its->phys_base, its_base_type_string[type], + alloc_pages, GITS_BASER_PAGES_MAX); + alloc_pages = GITS_BASER_PAGES_MAX; + order = get_order(GITS_BASER_PAGES_MAX * psz); + } + + base = (void *)__get_free_pages(GFP_KERNEL | __GFP_ZERO, order); + if (!base) + return -ENOMEM; + +retry_baser: + val = (virt_to_phys(base) | + (type << GITS_BASER_TYPE_SHIFT) | + ((esz - 1) << GITS_BASER_ENTRY_SIZE_SHIFT) | + ((alloc_pages - 1) << GITS_BASER_PAGES_SHIFT) | + cache | + shr | + GITS_BASER_VALID); + + switch (psz) { + case SZ_4K: + val |= GITS_BASER_PAGE_SIZE_4K; + break; + case SZ_16K: + val |= GITS_BASER_PAGE_SIZE_16K; + break; + case SZ_64K: + val |= GITS_BASER_PAGE_SIZE_64K; + break; + } + + its_write_baser(its, baser, val); + tmp = baser->val; + + if ((val ^ tmp) & GITS_BASER_SHAREABILITY_MASK) { + /* + * Shareability didn't stick. Just use + * whatever the read reported, which is likely + * to be the only thing this redistributor + * supports. If that's zero, make it + * non-cacheable as well. + */ + shr = tmp & GITS_BASER_SHAREABILITY_MASK; + if (!shr) { + cache = GITS_BASER_nC; + __flush_dcache_area(base, PAGE_ORDER_TO_SIZE(order)); + } + goto retry_baser; + } + + if ((val ^ tmp) & GITS_BASER_PAGE_SIZE_MASK) { + /* + * Page size didn't stick. Let's try a smaller + * size and retry. If we reach 4K, then + * something is horribly wrong... + */ + free_pages((unsigned long)base, order); + baser->base = NULL; + + switch (psz) { + case SZ_16K: + psz = SZ_4K; + goto retry_alloc_baser; + case SZ_64K: + psz = SZ_16K; + goto retry_alloc_baser; + } + } + + if (val != tmp) { + pr_err("ITS@%pa: %s doesn't stick: %lx %lx\n", + &its->phys_base, its_base_type_string[type], + (unsigned long) val, (unsigned long) tmp); + free_pages((unsigned long)base, order); + return -ENXIO; + } + + baser->order = order; + baser->base = base; + baser->psz = psz; + + pr_info("ITS@%pa: allocated %d %s @%lx (psz %dK, shr %d)\n", + &its->phys_base, (int)(PAGE_ORDER_TO_SIZE(order) / esz), + its_base_type_string[type], + (unsigned long)virt_to_phys(base), + psz / SZ_1K, (int)shr >> GITS_BASER_SHAREABILITY_SHIFT); + + return 0; +} + static void its_parse_baser_device(struct its_node *its, struct its_baser *baser, u32 *order) { @@ -879,25 +984,20 @@ static void its_free_tables(struct its_node *its) static int its_alloc_tables(const char *node_name, struct its_node *its) { - int err; - int i; - int psz = SZ_64K; + u64 typer = readq_relaxed(its->base + GITS_TYPER); + u32 ids = GITS_TYPER_DEVBITS(typer); u64 shr = GITS_BASER_InnerShareable; - u64 cache; - u64 typer; - u32 ids; + u64 cache = GITS_BASER_WaWb; + u32 psz = SZ_64K; + int err, i; if (its->flags & ITS_FLAGS_WORKAROUND_CAVIUM_22375) { /* - * erratum 22375: only alloc 8MB table size - * erratum 24313: ignore memory access type - */ - cache = 0; - ids = 0x14; /* 20 bits, 8MB */ - } else { - cache = GITS_BASER_WaWb; - typer = readq_relaxed(its->base + GITS_TYPER); - ids = GITS_TYPER_DEVBITS(typer); + * erratum 22375: only alloc 8MB table size + * erratum 24313: ignore memory access type + */ + cache = GITS_BASER_nCnB; + ids = 0x14; /* 20 bits, 8MB */ } its->device_ids = ids; @@ -906,11 +1006,7 @@ static int its_alloc_tables(const char *node_name, struct its_node *its) struct its_baser *baser = its->tables + i; u64 val = its_read_baser(its, baser); u64 type = GITS_BASER_TYPE(val); - u64 entry_size = GITS_BASER_ENTRY_SIZE(val); - int order = get_order(psz); - int alloc_pages; - u64 tmp; - void *base; + u32 order = get_order(psz); if (type == GITS_BASER_TYPE_NONE) continue; @@ -918,105 +1014,19 @@ static int its_alloc_tables(const char *node_name, struct its_node *its) if (type == GITS_BASER_TYPE_DEVICE) its_parse_baser_device(its, baser, &order); -retry_alloc_baser: - alloc_pages = (PAGE_ORDER_TO_SIZE(order) / psz); - if (alloc_pages > GITS_BASER_PAGES_MAX) { - alloc_pages = GITS_BASER_PAGES_MAX; - order = get_order(GITS_BASER_PAGES_MAX * psz); - pr_warn("%s: Device Table too large, reduce its page order to %u (%u pages)\n", - node_name, order, alloc_pages); - } - - base = (void *)__get_free_pages(GFP_KERNEL | __GFP_ZERO, order); - if (!base) { - err = -ENOMEM; - goto out_free; - } - - its->tables[i].base = base; - its->tables[i].order = order; - -retry_baser: - val = (virt_to_phys(base) | - (type << GITS_BASER_TYPE_SHIFT) | - ((entry_size - 1) << GITS_BASER_ENTRY_SIZE_SHIFT) | - cache | - shr | - GITS_BASER_VALID); - - switch (psz) { - case SZ_4K: - val |= GITS_BASER_PAGE_SIZE_4K; - break; - case SZ_16K: - val |= GITS_BASER_PAGE_SIZE_16K; - break; - case SZ_64K: - val |= GITS_BASER_PAGE_SIZE_64K; - break; - } - - val |= alloc_pages - 1; - - its_write_baser_cache(its, baser, val); - tmp = baser->val; - - if ((val ^ tmp) & GITS_BASER_SHAREABILITY_MASK) { - /* - * Shareability didn't stick. Just use - * whatever the read reported, which is likely - * to be the only thing this redistributor - * supports. If that's zero, make it - * non-cacheable as well. - */ - shr = tmp & GITS_BASER_SHAREABILITY_MASK; - if (!shr) { - cache = GITS_BASER_nC; - __flush_dcache_area(base, PAGE_ORDER_TO_SIZE(order)); - } - goto retry_baser; - } - - if ((val ^ tmp) & GITS_BASER_PAGE_SIZE_MASK) { - /* - * Page size didn't stick. Let's try a smaller - * size and retry. If we reach 4K, then - * something is horribly wrong... - */ - free_pages((unsigned long)base, order); - its->tables[i].base = NULL; - - switch (psz) { - case SZ_16K: - psz = SZ_4K; - goto retry_alloc_baser; - case SZ_64K: - psz = SZ_16K; - goto retry_alloc_baser; - } - } - - if (val != tmp) { - pr_err("ITS: %s: GITS_BASER%d doesn't stick: %lx %lx\n", - node_name, i, - (unsigned long) val, (unsigned long) tmp); - err = -ENXIO; - goto out_free; + err = its_setup_baser(its, baser, cache, shr, psz, order); + if (err < 0) { + its_free_tables(its); + return err; } - pr_info("ITS: allocated %d %s @%lx (psz %dK, shr %d)\n", - (int)(PAGE_ORDER_TO_SIZE(order) / entry_size), - its_base_type_string[type], - (unsigned long)virt_to_phys(base), - psz / SZ_1K, (int)shr >> GITS_BASER_SHAREABILITY_SHIFT); + /* Update settings which will be used for next BASERn */ + psz = baser->psz; + cache = baser->val & GITS_BASER_CACHEABILITY_MASK; + shr = baser->val & GITS_BASER_SHAREABILITY_MASK; } return 0; - -out_free: - its_free_tables(its); - - return err; } static int its_alloc_collections(struct its_node *its) diff --git a/include/linux/irqchip/arm-gic-v3.h b/include/linux/irqchip/arm-gic-v3.h index dc493e0..01cf171 100644 --- a/include/linux/irqchip/arm-gic-v3.h +++ b/include/linux/irqchip/arm-gic-v3.h @@ -228,6 +228,7 @@ #define GITS_BASER_PAGE_SIZE_64K (2UL << GITS_BASER_PAGE_SIZE_SHIFT) #define GITS_BASER_PAGE_SIZE_MASK (3UL << GITS_BASER_PAGE_SIZE_SHIFT) #define GITS_BASER_PAGES_MAX 256 +#define GITS_BASER_PAGES_SHIFT (0) #define GITS_BASER_TYPE_NONE 0 #define GITS_BASER_TYPE_DEVICE 1 -- cgit v0.10.2 From 0e0b0f69c5c528a750479c9bc9ba904df014517c Mon Sep 17 00:00:00 2001 From: Shanker Donthineni Date: Mon, 6 Jun 2016 18:17:31 -0500 Subject: irqchip/gicv3-its: Remove an unused argument 'node_name' No references to argument 'node_name' after modifying pr_xxx() messages to include ITS base address instead of 'node_name'. Signed-off-by: Shanker Donthineni Signed-off-by: Marc Zyngier diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c index 146189b..7afac33 100644 --- a/drivers/irqchip/irq-gic-v3-its.c +++ b/drivers/irqchip/irq-gic-v3-its.c @@ -982,7 +982,7 @@ static void its_free_tables(struct its_node *its) } } -static int its_alloc_tables(const char *node_name, struct its_node *its) +static int its_alloc_tables(struct its_node *its) { u64 typer = readq_relaxed(its->base + GITS_TYPER); u32 ids = GITS_TYPER_DEVBITS(typer); @@ -1598,7 +1598,7 @@ static int __init its_probe(struct device_node *node, its_enable_quirks(its); - err = its_alloc_tables(node->full_name, its); + err = its_alloc_tables(its); if (err) goto out_free_cmd; -- cgit v0.10.2 From 3faf24ea894a34887c0ca412f1643540251b9d82 Mon Sep 17 00:00:00 2001 From: Shanker Donthineni Date: Mon, 6 Jun 2016 18:17:32 -0500 Subject: irqchip/gicv3-its: Implement two-level(indirect) device table support Since device IDs are extremely sparse, the single, a.k.a flat table is not sufficient for the following two reasons. 1) According to ARM-GIC spec, ITS hw can access maximum of 256(pages)* 64K(pageszie) bytes. In the best case, it supports upto DEVid=21 sparse with minimum device table entry size 8bytes. 2) The maximum memory size that is possible without memblock depends on MAX_ORDER. 4MB on 4K page size kernel with default MAX_ORDER, so it supports DEVid range 19bits. The two-level device table feature brings us two advantages, the first is a very high possibility of supporting upto 32bit sparse, and the second one is the best utilization of memory allocation. The feature is enabled automatically during driver probe if the memory requirement is more than 2*ITS-pages and the hardware is capable of two-level table walk. Signed-off-by: Shanker Donthineni Signed-off-by: Marc Zyngier diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c index 7afac33..7ceaba8 100644 --- a/drivers/irqchip/irq-gic-v3-its.c +++ b/drivers/irqchip/irq-gic-v3-its.c @@ -842,7 +842,8 @@ static void its_write_baser(struct its_node *its, struct its_baser *baser, } static int its_setup_baser(struct its_node *its, struct its_baser *baser, - u64 cache, u64 shr, u32 psz, u32 order) + u64 cache, u64 shr, u32 psz, u32 order, + bool indirect) { u64 val = its_read_baser(its, baser); u64 esz = GITS_BASER_ENTRY_SIZE(val); @@ -874,6 +875,8 @@ retry_baser: shr | GITS_BASER_VALID); + val |= indirect ? GITS_BASER_INDIRECT : 0x0; + switch (psz) { case SZ_4K: val |= GITS_BASER_PAGE_SIZE_4K; @@ -935,28 +938,55 @@ retry_baser: baser->order = order; baser->base = base; baser->psz = psz; + tmp = indirect ? GITS_LVL1_ENTRY_SIZE : esz; - pr_info("ITS@%pa: allocated %d %s @%lx (psz %dK, shr %d)\n", - &its->phys_base, (int)(PAGE_ORDER_TO_SIZE(order) / esz), + pr_info("ITS@%pa: allocated %d %s @%lx (%s, esz %d, psz %dK, shr %d)\n", + &its->phys_base, (int)(PAGE_ORDER_TO_SIZE(order) / tmp), its_base_type_string[type], (unsigned long)virt_to_phys(base), + indirect ? "indirect" : "flat", (int)esz, psz / SZ_1K, (int)shr >> GITS_BASER_SHAREABILITY_SHIFT); return 0; } -static void its_parse_baser_device(struct its_node *its, struct its_baser *baser, - u32 *order) +static bool its_parse_baser_device(struct its_node *its, struct its_baser *baser, + u32 psz, u32 *order) { u64 esz = GITS_BASER_ENTRY_SIZE(its_read_baser(its, baser)); + u64 val = GITS_BASER_InnerShareable | GITS_BASER_WaWb; u32 ids = its->device_ids; u32 new_order = *order; + bool indirect = false; + + /* No need to enable Indirection if memory requirement < (psz*2)bytes */ + if ((esz << ids) > (psz * 2)) { + /* + * Find out whether hw supports a single or two-level table by + * table by reading bit at offset '62' after writing '1' to it. + */ + its_write_baser(its, baser, val | GITS_BASER_INDIRECT); + indirect = !!(baser->val & GITS_BASER_INDIRECT); + + if (indirect) { + /* + * The size of the lvl2 table is equal to ITS page size + * which is 'psz'. For computing lvl1 table size, + * subtract ID bits that sparse lvl2 table from 'ids' + * which is reported by ITS hardware times lvl1 table + * entry size. + */ + ids -= ilog2(psz / esz); + esz = GITS_LVL1_ENTRY_SIZE; + } + } /* * Allocate as many entries as required to fit the * range of device IDs that the ITS can grok... The ID * space being incredibly sparse, this results in a - * massive waste of memory. + * massive waste of memory if two-level device table + * feature is not supported by hardware. */ new_order = max_t(u32, get_order(esz << ids), new_order); if (new_order >= MAX_ORDER) { @@ -967,6 +997,8 @@ static void its_parse_baser_device(struct its_node *its, struct its_baser *baser } *order = new_order; + + return indirect; } static void its_free_tables(struct its_node *its) @@ -1007,14 +1039,15 @@ static int its_alloc_tables(struct its_node *its) u64 val = its_read_baser(its, baser); u64 type = GITS_BASER_TYPE(val); u32 order = get_order(psz); + bool indirect = false; if (type == GITS_BASER_TYPE_NONE) continue; if (type == GITS_BASER_TYPE_DEVICE) - its_parse_baser_device(its, baser, &order); + indirect = its_parse_baser_device(its, baser, psz, &order); - err = its_setup_baser(its, baser, cache, shr, psz, order); + err = its_setup_baser(its, baser, cache, shr, psz, order, indirect); if (err < 0) { its_free_tables(its); return err; @@ -1214,10 +1247,57 @@ static struct its_baser *its_get_baser(struct its_node *its, u32 type) return NULL; } +static bool its_alloc_device_table(struct its_node *its, u32 dev_id) +{ + struct its_baser *baser; + struct page *page; + u32 esz, idx; + __le64 *table; + + baser = its_get_baser(its, GITS_BASER_TYPE_DEVICE); + + /* Don't allow device id that exceeds ITS hardware limit */ + if (!baser) + return (ilog2(dev_id) < its->device_ids); + + /* Don't allow device id that exceeds single, flat table limit */ + esz = GITS_BASER_ENTRY_SIZE(baser->val); + if (!(baser->val & GITS_BASER_INDIRECT)) + return (dev_id < (PAGE_ORDER_TO_SIZE(baser->order) / esz)); + + /* Compute 1st level table index & check if that exceeds table limit */ + idx = dev_id >> ilog2(baser->psz / esz); + if (idx >= (PAGE_ORDER_TO_SIZE(baser->order) / GITS_LVL1_ENTRY_SIZE)) + return false; + + table = baser->base; + + /* Allocate memory for 2nd level table */ + if (!table[idx]) { + page = alloc_pages(GFP_KERNEL | __GFP_ZERO, get_order(baser->psz)); + if (!page) + return false; + + /* Flush Lvl2 table to PoC if hw doesn't support coherency */ + if (!(baser->val & GITS_BASER_SHAREABILITY_MASK)) + __flush_dcache_area(page_address(page), baser->psz); + + table[idx] = cpu_to_le64(page_to_phys(page) | GITS_BASER_VALID); + + /* Flush Lvl1 entry to PoC if hw doesn't support coherency */ + if (!(baser->val & GITS_BASER_SHAREABILITY_MASK)) + __flush_dcache_area(table + idx, GITS_LVL1_ENTRY_SIZE); + + /* Ensure updated table contents are visible to ITS hardware */ + dsb(sy); + } + + return true; +} + static struct its_device *its_create_device(struct its_node *its, u32 dev_id, int nvecs) { - struct its_baser *baser; struct its_device *dev; unsigned long *lpi_map; unsigned long flags; @@ -1228,14 +1308,7 @@ static struct its_device *its_create_device(struct its_node *its, u32 dev_id, int nr_ites; int sz; - baser = its_get_baser(its, GITS_BASER_TYPE_DEVICE); - - /* Don't allow 'dev_id' that exceeds single, flat table limit */ - if (baser) { - if (dev_id >= (PAGE_ORDER_TO_SIZE(baser->order) / - GITS_BASER_ENTRY_SIZE(baser->val))) - return NULL; - } else if (ilog2(dev_id) >= its->device_ids) + if (!its_alloc_device_table(its, dev_id)) return NULL; dev = kzalloc(sizeof(*dev), GFP_KERNEL); diff --git a/include/linux/irqchip/arm-gic-v3.h b/include/linux/irqchip/arm-gic-v3.h index 01cf171..107eed4 100644 --- a/include/linux/irqchip/arm-gic-v3.h +++ b/include/linux/irqchip/arm-gic-v3.h @@ -204,6 +204,7 @@ #define GITS_BASER_NR_REGS 8 #define GITS_BASER_VALID (1UL << 63) +#define GITS_BASER_INDIRECT (1UL << 62) #define GITS_BASER_nCnB (0UL << 59) #define GITS_BASER_nC (1UL << 59) #define GITS_BASER_RaWt (2UL << 59) @@ -239,6 +240,8 @@ #define GITS_BASER_TYPE_RESERVED6 6 #define GITS_BASER_TYPE_RESERVED7 7 +#define GITS_LVL1_ENTRY_SIZE (8UL) + /* * ITS commands */ -- cgit v0.10.2 From d72fea6214f3fee2355d8cb6c51348059d98768b Mon Sep 17 00:00:00 2001 From: Ajit Pandey Date: Mon, 13 Jun 2016 13:35:15 +0100 Subject: ASoC: wm5110: Add missing route from OUT3R to SYSCLK Output 3 is stereo on wm5110 and all inputs/outputs should have a connection to SYSCLK. This patch adds the missing DAPM route. Signed-off-by: Ajit Pandey Signed-off-by: Charles Keepax Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/wm5110.c b/sound/soc/codecs/wm5110.c index b5820e4..d54f1b4 100644 --- a/sound/soc/codecs/wm5110.c +++ b/sound/soc/codecs/wm5110.c @@ -1723,6 +1723,7 @@ static const struct snd_soc_dapm_route wm5110_dapm_routes[] = { { "OUT2L", NULL, "SYSCLK" }, { "OUT2R", NULL, "SYSCLK" }, { "OUT3L", NULL, "SYSCLK" }, + { "OUT3R", NULL, "SYSCLK" }, { "OUT4L", NULL, "SYSCLK" }, { "OUT4R", NULL, "SYSCLK" }, { "OUT5L", NULL, "SYSCLK" }, -- cgit v0.10.2 From 19edeb30c55079c9bba4573d700bbcafed03303c Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Mon, 13 Jun 2016 13:35:16 +0100 Subject: ASoC: wm5102: Correct supported channels on trace compressed DAI The audio trace firmware on wm5102 only supports 4 channels correct the DAI driver structure to reflect this. Signed-off-by: Charles Keepax Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/wm5102.c b/sound/soc/codecs/wm5102.c index da60e3f..e7fe6b7 100644 --- a/sound/soc/codecs/wm5102.c +++ b/sound/soc/codecs/wm5102.c @@ -1872,7 +1872,7 @@ static struct snd_soc_dai_driver wm5102_dai[] = { .capture = { .stream_name = "Audio Trace CPU", .channels_min = 1, - .channels_max = 6, + .channels_max = 4, .rates = WM5102_RATES, .formats = WM5102_FORMATS, }, -- cgit v0.10.2 From ed7bdf5c9c15f8b23af4d00975f9976734eadb14 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Mon, 13 Jun 2016 22:44:57 +0200 Subject: staging: lustre: hide call to Posix ACL in ifdef A call to forget_cached_acl() was recently added to the lustre file system, but this is only available when CONFIG_FS_POSIX_ACL is enabled, otherwise the build now fails with: lustre/llite/file.c: In function 'll_get_acl': lustre/llite/file.c:3134:2: error: implicit declaration of function 'forget_cached_acl' [-Werror=implicit-function-declaration] forget_cached_acl(inode, type); This adds one more #ifdef for this call, corresponding to the other 22 such checks for ACL in lustre. Signed-off-by: Arnd Bergmann Fixes: b788dc51e425 ("staging: lustre: llite: drop acl from cache") Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/lustre/lustre/llite/file.c b/drivers/staging/lustre/lustre/llite/file.c index bafa0b7..26c6cd6 100644 --- a/drivers/staging/lustre/lustre/llite/file.c +++ b/drivers/staging/lustre/lustre/llite/file.c @@ -3131,7 +3131,9 @@ struct posix_acl *ll_get_acl(struct inode *inode, int type) spin_lock(&lli->lli_lock); /* VFS' acl_permission_check->check_acl will release the refcount */ acl = posix_acl_dup(lli->lli_posix_acl); +#ifdef CONFIG_FS_POSIX_ACL forget_cached_acl(inode, type); +#endif spin_unlock(&lli->lli_lock); return acl; -- cgit v0.10.2 From b2de43605410d1970dc9e0f349e399f1d561be13 Mon Sep 17 00:00:00 2001 From: Tony Luck Date: Fri, 27 May 2016 14:11:06 -0700 Subject: x86/mce: Do not use bank 1 for APEI generated error logs BIOS can report a memory error to Linux using ACPI/APEI mechanism. When it does this, we create a fictitious machine check error record and feed it into the standard mce_log() function. The error record needs a machine check bank number, and for some reason we chose "1" for this. But "1" is a valid bank number, and this causes confusion and heartburn among h/w folks who are concerned that a memory error signature was somehow logged in bank 1. Change to use "-1" (field is a "u8" so will typically print as 255). This should make it clearer that this error did not originate in a machine check bank. Signed-off-by: Tony Luck Signed-off-by: Borislav Petkov Cc: Andy Lutomirski Cc: Aristeu Rozanski Cc: Borislav Petkov Cc: Brian Gerst Cc: Denys Vlasenko Cc: H. Peter Anvin Cc: Linus Torvalds Cc: Mauro Carvalho Chehab Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: linux-edac Link: http://lkml.kernel.org/r/b7fffb2b326bc1dd150ffceb9919a803f9496e0e.1464805958.git.tony.luck@intel.com Signed-off-by: Ingo Molnar diff --git a/arch/x86/kernel/cpu/mcheck/mce-apei.c b/arch/x86/kernel/cpu/mcheck/mce-apei.c index 34c89a3..83f1a98 100644 --- a/arch/x86/kernel/cpu/mcheck/mce-apei.c +++ b/arch/x86/kernel/cpu/mcheck/mce-apei.c @@ -46,7 +46,7 @@ void apei_mce_report_mem_error(int severity, struct cper_sec_mem_err *mem_err) return; mce_setup(&m); - m.bank = 1; + m.bank = -1; /* Fake a memory read error with unknown channel */ m.status = MCI_STATUS_VAL | MCI_STATUS_EN | MCI_STATUS_ADDRV | 0x9f; -- cgit v0.10.2 From 2348140d58f4f4245e9635ea8f1a77e940a4d877 Mon Sep 17 00:00:00 2001 From: Wanpeng Li Date: Mon, 13 Jun 2016 18:32:44 +0800 Subject: KVM: Fix steal clock warp during guest CPU hotplug MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Sometimes, after CPU hotplug you can observe a spike in stolen time (100%) followed by the CPU being marked as 100% idle when it's actually busy with a CPU hog task. The trace looks like the following: cpuhp/1-12 [001] d.h1 167.461657: account_process_tick: steal = 1291385514, prev_steal_time = 0 cpuhp/1-12 [001] d.h1 167.461659: account_process_tick: steal_jiffies = 1291 -0 [001] d.h1 167.462663: account_process_tick: steal = 18732255, prev_steal_time = 1291000000 -0 [001] d.h1 167.462664: account_process_tick: steal_jiffies = 18446744072437 The sudden decrease of "steal" causes steal_jiffies to underflow. The root cause is kvm_steal_time being reset to 0 after hot-plugging back in a CPU. Instead, the preexisting value can be used, which is what the core scheduler code expects. John Stultz also reported a similar issue after guest S3. Suggested-by: Paolo Bonzini Signed-off-by: Wanpeng Li Signed-off-by: Peter Zijlstra (Intel) Acked-by: Paolo Bonzini Cc: Frederic Weisbecker Cc: John Stultz Cc: Linus Torvalds Cc: Mike Galbraith Cc: Peter Zijlstra Cc: Radim Krčmář Cc: Rik van Riel Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/1465813966-3116-2-git-send-email-wanpeng.li@hotmail.com Signed-off-by: Ingo Molnar diff --git a/arch/x86/kernel/kvm.c b/arch/x86/kernel/kvm.c index eea2a6f..1ef5e48 100644 --- a/arch/x86/kernel/kvm.c +++ b/arch/x86/kernel/kvm.c @@ -301,8 +301,6 @@ static void kvm_register_steal_time(void) if (!has_steal_clock) return; - memset(st, 0, sizeof(*st)); - wrmsrl(MSR_KVM_STEAL_TIME, (slow_virt_to_phys(st) | KVM_MSR_ENABLED)); pr_info("kvm-stealtime: cpu %d, msr %llx\n", cpu, (unsigned long long) slow_virt_to_phys(st)); -- cgit v0.10.2 From 3d89e5478bf550a50c99e93adf659369798263b0 Mon Sep 17 00:00:00 2001 From: Wanpeng Li Date: Mon, 13 Jun 2016 18:32:45 +0800 Subject: sched/cputime: Fix prev steal time accouting during CPU hotplug MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit: e9532e69b8d1 ("sched/cputime: Fix steal time accounting vs. CPU hotplug") ... set rq->prev_* to 0 after a CPU hotplug comes back, in order to fix the case where (after CPU hotplug) steal time is smaller than rq->prev_steal_time. However, this should never happen. Steal time was only smaller because of the KVM-specific bug fixed by the previous patch. Worse, the previous patch triggers a bug on CPU hot-unplug/plug operation: because rq->prev_steal_time is cleared, all of the CPU's past steal time will be accounted again on hot-plug. Since the root cause has been fixed, we can just revert commit e9532e69b8d1. Signed-off-by: Wanpeng Li Signed-off-by: Peter Zijlstra (Intel) Acked-by: Paolo Bonzini Cc: Frederic Weisbecker Cc: Linus Torvalds Cc: Mike Galbraith Cc: Peter Zijlstra Cc: Radim Krčmář Cc: Rik van Riel Cc: Thomas Gleixner Fixes: 'commit e9532e69b8d1 ("sched/cputime: Fix steal time accounting vs. CPU hotplug")' Link: http://lkml.kernel.org/r/1465813966-3116-3-git-send-email-wanpeng.li@hotmail.com Signed-off-by: Ingo Molnar diff --git a/kernel/sched/core.c b/kernel/sched/core.c index 13d0896..c1b537b 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c @@ -7227,7 +7227,6 @@ static void sched_rq_cpu_starting(unsigned int cpu) struct rq *rq = cpu_rq(cpu); rq->calc_load_update = calc_load_update; - account_reset_rq(rq); update_max_interval(); } diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h index 72f1f30..de607e4 100644 --- a/kernel/sched/sched.h +++ b/kernel/sched/sched.h @@ -1809,16 +1809,3 @@ static inline void cpufreq_trigger_update(u64 time) {} #else /* arch_scale_freq_capacity */ #define arch_scale_freq_invariant() (false) #endif - -static inline void account_reset_rq(struct rq *rq) -{ -#ifdef CONFIG_IRQ_TIME_ACCOUNTING - rq->prev_irq_time = 0; -#endif -#ifdef CONFIG_PARAVIRT - rq->prev_steal_time = 0; -#endif -#ifdef CONFIG_PARAVIRT_TIME_ACCOUNTING - rq->prev_steal_time_rq = 0; -#endif -} -- cgit v0.10.2 From 807e5b80687c06715d62df51a5473b231e3e8b15 Mon Sep 17 00:00:00 2001 From: Wanpeng Li Date: Mon, 13 Jun 2016 18:32:46 +0800 Subject: sched/cputime: Add steal time support to full dynticks CPU time accounting MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch adds guest steal-time support to full dynticks CPU time accounting. After the following commit: ff9a9b4c4334 ("sched, time: Switch VIRT_CPU_ACCOUNTING_GEN to jiffy granularity") ... time sampling became jiffy based, even if we do the sampling from the context tracking code, so steal_account_process_tick() can be reused to account how many 'ticks' are stolen-time, after the last accumulation. Signed-off-by: Wanpeng Li Signed-off-by: Peter Zijlstra (Intel) Acked-by: Paolo Bonzini Cc: Frederic Weisbecker Cc: Linus Torvalds Cc: Mike Galbraith Cc: Peter Zijlstra Cc: Radim Krčmář Cc: Rik van Riel Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/1465813966-3116-4-git-send-email-wanpeng.li@hotmail.com Signed-off-by: Ingo Molnar diff --git a/kernel/sched/cputime.c b/kernel/sched/cputime.c index 75f98c5..3d60e5d 100644 --- a/kernel/sched/cputime.c +++ b/kernel/sched/cputime.c @@ -257,7 +257,7 @@ void account_idle_time(cputime_t cputime) cpustat[CPUTIME_IDLE] += (__force u64) cputime; } -static __always_inline bool steal_account_process_tick(void) +static __always_inline unsigned long steal_account_process_tick(unsigned long max_jiffies) { #ifdef CONFIG_PARAVIRT if (static_key_false(¶virt_steal_enabled)) { @@ -272,14 +272,14 @@ static __always_inline bool steal_account_process_tick(void) * time in jiffies. Lets cast the result to jiffies * granularity and account the rest on the next rounds. */ - steal_jiffies = nsecs_to_jiffies(steal); + steal_jiffies = min(nsecs_to_jiffies(steal), max_jiffies); this_rq()->prev_steal_time += jiffies_to_nsecs(steal_jiffies); account_steal_time(jiffies_to_cputime(steal_jiffies)); return steal_jiffies; } #endif - return false; + return 0; } /* @@ -346,7 +346,7 @@ static void irqtime_account_process_tick(struct task_struct *p, int user_tick, u64 cputime = (__force u64) cputime_one_jiffy; u64 *cpustat = kcpustat_this_cpu->cpustat; - if (steal_account_process_tick()) + if (steal_account_process_tick(ULONG_MAX)) return; cputime *= ticks; @@ -477,7 +477,7 @@ void account_process_tick(struct task_struct *p, int user_tick) return; } - if (steal_account_process_tick()) + if (steal_account_process_tick(ULONG_MAX)) return; if (user_tick) @@ -681,12 +681,14 @@ static cputime_t vtime_delta(struct task_struct *tsk) static cputime_t get_vtime_delta(struct task_struct *tsk) { unsigned long now = READ_ONCE(jiffies); - unsigned long delta = now - tsk->vtime_snap; + unsigned long delta_jiffies, steal_jiffies; + delta_jiffies = now - tsk->vtime_snap; + steal_jiffies = steal_account_process_tick(delta_jiffies); WARN_ON_ONCE(tsk->vtime_snap_whence == VTIME_INACTIVE); tsk->vtime_snap = now; - return jiffies_to_cputime(delta); + return jiffies_to_cputime(delta_jiffies - steal_jiffies); } static void __vtime_account_system(struct task_struct *tsk) -- cgit v0.10.2 From 281ee056e3f27d925350d65e5eb504b1320d7d5a Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Tue, 31 May 2016 16:25:27 -0500 Subject: perf/x86/intel/uncore: Remove redundant pci_get_drvdata() Remove redundant pci_get_drvdata() call. There's another call a few lines down, just before we test "box" for NULL. No functional change intended. Signed-off-by: Bjorn Helgaas Signed-off-by: Peter Zijlstra (Intel) Acked-by: Thomas Gleixner Cc: Alexander Shishkin Cc: Arnaldo Carvalho de Melo Cc: Borislav Petkov Cc: H. Peter Anvin Cc: Jiri Olsa Cc: Kan Liang Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Vince Weaver Link: http://lkml.kernel.org/r/20160531212527.28718.92371.stgit@bhelgaas-glaptop2.roam.corp.google.com Signed-off-by: Ingo Molnar diff --git a/arch/x86/events/intel/uncore.c b/arch/x86/events/intel/uncore.c index 4e70d27..dc965d2 100644 --- a/arch/x86/events/intel/uncore.c +++ b/arch/x86/events/intel/uncore.c @@ -974,7 +974,7 @@ static int uncore_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id static void uncore_pci_remove(struct pci_dev *pdev) { - struct intel_uncore_box *box = pci_get_drvdata(pdev); + struct intel_uncore_box *box; struct intel_uncore_pmu *pmu; int i, phys_id, pkg; -- cgit v0.10.2 From 2c95afc1e83d93fac3be6923465e1753c2c53b0a Mon Sep 17 00:00:00 2001 From: Andi Kleen Date: Thu, 9 Jun 2016 06:14:38 -0700 Subject: perf/x86/intel, watchdog: Switch NMI watchdog to ref cycles on x86 The NMI watchdog uses either the fixed cycles or a generic cycles counter. This causes a lot of conflicts with users of the PMU who want to run a full group including the cycles fixed counter, for example the --topdown support recently added to perf stat. The code needs to fall back to not use groups, which can cause measurement inaccuracy due to multiplexing errors. This patch switches the NMI watchdog to use reference cycles on Intel systems. This is actually more accurate than cycles, because cycles can tick faster than the measured CPU Frequency due to Turbo mode. The ref cycles always tick at their frequency, or slower when the system is idling. That means the NMI watchdog can never expire too early, unlike with cycles. The reference cycles tick roughly at the frequency of the TSC, so the same period computation can be used. Signed-off-by: Andi Kleen Signed-off-by: Peter Zijlstra (Intel) Cc: Alexander Shishkin Cc: Arnaldo Carvalho de Melo Cc: Jiri Olsa Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Thomas Gleixner Cc: Vince Weaver Cc: acme@kernel.org Cc: jolsa@kernel.org Link: http://lkml.kernel.org/r/1465478079-19993-1-git-send-email-andi@firstfloor.org Signed-off-by: Ingo Molnar diff --git a/arch/x86/kernel/apic/hw_nmi.c b/arch/x86/kernel/apic/hw_nmi.c index 7788ce6..016f426 100644 --- a/arch/x86/kernel/apic/hw_nmi.c +++ b/arch/x86/kernel/apic/hw_nmi.c @@ -18,8 +18,16 @@ #include #include #include +#include #ifdef CONFIG_HARDLOCKUP_DETECTOR +int hw_nmi_get_event(void) +{ + if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL) + return PERF_COUNT_HW_REF_CPU_CYCLES; + return PERF_COUNT_HW_CPU_CYCLES; +} + u64 hw_nmi_get_sample_period(int watchdog_thresh) { return (u64)(cpu_khz) * 1000 * watchdog_thresh; diff --git a/include/linux/nmi.h b/include/linux/nmi.h index 4630eea..79858af 100644 --- a/include/linux/nmi.h +++ b/include/linux/nmi.h @@ -66,6 +66,7 @@ static inline bool trigger_allbutself_cpu_backtrace(void) #ifdef CONFIG_LOCKUP_DETECTOR u64 hw_nmi_get_sample_period(int watchdog_thresh); +int hw_nmi_get_event(void); extern int nmi_watchdog_enabled; extern int soft_watchdog_enabled; extern int watchdog_user_enabled; diff --git a/kernel/watchdog.c b/kernel/watchdog.c index 9acb29f..8dd30fcd 100644 --- a/kernel/watchdog.c +++ b/kernel/watchdog.c @@ -315,6 +315,12 @@ static int is_softlockup(unsigned long touch_ts) #ifdef CONFIG_HARDLOCKUP_DETECTOR +/* Can be overriden by architecture */ +__weak int hw_nmi_get_event(void) +{ + return PERF_COUNT_HW_CPU_CYCLES; +} + static struct perf_event_attr wd_hw_attr = { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_CPU_CYCLES, @@ -604,6 +610,7 @@ static int watchdog_nmi_enable(unsigned int cpu) wd_attr = &wd_hw_attr; wd_attr->sample_period = hw_nmi_get_sample_period(watchdog_thresh); + wd_attr->config = hw_nmi_get_event(); /* Try to register using hardware perf events */ event = perf_event_create_kernel_counter(wd_attr, cpu, NULL, watchdog_overflow_callback, NULL); -- cgit v0.10.2 From 21c57fd135894f69ba2b8acc715ca81e90eeba15 Mon Sep 17 00:00:00 2001 From: Harvey Hunt Date: Mon, 23 May 2016 12:07:37 +0100 Subject: irqchip/mips-gic: Populate irq_domain names Set the irq_domain names so that they don't default to an unhelpful value. Signed-off-by: Harvey Hunt Reviewed-by: Matt Redfearn Cc: linux-mips@linux-mips.org Cc: Qais Yousef Cc: jason@lakedaemon.net Cc: marc.zyngier@arm.com Link: http://lkml.kernel.org/r/1464001657-31348-1-git-send-email-harvey.hunt@imgtec.com Signed-off-by: Thomas Gleixner diff --git a/drivers/irqchip/irq-mips-gic.c b/drivers/irqchip/irq-mips-gic.c index 3b5e10a..df9a1fe 100644 --- a/drivers/irqchip/irq-mips-gic.c +++ b/drivers/irqchip/irq-mips-gic.c @@ -1032,12 +1032,14 @@ static void __init __gic_init(unsigned long gic_base_addr, &gic_irq_domain_ops, NULL); if (!gic_irq_domain) panic("Failed to add GIC IRQ domain"); + gic_irq_domain->name = "mips-gic-irq"; gic_dev_domain = irq_domain_add_hierarchy(gic_irq_domain, 0, GIC_NUM_LOCAL_INTRS + gic_shared_intrs, node, &gic_dev_domain_ops, NULL); if (!gic_dev_domain) panic("Failed to add GIC DEV domain"); + gic_dev_domain->name = "mips-gic-dev"; gic_ipi_domain = irq_domain_add_hierarchy(gic_irq_domain, IRQ_DOMAIN_FLAG_IPI_PER_CPU, @@ -1046,6 +1048,7 @@ static void __init __gic_init(unsigned long gic_base_addr, if (!gic_ipi_domain) panic("Failed to add GIC IPI domain"); + gic_ipi_domain->name = "mips-gic-ipi"; gic_ipi_domain->bus_token = DOMAIN_BUS_IPI; if (node && -- cgit v0.10.2 From 1f03e8d2919270bd6ef64f39a45ce8df8a9f012a Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Mon, 4 Apr 2016 10:57:12 +0200 Subject: locking/barriers: Replace smp_cond_acquire() with smp_cond_load_acquire() This new form allows using hardware assisted waiting. Some hardware (ARM64 and x86) allow monitoring an address for changes, so by providing a pointer we can use this to replace the cpu_relax() with hardware optimized methods in the future. Requested-by: Will Deacon Suggested-by: Linus Torvalds Signed-off-by: Peter Zijlstra (Intel) Cc: Andrew Morton Cc: Paul E. McKenney Cc: Peter Zijlstra Cc: Thomas Gleixner Signed-off-by: Ingo Molnar diff --git a/include/linux/compiler.h b/include/linux/compiler.h index 06f27fd..2bcaedc0 100644 --- a/include/linux/compiler.h +++ b/include/linux/compiler.h @@ -305,21 +305,34 @@ static __always_inline void __write_once_size(volatile void *p, void *res, int s }) /** - * smp_cond_acquire() - Spin wait for cond with ACQUIRE ordering + * smp_cond_load_acquire() - (Spin) wait for cond with ACQUIRE ordering + * @ptr: pointer to the variable to wait on * @cond: boolean expression to wait for * * Equivalent to using smp_load_acquire() on the condition variable but employs * the control dependency of the wait to reduce the barrier on many platforms. * + * Due to C lacking lambda expressions we load the value of *ptr into a + * pre-named variable @VAL to be used in @cond. + * * The control dependency provides a LOAD->STORE order, the additional RMB * provides LOAD->LOAD order, together they provide LOAD->{LOAD,STORE} order, * aka. ACQUIRE. */ -#define smp_cond_acquire(cond) do { \ - while (!(cond)) \ - cpu_relax(); \ - smp_rmb(); /* ctrl + rmb := acquire */ \ -} while (0) +#ifndef smp_cond_load_acquire +#define smp_cond_load_acquire(ptr, cond_expr) ({ \ + typeof(ptr) __PTR = (ptr); \ + typeof(*ptr) VAL; \ + for (;;) { \ + VAL = READ_ONCE(*__PTR); \ + if (cond_expr) \ + break; \ + cpu_relax(); \ + } \ + smp_rmb(); /* ctrl + rmb := acquire */ \ + VAL; \ +}) +#endif #endif /* __KERNEL__ */ diff --git a/kernel/locking/qspinlock.c b/kernel/locking/qspinlock.c index 2f9153b..1b8dda9 100644 --- a/kernel/locking/qspinlock.c +++ b/kernel/locking/qspinlock.c @@ -475,7 +475,7 @@ void queued_spin_lock_slowpath(struct qspinlock *lock, u32 val) * sequentiality; this is because not all clear_pending_set_locked() * implementations imply full barriers. */ - smp_cond_acquire(!(atomic_read(&lock->val) & _Q_LOCKED_MASK)); + smp_cond_load_acquire(&lock->val.counter, !(VAL & _Q_LOCKED_MASK)); /* * take ownership and clear the pending bit. @@ -562,7 +562,7 @@ queue: * * The PV pv_wait_head_or_lock function, if active, will acquire * the lock and return a non-zero value. So we have to skip the - * smp_cond_acquire() call. As the next PV queue head hasn't been + * smp_cond_load_acquire() call. As the next PV queue head hasn't been * designated yet, there is no way for the locked value to become * _Q_SLOW_VAL. So both the set_locked() and the * atomic_cmpxchg_relaxed() calls will be safe. @@ -573,7 +573,7 @@ queue: if ((val = pv_wait_head_or_lock(lock, node))) goto locked; - smp_cond_acquire(!((val = atomic_read(&lock->val)) & _Q_LOCKED_PENDING_MASK)); + val = smp_cond_load_acquire(&lock->val.counter, !(VAL & _Q_LOCKED_PENDING_MASK)); locked: /* @@ -593,9 +593,9 @@ locked: break; } /* - * The smp_cond_acquire() call above has provided the necessary - * acquire semantics required for locking. At most two - * iterations of this loop may be ran. + * The smp_cond_load_acquire() call above has provided the + * necessary acquire semantics required for locking. At most + * two iterations of this loop may be ran. */ old = atomic_cmpxchg_relaxed(&lock->val, val, _Q_LOCKED_VAL); if (old == val) diff --git a/kernel/sched/core.c b/kernel/sched/core.c index 017d539..5cd6931 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c @@ -1935,7 +1935,7 @@ static void ttwu_queue(struct task_struct *p, int cpu, int wake_flags) * chain to provide order. Instead we do: * * 1) smp_store_release(X->on_cpu, 0) - * 2) smp_cond_acquire(!X->on_cpu) + * 2) smp_cond_load_acquire(!X->on_cpu) * * Example: * @@ -1946,7 +1946,7 @@ static void ttwu_queue(struct task_struct *p, int cpu, int wake_flags) * sched-out X * smp_store_release(X->on_cpu, 0); * - * smp_cond_acquire(!X->on_cpu); + * smp_cond_load_acquire(&X->on_cpu, !VAL); * X->state = WAKING * set_task_cpu(X,2) * @@ -1972,7 +1972,7 @@ static void ttwu_queue(struct task_struct *p, int cpu, int wake_flags) * This means that any means of doing remote wakeups must order the CPU doing * the wakeup against the CPU the task is going to end up running on. This, * however, is already required for the regular Program-Order guarantee above, - * since the waking CPU is the one issueing the ACQUIRE (smp_cond_acquire). + * since the waking CPU is the one issueing the ACQUIRE (smp_cond_load_acquire). * */ @@ -2045,7 +2045,7 @@ try_to_wake_up(struct task_struct *p, unsigned int state, int wake_flags) * This ensures that tasks getting woken will be fully ordered against * their previous state and preserve Program Order. */ - smp_cond_acquire(!p->on_cpu); + smp_cond_load_acquire(&p->on_cpu, !VAL); p->sched_contributes_to_load = !!task_contributes_to_load(p); p->state = TASK_WAKING; diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h index 72f1f30..425bf5d 100644 --- a/kernel/sched/sched.h +++ b/kernel/sched/sched.h @@ -1113,7 +1113,7 @@ static inline void finish_lock_switch(struct rq *rq, struct task_struct *prev) * In particular, the load of prev->state in finish_task_switch() must * happen before this. * - * Pairs with the smp_cond_acquire() in try_to_wake_up(). + * Pairs with the smp_cond_load_acquire() in try_to_wake_up(). */ smp_store_release(&prev->on_cpu, 0); #endif diff --git a/kernel/smp.c b/kernel/smp.c index 7416544..36552be 100644 --- a/kernel/smp.c +++ b/kernel/smp.c @@ -107,7 +107,7 @@ void __init call_function_init(void) */ static __always_inline void csd_lock_wait(struct call_single_data *csd) { - smp_cond_acquire(!(csd->flags & CSD_FLAG_LOCK)); + smp_cond_load_acquire(&csd->flags, !(VAL & CSD_FLAG_LOCK)); } static __always_inline void csd_lock(struct call_single_data *csd) -- cgit v0.10.2 From 33ac279677dcc2441cb93d8cb9cf7a74df62814d Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Tue, 24 May 2016 13:17:12 +0200 Subject: locking/barriers: Introduce smp_acquire__after_ctrl_dep() Introduce smp_acquire__after_ctrl_dep(), this construct is not uncommon, but the lack of this barrier is. Use it to better express smp_rmb() uses in WRITE_ONCE(), the IPC semaphore code and the qspinlock code. Signed-off-by: Peter Zijlstra (Intel) Cc: Andrew Morton Cc: Linus Torvalds Cc: Paul E. McKenney Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: linux-kernel@vger.kernel.org Signed-off-by: Ingo Molnar diff --git a/include/linux/compiler.h b/include/linux/compiler.h index 2bcaedc0..59a7004 100644 --- a/include/linux/compiler.h +++ b/include/linux/compiler.h @@ -305,6 +305,17 @@ static __always_inline void __write_once_size(volatile void *p, void *res, int s }) /** + * smp_acquire__after_ctrl_dep() - Provide ACQUIRE ordering after a control dependency + * + * A control dependency provides a LOAD->STORE order, the additional RMB + * provides LOAD->LOAD order, together they provide LOAD->{LOAD,STORE} order, + * aka. (load)-ACQUIRE. + * + * Architectures that do not do load speculation can have this be barrier(). + */ +#define smp_acquire__after_ctrl_dep() smp_rmb() + +/** * smp_cond_load_acquire() - (Spin) wait for cond with ACQUIRE ordering * @ptr: pointer to the variable to wait on * @cond: boolean expression to wait for @@ -314,10 +325,6 @@ static __always_inline void __write_once_size(volatile void *p, void *res, int s * * Due to C lacking lambda expressions we load the value of *ptr into a * pre-named variable @VAL to be used in @cond. - * - * The control dependency provides a LOAD->STORE order, the additional RMB - * provides LOAD->LOAD order, together they provide LOAD->{LOAD,STORE} order, - * aka. ACQUIRE. */ #ifndef smp_cond_load_acquire #define smp_cond_load_acquire(ptr, cond_expr) ({ \ @@ -329,7 +336,7 @@ static __always_inline void __write_once_size(volatile void *p, void *res, int s break; \ cpu_relax(); \ } \ - smp_rmb(); /* ctrl + rmb := acquire */ \ + smp_acquire__after_ctrl_dep(); \ VAL; \ }) #endif diff --git a/ipc/sem.c b/ipc/sem.c index b3757ea..84dff3d 100644 --- a/ipc/sem.c +++ b/ipc/sem.c @@ -260,16 +260,6 @@ static void sem_rcu_free(struct rcu_head *head) } /* - * spin_unlock_wait() and !spin_is_locked() are not memory barriers, they - * are only control barriers. - * The code must pair with spin_unlock(&sem->lock) or - * spin_unlock(&sem_perm.lock), thus just the control barrier is insufficient. - * - * smp_rmb() is sufficient, as writes cannot pass the control barrier. - */ -#define ipc_smp_acquire__after_spin_is_unlocked() smp_rmb() - -/* * Wait until all currently ongoing simple ops have completed. * Caller must own sem_perm.lock. * New simple ops cannot start, because simple ops first check @@ -292,7 +282,7 @@ static void sem_wait_array(struct sem_array *sma) sem = sma->sem_base + i; spin_unlock_wait(&sem->lock); } - ipc_smp_acquire__after_spin_is_unlocked(); + smp_acquire__after_ctrl_dep(); } /* @@ -350,7 +340,7 @@ static inline int sem_lock(struct sem_array *sma, struct sembuf *sops, * complex_count++; * spin_unlock(sem_perm.lock); */ - ipc_smp_acquire__after_spin_is_unlocked(); + smp_acquire__after_ctrl_dep(); /* * Now repeat the test of complex_count: diff --git a/kernel/locking/qspinlock.c b/kernel/locking/qspinlock.c index 1b8dda9..7306555 100644 --- a/kernel/locking/qspinlock.c +++ b/kernel/locking/qspinlock.c @@ -379,7 +379,7 @@ void queued_spin_unlock_wait(struct qspinlock *lock) cpu_relax(); done: - smp_rmb(); /* CTRL + RMB -> ACQUIRE */ + smp_acquire__after_ctrl_dep(); } EXPORT_SYMBOL(queued_spin_unlock_wait); #endif -- cgit v0.10.2 From 7cb45c0fe9858f92cc264f6bf9d2f6a0e7d3b249 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Wed, 1 Jun 2016 19:23:54 +0200 Subject: locking/barriers: Move smp_cond_load_acquire() to asm-generic/barrier.h Since all asm/barrier.h should/must include asm-generic/barrier.h the latter is a good place for generic infrastructure like this. This also allows archs to override the new smp_acquire__after_ctrl_dep(). Signed-off-by: Peter Zijlstra (Intel) Cc: Andrew Morton Cc: Linus Torvalds Cc: Paul E. McKenney Cc: Peter Zijlstra Cc: Thomas Gleixner Signed-off-by: Ingo Molnar diff --git a/include/asm-generic/barrier.h b/include/asm-generic/barrier.h index 1cceca14..ab7b0bd 100644 --- a/include/asm-generic/barrier.h +++ b/include/asm-generic/barrier.h @@ -207,5 +207,44 @@ do { \ #define virt_store_release(p, v) __smp_store_release(p, v) #define virt_load_acquire(p) __smp_load_acquire(p) +/** + * smp_acquire__after_ctrl_dep() - Provide ACQUIRE ordering after a control dependency + * + * A control dependency provides a LOAD->STORE order, the additional RMB + * provides LOAD->LOAD order, together they provide LOAD->{LOAD,STORE} order, + * aka. (load)-ACQUIRE. + * + * Architectures that do not do load speculation can have this be barrier(). + */ +#ifndef smp_acquire__after_ctrl_dep +#define smp_acquire__after_ctrl_dep() smp_rmb() +#endif + +/** + * smp_cond_load_acquire() - (Spin) wait for cond with ACQUIRE ordering + * @ptr: pointer to the variable to wait on + * @cond: boolean expression to wait for + * + * Equivalent to using smp_load_acquire() on the condition variable but employs + * the control dependency of the wait to reduce the barrier on many platforms. + * + * Due to C lacking lambda expressions we load the value of *ptr into a + * pre-named variable @VAL to be used in @cond. + */ +#ifndef smp_cond_load_acquire +#define smp_cond_load_acquire(ptr, cond_expr) ({ \ + typeof(ptr) __PTR = (ptr); \ + typeof(*ptr) VAL; \ + for (;;) { \ + VAL = READ_ONCE(*__PTR); \ + if (cond_expr) \ + break; \ + cpu_relax(); \ + } \ + smp_acquire__after_ctrl_dep(); \ + VAL; \ +}) +#endif + #endif /* !__ASSEMBLY__ */ #endif /* __ASM_GENERIC_BARRIER_H */ diff --git a/include/linux/compiler.h b/include/linux/compiler.h index 59a7004..2e853b6 100644 --- a/include/linux/compiler.h +++ b/include/linux/compiler.h @@ -304,43 +304,6 @@ static __always_inline void __write_once_size(volatile void *p, void *res, int s __u.__val; \ }) -/** - * smp_acquire__after_ctrl_dep() - Provide ACQUIRE ordering after a control dependency - * - * A control dependency provides a LOAD->STORE order, the additional RMB - * provides LOAD->LOAD order, together they provide LOAD->{LOAD,STORE} order, - * aka. (load)-ACQUIRE. - * - * Architectures that do not do load speculation can have this be barrier(). - */ -#define smp_acquire__after_ctrl_dep() smp_rmb() - -/** - * smp_cond_load_acquire() - (Spin) wait for cond with ACQUIRE ordering - * @ptr: pointer to the variable to wait on - * @cond: boolean expression to wait for - * - * Equivalent to using smp_load_acquire() on the condition variable but employs - * the control dependency of the wait to reduce the barrier on many platforms. - * - * Due to C lacking lambda expressions we load the value of *ptr into a - * pre-named variable @VAL to be used in @cond. - */ -#ifndef smp_cond_load_acquire -#define smp_cond_load_acquire(ptr, cond_expr) ({ \ - typeof(ptr) __PTR = (ptr); \ - typeof(*ptr) VAL; \ - for (;;) { \ - VAL = READ_ONCE(*__PTR); \ - if (cond_expr) \ - break; \ - cpu_relax(); \ - } \ - smp_acquire__after_ctrl_dep(); \ - VAL; \ -}) -#endif - #endif /* __KERNEL__ */ #endif /* __ASSEMBLY__ */ -- cgit v0.10.2 From b464d1270a8016edcf1fd20d77cefdecf9b0b73e Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Mon, 30 May 2016 14:32:04 +0200 Subject: locking/barriers, tile: Provide TILE specific smp_acquire__after_ctrl_dep() Since TILE doesn't do read speculation, its control dependencies also guarantee LOAD->LOAD order and we don't need the additional RMB otherwise required to provide ACQUIRE semantics. Signed-off-by: Peter Zijlstra (Intel) Acked-by: Chris Metcalf Cc: Andrew Morton Cc: Linus Torvalds Cc: Paul E. McKenney Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: linux-kernel@vger.kernel.org Signed-off-by: Ingo Molnar diff --git a/arch/tile/include/asm/barrier.h b/arch/tile/include/asm/barrier.h index d552228..4c419ab 100644 --- a/arch/tile/include/asm/barrier.h +++ b/arch/tile/include/asm/barrier.h @@ -87,6 +87,13 @@ mb_incoherent(void) #define __smp_mb__after_atomic() __smp_mb() #endif +/* + * The TILE architecture does not do speculative reads; this ensures + * that a control dependency also orders against loads and already provides + * a LOAD->{LOAD,STORE} order and can forgo the additional RMB. + */ +#define smp_acquire__after_ctrl_dep() barrier() + #include #endif /* !__ASSEMBLY__ */ -- cgit v0.10.2 From 726328d92a42b6d4b76078e2659f43067f82c4e8 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Thu, 26 May 2016 10:35:03 +0200 Subject: locking/spinlock, arch: Update and fix spin_unlock_wait() implementations This patch updates/fixes all spin_unlock_wait() implementations. The update is in semantics; where it previously was only a control dependency, we now upgrade to a full load-acquire to match the store-release from the spin_unlock() we waited on. This ensures that when spin_unlock_wait() returns, we're guaranteed to observe the full critical section we waited on. This fixes a number of spin_unlock_wait() users that (not unreasonably) rely on this. I also fixed a number of ticket lock versions to only wait on the current lock holder, instead of for a full unlock, as this is sufficient. Furthermore; again for ticket locks; I added an smp_rmb() in between the initial ticket load and the spin loop testing the current value because I could not convince myself the address dependency is sufficient, esp. if the loads are of different sizes. I'm more than happy to remove this smp_rmb() again if people are certain the address dependency does indeed work as expected. Note: PPC32 will be fixed independently Signed-off-by: Peter Zijlstra (Intel) Cc: Andrew Morton Cc: Linus Torvalds Cc: Paul E. McKenney Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: chris@zankel.net Cc: cmetcalf@mellanox.com Cc: davem@davemloft.net Cc: dhowells@redhat.com Cc: james.hogan@imgtec.com Cc: jejb@parisc-linux.org Cc: linux@armlinux.org.uk Cc: mpe@ellerman.id.au Cc: ralf@linux-mips.org Cc: realmz6@gmail.com Cc: rkuo@codeaurora.org Cc: rth@twiddle.net Cc: schwidefsky@de.ibm.com Cc: tony.luck@intel.com Cc: vgupta@synopsys.com Cc: ysato@users.sourceforge.jp Cc: linux-kernel@vger.kernel.org Signed-off-by: Ingo Molnar diff --git a/arch/alpha/include/asm/spinlock.h b/arch/alpha/include/asm/spinlock.h index fed9c6f..a40b9fc 100644 --- a/arch/alpha/include/asm/spinlock.h +++ b/arch/alpha/include/asm/spinlock.h @@ -3,6 +3,8 @@ #include #include +#include +#include /* * Simple spin lock operations. There are two variants, one clears IRQ's @@ -13,8 +15,11 @@ #define arch_spin_lock_flags(lock, flags) arch_spin_lock(lock) #define arch_spin_is_locked(x) ((x)->lock != 0) -#define arch_spin_unlock_wait(x) \ - do { cpu_relax(); } while ((x)->lock) + +static inline void arch_spin_unlock_wait(arch_spinlock_t *lock) +{ + smp_cond_load_acquire(&lock->lock, !VAL); +} static inline int arch_spin_value_unlocked(arch_spinlock_t lock) { diff --git a/arch/arc/include/asm/spinlock.h b/arch/arc/include/asm/spinlock.h index cded4a9..233d5ff 100644 --- a/arch/arc/include/asm/spinlock.h +++ b/arch/arc/include/asm/spinlock.h @@ -15,8 +15,11 @@ #define arch_spin_is_locked(x) ((x)->slock != __ARCH_SPIN_LOCK_UNLOCKED__) #define arch_spin_lock_flags(lock, flags) arch_spin_lock(lock) -#define arch_spin_unlock_wait(x) \ - do { while (arch_spin_is_locked(x)) cpu_relax(); } while (0) + +static inline void arch_spin_unlock_wait(arch_spinlock_t *lock) +{ + smp_cond_load_acquire(&lock->slock, !VAL); +} #ifdef CONFIG_ARC_HAS_LLSC diff --git a/arch/arm/include/asm/spinlock.h b/arch/arm/include/asm/spinlock.h index 0fa4184..4bec454 100644 --- a/arch/arm/include/asm/spinlock.h +++ b/arch/arm/include/asm/spinlock.h @@ -6,6 +6,8 @@ #endif #include +#include +#include /* * sev and wfe are ARMv6K extensions. Uniprocessor ARMv6 may not have the K @@ -50,8 +52,21 @@ static inline void dsb_sev(void) * memory. */ -#define arch_spin_unlock_wait(lock) \ - do { while (arch_spin_is_locked(lock)) cpu_relax(); } while (0) +static inline void arch_spin_unlock_wait(arch_spinlock_t *lock) +{ + u16 owner = READ_ONCE(lock->tickets.owner); + + for (;;) { + arch_spinlock_t tmp = READ_ONCE(*lock); + + if (tmp.tickets.owner == tmp.tickets.next || + tmp.tickets.owner != owner) + break; + + wfe(); + } + smp_acquire__after_ctrl_dep(); +} #define arch_spin_lock_flags(lock, flags) arch_spin_lock(lock) diff --git a/arch/blackfin/include/asm/spinlock.h b/arch/blackfin/include/asm/spinlock.h index 490c7ca..c58f4a8 100644 --- a/arch/blackfin/include/asm/spinlock.h +++ b/arch/blackfin/include/asm/spinlock.h @@ -12,6 +12,8 @@ #else #include +#include +#include asmlinkage int __raw_spin_is_locked_asm(volatile int *ptr); asmlinkage void __raw_spin_lock_asm(volatile int *ptr); @@ -48,8 +50,7 @@ static inline void arch_spin_unlock(arch_spinlock_t *lock) static inline void arch_spin_unlock_wait(arch_spinlock_t *lock) { - while (arch_spin_is_locked(lock)) - cpu_relax(); + smp_cond_load_acquire(&lock->lock, !VAL); } static inline int arch_read_can_lock(arch_rwlock_t *rw) diff --git a/arch/hexagon/include/asm/spinlock.h b/arch/hexagon/include/asm/spinlock.h index 12ca4eb..a1c5578 100644 --- a/arch/hexagon/include/asm/spinlock.h +++ b/arch/hexagon/include/asm/spinlock.h @@ -23,6 +23,8 @@ #define _ASM_SPINLOCK_H #include +#include +#include /* * This file is pulled in for SMP builds. @@ -176,8 +178,12 @@ static inline unsigned int arch_spin_trylock(arch_spinlock_t *lock) * SMP spinlocks are intended to allow only a single CPU at the lock */ #define arch_spin_lock_flags(lock, flags) arch_spin_lock(lock) -#define arch_spin_unlock_wait(lock) \ - do {while (arch_spin_is_locked(lock)) cpu_relax(); } while (0) + +static inline void arch_spin_unlock_wait(arch_spinlock_t *lock) +{ + smp_cond_load_acquire(&lock->lock, !VAL); +} + #define arch_spin_is_locked(x) ((x)->lock != 0) #define arch_read_lock_flags(lock, flags) arch_read_lock(lock) diff --git a/arch/ia64/include/asm/spinlock.h b/arch/ia64/include/asm/spinlock.h index 45698cd..ca9e761 100644 --- a/arch/ia64/include/asm/spinlock.h +++ b/arch/ia64/include/asm/spinlock.h @@ -15,6 +15,8 @@ #include #include +#include +#include #define arch_spin_lock_init(x) ((x)->lock = 0) @@ -86,6 +88,8 @@ static __always_inline void __ticket_spin_unlock_wait(arch_spinlock_t *lock) return; cpu_relax(); } + + smp_acquire__after_ctrl_dep(); } static inline int __ticket_spin_is_locked(arch_spinlock_t *lock) diff --git a/arch/m32r/include/asm/spinlock.h b/arch/m32r/include/asm/spinlock.h index fa13694..323c7fc 100644 --- a/arch/m32r/include/asm/spinlock.h +++ b/arch/m32r/include/asm/spinlock.h @@ -13,6 +13,8 @@ #include #include #include +#include +#include /* * Your basic SMP spinlocks, allowing only a single CPU anywhere @@ -27,8 +29,11 @@ #define arch_spin_is_locked(x) (*(volatile int *)(&(x)->slock) <= 0) #define arch_spin_lock_flags(lock, flags) arch_spin_lock(lock) -#define arch_spin_unlock_wait(x) \ - do { cpu_relax(); } while (arch_spin_is_locked(x)) + +static inline void arch_spin_unlock_wait(arch_spinlock_t *lock) +{ + smp_cond_load_acquire(&lock->slock, VAL > 0); +} /** * arch_spin_trylock - Try spin lock and return a result diff --git a/arch/metag/include/asm/spinlock.h b/arch/metag/include/asm/spinlock.h index 86a7cf3..c0c7a22 100644 --- a/arch/metag/include/asm/spinlock.h +++ b/arch/metag/include/asm/spinlock.h @@ -1,14 +1,24 @@ #ifndef __ASM_SPINLOCK_H #define __ASM_SPINLOCK_H +#include +#include + #ifdef CONFIG_METAG_ATOMICITY_LOCK1 #include #else #include #endif -#define arch_spin_unlock_wait(lock) \ - do { while (arch_spin_is_locked(lock)) cpu_relax(); } while (0) +/* + * both lock1 and lnkget are test-and-set spinlocks with 0 unlocked and 1 + * locked. + */ + +static inline void arch_spin_unlock_wait(arch_spinlock_t *lock) +{ + smp_cond_load_acquire(&lock->lock, !VAL); +} #define arch_spin_lock_flags(lock, flags) arch_spin_lock(lock) diff --git a/arch/mips/include/asm/spinlock.h b/arch/mips/include/asm/spinlock.h index 40196be..f485afe 100644 --- a/arch/mips/include/asm/spinlock.h +++ b/arch/mips/include/asm/spinlock.h @@ -12,6 +12,7 @@ #include #include +#include #include #include @@ -48,8 +49,22 @@ static inline int arch_spin_value_unlocked(arch_spinlock_t lock) } #define arch_spin_lock_flags(lock, flags) arch_spin_lock(lock) -#define arch_spin_unlock_wait(x) \ - while (arch_spin_is_locked(x)) { cpu_relax(); } + +static inline void arch_spin_unlock_wait(arch_spinlock_t *lock) +{ + u16 owner = READ_ONCE(lock->h.serving_now); + smp_rmb(); + for (;;) { + arch_spinlock_t tmp = READ_ONCE(*lock); + + if (tmp.h.serving_now == tmp.h.ticket || + tmp.h.serving_now != owner) + break; + + cpu_relax(); + } + smp_acquire__after_ctrl_dep(); +} static inline int arch_spin_is_contended(arch_spinlock_t *lock) { diff --git a/arch/mn10300/include/asm/spinlock.h b/arch/mn10300/include/asm/spinlock.h index 1ae580f..9c7b8f7 100644 --- a/arch/mn10300/include/asm/spinlock.h +++ b/arch/mn10300/include/asm/spinlock.h @@ -12,6 +12,8 @@ #define _ASM_SPINLOCK_H #include +#include +#include #include #include @@ -23,7 +25,11 @@ */ #define arch_spin_is_locked(x) (*(volatile signed char *)(&(x)->slock) != 0) -#define arch_spin_unlock_wait(x) do { barrier(); } while (arch_spin_is_locked(x)) + +static inline void arch_spin_unlock_wait(arch_spinlock_t *lock) +{ + smp_cond_load_acquire(&lock->slock, !VAL); +} static inline void arch_spin_unlock(arch_spinlock_t *lock) { diff --git a/arch/parisc/include/asm/spinlock.h b/arch/parisc/include/asm/spinlock.h index 64f2992..e32936c 100644 --- a/arch/parisc/include/asm/spinlock.h +++ b/arch/parisc/include/asm/spinlock.h @@ -13,8 +13,13 @@ static inline int arch_spin_is_locked(arch_spinlock_t *x) } #define arch_spin_lock(lock) arch_spin_lock_flags(lock, 0) -#define arch_spin_unlock_wait(x) \ - do { cpu_relax(); } while (arch_spin_is_locked(x)) + +static inline void arch_spin_unlock_wait(arch_spinlock_t *x) +{ + volatile unsigned int *a = __ldcw_align(x); + + smp_cond_load_acquire(a, VAL); +} static inline void arch_spin_lock_flags(arch_spinlock_t *x, unsigned long flags) diff --git a/arch/s390/include/asm/spinlock.h b/arch/s390/include/asm/spinlock.h index 63ebf37..7e9e09f 100644 --- a/arch/s390/include/asm/spinlock.h +++ b/arch/s390/include/asm/spinlock.h @@ -10,6 +10,8 @@ #define __ASM_SPINLOCK_H #include +#include +#include #define SPINLOCK_LOCKVAL (S390_lowcore.spinlock_lockval) @@ -97,6 +99,7 @@ static inline void arch_spin_unlock_wait(arch_spinlock_t *lock) { while (arch_spin_is_locked(lock)) arch_spin_relax(lock); + smp_acquire__after_ctrl_dep(); } /* diff --git a/arch/sh/include/asm/spinlock.h b/arch/sh/include/asm/spinlock.h index bdc0f3b..416834b 100644 --- a/arch/sh/include/asm/spinlock.h +++ b/arch/sh/include/asm/spinlock.h @@ -19,14 +19,20 @@ #error "Need movli.l/movco.l for spinlocks" #endif +#include +#include + /* * Your basic SMP spinlocks, allowing only a single CPU anywhere */ #define arch_spin_is_locked(x) ((x)->lock <= 0) #define arch_spin_lock_flags(lock, flags) arch_spin_lock(lock) -#define arch_spin_unlock_wait(x) \ - do { while (arch_spin_is_locked(x)) cpu_relax(); } while (0) + +static inline void arch_spin_unlock_wait(arch_spinlock_t *lock) +{ + smp_cond_load_acquire(&lock->lock, VAL > 0); +} /* * Simple spin lock operations. There are two variants, one clears IRQ's diff --git a/arch/sparc/include/asm/spinlock_32.h b/arch/sparc/include/asm/spinlock_32.h index bcc98fc..d9c5876 100644 --- a/arch/sparc/include/asm/spinlock_32.h +++ b/arch/sparc/include/asm/spinlock_32.h @@ -9,12 +9,15 @@ #ifndef __ASSEMBLY__ #include +#include #include /* for cpu_relax */ #define arch_spin_is_locked(lock) (*((volatile unsigned char *)(lock)) != 0) -#define arch_spin_unlock_wait(lock) \ - do { while (arch_spin_is_locked(lock)) cpu_relax(); } while (0) +static inline void arch_spin_unlock_wait(arch_spinlock_t *lock) +{ + smp_cond_load_acquire(&lock->lock, !VAL); +} static inline void arch_spin_lock(arch_spinlock_t *lock) { diff --git a/arch/sparc/include/asm/spinlock_64.h b/arch/sparc/include/asm/spinlock_64.h index 9689176..87990b7 100644 --- a/arch/sparc/include/asm/spinlock_64.h +++ b/arch/sparc/include/asm/spinlock_64.h @@ -8,6 +8,9 @@ #ifndef __ASSEMBLY__ +#include +#include + /* To get debugging spinlocks which detect and catch * deadlock situations, set CONFIG_DEBUG_SPINLOCK * and rebuild your kernel. @@ -23,9 +26,10 @@ #define arch_spin_is_locked(lp) ((lp)->lock != 0) -#define arch_spin_unlock_wait(lp) \ - do { rmb(); \ - } while((lp)->lock) +static inline void arch_spin_unlock_wait(arch_spinlock_t *lock) +{ + smp_cond_load_acquire(&lock->lock, !VAL); +} static inline void arch_spin_lock(arch_spinlock_t *lock) { diff --git a/arch/tile/lib/spinlock_32.c b/arch/tile/lib/spinlock_32.c index 88c2a53..076c6cc 100644 --- a/arch/tile/lib/spinlock_32.c +++ b/arch/tile/lib/spinlock_32.c @@ -76,6 +76,12 @@ void arch_spin_unlock_wait(arch_spinlock_t *lock) do { delay_backoff(iterations++); } while (READ_ONCE(lock->current_ticket) == curr); + + /* + * The TILE architecture doesn't do read speculation; therefore + * a control dependency guarantees a LOAD->{LOAD,STORE} order. + */ + barrier(); } EXPORT_SYMBOL(arch_spin_unlock_wait); diff --git a/arch/tile/lib/spinlock_64.c b/arch/tile/lib/spinlock_64.c index c8d1f94..a4b5b2c 100644 --- a/arch/tile/lib/spinlock_64.c +++ b/arch/tile/lib/spinlock_64.c @@ -76,6 +76,12 @@ void arch_spin_unlock_wait(arch_spinlock_t *lock) do { delay_backoff(iterations++); } while (arch_spin_current(READ_ONCE(lock->lock)) == curr); + + /* + * The TILE architecture doesn't do read speculation; therefore + * a control dependency guarantees a LOAD->{LOAD,STORE} order. + */ + barrier(); } EXPORT_SYMBOL(arch_spin_unlock_wait); diff --git a/arch/xtensa/include/asm/spinlock.h b/arch/xtensa/include/asm/spinlock.h index 1d95fa5..a36221c 100644 --- a/arch/xtensa/include/asm/spinlock.h +++ b/arch/xtensa/include/asm/spinlock.h @@ -11,6 +11,9 @@ #ifndef _XTENSA_SPINLOCK_H #define _XTENSA_SPINLOCK_H +#include +#include + /* * spinlock * @@ -29,8 +32,11 @@ */ #define arch_spin_is_locked(x) ((x)->slock != 0) -#define arch_spin_unlock_wait(lock) \ - do { while (arch_spin_is_locked(lock)) cpu_relax(); } while (0) + +static inline void arch_spin_unlock_wait(arch_spinlock_t *lock) +{ + smp_cond_load_acquire(&lock->slock, !VAL); +} #define arch_spin_lock_flags(lock, flags) arch_spin_lock(lock) diff --git a/include/asm-generic/barrier.h b/include/asm-generic/barrier.h index ab7b0bd..fe297b5 100644 --- a/include/asm-generic/barrier.h +++ b/include/asm-generic/barrier.h @@ -194,7 +194,7 @@ do { \ }) #endif -#endif +#endif /* CONFIG_SMP */ /* Barriers for virtual machine guests when talking to an SMP host */ #define virt_mb() __smp_mb() diff --git a/include/linux/spinlock_up.h b/include/linux/spinlock_up.h index 8b3ac0d..0d9848d 100644 --- a/include/linux/spinlock_up.h +++ b/include/linux/spinlock_up.h @@ -6,6 +6,7 @@ #endif #include /* for cpu_relax() */ +#include /* * include/linux/spinlock_up.h - UP-debug version of spinlocks. @@ -25,6 +26,11 @@ #ifdef CONFIG_DEBUG_SPINLOCK #define arch_spin_is_locked(x) ((x)->slock == 0) +static inline void arch_spin_unlock_wait(arch_spinlock_t *lock) +{ + smp_cond_load_acquire(&lock->slock, VAL); +} + static inline void arch_spin_lock(arch_spinlock_t *lock) { lock->slock = 0; @@ -67,6 +73,7 @@ static inline void arch_spin_unlock(arch_spinlock_t *lock) #else /* DEBUG_SPINLOCK */ #define arch_spin_is_locked(lock) ((void)(lock), 0) +#define arch_spin_unlock_wait(lock) do { barrier(); (void)(lock); } while (0) /* for sched/core.c and kernel_lock.c: */ # define arch_spin_lock(lock) do { barrier(); (void)(lock); } while (0) # define arch_spin_lock_flags(lock, flags) do { barrier(); (void)(lock); } while (0) @@ -79,7 +86,4 @@ static inline void arch_spin_unlock(arch_spinlock_t *lock) #define arch_read_can_lock(lock) (((void)(lock), 1)) #define arch_write_can_lock(lock) (((void)(lock), 1)) -#define arch_spin_unlock_wait(lock) \ - do { cpu_relax(); } while (arch_spin_is_locked(lock)) - #endif /* __LINUX_SPINLOCK_UP_H */ -- cgit v0.10.2 From be3e7844980352756de4261b276ee2ba5be7a26b Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Tue, 24 May 2016 14:45:21 +0200 Subject: locking/spinlock: Update spin_unlock_wait() users With the modified semantics of spin_unlock_wait() a number of explicit barriers can be removed. Also update the comment for the do_exit() usecase, as that was somewhat stale/obscure. Signed-off-by: Peter Zijlstra (Intel) Cc: Andrew Morton Cc: Linus Torvalds Cc: Paul E. McKenney Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: linux-kernel@vger.kernel.org Signed-off-by: Ingo Molnar diff --git a/ipc/sem.c b/ipc/sem.c index 84dff3d..ae72b3c 100644 --- a/ipc/sem.c +++ b/ipc/sem.c @@ -282,7 +282,6 @@ static void sem_wait_array(struct sem_array *sma) sem = sma->sem_base + i; spin_unlock_wait(&sem->lock); } - smp_acquire__after_ctrl_dep(); } /* diff --git a/kernel/exit.c b/kernel/exit.c index 9e6e135..0b40791 100644 --- a/kernel/exit.c +++ b/kernel/exit.c @@ -700,10 +700,14 @@ void do_exit(long code) exit_signals(tsk); /* sets PF_EXITING */ /* - * tsk->flags are checked in the futex code to protect against - * an exiting task cleaning up the robust pi futexes. + * Ensure that all new tsk->pi_lock acquisitions must observe + * PF_EXITING. Serializes against futex.c:attach_to_pi_owner(). */ smp_mb(); + /* + * Ensure that we must observe the pi_state in exit_mm() -> + * mm_release() -> exit_pi_state_list(). + */ raw_spin_unlock_wait(&tsk->pi_lock); if (unlikely(in_atomic())) { diff --git a/kernel/task_work.c b/kernel/task_work.c index 53fa971..6ab4842 100644 --- a/kernel/task_work.c +++ b/kernel/task_work.c @@ -108,7 +108,6 @@ void task_work_run(void) * fail, but it can play with *work and other entries. */ raw_spin_unlock_wait(&task->pi_lock); - smp_mb(); do { next = work->next; -- cgit v0.10.2 From b316ff783d17bd6217804e2e4385ce9347d7dad9 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Tue, 24 May 2016 15:00:38 +0200 Subject: locking/spinlock, netfilter: Fix nf_conntrack_lock() barriers Even with spin_unlock_wait() fixed, nf_conntrack_lock{,_all}() is borken as it misses a bunch of memory barriers to order the whole global vs local locks scheme. Even x86 (and other TSO archs) are affected. Signed-off-by: Peter Zijlstra (Intel) [ Updated the comments. ] Cc: Andrew Morton Cc: David S. Miller Cc: Linus Torvalds Cc: Paul E. McKenney Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: linux-kernel@vger.kernel.org Signed-off-by: Ingo Molnar diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c index db2312e..b8c5501 100644 --- a/net/netfilter/nf_conntrack_core.c +++ b/net/netfilter/nf_conntrack_core.c @@ -83,6 +83,13 @@ void nf_conntrack_lock(spinlock_t *lock) __acquires(lock) spin_lock(lock); while (unlikely(nf_conntrack_locks_all)) { spin_unlock(lock); + + /* + * Order the 'nf_conntrack_locks_all' load vs. the + * spin_unlock_wait() loads below, to ensure + * that 'nf_conntrack_locks_all_lock' is indeed held: + */ + smp_rmb(); /* spin_lock(&nf_conntrack_locks_all_lock) */ spin_unlock_wait(&nf_conntrack_locks_all_lock); spin_lock(lock); } @@ -128,6 +135,14 @@ static void nf_conntrack_all_lock(void) spin_lock(&nf_conntrack_locks_all_lock); nf_conntrack_locks_all = true; + /* + * Order the above store of 'nf_conntrack_locks_all' against + * the spin_unlock_wait() loads below, such that if + * nf_conntrack_lock() observes 'nf_conntrack_locks_all' + * we must observe nf_conntrack_locks[] held: + */ + smp_mb(); /* spin_lock(&nf_conntrack_locks_all_lock) */ + for (i = 0; i < CONNTRACK_LOCKS; i++) { spin_unlock_wait(&nf_conntrack_locks[i]); } @@ -135,7 +150,13 @@ static void nf_conntrack_all_lock(void) static void nf_conntrack_all_unlock(void) { - nf_conntrack_locks_all = false; + /* + * All prior stores must be complete before we clear + * 'nf_conntrack_locks_all'. Otherwise nf_conntrack_lock() + * might observe the false value but not the entire + * critical section: + */ + smp_store_release(&nf_conntrack_locks_all, false); spin_unlock(&nf_conntrack_locks_all_lock); } -- cgit v0.10.2 From 8d950d2fb23b696d393020486ab6a350bcb2c582 Mon Sep 17 00:00:00 2001 From: Jon Mason Date: Thu, 9 Jun 2016 13:24:19 -0400 Subject: MAINTAINERS: Update the Calgary IOMMU entry Update the contact info for Muli, clean-up my name, and update the mailing list to the IOMMU mailing list. Signed-off-by: Jon Mason Cc: Andrew Morton Cc: Bartlomiej Zolnierkiewicz Cc: Greg Kroah-Hartman Cc: Krzysztof Kozlowski Cc: Linus Torvalds Cc: Muli Ben-Yehuda Cc: Peter Zijlstra Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/1465493059-11840-2-git-send-email-jdmason@kudzu.us Signed-off-by: Ingo Molnar diff --git a/MAINTAINERS b/MAINTAINERS index 16700e4..f589a9d 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2773,9 +2773,9 @@ F: include/net/caif/ F: net/caif/ CALGARY x86-64 IOMMU -M: Muli Ben-Yehuda -M: "Jon D. Mason" -L: discuss@x86-64.org +M: Muli Ben-Yehuda +M: Jon Mason +L: iommu@lists.linux-foundation.org S: Maintained F: arch/x86/kernel/pci-calgary_64.c F: arch/x86/kernel/tce_64.c -- cgit v0.10.2 From f0702555b16d31d61dc758fac6efb994c3fe3ec6 Mon Sep 17 00:00:00 2001 From: Andy Lutomirski Date: Thu, 9 Jun 2016 13:57:04 -0700 Subject: x86/vdso/32: Assemble sigreturn.S separately sigreturn.S was historically included by the various __kernel_vsyscall implementations due to assumptions about all the 32-bit vDSO images having the sigreturn symbols at the same address. Those assumptions were removed in v3.16, and as of v4.4, there is only a single 32-bit vDSO left. Simplify the build process by assembling sigreturn.S into a normal object file. Signed-off-by: Andy Lutomirski Cc: Borislav Petkov Cc: Brian Gerst Cc: Denys Vlasenko Cc: H. Peter Anvin Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/d7b6dfde3c7397aa26977320da90448363b5a7e9.1465505753.git.luto@kernel.org Signed-off-by: Ingo Molnar diff --git a/arch/x86/entry/vdso/Makefile b/arch/x86/entry/vdso/Makefile index 253b72e..68b63fd 100644 --- a/arch/x86/entry/vdso/Makefile +++ b/arch/x86/entry/vdso/Makefile @@ -134,7 +134,7 @@ VDSO_LDFLAGS_vdso32.lds = -m32 -Wl,-m,elf_i386 -Wl,-soname=linux-gate.so.1 override obj-dirs = $(dir $(obj)) $(obj)/vdso32/ targets += vdso32/vdso32.lds -targets += vdso32/note.o vdso32/vclock_gettime.o vdso32/system_call.o +targets += vdso32/note.o vdso32/system_call.o vdso32/sigreturn.o targets += vdso32/vclock_gettime.o KBUILD_AFLAGS_32 := $(filter-out -m64,$(KBUILD_AFLAGS)) -DBUILD_VDSO @@ -156,7 +156,8 @@ $(obj)/vdso32.so.dbg: FORCE \ $(obj)/vdso32/vdso32.lds \ $(obj)/vdso32/vclock_gettime.o \ $(obj)/vdso32/note.o \ - $(obj)/vdso32/system_call.o + $(obj)/vdso32/system_call.o \ + $(obj)/vdso32/sigreturn.o $(call if_changed,vdso) # diff --git a/arch/x86/entry/vdso/vdso32/sigreturn.S b/arch/x86/entry/vdso/vdso32/sigreturn.S index d7ec4e2..20633e0 100644 --- a/arch/x86/entry/vdso/vdso32/sigreturn.S +++ b/arch/x86/entry/vdso/vdso32/sigreturn.S @@ -1,11 +1,3 @@ -/* - * Common code for the sigreturn entry points in vDSO images. - * So far this code is the same for both int80 and sysenter versions. - * This file is #include'd by int80.S et al to define them first thing. - * The kernel assumes that the addresses of these routines are constant - * for all vDSO implementations. - */ - #include #include #include diff --git a/arch/x86/entry/vdso/vdso32/system_call.S b/arch/x86/entry/vdso/vdso32/system_call.S index 0109ac6..ed4bc97 100644 --- a/arch/x86/entry/vdso/vdso32/system_call.S +++ b/arch/x86/entry/vdso/vdso32/system_call.S @@ -2,16 +2,11 @@ * AT_SYSINFO entry point */ +#include #include #include #include -/* - * First get the common code for the sigreturn entry points. - * This must come first. - */ -#include "sigreturn.S" - .text .globl __kernel_vsyscall .type __kernel_vsyscall,@function -- cgit v0.10.2 From a4455082dc6f0b5d51a23523f77600e8ede47c79 Mon Sep 17 00:00:00 2001 From: Dave Hansen Date: Wed, 8 Jun 2016 10:25:33 -0700 Subject: x86/signals: Add missing signal_compat code for x86 features The 32-bit siginfo is a different binary format than the 64-bit one. So, when running 32-bit binaries on 64-bit kernels, we have to convert the kernel's 64-bit version to a 32-bit version that userspace can grok. We've added a few features to siginfo over the past few years and neglected to add them to arch/x86/kernel/signal_compat.c: 1. The si_addr_lsb used in SIGBUS's sent for machine checks 2. The upper/lower bounds for MPX SIGSEGV faults 3. The protection key for pkey faults I caught this with some protection keys unit tests and realized it affected a few more features. This was tested only with my protection keys patch that looks for a proper value in si_pkey. I didn't actually test the machine check or MPX code. Signed-off-by: Dave Hansen Cc: Al Viro Cc: Andy Lutomirski Cc: Borislav Petkov Cc: Brian Gerst Cc: Dave Hansen Cc: Denys Vlasenko Cc: H. Peter Anvin Cc: Linus Torvalds Cc: Oleg Nesterov Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: Tony Luck Cc: linux-edac@vger.kernel.org Link: http://lkml.kernel.org/r/20160608172533.F8F05637@viggo.jf.intel.com Signed-off-by: Ingo Molnar diff --git a/arch/x86/include/asm/compat.h b/arch/x86/include/asm/compat.h index 5a3b2c1..a188061 100644 --- a/arch/x86/include/asm/compat.h +++ b/arch/x86/include/asm/compat.h @@ -40,6 +40,7 @@ typedef s32 compat_long_t; typedef s64 __attribute__((aligned(4))) compat_s64; typedef u32 compat_uint_t; typedef u32 compat_ulong_t; +typedef u32 compat_u32; typedef u64 __attribute__((aligned(4))) compat_u64; typedef u32 compat_uptr_t; @@ -181,6 +182,16 @@ typedef struct compat_siginfo { /* SIGILL, SIGFPE, SIGSEGV, SIGBUS */ struct { unsigned int _addr; /* faulting insn/memory ref. */ + short int _addr_lsb; /* Valid LSB of the reported address. */ + union { + /* used when si_code=SEGV_BNDERR */ + struct { + compat_uptr_t _lower; + compat_uptr_t _upper; + } _addr_bnd; + /* used when si_code=SEGV_PKUERR */ + compat_u32 _pkey; + }; } _sigfault; /* SIGPOLL */ diff --git a/arch/x86/kernel/signal_compat.c b/arch/x86/kernel/signal_compat.c index dc3c0b1..5335ad9 100644 --- a/arch/x86/kernel/signal_compat.c +++ b/arch/x86/kernel/signal_compat.c @@ -32,6 +32,21 @@ int copy_siginfo_to_user32(compat_siginfo_t __user *to, const siginfo_t *from) &to->_sifields._pad[0]); switch (from->si_code >> 16) { case __SI_FAULT >> 16: + if (from->si_signo == SIGBUS && + (from->si_code == BUS_MCEERR_AR || + from->si_code == BUS_MCEERR_AO)) + put_user_ex(from->si_addr_lsb, &to->si_addr_lsb); + + if (from->si_signo == SIGSEGV) { + if (from->si_code == SEGV_BNDERR) { + compat_uptr_t lower = (unsigned long)&to->si_lower; + compat_uptr_t upper = (unsigned long)&to->si_upper; + put_user_ex(lower, &to->si_lower); + put_user_ex(upper, &to->si_upper); + } + if (from->si_code == SEGV_PKUERR) + put_user_ex(from->si_pkey, &to->si_pkey); + } break; case __SI_SYS >> 16: put_user_ex(from->si_syscall, &to->si_syscall); -- cgit v0.10.2 From 02e8fda2cc00419a11cf38199afea4c0d7172be8 Mon Sep 17 00:00:00 2001 From: Dave Hansen Date: Wed, 8 Jun 2016 10:25:34 -0700 Subject: x86/signals: Add build-time checks to the siginfo compat code There were at least 3 features added to the __SI_FAULT area of the siginfo struct that did not make it to the compat siginfo: 1. The si_addr_lsb used in SIGBUS's sent for machine checks 2. The upper/lower bounds for MPX SIGSEGV faults 3. The protection key for pkey faults There was also some turmoil when I was attempting to add the pkey field because it needs to be a fixed size on 32 and 64-bit and not have any alignment constraints. This patch adds some compile-time checks to the compat code to make it harder to screw this up. Basically, the checks are supposed to trip any time someone changes the siginfo structure. That sounds bad, but it's what we want. If someone changes siginfo, we want them to also be _forced_ to go look at the compat code. The details are in the comments. Signed-off-by: Dave Hansen Cc: Al Viro Cc: Andy Lutomirski Cc: Borislav Petkov Cc: Brian Gerst Cc: Dave Hansen Cc: Denys Vlasenko Cc: H. Peter Anvin Cc: Linus Torvalds Cc: Oleg Nesterov Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: Tony Luck Cc: linux-edac@vger.kernel.org Link: http://lkml.kernel.org/r/20160608172534.C73DAFC3@viggo.jf.intel.com Signed-off-by: Ingo Molnar diff --git a/arch/x86/kernel/signal_compat.c b/arch/x86/kernel/signal_compat.c index 5335ad9..b44564b 100644 --- a/arch/x86/kernel/signal_compat.c +++ b/arch/x86/kernel/signal_compat.c @@ -1,11 +1,104 @@ #include #include +/* + * The compat_siginfo_t structure and handing code is very easy + * to break in several ways. It must always be updated when new + * updates are made to the main siginfo_t, and + * copy_siginfo_to_user32() must be updated when the + * (arch-independent) copy_siginfo_to_user() is updated. + * + * It is also easy to put a new member in the compat_siginfo_t + * which has implicit alignment which can move internal structure + * alignment around breaking the ABI. This can happen if you, + * for instance, put a plain 64-bit value in there. + */ +static inline void signal_compat_build_tests(void) +{ + int _sifields_offset = offsetof(compat_siginfo_t, _sifields); + + /* + * If adding a new si_code, there is probably new data in + * the siginfo. Make sure folks bumping the si_code + * limits also have to look at this code. Make sure any + * new fields are handled in copy_siginfo_to_user32()! + */ + BUILD_BUG_ON(NSIGILL != 8); + BUILD_BUG_ON(NSIGFPE != 8); + BUILD_BUG_ON(NSIGSEGV != 4); + BUILD_BUG_ON(NSIGBUS != 5); + BUILD_BUG_ON(NSIGTRAP != 4); + BUILD_BUG_ON(NSIGCHLD != 6); + BUILD_BUG_ON(NSIGSYS != 1); + + /* This is part of the ABI and can never change in size: */ + BUILD_BUG_ON(sizeof(compat_siginfo_t) != 128); + /* + * The offsets of all the (unioned) si_fields are fixed + * in the ABI, of course. Make sure none of them ever + * move and are always at the beginning: + */ + BUILD_BUG_ON(offsetof(compat_siginfo_t, _sifields) != 3 * sizeof(int)); +#define CHECK_CSI_OFFSET(name) BUILD_BUG_ON(_sifields_offset != offsetof(compat_siginfo_t, _sifields.name)) + + /* + * Ensure that the size of each si_field never changes. + * If it does, it is a sign that the + * copy_siginfo_to_user32() code below needs to updated + * along with the size in the CHECK_SI_SIZE(). + * + * We repeat this check for both the generic and compat + * siginfos. + * + * Note: it is OK for these to grow as long as the whole + * structure stays within the padding size (checked + * above). + */ +#define CHECK_CSI_SIZE(name, size) BUILD_BUG_ON(size != sizeof(((compat_siginfo_t *)0)->_sifields.name)) +#define CHECK_SI_SIZE(name, size) BUILD_BUG_ON(size != sizeof(((siginfo_t *)0)->_sifields.name)) + + CHECK_CSI_OFFSET(_kill); + CHECK_CSI_SIZE (_kill, 2*sizeof(int)); + CHECK_SI_SIZE (_kill, 2*sizeof(int)); + + CHECK_CSI_OFFSET(_timer); + CHECK_CSI_SIZE (_timer, 5*sizeof(int)); + CHECK_SI_SIZE (_timer, 6*sizeof(int)); + + CHECK_CSI_OFFSET(_rt); + CHECK_CSI_SIZE (_rt, 3*sizeof(int)); + CHECK_SI_SIZE (_rt, 4*sizeof(int)); + + CHECK_CSI_OFFSET(_sigchld); + CHECK_CSI_SIZE (_sigchld, 5*sizeof(int)); + CHECK_SI_SIZE (_sigchld, 8*sizeof(int)); + + CHECK_CSI_OFFSET(_sigchld_x32); + CHECK_CSI_SIZE (_sigchld_x32, 7*sizeof(int)); + /* no _sigchld_x32 in the generic siginfo_t */ + + CHECK_CSI_OFFSET(_sigfault); + CHECK_CSI_SIZE (_sigfault, 4*sizeof(int)); + CHECK_SI_SIZE (_sigfault, 8*sizeof(int)); + + CHECK_CSI_OFFSET(_sigpoll); + CHECK_CSI_SIZE (_sigpoll, 2*sizeof(int)); + CHECK_SI_SIZE (_sigpoll, 4*sizeof(int)); + + CHECK_CSI_OFFSET(_sigsys); + CHECK_CSI_SIZE (_sigsys, 3*sizeof(int)); + CHECK_SI_SIZE (_sigsys, 4*sizeof(int)); + + /* any new si_fields should be added here */ +} + int copy_siginfo_to_user32(compat_siginfo_t __user *to, const siginfo_t *from) { int err = 0; bool ia32 = test_thread_flag(TIF_IA32); + signal_compat_build_tests(); + if (!access_ok(VERIFY_WRITE, to, sizeof(compat_siginfo_t))) return -EFAULT; -- cgit v0.10.2 From e754aedc26efde6baef2d7824fbecf998a5510a4 Mon Sep 17 00:00:00 2001 From: Dave Hansen Date: Wed, 8 Jun 2016 10:25:35 -0700 Subject: x86/mpx, selftests: Add MPX self test I've had this code for a while, but never submitted it upstream. Now that Skylake hardware is out in the wild, folks can actually run this for real. It tests the following: 1. The MPX hardware is enabled by the kernel and doing what it is supposed to 2. The MPX management code is present and enabled in the kernel 3. MPX Signal handling 4. The MPX bounds table population code (on-demand population) 5. The MPX bounds table unmapping code (kernel-initiated freeing when unused) This has also caught bugs in the XSAVE code because MPX state is saved/restored with XSAVE. I'm submitting it now because it would have caught the recent issues with the compat_siginfo code not being properly augmented when new siginfo state is added. Signed-off-by: Dave Hansen Cc: Al Viro Cc: Andy Lutomirski Cc: Borislav Petkov Cc: Brian Gerst Cc: Dave Hansen Cc: Denys Vlasenko Cc: H. Peter Anvin Cc: Linus Torvalds Cc: Oleg Nesterov Cc: Peter Zijlstra Cc: Shuah Khan Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/20160608172535.5B40B0EE@viggo.jf.intel.com Signed-off-by: Ingo Molnar diff --git a/tools/testing/selftests/x86/Makefile b/tools/testing/selftests/x86/Makefile index c73425d..abe9c35 100644 --- a/tools/testing/selftests/x86/Makefile +++ b/tools/testing/selftests/x86/Makefile @@ -5,7 +5,7 @@ include ../lib.mk .PHONY: all all_32 all_64 warn_32bit_failure clean TARGETS_C_BOTHBITS := single_step_syscall sysret_ss_attrs syscall_nt ptrace_syscall \ - check_initial_reg_state sigreturn ldt_gdt iopl + check_initial_reg_state sigreturn ldt_gdt iopl mpx-mini-test TARGETS_C_32BIT_ONLY := entry_from_vm86 syscall_arg_fault test_syscall_vdso unwind_vdso \ test_FCMOV test_FCOMI test_FISTTP \ vdso_restorer diff --git a/tools/testing/selftests/x86/mpx-debug.h b/tools/testing/selftests/x86/mpx-debug.h new file mode 100644 index 0000000..9230981 --- /dev/null +++ b/tools/testing/selftests/x86/mpx-debug.h @@ -0,0 +1,14 @@ +#ifndef _MPX_DEBUG_H +#define _MPX_DEBUG_H + +#ifndef DEBUG_LEVEL +#define DEBUG_LEVEL 0 +#endif +#define dprintf_level(level, args...) do { if(level <= DEBUG_LEVEL) printf(args); } while(0) +#define dprintf1(args...) dprintf_level(1, args) +#define dprintf2(args...) dprintf_level(2, args) +#define dprintf3(args...) dprintf_level(3, args) +#define dprintf4(args...) dprintf_level(4, args) +#define dprintf5(args...) dprintf_level(5, args) + +#endif /* _MPX_DEBUG_H */ diff --git a/tools/testing/selftests/x86/mpx-dig.c b/tools/testing/selftests/x86/mpx-dig.c new file mode 100644 index 0000000..ce85356 --- /dev/null +++ b/tools/testing/selftests/x86/mpx-dig.c @@ -0,0 +1,498 @@ +/* + * Written by Dave Hansen + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "mpx-debug.h" +#include "mpx-mm.h" +#include "mpx-hw.h" + +unsigned long bounds_dir_global; + +#define mpx_dig_abort() __mpx_dig_abort(__FILE__, __func__, __LINE__) +static void inline __mpx_dig_abort(const char *file, const char *func, int line) +{ + fprintf(stderr, "MPX dig abort @ %s::%d in %s()\n", file, line, func); + printf("MPX dig abort @ %s::%d in %s()\n", file, line, func); + abort(); +} + +/* + * run like this (BDIR finds the probably bounds directory): + * + * BDIR="$(cat /proc/$pid/smaps | grep -B1 2097152 \ + * | head -1 | awk -F- '{print $1}')"; + * ./mpx-dig $pid 0x$BDIR + * + * NOTE: + * assumes that the only 2097152-kb VMA is the bounds dir + */ + +long nr_incore(void *ptr, unsigned long size_bytes) +{ + int i; + long ret = 0; + long vec_len = size_bytes / PAGE_SIZE; + unsigned char *vec = malloc(vec_len); + int incore_ret; + + if (!vec) + mpx_dig_abort(); + + incore_ret = mincore(ptr, size_bytes, vec); + if (incore_ret) { + printf("mincore ret: %d\n", incore_ret); + perror("mincore"); + mpx_dig_abort(); + } + for (i = 0; i < vec_len; i++) + ret += vec[i]; + free(vec); + return ret; +} + +int open_proc(int pid, char *file) +{ + static char buf[100]; + int fd; + + snprintf(&buf[0], sizeof(buf), "/proc/%d/%s", pid, file); + fd = open(&buf[0], O_RDONLY); + if (fd < 0) + perror(buf); + + return fd; +} + +struct vaddr_range { + unsigned long start; + unsigned long end; +}; +struct vaddr_range *ranges; +int nr_ranges_allocated; +int nr_ranges_populated; +int last_range = -1; + +int __pid_load_vaddrs(int pid) +{ + int ret = 0; + int proc_maps_fd = open_proc(pid, "maps"); + char linebuf[10000]; + unsigned long start; + unsigned long end; + char rest[1000]; + FILE *f = fdopen(proc_maps_fd, "r"); + + if (!f) + mpx_dig_abort(); + nr_ranges_populated = 0; + while (!feof(f)) { + char *readret = fgets(linebuf, sizeof(linebuf), f); + int parsed; + + if (readret == NULL) { + if (feof(f)) + break; + mpx_dig_abort(); + } + + parsed = sscanf(linebuf, "%lx-%lx%s", &start, &end, rest); + if (parsed != 3) + mpx_dig_abort(); + + dprintf4("result[%d]: %lx-%lx<->%s\n", parsed, start, end, rest); + if (nr_ranges_populated >= nr_ranges_allocated) { + ret = -E2BIG; + break; + } + ranges[nr_ranges_populated].start = start; + ranges[nr_ranges_populated].end = end; + nr_ranges_populated++; + } + last_range = -1; + fclose(f); + close(proc_maps_fd); + return ret; +} + +int pid_load_vaddrs(int pid) +{ + int ret; + + dprintf2("%s(%d)\n", __func__, pid); + if (!ranges) { + nr_ranges_allocated = 4; + ranges = malloc(nr_ranges_allocated * sizeof(ranges[0])); + dprintf2("%s(%d) allocated %d ranges @ %p\n", __func__, pid, + nr_ranges_allocated, ranges); + assert(ranges != NULL); + } + do { + ret = __pid_load_vaddrs(pid); + if (!ret) + break; + if (ret == -E2BIG) { + dprintf2("%s(%d) need to realloc\n", __func__, pid); + nr_ranges_allocated *= 2; + ranges = realloc(ranges, + nr_ranges_allocated * sizeof(ranges[0])); + dprintf2("%s(%d) allocated %d ranges @ %p\n", __func__, + pid, nr_ranges_allocated, ranges); + assert(ranges != NULL); + dprintf1("reallocating to hold %d ranges\n", nr_ranges_allocated); + } + } while (1); + + dprintf2("%s(%d) done\n", __func__, pid); + + return ret; +} + +static inline int vaddr_in_range(unsigned long vaddr, struct vaddr_range *r) +{ + if (vaddr < r->start) + return 0; + if (vaddr >= r->end) + return 0; + return 1; +} + +static inline int vaddr_mapped_by_range(unsigned long vaddr) +{ + int i; + + if (last_range > 0 && vaddr_in_range(vaddr, &ranges[last_range])) + return 1; + + for (i = 0; i < nr_ranges_populated; i++) { + struct vaddr_range *r = &ranges[i]; + + if (vaddr_in_range(vaddr, r)) + continue; + last_range = i; + return 1; + } + return 0; +} + +const int bt_entry_size_bytes = sizeof(unsigned long) * 4; + +void *read_bounds_table_into_buf(unsigned long table_vaddr) +{ +#ifdef MPX_DIG_STANDALONE + static char bt_buf[MPX_BOUNDS_TABLE_SIZE_BYTES]; + off_t seek_ret = lseek(fd, table_vaddr, SEEK_SET); + if (seek_ret != table_vaddr) + mpx_dig_abort(); + + int read_ret = read(fd, &bt_buf, sizeof(bt_buf)); + if (read_ret != sizeof(bt_buf)) + mpx_dig_abort(); + return &bt_buf; +#else + return (void *)table_vaddr; +#endif +} + +int dump_table(unsigned long table_vaddr, unsigned long base_controlled_vaddr, + unsigned long bde_vaddr) +{ + unsigned long offset_inside_bt; + int nr_entries = 0; + int do_abort = 0; + char *bt_buf; + + dprintf3("%s() base_controlled_vaddr: 0x%012lx bde_vaddr: 0x%012lx\n", + __func__, base_controlled_vaddr, bde_vaddr); + + bt_buf = read_bounds_table_into_buf(table_vaddr); + + dprintf4("%s() read done\n", __func__); + + for (offset_inside_bt = 0; + offset_inside_bt < MPX_BOUNDS_TABLE_SIZE_BYTES; + offset_inside_bt += bt_entry_size_bytes) { + unsigned long bt_entry_index; + unsigned long bt_entry_controls; + unsigned long this_bt_entry_for_vaddr; + unsigned long *bt_entry_buf; + int i; + + dprintf4("%s() offset_inside_bt: 0x%lx of 0x%llx\n", __func__, + offset_inside_bt, MPX_BOUNDS_TABLE_SIZE_BYTES); + bt_entry_buf = (void *)&bt_buf[offset_inside_bt]; + if (!bt_buf) { + printf("null bt_buf\n"); + mpx_dig_abort(); + } + if (!bt_entry_buf) { + printf("null bt_entry_buf\n"); + mpx_dig_abort(); + } + dprintf4("%s() reading *bt_entry_buf @ %p\n", __func__, + bt_entry_buf); + if (!bt_entry_buf[0] && + !bt_entry_buf[1] && + !bt_entry_buf[2] && + !bt_entry_buf[3]) + continue; + + nr_entries++; + + bt_entry_index = offset_inside_bt/bt_entry_size_bytes; + bt_entry_controls = sizeof(void *); + this_bt_entry_for_vaddr = + base_controlled_vaddr + bt_entry_index*bt_entry_controls; + /* + * We sign extend vaddr bits 48->63 which effectively + * creates a hole in the virtual address space. + * This calculation corrects for the hole. + */ + if (this_bt_entry_for_vaddr > 0x00007fffffffffffUL) + this_bt_entry_for_vaddr |= 0xffff800000000000; + + if (!vaddr_mapped_by_range(this_bt_entry_for_vaddr)) { + printf("bt_entry_buf: %p\n", bt_entry_buf); + printf("there is a bte for %lx but no mapping\n", + this_bt_entry_for_vaddr); + printf(" bde vaddr: %016lx\n", bde_vaddr); + printf("base_controlled_vaddr: %016lx\n", base_controlled_vaddr); + printf(" table_vaddr: %016lx\n", table_vaddr); + printf(" entry vaddr: %016lx @ offset %lx\n", + table_vaddr + offset_inside_bt, offset_inside_bt); + do_abort = 1; + mpx_dig_abort(); + } + if (DEBUG_LEVEL < 4) + continue; + + printf("table entry[%lx]: ", offset_inside_bt); + for (i = 0; i < bt_entry_size_bytes; i += sizeof(unsigned long)) + printf("0x%016lx ", bt_entry_buf[i]); + printf("\n"); + } + if (do_abort) + mpx_dig_abort(); + dprintf4("%s() done\n", __func__); + return nr_entries; +} + +int search_bd_buf(char *buf, int len_bytes, unsigned long bd_offset_bytes, + int *nr_populated_bdes) +{ + unsigned long i; + int total_entries = 0; + + dprintf3("%s(%p, %x, %lx, ...) buf end: %p\n", __func__, buf, + len_bytes, bd_offset_bytes, buf + len_bytes); + + for (i = 0; i < len_bytes; i += sizeof(unsigned long)) { + unsigned long bd_index = (bd_offset_bytes + i) / sizeof(unsigned long); + unsigned long *bounds_dir_entry_ptr = (unsigned long *)&buf[i]; + unsigned long bounds_dir_entry; + unsigned long bd_for_vaddr; + unsigned long bt_start; + unsigned long bt_tail; + int nr_entries; + + dprintf4("%s() loop i: %ld bounds_dir_entry_ptr: %p\n", __func__, i, + bounds_dir_entry_ptr); + + bounds_dir_entry = *bounds_dir_entry_ptr; + if (!bounds_dir_entry) { + dprintf4("no bounds dir at index 0x%lx / 0x%lx " + "start at offset:%lx %lx\n", bd_index, bd_index, + bd_offset_bytes, i); + continue; + } + dprintf3("found bounds_dir_entry: 0x%lx @ " + "index 0x%lx buf ptr: %p\n", bounds_dir_entry, i, + &buf[i]); + /* mask off the enable bit: */ + bounds_dir_entry &= ~0x1; + (*nr_populated_bdes)++; + dprintf4("nr_populated_bdes: %p\n", nr_populated_bdes); + dprintf4("*nr_populated_bdes: %d\n", *nr_populated_bdes); + + bt_start = bounds_dir_entry; + bt_tail = bounds_dir_entry + MPX_BOUNDS_TABLE_SIZE_BYTES - 1; + if (!vaddr_mapped_by_range(bt_start)) { + printf("bounds directory 0x%lx points to nowhere\n", + bounds_dir_entry); + mpx_dig_abort(); + } + if (!vaddr_mapped_by_range(bt_tail)) { + printf("bounds directory end 0x%lx points to nowhere\n", + bt_tail); + mpx_dig_abort(); + } + /* + * Each bounds directory entry controls 1MB of virtual address + * space. This variable is the virtual address in the process + * of the beginning of the area controlled by this bounds_dir. + */ + bd_for_vaddr = bd_index * (1UL<<20); + + nr_entries = dump_table(bounds_dir_entry, bd_for_vaddr, + bounds_dir_global+bd_offset_bytes+i); + total_entries += nr_entries; + dprintf5("dir entry[%4ld @ %p]: 0x%lx %6d entries " + "total this buf: %7d bd_for_vaddrs: 0x%lx -> 0x%lx\n", + bd_index, buf+i, + bounds_dir_entry, nr_entries, total_entries, + bd_for_vaddr, bd_for_vaddr + (1UL<<20)); + } + dprintf3("%s(%p, %x, %lx, ...) done\n", __func__, buf, len_bytes, + bd_offset_bytes); + return total_entries; +} + +int proc_pid_mem_fd = -1; + +void *fill_bounds_dir_buf_other(long byte_offset_inside_bounds_dir, + long buffer_size_bytes, void *buffer) +{ + unsigned long seekto = bounds_dir_global + byte_offset_inside_bounds_dir; + int read_ret; + off_t seek_ret = lseek(proc_pid_mem_fd, seekto, SEEK_SET); + + if (seek_ret != seekto) + mpx_dig_abort(); + + read_ret = read(proc_pid_mem_fd, buffer, buffer_size_bytes); + /* there shouldn't practically be short reads of /proc/$pid/mem */ + if (read_ret != buffer_size_bytes) + mpx_dig_abort(); + + return buffer; +} +void *fill_bounds_dir_buf_self(long byte_offset_inside_bounds_dir, + long buffer_size_bytes, void *buffer) + +{ + unsigned char vec[buffer_size_bytes / PAGE_SIZE]; + char *dig_bounds_dir_ptr = + (void *)(bounds_dir_global + byte_offset_inside_bounds_dir); + /* + * use mincore() to quickly find the areas of the bounds directory + * that have memory and thus will be worth scanning. + */ + int incore_ret; + + int incore = 0; + int i; + + dprintf4("%s() dig_bounds_dir_ptr: %p\n", __func__, dig_bounds_dir_ptr); + + incore_ret = mincore(dig_bounds_dir_ptr, buffer_size_bytes, &vec[0]); + if (incore_ret) { + printf("mincore ret: %d\n", incore_ret); + perror("mincore"); + mpx_dig_abort(); + } + for (i = 0; i < sizeof(vec); i++) + incore += vec[i]; + dprintf4("%s() total incore: %d\n", __func__, incore); + if (!incore) + return NULL; + dprintf3("%s() total incore: %d\n", __func__, incore); + return dig_bounds_dir_ptr; +} + +int inspect_pid(int pid) +{ + static int dig_nr; + long offset_inside_bounds_dir; + char bounds_dir_buf[sizeof(unsigned long) * (1UL << 15)]; + char *dig_bounds_dir_ptr; + int total_entries = 0; + int nr_populated_bdes = 0; + int inspect_self; + + if (getpid() == pid) { + dprintf4("inspecting self\n"); + inspect_self = 1; + } else { + dprintf4("inspecting pid %d\n", pid); + mpx_dig_abort(); + } + + for (offset_inside_bounds_dir = 0; + offset_inside_bounds_dir < MPX_BOUNDS_TABLE_SIZE_BYTES; + offset_inside_bounds_dir += sizeof(bounds_dir_buf)) { + static int bufs_skipped; + int this_entries; + + if (inspect_self) { + dig_bounds_dir_ptr = + fill_bounds_dir_buf_self(offset_inside_bounds_dir, + sizeof(bounds_dir_buf), + &bounds_dir_buf[0]); + } else { + dig_bounds_dir_ptr = + fill_bounds_dir_buf_other(offset_inside_bounds_dir, + sizeof(bounds_dir_buf), + &bounds_dir_buf[0]); + } + if (!dig_bounds_dir_ptr) { + bufs_skipped++; + continue; + } + this_entries = search_bd_buf(dig_bounds_dir_ptr, + sizeof(bounds_dir_buf), + offset_inside_bounds_dir, + &nr_populated_bdes); + total_entries += this_entries; + } + printf("mpx dig (%3d) complete, SUCCESS (%8d / %4d)\n", ++dig_nr, + total_entries, nr_populated_bdes); + return total_entries + nr_populated_bdes; +} + +#ifdef MPX_DIG_REMOTE +int main(int argc, char **argv) +{ + int err; + char *c; + unsigned long bounds_dir_entry; + int pid; + + printf("mpx-dig starting...\n"); + err = sscanf(argv[1], "%d", &pid); + printf("parsing: '%s', err: %d\n", argv[1], err); + if (err != 1) + mpx_dig_abort(); + + err = sscanf(argv[2], "%lx", &bounds_dir_global); + printf("parsing: '%s': %d\n", argv[2], err); + if (err != 1) + mpx_dig_abort(); + + proc_pid_mem_fd = open_proc(pid, "mem"); + if (proc_pid_mem_fd < 0) + mpx_dig_abort(); + + inspect_pid(pid); + return 0; +} +#endif + +long inspect_me(struct mpx_bounds_dir *bounds_dir) +{ + int pid = getpid(); + + pid_load_vaddrs(pid); + bounds_dir_global = (unsigned long)bounds_dir; + dprintf4("enter %s() bounds dir: %p\n", __func__, bounds_dir); + return inspect_pid(pid); +} diff --git a/tools/testing/selftests/x86/mpx-hw.h b/tools/testing/selftests/x86/mpx-hw.h new file mode 100644 index 0000000..093c190 --- /dev/null +++ b/tools/testing/selftests/x86/mpx-hw.h @@ -0,0 +1,123 @@ +#ifndef _MPX_HW_H +#define _MPX_HW_H + +#include + +/* Describe the MPX Hardware Layout in here */ + +#define NR_MPX_BOUNDS_REGISTERS 4 + +#ifdef __i386__ + +#define MPX_BOUNDS_TABLE_ENTRY_SIZE_BYTES 16 /* 4 * 32-bits */ +#define MPX_BOUNDS_TABLE_SIZE_BYTES (1ULL << 14) /* 16k */ +#define MPX_BOUNDS_DIR_ENTRY_SIZE_BYTES 4 +#define MPX_BOUNDS_DIR_SIZE_BYTES (1ULL << 22) /* 4MB */ + +#define MPX_BOUNDS_TABLE_BOTTOM_BIT 2 +#define MPX_BOUNDS_TABLE_TOP_BIT 11 +#define MPX_BOUNDS_DIR_BOTTOM_BIT 12 +#define MPX_BOUNDS_DIR_TOP_BIT 31 + +#else + +/* + * Linear Address of "pointer" (LAp) + * 0 -> 2: ignored + * 3 -> 19: index in to bounds table + * 20 -> 47: index in to bounds directory + * 48 -> 63: ignored + */ + +#define MPX_BOUNDS_TABLE_ENTRY_SIZE_BYTES 32 +#define MPX_BOUNDS_TABLE_SIZE_BYTES (1ULL << 22) /* 4MB */ +#define MPX_BOUNDS_DIR_ENTRY_SIZE_BYTES 8 +#define MPX_BOUNDS_DIR_SIZE_BYTES (1ULL << 31) /* 2GB */ + +#define MPX_BOUNDS_TABLE_BOTTOM_BIT 3 +#define MPX_BOUNDS_TABLE_TOP_BIT 19 +#define MPX_BOUNDS_DIR_BOTTOM_BIT 20 +#define MPX_BOUNDS_DIR_TOP_BIT 47 + +#endif + +#define MPX_BOUNDS_DIR_NR_ENTRIES \ + (MPX_BOUNDS_DIR_SIZE_BYTES/MPX_BOUNDS_DIR_ENTRY_SIZE_BYTES) +#define MPX_BOUNDS_TABLE_NR_ENTRIES \ + (MPX_BOUNDS_TABLE_SIZE_BYTES/MPX_BOUNDS_TABLE_ENTRY_SIZE_BYTES) + +#define MPX_BOUNDS_TABLE_ENTRY_VALID_BIT 0x1 + +struct mpx_bd_entry { + union { + char x[MPX_BOUNDS_DIR_ENTRY_SIZE_BYTES]; + void *contents[1]; + }; +} __attribute__((packed)); + +struct mpx_bt_entry { + union { + char x[MPX_BOUNDS_TABLE_ENTRY_SIZE_BYTES]; + unsigned long contents[1]; + }; +} __attribute__((packed)); + +struct mpx_bounds_dir { + struct mpx_bd_entry entries[MPX_BOUNDS_DIR_NR_ENTRIES]; +} __attribute__((packed)); + +struct mpx_bounds_table { + struct mpx_bt_entry entries[MPX_BOUNDS_TABLE_NR_ENTRIES]; +} __attribute__((packed)); + +static inline unsigned long GET_BITS(unsigned long val, int bottombit, int topbit) +{ + int total_nr_bits = topbit - bottombit; + unsigned long mask = (1UL << total_nr_bits)-1; + return (val >> bottombit) & mask; +} + +static inline unsigned long __vaddr_bounds_table_index(void *vaddr) +{ + return GET_BITS((unsigned long)vaddr, MPX_BOUNDS_TABLE_BOTTOM_BIT, + MPX_BOUNDS_TABLE_TOP_BIT); +} + +static inline unsigned long __vaddr_bounds_directory_index(void *vaddr) +{ + return GET_BITS((unsigned long)vaddr, MPX_BOUNDS_DIR_BOTTOM_BIT, + MPX_BOUNDS_DIR_TOP_BIT); +} + +static inline struct mpx_bd_entry *mpx_vaddr_to_bd_entry(void *vaddr, + struct mpx_bounds_dir *bounds_dir) +{ + unsigned long index = __vaddr_bounds_directory_index(vaddr); + return &bounds_dir->entries[index]; +} + +static inline int bd_entry_valid(struct mpx_bd_entry *bounds_dir_entry) +{ + unsigned long __bd_entry = (unsigned long)bounds_dir_entry->contents; + return (__bd_entry & MPX_BOUNDS_TABLE_ENTRY_VALID_BIT); +} + +static inline struct mpx_bounds_table * +__bd_entry_to_bounds_table(struct mpx_bd_entry *bounds_dir_entry) +{ + unsigned long __bd_entry = (unsigned long)bounds_dir_entry->contents; + assert(__bd_entry & MPX_BOUNDS_TABLE_ENTRY_VALID_BIT); + __bd_entry &= ~MPX_BOUNDS_TABLE_ENTRY_VALID_BIT; + return (struct mpx_bounds_table *)__bd_entry; +} + +static inline struct mpx_bt_entry * +mpx_vaddr_to_bt_entry(void *vaddr, struct mpx_bounds_dir *bounds_dir) +{ + struct mpx_bd_entry *bde = mpx_vaddr_to_bd_entry(vaddr, bounds_dir); + struct mpx_bounds_table *bt = __bd_entry_to_bounds_table(bde); + unsigned long index = __vaddr_bounds_table_index(vaddr); + return &bt->entries[index]; +} + +#endif /* _MPX_HW_H */ diff --git a/tools/testing/selftests/x86/mpx-mini-test.c b/tools/testing/selftests/x86/mpx-mini-test.c new file mode 100644 index 0000000..616ee96 --- /dev/null +++ b/tools/testing/selftests/x86/mpx-mini-test.c @@ -0,0 +1,1585 @@ +/* + * mpx-mini-test.c: routines to test Intel MPX (Memory Protection eXtentions) + * + * Written by: + * "Ren, Qiaowei" + * "Wei, Gang" + * "Hansen, Dave" + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2. + */ + +/* + * 2014-12-05: Dave Hansen: fixed all of the compiler warnings, and made sure + * it works on 32-bit. + */ + +int inspect_every_this_many_mallocs = 100; +int zap_all_every_this_many_mallocs = 1000; + +#define _GNU_SOURCE +#define _LARGEFILE64_SOURCE + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mpx-hw.h" +#include "mpx-debug.h" +#include "mpx-mm.h" + +#ifndef __always_inline +#define __always_inline inline __attribute__((always_inline) +#endif + +#ifndef TEST_DURATION_SECS +#define TEST_DURATION_SECS 3 +#endif + +void write_int_to(char *prefix, char *file, int int_to_write) +{ + char buf[100]; + int fd = open(file, O_RDWR); + int len; + int ret; + + assert(fd >= 0); + len = snprintf(buf, sizeof(buf), "%s%d", prefix, int_to_write); + assert(len >= 0); + assert(len < sizeof(buf)); + ret = write(fd, buf, len); + assert(ret == len); + ret = close(fd); + assert(!ret); +} + +void write_pid_to(char *prefix, char *file) +{ + write_int_to(prefix, file, getpid()); +} + +void trace_me(void) +{ +/* tracing events dir */ +#define TED "/sys/kernel/debug/tracing/events/" +/* + write_pid_to("common_pid=", TED "signal/filter"); + write_pid_to("common_pid=", TED "exceptions/filter"); + write_int_to("", TED "signal/enable", 1); + write_int_to("", TED "exceptions/enable", 1); +*/ + write_pid_to("", "/sys/kernel/debug/tracing/set_ftrace_pid"); + write_int_to("", "/sys/kernel/debug/tracing/trace", 0); +} + +#define test_failed() __test_failed(__FILE__, __LINE__) +static void __test_failed(char *f, int l) +{ + fprintf(stderr, "abort @ %s::%d\n", f, l); + abort(); +} + +/* Error Printf */ +#define eprintf(args...) fprintf(stderr, args) + +#ifdef __i386__ + +/* i386 directory size is 4MB */ +#define REG_IP_IDX REG_EIP +#define REX_PREFIX + +#define XSAVE_OFFSET_IN_FPMEM sizeof(struct _libc_fpstate) + +/* + * __cpuid() is from the Linux Kernel: + */ +static inline void __cpuid(unsigned int *eax, unsigned int *ebx, + unsigned int *ecx, unsigned int *edx) +{ + /* ecx is often an input as well as an output. */ + asm volatile( + "push %%ebx;" + "cpuid;" + "mov %%ebx, %1;" + "pop %%ebx" + : "=a" (*eax), + "=g" (*ebx), + "=c" (*ecx), + "=d" (*edx) + : "0" (*eax), "2" (*ecx)); +} + +#else /* __i386__ */ + +#define REG_IP_IDX REG_RIP +#define REX_PREFIX "0x48, " + +#define XSAVE_OFFSET_IN_FPMEM 0 + +/* + * __cpuid() is from the Linux Kernel: + */ +static inline void __cpuid(unsigned int *eax, unsigned int *ebx, + unsigned int *ecx, unsigned int *edx) +{ + /* ecx is often an input as well as an output. */ + asm volatile( + "cpuid;" + : "=a" (*eax), + "=b" (*ebx), + "=c" (*ecx), + "=d" (*edx) + : "0" (*eax), "2" (*ecx)); +} + +#endif /* !__i386__ */ + +struct xsave_hdr_struct { + uint64_t xstate_bv; + uint64_t reserved1[2]; + uint64_t reserved2[5]; +} __attribute__((packed)); + +struct bndregs_struct { + uint64_t bndregs[8]; +} __attribute__((packed)); + +struct bndcsr_struct { + uint64_t cfg_reg_u; + uint64_t status_reg; +} __attribute__((packed)); + +struct xsave_struct { + uint8_t fpu_sse[512]; + struct xsave_hdr_struct xsave_hdr; + uint8_t ymm[256]; + uint8_t lwp[128]; + struct bndregs_struct bndregs; + struct bndcsr_struct bndcsr; +} __attribute__((packed)); + +uint8_t __attribute__((__aligned__(64))) buffer[4096]; +struct xsave_struct *xsave_buf = (struct xsave_struct *)buffer; + +uint8_t __attribute__((__aligned__(64))) test_buffer[4096]; +struct xsave_struct *xsave_test_buf = (struct xsave_struct *)test_buffer; + +uint64_t num_bnd_chk; + +static __always_inline void xrstor_state(struct xsave_struct *fx, uint64_t mask) +{ + uint32_t lmask = mask; + uint32_t hmask = mask >> 32; + + asm volatile(".byte " REX_PREFIX "0x0f,0xae,0x2f\n\t" + : : "D" (fx), "m" (*fx), "a" (lmask), "d" (hmask) + : "memory"); +} + +static __always_inline void xsave_state_1(void *_fx, uint64_t mask) +{ + uint32_t lmask = mask; + uint32_t hmask = mask >> 32; + unsigned char *fx = _fx; + + asm volatile(".byte " REX_PREFIX "0x0f,0xae,0x27\n\t" + : : "D" (fx), "m" (*fx), "a" (lmask), "d" (hmask) + : "memory"); +} + +static inline uint64_t xgetbv(uint32_t index) +{ + uint32_t eax, edx; + + asm volatile(".byte 0x0f,0x01,0xd0" /* xgetbv */ + : "=a" (eax), "=d" (edx) + : "c" (index)); + return eax + ((uint64_t)edx << 32); +} + +static uint64_t read_mpx_status_sig(ucontext_t *uctxt) +{ + memset(buffer, 0, sizeof(buffer)); + memcpy(buffer, + (uint8_t *)uctxt->uc_mcontext.fpregs + XSAVE_OFFSET_IN_FPMEM, + sizeof(struct xsave_struct)); + + return xsave_buf->bndcsr.status_reg; +} + +#include + +static uint8_t *get_next_inst_ip(uint8_t *addr) +{ + uint8_t *ip = addr; + uint8_t sib; + uint8_t rm; + uint8_t mod; + uint8_t base; + uint8_t modrm; + + /* determine the prefix. */ + switch(*ip) { + case 0xf2: + case 0xf3: + case 0x66: + ip++; + break; + } + + /* look for rex prefix */ + if ((*ip & 0x40) == 0x40) + ip++; + + /* Make sure we have a MPX instruction. */ + if (*ip++ != 0x0f) + return addr; + + /* Skip the op code byte. */ + ip++; + + /* Get the modrm byte. */ + modrm = *ip++; + + /* Break it down into parts. */ + rm = modrm & 7; + mod = (modrm >> 6); + + /* Init the parts of the address mode. */ + base = 8; + + /* Is it a mem mode? */ + if (mod != 3) { + /* look for scaled indexed addressing */ + if (rm == 4) { + /* SIB addressing */ + sib = *ip++; + base = sib & 7; + switch (mod) { + case 0: + if (base == 5) + ip += 4; + break; + + case 1: + ip++; + break; + + case 2: + ip += 4; + break; + } + + } else { + /* MODRM addressing */ + switch (mod) { + case 0: + /* DISP32 addressing, no base */ + if (rm == 5) + ip += 4; + break; + + case 1: + ip++; + break; + + case 2: + ip += 4; + break; + } + } + } + return ip; +} + +#ifdef si_lower +static inline void *__si_bounds_lower(siginfo_t *si) +{ + return si->si_lower; +} + +static inline void *__si_bounds_upper(siginfo_t *si) +{ + return si->si_upper; +} +#else +static inline void **__si_bounds_hack(siginfo_t *si) +{ + void *sigfault = &si->_sifields._sigfault; + void *end_sigfault = sigfault + sizeof(si->_sifields._sigfault); + void **__si_lower = end_sigfault; + + return __si_lower; +} + +static inline void *__si_bounds_lower(siginfo_t *si) +{ + return *__si_bounds_hack(si); +} + +static inline void *__si_bounds_upper(siginfo_t *si) +{ + return (*__si_bounds_hack(si)) + sizeof(void *); +} +#endif + +static int br_count; +static int expected_bnd_index = -1; +uint64_t shadow_plb[NR_MPX_BOUNDS_REGISTERS][2]; /* shadow MPX bound registers */ +unsigned long shadow_map[NR_MPX_BOUNDS_REGISTERS]; + +/* + * The kernel is supposed to provide some information about the bounds + * exception in the siginfo. It should match what we have in the bounds + * registers that we are checking against. Just check against the shadow copy + * since it is easily available, and we also check that *it* matches the real + * registers. + */ +void check_siginfo_vs_shadow(siginfo_t* si) +{ + int siginfo_ok = 1; + void *shadow_lower = (void *)(unsigned long)shadow_plb[expected_bnd_index][0]; + void *shadow_upper = (void *)(unsigned long)shadow_plb[expected_bnd_index][1]; + + if ((expected_bnd_index < 0) || + (expected_bnd_index >= NR_MPX_BOUNDS_REGISTERS)) { + fprintf(stderr, "ERROR: invalid expected_bnd_index: %d\n", + expected_bnd_index); + exit(6); + } + if (__si_bounds_lower(si) != shadow_lower) + siginfo_ok = 0; + if (__si_bounds_upper(si) != shadow_upper) + siginfo_ok = 0; + + if (!siginfo_ok) { + fprintf(stderr, "ERROR: siginfo bounds do not match " + "shadow bounds for register %d\n", expected_bnd_index); + exit(7); + } +} + +void handler(int signum, siginfo_t *si, void *vucontext) +{ + int i; + ucontext_t *uctxt = vucontext; + int trapno; + unsigned long ip; + + dprintf1("entered signal handler\n"); + + trapno = uctxt->uc_mcontext.gregs[REG_TRAPNO]; + ip = uctxt->uc_mcontext.gregs[REG_IP_IDX]; + + if (trapno == 5) { + typeof(si->si_addr) *si_addr_ptr = &si->si_addr; + uint64_t status = read_mpx_status_sig(uctxt); + uint64_t br_reason = status & 0x3; + + br_count++; + dprintf1("#BR 0x%jx (total seen: %d)\n", status, br_count); + +#define __SI_FAULT (3 << 16) +#define SEGV_BNDERR (__SI_FAULT|3) /* failed address bound checks */ + + dprintf2("Saw a #BR! status 0x%jx at %016lx br_reason: %jx\n", + status, ip, br_reason); + dprintf2("si_signo: %d\n", si->si_signo); + dprintf2(" signum: %d\n", signum); + dprintf2("info->si_code == SEGV_BNDERR: %d\n", + (si->si_code == SEGV_BNDERR)); + dprintf2("info->si_code: %d\n", si->si_code); + dprintf2("info->si_lower: %p\n", __si_bounds_lower(si)); + dprintf2("info->si_upper: %p\n", __si_bounds_upper(si)); + + check_siginfo_vs_shadow(si); + + for (i = 0; i < 8; i++) + dprintf3("[%d]: %p\n", i, si_addr_ptr[i]); + switch (br_reason) { + case 0: /* traditional BR */ + fprintf(stderr, + "Undefined status with bound exception:%jx\n", + status); + exit(5); + case 1: /* #BR MPX bounds exception */ + /* these are normal and we expect to see them */ + dprintf1("bounds exception (normal): status 0x%jx at %p si_addr: %p\n", + status, (void *)ip, si->si_addr); + num_bnd_chk++; + uctxt->uc_mcontext.gregs[REG_IP_IDX] = + (greg_t)get_next_inst_ip((uint8_t *)ip); + break; + case 2: + fprintf(stderr, "#BR status == 2, missing bounds table," + "kernel should have handled!!\n"); + exit(4); + break; + default: + fprintf(stderr, "bound check error: status 0x%jx at %p\n", + status, (void *)ip); + num_bnd_chk++; + uctxt->uc_mcontext.gregs[REG_IP_IDX] = + (greg_t)get_next_inst_ip((uint8_t *)ip); + fprintf(stderr, "bound check error: si_addr %p\n", si->si_addr); + exit(3); + } + } else if (trapno == 14) { + eprintf("ERROR: In signal handler, page fault, trapno = %d, ip = %016lx\n", + trapno, ip); + eprintf("si_addr %p\n", si->si_addr); + eprintf("REG_ERR: %lx\n", (unsigned long)uctxt->uc_mcontext.gregs[REG_ERR]); + test_failed(); + } else { + eprintf("unexpected trap %d! at 0x%lx\n", trapno, ip); + eprintf("si_addr %p\n", si->si_addr); + eprintf("REG_ERR: %lx\n", (unsigned long)uctxt->uc_mcontext.gregs[REG_ERR]); + test_failed(); + } +} + +static inline void cpuid_count(unsigned int op, int count, + unsigned int *eax, unsigned int *ebx, + unsigned int *ecx, unsigned int *edx) +{ + *eax = op; + *ecx = count; + __cpuid(eax, ebx, ecx, edx); +} + +#define XSTATE_CPUID 0x0000000d + +/* + * List of XSAVE features Linux knows about: + */ +enum xfeature_bit { + XSTATE_BIT_FP, + XSTATE_BIT_SSE, + XSTATE_BIT_YMM, + XSTATE_BIT_BNDREGS, + XSTATE_BIT_BNDCSR, + XSTATE_BIT_OPMASK, + XSTATE_BIT_ZMM_Hi256, + XSTATE_BIT_Hi16_ZMM, + + XFEATURES_NR_MAX, +}; + +#define XSTATE_FP (1 << XSTATE_BIT_FP) +#define XSTATE_SSE (1 << XSTATE_BIT_SSE) +#define XSTATE_YMM (1 << XSTATE_BIT_YMM) +#define XSTATE_BNDREGS (1 << XSTATE_BIT_BNDREGS) +#define XSTATE_BNDCSR (1 << XSTATE_BIT_BNDCSR) +#define XSTATE_OPMASK (1 << XSTATE_BIT_OPMASK) +#define XSTATE_ZMM_Hi256 (1 << XSTATE_BIT_ZMM_Hi256) +#define XSTATE_Hi16_ZMM (1 << XSTATE_BIT_Hi16_ZMM) + +#define MPX_XSTATES (XSTATE_BNDREGS | XSTATE_BNDCSR) /* 0x18 */ + +bool one_bit(unsigned int x, int bit) +{ + return !!(x & (1<xsave_hdr.xstate_bv = 0x10; + xsave_buf->bndcsr.cfg_reg_u = (unsigned long)l1base | 1; + xsave_buf->bndcsr.status_reg = 0; + + dprintf2("bf xrstor\n"); + dprintf2("xsave cndcsr: status %jx, configu %jx\n", + xsave_buf->bndcsr.status_reg, xsave_buf->bndcsr.cfg_reg_u); + xrstor_state(xsave_buf, 0x18); + dprintf2("after xrstor\n"); + + xsave_state_1(xsave_buf, 0x18); + + dprintf1("xsave bndcsr: status %jx, configu %jx\n", + xsave_buf->bndcsr.status_reg, xsave_buf->bndcsr.cfg_reg_u); +} + +#include + +struct mpx_bounds_dir *bounds_dir_ptr; + +unsigned long __bd_incore(const char *func, int line) +{ + unsigned long ret = nr_incore(bounds_dir_ptr, MPX_BOUNDS_DIR_SIZE_BYTES); + return ret; +} +#define bd_incore() __bd_incore(__func__, __LINE__) + +void check_clear(void *ptr, unsigned long sz) +{ + unsigned long *i; + + for (i = ptr; (void *)i < ptr + sz; i++) { + if (*i) { + dprintf1("%p is NOT clear at %p\n", ptr, i); + assert(0); + } + } + dprintf1("%p is clear for %lx\n", ptr, sz); +} + +void check_clear_bd(void) +{ + check_clear(bounds_dir_ptr, 2UL << 30); +} + +#define USE_MALLOC_FOR_BOUNDS_DIR 1 +bool process_specific_init(void) +{ + unsigned long size; + unsigned long *dir; + /* Guarantee we have the space to align it, add padding: */ + unsigned long pad = getpagesize(); + + size = 2UL << 30; /* 2GB */ + if (sizeof(unsigned long) == 4) + size = 4UL << 20; /* 4MB */ + dprintf1("trying to allocate %ld MB bounds directory\n", (size >> 20)); + + if (USE_MALLOC_FOR_BOUNDS_DIR) { + unsigned long _dir; + + dir = malloc(size + pad); + assert(dir); + _dir = (unsigned long)dir; + _dir += 0xfffUL; + _dir &= ~0xfffUL; + dir = (void *)_dir; + } else { + /* + * This makes debugging easier because the address + * calculations are simpler: + */ + dir = mmap((void *)0x200000000000, size + pad, + PROT_READ|PROT_WRITE, + MAP_ANONYMOUS|MAP_PRIVATE, -1, 0); + if (dir == (void *)-1) { + perror("unable to allocate bounds directory"); + abort(); + } + check_clear(dir, size); + } + bounds_dir_ptr = (void *)dir; + madvise(bounds_dir_ptr, size, MADV_NOHUGEPAGE); + bd_incore(); + dprintf1("bounds directory: 0x%p -> 0x%p\n", bounds_dir_ptr, + (char *)bounds_dir_ptr + size); + check_clear(dir, size); + enable_mpx(dir); + check_clear(dir, size); + if (prctl(43, 0, 0, 0, 0)) { + printf("no MPX support\n"); + abort(); + return false; + } + return true; +} + +bool process_specific_finish(void) +{ + if (prctl(44)) { + printf("no MPX support\n"); + return false; + } + return true; +} + +void setup_handler() +{ + int r, rs; + struct sigaction newact; + struct sigaction oldact; + + /* #BR is mapped to sigsegv */ + int signum = SIGSEGV; + + newact.sa_handler = 0; /* void(*)(int)*/ + newact.sa_sigaction = handler; /* void (*)(int, siginfo_t*, void *) */ + + /*sigset_t - signals to block while in the handler */ + /* get the old signal mask. */ + rs = sigprocmask(SIG_SETMASK, 0, &newact.sa_mask); + assert(rs == 0); + + /* call sa_sigaction, not sa_handler*/ + newact.sa_flags = SA_SIGINFO; + + newact.sa_restorer = 0; /* void(*)(), obsolete */ + r = sigaction(signum, &newact, &oldact); + assert(r == 0); +} + +void mpx_prepare(void) +{ + dprintf2("%s()\n", __func__); + setup_handler(); + process_specific_init(); +} + +void mpx_cleanup(void) +{ + printf("%s(): %jd BRs. bye...\n", __func__, num_bnd_chk); + process_specific_finish(); +} + +/*-------------- the following is test case ---------------*/ +#include +#include +#include +#include +#include + +uint64_t num_lower_brs; +uint64_t num_upper_brs; + +#define MPX_CONFIG_OFFSET 1024 +#define MPX_BOUNDS_OFFSET 960 +#define MPX_HEADER_OFFSET 512 +#define MAX_ADDR_TESTED (1<<28) +#define TEST_ROUNDS 100 + +/* + 0F 1A /r BNDLDX-Load + 0F 1B /r BNDSTX-Store Extended Bounds Using Address Translation + 66 0F 1A /r BNDMOV bnd1, bnd2/m128 + 66 0F 1B /r BNDMOV bnd1/m128, bnd2 + F2 0F 1A /r BNDCU bnd, r/m64 + F2 0F 1B /r BNDCN bnd, r/m64 + F3 0F 1A /r BNDCL bnd, r/m64 + F3 0F 1B /r BNDMK bnd, m64 +*/ + +static __always_inline void xsave_state(void *_fx, uint64_t mask) +{ + uint32_t lmask = mask; + uint32_t hmask = mask >> 32; + unsigned char *fx = _fx; + + asm volatile(".byte " REX_PREFIX "0x0f,0xae,0x27\n\t" + : : "D" (fx), "m" (*fx), "a" (lmask), "d" (hmask) + : "memory"); +} + +static __always_inline void mpx_clear_bnd0(void) +{ + long size = 0; + void *ptr = NULL; + /* F3 0F 1B /r BNDMK bnd, m64 */ + /* f3 0f 1b 04 11 bndmk (%rcx,%rdx,1),%bnd0 */ + asm volatile(".byte 0xf3,0x0f,0x1b,0x04,0x11\n\t" + : : "c" (ptr), "d" (size-1) + : "memory"); +} + +static __always_inline void mpx_make_bound_helper(unsigned long ptr, + unsigned long size) +{ + /* F3 0F 1B /r BNDMK bnd, m64 */ + /* f3 0f 1b 04 11 bndmk (%rcx,%rdx,1),%bnd0 */ + asm volatile(".byte 0xf3,0x0f,0x1b,0x04,0x11\n\t" + : : "c" (ptr), "d" (size-1) + : "memory"); +} + +static __always_inline void mpx_check_lowerbound_helper(unsigned long ptr) +{ + /* F3 0F 1A /r NDCL bnd, r/m64 */ + /* f3 0f 1a 01 bndcl (%rcx),%bnd0 */ + asm volatile(".byte 0xf3,0x0f,0x1a,0x01\n\t" + : : "c" (ptr) + : "memory"); +} + +static __always_inline void mpx_check_upperbound_helper(unsigned long ptr) +{ + /* F2 0F 1A /r BNDCU bnd, r/m64 */ + /* f2 0f 1a 01 bndcu (%rcx),%bnd0 */ + asm volatile(".byte 0xf2,0x0f,0x1a,0x01\n\t" + : : "c" (ptr) + : "memory"); +} + +static __always_inline void mpx_movbndreg_helper() +{ + /* 66 0F 1B /r BNDMOV bnd1/m128, bnd2 */ + /* 66 0f 1b c2 bndmov %bnd0,%bnd2 */ + + asm volatile(".byte 0x66,0x0f,0x1b,0xc2\n\t"); +} + +static __always_inline void mpx_movbnd2mem_helper(uint8_t *mem) +{ + /* 66 0F 1B /r BNDMOV bnd1/m128, bnd2 */ + /* 66 0f 1b 01 bndmov %bnd0,(%rcx) */ + asm volatile(".byte 0x66,0x0f,0x1b,0x01\n\t" + : : "c" (mem) + : "memory"); +} + +static __always_inline void mpx_movbnd_from_mem_helper(uint8_t *mem) +{ + /* 66 0F 1A /r BNDMOV bnd1, bnd2/m128 */ + /* 66 0f 1a 01 bndmov (%rcx),%bnd0 */ + asm volatile(".byte 0x66,0x0f,0x1a,0x01\n\t" + : : "c" (mem) + : "memory"); +} + +static __always_inline void mpx_store_dsc_helper(unsigned long ptr_addr, + unsigned long ptr_val) +{ + /* 0F 1B /r BNDSTX-Store Extended Bounds Using Address Translation */ + /* 0f 1b 04 11 bndstx %bnd0,(%rcx,%rdx,1) */ + asm volatile(".byte 0x0f,0x1b,0x04,0x11\n\t" + : : "c" (ptr_addr), "d" (ptr_val) + : "memory"); +} + +static __always_inline void mpx_load_dsc_helper(unsigned long ptr_addr, + unsigned long ptr_val) +{ + /* 0F 1A /r BNDLDX-Load */ + /*/ 0f 1a 04 11 bndldx (%rcx,%rdx,1),%bnd0 */ + asm volatile(".byte 0x0f,0x1a,0x04,0x11\n\t" + : : "c" (ptr_addr), "d" (ptr_val) + : "memory"); +} + +void __print_context(void *__print_xsave_buffer, int line) +{ + uint64_t *bounds = (uint64_t *)(__print_xsave_buffer + MPX_BOUNDS_OFFSET); + uint64_t *cfg = (uint64_t *)(__print_xsave_buffer + MPX_CONFIG_OFFSET); + + int i; + eprintf("%s()::%d\n", "print_context", line); + for (i = 0; i < 4; i++) { + eprintf("bound[%d]: 0x%016lx 0x%016lx(0x%016lx)\n", i, + (unsigned long)bounds[i*2], + ~(unsigned long)bounds[i*2+1], + (unsigned long)bounds[i*2+1]); + } + + eprintf("cpcfg: %jx cpstatus: %jx\n", cfg[0], cfg[1]); +} +#define print_context(x) __print_context(x, __LINE__) +#ifdef DEBUG +#define dprint_context(x) print_context(x) +#else +#define dprint_context(x) do{}while(0) +#endif + +void init() +{ + int i; + + srand((unsigned int)time(NULL)); + + for (i = 0; i < 4; i++) { + shadow_plb[i][0] = 0; + shadow_plb[i][1] = ~(unsigned long)0; + } +} + +long int __mpx_random(int line) +{ +#ifdef NOT_SO_RANDOM + static long fake = 722122311; + fake += 563792075; + return fakse; +#else + return random(); +#endif +} +#define mpx_random() __mpx_random(__LINE__) + +uint8_t *get_random_addr() +{ + uint8_t*addr = (uint8_t *)(unsigned long)(rand() % MAX_ADDR_TESTED); + return (addr - (unsigned long)addr % sizeof(uint8_t *)); +} + +static inline bool compare_context(void *__xsave_buffer) +{ + uint64_t *bounds = (uint64_t *)(__xsave_buffer + MPX_BOUNDS_OFFSET); + + int i; + for (i = 0; i < 4; i++) { + dprintf3("shadow[%d]{%016lx/%016lx}\nbounds[%d]{%016lx/%016lx}\n", + i, (unsigned long)shadow_plb[i][0], (unsigned long)shadow_plb[i][1], + i, (unsigned long)bounds[i*2], ~(unsigned long)bounds[i*2+1]); + if ((shadow_plb[i][0] != bounds[i*2]) || + (shadow_plb[i][1] != ~(unsigned long)bounds[i*2+1])) { + eprintf("ERROR comparing shadow to real bound register %d\n", i); + eprintf("shadow{0x%016lx/0x%016lx}\nbounds{0x%016lx/0x%016lx}\n", + (unsigned long)shadow_plb[i][0], (unsigned long)shadow_plb[i][1], + (unsigned long)bounds[i*2], (unsigned long)bounds[i*2+1]); + return false; + } + } + + return true; +} + +void mkbnd_shadow(uint8_t *ptr, int index, long offset) +{ + uint64_t *lower = (uint64_t *)&(shadow_plb[index][0]); + uint64_t *upper = (uint64_t *)&(shadow_plb[index][1]); + *lower = (unsigned long)ptr; + *upper = (unsigned long)ptr + offset - 1; +} + +void check_lowerbound_shadow(uint8_t *ptr, int index) +{ + uint64_t *lower = (uint64_t *)&(shadow_plb[index][0]); + if (*lower > (uint64_t)(unsigned long)ptr) + num_lower_brs++; + else + dprintf1("LowerBoundChk passed:%p\n", ptr); +} + +void check_upperbound_shadow(uint8_t *ptr, int index) +{ + uint64_t upper = *(uint64_t *)&(shadow_plb[index][1]); + if (upper < (uint64_t)(unsigned long)ptr) + num_upper_brs++; + else + dprintf1("UpperBoundChk passed:%p\n", ptr); +} + +__always_inline void movbndreg_shadow(int src, int dest) +{ + shadow_plb[dest][0] = shadow_plb[src][0]; + shadow_plb[dest][1] = shadow_plb[src][1]; +} + +__always_inline void movbnd2mem_shadow(int src, unsigned long *dest) +{ + unsigned long *lower = (unsigned long *)&(shadow_plb[src][0]); + unsigned long *upper = (unsigned long *)&(shadow_plb[src][1]); + *dest = *lower; + *(dest+1) = *upper; +} + +__always_inline void movbnd_from_mem_shadow(unsigned long *src, int dest) +{ + unsigned long *lower = (unsigned long *)&(shadow_plb[dest][0]); + unsigned long *upper = (unsigned long *)&(shadow_plb[dest][1]); + *lower = *src; + *upper = *(src+1); +} + +__always_inline void stdsc_shadow(int index, uint8_t *ptr, uint8_t *ptr_val) +{ + shadow_map[0] = (unsigned long)shadow_plb[index][0]; + shadow_map[1] = (unsigned long)shadow_plb[index][1]; + shadow_map[2] = (unsigned long)ptr_val; + dprintf3("%s(%d, %p, %p) set shadow map[2]: %p\n", __func__, + index, ptr, ptr_val, ptr_val); + /*ptr ignored */ +} + +void lddsc_shadow(int index, uint8_t *ptr, uint8_t *ptr_val) +{ + uint64_t lower = shadow_map[0]; + uint64_t upper = shadow_map[1]; + uint8_t *value = (uint8_t *)shadow_map[2]; + + if (value != ptr_val) { + dprintf2("%s(%d, %p, %p) init shadow bounds[%d] " + "because %p != %p\n", __func__, index, ptr, + ptr_val, index, value, ptr_val); + shadow_plb[index][0] = 0; + shadow_plb[index][1] = ~(unsigned long)0; + } else { + shadow_plb[index][0] = lower; + shadow_plb[index][1] = upper; + } + /* ptr ignored */ +} + +static __always_inline void mpx_test_helper0(uint8_t *buf, uint8_t *ptr) +{ + mpx_make_bound_helper((unsigned long)ptr, 0x1800); +} + +static __always_inline void mpx_test_helper0_shadow(uint8_t *buf, uint8_t *ptr) +{ + mkbnd_shadow(ptr, 0, 0x1800); +} + +static __always_inline void mpx_test_helper1(uint8_t *buf, uint8_t *ptr) +{ + /* these are hard-coded to check bnd0 */ + expected_bnd_index = 0; + mpx_check_lowerbound_helper((unsigned long)(ptr-1)); + mpx_check_upperbound_helper((unsigned long)(ptr+0x1800)); + /* reset this since we do not expect any more bounds exceptions */ + expected_bnd_index = -1; +} + +static __always_inline void mpx_test_helper1_shadow(uint8_t *buf, uint8_t *ptr) +{ + check_lowerbound_shadow(ptr-1, 0); + check_upperbound_shadow(ptr+0x1800, 0); +} + +static __always_inline void mpx_test_helper2(uint8_t *buf, uint8_t *ptr) +{ + mpx_make_bound_helper((unsigned long)ptr, 0x1800); + mpx_movbndreg_helper(); + mpx_movbnd2mem_helper(buf); + mpx_make_bound_helper((unsigned long)(ptr+0x12), 0x1800); +} + +static __always_inline void mpx_test_helper2_shadow(uint8_t *buf, uint8_t *ptr) +{ + mkbnd_shadow(ptr, 0, 0x1800); + movbndreg_shadow(0, 2); + movbnd2mem_shadow(0, (unsigned long *)buf); + mkbnd_shadow(ptr+0x12, 0, 0x1800); +} + +static __always_inline void mpx_test_helper3(uint8_t *buf, uint8_t *ptr) +{ + mpx_movbnd_from_mem_helper(buf); +} + +static __always_inline void mpx_test_helper3_shadow(uint8_t *buf, uint8_t *ptr) +{ + movbnd_from_mem_shadow((unsigned long *)buf, 0); +} + +static __always_inline void mpx_test_helper4(uint8_t *buf, uint8_t *ptr) +{ + mpx_store_dsc_helper((unsigned long)buf, (unsigned long)ptr); + mpx_make_bound_helper((unsigned long)(ptr+0x12), 0x1800); +} + +static __always_inline void mpx_test_helper4_shadow(uint8_t *buf, uint8_t *ptr) +{ + stdsc_shadow(0, buf, ptr); + mkbnd_shadow(ptr+0x12, 0, 0x1800); +} + +static __always_inline void mpx_test_helper5(uint8_t *buf, uint8_t *ptr) +{ + mpx_load_dsc_helper((unsigned long)buf, (unsigned long)ptr); +} + +static __always_inline void mpx_test_helper5_shadow(uint8_t *buf, uint8_t *ptr) +{ + lddsc_shadow(0, buf, ptr); +} + +#define NR_MPX_TEST_FUNCTIONS 6 + +/* + * For compatibility reasons, MPX will clear the bounds registers + * when you make function calls (among other things). We have to + * preserve the registers in between calls to the "helpers" since + * they build on each other. + * + * Be very careful not to make any function calls inside the + * helpers, or anywhere else beween the xrstor and xsave. + */ +#define run_helper(helper_nr, buf, buf_shadow, ptr) do { \ + xrstor_state(xsave_test_buf, flags); \ + mpx_test_helper##helper_nr(buf, ptr); \ + xsave_state(xsave_test_buf, flags); \ + mpx_test_helper##helper_nr##_shadow(buf_shadow, ptr); \ +} while (0) + +static void run_helpers(int nr, uint8_t *buf, uint8_t *buf_shadow, uint8_t *ptr) +{ + uint64_t flags = 0x18; + + dprint_context(xsave_test_buf); + switch (nr) { + case 0: + run_helper(0, buf, buf_shadow, ptr); + break; + case 1: + run_helper(1, buf, buf_shadow, ptr); + break; + case 2: + run_helper(2, buf, buf_shadow, ptr); + break; + case 3: + run_helper(3, buf, buf_shadow, ptr); + break; + case 4: + run_helper(4, buf, buf_shadow, ptr); + break; + case 5: + run_helper(5, buf, buf_shadow, ptr); + break; + default: + test_failed(); + break; + } + dprint_context(xsave_test_buf); +} + +unsigned long buf_shadow[1024]; /* used to check load / store descriptors */ +extern long inspect_me(struct mpx_bounds_dir *bounds_dir); + +long cover_buf_with_bt_entries(void *buf, long buf_len) +{ + int i; + long nr_to_fill; + int ratio = 1000; + unsigned long buf_len_in_ptrs; + + /* Fill about 1/100 of the space with bt entries */ + nr_to_fill = buf_len / (sizeof(unsigned long) * ratio); + + if (!nr_to_fill) + dprintf3("%s() nr_to_fill: %ld\n", __func__, nr_to_fill); + + /* Align the buffer to pointer size */ + while (((unsigned long)buf) % sizeof(void *)) { + buf++; + buf_len--; + } + /* We are storing pointers, so make */ + buf_len_in_ptrs = buf_len / sizeof(void *); + + for (i = 0; i < nr_to_fill; i++) { + long index = (mpx_random() % buf_len_in_ptrs); + void *ptr = buf + index * sizeof(unsigned long); + unsigned long ptr_addr = (unsigned long)ptr; + + /* ptr and size can be anything */ + mpx_make_bound_helper((unsigned long)ptr, 8); + + /* + * take bnd0 and put it in to bounds tables "buf + index" is an + * address inside the buffer where we are pretending that we + * are going to put a pointer We do not, though because we will + * never load entries from the table, so it doesn't matter. + */ + mpx_store_dsc_helper(ptr_addr, (unsigned long)ptr); + dprintf4("storing bound table entry for %lx (buf start @ %p)\n", + ptr_addr, buf); + } + return nr_to_fill; +} + +unsigned long align_down(unsigned long alignme, unsigned long align_to) +{ + return alignme & ~(align_to-1); +} + +unsigned long align_up(unsigned long alignme, unsigned long align_to) +{ + return (alignme + align_to - 1) & ~(align_to-1); +} + +/* + * Using 1MB alignment guarantees that each no allocation + * will overlap with another's bounds tables. + * + * We have to cook our own allocator here. malloc() can + * mix other allocation with ours which means that even + * if we free all of our allocations, there might still + * be bounds tables for the *areas* since there is other + * valid memory there. + * + * We also can't use malloc() because a free() of an area + * might not free it back to the kernel. We want it + * completely unmapped an malloc() does not guarantee + * that. + */ +#ifdef __i386__ +long alignment = 4096; +long sz_alignment = 4096; +#else +long alignment = 1 * MB; +long sz_alignment = 1 * MB; +#endif +void *mpx_mini_alloc(unsigned long sz) +{ + unsigned long long tries = 0; + static void *last; + void *ptr; + void *try_at; + + sz = align_up(sz, sz_alignment); + + try_at = last + alignment; + while (1) { + ptr = mmap(try_at, sz, PROT_READ|PROT_WRITE, + MAP_ANONYMOUS|MAP_PRIVATE, -1, 0); + if (ptr == (void *)-1) + return NULL; + if (ptr == try_at) + break; + + munmap(ptr, sz); + try_at += alignment; +#ifdef __i386__ + /* + * This isn't quite correct for 32-bit binaries + * on 64-bit kernels since they can use the + * entire 32-bit address space, but it's close + * enough. + */ + if (try_at > (void *)0xC0000000) +#else + if (try_at > (void *)0x0000800000000000) +#endif + try_at = (void *)0x0; + if (!(++tries % 10000)) + dprintf1("stuck in %s(), tries: %lld\n", __func__, tries); + continue; + } + last = ptr; + dprintf3("mpx_mini_alloc(0x%lx) returning: %p\n", sz, ptr); + return ptr; +} +void mpx_mini_free(void *ptr, long sz) +{ + dprintf2("%s() ptr: %p\n", __func__, ptr); + if ((unsigned long)ptr > 0x100000000000) { + dprintf1("uh oh !!!!!!!!!!!!!!! pointer too high: %p\n", ptr); + test_failed(); + } + sz = align_up(sz, sz_alignment); + dprintf3("%s() ptr: %p before munmap\n", __func__, ptr); + munmap(ptr, sz); + dprintf3("%s() ptr: %p DONE\n", __func__, ptr); +} + +#define NR_MALLOCS 100 +struct one_malloc { + char *ptr; + int nr_filled_btes; + unsigned long size; +}; +struct one_malloc mallocs[NR_MALLOCS]; + +void free_one_malloc(int index) +{ + unsigned long free_ptr; + unsigned long mask; + + if (!mallocs[index].ptr) + return; + + mpx_mini_free(mallocs[index].ptr, mallocs[index].size); + dprintf4("freed[%d]: %p\n", index, mallocs[index].ptr); + + free_ptr = (unsigned long)mallocs[index].ptr; + mask = alignment-1; + dprintf4("lowerbits: %lx / %lx mask: %lx\n", free_ptr, + (free_ptr & mask), mask); + assert((free_ptr & mask) == 0); + + mallocs[index].ptr = NULL; +} + +#ifdef __i386__ +#define MPX_BOUNDS_TABLE_COVERS 4096 +#else +#define MPX_BOUNDS_TABLE_COVERS (1 * MB) +#endif +void zap_everything(void) +{ + long after_zap; + long before_zap; + int i; + + before_zap = inspect_me(bounds_dir_ptr); + dprintf1("zapping everything start: %ld\n", before_zap); + for (i = 0; i < NR_MALLOCS; i++) + free_one_malloc(i); + + after_zap = inspect_me(bounds_dir_ptr); + dprintf1("zapping everything done: %ld\n", after_zap); + /* + * We only guarantee to empty the thing out if our allocations are + * exactly aligned on the boundaries of a boudns table. + */ + if ((alignment >= MPX_BOUNDS_TABLE_COVERS) && + (sz_alignment >= MPX_BOUNDS_TABLE_COVERS)) { + if (after_zap != 0) + test_failed(); + + assert(after_zap == 0); + } +} + +void do_one_malloc(void) +{ + static int malloc_counter; + long sz; + int rand_index = (mpx_random() % NR_MALLOCS); + void *ptr = mallocs[rand_index].ptr; + + dprintf3("%s() enter\n", __func__); + + if (ptr) { + dprintf3("freeing one malloc at index: %d\n", rand_index); + free_one_malloc(rand_index); + if (mpx_random() % (NR_MALLOCS*3) == 3) { + int i; + dprintf3("zapping some more\n"); + for (i = rand_index; i < NR_MALLOCS; i++) + free_one_malloc(i); + } + if ((mpx_random() % zap_all_every_this_many_mallocs) == 4) + zap_everything(); + } + + /* 1->~1M */ + sz = (1 + mpx_random() % 1000) * 1000; + ptr = mpx_mini_alloc(sz); + if (!ptr) { + /* + * If we are failing allocations, just assume we + * are out of memory and zap everything. + */ + dprintf3("zapping everything because out of memory\n"); + zap_everything(); + goto out; + } + + dprintf3("malloc: %p size: 0x%lx\n", ptr, sz); + mallocs[rand_index].nr_filled_btes = cover_buf_with_bt_entries(ptr, sz); + mallocs[rand_index].ptr = ptr; + mallocs[rand_index].size = sz; +out: + if ((++malloc_counter) % inspect_every_this_many_mallocs == 0) + inspect_me(bounds_dir_ptr); +} + +void run_timed_test(void (*test_func)(void)) +{ + int done = 0; + long iteration = 0; + static time_t last_print; + time_t now; + time_t start; + + time(&start); + while (!done) { + time(&now); + if ((now - start) > TEST_DURATION_SECS) + done = 1; + + test_func(); + iteration++; + + if ((now - last_print > 1) || done) { + printf("iteration %ld complete, OK so far\n", iteration); + last_print = now; + } + } +} + +void check_bounds_table_frees(void) +{ + printf("executing unmaptest\n"); + inspect_me(bounds_dir_ptr); + run_timed_test(&do_one_malloc); + printf("done with malloc() fun\n"); +} + +void insn_test_failed(int test_nr, int test_round, void *buf, + void *buf_shadow, void *ptr) +{ + print_context(xsave_test_buf); + eprintf("ERROR: test %d round %d failed\n", test_nr, test_round); + while (test_nr == 5) { + struct mpx_bt_entry *bte; + struct mpx_bounds_dir *bd = (void *)bounds_dir_ptr; + struct mpx_bd_entry *bde = mpx_vaddr_to_bd_entry(buf, bd); + + printf(" bd: %p\n", bd); + printf("&bde: %p\n", bde); + printf("*bde: %lx\n", *(unsigned long *)bde); + if (!bd_entry_valid(bde)) + break; + + bte = mpx_vaddr_to_bt_entry(buf, bd); + printf(" te: %p\n", bte); + printf("bte[0]: %lx\n", bte->contents[0]); + printf("bte[1]: %lx\n", bte->contents[1]); + printf("bte[2]: %lx\n", bte->contents[2]); + printf("bte[3]: %lx\n", bte->contents[3]); + break; + } + test_failed(); +} + +void check_mpx_insns_and_tables(void) +{ + int successes = 0; + int failures = 0; + int buf_size = (1024*1024); + unsigned long *buf = malloc(buf_size); + const int total_nr_tests = NR_MPX_TEST_FUNCTIONS * TEST_ROUNDS; + int i, j; + + memset(buf, 0, buf_size); + memset(buf_shadow, 0, sizeof(buf_shadow)); + + for (i = 0; i < TEST_ROUNDS; i++) { + uint8_t *ptr = get_random_addr() + 8; + + for (j = 0; j < NR_MPX_TEST_FUNCTIONS; j++) { + if (0 && j != 5) { + successes++; + continue; + } + dprintf2("starting test %d round %d\n", j, i); + dprint_context(xsave_test_buf); + /* + * test5 loads an address from the bounds tables. + * The load will only complete if 'ptr' matches + * the load and the store, so with random addrs, + * the odds of this are very small. Make it + * higher by only moving 'ptr' 1/10 times. + */ + if (random() % 10 <= 0) + ptr = get_random_addr() + 8; + dprintf3("random ptr{%p}\n", ptr); + dprint_context(xsave_test_buf); + run_helpers(j, (void *)buf, (void *)buf_shadow, ptr); + dprint_context(xsave_test_buf); + if (!compare_context(xsave_test_buf)) { + insn_test_failed(j, i, buf, buf_shadow, ptr); + failures++; + goto exit; + } + successes++; + dprint_context(xsave_test_buf); + dprintf2("finished test %d round %d\n", j, i); + dprintf3("\n"); + dprint_context(xsave_test_buf); + } + } + +exit: + dprintf2("\nabout to free:\n"); + free(buf); + dprintf1("successes: %d\n", successes); + dprintf1(" failures: %d\n", failures); + dprintf1(" tests: %d\n", total_nr_tests); + dprintf1(" expected: %jd #BRs\n", num_upper_brs + num_lower_brs); + dprintf1(" saw: %d #BRs\n", br_count); + if (failures) { + eprintf("ERROR: non-zero number of failures\n"); + exit(20); + } + if (successes != total_nr_tests) { + eprintf("ERROR: succeded fewer than number of tries (%d != %d)\n", + successes, total_nr_tests); + exit(21); + } + if (num_upper_brs + num_lower_brs != br_count) { + eprintf("ERROR: unexpected number of #BRs: %jd %jd %d\n", + num_upper_brs, num_lower_brs, br_count); + eprintf("successes: %d\n", successes); + eprintf(" failures: %d\n", failures); + eprintf(" tests: %d\n", total_nr_tests); + eprintf(" expected: %jd #BRs\n", num_upper_brs + num_lower_brs); + eprintf(" saw: %d #BRs\n", br_count); + exit(22); + } +} + +/* + * This is supposed to SIGSEGV nicely once the kernel + * can no longer allocate vaddr space. + */ +void exhaust_vaddr_space(void) +{ + unsigned long ptr; + /* Try to make sure there is no room for a bounds table anywhere */ + unsigned long skip = MPX_BOUNDS_TABLE_SIZE_BYTES - PAGE_SIZE; +#ifdef __i386__ + unsigned long max_vaddr = 0xf7788000UL; +#else + unsigned long max_vaddr = 0x800000000000UL; +#endif + + dprintf1("%s() start\n", __func__); + /* do not start at 0, we aren't allowed to map there */ + for (ptr = PAGE_SIZE; ptr < max_vaddr; ptr += skip) { + void *ptr_ret; + int ret = madvise((void *)ptr, PAGE_SIZE, MADV_NORMAL); + + if (!ret) { + dprintf1("madvise() %lx ret: %d\n", ptr, ret); + continue; + } + ptr_ret = mmap((void *)ptr, PAGE_SIZE, PROT_READ|PROT_WRITE, + MAP_ANONYMOUS|MAP_PRIVATE, -1, 0); + if (ptr_ret != (void *)ptr) { + perror("mmap"); + dprintf1("mmap(%lx) ret: %p\n", ptr, ptr_ret); + break; + } + if (!(ptr & 0xffffff)) + dprintf1("mmap(%lx) ret: %p\n", ptr, ptr_ret); + } + for (ptr = PAGE_SIZE; ptr < max_vaddr; ptr += skip) { + dprintf2("covering 0x%lx with bounds table entries\n", ptr); + cover_buf_with_bt_entries((void *)ptr, PAGE_SIZE); + } + dprintf1("%s() end\n", __func__); + printf("done with vaddr space fun\n"); +} + +void mpx_table_test(void) +{ + printf("starting mpx bounds table test\n"); + run_timed_test(check_mpx_insns_and_tables); + printf("done with mpx bounds table test\n"); +} + +int main(int argc, char **argv) +{ + int unmaptest = 0; + int vaddrexhaust = 0; + int tabletest = 0; + int i; + + check_mpx_support(); + mpx_prepare(); + srandom(11179); + + bd_incore(); + init(); + bd_incore(); + + trace_me(); + + xsave_state((void *)xsave_test_buf, 0x1f); + if (!compare_context(xsave_test_buf)) + printf("Init failed\n"); + + for (i = 1; i < argc; i++) { + if (!strcmp(argv[i], "unmaptest")) + unmaptest = 1; + if (!strcmp(argv[i], "vaddrexhaust")) + vaddrexhaust = 1; + if (!strcmp(argv[i], "tabletest")) + tabletest = 1; + } + if (!(unmaptest || vaddrexhaust || tabletest)) { + unmaptest = 1; + /* vaddrexhaust = 1; */ + tabletest = 1; + } + if (unmaptest) + check_bounds_table_frees(); + if (tabletest) + mpx_table_test(); + if (vaddrexhaust) + exhaust_vaddr_space(); + printf("%s completed successfully\n", argv[0]); + exit(0); +} + +#include "mpx-dig.c" diff --git a/tools/testing/selftests/x86/mpx-mm.h b/tools/testing/selftests/x86/mpx-mm.h new file mode 100644 index 0000000..af706a5 --- /dev/null +++ b/tools/testing/selftests/x86/mpx-mm.h @@ -0,0 +1,9 @@ +#ifndef _MPX_MM_H +#define _MPX_MM_H + +#define PAGE_SIZE 4096 +#define MB (1UL<<20) + +extern long nr_incore(void *ptr, unsigned long size_bytes); + +#endif /* _MPX_MM_H */ -- cgit v0.10.2 From bb27570525a71f48347ed0e0c265063e7952bb61 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 13 Jun 2016 21:28:00 +0300 Subject: x86/platform/intel_mid_pci: Rework IRQ0 workaround On Intel Merrifield platform several PCI devices have a bogus configuration, i.e. the IRQ0 had been assigned to few of them. These are PCI root bridge, eMMC0, HS UART common registers, PWM, and HDMI. The actual interrupt line can be allocated to one device exclusively, in our case to eMMC0, the rest should cope without it and basically known drivers for them are not using interrupt line at all. Rework IRQ0 workaround, which was previously done to avoid conflict between eMMC0 and HS UART common registers, to behave differently based on the device in question, i.e. allocate interrupt line to eMMC0, but silently skip interrupt allocation for the rest except HS UART common registers which are not used anyway. With this rework IOSF MBI driver in particular would be used. Signed-off-by: Andy Shevchenko Acked-by: Thomas Gleixner Cc: Bjorn Helgaas Cc: Linus Torvalds Cc: Peter Zijlstra Fixes: 39d9b77b8deb ("x86/pci/intel_mid_pci: Work around for IRQ0 assignment") Link: http://lkml.kernel.org/r/1465842481-136852-1-git-send-email-andriy.shevchenko@linux.intel.com Signed-off-by: Ingo Molnar diff --git a/arch/x86/pci/intel_mid_pci.c b/arch/x86/pci/intel_mid_pci.c index 8b93e63..ae97f24 100644 --- a/arch/x86/pci/intel_mid_pci.c +++ b/arch/x86/pci/intel_mid_pci.c @@ -37,6 +37,7 @@ /* Quirks for the listed devices */ #define PCI_DEVICE_ID_INTEL_MRFL_MMC 0x1190 +#define PCI_DEVICE_ID_INTEL_MRFL_HSU 0x1191 /* Fixed BAR fields */ #define PCIE_VNDR_CAP_ID_FIXED_BAR 0x00 /* Fixed BAR (TBD) */ @@ -225,13 +226,20 @@ static int intel_mid_pci_irq_enable(struct pci_dev *dev) /* Special treatment for IRQ0 */ if (dev->irq == 0) { /* + * Skip HS UART common registers device since it has + * IRQ0 assigned and not used by the kernel. + */ + if (dev->device == PCI_DEVICE_ID_INTEL_MRFL_HSU) + return -EBUSY; + /* * TNG has IRQ0 assigned to eMMC controller. But there * are also other devices with bogus PCI configuration * that have IRQ0 assigned. This check ensures that - * eMMC gets it. + * eMMC gets it. The rest of devices still could be + * enabled without interrupt line being allocated. */ if (dev->device != PCI_DEVICE_ID_INTEL_MRFL_MMC) - return -EBUSY; + return 0; } break; default: -- cgit v0.10.2 From 9485f8b6a75921e1b9e94b001cdb45872a598534 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 13 Jun 2016 21:28:01 +0300 Subject: x86/platform/atom/punit: Enable support for Merrifield Intel Merrifield platform has Punit generation that somehow compatible to what is already supported by punit_atom_debug driver. Add necessary bits to enable that support. Signed-off-by: Andy Shevchenko Acked-by: Thomas Gleixner Cc: Bjorn Helgaas Cc: Linus Torvalds Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1465842481-136852-2-git-send-email-andriy.shevchenko@linux.intel.com Signed-off-by: Ingo Molnar diff --git a/arch/x86/platform/atom/punit_atom_debug.c b/arch/x86/platform/atom/punit_atom_debug.c index 1097829..8ff7b93 100644 --- a/arch/x86/platform/atom/punit_atom_debug.c +++ b/arch/x86/platform/atom/punit_atom_debug.c @@ -26,8 +26,6 @@ #include #include -/* Power gate status reg */ -#define PWRGT_STATUS 0x61 /* Subsystem config/status Video processor */ #define VED_SS_PM0 0x32 /* Subsystem config/status ISP (Image Signal Processor) */ @@ -36,12 +34,16 @@ #define MIO_SS_PM 0x3B /* Shift bits for getting status for video, isp and i/o */ #define SSS_SHIFT 24 + +/* Power gate status reg */ +#define PWRGT_STATUS 0x61 /* Shift bits for getting status for graphics rendering */ #define RENDER_POS 0 /* Shift bits for getting status for media control */ #define MEDIA_POS 2 /* Shift bits for getting status for Valley View/Baytrail display */ #define VLV_DISPLAY_POS 6 + /* Subsystem config/status display for Cherry Trail SOC */ #define CHT_DSP_SSS 0x36 /* Shift bits for getting status for display */ @@ -53,6 +55,14 @@ struct punit_device { int sss_pos; }; +static const struct punit_device punit_device_tng[] = { + { "DISPLAY", CHT_DSP_SSS, SSS_SHIFT }, + { "VED", VED_SS_PM0, SSS_SHIFT }, + { "ISP", ISP_SS_PM0, SSS_SHIFT }, + { "MIO", MIO_SS_PM, SSS_SHIFT }, + { NULL } +}; + static const struct punit_device punit_device_byt[] = { { "GFX RENDER", PWRGT_STATUS, RENDER_POS }, { "GFX MEDIA", PWRGT_STATUS, MEDIA_POS }, @@ -145,6 +155,7 @@ static void punit_dbgfs_unregister(void) static const struct x86_cpu_id intel_punit_cpu_ids[] = { ICPU(INTEL_FAM6_ATOM_SILVERMONT1, punit_device_byt), + ICPU(INTEL_FAM6_ATOM_MERRIFIELD1, punit_device_tng), ICPU(INTEL_FAM6_ATOM_AIRMONT, punit_device_cht), {} }; -- cgit v0.10.2 From 826424cc919529d6d234af12c6ba975b63528a74 Mon Sep 17 00:00:00 2001 From: Taeung Song Date: Wed, 8 Jun 2016 21:36:49 +0900 Subject: perf config: Handle NULL at perf_config_set__delete() perf_config_set__delete() purge and free the config set that contains all config key-value pairs. But if the config set (i.e. 'set' variable at the function) is NULL, this is wrong so handle it. Signed-off-by: Taeung Song Cc: Alexander Shishkin Cc: Jiri Olsa Cc: Masami Hiramatsu Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Wang Nan Link: http://lkml.kernel.org/r/1465389413-8936-2-git-send-email-treeze.taeung@gmail.com Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/util/config.c b/tools/perf/util/config.c index 8749eca..31e09a4 100644 --- a/tools/perf/util/config.c +++ b/tools/perf/util/config.c @@ -742,6 +742,9 @@ static void perf_config_set__purge(struct perf_config_set *set) void perf_config_set__delete(struct perf_config_set *set) { + if (set == NULL) + return; + perf_config_set__purge(set); free(set); } -- cgit v0.10.2 From 2a1ef032cfccd8c92f32b86615a0b0151a7cd86f Mon Sep 17 00:00:00 2001 From: Masami Hiramatsu Date: Wed, 8 Jun 2016 18:29:11 +0900 Subject: perf tools: Fix rm_rf() to handle non-regular files correctly Fix rm_rf() to handle non-regular files correctly. This fix includes two changes; - Fix to use lstat(3) instead of stat(3) since if the target file is a symbolic link, rm_rf() should unlink the symbolic link itself, not the file which pointed by the symlink. - Fix to unlink non-regular files (except for directory), including symlink. Even though the first one fixes to stat symlink itself, without second fix, it still failed because the symlink is not a regular file. Signed-off-by: Masami Hiramatsu Cc: Ananth N Mavinakayanahalli Cc: Brendan Gregg Cc: Hemant Kumar Cc: Namhyung Kim Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/20160608092911.3116.90929.stgit@devbox Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/util/util.c b/tools/perf/util/util.c index 23504ad..e08b9a0 100644 --- a/tools/perf/util/util.c +++ b/tools/perf/util/util.c @@ -97,20 +97,17 @@ int rm_rf(char *path) scnprintf(namebuf, sizeof(namebuf), "%s/%s", path, d->d_name); - ret = stat(namebuf, &statbuf); + /* We have to check symbolic link itself */ + ret = lstat(namebuf, &statbuf); if (ret < 0) { pr_debug("stat failed: %s\n", namebuf); break; } - if (S_ISREG(statbuf.st_mode)) - ret = unlink(namebuf); - else if (S_ISDIR(statbuf.st_mode)) + if (S_ISDIR(statbuf.st_mode)) ret = rm_rf(namebuf); - else { - pr_debug("unknown file: %s\n", namebuf); - ret = -1; - } + else + ret = unlink(namebuf); } closedir(dir); -- cgit v0.10.2 From 844faa4bcddc5d321311003ea3af9d808371c48e Mon Sep 17 00:00:00 2001 From: Masami Hiramatsu Date: Wed, 8 Jun 2016 18:29:21 +0900 Subject: perf probe: Fix to add NULL check for strndup Fix to add a NULL check for strndup when parsing probe trace command. Signed-off-by: Masami Hiramatsu Cc: Ananth N Mavinakayanahalli Cc: Brendan Gregg Cc: Hemant Kumar Cc: Namhyung Kim Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/20160608092920.3116.63319.stgit@devbox Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c index 74401a2..7ae3dd1 100644 --- a/tools/perf/util/probe-event.c +++ b/tools/perf/util/probe-event.c @@ -1603,6 +1603,10 @@ int parse_probe_trace_command(const char *cmd, struct probe_trace_event *tev) p = strchr(argv[1], ':'); if (p) { tp->module = strndup(argv[1], p - argv[1]); + if (!tp->module) { + ret = -ENOMEM; + goto out; + } p++; } else p = argv[1]; -- cgit v0.10.2 From 4698b8b7572ff74d9d17fdb02d5957b7148c64fe Mon Sep 17 00:00:00 2001 From: Masami Hiramatsu Date: Wed, 8 Jun 2016 18:29:30 +0900 Subject: perf buildid: Rename and export build_id_cache__cachedir() Rename and export build_id_cache__cachedir() for retrieving use of the path of cache directory for given build_id. Signed-off-by: Masami Hiramatsu Cc: Ananth N Mavinakayanahalli Cc: Brendan Gregg Cc: Hemant Kumar Cc: Namhyung Kim Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/20160608092930.3116.67575.stgit@devbox Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/util/build-id.c b/tools/perf/util/build-id.c index 20aef90..62b1473 100644 --- a/tools/perf/util/build-id.c +++ b/tools/perf/util/build-id.c @@ -387,9 +387,8 @@ void disable_buildid_cache(void) no_buildid_cache = true; } -static char *build_id_cache__dirname_from_path(const char *name, - bool is_kallsyms, bool is_vdso, - const char *sbuild_id) +char *build_id_cache__cachedir(const char *sbuild_id, const char *name, + bool is_kallsyms, bool is_vdso) { char *realname = (char *)name, *filename; bool slash = is_kallsyms || is_vdso; @@ -417,8 +416,7 @@ int build_id_cache__list_build_ids(const char *pathname, char *dir_name; int ret = 0; - dir_name = build_id_cache__dirname_from_path(pathname, false, false, - NULL); + dir_name = build_id_cache__cachedir(NULL, pathname, false, false); if (!dir_name) return -ENOMEM; @@ -444,8 +442,8 @@ int build_id_cache__add_s(const char *sbuild_id, const char *name, goto out_free; } - dir_name = build_id_cache__dirname_from_path(name, is_kallsyms, - is_vdso, sbuild_id); + dir_name = build_id_cache__cachedir(sbuild_id, name, + is_kallsyms, is_vdso); if (!dir_name) goto out_free; diff --git a/tools/perf/util/build-id.h b/tools/perf/util/build-id.h index e5435f4..d8c7f2f 100644 --- a/tools/perf/util/build-id.h +++ b/tools/perf/util/build-id.h @@ -30,6 +30,8 @@ bool perf_session__read_build_ids(struct perf_session *session, bool with_hits); int perf_session__write_buildid_table(struct perf_session *session, int fd); int perf_session__cache_build_ids(struct perf_session *session); +char *build_id_cache__cachedir(const char *sbuild_id, const char *name, + bool is_kallsyms, bool is_vdso); int build_id_cache__list_build_ids(const char *pathname, struct strlist **result); bool build_id_cache__cached(const char *sbuild_id); -- cgit v0.10.2 From 0542bb9c8da51faa8d8703c394c32e334ac4e9d6 Mon Sep 17 00:00:00 2001 From: Masami Hiramatsu Date: Wed, 8 Jun 2016 18:29:40 +0900 Subject: perf probe: Add perf_probe_event__copy() Add perf_probe_event__copy() to copy perf_probe_event data structure and sub data structures under given source perf_probe_event. Signed-off-by: Masami Hiramatsu Cc: Ananth N Mavinakayanahalli Cc: Brendan Gregg Cc: Hemant Kumar Cc: Namhyung Kim Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/20160608092940.3116.18034.stgit@devbox Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c index 7ae3dd1..84f4b2b3 100644 --- a/tools/perf/util/probe-event.c +++ b/tools/perf/util/probe-event.c @@ -2030,6 +2030,79 @@ void clear_perf_probe_event(struct perf_probe_event *pev) memset(pev, 0, sizeof(*pev)); } +#define strdup_or_goto(str, label) \ +({ char *__p = NULL; if (str && !(__p = strdup(str))) goto label; __p; }) + +static int perf_probe_point__copy(struct perf_probe_point *dst, + struct perf_probe_point *src) +{ + dst->file = strdup_or_goto(src->file, out_err); + dst->function = strdup_or_goto(src->function, out_err); + dst->lazy_line = strdup_or_goto(src->lazy_line, out_err); + dst->line = src->line; + dst->retprobe = src->retprobe; + dst->offset = src->offset; + return 0; + +out_err: + clear_perf_probe_point(dst); + return -ENOMEM; +} + +static int perf_probe_arg__copy(struct perf_probe_arg *dst, + struct perf_probe_arg *src) +{ + struct perf_probe_arg_field *field, **ppfield; + + dst->name = strdup_or_goto(src->name, out_err); + dst->var = strdup_or_goto(src->var, out_err); + dst->type = strdup_or_goto(src->type, out_err); + + field = src->field; + ppfield = &(dst->field); + while (field) { + *ppfield = zalloc(sizeof(*field)); + if (!*ppfield) + goto out_err; + (*ppfield)->name = strdup_or_goto(field->name, out_err); + (*ppfield)->index = field->index; + (*ppfield)->ref = field->ref; + field = field->next; + ppfield = &((*ppfield)->next); + } + return 0; +out_err: + return -ENOMEM; +} + +int perf_probe_event__copy(struct perf_probe_event *dst, + struct perf_probe_event *src) +{ + int i; + + dst->event = strdup_or_goto(src->event, out_err); + dst->group = strdup_or_goto(src->group, out_err); + dst->target = strdup_or_goto(src->target, out_err); + dst->uprobes = src->uprobes; + + if (perf_probe_point__copy(&dst->point, &src->point) < 0) + goto out_err; + + dst->args = zalloc(sizeof(struct perf_probe_arg) * src->nargs); + if (!dst->args) + goto out_err; + dst->nargs = src->nargs; + + for (i = 0; i < src->nargs; i++) + if (perf_probe_arg__copy(&dst->args[i], &src->args[i]) < 0) + goto out_err; + return 0; + +out_err: + clear_perf_probe_event(dst); + return -ENOMEM; +} + void clear_probe_trace_event(struct probe_trace_event *tev) { struct probe_trace_arg_ref *ref, *next; @@ -2505,9 +2578,6 @@ static int find_probe_functions(struct map *map, char *name, return found; } -#define strdup_or_goto(str, label) \ - ({ char *__p = strdup(str); if (!__p) goto label; __p; }) - void __weak arch__fix_tev_from_maps(struct perf_probe_event *pev __maybe_unused, struct probe_trace_event *tev __maybe_unused, struct map *map __maybe_unused, diff --git a/tools/perf/util/probe-event.h b/tools/perf/util/probe-event.h index 5a27eb4..367f886 100644 --- a/tools/perf/util/probe-event.h +++ b/tools/perf/util/probe-event.h @@ -122,6 +122,9 @@ char *synthesize_perf_probe_command(struct perf_probe_event *pev); char *synthesize_probe_trace_command(struct probe_trace_event *tev); char *synthesize_perf_probe_arg(struct perf_probe_arg *pa); +int perf_probe_event__copy(struct perf_probe_event *dst, + struct perf_probe_event *src); + /* Check the perf_probe_event needs debuginfo */ bool perf_probe_event_need_dwarf(struct perf_probe_event *pev); -- cgit v0.10.2 From c4ff49209bcdc1ef709773f4833a341ac49a26cc Mon Sep 17 00:00:00 2001 From: Masami Hiramatsu Date: Wed, 8 Jun 2016 18:29:50 +0900 Subject: perf probe: Uncomment and export synthesize_perf_probe_point() Uncomment and export synthesize_perf_probe_point() which had once introduced but has been disabled for a long time. This renews the code and re-enable it. Signed-off-by: Masami Hiramatsu Cc: Ananth N Mavinakayanahalli Cc: Brendan Gregg Cc: Hemant Kumar Cc: Namhyung Kim Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/20160608092949.3116.21958.stgit@devbox Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c index 84f4b2b3..cbc8a8b 100644 --- a/tools/perf/util/probe-event.c +++ b/tools/perf/util/probe-event.c @@ -67,7 +67,6 @@ int e_snprintf(char *str, size_t size, const char *format, ...) return ret; } -static char *synthesize_perf_probe_point(struct perf_probe_point *pp); static struct machine *host_machine; /* Initialize symbol maps and path of vmlinux/modules */ @@ -1716,7 +1715,7 @@ out: } /* Compose only probe point (not argument) */ -static char *synthesize_perf_probe_point(struct perf_probe_point *pp) +char *synthesize_perf_probe_point(struct perf_probe_point *pp) { struct strbuf buf; char *tmp, *ret = NULL; @@ -1755,30 +1754,36 @@ out: return ret; } -#if 0 char *synthesize_perf_probe_command(struct perf_probe_event *pev) { - char *buf; - int i, len, ret; + struct strbuf buf; + char *tmp, *ret = NULL; + int i; - buf = synthesize_perf_probe_point(&pev->point); - if (!buf) + if (strbuf_init(&buf, 64)) return NULL; + if (pev->event) + if (strbuf_addf(&buf, "%s:%s=", pev->group ?: PERFPROBE_GROUP, + pev->event) < 0) + goto out; + + tmp = synthesize_perf_probe_point(&pev->point); + if (!tmp || strbuf_addstr(&buf, tmp) < 0) + goto out; + free(tmp); - len = strlen(buf); for (i = 0; i < pev->nargs; i++) { - ret = e_snprintf(&buf[len], MAX_CMDLEN - len, " %s", - pev->args[i].name); - if (ret <= 0) { - free(buf); - return NULL; - } - len += ret; + tmp = synthesize_perf_probe_arg(pev->args + i); + if (!tmp || strbuf_addf(&buf, " %s", tmp) < 0) + goto out; + free(tmp); } - return buf; + ret = strbuf_detach(&buf, NULL); +out: + strbuf_release(&buf); + return ret; } -#endif static int __synthesize_probe_trace_arg_ref(struct probe_trace_arg_ref *ref, struct strbuf *buf, int depth) diff --git a/tools/perf/util/probe-event.h b/tools/perf/util/probe-event.h index 367f886..0b024ba 100644 --- a/tools/perf/util/probe-event.h +++ b/tools/perf/util/probe-event.h @@ -121,6 +121,7 @@ int parse_probe_trace_command(const char *cmd, struct probe_trace_event *tev); char *synthesize_perf_probe_command(struct perf_probe_event *pev); char *synthesize_probe_trace_command(struct probe_trace_event *tev); char *synthesize_perf_probe_arg(struct perf_probe_arg *pa); +char *synthesize_perf_probe_point(struct perf_probe_point *pp); int perf_probe_event__copy(struct perf_probe_event *dst, struct perf_probe_event *src); -- cgit v0.10.2 From b914bb55f2abd66937c23fa0b89becaf9bcceb37 Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Tue, 14 Jun 2016 21:33:44 +0530 Subject: ASoC: Intel: Skylake: Initialize module list for Broxton The module list was not initialized for Broxton DSP code, so initialize it. Signed-off-by: Vinod Koul Signed-off-by: Mark Brown diff --git a/sound/soc/intel/skylake/bxt-sst.c b/sound/soc/intel/skylake/bxt-sst.c index 965ce40..8b95e09 100644 --- a/sound/soc/intel/skylake/bxt-sst.c +++ b/sound/soc/intel/skylake/bxt-sst.c @@ -291,6 +291,7 @@ int bxt_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq, sst_dsp_mailbox_init(sst, (BXT_ADSP_SRAM0_BASE + SKL_ADSP_W0_STAT_SZ), SKL_ADSP_W0_UP_SZ, BXT_ADSP_SRAM1_BASE, SKL_ADSP_W1_SZ); + INIT_LIST_HEAD(&sst->module_list); ret = skl_ipc_init(dev, skl); if (ret) return ret; -- cgit v0.10.2 From 2921b12362babf5af7d45e7b933637cfdfdf6a2a Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Fri, 1 Apr 2016 05:09:53 -0700 Subject: documentation: Add reference to 2014 RCU API LWN article Reported-by: Jim Roskind Signed-off-by: Paul E. McKenney diff --git a/Documentation/RCU/whatisRCU.txt b/Documentation/RCU/whatisRCU.txt index 111770f..13266cf 100644 --- a/Documentation/RCU/whatisRCU.txt +++ b/Documentation/RCU/whatisRCU.txt @@ -5,6 +5,7 @@ to start learning about RCU: 2. What is RCU? Part 2: Usage http://lwn.net/Articles/263130/ 3. RCU part 3: the RCU API http://lwn.net/Articles/264090/ 4. The RCU API, 2010 Edition http://lwn.net/Articles/418853/ +5. The RCU API, 2014 Edition http://lwn.net/Articles/609904/ What is RCU? -- cgit v0.10.2 From db4855b5a88535746558fb756512090fc1ce5607 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Fri, 1 Apr 2016 05:21:56 -0700 Subject: documentation: Add references to 2010 and 2014 Big API Tables Reported-by: Jim Roskind Signed-off-by: Paul E. McKenney diff --git a/Documentation/RCU/whatisRCU.txt b/Documentation/RCU/whatisRCU.txt index 13266cf..2044227 100644 --- a/Documentation/RCU/whatisRCU.txt +++ b/Documentation/RCU/whatisRCU.txt @@ -5,7 +5,9 @@ to start learning about RCU: 2. What is RCU? Part 2: Usage http://lwn.net/Articles/263130/ 3. RCU part 3: the RCU API http://lwn.net/Articles/264090/ 4. The RCU API, 2010 Edition http://lwn.net/Articles/418853/ + 2010 Big API Table http://lwn.net/Articles/419086/ 5. The RCU API, 2014 Edition http://lwn.net/Articles/609904/ + 2014 Big API Table http://lwn.net/Articles/609973/ What is RCU? -- cgit v0.10.2 From c79dac758dc59f7461a721aaf65301cde8a448bc Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Wed, 20 Apr 2016 09:22:54 -0700 Subject: documentation: Add RCU_NONIDLE() restrictions to requirements Signed-off-by: Paul E. McKenney diff --git a/Documentation/RCU/Design/Requirements/Requirements.html b/Documentation/RCU/Design/Requirements/Requirements.html index e7e24b3..ece410f 100644 --- a/Documentation/RCU/Design/Requirements/Requirements.html +++ b/Documentation/RCU/Design/Requirements/Requirements.html @@ -2391,6 +2391,41 @@ and RCU_NONIDLE() on the other while inspecting idle-loop code. Steven Rostedt supplied _rcuidle event tracing, which is used quite heavily in the idle loop. +However, there are some restrictions on the code placed within +RCU_NONIDLE(): + +
    +
  1. Blocking is prohibited. + In practice, this is not a serious restriction given that idle + tasks are prohibited from blocking to begin with. +
  2. Although nesting RCU_NONIDLE() is permited, they cannot + nest indefinitely deeply. + However, given that they can be nested on the order of a million + deep, even on 32-bit systems, this should not be a serious + restriction. + This nesting limit would probably be reached long after the + compiler OOMed or the stack overflowed. +
  3. Any code path that enters RCU_NONIDLE() must sequence + out of that same RCU_NONIDLE(). + For example, the following is grossly illegal: + +
    +
    + 1     RCU_NONIDLE({
    + 2       do_something();
    + 3       goto bad_idea;  /* BUG!!! */
    + 4       do_something_else();});
    + 5   bad_idea:
    +	
    +
    + +

    + It is just as illegal to transfer control into the middle of + RCU_NONIDLE()'s argument. + Yes, in theory, you could transfer in as long as you also + transferred out, but in practice you could also expect to get sharply + worded review comments. +

It is similarly socially unacceptable to interrupt an -- cgit v0.10.2 From 14ef05754f397d468926187d285b9fee55603e86 Mon Sep 17 00:00:00 2001 From: Eric Engestrom Date: Mon, 25 Apr 2016 07:36:59 +0100 Subject: Documentation: Fix spelling mistake Signed-off-by: Eric Engestrom Reviewed-by: Josh Triplett Signed-off-by: Paul E. McKenney diff --git a/Documentation/RCU/stallwarn.txt b/Documentation/RCU/stallwarn.txt index 0f7fb42..e93d041 100644 --- a/Documentation/RCU/stallwarn.txt +++ b/Documentation/RCU/stallwarn.txt @@ -49,7 +49,7 @@ rcupdate.rcu_task_stall_timeout This boot/sysfs parameter controls the RCU-tasks stall warning interval. A value of zero or less suppresses RCU-tasks stall warnings. A positive value sets the stall-warning interval - in jiffies. An RCU-tasks stall warning starts wtih the line: + in jiffies. An RCU-tasks stall warning starts with the line: INFO: rcu_tasks detected stalls on tasks: -- cgit v0.10.2 From 0d95092ccba1a30b74fa52ff94ec5415e63744a0 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Fri, 8 Apr 2016 05:00:03 -0700 Subject: rcu: Fix outdated rcu_scheduler_active comment The comment header for rcu_scheduler_active states that it is used to optimize synchronize_sched() at early boot. This is incorrect. The synchronize_sched() function instead checks the number of online CPUs. This commit therefore replaces the comment's synchronize_sched() with synchronize_rcu(), which really does use rcu_scheduler_active for this purpose. Reported-by: Lihao Liang Signed-off-by: Paul E. McKenney diff --git a/kernel/rcu/tree.c b/kernel/rcu/tree.c index c7f1bc4..0fa692f 100644 --- a/kernel/rcu/tree.c +++ b/kernel/rcu/tree.c @@ -130,7 +130,7 @@ int rcu_num_nodes __read_mostly = NUM_RCU_NODES; /* Total # rcu_nodes in use. */ * The rcu_scheduler_active variable transitions from zero to one just * before the first task is spawned. So when this variable is zero, RCU * can assume that there is but one task, allowing RCU to (for example) - * optimize synchronize_sched() to a simple barrier(). When this variable + * optimize synchronize_rcu() to a simple barrier(). When this variable * is one, RCU must actually do all the hard work required to detect real * grace periods. This variable is also used to suppress boot-time false * positives from lockdep-RCU error checking. -- cgit v0.10.2 From 590d1757b9d177e7fe3707963d0209d6eefbc746 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Sun, 10 Apr 2016 08:23:24 -0700 Subject: rcu: Fix outdated hotplug-exclusion comment in rcu_gp_init() In the past, RCU grace-period initialization excluded CPU-hotplug operations, but this is no longer the case. This commit therefore removed an outdated comment in rcu_gp_init() claiming that these are excluded. Reported-by: Lihao Liang Signed-off-by: Paul E. McKenney diff --git a/kernel/rcu/tree.c b/kernel/rcu/tree.c index 0fa692f..6043c14 100644 --- a/kernel/rcu/tree.c +++ b/kernel/rcu/tree.c @@ -1989,8 +1989,7 @@ static bool rcu_gp_init(struct rcu_state *rsp) * of the tree within the rsp->node[] array. Note that other CPUs * will access only the leaves of the hierarchy, thus seeing that no * grace period is in progress, at least until the corresponding - * leaf node has been initialized. In addition, we have excluded - * CPU-hotplug operations. + * leaf node has been initialized. * * The grace period cannot complete until the initialization * process finishes, because this kthread handles both. -- cgit v0.10.2 From d3acab65f274800dd0901f0816f8bca9f2a8c8ec Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Thu, 10 Mar 2016 09:49:04 +0100 Subject: rcu: Remove some superfluous lines I think you'll find this condition is superfluous, as the whole function is under #ifdef of that same. Signed-off-by: Peter Zijlstra (Intel) Signed-off-by: Paul E. McKenney diff --git a/kernel/rcu/tree.c b/kernel/rcu/tree.c index 6043c14..4aefeaf 100644 --- a/kernel/rcu/tree.c +++ b/kernel/rcu/tree.c @@ -4363,9 +4363,6 @@ static void rcu_cleanup_dying_idle_cpu(int cpu, struct rcu_state *rsp) struct rcu_data *rdp = per_cpu_ptr(rsp->rda, cpu); struct rcu_node *rnp = rdp->mynode; /* Outgoing CPU's rdp & rnp. */ - if (!IS_ENABLED(CONFIG_HOTPLUG_CPU)) - return; - /* Remove outgoing CPU from mask in the leaf rcu_node structure. */ mask = rdp->grpmask; raw_spin_lock_irqsave_rcu_node(rnp, flags); /* Enforce GP memory-order guarantee. */ -- cgit v0.10.2 From 3549c2bc2c4ea8ecfeb9d21cb81cb00c6002b011 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Fri, 15 Apr 2016 16:35:29 -0700 Subject: rcu: Move expedited code from tree.c to tree_exp.h People have been having some difficulty finding their way around the RCU code. This commit therefore pulls some of the expedited grace-period code from tree.c to a new tree_exp.h file. This commit is strictly code movement, with the exception of a forward declaration that was added for the sync_sched_exp_online_cleanup() function. A subsequent commit will move the remaining expedited grace-period code from tree_plugin.h to tree_exp.h. Signed-off-by: Paul E. McKenney diff --git a/kernel/rcu/tree.c b/kernel/rcu/tree.c index 4aefeaf..c844b61 100644 --- a/kernel/rcu/tree.c +++ b/kernel/rcu/tree.c @@ -159,6 +159,7 @@ static void invoke_rcu_core(void); static void invoke_rcu_callbacks(struct rcu_state *rsp, struct rcu_data *rdp); static void rcu_report_exp_rdp(struct rcu_state *rsp, struct rcu_data *rdp, bool wake); +static void sync_sched_exp_online_cleanup(int cpu); /* rcuc/rcub kthread realtime priority */ #ifdef CONFIG_RCU_KTHREAD_PRIO @@ -3447,549 +3448,6 @@ static bool rcu_seq_done(unsigned long *sp, unsigned long s) return ULONG_CMP_GE(READ_ONCE(*sp), s); } -/* Wrapper functions for expedited grace periods. */ -static void rcu_exp_gp_seq_start(struct rcu_state *rsp) -{ - rcu_seq_start(&rsp->expedited_sequence); -} -static void rcu_exp_gp_seq_end(struct rcu_state *rsp) -{ - rcu_seq_end(&rsp->expedited_sequence); - smp_mb(); /* Ensure that consecutive grace periods serialize. */ -} -static unsigned long rcu_exp_gp_seq_snap(struct rcu_state *rsp) -{ - unsigned long s; - - smp_mb(); /* Caller's modifications seen first by other CPUs. */ - s = rcu_seq_snap(&rsp->expedited_sequence); - trace_rcu_exp_grace_period(rsp->name, s, TPS("snap")); - return s; -} -static bool rcu_exp_gp_seq_done(struct rcu_state *rsp, unsigned long s) -{ - return rcu_seq_done(&rsp->expedited_sequence, s); -} - -/* - * Reset the ->expmaskinit values in the rcu_node tree to reflect any - * recent CPU-online activity. Note that these masks are not cleared - * when CPUs go offline, so they reflect the union of all CPUs that have - * ever been online. This means that this function normally takes its - * no-work-to-do fastpath. - */ -static void sync_exp_reset_tree_hotplug(struct rcu_state *rsp) -{ - bool done; - unsigned long flags; - unsigned long mask; - unsigned long oldmask; - int ncpus = READ_ONCE(rsp->ncpus); - struct rcu_node *rnp; - struct rcu_node *rnp_up; - - /* If no new CPUs onlined since last time, nothing to do. */ - if (likely(ncpus == rsp->ncpus_snap)) - return; - rsp->ncpus_snap = ncpus; - - /* - * Each pass through the following loop propagates newly onlined - * CPUs for the current rcu_node structure up the rcu_node tree. - */ - rcu_for_each_leaf_node(rsp, rnp) { - raw_spin_lock_irqsave_rcu_node(rnp, flags); - if (rnp->expmaskinit == rnp->expmaskinitnext) { - raw_spin_unlock_irqrestore_rcu_node(rnp, flags); - continue; /* No new CPUs, nothing to do. */ - } - - /* Update this node's mask, track old value for propagation. */ - oldmask = rnp->expmaskinit; - rnp->expmaskinit = rnp->expmaskinitnext; - raw_spin_unlock_irqrestore_rcu_node(rnp, flags); - - /* If was already nonzero, nothing to propagate. */ - if (oldmask) - continue; - - /* Propagate the new CPU up the tree. */ - mask = rnp->grpmask; - rnp_up = rnp->parent; - done = false; - while (rnp_up) { - raw_spin_lock_irqsave_rcu_node(rnp_up, flags); - if (rnp_up->expmaskinit) - done = true; - rnp_up->expmaskinit |= mask; - raw_spin_unlock_irqrestore_rcu_node(rnp_up, flags); - if (done) - break; - mask = rnp_up->grpmask; - rnp_up = rnp_up->parent; - } - } -} - -/* - * Reset the ->expmask values in the rcu_node tree in preparation for - * a new expedited grace period. - */ -static void __maybe_unused sync_exp_reset_tree(struct rcu_state *rsp) -{ - unsigned long flags; - struct rcu_node *rnp; - - sync_exp_reset_tree_hotplug(rsp); - rcu_for_each_node_breadth_first(rsp, rnp) { - raw_spin_lock_irqsave_rcu_node(rnp, flags); - WARN_ON_ONCE(rnp->expmask); - rnp->expmask = rnp->expmaskinit; - raw_spin_unlock_irqrestore_rcu_node(rnp, flags); - } -} - -/* - * Return non-zero if there is no RCU expedited grace period in progress - * for the specified rcu_node structure, in other words, if all CPUs and - * tasks covered by the specified rcu_node structure have done their bit - * for the current expedited grace period. Works only for preemptible - * RCU -- other RCU implementation use other means. - * - * Caller must hold the rcu_state's exp_mutex. - */ -static int sync_rcu_preempt_exp_done(struct rcu_node *rnp) -{ - return rnp->exp_tasks == NULL && - READ_ONCE(rnp->expmask) == 0; -} - -/* - * Report the exit from RCU read-side critical section for the last task - * that queued itself during or before the current expedited preemptible-RCU - * grace period. This event is reported either to the rcu_node structure on - * which the task was queued or to one of that rcu_node structure's ancestors, - * recursively up the tree. (Calm down, calm down, we do the recursion - * iteratively!) - * - * Caller must hold the rcu_state's exp_mutex and the specified rcu_node - * structure's ->lock. - */ -static void __rcu_report_exp_rnp(struct rcu_state *rsp, struct rcu_node *rnp, - bool wake, unsigned long flags) - __releases(rnp->lock) -{ - unsigned long mask; - - for (;;) { - if (!sync_rcu_preempt_exp_done(rnp)) { - if (!rnp->expmask) - rcu_initiate_boost(rnp, flags); - else - raw_spin_unlock_irqrestore_rcu_node(rnp, flags); - break; - } - if (rnp->parent == NULL) { - raw_spin_unlock_irqrestore_rcu_node(rnp, flags); - if (wake) { - smp_mb(); /* EGP done before wake_up(). */ - swake_up(&rsp->expedited_wq); - } - break; - } - mask = rnp->grpmask; - raw_spin_unlock_rcu_node(rnp); /* irqs remain disabled */ - rnp = rnp->parent; - raw_spin_lock_rcu_node(rnp); /* irqs already disabled */ - WARN_ON_ONCE(!(rnp->expmask & mask)); - rnp->expmask &= ~mask; - } -} - -/* - * Report expedited quiescent state for specified node. This is a - * lock-acquisition wrapper function for __rcu_report_exp_rnp(). - * - * Caller must hold the rcu_state's exp_mutex. - */ -static void __maybe_unused rcu_report_exp_rnp(struct rcu_state *rsp, - struct rcu_node *rnp, bool wake) -{ - unsigned long flags; - - raw_spin_lock_irqsave_rcu_node(rnp, flags); - __rcu_report_exp_rnp(rsp, rnp, wake, flags); -} - -/* - * Report expedited quiescent state for multiple CPUs, all covered by the - * specified leaf rcu_node structure. Caller must hold the rcu_state's - * exp_mutex. - */ -static void rcu_report_exp_cpu_mult(struct rcu_state *rsp, struct rcu_node *rnp, - unsigned long mask, bool wake) -{ - unsigned long flags; - - raw_spin_lock_irqsave_rcu_node(rnp, flags); - if (!(rnp->expmask & mask)) { - raw_spin_unlock_irqrestore_rcu_node(rnp, flags); - return; - } - rnp->expmask &= ~mask; - __rcu_report_exp_rnp(rsp, rnp, wake, flags); /* Releases rnp->lock. */ -} - -/* - * Report expedited quiescent state for specified rcu_data (CPU). - */ -static void rcu_report_exp_rdp(struct rcu_state *rsp, struct rcu_data *rdp, - bool wake) -{ - rcu_report_exp_cpu_mult(rsp, rdp->mynode, rdp->grpmask, wake); -} - -/* Common code for synchronize_{rcu,sched}_expedited() work-done checking. */ -static bool sync_exp_work_done(struct rcu_state *rsp, atomic_long_t *stat, - unsigned long s) -{ - if (rcu_exp_gp_seq_done(rsp, s)) { - trace_rcu_exp_grace_period(rsp->name, s, TPS("done")); - /* Ensure test happens before caller kfree(). */ - smp_mb__before_atomic(); /* ^^^ */ - atomic_long_inc(stat); - return true; - } - return false; -} - -/* - * Funnel-lock acquisition for expedited grace periods. Returns true - * if some other task completed an expedited grace period that this task - * can piggy-back on, and with no mutex held. Otherwise, returns false - * with the mutex held, indicating that the caller must actually do the - * expedited grace period. - */ -static bool exp_funnel_lock(struct rcu_state *rsp, unsigned long s) -{ - struct rcu_data *rdp = per_cpu_ptr(rsp->rda, raw_smp_processor_id()); - struct rcu_node *rnp = rdp->mynode; - struct rcu_node *rnp_root = rcu_get_root(rsp); - - /* Low-contention fastpath. */ - if (ULONG_CMP_LT(READ_ONCE(rnp->exp_seq_rq), s) && - (rnp == rnp_root || - ULONG_CMP_LT(READ_ONCE(rnp_root->exp_seq_rq), s)) && - !mutex_is_locked(&rsp->exp_mutex) && - mutex_trylock(&rsp->exp_mutex)) - goto fastpath; - - /* - * Each pass through the following loop works its way up - * the rcu_node tree, returning if others have done the work or - * otherwise falls through to acquire rsp->exp_mutex. The mapping - * from CPU to rcu_node structure can be inexact, as it is just - * promoting locality and is not strictly needed for correctness. - */ - for (; rnp != NULL; rnp = rnp->parent) { - if (sync_exp_work_done(rsp, &rdp->exp_workdone1, s)) - return true; - - /* Work not done, either wait here or go up. */ - spin_lock(&rnp->exp_lock); - if (ULONG_CMP_GE(rnp->exp_seq_rq, s)) { - - /* Someone else doing GP, so wait for them. */ - spin_unlock(&rnp->exp_lock); - trace_rcu_exp_funnel_lock(rsp->name, rnp->level, - rnp->grplo, rnp->grphi, - TPS("wait")); - wait_event(rnp->exp_wq[(s >> 1) & 0x3], - sync_exp_work_done(rsp, - &rdp->exp_workdone2, s)); - return true; - } - rnp->exp_seq_rq = s; /* Followers can wait on us. */ - spin_unlock(&rnp->exp_lock); - trace_rcu_exp_funnel_lock(rsp->name, rnp->level, rnp->grplo, - rnp->grphi, TPS("nxtlvl")); - } - mutex_lock(&rsp->exp_mutex); -fastpath: - if (sync_exp_work_done(rsp, &rdp->exp_workdone3, s)) { - mutex_unlock(&rsp->exp_mutex); - return true; - } - rcu_exp_gp_seq_start(rsp); - trace_rcu_exp_grace_period(rsp->name, s, TPS("start")); - return false; -} - -/* Invoked on each online non-idle CPU for expedited quiescent state. */ -static void sync_sched_exp_handler(void *data) -{ - struct rcu_data *rdp; - struct rcu_node *rnp; - struct rcu_state *rsp = data; - - rdp = this_cpu_ptr(rsp->rda); - rnp = rdp->mynode; - if (!(READ_ONCE(rnp->expmask) & rdp->grpmask) || - __this_cpu_read(rcu_sched_data.cpu_no_qs.b.exp)) - return; - if (rcu_is_cpu_rrupt_from_idle()) { - rcu_report_exp_rdp(&rcu_sched_state, - this_cpu_ptr(&rcu_sched_data), true); - return; - } - __this_cpu_write(rcu_sched_data.cpu_no_qs.b.exp, true); - resched_cpu(smp_processor_id()); -} - -/* Send IPI for expedited cleanup if needed at end of CPU-hotplug operation. */ -static void sync_sched_exp_online_cleanup(int cpu) -{ - struct rcu_data *rdp; - int ret; - struct rcu_node *rnp; - struct rcu_state *rsp = &rcu_sched_state; - - rdp = per_cpu_ptr(rsp->rda, cpu); - rnp = rdp->mynode; - if (!(READ_ONCE(rnp->expmask) & rdp->grpmask)) - return; - ret = smp_call_function_single(cpu, sync_sched_exp_handler, rsp, 0); - WARN_ON_ONCE(ret); -} - -/* - * Select the nodes that the upcoming expedited grace period needs - * to wait for. - */ -static void sync_rcu_exp_select_cpus(struct rcu_state *rsp, - smp_call_func_t func) -{ - int cpu; - unsigned long flags; - unsigned long mask; - unsigned long mask_ofl_test; - unsigned long mask_ofl_ipi; - int ret; - struct rcu_node *rnp; - - sync_exp_reset_tree(rsp); - rcu_for_each_leaf_node(rsp, rnp) { - raw_spin_lock_irqsave_rcu_node(rnp, flags); - - /* Each pass checks a CPU for identity, offline, and idle. */ - mask_ofl_test = 0; - for (cpu = rnp->grplo; cpu <= rnp->grphi; cpu++) { - struct rcu_data *rdp = per_cpu_ptr(rsp->rda, cpu); - struct rcu_dynticks *rdtp = &per_cpu(rcu_dynticks, cpu); - - if (raw_smp_processor_id() == cpu || - !(atomic_add_return(0, &rdtp->dynticks) & 0x1)) - mask_ofl_test |= rdp->grpmask; - } - mask_ofl_ipi = rnp->expmask & ~mask_ofl_test; - - /* - * Need to wait for any blocked tasks as well. Note that - * additional blocking tasks will also block the expedited - * GP until such time as the ->expmask bits are cleared. - */ - if (rcu_preempt_has_tasks(rnp)) - rnp->exp_tasks = rnp->blkd_tasks.next; - raw_spin_unlock_irqrestore_rcu_node(rnp, flags); - - /* IPI the remaining CPUs for expedited quiescent state. */ - mask = 1; - for (cpu = rnp->grplo; cpu <= rnp->grphi; cpu++, mask <<= 1) { - if (!(mask_ofl_ipi & mask)) - continue; -retry_ipi: - ret = smp_call_function_single(cpu, func, rsp, 0); - if (!ret) { - mask_ofl_ipi &= ~mask; - continue; - } - /* Failed, raced with offline. */ - raw_spin_lock_irqsave_rcu_node(rnp, flags); - if (cpu_online(cpu) && - (rnp->expmask & mask)) { - raw_spin_unlock_irqrestore_rcu_node(rnp, flags); - schedule_timeout_uninterruptible(1); - if (cpu_online(cpu) && - (rnp->expmask & mask)) - goto retry_ipi; - raw_spin_lock_irqsave_rcu_node(rnp, flags); - } - if (!(rnp->expmask & mask)) - mask_ofl_ipi &= ~mask; - raw_spin_unlock_irqrestore_rcu_node(rnp, flags); - } - /* Report quiescent states for those that went offline. */ - mask_ofl_test |= mask_ofl_ipi; - if (mask_ofl_test) - rcu_report_exp_cpu_mult(rsp, rnp, mask_ofl_test, false); - } -} - -static void synchronize_sched_expedited_wait(struct rcu_state *rsp) -{ - int cpu; - unsigned long jiffies_stall; - unsigned long jiffies_start; - unsigned long mask; - int ndetected; - struct rcu_node *rnp; - struct rcu_node *rnp_root = rcu_get_root(rsp); - int ret; - - jiffies_stall = rcu_jiffies_till_stall_check(); - jiffies_start = jiffies; - - for (;;) { - ret = swait_event_timeout( - rsp->expedited_wq, - sync_rcu_preempt_exp_done(rnp_root), - jiffies_stall); - if (ret > 0 || sync_rcu_preempt_exp_done(rnp_root)) - return; - if (ret < 0) { - /* Hit a signal, disable CPU stall warnings. */ - swait_event(rsp->expedited_wq, - sync_rcu_preempt_exp_done(rnp_root)); - return; - } - pr_err("INFO: %s detected expedited stalls on CPUs/tasks: {", - rsp->name); - ndetected = 0; - rcu_for_each_leaf_node(rsp, rnp) { - ndetected += rcu_print_task_exp_stall(rnp); - mask = 1; - for (cpu = rnp->grplo; cpu <= rnp->grphi; cpu++, mask <<= 1) { - struct rcu_data *rdp; - - if (!(rnp->expmask & mask)) - continue; - ndetected++; - rdp = per_cpu_ptr(rsp->rda, cpu); - pr_cont(" %d-%c%c%c", cpu, - "O."[!!cpu_online(cpu)], - "o."[!!(rdp->grpmask & rnp->expmaskinit)], - "N."[!!(rdp->grpmask & rnp->expmaskinitnext)]); - } - mask <<= 1; - } - pr_cont(" } %lu jiffies s: %lu root: %#lx/%c\n", - jiffies - jiffies_start, rsp->expedited_sequence, - rnp_root->expmask, ".T"[!!rnp_root->exp_tasks]); - if (ndetected) { - pr_err("blocking rcu_node structures:"); - rcu_for_each_node_breadth_first(rsp, rnp) { - if (rnp == rnp_root) - continue; /* printed unconditionally */ - if (sync_rcu_preempt_exp_done(rnp)) - continue; - pr_cont(" l=%u:%d-%d:%#lx/%c", - rnp->level, rnp->grplo, rnp->grphi, - rnp->expmask, - ".T"[!!rnp->exp_tasks]); - } - pr_cont("\n"); - } - rcu_for_each_leaf_node(rsp, rnp) { - mask = 1; - for (cpu = rnp->grplo; cpu <= rnp->grphi; cpu++, mask <<= 1) { - if (!(rnp->expmask & mask)) - continue; - dump_cpu_task(cpu); - } - } - jiffies_stall = 3 * rcu_jiffies_till_stall_check() + 3; - } -} - -/* - * Wait for the current expedited grace period to complete, and then - * wake up everyone who piggybacked on the just-completed expedited - * grace period. Also update all the ->exp_seq_rq counters as needed - * in order to avoid counter-wrap problems. - */ -static void rcu_exp_wait_wake(struct rcu_state *rsp, unsigned long s) -{ - struct rcu_node *rnp; - - synchronize_sched_expedited_wait(rsp); - rcu_exp_gp_seq_end(rsp); - trace_rcu_exp_grace_period(rsp->name, s, TPS("end")); - - /* - * Switch over to wakeup mode, allowing the next GP, but -only- the - * next GP, to proceed. - */ - mutex_lock(&rsp->exp_wake_mutex); - mutex_unlock(&rsp->exp_mutex); - - rcu_for_each_node_breadth_first(rsp, rnp) { - if (ULONG_CMP_LT(READ_ONCE(rnp->exp_seq_rq), s)) { - spin_lock(&rnp->exp_lock); - /* Recheck, avoid hang in case someone just arrived. */ - if (ULONG_CMP_LT(rnp->exp_seq_rq, s)) - rnp->exp_seq_rq = s; - spin_unlock(&rnp->exp_lock); - } - wake_up_all(&rnp->exp_wq[(rsp->expedited_sequence >> 1) & 0x3]); - } - trace_rcu_exp_grace_period(rsp->name, s, TPS("endwake")); - mutex_unlock(&rsp->exp_wake_mutex); -} - -/** - * synchronize_sched_expedited - Brute-force RCU-sched grace period - * - * Wait for an RCU-sched grace period to elapse, but use a "big hammer" - * approach to force the grace period to end quickly. This consumes - * significant time on all CPUs and is unfriendly to real-time workloads, - * so is thus not recommended for any sort of common-case code. In fact, - * if you are using synchronize_sched_expedited() in a loop, please - * restructure your code to batch your updates, and then use a single - * synchronize_sched() instead. - * - * This implementation can be thought of as an application of sequence - * locking to expedited grace periods, but using the sequence counter to - * determine when someone else has already done the work instead of for - * retrying readers. - */ -void synchronize_sched_expedited(void) -{ - unsigned long s; - struct rcu_state *rsp = &rcu_sched_state; - - /* If only one CPU, this is automatically a grace period. */ - if (rcu_blocking_is_gp()) - return; - - /* If expedited grace periods are prohibited, fall back to normal. */ - if (rcu_gp_is_normal()) { - wait_rcu_gp(call_rcu_sched); - return; - } - - /* Take a snapshot of the sequence number. */ - s = rcu_exp_gp_seq_snap(rsp); - if (exp_funnel_lock(rsp, s)) - return; /* Someone else did our work for us. */ - - /* Initialize the rcu_node tree in preparation for the wait. */ - sync_rcu_exp_select_cpus(rsp, sync_sched_exp_handler); - - /* Wait and clean up, including waking everyone. */ - rcu_exp_wait_wake(rsp, s); -} -EXPORT_SYMBOL_GPL(synchronize_sched_expedited); - /* * Check to see if there is any immediate RCU-related work to be done * by the current CPU, for the specified type of RCU, returning 1 if so. @@ -4747,4 +4205,5 @@ void __init rcu_init(void) rcu_cpu_notify(NULL, CPU_UP_PREPARE, (void *)(long)cpu); } +#include "tree_exp.h" #include "tree_plugin.h" diff --git a/kernel/rcu/tree_exp.h b/kernel/rcu/tree_exp.h new file mode 100644 index 0000000..db0909c --- /dev/null +++ b/kernel/rcu/tree_exp.h @@ -0,0 +1,564 @@ +/* + * RCU expedited grace periods + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, you can access it online at + * http://www.gnu.org/licenses/gpl-2.0.html. + * + * Copyright IBM Corporation, 2016 + * + * Authors: Paul E. McKenney + */ + +/* Wrapper functions for expedited grace periods. */ +static void rcu_exp_gp_seq_start(struct rcu_state *rsp) +{ + rcu_seq_start(&rsp->expedited_sequence); +} +static void rcu_exp_gp_seq_end(struct rcu_state *rsp) +{ + rcu_seq_end(&rsp->expedited_sequence); + smp_mb(); /* Ensure that consecutive grace periods serialize. */ +} +static unsigned long rcu_exp_gp_seq_snap(struct rcu_state *rsp) +{ + unsigned long s; + + smp_mb(); /* Caller's modifications seen first by other CPUs. */ + s = rcu_seq_snap(&rsp->expedited_sequence); + trace_rcu_exp_grace_period(rsp->name, s, TPS("snap")); + return s; +} +static bool rcu_exp_gp_seq_done(struct rcu_state *rsp, unsigned long s) +{ + return rcu_seq_done(&rsp->expedited_sequence, s); +} + +/* + * Reset the ->expmaskinit values in the rcu_node tree to reflect any + * recent CPU-online activity. Note that these masks are not cleared + * when CPUs go offline, so they reflect the union of all CPUs that have + * ever been online. This means that this function normally takes its + * no-work-to-do fastpath. + */ +static void sync_exp_reset_tree_hotplug(struct rcu_state *rsp) +{ + bool done; + unsigned long flags; + unsigned long mask; + unsigned long oldmask; + int ncpus = READ_ONCE(rsp->ncpus); + struct rcu_node *rnp; + struct rcu_node *rnp_up; + + /* If no new CPUs onlined since last time, nothing to do. */ + if (likely(ncpus == rsp->ncpus_snap)) + return; + rsp->ncpus_snap = ncpus; + + /* + * Each pass through the following loop propagates newly onlined + * CPUs for the current rcu_node structure up the rcu_node tree. + */ + rcu_for_each_leaf_node(rsp, rnp) { + raw_spin_lock_irqsave_rcu_node(rnp, flags); + if (rnp->expmaskinit == rnp->expmaskinitnext) { + raw_spin_unlock_irqrestore_rcu_node(rnp, flags); + continue; /* No new CPUs, nothing to do. */ + } + + /* Update this node's mask, track old value for propagation. */ + oldmask = rnp->expmaskinit; + rnp->expmaskinit = rnp->expmaskinitnext; + raw_spin_unlock_irqrestore_rcu_node(rnp, flags); + + /* If was already nonzero, nothing to propagate. */ + if (oldmask) + continue; + + /* Propagate the new CPU up the tree. */ + mask = rnp->grpmask; + rnp_up = rnp->parent; + done = false; + while (rnp_up) { + raw_spin_lock_irqsave_rcu_node(rnp_up, flags); + if (rnp_up->expmaskinit) + done = true; + rnp_up->expmaskinit |= mask; + raw_spin_unlock_irqrestore_rcu_node(rnp_up, flags); + if (done) + break; + mask = rnp_up->grpmask; + rnp_up = rnp_up->parent; + } + } +} + +/* + * Reset the ->expmask values in the rcu_node tree in preparation for + * a new expedited grace period. + */ +static void __maybe_unused sync_exp_reset_tree(struct rcu_state *rsp) +{ + unsigned long flags; + struct rcu_node *rnp; + + sync_exp_reset_tree_hotplug(rsp); + rcu_for_each_node_breadth_first(rsp, rnp) { + raw_spin_lock_irqsave_rcu_node(rnp, flags); + WARN_ON_ONCE(rnp->expmask); + rnp->expmask = rnp->expmaskinit; + raw_spin_unlock_irqrestore_rcu_node(rnp, flags); + } +} + +/* + * Return non-zero if there is no RCU expedited grace period in progress + * for the specified rcu_node structure, in other words, if all CPUs and + * tasks covered by the specified rcu_node structure have done their bit + * for the current expedited grace period. Works only for preemptible + * RCU -- other RCU implementation use other means. + * + * Caller must hold the rcu_state's exp_mutex. + */ +static int sync_rcu_preempt_exp_done(struct rcu_node *rnp) +{ + return rnp->exp_tasks == NULL && + READ_ONCE(rnp->expmask) == 0; +} + +/* + * Report the exit from RCU read-side critical section for the last task + * that queued itself during or before the current expedited preemptible-RCU + * grace period. This event is reported either to the rcu_node structure on + * which the task was queued or to one of that rcu_node structure's ancestors, + * recursively up the tree. (Calm down, calm down, we do the recursion + * iteratively!) + * + * Caller must hold the rcu_state's exp_mutex and the specified rcu_node + * structure's ->lock. + */ +static void __rcu_report_exp_rnp(struct rcu_state *rsp, struct rcu_node *rnp, + bool wake, unsigned long flags) + __releases(rnp->lock) +{ + unsigned long mask; + + for (;;) { + if (!sync_rcu_preempt_exp_done(rnp)) { + if (!rnp->expmask) + rcu_initiate_boost(rnp, flags); + else + raw_spin_unlock_irqrestore_rcu_node(rnp, flags); + break; + } + if (rnp->parent == NULL) { + raw_spin_unlock_irqrestore_rcu_node(rnp, flags); + if (wake) { + smp_mb(); /* EGP done before wake_up(). */ + swake_up(&rsp->expedited_wq); + } + break; + } + mask = rnp->grpmask; + raw_spin_unlock_rcu_node(rnp); /* irqs remain disabled */ + rnp = rnp->parent; + raw_spin_lock_rcu_node(rnp); /* irqs already disabled */ + WARN_ON_ONCE(!(rnp->expmask & mask)); + rnp->expmask &= ~mask; + } +} + +/* + * Report expedited quiescent state for specified node. This is a + * lock-acquisition wrapper function for __rcu_report_exp_rnp(). + * + * Caller must hold the rcu_state's exp_mutex. + */ +static void __maybe_unused rcu_report_exp_rnp(struct rcu_state *rsp, + struct rcu_node *rnp, bool wake) +{ + unsigned long flags; + + raw_spin_lock_irqsave_rcu_node(rnp, flags); + __rcu_report_exp_rnp(rsp, rnp, wake, flags); +} + +/* + * Report expedited quiescent state for multiple CPUs, all covered by the + * specified leaf rcu_node structure. Caller must hold the rcu_state's + * exp_mutex. + */ +static void rcu_report_exp_cpu_mult(struct rcu_state *rsp, struct rcu_node *rnp, + unsigned long mask, bool wake) +{ + unsigned long flags; + + raw_spin_lock_irqsave_rcu_node(rnp, flags); + if (!(rnp->expmask & mask)) { + raw_spin_unlock_irqrestore_rcu_node(rnp, flags); + return; + } + rnp->expmask &= ~mask; + __rcu_report_exp_rnp(rsp, rnp, wake, flags); /* Releases rnp->lock. */ +} + +/* + * Report expedited quiescent state for specified rcu_data (CPU). + */ +static void rcu_report_exp_rdp(struct rcu_state *rsp, struct rcu_data *rdp, + bool wake) +{ + rcu_report_exp_cpu_mult(rsp, rdp->mynode, rdp->grpmask, wake); +} + +/* Common code for synchronize_{rcu,sched}_expedited() work-done checking. */ +static bool sync_exp_work_done(struct rcu_state *rsp, atomic_long_t *stat, + unsigned long s) +{ + if (rcu_exp_gp_seq_done(rsp, s)) { + trace_rcu_exp_grace_period(rsp->name, s, TPS("done")); + /* Ensure test happens before caller kfree(). */ + smp_mb__before_atomic(); /* ^^^ */ + atomic_long_inc(stat); + return true; + } + return false; +} + +/* + * Funnel-lock acquisition for expedited grace periods. Returns true + * if some other task completed an expedited grace period that this task + * can piggy-back on, and with no mutex held. Otherwise, returns false + * with the mutex held, indicating that the caller must actually do the + * expedited grace period. + */ +static bool exp_funnel_lock(struct rcu_state *rsp, unsigned long s) +{ + struct rcu_data *rdp = per_cpu_ptr(rsp->rda, raw_smp_processor_id()); + struct rcu_node *rnp = rdp->mynode; + struct rcu_node *rnp_root = rcu_get_root(rsp); + + /* Low-contention fastpath. */ + if (ULONG_CMP_LT(READ_ONCE(rnp->exp_seq_rq), s) && + (rnp == rnp_root || + ULONG_CMP_LT(READ_ONCE(rnp_root->exp_seq_rq), s)) && + !mutex_is_locked(&rsp->exp_mutex) && + mutex_trylock(&rsp->exp_mutex)) + goto fastpath; + + /* + * Each pass through the following loop works its way up + * the rcu_node tree, returning if others have done the work or + * otherwise falls through to acquire rsp->exp_mutex. The mapping + * from CPU to rcu_node structure can be inexact, as it is just + * promoting locality and is not strictly needed for correctness. + */ + for (; rnp != NULL; rnp = rnp->parent) { + if (sync_exp_work_done(rsp, &rdp->exp_workdone1, s)) + return true; + + /* Work not done, either wait here or go up. */ + spin_lock(&rnp->exp_lock); + if (ULONG_CMP_GE(rnp->exp_seq_rq, s)) { + + /* Someone else doing GP, so wait for them. */ + spin_unlock(&rnp->exp_lock); + trace_rcu_exp_funnel_lock(rsp->name, rnp->level, + rnp->grplo, rnp->grphi, + TPS("wait")); + wait_event(rnp->exp_wq[(s >> 1) & 0x3], + sync_exp_work_done(rsp, + &rdp->exp_workdone2, s)); + return true; + } + rnp->exp_seq_rq = s; /* Followers can wait on us. */ + spin_unlock(&rnp->exp_lock); + trace_rcu_exp_funnel_lock(rsp->name, rnp->level, rnp->grplo, + rnp->grphi, TPS("nxtlvl")); + } + mutex_lock(&rsp->exp_mutex); +fastpath: + if (sync_exp_work_done(rsp, &rdp->exp_workdone3, s)) { + mutex_unlock(&rsp->exp_mutex); + return true; + } + rcu_exp_gp_seq_start(rsp); + trace_rcu_exp_grace_period(rsp->name, s, TPS("start")); + return false; +} + +/* Invoked on each online non-idle CPU for expedited quiescent state. */ +static void sync_sched_exp_handler(void *data) +{ + struct rcu_data *rdp; + struct rcu_node *rnp; + struct rcu_state *rsp = data; + + rdp = this_cpu_ptr(rsp->rda); + rnp = rdp->mynode; + if (!(READ_ONCE(rnp->expmask) & rdp->grpmask) || + __this_cpu_read(rcu_sched_data.cpu_no_qs.b.exp)) + return; + if (rcu_is_cpu_rrupt_from_idle()) { + rcu_report_exp_rdp(&rcu_sched_state, + this_cpu_ptr(&rcu_sched_data), true); + return; + } + __this_cpu_write(rcu_sched_data.cpu_no_qs.b.exp, true); + resched_cpu(smp_processor_id()); +} + +/* Send IPI for expedited cleanup if needed at end of CPU-hotplug operation. */ +static void sync_sched_exp_online_cleanup(int cpu) +{ + struct rcu_data *rdp; + int ret; + struct rcu_node *rnp; + struct rcu_state *rsp = &rcu_sched_state; + + rdp = per_cpu_ptr(rsp->rda, cpu); + rnp = rdp->mynode; + if (!(READ_ONCE(rnp->expmask) & rdp->grpmask)) + return; + ret = smp_call_function_single(cpu, sync_sched_exp_handler, rsp, 0); + WARN_ON_ONCE(ret); +} + +/* + * Select the nodes that the upcoming expedited grace period needs + * to wait for. + */ +static void sync_rcu_exp_select_cpus(struct rcu_state *rsp, + smp_call_func_t func) +{ + int cpu; + unsigned long flags; + unsigned long mask; + unsigned long mask_ofl_test; + unsigned long mask_ofl_ipi; + int ret; + struct rcu_node *rnp; + + sync_exp_reset_tree(rsp); + rcu_for_each_leaf_node(rsp, rnp) { + raw_spin_lock_irqsave_rcu_node(rnp, flags); + + /* Each pass checks a CPU for identity, offline, and idle. */ + mask_ofl_test = 0; + for (cpu = rnp->grplo; cpu <= rnp->grphi; cpu++) { + struct rcu_data *rdp = per_cpu_ptr(rsp->rda, cpu); + struct rcu_dynticks *rdtp = &per_cpu(rcu_dynticks, cpu); + + if (raw_smp_processor_id() == cpu || + !(atomic_add_return(0, &rdtp->dynticks) & 0x1)) + mask_ofl_test |= rdp->grpmask; + } + mask_ofl_ipi = rnp->expmask & ~mask_ofl_test; + + /* + * Need to wait for any blocked tasks as well. Note that + * additional blocking tasks will also block the expedited + * GP until such time as the ->expmask bits are cleared. + */ + if (rcu_preempt_has_tasks(rnp)) + rnp->exp_tasks = rnp->blkd_tasks.next; + raw_spin_unlock_irqrestore_rcu_node(rnp, flags); + + /* IPI the remaining CPUs for expedited quiescent state. */ + mask = 1; + for (cpu = rnp->grplo; cpu <= rnp->grphi; cpu++, mask <<= 1) { + if (!(mask_ofl_ipi & mask)) + continue; +retry_ipi: + ret = smp_call_function_single(cpu, func, rsp, 0); + if (!ret) { + mask_ofl_ipi &= ~mask; + continue; + } + /* Failed, raced with offline. */ + raw_spin_lock_irqsave_rcu_node(rnp, flags); + if (cpu_online(cpu) && + (rnp->expmask & mask)) { + raw_spin_unlock_irqrestore_rcu_node(rnp, flags); + schedule_timeout_uninterruptible(1); + if (cpu_online(cpu) && + (rnp->expmask & mask)) + goto retry_ipi; + raw_spin_lock_irqsave_rcu_node(rnp, flags); + } + if (!(rnp->expmask & mask)) + mask_ofl_ipi &= ~mask; + raw_spin_unlock_irqrestore_rcu_node(rnp, flags); + } + /* Report quiescent states for those that went offline. */ + mask_ofl_test |= mask_ofl_ipi; + if (mask_ofl_test) + rcu_report_exp_cpu_mult(rsp, rnp, mask_ofl_test, false); + } +} + +static void synchronize_sched_expedited_wait(struct rcu_state *rsp) +{ + int cpu; + unsigned long jiffies_stall; + unsigned long jiffies_start; + unsigned long mask; + int ndetected; + struct rcu_node *rnp; + struct rcu_node *rnp_root = rcu_get_root(rsp); + int ret; + + jiffies_stall = rcu_jiffies_till_stall_check(); + jiffies_start = jiffies; + + for (;;) { + ret = swait_event_timeout( + rsp->expedited_wq, + sync_rcu_preempt_exp_done(rnp_root), + jiffies_stall); + if (ret > 0 || sync_rcu_preempt_exp_done(rnp_root)) + return; + if (ret < 0) { + /* Hit a signal, disable CPU stall warnings. */ + swait_event(rsp->expedited_wq, + sync_rcu_preempt_exp_done(rnp_root)); + return; + } + pr_err("INFO: %s detected expedited stalls on CPUs/tasks: {", + rsp->name); + ndetected = 0; + rcu_for_each_leaf_node(rsp, rnp) { + ndetected += rcu_print_task_exp_stall(rnp); + mask = 1; + for (cpu = rnp->grplo; cpu <= rnp->grphi; cpu++, mask <<= 1) { + struct rcu_data *rdp; + + if (!(rnp->expmask & mask)) + continue; + ndetected++; + rdp = per_cpu_ptr(rsp->rda, cpu); + pr_cont(" %d-%c%c%c", cpu, + "O."[!!cpu_online(cpu)], + "o."[!!(rdp->grpmask & rnp->expmaskinit)], + "N."[!!(rdp->grpmask & rnp->expmaskinitnext)]); + } + mask <<= 1; + } + pr_cont(" } %lu jiffies s: %lu root: %#lx/%c\n", + jiffies - jiffies_start, rsp->expedited_sequence, + rnp_root->expmask, ".T"[!!rnp_root->exp_tasks]); + if (ndetected) { + pr_err("blocking rcu_node structures:"); + rcu_for_each_node_breadth_first(rsp, rnp) { + if (rnp == rnp_root) + continue; /* printed unconditionally */ + if (sync_rcu_preempt_exp_done(rnp)) + continue; + pr_cont(" l=%u:%d-%d:%#lx/%c", + rnp->level, rnp->grplo, rnp->grphi, + rnp->expmask, + ".T"[!!rnp->exp_tasks]); + } + pr_cont("\n"); + } + rcu_for_each_leaf_node(rsp, rnp) { + mask = 1; + for (cpu = rnp->grplo; cpu <= rnp->grphi; cpu++, mask <<= 1) { + if (!(rnp->expmask & mask)) + continue; + dump_cpu_task(cpu); + } + } + jiffies_stall = 3 * rcu_jiffies_till_stall_check() + 3; + } +} + +/* + * Wait for the current expedited grace period to complete, and then + * wake up everyone who piggybacked on the just-completed expedited + * grace period. Also update all the ->exp_seq_rq counters as needed + * in order to avoid counter-wrap problems. + */ +static void rcu_exp_wait_wake(struct rcu_state *rsp, unsigned long s) +{ + struct rcu_node *rnp; + + synchronize_sched_expedited_wait(rsp); + rcu_exp_gp_seq_end(rsp); + trace_rcu_exp_grace_period(rsp->name, s, TPS("end")); + + /* + * Switch over to wakeup mode, allowing the next GP, but -only- the + * next GP, to proceed. + */ + mutex_lock(&rsp->exp_wake_mutex); + mutex_unlock(&rsp->exp_mutex); + + rcu_for_each_node_breadth_first(rsp, rnp) { + if (ULONG_CMP_LT(READ_ONCE(rnp->exp_seq_rq), s)) { + spin_lock(&rnp->exp_lock); + /* Recheck, avoid hang in case someone just arrived. */ + if (ULONG_CMP_LT(rnp->exp_seq_rq, s)) + rnp->exp_seq_rq = s; + spin_unlock(&rnp->exp_lock); + } + wake_up_all(&rnp->exp_wq[(rsp->expedited_sequence >> 1) & 0x3]); + } + trace_rcu_exp_grace_period(rsp->name, s, TPS("endwake")); + mutex_unlock(&rsp->exp_wake_mutex); +} + +/** + * synchronize_sched_expedited - Brute-force RCU-sched grace period + * + * Wait for an RCU-sched grace period to elapse, but use a "big hammer" + * approach to force the grace period to end quickly. This consumes + * significant time on all CPUs and is unfriendly to real-time workloads, + * so is thus not recommended for any sort of common-case code. In fact, + * if you are using synchronize_sched_expedited() in a loop, please + * restructure your code to batch your updates, and then use a single + * synchronize_sched() instead. + * + * This implementation can be thought of as an application of sequence + * locking to expedited grace periods, but using the sequence counter to + * determine when someone else has already done the work instead of for + * retrying readers. + */ +void synchronize_sched_expedited(void) +{ + unsigned long s; + struct rcu_state *rsp = &rcu_sched_state; + + /* If only one CPU, this is automatically a grace period. */ + if (rcu_blocking_is_gp()) + return; + + /* If expedited grace periods are prohibited, fall back to normal. */ + if (rcu_gp_is_normal()) { + wait_rcu_gp(call_rcu_sched); + return; + } + + /* Take a snapshot of the sequence number. */ + s = rcu_exp_gp_seq_snap(rsp); + if (exp_funnel_lock(rsp, s)) + return; /* Someone else did our work for us. */ + + /* Initialize the rcu_node tree in preparation for the wait. */ + sync_rcu_exp_select_cpus(rsp, sync_sched_exp_handler); + + /* Wait and clean up, including waking everyone. */ + rcu_exp_wait_wake(rsp, s); +} +EXPORT_SYMBOL_GPL(synchronize_sched_expedited); -- cgit v0.10.2 From 40e0a6cfd53e37d9b8863cdbc0adb1f72e9311e7 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Fri, 15 Apr 2016 16:44:07 -0700 Subject: rcu: Move expedited code from tree_plugin.h to tree_exp.h People have been having some difficulty finding their way around the RCU code. This commit therefore pulls some of the expedited grace-period code from tree_plugin.h to a new tree_exp.h file. This commit is strictly code movement. Signed-off-by: Paul E. McKenney diff --git a/kernel/rcu/tree_exp.h b/kernel/rcu/tree_exp.h index db0909c..00a02a2 100644 --- a/kernel/rcu/tree_exp.h +++ b/kernel/rcu/tree_exp.h @@ -562,3 +562,97 @@ void synchronize_sched_expedited(void) rcu_exp_wait_wake(rsp, s); } EXPORT_SYMBOL_GPL(synchronize_sched_expedited); + +#ifdef CONFIG_PREEMPT_RCU + +/* + * Remote handler for smp_call_function_single(). If there is an + * RCU read-side critical section in effect, request that the + * next rcu_read_unlock() record the quiescent state up the + * ->expmask fields in the rcu_node tree. Otherwise, immediately + * report the quiescent state. + */ +static void sync_rcu_exp_handler(void *info) +{ + struct rcu_data *rdp; + struct rcu_state *rsp = info; + struct task_struct *t = current; + + /* + * Within an RCU read-side critical section, request that the next + * rcu_read_unlock() report. Unless this RCU read-side critical + * section has already blocked, in which case it is already set + * up for the expedited grace period to wait on it. + */ + if (t->rcu_read_lock_nesting > 0 && + !t->rcu_read_unlock_special.b.blocked) { + t->rcu_read_unlock_special.b.exp_need_qs = true; + return; + } + + /* + * We are either exiting an RCU read-side critical section (negative + * values of t->rcu_read_lock_nesting) or are not in one at all + * (zero value of t->rcu_read_lock_nesting). Or we are in an RCU + * read-side critical section that blocked before this expedited + * grace period started. Either way, we can immediately report + * the quiescent state. + */ + rdp = this_cpu_ptr(rsp->rda); + rcu_report_exp_rdp(rsp, rdp, true); +} + +/** + * synchronize_rcu_expedited - Brute-force RCU grace period + * + * Wait for an RCU-preempt grace period, but expedite it. The basic + * idea is to IPI all non-idle non-nohz online CPUs. The IPI handler + * checks whether the CPU is in an RCU-preempt critical section, and + * if so, it sets a flag that causes the outermost rcu_read_unlock() + * to report the quiescent state. On the other hand, if the CPU is + * not in an RCU read-side critical section, the IPI handler reports + * the quiescent state immediately. + * + * Although this is a greate improvement over previous expedited + * implementations, it is still unfriendly to real-time workloads, so is + * thus not recommended for any sort of common-case code. In fact, if + * you are using synchronize_rcu_expedited() in a loop, please restructure + * your code to batch your updates, and then Use a single synchronize_rcu() + * instead. + */ +void synchronize_rcu_expedited(void) +{ + struct rcu_state *rsp = rcu_state_p; + unsigned long s; + + /* If expedited grace periods are prohibited, fall back to normal. */ + if (rcu_gp_is_normal()) { + wait_rcu_gp(call_rcu); + return; + } + + s = rcu_exp_gp_seq_snap(rsp); + if (exp_funnel_lock(rsp, s)) + return; /* Someone else did our work for us. */ + + /* Initialize the rcu_node tree in preparation for the wait. */ + sync_rcu_exp_select_cpus(rsp, sync_rcu_exp_handler); + + /* Wait for ->blkd_tasks lists to drain, then wake everyone up. */ + rcu_exp_wait_wake(rsp, s); +} +EXPORT_SYMBOL_GPL(synchronize_rcu_expedited); + +#else /* #ifdef CONFIG_PREEMPT_RCU */ + +/* + * Wait for an rcu-preempt grace period, but make it happen quickly. + * But because preemptible RCU does not exist, map to rcu-sched. + */ +void synchronize_rcu_expedited(void) +{ + synchronize_sched_expedited(); +} +EXPORT_SYMBOL_GPL(synchronize_rcu_expedited); + +#endif /* #else #ifdef CONFIG_PREEMPT_RCU */ diff --git a/kernel/rcu/tree_plugin.h b/kernel/rcu/tree_plugin.h index ff1cd4e..695071d 100644 --- a/kernel/rcu/tree_plugin.h +++ b/kernel/rcu/tree_plugin.h @@ -681,84 +681,6 @@ void synchronize_rcu(void) } EXPORT_SYMBOL_GPL(synchronize_rcu); -/* - * Remote handler for smp_call_function_single(). If there is an - * RCU read-side critical section in effect, request that the - * next rcu_read_unlock() record the quiescent state up the - * ->expmask fields in the rcu_node tree. Otherwise, immediately - * report the quiescent state. - */ -static void sync_rcu_exp_handler(void *info) -{ - struct rcu_data *rdp; - struct rcu_state *rsp = info; - struct task_struct *t = current; - - /* - * Within an RCU read-side critical section, request that the next - * rcu_read_unlock() report. Unless this RCU read-side critical - * section has already blocked, in which case it is already set - * up for the expedited grace period to wait on it. - */ - if (t->rcu_read_lock_nesting > 0 && - !t->rcu_read_unlock_special.b.blocked) { - t->rcu_read_unlock_special.b.exp_need_qs = true; - return; - } - - /* - * We are either exiting an RCU read-side critical section (negative - * values of t->rcu_read_lock_nesting) or are not in one at all - * (zero value of t->rcu_read_lock_nesting). Or we are in an RCU - * read-side critical section that blocked before this expedited - * grace period started. Either way, we can immediately report - * the quiescent state. - */ - rdp = this_cpu_ptr(rsp->rda); - rcu_report_exp_rdp(rsp, rdp, true); -} - -/** - * synchronize_rcu_expedited - Brute-force RCU grace period - * - * Wait for an RCU-preempt grace period, but expedite it. The basic - * idea is to IPI all non-idle non-nohz online CPUs. The IPI handler - * checks whether the CPU is in an RCU-preempt critical section, and - * if so, it sets a flag that causes the outermost rcu_read_unlock() - * to report the quiescent state. On the other hand, if the CPU is - * not in an RCU read-side critical section, the IPI handler reports - * the quiescent state immediately. - * - * Although this is a greate improvement over previous expedited - * implementations, it is still unfriendly to real-time workloads, so is - * thus not recommended for any sort of common-case code. In fact, if - * you are using synchronize_rcu_expedited() in a loop, please restructure - * your code to batch your updates, and then Use a single synchronize_rcu() - * instead. - */ -void synchronize_rcu_expedited(void) -{ - struct rcu_state *rsp = rcu_state_p; - unsigned long s; - - /* If expedited grace periods are prohibited, fall back to normal. */ - if (rcu_gp_is_normal()) { - wait_rcu_gp(call_rcu); - return; - } - - s = rcu_exp_gp_seq_snap(rsp); - if (exp_funnel_lock(rsp, s)) - return; /* Someone else did our work for us. */ - - /* Initialize the rcu_node tree in preparation for the wait. */ - sync_rcu_exp_select_cpus(rsp, sync_rcu_exp_handler); - - /* Wait for ->blkd_tasks lists to drain, then wake everyone up. */ - rcu_exp_wait_wake(rsp, s); -} -EXPORT_SYMBOL_GPL(synchronize_rcu_expedited); - /** * rcu_barrier - Wait until all in-flight call_rcu() callbacks complete. * @@ -883,16 +805,6 @@ static void rcu_preempt_check_callbacks(void) } /* - * Wait for an rcu-preempt grace period, but make it happen quickly. - * But because preemptible RCU does not exist, map to rcu-sched. - */ -void synchronize_rcu_expedited(void) -{ - synchronize_sched_expedited(); -} -EXPORT_SYMBOL_GPL(synchronize_rcu_expedited); - -/* * Because preemptible RCU does not exist, rcu_barrier() is just * another name for rcu_barrier_sched(). */ -- cgit v0.10.2 From 810ce8b5df1c8338065f2ae1d2ec08cc566fbb8b Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Wed, 20 Apr 2016 09:22:15 -0700 Subject: rcu: Document RCU_NONIDLE() restrictions in comment header Signed-off-by: Paul E. McKenney diff --git a/include/linux/rcupdate.h b/include/linux/rcupdate.h index 5f1533e..c61b6b9 100644 --- a/include/linux/rcupdate.h +++ b/include/linux/rcupdate.h @@ -379,12 +379,13 @@ static inline void rcu_init_nohz(void) * in the inner idle loop. * * This macro provides the way out: RCU_NONIDLE(do_something_with_RCU()) - * will tell RCU that it needs to pay attending, invoke its argument - * (in this example, a call to the do_something_with_RCU() function), + * will tell RCU that it needs to pay attention, invoke its argument + * (in this example, calling the do_something_with_RCU() function), * and then tell RCU to go back to ignoring this CPU. It is permissible - * to nest RCU_NONIDLE() wrappers, but the nesting level is currently - * quite limited. If deeper nesting is required, it will be necessary - * to adjust DYNTICK_TASK_NESTING_VALUE accordingly. + * to nest RCU_NONIDLE() wrappers, but not indefinitely (but the limit is + * on the order of a million or so, even on 32-bit systems). It is + * not legal to block within RCU_NONIDLE(), nor is it permissible to + * transfer control either into or out of RCU_NONIDLE()'s statement. */ #define RCU_NONIDLE(a) \ do { \ -- cgit v0.10.2 From f8cbdee99b161cb08c3fb55200941028c5fe25c8 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Tue, 19 Apr 2016 13:03:18 -0700 Subject: torture: Simplify code, eliminate RCU_PERF_TEST_RUNNABLE This commit applies the infamous IS_ENABLED() macro to eliminate a #ifdef. It also eliminates the RCU_PERF_TEST_RUNNABLE Kconfig option in favor of the already-existing rcuperf.perf_runnable kernel boot parameter. Signed-off-by: Paul E. McKenney diff --git a/kernel/rcu/rcuperf.c b/kernel/rcu/rcuperf.c index 3cee0d8..afd174e 100644 --- a/kernel/rcu/rcuperf.c +++ b/kernel/rcu/rcuperf.c @@ -96,12 +96,7 @@ static int rcu_perf_writer_state; #define MAX_MEAS 10000 #define MIN_MEAS 100 -#if defined(MODULE) || defined(CONFIG_RCU_PERF_TEST_RUNNABLE) -#define RCUPERF_RUNNABLE_INIT 1 -#else -#define RCUPERF_RUNNABLE_INIT 0 -#endif -static int perf_runnable = RCUPERF_RUNNABLE_INIT; +static int perf_runnable = IS_ENABLED(MODULE); module_param(perf_runnable, int, 0444); MODULE_PARM_DESC(perf_runnable, "Start rcuperf at boot"); diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index b9cfdbf..cf6ddcd 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug @@ -1307,22 +1307,6 @@ config RCU_PERF_TEST Say M if you want the RCU performance tests to build as a module. Say N if you are unsure. -config RCU_PERF_TEST_RUNNABLE - bool "performance tests for RCU runnable by default" - depends on RCU_PERF_TEST = y - default n - help - This option provides a way to build the RCU performance tests - directly into the kernel without them starting up at boot time. - You can use /sys/module to manually override this setting. - This /proc file is available only when the RCU performance - tests have been built into the kernel. - - Say Y here if you want the RCU performance tests to start during - boot (you probably don't). - Say N here if you want the RCU performance tests to start only - after being manually enabled via /sys/module. - config RCU_TORTURE_TEST tristate "torture tests for RCU" depends on DEBUG_KERNEL -- cgit v0.10.2 From 4e9a073f60367157fd64b65490654c39d4c44321 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Tue, 19 Apr 2016 14:42:34 -0700 Subject: torture: Remove CONFIG_RCU_TORTURE_TEST_RUNNABLE, simplify code This commit removes CONFIG_RCU_TORTURE_TEST_RUNNABLE in favor of the already-existing rcutorture.torture_runnable kernel boot parameter. It also converts an #ifdef into IS_ENABLED(), saving a few lines of code. Signed-off-by: Paul E. McKenney diff --git a/kernel/rcu/rcutorture.c b/kernel/rcu/rcutorture.c index 084a28a..01cb57f 100644 --- a/kernel/rcu/rcutorture.c +++ b/kernel/rcu/rcutorture.c @@ -182,12 +182,7 @@ static const char *rcu_torture_writer_state_getname(void) return rcu_torture_writer_state_names[i]; } -#if defined(MODULE) || defined(CONFIG_RCU_TORTURE_TEST_RUNNABLE) -#define RCUTORTURE_RUNNABLE_INIT 1 -#else -#define RCUTORTURE_RUNNABLE_INIT 0 -#endif -static int torture_runnable = RCUTORTURE_RUNNABLE_INIT; +static int torture_runnable = IS_ENABLED(MODULE); module_param(torture_runnable, int, 0444); MODULE_PARM_DESC(torture_runnable, "Start rcutorture at boot"); diff --git a/kernel/rcu/tree_plugin.h b/kernel/rcu/tree_plugin.h index ff1cd4e..5b2d723 100644 --- a/kernel/rcu/tree_plugin.h +++ b/kernel/rcu/tree_plugin.h @@ -79,8 +79,6 @@ static void __init rcu_bootup_announce_oddness(void) pr_info("\tRCU dyntick-idle grace-period acceleration is enabled.\n"); if (IS_ENABLED(CONFIG_PROVE_RCU)) pr_info("\tRCU lockdep checking is enabled.\n"); - if (IS_ENABLED(CONFIG_RCU_TORTURE_TEST_RUNNABLE)) - pr_info("\tRCU torture testing starts during boot.\n"); if (RCU_NUM_LVLS >= 4) pr_info("\tFour(or more)-level hierarchy is enabled.\n"); if (RCU_FANOUT_LEAF != 16) diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index cf6ddcd..805b704 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug @@ -1324,23 +1324,6 @@ config RCU_TORTURE_TEST Say M if you want the RCU torture tests to build as a module. Say N if you are unsure. -config RCU_TORTURE_TEST_RUNNABLE - bool "torture tests for RCU runnable by default" - depends on RCU_TORTURE_TEST = y - default n - help - This option provides a way to build the RCU torture tests - directly into the kernel without them starting up at boot - time. You can use /proc/sys/kernel/rcutorture_runnable - to manually override this setting. This /proc file is - available only when the RCU torture tests have been built - into the kernel. - - Say Y here if you want the RCU torture tests to start during - boot (you probably don't). - Say N here if you want the RCU torture tests to start only - after being manually enabled via /proc. - config RCU_TORTURE_TEST_SLOW_PREINIT bool "Slow down RCU grace-period pre-initialization to expose races" depends on RCU_TORTURE_TEST -- cgit v0.10.2 From 6e8c66c867f919128855b77623ca9917770f1894 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Tue, 19 Apr 2016 16:50:44 -0700 Subject: torture: Forgive lengthy trace dumps and preemption This commit avoids killing qemu if a trace dump is making progress or if console log output is continuing and the console log timestamp does not exceed the total plus grace period. Signed-off-by: Paul E. McKenney diff --git a/tools/testing/selftests/rcutorture/bin/kvm-test-1-run.sh b/tools/testing/selftests/rcutorture/bin/kvm-test-1-run.sh index 4109f30..9b17c52 100755 --- a/tools/testing/selftests/rcutorture/bin/kvm-test-1-run.sh +++ b/tools/testing/selftests/rcutorture/bin/kvm-test-1-run.sh @@ -229,6 +229,7 @@ fi if test $commandcompleted -eq 0 -a -n "$qemu_pid" then echo Grace period for qemu job at pid $qemu_pid + oldline="`tail $resdir/console.log`" while : do kruntime=`awk 'BEGIN { print systime() - '"$kstarttime"' }' < /dev/null` @@ -238,13 +239,29 @@ then else break fi - if test $kruntime -ge $((seconds + $TORTURE_SHUTDOWN_GRACE)) + must_continue=no + newline="`tail $resdir/console.log`" + if test "$newline" != "$oldline" && echo $newline | grep -q ' [0-9]\+us : ' + then + must_continue=yes + fi + last_ts="`tail $resdir/console.log | grep '^\[ *[0-9]\+\.[0-9]\+]' | tail -1 | sed -e 's/^\[ *//' -e 's/\..*$//'`" + if test -z "last_ts" + then + last_ts=0 + fi + if test "$newline" != "$oldline" -a "$last_ts" -lt $((seconds + $TORTURE_SHUTDOWN_GRACE)) + then + must_continue=yes + fi + if test $must_continue = no -a $kruntime -ge $((seconds + $TORTURE_SHUTDOWN_GRACE)) then echo "!!! PID $qemu_pid hung at $kruntime vs. $seconds seconds" >> $resdir/Warnings 2>&1 kill -KILL $qemu_pid break fi - sleep 1 + oldline=$newline + sleep 10 done elif test -z "$qemu_pid" then -- cgit v0.10.2 From d95f5ba90fa6043a366958897fdef705af968b70 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Wed, 20 Apr 2016 17:18:41 -0700 Subject: torture: Break online and offline functions out of torture_onoff() This commit breaks torture_online() and torture_offline() out of torture_onoff() in preparation for allowing waketorture finer-grained control of its CPU-hotplug workload. Signed-off-by: Paul E. McKenney diff --git a/include/linux/torture.h b/include/linux/torture.h index 7759fc3..6685a73 100644 --- a/include/linux/torture.h +++ b/include/linux/torture.h @@ -50,6 +50,10 @@ do { if (verbose) pr_alert("%s" TORTURE_FLAG "!!! %s\n", torture_type, s); } while (0) /* Definitions for online/offline exerciser. */ +bool torture_offline(int cpu, long *n_onl_attempts, long *n_onl_successes, + unsigned long *sum_offl, int *min_onl, int *max_onl); +bool torture_online(int cpu, long *n_onl_attempts, long *n_onl_successes, + unsigned long *sum_onl, int *min_onl, int *max_onl); int torture_onoff_init(long ooholdoff, long oointerval); void torture_onoff_stats(void); bool torture_onoff_failures(void); diff --git a/kernel/torture.c b/kernel/torture.c index fa0bdee..fb39a06 100644 --- a/kernel/torture.c +++ b/kernel/torture.c @@ -82,6 +82,104 @@ static int min_online = -1; static int max_online; /* + * Attempt to take a CPU offline. Return false if the CPU is already + * offline or if it is not subject to CPU-hotplug operations. The + * caller can detect other failures by looking at the statistics. + */ +bool torture_offline(int cpu, long *n_offl_attempts, long *n_offl_successes, + unsigned long *sum_offl, int *min_offl, int *max_offl) +{ + unsigned long delta; + int ret; + unsigned long starttime; + + if (!cpu_online(cpu) || !cpu_is_hotpluggable(cpu)) + return false; + + if (verbose) + pr_alert("%s" TORTURE_FLAG + "torture_onoff task: offlining %d\n", + torture_type, cpu); + starttime = jiffies; + (*n_offl_attempts)++; + ret = cpu_down(cpu); + if (ret) { + if (verbose) + pr_alert("%s" TORTURE_FLAG + "torture_onoff task: offline %d failed: errno %d\n", + torture_type, cpu, ret); + } else { + if (verbose) + pr_alert("%s" TORTURE_FLAG + "torture_onoff task: offlined %d\n", + torture_type, cpu); + (*n_offl_successes)++; + delta = jiffies - starttime; + sum_offl += delta; + if (*min_offl < 0) { + *min_offl = delta; + *max_offl = delta; + } + if (*min_offl > delta) + *min_offl = delta; + if (*max_offl < delta) + *max_offl = delta; + } + + return true; +} +EXPORT_SYMBOL_GPL(torture_offline); + +/* + * Attempt to bring a CPU online. Return false if the CPU is already + * online or if it is not subject to CPU-hotplug operations. The + * caller can detect other failures by looking at the statistics. + */ +bool torture_online(int cpu, long *n_onl_attempts, long *n_onl_successes, + unsigned long *sum_onl, int *min_onl, int *max_onl) +{ + unsigned long delta; + int ret; + unsigned long starttime; + + if (cpu_online(cpu) || !cpu_is_hotpluggable(cpu)) + return false; + + if (verbose) + pr_alert("%s" TORTURE_FLAG + "torture_onoff task: onlining %d\n", + torture_type, cpu); + starttime = jiffies; + (*n_onl_attempts)++; + ret = cpu_up(cpu); + if (ret) { + if (verbose) + pr_alert("%s" TORTURE_FLAG + "torture_onoff task: online %d failed: errno %d\n", + torture_type, cpu, ret); + } else { + if (verbose) + pr_alert("%s" TORTURE_FLAG + "torture_onoff task: onlined %d\n", + torture_type, cpu); + (*n_onl_successes)++; + delta = jiffies - starttime; + *sum_onl += delta; + if (*min_onl < 0) { + *min_onl = delta; + *max_onl = delta; + } + if (*min_onl > delta) + *min_onl = delta; + if (*max_onl < delta) + *max_onl = delta; + } + + return true; +} +EXPORT_SYMBOL_GPL(torture_online); + +/* * Execute random CPU-hotplug operations at the interval specified * by the onoff_interval. */ @@ -89,11 +187,8 @@ static int torture_onoff(void *arg) { int cpu; - unsigned long delta; int maxcpu = -1; DEFINE_TORTURE_RANDOM(rand); - int ret; - unsigned long starttime; VERBOSE_TOROUT_STRING("torture_onoff task started"); for_each_online_cpu(cpu) @@ -106,67 +201,12 @@ torture_onoff(void *arg) } while (!torture_must_stop()) { cpu = (torture_random(&rand) >> 4) % (maxcpu + 1); - if (cpu_online(cpu) && cpu_is_hotpluggable(cpu)) { - if (verbose) - pr_alert("%s" TORTURE_FLAG - "torture_onoff task: offlining %d\n", - torture_type, cpu); - starttime = jiffies; - n_offline_attempts++; - ret = cpu_down(cpu); - if (ret) { - if (verbose) - pr_alert("%s" TORTURE_FLAG - "torture_onoff task: offline %d failed: errno %d\n", - torture_type, cpu, ret); - } else { - if (verbose) - pr_alert("%s" TORTURE_FLAG - "torture_onoff task: offlined %d\n", - torture_type, cpu); - n_offline_successes++; - delta = jiffies - starttime; - sum_offline += delta; - if (min_offline < 0) { - min_offline = delta; - max_offline = delta; - } - if (min_offline > delta) - min_offline = delta; - if (max_offline < delta) - max_offline = delta; - } - } else if (cpu_is_hotpluggable(cpu)) { - if (verbose) - pr_alert("%s" TORTURE_FLAG - "torture_onoff task: onlining %d\n", - torture_type, cpu); - starttime = jiffies; - n_online_attempts++; - ret = cpu_up(cpu); - if (ret) { - if (verbose) - pr_alert("%s" TORTURE_FLAG - "torture_onoff task: online %d failed: errno %d\n", - torture_type, cpu, ret); - } else { - if (verbose) - pr_alert("%s" TORTURE_FLAG - "torture_onoff task: onlined %d\n", - torture_type, cpu); - n_online_successes++; - delta = jiffies - starttime; - sum_online += delta; - if (min_online < 0) { - min_online = delta; - max_online = delta; - } - if (min_online > delta) - min_online = delta; - if (max_online < delta) - max_online = delta; - } - } + if (!torture_offline(cpu, + &n_offline_attempts, &n_offline_successes, + &sum_offline, &min_offline, &max_offline)) + torture_online(cpu, + &n_online_attempts, &n_online_successes, + &sum_online, &min_online, &max_online); schedule_timeout_interruptible(onoff_interval); } torture_kthread_stopping("torture_onoff"); -- cgit v0.10.2 From 682ed706c5bb1526b001bc69aa4ee1e8b456bfa6 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Thu, 21 Apr 2016 12:03:06 -0700 Subject: torture: Add starvation events to error summary This commit adds a string of the form "Starves: 10" to the summary line for error conditions found in the console output. Signed-off-by: Paul E. McKenney diff --git a/tools/testing/selftests/rcutorture/bin/parse-console.sh b/tools/testing/selftests/rcutorture/bin/parse-console.sh index 5eb49b7..08aa7d5 100755 --- a/tools/testing/selftests/rcutorture/bin/parse-console.sh +++ b/tools/testing/selftests/rcutorture/bin/parse-console.sh @@ -33,7 +33,7 @@ if grep -Pq '\x00' < $file then print_warning Console output contains nul bytes, old qemu still running? fi -egrep 'Badness|WARNING:|Warn|BUG|===========|Call Trace:|Oops:|detected stalls on CPUs/tasks:|self-detected stall on CPU|Stall ended before state dump start|\?\?\? Writer stall state' < $file | grep -v 'ODEBUG: ' | grep -v 'Warning: unable to open an initial console' > $1.diags +egrep 'Badness|WARNING:|Warn|BUG|===========|Call Trace:|Oops:|detected stalls on CPUs/tasks:|self-detected stall on CPU|Stall ended before state dump start|\?\?\? Writer stall state|rcu_.*kthread starved for' < $file | grep -v 'ODEBUG: ' | grep -v 'Warning: unable to open an initial console' > $1.diags if test -s $1.diags then print_warning Assertion failure in $file $title @@ -69,6 +69,11 @@ then then summary="$summary Stalls: $n_stalls" fi + n_starves=`grep -c 'rcu_.*kthread starved for' $1` + if test "$n_starves" -ne 0 + then + summary="$summary Starves: $n_starves" + fi print_warning Summary: $summary else rm $1.diags -- cgit v0.10.2 From 750db0f5f7d0ff6b86158015f02c275702639b20 Mon Sep 17 00:00:00 2001 From: Boqun Feng Date: Mon, 2 May 2016 10:30:00 +0800 Subject: torture: Stop onoff task if there is only one cpu If the whole system has only one cpu, that cpu won't be able to be offlined, so there is no need onoff task is stil running. Signed-off-by: Boqun Feng Signed-off-by: Paul E. McKenney diff --git a/kernel/torture.c b/kernel/torture.c index fb39a06..75961b3 100644 --- a/kernel/torture.c +++ b/kernel/torture.c @@ -194,6 +194,12 @@ torture_onoff(void *arg) for_each_online_cpu(cpu) maxcpu = cpu; WARN_ON(maxcpu < 0); + + if (maxcpu == 0) { + VERBOSE_TOROUT_STRING("Only one CPU, so CPU-hotplug testing is disabled"); + goto stop; + } + if (onoff_holdoff > 0) { VERBOSE_TOROUT_STRING("torture_onoff begin holdoff"); schedule_timeout_interruptible(onoff_holdoff); @@ -209,6 +215,8 @@ torture_onoff(void *arg) &sum_online, &min_online, &max_online); schedule_timeout_interruptible(onoff_interval); } + +stop: torture_kthread_stopping("torture_onoff"); return 0; } -- cgit v0.10.2 From e5731b584b3e521e3db6fda9cdfe10646d3413a3 Mon Sep 17 00:00:00 2001 From: Boqun Feng Date: Thu, 19 May 2016 11:42:21 +0800 Subject: rcutorture/doc: Create initrd using dracut Using dracut is another way to get an initramfs for KVM-based RCU torture tests, which is more flexible than using the host's initramfs image, because modules and binaries may be added or removed via dracut command options. So add an example in the document, in case that there are some situations where host's initramfs couldn't be used. Signed-off-by: Boqun Feng Reviewed-by: Josh Triplett Signed-off-by: Paul E. McKenney diff --git a/tools/testing/selftests/rcutorture/doc/initrd.txt b/tools/testing/selftests/rcutorture/doc/initrd.txt index 4170e71..833f826 100644 --- a/tools/testing/selftests/rcutorture/doc/initrd.txt +++ b/tools/testing/selftests/rcutorture/doc/initrd.txt @@ -13,6 +13,22 @@ cd initrd cpio -id < /tmp/initrd.img.zcat ------------------------------------------------------------------------ +Another way to create an initramfs image is using "dracut"[1], which is +available on many distros, however the initramfs dracut generates is a cpio +archive with another cpio archive in it, so an extra step is needed to create +the initrd directory hierarchy. + +Here are the commands to create a initrd directory for rcutorture using +dracut: + +------------------------------------------------------------------------ +dracut --no-hostonly --no-hostonly-cmdline --module "base bash shutdown" /tmp/initramfs.img +cd tools/testing/selftests/rcutorture +mkdir initrd +cd initrd +/usr/lib/dracut/skipcpio /tmp/initramfs.img | zcat | cpio -id < /tmp/initramfs.img +------------------------------------------------------------------------ + Interestingly enough, if you are running rcutorture, you don't really need userspace in many cases. Running without userspace has the advantage of allowing you to test your kernel independently of the @@ -89,3 +105,9 @@ while : do sleep 10 done +------------------------------------------------------------------------ + +References: +[1]: https://dracut.wiki.kernel.org/index.php/Main_Page +[2]: http://blog.elastocloud.org/2015/06/rapid-linux-kernel-devtest-with-qemu.html +[3]: https://www.centos.org/forums/viewtopic.php?t=51621 -- cgit v0.10.2 From 1b900c6a26de26e111617d6b69b64aaee7b9de01 Mon Sep 17 00:00:00 2001 From: Boqun Feng Date: Thu, 19 May 2016 11:42:22 +0800 Subject: rcutorture: Use vmlinux as the fallback kernel image The vmlinux image is available for all the architectures, and suitable for running a KVM guest by QEMU, besides, we used to copy the vmlinux to $resdir anyway. Therefore it makes sense to use it as the fallback kernel image for rcutorture KVM tests. This patch makes identify_boot_image() return vmlinux if ${TORTURE_BOOT_IMAGE} is not set on non-x86 architectures, also fixes several places that hard-code "bzImage" as $KERNEL. This also fixes a problem that PPC doesn't have a bzImage file as build results. Signed-off-by: Boqun Feng Reviewed-by: Josh Triplett Signed-off-by: Paul E. McKenney diff --git a/tools/testing/selftests/rcutorture/bin/functions.sh b/tools/testing/selftests/rcutorture/bin/functions.sh index b325470..6161801 100644 --- a/tools/testing/selftests/rcutorture/bin/functions.sh +++ b/tools/testing/selftests/rcutorture/bin/functions.sh @@ -99,8 +99,9 @@ configfrag_hotplug_cpu () { # identify_boot_image qemu-cmd # # Returns the relative path to the kernel build image. This will be -# arch//boot/bzImage unless overridden with the TORTURE_BOOT_IMAGE -# environment variable. +# arch//boot/bzImage or vmlinux if bzImage is not a target for the +# architecture, unless overridden with the TORTURE_BOOT_IMAGE environment +# variable. identify_boot_image () { if test -n "$TORTURE_BOOT_IMAGE" then @@ -110,11 +111,8 @@ identify_boot_image () { qemu-system-x86_64|qemu-system-i386) echo arch/x86/boot/bzImage ;; - qemu-system-ppc64) - echo arch/powerpc/boot/bzImage - ;; *) - echo "" + echo vmlinux ;; esac fi diff --git a/tools/testing/selftests/rcutorture/bin/kvm-test-1-run.sh b/tools/testing/selftests/rcutorture/bin/kvm-test-1-run.sh index 9b17c52..8dc5e463 100755 --- a/tools/testing/selftests/rcutorture/bin/kvm-test-1-run.sh +++ b/tools/testing/selftests/rcutorture/bin/kvm-test-1-run.sh @@ -96,7 +96,8 @@ if test "$base_resdir" != "$resdir" -a -f $base_resdir/bzImage -a -f $base_resdi then # Rerunning previous test, so use that test's kernel. QEMU="`identify_qemu $base_resdir/vmlinux`" - KERNEL=$base_resdir/bzImage + BOOT_IMAGE="`identify_boot_image $QEMU`" + KERNEL=$base_resdir/${BOOT_IMAGE##*/} # use the last component of ${BOOT_IMAGE} ln -s $base_resdir/Make*.out $resdir # for kvm-recheck.sh ln -s $base_resdir/.config $resdir # for kvm-recheck.sh elif kvm-build.sh $config_template $builddir $T @@ -110,7 +111,7 @@ then if test -n "$BOOT_IMAGE" then cp $builddir/$BOOT_IMAGE $resdir - KERNEL=$resdir/bzImage + KERNEL=$resdir/${BOOT_IMAGE##*/} else echo No identifiable boot image, not running KVM, see $resdir. echo Do the torture scripts know about your architecture? -- cgit v0.10.2 From 1b2f48f29e5507a15c1fa8264362d30c02607dcd Mon Sep 17 00:00:00 2001 From: Boqun Feng Date: Thu, 19 May 2016 11:42:23 +0800 Subject: rcutorture: Make -soundhw a x86 specific option The option "-soundhw pcspk" gives me a error on PPC as follow: qemu-system-ppc64: ISA bus not available for pcspk This means this option doesn't work on ppc by default. So simply make this an x86-specific option via identify_qemu_args(). Signed-off-by: Boqun Feng Reviewed-by: Josh Triplett Signed-off-by: Paul E. McKenney diff --git a/tools/testing/selftests/rcutorture/bin/functions.sh b/tools/testing/selftests/rcutorture/bin/functions.sh index 6161801..77fdb46c 100644 --- a/tools/testing/selftests/rcutorture/bin/functions.sh +++ b/tools/testing/selftests/rcutorture/bin/functions.sh @@ -171,6 +171,7 @@ identify_qemu_append () { identify_qemu_args () { case "$1" in qemu-system-x86_64|qemu-system-i386) + echo -soundhw pcspk ;; qemu-system-ppc64) echo -enable-kvm -M pseries -cpu POWER7 -nodefaults diff --git a/tools/testing/selftests/rcutorture/bin/kvm-test-1-run.sh b/tools/testing/selftests/rcutorture/bin/kvm-test-1-run.sh index 8dc5e463..ea6e373 100755 --- a/tools/testing/selftests/rcutorture/bin/kvm-test-1-run.sh +++ b/tools/testing/selftests/rcutorture/bin/kvm-test-1-run.sh @@ -8,9 +8,9 @@ # # Usage: kvm-test-1-run.sh config builddir resdir seconds qemu-args boot_args # -# qemu-args defaults to "-enable-kvm -soundhw pcspk -nographic", along with -# arguments specifying the number of CPUs and other -# options generated from the underlying CPU architecture. +# qemu-args defaults to "-enable-kvm -nographic", along with arguments +# specifying the number of CPUs and other options +# generated from the underlying CPU architecture. # boot_args defaults to value returned by the per_version_boot_params # shell function. # @@ -148,7 +148,7 @@ then fi # Generate -smp qemu argument. -qemu_args="-enable-kvm -soundhw pcspk -nographic $qemu_args" +qemu_args="-enable-kvm -nographic $qemu_args" cpu_count=`configNR_CPUS.sh $config_template` cpu_count=`configfrag_boot_cpus "$boot_args" "$config_template" "$cpu_count"` vcpus=`identify_qemu_vcpus` -- cgit v0.10.2 From d5e953739ca6874caa6a656b67593cafb223b700 Mon Sep 17 00:00:00 2001 From: Boqun Feng Date: Thu, 19 May 2016 11:42:24 +0800 Subject: rcutorture: Don't specify the cpu type of QEMU on PPC Do not restrict the cpu type to POWER7 for QEMU as we have POWER8 now. Signed-off-by: Boqun Feng Reviewed-by: Josh Triplett Signed-off-by: Paul E. McKenney diff --git a/tools/testing/selftests/rcutorture/bin/functions.sh b/tools/testing/selftests/rcutorture/bin/functions.sh index 77fdb46c..56ac202 100644 --- a/tools/testing/selftests/rcutorture/bin/functions.sh +++ b/tools/testing/selftests/rcutorture/bin/functions.sh @@ -174,7 +174,7 @@ identify_qemu_args () { echo -soundhw pcspk ;; qemu-system-ppc64) - echo -enable-kvm -M pseries -cpu POWER7 -nodefaults + echo -enable-kvm -M pseries -nodefaults echo -device spapr-vscsi if test -n "$TORTURE_QEMU_INTERACTIVE" -a -n "$TORTURE_QEMU_MAC" then -- cgit v0.10.2 From 5ef20f872d10c695c30ee036f11c687a23944158 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Mon, 23 May 2016 14:18:48 -0700 Subject: rcutorture: Drop "-soundhw pcspkr" from x86 boot arguments Because recent testing shows that "-soundhw pcspkr" is no longer required in the kernel boot arguments, this commit drops this qemu argument. Reported-by: Josh Triplett Signed-off-by: Paul E. McKenney diff --git a/tools/testing/selftests/rcutorture/bin/functions.sh b/tools/testing/selftests/rcutorture/bin/functions.sh index 56ac202..1426a9b 100644 --- a/tools/testing/selftests/rcutorture/bin/functions.sh +++ b/tools/testing/selftests/rcutorture/bin/functions.sh @@ -171,7 +171,6 @@ identify_qemu_append () { identify_qemu_args () { case "$1" in qemu-system-x86_64|qemu-system-i386) - echo -soundhw pcspk ;; qemu-system-ppc64) echo -enable-kvm -M pseries -nodefaults -- cgit v0.10.2 From af06d4f74a7d2132c805339bfd5ab771b5706f42 Mon Sep 17 00:00:00 2001 From: Boqun Feng Date: Wed, 25 May 2016 09:25:33 +0800 Subject: rcuperf: Don't treat gp_exp mis-setting as a WARN 0day found a boot warning triggered in rcu_perf_writer() on !SMP kernel: WARN_ON(rcu_gp_is_normal() && gp_exp); , the root cause of which is trying to measure expedited grace periods(by setting gp_exp to true by default) when all the grace periods are normal(TINY RCU only has normal grace periods). However, such a mis-setting would only result in failing to measure the performance for a specific kind of grace periods, therefore using a WARN_ON to check this is a little overkilling. We could handle this inside rcuperf module via some error messages to tell users about the mis-settings. Therefore this patch removes the WARN_ON in rcu_perf_writer() and handles those checkings in rcu_perf_init() with plain if() code. Moreover, this patch changes the default value of gp_exp to 1) align with rcutorture tests and 2) make the default setting work for all RCU implementations by default. Suggested-by: Paul E. McKenney Signed-off-by: Boqun Feng Fixes: http://lkml.kernel.org/r/57411b10.mFvG0+AgcrMXGtcj%fengguang.wu@intel.com Signed-off-by: Paul E. McKenney diff --git a/kernel/rcu/rcuperf.c b/kernel/rcu/rcuperf.c index afd174e..7b2dbdf 100644 --- a/kernel/rcu/rcuperf.c +++ b/kernel/rcu/rcuperf.c @@ -58,7 +58,7 @@ MODULE_AUTHOR("Paul E. McKenney "); #define VERBOSE_PERFOUT_ERRSTRING(s) \ do { if (verbose) pr_alert("%s" PERF_FLAG "!!! %s\n", perf_type, s); } while (0) -torture_param(bool, gp_exp, true, "Use expedited GP wait primitives"); +torture_param(bool, gp_exp, false, "Use expedited GP wait primitives"); torture_param(int, holdoff, 10, "Holdoff time before test start (s)"); torture_param(int, nreaders, -1, "Number of RCU reader threads"); torture_param(int, nwriters, -1, "Number of RCU updater threads"); @@ -358,8 +358,6 @@ rcu_perf_writer(void *arg) u64 *wdpp = writer_durations[me]; VERBOSE_PERFOUT_STRING("rcu_perf_writer task started"); - WARN_ON(rcu_gp_is_expedited() && !rcu_gp_is_normal() && !gp_exp); - WARN_ON(rcu_gp_is_normal() && gp_exp); WARN_ON(!wdpp); set_cpus_allowed_ptr(current, cpumask_of(me % nr_cpu_ids)); sp.sched_priority = 1; @@ -626,6 +624,16 @@ rcu_perf_init(void) firsterr = -ENOMEM; goto unwind; } + if (rcu_gp_is_expedited() && !rcu_gp_is_normal() && !gp_exp) { + VERBOSE_PERFOUT_ERRSTRING("All grace periods expedited, no normal ones to measure!"); + firsterr = -EINVAL; + goto unwind; + } + if (rcu_gp_is_normal() && gp_exp) { + VERBOSE_PERFOUT_ERRSTRING("All grace periods normal, no expedited ones to measure!"); + firsterr = -EINVAL; + goto unwind; + } for (i = 0; i < nrealwriters; i++) { writer_durations[i] = kcalloc(MAX_MEAS, sizeof(*writer_durations[i]), -- cgit v0.10.2 From 65cbea5bbd32280f4620c20a6f651c37a6058752 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Wed, 1 Jun 2016 13:09:19 -0700 Subject: torture: Inflict default jitter This commit enables jitter by default. It may be manually disabled by passing "--jitter 0" to kvm.sh. Signed-off-by: Paul E. McKenney diff --git a/tools/testing/selftests/rcutorture/bin/kvm.sh b/tools/testing/selftests/rcutorture/bin/kvm.sh index 0d59814..0aed965 100755 --- a/tools/testing/selftests/rcutorture/bin/kvm.sh +++ b/tools/testing/selftests/rcutorture/bin/kvm.sh @@ -48,7 +48,7 @@ resdir="" configs="" cpus=0 ds=`date +%Y.%m.%d-%H:%M:%S` -jitter=0 +jitter="-1" . functions.sh -- cgit v0.10.2 From 05dbbfe753792dcebb6b85d84fa5926f09723cfe Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Mon, 13 Jun 2016 15:20:39 +0000 Subject: rcutorture: Fix error return code in rcu_perf_init() Fix to return a negative error code -ENOMEM from kcalloc() error handling case instead of 0, as done elsewhere in this function. Signed-off-by: Wei Yongjun Signed-off-by: Paul E. McKenney diff --git a/kernel/rcu/rcuperf.c b/kernel/rcu/rcuperf.c index 7b2dbdf..d38ab08 100644 --- a/kernel/rcu/rcuperf.c +++ b/kernel/rcu/rcuperf.c @@ -638,8 +638,10 @@ rcu_perf_init(void) writer_durations[i] = kcalloc(MAX_MEAS, sizeof(*writer_durations[i]), GFP_KERNEL); - if (!writer_durations[i]) + if (!writer_durations[i]) { + firsterr = -ENOMEM; goto unwind; + } firsterr = torture_create_kthread(rcu_perf_writer, (void *)i, writer_tasks[i]); if (firsterr) -- cgit v0.10.2 From 5823d0893ec284f37902e2ecd332dbb396a143d1 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 14 Jun 2016 21:29:45 +0300 Subject: x86/platform/intel-mid: Add Power Management Unit driver Add Power Management Unit driver to handle power states of South Complex devices on Intel Tangier. In the future it might be expanded to cover North Complex devices as well. With this driver the power state of the host controllers such as SPI, I2C, UART, eMMC, and DMA would be managed. Signed-off-by: Andy Shevchenko Cc: Bjorn Helgaas Cc: David Cohen Cc: Linus Torvalds Cc: Mika Westerberg Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: linux-pci@vger.kernel.org Link: http://lkml.kernel.org/r/1465928985-12113-1-git-send-email-andriy.shevchenko@linux.intel.com [ Minor readability edits. ] Signed-off-by: Ingo Molnar diff --git a/arch/x86/include/asm/intel-mid.h b/arch/x86/include/asm/intel-mid.h index 7c5af12..38498a4 100644 --- a/arch/x86/include/asm/intel-mid.h +++ b/arch/x86/include/asm/intel-mid.h @@ -12,9 +12,17 @@ #define _ASM_X86_INTEL_MID_H #include +#include #include extern int intel_mid_pci_init(void); +extern int intel_mid_pci_set_power_state(struct pci_dev *pdev, pci_power_t state); + +#define INTEL_MID_PWR_LSS_OFFSET 4 +#define INTEL_MID_PWR_LSS_TYPE (1 << 7) + +extern int intel_mid_pwr_get_lss_id(struct pci_dev *pdev); + extern int get_gpio_by_name(const char *name); extern void intel_scu_device_register(struct platform_device *pdev); extern int __init sfi_parse_mrtc(struct sfi_table_header *table); diff --git a/arch/x86/pci/intel_mid_pci.c b/arch/x86/pci/intel_mid_pci.c index ae97f24..a971043 100644 --- a/arch/x86/pci/intel_mid_pci.c +++ b/arch/x86/pci/intel_mid_pci.c @@ -316,14 +316,44 @@ static void pci_d3delay_fixup(struct pci_dev *dev) } DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_ANY_ID, pci_d3delay_fixup); -static void mrst_power_off_unused_dev(struct pci_dev *dev) +static void mid_power_off_dev(struct pci_dev *dev) { + u16 pmcsr; + + /* + * Update current state first, otherwise PCI core enforces PCI_D0 in + * pci_set_power_state() for devices which status was PCI_UNKNOWN. + */ + pci_read_config_word(dev, dev->pm_cap + PCI_PM_CTRL, &pmcsr); + dev->current_state = (pci_power_t __force)(pmcsr & PCI_PM_CTRL_STATE_MASK); + pci_set_power_state(dev, PCI_D3hot); } -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x0801, mrst_power_off_unused_dev); -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x0809, mrst_power_off_unused_dev); -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x080C, mrst_power_off_unused_dev); -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x0815, mrst_power_off_unused_dev); + +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x0801, mid_power_off_dev); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x0809, mid_power_off_dev); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x080C, mid_power_off_dev); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x0815, mid_power_off_dev); + +static void mrfld_power_off_dev(struct pci_dev *dev) +{ + int id; + + if (!pci_soc_mode) + return; + + id = intel_mid_pwr_get_lss_id(dev); + if (id < 0) + return; + + /* + * This sets only PMCSR bits. The actual power off will happen in + * arch/x86/platform/intel-mid/pwr.c. + */ + mid_power_off_dev(dev); +} + +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_ANY_ID, mrfld_power_off_dev); /* * Langwell devices reside at fixed offsets, don't try to move them. diff --git a/arch/x86/platform/intel-mid/Makefile b/arch/x86/platform/intel-mid/Makefile index 0ce1b19..aebb5b9 100644 --- a/arch/x86/platform/intel-mid/Makefile +++ b/arch/x86/platform/intel-mid/Makefile @@ -1,4 +1,4 @@ -obj-$(CONFIG_X86_INTEL_MID) += intel-mid.o intel_mid_vrtc.o mfld.o mrfl.o +obj-$(CONFIG_X86_INTEL_MID) += intel-mid.o intel_mid_vrtc.o mfld.o mrfl.o pwr.o # SFI specific code ifdef CONFIG_X86_INTEL_MID diff --git a/arch/x86/platform/intel-mid/pwr.c b/arch/x86/platform/intel-mid/pwr.c new file mode 100644 index 0000000..59faf05 --- /dev/null +++ b/arch/x86/platform/intel-mid/pwr.c @@ -0,0 +1,416 @@ +/* + * Intel MID Power Management Unit (PWRMU) device driver + * + * Copyright (C) 2016, Intel Corporation + * + * Author: Andy Shevchenko + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * Intel MID Power Management Unit device driver handles the South Complex PCI + * devices such as GPDMA, SPI, I2C, PWM, and so on. By default PCI core + * modifies bits in PMCSR register in the PCI configuration space. This is not + * enough on some SoCs like Intel Tangier. In such case PCI core sets a new + * power state of the device in question through a PM hook registered in struct + * pci_platform_pm_ops (see drivers/pci/pci-mid.c). + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +/* Registers */ +#define PM_STS 0x00 +#define PM_CMD 0x04 +#define PM_ICS 0x08 +#define PM_WKC(x) (0x10 + (x) * 4) +#define PM_WKS(x) (0x18 + (x) * 4) +#define PM_SSC(x) (0x20 + (x) * 4) +#define PM_SSS(x) (0x30 + (x) * 4) + +/* Bits in PM_STS */ +#define PM_STS_BUSY (1 << 8) + +/* Bits in PM_CMD */ +#define PM_CMD_CMD(x) ((x) << 0) +#define PM_CMD_IOC (1 << 8) +#define PM_CMD_D3cold (1 << 21) + +/* List of commands */ +#define CMD_SET_CFG 0x01 + +/* Bits in PM_ICS */ +#define PM_ICS_INT_STATUS(x) ((x) & 0xff) +#define PM_ICS_IE (1 << 8) +#define PM_ICS_IP (1 << 9) +#define PM_ICS_SW_INT_STS (1 << 10) + +/* List of interrupts */ +#define INT_INVALID 0 +#define INT_CMD_COMPLETE 1 +#define INT_CMD_ERR 2 +#define INT_WAKE_EVENT 3 +#define INT_LSS_POWER_ERR 4 +#define INT_S0iX_MSG_ERR 5 +#define INT_NO_C6 6 +#define INT_TRIGGER_ERR 7 +#define INT_INACTIVITY 8 + +/* South Complex devices */ +#define LSS_MAX_SHARED_DEVS 4 +#define LSS_MAX_DEVS 64 + +#define LSS_WS_BITS 1 /* wake state width */ +#define LSS_PWS_BITS 2 /* power state width */ + +/* Supported device IDs */ +#define PCI_DEVICE_ID_TANGIER 0x11a1 + +struct mid_pwr_dev { + struct pci_dev *pdev; + pci_power_t state; +}; + +struct mid_pwr { + struct device *dev; + void __iomem *regs; + int irq; + bool available; + + struct mutex lock; + struct mid_pwr_dev lss[LSS_MAX_DEVS][LSS_MAX_SHARED_DEVS]; +}; + +static struct mid_pwr *midpwr; + +static u32 mid_pwr_get_state(struct mid_pwr *pwr, int reg) +{ + return readl(pwr->regs + PM_SSS(reg)); +} + +static void mid_pwr_set_state(struct mid_pwr *pwr, int reg, u32 value) +{ + writel(value, pwr->regs + PM_SSC(reg)); +} + +static void mid_pwr_set_wake(struct mid_pwr *pwr, int reg, u32 value) +{ + writel(value, pwr->regs + PM_WKC(reg)); +} + +static void mid_pwr_interrupt_disable(struct mid_pwr *pwr) +{ + writel(~PM_ICS_IE, pwr->regs + PM_ICS); +} + +static bool mid_pwr_is_busy(struct mid_pwr *pwr) +{ + return !!(readl(pwr->regs + PM_STS) & PM_STS_BUSY); +} + +/* Wait 500ms that the latest PWRMU command finished */ +static int mid_pwr_wait(struct mid_pwr *pwr) +{ + unsigned int count = 500000; + bool busy; + + do { + busy = mid_pwr_is_busy(pwr); + if (!busy) + return 0; + udelay(1); + } while (--count); + + return -EBUSY; +} + +static int mid_pwr_wait_for_cmd(struct mid_pwr *pwr, u8 cmd) +{ + writel(PM_CMD_CMD(cmd), pwr->regs + PM_CMD); + return mid_pwr_wait(pwr); +} + +static int __update_power_state(struct mid_pwr *pwr, int reg, int bit, int new) +{ + int curstate; + u32 power; + int ret; + + /* Check if the device is already in desired state */ + power = mid_pwr_get_state(pwr, reg); + curstate = (power >> bit) & 3; + if (curstate == new) + return 0; + + /* Update the power state */ + mid_pwr_set_state(pwr, reg, (power & ~(3 << bit)) | (new << bit)); + + /* Send command to SCU */ + ret = mid_pwr_wait_for_cmd(pwr, CMD_SET_CFG); + if (ret) + return ret; + + /* Check if the device is already in desired state */ + power = mid_pwr_get_state(pwr, reg); + curstate = (power >> bit) & 3; + if (curstate != new) + return -EAGAIN; + + return 0; +} + +static pci_power_t __find_weakest_power_state(struct mid_pwr_dev *lss, + struct pci_dev *pdev, + pci_power_t state) +{ + pci_power_t weakest = PCI_D3hot; + unsigned int j; + + /* Find device in cache or first free cell */ + for (j = 0; j < LSS_MAX_SHARED_DEVS; j++) { + if (lss[j].pdev == pdev || !lss[j].pdev) + break; + } + + /* Store the desired state in cache */ + if (j < LSS_MAX_SHARED_DEVS) { + lss[j].pdev = pdev; + lss[j].state = state; + } else { + dev_WARN(&pdev->dev, "No room for device in PWRMU LSS cache\n"); + weakest = state; + } + + /* Find the power state we may use */ + for (j = 0; j < LSS_MAX_SHARED_DEVS; j++) { + if (lss[j].state < weakest) + weakest = lss[j].state; + } + + return weakest; +} + +static int __set_power_state(struct mid_pwr *pwr, struct pci_dev *pdev, + pci_power_t state, int id, int reg, int bit) +{ + const char *name; + int ret; + + state = __find_weakest_power_state(pwr->lss[id], pdev, state); + name = pci_power_name(state); + + ret = __update_power_state(pwr, reg, bit, (__force int)state); + if (ret) { + dev_warn(&pdev->dev, "Can't set power state %s: %d\n", name, ret); + return ret; + } + + dev_vdbg(&pdev->dev, "Set power state %s\n", name); + return 0; +} + +static int mid_pwr_set_power_state(struct mid_pwr *pwr, struct pci_dev *pdev, + pci_power_t state) +{ + int id, reg, bit; + int ret; + + id = intel_mid_pwr_get_lss_id(pdev); + if (id < 0) + return id; + + reg = (id * LSS_PWS_BITS) / 32; + bit = (id * LSS_PWS_BITS) % 32; + + /* We support states between PCI_D0 and PCI_D3hot */ + if (state < PCI_D0) + state = PCI_D0; + if (state > PCI_D3hot) + state = PCI_D3hot; + + mutex_lock(&pwr->lock); + ret = __set_power_state(pwr, pdev, state, id, reg, bit); + mutex_unlock(&pwr->lock); + return ret; +} + +int intel_mid_pci_set_power_state(struct pci_dev *pdev, pci_power_t state) +{ + struct mid_pwr *pwr = midpwr; + int ret = 0; + + might_sleep(); + + if (pwr && pwr->available) + ret = mid_pwr_set_power_state(pwr, pdev, state); + dev_vdbg(&pdev->dev, "set_power_state() returns %d\n", ret); + + return 0; +} +EXPORT_SYMBOL_GPL(intel_mid_pci_set_power_state); + +int intel_mid_pwr_get_lss_id(struct pci_dev *pdev) +{ + int vndr; + u8 id; + + /* + * Mapping to PWRMU index is kept in the Logical SubSystem ID byte of + * Vendor capability. + */ + vndr = pci_find_capability(pdev, PCI_CAP_ID_VNDR); + if (!vndr) + return -EINVAL; + + /* Read the Logical SubSystem ID byte */ + pci_read_config_byte(pdev, vndr + INTEL_MID_PWR_LSS_OFFSET, &id); + if (!(id & INTEL_MID_PWR_LSS_TYPE)) + return -ENODEV; + + id &= ~INTEL_MID_PWR_LSS_TYPE; + if (id >= LSS_MAX_DEVS) + return -ERANGE; + + return id; +} + +static irqreturn_t mid_pwr_irq_handler(int irq, void *dev_id) +{ + struct mid_pwr *pwr = dev_id; + u32 ics; + + ics = readl(pwr->regs + PM_ICS); + if (!(ics & PM_ICS_IP)) + return IRQ_NONE; + + writel(ics | PM_ICS_IP, pwr->regs + PM_ICS); + + dev_warn(pwr->dev, "Unexpected IRQ: %#x\n", PM_ICS_INT_STATUS(ics)); + return IRQ_HANDLED; +} + +struct mid_pwr_device_info { + int (*set_initial_state)(struct mid_pwr *pwr); +}; + +static int mid_pwr_probe(struct pci_dev *pdev, const struct pci_device_id *id) +{ + struct mid_pwr_device_info *info = (void *)id->driver_data; + struct device *dev = &pdev->dev; + struct mid_pwr *pwr; + int ret; + + ret = pcim_enable_device(pdev); + if (ret < 0) { + dev_err(&pdev->dev, "error: could not enable device\n"); + return ret; + } + + ret = pcim_iomap_regions(pdev, 1 << 0, pci_name(pdev)); + if (ret) { + dev_err(&pdev->dev, "I/O memory remapping failed\n"); + return ret; + } + + pwr = devm_kzalloc(dev, sizeof(*pwr), GFP_KERNEL); + if (!pwr) + return -ENOMEM; + + pwr->dev = dev; + pwr->regs = pcim_iomap_table(pdev)[0]; + pwr->irq = pdev->irq; + + mutex_init(&pwr->lock); + + /* Disable interrupts */ + mid_pwr_interrupt_disable(pwr); + + if (info && info->set_initial_state) { + ret = info->set_initial_state(pwr); + if (ret) + dev_warn(dev, "Can't set initial state: %d\n", ret); + } + + ret = devm_request_irq(dev, pdev->irq, mid_pwr_irq_handler, + IRQF_NO_SUSPEND, pci_name(pdev), pwr); + if (ret) + return ret; + + pwr->available = true; + midpwr = pwr; + + pci_set_drvdata(pdev, pwr); + return 0; +} + +static int tng_set_initial_state(struct mid_pwr *pwr) +{ + unsigned int i, j; + int ret; + + /* + * Enable wake events. + * + * PWRMU supports up to 32 sources for wake up the system. Ungate them + * all here. + */ + mid_pwr_set_wake(pwr, 0, 0xffffffff); + mid_pwr_set_wake(pwr, 1, 0xffffffff); + + /* + * Power off South Complex devices. + * + * There is a map (see a note below) of 64 devices with 2 bits per each + * on 32-bit HW registers. The following calls set all devices to one + * known initial state, i.e. PCI_D3hot. This is done in conjunction + * with PMCSR setting in arch/x86/pci/intel_mid_pci.c. + * + * NOTE: The actual device mapping is provided by a platform at run + * time using vendor capability of PCI configuration space. + */ + mid_pwr_set_state(pwr, 0, 0xffffffff); + mid_pwr_set_state(pwr, 1, 0xffffffff); + mid_pwr_set_state(pwr, 2, 0xffffffff); + mid_pwr_set_state(pwr, 3, 0xffffffff); + + /* Send command to SCU */ + ret = mid_pwr_wait_for_cmd(pwr, CMD_SET_CFG); + if (ret) + return ret; + + for (i = 0; i < LSS_MAX_DEVS; i++) { + for (j = 0; j < LSS_MAX_SHARED_DEVS; j++) + pwr->lss[i][j].state = PCI_D3hot; + } + + return 0; +} + +static const struct mid_pwr_device_info tng_info = { + .set_initial_state = tng_set_initial_state, +}; + +static const struct pci_device_id mid_pwr_pci_ids[] = { + { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_TANGIER), (kernel_ulong_t)&tng_info }, + {} +}; +MODULE_DEVICE_TABLE(pci, mid_pwr_pci_ids); + +static struct pci_driver mid_pwr_pci_driver = { + .name = "intel_mid_pwr", + .probe = mid_pwr_probe, + .id_table = mid_pwr_pci_ids, +}; + +builtin_pci_driver(mid_pwr_pci_driver); diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile index 1fa6925..8db5079 100644 --- a/drivers/pci/Makefile +++ b/drivers/pci/Makefile @@ -51,6 +51,9 @@ obj-$(CONFIG_ACPI) += pci-acpi.o # SMBIOS provided firmware instance and labels obj-$(CONFIG_PCI_LABEL) += pci-label.o +# Intel MID platform PM support +obj-$(CONFIG_X86_INTEL_MID) += pci-mid.o + obj-$(CONFIG_PCI_SYSCALL) += syscall.o obj-$(CONFIG_PCI_STUB) += pci-stub.o diff --git a/drivers/pci/pci-mid.c b/drivers/pci/pci-mid.c new file mode 100644 index 0000000..c878aa7 --- /dev/null +++ b/drivers/pci/pci-mid.c @@ -0,0 +1,77 @@ +/* + * Intel MID platform PM support + * + * Copyright (C) 2016, Intel Corporation + * + * Author: Andy Shevchenko + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + */ + +#include +#include + +#include +#include +#include + +#include "pci.h" + +static bool mid_pci_power_manageable(struct pci_dev *dev) +{ + return true; +} + +static int mid_pci_set_power_state(struct pci_dev *pdev, pci_power_t state) +{ + return intel_mid_pci_set_power_state(pdev, state); +} + +static pci_power_t mid_pci_choose_state(struct pci_dev *pdev) +{ + return PCI_D3hot; +} + +static int mid_pci_sleep_wake(struct pci_dev *dev, bool enable) +{ + return 0; +} + +static int mid_pci_run_wake(struct pci_dev *dev, bool enable) +{ + return 0; +} + +static bool mid_pci_need_resume(struct pci_dev *dev) +{ + return false; +} + +static struct pci_platform_pm_ops mid_pci_platform_pm = { + .is_manageable = mid_pci_power_manageable, + .set_state = mid_pci_set_power_state, + .choose_state = mid_pci_choose_state, + .sleep_wake = mid_pci_sleep_wake, + .run_wake = mid_pci_run_wake, + .need_resume = mid_pci_need_resume, +}; + +#define ICPU(model) { X86_VENDOR_INTEL, 6, model, X86_FEATURE_ANY, } + +static const struct x86_cpu_id lpss_cpu_ids[] = { + ICPU(INTEL_FAM6_ATOM_MERRIFIELD1), + {} +}; + +static int __init mid_pci_init(void) +{ + const struct x86_cpu_id *id; + + id = x86_match_cpu(lpss_cpu_ids); + if (id) + pci_set_platform_pm(&mid_pci_platform_pm); + return 0; +} +arch_initcall(mid_pci_init); -- cgit v0.10.2 From 43160ffd12c8d1d331362362eea3c70e04b6f9c4 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Wed, 15 Jun 2016 10:21:34 +0800 Subject: regulator: qcom_smd: Remove list_voltage callback for rpm_smps_ldo_ops_fixed Use regulator_list_voltage_linear_range in rpm_smps_ldo_ops_fixed is wrong because it is used for fixed regulator without any linear range. The rpm_smps_ldo_ops_fixed is used for pm8941_lnldo which has fixed_uV set and n_voltages = 1. In this case, regulator_list_voltage() can return rdev->desc->fixed_uV without .list_voltage implementation. Fixes: 3bfbb4d1a480 ("regulator: qcom_smd: add list_voltage callback") Signed-off-by: Axel Lin Signed-off-by: Mark Brown diff --git a/drivers/regulator/qcom_smd-regulator.c b/drivers/regulator/qcom_smd-regulator.c index 526bf23..6c7fe477 100644 --- a/drivers/regulator/qcom_smd-regulator.c +++ b/drivers/regulator/qcom_smd-regulator.c @@ -152,7 +152,6 @@ static const struct regulator_ops rpm_smps_ldo_ops_fixed = { .enable = rpm_reg_enable, .disable = rpm_reg_disable, .is_enabled = rpm_reg_is_enabled, - .list_voltage = regulator_list_voltage_linear_range, .get_voltage = rpm_reg_get_voltage, .set_voltage = rpm_reg_set_voltage, -- cgit v0.10.2 From 00688272157d83e48d1369d7d11c479571324e40 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 15 Jun 2016 12:48:53 +0300 Subject: x86/platform/intel-mid: Enable GPIO expanders on Edison Intel Edison board provides GPIO expanders connected to I2C bus. Add necessary file to get those enumerated. Signed-off-by: Andy Shevchenko Cc: Dan O'Donovan Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/1465984133-41639-1-git-send-email-andriy.shevchenko@linux.intel.com Signed-off-by: Ingo Molnar diff --git a/arch/x86/platform/intel-mid/device_libs/Makefile b/arch/x86/platform/intel-mid/device_libs/Makefile index 91ec9f8..abe8ba8 100644 --- a/arch/x86/platform/intel-mid/device_libs/Makefile +++ b/arch/x86/platform/intel-mid/device_libs/Makefile @@ -11,11 +11,13 @@ obj-$(subst m,y,$(CONFIG_INTEL_MFLD_THERMAL)) += platform_msic_thermal.o # I2C Devices obj-$(subst m,y,$(CONFIG_SENSORS_EMC1403)) += platform_emc1403.o obj-$(subst m,y,$(CONFIG_SENSORS_LIS3LV02D)) += platform_lis331.o -obj-$(subst m,y,$(CONFIG_GPIO_PCA953X)) += platform_max7315.o obj-$(subst m,y,$(CONFIG_INPUT_MPU3050)) += platform_mpu3050.o obj-$(subst m,y,$(CONFIG_INPUT_BMA150)) += platform_bma023.o -obj-$(subst m,y,$(CONFIG_GPIO_PCA953X)) += platform_tca6416.o obj-$(subst m,y,$(CONFIG_DRM_MEDFIELD)) += platform_tc35876x.o +# I2C GPIO Expanders +obj-$(subst m,y,$(CONFIG_GPIO_PCA953X)) += platform_max7315.o +obj-$(subst m,y,$(CONFIG_GPIO_PCA953X)) += platform_pcal9555a.o +obj-$(subst m,y,$(CONFIG_GPIO_PCA953X)) += platform_tca6416.o # MISC Devices obj-$(subst m,y,$(CONFIG_KEYBOARD_GPIO)) += platform_gpio_keys.o obj-$(subst m,y,$(CONFIG_INTEL_MID_WATCHDOG)) += platform_wdt.o diff --git a/arch/x86/platform/intel-mid/device_libs/platform_pcal9555a.c b/arch/x86/platform/intel-mid/device_libs/platform_pcal9555a.c new file mode 100644 index 0000000..429a941 --- /dev/null +++ b/arch/x86/platform/intel-mid/device_libs/platform_pcal9555a.c @@ -0,0 +1,99 @@ +/* + * PCAL9555a platform data initilization file + * + * Copyright (C) 2016, Intel Corporation + * + * Authors: Andy Shevchenko + * Dan O'Donovan + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; version 2 + * of the License. + */ + +#include +#include +#include +#include +#include + +#include + +#define PCAL9555A_NUM 4 + +static struct pca953x_platform_data pcal9555a_pdata[PCAL9555A_NUM]; +static int nr; + +static void __init *pcal9555a_platform_data(void *info) +{ + struct i2c_board_info *i2c_info = info; + char *type = i2c_info->type; + struct pca953x_platform_data *pcal9555a; + char base_pin_name[SFI_NAME_LEN + 1]; + char intr_pin_name[SFI_NAME_LEN + 1]; + int gpio_base, intr; + + snprintf(base_pin_name, sizeof(base_pin_name), "%s_base", type); + snprintf(intr_pin_name, sizeof(intr_pin_name), "%s_int", type); + + gpio_base = get_gpio_by_name(base_pin_name); + intr = get_gpio_by_name(intr_pin_name); + + /* Check if the SFI record valid */ + if (gpio_base == -1) + return NULL; + + if (nr >= PCAL9555A_NUM) { + pr_err("%s: Too many instances, only %d supported\n", __func__, + PCAL9555A_NUM); + return NULL; + } + + pcal9555a = &pcal9555a_pdata[nr++]; + pcal9555a->gpio_base = gpio_base; + + if (intr >= 0) { + i2c_info->irq = intr + INTEL_MID_IRQ_OFFSET; + pcal9555a->irq_base = gpio_base + INTEL_MID_IRQ_OFFSET; + } else { + i2c_info->irq = -1; + pcal9555a->irq_base = -1; + } + + strcpy(type, "pcal9555a"); + return pcal9555a; +} + +static const struct devs_id pcal9555a_1_dev_id __initconst = { + .name = "pcal9555a-1", + .type = SFI_DEV_TYPE_I2C, + .delay = 1, + .get_platform_data = &pcal9555a_platform_data, +}; + +static const struct devs_id pcal9555a_2_dev_id __initconst = { + .name = "pcal9555a-2", + .type = SFI_DEV_TYPE_I2C, + .delay = 1, + .get_platform_data = &pcal9555a_platform_data, +}; + +static const struct devs_id pcal9555a_3_dev_id __initconst = { + .name = "pcal9555a-3", + .type = SFI_DEV_TYPE_I2C, + .delay = 1, + .get_platform_data = &pcal9555a_platform_data, +}; + +static const struct devs_id pcal9555a_4_dev_id __initconst = { + .name = "pcal9555a-4", + .type = SFI_DEV_TYPE_I2C, + .delay = 1, + .get_platform_data = &pcal9555a_platform_data, +}; + +sfi_device(pcal9555a_1_dev_id); +sfi_device(pcal9555a_2_dev_id); +sfi_device(pcal9555a_3_dev_id); +sfi_device(pcal9555a_4_dev_id); -- cgit v0.10.2 From 906a8276429c7eb3b53676dab4e2acb632ffcc5a Mon Sep 17 00:00:00 2001 From: He Kuang Date: Wed, 15 Jun 2016 11:03:56 +0000 Subject: perf unwind: Fix compile error for static cross build Build failure for static cross-compiling on aarch64, with libunwind-x86 provided: $ file ./libunwind_for_x86_on_aarch64/lib/libunwind-x86.so.8.0.1 libunwind-x86.so.8.0.1: ELF 64-bit LSB shared object, ARM aarch64, version 1 (SYSV), dynamically linked, not stripped $ make LDFLAGS=-static LIBUNWIND_DIR=./libunwind_for_x86_on_aarch64 ARCH=aarch64 CROSS_COMPILE=aarch64-buildroot-linux-gnu- ~/libperf.a(libperf-in.o): In function `find_proc_info': :(.text+0xae4ac): undefined reference to `_Ux86_dwarf_search_unwind_table' ~/libperf.a(libperf-in.o): In function `_unwind__prepare_access': :(.text+0xaedd0): undefined reference to `_Ux86_create_addr_space' :(.text+0xaee24): undefined reference to `_Ux86_set_caching_policy' ~/libperf.a(libperf-in.o): In function `_unwind__flush_access': :(.text+0xaee98): undefined reference to `_Ux86_flush_cache' ~/libperf.a(libperf-in.o): In function `_unwind__finish_access': :(.text+0xaef08): undefined reference to `_Ux86_destroy_addr_space' ~/libperf.a(libperf-in.o): In function `get_entries': :(.text+0xaf148): undefined reference to `_Ux86_init_remote' :(.text+0xaf184): undefined reference to `_Ux86_get_reg' :(.text+0xaf1a4): undefined reference to `_Ux86_step' collect2: error: ld returned 1 exit status Makefile.perf:350: recipe for target '~/perf' failed make[1]: *** [~/perf] Error 1 Makefile:68: recipe for target 'all' failed make: *** [all] Error 2 This is because the remote libunwind library detected is not appended to EXTLIBS variable, which will be included between 'start-group' and 'end-group' when linking. The existing variable LIBUNWIND_LIBS is assigned to libs for local unwind, this patch introduces a new variable EXTLIBS_LIBUNWIND for storing remote libunwind libraries instead. Signed-off-by: He Kuang Cc: Alexander Shishkin Cc: Jiri Olsa Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Wang Nan Link: http://lkml.kernel.org/r/1465988636-81502-1-git-send-email-hekuang@huawei.com Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/config/Makefile b/tools/perf/config/Makefile index 098874b..80018fe 100644 --- a/tools/perf/config/Makefile +++ b/tools/perf/config/Makefile @@ -365,6 +365,7 @@ ifndef NO_LIBUNWIND $(call detected,CONFIG_LIBUNWIND_X86) CFLAGS += -DHAVE_LIBUNWIND_X86_SUPPORT LDFLAGS += -lunwind-x86 + EXTLIBS_LIBUNWIND += -lunwind-x86 have_libunwind = 1 endif @@ -372,6 +373,7 @@ ifndef NO_LIBUNWIND $(call detected,CONFIG_LIBUNWIND_AARCH64) CFLAGS += -DHAVE_LIBUNWIND_AARCH64_SUPPORT LDFLAGS += -lunwind-aarch64 + EXTLIBS_LIBUNWIND += -lunwind-aarch64 have_libunwind = 1 $(call feature_check,libunwind-debug-frame-aarch64) ifneq ($(feature-libunwind-debug-frame-aarch64), 1) @@ -449,6 +451,7 @@ ifndef NO_LIBUNWIND CFLAGS += -DHAVE_LIBUNWIND_SUPPORT CFLAGS += $(LIBUNWIND_CFLAGS) LDFLAGS += $(LIBUNWIND_LDFLAGS) + EXTLIBS += $(EXTLIBS_LIBUNWIND) endif ifndef NO_LIBAUDIT -- cgit v0.10.2 From b0d745b3c34a7fd9ee0b78b929b94c706f84e341 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Tue, 14 Jun 2016 20:19:11 +0200 Subject: perf mem: Add --ldlat option Adding --ldlat option to specify desired latency for loads event. Specify 50 as loads event latency: $ perf mem record -e ldlat-loads -v --ldlat 50 true calling: record -W -d -e cpu/mem-loads,ldlat=50/P true Signed-off-by: Jiri Olsa Cc: David Ahern Cc: Namhyung Kim Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1465928361-2442-2-git-send-email-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/Documentation/perf-mem.txt b/tools/perf/Documentation/perf-mem.txt index 1d6092c..7349632 100644 --- a/tools/perf/Documentation/perf-mem.txt +++ b/tools/perf/Documentation/perf-mem.txt @@ -56,6 +56,9 @@ OPTIONS --all-user:: Configure all used events to run in user space. +--ldload:: + Specify desired latency for loads event. + SEE ALSO -------- linkperf:perf-record[1], linkperf:perf-report[1] diff --git a/tools/perf/builtin-mem.c b/tools/perf/builtin-mem.c index 1dc140c..d608a2c 100644 --- a/tools/perf/builtin-mem.c +++ b/tools/perf/builtin-mem.c @@ -67,6 +67,7 @@ static int __cmd_record(int argc, const char **argv, struct perf_mem *mem) OPT_CALLBACK('e', "event", &mem, "event", "event selector. use 'perf mem record -e list' to list available events", parse_record_events), + OPT_UINTEGER(0, "ldlat", &perf_mem_events__loads_ldlat, "mem-loads latency"), OPT_INCR('v', "verbose", &verbose, "be more verbose (show counter open errors, etc)"), OPT_BOOLEAN('U', "--all-user", &all_user, "collect only user level data"), diff --git a/tools/perf/util/mem-events.c b/tools/perf/util/mem-events.c index 75465f8..bbc368e 100644 --- a/tools/perf/util/mem-events.c +++ b/tools/perf/util/mem-events.c @@ -10,18 +10,33 @@ #include "debug.h" #include "symbol.h" +unsigned int perf_mem_events__loads_ldlat = 30; + #define E(t, n, s) { .tag = t, .name = n, .sysfs_name = s } struct perf_mem_event perf_mem_events[PERF_MEM_EVENTS__MAX] = { - E("ldlat-loads", "cpu/mem-loads,ldlat=30/P", "mem-loads"), + E("ldlat-loads", "cpu/mem-loads,ldlat=%u/P", "mem-loads"), E("ldlat-stores", "cpu/mem-stores/P", "mem-stores"), }; #undef E #undef E +static char mem_loads_name[100]; +static bool mem_loads_name__init; + char *perf_mem_events__name(int i) { + if (i == PERF_MEM_EVENTS__LOAD) { + if (!mem_loads_name__init) { + mem_loads_name__init = true; + scnprintf(mem_loads_name, sizeof(mem_loads_name), + perf_mem_events[i].name, + perf_mem_events__loads_ldlat); + } + return mem_loads_name; + } + return (char *)perf_mem_events[i].name; } diff --git a/tools/perf/util/mem-events.h b/tools/perf/util/mem-events.h index 5d6d930..7f69bf9 100644 --- a/tools/perf/util/mem-events.h +++ b/tools/perf/util/mem-events.h @@ -18,6 +18,7 @@ enum { }; extern struct perf_mem_event perf_mem_events[PERF_MEM_EVENTS__MAX]; +extern unsigned int perf_mem_events__loads_ldlat; int perf_mem_events__parse(const char *str); int perf_mem_events__init(void); -- cgit v0.10.2 From 94c39988995d34f3de1b1763cc32141c67c0340c Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Tue, 14 Jun 2016 20:19:12 +0200 Subject: perf tools: Fix Data Object sort entry width index Putting correct HISTC_MEM_DADDR_DSO index to Data Object sort entry. Signed-off-by: Jiri Olsa Cc: David Ahern Cc: Namhyung Kim Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1465928361-2442-3-git-send-email-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c index c4e9bd7..ba5b42f 100644 --- a/tools/perf/util/sort.c +++ b/tools/perf/util/sort.c @@ -1218,7 +1218,7 @@ struct sort_entry sort_mem_daddr_dso = { .se_header = "Data Object", .se_cmp = sort__dso_daddr_cmp, .se_snprintf = hist_entry__dso_daddr_snprintf, - .se_width_idx = HISTC_MEM_DADDR_SYMBOL, + .se_width_idx = HISTC_MEM_DADDR_DSO, }; struct sort_entry sort_mem_locked = { -- cgit v0.10.2 From 01b4770d5654fcb71645a1ee095759c255048466 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Tue, 14 Jun 2016 20:19:13 +0200 Subject: perf tui: Separate hierarchy and standard headers output It will be useful for future changes that enhance headers with multiple lines and span columns, which don't affect hierarchy headers. Signed-off-by: Jiri Olsa Tested-by: Arnaldo Carvalho de Melo Cc: David Ahern Cc: Namhyung Kim Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1465928361-2442-4-git-send-email-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c index 538bae8..e21ea52 100644 --- a/tools/perf/ui/browsers/hists.c +++ b/tools/perf/ui/browsers/hists.c @@ -1622,21 +1622,38 @@ static int hists_browser__scnprintf_hierarchy_headers(struct hist_browser *brows return ret; } -static void hist_browser__show_headers(struct hist_browser *browser) +static void hists_browser__hierarchy_headers(struct hist_browser *browser) { char headers[1024]; - if (symbol_conf.report_hierarchy) - hists_browser__scnprintf_hierarchy_headers(browser, headers, - sizeof(headers)); - else - hists_browser__scnprintf_headers(browser, headers, - sizeof(headers)); + hists_browser__scnprintf_hierarchy_headers(browser, headers, + sizeof(headers)); + ui_browser__gotorc(&browser->b, 0, 0); ui_browser__set_color(&browser->b, HE_COLORSET_ROOT); ui_browser__write_nstring(&browser->b, headers, browser->b.width + 1); } +static void hists_browser__headers(struct hist_browser *browser) +{ + char headers[1024]; + + hists_browser__scnprintf_headers(browser, headers, + sizeof(headers)); + + ui_browser__gotorc(&browser->b, 0, 0); + ui_browser__set_color(&browser->b, HE_COLORSET_ROOT); + ui_browser__write_nstring(&browser->b, headers, browser->b.width + 1); +} + +static void hist_browser__show_headers(struct hist_browser *browser) +{ + if (symbol_conf.report_hierarchy) + hists_browser__hierarchy_headers(browser); + else + hists_browser__headers(browser); +} + static void ui_browser__hists_init_top(struct ui_browser *browser) { if (browser->top == NULL) { -- cgit v0.10.2 From 36592ebb73782aa2304a71f9a3b586566c2892ee Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Tue, 14 Jun 2016 20:19:14 +0200 Subject: perf stdio: Separate headers output Introducing hists__fprintf_headers function to separate the code that displays headers. Signed-off-by: Jiri Olsa Tested-by: Arnaldo Carvalho de Melo Cc: David Ahern Cc: Namhyung Kim Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1465928361-2442-5-git-send-email-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/ui/stdio/hist.c b/tools/perf/ui/stdio/hist.c index 560eb47..91353ca 100644 --- a/tools/perf/ui/stdio/hist.c +++ b/tools/perf/ui/stdio/hist.c @@ -622,36 +622,18 @@ static int print_hierarchy_header(struct hists *hists, struct perf_hpp *hpp, return 2; } -size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows, - int max_cols, float min_pcnt, FILE *fp) +static int hists__fprintf_headers(struct hists *hists, FILE *fp) { struct perf_hpp_fmt *fmt; struct perf_hpp_list_node *fmt_node; - struct rb_node *nd; - size_t ret = 0; unsigned int width; const char *sep = symbol_conf.field_sep; - int nr_rows = 0; char bf[96]; struct perf_hpp dummy_hpp = { .buf = bf, .size = sizeof(bf), }; bool first = true; - size_t linesz; - char *line = NULL; - unsigned indent; - - init_rem_hits(); - - hists__for_each_format(hists, fmt) - perf_hpp__reset_width(fmt, hists); - - if (symbol_conf.col_width_list_str) - perf_hpp__set_user_width(symbol_conf.col_width_list_str); - - if (!show_header) - goto print_entries; fprintf(fp, "# "); @@ -660,8 +642,7 @@ size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows, perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) perf_hpp__reset_width(fmt, hists); } - nr_rows += print_hierarchy_header(hists, &dummy_hpp, sep, fp); - goto print_entries; + return print_hierarchy_header(hists, &dummy_hpp, sep, fp); } hists__for_each_format(hists, fmt) { @@ -678,11 +659,9 @@ size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows, } fprintf(fp, "\n"); - if (max_rows && ++nr_rows >= max_rows) - goto out; if (sep) - goto print_entries; + return 1; first = true; @@ -705,14 +684,36 @@ size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows, } fprintf(fp, "\n"); - if (max_rows && ++nr_rows >= max_rows) - goto out; - fprintf(fp, "#\n"); - if (max_rows && ++nr_rows >= max_rows) + return 3; +} + +size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows, + int max_cols, float min_pcnt, FILE *fp) +{ + struct perf_hpp_fmt *fmt; + struct rb_node *nd; + size_t ret = 0; + const char *sep = symbol_conf.field_sep; + int nr_rows = 0; + size_t linesz; + char *line = NULL; + unsigned indent; + + init_rem_hits(); + + hists__for_each_format(hists, fmt) + perf_hpp__reset_width(fmt, hists); + + if (symbol_conf.col_width_list_str) + perf_hpp__set_user_width(symbol_conf.col_width_list_str); + + if (show_header) + nr_rows += hists__fprintf_headers(hists, fp); + + if (max_rows && nr_rows >= max_rows) goto out; -print_entries: linesz = hists__sort_list_width(hists) + 3 + 1; linesz += perf_hpp__color_overhead(); line = malloc(linesz); -- cgit v0.10.2 From 5c854f3793c03539dcca48d8a89da9267127e436 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Tue, 14 Jun 2016 20:19:15 +0200 Subject: perf stdio: Separate hierarchy headers output Introducing hists__fprintf_hierarchy_headers function to separate hierarchy headers display code. Signed-off-by: Jiri Olsa Tested-by: Arnaldo Carvalho de Melo Cc: David Ahern Cc: Namhyung Kim Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1465928361-2442-6-git-send-email-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/ui/stdio/hist.c b/tools/perf/ui/stdio/hist.c index 91353ca..7498ce2 100644 --- a/tools/perf/ui/stdio/hist.c +++ b/tools/perf/ui/stdio/hist.c @@ -622,10 +622,25 @@ static int print_hierarchy_header(struct hists *hists, struct perf_hpp *hpp, return 2; } +static int +hists__fprintf_hierarchy_headers(struct hists *hists, + struct perf_hpp *hpp, + FILE *fp) +{ + struct perf_hpp_list_node *fmt_node; + struct perf_hpp_fmt *fmt; + + list_for_each_entry(fmt_node, &hists->hpp_formats, list) { + perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) + perf_hpp__reset_width(fmt, hists); + } + + return print_hierarchy_header(hists, hpp, symbol_conf.field_sep, fp); +} + static int hists__fprintf_headers(struct hists *hists, FILE *fp) { struct perf_hpp_fmt *fmt; - struct perf_hpp_list_node *fmt_node; unsigned int width; const char *sep = symbol_conf.field_sep; char bf[96]; @@ -637,13 +652,8 @@ static int hists__fprintf_headers(struct hists *hists, FILE *fp) fprintf(fp, "# "); - if (symbol_conf.report_hierarchy) { - list_for_each_entry(fmt_node, &hists->hpp_formats, list) { - perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) - perf_hpp__reset_width(fmt, hists); - } - return print_hierarchy_header(hists, &dummy_hpp, sep, fp); - } + if (symbol_conf.report_hierarchy) + return hists__fprintf_hierarchy_headers(hists, &dummy_hpp, fp); hists__for_each_format(hists, fmt) { if (perf_hpp__should_skip(fmt, hists)) -- cgit v0.10.2 From 7a72a2e5e6e06172ae26a3c5c8c89a5578f28432 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Tue, 14 Jun 2016 20:19:16 +0200 Subject: perf stdio: Separate standard headers output Introducing hists__fprintf_standard_headers function to separate standard headers display code. Signed-off-by: Jiri Olsa Tested-by: Arnaldo Carvalho de Melo Cc: David Ahern Cc: Namhyung Kim Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1465928361-2442-7-git-send-email-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/ui/stdio/hist.c b/tools/perf/ui/stdio/hist.c index 7498ce2..5d00783 100644 --- a/tools/perf/ui/stdio/hist.c +++ b/tools/perf/ui/stdio/hist.c @@ -638,23 +638,16 @@ hists__fprintf_hierarchy_headers(struct hists *hists, return print_hierarchy_header(hists, hpp, symbol_conf.field_sep, fp); } -static int hists__fprintf_headers(struct hists *hists, FILE *fp) +static int +hists__fprintf_standard_headers(struct hists *hists, + struct perf_hpp *hpp, + FILE *fp) { struct perf_hpp_fmt *fmt; unsigned int width; const char *sep = symbol_conf.field_sep; - char bf[96]; - struct perf_hpp dummy_hpp = { - .buf = bf, - .size = sizeof(bf), - }; bool first = true; - fprintf(fp, "# "); - - if (symbol_conf.report_hierarchy) - return hists__fprintf_hierarchy_headers(hists, &dummy_hpp, fp); - hists__for_each_format(hists, fmt) { if (perf_hpp__should_skip(fmt, hists)) continue; @@ -664,8 +657,8 @@ static int hists__fprintf_headers(struct hists *hists, FILE *fp) else first = false; - fmt->header(fmt, &dummy_hpp, hists_to_evsel(hists)); - fprintf(fp, "%s", bf); + fmt->header(fmt, hpp, hists_to_evsel(hists)); + fprintf(fp, "%s", hpp->buf); } fprintf(fp, "\n"); @@ -688,7 +681,7 @@ static int hists__fprintf_headers(struct hists *hists, FILE *fp) else first = false; - width = fmt->width(fmt, &dummy_hpp, hists_to_evsel(hists)); + width = fmt->width(fmt, hpp, hists_to_evsel(hists)); for (i = 0; i < width; i++) fprintf(fp, "."); } @@ -698,6 +691,23 @@ static int hists__fprintf_headers(struct hists *hists, FILE *fp) return 3; } +static int hists__fprintf_headers(struct hists *hists, FILE *fp) +{ + char bf[96]; + struct perf_hpp dummy_hpp = { + .buf = bf, + .size = sizeof(bf), + }; + + fprintf(fp, "# "); + + if (symbol_conf.report_hierarchy) + return hists__fprintf_hierarchy_headers(hists, &dummy_hpp, fp); + else + return hists__fprintf_standard_headers(hists, &dummy_hpp, fp); + +} + size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows, int max_cols, float min_pcnt, FILE *fp) { -- cgit v0.10.2 From 8f1d1b4452ce71a231d1a22e6357285fb773c551 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Tue, 14 Jun 2016 20:19:17 +0200 Subject: perf stdio: Do not pass hists in hist_entry__fprintf There's no need, we have the hists pointer in struct hist_entry. Signed-off-by: Jiri Olsa Tested-by: Arnaldo Carvalho de Melo Cc: David Ahern Cc: Namhyung Kim Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1465928361-2442-8-git-send-email-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/ui/stdio/hist.c b/tools/perf/ui/stdio/hist.c index 5d00783..150c4de 100644 --- a/tools/perf/ui/stdio/hist.c +++ b/tools/perf/ui/stdio/hist.c @@ -492,7 +492,6 @@ out: } static int hist_entry__fprintf(struct hist_entry *he, size_t size, - struct hists *hists, char *bf, size_t bfsz, FILE *fp) { int ret; @@ -500,6 +499,7 @@ static int hist_entry__fprintf(struct hist_entry *he, size_t size, .buf = bf, .size = size, }; + struct hists *hists = he->hists; u64 total_period = hists->stats.total_period; if (size == 0 || size > bfsz) @@ -755,7 +755,7 @@ size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows, if (percent < min_pcnt) continue; - ret += hist_entry__fprintf(h, max_cols, hists, line, linesz, fp); + ret += hist_entry__fprintf(h, max_cols, line, linesz, fp); if (max_rows && ++nr_rows >= max_rows) break; -- cgit v0.10.2 From d05e3aaeea56d7cd23976cb1fa626faf1a8bfbed Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Tue, 14 Jun 2016 20:19:18 +0200 Subject: perf stdio: Add use_callchain parameter to hists__fprintf It will be convenient in following patches to display hists entries without callchains even if they are defined. Signed-off-by: Jiri Olsa Cc: David Ahern Cc: Namhyung Kim Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1465928361-2442-9-git-send-email-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c index f7645a4..69bad45 100644 --- a/tools/perf/builtin-diff.c +++ b/tools/perf/builtin-diff.c @@ -666,7 +666,8 @@ static void hists__process(struct hists *hists) hists__precompute(hists); hists__output_resort(hists, NULL); - hists__fprintf(hists, true, 0, 0, 0, stdout); + hists__fprintf(hists, true, 0, 0, 0, stdout, + symbol_conf.use_callchain); } static void data__fprintf(void) diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index a87cb33..9f36b23 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c @@ -370,7 +370,8 @@ static int perf_evlist__tty_browse_hists(struct perf_evlist *evlist, continue; hists__fprintf_nr_sample_events(hists, rep, evname, stdout); - hists__fprintf(hists, true, 0, 0, rep->min_percent, stdout); + hists__fprintf(hists, true, 0, 0, rep->min_percent, stdout, + symbol_conf.use_callchain); fprintf(stdout, "\n\n"); } diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 2a6cc25..81dba80 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -295,7 +295,7 @@ static void perf_top__print_sym_table(struct perf_top *top) hists__output_recalc_col_len(hists, top->print_entries - printed); putchar('\n'); hists__fprintf(hists, false, top->print_entries - printed, win_width, - top->min_percent, stdout); + top->min_percent, stdout, symbol_conf.use_callchain); } static void prompt_integer(int *target, const char *msg) diff --git a/tools/perf/ui/stdio/hist.c b/tools/perf/ui/stdio/hist.c index 150c4de..9a972cb 100644 --- a/tools/perf/ui/stdio/hist.c +++ b/tools/perf/ui/stdio/hist.c @@ -492,7 +492,8 @@ out: } static int hist_entry__fprintf(struct hist_entry *he, size_t size, - char *bf, size_t bfsz, FILE *fp) + char *bf, size_t bfsz, FILE *fp, + bool use_callchain) { int ret; struct perf_hpp hpp = { @@ -512,7 +513,7 @@ static int hist_entry__fprintf(struct hist_entry *he, size_t size, ret = fprintf(fp, "%s\n", bf); - if (symbol_conf.use_callchain) + if (use_callchain) ret += hist_entry_callchain__fprintf(he, total_period, 0, fp); return ret; @@ -709,7 +710,8 @@ static int hists__fprintf_headers(struct hists *hists, FILE *fp) } size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows, - int max_cols, float min_pcnt, FILE *fp) + int max_cols, float min_pcnt, FILE *fp, + bool use_callchain) { struct perf_hpp_fmt *fmt; struct rb_node *nd; @@ -755,7 +757,7 @@ size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows, if (percent < min_pcnt) continue; - ret += hist_entry__fprintf(h, max_cols, line, linesz, fp); + ret += hist_entry__fprintf(h, max_cols, line, linesz, fp, use_callchain); if (max_rows && ++nr_rows >= max_rows) break; diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h index 7b54ccf..a73fde0 100644 --- a/tools/perf/util/hist.h +++ b/tools/perf/util/hist.h @@ -159,7 +159,8 @@ void events_stats__inc(struct events_stats *stats, u32 type); size_t events_stats__fprintf(struct events_stats *stats, FILE *fp); size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows, - int max_cols, float min_pcnt, FILE *fp); + int max_cols, float min_pcnt, FILE *fp, + bool use_callchain); size_t perf_evlist__fprintf_nr_events(struct perf_evlist *evlist, FILE *fp); void hists__filter_by_dso(struct hists *hists); -- cgit v0.10.2 From 053721736011ee52e83b8e8794d922d1c511a4d3 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Tue, 14 Jun 2016 20:19:19 +0200 Subject: perf hists: Replace perf_evsel arg perf_hpp_fmt's header callback Replacing perf_evsel arg perf_hpp_fmt's header callback with hists object. None of the actual callbacks actually use evsel object, also this will be helpful in future for non evsel related hist browsers. Signed-off-by: Jiri Olsa Cc: David Ahern Cc: Namhyung Kim Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1465928361-2442-10-git-send-email-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c index 69bad45..b75ea77 100644 --- a/tools/perf/builtin-diff.c +++ b/tools/perf/builtin-diff.c @@ -1045,7 +1045,7 @@ static int hpp__entry_global(struct perf_hpp_fmt *_fmt, struct perf_hpp *hpp, } static int hpp__header(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, - struct perf_evsel *evsel __maybe_unused) + struct hists *hists __maybe_unused) { struct diff_hpp_fmt *dfmt = container_of(fmt, struct diff_hpp_fmt, fmt); diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c index e21ea52..c20425d 100644 --- a/tools/perf/ui/browsers/hists.c +++ b/tools/perf/ui/browsers/hists.c @@ -1531,7 +1531,7 @@ static int hists_browser__scnprintf_headers(struct hist_browser *browser, char * if (perf_hpp__should_skip(fmt, hists) || column++ < browser->b.horiz_scroll) continue; - ret = fmt->header(fmt, &dummy_hpp, hists_to_evsel(hists)); + ret = fmt->header(fmt, &dummy_hpp, hists); if (advance_hpp_check(&dummy_hpp, ret)) break; @@ -1568,7 +1568,7 @@ static int hists_browser__scnprintf_hierarchy_headers(struct hist_browser *brows if (column++ < browser->b.horiz_scroll) continue; - ret = fmt->header(fmt, &dummy_hpp, hists_to_evsel(hists)); + ret = fmt->header(fmt, &dummy_hpp, hists); if (advance_hpp_check(&dummy_hpp, ret)) break; @@ -1605,7 +1605,7 @@ static int hists_browser__scnprintf_hierarchy_headers(struct hist_browser *brows } first_col = false; - ret = fmt->header(fmt, &dummy_hpp, hists_to_evsel(hists)); + ret = fmt->header(fmt, &dummy_hpp, hists); dummy_hpp.buf[ret] = '\0'; start = trim(dummy_hpp.buf); diff --git a/tools/perf/ui/gtk/hists.c b/tools/perf/ui/gtk/hists.c index 932adfa..e5c1325 100644 --- a/tools/perf/ui/gtk/hists.c +++ b/tools/perf/ui/gtk/hists.c @@ -549,7 +549,7 @@ static void perf_gtk__show_hierarchy(GtkWidget *window, struct hists *hists, strcat(buf, "+"); first_col = false; - fmt->header(fmt, &hpp, hists_to_evsel(hists)); + fmt->header(fmt, &hpp, hists); strcat(buf, ltrim(rtrim(hpp.buf))); } } diff --git a/tools/perf/ui/hist.c b/tools/perf/ui/hist.c index af07ffb..0b232d6 100644 --- a/tools/perf/ui/hist.c +++ b/tools/perf/ui/hist.c @@ -229,9 +229,9 @@ static int hpp__width_fn(struct perf_hpp_fmt *fmt, } static int hpp__header_fn(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, - struct perf_evsel *evsel) + struct hists *hists) { - int len = hpp__width_fn(fmt, hpp, evsel); + int len = hpp__width_fn(fmt, hpp, hists_to_evsel(hists)); return scnprintf(hpp->buf, hpp->size, "%*s", len, fmt->name); } diff --git a/tools/perf/ui/stdio/hist.c b/tools/perf/ui/stdio/hist.c index 9a972cb..d0534fa 100644 --- a/tools/perf/ui/stdio/hist.c +++ b/tools/perf/ui/stdio/hist.c @@ -549,7 +549,7 @@ static int print_hierarchy_header(struct hists *hists, struct perf_hpp *hpp, struct perf_hpp_list_node, list); perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) { - fmt->header(fmt, hpp, hists_to_evsel(hists)); + fmt->header(fmt, hpp, hists); fprintf(fp, "%s%s", hpp->buf, sep ?: " "); } @@ -569,7 +569,7 @@ static int print_hierarchy_header(struct hists *hists, struct perf_hpp *hpp, header_width += fprintf(fp, "+"); first_col = false; - fmt->header(fmt, hpp, hists_to_evsel(hists)); + fmt->header(fmt, hpp, hists); header_width += fprintf(fp, "%s", trim(hpp->buf)); } @@ -658,7 +658,7 @@ hists__fprintf_standard_headers(struct hists *hists, else first = false; - fmt->header(fmt, hpp, hists_to_evsel(hists)); + fmt->header(fmt, hpp, hists); fprintf(fp, "%s", hpp->buf); } diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h index a73fde0..aae932f 100644 --- a/tools/perf/util/hist.h +++ b/tools/perf/util/hist.h @@ -215,7 +215,7 @@ struct perf_hpp { struct perf_hpp_fmt { const char *name; int (*header)(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, - struct perf_evsel *evsel); + struct hists *hists); int (*width)(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, struct perf_evsel *evsel); int (*color)(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c index ba5b42f..3e52c77 100644 --- a/tools/perf/util/sort.c +++ b/tools/perf/util/sort.c @@ -1488,7 +1488,7 @@ void perf_hpp__reset_sort_width(struct perf_hpp_fmt *fmt, struct hists *hists) } static int __sort__hpp_header(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, - struct perf_evsel *evsel) + struct hists *hists) { struct hpp_sort_entry *hse; size_t len = fmt->user_len; @@ -1496,7 +1496,7 @@ static int __sort__hpp_header(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, hse = container_of(fmt, struct hpp_sort_entry, hpp); if (!len) - len = hists__col_len(evsel__hists(evsel), hse->se->se_width_idx); + len = hists__col_len(hists, hse->se->se_width_idx); return scnprintf(hpp->buf, hpp->size, "%-*.*s", len, len, fmt->name); } @@ -1793,7 +1793,7 @@ static void update_dynamic_len(struct hpp_dynamic_entry *hde, } static int __sort__hde_header(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, - struct perf_evsel *evsel __maybe_unused) + struct hists *hists __maybe_unused) { struct hpp_dynamic_entry *hde; size_t len = fmt->user_len; -- cgit v0.10.2 From da1b0407c866e7a8679cd3b64b35d83825c58a14 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Tue, 14 Jun 2016 20:19:20 +0200 Subject: perf hists: Replace perf_evsel arg perf_hpp_fmt's width callback Replacing perf_evsel arg perf_hpp_fmt's width callback with hists object. This will be helpful in future for non evsel related hist browsers. Signed-off-by: Jiri Olsa Cc: David Ahern Cc: Namhyung Kim Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1465928361-2442-11-git-send-email-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c index b75ea77..7f628f9 100644 --- a/tools/perf/builtin-diff.c +++ b/tools/perf/builtin-diff.c @@ -1056,7 +1056,7 @@ static int hpp__header(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, static int hpp__width(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp __maybe_unused, - struct perf_evsel *evsel __maybe_unused) + struct hists *hists __maybe_unused) { struct diff_hpp_fmt *dfmt = container_of(fmt, struct diff_hpp_fmt, fmt); diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c index c20425d..b1b6054 100644 --- a/tools/perf/ui/browsers/hists.c +++ b/tools/perf/ui/browsers/hists.c @@ -1470,7 +1470,7 @@ static int hist_browser__show_no_entry(struct hist_browser *browser, column++ < browser->b.horiz_scroll) continue; - ret = fmt->width(fmt, NULL, hists_to_evsel(browser->hists)); + ret = fmt->width(fmt, NULL, browser->hists); if (first) { /* for folded sign */ diff --git a/tools/perf/ui/hist.c b/tools/perf/ui/hist.c index 0b232d6..6940745 100644 --- a/tools/perf/ui/hist.c +++ b/tools/perf/ui/hist.c @@ -215,9 +215,10 @@ static int __hpp__sort_acc(struct hist_entry *a, struct hist_entry *b, static int hpp__width_fn(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp __maybe_unused, - struct perf_evsel *evsel) + struct hists *hists) { int len = fmt->user_len ?: fmt->len; + struct perf_evsel *evsel = hists_to_evsel(hists); if (symbol_conf.event_group) len = max(len, evsel->nr_members * fmt->len); @@ -231,7 +232,7 @@ static int hpp__width_fn(struct perf_hpp_fmt *fmt, static int hpp__header_fn(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, struct hists *hists) { - int len = hpp__width_fn(fmt, hpp, hists_to_evsel(hists)); + int len = hpp__width_fn(fmt, hpp, hists); return scnprintf(hpp->buf, hpp->size, "%*s", len, fmt->name); } @@ -632,7 +633,7 @@ unsigned int hists__sort_list_width(struct hists *hists) else ret += 2; - ret += fmt->width(fmt, &dummy_hpp, hists_to_evsel(hists)); + ret += fmt->width(fmt, &dummy_hpp, hists); } if (verbose && hists__has(hists, sym)) /* Addr + origin */ @@ -657,7 +658,7 @@ unsigned int hists__overhead_width(struct hists *hists) else ret += 2; - ret += fmt->width(fmt, &dummy_hpp, hists_to_evsel(hists)); + ret += fmt->width(fmt, &dummy_hpp, hists); } return ret; diff --git a/tools/perf/ui/stdio/hist.c b/tools/perf/ui/stdio/hist.c index d0534fa..f04a631 100644 --- a/tools/perf/ui/stdio/hist.c +++ b/tools/perf/ui/stdio/hist.c @@ -590,7 +590,7 @@ static int print_hierarchy_header(struct hists *hists, struct perf_hpp *hpp, fprintf(fp, "%s", sep ?: ".."); first_col = false; - width = fmt->width(fmt, hpp, hists_to_evsel(hists)); + width = fmt->width(fmt, hpp, hists); fprintf(fp, "%.*s", width, dots); } @@ -607,7 +607,7 @@ static int print_hierarchy_header(struct hists *hists, struct perf_hpp *hpp, width++; /* for '+' sign between column header */ first_col = false; - width += fmt->width(fmt, hpp, hists_to_evsel(hists)); + width += fmt->width(fmt, hpp, hists); } if (width > header_width) @@ -682,7 +682,7 @@ hists__fprintf_standard_headers(struct hists *hists, else first = false; - width = fmt->width(fmt, hpp, hists_to_evsel(hists)); + width = fmt->width(fmt, hpp, hists); for (i = 0; i < width; i++) fprintf(fp, "."); } diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c index d1f19e0..2515cfd 100644 --- a/tools/perf/util/hist.c +++ b/tools/perf/util/hist.c @@ -1081,7 +1081,7 @@ int hist_entry__snprintf_alignment(struct hist_entry *he, struct perf_hpp *hpp, struct perf_hpp_fmt *fmt, int printed) { if (!list_is_last(&fmt->list, &he->hists->hpp_list->fields)) { - const int width = fmt->width(fmt, hpp, hists_to_evsel(he->hists)); + const int width = fmt->width(fmt, hpp, he->hists); if (printed < width) { advance_hpp(hpp, printed); printed = scnprintf(hpp->buf, hpp->size, "%-*s", width - printed, " "); diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h index aae932f..a191128 100644 --- a/tools/perf/util/hist.h +++ b/tools/perf/util/hist.h @@ -217,7 +217,7 @@ struct perf_hpp_fmt { int (*header)(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, struct hists *hists); int (*width)(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, - struct perf_evsel *evsel); + struct hists *hists); int (*color)(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, struct hist_entry *he); int (*entry)(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c index 3e52c77..896d34eb 100644 --- a/tools/perf/util/sort.c +++ b/tools/perf/util/sort.c @@ -1503,7 +1503,7 @@ static int __sort__hpp_header(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, static int __sort__hpp_width(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp __maybe_unused, - struct perf_evsel *evsel) + struct hists *hists) { struct hpp_sort_entry *hse; size_t len = fmt->user_len; @@ -1511,7 +1511,7 @@ static int __sort__hpp_width(struct perf_hpp_fmt *fmt, hse = container_of(fmt, struct hpp_sort_entry, hpp); if (!len) - len = hists__col_len(evsel__hists(evsel), hse->se->se_width_idx); + len = hists__col_len(hists, hse->se->se_width_idx); return len; } @@ -1808,7 +1808,7 @@ static int __sort__hde_header(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, static int __sort__hde_width(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp __maybe_unused, - struct perf_evsel *evsel __maybe_unused) + struct hists *hists __maybe_unused) { struct hpp_dynamic_entry *hde; size_t len = fmt->user_len; -- cgit v0.10.2 From dd975497adcdd2526ae332d3938bd5d6e1c3731a Mon Sep 17 00:00:00 2001 From: Masami Hiramatsu Date: Wed, 15 Jun 2016 12:28:30 +0900 Subject: perf probe: Introduce perf_cache interfaces Introduce perf_cache object and interfaces to create, add entries, commit, and delete the object. perf_cache represents a file for the cached "perf probe" definitions on one binary file or vmlinux which has its own build id. The probe cache file is located under the build-id cache directory of the target binary, as below; /.build-id///probe Signed-off-by: Masami Hiramatsu Signed-off-by: Masami Hiramatsu Cc: Ananth N Mavinakayanahalli Cc: Brendan Gregg Cc: Hemant Kumar Cc: Namhyung Kim Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/20160615032830.31330.84998.stgit@devbox Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/util/probe-file.c b/tools/perf/util/probe-file.c index 3fe6214..25a4042 100644 --- a/tools/perf/util/probe-file.c +++ b/tools/perf/util/probe-file.c @@ -14,6 +14,7 @@ * GNU General Public License for more details. * */ +#include #include "util.h" #include "event.h" #include "strlist.h" @@ -324,3 +325,333 @@ int probe_file__del_events(int fd, struct strfilter *filter) return ret; } + +/* Caller must ensure to remove this entry from list */ +static void probe_cache_entry__delete(struct probe_cache_entry *entry) +{ + if (entry) { + BUG_ON(!list_empty(&entry->node)); + + strlist__delete(entry->tevlist); + clear_perf_probe_event(&entry->pev); + zfree(&entry->spev); + free(entry); + } +} + +static struct probe_cache_entry * +probe_cache_entry__new(struct perf_probe_event *pev) +{ + struct probe_cache_entry *entry = zalloc(sizeof(*entry)); + + if (entry) { + INIT_LIST_HEAD(&entry->node); + entry->tevlist = strlist__new(NULL, NULL); + if (!entry->tevlist) + zfree(&entry); + else if (pev) { + entry->spev = synthesize_perf_probe_command(pev); + if (!entry->spev || + perf_probe_event__copy(&entry->pev, pev) < 0) { + probe_cache_entry__delete(entry); + return NULL; + } + } + } + + return entry; +} + +/* For the kernel probe caches, pass target = NULL */ +static int probe_cache__open(struct probe_cache *pcache, const char *target) +{ + char cpath[PATH_MAX]; + char sbuildid[SBUILD_ID_SIZE]; + char *dir_name; + bool is_kallsyms = !target; + int ret, fd; + + if (target) + ret = filename__sprintf_build_id(target, sbuildid); + else { + target = DSO__NAME_KALLSYMS; + ret = sysfs__sprintf_build_id("/", sbuildid); + } + if (ret < 0) { + pr_debug("Failed to get build-id from %s.\n", target); + return ret; + } + + /* If we have no buildid cache, make it */ + if (!build_id_cache__cached(sbuildid)) { + ret = build_id_cache__add_s(sbuildid, target, + is_kallsyms, NULL); + if (ret < 0) { + pr_debug("Failed to add build-id cache: %s\n", target); + return ret; + } + } + + dir_name = build_id_cache__cachedir(sbuildid, target, is_kallsyms, + false); + if (!dir_name) + return -ENOMEM; + + snprintf(cpath, PATH_MAX, "%s/probes", dir_name); + fd = open(cpath, O_CREAT | O_RDWR, 0644); + if (fd < 0) + pr_debug("Failed to open cache(%d): %s\n", fd, cpath); + free(dir_name); + pcache->fd = fd; + + return fd; +} + +static int probe_cache__load(struct probe_cache *pcache) +{ + struct probe_cache_entry *entry = NULL; + char buf[MAX_CMDLEN], *p; + int ret = 0; + FILE *fp; + + fp = fdopen(dup(pcache->fd), "r"); + if (!fp) + return -EINVAL; + + while (!feof(fp)) { + if (!fgets(buf, MAX_CMDLEN, fp)) + break; + p = strchr(buf, '\n'); + if (p) + *p = '\0'; + if (buf[0] == '#') { /* #perf_probe_event */ + entry = probe_cache_entry__new(NULL); + if (!entry) { + ret = -ENOMEM; + goto out; + } + entry->spev = strdup(buf + 1); + if (entry->spev) + ret = parse_perf_probe_command(buf + 1, + &entry->pev); + else + ret = -ENOMEM; + if (ret < 0) { + probe_cache_entry__delete(entry); + goto out; + } + list_add_tail(&entry->node, &pcache->entries); + } else { /* trace_probe_event */ + if (!entry) { + ret = -EINVAL; + goto out; + } + strlist__add(entry->tevlist, buf); + } + } +out: + fclose(fp); + return ret; +} + +static struct probe_cache *probe_cache__alloc(void) +{ + struct probe_cache *pcache = zalloc(sizeof(*pcache)); + + if (pcache) { + INIT_LIST_HEAD(&pcache->entries); + pcache->fd = -EINVAL; + } + return pcache; +} + +void probe_cache__purge(struct probe_cache *pcache) +{ + struct probe_cache_entry *entry, *n; + + list_for_each_entry_safe(entry, n, &pcache->entries, node) { + list_del_init(&entry->node); + probe_cache_entry__delete(entry); + } +} + +void probe_cache__delete(struct probe_cache *pcache) +{ + if (!pcache) + return; + + probe_cache__purge(pcache); + if (pcache->fd > 0) + close(pcache->fd); + free(pcache); +} + +struct probe_cache *probe_cache__new(const char *target) +{ + struct probe_cache *pcache = probe_cache__alloc(); + int ret; + + if (!pcache) + return NULL; + + ret = probe_cache__open(pcache, target); + if (ret < 0) { + pr_debug("Cache open error: %d\n", ret); + goto out_err; + } + + ret = probe_cache__load(pcache); + if (ret < 0) { + pr_debug("Cache read error: %d\n", ret); + goto out_err; + } + + return pcache; + +out_err: + probe_cache__delete(pcache); + return NULL; +} + +static bool streql(const char *a, const char *b) +{ + if (a == b) + return true; + + if (!a || !b) + return false; + + return !strcmp(a, b); +} + +static struct probe_cache_entry * +probe_cache__find(struct probe_cache *pcache, struct perf_probe_event *pev) +{ + struct probe_cache_entry *entry = NULL; + char *cmd = synthesize_perf_probe_command(pev); + + if (!cmd) + return NULL; + + list_for_each_entry(entry, &pcache->entries, node) { + /* Hit if same event name or same command-string */ + if ((pev->event && + (streql(entry->pev.group, pev->group) && + streql(entry->pev.event, pev->event))) || + (!strcmp(entry->spev, cmd))) + goto found; + } + entry = NULL; + +found: + free(cmd); + return entry; +} + +int probe_cache__add_entry(struct probe_cache *pcache, + struct perf_probe_event *pev, + struct probe_trace_event *tevs, int ntevs) +{ + struct probe_cache_entry *entry = NULL; + char *command; + int i, ret = 0; + + if (!pcache || !pev || !tevs || ntevs <= 0) { + ret = -EINVAL; + goto out_err; + } + + /* Remove old cache entry */ + entry = probe_cache__find(pcache, pev); + if (entry) { + list_del_init(&entry->node); + probe_cache_entry__delete(entry); + } + + ret = -ENOMEM; + entry = probe_cache_entry__new(pev); + if (!entry) + goto out_err; + + for (i = 0; i < ntevs; i++) { + if (!tevs[i].point.symbol) + continue; + + command = synthesize_probe_trace_command(&tevs[i]); + if (!command) + goto out_err; + strlist__add(entry->tevlist, command); + free(command); + } + list_add_tail(&entry->node, &pcache->entries); + pr_debug("Added probe cache: %d\n", ntevs); + return 0; + +out_err: + pr_debug("Failed to add probe caches\n"); + probe_cache_entry__delete(entry); + return ret; +} + +static int probe_cache_entry__write(struct probe_cache_entry *entry, int fd) +{ + struct str_node *snode; + struct stat st; + struct iovec iov[3]; + int ret; + /* Save stat for rollback */ + ret = fstat(fd, &st); + if (ret < 0) + return ret; + + pr_debug("Writing cache: #%s\n", entry->spev); + iov[0].iov_base = (void *)"#"; iov[0].iov_len = 1; + iov[1].iov_base = entry->spev; iov[1].iov_len = strlen(entry->spev); + iov[2].iov_base = (void *)"\n"; iov[2].iov_len = 1; + ret = writev(fd, iov, 3); + if (ret < (int)iov[1].iov_len + 2) + goto rollback; + + strlist__for_each(snode, entry->tevlist) { + iov[0].iov_base = (void *)snode->s; + iov[0].iov_len = strlen(snode->s); + iov[1].iov_base = (void *)"\n"; iov[1].iov_len = 1; + ret = writev(fd, iov, 2); + if (ret < (int)iov[0].iov_len + 1) + goto rollback; + } + return 0; + +rollback: + /* Rollback to avoid cache file corruption */ + if (ret > 0) + ret = -1; + if (ftruncate(fd, st.st_size) < 0) + ret = -2; + + return ret; +} + +int probe_cache__commit(struct probe_cache *pcache) +{ + struct probe_cache_entry *entry; + int ret = 0; + + /* TBD: if we do not update existing entries, skip it */ + ret = lseek(pcache->fd, 0, SEEK_SET); + if (ret < 0) + goto out; + + ret = ftruncate(pcache->fd, 0); + if (ret < 0) + goto out; + + list_for_each_entry(entry, &pcache->entries, node) { + ret = probe_cache_entry__write(entry, pcache->fd); + pr_debug("Cache committed: %d\n", ret); + if (ret < 0) + break; + } +out: + return ret; +} diff --git a/tools/perf/util/probe-file.h b/tools/perf/util/probe-file.h index 18ac9cf..d872e3d 100644 --- a/tools/perf/util/probe-file.h +++ b/tools/perf/util/probe-file.h @@ -5,6 +5,19 @@ #include "strfilter.h" #include "probe-event.h" +/* Cache of probe definitions */ +struct probe_cache_entry { + struct list_head node; + struct perf_probe_event pev; + char *spev; + struct strlist *tevlist; +}; + +struct probe_cache { + int fd; + struct list_head entries; +}; + #define PF_FL_UPROBE 1 #define PF_FL_RW 2 @@ -18,5 +31,12 @@ int probe_file__get_events(int fd, struct strfilter *filter, struct strlist *plist); int probe_file__del_strlist(int fd, struct strlist *namelist); +struct probe_cache *probe_cache__new(const char *target); +int probe_cache__add_entry(struct probe_cache *pcache, + struct perf_probe_event *pev, + struct probe_trace_event *tevs, int ntevs); +int probe_cache__commit(struct probe_cache *pcache); +void probe_cache__purge(struct probe_cache *pcache); +void probe_cache__delete(struct probe_cache *pcache); #endif -- cgit v0.10.2 From 2fd457a34525ea3bc609e377b46af759af8a7934 Mon Sep 17 00:00:00 2001 From: Masami Hiramatsu Date: Wed, 15 Jun 2016 12:28:40 +0900 Subject: perf probe: Add --cache option to cache the probe definitions Add --cache option to cache the probe definitions. This just saves the result of the dwarf analysis to probe cache. Signed-off-by: Masami Hiramatsu Signed-off-by: Masami Hiramatsu Cc: Ananth N Mavinakayanahalli Cc: Brendan Gregg Cc: Hemant Kumar Cc: Masami Hiramatsu Cc: Namhyung Kim Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/20160615032840.31330.44412.stgit@devbox Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/Documentation/perf-probe.txt b/tools/perf/Documentation/perf-probe.txt index 3a8a9ba..947db6f 100644 --- a/tools/perf/Documentation/perf-probe.txt +++ b/tools/perf/Documentation/perf-probe.txt @@ -109,6 +109,10 @@ OPTIONS Dry run. With this option, --add and --del doesn't execute actual adding and removal operations. +--cache:: + Cache the probes (with --add option). Any events which successfully added + are also stored in the cache file. + --max-probes=NUM:: Set the maximum number of probe points for an event. Default is 128. diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c index 9af859b..6d7ab431 100644 --- a/tools/perf/builtin-probe.c +++ b/tools/perf/builtin-probe.c @@ -512,6 +512,7 @@ __cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused) "Enable symbol demangling"), OPT_BOOLEAN(0, "demangle-kernel", &symbol_conf.demangle_kernel, "Enable kernel symbol demangling"), + OPT_BOOLEAN(0, "cache", &probe_conf.cache, "Manipulate probe cache"), OPT_END() }; int ret; diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c index cbc8a8b..084756c 100644 --- a/tools/perf/util/probe-event.c +++ b/tools/perf/util/probe-event.c @@ -2514,6 +2514,7 @@ static int __add_probe_trace_events(struct perf_probe_event *pev, { int i, fd, ret; struct probe_trace_event *tev = NULL; + struct probe_cache *cache = NULL; struct strlist *namelist; fd = probe_file__open(PF_FL_RW | (pev->uprobes ? PF_FL_UPROBE : 0)); @@ -2555,6 +2556,14 @@ static int __add_probe_trace_events(struct perf_probe_event *pev, } if (ret == -EINVAL && pev->uprobes) warn_uprobe_event_compat(tev); + if (ret == 0 && probe_conf.cache) { + cache = probe_cache__new(pev->target); + if (!cache || + probe_cache__add_entry(cache, pev, tevs, ntevs) < 0 || + probe_cache__commit(cache) < 0) + pr_warning("Failed to add event to probe cache\n"); + probe_cache__delete(cache); + } strlist__delete(namelist); close_out: diff --git a/tools/perf/util/probe-event.h b/tools/perf/util/probe-event.h index 0b024ba..432b690 100644 --- a/tools/perf/util/probe-event.h +++ b/tools/perf/util/probe-event.h @@ -12,6 +12,7 @@ struct probe_conf { bool show_location_range; bool force_add; bool no_inlines; + bool cache; int max_probes; }; extern struct probe_conf probe_conf; -- cgit v0.10.2 From 3a37f7275cda5ad25c1fe9be8f20c76c60d175fa Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Sun, 1 May 2016 18:46:54 -0700 Subject: rcu: No ordering for rcu_assign_pointer() of NULL This commit does a compile-time check for rcu_assign_pointer() of NULL, and uses WRITE_ONCE() rather than smp_store_release() in that case. Reported-by: Christoph Hellwig Signed-off-by: Paul E. McKenney diff --git a/include/linux/rcupdate.h b/include/linux/rcupdate.h index c61b6b9..a8af797 100644 --- a/include/linux/rcupdate.h +++ b/include/linux/rcupdate.h @@ -650,7 +650,16 @@ static inline void rcu_preempt_sleep_check(void) * please be careful when making changes to rcu_assign_pointer() and the * other macros that it invokes. */ -#define rcu_assign_pointer(p, v) smp_store_release(&p, RCU_INITIALIZER(v)) +#define rcu_assign_pointer(p, v) \ +({ \ + uintptr_t _r_a_p__v = (uintptr_t)(v); \ + \ + if (__builtin_constant_p(v) && (_r_a_p__v) == (uintptr_t)NULL) \ + WRITE_ONCE((p), (typeof(p))(_r_a_p__v)); \ + else \ + smp_store_release(&p, RCU_INITIALIZER((typeof(p))_r_a_p__v)); \ + _r_a_p__v; \ +}) /** * rcu_access_pointer() - fetch RCU pointer with no dereferencing -- cgit v0.10.2 From 570dd3c7424179b831decb655ea9dd1ecea38adc Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Wed, 15 Jun 2016 08:56:53 -0700 Subject: rcu: Disable TASKS_RCU for usermode Linux Usermode Linux currently does not implement arch_irqs_disabled_flags(), which results in a build failure in TASKS_RCU. Therefore, this commit disables the TASKS_RCU Kconfig option in usermode Linux builds. The usermode Linux maintainers expect to merge arch_irqs_disabled_flags() into 4.8, at which point this commit may be reverted. Signed-off-by: Paul E. McKenney Cc: Jeff Dike Acked-by: Richard Weinberger diff --git a/init/Kconfig b/init/Kconfig index f755a60..a068265 100644 --- a/init/Kconfig +++ b/init/Kconfig @@ -517,6 +517,7 @@ config SRCU config TASKS_RCU bool default n + depends on !UML select SRCU help This option enables a task-based RCU implementation that uses -- cgit v0.10.2 From 4929c913bda505dbe44bb42c00da06011fee6c9d Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Mon, 2 May 2016 11:58:56 -0700 Subject: rcu: Make call_rcu_tasks() tolerate first call with irqs disabled Currently, if the very first call to call_rcu_tasks() has irqs disabled, it will create the rcu_tasks_kthread with irqs disabled, which will result in a splat in the memory allocator, which kthread_run() invokes with the expectation that irqs are enabled. This commit fixes this problem by deferring kthread creation if called with irqs disabled. The first call to call_rcu_tasks() that has irqs enabled will create the kthread. This bug was detected by rcutorture changes that were motivated by Iftekhar Ahmed's mutation-testing efforts. Signed-off-by: Paul E. McKenney diff --git a/include/linux/rcupdate.h b/include/linux/rcupdate.h index a8af797..3bc5de0 100644 --- a/include/linux/rcupdate.h +++ b/include/linux/rcupdate.h @@ -45,6 +45,7 @@ #include #include #include +#include #include diff --git a/kernel/rcu/update.c b/kernel/rcu/update.c index 3e888cd..f0d8322 100644 --- a/kernel/rcu/update.c +++ b/kernel/rcu/update.c @@ -528,6 +528,7 @@ static int rcu_task_stall_timeout __read_mostly = HZ * 60 * 10; module_param(rcu_task_stall_timeout, int, 0644); static void rcu_spawn_tasks_kthread(void); +static struct task_struct *rcu_tasks_kthread_ptr; /* * Post an RCU-tasks callback. First call must be from process context @@ -537,6 +538,7 @@ void call_rcu_tasks(struct rcu_head *rhp, rcu_callback_t func) { unsigned long flags; bool needwake; + bool havetask = READ_ONCE(rcu_tasks_kthread_ptr); rhp->next = NULL; rhp->func = func; @@ -545,7 +547,9 @@ void call_rcu_tasks(struct rcu_head *rhp, rcu_callback_t func) *rcu_tasks_cbs_tail = rhp; rcu_tasks_cbs_tail = &rhp->next; raw_spin_unlock_irqrestore(&rcu_tasks_cbs_lock, flags); - if (needwake) { + /* We can't create the thread unless interrupts are enabled. */ + if ((needwake && havetask) || + (!havetask && !irqs_disabled_flags(flags))) { rcu_spawn_tasks_kthread(); wake_up(&rcu_tasks_cbs_wq); } @@ -790,7 +794,6 @@ static int __noreturn rcu_tasks_kthread(void *arg) static void rcu_spawn_tasks_kthread(void) { static DEFINE_MUTEX(rcu_tasks_kthread_mutex); - static struct task_struct *rcu_tasks_kthread_ptr; struct task_struct *t; if (READ_ONCE(rcu_tasks_kthread_ptr)) { -- cgit v0.10.2 From aab057382cb9b16249552684c1ebd270f070ec02 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Mon, 2 May 2016 12:20:51 -0700 Subject: rcu: Fix a typo in a comment In the area in hot pursuit of a bug, so might as well clean it up. Signed-off-by: Paul E. McKenney diff --git a/kernel/rcu/rcutorture.c b/kernel/rcu/rcutorture.c index 084a28a..60bd533 100644 --- a/kernel/rcu/rcutorture.c +++ b/kernel/rcu/rcutorture.c @@ -1476,7 +1476,7 @@ static int rcu_torture_barrier_cbs(void *arg) break; /* * The above smp_load_acquire() ensures barrier_phase load - * is ordered before the folloiwng ->call(). + * is ordered before the following ->call(). */ local_irq_disable(); /* Just to test no-irq call_rcu(). */ cur_ops->call(&rcu, rcu_torture_barrier_cbf); -- cgit v0.10.2 From 088e9d253d3a4ab7e058dd84bb532c32dadf1882 Mon Sep 17 00:00:00 2001 From: Daniel Bristot de Oliveira Date: Thu, 2 Jun 2016 13:51:41 -0300 Subject: rcu: sysctl: Panic on RCU Stall It is not always easy to determine the cause of an RCU stall just by analysing the RCU stall messages, mainly when the problem is caused by the indirect starvation of rcu threads. For example, when preempt_rcu is not awakened due to the starvation of a timer softirq. We have been hard coding panic() in the RCU stall functions for some time while testing the kernel-rt. But this is not possible in some scenarios, like when supporting customers. This patch implements the sysctl kernel.panic_on_rcu_stall. If set to 1, the system will panic() when an RCU stall takes place, enabling the capture of a vmcore. The vmcore provides a way to analyze all kernel/tasks states, helping out to point to the culprit and the solution for the stall. The kernel.panic_on_rcu_stall sysctl is disabled by default. Changes from v1: - Fixed a typo in the git log - The if(sysctl_panic_on_rcu_stall) panic() is in a static function - Fixed the CONFIG_TINY_RCU compilation issue - The var sysctl_panic_on_rcu_stall is now __read_mostly Cc: Jonathan Corbet Cc: "Paul E. McKenney" Cc: Josh Triplett Cc: Steven Rostedt Cc: Mathieu Desnoyers Cc: Lai Jiangshan Acked-by: Christian Borntraeger Reviewed-by: Josh Triplett Reviewed-by: Arnaldo Carvalho de Melo Tested-by: "Luis Claudio R. Goncalves" Signed-off-by: Daniel Bristot de Oliveira Signed-off-by: Paul E. McKenney diff --git a/Documentation/sysctl/kernel.txt b/Documentation/sysctl/kernel.txt index a3683ce..3320460 100644 --- a/Documentation/sysctl/kernel.txt +++ b/Documentation/sysctl/kernel.txt @@ -58,6 +58,7 @@ show up in /proc/sys/kernel: - panic_on_stackoverflow - panic_on_unrecovered_nmi - panic_on_warn +- panic_on_rcu_stall - perf_cpu_time_max_percent - perf_event_paranoid - perf_event_max_stack @@ -618,6 +619,17 @@ a kernel rebuild when attempting to kdump at the location of a WARN(). ============================================================== +panic_on_rcu_stall: + +When set to 1, calls panic() after RCU stall detection messages. This +is useful to define the root cause of RCU stalls using a vmcore. + +0: do not panic() when RCU stall takes place, default behavior. + +1: panic() after printing RCU stall messages. + +============================================================== + perf_cpu_time_max_percent: Hints to the kernel how much CPU time it should be allowed to diff --git a/include/linux/kernel.h b/include/linux/kernel.h index 94aa10f..c420821 100644 --- a/include/linux/kernel.h +++ b/include/linux/kernel.h @@ -451,6 +451,7 @@ extern int panic_on_oops; extern int panic_on_unrecovered_nmi; extern int panic_on_io_nmi; extern int panic_on_warn; +extern int sysctl_panic_on_rcu_stall; extern int sysctl_panic_on_stackoverflow; extern bool crash_kexec_post_notifiers; diff --git a/kernel/rcu/tree.c b/kernel/rcu/tree.c index c844b61..e5ca15a 100644 --- a/kernel/rcu/tree.c +++ b/kernel/rcu/tree.c @@ -125,6 +125,8 @@ int rcu_num_lvls __read_mostly = RCU_NUM_LVLS; /* Number of rcu_nodes at specified level. */ static int num_rcu_lvl[] = NUM_RCU_LVL_INIT; int rcu_num_nodes __read_mostly = NUM_RCU_NODES; /* Total # rcu_nodes in use. */ +/* panic() on RCU Stall sysctl. */ +int sysctl_panic_on_rcu_stall __read_mostly; /* * The rcu_scheduler_active variable transitions from zero to one just @@ -1312,6 +1314,12 @@ static void rcu_stall_kick_kthreads(struct rcu_state *rsp) } } +static inline void panic_on_rcu_stall(void) +{ + if (sysctl_panic_on_rcu_stall) + panic("RCU Stall\n"); +} + static void print_other_cpu_stall(struct rcu_state *rsp, unsigned long gpnum) { int cpu; @@ -1391,6 +1399,8 @@ static void print_other_cpu_stall(struct rcu_state *rsp, unsigned long gpnum) rcu_check_gp_kthread_starvation(rsp); + panic_on_rcu_stall(); + force_quiescent_state(rsp); /* Kick them all. */ } @@ -1431,6 +1441,8 @@ static void print_cpu_stall(struct rcu_state *rsp) jiffies + 3 * rcu_jiffies_till_stall_check() + 3); raw_spin_unlock_irqrestore_rcu_node(rnp, flags); + panic_on_rcu_stall(); + /* * Attempt to revive the RCU machinery by forcing a context switch. * diff --git a/kernel/sysctl.c b/kernel/sysctl.c index 87b2fc3..35f0dcb 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c @@ -1205,6 +1205,17 @@ static struct ctl_table kern_table[] = { .extra2 = &one, }, #endif +#if defined(CONFIG_TREE_RCU) || defined(CONFIG_PREEMPT_RCU) + { + .procname = "panic_on_rcu_stall", + .data = &sysctl_panic_on_rcu_stall, + .maxlen = sizeof(sysctl_panic_on_rcu_stall), + .mode = 0644, + .proc_handler = proc_dointvec_minmax, + .extra1 = &zero, + .extra2 = &one, + }, +#endif { } }; -- cgit v0.10.2 From bc75e99983df1efd977a5cd468893d55d52b8d70 Mon Sep 17 00:00:00 2001 From: Mark Rutland Date: Fri, 3 Jun 2016 15:20:04 +0100 Subject: rcu: Correctly handle sparse possible cpus In many cases in the RCU tree code, we iterate over the set of cpus for a leaf node described by rcu_node::grplo and rcu_node::grphi, checking per-cpu data for each cpu in this range. However, if the set of possible cpus is sparse, some cpus described in this range are not possible, and thus no per-cpu region will have been allocated (or initialised) for them by the generic percpu code. Erroneous accesses to a per-cpu area for these !possible cpus may fault or may hit other data depending on the addressed generated when the erroneous per cpu offset is applied. In practice, both cases have been observed on arm64 hardware (the former being silent, but detectable with additional patches). To avoid issues resulting from this, we must iterate over the set of *possible* cpus for a given leaf node. This patch add a new helper, for_each_leaf_node_possible_cpu, to enable this. As iteration is often intertwined with rcu_node local bitmask manipulation, a new leaf_node_cpu_bit helper is added to make this simpler and more consistent. The RCU tree code is made to use both of these where appropriate. Without this patch, running reboot at a shell can result in an oops like: [ 3369.075979] Unable to handle kernel paging request at virtual address ffffff8008b21b4c [ 3369.083881] pgd = ffffffc3ecdda000 [ 3369.087270] [ffffff8008b21b4c] *pgd=00000083eca48003, *pud=00000083eca48003, *pmd=0000000000000000 [ 3369.096222] Internal error: Oops: 96000007 [#1] PREEMPT SMP [ 3369.101781] Modules linked in: [ 3369.104825] CPU: 2 PID: 1817 Comm: NetworkManager Tainted: G W 4.6.0+ #3 [ 3369.121239] task: ffffffc0fa13e000 ti: ffffffc3eb940000 task.ti: ffffffc3eb940000 [ 3369.128708] PC is at sync_rcu_exp_select_cpus+0x188/0x510 [ 3369.134094] LR is at sync_rcu_exp_select_cpus+0x104/0x510 [ 3369.139479] pc : [] lr : [] pstate: 200001c5 [ 3369.146860] sp : ffffffc3eb9435a0 [ 3369.150162] x29: ffffffc3eb9435a0 x28: ffffff8008be4f88 [ 3369.155465] x27: ffffff8008b66c80 x26: ffffffc3eceb2600 [ 3369.160767] x25: 0000000000000001 x24: ffffff8008be4f88 [ 3369.166070] x23: ffffff8008b51c3c x22: ffffff8008b66c80 [ 3369.171371] x21: 0000000000000001 x20: ffffff8008b21b40 [ 3369.176673] x19: ffffff8008b66c80 x18: 0000000000000000 [ 3369.181975] x17: 0000007fa951a010 x16: ffffff80086a30f0 [ 3369.187278] x15: 0000007fa9505590 x14: 0000000000000000 [ 3369.192580] x13: ffffff8008b51000 x12: ffffffc3eb940000 [ 3369.197882] x11: 0000000000000006 x10: ffffff8008b51b78 [ 3369.203184] x9 : 0000000000000001 x8 : ffffff8008be4000 [ 3369.208486] x7 : ffffff8008b21b40 x6 : 0000000000001003 [ 3369.213788] x5 : 0000000000000000 x4 : ffffff8008b27280 [ 3369.219090] x3 : ffffff8008b21b4c x2 : 0000000000000001 [ 3369.224406] x1 : 0000000000000001 x0 : 0000000000000140 ... [ 3369.972257] [] sync_rcu_exp_select_cpus+0x188/0x510 [ 3369.978685] [] synchronize_rcu_expedited+0x64/0xa8 [ 3369.985026] [] synchronize_net+0x24/0x30 [ 3369.990499] [] dev_deactivate_many+0x28c/0x298 [ 3369.996493] [] __dev_close_many+0x60/0xd0 [ 3370.002052] [] __dev_close+0x28/0x40 [ 3370.007178] [] __dev_change_flags+0x8c/0x158 [ 3370.012999] [] dev_change_flags+0x20/0x60 [ 3370.018558] [] do_setlink+0x288/0x918 [ 3370.023771] [] rtnl_newlink+0x398/0x6a8 [ 3370.029158] [] rtnetlink_rcv_msg+0xe4/0x220 [ 3370.034891] [] netlink_rcv_skb+0xc4/0xf8 [ 3370.040364] [] rtnetlink_rcv+0x2c/0x40 [ 3370.045663] [] netlink_unicast+0x160/0x238 [ 3370.051309] [] netlink_sendmsg+0x2f0/0x358 [ 3370.056956] [] sock_sendmsg+0x18/0x30 [ 3370.062168] [] ___sys_sendmsg+0x26c/0x280 [ 3370.067728] [] __sys_sendmsg+0x44/0x88 [ 3370.073027] [] SyS_sendmsg+0x10/0x20 [ 3370.078153] [] el0_svc_naked+0x24/0x28 Signed-off-by: Mark Rutland Reported-by: Dennis Chen Cc: Catalin Marinas Cc: Josh Triplett Cc: Lai Jiangshan Cc: Mathieu Desnoyers Cc: Steve Capper Cc: Steven Rostedt Cc: Will Deacon Cc: linux-kernel@vger.kernel.org Signed-off-by: Paul E. McKenney diff --git a/kernel/rcu/tree.c b/kernel/rcu/tree.c index e5ca15a..f433959 100644 --- a/kernel/rcu/tree.c +++ b/kernel/rcu/tree.c @@ -1287,9 +1287,9 @@ static void rcu_dump_cpu_stacks(struct rcu_state *rsp) rcu_for_each_leaf_node(rsp, rnp) { raw_spin_lock_irqsave_rcu_node(rnp, flags); if (rnp->qsmask != 0) { - for (cpu = 0; cpu <= rnp->grphi - rnp->grplo; cpu++) - if (rnp->qsmask & (1UL << cpu)) - dump_cpu_task(rnp->grplo + cpu); + for_each_leaf_node_possible_cpu(rnp, cpu) + if (rnp->qsmask & leaf_node_cpu_bit(rnp, cpu)) + dump_cpu_task(cpu); } raw_spin_unlock_irqrestore_rcu_node(rnp, flags); } @@ -1360,10 +1360,9 @@ static void print_other_cpu_stall(struct rcu_state *rsp, unsigned long gpnum) raw_spin_lock_irqsave_rcu_node(rnp, flags); ndetected += rcu_print_task_stall(rnp); if (rnp->qsmask != 0) { - for (cpu = 0; cpu <= rnp->grphi - rnp->grplo; cpu++) - if (rnp->qsmask & (1UL << cpu)) { - print_cpu_stall_info(rsp, - rnp->grplo + cpu); + for_each_leaf_node_possible_cpu(rnp, cpu) + if (rnp->qsmask & leaf_node_cpu_bit(rnp, cpu)) { + print_cpu_stall_info(rsp, cpu); ndetected++; } } @@ -2884,7 +2883,6 @@ static void force_qs_rnp(struct rcu_state *rsp, unsigned long *maxj), bool *isidle, unsigned long *maxj) { - unsigned long bit; int cpu; unsigned long flags; unsigned long mask; @@ -2919,9 +2917,8 @@ static void force_qs_rnp(struct rcu_state *rsp, continue; } } - cpu = rnp->grplo; - bit = 1; - for (; cpu <= rnp->grphi; cpu++, bit <<= 1) { + for_each_leaf_node_possible_cpu(rnp, cpu) { + unsigned long bit = leaf_node_cpu_bit(rnp, cpu); if ((rnp->qsmask & bit) != 0) { if (f(per_cpu_ptr(rsp->rda, cpu), isidle, maxj)) mask |= bit; @@ -3750,7 +3747,7 @@ rcu_boot_init_percpu_data(int cpu, struct rcu_state *rsp) /* Set up local state, ensuring consistent view of global state. */ raw_spin_lock_irqsave_rcu_node(rnp, flags); - rdp->grpmask = 1UL << (cpu - rdp->mynode->grplo); + rdp->grpmask = leaf_node_cpu_bit(rdp->mynode, cpu); rdp->dynticks = &per_cpu(rcu_dynticks, cpu); WARN_ON_ONCE(rdp->dynticks->dynticks_nesting != DYNTICK_TASK_EXIT_IDLE); WARN_ON_ONCE(atomic_read(&rdp->dynticks->dynticks) != 1); diff --git a/kernel/rcu/tree.h b/kernel/rcu/tree.h index e3959f5..f714f87 100644 --- a/kernel/rcu/tree.h +++ b/kernel/rcu/tree.h @@ -254,6 +254,13 @@ struct rcu_node { } ____cacheline_internodealigned_in_smp; /* + * Bitmasks in an rcu_node cover the interval [grplo, grphi] of CPU IDs, and + * are indexed relative to this interval rather than the global CPU ID space. + * This generates the bit for a CPU in node-local masks. + */ +#define leaf_node_cpu_bit(rnp, cpu) (1UL << ((cpu) - (rnp)->grplo)) + +/* * Do a full breadth-first scan of the rcu_node structures for the * specified rcu_state structure. */ @@ -281,6 +288,14 @@ struct rcu_node { (rnp) < &(rsp)->node[rcu_num_nodes]; (rnp)++) /* + * Iterate over all possible CPUs in a leaf RCU node. + */ +#define for_each_leaf_node_possible_cpu(rnp, cpu) \ + for ((cpu) = cpumask_next(rnp->grplo - 1, cpu_possible_mask); \ + cpu <= rnp->grphi; \ + cpu = cpumask_next((cpu), cpu_possible_mask)) + +/* * Union to allow "aggregate OR" operation on the need for a quiescent * state by the normal and expedited grace periods. */ diff --git a/kernel/rcu/tree_exp.h b/kernel/rcu/tree_exp.h index 00a02a2..d400434 100644 --- a/kernel/rcu/tree_exp.h +++ b/kernel/rcu/tree_exp.h @@ -344,7 +344,6 @@ static void sync_rcu_exp_select_cpus(struct rcu_state *rsp, { int cpu; unsigned long flags; - unsigned long mask; unsigned long mask_ofl_test; unsigned long mask_ofl_ipi; int ret; @@ -356,7 +355,7 @@ static void sync_rcu_exp_select_cpus(struct rcu_state *rsp, /* Each pass checks a CPU for identity, offline, and idle. */ mask_ofl_test = 0; - for (cpu = rnp->grplo; cpu <= rnp->grphi; cpu++) { + for_each_leaf_node_possible_cpu(rnp, cpu) { struct rcu_data *rdp = per_cpu_ptr(rsp->rda, cpu); struct rcu_dynticks *rdtp = &per_cpu(rcu_dynticks, cpu); @@ -376,8 +375,8 @@ static void sync_rcu_exp_select_cpus(struct rcu_state *rsp, raw_spin_unlock_irqrestore_rcu_node(rnp, flags); /* IPI the remaining CPUs for expedited quiescent state. */ - mask = 1; - for (cpu = rnp->grplo; cpu <= rnp->grphi; cpu++, mask <<= 1) { + for_each_leaf_node_possible_cpu(rnp, cpu) { + unsigned long mask = leaf_node_cpu_bit(rnp, cpu); if (!(mask_ofl_ipi & mask)) continue; retry_ipi: @@ -440,10 +439,10 @@ static void synchronize_sched_expedited_wait(struct rcu_state *rsp) ndetected = 0; rcu_for_each_leaf_node(rsp, rnp) { ndetected += rcu_print_task_exp_stall(rnp); - mask = 1; - for (cpu = rnp->grplo; cpu <= rnp->grphi; cpu++, mask <<= 1) { + for_each_leaf_node_possible_cpu(rnp, cpu) { struct rcu_data *rdp; + mask = leaf_node_cpu_bit(rnp, cpu); if (!(rnp->expmask & mask)) continue; ndetected++; @@ -453,7 +452,6 @@ static void synchronize_sched_expedited_wait(struct rcu_state *rsp) "o."[!!(rdp->grpmask & rnp->expmaskinit)], "N."[!!(rdp->grpmask & rnp->expmaskinitnext)]); } - mask <<= 1; } pr_cont(" } %lu jiffies s: %lu root: %#lx/%c\n", jiffies - jiffies_start, rsp->expedited_sequence, @@ -473,8 +471,8 @@ static void synchronize_sched_expedited_wait(struct rcu_state *rsp) pr_cont("\n"); } rcu_for_each_leaf_node(rsp, rnp) { - mask = 1; - for (cpu = rnp->grplo; cpu <= rnp->grphi; cpu++, mask <<= 1) { + for_each_leaf_node_possible_cpu(rnp, cpu) { + mask = leaf_node_cpu_bit(rnp, cpu); if (!(rnp->expmask & mask)) continue; dump_cpu_task(cpu); diff --git a/kernel/rcu/tree_plugin.h b/kernel/rcu/tree_plugin.h index 695071d..534c590 100644 --- a/kernel/rcu/tree_plugin.h +++ b/kernel/rcu/tree_plugin.h @@ -1166,8 +1166,9 @@ static void rcu_boost_kthread_setaffinity(struct rcu_node *rnp, int outgoingcpu) return; if (!zalloc_cpumask_var(&cm, GFP_KERNEL)) return; - for (cpu = rnp->grplo; cpu <= rnp->grphi; cpu++, mask >>= 1) - if ((mask & 0x1) && cpu != outgoingcpu) + for_each_leaf_node_possible_cpu(rnp, cpu) + if ((mask & leaf_node_cpu_bit(rnp, cpu)) && + cpu != outgoingcpu) cpumask_set_cpu(cpu, cm); if (cpumask_weight(cm) == 0) cpumask_setall(cm); -- cgit v0.10.2 From 9ca91a65583c73e4be6e9f53323a7ae04e6803ef Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 15 Jun 2016 17:55:23 +0200 Subject: clk: sunxi: remove unused variable The only use of the local num_parents variable was remove, so we now get a warning: drivers/clk/sunxi/clk-sun4i-tcon-ch1.c: In function 'tcon_ch1_get_parent': drivers/clk/sunxi/clk-sun4i-tcon-ch1.c:82:6: error: unused variable 'num_parents' [-Werror=unused-variable] This removes the variable. Signed-off-by: Arnd Bergmann Fixes: 4de2d58bc973 ("clk: sunxi: tcon-ch1: Do not return a negative error in get_parent") Signed-off-by: Maxime Ripard diff --git a/drivers/clk/sunxi/clk-sun4i-tcon-ch1.c b/drivers/clk/sunxi/clk-sun4i-tcon-ch1.c index 2485852..b6d29d1 100644 --- a/drivers/clk/sunxi/clk-sun4i-tcon-ch1.c +++ b/drivers/clk/sunxi/clk-sun4i-tcon-ch1.c @@ -79,7 +79,6 @@ static int tcon_ch1_is_enabled(struct clk_hw *hw) static u8 tcon_ch1_get_parent(struct clk_hw *hw) { struct tcon_ch1_clk *tclk = hw_to_tclk(hw); - int num_parents = clk_hw_get_num_parents(hw); u32 reg; reg = readl(tclk->reg) >> TCON_CH1_SCLK2_MUX_SHIFT; -- cgit v0.10.2 From 5fc39d347267bd029fcc9099c70e2fe2d53130e9 Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Wed, 15 Jun 2016 13:20:19 +0200 Subject: ARM: sunxi/dt: make the CHIP inherit from allwinner,sun5i-a13 The sun4i-timer driver registers its sched_clock only if the machine is compatible with "allwinner,sun5i-a13", "allwinner,sun5i-a10s" or "allwinner,sun4i-a10". Add the missing "allwinner,sun5i-a13" string to the machine compatible. Signed-off-by: Boris Brezillon Fixes: 465a225fb2af ("ARM: sun5i: Add C.H.I.P DTS") Cc: Signed-off-by: Maxime Ripard diff --git a/arch/arm/boot/dts/sun5i-r8-chip.dts b/arch/arm/boot/dts/sun5i-r8-chip.dts index a8d8b45..f694482 100644 --- a/arch/arm/boot/dts/sun5i-r8-chip.dts +++ b/arch/arm/boot/dts/sun5i-r8-chip.dts @@ -52,7 +52,7 @@ / { model = "NextThing C.H.I.P."; - compatible = "nextthing,chip", "allwinner,sun5i-r8"; + compatible = "nextthing,chip", "allwinner,sun5i-r8", "allwinner,sun5i-a13"; aliases { i2c0 = &i2c0; -- cgit v0.10.2 From 1f51dee7ca7424be6f84067395166f878dbdd8be Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Mon, 18 Apr 2016 01:16:10 +0200 Subject: locking/atomic, arch/alpha: Implement atomic{,64}_fetch_{add,sub,and,andnot,or,xor}() Implement FETCH-OP atomic primitives, these are very similar to the existing OP-RETURN primitives we already have, except they return the value of the atomic variable _before_ modification. This is especially useful for irreversible operations -- such as bitops (because it becomes impossible to reconstruct the state prior to modification). Signed-off-by: Peter Zijlstra (Intel) Cc: Andrew Morton Cc: Ivan Kokshaysky Cc: Linus Torvalds Cc: Matt Turner Cc: Paul E. McKenney Cc: Peter Zijlstra Cc: Richard Henderson Cc: Thomas Gleixner Cc: linux-alpha@vger.kernel.org Cc: linux-arch@vger.kernel.org Cc: linux-kernel@vger.kernel.org Signed-off-by: Ingo Molnar diff --git a/arch/alpha/include/asm/atomic.h b/arch/alpha/include/asm/atomic.h index 572b228..8243f17 100644 --- a/arch/alpha/include/asm/atomic.h +++ b/arch/alpha/include/asm/atomic.h @@ -65,6 +65,25 @@ static inline int atomic_##op##_return(int i, atomic_t *v) \ return result; \ } +#define ATOMIC_FETCH_OP(op, asm_op) \ +static inline int atomic_fetch_##op(int i, atomic_t *v) \ +{ \ + long temp, result; \ + smp_mb(); \ + __asm__ __volatile__( \ + "1: ldl_l %2,%1\n" \ + " " #asm_op " %2,%3,%0\n" \ + " stl_c %0,%1\n" \ + " beq %0,2f\n" \ + ".subsection 2\n" \ + "2: br 1b\n" \ + ".previous" \ + :"=&r" (temp), "=m" (v->counter), "=&r" (result) \ + :"Ir" (i), "m" (v->counter) : "memory"); \ + smp_mb(); \ + return result; \ +} + #define ATOMIC64_OP(op, asm_op) \ static __inline__ void atomic64_##op(long i, atomic64_t * v) \ { \ @@ -101,11 +120,32 @@ static __inline__ long atomic64_##op##_return(long i, atomic64_t * v) \ return result; \ } +#define ATOMIC64_FETCH_OP(op, asm_op) \ +static __inline__ long atomic64_fetch_##op(long i, atomic64_t * v) \ +{ \ + long temp, result; \ + smp_mb(); \ + __asm__ __volatile__( \ + "1: ldq_l %2,%1\n" \ + " " #asm_op " %2,%3,%0\n" \ + " stq_c %0,%1\n" \ + " beq %0,2f\n" \ + ".subsection 2\n" \ + "2: br 1b\n" \ + ".previous" \ + :"=&r" (temp), "=m" (v->counter), "=&r" (result) \ + :"Ir" (i), "m" (v->counter) : "memory"); \ + smp_mb(); \ + return result; \ +} + #define ATOMIC_OPS(op) \ ATOMIC_OP(op, op##l) \ ATOMIC_OP_RETURN(op, op##l) \ + ATOMIC_FETCH_OP(op, op##l) \ ATOMIC64_OP(op, op##q) \ - ATOMIC64_OP_RETURN(op, op##q) + ATOMIC64_OP_RETURN(op, op##q) \ + ATOMIC64_FETCH_OP(op, op##q) ATOMIC_OPS(add) ATOMIC_OPS(sub) @@ -113,18 +153,25 @@ ATOMIC_OPS(sub) #define atomic_andnot atomic_andnot #define atomic64_andnot atomic64_andnot -ATOMIC_OP(and, and) -ATOMIC_OP(andnot, bic) -ATOMIC_OP(or, bis) -ATOMIC_OP(xor, xor) -ATOMIC64_OP(and, and) -ATOMIC64_OP(andnot, bic) -ATOMIC64_OP(or, bis) -ATOMIC64_OP(xor, xor) +#define atomic_fetch_or atomic_fetch_or + +#undef ATOMIC_OPS +#define ATOMIC_OPS(op, asm) \ + ATOMIC_OP(op, asm) \ + ATOMIC_FETCH_OP(op, asm) \ + ATOMIC64_OP(op, asm) \ + ATOMIC64_FETCH_OP(op, asm) + +ATOMIC_OPS(and, and) +ATOMIC_OPS(andnot, bic) +ATOMIC_OPS(or, bis) +ATOMIC_OPS(xor, xor) #undef ATOMIC_OPS +#undef ATOMIC64_FETCH_OP #undef ATOMIC64_OP_RETURN #undef ATOMIC64_OP +#undef ATOMIC_FETCH_OP #undef ATOMIC_OP_RETURN #undef ATOMIC_OP -- cgit v0.10.2 From fbffe892e5253dd02c016c59a9d792eafe9d53e1 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Mon, 18 Apr 2016 01:16:09 +0200 Subject: locking/atomic, arch/arc: Implement atomic_fetch_{add,sub,and,andnot,or,xor}() Implement FETCH-OP atomic primitives, these are very similar to the existing OP-RETURN primitives we already have, except they return the value of the atomic variable _before_ modification. This is especially useful for irreversible operations -- such as bitops (because it becomes impossible to reconstruct the state prior to modification). Signed-off-by: Peter Zijlstra (Intel) Acked-by: Vineet Gupta Cc: Andrew Morton Cc: Linus Torvalds Cc: Noam Camus Cc: Paul E. McKenney Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: linux-arch@vger.kernel.org Cc: linux-kernel@vger.kernel.org Cc: linux-snps-arc@lists.infradead.org Signed-off-by: Ingo Molnar diff --git a/arch/arc/include/asm/atomic.h b/arch/arc/include/asm/atomic.h index dd68399..c066a21 100644 --- a/arch/arc/include/asm/atomic.h +++ b/arch/arc/include/asm/atomic.h @@ -67,6 +67,37 @@ static inline int atomic_##op##_return(int i, atomic_t *v) \ return val; \ } +#define ATOMIC_FETCH_OP(op, c_op, asm_op) \ +static inline int atomic_fetch_##op(int i, atomic_t *v) \ +{ \ + unsigned int val, orig; \ + SCOND_FAIL_RETRY_VAR_DEF \ + \ + /* \ + * Explicit full memory barrier needed before/after as \ + * LLOCK/SCOND thmeselves don't provide any such semantics \ + */ \ + smp_mb(); \ + \ + __asm__ __volatile__( \ + "1: llock %[orig], [%[ctr]] \n" \ + " " #asm_op " %[val], %[orig], %[i] \n" \ + " scond %[val], [%[ctr]] \n" \ + " \n" \ + SCOND_FAIL_RETRY_ASM \ + \ + : [val] "=&r" (val), \ + [orig] "=&r" (orig) \ + SCOND_FAIL_RETRY_VARS \ + : [ctr] "r" (&v->counter), \ + [i] "ir" (i) \ + : "cc"); \ + \ + smp_mb(); \ + \ + return orig; \ +} + #else /* !CONFIG_ARC_HAS_LLSC */ #ifndef CONFIG_SMP @@ -129,21 +160,46 @@ static inline int atomic_##op##_return(int i, atomic_t *v) \ return temp; \ } +#define ATOMIC_FETCH_OP(op, c_op, asm_op) \ +static inline int atomic_fetch_##op(int i, atomic_t *v) \ +{ \ + unsigned long flags; \ + unsigned long orig; \ + \ + /* \ + * spin lock/unlock provides the needed smp_mb() before/after \ + */ \ + atomic_ops_lock(flags); \ + orig = v->counter; \ + v->counter c_op i; \ + atomic_ops_unlock(flags); \ + \ + return orig; \ +} + #endif /* !CONFIG_ARC_HAS_LLSC */ #define ATOMIC_OPS(op, c_op, asm_op) \ ATOMIC_OP(op, c_op, asm_op) \ - ATOMIC_OP_RETURN(op, c_op, asm_op) + ATOMIC_OP_RETURN(op, c_op, asm_op) \ + ATOMIC_FETCH_OP(op, c_op, asm_op) ATOMIC_OPS(add, +=, add) ATOMIC_OPS(sub, -=, sub) #define atomic_andnot atomic_andnot -ATOMIC_OP(and, &=, and) -ATOMIC_OP(andnot, &= ~, bic) -ATOMIC_OP(or, |=, or) -ATOMIC_OP(xor, ^=, xor) +#define atomic_fetch_or atomic_fetch_or + +#undef ATOMIC_OPS +#define ATOMIC_OPS(op, c_op, asm_op) \ + ATOMIC_OP(op, c_op, asm_op) \ + ATOMIC_FETCH_OP(op, c_op, asm_op) + +ATOMIC_OPS(and, &=, and) +ATOMIC_OPS(andnot, &= ~, bic) +ATOMIC_OPS(or, |=, or) +ATOMIC_OPS(xor, ^=, xor) #undef SCOND_FAIL_RETRY_VAR_DEF #undef SCOND_FAIL_RETRY_ASM @@ -208,22 +264,51 @@ static inline int atomic_##op##_return(int i, atomic_t *v) \ return temp; \ } +#define ATOMIC_FETCH_OP(op, c_op, asm_op) \ +static inline int atomic_fetch_##op(int i, atomic_t *v) \ +{ \ + unsigned int temp = i; \ + \ + /* Explicit full memory barrier needed before/after */ \ + smp_mb(); \ + \ + __asm__ __volatile__( \ + " mov r2, %0\n" \ + " mov r3, %1\n" \ + " .word %2\n" \ + " mov %0, r2" \ + : "+r"(temp) \ + : "r"(&v->counter), "i"(asm_op) \ + : "r2", "r3", "memory"); \ + \ + smp_mb(); \ + \ + return temp; \ +} + #define ATOMIC_OPS(op, c_op, asm_op) \ ATOMIC_OP(op, c_op, asm_op) \ - ATOMIC_OP_RETURN(op, c_op, asm_op) + ATOMIC_OP_RETURN(op, c_op, asm_op) \ + ATOMIC_FETCH_OP(op, c_op, asm_op) ATOMIC_OPS(add, +=, CTOP_INST_AADD_DI_R2_R2_R3) #define atomic_sub(i, v) atomic_add(-(i), (v)) #define atomic_sub_return(i, v) atomic_add_return(-(i), (v)) -ATOMIC_OP(and, &=, CTOP_INST_AAND_DI_R2_R2_R3) +#undef ATOMIC_OPS +#define ATOMIC_OPS(op, c_op, asm_op) \ + ATOMIC_OP(op, c_op, asm_op) \ + ATOMIC_FETCH_OP(op, c_op, asm_op) + +ATOMIC_OPS(and, &=, CTOP_INST_AAND_DI_R2_R2_R3) #define atomic_andnot(mask, v) atomic_and(~(mask), (v)) -ATOMIC_OP(or, |=, CTOP_INST_AOR_DI_R2_R2_R3) -ATOMIC_OP(xor, ^=, CTOP_INST_AXOR_DI_R2_R2_R3) +ATOMIC_OPS(or, |=, CTOP_INST_AOR_DI_R2_R2_R3) +ATOMIC_OPS(xor, ^=, CTOP_INST_AXOR_DI_R2_R2_R3) #endif /* CONFIG_ARC_PLAT_EZNPS */ #undef ATOMIC_OPS +#undef ATOMIC_FETCH_OP #undef ATOMIC_OP_RETURN #undef ATOMIC_OP -- cgit v0.10.2 From 6da068c1beba684b2a0dbf43a07b0529edd9e959 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Mon, 18 Apr 2016 01:10:52 +0200 Subject: locking/atomic, arch/arm: Implement atomic{,64}_fetch_{add,sub,and,andnot,or,xor}{,_relaxed,_acquire,_release}() Implement FETCH-OP atomic primitives, these are very similar to the existing OP-RETURN primitives we already have, except they return the value of the atomic variable _before_ modification. This is especially useful for irreversible operations -- such as bitops (because it becomes impossible to reconstruct the state prior to modification). Signed-off-by: Peter Zijlstra (Intel) Acked-by: Will Deacon Cc: Andrew Morton Cc: Davidlohr Bueso Cc: Linus Torvalds Cc: Paul E. McKenney Cc: Peter Zijlstra Cc: Russell King Cc: Thomas Gleixner Cc: linux-arch@vger.kernel.org Cc: linux-arm-kernel@lists.infradead.org Cc: linux-kernel@vger.kernel.org Signed-off-by: Ingo Molnar diff --git a/arch/arm/include/asm/atomic.h b/arch/arm/include/asm/atomic.h index 9e10c45..0feb110 100644 --- a/arch/arm/include/asm/atomic.h +++ b/arch/arm/include/asm/atomic.h @@ -77,8 +77,36 @@ static inline int atomic_##op##_return_relaxed(int i, atomic_t *v) \ return result; \ } +#define ATOMIC_FETCH_OP(op, c_op, asm_op) \ +static inline int atomic_fetch_##op##_relaxed(int i, atomic_t *v) \ +{ \ + unsigned long tmp; \ + int result, val; \ + \ + prefetchw(&v->counter); \ + \ + __asm__ __volatile__("@ atomic_fetch_" #op "\n" \ +"1: ldrex %0, [%4]\n" \ +" " #asm_op " %1, %0, %5\n" \ +" strex %2, %1, [%4]\n" \ +" teq %2, #0\n" \ +" bne 1b" \ + : "=&r" (result), "=&r" (val), "=&r" (tmp), "+Qo" (v->counter) \ + : "r" (&v->counter), "Ir" (i) \ + : "cc"); \ + \ + return result; \ +} + #define atomic_add_return_relaxed atomic_add_return_relaxed #define atomic_sub_return_relaxed atomic_sub_return_relaxed +#define atomic_fetch_add_relaxed atomic_fetch_add_relaxed +#define atomic_fetch_sub_relaxed atomic_fetch_sub_relaxed + +#define atomic_fetch_and_relaxed atomic_fetch_and_relaxed +#define atomic_fetch_andnot_relaxed atomic_fetch_andnot_relaxed +#define atomic_fetch_or_relaxed atomic_fetch_or_relaxed +#define atomic_fetch_xor_relaxed atomic_fetch_xor_relaxed static inline int atomic_cmpxchg_relaxed(atomic_t *ptr, int old, int new) { @@ -159,6 +187,22 @@ static inline int atomic_##op##_return(int i, atomic_t *v) \ return val; \ } +#define ATOMIC_FETCH_OP(op, c_op, asm_op) \ +static inline int atomic_fetch_##op(int i, atomic_t *v) \ +{ \ + unsigned long flags; \ + int val; \ + \ + raw_local_irq_save(flags); \ + val = v->counter; \ + v->counter c_op i; \ + raw_local_irq_restore(flags); \ + \ + return val; \ +} + +#define atomic_fetch_or atomic_fetch_or + static inline int atomic_cmpxchg(atomic_t *v, int old, int new) { int ret; @@ -187,19 +231,26 @@ static inline int __atomic_add_unless(atomic_t *v, int a, int u) #define ATOMIC_OPS(op, c_op, asm_op) \ ATOMIC_OP(op, c_op, asm_op) \ - ATOMIC_OP_RETURN(op, c_op, asm_op) + ATOMIC_OP_RETURN(op, c_op, asm_op) \ + ATOMIC_FETCH_OP(op, c_op, asm_op) ATOMIC_OPS(add, +=, add) ATOMIC_OPS(sub, -=, sub) #define atomic_andnot atomic_andnot -ATOMIC_OP(and, &=, and) -ATOMIC_OP(andnot, &= ~, bic) -ATOMIC_OP(or, |=, orr) -ATOMIC_OP(xor, ^=, eor) +#undef ATOMIC_OPS +#define ATOMIC_OPS(op, c_op, asm_op) \ + ATOMIC_OP(op, c_op, asm_op) \ + ATOMIC_FETCH_OP(op, c_op, asm_op) + +ATOMIC_OPS(and, &=, and) +ATOMIC_OPS(andnot, &= ~, bic) +ATOMIC_OPS(or, |=, orr) +ATOMIC_OPS(xor, ^=, eor) #undef ATOMIC_OPS +#undef ATOMIC_FETCH_OP #undef ATOMIC_OP_RETURN #undef ATOMIC_OP @@ -317,24 +368,61 @@ atomic64_##op##_return_relaxed(long long i, atomic64_t *v) \ return result; \ } +#define ATOMIC64_FETCH_OP(op, op1, op2) \ +static inline long long \ +atomic64_fetch_##op##_relaxed(long long i, atomic64_t *v) \ +{ \ + long long result, val; \ + unsigned long tmp; \ + \ + prefetchw(&v->counter); \ + \ + __asm__ __volatile__("@ atomic64_fetch_" #op "\n" \ +"1: ldrexd %0, %H0, [%4]\n" \ +" " #op1 " %Q1, %Q0, %Q5\n" \ +" " #op2 " %R1, %R0, %R5\n" \ +" strexd %2, %1, %H1, [%4]\n" \ +" teq %2, #0\n" \ +" bne 1b" \ + : "=&r" (result), "=&r" (val), "=&r" (tmp), "+Qo" (v->counter) \ + : "r" (&v->counter), "r" (i) \ + : "cc"); \ + \ + return result; \ +} + #define ATOMIC64_OPS(op, op1, op2) \ ATOMIC64_OP(op, op1, op2) \ - ATOMIC64_OP_RETURN(op, op1, op2) + ATOMIC64_OP_RETURN(op, op1, op2) \ + ATOMIC64_FETCH_OP(op, op1, op2) ATOMIC64_OPS(add, adds, adc) ATOMIC64_OPS(sub, subs, sbc) #define atomic64_add_return_relaxed atomic64_add_return_relaxed #define atomic64_sub_return_relaxed atomic64_sub_return_relaxed +#define atomic64_fetch_add_relaxed atomic64_fetch_add_relaxed +#define atomic64_fetch_sub_relaxed atomic64_fetch_sub_relaxed + +#undef ATOMIC64_OPS +#define ATOMIC64_OPS(op, op1, op2) \ + ATOMIC64_OP(op, op1, op2) \ + ATOMIC64_FETCH_OP(op, op1, op2) #define atomic64_andnot atomic64_andnot -ATOMIC64_OP(and, and, and) -ATOMIC64_OP(andnot, bic, bic) -ATOMIC64_OP(or, orr, orr) -ATOMIC64_OP(xor, eor, eor) +ATOMIC64_OPS(and, and, and) +ATOMIC64_OPS(andnot, bic, bic) +ATOMIC64_OPS(or, orr, orr) +ATOMIC64_OPS(xor, eor, eor) + +#define atomic64_fetch_and_relaxed atomic64_fetch_and_relaxed +#define atomic64_fetch_andnot_relaxed atomic64_fetch_andnot_relaxed +#define atomic64_fetch_or_relaxed atomic64_fetch_or_relaxed +#define atomic64_fetch_xor_relaxed atomic64_fetch_xor_relaxed #undef ATOMIC64_OPS +#undef ATOMIC64_FETCH_OP #undef ATOMIC64_OP_RETURN #undef ATOMIC64_OP -- cgit v0.10.2 From e490f9b1d3b40ba32ad07432b63b813ce3052d41 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Mon, 18 Apr 2016 01:16:09 +0200 Subject: locking/atomic, arch/arm64: Implement atomic{,64}_fetch_{add,sub,and,andnot,or,xor}{,_relaxed,_acquire,_release}() Implement FETCH-OP atomic primitives, these are very similar to the existing OP-RETURN primitives we already have, except they return the value of the atomic variable _before_ modification. This is especially useful for irreversible operations -- such as bitops (because it becomes impossible to reconstruct the state prior to modification). [wildea01: compile fixes for ll/sc] Signed-off-by: Peter Zijlstra (Intel) Cc: Andrew Morton Cc: Catalin Marinas Cc: Linus Torvalds Cc: Lorenzo Pieralisi Cc: Mark Rutland Cc: Paul E. McKenney Cc: Peter Zijlstra Cc: Steve Capper Cc: Thomas Gleixner Cc: Will Deacon Cc: linux-arch@vger.kernel.org Cc: linux-arm-kernel@lists.infradead.org Cc: linux-kernel@vger.kernel.org Signed-off-by: Ingo Molnar diff --git a/arch/arm64/include/asm/atomic.h b/arch/arm64/include/asm/atomic.h index f3a3586..3128c3d 100644 --- a/arch/arm64/include/asm/atomic.h +++ b/arch/arm64/include/asm/atomic.h @@ -76,6 +76,36 @@ #define atomic_dec_return_release(v) atomic_sub_return_release(1, (v)) #define atomic_dec_return(v) atomic_sub_return(1, (v)) +#define atomic_fetch_add_relaxed atomic_fetch_add_relaxed +#define atomic_fetch_add_acquire atomic_fetch_add_acquire +#define atomic_fetch_add_release atomic_fetch_add_release +#define atomic_fetch_add atomic_fetch_add + +#define atomic_fetch_sub_relaxed atomic_fetch_sub_relaxed +#define atomic_fetch_sub_acquire atomic_fetch_sub_acquire +#define atomic_fetch_sub_release atomic_fetch_sub_release +#define atomic_fetch_sub atomic_fetch_sub + +#define atomic_fetch_and_relaxed atomic_fetch_and_relaxed +#define atomic_fetch_and_acquire atomic_fetch_and_acquire +#define atomic_fetch_and_release atomic_fetch_and_release +#define atomic_fetch_and atomic_fetch_and + +#define atomic_fetch_andnot_relaxed atomic_fetch_andnot_relaxed +#define atomic_fetch_andnot_acquire atomic_fetch_andnot_acquire +#define atomic_fetch_andnot_release atomic_fetch_andnot_release +#define atomic_fetch_andnot atomic_fetch_andnot + +#define atomic_fetch_or_relaxed atomic_fetch_or_relaxed +#define atomic_fetch_or_acquire atomic_fetch_or_acquire +#define atomic_fetch_or_release atomic_fetch_or_release +#define atomic_fetch_or atomic_fetch_or + +#define atomic_fetch_xor_relaxed atomic_fetch_xor_relaxed +#define atomic_fetch_xor_acquire atomic_fetch_xor_acquire +#define atomic_fetch_xor_release atomic_fetch_xor_release +#define atomic_fetch_xor atomic_fetch_xor + #define atomic_xchg_relaxed(v, new) xchg_relaxed(&((v)->counter), (new)) #define atomic_xchg_acquire(v, new) xchg_acquire(&((v)->counter), (new)) #define atomic_xchg_release(v, new) xchg_release(&((v)->counter), (new)) @@ -98,6 +128,8 @@ #define __atomic_add_unless(v, a, u) ___atomic_add_unless(v, a, u,) #define atomic_andnot atomic_andnot +#define atomic_fetch_or atomic_fetch_or + /* * 64-bit atomic operations. */ @@ -125,6 +157,36 @@ #define atomic64_dec_return_release(v) atomic64_sub_return_release(1, (v)) #define atomic64_dec_return(v) atomic64_sub_return(1, (v)) +#define atomic64_fetch_add_relaxed atomic64_fetch_add_relaxed +#define atomic64_fetch_add_acquire atomic64_fetch_add_acquire +#define atomic64_fetch_add_release atomic64_fetch_add_release +#define atomic64_fetch_add atomic64_fetch_add + +#define atomic64_fetch_sub_relaxed atomic64_fetch_sub_relaxed +#define atomic64_fetch_sub_acquire atomic64_fetch_sub_acquire +#define atomic64_fetch_sub_release atomic64_fetch_sub_release +#define atomic64_fetch_sub atomic64_fetch_sub + +#define atomic64_fetch_and_relaxed atomic64_fetch_and_relaxed +#define atomic64_fetch_and_acquire atomic64_fetch_and_acquire +#define atomic64_fetch_and_release atomic64_fetch_and_release +#define atomic64_fetch_and atomic64_fetch_and + +#define atomic64_fetch_andnot_relaxed atomic64_fetch_andnot_relaxed +#define atomic64_fetch_andnot_acquire atomic64_fetch_andnot_acquire +#define atomic64_fetch_andnot_release atomic64_fetch_andnot_release +#define atomic64_fetch_andnot atomic64_fetch_andnot + +#define atomic64_fetch_or_relaxed atomic64_fetch_or_relaxed +#define atomic64_fetch_or_acquire atomic64_fetch_or_acquire +#define atomic64_fetch_or_release atomic64_fetch_or_release +#define atomic64_fetch_or atomic64_fetch_or + +#define atomic64_fetch_xor_relaxed atomic64_fetch_xor_relaxed +#define atomic64_fetch_xor_acquire atomic64_fetch_xor_acquire +#define atomic64_fetch_xor_release atomic64_fetch_xor_release +#define atomic64_fetch_xor atomic64_fetch_xor + #define atomic64_xchg_relaxed atomic_xchg_relaxed #define atomic64_xchg_acquire atomic_xchg_acquire #define atomic64_xchg_release atomic_xchg_release diff --git a/arch/arm64/include/asm/atomic_ll_sc.h b/arch/arm64/include/asm/atomic_ll_sc.h index f61c84f..f819fdc 100644 --- a/arch/arm64/include/asm/atomic_ll_sc.h +++ b/arch/arm64/include/asm/atomic_ll_sc.h @@ -77,26 +77,57 @@ __LL_SC_PREFIX(atomic_##op##_return##name(int i, atomic_t *v)) \ } \ __LL_SC_EXPORT(atomic_##op##_return##name); +#define ATOMIC_FETCH_OP(name, mb, acq, rel, cl, op, asm_op) \ +__LL_SC_INLINE int \ +__LL_SC_PREFIX(atomic_fetch_##op##name(int i, atomic_t *v)) \ +{ \ + unsigned long tmp; \ + int val, result; \ + \ + asm volatile("// atomic_fetch_" #op #name "\n" \ +" prfm pstl1strm, %3\n" \ +"1: ld" #acq "xr %w0, %3\n" \ +" " #asm_op " %w1, %w0, %w4\n" \ +" st" #rel "xr %w2, %w1, %3\n" \ +" cbnz %w2, 1b\n" \ +" " #mb \ + : "=&r" (result), "=&r" (val), "=&r" (tmp), "+Q" (v->counter) \ + : "Ir" (i) \ + : cl); \ + \ + return result; \ +} \ +__LL_SC_EXPORT(atomic_fetch_##op##name); + #define ATOMIC_OPS(...) \ ATOMIC_OP(__VA_ARGS__) \ - ATOMIC_OP_RETURN( , dmb ish, , l, "memory", __VA_ARGS__) - -#define ATOMIC_OPS_RLX(...) \ - ATOMIC_OPS(__VA_ARGS__) \ + ATOMIC_OP_RETURN( , dmb ish, , l, "memory", __VA_ARGS__)\ ATOMIC_OP_RETURN(_relaxed, , , , , __VA_ARGS__)\ ATOMIC_OP_RETURN(_acquire, , a, , "memory", __VA_ARGS__)\ - ATOMIC_OP_RETURN(_release, , , l, "memory", __VA_ARGS__) + ATOMIC_OP_RETURN(_release, , , l, "memory", __VA_ARGS__)\ + ATOMIC_FETCH_OP ( , dmb ish, , l, "memory", __VA_ARGS__)\ + ATOMIC_FETCH_OP (_relaxed, , , , , __VA_ARGS__)\ + ATOMIC_FETCH_OP (_acquire, , a, , "memory", __VA_ARGS__)\ + ATOMIC_FETCH_OP (_release, , , l, "memory", __VA_ARGS__) -ATOMIC_OPS_RLX(add, add) -ATOMIC_OPS_RLX(sub, sub) +ATOMIC_OPS(add, add) +ATOMIC_OPS(sub, sub) + +#undef ATOMIC_OPS +#define ATOMIC_OPS(...) \ + ATOMIC_OP(__VA_ARGS__) \ + ATOMIC_FETCH_OP ( , dmb ish, , l, "memory", __VA_ARGS__)\ + ATOMIC_FETCH_OP (_relaxed, , , , , __VA_ARGS__)\ + ATOMIC_FETCH_OP (_acquire, , a, , "memory", __VA_ARGS__)\ + ATOMIC_FETCH_OP (_release, , , l, "memory", __VA_ARGS__) -ATOMIC_OP(and, and) -ATOMIC_OP(andnot, bic) -ATOMIC_OP(or, orr) -ATOMIC_OP(xor, eor) +ATOMIC_OPS(and, and) +ATOMIC_OPS(andnot, bic) +ATOMIC_OPS(or, orr) +ATOMIC_OPS(xor, eor) -#undef ATOMIC_OPS_RLX #undef ATOMIC_OPS +#undef ATOMIC_FETCH_OP #undef ATOMIC_OP_RETURN #undef ATOMIC_OP @@ -140,26 +171,57 @@ __LL_SC_PREFIX(atomic64_##op##_return##name(long i, atomic64_t *v)) \ } \ __LL_SC_EXPORT(atomic64_##op##_return##name); +#define ATOMIC64_FETCH_OP(name, mb, acq, rel, cl, op, asm_op) \ +__LL_SC_INLINE long \ +__LL_SC_PREFIX(atomic64_fetch_##op##name(long i, atomic64_t *v)) \ +{ \ + long result, val; \ + unsigned long tmp; \ + \ + asm volatile("// atomic64_fetch_" #op #name "\n" \ +" prfm pstl1strm, %3\n" \ +"1: ld" #acq "xr %0, %3\n" \ +" " #asm_op " %1, %0, %4\n" \ +" st" #rel "xr %w2, %1, %3\n" \ +" cbnz %w2, 1b\n" \ +" " #mb \ + : "=&r" (result), "=&r" (val), "=&r" (tmp), "+Q" (v->counter) \ + : "Ir" (i) \ + : cl); \ + \ + return result; \ +} \ +__LL_SC_EXPORT(atomic64_fetch_##op##name); + #define ATOMIC64_OPS(...) \ ATOMIC64_OP(__VA_ARGS__) \ - ATOMIC64_OP_RETURN(, dmb ish, , l, "memory", __VA_ARGS__) - -#define ATOMIC64_OPS_RLX(...) \ - ATOMIC64_OPS(__VA_ARGS__) \ + ATOMIC64_OP_RETURN(, dmb ish, , l, "memory", __VA_ARGS__) \ ATOMIC64_OP_RETURN(_relaxed,, , , , __VA_ARGS__) \ ATOMIC64_OP_RETURN(_acquire,, a, , "memory", __VA_ARGS__) \ - ATOMIC64_OP_RETURN(_release,, , l, "memory", __VA_ARGS__) + ATOMIC64_OP_RETURN(_release,, , l, "memory", __VA_ARGS__) \ + ATOMIC64_FETCH_OP (, dmb ish, , l, "memory", __VA_ARGS__) \ + ATOMIC64_FETCH_OP (_relaxed,, , , , __VA_ARGS__) \ + ATOMIC64_FETCH_OP (_acquire,, a, , "memory", __VA_ARGS__) \ + ATOMIC64_FETCH_OP (_release,, , l, "memory", __VA_ARGS__) -ATOMIC64_OPS_RLX(add, add) -ATOMIC64_OPS_RLX(sub, sub) +ATOMIC64_OPS(add, add) +ATOMIC64_OPS(sub, sub) + +#undef ATOMIC64_OPS +#define ATOMIC64_OPS(...) \ + ATOMIC64_OP(__VA_ARGS__) \ + ATOMIC64_FETCH_OP (, dmb ish, , l, "memory", __VA_ARGS__) \ + ATOMIC64_FETCH_OP (_relaxed,, , , , __VA_ARGS__) \ + ATOMIC64_FETCH_OP (_acquire,, a, , "memory", __VA_ARGS__) \ + ATOMIC64_FETCH_OP (_release,, , l, "memory", __VA_ARGS__) -ATOMIC64_OP(and, and) -ATOMIC64_OP(andnot, bic) -ATOMIC64_OP(or, orr) -ATOMIC64_OP(xor, eor) +ATOMIC64_OPS(and, and) +ATOMIC64_OPS(andnot, bic) +ATOMIC64_OPS(or, orr) +ATOMIC64_OPS(xor, eor) -#undef ATOMIC64_OPS_RLX #undef ATOMIC64_OPS +#undef ATOMIC64_FETCH_OP #undef ATOMIC64_OP_RETURN #undef ATOMIC64_OP -- cgit v0.10.2 From 6822a84dd4e35a1beb70028e46b5f60c14fc422d Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Fri, 22 Apr 2016 18:01:32 +0100 Subject: locking/atomic, arch/arm64: Generate LSE non-return cases using common macros atomic[64]_{add,and,andnot,or,xor} all follow the same patterns, so generate them using macros, like we do for the LL/SC case already. Signed-off-by: Will Deacon Signed-off-by: Peter Zijlstra (Intel) Cc: Andrew Morton Cc: Ard Biesheuvel Cc: Catalin Marinas Cc: Linus Torvalds Cc: Lorenzo Pieralisi Cc: Paul E. McKenney Cc: Peter Zijlstra Cc: Steve Capper Cc: Thomas Gleixner Cc: linux-arch@vger.kernel.org Cc: linux-arm-kernel@lists.infradead.org Cc: linux-kernel@vger.kernel.org Link: http://lkml.kernel.org/r/1461344493-8262-1-git-send-email-will.deacon@arm.com Signed-off-by: Ingo Molnar diff --git a/arch/arm64/include/asm/atomic_lse.h b/arch/arm64/include/asm/atomic_lse.h index 39c1d34..37a0f03 100644 --- a/arch/arm64/include/asm/atomic_lse.h +++ b/arch/arm64/include/asm/atomic_lse.h @@ -26,54 +26,25 @@ #endif #define __LL_SC_ATOMIC(op) __LL_SC_CALL(atomic_##op) - -static inline void atomic_andnot(int i, atomic_t *v) -{ - register int w0 asm ("w0") = i; - register atomic_t *x1 asm ("x1") = v; - - asm volatile(ARM64_LSE_ATOMIC_INSN(__LL_SC_ATOMIC(andnot), - " stclr %w[i], %[v]\n") - : [i] "+r" (w0), [v] "+Q" (v->counter) - : "r" (x1) - : __LL_SC_CLOBBERS); -} - -static inline void atomic_or(int i, atomic_t *v) -{ - register int w0 asm ("w0") = i; - register atomic_t *x1 asm ("x1") = v; - - asm volatile(ARM64_LSE_ATOMIC_INSN(__LL_SC_ATOMIC(or), - " stset %w[i], %[v]\n") - : [i] "+r" (w0), [v] "+Q" (v->counter) - : "r" (x1) - : __LL_SC_CLOBBERS); -} - -static inline void atomic_xor(int i, atomic_t *v) -{ - register int w0 asm ("w0") = i; - register atomic_t *x1 asm ("x1") = v; - - asm volatile(ARM64_LSE_ATOMIC_INSN(__LL_SC_ATOMIC(xor), - " steor %w[i], %[v]\n") - : [i] "+r" (w0), [v] "+Q" (v->counter) - : "r" (x1) - : __LL_SC_CLOBBERS); +#define ATOMIC_OP(op, asm_op) \ +static inline void atomic_##op(int i, atomic_t *v) \ +{ \ + register int w0 asm ("w0") = i; \ + register atomic_t *x1 asm ("x1") = v; \ + \ + asm volatile(ARM64_LSE_ATOMIC_INSN(__LL_SC_ATOMIC(op), \ +" " #asm_op " %w[i], %[v]\n") \ + : [i] "+r" (w0), [v] "+Q" (v->counter) \ + : "r" (x1) \ + : __LL_SC_CLOBBERS); \ } -static inline void atomic_add(int i, atomic_t *v) -{ - register int w0 asm ("w0") = i; - register atomic_t *x1 asm ("x1") = v; +ATOMIC_OP(andnot, stclr) +ATOMIC_OP(or, stset) +ATOMIC_OP(xor, steor) +ATOMIC_OP(add, stadd) - asm volatile(ARM64_LSE_ATOMIC_INSN(__LL_SC_ATOMIC(add), - " stadd %w[i], %[v]\n") - : [i] "+r" (w0), [v] "+Q" (v->counter) - : "r" (x1) - : __LL_SC_CLOBBERS); -} +#undef ATOMIC_OP #define ATOMIC_OP_ADD_RETURN(name, mb, cl...) \ static inline int atomic_add_return##name(int i, atomic_t *v) \ @@ -167,54 +138,25 @@ ATOMIC_OP_SUB_RETURN( , al, "memory") #undef __LL_SC_ATOMIC #define __LL_SC_ATOMIC64(op) __LL_SC_CALL(atomic64_##op) - -static inline void atomic64_andnot(long i, atomic64_t *v) -{ - register long x0 asm ("x0") = i; - register atomic64_t *x1 asm ("x1") = v; - - asm volatile(ARM64_LSE_ATOMIC_INSN(__LL_SC_ATOMIC64(andnot), - " stclr %[i], %[v]\n") - : [i] "+r" (x0), [v] "+Q" (v->counter) - : "r" (x1) - : __LL_SC_CLOBBERS); -} - -static inline void atomic64_or(long i, atomic64_t *v) -{ - register long x0 asm ("x0") = i; - register atomic64_t *x1 asm ("x1") = v; - - asm volatile(ARM64_LSE_ATOMIC_INSN(__LL_SC_ATOMIC64(or), - " stset %[i], %[v]\n") - : [i] "+r" (x0), [v] "+Q" (v->counter) - : "r" (x1) - : __LL_SC_CLOBBERS); -} - -static inline void atomic64_xor(long i, atomic64_t *v) -{ - register long x0 asm ("x0") = i; - register atomic64_t *x1 asm ("x1") = v; - - asm volatile(ARM64_LSE_ATOMIC_INSN(__LL_SC_ATOMIC64(xor), - " steor %[i], %[v]\n") - : [i] "+r" (x0), [v] "+Q" (v->counter) - : "r" (x1) - : __LL_SC_CLOBBERS); +#define ATOMIC64_OP(op, asm_op) \ +static inline void atomic64_##op(long i, atomic64_t *v) \ +{ \ + register long x0 asm ("x0") = i; \ + register atomic64_t *x1 asm ("x1") = v; \ + \ + asm volatile(ARM64_LSE_ATOMIC_INSN(__LL_SC_ATOMIC64(op), \ +" " #asm_op " %[i], %[v]\n") \ + : [i] "+r" (x0), [v] "+Q" (v->counter) \ + : "r" (x1) \ + : __LL_SC_CLOBBERS); \ } -static inline void atomic64_add(long i, atomic64_t *v) -{ - register long x0 asm ("x0") = i; - register atomic64_t *x1 asm ("x1") = v; +ATOMIC64_OP(andnot, stclr) +ATOMIC64_OP(or, stset) +ATOMIC64_OP(xor, steor) +ATOMIC64_OP(add, stadd) - asm volatile(ARM64_LSE_ATOMIC_INSN(__LL_SC_ATOMIC64(add), - " stadd %[i], %[v]\n") - : [i] "+r" (x0), [v] "+Q" (v->counter) - : "r" (x1) - : __LL_SC_CLOBBERS); -} +#undef ATOMIC64_OP #define ATOMIC64_OP_ADD_RETURN(name, mb, cl...) \ static inline long atomic64_add_return##name(long i, atomic64_t *v) \ -- cgit v0.10.2 From 2efe95fe695270ae1a225805f016303505972d86 Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Fri, 22 Apr 2016 18:01:33 +0100 Subject: locking/atomic, arch/arm64: Implement atomic{,64}_fetch_{add,sub,and,andnot,or,xor}{,_relaxed,_acquire,_release}() for LSE instructions Implement FETCH-OP atomic primitives, these are very similar to the existing OP-RETURN primitives we already have, except they return the value of the atomic variable _before_ modification. This is especially useful for irreversible operations -- such as bitops (because it becomes impossible to reconstruct the state prior to modification). This patch implements the LSE variants. Signed-off-by: Will Deacon Signed-off-by: Peter Zijlstra (Intel) Cc: Andrew Morton Cc: Ard Biesheuvel Cc: Catalin Marinas Cc: Linus Torvalds Cc: Lorenzo Pieralisi Cc: Paul E. McKenney Cc: Peter Zijlstra Cc: Steve Capper Cc: Thomas Gleixner Cc: linux-arch@vger.kernel.org Cc: linux-arm-kernel@lists.infradead.org Cc: linux-kernel@vger.kernel.org Link: http://lkml.kernel.org/r/1461344493-8262-2-git-send-email-will.deacon@arm.com Signed-off-by: Ingo Molnar diff --git a/arch/arm64/include/asm/atomic_lse.h b/arch/arm64/include/asm/atomic_lse.h index 37a0f03..b5890be 100644 --- a/arch/arm64/include/asm/atomic_lse.h +++ b/arch/arm64/include/asm/atomic_lse.h @@ -46,6 +46,38 @@ ATOMIC_OP(add, stadd) #undef ATOMIC_OP +#define ATOMIC_FETCH_OP(name, mb, op, asm_op, cl...) \ +static inline int atomic_fetch_##op##name(int i, atomic_t *v) \ +{ \ + register int w0 asm ("w0") = i; \ + register atomic_t *x1 asm ("x1") = v; \ + \ + asm volatile(ARM64_LSE_ATOMIC_INSN( \ + /* LL/SC */ \ + __LL_SC_ATOMIC(fetch_##op##name), \ + /* LSE atomics */ \ +" " #asm_op #mb " %w[i], %w[i], %[v]") \ + : [i] "+r" (w0), [v] "+Q" (v->counter) \ + : "r" (x1) \ + : __LL_SC_CLOBBERS, ##cl); \ + \ + return w0; \ +} + +#define ATOMIC_FETCH_OPS(op, asm_op) \ + ATOMIC_FETCH_OP(_relaxed, , op, asm_op) \ + ATOMIC_FETCH_OP(_acquire, a, op, asm_op, "memory") \ + ATOMIC_FETCH_OP(_release, l, op, asm_op, "memory") \ + ATOMIC_FETCH_OP( , al, op, asm_op, "memory") + +ATOMIC_FETCH_OPS(andnot, ldclr) +ATOMIC_FETCH_OPS(or, ldset) +ATOMIC_FETCH_OPS(xor, ldeor) +ATOMIC_FETCH_OPS(add, ldadd) + +#undef ATOMIC_FETCH_OP +#undef ATOMIC_FETCH_OPS + #define ATOMIC_OP_ADD_RETURN(name, mb, cl...) \ static inline int atomic_add_return##name(int i, atomic_t *v) \ { \ @@ -90,6 +122,33 @@ static inline void atomic_and(int i, atomic_t *v) : __LL_SC_CLOBBERS); } +#define ATOMIC_FETCH_OP_AND(name, mb, cl...) \ +static inline int atomic_fetch_and##name(int i, atomic_t *v) \ +{ \ + register int w0 asm ("w0") = i; \ + register atomic_t *x1 asm ("x1") = v; \ + \ + asm volatile(ARM64_LSE_ATOMIC_INSN( \ + /* LL/SC */ \ + " nop\n" \ + __LL_SC_ATOMIC(fetch_and##name), \ + /* LSE atomics */ \ + " mvn %w[i], %w[i]\n" \ + " ldclr" #mb " %w[i], %w[i], %[v]") \ + : [i] "+r" (w0), [v] "+Q" (v->counter) \ + : "r" (x1) \ + : __LL_SC_CLOBBERS, ##cl); \ + \ + return w0; \ +} + +ATOMIC_FETCH_OP_AND(_relaxed, ) +ATOMIC_FETCH_OP_AND(_acquire, a, "memory") +ATOMIC_FETCH_OP_AND(_release, l, "memory") +ATOMIC_FETCH_OP_AND( , al, "memory") + +#undef ATOMIC_FETCH_OP_AND + static inline void atomic_sub(int i, atomic_t *v) { register int w0 asm ("w0") = i; @@ -135,6 +194,33 @@ ATOMIC_OP_SUB_RETURN(_release, l, "memory") ATOMIC_OP_SUB_RETURN( , al, "memory") #undef ATOMIC_OP_SUB_RETURN + +#define ATOMIC_FETCH_OP_SUB(name, mb, cl...) \ +static inline int atomic_fetch_sub##name(int i, atomic_t *v) \ +{ \ + register int w0 asm ("w0") = i; \ + register atomic_t *x1 asm ("x1") = v; \ + \ + asm volatile(ARM64_LSE_ATOMIC_INSN( \ + /* LL/SC */ \ + " nop\n" \ + __LL_SC_ATOMIC(fetch_sub##name), \ + /* LSE atomics */ \ + " neg %w[i], %w[i]\n" \ + " ldadd" #mb " %w[i], %w[i], %[v]") \ + : [i] "+r" (w0), [v] "+Q" (v->counter) \ + : "r" (x1) \ + : __LL_SC_CLOBBERS, ##cl); \ + \ + return w0; \ +} + +ATOMIC_FETCH_OP_SUB(_relaxed, ) +ATOMIC_FETCH_OP_SUB(_acquire, a, "memory") +ATOMIC_FETCH_OP_SUB(_release, l, "memory") +ATOMIC_FETCH_OP_SUB( , al, "memory") + +#undef ATOMIC_FETCH_OP_SUB #undef __LL_SC_ATOMIC #define __LL_SC_ATOMIC64(op) __LL_SC_CALL(atomic64_##op) @@ -158,6 +244,38 @@ ATOMIC64_OP(add, stadd) #undef ATOMIC64_OP +#define ATOMIC64_FETCH_OP(name, mb, op, asm_op, cl...) \ +static inline long atomic64_fetch_##op##name(long i, atomic64_t *v) \ +{ \ + register long x0 asm ("x0") = i; \ + register atomic64_t *x1 asm ("x1") = v; \ + \ + asm volatile(ARM64_LSE_ATOMIC_INSN( \ + /* LL/SC */ \ + __LL_SC_ATOMIC64(fetch_##op##name), \ + /* LSE atomics */ \ +" " #asm_op #mb " %[i], %[i], %[v]") \ + : [i] "+r" (x0), [v] "+Q" (v->counter) \ + : "r" (x1) \ + : __LL_SC_CLOBBERS, ##cl); \ + \ + return x0; \ +} + +#define ATOMIC64_FETCH_OPS(op, asm_op) \ + ATOMIC64_FETCH_OP(_relaxed, , op, asm_op) \ + ATOMIC64_FETCH_OP(_acquire, a, op, asm_op, "memory") \ + ATOMIC64_FETCH_OP(_release, l, op, asm_op, "memory") \ + ATOMIC64_FETCH_OP( , al, op, asm_op, "memory") + +ATOMIC64_FETCH_OPS(andnot, ldclr) +ATOMIC64_FETCH_OPS(or, ldset) +ATOMIC64_FETCH_OPS(xor, ldeor) +ATOMIC64_FETCH_OPS(add, ldadd) + +#undef ATOMIC64_FETCH_OP +#undef ATOMIC64_FETCH_OPS + #define ATOMIC64_OP_ADD_RETURN(name, mb, cl...) \ static inline long atomic64_add_return##name(long i, atomic64_t *v) \ { \ @@ -202,6 +320,33 @@ static inline void atomic64_and(long i, atomic64_t *v) : __LL_SC_CLOBBERS); } +#define ATOMIC64_FETCH_OP_AND(name, mb, cl...) \ +static inline long atomic64_fetch_and##name(long i, atomic64_t *v) \ +{ \ + register long x0 asm ("w0") = i; \ + register atomic64_t *x1 asm ("x1") = v; \ + \ + asm volatile(ARM64_LSE_ATOMIC_INSN( \ + /* LL/SC */ \ + " nop\n" \ + __LL_SC_ATOMIC64(fetch_and##name), \ + /* LSE atomics */ \ + " mvn %[i], %[i]\n" \ + " ldclr" #mb " %[i], %[i], %[v]") \ + : [i] "+r" (x0), [v] "+Q" (v->counter) \ + : "r" (x1) \ + : __LL_SC_CLOBBERS, ##cl); \ + \ + return x0; \ +} + +ATOMIC64_FETCH_OP_AND(_relaxed, ) +ATOMIC64_FETCH_OP_AND(_acquire, a, "memory") +ATOMIC64_FETCH_OP_AND(_release, l, "memory") +ATOMIC64_FETCH_OP_AND( , al, "memory") + +#undef ATOMIC64_FETCH_OP_AND + static inline void atomic64_sub(long i, atomic64_t *v) { register long x0 asm ("x0") = i; @@ -248,6 +393,33 @@ ATOMIC64_OP_SUB_RETURN( , al, "memory") #undef ATOMIC64_OP_SUB_RETURN +#define ATOMIC64_FETCH_OP_SUB(name, mb, cl...) \ +static inline long atomic64_fetch_sub##name(long i, atomic64_t *v) \ +{ \ + register long x0 asm ("w0") = i; \ + register atomic64_t *x1 asm ("x1") = v; \ + \ + asm volatile(ARM64_LSE_ATOMIC_INSN( \ + /* LL/SC */ \ + " nop\n" \ + __LL_SC_ATOMIC64(fetch_sub##name), \ + /* LSE atomics */ \ + " neg %[i], %[i]\n" \ + " ldadd" #mb " %[i], %[i], %[v]") \ + : [i] "+r" (x0), [v] "+Q" (v->counter) \ + : "r" (x1) \ + : __LL_SC_CLOBBERS, ##cl); \ + \ + return x0; \ +} + +ATOMIC64_FETCH_OP_SUB(_relaxed, ) +ATOMIC64_FETCH_OP_SUB(_acquire, a, "memory") +ATOMIC64_FETCH_OP_SUB(_release, l, "memory") +ATOMIC64_FETCH_OP_SUB( , al, "memory") + +#undef ATOMIC64_FETCH_OP_SUB + static inline long atomic64_dec_if_positive(atomic64_t *v) { register long x0 asm ("x0") = (long)v; -- cgit v0.10.2 From 1a6eafacd4811cdc1b138faee858527658eee4e1 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Mon, 18 Apr 2016 01:16:08 +0200 Subject: locking/atomic, arch/avr32: Implement atomic_fetch_{add,sub,and,or,xor}() Implement FETCH-OP atomic primitives, these are very similar to the existing OP-RETURN primitives we already have, except they return the value of the atomic variable _before_ modification. This is especially useful for irreversible operations -- such as bitops (because it becomes impossible to reconstruct the state prior to modification). Signed-off-by: Peter Zijlstra (Intel) Acked-by: Hans-Christian Noren Egtvedt Cc: Andrew Morton Cc: Haavard Skinnemoen Cc: Hans-Christian Egtvedt Cc: Linus Torvalds Cc: Paul E. McKenney Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: linux-arch@vger.kernel.org Cc: linux-kernel@vger.kernel.org Signed-off-by: Ingo Molnar diff --git a/arch/avr32/include/asm/atomic.h b/arch/avr32/include/asm/atomic.h index d74fd8c..b8681fd 100644 --- a/arch/avr32/include/asm/atomic.h +++ b/arch/avr32/include/asm/atomic.h @@ -41,21 +41,51 @@ static inline int __atomic_##op##_return(int i, atomic_t *v) \ return result; \ } +#define ATOMIC_FETCH_OP(op, asm_op, asm_con) \ +static inline int __atomic_fetch_##op(int i, atomic_t *v) \ +{ \ + int result, val; \ + \ + asm volatile( \ + "/* atomic_fetch_" #op " */\n" \ + "1: ssrf 5\n" \ + " ld.w %0, %3\n" \ + " mov %1, %0\n" \ + " " #asm_op " %1, %4\n" \ + " stcond %2, %1\n" \ + " brne 1b" \ + : "=&r" (result), "=&r" (val), "=o" (v->counter) \ + : "m" (v->counter), #asm_con (i) \ + : "cc"); \ + \ + return result; \ +} + ATOMIC_OP_RETURN(sub, sub, rKs21) ATOMIC_OP_RETURN(add, add, r) +ATOMIC_FETCH_OP (sub, sub, rKs21) +ATOMIC_FETCH_OP (add, add, r) + +#define atomic_fetch_or atomic_fetch_or -#define ATOMIC_OP(op, asm_op) \ +#define ATOMIC_OPS(op, asm_op) \ ATOMIC_OP_RETURN(op, asm_op, r) \ static inline void atomic_##op(int i, atomic_t *v) \ { \ (void)__atomic_##op##_return(i, v); \ +} \ +ATOMIC_FETCH_OP(op, asm_op, r) \ +static inline int atomic_fetch_##op(int i, atomic_t *v) \ +{ \ + return __atomic_fetch_##op(i, v); \ } -ATOMIC_OP(and, and) -ATOMIC_OP(or, or) -ATOMIC_OP(xor, eor) +ATOMIC_OPS(and, and) +ATOMIC_OPS(or, or) +ATOMIC_OPS(xor, eor) -#undef ATOMIC_OP +#undef ATOMIC_OPS +#undef ATOMIC_FETCH_OP #undef ATOMIC_OP_RETURN /* @@ -87,6 +117,14 @@ static inline int atomic_add_return(int i, atomic_t *v) return __atomic_add_return(i, v); } +static inline int atomic_fetch_add(int i, atomic_t *v) +{ + if (IS_21BIT_CONST(i)) + return __atomic_fetch_sub(-i, v); + + return __atomic_fetch_add(i, v); +} + /* * atomic_sub_return - subtract the atomic variable * @i: integer value to subtract @@ -102,6 +140,14 @@ static inline int atomic_sub_return(int i, atomic_t *v) return __atomic_add_return(-i, v); } +static inline int atomic_fetch_sub(int i, atomic_t *v) +{ + if (IS_21BIT_CONST(i)) + return __atomic_fetch_sub(i, v); + + return __atomic_fetch_add(-i, v); +} + /* * __atomic_add_unless - add unless the number is a given value * @v: pointer of type atomic_t -- cgit v0.10.2 From e87fc0ec070554e34812be68267a9450271868d6 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Mon, 18 Apr 2016 01:16:08 +0200 Subject: locking/atomic, arch/blackfin: Implement atomic_fetch_{add,sub,and,or,xor}() Implement FETCH-OP atomic primitives, these are very similar to the existing OP-RETURN primitives we already have, except they return the value of the atomic variable _before_ modification. This is especially useful for irreversible operations -- such as bitops (because it becomes impossible to reconstruct the state prior to modification). Signed-off-by: Peter Zijlstra (Intel) Cc: Andrew Morton Cc: Linus Torvalds Cc: Paul E. McKenney Cc: Peter Zijlstra Cc: Steven Miao Cc: Thomas Gleixner Cc: adi-buildroot-devel@lists.sourceforge.net Cc: linux-arch@vger.kernel.org Cc: linux-kernel@vger.kernel.org Signed-off-by: Ingo Molnar diff --git a/arch/blackfin/include/asm/atomic.h b/arch/blackfin/include/asm/atomic.h index 1c1c423..63c7dec 100644 --- a/arch/blackfin/include/asm/atomic.h +++ b/arch/blackfin/include/asm/atomic.h @@ -17,6 +17,7 @@ asmlinkage int __raw_uncached_fetch_asm(const volatile int *ptr); asmlinkage int __raw_atomic_add_asm(volatile int *ptr, int value); +asmlinkage int __raw_atomic_xadd_asm(volatile int *ptr, int value); asmlinkage int __raw_atomic_and_asm(volatile int *ptr, int value); asmlinkage int __raw_atomic_or_asm(volatile int *ptr, int value); @@ -28,10 +29,17 @@ asmlinkage int __raw_atomic_test_asm(const volatile int *ptr, int value); #define atomic_add_return(i, v) __raw_atomic_add_asm(&(v)->counter, i) #define atomic_sub_return(i, v) __raw_atomic_add_asm(&(v)->counter, -(i)) +#define atomic_fetch_add(i, v) __raw_atomic_xadd_asm(&(v)->counter, i) +#define atomic_fetch_sub(i, v) __raw_atomic_xadd_asm(&(v)->counter, -(i)) + #define atomic_or(i, v) (void)__raw_atomic_or_asm(&(v)->counter, i) #define atomic_and(i, v) (void)__raw_atomic_and_asm(&(v)->counter, i) #define atomic_xor(i, v) (void)__raw_atomic_xor_asm(&(v)->counter, i) +#define atomic_fetch_or(i, v) __raw_atomic_or_asm(&(v)->counter, i) +#define atomic_fetch_and(i, v) __raw_atomic_and_asm(&(v)->counter, i) +#define atomic_fetch_xor(i, v) __raw_atomic_xor_asm(&(v)->counter, i) + #endif #include diff --git a/arch/blackfin/kernel/bfin_ksyms.c b/arch/blackfin/kernel/bfin_ksyms.c index a401c27..68096e8 100644 --- a/arch/blackfin/kernel/bfin_ksyms.c +++ b/arch/blackfin/kernel/bfin_ksyms.c @@ -84,6 +84,7 @@ EXPORT_SYMBOL(insl_16); #ifdef CONFIG_SMP EXPORT_SYMBOL(__raw_atomic_add_asm); +EXPORT_SYMBOL(__raw_atomic_xadd_asm); EXPORT_SYMBOL(__raw_atomic_and_asm); EXPORT_SYMBOL(__raw_atomic_or_asm); EXPORT_SYMBOL(__raw_atomic_xor_asm); diff --git a/arch/blackfin/mach-bf561/atomic.S b/arch/blackfin/mach-bf561/atomic.S index 26fccb5..1e2989c 100644 --- a/arch/blackfin/mach-bf561/atomic.S +++ b/arch/blackfin/mach-bf561/atomic.S @@ -607,6 +607,28 @@ ENDPROC(___raw_atomic_add_asm) /* * r0 = ptr + * r1 = value + * + * ADD a signed value to a 32bit word and return the old value atomically. + * Clobbers: r3:0, p1:0 + */ +ENTRY(___raw_atomic_xadd_asm) + p1 = r0; + r3 = r1; + [--sp] = rets; + call _get_core_lock; + r3 = [p1]; + r2 = r3 + r2; + [p1] = r2; + r1 = p1; + call _put_core_lock; + r0 = r3; + rets = [sp++]; + rts; +ENDPROC(___raw_atomic_add_asm) + +/* + * r0 = ptr * r1 = mask * * AND the mask bits from a 32bit word and return the old 32bit value @@ -618,10 +640,9 @@ ENTRY(___raw_atomic_and_asm) r3 = r1; [--sp] = rets; call _get_core_lock; - r2 = [p1]; - r3 = r2 & r3; - [p1] = r3; - r3 = r2; + r3 = [p1]; + r2 = r2 & r3; + [p1] = r2; r1 = p1; call _put_core_lock; r0 = r3; @@ -642,10 +663,9 @@ ENTRY(___raw_atomic_or_asm) r3 = r1; [--sp] = rets; call _get_core_lock; - r2 = [p1]; - r3 = r2 | r3; - [p1] = r3; - r3 = r2; + r3 = [p1]; + r2 = r2 | r3; + [p1] = r2; r1 = p1; call _put_core_lock; r0 = r3; @@ -666,10 +686,9 @@ ENTRY(___raw_atomic_xor_asm) r3 = r1; [--sp] = rets; call _get_core_lock; - r2 = [p1]; - r3 = r2 ^ r3; - [p1] = r3; - r3 = r2; + r3 = [p1]; + r2 = r2 ^ r3; + [p1] = r2; r1 = p1; call _put_core_lock; r0 = r3; -- cgit v0.10.2 From d9c730281617e55ca470e66f8e9d7d3f5f420fec Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Mon, 18 Apr 2016 01:16:08 +0200 Subject: locking/atomic, arch/frv: Implement atomic{,64}_fetch_{add,sub,and,or,xor}() Implement FETCH-OP atomic primitives, these are very similar to the existing OP-RETURN primitives we already have, except they return the value of the atomic variable _before_ modification. This is especially useful for irreversible operations -- such as bitops (because it becomes impossible to reconstruct the state prior to modification). Signed-off-by: Peter Zijlstra (Intel) Cc: Andrew Morton Cc: Linus Torvalds Cc: Paul E. McKenney Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: linux-arch@vger.kernel.org Cc: linux-kernel@vger.kernel.org Signed-off-by: Ingo Molnar diff --git a/arch/frv/include/asm/atomic.h b/arch/frv/include/asm/atomic.h index 64f02d4..e3e06da 100644 --- a/arch/frv/include/asm/atomic.h +++ b/arch/frv/include/asm/atomic.h @@ -60,16 +60,6 @@ static inline int atomic_add_negative(int i, atomic_t *v) return atomic_add_return(i, v) < 0; } -static inline void atomic_add(int i, atomic_t *v) -{ - atomic_add_return(i, v); -} - -static inline void atomic_sub(int i, atomic_t *v) -{ - atomic_sub_return(i, v); -} - static inline void atomic_inc(atomic_t *v) { atomic_inc_return(v); @@ -84,6 +74,8 @@ static inline void atomic_dec(atomic_t *v) #define atomic_dec_and_test(v) (atomic_sub_return(1, (v)) == 0) #define atomic_inc_and_test(v) (atomic_add_return(1, (v)) == 0) +#define atomic_fetch_or atomic_fetch_or + /* * 64-bit atomic ops */ @@ -136,16 +128,6 @@ static inline long long atomic64_add_negative(long long i, atomic64_t *v) return atomic64_add_return(i, v) < 0; } -static inline void atomic64_add(long long i, atomic64_t *v) -{ - atomic64_add_return(i, v); -} - -static inline void atomic64_sub(long long i, atomic64_t *v) -{ - atomic64_sub_return(i, v); -} - static inline void atomic64_inc(atomic64_t *v) { atomic64_inc_return(v); @@ -182,11 +164,19 @@ static __inline__ int __atomic_add_unless(atomic_t *v, int a, int u) } #define ATOMIC_OP(op) \ +static inline int atomic_fetch_##op(int i, atomic_t *v) \ +{ \ + return __atomic32_fetch_##op(i, &v->counter); \ +} \ static inline void atomic_##op(int i, atomic_t *v) \ { \ (void)__atomic32_fetch_##op(i, &v->counter); \ } \ \ +static inline long long atomic64_fetch_##op(long long i, atomic64_t *v) \ +{ \ + return __atomic64_fetch_##op(i, &v->counter); \ +} \ static inline void atomic64_##op(long long i, atomic64_t *v) \ { \ (void)__atomic64_fetch_##op(i, &v->counter); \ @@ -195,6 +185,8 @@ static inline void atomic64_##op(long long i, atomic64_t *v) \ ATOMIC_OP(or) ATOMIC_OP(and) ATOMIC_OP(xor) +ATOMIC_OP(add) +ATOMIC_OP(sub) #undef ATOMIC_OP diff --git a/arch/frv/include/asm/atomic_defs.h b/arch/frv/include/asm/atomic_defs.h index 36e126d..d4912c8 100644 --- a/arch/frv/include/asm/atomic_defs.h +++ b/arch/frv/include/asm/atomic_defs.h @@ -162,6 +162,8 @@ ATOMIC_EXPORT(__atomic64_fetch_##op); ATOMIC_FETCH_OP(or) ATOMIC_FETCH_OP(and) ATOMIC_FETCH_OP(xor) +ATOMIC_FETCH_OP(add) +ATOMIC_FETCH_OP(sub) ATOMIC_OP_RETURN(add) ATOMIC_OP_RETURN(sub) -- cgit v0.10.2 From 0c074cbc33091dd69fe70ec27474d228c3184860 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Mon, 18 Apr 2016 01:16:08 +0200 Subject: locking/atomic, arch/h8300: Implement atomic_fetch_{add,sub,and,or,xor}() Implement FETCH-OP atomic primitives, these are very similar to the existing OP-RETURN primitives we already have, except they return the value of the atomic variable _before_ modification. This is especially useful for irreversible operations -- such as bitops (because it becomes impossible to reconstruct the state prior to modification). Signed-off-by: Peter Zijlstra (Intel) Cc: Andrew Morton Cc: Linus Torvalds Cc: Paul E. McKenney Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: Yoshinori Sato Cc: linux-arch@vger.kernel.org Cc: linux-kernel@vger.kernel.org Cc: uclinux-h8-devel@lists.sourceforge.jp Signed-off-by: Ingo Molnar diff --git a/arch/h8300/include/asm/atomic.h b/arch/h8300/include/asm/atomic.h index 4435a44..0961b61 100644 --- a/arch/h8300/include/asm/atomic.h +++ b/arch/h8300/include/asm/atomic.h @@ -28,6 +28,19 @@ static inline int atomic_##op##_return(int i, atomic_t *v) \ return ret; \ } +#define ATOMIC_FETCH_OP(op, c_op) \ +static inline int atomic_fetch_##op(int i, atomic_t *v) \ +{ \ + h8300flags flags; \ + int ret; \ + \ + flags = arch_local_irq_save(); \ + ret = v->counter; \ + v->counter c_op i; \ + arch_local_irq_restore(flags); \ + return ret; \ +} + #define ATOMIC_OP(op, c_op) \ static inline void atomic_##op(int i, atomic_t *v) \ { \ @@ -41,17 +54,23 @@ static inline void atomic_##op(int i, atomic_t *v) \ ATOMIC_OP_RETURN(add, +=) ATOMIC_OP_RETURN(sub, -=) -ATOMIC_OP(and, &=) -ATOMIC_OP(or, |=) -ATOMIC_OP(xor, ^=) +#define atomic_fetch_or atomic_fetch_or +#define ATOMIC_OPS(op, c_op) \ + ATOMIC_OP(op, c_op) \ + ATOMIC_FETCH_OP(op, c_op) + +ATOMIC_OPS(and, &=) +ATOMIC_OPS(or, |=) +ATOMIC_OPS(xor, ^=) +ATOMIC_OPS(add, +=) +ATOMIC_OPS(sub, -=) + +#undef ATOMIC_OPS #undef ATOMIC_OP_RETURN #undef ATOMIC_OP -#define atomic_add(i, v) (void)atomic_add_return(i, v) #define atomic_add_negative(a, v) (atomic_add_return((a), (v)) < 0) - -#define atomic_sub(i, v) (void)atomic_sub_return(i, v) #define atomic_sub_and_test(i, v) (atomic_sub_return(i, v) == 0) #define atomic_inc_return(v) atomic_add_return(1, v) -- cgit v0.10.2 From 4be7dd393515615430a4d07ca1ffceaf2a331620 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Mon, 18 Apr 2016 01:16:07 +0200 Subject: locking/atomic, arch/hexagon: Implement atomic_fetch_{add,sub,and,or,xor}() Implement FETCH-OP atomic primitives, these are very similar to the existing OP-RETURN primitives we already have, except they return the value of the atomic variable _before_ modification. This is especially useful for irreversible operations -- such as bitops (because it becomes impossible to reconstruct the state prior to modification). Signed-off-by: Peter Zijlstra (Intel) Cc: Andrew Morton Cc: Linus Torvalds Cc: Paul E. McKenney Cc: Peter Zijlstra Cc: Richard Kuo Cc: Thomas Gleixner Cc: linux-arch@vger.kernel.org Cc: linux-hexagon@vger.kernel.org Cc: linux-kernel@vger.kernel.org Signed-off-by: Ingo Molnar diff --git a/arch/hexagon/include/asm/atomic.h b/arch/hexagon/include/asm/atomic.h index 55696c4..07dbb33 100644 --- a/arch/hexagon/include/asm/atomic.h +++ b/arch/hexagon/include/asm/atomic.h @@ -110,7 +110,7 @@ static inline void atomic_##op(int i, atomic_t *v) \ ); \ } \ -#define ATOMIC_OP_RETURN(op) \ +#define ATOMIC_OP_RETURN(op) \ static inline int atomic_##op##_return(int i, atomic_t *v) \ { \ int output; \ @@ -127,16 +127,39 @@ static inline int atomic_##op##_return(int i, atomic_t *v) \ return output; \ } -#define ATOMIC_OPS(op) ATOMIC_OP(op) ATOMIC_OP_RETURN(op) +#define ATOMIC_FETCH_OP(op) \ +static inline int atomic_fetch_##op(int i, atomic_t *v) \ +{ \ + int output, val; \ + \ + __asm__ __volatile__ ( \ + "1: %0 = memw_locked(%2);\n" \ + " %1 = "#op "(%0,%3);\n" \ + " memw_locked(%2,P3)=%1;\n" \ + " if !P3 jump 1b;\n" \ + : "=&r" (output), "=&r" (val) \ + : "r" (&v->counter), "r" (i) \ + : "memory", "p3" \ + ); \ + return output; \ +} + +#define ATOMIC_OPS(op) ATOMIC_OP(op) ATOMIC_OP_RETURN(op) ATOMIC_FETCH_OP(op) ATOMIC_OPS(add) ATOMIC_OPS(sub) -ATOMIC_OP(and) -ATOMIC_OP(or) -ATOMIC_OP(xor) +#undef ATOMIC_OPS +#define ATOMIC_OPS(op) ATOMIC_OP(op) ATOMIC_FETCH_OP(op) + +#define atomic_fetch_or atomic_fetch_or + +ATOMIC_OPS(and) +ATOMIC_OPS(or) +ATOMIC_OPS(xor) #undef ATOMIC_OPS +#undef ATOMIC_FETCH_OP #undef ATOMIC_OP_RETURN #undef ATOMIC_OP -- cgit v0.10.2 From cc102507fac75f9f4f37938f49d10c25e596a608 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Mon, 18 Apr 2016 01:16:07 +0200 Subject: locking/atomic, arch/ia64: Implement atomic{,64}_fetch_{add,sub,and,or,xor}() Implement FETCH-OP atomic primitives, these are very similar to the existing OP-RETURN primitives we already have, except they return the value of the atomic variable _before_ modification. This is especially useful for irreversible operations -- such as bitops (because it becomes impossible to reconstruct the state prior to modification). Signed-off-by: Peter Zijlstra (Intel) Cc: Andrew Morton Cc: Fenghua Yu Cc: Linus Torvalds Cc: Paul E. McKenney Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: Tony Luck Cc: linux-arch@vger.kernel.org Cc: linux-ia64@vger.kernel.org Cc: linux-kernel@vger.kernel.org Signed-off-by: Ingo Molnar diff --git a/arch/ia64/include/asm/atomic.h b/arch/ia64/include/asm/atomic.h index 8dfb5f6..f565ad3 100644 --- a/arch/ia64/include/asm/atomic.h +++ b/arch/ia64/include/asm/atomic.h @@ -42,8 +42,27 @@ ia64_atomic_##op (int i, atomic_t *v) \ return new; \ } -ATOMIC_OP(add, +) -ATOMIC_OP(sub, -) +#define ATOMIC_FETCH_OP(op, c_op) \ +static __inline__ int \ +ia64_atomic_fetch_##op (int i, atomic_t *v) \ +{ \ + __s32 old, new; \ + CMPXCHG_BUGCHECK_DECL \ + \ + do { \ + CMPXCHG_BUGCHECK(v); \ + old = atomic_read(v); \ + new = old c_op i; \ + } while (ia64_cmpxchg(acq, v, old, new, sizeof(atomic_t)) != old); \ + return old; \ +} + +#define ATOMIC_OPS(op, c_op) \ + ATOMIC_OP(op, c_op) \ + ATOMIC_FETCH_OP(op, c_op) + +ATOMIC_OPS(add, +) +ATOMIC_OPS(sub, -) #define atomic_add_return(i,v) \ ({ \ @@ -69,14 +88,44 @@ ATOMIC_OP(sub, -) : ia64_atomic_sub(__ia64_asr_i, v); \ }) -ATOMIC_OP(and, &) -ATOMIC_OP(or, |) -ATOMIC_OP(xor, ^) +#define atomic_fetch_add(i,v) \ +({ \ + int __ia64_aar_i = (i); \ + (__builtin_constant_p(i) \ + && ( (__ia64_aar_i == 1) || (__ia64_aar_i == 4) \ + || (__ia64_aar_i == 8) || (__ia64_aar_i == 16) \ + || (__ia64_aar_i == -1) || (__ia64_aar_i == -4) \ + || (__ia64_aar_i == -8) || (__ia64_aar_i == -16))) \ + ? ia64_fetchadd(__ia64_aar_i, &(v)->counter, acq) \ + : ia64_atomic_fetch_add(__ia64_aar_i, v); \ +}) + +#define atomic_fetch_sub(i,v) \ +({ \ + int __ia64_asr_i = (i); \ + (__builtin_constant_p(i) \ + && ( (__ia64_asr_i == 1) || (__ia64_asr_i == 4) \ + || (__ia64_asr_i == 8) || (__ia64_asr_i == 16) \ + || (__ia64_asr_i == -1) || (__ia64_asr_i == -4) \ + || (__ia64_asr_i == -8) || (__ia64_asr_i == -16))) \ + ? ia64_fetchadd(-__ia64_asr_i, &(v)->counter, acq) \ + : ia64_atomic_fetch_sub(__ia64_asr_i, v); \ +}) + +ATOMIC_FETCH_OP(and, &) +ATOMIC_FETCH_OP(or, |) +ATOMIC_FETCH_OP(xor, ^) + +#define atomic_and(i,v) (void)ia64_atomic_fetch_and(i,v) +#define atomic_or(i,v) (void)ia64_atomic_fetch_or(i,v) +#define atomic_xor(i,v) (void)ia64_atomic_fetch_xor(i,v) -#define atomic_and(i,v) (void)ia64_atomic_and(i,v) -#define atomic_or(i,v) (void)ia64_atomic_or(i,v) -#define atomic_xor(i,v) (void)ia64_atomic_xor(i,v) +#define atomic_fetch_and(i,v) ia64_atomic_fetch_and(i,v) +#define atomic_fetch_or(i,v) ia64_atomic_fetch_or(i,v) +#define atomic_fetch_xor(i,v) ia64_atomic_fetch_xor(i,v) +#undef ATOMIC_OPS +#undef ATOMIC_FETCH_OP #undef ATOMIC_OP #define ATOMIC64_OP(op, c_op) \ @@ -94,8 +143,27 @@ ia64_atomic64_##op (__s64 i, atomic64_t *v) \ return new; \ } -ATOMIC64_OP(add, +) -ATOMIC64_OP(sub, -) +#define ATOMIC64_FETCH_OP(op, c_op) \ +static __inline__ long \ +ia64_atomic64_fetch_##op (__s64 i, atomic64_t *v) \ +{ \ + __s64 old, new; \ + CMPXCHG_BUGCHECK_DECL \ + \ + do { \ + CMPXCHG_BUGCHECK(v); \ + old = atomic64_read(v); \ + new = old c_op i; \ + } while (ia64_cmpxchg(acq, v, old, new, sizeof(atomic64_t)) != old); \ + return old; \ +} + +#define ATOMIC64_OPS(op, c_op) \ + ATOMIC64_OP(op, c_op) \ + ATOMIC64_FETCH_OP(op, c_op) + +ATOMIC64_OPS(add, +) +ATOMIC64_OPS(sub, -) #define atomic64_add_return(i,v) \ ({ \ @@ -121,14 +189,44 @@ ATOMIC64_OP(sub, -) : ia64_atomic64_sub(__ia64_asr_i, v); \ }) -ATOMIC64_OP(and, &) -ATOMIC64_OP(or, |) -ATOMIC64_OP(xor, ^) +#define atomic64_fetch_add(i,v) \ +({ \ + long __ia64_aar_i = (i); \ + (__builtin_constant_p(i) \ + && ( (__ia64_aar_i == 1) || (__ia64_aar_i == 4) \ + || (__ia64_aar_i == 8) || (__ia64_aar_i == 16) \ + || (__ia64_aar_i == -1) || (__ia64_aar_i == -4) \ + || (__ia64_aar_i == -8) || (__ia64_aar_i == -16))) \ + ? ia64_fetchadd(__ia64_aar_i, &(v)->counter, acq) \ + : ia64_atomic64_fetch_add(__ia64_aar_i, v); \ +}) + +#define atomic64_fetch_sub(i,v) \ +({ \ + long __ia64_asr_i = (i); \ + (__builtin_constant_p(i) \ + && ( (__ia64_asr_i == 1) || (__ia64_asr_i == 4) \ + || (__ia64_asr_i == 8) || (__ia64_asr_i == 16) \ + || (__ia64_asr_i == -1) || (__ia64_asr_i == -4) \ + || (__ia64_asr_i == -8) || (__ia64_asr_i == -16))) \ + ? ia64_fetchadd(-__ia64_asr_i, &(v)->counter, acq) \ + : ia64_atomic64_fetch_sub(__ia64_asr_i, v); \ +}) + +ATOMIC64_FETCH_OP(and, &) +ATOMIC64_FETCH_OP(or, |) +ATOMIC64_FETCH_OP(xor, ^) + +#define atomic64_and(i,v) (void)ia64_atomic64_fetch_and(i,v) +#define atomic64_or(i,v) (void)ia64_atomic64_fetch_or(i,v) +#define atomic64_xor(i,v) (void)ia64_atomic64_fetch_xor(i,v) -#define atomic64_and(i,v) (void)ia64_atomic64_and(i,v) -#define atomic64_or(i,v) (void)ia64_atomic64_or(i,v) -#define atomic64_xor(i,v) (void)ia64_atomic64_xor(i,v) +#define atomic64_fetch_and(i,v) ia64_atomic64_fetch_and(i,v) +#define atomic64_fetch_or(i,v) ia64_atomic64_fetch_or(i,v) +#define atomic64_fetch_xor(i,v) ia64_atomic64_fetch_xor(i,v) +#undef ATOMIC64_OPS +#undef ATOMIC64_FETCH_OP #undef ATOMIC64_OP #define atomic_cmpxchg(v, old, new) (cmpxchg(&((v)->counter), old, new)) -- cgit v0.10.2 From f649370523033c7c2adf16a9d062438c8a7758b3 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Mon, 18 Apr 2016 01:16:07 +0200 Subject: locking/atomic, arch/m32r: Implement atomic_fetch_{add,sub,and,or,xor}() Implement FETCH-OP atomic primitives, these are very similar to the existing OP-RETURN primitives we already have, except they return the value of the atomic variable _before_ modification. This is especially useful for irreversible operations -- such as bitops (because it becomes impossible to reconstruct the state prior to modification). Signed-off-by: Peter Zijlstra (Intel) Cc: Andrew Morton Cc: Linus Torvalds Cc: Paul E. McKenney Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: linux-arch@vger.kernel.org Cc: linux-kernel@vger.kernel.org Signed-off-by: Ingo Molnar diff --git a/arch/m32r/include/asm/atomic.h b/arch/m32r/include/asm/atomic.h index ea35160..8ba8a0a 100644 --- a/arch/m32r/include/asm/atomic.h +++ b/arch/m32r/include/asm/atomic.h @@ -89,16 +89,46 @@ static __inline__ int atomic_##op##_return(int i, atomic_t *v) \ return result; \ } -#define ATOMIC_OPS(op) ATOMIC_OP(op) ATOMIC_OP_RETURN(op) +#define ATOMIC_FETCH_OP(op) \ +static __inline__ int atomic_fetch_##op(int i, atomic_t *v) \ +{ \ + unsigned long flags; \ + int result, val; \ + \ + local_irq_save(flags); \ + __asm__ __volatile__ ( \ + "# atomic_fetch_" #op " \n\t" \ + DCACHE_CLEAR("%0", "r4", "%2") \ + M32R_LOCK" %1, @%2; \n\t" \ + "mv %0, %1 \n\t" \ + #op " %1, %3; \n\t" \ + M32R_UNLOCK" %1, @%2; \n\t" \ + : "=&r" (result), "=&r" (val) \ + : "r" (&v->counter), "r" (i) \ + : "memory" \ + __ATOMIC_CLOBBER \ + ); \ + local_irq_restore(flags); \ + \ + return result; \ +} + +#define ATOMIC_OPS(op) ATOMIC_OP(op) ATOMIC_OP_RETURN(op) ATOMIC_FETCH_OP(op) ATOMIC_OPS(add) ATOMIC_OPS(sub) -ATOMIC_OP(and) -ATOMIC_OP(or) -ATOMIC_OP(xor) +#undef ATOMIC_OPS +#define ATOMIC_OPS(op) ATOMIC_OP(op) ATOMIC_FETCH_OP(op) + +#define atomic_fetch_or atomic_fetch_or + +ATOMIC_OPS(and) +ATOMIC_OPS(or) +ATOMIC_OPS(xor) #undef ATOMIC_OPS +#undef ATOMIC_FETCH_OP #undef ATOMIC_OP_RETURN #undef ATOMIC_OP -- cgit v0.10.2 From e39d88ea3ce4a471cd0202f4f2c8f5ee0f8d7f53 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Mon, 18 Apr 2016 01:16:06 +0200 Subject: locking/atomic, arch/m68k: Implement atomic_fetch_{add,sub,and,or,xor}() Implement FETCH-OP atomic primitives, these are very similar to the existing OP-RETURN primitives we already have, except they return the value of the atomic variable _before_ modification. This is especially useful for irreversible operations -- such as bitops (because it becomes impossible to reconstruct the state prior to modification). Signed-off-by: Peter Zijlstra (Intel) Cc: Andrew Morton Cc: Geert Uytterhoeven Cc: Linus Torvalds Cc: Paul E. McKenney Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: linux-arch@vger.kernel.org Cc: linux-kernel@vger.kernel.org Cc: linux-m68k@lists.linux-m68k.org Signed-off-by: Ingo Molnar diff --git a/arch/m68k/include/asm/atomic.h b/arch/m68k/include/asm/atomic.h index 4858178..5cf9b3b 100644 --- a/arch/m68k/include/asm/atomic.h +++ b/arch/m68k/include/asm/atomic.h @@ -38,6 +38,13 @@ static inline void atomic_##op(int i, atomic_t *v) \ #ifdef CONFIG_RMW_INSNS +/* + * Am I reading these CAS loops right in that %2 is the old value and the first + * iteration uses an uninitialized value? + * + * Would it not make sense to add: tmp = atomic_read(v); to avoid this? + */ + #define ATOMIC_OP_RETURN(op, c_op, asm_op) \ static inline int atomic_##op##_return(int i, atomic_t *v) \ { \ @@ -53,6 +60,21 @@ static inline int atomic_##op##_return(int i, atomic_t *v) \ return t; \ } +#define ATOMIC_FETCH_OP(op, c_op, asm_op) \ +static inline int atomic_fetch_##op(int i, atomic_t *v) \ +{ \ + int t, tmp; \ + \ + __asm__ __volatile__( \ + "1: movel %2,%1\n" \ + " " #asm_op "l %3,%1\n" \ + " casl %2,%1,%0\n" \ + " jne 1b" \ + : "+m" (*v), "=&d" (t), "=&d" (tmp) \ + : "g" (i), "2" (atomic_read(v))); \ + return tmp; \ +} + #else #define ATOMIC_OP_RETURN(op, c_op, asm_op) \ @@ -68,20 +90,43 @@ static inline int atomic_##op##_return(int i, atomic_t * v) \ return t; \ } +#define ATOMIC_FETCH_OP(op, c_op, asm_op) \ +static inline int atomic_fetch_##op(int i, atomic_t * v) \ +{ \ + unsigned long flags; \ + int t; \ + \ + local_irq_save(flags); \ + t = v->counter; \ + v->counter c_op i; \ + local_irq_restore(flags); \ + \ + return t; \ +} + #endif /* CONFIG_RMW_INSNS */ #define ATOMIC_OPS(op, c_op, asm_op) \ ATOMIC_OP(op, c_op, asm_op) \ - ATOMIC_OP_RETURN(op, c_op, asm_op) + ATOMIC_OP_RETURN(op, c_op, asm_op) \ + ATOMIC_FETCH_OP(op, c_op, asm_op) ATOMIC_OPS(add, +=, add) ATOMIC_OPS(sub, -=, sub) -ATOMIC_OP(and, &=, and) -ATOMIC_OP(or, |=, or) -ATOMIC_OP(xor, ^=, eor) +#undef ATOMIC_OPS +#define ATOMIC_OPS(op, c_op, asm_op) \ + ATOMIC_OP(op, c_op, asm_op) \ + ATOMIC_FETCH_OP(op, c_op, asm_op) + +#define atomic_fetch_or atomic_fetch_or + +ATOMIC_OPS(and, &=, and) +ATOMIC_OPS(or, |=, or) +ATOMIC_OPS(xor, ^=, eor) #undef ATOMIC_OPS +#undef ATOMIC_FETCH_OP #undef ATOMIC_OP_RETURN #undef ATOMIC_OP -- cgit v0.10.2 From e898eb27ffd8b0ad6f4fd0b631559bc877c85444 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Mon, 18 Apr 2016 01:16:06 +0200 Subject: locking/atomic, arch/metag: Implement atomic_fetch_{add,sub,and,or,xor}() Implement FETCH-OP atomic primitives, these are very similar to the existing OP-RETURN primitives we already have, except they return the value of the atomic variable _before_ modification. This is especially useful for irreversible operations -- such as bitops (because it becomes impossible to reconstruct the state prior to modification). Signed-off-by: Peter Zijlstra (Intel) Acked-by: James Hogan Cc: Andrew Morton Cc: Linus Torvalds Cc: Paul E. McKenney Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: linux-arch@vger.kernel.org Cc: linux-kernel@vger.kernel.org Cc: linux-metag@vger.kernel.org Signed-off-by: Ingo Molnar diff --git a/arch/metag/include/asm/atomic.h b/arch/metag/include/asm/atomic.h index 470e365..6ca210d 100644 --- a/arch/metag/include/asm/atomic.h +++ b/arch/metag/include/asm/atomic.h @@ -17,6 +17,8 @@ #include #endif +#define atomic_fetch_or atomic_fetch_or + #define atomic_add_negative(a, v) (atomic_add_return((a), (v)) < 0) #define atomic_dec_return(v) atomic_sub_return(1, (v)) diff --git a/arch/metag/include/asm/atomic_lnkget.h b/arch/metag/include/asm/atomic_lnkget.h index 88fa25f..def2c64 100644 --- a/arch/metag/include/asm/atomic_lnkget.h +++ b/arch/metag/include/asm/atomic_lnkget.h @@ -69,16 +69,44 @@ static inline int atomic_##op##_return(int i, atomic_t *v) \ return result; \ } -#define ATOMIC_OPS(op) ATOMIC_OP(op) ATOMIC_OP_RETURN(op) +#define ATOMIC_FETCH_OP(op) \ +static inline int atomic_fetch_##op(int i, atomic_t *v) \ +{ \ + int result, temp; \ + \ + smp_mb(); \ + \ + asm volatile ( \ + "1: LNKGETD %1, [%2]\n" \ + " " #op " %0, %1, %3\n" \ + " LNKSETD [%2], %0\n" \ + " DEFR %0, TXSTAT\n" \ + " ANDT %0, %0, #HI(0x3f000000)\n" \ + " CMPT %0, #HI(0x02000000)\n" \ + " BNZ 1b\n" \ + : "=&d" (temp), "=&d" (result) \ + : "da" (&v->counter), "bd" (i) \ + : "cc"); \ + \ + smp_mb(); \ + \ + return result; \ +} + +#define ATOMIC_OPS(op) ATOMIC_OP(op) ATOMIC_OP_RETURN(op) ATOMIC_FETCH_OP(op) ATOMIC_OPS(add) ATOMIC_OPS(sub) -ATOMIC_OP(and) -ATOMIC_OP(or) -ATOMIC_OP(xor) +#undef ATOMIC_OPS +#define ATOMIC_OPS(op) ATOMIC_OP(op) ATOMIC_FETCH_OP(op) + +ATOMIC_OPS(and) +ATOMIC_OPS(or) +ATOMIC_OPS(xor) #undef ATOMIC_OPS +#undef ATOMIC_FETCH_OP #undef ATOMIC_OP_RETURN #undef ATOMIC_OP diff --git a/arch/metag/include/asm/atomic_lock1.h b/arch/metag/include/asm/atomic_lock1.h index 0295d9b..6c1380a 100644 --- a/arch/metag/include/asm/atomic_lock1.h +++ b/arch/metag/include/asm/atomic_lock1.h @@ -64,15 +64,40 @@ static inline int atomic_##op##_return(int i, atomic_t *v) \ return result; \ } -#define ATOMIC_OPS(op, c_op) ATOMIC_OP(op, c_op) ATOMIC_OP_RETURN(op, c_op) +#define ATOMIC_FETCH_OP(op, c_op) \ +static inline int atomic_fetch_##op(int i, atomic_t *v) \ +{ \ + unsigned long result; \ + unsigned long flags; \ + \ + __global_lock1(flags); \ + result = v->counter; \ + fence(); \ + v->counter c_op i; \ + __global_unlock1(flags); \ + \ + return result; \ +} + +#define ATOMIC_OPS(op, c_op) \ + ATOMIC_OP(op, c_op) \ + ATOMIC_OP_RETURN(op, c_op) \ + ATOMIC_FETCH_OP(op, c_op) ATOMIC_OPS(add, +=) ATOMIC_OPS(sub, -=) -ATOMIC_OP(and, &=) -ATOMIC_OP(or, |=) -ATOMIC_OP(xor, ^=) #undef ATOMIC_OPS +#define ATOMIC_OPS(op, c_op) \ + ATOMIC_OP(op, c_op) \ + ATOMIC_FETCH_OP(op, c_op) + +ATOMIC_OPS(and, &=) +ATOMIC_OPS(or, |=) +ATOMIC_OPS(xor, ^=) + +#undef ATOMIC_OPS +#undef ATOMIC_FETCH_OP #undef ATOMIC_OP_RETURN #undef ATOMIC_OP -- cgit v0.10.2 From 4edac529eb629ccd598e2236c61762537f16e883 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Mon, 18 Apr 2016 01:16:06 +0200 Subject: locking/atomic, arch/mips: Implement atomic{,64}_fetch_{add,sub,and,or,xor}() Implement FETCH-OP atomic primitives, these are very similar to the existing OP-RETURN primitives we already have, except they return the value of the atomic variable _before_ modification. This is especially useful for irreversible operations -- such as bitops (because it becomes impossible to reconstruct the state prior to modification). Signed-off-by: Peter Zijlstra (Intel) Cc: Andrew Morton Cc: Linus Torvalds Cc: Paul E. McKenney Cc: Peter Zijlstra Cc: Ralf Baechle Cc: Thomas Gleixner Cc: linux-arch@vger.kernel.org Cc: linux-kernel@vger.kernel.org Cc: linux-mips@linux-mips.org Signed-off-by: Ingo Molnar diff --git a/arch/mips/include/asm/atomic.h b/arch/mips/include/asm/atomic.h index 835b402..431079f 100644 --- a/arch/mips/include/asm/atomic.h +++ b/arch/mips/include/asm/atomic.h @@ -66,7 +66,7 @@ static __inline__ void atomic_##op(int i, atomic_t * v) \ " " #asm_op " %0, %2 \n" \ " sc %0, %1 \n" \ " .set mips0 \n" \ - : "=&r" (temp), "+" GCC_OFF_SMALL_ASM() (v->counter) \ + : "=&r" (temp), "+" GCC_OFF_SMALL_ASM() (v->counter) \ : "Ir" (i)); \ } while (unlikely(!temp)); \ } else { \ @@ -130,18 +130,78 @@ static __inline__ int atomic_##op##_return(int i, atomic_t * v) \ return result; \ } +#define ATOMIC_FETCH_OP(op, c_op, asm_op) \ +static __inline__ int atomic_fetch_##op(int i, atomic_t * v) \ +{ \ + int result; \ + \ + smp_mb__before_llsc(); \ + \ + if (kernel_uses_llsc && R10000_LLSC_WAR) { \ + int temp; \ + \ + __asm__ __volatile__( \ + " .set arch=r4000 \n" \ + "1: ll %1, %2 # atomic_fetch_" #op " \n" \ + " " #asm_op " %0, %1, %3 \n" \ + " sc %0, %2 \n" \ + " beqzl %0, 1b \n" \ + " move %0, %1 \n" \ + " .set mips0 \n" \ + : "=&r" (result), "=&r" (temp), \ + "+" GCC_OFF_SMALL_ASM() (v->counter) \ + : "Ir" (i)); \ + } else if (kernel_uses_llsc) { \ + int temp; \ + \ + do { \ + __asm__ __volatile__( \ + " .set "MIPS_ISA_LEVEL" \n" \ + " ll %1, %2 # atomic_fetch_" #op " \n" \ + " " #asm_op " %0, %1, %3 \n" \ + " sc %0, %2 \n" \ + " .set mips0 \n" \ + : "=&r" (result), "=&r" (temp), \ + "+" GCC_OFF_SMALL_ASM() (v->counter) \ + : "Ir" (i)); \ + } while (unlikely(!result)); \ + \ + result = temp; \ + } else { \ + unsigned long flags; \ + \ + raw_local_irq_save(flags); \ + result = v->counter; \ + v->counter c_op i; \ + raw_local_irq_restore(flags); \ + } \ + \ + smp_llsc_mb(); \ + \ + return result; \ +} + #define ATOMIC_OPS(op, c_op, asm_op) \ ATOMIC_OP(op, c_op, asm_op) \ - ATOMIC_OP_RETURN(op, c_op, asm_op) + ATOMIC_OP_RETURN(op, c_op, asm_op) \ + ATOMIC_FETCH_OP(op, c_op, asm_op) ATOMIC_OPS(add, +=, addu) ATOMIC_OPS(sub, -=, subu) -ATOMIC_OP(and, &=, and) -ATOMIC_OP(or, |=, or) -ATOMIC_OP(xor, ^=, xor) +#undef ATOMIC_OPS +#define ATOMIC_OPS(op, c_op, asm_op) \ + ATOMIC_OP(op, c_op, asm_op) \ + ATOMIC_FETCH_OP(op, c_op, asm_op) + +#define atomic_fetch_or atomic_fetch_or + +ATOMIC_OPS(and, &=, and) +ATOMIC_OPS(or, |=, or) +ATOMIC_OPS(xor, ^=, xor) #undef ATOMIC_OPS +#undef ATOMIC_FETCH_OP #undef ATOMIC_OP_RETURN #undef ATOMIC_OP @@ -414,17 +474,77 @@ static __inline__ long atomic64_##op##_return(long i, atomic64_t * v) \ return result; \ } +#define ATOMIC64_FETCH_OP(op, c_op, asm_op) \ +static __inline__ long atomic64_fetch_##op(long i, atomic64_t * v) \ +{ \ + long result; \ + \ + smp_mb__before_llsc(); \ + \ + if (kernel_uses_llsc && R10000_LLSC_WAR) { \ + long temp; \ + \ + __asm__ __volatile__( \ + " .set arch=r4000 \n" \ + "1: lld %1, %2 # atomic64_fetch_" #op "\n" \ + " " #asm_op " %0, %1, %3 \n" \ + " scd %0, %2 \n" \ + " beqzl %0, 1b \n" \ + " move %0, %1 \n" \ + " .set mips0 \n" \ + : "=&r" (result), "=&r" (temp), \ + "+" GCC_OFF_SMALL_ASM() (v->counter) \ + : "Ir" (i)); \ + } else if (kernel_uses_llsc) { \ + long temp; \ + \ + do { \ + __asm__ __volatile__( \ + " .set "MIPS_ISA_LEVEL" \n" \ + " lld %1, %2 # atomic64_fetch_" #op "\n" \ + " " #asm_op " %0, %1, %3 \n" \ + " scd %0, %2 \n" \ + " .set mips0 \n" \ + : "=&r" (result), "=&r" (temp), \ + "=" GCC_OFF_SMALL_ASM() (v->counter) \ + : "Ir" (i), GCC_OFF_SMALL_ASM() (v->counter) \ + : "memory"); \ + } while (unlikely(!result)); \ + \ + result = temp; \ + } else { \ + unsigned long flags; \ + \ + raw_local_irq_save(flags); \ + result = v->counter; \ + v->counter c_op i; \ + raw_local_irq_restore(flags); \ + } \ + \ + smp_llsc_mb(); \ + \ + return result; \ +} + #define ATOMIC64_OPS(op, c_op, asm_op) \ ATOMIC64_OP(op, c_op, asm_op) \ - ATOMIC64_OP_RETURN(op, c_op, asm_op) + ATOMIC64_OP_RETURN(op, c_op, asm_op) \ + ATOMIC64_FETCH_OP(op, c_op, asm_op) ATOMIC64_OPS(add, +=, daddu) ATOMIC64_OPS(sub, -=, dsubu) -ATOMIC64_OP(and, &=, and) -ATOMIC64_OP(or, |=, or) -ATOMIC64_OP(xor, ^=, xor) #undef ATOMIC64_OPS +#define ATOMIC64_OPS(op, c_op, asm_op) \ + ATOMIC64_OP(op, c_op, asm_op) \ + ATOMIC64_FETCH_OP(op, c_op, asm_op) + +ATOMIC64_OPS(and, &=, and) +ATOMIC64_OPS(or, |=, or) +ATOMIC64_OPS(xor, ^=, xor) + +#undef ATOMIC64_OPS +#undef ATOMIC64_FETCH_OP #undef ATOMIC64_OP_RETURN #undef ATOMIC64_OP -- cgit v0.10.2 From f8d638e28d7cc858066d2de484d9719dc181593a Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Mon, 18 Apr 2016 01:16:05 +0200 Subject: locking/atomic, arch/mn10300: Implement atomic_fetch_{add,sub,and,or,xor}() Implement FETCH-OP atomic primitives, these are very similar to the existing OP-RETURN primitives we already have, except they return the value of the atomic variable _before_ modification. This is especially useful for irreversible operations -- such as bitops (because it becomes impossible to reconstruct the state prior to modification). Signed-off-by: Peter Zijlstra (Intel) Cc: Andrew Morton Cc: David Howells Cc: Linus Torvalds Cc: Paul E. McKenney Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: linux-am33-list@redhat.com Cc: linux-arch@vger.kernel.org Cc: linux-kernel@vger.kernel.org Signed-off-by: Ingo Molnar diff --git a/arch/mn10300/include/asm/atomic.h b/arch/mn10300/include/asm/atomic.h index ce318d5..3580f78 100644 --- a/arch/mn10300/include/asm/atomic.h +++ b/arch/mn10300/include/asm/atomic.h @@ -84,16 +84,43 @@ static inline int atomic_##op##_return(int i, atomic_t *v) \ return retval; \ } -#define ATOMIC_OPS(op) ATOMIC_OP(op) ATOMIC_OP_RETURN(op) +#define ATOMIC_FETCH_OP(op) \ +static inline int atomic_fetch_##op(int i, atomic_t *v) \ +{ \ + int retval, status; \ + \ + asm volatile( \ + "1: mov %4,(_AAR,%3) \n" \ + " mov (_ADR,%3),%1 \n" \ + " mov %1,%0 \n" \ + " " #op " %5,%0 \n" \ + " mov %0,(_ADR,%3) \n" \ + " mov (_ADR,%3),%0 \n" /* flush */ \ + " mov (_ASR,%3),%0 \n" \ + " or %0,%0 \n" \ + " bne 1b \n" \ + : "=&r"(status), "=&r"(retval), "=m"(v->counter) \ + : "a"(ATOMIC_OPS_BASE_ADDR), "r"(&v->counter), "r"(i) \ + : "memory", "cc"); \ + return retval; \ +} + +#define ATOMIC_OPS(op) ATOMIC_OP(op) ATOMIC_OP_RETURN(op) ATOMIC_FETCH_OP(op) ATOMIC_OPS(add) ATOMIC_OPS(sub) -ATOMIC_OP(and) -ATOMIC_OP(or) -ATOMIC_OP(xor) +#undef ATOMIC_OPS +#define ATOMIC_OPS(op) ATOMIC_OP(op) ATOMIC_FETCH_OP(op) + +#define atomic_fetch_or atomic_fetch_or + +ATOMIC_OPS(and) +ATOMIC_OPS(or) +ATOMIC_OPS(xor) #undef ATOMIC_OPS +#undef ATOMIC_FETCH_OP #undef ATOMIC_OP_RETURN #undef ATOMIC_OP -- cgit v0.10.2 From e5857a6ed6004cac5273b8cdc189ab4b6363cfaf Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Mon, 18 Apr 2016 01:16:05 +0200 Subject: locking/atomic, arch/parisc: Implement atomic{,64}_fetch_{add,sub,and,or,xor}() Implement FETCH-OP atomic primitives, these are very similar to the existing OP-RETURN primitives we already have, except they return the value of the atomic variable _before_ modification. This is especially useful for irreversible operations -- such as bitops (because it becomes impossible to reconstruct the state prior to modification). Signed-off-by: Peter Zijlstra (Intel) Cc: Andrew Morton Cc: Helge Deller Cc: James E.J. Bottomley Cc: Linus Torvalds Cc: Paul E. McKenney Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: linux-arch@vger.kernel.org Cc: linux-kernel@vger.kernel.org Cc: linux-parisc@vger.kernel.org Signed-off-by: Ingo Molnar diff --git a/arch/parisc/include/asm/atomic.h b/arch/parisc/include/asm/atomic.h index 1d10999..29df1f8 100644 --- a/arch/parisc/include/asm/atomic.h +++ b/arch/parisc/include/asm/atomic.h @@ -121,16 +121,41 @@ static __inline__ int atomic_##op##_return(int i, atomic_t *v) \ return ret; \ } -#define ATOMIC_OPS(op, c_op) ATOMIC_OP(op, c_op) ATOMIC_OP_RETURN(op, c_op) +#define ATOMIC_FETCH_OP(op, c_op) \ +static __inline__ int atomic_fetch_##op(int i, atomic_t *v) \ +{ \ + unsigned long flags; \ + int ret; \ + \ + _atomic_spin_lock_irqsave(v, flags); \ + ret = v->counter; \ + v->counter c_op i; \ + _atomic_spin_unlock_irqrestore(v, flags); \ + \ + return ret; \ +} + +#define ATOMIC_OPS(op, c_op) \ + ATOMIC_OP(op, c_op) \ + ATOMIC_OP_RETURN(op, c_op) \ + ATOMIC_FETCH_OP(op, c_op) ATOMIC_OPS(add, +=) ATOMIC_OPS(sub, -=) -ATOMIC_OP(and, &=) -ATOMIC_OP(or, |=) -ATOMIC_OP(xor, ^=) +#undef ATOMIC_OPS +#define ATOMIC_OPS(op, c_op) \ + ATOMIC_OP(op, c_op) \ + ATOMIC_FETCH_OP(op, c_op) + +#define atomic_fetch_or atomic_fetch_or + +ATOMIC_OPS(and, &=) +ATOMIC_OPS(or, |=) +ATOMIC_OPS(xor, ^=) #undef ATOMIC_OPS +#undef ATOMIC_FETCH_OP #undef ATOMIC_OP_RETURN #undef ATOMIC_OP @@ -185,15 +210,39 @@ static __inline__ s64 atomic64_##op##_return(s64 i, atomic64_t *v) \ return ret; \ } -#define ATOMIC64_OPS(op, c_op) ATOMIC64_OP(op, c_op) ATOMIC64_OP_RETURN(op, c_op) +#define ATOMIC64_FETCH_OP(op, c_op) \ +static __inline__ s64 atomic64_fetch_##op(s64 i, atomic64_t *v) \ +{ \ + unsigned long flags; \ + s64 ret; \ + \ + _atomic_spin_lock_irqsave(v, flags); \ + ret = v->counter; \ + v->counter c_op i; \ + _atomic_spin_unlock_irqrestore(v, flags); \ + \ + return ret; \ +} + +#define ATOMIC64_OPS(op, c_op) \ + ATOMIC64_OP(op, c_op) \ + ATOMIC64_OP_RETURN(op, c_op) \ + ATOMIC64_FETCH_OP(op, c_op) ATOMIC64_OPS(add, +=) ATOMIC64_OPS(sub, -=) -ATOMIC64_OP(and, &=) -ATOMIC64_OP(or, |=) -ATOMIC64_OP(xor, ^=) #undef ATOMIC64_OPS +#define ATOMIC64_OPS(op, c_op) \ + ATOMIC64_OP(op, c_op) \ + ATOMIC64_FETCH_OP(op, c_op) + +ATOMIC64_OPS(and, &=) +ATOMIC64_OPS(or, |=) +ATOMIC64_OPS(xor, ^=) + +#undef ATOMIC64_OPS +#undef ATOMIC64_FETCH_OP #undef ATOMIC64_OP_RETURN #undef ATOMIC64_OP -- cgit v0.10.2 From a28cc7bbe8e30ee573e1a27e704558f0862d8c6d Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Mon, 18 Apr 2016 01:16:05 +0200 Subject: locking/atomic, arch/powerpc: Implement atomic{,64}_fetch_{add,sub,and,or,xor}{,_relaxed,_acquire,_release}() Implement FETCH-OP atomic primitives, these are very similar to the existing OP-RETURN primitives we already have, except they return the value of the atomic variable _before_ modification. This is especially useful for irreversible operations -- such as bitops (because it becomes impossible to reconstruct the state prior to modification). Tested-by: Boqun Feng Signed-off-by: Peter Zijlstra (Intel) Cc: Andrew Morton Cc: Benjamin Herrenschmidt Cc: Linus Torvalds Cc: Michael Ellerman Cc: Paul E. McKenney Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: linux-arch@vger.kernel.org Cc: linux-kernel@vger.kernel.org Cc: linuxppc-dev@lists.ozlabs.org Signed-off-by: Ingo Molnar diff --git a/arch/powerpc/include/asm/atomic.h b/arch/powerpc/include/asm/atomic.h index ae0751e..f08d567 100644 --- a/arch/powerpc/include/asm/atomic.h +++ b/arch/powerpc/include/asm/atomic.h @@ -78,21 +78,53 @@ static inline int atomic_##op##_return_relaxed(int a, atomic_t *v) \ return t; \ } +#define ATOMIC_FETCH_OP_RELAXED(op, asm_op) \ +static inline int atomic_fetch_##op##_relaxed(int a, atomic_t *v) \ +{ \ + int res, t; \ + \ + __asm__ __volatile__( \ +"1: lwarx %0,0,%4 # atomic_fetch_" #op "_relaxed\n" \ + #asm_op " %1,%3,%0\n" \ + PPC405_ERR77(0, %4) \ +" stwcx. %1,0,%4\n" \ +" bne- 1b\n" \ + : "=&r" (res), "=&r" (t), "+m" (v->counter) \ + : "r" (a), "r" (&v->counter) \ + : "cc"); \ + \ + return res; \ +} + #define ATOMIC_OPS(op, asm_op) \ ATOMIC_OP(op, asm_op) \ - ATOMIC_OP_RETURN_RELAXED(op, asm_op) + ATOMIC_OP_RETURN_RELAXED(op, asm_op) \ + ATOMIC_FETCH_OP_RELAXED(op, asm_op) ATOMIC_OPS(add, add) ATOMIC_OPS(sub, subf) -ATOMIC_OP(and, and) -ATOMIC_OP(or, or) -ATOMIC_OP(xor, xor) - #define atomic_add_return_relaxed atomic_add_return_relaxed #define atomic_sub_return_relaxed atomic_sub_return_relaxed +#define atomic_fetch_add_relaxed atomic_fetch_add_relaxed +#define atomic_fetch_sub_relaxed atomic_fetch_sub_relaxed + +#undef ATOMIC_OPS +#define ATOMIC_OPS(op, asm_op) \ + ATOMIC_OP(op, asm_op) \ + ATOMIC_FETCH_OP_RELAXED(op, asm_op) + +ATOMIC_OPS(and, and) +ATOMIC_OPS(or, or) +ATOMIC_OPS(xor, xor) + +#define atomic_fetch_and_relaxed atomic_fetch_and_relaxed +#define atomic_fetch_or_relaxed atomic_fetch_or_relaxed +#define atomic_fetch_xor_relaxed atomic_fetch_xor_relaxed + #undef ATOMIC_OPS +#undef ATOMIC_FETCH_OP_RELAXED #undef ATOMIC_OP_RETURN_RELAXED #undef ATOMIC_OP @@ -329,20 +361,53 @@ atomic64_##op##_return_relaxed(long a, atomic64_t *v) \ return t; \ } +#define ATOMIC64_FETCH_OP_RELAXED(op, asm_op) \ +static inline long \ +atomic64_fetch_##op##_relaxed(long a, atomic64_t *v) \ +{ \ + long res, t; \ + \ + __asm__ __volatile__( \ +"1: ldarx %0,0,%4 # atomic64_fetch_" #op "_relaxed\n" \ + #asm_op " %1,%3,%0\n" \ +" stdcx. %1,0,%4\n" \ +" bne- 1b\n" \ + : "=&r" (res), "=&r" (t), "+m" (v->counter) \ + : "r" (a), "r" (&v->counter) \ + : "cc"); \ + \ + return res; \ +} + #define ATOMIC64_OPS(op, asm_op) \ ATOMIC64_OP(op, asm_op) \ - ATOMIC64_OP_RETURN_RELAXED(op, asm_op) + ATOMIC64_OP_RETURN_RELAXED(op, asm_op) \ + ATOMIC64_FETCH_OP_RELAXED(op, asm_op) ATOMIC64_OPS(add, add) ATOMIC64_OPS(sub, subf) -ATOMIC64_OP(and, and) -ATOMIC64_OP(or, or) -ATOMIC64_OP(xor, xor) #define atomic64_add_return_relaxed atomic64_add_return_relaxed #define atomic64_sub_return_relaxed atomic64_sub_return_relaxed +#define atomic64_fetch_add_relaxed atomic64_fetch_add_relaxed +#define atomic64_fetch_sub_relaxed atomic64_fetch_sub_relaxed + +#undef ATOMIC64_OPS +#define ATOMIC64_OPS(op, asm_op) \ + ATOMIC64_OP(op, asm_op) \ + ATOMIC64_FETCH_OP_RELAXED(op, asm_op) + +ATOMIC64_OPS(and, and) +ATOMIC64_OPS(or, or) +ATOMIC64_OPS(xor, xor) + +#define atomic64_fetch_and_relaxed atomic64_fetch_and_relaxed +#define atomic64_fetch_or_relaxed atomic64_fetch_or_relaxed +#define atomic64_fetch_xor_relaxed atomic64_fetch_xor_relaxed + #undef ATOPIC64_OPS +#undef ATOMIC64_FETCH_OP_RELAXED #undef ATOMIC64_OP_RETURN_RELAXED #undef ATOMIC64_OP -- cgit v0.10.2 From 56fefbbc3f13ad8cc9f502dbc6b5c9ddc8c4395e Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Mon, 18 Apr 2016 01:16:05 +0200 Subject: locking/atomic, arch/s390: Implement atomic{,64}_fetch_{add,sub,and,or,xor}() Implement FETCH-OP atomic primitives, these are very similar to the existing OP-RETURN primitives we already have, except they return the value of the atomic variable _before_ modification. This is especially useful for irreversible operations -- such as bitops (because it becomes impossible to reconstruct the state prior to modification). Signed-off-by: Peter Zijlstra (Intel) Acked-by: Martin Schwidefsky Cc: Andrew Morton Cc: Heiko Carstens Cc: Linus Torvalds Cc: Paul E. McKenney Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: linux-arch@vger.kernel.org Cc: linux-kernel@vger.kernel.org Cc: linux-s390@vger.kernel.org Signed-off-by: Ingo Molnar diff --git a/arch/s390/include/asm/atomic.h b/arch/s390/include/asm/atomic.h index 911064a..2324e759 100644 --- a/arch/s390/include/asm/atomic.h +++ b/arch/s390/include/asm/atomic.h @@ -93,6 +93,11 @@ static inline int atomic_add_return(int i, atomic_t *v) return __ATOMIC_LOOP(v, i, __ATOMIC_ADD, __ATOMIC_BARRIER) + i; } +static inline int atomic_fetch_add(int i, atomic_t *v) +{ + return __ATOMIC_LOOP(v, i, __ATOMIC_ADD, __ATOMIC_BARRIER); +} + static inline void atomic_add(int i, atomic_t *v) { #ifdef CONFIG_HAVE_MARCH_Z196_FEATURES @@ -114,22 +119,29 @@ static inline void atomic_add(int i, atomic_t *v) #define atomic_inc_and_test(_v) (atomic_add_return(1, _v) == 0) #define atomic_sub(_i, _v) atomic_add(-(int)(_i), _v) #define atomic_sub_return(_i, _v) atomic_add_return(-(int)(_i), _v) +#define atomic_fetch_sub(_i, _v) atomic_fetch_add(-(int)(_i), _v) #define atomic_sub_and_test(_i, _v) (atomic_sub_return(_i, _v) == 0) #define atomic_dec(_v) atomic_sub(1, _v) #define atomic_dec_return(_v) atomic_sub_return(1, _v) #define atomic_dec_and_test(_v) (atomic_sub_return(1, _v) == 0) -#define ATOMIC_OP(op, OP) \ +#define ATOMIC_OPS(op, OP) \ static inline void atomic_##op(int i, atomic_t *v) \ { \ __ATOMIC_LOOP(v, i, __ATOMIC_##OP, __ATOMIC_NO_BARRIER); \ +} \ +static inline int atomic_fetch_##op(int i, atomic_t *v) \ +{ \ + return __ATOMIC_LOOP(v, i, __ATOMIC_##OP, __ATOMIC_BARRIER); \ } -ATOMIC_OP(and, AND) -ATOMIC_OP(or, OR) -ATOMIC_OP(xor, XOR) +#define atomic_fetch_or atomic_fetch_or + +ATOMIC_OPS(and, AND) +ATOMIC_OPS(or, OR) +ATOMIC_OPS(xor, XOR) -#undef ATOMIC_OP +#undef ATOMIC_OPS #define atomic_xchg(v, new) (xchg(&((v)->counter), new)) @@ -236,6 +248,11 @@ static inline long long atomic64_add_return(long long i, atomic64_t *v) return __ATOMIC64_LOOP(v, i, __ATOMIC64_ADD, __ATOMIC64_BARRIER) + i; } +static inline long long atomic64_fetch_add(long long i, atomic64_t *v) +{ + return __ATOMIC64_LOOP(v, i, __ATOMIC64_ADD, __ATOMIC64_BARRIER); +} + static inline void atomic64_add(long long i, atomic64_t *v) { #ifdef CONFIG_HAVE_MARCH_Z196_FEATURES @@ -264,17 +281,21 @@ static inline long long atomic64_cmpxchg(atomic64_t *v, return old; } -#define ATOMIC64_OP(op, OP) \ +#define ATOMIC64_OPS(op, OP) \ static inline void atomic64_##op(long i, atomic64_t *v) \ { \ __ATOMIC64_LOOP(v, i, __ATOMIC64_##OP, __ATOMIC64_NO_BARRIER); \ +} \ +static inline long atomic64_fetch_##op(long i, atomic64_t *v) \ +{ \ + return __ATOMIC64_LOOP(v, i, __ATOMIC64_##OP, __ATOMIC64_BARRIER); \ } -ATOMIC64_OP(and, AND) -ATOMIC64_OP(or, OR) -ATOMIC64_OP(xor, XOR) +ATOMIC64_OPS(and, AND) +ATOMIC64_OPS(or, OR) +ATOMIC64_OPS(xor, XOR) -#undef ATOMIC64_OP +#undef ATOMIC64_OPS #undef __ATOMIC64_LOOP static inline int atomic64_add_unless(atomic64_t *v, long long i, long long u) @@ -315,6 +336,7 @@ static inline long long atomic64_dec_if_positive(atomic64_t *v) #define atomic64_inc_return(_v) atomic64_add_return(1, _v) #define atomic64_inc_and_test(_v) (atomic64_add_return(1, _v) == 0) #define atomic64_sub_return(_i, _v) atomic64_add_return(-(long long)(_i), _v) +#define atomic64_fetch_sub(_i, _v) atomic64_fetch_add(-(long long)(_i), _v) #define atomic64_sub(_i, _v) atomic64_add(-(long long)(_i), _v) #define atomic64_sub_and_test(_i, _v) (atomic64_sub_return(_i, _v) == 0) #define atomic64_dec(_v) atomic64_sub(1, _v) -- cgit v0.10.2 From 7d9794e7523798e1b9422ad9f4e4d808ae5d5932 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Mon, 18 Apr 2016 01:16:04 +0200 Subject: locking/atomic, arch/sh: Implement atomic_fetch_{add,sub,and,or,xor}() Implement FETCH-OP atomic primitives, these are very similar to the existing OP-RETURN primitives we already have, except they return the value of the atomic variable _before_ modification. This is especially useful for irreversible operations -- such as bitops (because it becomes impossible to reconstruct the state prior to modification). Signed-off-by: Peter Zijlstra (Intel) Cc: Andrew Morton Cc: Linus Torvalds Cc: Paul E. McKenney Cc: Peter Zijlstra Cc: Rich Felker Cc: Thomas Gleixner Cc: Yoshinori Sato Cc: linux-arch@vger.kernel.org Cc: linux-kernel@vger.kernel.org Cc: linux-sh@vger.kernel.org Signed-off-by: Ingo Molnar diff --git a/arch/sh/include/asm/atomic-grb.h b/arch/sh/include/asm/atomic-grb.h index b94df40..d755e96 100644 --- a/arch/sh/include/asm/atomic-grb.h +++ b/arch/sh/include/asm/atomic-grb.h @@ -43,16 +43,42 @@ static inline int atomic_##op##_return(int i, atomic_t *v) \ return tmp; \ } -#define ATOMIC_OPS(op) ATOMIC_OP(op) ATOMIC_OP_RETURN(op) +#define ATOMIC_FETCH_OP(op) \ +static inline int atomic_fetch_##op(int i, atomic_t *v) \ +{ \ + int res, tmp; \ + \ + __asm__ __volatile__ ( \ + " .align 2 \n\t" \ + " mova 1f, r0 \n\t" /* r0 = end point */ \ + " mov r15, r1 \n\t" /* r1 = saved sp */ \ + " mov #-6, r15 \n\t" /* LOGIN: r15 = size */ \ + " mov.l @%2, %0 \n\t" /* load old value */ \ + " mov %0, %1 \n\t" /* save old value */ \ + " " #op " %3, %0 \n\t" /* $op */ \ + " mov.l %0, @%2 \n\t" /* store new value */ \ + "1: mov r1, r15 \n\t" /* LOGOUT */ \ + : "=&r" (tmp), "=&r" (res), "+r" (v) \ + : "r" (i) \ + : "memory" , "r0", "r1"); \ + \ + return res; \ +} + +#define ATOMIC_OPS(op) ATOMIC_OP(op) ATOMIC_OP_RETURN(op) ATOMIC_FETCH_OP(op) ATOMIC_OPS(add) ATOMIC_OPS(sub) -ATOMIC_OP(and) -ATOMIC_OP(or) -ATOMIC_OP(xor) +#undef ATOMIC_OPS +#define ATOMIC_OPS(op) ATOMIC_OP(op) ATOMIC_FETCH_OP(op) + +ATOMIC_OPS(and) +ATOMIC_OPS(or) +ATOMIC_OPS(xor) #undef ATOMIC_OPS +#undef ATOMIC_FETCH_OP #undef ATOMIC_OP_RETURN #undef ATOMIC_OP diff --git a/arch/sh/include/asm/atomic-irq.h b/arch/sh/include/asm/atomic-irq.h index 23fcdad..8e2da5f 100644 --- a/arch/sh/include/asm/atomic-irq.h +++ b/arch/sh/include/asm/atomic-irq.h @@ -33,15 +33,38 @@ static inline int atomic_##op##_return(int i, atomic_t *v) \ return temp; \ } -#define ATOMIC_OPS(op, c_op) ATOMIC_OP(op, c_op) ATOMIC_OP_RETURN(op, c_op) +#define ATOMIC_FETCH_OP(op, c_op) \ +static inline int atomic_fetch_##op(int i, atomic_t *v) \ +{ \ + unsigned long temp, flags; \ + \ + raw_local_irq_save(flags); \ + temp = v->counter; \ + v->counter c_op i; \ + raw_local_irq_restore(flags); \ + \ + return temp; \ +} + +#define ATOMIC_OPS(op, c_op) \ + ATOMIC_OP(op, c_op) \ + ATOMIC_OP_RETURN(op, c_op) \ + ATOMIC_FETCH_OP(op, c_op) ATOMIC_OPS(add, +=) ATOMIC_OPS(sub, -=) -ATOMIC_OP(and, &=) -ATOMIC_OP(or, |=) -ATOMIC_OP(xor, ^=) #undef ATOMIC_OPS +#define ATOMIC_OPS(op, c_op) \ + ATOMIC_OP(op, c_op) \ + ATOMIC_FETCH_OP(op, c_op) + +ATOMIC_OPS(and, &=) +ATOMIC_OPS(or, |=) +ATOMIC_OPS(xor, ^=) + +#undef ATOMIC_OPS +#undef ATOMIC_FETCH_OP #undef ATOMIC_OP_RETURN #undef ATOMIC_OP diff --git a/arch/sh/include/asm/atomic-llsc.h b/arch/sh/include/asm/atomic-llsc.h index 33d34b1..caea2c4 100644 --- a/arch/sh/include/asm/atomic-llsc.h +++ b/arch/sh/include/asm/atomic-llsc.h @@ -48,15 +48,39 @@ static inline int atomic_##op##_return(int i, atomic_t *v) \ return temp; \ } -#define ATOMIC_OPS(op) ATOMIC_OP(op) ATOMIC_OP_RETURN(op) +#define ATOMIC_FETCH_OP(op) \ +static inline int atomic_fetch_##op(int i, atomic_t *v) \ +{ \ + unsigned long res, temp; \ + \ + __asm__ __volatile__ ( \ +"1: movli.l @%3, %0 ! atomic_fetch_" #op " \n" \ +" mov %0, %1 \n" \ +" " #op " %2, %0 \n" \ +" movco.l %0, @%3 \n" \ +" bf 1b \n" \ +" synco \n" \ + : "=&z" (temp), "=&z" (res) \ + : "r" (i), "r" (&v->counter) \ + : "t"); \ + \ + return res; \ +} + +#define ATOMIC_OPS(op) ATOMIC_OP(op) ATOMIC_OP_RETURN(op) ATOMIC_FETCH_OP(op) ATOMIC_OPS(add) ATOMIC_OPS(sub) -ATOMIC_OP(and) -ATOMIC_OP(or) -ATOMIC_OP(xor) #undef ATOMIC_OPS +#define ATOMIC_OPS(op) ATOMIC_OP(op) ATOMIC_FETCH_OP(op) + +ATOMIC_OPS(and) +ATOMIC_OPS(or) +ATOMIC_OPS(xor) + +#undef ATOMIC_OPS +#undef ATOMIC_FETCH_OP #undef ATOMIC_OP_RETURN #undef ATOMIC_OP diff --git a/arch/sh/include/asm/atomic.h b/arch/sh/include/asm/atomic.h index c399e1c..d93ed7c 100644 --- a/arch/sh/include/asm/atomic.h +++ b/arch/sh/include/asm/atomic.h @@ -25,6 +25,8 @@ #include #endif +#define atomic_fetch_or atomic_fetch_or + #define atomic_add_negative(a, v) (atomic_add_return((a), (v)) < 0) #define atomic_dec_return(v) atomic_sub_return(1, (v)) #define atomic_inc_return(v) atomic_add_return(1, (v)) -- cgit v0.10.2 From 3a1adb23a52c920304239efff377d3bc967febc2 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Mon, 18 Apr 2016 01:16:04 +0200 Subject: locking/atomic, arch/sparc: Implement atomic{,64}_fetch_{add,sub,and,or,xor}() Implement FETCH-OP atomic primitives, these are very similar to the existing OP-RETURN primitives we already have, except they return the value of the atomic variable _before_ modification. This is especially useful for irreversible operations -- such as bitops (because it becomes impossible to reconstruct the state prior to modification). Signed-off-by: Peter Zijlstra (Intel) Acked-by: David S. Miller Cc: Andrew Morton Cc: James Y Knight Cc: Linus Torvalds Cc: Paul E. McKenney Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: linux-arch@vger.kernel.org Cc: linux-kernel@vger.kernel.org Cc: sparclinux@vger.kernel.org Signed-off-by: Ingo Molnar diff --git a/arch/sparc/include/asm/atomic.h b/arch/sparc/include/asm/atomic.h index 8ff83d8..1f741bc 100644 --- a/arch/sparc/include/asm/atomic.h +++ b/arch/sparc/include/asm/atomic.h @@ -5,4 +5,5 @@ #else #include #endif +#define atomic_fetch_or atomic_fetch_or #endif diff --git a/arch/sparc/include/asm/atomic_32.h b/arch/sparc/include/asm/atomic_32.h index 7dcbebb..5cfb20a 100644 --- a/arch/sparc/include/asm/atomic_32.h +++ b/arch/sparc/include/asm/atomic_32.h @@ -20,9 +20,10 @@ #define ATOMIC_INIT(i) { (i) } int atomic_add_return(int, atomic_t *); -void atomic_and(int, atomic_t *); -void atomic_or(int, atomic_t *); -void atomic_xor(int, atomic_t *); +int atomic_fetch_add(int, atomic_t *); +int atomic_fetch_and(int, atomic_t *); +int atomic_fetch_or(int, atomic_t *); +int atomic_fetch_xor(int, atomic_t *); int atomic_cmpxchg(atomic_t *, int, int); int atomic_xchg(atomic_t *, int); int __atomic_add_unless(atomic_t *, int, int); @@ -35,7 +36,15 @@ void atomic_set(atomic_t *, int); #define atomic_inc(v) ((void)atomic_add_return( 1, (v))) #define atomic_dec(v) ((void)atomic_add_return( -1, (v))) +#define atomic_fetch_or atomic_fetch_or + +#define atomic_and(i, v) ((void)atomic_fetch_and((i), (v))) +#define atomic_or(i, v) ((void)atomic_fetch_or((i), (v))) +#define atomic_xor(i, v) ((void)atomic_fetch_xor((i), (v))) + #define atomic_sub_return(i, v) (atomic_add_return(-(int)(i), (v))) +#define atomic_fetch_sub(i, v) (atomic_fetch_add (-(int)(i), (v))) + #define atomic_inc_return(v) (atomic_add_return( 1, (v))) #define atomic_dec_return(v) (atomic_add_return( -1, (v))) diff --git a/arch/sparc/include/asm/atomic_64.h b/arch/sparc/include/asm/atomic_64.h index f2fbf9e..24827a3 100644 --- a/arch/sparc/include/asm/atomic_64.h +++ b/arch/sparc/include/asm/atomic_64.h @@ -28,16 +28,24 @@ void atomic64_##op(long, atomic64_t *); int atomic_##op##_return(int, atomic_t *); \ long atomic64_##op##_return(long, atomic64_t *); -#define ATOMIC_OPS(op) ATOMIC_OP(op) ATOMIC_OP_RETURN(op) +#define ATOMIC_FETCH_OP(op) \ +int atomic_fetch_##op(int, atomic_t *); \ +long atomic64_fetch_##op(long, atomic64_t *); + +#define ATOMIC_OPS(op) ATOMIC_OP(op) ATOMIC_OP_RETURN(op) ATOMIC_FETCH_OP(op) ATOMIC_OPS(add) ATOMIC_OPS(sub) -ATOMIC_OP(and) -ATOMIC_OP(or) -ATOMIC_OP(xor) +#undef ATOMIC_OPS +#define ATOMIC_OPS(op) ATOMIC_OP(op) ATOMIC_FETCH_OP(op) + +ATOMIC_OPS(and) +ATOMIC_OPS(or) +ATOMIC_OPS(xor) #undef ATOMIC_OPS +#undef ATOMIC_FETCH_OP #undef ATOMIC_OP_RETURN #undef ATOMIC_OP diff --git a/arch/sparc/lib/atomic32.c b/arch/sparc/lib/atomic32.c index b9d63c0..2c37332 100644 --- a/arch/sparc/lib/atomic32.c +++ b/arch/sparc/lib/atomic32.c @@ -27,39 +27,44 @@ static DEFINE_SPINLOCK(dummy); #endif /* SMP */ -#define ATOMIC_OP_RETURN(op, c_op) \ -int atomic_##op##_return(int i, atomic_t *v) \ +#define ATOMIC_FETCH_OP(op, c_op) \ +int atomic_fetch_##op(int i, atomic_t *v) \ { \ int ret; \ unsigned long flags; \ spin_lock_irqsave(ATOMIC_HASH(v), flags); \ \ - ret = (v->counter c_op i); \ + ret = v->counter; \ + v->counter c_op i; \ \ spin_unlock_irqrestore(ATOMIC_HASH(v), flags); \ return ret; \ } \ -EXPORT_SYMBOL(atomic_##op##_return); +EXPORT_SYMBOL(atomic_fetch_##op); -#define ATOMIC_OP(op, c_op) \ -void atomic_##op(int i, atomic_t *v) \ +#define ATOMIC_OP_RETURN(op, c_op) \ +int atomic_##op##_return(int i, atomic_t *v) \ { \ + int ret; \ unsigned long flags; \ spin_lock_irqsave(ATOMIC_HASH(v), flags); \ \ - v->counter c_op i; \ + ret = (v->counter c_op i); \ \ spin_unlock_irqrestore(ATOMIC_HASH(v), flags); \ + return ret; \ } \ -EXPORT_SYMBOL(atomic_##op); +EXPORT_SYMBOL(atomic_##op##_return); ATOMIC_OP_RETURN(add, +=) -ATOMIC_OP(and, &=) -ATOMIC_OP(or, |=) -ATOMIC_OP(xor, ^=) +ATOMIC_FETCH_OP(add, +=) +ATOMIC_FETCH_OP(and, &=) +ATOMIC_FETCH_OP(or, |=) +ATOMIC_FETCH_OP(xor, ^=) + +#undef ATOMIC_FETCH_OP #undef ATOMIC_OP_RETURN -#undef ATOMIC_OP int atomic_xchg(atomic_t *v, int new) { diff --git a/arch/sparc/lib/atomic_64.S b/arch/sparc/lib/atomic_64.S index d6b0363..a5c5a02 100644 --- a/arch/sparc/lib/atomic_64.S +++ b/arch/sparc/lib/atomic_64.S @@ -9,10 +9,11 @@ .text - /* Two versions of the atomic routines, one that + /* Three versions of the atomic routines, one that * does not return a value and does not perform - * memory barriers, and a second which returns - * a value and does the barriers. + * memory barriers, and a two which return + * a value, the new and old value resp. and does the + * barriers. */ #define ATOMIC_OP(op) \ @@ -43,15 +44,34 @@ ENTRY(atomic_##op##_return) /* %o0 = increment, %o1 = atomic_ptr */ \ 2: BACKOFF_SPIN(%o2, %o3, 1b); \ ENDPROC(atomic_##op##_return); -#define ATOMIC_OPS(op) ATOMIC_OP(op) ATOMIC_OP_RETURN(op) +#define ATOMIC_FETCH_OP(op) \ +ENTRY(atomic_fetch_##op) /* %o0 = increment, %o1 = atomic_ptr */ \ + BACKOFF_SETUP(%o2); \ +1: lduw [%o1], %g1; \ + op %g1, %o0, %g7; \ + cas [%o1], %g1, %g7; \ + cmp %g1, %g7; \ + bne,pn %icc, BACKOFF_LABEL(2f, 1b); \ + nop; \ + retl; \ + sra %g1, 0, %o0; \ +2: BACKOFF_SPIN(%o2, %o3, 1b); \ +ENDPROC(atomic_fetch_##op); + +#define ATOMIC_OPS(op) ATOMIC_OP(op) ATOMIC_OP_RETURN(op) ATOMIC_FETCH_OP(op) ATOMIC_OPS(add) ATOMIC_OPS(sub) -ATOMIC_OP(and) -ATOMIC_OP(or) -ATOMIC_OP(xor) #undef ATOMIC_OPS +#define ATOMIC_OPS(op) ATOMIC_OP(op) ATOMIC_FETCH_OP(op) + +ATOMIC_OPS(and) +ATOMIC_OPS(or) +ATOMIC_OPS(xor) + +#undef ATOMIC_OPS +#undef ATOMIC_FETCH_OP #undef ATOMIC_OP_RETURN #undef ATOMIC_OP @@ -83,15 +103,34 @@ ENTRY(atomic64_##op##_return) /* %o0 = increment, %o1 = atomic_ptr */ \ 2: BACKOFF_SPIN(%o2, %o3, 1b); \ ENDPROC(atomic64_##op##_return); -#define ATOMIC64_OPS(op) ATOMIC64_OP(op) ATOMIC64_OP_RETURN(op) +#define ATOMIC64_FETCH_OP(op) \ +ENTRY(atomic64_fetch_##op) /* %o0 = increment, %o1 = atomic_ptr */ \ + BACKOFF_SETUP(%o2); \ +1: ldx [%o1], %g1; \ + op %g1, %o0, %g7; \ + casx [%o1], %g1, %g7; \ + cmp %g1, %g7; \ + bne,pn %xcc, BACKOFF_LABEL(2f, 1b); \ + nop; \ + retl; \ + mov %g1, %o0; \ +2: BACKOFF_SPIN(%o2, %o3, 1b); \ +ENDPROC(atomic64_fetch_##op); + +#define ATOMIC64_OPS(op) ATOMIC64_OP(op) ATOMIC64_OP_RETURN(op) ATOMIC64_FETCH_OP(op) ATOMIC64_OPS(add) ATOMIC64_OPS(sub) -ATOMIC64_OP(and) -ATOMIC64_OP(or) -ATOMIC64_OP(xor) #undef ATOMIC64_OPS +#define ATOMIC64_OPS(op) ATOMIC64_OP(op) ATOMIC64_FETCH_OP(op) + +ATOMIC64_OPS(and) +ATOMIC64_OPS(or) +ATOMIC64_OPS(xor) + +#undef ATOMIC64_OPS +#undef ATOMIC64_FETCH_OP #undef ATOMIC64_OP_RETURN #undef ATOMIC64_OP diff --git a/arch/sparc/lib/ksyms.c b/arch/sparc/lib/ksyms.c index 8eb454c..de5e978 100644 --- a/arch/sparc/lib/ksyms.c +++ b/arch/sparc/lib/ksyms.c @@ -107,15 +107,24 @@ EXPORT_SYMBOL(atomic64_##op); EXPORT_SYMBOL(atomic_##op##_return); \ EXPORT_SYMBOL(atomic64_##op##_return); -#define ATOMIC_OPS(op) ATOMIC_OP(op) ATOMIC_OP_RETURN(op) +#define ATOMIC_FETCH_OP(op) \ +EXPORT_SYMBOL(atomic_fetch_##op); \ +EXPORT_SYMBOL(atomic64_fetch_##op); + +#define ATOMIC_OPS(op) ATOMIC_OP(op) ATOMIC_OP_RETURN(op) ATOMIC_FETCH_OP(op) ATOMIC_OPS(add) ATOMIC_OPS(sub) -ATOMIC_OP(and) -ATOMIC_OP(or) -ATOMIC_OP(xor) #undef ATOMIC_OPS +#define ATOMIC_OPS(op) ATOMIC_OP(op) ATOMIC_FETCH_OP(op) + +ATOMIC_OPS(and) +ATOMIC_OPS(or) +ATOMIC_OPS(xor) + +#undef ATOMIC_OPS +#undef ATOMIC_FETCH_OP #undef ATOMIC_OP_RETURN #undef ATOMIC_OP -- cgit v0.10.2 From 1af5de9af138941fb8638cf126293b16f3387de4 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Mon, 18 Apr 2016 01:16:03 +0200 Subject: locking/atomic, arch/tile: Implement atomic{,64}_fetch_{add,sub,and,or,xor}() Implement FETCH-OP atomic primitives, these are very similar to the existing OP-RETURN primitives we already have, except they return the value of the atomic variable _before_ modification. This is especially useful for irreversible operations -- such as bitops (because it becomes impossible to reconstruct the state prior to modification). Signed-off-by: Peter Zijlstra (Intel) Acked-by: Chris Metcalf Cc: Andrew Morton Cc: Linus Torvalds Cc: Paul E. McKenney Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: linux-arch@vger.kernel.org Cc: linux-kernel@vger.kernel.org Signed-off-by: Ingo Molnar diff --git a/arch/tile/include/asm/atomic.h b/arch/tile/include/asm/atomic.h index 9fc0107..9807030 100644 --- a/arch/tile/include/asm/atomic.h +++ b/arch/tile/include/asm/atomic.h @@ -46,6 +46,10 @@ static inline int atomic_read(const atomic_t *v) */ #define atomic_sub_return(i, v) atomic_add_return((int)(-(i)), (v)) +#define atomic_fetch_sub(i, v) atomic_fetch_add(-(int)(i), (v)) + +#define atomic_fetch_or atomic_fetch_or + /** * atomic_sub - subtract integer from atomic variable * @i: integer value to subtract diff --git a/arch/tile/include/asm/atomic_32.h b/arch/tile/include/asm/atomic_32.h index d320ce2..da8eb4e 100644 --- a/arch/tile/include/asm/atomic_32.h +++ b/arch/tile/include/asm/atomic_32.h @@ -34,18 +34,29 @@ static inline void atomic_add(int i, atomic_t *v) _atomic_xchg_add(&v->counter, i); } -#define ATOMIC_OP(op) \ -unsigned long _atomic_##op(volatile unsigned long *p, unsigned long mask); \ +#define ATOMIC_OPS(op) \ +unsigned long _atomic_fetch_##op(volatile unsigned long *p, unsigned long mask); \ static inline void atomic_##op(int i, atomic_t *v) \ { \ - _atomic_##op((unsigned long *)&v->counter, i); \ + _atomic_fetch_##op((unsigned long *)&v->counter, i); \ +} \ +static inline int atomic_fetch_##op(int i, atomic_t *v) \ +{ \ + smp_mb(); \ + return _atomic_fetch_##op((unsigned long *)&v->counter, i); \ } -ATOMIC_OP(and) -ATOMIC_OP(or) -ATOMIC_OP(xor) +ATOMIC_OPS(and) +ATOMIC_OPS(or) +ATOMIC_OPS(xor) + +#undef ATOMIC_OPS -#undef ATOMIC_OP +static inline int atomic_fetch_add(int i, atomic_t *v) +{ + smp_mb(); + return _atomic_xchg_add(&v->counter, i); +} /** * atomic_add_return - add integer and return @@ -126,17 +137,30 @@ static inline void atomic64_add(long long i, atomic64_t *v) _atomic64_xchg_add(&v->counter, i); } -#define ATOMIC64_OP(op) \ -long long _atomic64_##op(long long *v, long long n); \ +#define ATOMIC64_OPS(op) \ +long long _atomic64_fetch_##op(long long *v, long long n); \ +static inline void atomic64_##op(long long i, atomic64_t *v) \ +{ \ + _atomic64_fetch_##op(&v->counter, i); \ +} \ static inline void atomic64_##op(long long i, atomic64_t *v) \ { \ - _atomic64_##op(&v->counter, i); \ + smp_mb(); \ + return _atomic64_fetch_##op(&v->counter, i); \ } ATOMIC64_OP(and) ATOMIC64_OP(or) ATOMIC64_OP(xor) +#undef ATOMIC64_OPS + +static inline long long atomic64_fetch_add(long long i, atomic64_t *v) +{ + smp_mb(); + return _atomic64_xchg_add(&v->counter, i); +} + /** * atomic64_add_return - add integer and return * @v: pointer of type atomic64_t @@ -186,6 +210,7 @@ static inline void atomic64_set(atomic64_t *v, long long n) #define atomic64_inc_return(v) atomic64_add_return(1LL, (v)) #define atomic64_inc_and_test(v) (atomic64_inc_return(v) == 0) #define atomic64_sub_return(i, v) atomic64_add_return(-(i), (v)) +#define atomic64_fetch_sub(i, v) atomic64_fetch_add(-(i), (v)) #define atomic64_sub_and_test(a, v) (atomic64_sub_return((a), (v)) == 0) #define atomic64_sub(i, v) atomic64_add(-(i), (v)) #define atomic64_dec(v) atomic64_sub(1LL, (v)) @@ -193,7 +218,6 @@ static inline void atomic64_set(atomic64_t *v, long long n) #define atomic64_dec_and_test(v) (atomic64_dec_return((v)) == 0) #define atomic64_inc_not_zero(v) atomic64_add_unless((v), 1LL, 0LL) - #endif /* !__ASSEMBLY__ */ /* @@ -248,10 +272,10 @@ extern struct __get_user __atomic_xchg(volatile int *p, int *lock, int n); extern struct __get_user __atomic_xchg_add(volatile int *p, int *lock, int n); extern struct __get_user __atomic_xchg_add_unless(volatile int *p, int *lock, int o, int n); -extern struct __get_user __atomic_or(volatile int *p, int *lock, int n); -extern struct __get_user __atomic_and(volatile int *p, int *lock, int n); -extern struct __get_user __atomic_andn(volatile int *p, int *lock, int n); -extern struct __get_user __atomic_xor(volatile int *p, int *lock, int n); +extern struct __get_user __atomic_fetch_or(volatile int *p, int *lock, int n); +extern struct __get_user __atomic_fetch_and(volatile int *p, int *lock, int n); +extern struct __get_user __atomic_fetch_andn(volatile int *p, int *lock, int n); +extern struct __get_user __atomic_fetch_xor(volatile int *p, int *lock, int n); extern long long __atomic64_cmpxchg(volatile long long *p, int *lock, long long o, long long n); extern long long __atomic64_xchg(volatile long long *p, int *lock, long long n); @@ -259,9 +283,9 @@ extern long long __atomic64_xchg_add(volatile long long *p, int *lock, long long n); extern long long __atomic64_xchg_add_unless(volatile long long *p, int *lock, long long o, long long n); -extern long long __atomic64_and(volatile long long *p, int *lock, long long n); -extern long long __atomic64_or(volatile long long *p, int *lock, long long n); -extern long long __atomic64_xor(volatile long long *p, int *lock, long long n); +extern long long __atomic64_fetch_and(volatile long long *p, int *lock, long long n); +extern long long __atomic64_fetch_or(volatile long long *p, int *lock, long long n); +extern long long __atomic64_fetch_xor(volatile long long *p, int *lock, long long n); /* Return failure from the atomic wrappers. */ struct __get_user __atomic_bad_address(int __user *addr); diff --git a/arch/tile/include/asm/atomic_64.h b/arch/tile/include/asm/atomic_64.h index b0531a6..4cefa0c 100644 --- a/arch/tile/include/asm/atomic_64.h +++ b/arch/tile/include/asm/atomic_64.h @@ -32,11 +32,6 @@ * on any routine which updates memory and returns a value. */ -static inline void atomic_add(int i, atomic_t *v) -{ - __insn_fetchadd4((void *)&v->counter, i); -} - /* * Note a subtlety of the locking here. We are required to provide a * full memory barrier before and after the operation. However, we @@ -59,28 +54,39 @@ static inline int atomic_add_return(int i, atomic_t *v) return val; } -static inline int __atomic_add_unless(atomic_t *v, int a, int u) +#define ATOMIC_OPS(op) \ +static inline int atomic_fetch_##op(int i, atomic_t *v) \ +{ \ + int val; \ + smp_mb(); \ + val = __insn_fetch##op##4((void *)&v->counter, i); \ + smp_mb(); \ + return val; \ +} \ +static inline void atomic_##op(int i, atomic_t *v) \ +{ \ + __insn_fetch##op##4((void *)&v->counter, i); \ +} + +ATOMIC_OPS(add) +ATOMIC_OPS(and) +ATOMIC_OPS(or) + +#undef ATOMIC_OPS + +static inline int atomic_fetch_xor(int i, atomic_t *v) { int guess, oldval = v->counter; + smp_mb(); do { - if (oldval == u) - break; guess = oldval; - oldval = cmpxchg(&v->counter, guess, guess + a); + __insn_mtspr(SPR_CMPEXCH_VALUE, guess); + oldval = __insn_cmpexch4(&v->counter, guess ^ i); } while (guess != oldval); + smp_mb(); return oldval; } -static inline void atomic_and(int i, atomic_t *v) -{ - __insn_fetchand4((void *)&v->counter, i); -} - -static inline void atomic_or(int i, atomic_t *v) -{ - __insn_fetchor4((void *)&v->counter, i); -} - static inline void atomic_xor(int i, atomic_t *v) { int guess, oldval = v->counter; @@ -91,6 +97,18 @@ static inline void atomic_xor(int i, atomic_t *v) } while (guess != oldval); } +static inline int __atomic_add_unless(atomic_t *v, int a, int u) +{ + int guess, oldval = v->counter; + do { + if (oldval == u) + break; + guess = oldval; + oldval = cmpxchg(&v->counter, guess, guess + a); + } while (guess != oldval); + return oldval; +} + /* Now the true 64-bit operations. */ #define ATOMIC64_INIT(i) { (i) } @@ -98,11 +116,6 @@ static inline void atomic_xor(int i, atomic_t *v) #define atomic64_read(v) READ_ONCE((v)->counter) #define atomic64_set(v, i) WRITE_ONCE((v)->counter, (i)) -static inline void atomic64_add(long i, atomic64_t *v) -{ - __insn_fetchadd((void *)&v->counter, i); -} - static inline long atomic64_add_return(long i, atomic64_t *v) { int val; @@ -112,26 +125,37 @@ static inline long atomic64_add_return(long i, atomic64_t *v) return val; } -static inline long atomic64_add_unless(atomic64_t *v, long a, long u) +#define ATOMIC64_OPS(op) \ +static inline long atomic64_fetch_##op(long i, atomic64_t *v) \ +{ \ + long val; \ + smp_mb(); \ + val = __insn_fetch##op((void *)&v->counter, i); \ + smp_mb(); \ + return val; \ +} \ +static inline void atomic64_##op(long i, atomic64_t *v) \ +{ \ + __insn_fetch##op((void *)&v->counter, i); \ +} + +ATOMIC64_OPS(add) +ATOMIC64_OPS(and) +ATOMIC64_OPS(or) + +#undef ATOMIC64_OPS + +static inline long atomic64_fetch_xor(long i, atomic64_t *v) { long guess, oldval = v->counter; + smp_mb(); do { - if (oldval == u) - break; guess = oldval; - oldval = cmpxchg(&v->counter, guess, guess + a); + __insn_mtspr(SPR_CMPEXCH_VALUE, guess); + oldval = __insn_cmpexch(&v->counter, guess ^ i); } while (guess != oldval); - return oldval != u; -} - -static inline void atomic64_and(long i, atomic64_t *v) -{ - __insn_fetchand((void *)&v->counter, i); -} - -static inline void atomic64_or(long i, atomic64_t *v) -{ - __insn_fetchor((void *)&v->counter, i); + smp_mb(); + return oldval; } static inline void atomic64_xor(long i, atomic64_t *v) @@ -144,7 +168,20 @@ static inline void atomic64_xor(long i, atomic64_t *v) } while (guess != oldval); } +static inline long atomic64_add_unless(atomic64_t *v, long a, long u) +{ + long guess, oldval = v->counter; + do { + if (oldval == u) + break; + guess = oldval; + oldval = cmpxchg(&v->counter, guess, guess + a); + } while (guess != oldval); + return oldval != u; +} + #define atomic64_sub_return(i, v) atomic64_add_return(-(i), (v)) +#define atomic64_fetch_sub(i, v) atomic64_fetch_add(-(i), (v)) #define atomic64_sub(i, v) atomic64_add(-(i), (v)) #define atomic64_inc_return(v) atomic64_add_return(1, (v)) #define atomic64_dec_return(v) atomic64_sub_return(1, (v)) diff --git a/arch/tile/include/asm/bitops_32.h b/arch/tile/include/asm/bitops_32.h index bbf7b66..d1406a9 100644 --- a/arch/tile/include/asm/bitops_32.h +++ b/arch/tile/include/asm/bitops_32.h @@ -19,9 +19,9 @@ #include /* Tile-specific routines to support . */ -unsigned long _atomic_or(volatile unsigned long *p, unsigned long mask); -unsigned long _atomic_andn(volatile unsigned long *p, unsigned long mask); -unsigned long _atomic_xor(volatile unsigned long *p, unsigned long mask); +unsigned long _atomic_fetch_or(volatile unsigned long *p, unsigned long mask); +unsigned long _atomic_fetch_andn(volatile unsigned long *p, unsigned long mask); +unsigned long _atomic_fetch_xor(volatile unsigned long *p, unsigned long mask); /** * set_bit - Atomically set a bit in memory @@ -35,7 +35,7 @@ unsigned long _atomic_xor(volatile unsigned long *p, unsigned long mask); */ static inline void set_bit(unsigned nr, volatile unsigned long *addr) { - _atomic_or(addr + BIT_WORD(nr), BIT_MASK(nr)); + _atomic_fetch_or(addr + BIT_WORD(nr), BIT_MASK(nr)); } /** @@ -54,7 +54,7 @@ static inline void set_bit(unsigned nr, volatile unsigned long *addr) */ static inline void clear_bit(unsigned nr, volatile unsigned long *addr) { - _atomic_andn(addr + BIT_WORD(nr), BIT_MASK(nr)); + _atomic_fetch_andn(addr + BIT_WORD(nr), BIT_MASK(nr)); } /** @@ -69,7 +69,7 @@ static inline void clear_bit(unsigned nr, volatile unsigned long *addr) */ static inline void change_bit(unsigned nr, volatile unsigned long *addr) { - _atomic_xor(addr + BIT_WORD(nr), BIT_MASK(nr)); + _atomic_fetch_xor(addr + BIT_WORD(nr), BIT_MASK(nr)); } /** @@ -85,7 +85,7 @@ static inline int test_and_set_bit(unsigned nr, volatile unsigned long *addr) unsigned long mask = BIT_MASK(nr); addr += BIT_WORD(nr); smp_mb(); /* barrier for proper semantics */ - return (_atomic_or(addr, mask) & mask) != 0; + return (_atomic_fetch_or(addr, mask) & mask) != 0; } /** @@ -101,7 +101,7 @@ static inline int test_and_clear_bit(unsigned nr, volatile unsigned long *addr) unsigned long mask = BIT_MASK(nr); addr += BIT_WORD(nr); smp_mb(); /* barrier for proper semantics */ - return (_atomic_andn(addr, mask) & mask) != 0; + return (_atomic_fetch_andn(addr, mask) & mask) != 0; } /** @@ -118,7 +118,7 @@ static inline int test_and_change_bit(unsigned nr, unsigned long mask = BIT_MASK(nr); addr += BIT_WORD(nr); smp_mb(); /* barrier for proper semantics */ - return (_atomic_xor(addr, mask) & mask) != 0; + return (_atomic_fetch_xor(addr, mask) & mask) != 0; } #include diff --git a/arch/tile/lib/atomic_32.c b/arch/tile/lib/atomic_32.c index 298df1e..5b6bd93 100644 --- a/arch/tile/lib/atomic_32.c +++ b/arch/tile/lib/atomic_32.c @@ -88,29 +88,29 @@ int _atomic_cmpxchg(int *v, int o, int n) } EXPORT_SYMBOL(_atomic_cmpxchg); -unsigned long _atomic_or(volatile unsigned long *p, unsigned long mask) +unsigned long _atomic_fetch_or(volatile unsigned long *p, unsigned long mask) { - return __atomic_or((int *)p, __atomic_setup(p), mask).val; + return __atomic_fetch_or((int *)p, __atomic_setup(p), mask).val; } -EXPORT_SYMBOL(_atomic_or); +EXPORT_SYMBOL(_atomic_fetch_or); -unsigned long _atomic_and(volatile unsigned long *p, unsigned long mask) +unsigned long _atomic_fetch_and(volatile unsigned long *p, unsigned long mask) { - return __atomic_and((int *)p, __atomic_setup(p), mask).val; + return __atomic_fetch_and((int *)p, __atomic_setup(p), mask).val; } -EXPORT_SYMBOL(_atomic_and); +EXPORT_SYMBOL(_atomic_fetch_and); -unsigned long _atomic_andn(volatile unsigned long *p, unsigned long mask) +unsigned long _atomic_fetch_andn(volatile unsigned long *p, unsigned long mask) { - return __atomic_andn((int *)p, __atomic_setup(p), mask).val; + return __atomic_fetch_andn((int *)p, __atomic_setup(p), mask).val; } -EXPORT_SYMBOL(_atomic_andn); +EXPORT_SYMBOL(_atomic_fetch_andn); -unsigned long _atomic_xor(volatile unsigned long *p, unsigned long mask) +unsigned long _atomic_fetch_xor(volatile unsigned long *p, unsigned long mask) { - return __atomic_xor((int *)p, __atomic_setup(p), mask).val; + return __atomic_fetch_xor((int *)p, __atomic_setup(p), mask).val; } -EXPORT_SYMBOL(_atomic_xor); +EXPORT_SYMBOL(_atomic_fetch_xor); long long _atomic64_xchg(long long *v, long long n) @@ -142,23 +142,23 @@ long long _atomic64_cmpxchg(long long *v, long long o, long long n) } EXPORT_SYMBOL(_atomic64_cmpxchg); -long long _atomic64_and(long long *v, long long n) +long long _atomic64_fetch_and(long long *v, long long n) { - return __atomic64_and(v, __atomic_setup(v), n); + return __atomic64_fetch_and(v, __atomic_setup(v), n); } -EXPORT_SYMBOL(_atomic64_and); +EXPORT_SYMBOL(_atomic64_fetch_and); -long long _atomic64_or(long long *v, long long n) +long long _atomic64_fetch_or(long long *v, long long n) { - return __atomic64_or(v, __atomic_setup(v), n); + return __atomic64_fetch_or(v, __atomic_setup(v), n); } -EXPORT_SYMBOL(_atomic64_or); +EXPORT_SYMBOL(_atomic64_fetch_or); -long long _atomic64_xor(long long *v, long long n) +long long _atomic64_fetch_xor(long long *v, long long n) { - return __atomic64_xor(v, __atomic_setup(v), n); + return __atomic64_fetch_xor(v, __atomic_setup(v), n); } -EXPORT_SYMBOL(_atomic64_xor); +EXPORT_SYMBOL(_atomic64_fetch_xor); /* * If any of the atomic or futex routines hit a bad address (not in diff --git a/arch/tile/lib/atomic_asm_32.S b/arch/tile/lib/atomic_asm_32.S index f611265..507abdd 100644 --- a/arch/tile/lib/atomic_asm_32.S +++ b/arch/tile/lib/atomic_asm_32.S @@ -177,10 +177,10 @@ atomic_op _xchg, 32, "move r24, r2" atomic_op _xchg_add, 32, "add r24, r22, r2" atomic_op _xchg_add_unless, 32, \ "sne r26, r22, r2; { bbns r26, 3f; add r24, r22, r3 }" -atomic_op _or, 32, "or r24, r22, r2" -atomic_op _and, 32, "and r24, r22, r2" -atomic_op _andn, 32, "nor r2, r2, zero; and r24, r22, r2" -atomic_op _xor, 32, "xor r24, r22, r2" +atomic_op _fetch_or, 32, "or r24, r22, r2" +atomic_op _fetch_and, 32, "and r24, r22, r2" +atomic_op _fetch_andn, 32, "nor r2, r2, zero; and r24, r22, r2" +atomic_op _fetch_xor, 32, "xor r24, r22, r2" atomic_op 64_cmpxchg, 64, "{ seq r26, r22, r2; seq r27, r23, r3 }; \ { bbns r26, 3f; move r24, r4 }; { bbns r27, 3f; move r25, r5 }" @@ -192,9 +192,9 @@ atomic_op 64_xchg_add_unless, 64, \ { bbns r26, 3f; add r24, r22, r4 }; \ { bbns r27, 3f; add r25, r23, r5 }; \ slt_u r26, r24, r22; add r25, r25, r26" -atomic_op 64_or, 64, "{ or r24, r22, r2; or r25, r23, r3 }" -atomic_op 64_and, 64, "{ and r24, r22, r2; and r25, r23, r3 }" -atomic_op 64_xor, 64, "{ xor r24, r22, r2; xor r25, r23, r3 }" +atomic_op 64_fetch_or, 64, "{ or r24, r22, r2; or r25, r23, r3 }" +atomic_op 64_fetch_and, 64, "{ and r24, r22, r2; and r25, r23, r3 }" +atomic_op 64_fetch_xor, 64, "{ xor r24, r22, r2; xor r25, r23, r3 }" jrp lr /* happy backtracer */ -- cgit v0.10.2 From a8bcccaba162632c3963259b8a442c6b490f4c68 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Mon, 18 Apr 2016 01:16:03 +0200 Subject: locking/atomic, arch/x86: Implement atomic{,64}_fetch_{add,sub,and,or,xor}() Implement FETCH-OP atomic primitives, these are very similar to the existing OP-RETURN primitives we already have, except they return the value of the atomic variable _before_ modification. This is especially useful for irreversible operations -- such as bitops (because it becomes impossible to reconstruct the state prior to modification). Signed-off-by: Peter Zijlstra (Intel) Cc: Andrew Morton Cc: Linus Torvalds Cc: Paul E. McKenney Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: linux-arch@vger.kernel.org Cc: linux-kernel@vger.kernel.org Signed-off-by: Ingo Molnar diff --git a/arch/x86/include/asm/atomic.h b/arch/x86/include/asm/atomic.h index 3e86742..73b8463 100644 --- a/arch/x86/include/asm/atomic.h +++ b/arch/x86/include/asm/atomic.h @@ -171,6 +171,16 @@ static __always_inline int atomic_sub_return(int i, atomic_t *v) #define atomic_inc_return(v) (atomic_add_return(1, v)) #define atomic_dec_return(v) (atomic_sub_return(1, v)) +static __always_inline int atomic_fetch_add(int i, atomic_t *v) +{ + return xadd(&v->counter, i); +} + +static __always_inline int atomic_fetch_sub(int i, atomic_t *v) +{ + return xadd(&v->counter, -i); +} + static __always_inline int atomic_cmpxchg(atomic_t *v, int old, int new) { return cmpxchg(&v->counter, old, new); @@ -190,10 +200,31 @@ static inline void atomic_##op(int i, atomic_t *v) \ : "memory"); \ } -ATOMIC_OP(and) -ATOMIC_OP(or) -ATOMIC_OP(xor) +#define ATOMIC_FETCH_OP(op, c_op) \ +static inline int atomic_fetch_##op(int i, atomic_t *v) \ +{ \ + int old, val = atomic_read(v); \ + for (;;) { \ + old = atomic_cmpxchg(v, val, val c_op i); \ + if (old == val) \ + break; \ + val = old; \ + } \ + return old; \ +} + +#define ATOMIC_OPS(op, c_op) \ + ATOMIC_OP(op) \ + ATOMIC_FETCH_OP(op, c_op) + +#define atomic_fetch_or atomic_fetch_or + +ATOMIC_OPS(and, &) +ATOMIC_OPS(or , |) +ATOMIC_OPS(xor, ^) +#undef ATOMIC_OPS +#undef ATOMIC_FETCH_OP #undef ATOMIC_OP /** diff --git a/arch/x86/include/asm/atomic64_32.h b/arch/x86/include/asm/atomic64_32.h index a984111..71d7705 100644 --- a/arch/x86/include/asm/atomic64_32.h +++ b/arch/x86/include/asm/atomic64_32.h @@ -320,10 +320,29 @@ static inline void atomic64_##op(long long i, atomic64_t *v) \ c = old; \ } -ATOMIC64_OP(and, &) -ATOMIC64_OP(or, |) -ATOMIC64_OP(xor, ^) +#define ATOMIC64_FETCH_OP(op, c_op) \ +static inline long long atomic64_fetch_##op(long long i, atomic64_t *v) \ +{ \ + long long old, c = 0; \ + while ((old = atomic64_cmpxchg(v, c, c c_op i)) != c) \ + c = old; \ + return old; \ +} + +ATOMIC64_FETCH_OP(add, +) + +#define atomic64_fetch_sub(i, v) atomic64_fetch_add(-(i), (v)) + +#define ATOMIC64_OPS(op, c_op) \ + ATOMIC64_OP(op, c_op) \ + ATOMIC64_FETCH_OP(op, c_op) + +ATOMIC64_OPS(and, &) +ATOMIC64_OPS(or, |) +ATOMIC64_OPS(xor, ^) +#undef ATOMIC64_OPS +#undef ATOMIC64_FETCH_OP #undef ATOMIC64_OP #endif /* _ASM_X86_ATOMIC64_32_H */ diff --git a/arch/x86/include/asm/atomic64_64.h b/arch/x86/include/asm/atomic64_64.h index 0373510..70eed0e 100644 --- a/arch/x86/include/asm/atomic64_64.h +++ b/arch/x86/include/asm/atomic64_64.h @@ -158,6 +158,16 @@ static inline long atomic64_sub_return(long i, atomic64_t *v) return atomic64_add_return(-i, v); } +static inline long atomic64_fetch_add(long i, atomic64_t *v) +{ + return xadd(&v->counter, i); +} + +static inline long atomic64_fetch_sub(long i, atomic64_t *v) +{ + return xadd(&v->counter, -i); +} + #define atomic64_inc_return(v) (atomic64_add_return(1, (v))) #define atomic64_dec_return(v) (atomic64_sub_return(1, (v))) @@ -229,10 +239,29 @@ static inline void atomic64_##op(long i, atomic64_t *v) \ : "memory"); \ } -ATOMIC64_OP(and) -ATOMIC64_OP(or) -ATOMIC64_OP(xor) +#define ATOMIC64_FETCH_OP(op, c_op) \ +static inline long atomic64_fetch_##op(long i, atomic64_t *v) \ +{ \ + long old, val = atomic64_read(v); \ + for (;;) { \ + old = atomic64_cmpxchg(v, val, val c_op i); \ + if (old == val) \ + break; \ + val = old; \ + } \ + return old; \ +} + +#define ATOMIC64_OPS(op, c_op) \ + ATOMIC64_OP(op) \ + ATOMIC64_FETCH_OP(op, c_op) + +ATOMIC64_OPS(and, &) +ATOMIC64_OPS(or, |) +ATOMIC64_OPS(xor, ^) +#undef ATOMIC64_OPS +#undef ATOMIC64_FETCH_OP #undef ATOMIC64_OP #endif /* _ASM_X86_ATOMIC64_64_H */ -- cgit v0.10.2 From 6dc25876cdb17fd3906504dcabb9e537f8433000 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Mon, 18 Apr 2016 01:16:03 +0200 Subject: locking/atomic, arch/xtensa: Implement atomic_fetch_{add,sub,and,or,xor}() Implement FETCH-OP atomic primitives, these are very similar to the existing OP-RETURN primitives we already have, except they return the value of the atomic variable _before_ modification. This is especially useful for irreversible operations -- such as bitops (because it becomes impossible to reconstruct the state prior to modification). Signed-off-by: Peter Zijlstra (Intel) Cc: Andrew Morton Cc: Chris Zankel Cc: Linus Torvalds Cc: Max Filippov Cc: Paul E. McKenney Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: linux-arch@vger.kernel.org Cc: linux-kernel@vger.kernel.org Cc: linux-xtensa@linux-xtensa.org Signed-off-by: Ingo Molnar diff --git a/arch/xtensa/include/asm/atomic.h b/arch/xtensa/include/asm/atomic.h index fd8017c..d95a8aa 100644 --- a/arch/xtensa/include/asm/atomic.h +++ b/arch/xtensa/include/asm/atomic.h @@ -98,6 +98,26 @@ static inline int atomic_##op##_return(int i, atomic_t * v) \ return result; \ } +#define ATOMIC_FETCH_OP(op) \ +static inline int atomic_fetch_##op(int i, atomic_t * v) \ +{ \ + unsigned long tmp; \ + int result; \ + \ + __asm__ __volatile__( \ + "1: l32i %1, %3, 0\n" \ + " wsr %1, scompare1\n" \ + " " #op " %0, %1, %2\n" \ + " s32c1i %0, %3, 0\n" \ + " bne %0, %1, 1b\n" \ + : "=&a" (result), "=&a" (tmp) \ + : "a" (i), "a" (v) \ + : "memory" \ + ); \ + \ + return result; \ +} + #else /* XCHAL_HAVE_S32C1I */ #define ATOMIC_OP(op) \ @@ -138,18 +158,44 @@ static inline int atomic_##op##_return(int i, atomic_t * v) \ return vval; \ } +#define ATOMIC_FETCH_OP(op) \ +static inline int atomic_fetch_##op(int i, atomic_t * v) \ +{ \ + unsigned int tmp, vval; \ + \ + __asm__ __volatile__( \ + " rsil a15,"__stringify(TOPLEVEL)"\n" \ + " l32i %0, %3, 0\n" \ + " " #op " %1, %0, %2\n" \ + " s32i %1, %3, 0\n" \ + " wsr a15, ps\n" \ + " rsync\n" \ + : "=&a" (vval), "=&a" (tmp) \ + : "a" (i), "a" (v) \ + : "a15", "memory" \ + ); \ + \ + return vval; \ +} + #endif /* XCHAL_HAVE_S32C1I */ -#define ATOMIC_OPS(op) ATOMIC_OP(op) ATOMIC_OP_RETURN(op) +#define ATOMIC_OPS(op) ATOMIC_OP(op) ATOMIC_FETCH_OP(op) ATOMIC_OP_RETURN(op) ATOMIC_OPS(add) ATOMIC_OPS(sub) -ATOMIC_OP(and) -ATOMIC_OP(or) -ATOMIC_OP(xor) +#undef ATOMIC_OPS +#define ATOMIC_OPS(op) ATOMIC_OP(op) ATOMIC_FETCH_OP(op) + +#define atomic_fetch_or atomic_fetch_or + +ATOMIC_OPS(and) +ATOMIC_OPS(or) +ATOMIC_OPS(xor) #undef ATOMIC_OPS +#undef ATOMIC_FETCH_OP #undef ATOMIC_OP_RETURN #undef ATOMIC_OP -- cgit v0.10.2 From e12133324b7daaa176bb687c1eb59e1a6b203da4 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Mon, 18 Apr 2016 00:52:13 +0200 Subject: locking/atomic: Fix atomic64_relaxed() bits We should only expand the atomic64 relaxed bits once we've included all relevant headers. So move it down until after we potentially include asm-generic/atomic64.h. In practise this will not have made a difference so far, since the generic bits will not define _relaxed versions. Signed-off-by: Peter Zijlstra (Intel) Cc: Andrew Morton Cc: Davidlohr Bueso Cc: Frederic Weisbecker Cc: Linus Torvalds Cc: Paul E. McKenney Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: Will Deacon Cc: linux-arch@vger.kernel.org Cc: linux-kernel@vger.kernel.org Signed-off-by: Ingo Molnar diff --git a/include/linux/atomic.h b/include/linux/atomic.h index e451534..351f89e 100644 --- a/include/linux/atomic.h +++ b/include/linux/atomic.h @@ -211,159 +211,6 @@ #endif #endif /* atomic_cmpxchg_relaxed */ -#ifndef atomic64_read_acquire -#define atomic64_read_acquire(v) smp_load_acquire(&(v)->counter) -#endif - -#ifndef atomic64_set_release -#define atomic64_set_release(v, i) smp_store_release(&(v)->counter, (i)) -#endif - -/* atomic64_add_return_relaxed */ -#ifndef atomic64_add_return_relaxed -#define atomic64_add_return_relaxed atomic64_add_return -#define atomic64_add_return_acquire atomic64_add_return -#define atomic64_add_return_release atomic64_add_return - -#else /* atomic64_add_return_relaxed */ - -#ifndef atomic64_add_return_acquire -#define atomic64_add_return_acquire(...) \ - __atomic_op_acquire(atomic64_add_return, __VA_ARGS__) -#endif - -#ifndef atomic64_add_return_release -#define atomic64_add_return_release(...) \ - __atomic_op_release(atomic64_add_return, __VA_ARGS__) -#endif - -#ifndef atomic64_add_return -#define atomic64_add_return(...) \ - __atomic_op_fence(atomic64_add_return, __VA_ARGS__) -#endif -#endif /* atomic64_add_return_relaxed */ - -/* atomic64_inc_return_relaxed */ -#ifndef atomic64_inc_return_relaxed -#define atomic64_inc_return_relaxed atomic64_inc_return -#define atomic64_inc_return_acquire atomic64_inc_return -#define atomic64_inc_return_release atomic64_inc_return - -#else /* atomic64_inc_return_relaxed */ - -#ifndef atomic64_inc_return_acquire -#define atomic64_inc_return_acquire(...) \ - __atomic_op_acquire(atomic64_inc_return, __VA_ARGS__) -#endif - -#ifndef atomic64_inc_return_release -#define atomic64_inc_return_release(...) \ - __atomic_op_release(atomic64_inc_return, __VA_ARGS__) -#endif - -#ifndef atomic64_inc_return -#define atomic64_inc_return(...) \ - __atomic_op_fence(atomic64_inc_return, __VA_ARGS__) -#endif -#endif /* atomic64_inc_return_relaxed */ - - -/* atomic64_sub_return_relaxed */ -#ifndef atomic64_sub_return_relaxed -#define atomic64_sub_return_relaxed atomic64_sub_return -#define atomic64_sub_return_acquire atomic64_sub_return -#define atomic64_sub_return_release atomic64_sub_return - -#else /* atomic64_sub_return_relaxed */ - -#ifndef atomic64_sub_return_acquire -#define atomic64_sub_return_acquire(...) \ - __atomic_op_acquire(atomic64_sub_return, __VA_ARGS__) -#endif - -#ifndef atomic64_sub_return_release -#define atomic64_sub_return_release(...) \ - __atomic_op_release(atomic64_sub_return, __VA_ARGS__) -#endif - -#ifndef atomic64_sub_return -#define atomic64_sub_return(...) \ - __atomic_op_fence(atomic64_sub_return, __VA_ARGS__) -#endif -#endif /* atomic64_sub_return_relaxed */ - -/* atomic64_dec_return_relaxed */ -#ifndef atomic64_dec_return_relaxed -#define atomic64_dec_return_relaxed atomic64_dec_return -#define atomic64_dec_return_acquire atomic64_dec_return -#define atomic64_dec_return_release atomic64_dec_return - -#else /* atomic64_dec_return_relaxed */ - -#ifndef atomic64_dec_return_acquire -#define atomic64_dec_return_acquire(...) \ - __atomic_op_acquire(atomic64_dec_return, __VA_ARGS__) -#endif - -#ifndef atomic64_dec_return_release -#define atomic64_dec_return_release(...) \ - __atomic_op_release(atomic64_dec_return, __VA_ARGS__) -#endif - -#ifndef atomic64_dec_return -#define atomic64_dec_return(...) \ - __atomic_op_fence(atomic64_dec_return, __VA_ARGS__) -#endif -#endif /* atomic64_dec_return_relaxed */ - -/* atomic64_xchg_relaxed */ -#ifndef atomic64_xchg_relaxed -#define atomic64_xchg_relaxed atomic64_xchg -#define atomic64_xchg_acquire atomic64_xchg -#define atomic64_xchg_release atomic64_xchg - -#else /* atomic64_xchg_relaxed */ - -#ifndef atomic64_xchg_acquire -#define atomic64_xchg_acquire(...) \ - __atomic_op_acquire(atomic64_xchg, __VA_ARGS__) -#endif - -#ifndef atomic64_xchg_release -#define atomic64_xchg_release(...) \ - __atomic_op_release(atomic64_xchg, __VA_ARGS__) -#endif - -#ifndef atomic64_xchg -#define atomic64_xchg(...) \ - __atomic_op_fence(atomic64_xchg, __VA_ARGS__) -#endif -#endif /* atomic64_xchg_relaxed */ - -/* atomic64_cmpxchg_relaxed */ -#ifndef atomic64_cmpxchg_relaxed -#define atomic64_cmpxchg_relaxed atomic64_cmpxchg -#define atomic64_cmpxchg_acquire atomic64_cmpxchg -#define atomic64_cmpxchg_release atomic64_cmpxchg - -#else /* atomic64_cmpxchg_relaxed */ - -#ifndef atomic64_cmpxchg_acquire -#define atomic64_cmpxchg_acquire(...) \ - __atomic_op_acquire(atomic64_cmpxchg, __VA_ARGS__) -#endif - -#ifndef atomic64_cmpxchg_release -#define atomic64_cmpxchg_release(...) \ - __atomic_op_release(atomic64_cmpxchg, __VA_ARGS__) -#endif - -#ifndef atomic64_cmpxchg -#define atomic64_cmpxchg(...) \ - __atomic_op_fence(atomic64_cmpxchg, __VA_ARGS__) -#endif -#endif /* atomic64_cmpxchg_relaxed */ - /* cmpxchg_relaxed */ #ifndef cmpxchg_relaxed #define cmpxchg_relaxed cmpxchg @@ -583,6 +430,159 @@ static inline int atomic_fetch_or(int mask, atomic_t *p) #include #endif +#ifndef atomic64_read_acquire +#define atomic64_read_acquire(v) smp_load_acquire(&(v)->counter) +#endif + +#ifndef atomic64_set_release +#define atomic64_set_release(v, i) smp_store_release(&(v)->counter, (i)) +#endif + +/* atomic64_add_return_relaxed */ +#ifndef atomic64_add_return_relaxed +#define atomic64_add_return_relaxed atomic64_add_return +#define atomic64_add_return_acquire atomic64_add_return +#define atomic64_add_return_release atomic64_add_return + +#else /* atomic64_add_return_relaxed */ + +#ifndef atomic64_add_return_acquire +#define atomic64_add_return_acquire(...) \ + __atomic_op_acquire(atomic64_add_return, __VA_ARGS__) +#endif + +#ifndef atomic64_add_return_release +#define atomic64_add_return_release(...) \ + __atomic_op_release(atomic64_add_return, __VA_ARGS__) +#endif + +#ifndef atomic64_add_return +#define atomic64_add_return(...) \ + __atomic_op_fence(atomic64_add_return, __VA_ARGS__) +#endif +#endif /* atomic64_add_return_relaxed */ + +/* atomic64_inc_return_relaxed */ +#ifndef atomic64_inc_return_relaxed +#define atomic64_inc_return_relaxed atomic64_inc_return +#define atomic64_inc_return_acquire atomic64_inc_return +#define atomic64_inc_return_release atomic64_inc_return + +#else /* atomic64_inc_return_relaxed */ + +#ifndef atomic64_inc_return_acquire +#define atomic64_inc_return_acquire(...) \ + __atomic_op_acquire(atomic64_inc_return, __VA_ARGS__) +#endif + +#ifndef atomic64_inc_return_release +#define atomic64_inc_return_release(...) \ + __atomic_op_release(atomic64_inc_return, __VA_ARGS__) +#endif + +#ifndef atomic64_inc_return +#define atomic64_inc_return(...) \ + __atomic_op_fence(atomic64_inc_return, __VA_ARGS__) +#endif +#endif /* atomic64_inc_return_relaxed */ + + +/* atomic64_sub_return_relaxed */ +#ifndef atomic64_sub_return_relaxed +#define atomic64_sub_return_relaxed atomic64_sub_return +#define atomic64_sub_return_acquire atomic64_sub_return +#define atomic64_sub_return_release atomic64_sub_return + +#else /* atomic64_sub_return_relaxed */ + +#ifndef atomic64_sub_return_acquire +#define atomic64_sub_return_acquire(...) \ + __atomic_op_acquire(atomic64_sub_return, __VA_ARGS__) +#endif + +#ifndef atomic64_sub_return_release +#define atomic64_sub_return_release(...) \ + __atomic_op_release(atomic64_sub_return, __VA_ARGS__) +#endif + +#ifndef atomic64_sub_return +#define atomic64_sub_return(...) \ + __atomic_op_fence(atomic64_sub_return, __VA_ARGS__) +#endif +#endif /* atomic64_sub_return_relaxed */ + +/* atomic64_dec_return_relaxed */ +#ifndef atomic64_dec_return_relaxed +#define atomic64_dec_return_relaxed atomic64_dec_return +#define atomic64_dec_return_acquire atomic64_dec_return +#define atomic64_dec_return_release atomic64_dec_return + +#else /* atomic64_dec_return_relaxed */ + +#ifndef atomic64_dec_return_acquire +#define atomic64_dec_return_acquire(...) \ + __atomic_op_acquire(atomic64_dec_return, __VA_ARGS__) +#endif + +#ifndef atomic64_dec_return_release +#define atomic64_dec_return_release(...) \ + __atomic_op_release(atomic64_dec_return, __VA_ARGS__) +#endif + +#ifndef atomic64_dec_return +#define atomic64_dec_return(...) \ + __atomic_op_fence(atomic64_dec_return, __VA_ARGS__) +#endif +#endif /* atomic64_dec_return_relaxed */ + +/* atomic64_xchg_relaxed */ +#ifndef atomic64_xchg_relaxed +#define atomic64_xchg_relaxed atomic64_xchg +#define atomic64_xchg_acquire atomic64_xchg +#define atomic64_xchg_release atomic64_xchg + +#else /* atomic64_xchg_relaxed */ + +#ifndef atomic64_xchg_acquire +#define atomic64_xchg_acquire(...) \ + __atomic_op_acquire(atomic64_xchg, __VA_ARGS__) +#endif + +#ifndef atomic64_xchg_release +#define atomic64_xchg_release(...) \ + __atomic_op_release(atomic64_xchg, __VA_ARGS__) +#endif + +#ifndef atomic64_xchg +#define atomic64_xchg(...) \ + __atomic_op_fence(atomic64_xchg, __VA_ARGS__) +#endif +#endif /* atomic64_xchg_relaxed */ + +/* atomic64_cmpxchg_relaxed */ +#ifndef atomic64_cmpxchg_relaxed +#define atomic64_cmpxchg_relaxed atomic64_cmpxchg +#define atomic64_cmpxchg_acquire atomic64_cmpxchg +#define atomic64_cmpxchg_release atomic64_cmpxchg + +#else /* atomic64_cmpxchg_relaxed */ + +#ifndef atomic64_cmpxchg_acquire +#define atomic64_cmpxchg_acquire(...) \ + __atomic_op_acquire(atomic64_cmpxchg, __VA_ARGS__) +#endif + +#ifndef atomic64_cmpxchg_release +#define atomic64_cmpxchg_release(...) \ + __atomic_op_release(atomic64_cmpxchg, __VA_ARGS__) +#endif + +#ifndef atomic64_cmpxchg +#define atomic64_cmpxchg(...) \ + __atomic_op_fence(atomic64_cmpxchg, __VA_ARGS__) +#endif +#endif /* atomic64_cmpxchg_relaxed */ + #ifndef atomic64_andnot static inline void atomic64_andnot(long long i, atomic64_t *v) { -- cgit v0.10.2 From 28aa2bda2211f4327d83b44a4f917b4a061b1c56 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Mon, 18 Apr 2016 00:54:38 +0200 Subject: locking/atomic: Implement atomic{,64,_long}_fetch_{add,sub,and,andnot,or,xor}{,_relaxed,_acquire,_release}() Now that all the architectures have implemented support for these new atomic primitives add on the generic infrastructure to expose and use it. Signed-off-by: Peter Zijlstra (Intel) Cc: Andrew Morton Cc: Arnd Bergmann Cc: Boqun Feng Cc: Borislav Petkov Cc: Davidlohr Bueso Cc: Frederic Weisbecker Cc: Linus Torvalds Cc: Paul E. McKenney Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: Will Deacon Cc: linux-arch@vger.kernel.org Cc: linux-kernel@vger.kernel.org Signed-off-by: Ingo Molnar diff --git a/include/asm-generic/atomic-long.h b/include/asm-generic/atomic-long.h index 5e1f345..2d0d3cf 100644 --- a/include/asm-generic/atomic-long.h +++ b/include/asm-generic/atomic-long.h @@ -112,6 +112,40 @@ static __always_inline void atomic_long_dec(atomic_long_t *l) ATOMIC_LONG_PFX(_dec)(v); } +#define ATOMIC_LONG_FETCH_OP(op, mo) \ +static inline long \ +atomic_long_fetch_##op##mo(long i, atomic_long_t *l) \ +{ \ + ATOMIC_LONG_PFX(_t) *v = (ATOMIC_LONG_PFX(_t) *)l; \ + \ + return (long)ATOMIC_LONG_PFX(_fetch_##op##mo)(i, v); \ +} + +ATOMIC_LONG_FETCH_OP(add, ) +ATOMIC_LONG_FETCH_OP(add, _relaxed) +ATOMIC_LONG_FETCH_OP(add, _acquire) +ATOMIC_LONG_FETCH_OP(add, _release) +ATOMIC_LONG_FETCH_OP(sub, ) +ATOMIC_LONG_FETCH_OP(sub, _relaxed) +ATOMIC_LONG_FETCH_OP(sub, _acquire) +ATOMIC_LONG_FETCH_OP(sub, _release) +ATOMIC_LONG_FETCH_OP(and, ) +ATOMIC_LONG_FETCH_OP(and, _relaxed) +ATOMIC_LONG_FETCH_OP(and, _acquire) +ATOMIC_LONG_FETCH_OP(and, _release) +ATOMIC_LONG_FETCH_OP(andnot, ) +ATOMIC_LONG_FETCH_OP(andnot, _relaxed) +ATOMIC_LONG_FETCH_OP(andnot, _acquire) +ATOMIC_LONG_FETCH_OP(andnot, _release) +ATOMIC_LONG_FETCH_OP(or, ) +ATOMIC_LONG_FETCH_OP(or, _relaxed) +ATOMIC_LONG_FETCH_OP(or, _acquire) +ATOMIC_LONG_FETCH_OP(or, _release) +ATOMIC_LONG_FETCH_OP(xor, ) +ATOMIC_LONG_FETCH_OP(xor, _relaxed) +ATOMIC_LONG_FETCH_OP(xor, _acquire) +ATOMIC_LONG_FETCH_OP(xor, _release) + #define ATOMIC_LONG_OP(op) \ static __always_inline void \ atomic_long_##op(long i, atomic_long_t *l) \ @@ -124,9 +158,9 @@ atomic_long_##op(long i, atomic_long_t *l) \ ATOMIC_LONG_OP(add) ATOMIC_LONG_OP(sub) ATOMIC_LONG_OP(and) +ATOMIC_LONG_OP(andnot) ATOMIC_LONG_OP(or) ATOMIC_LONG_OP(xor) -ATOMIC_LONG_OP(andnot) #undef ATOMIC_LONG_OP diff --git a/include/asm-generic/atomic.h b/include/asm-generic/atomic.h index 74f1a37..a2304cc 100644 --- a/include/asm-generic/atomic.h +++ b/include/asm-generic/atomic.h @@ -61,6 +61,18 @@ static inline int atomic_##op##_return(int i, atomic_t *v) \ return c c_op i; \ } +#define ATOMIC_FETCH_OP(op, c_op) \ +static inline int atomic_fetch_##op(int i, atomic_t *v) \ +{ \ + int c, old; \ + \ + c = v->counter; \ + while ((old = cmpxchg(&v->counter, c, c c_op i)) != c) \ + c = old; \ + \ + return c; \ +} + #else #include @@ -88,6 +100,20 @@ static inline int atomic_##op##_return(int i, atomic_t *v) \ return ret; \ } +#define ATOMIC_FETCH_OP(op, c_op) \ +static inline int atomic_fetch_##op(int i, atomic_t *v) \ +{ \ + unsigned long flags; \ + int ret; \ + \ + raw_local_irq_save(flags); \ + ret = v->counter; \ + v->counter = v->counter c_op i; \ + raw_local_irq_restore(flags); \ + \ + return ret; \ +} + #endif /* CONFIG_SMP */ #ifndef atomic_add_return @@ -98,6 +124,28 @@ ATOMIC_OP_RETURN(add, +) ATOMIC_OP_RETURN(sub, -) #endif +#ifndef atomic_fetch_add +ATOMIC_FETCH_OP(add, +) +#endif + +#ifndef atomic_fetch_sub +ATOMIC_FETCH_OP(sub, -) +#endif + +#ifndef atomic_fetch_and +ATOMIC_FETCH_OP(and, &) +#endif + +#ifndef atomic_fetch_or +#define atomic_fetch_or atomic_fetch_or + +ATOMIC_FETCH_OP(or, |) +#endif + +#ifndef atomic_fetch_xor +ATOMIC_FETCH_OP(xor, ^) +#endif + #ifndef atomic_and ATOMIC_OP(and, &) #endif @@ -110,6 +158,7 @@ ATOMIC_OP(or, |) ATOMIC_OP(xor, ^) #endif +#undef ATOMIC_FETCH_OP #undef ATOMIC_OP_RETURN #undef ATOMIC_OP diff --git a/include/asm-generic/atomic64.h b/include/asm-generic/atomic64.h index d48e78c..dad68bf 100644 --- a/include/asm-generic/atomic64.h +++ b/include/asm-generic/atomic64.h @@ -27,16 +27,23 @@ extern void atomic64_##op(long long a, atomic64_t *v); #define ATOMIC64_OP_RETURN(op) \ extern long long atomic64_##op##_return(long long a, atomic64_t *v); -#define ATOMIC64_OPS(op) ATOMIC64_OP(op) ATOMIC64_OP_RETURN(op) +#define ATOMIC64_FETCH_OP(op) \ +extern long long atomic64_fetch_##op(long long a, atomic64_t *v); + +#define ATOMIC64_OPS(op) ATOMIC64_OP(op) ATOMIC64_OP_RETURN(op) ATOMIC64_FETCH_OP(op) ATOMIC64_OPS(add) ATOMIC64_OPS(sub) -ATOMIC64_OP(and) -ATOMIC64_OP(or) -ATOMIC64_OP(xor) +#undef ATOMIC64_OPS +#define ATOMIC64_OPS(op) ATOMIC64_OP(op) ATOMIC64_FETCH_OP(op) + +ATOMIC64_OPS(and) +ATOMIC64_OPS(or) +ATOMIC64_OPS(xor) #undef ATOMIC64_OPS +#undef ATOMIC64_FETCH_OP #undef ATOMIC64_OP_RETURN #undef ATOMIC64_OP diff --git a/include/linux/atomic.h b/include/linux/atomic.h index 351f89e..2e6c013 100644 --- a/include/linux/atomic.h +++ b/include/linux/atomic.h @@ -163,6 +163,154 @@ #endif #endif /* atomic_dec_return_relaxed */ + +/* atomic_fetch_add_relaxed */ +#ifndef atomic_fetch_add_relaxed +#define atomic_fetch_add_relaxed atomic_fetch_add +#define atomic_fetch_add_acquire atomic_fetch_add +#define atomic_fetch_add_release atomic_fetch_add + +#else /* atomic_fetch_add_relaxed */ + +#ifndef atomic_fetch_add_acquire +#define atomic_fetch_add_acquire(...) \ + __atomic_op_acquire(atomic_fetch_add, __VA_ARGS__) +#endif + +#ifndef atomic_fetch_add_release +#define atomic_fetch_add_release(...) \ + __atomic_op_release(atomic_fetch_add, __VA_ARGS__) +#endif + +#ifndef atomic_fetch_add +#define atomic_fetch_add(...) \ + __atomic_op_fence(atomic_fetch_add, __VA_ARGS__) +#endif +#endif /* atomic_fetch_add_relaxed */ + +/* atomic_fetch_sub_relaxed */ +#ifndef atomic_fetch_sub_relaxed +#define atomic_fetch_sub_relaxed atomic_fetch_sub +#define atomic_fetch_sub_acquire atomic_fetch_sub +#define atomic_fetch_sub_release atomic_fetch_sub + +#else /* atomic_fetch_sub_relaxed */ + +#ifndef atomic_fetch_sub_acquire +#define atomic_fetch_sub_acquire(...) \ + __atomic_op_acquire(atomic_fetch_sub, __VA_ARGS__) +#endif + +#ifndef atomic_fetch_sub_release +#define atomic_fetch_sub_release(...) \ + __atomic_op_release(atomic_fetch_sub, __VA_ARGS__) +#endif + +#ifndef atomic_fetch_sub +#define atomic_fetch_sub(...) \ + __atomic_op_fence(atomic_fetch_sub, __VA_ARGS__) +#endif +#endif /* atomic_fetch_sub_relaxed */ + +/* atomic_fetch_or_relaxed */ +#ifndef atomic_fetch_or_relaxed +#define atomic_fetch_or_relaxed atomic_fetch_or +#define atomic_fetch_or_acquire atomic_fetch_or +#define atomic_fetch_or_release atomic_fetch_or + +#else /* atomic_fetch_or_relaxed */ + +#ifndef atomic_fetch_or_acquire +#define atomic_fetch_or_acquire(...) \ + __atomic_op_acquire(atomic_fetch_or, __VA_ARGS__) +#endif + +#ifndef atomic_fetch_or_release +#define atomic_fetch_or_release(...) \ + __atomic_op_release(atomic_fetch_or, __VA_ARGS__) +#endif + +#ifndef atomic_fetch_or +#define atomic_fetch_or(...) \ + __atomic_op_fence(atomic_fetch_or, __VA_ARGS__) +#endif +#endif /* atomic_fetch_or_relaxed */ + +/* atomic_fetch_and_relaxed */ +#ifndef atomic_fetch_and_relaxed +#define atomic_fetch_and_relaxed atomic_fetch_and +#define atomic_fetch_and_acquire atomic_fetch_and +#define atomic_fetch_and_release atomic_fetch_and + +#else /* atomic_fetch_and_relaxed */ + +#ifndef atomic_fetch_and_acquire +#define atomic_fetch_and_acquire(...) \ + __atomic_op_acquire(atomic_fetch_and, __VA_ARGS__) +#endif + +#ifndef atomic_fetch_and_release +#define atomic_fetch_and_release(...) \ + __atomic_op_release(atomic_fetch_and, __VA_ARGS__) +#endif + +#ifndef atomic_fetch_and +#define atomic_fetch_and(...) \ + __atomic_op_fence(atomic_fetch_and, __VA_ARGS__) +#endif +#endif /* atomic_fetch_and_relaxed */ + +#ifdef atomic_andnot +/* atomic_fetch_andnot_relaxed */ +#ifndef atomic_fetch_andnot_relaxed +#define atomic_fetch_andnot_relaxed atomic_fetch_andnot +#define atomic_fetch_andnot_acquire atomic_fetch_andnot +#define atomic_fetch_andnot_release atomic_fetch_andnot + +#else /* atomic_fetch_andnot_relaxed */ + +#ifndef atomic_fetch_andnot_acquire +#define atomic_fetch_andnot_acquire(...) \ + __atomic_op_acquire(atomic_fetch_andnot, __VA_ARGS__) +#endif + +#ifndef atomic_fetch_andnot_release +#define atomic_fetch_andnot_release(...) \ + __atomic_op_release(atomic_fetch_andnot, __VA_ARGS__) +#endif + +#ifndef atomic_fetch_andnot +#define atomic_fetch_andnot(...) \ + __atomic_op_fence(atomic_fetch_andnot, __VA_ARGS__) +#endif +#endif /* atomic_fetch_andnot_relaxed */ +#endif /* atomic_andnot */ + +/* atomic_fetch_xor_relaxed */ +#ifndef atomic_fetch_xor_relaxed +#define atomic_fetch_xor_relaxed atomic_fetch_xor +#define atomic_fetch_xor_acquire atomic_fetch_xor +#define atomic_fetch_xor_release atomic_fetch_xor + +#else /* atomic_fetch_xor_relaxed */ + +#ifndef atomic_fetch_xor_acquire +#define atomic_fetch_xor_acquire(...) \ + __atomic_op_acquire(atomic_fetch_xor, __VA_ARGS__) +#endif + +#ifndef atomic_fetch_xor_release +#define atomic_fetch_xor_release(...) \ + __atomic_op_release(atomic_fetch_xor, __VA_ARGS__) +#endif + +#ifndef atomic_fetch_xor +#define atomic_fetch_xor(...) \ + __atomic_op_fence(atomic_fetch_xor, __VA_ARGS__) +#endif +#endif /* atomic_fetch_xor_relaxed */ + + /* atomic_xchg_relaxed */ #ifndef atomic_xchg_relaxed #define atomic_xchg_relaxed atomic_xchg @@ -310,6 +458,26 @@ static inline void atomic_andnot(int i, atomic_t *v) { atomic_and(~i, v); } + +static inline int atomic_fetch_andnot(int i, atomic_t *v) +{ + return atomic_fetch_and(~i, v); +} + +static inline int atomic_fetch_andnot_relaxed(int i, atomic_t *v) +{ + return atomic_fetch_and_relaxed(~i, v); +} + +static inline int atomic_fetch_andnot_acquire(int i, atomic_t *v) +{ + return atomic_fetch_and_acquire(~i, v); +} + +static inline int atomic_fetch_andnot_release(int i, atomic_t *v) +{ + return atomic_fetch_and_release(~i, v); +} #endif static inline __deprecated void atomic_clear_mask(unsigned int mask, atomic_t *v) @@ -535,6 +703,154 @@ static inline int atomic_fetch_or(int mask, atomic_t *p) #endif #endif /* atomic64_dec_return_relaxed */ + +/* atomic64_fetch_add_relaxed */ +#ifndef atomic64_fetch_add_relaxed +#define atomic64_fetch_add_relaxed atomic64_fetch_add +#define atomic64_fetch_add_acquire atomic64_fetch_add +#define atomic64_fetch_add_release atomic64_fetch_add + +#else /* atomic64_fetch_add_relaxed */ + +#ifndef atomic64_fetch_add_acquire +#define atomic64_fetch_add_acquire(...) \ + __atomic_op_acquire(atomic64_fetch_add, __VA_ARGS__) +#endif + +#ifndef atomic64_fetch_add_release +#define atomic64_fetch_add_release(...) \ + __atomic_op_release(atomic64_fetch_add, __VA_ARGS__) +#endif + +#ifndef atomic64_fetch_add +#define atomic64_fetch_add(...) \ + __atomic_op_fence(atomic64_fetch_add, __VA_ARGS__) +#endif +#endif /* atomic64_fetch_add_relaxed */ + +/* atomic64_fetch_sub_relaxed */ +#ifndef atomic64_fetch_sub_relaxed +#define atomic64_fetch_sub_relaxed atomic64_fetch_sub +#define atomic64_fetch_sub_acquire atomic64_fetch_sub +#define atomic64_fetch_sub_release atomic64_fetch_sub + +#else /* atomic64_fetch_sub_relaxed */ + +#ifndef atomic64_fetch_sub_acquire +#define atomic64_fetch_sub_acquire(...) \ + __atomic_op_acquire(atomic64_fetch_sub, __VA_ARGS__) +#endif + +#ifndef atomic64_fetch_sub_release +#define atomic64_fetch_sub_release(...) \ + __atomic_op_release(atomic64_fetch_sub, __VA_ARGS__) +#endif + +#ifndef atomic64_fetch_sub +#define atomic64_fetch_sub(...) \ + __atomic_op_fence(atomic64_fetch_sub, __VA_ARGS__) +#endif +#endif /* atomic64_fetch_sub_relaxed */ + +/* atomic64_fetch_or_relaxed */ +#ifndef atomic64_fetch_or_relaxed +#define atomic64_fetch_or_relaxed atomic64_fetch_or +#define atomic64_fetch_or_acquire atomic64_fetch_or +#define atomic64_fetch_or_release atomic64_fetch_or + +#else /* atomic64_fetch_or_relaxed */ + +#ifndef atomic64_fetch_or_acquire +#define atomic64_fetch_or_acquire(...) \ + __atomic_op_acquire(atomic64_fetch_or, __VA_ARGS__) +#endif + +#ifndef atomic64_fetch_or_release +#define atomic64_fetch_or_release(...) \ + __atomic_op_release(atomic64_fetch_or, __VA_ARGS__) +#endif + +#ifndef atomic64_fetch_or +#define atomic64_fetch_or(...) \ + __atomic_op_fence(atomic64_fetch_or, __VA_ARGS__) +#endif +#endif /* atomic64_fetch_or_relaxed */ + +/* atomic64_fetch_and_relaxed */ +#ifndef atomic64_fetch_and_relaxed +#define atomic64_fetch_and_relaxed atomic64_fetch_and +#define atomic64_fetch_and_acquire atomic64_fetch_and +#define atomic64_fetch_and_release atomic64_fetch_and + +#else /* atomic64_fetch_and_relaxed */ + +#ifndef atomic64_fetch_and_acquire +#define atomic64_fetch_and_acquire(...) \ + __atomic_op_acquire(atomic64_fetch_and, __VA_ARGS__) +#endif + +#ifndef atomic64_fetch_and_release +#define atomic64_fetch_and_release(...) \ + __atomic_op_release(atomic64_fetch_and, __VA_ARGS__) +#endif + +#ifndef atomic64_fetch_and +#define atomic64_fetch_and(...) \ + __atomic_op_fence(atomic64_fetch_and, __VA_ARGS__) +#endif +#endif /* atomic64_fetch_and_relaxed */ + +#ifdef atomic64_andnot +/* atomic64_fetch_andnot_relaxed */ +#ifndef atomic64_fetch_andnot_relaxed +#define atomic64_fetch_andnot_relaxed atomic64_fetch_andnot +#define atomic64_fetch_andnot_acquire atomic64_fetch_andnot +#define atomic64_fetch_andnot_release atomic64_fetch_andnot + +#else /* atomic64_fetch_andnot_relaxed */ + +#ifndef atomic64_fetch_andnot_acquire +#define atomic64_fetch_andnot_acquire(...) \ + __atomic_op_acquire(atomic64_fetch_andnot, __VA_ARGS__) +#endif + +#ifndef atomic64_fetch_andnot_release +#define atomic64_fetch_andnot_release(...) \ + __atomic_op_release(atomic64_fetch_andnot, __VA_ARGS__) +#endif + +#ifndef atomic64_fetch_andnot +#define atomic64_fetch_andnot(...) \ + __atomic_op_fence(atomic64_fetch_andnot, __VA_ARGS__) +#endif +#endif /* atomic64_fetch_andnot_relaxed */ +#endif /* atomic64_andnot */ + +/* atomic64_fetch_xor_relaxed */ +#ifndef atomic64_fetch_xor_relaxed +#define atomic64_fetch_xor_relaxed atomic64_fetch_xor +#define atomic64_fetch_xor_acquire atomic64_fetch_xor +#define atomic64_fetch_xor_release atomic64_fetch_xor + +#else /* atomic64_fetch_xor_relaxed */ + +#ifndef atomic64_fetch_xor_acquire +#define atomic64_fetch_xor_acquire(...) \ + __atomic_op_acquire(atomic64_fetch_xor, __VA_ARGS__) +#endif + +#ifndef atomic64_fetch_xor_release +#define atomic64_fetch_xor_release(...) \ + __atomic_op_release(atomic64_fetch_xor, __VA_ARGS__) +#endif + +#ifndef atomic64_fetch_xor +#define atomic64_fetch_xor(...) \ + __atomic_op_fence(atomic64_fetch_xor, __VA_ARGS__) +#endif +#endif /* atomic64_fetch_xor_relaxed */ + + /* atomic64_xchg_relaxed */ #ifndef atomic64_xchg_relaxed #define atomic64_xchg_relaxed atomic64_xchg @@ -588,6 +904,26 @@ static inline void atomic64_andnot(long long i, atomic64_t *v) { atomic64_and(~i, v); } + +static inline long long atomic64_fetch_andnot(long long i, atomic64_t *v) +{ + return atomic64_fetch_and(~i, v); +} + +static inline long long atomic64_fetch_andnot_relaxed(long long i, atomic64_t *v) +{ + return atomic64_fetch_and_relaxed(~i, v); +} + +static inline long long atomic64_fetch_andnot_acquire(long long i, atomic64_t *v) +{ + return atomic64_fetch_and_acquire(~i, v); +} + +static inline long long atomic64_fetch_andnot_release(long long i, atomic64_t *v) +{ + return atomic64_fetch_and_release(~i, v); +} #endif #include diff --git a/lib/atomic64.c b/lib/atomic64.c index 2886eba..53c2d5e 100644 --- a/lib/atomic64.c +++ b/lib/atomic64.c @@ -96,17 +96,41 @@ long long atomic64_##op##_return(long long a, atomic64_t *v) \ } \ EXPORT_SYMBOL(atomic64_##op##_return); +#define ATOMIC64_FETCH_OP(op, c_op) \ +long long atomic64_fetch_##op(long long a, atomic64_t *v) \ +{ \ + unsigned long flags; \ + raw_spinlock_t *lock = lock_addr(v); \ + long long val; \ + \ + raw_spin_lock_irqsave(lock, flags); \ + val = v->counter; \ + v->counter c_op a; \ + raw_spin_unlock_irqrestore(lock, flags); \ + return val; \ +} \ +EXPORT_SYMBOL(atomic64_fetch_##op); + #define ATOMIC64_OPS(op, c_op) \ ATOMIC64_OP(op, c_op) \ - ATOMIC64_OP_RETURN(op, c_op) + ATOMIC64_OP_RETURN(op, c_op) \ + ATOMIC64_FETCH_OP(op, c_op) ATOMIC64_OPS(add, +=) ATOMIC64_OPS(sub, -=) -ATOMIC64_OP(and, &=) -ATOMIC64_OP(or, |=) -ATOMIC64_OP(xor, ^=) #undef ATOMIC64_OPS +#define ATOMIC64_OPS(op, c_op) \ + ATOMIC64_OP(op, c_op) \ + ATOMIC64_OP_RETURN(op, c_op) \ + ATOMIC64_FETCH_OP(op, c_op) + +ATOMIC64_OPS(and, &=) +ATOMIC64_OPS(or, |=) +ATOMIC64_OPS(xor, ^=) + +#undef ATOMIC64_OPS +#undef ATOMIC64_FETCH_OP #undef ATOMIC64_OP_RETURN #undef ATOMIC64_OP diff --git a/lib/atomic64_test.c b/lib/atomic64_test.c index 1234818..dbb3691 100644 --- a/lib/atomic64_test.c +++ b/lib/atomic64_test.c @@ -53,11 +53,25 @@ do { \ BUG_ON(atomic##bit##_read(&v) != r); \ } while (0) +#define TEST_FETCH(bit, op, c_op, val) \ +do { \ + atomic##bit##_set(&v, v0); \ + r = v0; \ + r c_op val; \ + BUG_ON(atomic##bit##_##op(val, &v) != v0); \ + BUG_ON(atomic##bit##_read(&v) != r); \ +} while (0) + #define RETURN_FAMILY_TEST(bit, op, c_op, val) \ do { \ FAMILY_TEST(TEST_RETURN, bit, op, c_op, val); \ } while (0) +#define FETCH_FAMILY_TEST(bit, op, c_op, val) \ +do { \ + FAMILY_TEST(TEST_FETCH, bit, op, c_op, val); \ +} while (0) + #define TEST_ARGS(bit, op, init, ret, expect, args...) \ do { \ atomic##bit##_set(&v, init); \ @@ -114,6 +128,16 @@ static __init void test_atomic(void) RETURN_FAMILY_TEST(, sub_return, -=, onestwos); RETURN_FAMILY_TEST(, sub_return, -=, -one); + FETCH_FAMILY_TEST(, fetch_add, +=, onestwos); + FETCH_FAMILY_TEST(, fetch_add, +=, -one); + FETCH_FAMILY_TEST(, fetch_sub, -=, onestwos); + FETCH_FAMILY_TEST(, fetch_sub, -=, -one); + + FETCH_FAMILY_TEST(, fetch_or, |=, v1); + FETCH_FAMILY_TEST(, fetch_and, &=, v1); + FETCH_FAMILY_TEST(, fetch_andnot, &= ~, v1); + FETCH_FAMILY_TEST(, fetch_xor, ^=, v1); + INC_RETURN_FAMILY_TEST(, v0); DEC_RETURN_FAMILY_TEST(, v0); @@ -154,6 +178,16 @@ static __init void test_atomic64(void) RETURN_FAMILY_TEST(64, sub_return, -=, onestwos); RETURN_FAMILY_TEST(64, sub_return, -=, -one); + FETCH_FAMILY_TEST(64, fetch_add, +=, onestwos); + FETCH_FAMILY_TEST(64, fetch_add, +=, -one); + FETCH_FAMILY_TEST(64, fetch_sub, -=, onestwos); + FETCH_FAMILY_TEST(64, fetch_sub, -=, -one); + + FETCH_FAMILY_TEST(64, fetch_or, |=, v1); + FETCH_FAMILY_TEST(64, fetch_and, &=, v1); + FETCH_FAMILY_TEST(64, fetch_andnot, &= ~, v1); + FETCH_FAMILY_TEST(64, fetch_xor, ^=, v1); + INIT(v0); atomic64_inc(&v); r += one; -- cgit v0.10.2 From b53d6bedbe781974097fd8c38263f6cc78ff9ea7 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Mon, 18 Apr 2016 00:58:25 +0200 Subject: locking/atomic: Remove linux/atomic.h:atomic_fetch_or() Since all architectures have this implemented now natively, remove this dead code. Signed-off-by: Peter Zijlstra (Intel) Cc: Andrew Morton Cc: Linus Torvalds Cc: Paul E. McKenney Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: linux-arch@vger.kernel.org Cc: linux-kernel@vger.kernel.org Signed-off-by: Ingo Molnar diff --git a/arch/alpha/include/asm/atomic.h b/arch/alpha/include/asm/atomic.h index 8243f17..5377ca8 100644 --- a/arch/alpha/include/asm/atomic.h +++ b/arch/alpha/include/asm/atomic.h @@ -153,8 +153,6 @@ ATOMIC_OPS(sub) #define atomic_andnot atomic_andnot #define atomic64_andnot atomic64_andnot -#define atomic_fetch_or atomic_fetch_or - #undef ATOMIC_OPS #define ATOMIC_OPS(op, asm) \ ATOMIC_OP(op, asm) \ diff --git a/arch/arc/include/asm/atomic.h b/arch/arc/include/asm/atomic.h index c066a21..bd9c51c 100644 --- a/arch/arc/include/asm/atomic.h +++ b/arch/arc/include/asm/atomic.h @@ -189,8 +189,6 @@ ATOMIC_OPS(sub, -=, sub) #define atomic_andnot atomic_andnot -#define atomic_fetch_or atomic_fetch_or - #undef ATOMIC_OPS #define ATOMIC_OPS(op, c_op, asm_op) \ ATOMIC_OP(op, c_op, asm_op) \ diff --git a/arch/arm/include/asm/atomic.h b/arch/arm/include/asm/atomic.h index 0feb110..66d0e21 100644 --- a/arch/arm/include/asm/atomic.h +++ b/arch/arm/include/asm/atomic.h @@ -201,8 +201,6 @@ static inline int atomic_fetch_##op(int i, atomic_t *v) \ return val; \ } -#define atomic_fetch_or atomic_fetch_or - static inline int atomic_cmpxchg(atomic_t *v, int old, int new) { int ret; diff --git a/arch/arm64/include/asm/atomic.h b/arch/arm64/include/asm/atomic.h index 3128c3d..c0235e0 100644 --- a/arch/arm64/include/asm/atomic.h +++ b/arch/arm64/include/asm/atomic.h @@ -128,8 +128,6 @@ #define __atomic_add_unless(v, a, u) ___atomic_add_unless(v, a, u,) #define atomic_andnot atomic_andnot -#define atomic_fetch_or atomic_fetch_or - /* * 64-bit atomic operations. */ diff --git a/arch/avr32/include/asm/atomic.h b/arch/avr32/include/asm/atomic.h index b8681fd..3d5ce38 100644 --- a/arch/avr32/include/asm/atomic.h +++ b/arch/avr32/include/asm/atomic.h @@ -66,8 +66,6 @@ ATOMIC_OP_RETURN(add, add, r) ATOMIC_FETCH_OP (sub, sub, rKs21) ATOMIC_FETCH_OP (add, add, r) -#define atomic_fetch_or atomic_fetch_or - #define ATOMIC_OPS(op, asm_op) \ ATOMIC_OP_RETURN(op, asm_op, r) \ static inline void atomic_##op(int i, atomic_t *v) \ diff --git a/arch/frv/include/asm/atomic.h b/arch/frv/include/asm/atomic.h index e3e06da..1c2a5e2 100644 --- a/arch/frv/include/asm/atomic.h +++ b/arch/frv/include/asm/atomic.h @@ -74,8 +74,6 @@ static inline void atomic_dec(atomic_t *v) #define atomic_dec_and_test(v) (atomic_sub_return(1, (v)) == 0) #define atomic_inc_and_test(v) (atomic_add_return(1, (v)) == 0) -#define atomic_fetch_or atomic_fetch_or - /* * 64-bit atomic ops */ diff --git a/arch/h8300/include/asm/atomic.h b/arch/h8300/include/asm/atomic.h index 0961b61..349a47a 100644 --- a/arch/h8300/include/asm/atomic.h +++ b/arch/h8300/include/asm/atomic.h @@ -54,8 +54,6 @@ static inline void atomic_##op(int i, atomic_t *v) \ ATOMIC_OP_RETURN(add, +=) ATOMIC_OP_RETURN(sub, -=) -#define atomic_fetch_or atomic_fetch_or - #define ATOMIC_OPS(op, c_op) \ ATOMIC_OP(op, c_op) \ ATOMIC_FETCH_OP(op, c_op) diff --git a/arch/hexagon/include/asm/atomic.h b/arch/hexagon/include/asm/atomic.h index 07dbb33..a62ba36 100644 --- a/arch/hexagon/include/asm/atomic.h +++ b/arch/hexagon/include/asm/atomic.h @@ -152,8 +152,6 @@ ATOMIC_OPS(sub) #undef ATOMIC_OPS #define ATOMIC_OPS(op) ATOMIC_OP(op) ATOMIC_FETCH_OP(op) -#define atomic_fetch_or atomic_fetch_or - ATOMIC_OPS(and) ATOMIC_OPS(or) ATOMIC_OPS(xor) diff --git a/arch/m32r/include/asm/atomic.h b/arch/m32r/include/asm/atomic.h index 8ba8a0a..640cc1c 100644 --- a/arch/m32r/include/asm/atomic.h +++ b/arch/m32r/include/asm/atomic.h @@ -121,8 +121,6 @@ ATOMIC_OPS(sub) #undef ATOMIC_OPS #define ATOMIC_OPS(op) ATOMIC_OP(op) ATOMIC_FETCH_OP(op) -#define atomic_fetch_or atomic_fetch_or - ATOMIC_OPS(and) ATOMIC_OPS(or) ATOMIC_OPS(xor) diff --git a/arch/m68k/include/asm/atomic.h b/arch/m68k/include/asm/atomic.h index 5cf9b3b..3e03de7 100644 --- a/arch/m68k/include/asm/atomic.h +++ b/arch/m68k/include/asm/atomic.h @@ -119,8 +119,6 @@ ATOMIC_OPS(sub, -=, sub) ATOMIC_OP(op, c_op, asm_op) \ ATOMIC_FETCH_OP(op, c_op, asm_op) -#define atomic_fetch_or atomic_fetch_or - ATOMIC_OPS(and, &=, and) ATOMIC_OPS(or, |=, or) ATOMIC_OPS(xor, ^=, eor) diff --git a/arch/metag/include/asm/atomic.h b/arch/metag/include/asm/atomic.h index 6ca210d..470e365 100644 --- a/arch/metag/include/asm/atomic.h +++ b/arch/metag/include/asm/atomic.h @@ -17,8 +17,6 @@ #include #endif -#define atomic_fetch_or atomic_fetch_or - #define atomic_add_negative(a, v) (atomic_add_return((a), (v)) < 0) #define atomic_dec_return(v) atomic_sub_return(1, (v)) diff --git a/arch/mips/include/asm/atomic.h b/arch/mips/include/asm/atomic.h index 431079f..387ce28 100644 --- a/arch/mips/include/asm/atomic.h +++ b/arch/mips/include/asm/atomic.h @@ -194,8 +194,6 @@ ATOMIC_OPS(sub, -=, subu) ATOMIC_OP(op, c_op, asm_op) \ ATOMIC_FETCH_OP(op, c_op, asm_op) -#define atomic_fetch_or atomic_fetch_or - ATOMIC_OPS(and, &=, and) ATOMIC_OPS(or, |=, or) ATOMIC_OPS(xor, ^=, xor) diff --git a/arch/mn10300/include/asm/atomic.h b/arch/mn10300/include/asm/atomic.h index 3580f78..36389ef 100644 --- a/arch/mn10300/include/asm/atomic.h +++ b/arch/mn10300/include/asm/atomic.h @@ -113,8 +113,6 @@ ATOMIC_OPS(sub) #undef ATOMIC_OPS #define ATOMIC_OPS(op) ATOMIC_OP(op) ATOMIC_FETCH_OP(op) -#define atomic_fetch_or atomic_fetch_or - ATOMIC_OPS(and) ATOMIC_OPS(or) ATOMIC_OPS(xor) diff --git a/arch/parisc/include/asm/atomic.h b/arch/parisc/include/asm/atomic.h index 29df1f8..5394b9c 100644 --- a/arch/parisc/include/asm/atomic.h +++ b/arch/parisc/include/asm/atomic.h @@ -148,8 +148,6 @@ ATOMIC_OPS(sub, -=) ATOMIC_OP(op, c_op) \ ATOMIC_FETCH_OP(op, c_op) -#define atomic_fetch_or atomic_fetch_or - ATOMIC_OPS(and, &=) ATOMIC_OPS(or, |=) ATOMIC_OPS(xor, ^=) diff --git a/arch/s390/include/asm/atomic.h b/arch/s390/include/asm/atomic.h index 2324e759..d28cc2f 100644 --- a/arch/s390/include/asm/atomic.h +++ b/arch/s390/include/asm/atomic.h @@ -135,8 +135,6 @@ static inline int atomic_fetch_##op(int i, atomic_t *v) \ return __ATOMIC_LOOP(v, i, __ATOMIC_##OP, __ATOMIC_BARRIER); \ } -#define atomic_fetch_or atomic_fetch_or - ATOMIC_OPS(and, AND) ATOMIC_OPS(or, OR) ATOMIC_OPS(xor, XOR) diff --git a/arch/sh/include/asm/atomic.h b/arch/sh/include/asm/atomic.h index d93ed7c..c399e1c 100644 --- a/arch/sh/include/asm/atomic.h +++ b/arch/sh/include/asm/atomic.h @@ -25,8 +25,6 @@ #include #endif -#define atomic_fetch_or atomic_fetch_or - #define atomic_add_negative(a, v) (atomic_add_return((a), (v)) < 0) #define atomic_dec_return(v) atomic_sub_return(1, (v)) #define atomic_inc_return(v) atomic_add_return(1, (v)) diff --git a/arch/sparc/include/asm/atomic.h b/arch/sparc/include/asm/atomic.h index 1f741bc..8ff83d8 100644 --- a/arch/sparc/include/asm/atomic.h +++ b/arch/sparc/include/asm/atomic.h @@ -5,5 +5,4 @@ #else #include #endif -#define atomic_fetch_or atomic_fetch_or #endif diff --git a/arch/sparc/include/asm/atomic_32.h b/arch/sparc/include/asm/atomic_32.h index 5cfb20a..ee3f11c 100644 --- a/arch/sparc/include/asm/atomic_32.h +++ b/arch/sparc/include/asm/atomic_32.h @@ -36,8 +36,6 @@ void atomic_set(atomic_t *, int); #define atomic_inc(v) ((void)atomic_add_return( 1, (v))) #define atomic_dec(v) ((void)atomic_add_return( -1, (v))) -#define atomic_fetch_or atomic_fetch_or - #define atomic_and(i, v) ((void)atomic_fetch_and((i), (v))) #define atomic_or(i, v) ((void)atomic_fetch_or((i), (v))) #define atomic_xor(i, v) ((void)atomic_fetch_xor((i), (v))) diff --git a/arch/tile/include/asm/atomic.h b/arch/tile/include/asm/atomic.h index 9807030..8dda3c8 100644 --- a/arch/tile/include/asm/atomic.h +++ b/arch/tile/include/asm/atomic.h @@ -48,8 +48,6 @@ static inline int atomic_read(const atomic_t *v) #define atomic_fetch_sub(i, v) atomic_fetch_add(-(int)(i), (v)) -#define atomic_fetch_or atomic_fetch_or - /** * atomic_sub - subtract integer from atomic variable * @i: integer value to subtract diff --git a/arch/x86/include/asm/atomic.h b/arch/x86/include/asm/atomic.h index 73b8463..a58b998 100644 --- a/arch/x86/include/asm/atomic.h +++ b/arch/x86/include/asm/atomic.h @@ -217,8 +217,6 @@ static inline int atomic_fetch_##op(int i, atomic_t *v) \ ATOMIC_OP(op) \ ATOMIC_FETCH_OP(op, c_op) -#define atomic_fetch_or atomic_fetch_or - ATOMIC_OPS(and, &) ATOMIC_OPS(or , |) ATOMIC_OPS(xor, ^) diff --git a/arch/xtensa/include/asm/atomic.h b/arch/xtensa/include/asm/atomic.h index d95a8aa..e7a23f2 100644 --- a/arch/xtensa/include/asm/atomic.h +++ b/arch/xtensa/include/asm/atomic.h @@ -188,8 +188,6 @@ ATOMIC_OPS(sub) #undef ATOMIC_OPS #define ATOMIC_OPS(op) ATOMIC_OP(op) ATOMIC_FETCH_OP(op) -#define atomic_fetch_or atomic_fetch_or - ATOMIC_OPS(and) ATOMIC_OPS(or) ATOMIC_OPS(xor) diff --git a/include/asm-generic/atomic.h b/include/asm-generic/atomic.h index a2304cc..9ed8b98 100644 --- a/include/asm-generic/atomic.h +++ b/include/asm-generic/atomic.h @@ -137,8 +137,6 @@ ATOMIC_FETCH_OP(and, &) #endif #ifndef atomic_fetch_or -#define atomic_fetch_or atomic_fetch_or - ATOMIC_FETCH_OP(or, |) #endif diff --git a/include/linux/atomic.h b/include/linux/atomic.h index 2e6c013..0b3802d 100644 --- a/include/linux/atomic.h +++ b/include/linux/atomic.h @@ -573,27 +573,6 @@ static inline int atomic_dec_if_positive(atomic_t *v) } #endif -/** - * atomic_fetch_or - perform *p |= mask and return old value of *p - * @mask: mask to OR on the atomic_t - * @p: pointer to atomic_t - */ -#ifndef atomic_fetch_or -static inline int atomic_fetch_or(int mask, atomic_t *p) -{ - int old, val = atomic_read(p); - - for (;;) { - old = atomic_cmpxchg(p, val, val | mask); - if (old == val) - break; - val = old; - } - - return old; -} -#endif - #ifdef CONFIG_GENERIC_ATOMIC64 #include #endif -- cgit v0.10.2 From e37837fb62f95a81bdcefa86ceea043df84937d7 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Mon, 18 Apr 2016 01:01:27 +0200 Subject: locking/atomic: Remove the deprecated atomic_{set,clear}_mask() functions These functions have been deprecated for a while and there is only the one user left, convert and kill. Signed-off-by: Peter Zijlstra (Intel) Cc: Andrew Morton Cc: Boqun Feng Cc: Davidlohr Bueso Cc: Frederic Weisbecker Cc: Linus Torvalds Cc: Paul E. McKenney Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: Will Deacon Cc: linux-arch@vger.kernel.org Cc: linux-kernel@vger.kernel.org Signed-off-by: Ingo Molnar diff --git a/include/linux/atomic.h b/include/linux/atomic.h index 0b3802d..12d910d 100644 --- a/include/linux/atomic.h +++ b/include/linux/atomic.h @@ -480,16 +480,6 @@ static inline int atomic_fetch_andnot_release(int i, atomic_t *v) } #endif -static inline __deprecated void atomic_clear_mask(unsigned int mask, atomic_t *v) -{ - atomic_andnot(mask, v); -} - -static inline __deprecated void atomic_set_mask(unsigned int mask, atomic_t *v) -{ - atomic_or(mask, v); -} - /** * atomic_inc_not_zero_hint - increment if not null * @v: pointer of type atomic_t diff --git a/kernel/locking/qspinlock_paravirt.h b/kernel/locking/qspinlock_paravirt.h index 21ede57..37649e6 100644 --- a/kernel/locking/qspinlock_paravirt.h +++ b/kernel/locking/qspinlock_paravirt.h @@ -112,12 +112,12 @@ static __always_inline int trylock_clear_pending(struct qspinlock *lock) #else /* _Q_PENDING_BITS == 8 */ static __always_inline void set_pending(struct qspinlock *lock) { - atomic_set_mask(_Q_PENDING_VAL, &lock->val); + atomic_or(_Q_PENDING_VAL, &lock->val); } static __always_inline void clear_pending(struct qspinlock *lock) { - atomic_clear_mask(_Q_PENDING_VAL, &lock->val); + atomic_andnot(_Q_PENDING_VAL, &lock->val); } static __always_inline int trylock_clear_pending(struct qspinlock *lock) -- cgit v0.10.2 From fe14d2f12d5e641f114e27c2ea1fb85843c58967 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Mon, 18 Apr 2016 01:09:20 +0200 Subject: locking/atomic, arch/alpha: Convert to _relaxed atomics Generic code will construct {,_acquire,_release} versions by adding the required smp_mb__{before,after}_atomic() calls. Signed-off-by: Peter Zijlstra (Intel) Cc: Andrew Morton Cc: Ivan Kokshaysky Cc: Linus Torvalds Cc: Matt Turner Cc: Paul E. McKenney Cc: Peter Zijlstra Cc: Richard Henderson Cc: Thomas Gleixner Cc: linux-alpha@vger.kernel.org Cc: linux-arch@vger.kernel.org Cc: linux-kernel@vger.kernel.org Signed-off-by: Ingo Molnar diff --git a/arch/alpha/include/asm/atomic.h b/arch/alpha/include/asm/atomic.h index 5377ca8..498933a 100644 --- a/arch/alpha/include/asm/atomic.h +++ b/arch/alpha/include/asm/atomic.h @@ -46,10 +46,9 @@ static __inline__ void atomic_##op(int i, atomic_t * v) \ } \ #define ATOMIC_OP_RETURN(op, asm_op) \ -static inline int atomic_##op##_return(int i, atomic_t *v) \ +static inline int atomic_##op##_return_relaxed(int i, atomic_t *v) \ { \ long temp, result; \ - smp_mb(); \ __asm__ __volatile__( \ "1: ldl_l %0,%1\n" \ " " #asm_op " %0,%3,%2\n" \ @@ -61,15 +60,13 @@ static inline int atomic_##op##_return(int i, atomic_t *v) \ ".previous" \ :"=&r" (temp), "=m" (v->counter), "=&r" (result) \ :"Ir" (i), "m" (v->counter) : "memory"); \ - smp_mb(); \ return result; \ } #define ATOMIC_FETCH_OP(op, asm_op) \ -static inline int atomic_fetch_##op(int i, atomic_t *v) \ +static inline int atomic_fetch_##op##_relaxed(int i, atomic_t *v) \ { \ long temp, result; \ - smp_mb(); \ __asm__ __volatile__( \ "1: ldl_l %2,%1\n" \ " " #asm_op " %2,%3,%0\n" \ @@ -80,7 +77,6 @@ static inline int atomic_fetch_##op(int i, atomic_t *v) \ ".previous" \ :"=&r" (temp), "=m" (v->counter), "=&r" (result) \ :"Ir" (i), "m" (v->counter) : "memory"); \ - smp_mb(); \ return result; \ } @@ -101,10 +97,9 @@ static __inline__ void atomic64_##op(long i, atomic64_t * v) \ } \ #define ATOMIC64_OP_RETURN(op, asm_op) \ -static __inline__ long atomic64_##op##_return(long i, atomic64_t * v) \ +static __inline__ long atomic64_##op##_return_relaxed(long i, atomic64_t * v) \ { \ long temp, result; \ - smp_mb(); \ __asm__ __volatile__( \ "1: ldq_l %0,%1\n" \ " " #asm_op " %0,%3,%2\n" \ @@ -116,15 +111,13 @@ static __inline__ long atomic64_##op##_return(long i, atomic64_t * v) \ ".previous" \ :"=&r" (temp), "=m" (v->counter), "=&r" (result) \ :"Ir" (i), "m" (v->counter) : "memory"); \ - smp_mb(); \ return result; \ } #define ATOMIC64_FETCH_OP(op, asm_op) \ -static __inline__ long atomic64_fetch_##op(long i, atomic64_t * v) \ +static __inline__ long atomic64_fetch_##op##_relaxed(long i, atomic64_t * v) \ { \ long temp, result; \ - smp_mb(); \ __asm__ __volatile__( \ "1: ldq_l %2,%1\n" \ " " #asm_op " %2,%3,%0\n" \ @@ -135,7 +128,6 @@ static __inline__ long atomic64_fetch_##op(long i, atomic64_t * v) \ ".previous" \ :"=&r" (temp), "=m" (v->counter), "=&r" (result) \ :"Ir" (i), "m" (v->counter) : "memory"); \ - smp_mb(); \ return result; \ } @@ -150,6 +142,16 @@ static __inline__ long atomic64_fetch_##op(long i, atomic64_t * v) \ ATOMIC_OPS(add) ATOMIC_OPS(sub) +#define atomic_add_return_relaxed atomic_add_return_relaxed +#define atomic_sub_return_relaxed atomic_sub_return_relaxed +#define atomic_fetch_add_relaxed atomic_fetch_add_relaxed +#define atomic_fetch_sub_relaxed atomic_fetch_sub_relaxed + +#define atomic64_add_return_relaxed atomic64_add_return_relaxed +#define atomic64_sub_return_relaxed atomic64_sub_return_relaxed +#define atomic64_fetch_add_relaxed atomic64_fetch_add_relaxed +#define atomic64_fetch_sub_relaxed atomic64_fetch_sub_relaxed + #define atomic_andnot atomic_andnot #define atomic64_andnot atomic64_andnot @@ -165,6 +167,16 @@ ATOMIC_OPS(andnot, bic) ATOMIC_OPS(or, bis) ATOMIC_OPS(xor, xor) +#define atomic_fetch_and_relaxed atomic_fetch_and_relaxed +#define atomic_fetch_andnot_relaxed atomic_fetch_andnot_relaxed +#define atomic_fetch_or_relaxed atomic_fetch_or_relaxed +#define atomic_fetch_xor_relaxed atomic_fetch_xor_relaxed + +#define atomic64_fetch_and_relaxed atomic64_fetch_and_relaxed +#define atomic64_fetch_andnot_relaxed atomic64_fetch_andnot_relaxed +#define atomic64_fetch_or_relaxed atomic64_fetch_or_relaxed +#define atomic64_fetch_xor_relaxed atomic64_fetch_xor_relaxed + #undef ATOMIC_OPS #undef ATOMIC64_FETCH_OP #undef ATOMIC64_OP_RETURN -- cgit v0.10.2 From 4ec45856b698c37e73d973fb4b1a094dfb9d5732 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Mon, 18 Apr 2016 01:15:25 +0200 Subject: locking/atomic, arch/mips: Convert to _relaxed atomics Generic code will construct {,_acquire,_release} versions by adding the required smp_mb__{before,after}_atomic() calls. XXX if/when MIPS will start using their new SYNCxx instructions they can provide custom __atomic_op_{acquire,release}() macros as per the powerpc example. Signed-off-by: Peter Zijlstra (Intel) Cc: Andrew Morton Cc: Linus Torvalds Cc: Paul E. McKenney Cc: Peter Zijlstra Cc: Ralf Baechle Cc: Thomas Gleixner Cc: linux-arch@vger.kernel.org Cc: linux-kernel@vger.kernel.org Cc: linux-mips@linux-mips.org Signed-off-by: Ingo Molnar diff --git a/arch/mips/include/asm/atomic.h b/arch/mips/include/asm/atomic.h index 387ce28..0ab176b 100644 --- a/arch/mips/include/asm/atomic.h +++ b/arch/mips/include/asm/atomic.h @@ -79,12 +79,10 @@ static __inline__ void atomic_##op(int i, atomic_t * v) \ } #define ATOMIC_OP_RETURN(op, c_op, asm_op) \ -static __inline__ int atomic_##op##_return(int i, atomic_t * v) \ +static __inline__ int atomic_##op##_return_relaxed(int i, atomic_t * v) \ { \ int result; \ \ - smp_mb__before_llsc(); \ - \ if (kernel_uses_llsc && R10000_LLSC_WAR) { \ int temp; \ \ @@ -125,18 +123,14 @@ static __inline__ int atomic_##op##_return(int i, atomic_t * v) \ raw_local_irq_restore(flags); \ } \ \ - smp_llsc_mb(); \ - \ return result; \ } #define ATOMIC_FETCH_OP(op, c_op, asm_op) \ -static __inline__ int atomic_fetch_##op(int i, atomic_t * v) \ +static __inline__ int atomic_fetch_##op##_relaxed(int i, atomic_t * v) \ { \ int result; \ \ - smp_mb__before_llsc(); \ - \ if (kernel_uses_llsc && R10000_LLSC_WAR) { \ int temp; \ \ @@ -176,8 +170,6 @@ static __inline__ int atomic_fetch_##op(int i, atomic_t * v) \ raw_local_irq_restore(flags); \ } \ \ - smp_llsc_mb(); \ - \ return result; \ } @@ -189,6 +181,11 @@ static __inline__ int atomic_fetch_##op(int i, atomic_t * v) \ ATOMIC_OPS(add, +=, addu) ATOMIC_OPS(sub, -=, subu) +#define atomic_add_return_relaxed atomic_add_return_relaxed +#define atomic_sub_return_relaxed atomic_sub_return_relaxed +#define atomic_fetch_add_relaxed atomic_fetch_add_relaxed +#define atomic_fetch_sub_relaxed atomic_fetch_sub_relaxed + #undef ATOMIC_OPS #define ATOMIC_OPS(op, c_op, asm_op) \ ATOMIC_OP(op, c_op, asm_op) \ @@ -198,6 +195,10 @@ ATOMIC_OPS(and, &=, and) ATOMIC_OPS(or, |=, or) ATOMIC_OPS(xor, ^=, xor) +#define atomic_fetch_and_relaxed atomic_fetch_and_relaxed +#define atomic_fetch_or_relaxed atomic_fetch_or_relaxed +#define atomic_fetch_xor_relaxed atomic_fetch_xor_relaxed + #undef ATOMIC_OPS #undef ATOMIC_FETCH_OP #undef ATOMIC_OP_RETURN @@ -420,12 +421,10 @@ static __inline__ void atomic64_##op(long i, atomic64_t * v) \ } #define ATOMIC64_OP_RETURN(op, c_op, asm_op) \ -static __inline__ long atomic64_##op##_return(long i, atomic64_t * v) \ +static __inline__ long atomic64_##op##_return_relaxed(long i, atomic64_t * v) \ { \ long result; \ \ - smp_mb__before_llsc(); \ - \ if (kernel_uses_llsc && R10000_LLSC_WAR) { \ long temp; \ \ @@ -467,18 +466,14 @@ static __inline__ long atomic64_##op##_return(long i, atomic64_t * v) \ raw_local_irq_restore(flags); \ } \ \ - smp_llsc_mb(); \ - \ return result; \ } #define ATOMIC64_FETCH_OP(op, c_op, asm_op) \ -static __inline__ long atomic64_fetch_##op(long i, atomic64_t * v) \ +static __inline__ long atomic64_fetch_##op##_relaxed(long i, atomic64_t * v) \ { \ long result; \ \ - smp_mb__before_llsc(); \ - \ if (kernel_uses_llsc && R10000_LLSC_WAR) { \ long temp; \ \ @@ -519,8 +514,6 @@ static __inline__ long atomic64_fetch_##op(long i, atomic64_t * v) \ raw_local_irq_restore(flags); \ } \ \ - smp_llsc_mb(); \ - \ return result; \ } @@ -532,6 +525,11 @@ static __inline__ long atomic64_fetch_##op(long i, atomic64_t * v) \ ATOMIC64_OPS(add, +=, daddu) ATOMIC64_OPS(sub, -=, dsubu) +#define atomic64_add_return_relaxed atomic64_add_return_relaxed +#define atomic64_sub_return_relaxed atomic64_sub_return_relaxed +#define atomic64_fetch_add_relaxed atomic64_fetch_add_relaxed +#define atomic64_fetch_sub_relaxed atomic64_fetch_sub_relaxed + #undef ATOMIC64_OPS #define ATOMIC64_OPS(op, c_op, asm_op) \ ATOMIC64_OP(op, c_op, asm_op) \ @@ -541,6 +539,10 @@ ATOMIC64_OPS(and, &=, and) ATOMIC64_OPS(or, |=, or) ATOMIC64_OPS(xor, ^=, xor) +#define atomic64_fetch_and_relaxed atomic64_fetch_and_relaxed +#define atomic64_fetch_or_relaxed atomic64_fetch_or_relaxed +#define atomic64_fetch_xor_relaxed atomic64_fetch_xor_relaxed + #undef ATOMIC64_OPS #undef ATOMIC64_FETCH_OP #undef ATOMIC64_OP_RETURN -- cgit v0.10.2 From f9852b74bec0117b888da39d070c323ea1cb7f4c Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Mon, 18 Apr 2016 01:27:03 +0200 Subject: locking/atomic, arch/qrwlock: Employ atomic_fetch_add_acquire() The only reason for the current code is to make GCC emit only the "LOCK XADD" instruction on x86 (and not do a pointless extra ADD on the result), do so nicer. Signed-off-by: Peter Zijlstra (Intel) Acked-by: Waiman Long Cc: Andrew Morton Cc: Linus Torvalds Cc: Paul E. McKenney Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: linux-arch@vger.kernel.org Cc: linux-kernel@vger.kernel.org Signed-off-by: Ingo Molnar diff --git a/kernel/locking/qrwlock.c b/kernel/locking/qrwlock.c index fec0823..19248dd 100644 --- a/kernel/locking/qrwlock.c +++ b/kernel/locking/qrwlock.c @@ -93,7 +93,7 @@ void queued_read_lock_slowpath(struct qrwlock *lock, u32 cnts) * that accesses can't leak upwards out of our subsequent critical * section in the case that the lock is currently held for write. */ - cnts = atomic_add_return_acquire(_QR_BIAS, &lock->cnts) - _QR_BIAS; + cnts = atomic_fetch_add_acquire(_QR_BIAS, &lock->cnts); rspin_until_writer_unlock(lock, cnts); /* -- cgit v0.10.2 From 86a3b5f34fc1fb307abef4fde76bebd3edce0324 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Wed, 18 May 2016 12:42:21 +0200 Subject: locking/atomic, arch/rwsem: Employ atomic_long_fetch_add() Now that we have fetch_add() we can stop using add_return() - val. Signed-off-by: Peter Zijlstra (Intel) Cc: Andrew Morton Cc: Jason Low Cc: Linus Torvalds Cc: Paul E. McKenney Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: Waiman Long Cc: linux-arch@vger.kernel.org Cc: linux-kernel@vger.kernel.org Signed-off-by: Ingo Molnar diff --git a/kernel/locking/rwsem-xadd.c b/kernel/locking/rwsem-xadd.c index 2031281..447e08d 100644 --- a/kernel/locking/rwsem-xadd.c +++ b/kernel/locking/rwsem-xadd.c @@ -153,7 +153,7 @@ __rwsem_mark_wake(struct rw_semaphore *sem, if (wake_type != RWSEM_WAKE_READ_OWNED) { adjustment = RWSEM_ACTIVE_READ_BIAS; try_reader_grant: - oldcount = atomic_long_add_return(adjustment, &sem->count) - adjustment; + oldcount = atomic_long_fetch_add(adjustment, &sem->count); if (unlikely(oldcount < RWSEM_WAITING_BIAS)) { /* -- cgit v0.10.2 From c5379ba8fccd99d5f99632c789f0393d84a57805 Mon Sep 17 00:00:00 2001 From: Thomas Petazzoni Date: Thu, 16 Jun 2016 15:42:25 +0200 Subject: ARM: mvebu: fix HW I/O coherency related deadlocks Until now, our understanding for HW I/O coherency to work on the Cortex-A9 based Marvell SoC was that only the PCIe regions should be mapped strongly-ordered. However, we were still encountering some deadlocks, especially when testing the CESA crypto engine. After checking with the HW designers, it was concluded that all the MMIO registers should be mapped as strongly ordered for the HW I/O coherency mechanism to work properly. This fixes some easy to reproduce deadlocks with the CESA crypto engine driver (dmcrypt on a sufficiently large disk partition). Tested-by: Terry Stockert Tested-by: Romain Perier Cc: Terry Stockert Cc: Romain Perier Cc: Signed-off-by: Thomas Petazzoni Signed-off-by: Gregory CLEMENT diff --git a/arch/arm/mach-mvebu/coherency.c b/arch/arm/mach-mvebu/coherency.c index 7e989d6..474abff 100644 --- a/arch/arm/mach-mvebu/coherency.c +++ b/arch/arm/mach-mvebu/coherency.c @@ -162,22 +162,16 @@ exit: } /* - * This ioremap hook is used on Armada 375/38x to ensure that PCIe - * memory areas are mapped as MT_UNCACHED instead of MT_DEVICE. This - * is needed as a workaround for a deadlock issue between the PCIe - * interface and the cache controller. + * This ioremap hook is used on Armada 375/38x to ensure that all MMIO + * areas are mapped as MT_UNCACHED instead of MT_DEVICE. This is + * needed for the HW I/O coherency mechanism to work properly without + * deadlock. */ static void __iomem * -armada_pcie_wa_ioremap_caller(phys_addr_t phys_addr, size_t size, - unsigned int mtype, void *caller) +armada_wa_ioremap_caller(phys_addr_t phys_addr, size_t size, + unsigned int mtype, void *caller) { - struct resource pcie_mem; - - mvebu_mbus_get_pcie_mem_aperture(&pcie_mem); - - if (pcie_mem.start <= phys_addr && (phys_addr + size) <= pcie_mem.end) - mtype = MT_UNCACHED; - + mtype = MT_UNCACHED; return __arm_ioremap_caller(phys_addr, size, mtype, caller); } @@ -186,7 +180,7 @@ static void __init armada_375_380_coherency_init(struct device_node *np) struct device_node *cache_dn; coherency_cpu_base = of_iomap(np, 0); - arch_ioremap_caller = armada_pcie_wa_ioremap_caller; + arch_ioremap_caller = armada_wa_ioremap_caller; /* * We should switch the PL310 to I/O coherency mode only if -- cgit v0.10.2 From 6a02734d420fca778554878d03017017537d92e1 Mon Sep 17 00:00:00 2001 From: Thomas Petazzoni Date: Thu, 16 Jun 2016 15:42:26 +0200 Subject: ARM: mvebu: map PCI I/O regions strongly ordered In order for HW I/O coherency to work on Cortex-A9 based Marvell SoCs, all MMIO registers must be mapped strongly ordered. In commit 1c8c3cf0b5239 ("ARM: 8060/1: mm: allow sub-architectures to override PCI I/O memory type") we implemented a new function, pci_ioremap_set_mem_type(), that allow sub-architecture code to override the memory type used to map PCI I/O regions. In the discussion around this patch series [1], Arnd Bergmann made the comment that maybe all PCI I/O regions should be mapped strongly-ordered, which would have made our proposal to add pci_ioremap_set_mem_type() irrelevant. So, we submitted a patch [2] that did what Arnd suggested. However, Russell in the end merged our initial proposal to add pci_ioremap_set_mem_type(), but it was never used anywhere. Further discussion with Arnd and other folks on IRC lead to the conclusion that in fact using strongly-ordered for all platforms was maybe not desirable, and therefore, using pci_ioremap_set_mem_type() was the most appropriate solution. As a consequence, this commit finally adds the pci_ioremap_set_mem_type() call in the mach-mvebu platform code, which was originally part of our initial patch series [3] and is necessary for the whole mechanism to work. [1] http://lists.infradead.org/pipermail/linux-arm-kernel/2014-May/256565.html [2] http://lists.infradead.org/pipermail/linux-arm-kernel/2014-May/256755.html [3] http://lists.infradead.org/pipermail/linux-arm-kernel/2014-May/256563.html Signed-off-by: Thomas Petazzoni Signed-off-by: Gregory CLEMENT diff --git a/arch/arm/mach-mvebu/coherency.c b/arch/arm/mach-mvebu/coherency.c index 474abff..e80f0dd 100644 --- a/arch/arm/mach-mvebu/coherency.c +++ b/arch/arm/mach-mvebu/coherency.c @@ -181,6 +181,7 @@ static void __init armada_375_380_coherency_init(struct device_node *np) coherency_cpu_base = of_iomap(np, 0); arch_ioremap_caller = armada_wa_ioremap_caller; + pci_ioremap_set_mem_type(MT_UNCACHED); /* * We should switch the PL310 to I/O coherency mode only if -- cgit v0.10.2 From 929e604efa3dc0522214e0dc18984be23993e9f0 Mon Sep 17 00:00:00 2001 From: Thomas Petazzoni Date: Thu, 16 Jun 2016 15:42:27 +0200 Subject: ARM: dts: armada-38x: fix MBUS_ID for crypto SRAM on Armada 385 Linksys When the support for the Marvell crypto engine was added in the Device Tree of the various Armada 385 Device Tree files in commit d716f2e837ac6 ("ARM: mvebu: define crypto SRAM ranges for all armada-38x boards"), a typo was made in the MBus window attributes for the Armada 385 Linksys board: 0x09/0x05 are used instead of 0x19/0x15. This commit fixes this typo, which makes the CESA engines operational on Armada 385 Linksys boards. Reported-by: Terry Stockert Cc: Terry Stockert Cc: Imre Kaloz Cc: Boris Brezillon Cc: Fixes: d716f2e837ac6 ("ARM: mvebu: define crypto SRAM ranges for all armada-38x boards") Signed-off-by: Thomas Petazzoni Signed-off-by: Gregory CLEMENT diff --git a/arch/arm/boot/dts/armada-385-linksys.dtsi b/arch/arm/boot/dts/armada-385-linksys.dtsi index 8450944..22f7a13 100644 --- a/arch/arm/boot/dts/armada-385-linksys.dtsi +++ b/arch/arm/boot/dts/armada-385-linksys.dtsi @@ -58,8 +58,8 @@ soc { ranges = ; + MBUS_ID(0x09, 0x19) 0 0xf1100000 0x10000 + MBUS_ID(0x09, 0x15) 0 0xf1110000 0x10000>; internal-regs { -- cgit v0.10.2 From d945b5e9f0e35cb56a3783d849b5f0f37da0a7f1 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Thu, 16 Jun 2016 14:38:42 +0200 Subject: workqueue: Fix setting affinity of unbound worker threads With commit e9d867a67fd03ccc ("sched: Allow per-cpu kernel threads to run on online && !active"), __set_cpus_allowed_ptr() expects that only strict per-cpu kernel threads can have affinity to an online CPU which is not yet active. This assumption is currently broken in the CPU_ONLINE notification handler for the workqueues where restore_unbound_workers_cpumask() calls set_cpus_allowed_ptr() when the first cpu in the unbound worker's pool->attr->cpumask comes online. Since set_cpus_allowed_ptr() is called with pool->attr->cpumask in which only one CPU is online which is not yet active, we get the following WARN_ON during an CPU online operation. ------------[ cut here ]------------ WARNING: CPU: 40 PID: 248 at kernel/sched/core.c:1166 __set_cpus_allowed_ptr+0x228/0x2e0 Modules linked in: CPU: 40 PID: 248 Comm: cpuhp/40 Not tainted 4.6.0-autotest+ #4 <..snip..> Call Trace: [c000000f273ff920] [c00000000010493c] __set_cpus_allowed_ptr+0x2cc/0x2e0 (unreliable) [c000000f273ffac0] [c0000000000ed4b0] workqueue_cpu_up_callback+0x2c0/0x470 [c000000f273ffb70] [c0000000000f5c58] notifier_call_chain+0x98/0x100 [c000000f273ffbc0] [c0000000000c5ed0] __cpu_notify+0x70/0xe0 [c000000f273ffc00] [c0000000000c6028] notify_online+0x38/0x50 [c000000f273ffc30] [c0000000000c5214] cpuhp_invoke_callback+0x84/0x250 [c000000f273ffc90] [c0000000000c562c] cpuhp_up_callbacks+0x5c/0x120 [c000000f273ffce0] [c0000000000c64d4] cpuhp_thread_fun+0x184/0x1c0 [c000000f273ffd20] [c0000000000fa050] smpboot_thread_fn+0x290/0x2a0 [c000000f273ffd80] [c0000000000f45b0] kthread+0x110/0x130 [c000000f273ffe30] [c000000000009570] ret_from_kernel_thread+0x5c/0x6c ---[ end trace 00f1456578b2a3b2 ]--- This patch fixes this by limiting the mask to the intersection of the pool affinity and online CPUs. Changelog-cribbed-from: Gautham R. Shenoy Reported-by: Abdul Haleem Signed-off-by: Peter Zijlstra (Intel) Signed-off-by: Tejun Heo diff --git a/kernel/workqueue.c b/kernel/workqueue.c index e1c0e99..97e7b79 100644 --- a/kernel/workqueue.c +++ b/kernel/workqueue.c @@ -4600,15 +4600,11 @@ static void restore_unbound_workers_cpumask(struct worker_pool *pool, int cpu) if (!cpumask_test_cpu(cpu, pool->attrs->cpumask)) return; - /* is @cpu the only online CPU? */ cpumask_and(&cpumask, pool->attrs->cpumask, cpu_online_mask); - if (cpumask_weight(&cpumask) != 1) - return; /* as we're called from CPU_ONLINE, the following shouldn't fail */ for_each_pool_worker(worker, pool) - WARN_ON_ONCE(set_cpus_allowed_ptr(worker->task, - pool->attrs->cpumask) < 0); + WARN_ON_ONCE(set_cpus_allowed_ptr(worker->task, &cpumask) < 0); } /* -- cgit v0.10.2 From ebff09a6ff164aec2b33bf1f9a488c45ac108413 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Wed, 15 Jun 2016 16:08:17 -0700 Subject: locking/Documentation: Clarify limited control-dependency scope Nothing in the control-dependencies section of memory-barriers.txt says that control dependencies don't extend beyond the end of the if-statement containing the control dependency. Worse yet, in many situations, they do extend beyond that if-statement. In particular, the compiler cannot destroy the control dependency given proper use of READ_ONCE() and WRITE_ONCE(). However, a weakly ordered system having a conditional-move instruction provides the control-dependency guarantee only to code within the scope of the if-statement itself. This commit therefore adds words and an example demonstrating this limitation of control dependencies. Reported-by: Will Deacon Signed-off-by: Paul E. McKenney Acked-by: Peter Zijlstra (Intel) Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: corbet@lwn.net Cc: linux-arch@vger.kernel.org Cc: linux-doc@vger.kernel.org Link: http://lkml.kernel.org/r/20160615230817.GA18039@linux.vnet.ibm.com Signed-off-by: Ingo Molnar diff --git a/Documentation/memory-barriers.txt b/Documentation/memory-barriers.txt index 147ae8e..a4d0a99 100644 --- a/Documentation/memory-barriers.txt +++ b/Documentation/memory-barriers.txt @@ -806,6 +806,41 @@ out-guess your code. More generally, although READ_ONCE() does force the compiler to actually emit code for a given load, it does not force the compiler to use the results. +In addition, control dependencies apply only to the then-clause and +else-clause of the if-statement in question. In particular, it does +not necessarily apply to code following the if-statement: + + q = READ_ONCE(a); + if (q) { + WRITE_ONCE(b, p); + } else { + WRITE_ONCE(b, r); + } + WRITE_ONCE(c, 1); /* BUG: No ordering against the read from "a". */ + +It is tempting to argue that there in fact is ordering because the +compiler cannot reorder volatile accesses and also cannot reorder +the writes to "b" with the condition. Unfortunately for this line +of reasoning, the compiler might compile the two writes to "b" as +conditional-move instructions, as in this fanciful pseudo-assembly +language: + + ld r1,a + ld r2,p + ld r3,r + cmp r1,$0 + cmov,ne r4,r2 + cmov,eq r4,r3 + st r4,b + st $1,c + +A weakly ordered CPU would have no dependency of any sort between the load +from "a" and the store to "c". The control dependencies would extend +only to the pair of cmov instructions and the store depending on them. +In short, control dependencies apply only to the stores in the then-clause +and else-clause of the if-statement in question (including functions +invoked by those two clauses), not to code following that if-statement. + Finally, control dependencies do -not- provide transitivity. This is demonstrated by two related examples, with the initial values of x and y both being zero: @@ -869,6 +904,12 @@ In summary: atomic{,64}_read() can help to preserve your control dependency. Please see the COMPILER BARRIER section for more information. + (*) Control dependencies apply only to the then-clause and else-clause + of the if-statement containing the control dependency, including + any functions that these two clauses call. Control dependencies + do -not- apply to code following the if-statement containing the + control dependency. + (*) Control dependencies pair normally with other types of barriers. (*) Control dependencies do -not- provide transitivity. If you -- cgit v0.10.2 From 50c7a0ef2d97e56c7ce2f1ea5fe1d8e25aadc1bb Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 16 Jun 2016 14:34:32 +0200 Subject: ASoC: wm8940: Enable cache usage to fix crashes on resume The wm8940 driver is using a regmap cache sync to restore the configuration of the chip when switching from OFF to STANDBY, but does not actually define a register cache which means that the restore is never going to work and we trigger asserts in regmap. Fix this by enabling caching. Based on commit d3030d11961a8c10 ("ASoC: ak4642: Enable cache usage to fix crashes on resume") by Mark Brown . Signed-off-by: Geert Uytterhoeven Acked-by: Charles Keepax Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/wm8940.c b/sound/soc/codecs/wm8940.c index f6f9395..1c60081 100644 --- a/sound/soc/codecs/wm8940.c +++ b/sound/soc/codecs/wm8940.c @@ -743,6 +743,7 @@ static const struct regmap_config wm8940_regmap = { .max_register = WM8940_MONOMIX, .reg_defaults = wm8940_reg_defaults, .num_reg_defaults = ARRAY_SIZE(wm8940_reg_defaults), + .cache_type = REGCACHE_RBTREE, .readable_reg = wm8940_readable_register, .volatile_reg = wm8940_volatile_register, -- cgit v0.10.2 From dcd2d1f78664fdc75eadaaf65257834e24383d01 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 16 Jun 2016 14:34:30 +0200 Subject: ASoC: ak4613: Enable cache usage to fix crashes on resume During system resume: kernel BUG at drivers/base/regmap/regcache.c:347! ... PC is at regcache_sync+0x1c/0x128 LR is at ak4613_resume+0x28/0x34 The ak4613 driver is using a regmap cache sync to restore the configuration of the chip on resume but does not actually define a register cache which means that the resume is never going to work and we trigger asserts in regmap. Fix this by enabling caching. Based on commit d3030d11961a8c10 ("ASoC: ak4642: Enable cache usage to fix crashes on resume") by Mark Brown . Signed-off-by: Geert Uytterhoeven Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/ak4613.c b/sound/soc/codecs/ak4613.c index 33d2f2e1..5013d2b 100644 --- a/sound/soc/codecs/ak4613.c +++ b/sound/soc/codecs/ak4613.c @@ -146,6 +146,7 @@ static const struct regmap_config ak4613_regmap_cfg = { .max_register = 0x16, .reg_defaults = ak4613_reg, .num_reg_defaults = ARRAY_SIZE(ak4613_reg), + .cache_type = REGCACHE_RBTREE, }; static const struct of_device_id ak4613_of_match[] = { -- cgit v0.10.2 From 86c0ae7cde7a8699116b365a5e3016753f0cd92a Mon Sep 17 00:00:00 2001 From: Janusz Krzysztofik Date: Thu, 16 Jun 2016 22:04:35 +0200 Subject: ASoC: cx20442: set tty->receiver_room in v253_open Commit 79901317ce80 ("n_tty: Don't flush buffer when closing ldisc"), introduced in v3.10, revealed a bug in the cx20442 codec driver which has never been setting tty->receive_room on line discipline open as it should from the beginning. Fix it. Created and tested on Amstrad Delta against Linux-4.7-rc3 Signed-off-by: Janusz Krzysztofik Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/cx20442.c b/sound/soc/codecs/cx20442.c index d6f4abb..fb3885f 100644 --- a/sound/soc/codecs/cx20442.c +++ b/sound/soc/codecs/cx20442.c @@ -226,6 +226,7 @@ static int v253_open(struct tty_struct *tty) if (!tty->disc_data) return -ENODEV; + tty->receive_room = 16; if (tty->ops->write(tty, v253_init, len) != len) { ret = -EIO; goto err; -- cgit v0.10.2 From 1e875f5a95a28b5286165db9fa832b0773657ddb Mon Sep 17 00:00:00 2001 From: Andreas Gruenbacher Date: Fri, 17 Jun 2016 07:22:15 -0500 Subject: gfs2: Initialize iopen glock holder for new inodes In gfs2_init_inode_once, initialize inode->i_iopen_gh.gh_gl to NULL: otherwise, when gfs2_inode_lookup fails, the iopen glock holder can remain unset and iget_failed can end up accessing random memory. Signed-off-by: Andreas Gruenbacher Signed-off-by: Bob Peterson diff --git a/fs/gfs2/main.c b/fs/gfs2/main.c index f99f8e9..615f675 100644 --- a/fs/gfs2/main.c +++ b/fs/gfs2/main.c @@ -45,6 +45,7 @@ static void gfs2_init_inode_once(void *foo) memset(&ip->i_res, 0, sizeof(ip->i_res)); RB_CLEAR_NODE(&ip->i_res.rs_node); ip->i_hash_cache = NULL; + ip->i_iopen_gh.gh_gl = NULL; } static void gfs2_init_glock_once(void *foo) -- cgit v0.10.2 From 04a6284fb0b7a8e618e126695195d3aa64b626fd Mon Sep 17 00:00:00 2001 From: Nathaniel Clark Date: Thu, 9 Jun 2016 22:35:11 -0400 Subject: staging/lustre/osc: Fix Multiple Assignment Warnings Fix all multiple assignments on lustre/osc directory. Signed-off-by: Nathaniel Clark Signed-off-by: Oleg Drokin Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/lustre/lustre/osc/osc_cache.c b/drivers/staging/lustre/lustre/osc/osc_cache.c index 5a14bea..2ca5045 100644 --- a/drivers/staging/lustre/lustre/osc/osc_cache.c +++ b/drivers/staging/lustre/lustre/osc/osc_cache.c @@ -2773,7 +2773,8 @@ int osc_queue_sync_pages(const struct lu_env *env, struct osc_object *obj, ext->oe_sync = 1; ext->oe_urgent = 1; ext->oe_start = start; - ext->oe_end = ext->oe_max_end = end; + ext->oe_end = end; + ext->oe_max_end = end; ext->oe_obj = obj; ext->oe_srvlock = !!(brw_flags & OBD_BRW_SRVLOCK); ext->oe_nr_pages = page_count; @@ -3308,7 +3309,8 @@ int osc_lock_discard_pages(const struct lu_env *env, struct osc_object *osc, goto out; cb = mode == CLM_READ ? check_and_discard_cb : discard_cb; - info->oti_fn_index = info->oti_next_index = start; + info->oti_fn_index = start; + info->oti_next_index = start; do { res = osc_page_gang_lookup(env, io, osc, info->oti_next_index, end, cb, osc); diff --git a/drivers/staging/lustre/lustre/osc/osc_io.c b/drivers/staging/lustre/lustre/osc/osc_io.c index d534b0e..d3bce45 100644 --- a/drivers/staging/lustre/lustre/osc/osc_io.c +++ b/drivers/staging/lustre/lustre/osc/osc_io.c @@ -221,7 +221,8 @@ static void osc_page_touch_at(const struct lu_env *env, kms > loi->loi_kms ? "" : "not ", loi->loi_kms, kms, loi->loi_lvb.lvb_size); - attr->cat_mtime = attr->cat_ctime = LTIME_S(CURRENT_TIME); + attr->cat_ctime = LTIME_S(CURRENT_TIME); + attr->cat_mtime = attr->cat_ctime; valid = CAT_MTIME | CAT_CTIME; if (kms > loi->loi_kms) { attr->cat_kms = kms; @@ -458,7 +459,8 @@ static int osc_io_setattr_start(const struct lu_env *env, unsigned int cl_valid = 0; if (ia_valid & ATTR_SIZE) { - attr->cat_size = attr->cat_kms = size; + attr->cat_size = size; + attr->cat_kms = size; cl_valid = CAT_SIZE | CAT_KMS; } if (ia_valid & ATTR_MTIME_SET) { @@ -526,7 +528,8 @@ static void osc_io_setattr_end(const struct lu_env *env, if (cbargs->opc_rpc_sent) { wait_for_completion(&cbargs->opc_sync); - result = io->ci_result = cbargs->opc_rc; + result = cbargs->opc_rc; + io->ci_result = cbargs->opc_rc; } if (result == 0) { if (oio->oi_lockless) { @@ -575,7 +578,8 @@ static int osc_io_write_start(const struct lu_env *env, OBD_FAIL_TIMEOUT(OBD_FAIL_OSC_DELAY_SETTIME, 1); cl_object_attr_lock(obj); - attr->cat_mtime = attr->cat_ctime = ktime_get_real_seconds(); + attr->cat_ctime = ktime_get_real_seconds(); + attr->cat_mtime = attr->cat_ctime; rc = cl_object_attr_set(env, obj, attr, CAT_MTIME | CAT_CTIME); cl_object_attr_unlock(obj); diff --git a/drivers/staging/lustre/lustre/osc/osc_lock.c b/drivers/staging/lustre/lustre/osc/osc_lock.c index 16f9cd9..d30ed2f 100644 --- a/drivers/staging/lustre/lustre/osc/osc_lock.c +++ b/drivers/staging/lustre/lustre/osc/osc_lock.c @@ -1120,7 +1120,8 @@ static void osc_lock_set_writer(const struct lu_env *env, } } else { LASSERT(cl_io_is_mkwrite(io)); - io_start = io_end = io->u.ci_fault.ft_index; + io_start = io->u.ci_fault.ft_index; + io_end = io->u.ci_fault.ft_index; } if (descr->cld_mode >= CLM_WRITE && diff --git a/drivers/staging/lustre/lustre/osc/osc_request.c b/drivers/staging/lustre/lustre/osc/osc_request.c index 47417f8..7b1fc7e 100644 --- a/drivers/staging/lustre/lustre/osc/osc_request.c +++ b/drivers/staging/lustre/lustre/osc/osc_request.c @@ -474,7 +474,8 @@ static int osc_real_create(struct obd_export *exp, struct obdo *oa, DEBUG_REQ(D_HA, req, "delorphan from OST integration"); /* Don't resend the delorphan req */ - req->rq_no_resend = req->rq_no_delay = 1; + req->rq_no_resend = 1; + req->rq_no_delay = 1; } rc = ptlrpc_queue_wait(req); @@ -2775,7 +2776,8 @@ static int osc_get_info(const struct lu_env *env, struct obd_export *exp, tmp = req_capsule_client_get(&req->rq_pill, &RMF_SETINFO_KEY); memcpy(tmp, key, keylen); - req->rq_no_delay = req->rq_no_resend = 1; + req->rq_no_delay = 1; + req->rq_no_resend = 1; ptlrpc_request_set_replen(req); rc = ptlrpc_queue_wait(req); if (rc) -- cgit v0.10.2 From a30dd801fad1ff961c8eb28850b3b8d013316743 Mon Sep 17 00:00:00 2001 From: Nathaniel Clark Date: Thu, 9 Jun 2016 22:35:12 -0400 Subject: staging/lustre/fid: Fix Multiple Assignments Fix all multiple assignments on lustre/fid directory. Signed-off-by: Nathaniel Clark Signed-off-by: Oleg Drokin Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/lustre/lustre/fid/fid_request.c b/drivers/staging/lustre/lustre/fid/fid_request.c index 3a4df62..9db21ba 100644 --- a/drivers/staging/lustre/lustre/fid/fid_request.c +++ b/drivers/staging/lustre/lustre/fid/fid_request.c @@ -98,8 +98,10 @@ static int seq_client_rpc(struct lu_client_seq *seq, * request here, otherwise if MDT0 is failed(umounted), * it can not release the export of MDT0 */ - if (seq->lcs_type == LUSTRE_SEQ_DATA) - req->rq_no_delay = req->rq_no_resend = 1; + if (seq->lcs_type == LUSTRE_SEQ_DATA) { + req->rq_no_delay = 1; + req->rq_no_resend = 1; + } debug_mask = D_CONSOLE; } else { if (seq->lcs_type == LUSTRE_SEQ_METADATA) { -- cgit v0.10.2 From 95c9c00886a8c2c053bc2e5f6ebf3b8b3490d608 Mon Sep 17 00:00:00 2001 From: Nathaniel Clark Date: Thu, 9 Jun 2016 22:35:13 -0400 Subject: staging/lustre/ldlm: Fix Multiple Assignments Fix all multiple assignments on lustre/ldlm directory. Signed-off-by: Nathaniel Clark Signed-off-by: Oleg Drokin Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/lustre/lustre/ldlm/ldlm_lib.c b/drivers/staging/lustre/lustre/ldlm/ldlm_lib.c index b4ffbe2..b6a90b0 100644 --- a/drivers/staging/lustre/lustre/ldlm/ldlm_lib.c +++ b/drivers/staging/lustre/lustre/ldlm/ldlm_lib.c @@ -345,7 +345,8 @@ int client_obd_setup(struct obd_device *obddev, struct lustre_cfg *lcfg) * Set cl_chksum* to CRC32 for now to avoid returning screwed info * through procfs. */ - cli->cl_cksum_type = cli->cl_supp_cksum_types = OBD_CKSUM_CRC32; + cli->cl_cksum_type = OBD_CKSUM_CRC32; + cli->cl_supp_cksum_types = OBD_CKSUM_CRC32; atomic_set(&cli->cl_resends, OSC_DEFAULT_RESENDS); /* This value may be reduced at connect time in diff --git a/drivers/staging/lustre/lustre/ldlm/ldlm_lockd.c b/drivers/staging/lustre/lustre/ldlm/ldlm_lockd.c index ab739f0..3303ffa 100644 --- a/drivers/staging/lustre/lustre/ldlm/ldlm_lockd.c +++ b/drivers/staging/lustre/lustre/ldlm/ldlm_lockd.c @@ -1011,9 +1011,11 @@ static int ldlm_setup(void) blp->blp_min_threads = LDLM_NTHRS_INIT; blp->blp_max_threads = LDLM_NTHRS_MAX; } else { - blp->blp_min_threads = blp->blp_max_threads = - min_t(int, LDLM_NTHRS_MAX, max_t(int, LDLM_NTHRS_INIT, - ldlm_num_threads)); + blp->blp_min_threads = min_t(int, LDLM_NTHRS_MAX, + max_t(int, LDLM_NTHRS_INIT, + ldlm_num_threads)); + + blp->blp_max_threads = blp->blp_min_threads; } for (i = 0; i < blp->blp_min_threads; i++) { -- cgit v0.10.2 From 7551b8b5a97d5b6b2cab52ed7deabdb5f90fe787 Mon Sep 17 00:00:00 2001 From: Nathaniel Clark Date: Thu, 9 Jun 2016 22:35:14 -0400 Subject: staging/lustre/llite: Fix Multiple Assignments Fix all multiple assignments on lustre/llite directory. Signed-off-by: Nathaniel Clark Signed-off-by: Oleg Drokin Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/lustre/lustre/llite/llite_lib.c b/drivers/staging/lustre/lustre/llite/llite_lib.c index 96c7e9f..b260f60 100644 --- a/drivers/staging/lustre/lustre/llite/llite_lib.c +++ b/drivers/staging/lustre/lustre/llite/llite_lib.c @@ -864,7 +864,8 @@ int ll_fill_super(struct super_block *sb, struct vfsmount *mnt) try_module_get(THIS_MODULE); /* client additional sb info */ - lsi->lsi_llsbi = sbi = ll_init_sbi(sb); + sbi = ll_init_sbi(sb); + lsi->lsi_llsbi = sbi; if (!sbi) { module_put(THIS_MODULE); kfree(cfg); diff --git a/drivers/staging/lustre/lustre/llite/namei.c b/drivers/staging/lustre/lustre/llite/namei.c index 5eba0eb..95643bc 100644 --- a/drivers/staging/lustre/lustre/llite/namei.c +++ b/drivers/staging/lustre/lustre/llite/namei.c @@ -318,7 +318,8 @@ static struct dentry *ll_find_alias(struct inode *inode, struct dentry *dentry) if (hlist_empty(&inode->i_dentry)) return NULL; - discon_alias = invalid_alias = NULL; + discon_alias = NULL; + invalid_alias = NULL; ll_lock_dcache(inode); hlist_for_each_entry(alias, &inode->i_dentry, d_u.d_alias) { diff --git a/drivers/staging/lustre/lustre/llite/vvp_io.c b/drivers/staging/lustre/lustre/llite/vvp_io.c index e26e0f8..763d336 100644 --- a/drivers/staging/lustre/lustre/llite/vvp_io.c +++ b/drivers/staging/lustre/lustre/llite/vvp_io.c @@ -954,7 +954,8 @@ static int vvp_io_write_start(const struct lu_env *env, * out-of-order writes. */ ll_merge_attr(env, inode); - pos = io->u.ci_wr.wr.crw_pos = i_size_read(inode); + pos = i_size_read(inode); + io->u.ci_wr.wr.crw_pos = pos; vio->vui_iocb->ki_pos = pos; } else { LASSERT(vio->vui_iocb->ki_pos == pos); -- cgit v0.10.2 From a3f16d017f10e89b5544f56b885eb4ce1b8d8811 Mon Sep 17 00:00:00 2001 From: Nathaniel Clark Date: Thu, 9 Jun 2016 22:35:15 -0400 Subject: staging/lustre/lov: Fix Multiple Assignments Fix all multiple assignments on lustre/lov directory. Signed-off-by: Nathaniel Clark Signed-off-by: Oleg Drokin Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/lustre/lustre/lov/lov_obd.c b/drivers/staging/lustre/lustre/lov/lov_obd.c index e15ef2e..c179b31 100644 --- a/drivers/staging/lustre/lustre/lov/lov_obd.c +++ b/drivers/staging/lustre/lustre/lov/lov_obd.c @@ -1772,7 +1772,8 @@ static int lov_fiemap(struct lov_obd *lov, __u32 keylen, void *key, fm_start = fiemap->fm_start; fm_length = fiemap->fm_length; /* Calculate start stripe, last stripe and length of mapping */ - actual_start_stripe = start_stripe = lov_stripe_number(lsm, fm_start); + start_stripe = lov_stripe_number(lsm, fm_start); + actual_start_stripe = start_stripe; fm_end = (fm_length == ~0ULL ? fm_key->oa.o_size : fm_start + fm_length - 1); /* If fm_length != ~0ULL but fm_start+fm_length-1 exceeds file size */ @@ -2095,11 +2096,9 @@ static int lov_set_info_async(const struct lu_env *env, struct obd_export *exp, u32 count; int i, rc = 0, err; struct lov_tgt_desc *tgt; - unsigned incr, check_uuid, - do_inactive, no_set; - unsigned next_id = 0, mds_con = 0; + unsigned int incr = 0, check_uuid = 0, do_inactive = 0, no_set = 0; + unsigned int next_id = 0, mds_con = 0; - incr = check_uuid = do_inactive = no_set = 0; if (!set) { no_set = 1; set = ptlrpc_prep_set(); -- cgit v0.10.2 From 89c60364978977411efc4b5292d77d2dadd2cb50 Mon Sep 17 00:00:00 2001 From: Nathaniel Clark Date: Thu, 9 Jun 2016 22:35:16 -0400 Subject: staging/lustre/obdclass: Fix Multiple Assignments Fix all multiple assignments on lustre/obdclass directory. Signed-off-by: Nathaniel Clark Signed-off-by: Oleg Drokin Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/lustre/lustre/obdclass/llog.c b/drivers/staging/lustre/lustre/obdclass/llog.c index 79194d8..55a9755 100644 --- a/drivers/staging/lustre/lustre/obdclass/llog.c +++ b/drivers/staging/lustre/lustre/obdclass/llog.c @@ -123,8 +123,10 @@ static int llog_read_header(const struct lu_env *env, handle->lgh_last_idx = 0; /* header is record with index 0 */ llh->llh_count = 1; /* for the header record */ llh->llh_hdr.lrh_type = LLOG_HDR_MAGIC; - llh->llh_hdr.lrh_len = llh->llh_tail.lrt_len = LLOG_CHUNK_SIZE; - llh->llh_hdr.lrh_index = llh->llh_tail.lrt_index = 0; + llh->llh_hdr.lrh_len = LLOG_CHUNK_SIZE; + llh->llh_tail.lrt_len = LLOG_CHUNK_SIZE; + llh->llh_hdr.lrh_index = 0; + llh->llh_tail.lrt_index = 0; llh->llh_timestamp = ktime_get_real_seconds(); if (uuid) memcpy(&llh->llh_tgtuuid, uuid, -- cgit v0.10.2 From 3d2b8f5719bb3db99d5ed4a84ab8a7b899ce796a Mon Sep 17 00:00:00 2001 From: Nathaniel Clark Date: Thu, 9 Jun 2016 22:35:17 -0400 Subject: staging/lustre/ptlrpc: Fix Multiple Assignments Fix all multiple assignments on lustre/ptlrpc directory. Signed-off-by: Nathaniel Clark Signed-off-by: Oleg Drokin Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/lustre/lustre/ptlrpc/client.c b/drivers/staging/lustre/lustre/ptlrpc/client.c index 4b7912a..8336ed1 100644 --- a/drivers/staging/lustre/lustre/ptlrpc/client.c +++ b/drivers/staging/lustre/lustre/ptlrpc/client.c @@ -3024,8 +3024,10 @@ void *ptlrpcd_alloc_work(struct obd_import *imp, req->rq_interpret_reply = work_interpreter; /* don't want reply */ req->rq_receiving_reply = 0; - req->rq_req_unlink = req->rq_reply_unlink = 0; - req->rq_no_delay = req->rq_no_resend = 1; + req->rq_req_unlink = 0; + req->rq_reply_unlink = 0; + req->rq_no_delay = 1; + req->rq_no_resend = 1; req->rq_pill.rc_fmt = (void *)&worker_format; spin_lock_init(&req->rq_lock); diff --git a/drivers/staging/lustre/lustre/ptlrpc/import.c b/drivers/staging/lustre/lustre/ptlrpc/import.c index a4f7544..a236e38 100644 --- a/drivers/staging/lustre/lustre/ptlrpc/import.c +++ b/drivers/staging/lustre/lustre/ptlrpc/import.c @@ -698,7 +698,8 @@ int ptlrpc_connect_import(struct obd_import *imp) lustre_msg_add_op_flags(request->rq_reqmsg, MSG_CONNECT_NEXT_VER); - request->rq_no_resend = request->rq_no_delay = 1; + request->rq_no_resend = 1; + request->rq_no_delay = 1; request->rq_send_state = LUSTRE_IMP_CONNECTING; /* Allow a slightly larger reply for future growth compatibility */ req_capsule_set_size(&request->rq_pill, &RMF_CONNECT_DATA, RCL_SERVER, diff --git a/drivers/staging/lustre/lustre/ptlrpc/lproc_ptlrpc.c b/drivers/staging/lustre/lustre/ptlrpc/lproc_ptlrpc.c index 64c0f1e..ff40be2 100644 --- a/drivers/staging/lustre/lustre/ptlrpc/lproc_ptlrpc.c +++ b/drivers/staging/lustre/lustre/ptlrpc/lproc_ptlrpc.c @@ -872,7 +872,8 @@ ptlrpc_lprocfs_svc_req_history_next(struct seq_file *s, if (i > srhi->srhi_idx) { /* reset iterator for a new CPT */ srhi->srhi_req = NULL; - seq = srhi->srhi_seq = 0; + seq = 0; + srhi->srhi_seq = 0; } else { /* the next sequence */ seq = srhi->srhi_seq + (1 << svc->srv_cpt_bits); } diff --git a/drivers/staging/lustre/lustre/ptlrpc/pinger.c b/drivers/staging/lustre/lustre/ptlrpc/pinger.c index 8a86931..d9d4ca2 100644 --- a/drivers/staging/lustre/lustre/ptlrpc/pinger.c +++ b/drivers/staging/lustre/lustre/ptlrpc/pinger.c @@ -57,7 +57,8 @@ ptlrpc_prep_ping(struct obd_import *imp) LUSTRE_OBD_VERSION, OBD_PING); if (req) { ptlrpc_request_set_replen(req); - req->rq_no_resend = req->rq_no_delay = 1; + req->rq_no_resend = 1; + req->rq_no_delay = 1; } return req; } diff --git a/drivers/staging/lustre/lustre/ptlrpc/sec_null.c b/drivers/staging/lustre/lustre/ptlrpc/sec_null.c index 40e5349..af92e9e 100644 --- a/drivers/staging/lustre/lustre/ptlrpc/sec_null.c +++ b/drivers/staging/lustre/lustre/ptlrpc/sec_null.c @@ -265,7 +265,8 @@ int null_enlarge_reqbuf(struct ptlrpc_sec *sec, memcpy(newbuf, req->rq_reqbuf, req->rq_reqlen); kvfree(req->rq_reqbuf); - req->rq_reqbuf = req->rq_reqmsg = newbuf; + req->rq_reqbuf = newbuf; + req->rq_reqmsg = newbuf; req->rq_reqbuf_len = alloc_size; if (req->rq_import) -- cgit v0.10.2 From 77447a863f6a006c60c664349fe869d0e147f6ed Mon Sep 17 00:00:00 2001 From: Nathaniel Clark Date: Thu, 9 Jun 2016 22:35:18 -0400 Subject: staging/lustre/lmv: Fix Multiple Assignments Fix all multiple assignments on lustre/lmv directory. Signed-off-by: Nathaniel Clark Signed-off-by: Oleg Drokin Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/lustre/lustre/lmv/lmv_obd.c b/drivers/staging/lustre/lustre/lmv/lmv_obd.c index 9e31f6b..1d9875e 100644 --- a/drivers/staging/lustre/lustre/lmv/lmv_obd.c +++ b/drivers/staging/lustre/lustre/lmv/lmv_obd.c @@ -2686,7 +2686,7 @@ static int lmv_quotactl(struct obd_device *unused, struct obd_export *exp, struct lmv_obd *lmv = &obd->u.lmv; struct lmv_tgt_desc *tgt = lmv->tgts[0]; int rc = 0, i; - __u64 curspace, curinodes; + __u64 curspace = 0, curinodes = 0; if (!tgt || !tgt->ltd_exp || !tgt->ltd_active || !lmv->desc.ld_tgt_count) { @@ -2699,7 +2699,6 @@ static int lmv_quotactl(struct obd_device *unused, struct obd_export *exp, return rc; } - curspace = curinodes = 0; for (i = 0; i < lmv->desc.ld_tgt_count; i++) { int err; -- cgit v0.10.2 From 8d9de3f4859a24f06f7d136e32112cdf2fb893d9 Mon Sep 17 00:00:00 2001 From: James Simmons Date: Fri, 10 Jun 2016 16:13:39 -0400 Subject: staging: lustre: o2iblnd: remove typedefs Remove all remaining typedefs in o2iblnd driver. Signed-off-by: James Simmons Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c index 4bb32f1..3f3a9c1 100644 --- a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c +++ b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c @@ -44,7 +44,7 @@ static lnd_t the_o2iblnd; -kib_data_t kiblnd_data; +struct kib_data kiblnd_data; static __u32 kiblnd_cksum(void *ptr, int nob) { @@ -98,40 +98,40 @@ static char *kiblnd_msgtype2str(int type) static int kiblnd_msgtype2size(int type) { - const int hdr_size = offsetof(kib_msg_t, ibm_u); + const int hdr_size = offsetof(struct kib_msg, ibm_u); switch (type) { case IBLND_MSG_CONNREQ: case IBLND_MSG_CONNACK: - return hdr_size + sizeof(kib_connparams_t); + return hdr_size + sizeof(struct kib_connparams); case IBLND_MSG_NOOP: return hdr_size; case IBLND_MSG_IMMEDIATE: - return offsetof(kib_msg_t, ibm_u.immediate.ibim_payload[0]); + return offsetof(struct kib_msg, ibm_u.immediate.ibim_payload[0]); case IBLND_MSG_PUT_REQ: - return hdr_size + sizeof(kib_putreq_msg_t); + return hdr_size + sizeof(struct kib_putreq_msg); case IBLND_MSG_PUT_ACK: - return hdr_size + sizeof(kib_putack_msg_t); + return hdr_size + sizeof(struct kib_putack_msg); case IBLND_MSG_GET_REQ: - return hdr_size + sizeof(kib_get_msg_t); + return hdr_size + sizeof(struct kib_get_msg); case IBLND_MSG_PUT_NAK: case IBLND_MSG_PUT_DONE: case IBLND_MSG_GET_DONE: - return hdr_size + sizeof(kib_completion_msg_t); + return hdr_size + sizeof(struct kib_completion_msg); default: return -1; } } -static int kiblnd_unpack_rd(kib_msg_t *msg, int flip) +static int kiblnd_unpack_rd(struct kib_msg *msg, int flip) { - kib_rdma_desc_t *rd; + struct kib_rdma_desc *rd; int nob; int n; int i; @@ -156,7 +156,7 @@ static int kiblnd_unpack_rd(kib_msg_t *msg, int flip) return 1; } - nob = offsetof(kib_msg_t, ibm_u) + + nob = offsetof(struct kib_msg, ibm_u) + kiblnd_rd_msg_size(rd, msg->ibm_type, n); if (msg->ibm_nob < nob) { @@ -176,10 +176,10 @@ static int kiblnd_unpack_rd(kib_msg_t *msg, int flip) return 0; } -void kiblnd_pack_msg(lnet_ni_t *ni, kib_msg_t *msg, int version, +void kiblnd_pack_msg(lnet_ni_t *ni, struct kib_msg *msg, int version, int credits, lnet_nid_t dstnid, __u64 dststamp) { - kib_net_t *net = ni->ni_data; + struct kib_net *net = ni->ni_data; /* * CAVEAT EMPTOR! all message fields not set here should have been @@ -202,9 +202,9 @@ void kiblnd_pack_msg(lnet_ni_t *ni, kib_msg_t *msg, int version, } } -int kiblnd_unpack_msg(kib_msg_t *msg, int nob) +int kiblnd_unpack_msg(struct kib_msg *msg, int nob) { - const int hdr_size = offsetof(kib_msg_t, ibm_u); + const int hdr_size = offsetof(struct kib_msg, ibm_u); __u32 msg_cksum; __u16 version; int msg_nob; @@ -315,10 +315,10 @@ int kiblnd_unpack_msg(kib_msg_t *msg, int nob) return 0; } -int kiblnd_create_peer(lnet_ni_t *ni, kib_peer_t **peerp, lnet_nid_t nid) +int kiblnd_create_peer(lnet_ni_t *ni, struct kib_peer **peerp, lnet_nid_t nid) { - kib_peer_t *peer; - kib_net_t *net = ni->ni_data; + struct kib_peer *peer; + struct kib_net *net = ni->ni_data; int cpt = lnet_cpt_of_nid(nid); unsigned long flags; @@ -357,9 +357,9 @@ int kiblnd_create_peer(lnet_ni_t *ni, kib_peer_t **peerp, lnet_nid_t nid) return 0; } -void kiblnd_destroy_peer(kib_peer_t *peer) +void kiblnd_destroy_peer(struct kib_peer *peer) { - kib_net_t *net = peer->ibp_ni->ni_data; + struct kib_net *net = peer->ibp_ni->ni_data; LASSERT(net); LASSERT(!atomic_read(&peer->ibp_refcount)); @@ -378,7 +378,7 @@ void kiblnd_destroy_peer(kib_peer_t *peer) atomic_dec(&net->ibn_npeers); } -kib_peer_t *kiblnd_find_peer_locked(lnet_nid_t nid) +struct kib_peer *kiblnd_find_peer_locked(lnet_nid_t nid) { /* * the caller is responsible for accounting the additional reference @@ -386,10 +386,10 @@ kib_peer_t *kiblnd_find_peer_locked(lnet_nid_t nid) */ struct list_head *peer_list = kiblnd_nid2peerlist(nid); struct list_head *tmp; - kib_peer_t *peer; + struct kib_peer *peer; list_for_each(tmp, peer_list) { - peer = list_entry(tmp, kib_peer_t, ibp_list); + peer = list_entry(tmp, struct kib_peer, ibp_list); LASSERT(!kiblnd_peer_idle(peer)); if (peer->ibp_nid != nid) @@ -404,7 +404,7 @@ kib_peer_t *kiblnd_find_peer_locked(lnet_nid_t nid) return NULL; } -void kiblnd_unlink_peer_locked(kib_peer_t *peer) +void kiblnd_unlink_peer_locked(struct kib_peer *peer) { LASSERT(list_empty(&peer->ibp_conns)); @@ -417,7 +417,7 @@ void kiblnd_unlink_peer_locked(kib_peer_t *peer) static int kiblnd_get_peer_info(lnet_ni_t *ni, int index, lnet_nid_t *nidp, int *count) { - kib_peer_t *peer; + struct kib_peer *peer; struct list_head *ptmp; int i; unsigned long flags; @@ -426,7 +426,7 @@ static int kiblnd_get_peer_info(lnet_ni_t *ni, int index, for (i = 0; i < kiblnd_data.kib_peer_hash_size; i++) { list_for_each(ptmp, &kiblnd_data.kib_peers[i]) { - peer = list_entry(ptmp, kib_peer_t, ibp_list); + peer = list_entry(ptmp, struct kib_peer, ibp_list); LASSERT(!kiblnd_peer_idle(peer)); if (peer->ibp_ni != ni) @@ -448,17 +448,17 @@ static int kiblnd_get_peer_info(lnet_ni_t *ni, int index, return -ENOENT; } -static void kiblnd_del_peer_locked(kib_peer_t *peer) +static void kiblnd_del_peer_locked(struct kib_peer *peer) { struct list_head *ctmp; struct list_head *cnxt; - kib_conn_t *conn; + struct kib_conn *conn; if (list_empty(&peer->ibp_conns)) { kiblnd_unlink_peer_locked(peer); } else { list_for_each_safe(ctmp, cnxt, &peer->ibp_conns) { - conn = list_entry(ctmp, kib_conn_t, ibc_list); + conn = list_entry(ctmp, struct kib_conn, ibc_list); kiblnd_close_conn_locked(conn, 0); } @@ -475,7 +475,7 @@ static int kiblnd_del_peer(lnet_ni_t *ni, lnet_nid_t nid) LIST_HEAD(zombies); struct list_head *ptmp; struct list_head *pnxt; - kib_peer_t *peer; + struct kib_peer *peer; int lo; int hi; int i; @@ -494,7 +494,7 @@ static int kiblnd_del_peer(lnet_ni_t *ni, lnet_nid_t nid) for (i = lo; i <= hi; i++) { list_for_each_safe(ptmp, pnxt, &kiblnd_data.kib_peers[i]) { - peer = list_entry(ptmp, kib_peer_t, ibp_list); + peer = list_entry(ptmp, struct kib_peer, ibp_list); LASSERT(!kiblnd_peer_idle(peer)); if (peer->ibp_ni != ni) @@ -522,11 +522,11 @@ static int kiblnd_del_peer(lnet_ni_t *ni, lnet_nid_t nid) return rc; } -static kib_conn_t *kiblnd_get_conn_by_idx(lnet_ni_t *ni, int index) +static struct kib_conn *kiblnd_get_conn_by_idx(lnet_ni_t *ni, int index) { - kib_peer_t *peer; + struct kib_peer *peer; struct list_head *ptmp; - kib_conn_t *conn; + struct kib_conn *conn; struct list_head *ctmp; int i; unsigned long flags; @@ -535,7 +535,7 @@ static kib_conn_t *kiblnd_get_conn_by_idx(lnet_ni_t *ni, int index) for (i = 0; i < kiblnd_data.kib_peer_hash_size; i++) { list_for_each(ptmp, &kiblnd_data.kib_peers[i]) { - peer = list_entry(ptmp, kib_peer_t, ibp_list); + peer = list_entry(ptmp, struct kib_peer, ibp_list); LASSERT(!kiblnd_peer_idle(peer)); if (peer->ibp_ni != ni) @@ -545,7 +545,7 @@ static kib_conn_t *kiblnd_get_conn_by_idx(lnet_ni_t *ni, int index) if (index-- > 0) continue; - conn = list_entry(ctmp, kib_conn_t, + conn = list_entry(ctmp, struct kib_conn, ibc_list); kiblnd_conn_addref(conn); read_unlock_irqrestore( @@ -594,7 +594,7 @@ static void kiblnd_setup_mtu_locked(struct rdma_cm_id *cmid) cmid->route.path_rec->mtu = mtu; } -static int kiblnd_get_completion_vector(kib_conn_t *conn, int cpt) +static int kiblnd_get_completion_vector(struct kib_conn *conn, int cpt) { cpumask_t *mask; int vectors; @@ -621,7 +621,7 @@ static int kiblnd_get_completion_vector(kib_conn_t *conn, int cpt) return 1; } -kib_conn_t *kiblnd_create_conn(kib_peer_t *peer, struct rdma_cm_id *cmid, +struct kib_conn *kiblnd_create_conn(struct kib_peer *peer, struct rdma_cm_id *cmid, int state, int version) { /* @@ -634,12 +634,12 @@ kib_conn_t *kiblnd_create_conn(kib_peer_t *peer, struct rdma_cm_id *cmid, * its ref on 'cmid'). */ rwlock_t *glock = &kiblnd_data.kib_global_lock; - kib_net_t *net = peer->ibp_ni->ni_data; - kib_dev_t *dev; + struct kib_net *net = peer->ibp_ni->ni_data; + struct kib_dev *dev; struct ib_qp_init_attr *init_qp_attr; struct kib_sched_info *sched; struct ib_cq_init_attr cq_attr = {}; - kib_conn_t *conn; + struct kib_conn *conn; struct ib_cq *cq; unsigned long flags; int cpt; @@ -723,7 +723,7 @@ kib_conn_t *kiblnd_create_conn(kib_peer_t *peer, struct rdma_cm_id *cmid, write_unlock_irqrestore(glock, flags); LIBCFS_CPT_ALLOC(conn->ibc_rxs, lnet_cpt_table(), cpt, - IBLND_RX_MSGS(conn) * sizeof(kib_rx_t)); + IBLND_RX_MSGS(conn) * sizeof(struct kib_rx)); if (!conn->ibc_rxs) { CERROR("Cannot allocate RX buffers\n"); goto failed_2; @@ -833,10 +833,10 @@ kib_conn_t *kiblnd_create_conn(kib_peer_t *peer, struct rdma_cm_id *cmid, return NULL; } -void kiblnd_destroy_conn(kib_conn_t *conn, bool free_conn) +void kiblnd_destroy_conn(struct kib_conn *conn, bool free_conn) { struct rdma_cm_id *cmid = conn->ibc_cmid; - kib_peer_t *peer = conn->ibc_peer; + struct kib_peer *peer = conn->ibc_peer; int rc; LASSERT(!in_interrupt()); @@ -879,7 +879,7 @@ void kiblnd_destroy_conn(kib_conn_t *conn, bool free_conn) if (conn->ibc_rxs) { LIBCFS_FREE(conn->ibc_rxs, - IBLND_RX_MSGS(conn) * sizeof(kib_rx_t)); + IBLND_RX_MSGS(conn) * sizeof(struct kib_rx)); } if (conn->ibc_connvars) @@ -890,7 +890,7 @@ void kiblnd_destroy_conn(kib_conn_t *conn, bool free_conn) /* See CAVEAT EMPTOR above in kiblnd_create_conn */ if (conn->ibc_state != IBLND_CONN_INIT) { - kib_net_t *net = peer->ibp_ni->ni_data; + struct kib_net *net = peer->ibp_ni->ni_data; kiblnd_peer_decref(peer); rdma_destroy_id(cmid); @@ -900,15 +900,15 @@ void kiblnd_destroy_conn(kib_conn_t *conn, bool free_conn) LIBCFS_FREE(conn, sizeof(*conn)); } -int kiblnd_close_peer_conns_locked(kib_peer_t *peer, int why) +int kiblnd_close_peer_conns_locked(struct kib_peer *peer, int why) { - kib_conn_t *conn; + struct kib_conn *conn; struct list_head *ctmp; struct list_head *cnxt; int count = 0; list_for_each_safe(ctmp, cnxt, &peer->ibp_conns) { - conn = list_entry(ctmp, kib_conn_t, ibc_list); + conn = list_entry(ctmp, struct kib_conn, ibc_list); CDEBUG(D_NET, "Closing conn -> %s, version: %x, reason: %d\n", libcfs_nid2str(peer->ibp_nid), @@ -921,16 +921,16 @@ int kiblnd_close_peer_conns_locked(kib_peer_t *peer, int why) return count; } -int kiblnd_close_stale_conns_locked(kib_peer_t *peer, +int kiblnd_close_stale_conns_locked(struct kib_peer *peer, int version, __u64 incarnation) { - kib_conn_t *conn; + struct kib_conn *conn; struct list_head *ctmp; struct list_head *cnxt; int count = 0; list_for_each_safe(ctmp, cnxt, &peer->ibp_conns) { - conn = list_entry(ctmp, kib_conn_t, ibc_list); + conn = list_entry(ctmp, struct kib_conn, ibc_list); if (conn->ibc_version == version && conn->ibc_incarnation == incarnation) @@ -951,7 +951,7 @@ int kiblnd_close_stale_conns_locked(kib_peer_t *peer, static int kiblnd_close_matching_conns(lnet_ni_t *ni, lnet_nid_t nid) { - kib_peer_t *peer; + struct kib_peer *peer; struct list_head *ptmp; struct list_head *pnxt; int lo; @@ -972,7 +972,7 @@ static int kiblnd_close_matching_conns(lnet_ni_t *ni, lnet_nid_t nid) for (i = lo; i <= hi; i++) { list_for_each_safe(ptmp, pnxt, &kiblnd_data.kib_peers[i]) { - peer = list_entry(ptmp, kib_peer_t, ibp_list); + peer = list_entry(ptmp, struct kib_peer, ibp_list); LASSERT(!kiblnd_peer_idle(peer)); if (peer->ibp_ni != ni) @@ -1016,7 +1016,7 @@ static int kiblnd_ctl(lnet_ni_t *ni, unsigned int cmd, void *arg) break; } case IOC_LIBCFS_GET_CONN: { - kib_conn_t *conn; + struct kib_conn *conn; rc = 0; conn = kiblnd_get_conn_by_idx(ni, data->ioc_count); @@ -1052,7 +1052,7 @@ static void kiblnd_query(lnet_ni_t *ni, lnet_nid_t nid, unsigned long *when) unsigned long last_alive = 0; unsigned long now = cfs_time_current(); rwlock_t *glock = &kiblnd_data.kib_global_lock; - kib_peer_t *peer; + struct kib_peer *peer; unsigned long flags; read_lock_irqsave(glock, flags); @@ -1078,7 +1078,7 @@ static void kiblnd_query(lnet_ni_t *ni, lnet_nid_t nid, unsigned long *when) last_alive ? cfs_duration_sec(now - last_alive) : -1); } -static void kiblnd_free_pages(kib_pages_t *p) +static void kiblnd_free_pages(struct kib_pages *p) { int npages = p->ibp_npages; int i; @@ -1088,22 +1088,22 @@ static void kiblnd_free_pages(kib_pages_t *p) __free_page(p->ibp_pages[i]); } - LIBCFS_FREE(p, offsetof(kib_pages_t, ibp_pages[npages])); + LIBCFS_FREE(p, offsetof(struct kib_pages, ibp_pages[npages])); } -int kiblnd_alloc_pages(kib_pages_t **pp, int cpt, int npages) +int kiblnd_alloc_pages(struct kib_pages **pp, int cpt, int npages) { - kib_pages_t *p; + struct kib_pages *p; int i; LIBCFS_CPT_ALLOC(p, lnet_cpt_table(), cpt, - offsetof(kib_pages_t, ibp_pages[npages])); + offsetof(struct kib_pages, ibp_pages[npages])); if (!p) { CERROR("Can't allocate descriptor for %d pages\n", npages); return -ENOMEM; } - memset(p, 0, offsetof(kib_pages_t, ibp_pages[npages])); + memset(p, 0, offsetof(struct kib_pages, ibp_pages[npages])); p->ibp_npages = npages; for (i = 0; i < npages; i++) { @@ -1121,9 +1121,9 @@ int kiblnd_alloc_pages(kib_pages_t **pp, int cpt, int npages) return 0; } -void kiblnd_unmap_rx_descs(kib_conn_t *conn) +void kiblnd_unmap_rx_descs(struct kib_conn *conn) { - kib_rx_t *rx; + struct kib_rx *rx; int i; LASSERT(conn->ibc_rxs); @@ -1145,9 +1145,9 @@ void kiblnd_unmap_rx_descs(kib_conn_t *conn) conn->ibc_rx_pages = NULL; } -void kiblnd_map_rx_descs(kib_conn_t *conn) +void kiblnd_map_rx_descs(struct kib_conn *conn) { - kib_rx_t *rx; + struct kib_rx *rx; struct page *pg; int pg_off; int ipg; @@ -1158,7 +1158,7 @@ void kiblnd_map_rx_descs(kib_conn_t *conn) rx = &conn->ibc_rxs[i]; rx->rx_conn = conn; - rx->rx_msg = (kib_msg_t *)(((char *)page_address(pg)) + pg_off); + rx->rx_msg = (struct kib_msg *)(((char *)page_address(pg)) + pg_off); rx->rx_msgaddr = kiblnd_dma_map_single(conn->ibc_hdev->ibh_ibdev, rx->rx_msg, @@ -1183,10 +1183,10 @@ void kiblnd_map_rx_descs(kib_conn_t *conn) } } -static void kiblnd_unmap_tx_pool(kib_tx_pool_t *tpo) +static void kiblnd_unmap_tx_pool(struct kib_tx_pool *tpo) { - kib_hca_dev_t *hdev = tpo->tpo_hdev; - kib_tx_t *tx; + struct kib_hca_dev *hdev = tpo->tpo_hdev; + struct kib_tx *tx; int i; LASSERT(!tpo->tpo_pool.po_allocated); @@ -1206,9 +1206,9 @@ static void kiblnd_unmap_tx_pool(kib_tx_pool_t *tpo) tpo->tpo_hdev = NULL; } -static kib_hca_dev_t *kiblnd_current_hdev(kib_dev_t *dev) +static struct kib_hca_dev *kiblnd_current_hdev(struct kib_dev *dev) { - kib_hca_dev_t *hdev; + struct kib_hca_dev *hdev; unsigned long flags; int i = 0; @@ -1232,14 +1232,14 @@ static kib_hca_dev_t *kiblnd_current_hdev(kib_dev_t *dev) return hdev; } -static void kiblnd_map_tx_pool(kib_tx_pool_t *tpo) +static void kiblnd_map_tx_pool(struct kib_tx_pool *tpo) { - kib_pages_t *txpgs = tpo->tpo_tx_pages; - kib_pool_t *pool = &tpo->tpo_pool; - kib_net_t *net = pool->po_owner->ps_net; - kib_dev_t *dev; + struct kib_pages *txpgs = tpo->tpo_tx_pages; + struct kib_pool *pool = &tpo->tpo_pool; + struct kib_net *net = pool->po_owner->ps_net; + struct kib_dev *dev; struct page *page; - kib_tx_t *tx; + struct kib_tx *tx; int page_offset; int ipage; int i; @@ -1260,7 +1260,7 @@ static void kiblnd_map_tx_pool(kib_tx_pool_t *tpo) page = txpgs->ibp_pages[ipage]; tx = &tpo->tpo_tx_descs[i]; - tx->tx_msg = (kib_msg_t *)(((char *)page_address(page)) + + tx->tx_msg = (struct kib_msg *)(((char *)page_address(page)) + page_offset); tx->tx_msgaddr = kiblnd_dma_map_single( @@ -1283,11 +1283,11 @@ static void kiblnd_map_tx_pool(kib_tx_pool_t *tpo) } } -struct ib_mr *kiblnd_find_rd_dma_mr(struct lnet_ni *ni, kib_rdma_desc_t *rd, +struct ib_mr *kiblnd_find_rd_dma_mr(struct lnet_ni *ni, struct kib_rdma_desc *rd, int negotiated_nfrags) { - kib_net_t *net = ni->ni_data; - kib_hca_dev_t *hdev = net->ibn_dev->ibd_hdev; + struct kib_net *net = ni->ni_data; + struct kib_hca_dev *hdev = net->ibn_dev->ibd_hdev; struct lnet_ioctl_config_o2iblnd_tunables *tunables; __u16 nfrags; int mod; @@ -1304,7 +1304,7 @@ struct ib_mr *kiblnd_find_rd_dma_mr(struct lnet_ni *ni, kib_rdma_desc_t *rd, return hdev->ibh_mrs; } -static void kiblnd_destroy_fmr_pool(kib_fmr_pool_t *fpo) +static void kiblnd_destroy_fmr_pool(struct kib_fmr_pool *fpo) { LASSERT(!fpo->fpo_map_count); @@ -1335,7 +1335,7 @@ static void kiblnd_destroy_fmr_pool(kib_fmr_pool_t *fpo) static void kiblnd_destroy_fmr_pool_list(struct list_head *head) { - kib_fmr_pool_t *fpo, *tmp; + struct kib_fmr_pool *fpo, *tmp; list_for_each_entry_safe(fpo, tmp, head, fpo_list) { list_del(&fpo->fpo_list); @@ -1361,7 +1361,7 @@ kiblnd_fmr_flush_trigger(struct lnet_ioctl_config_o2iblnd_tunables *tunables, return max(IBLND_FMR_POOL_FLUSH, size); } -static int kiblnd_alloc_fmr_pool(kib_fmr_poolset_t *fps, kib_fmr_pool_t *fpo) +static int kiblnd_alloc_fmr_pool(struct kib_fmr_poolset *fps, struct kib_fmr_pool *fpo) { struct ib_fmr_pool_param param = { .max_pages_per_fmr = LNET_MAX_PAYLOAD / PAGE_SIZE, @@ -1388,7 +1388,7 @@ static int kiblnd_alloc_fmr_pool(kib_fmr_poolset_t *fps, kib_fmr_pool_t *fpo) return rc; } -static int kiblnd_alloc_freg_pool(kib_fmr_poolset_t *fps, kib_fmr_pool_t *fpo) +static int kiblnd_alloc_freg_pool(struct kib_fmr_poolset *fps, struct kib_fmr_pool *fpo) { struct kib_fast_reg_descriptor *frd, *tmp; int i, rc; @@ -1438,12 +1438,12 @@ out: return rc; } -static int kiblnd_create_fmr_pool(kib_fmr_poolset_t *fps, - kib_fmr_pool_t **pp_fpo) +static int kiblnd_create_fmr_pool(struct kib_fmr_poolset *fps, + struct kib_fmr_pool **pp_fpo) { - kib_dev_t *dev = fps->fps_net->ibn_dev; + struct kib_dev *dev = fps->fps_net->ibn_dev; struct ib_device_attr *dev_attr; - kib_fmr_pool_t *fpo; + struct kib_fmr_pool *fpo; int rc; LIBCFS_CPT_ALLOC(fpo, lnet_cpt_table(), fps->fps_cpt, sizeof(*fpo)); @@ -1488,7 +1488,7 @@ out_fpo: return rc; } -static void kiblnd_fail_fmr_poolset(kib_fmr_poolset_t *fps, +static void kiblnd_fail_fmr_poolset(struct kib_fmr_poolset *fps, struct list_head *zombies) { if (!fps->fps_net) /* intialized? */ @@ -1497,8 +1497,8 @@ static void kiblnd_fail_fmr_poolset(kib_fmr_poolset_t *fps, spin_lock(&fps->fps_lock); while (!list_empty(&fps->fps_pool_list)) { - kib_fmr_pool_t *fpo = list_entry(fps->fps_pool_list.next, - kib_fmr_pool_t, fpo_list); + struct kib_fmr_pool *fpo = list_entry(fps->fps_pool_list.next, + struct kib_fmr_pool, fpo_list); fpo->fpo_failed = 1; list_del(&fpo->fpo_list); if (!fpo->fpo_map_count) @@ -1510,7 +1510,7 @@ static void kiblnd_fail_fmr_poolset(kib_fmr_poolset_t *fps, spin_unlock(&fps->fps_lock); } -static void kiblnd_fini_fmr_poolset(kib_fmr_poolset_t *fps) +static void kiblnd_fini_fmr_poolset(struct kib_fmr_poolset *fps) { if (fps->fps_net) { /* initialized? */ kiblnd_destroy_fmr_pool_list(&fps->fps_failed_pool_list); @@ -1519,11 +1519,11 @@ static void kiblnd_fini_fmr_poolset(kib_fmr_poolset_t *fps) } static int -kiblnd_init_fmr_poolset(kib_fmr_poolset_t *fps, int cpt, int ncpts, - kib_net_t *net, +kiblnd_init_fmr_poolset(struct kib_fmr_poolset *fps, int cpt, int ncpts, + struct kib_net *net, struct lnet_ioctl_config_o2iblnd_tunables *tunables) { - kib_fmr_pool_t *fpo; + struct kib_fmr_pool *fpo; int rc; memset(fps, 0, sizeof(*fps)); @@ -1546,7 +1546,7 @@ kiblnd_init_fmr_poolset(kib_fmr_poolset_t *fps, int cpt, int ncpts, return rc; } -static int kiblnd_fmr_pool_is_idle(kib_fmr_pool_t *fpo, unsigned long now) +static int kiblnd_fmr_pool_is_idle(struct kib_fmr_pool *fpo, unsigned long now) { if (fpo->fpo_map_count) /* still in use */ return 0; @@ -1556,10 +1556,10 @@ static int kiblnd_fmr_pool_is_idle(kib_fmr_pool_t *fpo, unsigned long now) } static int -kiblnd_map_tx_pages(kib_tx_t *tx, kib_rdma_desc_t *rd) +kiblnd_map_tx_pages(struct kib_tx *tx, struct kib_rdma_desc *rd) { __u64 *pages = tx->tx_pages; - kib_hca_dev_t *hdev; + struct kib_hca_dev *hdev; int npages; int size; int i; @@ -1577,13 +1577,13 @@ kiblnd_map_tx_pages(kib_tx_t *tx, kib_rdma_desc_t *rd) return npages; } -void kiblnd_fmr_pool_unmap(kib_fmr_t *fmr, int status) +void kiblnd_fmr_pool_unmap(struct kib_fmr *fmr, int status) { LIST_HEAD(zombies); - kib_fmr_pool_t *fpo = fmr->fmr_pool; - kib_fmr_poolset_t *fps; + struct kib_fmr_pool *fpo = fmr->fmr_pool; + struct kib_fmr_poolset *fps; unsigned long now = cfs_time_current(); - kib_fmr_pool_t *tmp; + struct kib_fmr_pool *tmp; int rc; if (!fpo) @@ -1633,14 +1633,14 @@ void kiblnd_fmr_pool_unmap(kib_fmr_t *fmr, int status) kiblnd_destroy_fmr_pool_list(&zombies); } -int kiblnd_fmr_pool_map(kib_fmr_poolset_t *fps, kib_tx_t *tx, - kib_rdma_desc_t *rd, __u32 nob, __u64 iov, - kib_fmr_t *fmr) +int kiblnd_fmr_pool_map(struct kib_fmr_poolset *fps, struct kib_tx *tx, + struct kib_rdma_desc *rd, __u32 nob, __u64 iov, + struct kib_fmr *fmr) { __u64 *pages = tx->tx_pages; bool is_rx = (rd != tx->tx_rd); bool tx_pages_mapped = 0; - kib_fmr_pool_t *fpo; + struct kib_fmr_pool *fpo; int npages = 0; __u64 version; int rc; @@ -1780,7 +1780,7 @@ int kiblnd_fmr_pool_map(kib_fmr_poolset_t *fps, kib_tx_t *tx, goto again; } -static void kiblnd_fini_pool(kib_pool_t *pool) +static void kiblnd_fini_pool(struct kib_pool *pool) { LASSERT(list_empty(&pool->po_free_list)); LASSERT(!pool->po_allocated); @@ -1788,7 +1788,7 @@ static void kiblnd_fini_pool(kib_pool_t *pool) CDEBUG(D_NET, "Finalize %s pool\n", pool->po_owner->ps_name); } -static void kiblnd_init_pool(kib_poolset_t *ps, kib_pool_t *pool, int size) +static void kiblnd_init_pool(struct kib_poolset *ps, struct kib_pool *pool, int size) { CDEBUG(D_NET, "Initialize %s pool\n", ps->ps_name); @@ -1801,10 +1801,10 @@ static void kiblnd_init_pool(kib_poolset_t *ps, kib_pool_t *pool, int size) static void kiblnd_destroy_pool_list(struct list_head *head) { - kib_pool_t *pool; + struct kib_pool *pool; while (!list_empty(head)) { - pool = list_entry(head->next, kib_pool_t, po_list); + pool = list_entry(head->next, struct kib_pool, po_list); list_del(&pool->po_list); LASSERT(pool->po_owner); @@ -1812,15 +1812,15 @@ static void kiblnd_destroy_pool_list(struct list_head *head) } } -static void kiblnd_fail_poolset(kib_poolset_t *ps, struct list_head *zombies) +static void kiblnd_fail_poolset(struct kib_poolset *ps, struct list_head *zombies) { if (!ps->ps_net) /* intialized? */ return; spin_lock(&ps->ps_lock); while (!list_empty(&ps->ps_pool_list)) { - kib_pool_t *po = list_entry(ps->ps_pool_list.next, - kib_pool_t, po_list); + struct kib_pool *po = list_entry(ps->ps_pool_list.next, + struct kib_pool, po_list); po->po_failed = 1; list_del(&po->po_list); if (!po->po_allocated) @@ -1831,7 +1831,7 @@ static void kiblnd_fail_poolset(kib_poolset_t *ps, struct list_head *zombies) spin_unlock(&ps->ps_lock); } -static void kiblnd_fini_poolset(kib_poolset_t *ps) +static void kiblnd_fini_poolset(struct kib_poolset *ps) { if (ps->ps_net) { /* initialized? */ kiblnd_destroy_pool_list(&ps->ps_failed_pool_list); @@ -1839,14 +1839,14 @@ static void kiblnd_fini_poolset(kib_poolset_t *ps) } } -static int kiblnd_init_poolset(kib_poolset_t *ps, int cpt, - kib_net_t *net, char *name, int size, +static int kiblnd_init_poolset(struct kib_poolset *ps, int cpt, + struct kib_net *net, char *name, int size, kib_ps_pool_create_t po_create, kib_ps_pool_destroy_t po_destroy, kib_ps_node_init_t nd_init, kib_ps_node_fini_t nd_fini) { - kib_pool_t *pool; + struct kib_pool *pool; int rc; memset(ps, 0, sizeof(*ps)); @@ -1874,7 +1874,7 @@ static int kiblnd_init_poolset(kib_poolset_t *ps, int cpt, return rc; } -static int kiblnd_pool_is_idle(kib_pool_t *pool, unsigned long now) +static int kiblnd_pool_is_idle(struct kib_pool *pool, unsigned long now) { if (pool->po_allocated) /* still in use */ return 0; @@ -1883,11 +1883,11 @@ static int kiblnd_pool_is_idle(kib_pool_t *pool, unsigned long now) return cfs_time_aftereq(now, pool->po_deadline); } -void kiblnd_pool_free_node(kib_pool_t *pool, struct list_head *node) +void kiblnd_pool_free_node(struct kib_pool *pool, struct list_head *node) { LIST_HEAD(zombies); - kib_poolset_t *ps = pool->po_owner; - kib_pool_t *tmp; + struct kib_poolset *ps = pool->po_owner; + struct kib_pool *tmp; unsigned long now = cfs_time_current(); spin_lock(&ps->ps_lock); @@ -1913,10 +1913,10 @@ void kiblnd_pool_free_node(kib_pool_t *pool, struct list_head *node) kiblnd_destroy_pool_list(&zombies); } -struct list_head *kiblnd_pool_alloc_node(kib_poolset_t *ps) +struct list_head *kiblnd_pool_alloc_node(struct kib_poolset *ps) { struct list_head *node; - kib_pool_t *pool; + struct kib_pool *pool; unsigned int interval = 1; unsigned long time_before; unsigned int trips = 0; @@ -1986,9 +1986,9 @@ struct list_head *kiblnd_pool_alloc_node(kib_poolset_t *ps) goto again; } -static void kiblnd_destroy_tx_pool(kib_pool_t *pool) +static void kiblnd_destroy_tx_pool(struct kib_pool *pool) { - kib_tx_pool_t *tpo = container_of(pool, kib_tx_pool_t, tpo_pool); + struct kib_tx_pool *tpo = container_of(pool, struct kib_tx_pool, tpo_pool); int i; LASSERT(!pool->po_allocated); @@ -2002,7 +2002,7 @@ static void kiblnd_destroy_tx_pool(kib_pool_t *pool) goto out; for (i = 0; i < pool->po_size; i++) { - kib_tx_t *tx = &tpo->tpo_tx_descs[i]; + struct kib_tx *tx = &tpo->tpo_tx_descs[i]; list_del(&tx->tx_list); if (tx->tx_pages) @@ -2023,12 +2023,12 @@ static void kiblnd_destroy_tx_pool(kib_pool_t *pool) sizeof(*tx->tx_sge)); if (tx->tx_rd) LIBCFS_FREE(tx->tx_rd, - offsetof(kib_rdma_desc_t, + offsetof(struct kib_rdma_desc, rd_frags[IBLND_MAX_RDMA_FRAGS])); } LIBCFS_FREE(tpo->tpo_tx_descs, - pool->po_size * sizeof(kib_tx_t)); + pool->po_size * sizeof(struct kib_tx)); out: kiblnd_fini_pool(pool); LIBCFS_FREE(tpo, sizeof(*tpo)); @@ -2041,13 +2041,13 @@ static int kiblnd_tx_pool_size(int ncpts) return max(IBLND_TX_POOL, ntx); } -static int kiblnd_create_tx_pool(kib_poolset_t *ps, int size, - kib_pool_t **pp_po) +static int kiblnd_create_tx_pool(struct kib_poolset *ps, int size, + struct kib_pool **pp_po) { int i; int npg; - kib_pool_t *pool; - kib_tx_pool_t *tpo; + struct kib_pool *pool; + struct kib_tx_pool *tpo; LIBCFS_CPT_ALLOC(tpo, lnet_cpt_table(), ps->ps_cpt, sizeof(*tpo)); if (!tpo) { @@ -2068,17 +2068,17 @@ static int kiblnd_create_tx_pool(kib_poolset_t *ps, int size, } LIBCFS_CPT_ALLOC(tpo->tpo_tx_descs, lnet_cpt_table(), ps->ps_cpt, - size * sizeof(kib_tx_t)); + size * sizeof(struct kib_tx)); if (!tpo->tpo_tx_descs) { CERROR("Can't allocate %d tx descriptors\n", size); ps->ps_pool_destroy(pool); return -ENOMEM; } - memset(tpo->tpo_tx_descs, 0, size * sizeof(kib_tx_t)); + memset(tpo->tpo_tx_descs, 0, size * sizeof(struct kib_tx)); for (i = 0; i < size; i++) { - kib_tx_t *tx = &tpo->tpo_tx_descs[i]; + struct kib_tx *tx = &tpo->tpo_tx_descs[i]; tx->tx_pool = tpo; if (ps->ps_net->ibn_fmr_ps) { @@ -2110,7 +2110,7 @@ static int kiblnd_create_tx_pool(kib_poolset_t *ps, int size, break; LIBCFS_CPT_ALLOC(tx->tx_rd, lnet_cpt_table(), ps->ps_cpt, - offsetof(kib_rdma_desc_t, + offsetof(struct kib_rdma_desc, rd_frags[IBLND_MAX_RDMA_FRAGS])); if (!tx->tx_rd) break; @@ -2126,22 +2126,23 @@ static int kiblnd_create_tx_pool(kib_poolset_t *ps, int size, return -ENOMEM; } -static void kiblnd_tx_init(kib_pool_t *pool, struct list_head *node) +static void kiblnd_tx_init(struct kib_pool *pool, struct list_head *node) { - kib_tx_poolset_t *tps = container_of(pool->po_owner, kib_tx_poolset_t, - tps_poolset); - kib_tx_t *tx = list_entry(node, kib_tx_t, tx_list); + struct kib_tx_poolset *tps = container_of(pool->po_owner, + struct kib_tx_poolset, + tps_poolset); + struct kib_tx *tx = list_entry(node, struct kib_tx, tx_list); tx->tx_cookie = tps->tps_next_tx_cookie++; } -static void kiblnd_net_fini_pools(kib_net_t *net) +static void kiblnd_net_fini_pools(struct kib_net *net) { int i; cfs_cpt_for_each(i, lnet_cpt_table()) { - kib_tx_poolset_t *tps; - kib_fmr_poolset_t *fps; + struct kib_tx_poolset *tps; + struct kib_fmr_poolset *fps; if (net->ibn_tx_ps) { tps = net->ibn_tx_ps[i]; @@ -2165,7 +2166,7 @@ static void kiblnd_net_fini_pools(kib_net_t *net) } } -static int kiblnd_net_init_pools(kib_net_t *net, lnet_ni_t *ni, __u32 *cpts, +static int kiblnd_net_init_pools(struct kib_net *net, lnet_ni_t *ni, __u32 *cpts, int ncpts) { struct lnet_ioctl_config_o2iblnd_tunables *tunables; @@ -2207,7 +2208,7 @@ static int kiblnd_net_init_pools(kib_net_t *net, lnet_ni_t *ni, __u32 *cpts, * number of CPTs that exist, i.e net->ibn_fmr_ps[cpt]. */ net->ibn_fmr_ps = cfs_percpt_alloc(lnet_cpt_table(), - sizeof(kib_fmr_poolset_t)); + sizeof(struct kib_fmr_poolset)); if (!net->ibn_fmr_ps) { CERROR("Failed to allocate FMR pool array\n"); rc = -ENOMEM; @@ -2235,7 +2236,7 @@ static int kiblnd_net_init_pools(kib_net_t *net, lnet_ni_t *ni, __u32 *cpts, * number of CPTs that exist, i.e net->ibn_tx_ps[cpt]. */ net->ibn_tx_ps = cfs_percpt_alloc(lnet_cpt_table(), - sizeof(kib_tx_poolset_t)); + sizeof(struct kib_tx_poolset)); if (!net->ibn_tx_ps) { CERROR("Failed to allocate tx pool array\n"); rc = -ENOMEM; @@ -2264,7 +2265,7 @@ static int kiblnd_net_init_pools(kib_net_t *net, lnet_ni_t *ni, __u32 *cpts, return rc; } -static int kiblnd_hdev_get_attr(kib_hca_dev_t *hdev) +static int kiblnd_hdev_get_attr(struct kib_hca_dev *hdev) { /* * It's safe to assume a HCA can handle a page size @@ -2284,7 +2285,7 @@ static int kiblnd_hdev_get_attr(kib_hca_dev_t *hdev) return -EINVAL; } -static void kiblnd_hdev_cleanup_mrs(kib_hca_dev_t *hdev) +static void kiblnd_hdev_cleanup_mrs(struct kib_hca_dev *hdev) { if (!hdev->ibh_mrs) return; @@ -2294,7 +2295,7 @@ static void kiblnd_hdev_cleanup_mrs(kib_hca_dev_t *hdev) hdev->ibh_mrs = NULL; } -void kiblnd_hdev_destroy(kib_hca_dev_t *hdev) +void kiblnd_hdev_destroy(struct kib_hca_dev *hdev) { kiblnd_hdev_cleanup_mrs(hdev); @@ -2307,7 +2308,7 @@ void kiblnd_hdev_destroy(kib_hca_dev_t *hdev) LIBCFS_FREE(hdev, sizeof(*hdev)); } -static int kiblnd_hdev_setup_mrs(kib_hca_dev_t *hdev) +static int kiblnd_hdev_setup_mrs(struct kib_hca_dev *hdev) { struct ib_mr *mr; int rc; @@ -2336,7 +2337,7 @@ static int kiblnd_dummy_callback(struct rdma_cm_id *cmid, return 0; } -static int kiblnd_dev_need_failover(kib_dev_t *dev) +static int kiblnd_dev_need_failover(struct kib_dev *dev) { struct rdma_cm_id *cmid; struct sockaddr_in srcaddr; @@ -2390,15 +2391,15 @@ static int kiblnd_dev_need_failover(kib_dev_t *dev) return rc; } -int kiblnd_dev_failover(kib_dev_t *dev) +int kiblnd_dev_failover(struct kib_dev *dev) { LIST_HEAD(zombie_tpo); LIST_HEAD(zombie_ppo); LIST_HEAD(zombie_fpo); struct rdma_cm_id *cmid = NULL; - kib_hca_dev_t *hdev = NULL; + struct kib_hca_dev *hdev = NULL; struct ib_pd *pd; - kib_net_t *net; + struct kib_net *net; struct sockaddr_in addr; unsigned long flags; int rc = 0; @@ -2523,7 +2524,7 @@ int kiblnd_dev_failover(kib_dev_t *dev) return rc; } -void kiblnd_destroy_dev(kib_dev_t *dev) +void kiblnd_destroy_dev(struct kib_dev *dev) { LASSERT(!dev->ibd_nnets); LASSERT(list_empty(&dev->ibd_nets)); @@ -2537,10 +2538,10 @@ void kiblnd_destroy_dev(kib_dev_t *dev) LIBCFS_FREE(dev, sizeof(*dev)); } -static kib_dev_t *kiblnd_create_dev(char *ifname) +static struct kib_dev *kiblnd_create_dev(char *ifname) { struct net_device *netdev; - kib_dev_t *dev; + struct kib_dev *dev; __u32 netmask; __u32 ip; int up; @@ -2655,7 +2656,7 @@ static void kiblnd_base_shutdown(void) static void kiblnd_shutdown(lnet_ni_t *ni) { - kib_net_t *net = ni->ni_data; + struct kib_net *net = ni->ni_data; rwlock_t *g_lock = &kiblnd_data.kib_global_lock; int i; unsigned long flags; @@ -2852,7 +2853,7 @@ static int kiblnd_start_schedulers(struct kib_sched_info *sched) return rc; } -static int kiblnd_dev_start_threads(kib_dev_t *dev, int newdev, __u32 *cpts, +static int kiblnd_dev_start_threads(struct kib_dev *dev, int newdev, __u32 *cpts, int ncpts) { int cpt; @@ -2878,10 +2879,10 @@ static int kiblnd_dev_start_threads(kib_dev_t *dev, int newdev, __u32 *cpts, return 0; } -static kib_dev_t *kiblnd_dev_search(char *ifname) +static struct kib_dev *kiblnd_dev_search(char *ifname) { - kib_dev_t *alias = NULL; - kib_dev_t *dev; + struct kib_dev *alias = NULL; + struct kib_dev *dev; char *colon; char *colon2; @@ -2913,8 +2914,8 @@ static kib_dev_t *kiblnd_dev_search(char *ifname) static int kiblnd_startup(lnet_ni_t *ni) { char *ifname; - kib_dev_t *ibdev = NULL; - kib_net_t *net; + struct kib_dev *ibdev = NULL; + struct kib_net *net; struct timespec64 tv; unsigned long flags; int rc; @@ -3021,11 +3022,11 @@ static void __exit ko2iblnd_exit(void) static int __init ko2iblnd_init(void) { - CLASSERT(sizeof(kib_msg_t) <= IBLND_MSG_SIZE); - CLASSERT(offsetof(kib_msg_t, + CLASSERT(sizeof(struct kib_msg) <= IBLND_MSG_SIZE); + CLASSERT(offsetof(struct kib_msg, ibm_u.get.ibgm_rd.rd_frags[IBLND_MAX_RDMA_FRAGS]) <= IBLND_MSG_SIZE); - CLASSERT(offsetof(kib_msg_t, + CLASSERT(offsetof(struct kib_msg, ibm_u.putack.ibpam_rd.rd_frags[IBLND_MAX_RDMA_FRAGS]) <= IBLND_MSG_SIZE); diff --git a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.h b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.h index 45bbe93..4bac2b7 100644 --- a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.h +++ b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.h @@ -78,12 +78,12 @@ #define IBLND_N_SCHED 2 #define IBLND_N_SCHED_HIGH 4 -typedef struct { +struct kib_tunables { int *kib_dev_failover; /* HCA failover */ unsigned int *kib_service; /* IB service number */ int *kib_min_reconnect_interval; /* first failed connection retry... */ int *kib_max_reconnect_interval; /* exponentially increasing to this */ - int *kib_cksum; /* checksum kib_msg_t? */ + int *kib_cksum; /* checksum struct kib_msg? */ int *kib_timeout; /* comms timeout (seconds) */ int *kib_keepalive; /* keepalive timeout (seconds) */ int *kib_ntx; /* # tx descs */ @@ -94,15 +94,15 @@ typedef struct { int *kib_require_priv_port; /* accept only privileged ports */ int *kib_use_priv_port; /* use privileged port for active connect */ int *kib_nscheds; /* # threads on each CPT */ -} kib_tunables_t; +}; -extern kib_tunables_t kiblnd_tunables; +extern struct kib_tunables kiblnd_tunables; #define IBLND_MSG_QUEUE_SIZE_V1 8 /* V1 only : # messages/RDMAs in-flight */ #define IBLND_CREDIT_HIGHWATER_V1 7 /* V1 only : when eagerly to return credits */ #define IBLND_CREDITS_DEFAULT 8 /* default # of peer credits */ -#define IBLND_CREDITS_MAX ((typeof(((kib_msg_t *) 0)->ibm_credits)) - 1) /* Max # of peer credits */ +#define IBLND_CREDITS_MAX ((typeof(((struct kib_msg *) 0)->ibm_credits)) - 1) /* Max # of peer credits */ /* when eagerly to return credits */ #define IBLND_CREDITS_HIGHWATER(t, v) ((v) == IBLND_MSG_VERSION_1 ? \ @@ -150,7 +150,7 @@ struct kib_hca_dev; #define KIB_IFNAME_SIZE 256 #endif -typedef struct { +struct kib_dev { struct list_head ibd_list; /* chain on kib_devs */ struct list_head ibd_fail_list; /* chain on kib_failed_devs */ __u32 ibd_ifip; /* IPoIB interface IP */ @@ -165,9 +165,9 @@ typedef struct { unsigned int ibd_can_failover; /* IPoIB interface is a bonding master */ struct list_head ibd_nets; struct kib_hca_dev *ibd_hdev; -} kib_dev_t; +}; -typedef struct kib_hca_dev { +struct kib_hca_dev { struct rdma_cm_id *ibh_cmid; /* listener cmid */ struct ib_device *ibh_ibdev; /* IB device */ int ibh_page_shift; /* page shift of current HCA */ @@ -177,19 +177,19 @@ typedef struct kib_hca_dev { __u64 ibh_mr_size; /* size of MR */ struct ib_mr *ibh_mrs; /* global MR */ struct ib_pd *ibh_pd; /* PD */ - kib_dev_t *ibh_dev; /* owner */ + struct kib_dev *ibh_dev; /* owner */ atomic_t ibh_ref; /* refcount */ -} kib_hca_dev_t; +}; /** # of seconds to keep pool alive */ #define IBLND_POOL_DEADLINE 300 /** # of seconds to retry if allocation failed */ #define IBLND_POOL_RETRY 1 -typedef struct { +struct kib_pages { int ibp_npages; /* # pages */ struct page *ibp_pages[0]; /* page array */ -} kib_pages_t; +}; struct kib_pool; struct kib_poolset; @@ -204,7 +204,7 @@ struct kib_net; #define IBLND_POOL_NAME_LEN 32 -typedef struct kib_poolset { +struct kib_poolset { spinlock_t ps_lock; /* serialize */ struct kib_net *ps_net; /* network it belongs to */ char ps_name[IBLND_POOL_NAME_LEN]; /* pool set name */ @@ -220,31 +220,31 @@ typedef struct kib_poolset { kib_ps_pool_destroy_t ps_pool_destroy; /* destroy a pool */ kib_ps_node_init_t ps_node_init; /* initialize new allocated node */ kib_ps_node_fini_t ps_node_fini; /* finalize node */ -} kib_poolset_t; +}; -typedef struct kib_pool { +struct kib_pool { struct list_head po_list; /* chain on pool list */ struct list_head po_free_list; /* pre-allocated node */ - kib_poolset_t *po_owner; /* pool_set of this pool */ + struct kib_poolset *po_owner; /* pool_set of this pool */ unsigned long po_deadline; /* deadline of this pool */ int po_allocated; /* # of elements in use */ int po_failed; /* pool is created on failed HCA */ int po_size; /* # of pre-allocated elements */ -} kib_pool_t; +}; -typedef struct { - kib_poolset_t tps_poolset; /* pool-set */ +struct kib_tx_poolset { + struct kib_poolset tps_poolset; /* pool-set */ __u64 tps_next_tx_cookie; /* cookie of TX */ -} kib_tx_poolset_t; +}; -typedef struct { - kib_pool_t tpo_pool; /* pool */ - struct kib_hca_dev *tpo_hdev; /* device for this pool */ - struct kib_tx *tpo_tx_descs; /* all the tx descriptors */ - kib_pages_t *tpo_tx_pages; /* premapped tx msg pages */ -} kib_tx_pool_t; +struct kib_tx_pool { + struct kib_pool tpo_pool; /* pool */ + struct kib_hca_dev *tpo_hdev; /* device for this pool */ + struct kib_tx *tpo_tx_descs; /* all the tx descriptors */ + struct kib_pages *tpo_tx_pages; /* premapped tx msg pages */ +}; -typedef struct { +struct kib_fmr_poolset { spinlock_t fps_lock; /* serialize */ struct kib_net *fps_net; /* IB network */ struct list_head fps_pool_list; /* FMR pool list */ @@ -257,7 +257,7 @@ typedef struct { int fps_increasing; /* is allocating new pool */ unsigned long fps_next_retry; /* time stamp for retry if*/ /* failed to allocate */ -} kib_fmr_poolset_t; +}; struct kib_fast_reg_descriptor { /* For fast registration */ struct list_head frd_list; @@ -267,10 +267,10 @@ struct kib_fast_reg_descriptor { /* For fast registration */ bool frd_valid; }; -typedef struct { - struct list_head fpo_list; /* chain on pool list */ - struct kib_hca_dev *fpo_hdev; /* device for this pool */ - kib_fmr_poolset_t *fpo_owner; /* owner of this pool */ +struct kib_fmr_pool { + struct list_head fpo_list; /* chain on pool list */ + struct kib_hca_dev *fpo_hdev; /* device for this pool */ + struct kib_fmr_poolset *fpo_owner; /* owner of this pool */ union { struct { struct ib_fmr_pool *fpo_fmr_pool; /* IB FMR pool */ @@ -284,17 +284,17 @@ typedef struct { int fpo_failed; /* fmr pool is failed */ int fpo_map_count; /* # of mapped FMR */ int fpo_is_fmr; -} kib_fmr_pool_t; +}; -typedef struct { - kib_fmr_pool_t *fmr_pool; /* pool of FMR */ +struct kib_fmr { + struct kib_fmr_pool *fmr_pool; /* pool of FMR */ struct ib_pool_fmr *fmr_pfmr; /* IB pool fmr */ struct kib_fast_reg_descriptor *fmr_frd; u32 fmr_key; -} kib_fmr_t; +}; -typedef struct kib_net { - struct list_head ibn_list; /* chain on kib_dev_t::ibd_nets */ +struct kib_net { + struct list_head ibn_list; /* chain on struct kib_dev::ibd_nets */ __u64 ibn_incarnation;/* my epoch */ int ibn_init; /* initialisation state */ int ibn_shutdown; /* shutting down? */ @@ -302,11 +302,11 @@ typedef struct kib_net { atomic_t ibn_npeers; /* # peers extant */ atomic_t ibn_nconns; /* # connections extant */ - kib_tx_poolset_t **ibn_tx_ps; /* tx pool-set */ - kib_fmr_poolset_t **ibn_fmr_ps; /* fmr pool-set */ + struct kib_tx_poolset **ibn_tx_ps; /* tx pool-set */ + struct kib_fmr_poolset **ibn_fmr_ps; /* fmr pool-set */ - kib_dev_t *ibn_dev; /* underlying IB device */ -} kib_net_t; + struct kib_dev *ibn_dev; /* underlying IB device */ +}; #define KIB_THREAD_SHIFT 16 #define KIB_THREAD_ID(cpt, tid) ((cpt) << KIB_THREAD_SHIFT | (tid)) @@ -322,7 +322,7 @@ struct kib_sched_info { int ibs_cpt; /* CPT id */ }; -typedef struct { +struct kib_data { int kib_init; /* initialisation state */ int kib_shutdown; /* shut down? */ struct list_head kib_devs; /* IB devices extant */ @@ -349,7 +349,7 @@ typedef struct { spinlock_t kib_connd_lock; /* serialise */ struct ib_qp_attr kib_error_qpa; /* QP->ERROR */ struct kib_sched_info **kib_scheds; /* percpt data for schedulers */ -} kib_data_t; +}; #define IBLND_INIT_NOTHING 0 #define IBLND_INIT_DATA 1 @@ -360,51 +360,51 @@ typedef struct { * These are sent in sender's byte order (i.e. receiver flips). */ -typedef struct kib_connparams { +struct kib_connparams { __u16 ibcp_queue_depth; __u16 ibcp_max_frags; __u32 ibcp_max_msg_size; -} WIRE_ATTR kib_connparams_t; +} WIRE_ATTR; -typedef struct { +struct kib_immediate_msg { lnet_hdr_t ibim_hdr; /* portals header */ char ibim_payload[0]; /* piggy-backed payload */ -} WIRE_ATTR kib_immediate_msg_t; +} WIRE_ATTR; -typedef struct { +struct kib_rdma_frag { __u32 rf_nob; /* # bytes this frag */ __u64 rf_addr; /* CAVEAT EMPTOR: misaligned!! */ -} WIRE_ATTR kib_rdma_frag_t; +} WIRE_ATTR; -typedef struct { +struct kib_rdma_desc { __u32 rd_key; /* local/remote key */ __u32 rd_nfrags; /* # fragments */ - kib_rdma_frag_t rd_frags[0]; /* buffer frags */ -} WIRE_ATTR kib_rdma_desc_t; + struct kib_rdma_frag rd_frags[0]; /* buffer frags */ +} WIRE_ATTR; -typedef struct { +struct kib_putreq_msg { lnet_hdr_t ibprm_hdr; /* portals header */ __u64 ibprm_cookie; /* opaque completion cookie */ -} WIRE_ATTR kib_putreq_msg_t; +} WIRE_ATTR; -typedef struct { +struct kib_putack_msg { __u64 ibpam_src_cookie; /* reflected completion cookie */ __u64 ibpam_dst_cookie; /* opaque completion cookie */ - kib_rdma_desc_t ibpam_rd; /* sender's sink buffer */ -} WIRE_ATTR kib_putack_msg_t; + struct kib_rdma_desc ibpam_rd; /* sender's sink buffer */ +} WIRE_ATTR; -typedef struct { +struct kib_get_msg { lnet_hdr_t ibgm_hdr; /* portals header */ __u64 ibgm_cookie; /* opaque completion cookie */ - kib_rdma_desc_t ibgm_rd; /* rdma descriptor */ -} WIRE_ATTR kib_get_msg_t; + struct kib_rdma_desc ibgm_rd; /* rdma descriptor */ +} WIRE_ATTR; -typedef struct { +struct kib_completion_msg { __u64 ibcm_cookie; /* opaque completion cookie */ __s32 ibcm_status; /* < 0 failure: >= 0 length */ -} WIRE_ATTR kib_completion_msg_t; +} WIRE_ATTR; -typedef struct { +struct kib_msg { /* First 2 fields fixed FOR ALL TIME */ __u32 ibm_magic; /* I'm an ibnal message */ __u16 ibm_version; /* this is my version number */ @@ -419,14 +419,14 @@ typedef struct { __u64 ibm_dststamp; /* destination's incarnation */ union { - kib_connparams_t connparams; - kib_immediate_msg_t immediate; - kib_putreq_msg_t putreq; - kib_putack_msg_t putack; - kib_get_msg_t get; - kib_completion_msg_t completion; + struct kib_connparams connparams; + struct kib_immediate_msg immediate; + struct kib_putreq_msg putreq; + struct kib_putack_msg putack; + struct kib_get_msg get; + struct kib_completion_msg completion; } WIRE_ATTR ibm_u; -} WIRE_ATTR kib_msg_t; +} WIRE_ATTR; #define IBLND_MSG_MAGIC LNET_PROTO_IB_MAGIC /* unique magic */ @@ -445,14 +445,14 @@ typedef struct { #define IBLND_MSG_GET_REQ 0xd6 /* getreq (sink->src) */ #define IBLND_MSG_GET_DONE 0xd7 /* completion (src->sink: all OK) */ -typedef struct { +struct kib_rej { __u32 ibr_magic; /* sender's magic */ __u16 ibr_version; /* sender's version */ __u8 ibr_why; /* reject reason */ __u8 ibr_padding; /* padding */ __u64 ibr_incarnation; /* incarnation of peer */ - kib_connparams_t ibr_cp; /* connection parameters */ -} WIRE_ATTR kib_rej_t; + struct kib_connparams ibr_cp; /* connection parameters */ +} WIRE_ATTR; /* connection rejection reasons */ #define IBLND_REJECT_CONN_RACE 1 /* You lost connection race */ @@ -467,28 +467,26 @@ typedef struct { /***********************************************************************/ -typedef struct kib_rx /* receive message */ -{ +struct kib_rx { /* receive message */ struct list_head rx_list; /* queue for attention */ struct kib_conn *rx_conn; /* owning conn */ int rx_nob; /* # bytes received (-1 while posted) */ enum ib_wc_status rx_status; /* completion status */ - kib_msg_t *rx_msg; /* message buffer (host vaddr) */ + struct kib_msg *rx_msg; /* message buffer (host vaddr) */ __u64 rx_msgaddr; /* message buffer (I/O addr) */ DECLARE_PCI_UNMAP_ADDR(rx_msgunmap); /* for dma_unmap_single() */ struct ib_recv_wr rx_wrq; /* receive work item... */ struct ib_sge rx_sge; /* ...and its memory */ -} kib_rx_t; +}; #define IBLND_POSTRX_DONT_POST 0 /* don't post */ #define IBLND_POSTRX_NO_CREDIT 1 /* post: no credits */ #define IBLND_POSTRX_PEER_CREDIT 2 /* post: give peer back 1 credit */ #define IBLND_POSTRX_RSRVD_CREDIT 3 /* post: give self back 1 reserved credit */ -typedef struct kib_tx /* transmit message */ -{ +struct kib_tx { /* transmit message */ struct list_head tx_list; /* queue on idle_txs ibc_tx_queue etc. */ - kib_tx_pool_t *tx_pool; /* pool I'm from */ + struct kib_tx_pool *tx_pool; /* pool I'm from */ struct kib_conn *tx_conn; /* owning conn */ short tx_sending; /* # tx callbacks outstanding */ short tx_queued; /* queued for sending */ @@ -497,28 +495,28 @@ typedef struct kib_tx /* transmit message */ unsigned long tx_deadline; /* completion deadline */ __u64 tx_cookie; /* completion cookie */ lnet_msg_t *tx_lntmsg[2]; /* lnet msgs to finalize on completion */ - kib_msg_t *tx_msg; /* message buffer (host vaddr) */ + struct kib_msg *tx_msg; /* message buffer (host vaddr) */ __u64 tx_msgaddr; /* message buffer (I/O addr) */ DECLARE_PCI_UNMAP_ADDR(tx_msgunmap); /* for dma_unmap_single() */ int tx_nwrq; /* # send work items */ struct ib_rdma_wr *tx_wrq; /* send work items... */ struct ib_sge *tx_sge; /* ...and their memory */ - kib_rdma_desc_t *tx_rd; /* rdma descriptor */ + struct kib_rdma_desc *tx_rd; /* rdma descriptor */ int tx_nfrags; /* # entries in... */ struct scatterlist *tx_frags; /* dma_map_sg descriptor */ __u64 *tx_pages; /* rdma phys page addrs */ - kib_fmr_t fmr; /* FMR */ + struct kib_fmr fmr; /* FMR */ int tx_dmadir; /* dma direction */ -} kib_tx_t; +}; -typedef struct kib_connvars { - kib_msg_t cv_msg; /* connection-in-progress variables */ -} kib_connvars_t; +struct kib_connvars { + struct kib_msg cv_msg; /* connection-in-progress variables */ +}; -typedef struct kib_conn { +struct kib_conn { struct kib_sched_info *ibc_sched; /* scheduler information */ struct kib_peer *ibc_peer; /* owning peer */ - kib_hca_dev_t *ibc_hdev; /* HCA bound on */ + struct kib_hca_dev *ibc_hdev; /* HCA bound on */ struct list_head ibc_list; /* stash on peer's conn list */ struct list_head ibc_sched_list; /* schedule for attention */ __u16 ibc_version; /* version of connection */ @@ -553,14 +551,14 @@ typedef struct kib_conn { /* reserve an ACK/DONE msg */ struct list_head ibc_active_txs; /* active tx awaiting completion */ spinlock_t ibc_lock; /* serialise */ - kib_rx_t *ibc_rxs; /* the rx descs */ - kib_pages_t *ibc_rx_pages; /* premapped rx msg pages */ + struct kib_rx *ibc_rxs; /* the rx descs */ + struct kib_pages *ibc_rx_pages; /* premapped rx msg pages */ struct rdma_cm_id *ibc_cmid; /* CM id */ struct ib_cq *ibc_cq; /* completion queue */ - kib_connvars_t *ibc_connvars; /* in-progress connection state */ -} kib_conn_t; + struct kib_connvars *ibc_connvars; /* in-progress connection state */ +}; #define IBLND_CONN_INIT 0 /* being initialised */ #define IBLND_CONN_ACTIVE_CONNECT 1 /* active sending req */ @@ -569,7 +567,7 @@ typedef struct kib_conn { #define IBLND_CONN_CLOSING 4 /* being closed */ #define IBLND_CONN_DISCONNECTED 5 /* disconnected */ -typedef struct kib_peer { +struct kib_peer { struct list_head ibp_list; /* stash on global peer list */ lnet_nid_t ibp_nid; /* who's on the other end(s) */ lnet_ni_t *ibp_ni; /* LNet interface */ @@ -596,11 +594,11 @@ typedef struct kib_peer { __u16 ibp_max_frags; /* max_peer_credits */ __u16 ibp_queue_depth; -} kib_peer_t; +}; -extern kib_data_t kiblnd_data; +extern struct kib_data kiblnd_data; -void kiblnd_hdev_destroy(kib_hca_dev_t *hdev); +void kiblnd_hdev_destroy(struct kib_hca_dev *hdev); int kiblnd_msg_queue_size(int version, struct lnet_ni *ni); @@ -645,14 +643,14 @@ kiblnd_concurrent_sends(int version, struct lnet_ni *ni) } static inline void -kiblnd_hdev_addref_locked(kib_hca_dev_t *hdev) +kiblnd_hdev_addref_locked(struct kib_hca_dev *hdev) { LASSERT(atomic_read(&hdev->ibh_ref) > 0); atomic_inc(&hdev->ibh_ref); } static inline void -kiblnd_hdev_decref(kib_hca_dev_t *hdev) +kiblnd_hdev_decref(struct kib_hca_dev *hdev) { LASSERT(atomic_read(&hdev->ibh_ref) > 0); if (atomic_dec_and_test(&hdev->ibh_ref)) @@ -660,7 +658,7 @@ kiblnd_hdev_decref(kib_hca_dev_t *hdev) } static inline int -kiblnd_dev_can_failover(kib_dev_t *dev) +kiblnd_dev_can_failover(struct kib_dev *dev) { if (!list_empty(&dev->ibd_fail_list)) /* already scheduled */ return 0; @@ -716,7 +714,7 @@ do { \ } while (0) static inline bool -kiblnd_peer_connecting(kib_peer_t *peer) +kiblnd_peer_connecting(struct kib_peer *peer) { return peer->ibp_connecting || peer->ibp_reconnecting || @@ -724,7 +722,7 @@ kiblnd_peer_connecting(kib_peer_t *peer) } static inline bool -kiblnd_peer_idle(kib_peer_t *peer) +kiblnd_peer_idle(struct kib_peer *peer) { return !kiblnd_peer_connecting(peer) && list_empty(&peer->ibp_conns); } @@ -739,23 +737,23 @@ kiblnd_nid2peerlist(lnet_nid_t nid) } static inline int -kiblnd_peer_active(kib_peer_t *peer) +kiblnd_peer_active(struct kib_peer *peer) { /* Am I in the peer hash table? */ return !list_empty(&peer->ibp_list); } -static inline kib_conn_t * -kiblnd_get_conn_locked(kib_peer_t *peer) +static inline struct kib_conn * +kiblnd_get_conn_locked(struct kib_peer *peer) { LASSERT(!list_empty(&peer->ibp_conns)); /* just return the first connection */ - return list_entry(peer->ibp_conns.next, kib_conn_t, ibc_list); + return list_entry(peer->ibp_conns.next, struct kib_conn, ibc_list); } static inline int -kiblnd_send_keepalive(kib_conn_t *conn) +kiblnd_send_keepalive(struct kib_conn *conn) { return (*kiblnd_tunables.kib_keepalive > 0) && cfs_time_after(jiffies, conn->ibc_last_send + @@ -764,7 +762,7 @@ kiblnd_send_keepalive(kib_conn_t *conn) } static inline int -kiblnd_need_noop(kib_conn_t *conn) +kiblnd_need_noop(struct kib_conn *conn) { struct lnet_ioctl_config_o2iblnd_tunables *tunables; lnet_ni_t *ni = conn->ibc_peer->ibp_ni; @@ -800,14 +798,14 @@ kiblnd_need_noop(kib_conn_t *conn) } static inline void -kiblnd_abort_receives(kib_conn_t *conn) +kiblnd_abort_receives(struct kib_conn *conn) { ib_modify_qp(conn->ibc_cmid->qp, &kiblnd_data.kib_error_qpa, IB_QP_STATE); } static inline const char * -kiblnd_queue2str(kib_conn_t *conn, struct list_head *q) +kiblnd_queue2str(struct kib_conn *conn, struct list_head *q) { if (q == &conn->ibc_tx_queue) return "tx_queue"; @@ -858,21 +856,21 @@ kiblnd_wreqid2type(__u64 wreqid) } static inline void -kiblnd_set_conn_state(kib_conn_t *conn, int state) +kiblnd_set_conn_state(struct kib_conn *conn, int state) { conn->ibc_state = state; mb(); } static inline void -kiblnd_init_msg(kib_msg_t *msg, int type, int body_nob) +kiblnd_init_msg(struct kib_msg *msg, int type, int body_nob) { msg->ibm_type = type; - msg->ibm_nob = offsetof(kib_msg_t, ibm_u) + body_nob; + msg->ibm_nob = offsetof(struct kib_msg, ibm_u) + body_nob; } static inline int -kiblnd_rd_size(kib_rdma_desc_t *rd) +kiblnd_rd_size(struct kib_rdma_desc *rd) { int i; int size; @@ -884,25 +882,25 @@ kiblnd_rd_size(kib_rdma_desc_t *rd) } static inline __u64 -kiblnd_rd_frag_addr(kib_rdma_desc_t *rd, int index) +kiblnd_rd_frag_addr(struct kib_rdma_desc *rd, int index) { return rd->rd_frags[index].rf_addr; } static inline __u32 -kiblnd_rd_frag_size(kib_rdma_desc_t *rd, int index) +kiblnd_rd_frag_size(struct kib_rdma_desc *rd, int index) { return rd->rd_frags[index].rf_nob; } static inline __u32 -kiblnd_rd_frag_key(kib_rdma_desc_t *rd, int index) +kiblnd_rd_frag_key(struct kib_rdma_desc *rd, int index) { return rd->rd_key; } static inline int -kiblnd_rd_consume_frag(kib_rdma_desc_t *rd, int index, __u32 nob) +kiblnd_rd_consume_frag(struct kib_rdma_desc *rd, int index, __u32 nob) { if (nob < rd->rd_frags[index].rf_nob) { rd->rd_frags[index].rf_addr += nob; @@ -915,14 +913,14 @@ kiblnd_rd_consume_frag(kib_rdma_desc_t *rd, int index, __u32 nob) } static inline int -kiblnd_rd_msg_size(kib_rdma_desc_t *rd, int msgtype, int n) +kiblnd_rd_msg_size(struct kib_rdma_desc *rd, int msgtype, int n) { LASSERT(msgtype == IBLND_MSG_GET_REQ || msgtype == IBLND_MSG_PUT_ACK); return msgtype == IBLND_MSG_GET_REQ ? - offsetof(kib_get_msg_t, ibgm_rd.rd_frags[n]) : - offsetof(kib_putack_msg_t, ibpam_rd.rd_frags[n]); + offsetof(struct kib_get_msg, ibgm_rd.rd_frags[n]) : + offsetof(struct kib_putack_msg, ibpam_rd.rd_frags[n]); } static inline __u64 @@ -981,17 +979,17 @@ static inline unsigned int kiblnd_sg_dma_len(struct ib_device *dev, #define KIBLND_CONN_PARAM(e) ((e)->param.conn.private_data) #define KIBLND_CONN_PARAM_LEN(e) ((e)->param.conn.private_data_len) -struct ib_mr *kiblnd_find_rd_dma_mr(struct lnet_ni *ni, kib_rdma_desc_t *rd, +struct ib_mr *kiblnd_find_rd_dma_mr(struct lnet_ni *ni, struct kib_rdma_desc *rd, int negotiated_nfrags); -void kiblnd_map_rx_descs(kib_conn_t *conn); -void kiblnd_unmap_rx_descs(kib_conn_t *conn); -void kiblnd_pool_free_node(kib_pool_t *pool, struct list_head *node); -struct list_head *kiblnd_pool_alloc_node(kib_poolset_t *ps); +void kiblnd_map_rx_descs(struct kib_conn *conn); +void kiblnd_unmap_rx_descs(struct kib_conn *conn); +void kiblnd_pool_free_node(struct kib_pool *pool, struct list_head *node); +struct list_head *kiblnd_pool_alloc_node(struct kib_poolset *ps); -int kiblnd_fmr_pool_map(kib_fmr_poolset_t *fps, kib_tx_t *tx, - kib_rdma_desc_t *rd, __u32 nob, __u64 iov, - kib_fmr_t *fmr); -void kiblnd_fmr_pool_unmap(kib_fmr_t *fmr, int status); +int kiblnd_fmr_pool_map(struct kib_fmr_poolset *fps, struct kib_tx *tx, + struct kib_rdma_desc *rd, __u32 nob, __u64 iov, + struct kib_fmr *fmr); +void kiblnd_fmr_pool_unmap(struct kib_fmr *fmr, int status); int kiblnd_tunables_setup(struct lnet_ni *ni); void kiblnd_tunables_init(void); @@ -1001,30 +999,31 @@ int kiblnd_scheduler(void *arg); int kiblnd_thread_start(int (*fn)(void *arg), void *arg, char *name); int kiblnd_failover_thread(void *arg); -int kiblnd_alloc_pages(kib_pages_t **pp, int cpt, int npages); +int kiblnd_alloc_pages(struct kib_pages **pp, int cpt, int npages); int kiblnd_cm_callback(struct rdma_cm_id *cmid, struct rdma_cm_event *event); int kiblnd_translate_mtu(int value); -int kiblnd_dev_failover(kib_dev_t *dev); -int kiblnd_create_peer(lnet_ni_t *ni, kib_peer_t **peerp, lnet_nid_t nid); -void kiblnd_destroy_peer(kib_peer_t *peer); -bool kiblnd_reconnect_peer(kib_peer_t *peer); -void kiblnd_destroy_dev(kib_dev_t *dev); -void kiblnd_unlink_peer_locked(kib_peer_t *peer); -kib_peer_t *kiblnd_find_peer_locked(lnet_nid_t nid); -int kiblnd_close_stale_conns_locked(kib_peer_t *peer, +int kiblnd_dev_failover(struct kib_dev *dev); +int kiblnd_create_peer(lnet_ni_t *ni, struct kib_peer **peerp, lnet_nid_t nid); +void kiblnd_destroy_peer(struct kib_peer *peer); +bool kiblnd_reconnect_peer(struct kib_peer *peer); +void kiblnd_destroy_dev(struct kib_dev *dev); +void kiblnd_unlink_peer_locked(struct kib_peer *peer); +struct kib_peer *kiblnd_find_peer_locked(lnet_nid_t nid); +int kiblnd_close_stale_conns_locked(struct kib_peer *peer, int version, __u64 incarnation); -int kiblnd_close_peer_conns_locked(kib_peer_t *peer, int why); +int kiblnd_close_peer_conns_locked(struct kib_peer *peer, int why); -kib_conn_t *kiblnd_create_conn(kib_peer_t *peer, struct rdma_cm_id *cmid, - int state, int version); -void kiblnd_destroy_conn(kib_conn_t *conn, bool free_conn); -void kiblnd_close_conn(kib_conn_t *conn, int error); -void kiblnd_close_conn_locked(kib_conn_t *conn, int error); +struct kib_conn *kiblnd_create_conn(struct kib_peer *peer, + struct rdma_cm_id *cmid, + int state, int version); +void kiblnd_destroy_conn(struct kib_conn *conn, bool free_conn); +void kiblnd_close_conn(struct kib_conn *conn, int error); +void kiblnd_close_conn_locked(struct kib_conn *conn, int error); -void kiblnd_launch_tx(lnet_ni_t *ni, kib_tx_t *tx, lnet_nid_t nid); +void kiblnd_launch_tx(lnet_ni_t *ni, struct kib_tx *tx, lnet_nid_t nid); void kiblnd_txlist_done(lnet_ni_t *ni, struct list_head *txlist, int status); @@ -1032,10 +1031,10 @@ void kiblnd_qp_event(struct ib_event *event, void *arg); void kiblnd_cq_event(struct ib_event *event, void *arg); void kiblnd_cq_completion(struct ib_cq *cq, void *arg); -void kiblnd_pack_msg(lnet_ni_t *ni, kib_msg_t *msg, int version, +void kiblnd_pack_msg(lnet_ni_t *ni, struct kib_msg *msg, int version, int credits, lnet_nid_t dstnid, __u64 dststamp); -int kiblnd_unpack_msg(kib_msg_t *msg, int nob); -int kiblnd_post_rx(kib_rx_t *rx, int credit); +int kiblnd_unpack_msg(struct kib_msg *msg, int nob); +int kiblnd_post_rx(struct kib_rx *rx, int credit); int kiblnd_send(lnet_ni_t *ni, void *private, lnet_msg_t *lntmsg); int kiblnd_recv(lnet_ni_t *ni, void *private, lnet_msg_t *lntmsg, int delayed, diff --git a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd_cb.c b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd_cb.c index 0f7e3a1..b3cf62f 100644 --- a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd_cb.c +++ b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd_cb.c @@ -40,22 +40,22 @@ #include "o2iblnd.h" -static void kiblnd_peer_alive(kib_peer_t *peer); -static void kiblnd_peer_connect_failed(kib_peer_t *peer, int active, int error); -static void kiblnd_check_sends(kib_conn_t *conn); -static void kiblnd_init_tx_msg(lnet_ni_t *ni, kib_tx_t *tx, +static void kiblnd_peer_alive(struct kib_peer *peer); +static void kiblnd_peer_connect_failed(struct kib_peer *peer, int active, int error); +static void kiblnd_check_sends(struct kib_conn *conn); +static void kiblnd_init_tx_msg(lnet_ni_t *ni, struct kib_tx *tx, int type, int body_nob); -static int kiblnd_init_rdma(kib_conn_t *conn, kib_tx_t *tx, int type, - int resid, kib_rdma_desc_t *dstrd, __u64 dstcookie); -static void kiblnd_queue_tx_locked(kib_tx_t *tx, kib_conn_t *conn); -static void kiblnd_queue_tx(kib_tx_t *tx, kib_conn_t *conn); -static void kiblnd_unmap_tx(lnet_ni_t *ni, kib_tx_t *tx); +static int kiblnd_init_rdma(struct kib_conn *conn, struct kib_tx *tx, int type, + int resid, struct kib_rdma_desc *dstrd, __u64 dstcookie); +static void kiblnd_queue_tx_locked(struct kib_tx *tx, struct kib_conn *conn); +static void kiblnd_queue_tx(struct kib_tx *tx, struct kib_conn *conn); +static void kiblnd_unmap_tx(lnet_ni_t *ni, struct kib_tx *tx); static void -kiblnd_tx_done(lnet_ni_t *ni, kib_tx_t *tx) +kiblnd_tx_done(lnet_ni_t *ni, struct kib_tx *tx) { lnet_msg_t *lntmsg[2]; - kib_net_t *net = ni->ni_data; + struct kib_net *net = ni->ni_data; int rc; int i; @@ -97,10 +97,10 @@ kiblnd_tx_done(lnet_ni_t *ni, kib_tx_t *tx) void kiblnd_txlist_done(lnet_ni_t *ni, struct list_head *txlist, int status) { - kib_tx_t *tx; + struct kib_tx *tx; while (!list_empty(txlist)) { - tx = list_entry(txlist->next, kib_tx_t, tx_list); + tx = list_entry(txlist->next, struct kib_tx, tx_list); list_del(&tx->tx_list); /* complete now */ @@ -110,19 +110,19 @@ kiblnd_txlist_done(lnet_ni_t *ni, struct list_head *txlist, int status) } } -static kib_tx_t * +static struct kib_tx * kiblnd_get_idle_tx(lnet_ni_t *ni, lnet_nid_t target) { - kib_net_t *net = (kib_net_t *)ni->ni_data; + struct kib_net *net = (struct kib_net *)ni->ni_data; struct list_head *node; - kib_tx_t *tx; - kib_tx_poolset_t *tps; + struct kib_tx *tx; + struct kib_tx_poolset *tps; tps = net->ibn_tx_ps[lnet_cpt_of_nid(target)]; node = kiblnd_pool_alloc_node(&tps->tps_poolset); if (!node) return NULL; - tx = list_entry(node, kib_tx_t, tx_list); + tx = list_entry(node, struct kib_tx, tx_list); LASSERT(!tx->tx_nwrq); LASSERT(!tx->tx_queued); @@ -138,9 +138,9 @@ kiblnd_get_idle_tx(lnet_ni_t *ni, lnet_nid_t target) } static void -kiblnd_drop_rx(kib_rx_t *rx) +kiblnd_drop_rx(struct kib_rx *rx) { - kib_conn_t *conn = rx->rx_conn; + struct kib_conn *conn = rx->rx_conn; struct kib_sched_info *sched = conn->ibc_sched; unsigned long flags; @@ -153,10 +153,10 @@ kiblnd_drop_rx(kib_rx_t *rx) } int -kiblnd_post_rx(kib_rx_t *rx, int credit) +kiblnd_post_rx(struct kib_rx *rx, int credit) { - kib_conn_t *conn = rx->rx_conn; - kib_net_t *net = conn->ibc_peer->ibp_ni->ni_data; + struct kib_conn *conn = rx->rx_conn; + struct kib_net *net = conn->ibc_peer->ibp_ni->ni_data; struct ib_recv_wr *bad_wrq = NULL; struct ib_mr *mr = conn->ibc_hdev->ibh_mrs; int rc; @@ -223,13 +223,13 @@ out: return rc; } -static kib_tx_t * -kiblnd_find_waiting_tx_locked(kib_conn_t *conn, int txtype, __u64 cookie) +static struct kib_tx * +kiblnd_find_waiting_tx_locked(struct kib_conn *conn, int txtype, __u64 cookie) { struct list_head *tmp; list_for_each(tmp, &conn->ibc_active_txs) { - kib_tx_t *tx = list_entry(tmp, kib_tx_t, tx_list); + struct kib_tx *tx = list_entry(tmp, struct kib_tx, tx_list); LASSERT(!tx->tx_queued); LASSERT(tx->tx_sending || tx->tx_waiting); @@ -249,9 +249,9 @@ kiblnd_find_waiting_tx_locked(kib_conn_t *conn, int txtype, __u64 cookie) } static void -kiblnd_handle_completion(kib_conn_t *conn, int txtype, int status, __u64 cookie) +kiblnd_handle_completion(struct kib_conn *conn, int txtype, int status, __u64 cookie) { - kib_tx_t *tx; + struct kib_tx *tx; lnet_ni_t *ni = conn->ibc_peer->ibp_ni; int idle; @@ -287,10 +287,10 @@ kiblnd_handle_completion(kib_conn_t *conn, int txtype, int status, __u64 cookie) } static void -kiblnd_send_completion(kib_conn_t *conn, int type, int status, __u64 cookie) +kiblnd_send_completion(struct kib_conn *conn, int type, int status, __u64 cookie) { lnet_ni_t *ni = conn->ibc_peer->ibp_ni; - kib_tx_t *tx = kiblnd_get_idle_tx(ni, conn->ibc_peer->ibp_nid); + struct kib_tx *tx = kiblnd_get_idle_tx(ni, conn->ibc_peer->ibp_nid); if (!tx) { CERROR("Can't get tx for completion %x for %s\n", @@ -300,19 +300,19 @@ kiblnd_send_completion(kib_conn_t *conn, int type, int status, __u64 cookie) tx->tx_msg->ibm_u.completion.ibcm_status = status; tx->tx_msg->ibm_u.completion.ibcm_cookie = cookie; - kiblnd_init_tx_msg(ni, tx, type, sizeof(kib_completion_msg_t)); + kiblnd_init_tx_msg(ni, tx, type, sizeof(struct kib_completion_msg)); kiblnd_queue_tx(tx, conn); } static void -kiblnd_handle_rx(kib_rx_t *rx) +kiblnd_handle_rx(struct kib_rx *rx) { - kib_msg_t *msg = rx->rx_msg; - kib_conn_t *conn = rx->rx_conn; + struct kib_msg *msg = rx->rx_msg; + struct kib_conn *conn = rx->rx_conn; lnet_ni_t *ni = conn->ibc_peer->ibp_ni; int credits = msg->ibm_credits; - kib_tx_t *tx; + struct kib_tx *tx; int rc = 0; int rc2; int post_credit; @@ -467,12 +467,12 @@ kiblnd_handle_rx(kib_rx_t *rx) } static void -kiblnd_rx_complete(kib_rx_t *rx, int status, int nob) +kiblnd_rx_complete(struct kib_rx *rx, int status, int nob) { - kib_msg_t *msg = rx->rx_msg; - kib_conn_t *conn = rx->rx_conn; + struct kib_msg *msg = rx->rx_msg; + struct kib_conn *conn = rx->rx_conn; lnet_ni_t *ni = conn->ibc_peer->ibp_ni; - kib_net_t *net = ni->ni_data; + struct kib_net *net = ni->ni_data; int rc; int err = -EIO; @@ -561,10 +561,10 @@ kiblnd_kvaddr_to_page(unsigned long vaddr) } static int -kiblnd_fmr_map_tx(kib_net_t *net, kib_tx_t *tx, kib_rdma_desc_t *rd, __u32 nob) +kiblnd_fmr_map_tx(struct kib_net *net, struct kib_tx *tx, struct kib_rdma_desc *rd, __u32 nob) { - kib_hca_dev_t *hdev; - kib_fmr_poolset_t *fps; + struct kib_hca_dev *hdev; + struct kib_fmr_poolset *fps; int cpt; int rc; @@ -593,9 +593,9 @@ kiblnd_fmr_map_tx(kib_net_t *net, kib_tx_t *tx, kib_rdma_desc_t *rd, __u32 nob) return 0; } -static void kiblnd_unmap_tx(lnet_ni_t *ni, kib_tx_t *tx) +static void kiblnd_unmap_tx(lnet_ni_t *ni, struct kib_tx *tx) { - kib_net_t *net = ni->ni_data; + struct kib_net *net = ni->ni_data; LASSERT(net); @@ -609,11 +609,11 @@ static void kiblnd_unmap_tx(lnet_ni_t *ni, kib_tx_t *tx) } } -static int kiblnd_map_tx(lnet_ni_t *ni, kib_tx_t *tx, kib_rdma_desc_t *rd, +static int kiblnd_map_tx(lnet_ni_t *ni, struct kib_tx *tx, struct kib_rdma_desc *rd, int nfrags) { - kib_net_t *net = ni->ni_data; - kib_hca_dev_t *hdev = net->ibn_dev->ibd_hdev; + struct kib_net *net = ni->ni_data; + struct kib_hca_dev *hdev = net->ibn_dev->ibd_hdev; struct ib_mr *mr = NULL; __u32 nob; int i; @@ -651,10 +651,10 @@ static int kiblnd_map_tx(lnet_ni_t *ni, kib_tx_t *tx, kib_rdma_desc_t *rd, } static int -kiblnd_setup_rd_iov(lnet_ni_t *ni, kib_tx_t *tx, kib_rdma_desc_t *rd, +kiblnd_setup_rd_iov(lnet_ni_t *ni, struct kib_tx *tx, struct kib_rdma_desc *rd, unsigned int niov, struct kvec *iov, int offset, int nob) { - kib_net_t *net = ni->ni_data; + struct kib_net *net = ni->ni_data; struct page *page; struct scatterlist *sg; unsigned long vaddr; @@ -708,10 +708,10 @@ kiblnd_setup_rd_iov(lnet_ni_t *ni, kib_tx_t *tx, kib_rdma_desc_t *rd, } static int -kiblnd_setup_rd_kiov(lnet_ni_t *ni, kib_tx_t *tx, kib_rdma_desc_t *rd, +kiblnd_setup_rd_kiov(lnet_ni_t *ni, struct kib_tx *tx, struct kib_rdma_desc *rd, int nkiov, lnet_kiov_t *kiov, int offset, int nob) { - kib_net_t *net = ni->ni_data; + struct kib_net *net = ni->ni_data; struct scatterlist *sg; int fragnob; @@ -752,11 +752,11 @@ kiblnd_setup_rd_kiov(lnet_ni_t *ni, kib_tx_t *tx, kib_rdma_desc_t *rd, } static int -kiblnd_post_tx_locked(kib_conn_t *conn, kib_tx_t *tx, int credit) +kiblnd_post_tx_locked(struct kib_conn *conn, struct kib_tx *tx, int credit) __must_hold(&conn->ibc_lock) { - kib_msg_t *msg = tx->tx_msg; - kib_peer_t *peer = conn->ibc_peer; + struct kib_msg *msg = tx->tx_msg; + struct kib_peer *peer = conn->ibc_peer; struct lnet_ni *ni = peer->ibp_ni; int ver = conn->ibc_version; int rc; @@ -909,11 +909,11 @@ kiblnd_post_tx_locked(kib_conn_t *conn, kib_tx_t *tx, int credit) } static void -kiblnd_check_sends(kib_conn_t *conn) +kiblnd_check_sends(struct kib_conn *conn) { int ver = conn->ibc_version; lnet_ni_t *ni = conn->ibc_peer->ibp_ni; - kib_tx_t *tx; + struct kib_tx *tx; /* Don't send anything until after the connection is established */ if (conn->ibc_state < IBLND_CONN_ESTABLISHED) { @@ -932,7 +932,7 @@ kiblnd_check_sends(kib_conn_t *conn) while (conn->ibc_reserved_credits > 0 && !list_empty(&conn->ibc_tx_queue_rsrvd)) { tx = list_entry(conn->ibc_tx_queue_rsrvd.next, - kib_tx_t, tx_list); + struct kib_tx, tx_list); list_del(&tx->tx_list); list_add_tail(&tx->tx_list, &conn->ibc_tx_queue); conn->ibc_reserved_credits--; @@ -956,16 +956,16 @@ kiblnd_check_sends(kib_conn_t *conn) if (!list_empty(&conn->ibc_tx_queue_nocred)) { credit = 0; tx = list_entry(conn->ibc_tx_queue_nocred.next, - kib_tx_t, tx_list); + struct kib_tx, tx_list); } else if (!list_empty(&conn->ibc_tx_noops)) { LASSERT(!IBLND_OOB_CAPABLE(ver)); credit = 1; tx = list_entry(conn->ibc_tx_noops.next, - kib_tx_t, tx_list); + struct kib_tx, tx_list); } else if (!list_empty(&conn->ibc_tx_queue)) { credit = 1; tx = list_entry(conn->ibc_tx_queue.next, - kib_tx_t, tx_list); + struct kib_tx, tx_list); } else { break; } @@ -978,10 +978,10 @@ kiblnd_check_sends(kib_conn_t *conn) } static void -kiblnd_tx_complete(kib_tx_t *tx, int status) +kiblnd_tx_complete(struct kib_tx *tx, int status) { int failed = (status != IB_WC_SUCCESS); - kib_conn_t *conn = tx->tx_conn; + struct kib_conn *conn = tx->tx_conn; int idle; LASSERT(tx->tx_sending > 0); @@ -1033,12 +1033,12 @@ kiblnd_tx_complete(kib_tx_t *tx, int status) } static void -kiblnd_init_tx_msg(lnet_ni_t *ni, kib_tx_t *tx, int type, int body_nob) +kiblnd_init_tx_msg(lnet_ni_t *ni, struct kib_tx *tx, int type, int body_nob) { - kib_hca_dev_t *hdev = tx->tx_pool->tpo_hdev; + struct kib_hca_dev *hdev = tx->tx_pool->tpo_hdev; struct ib_sge *sge = &tx->tx_sge[tx->tx_nwrq]; struct ib_rdma_wr *wrq = &tx->tx_wrq[tx->tx_nwrq]; - int nob = offsetof(kib_msg_t, ibm_u) + body_nob; + int nob = offsetof(struct kib_msg, ibm_u) + body_nob; struct ib_mr *mr = hdev->ibh_mrs; LASSERT(tx->tx_nwrq >= 0); @@ -1065,11 +1065,11 @@ kiblnd_init_tx_msg(lnet_ni_t *ni, kib_tx_t *tx, int type, int body_nob) } static int -kiblnd_init_rdma(kib_conn_t *conn, kib_tx_t *tx, int type, - int resid, kib_rdma_desc_t *dstrd, __u64 dstcookie) +kiblnd_init_rdma(struct kib_conn *conn, struct kib_tx *tx, int type, + int resid, struct kib_rdma_desc *dstrd, __u64 dstcookie) { - kib_msg_t *ibmsg = tx->tx_msg; - kib_rdma_desc_t *srcrd = tx->tx_rd; + struct kib_msg *ibmsg = tx->tx_msg; + struct kib_rdma_desc *srcrd = tx->tx_rd; struct ib_sge *sge = &tx->tx_sge[0]; struct ib_rdma_wr *wrq, *next; int rc = resid; @@ -1143,13 +1143,13 @@ kiblnd_init_rdma(kib_conn_t *conn, kib_tx_t *tx, int type, ibmsg->ibm_u.completion.ibcm_status = rc; ibmsg->ibm_u.completion.ibcm_cookie = dstcookie; kiblnd_init_tx_msg(conn->ibc_peer->ibp_ni, tx, - type, sizeof(kib_completion_msg_t)); + type, sizeof(struct kib_completion_msg)); return rc; } static void -kiblnd_queue_tx_locked(kib_tx_t *tx, kib_conn_t *conn) +kiblnd_queue_tx_locked(struct kib_tx *tx, struct kib_conn *conn) { struct list_head *q; @@ -1204,7 +1204,7 @@ kiblnd_queue_tx_locked(kib_tx_t *tx, kib_conn_t *conn) } static void -kiblnd_queue_tx(kib_tx_t *tx, kib_conn_t *conn) +kiblnd_queue_tx(struct kib_tx *tx, struct kib_conn *conn) { spin_lock(&conn->ibc_lock); kiblnd_queue_tx_locked(tx, conn); @@ -1251,11 +1251,11 @@ static int kiblnd_resolve_addr(struct rdma_cm_id *cmid, } static void -kiblnd_connect_peer(kib_peer_t *peer) +kiblnd_connect_peer(struct kib_peer *peer) { struct rdma_cm_id *cmid; - kib_dev_t *dev; - kib_net_t *net = peer->ibp_ni->ni_data; + struct kib_dev *dev; + struct kib_net *net = peer->ibp_ni->ni_data; struct sockaddr_in srcaddr; struct sockaddr_in dstaddr; int rc; @@ -1319,7 +1319,7 @@ kiblnd_connect_peer(kib_peer_t *peer) } bool -kiblnd_reconnect_peer(kib_peer_t *peer) +kiblnd_reconnect_peer(struct kib_peer *peer) { rwlock_t *glock = &kiblnd_data.kib_global_lock; char *reason = NULL; @@ -1369,11 +1369,11 @@ no_reconnect: } void -kiblnd_launch_tx(lnet_ni_t *ni, kib_tx_t *tx, lnet_nid_t nid) +kiblnd_launch_tx(lnet_ni_t *ni, struct kib_tx *tx, lnet_nid_t nid) { - kib_peer_t *peer; - kib_peer_t *peer2; - kib_conn_t *conn; + struct kib_peer *peer; + struct kib_peer *peer2; + struct kib_conn *conn; rwlock_t *g_lock = &kiblnd_data.kib_global_lock; unsigned long flags; int rc; @@ -1476,7 +1476,7 @@ kiblnd_launch_tx(lnet_ni_t *ni, kib_tx_t *tx, lnet_nid_t nid) peer->ibp_connecting = 1; /* always called with a ref on ni, which prevents ni being shutdown */ - LASSERT(!((kib_net_t *)ni->ni_data)->ibn_shutdown); + LASSERT(!((struct kib_net *)ni->ni_data)->ibn_shutdown); if (tx) list_add_tail(&tx->tx_list, &peer->ibp_tx_queue); @@ -1503,9 +1503,9 @@ kiblnd_send(lnet_ni_t *ni, void *private, lnet_msg_t *lntmsg) lnet_kiov_t *payload_kiov = lntmsg->msg_kiov; unsigned int payload_offset = lntmsg->msg_offset; unsigned int payload_nob = lntmsg->msg_len; - kib_msg_t *ibmsg; - kib_rdma_desc_t *rd; - kib_tx_t *tx; + struct kib_msg *ibmsg; + struct kib_rdma_desc *rd; + struct kib_tx *tx; int nob; int rc; @@ -1536,7 +1536,7 @@ kiblnd_send(lnet_ni_t *ni, void *private, lnet_msg_t *lntmsg) break; /* send IMMEDIATE */ /* is the REPLY message too small for RDMA? */ - nob = offsetof(kib_msg_t, ibm_u.immediate.ibim_payload[lntmsg->msg_md->md_length]); + nob = offsetof(struct kib_msg, ibm_u.immediate.ibim_payload[lntmsg->msg_md->md_length]); if (nob <= IBLND_MSG_SIZE) break; /* send IMMEDIATE */ @@ -1566,7 +1566,7 @@ kiblnd_send(lnet_ni_t *ni, void *private, lnet_msg_t *lntmsg) return -EIO; } - nob = offsetof(kib_get_msg_t, ibgm_rd.rd_frags[rd->rd_nfrags]); + nob = offsetof(struct kib_get_msg, ibgm_rd.rd_frags[rd->rd_nfrags]); ibmsg->ibm_u.get.ibgm_cookie = tx->tx_cookie; ibmsg->ibm_u.get.ibgm_hdr = *hdr; @@ -1588,7 +1588,7 @@ kiblnd_send(lnet_ni_t *ni, void *private, lnet_msg_t *lntmsg) case LNET_MSG_REPLY: case LNET_MSG_PUT: /* Is the payload small enough not to need RDMA? */ - nob = offsetof(kib_msg_t, ibm_u.immediate.ibim_payload[payload_nob]); + nob = offsetof(struct kib_msg, ibm_u.immediate.ibim_payload[payload_nob]); if (nob <= IBLND_MSG_SIZE) break; /* send IMMEDIATE */ @@ -1618,7 +1618,7 @@ kiblnd_send(lnet_ni_t *ni, void *private, lnet_msg_t *lntmsg) ibmsg = tx->tx_msg; ibmsg->ibm_u.putreq.ibprm_hdr = *hdr; ibmsg->ibm_u.putreq.ibprm_cookie = tx->tx_cookie; - kiblnd_init_tx_msg(ni, tx, IBLND_MSG_PUT_REQ, sizeof(kib_putreq_msg_t)); + kiblnd_init_tx_msg(ni, tx, IBLND_MSG_PUT_REQ, sizeof(struct kib_putreq_msg)); tx->tx_lntmsg[0] = lntmsg; /* finalise lntmsg on completion */ tx->tx_waiting = 1; /* waiting for PUT_{ACK,NAK} */ @@ -1628,7 +1628,7 @@ kiblnd_send(lnet_ni_t *ni, void *private, lnet_msg_t *lntmsg) /* send IMMEDIATE */ - LASSERT(offsetof(kib_msg_t, ibm_u.immediate.ibim_payload[payload_nob]) + LASSERT(offsetof(struct kib_msg, ibm_u.immediate.ibim_payload[payload_nob]) <= IBLND_MSG_SIZE); tx = kiblnd_get_idle_tx(ni, target.nid); @@ -1643,16 +1643,16 @@ kiblnd_send(lnet_ni_t *ni, void *private, lnet_msg_t *lntmsg) if (payload_kiov) lnet_copy_kiov2flat(IBLND_MSG_SIZE, ibmsg, - offsetof(kib_msg_t, ibm_u.immediate.ibim_payload), + offsetof(struct kib_msg, ibm_u.immediate.ibim_payload), payload_niov, payload_kiov, payload_offset, payload_nob); else lnet_copy_iov2flat(IBLND_MSG_SIZE, ibmsg, - offsetof(kib_msg_t, ibm_u.immediate.ibim_payload), + offsetof(struct kib_msg, ibm_u.immediate.ibim_payload), payload_niov, payload_iov, payload_offset, payload_nob); - nob = offsetof(kib_immediate_msg_t, ibim_payload[payload_nob]); + nob = offsetof(struct kib_immediate_msg, ibim_payload[payload_nob]); kiblnd_init_tx_msg(ni, tx, IBLND_MSG_IMMEDIATE, nob); tx->tx_lntmsg[0] = lntmsg; /* finalise lntmsg on completion */ @@ -1661,7 +1661,7 @@ kiblnd_send(lnet_ni_t *ni, void *private, lnet_msg_t *lntmsg) } static void -kiblnd_reply(lnet_ni_t *ni, kib_rx_t *rx, lnet_msg_t *lntmsg) +kiblnd_reply(lnet_ni_t *ni, struct kib_rx *rx, lnet_msg_t *lntmsg) { lnet_process_id_t target = lntmsg->msg_target; unsigned int niov = lntmsg->msg_niov; @@ -1669,7 +1669,7 @@ kiblnd_reply(lnet_ni_t *ni, kib_rx_t *rx, lnet_msg_t *lntmsg) lnet_kiov_t *kiov = lntmsg->msg_kiov; unsigned int offset = lntmsg->msg_offset; unsigned int nob = lntmsg->msg_len; - kib_tx_t *tx; + struct kib_tx *tx; int rc; tx = kiblnd_get_idle_tx(ni, rx->rx_conn->ibc_peer->ibp_nid); @@ -1726,10 +1726,10 @@ kiblnd_recv(lnet_ni_t *ni, void *private, lnet_msg_t *lntmsg, int delayed, unsigned int niov, struct kvec *iov, lnet_kiov_t *kiov, unsigned int offset, unsigned int mlen, unsigned int rlen) { - kib_rx_t *rx = private; - kib_msg_t *rxmsg = rx->rx_msg; - kib_conn_t *conn = rx->rx_conn; - kib_tx_t *tx; + struct kib_rx *rx = private; + struct kib_msg *rxmsg = rx->rx_msg; + struct kib_conn *conn = rx->rx_conn; + struct kib_tx *tx; int nob; int post_credit = IBLND_POSTRX_PEER_CREDIT; int rc = 0; @@ -1744,7 +1744,7 @@ kiblnd_recv(lnet_ni_t *ni, void *private, lnet_msg_t *lntmsg, int delayed, LBUG(); case IBLND_MSG_IMMEDIATE: - nob = offsetof(kib_msg_t, ibm_u.immediate.ibim_payload[rlen]); + nob = offsetof(struct kib_msg, ibm_u.immediate.ibim_payload[rlen]); if (nob > rx->rx_nob) { CERROR("Immediate message from %s too big: %d(%d)\n", libcfs_nid2str(rxmsg->ibm_u.immediate.ibim_hdr.src_nid), @@ -1756,19 +1756,19 @@ kiblnd_recv(lnet_ni_t *ni, void *private, lnet_msg_t *lntmsg, int delayed, if (kiov) lnet_copy_flat2kiov(niov, kiov, offset, IBLND_MSG_SIZE, rxmsg, - offsetof(kib_msg_t, ibm_u.immediate.ibim_payload), + offsetof(struct kib_msg, ibm_u.immediate.ibim_payload), mlen); else lnet_copy_flat2iov(niov, iov, offset, IBLND_MSG_SIZE, rxmsg, - offsetof(kib_msg_t, ibm_u.immediate.ibim_payload), + offsetof(struct kib_msg, ibm_u.immediate.ibim_payload), mlen); lnet_finalize(ni, lntmsg, 0); break; case IBLND_MSG_PUT_REQ: { - kib_msg_t *txmsg; - kib_rdma_desc_t *rd; + struct kib_msg *txmsg; + struct kib_rdma_desc *rd; if (!mlen) { lnet_finalize(ni, lntmsg, 0); @@ -1804,7 +1804,7 @@ kiblnd_recv(lnet_ni_t *ni, void *private, lnet_msg_t *lntmsg, int delayed, break; } - nob = offsetof(kib_putack_msg_t, ibpam_rd.rd_frags[rd->rd_nfrags]); + nob = offsetof(struct kib_putack_msg, ibpam_rd.rd_frags[rd->rd_nfrags]); txmsg->ibm_u.putack.ibpam_src_cookie = rxmsg->ibm_u.putreq.ibprm_cookie; txmsg->ibm_u.putack.ibpam_dst_cookie = tx->tx_cookie; @@ -1855,7 +1855,7 @@ kiblnd_thread_fini(void) } static void -kiblnd_peer_alive(kib_peer_t *peer) +kiblnd_peer_alive(struct kib_peer *peer) { /* This is racy, but everyone's only writing cfs_time_current() */ peer->ibp_last_alive = cfs_time_current(); @@ -1863,7 +1863,7 @@ kiblnd_peer_alive(kib_peer_t *peer) } static void -kiblnd_peer_notify(kib_peer_t *peer) +kiblnd_peer_notify(struct kib_peer *peer) { int error = 0; unsigned long last_alive = 0; @@ -1886,7 +1886,7 @@ kiblnd_peer_notify(kib_peer_t *peer) } void -kiblnd_close_conn_locked(kib_conn_t *conn, int error) +kiblnd_close_conn_locked(struct kib_conn *conn, int error) { /* * This just does the immediate housekeeping. 'error' is zero for a @@ -1896,8 +1896,8 @@ kiblnd_close_conn_locked(kib_conn_t *conn, int error) * already dealing with it (either to set it up or tear it down). * Caller holds kib_global_lock exclusively in irq context */ - kib_peer_t *peer = conn->ibc_peer; - kib_dev_t *dev; + struct kib_peer *peer = conn->ibc_peer; + struct kib_dev *dev; unsigned long flags; LASSERT(error || conn->ibc_state >= IBLND_CONN_ESTABLISHED); @@ -1926,7 +1926,7 @@ kiblnd_close_conn_locked(kib_conn_t *conn, int error) list_empty(&conn->ibc_active_txs) ? "" : "(waiting)"); } - dev = ((kib_net_t *)peer->ibp_ni->ni_data)->ibn_dev; + dev = ((struct kib_net *)peer->ibp_ni->ni_data)->ibn_dev; list_del(&conn->ibc_list); /* connd (see below) takes over ibc_list's ref */ @@ -1956,7 +1956,7 @@ kiblnd_close_conn_locked(kib_conn_t *conn, int error) } void -kiblnd_close_conn(kib_conn_t *conn, int error) +kiblnd_close_conn(struct kib_conn *conn, int error) { unsigned long flags; @@ -1968,11 +1968,11 @@ kiblnd_close_conn(kib_conn_t *conn, int error) } static void -kiblnd_handle_early_rxs(kib_conn_t *conn) +kiblnd_handle_early_rxs(struct kib_conn *conn) { unsigned long flags; - kib_rx_t *rx; - kib_rx_t *tmp; + struct kib_rx *rx; + struct kib_rx *tmp; LASSERT(!in_interrupt()); LASSERT(conn->ibc_state >= IBLND_CONN_ESTABLISHED); @@ -1990,17 +1990,17 @@ kiblnd_handle_early_rxs(kib_conn_t *conn) } static void -kiblnd_abort_txs(kib_conn_t *conn, struct list_head *txs) +kiblnd_abort_txs(struct kib_conn *conn, struct list_head *txs) { LIST_HEAD(zombies); struct list_head *tmp; struct list_head *nxt; - kib_tx_t *tx; + struct kib_tx *tx; spin_lock(&conn->ibc_lock); list_for_each_safe(tmp, nxt, txs) { - tx = list_entry(tmp, kib_tx_t, tx_list); + tx = list_entry(tmp, struct kib_tx, tx_list); if (txs == &conn->ibc_active_txs) { LASSERT(!tx->tx_queued); @@ -2025,7 +2025,7 @@ kiblnd_abort_txs(kib_conn_t *conn, struct list_head *txs) } static void -kiblnd_finalise_conn(kib_conn_t *conn) +kiblnd_finalise_conn(struct kib_conn *conn) { LASSERT(!in_interrupt()); LASSERT(conn->ibc_state > IBLND_CONN_INIT); @@ -2053,7 +2053,7 @@ kiblnd_finalise_conn(kib_conn_t *conn) } static void -kiblnd_peer_connect_failed(kib_peer_t *peer, int active, int error) +kiblnd_peer_connect_failed(struct kib_peer *peer, int active, int error) { LIST_HEAD(zombies); unsigned long flags; @@ -2107,11 +2107,11 @@ kiblnd_peer_connect_failed(kib_peer_t *peer, int active, int error) } static void -kiblnd_connreq_done(kib_conn_t *conn, int status) +kiblnd_connreq_done(struct kib_conn *conn, int status) { - kib_peer_t *peer = conn->ibc_peer; - kib_tx_t *tx; - kib_tx_t *tmp; + struct kib_peer *peer = conn->ibc_peer; + struct kib_tx *tx; + struct kib_tx *tmp; struct list_head txs; unsigned long flags; int active; @@ -2217,7 +2217,7 @@ kiblnd_connreq_done(kib_conn_t *conn, int status) } static void -kiblnd_reject(struct rdma_cm_id *cmid, kib_rej_t *rej) +kiblnd_reject(struct rdma_cm_id *cmid, struct kib_rej *rej) { int rc; @@ -2231,17 +2231,17 @@ static int kiblnd_passive_connect(struct rdma_cm_id *cmid, void *priv, int priv_nob) { rwlock_t *g_lock = &kiblnd_data.kib_global_lock; - kib_msg_t *reqmsg = priv; - kib_msg_t *ackmsg; - kib_dev_t *ibdev; - kib_peer_t *peer; - kib_peer_t *peer2; - kib_conn_t *conn; + struct kib_msg *reqmsg = priv; + struct kib_msg *ackmsg; + struct kib_dev *ibdev; + struct kib_peer *peer; + struct kib_peer *peer2; + struct kib_conn *conn; lnet_ni_t *ni = NULL; - kib_net_t *net = NULL; + struct kib_net *net = NULL; lnet_nid_t nid; struct rdma_conn_param cp; - kib_rej_t rej; + struct kib_rej rej; int version = IBLND_MSG_VERSION; unsigned long flags; int rc; @@ -2250,7 +2250,7 @@ kiblnd_passive_connect(struct rdma_cm_id *cmid, void *priv, int priv_nob) LASSERT(!in_interrupt()); /* cmid inherits 'context' from the corresponding listener id */ - ibdev = (kib_dev_t *)cmid->context; + ibdev = (struct kib_dev *)cmid->context; LASSERT(ibdev); memset(&rej, 0, sizeof(rej)); @@ -2268,7 +2268,7 @@ kiblnd_passive_connect(struct rdma_cm_id *cmid, void *priv, int priv_nob) goto failed; } - if (priv_nob < offsetof(kib_msg_t, ibm_type)) { + if (priv_nob < offsetof(struct kib_msg, ibm_type)) { CERROR("Short connection request\n"); goto failed; } @@ -2303,7 +2303,7 @@ kiblnd_passive_connect(struct rdma_cm_id *cmid, void *priv, int priv_nob) ni = lnet_net2ni(LNET_NIDNET(reqmsg->ibm_dstnid)); if (ni) { - net = (kib_net_t *)ni->ni_data; + net = (struct kib_net *)ni->ni_data; rej.ibr_incarnation = net->ibn_incarnation; } @@ -2541,11 +2541,11 @@ kiblnd_passive_connect(struct rdma_cm_id *cmid, void *priv, int priv_nob) } static void -kiblnd_check_reconnect(kib_conn_t *conn, int version, - __u64 incarnation, int why, kib_connparams_t *cp) +kiblnd_check_reconnect(struct kib_conn *conn, int version, + __u64 incarnation, int why, struct kib_connparams *cp) { rwlock_t *glock = &kiblnd_data.kib_global_lock; - kib_peer_t *peer = conn->ibc_peer; + struct kib_peer *peer = conn->ibc_peer; char *reason; int msg_size = IBLND_MSG_SIZE; int frag_num = -1; @@ -2654,9 +2654,9 @@ out: } static void -kiblnd_rejected(kib_conn_t *conn, int reason, void *priv, int priv_nob) +kiblnd_rejected(struct kib_conn *conn, int reason, void *priv, int priv_nob) { - kib_peer_t *peer = conn->ibc_peer; + struct kib_peer *peer = conn->ibc_peer; LASSERT(!in_interrupt()); LASSERT(conn->ibc_state == IBLND_CONN_ACTIVE_CONNECT); @@ -2674,9 +2674,9 @@ kiblnd_rejected(kib_conn_t *conn, int reason, void *priv, int priv_nob) break; case IB_CM_REJ_CONSUMER_DEFINED: - if (priv_nob >= offsetof(kib_rej_t, ibr_padding)) { - kib_rej_t *rej = priv; - kib_connparams_t *cp = NULL; + if (priv_nob >= offsetof(struct kib_rej, ibr_padding)) { + struct kib_rej *rej = priv; + struct kib_connparams *cp = NULL; int flip = 0; __u64 incarnation = -1; @@ -2699,7 +2699,7 @@ kiblnd_rejected(kib_conn_t *conn, int reason, void *priv, int priv_nob) flip = 1; } - if (priv_nob >= sizeof(kib_rej_t) && + if (priv_nob >= sizeof(struct kib_rej) && rej->ibr_version > IBLND_MSG_VERSION_1) { /* * priv_nob is always 148 in current version @@ -2782,12 +2782,12 @@ kiblnd_rejected(kib_conn_t *conn, int reason, void *priv, int priv_nob) } static void -kiblnd_check_connreply(kib_conn_t *conn, void *priv, int priv_nob) +kiblnd_check_connreply(struct kib_conn *conn, void *priv, int priv_nob) { - kib_peer_t *peer = conn->ibc_peer; + struct kib_peer *peer = conn->ibc_peer; lnet_ni_t *ni = peer->ibp_ni; - kib_net_t *net = ni->ni_data; - kib_msg_t *msg = priv; + struct kib_net *net = ni->ni_data; + struct kib_msg *msg = priv; int ver = conn->ibc_version; int rc = kiblnd_unpack_msg(msg, priv_nob); unsigned long flags; @@ -2884,9 +2884,9 @@ kiblnd_check_connreply(kib_conn_t *conn, void *priv, int priv_nob) static int kiblnd_active_connect(struct rdma_cm_id *cmid) { - kib_peer_t *peer = (kib_peer_t *)cmid->context; - kib_conn_t *conn; - kib_msg_t *msg; + struct kib_peer *peer = (struct kib_peer *)cmid->context; + struct kib_conn *conn; + struct kib_msg *msg; struct rdma_conn_param cp; int version; __u64 incarnation; @@ -2951,8 +2951,8 @@ kiblnd_active_connect(struct rdma_cm_id *cmid) int kiblnd_cm_callback(struct rdma_cm_id *cmid, struct rdma_cm_event *event) { - kib_peer_t *peer; - kib_conn_t *conn; + struct kib_peer *peer; + struct kib_conn *conn; int rc; switch (event->event) { @@ -2970,7 +2970,7 @@ kiblnd_cm_callback(struct rdma_cm_id *cmid, struct rdma_cm_event *event) return rc; case RDMA_CM_EVENT_ADDR_ERROR: - peer = (kib_peer_t *)cmid->context; + peer = (struct kib_peer *)cmid->context; CNETERR("%s: ADDR ERROR %d\n", libcfs_nid2str(peer->ibp_nid), event->status); kiblnd_peer_connect_failed(peer, 1, -EHOSTUNREACH); @@ -2978,7 +2978,7 @@ kiblnd_cm_callback(struct rdma_cm_id *cmid, struct rdma_cm_event *event) return -EHOSTUNREACH; /* rc destroys cmid */ case RDMA_CM_EVENT_ADDR_RESOLVED: - peer = (kib_peer_t *)cmid->context; + peer = (struct kib_peer *)cmid->context; CDEBUG(D_NET, "%s Addr resolved: %d\n", libcfs_nid2str(peer->ibp_nid), event->status); @@ -3001,7 +3001,7 @@ kiblnd_cm_callback(struct rdma_cm_id *cmid, struct rdma_cm_event *event) return rc; /* rc destroys cmid */ case RDMA_CM_EVENT_ROUTE_ERROR: - peer = (kib_peer_t *)cmid->context; + peer = (struct kib_peer *)cmid->context; CNETERR("%s: ROUTE ERROR %d\n", libcfs_nid2str(peer->ibp_nid), event->status); kiblnd_peer_connect_failed(peer, 1, -EHOSTUNREACH); @@ -3009,7 +3009,7 @@ kiblnd_cm_callback(struct rdma_cm_id *cmid, struct rdma_cm_event *event) return -EHOSTUNREACH; /* rc destroys cmid */ case RDMA_CM_EVENT_ROUTE_RESOLVED: - peer = (kib_peer_t *)cmid->context; + peer = (struct kib_peer *)cmid->context; CDEBUG(D_NET, "%s Route resolved: %d\n", libcfs_nid2str(peer->ibp_nid), event->status); @@ -3023,7 +3023,7 @@ kiblnd_cm_callback(struct rdma_cm_id *cmid, struct rdma_cm_event *event) return event->status; /* rc destroys cmid */ case RDMA_CM_EVENT_UNREACHABLE: - conn = (kib_conn_t *)cmid->context; + conn = (struct kib_conn *)cmid->context; LASSERT(conn->ibc_state == IBLND_CONN_ACTIVE_CONNECT || conn->ibc_state == IBLND_CONN_PASSIVE_WAIT); CNETERR("%s: UNREACHABLE %d\n", @@ -3033,7 +3033,7 @@ kiblnd_cm_callback(struct rdma_cm_id *cmid, struct rdma_cm_event *event) return 0; case RDMA_CM_EVENT_CONNECT_ERROR: - conn = (kib_conn_t *)cmid->context; + conn = (struct kib_conn *)cmid->context; LASSERT(conn->ibc_state == IBLND_CONN_ACTIVE_CONNECT || conn->ibc_state == IBLND_CONN_PASSIVE_WAIT); CNETERR("%s: CONNECT ERROR %d\n", @@ -3043,7 +3043,7 @@ kiblnd_cm_callback(struct rdma_cm_id *cmid, struct rdma_cm_event *event) return 0; case RDMA_CM_EVENT_REJECTED: - conn = (kib_conn_t *)cmid->context; + conn = (struct kib_conn *)cmid->context; switch (conn->ibc_state) { default: LBUG(); @@ -3065,7 +3065,7 @@ kiblnd_cm_callback(struct rdma_cm_id *cmid, struct rdma_cm_event *event) return 0; case RDMA_CM_EVENT_ESTABLISHED: - conn = (kib_conn_t *)cmid->context; + conn = (struct kib_conn *)cmid->context; switch (conn->ibc_state) { default: LBUG(); @@ -3091,7 +3091,7 @@ kiblnd_cm_callback(struct rdma_cm_id *cmid, struct rdma_cm_event *event) CDEBUG(D_NET, "Ignore TIMEWAIT_EXIT event\n"); return 0; case RDMA_CM_EVENT_DISCONNECTED: - conn = (kib_conn_t *)cmid->context; + conn = (struct kib_conn *)cmid->context; if (conn->ibc_state < IBLND_CONN_ESTABLISHED) { CERROR("%s DISCONNECTED\n", libcfs_nid2str(conn->ibc_peer->ibp_nid)); @@ -3120,13 +3120,13 @@ kiblnd_cm_callback(struct rdma_cm_id *cmid, struct rdma_cm_event *event) } static int -kiblnd_check_txs_locked(kib_conn_t *conn, struct list_head *txs) +kiblnd_check_txs_locked(struct kib_conn *conn, struct list_head *txs) { - kib_tx_t *tx; + struct kib_tx *tx; struct list_head *ttmp; list_for_each(ttmp, txs) { - tx = list_entry(ttmp, kib_tx_t, tx_list); + tx = list_entry(ttmp, struct kib_tx, tx_list); if (txs != &conn->ibc_active_txs) { LASSERT(tx->tx_queued); @@ -3147,7 +3147,7 @@ kiblnd_check_txs_locked(kib_conn_t *conn, struct list_head *txs) } static int -kiblnd_conn_timed_out_locked(kib_conn_t *conn) +kiblnd_conn_timed_out_locked(struct kib_conn *conn) { return kiblnd_check_txs_locked(conn, &conn->ibc_tx_queue) || kiblnd_check_txs_locked(conn, &conn->ibc_tx_noops) || @@ -3163,10 +3163,10 @@ kiblnd_check_conns(int idx) LIST_HEAD(checksends); struct list_head *peers = &kiblnd_data.kib_peers[idx]; struct list_head *ptmp; - kib_peer_t *peer; - kib_conn_t *conn; - kib_conn_t *temp; - kib_conn_t *tmp; + struct kib_peer *peer; + struct kib_conn *conn; + struct kib_conn *temp; + struct kib_conn *tmp; struct list_head *ctmp; unsigned long flags; @@ -3178,13 +3178,13 @@ kiblnd_check_conns(int idx) read_lock_irqsave(&kiblnd_data.kib_global_lock, flags); list_for_each(ptmp, peers) { - peer = list_entry(ptmp, kib_peer_t, ibp_list); + peer = list_entry(ptmp, struct kib_peer, ibp_list); list_for_each(ctmp, &peer->ibp_conns) { int timedout; int sendnoop; - conn = list_entry(ctmp, kib_conn_t, ibc_list); + conn = list_entry(ctmp, struct kib_conn, ibc_list); LASSERT(conn->ibc_state == IBLND_CONN_ESTABLISHED); @@ -3242,7 +3242,7 @@ kiblnd_check_conns(int idx) } static void -kiblnd_disconnect_conn(kib_conn_t *conn) +kiblnd_disconnect_conn(struct kib_conn *conn) { LASSERT(!in_interrupt()); LASSERT(current == kiblnd_data.kib_connd); @@ -3271,7 +3271,7 @@ kiblnd_connd(void *arg) spinlock_t *lock= &kiblnd_data.kib_connd_lock; wait_queue_t wait; unsigned long flags; - kib_conn_t *conn; + struct kib_conn *conn; int timeout; int i; int dropped_lock; @@ -3291,10 +3291,10 @@ kiblnd_connd(void *arg) dropped_lock = 0; if (!list_empty(&kiblnd_data.kib_connd_zombies)) { - kib_peer_t *peer = NULL; + struct kib_peer *peer = NULL; conn = list_entry(kiblnd_data.kib_connd_zombies.next, - kib_conn_t, ibc_list); + struct kib_conn, ibc_list); list_del(&conn->ibc_list); if (conn->ibc_reconnect) { peer = conn->ibc_peer; @@ -3321,7 +3321,7 @@ kiblnd_connd(void *arg) if (!list_empty(&kiblnd_data.kib_connd_conns)) { conn = list_entry(kiblnd_data.kib_connd_conns.next, - kib_conn_t, ibc_list); + struct kib_conn, ibc_list); list_del(&conn->ibc_list); spin_unlock_irqrestore(lock, flags); @@ -3345,7 +3345,7 @@ kiblnd_connd(void *arg) break; conn = list_entry(kiblnd_data.kib_reconn_list.next, - kib_conn_t, ibc_list); + struct kib_conn, ibc_list); list_del(&conn->ibc_list); spin_unlock_irqrestore(lock, flags); @@ -3416,7 +3416,7 @@ kiblnd_connd(void *arg) void kiblnd_qp_event(struct ib_event *event, void *arg) { - kib_conn_t *conn = arg; + struct kib_conn *conn = arg; switch (event->event) { case IB_EVENT_COMM_EST: @@ -3478,7 +3478,7 @@ kiblnd_cq_completion(struct ib_cq *cq, void *arg) * occurred. But in this case, !ibc_nrx && !ibc_nsends_posted * and this CQ is about to be destroyed so I NOOP. */ - kib_conn_t *conn = arg; + struct kib_conn *conn = arg; struct kib_sched_info *sched = conn->ibc_sched; unsigned long flags; @@ -3505,7 +3505,7 @@ kiblnd_cq_completion(struct ib_cq *cq, void *arg) void kiblnd_cq_event(struct ib_event *event, void *arg) { - kib_conn_t *conn = arg; + struct kib_conn *conn = arg; CERROR("%s: async CQ event type %d\n", libcfs_nid2str(conn->ibc_peer->ibp_nid), event->event); @@ -3516,7 +3516,7 @@ kiblnd_scheduler(void *arg) { long id = (long)arg; struct kib_sched_info *sched; - kib_conn_t *conn; + struct kib_conn *conn; wait_queue_t wait; unsigned long flags; struct ib_wc wc; @@ -3551,7 +3551,7 @@ kiblnd_scheduler(void *arg) did_something = 0; if (!list_empty(&sched->ibs_conns)) { - conn = list_entry(sched->ibs_conns.next, kib_conn_t, + conn = list_entry(sched->ibs_conns.next, struct kib_conn, ibc_sched_list); /* take over kib_sched_conns' ref on conn... */ LASSERT(conn->ibc_scheduled); @@ -3651,7 +3651,7 @@ int kiblnd_failover_thread(void *arg) { rwlock_t *glock = &kiblnd_data.kib_global_lock; - kib_dev_t *dev; + struct kib_dev *dev; wait_queue_t wait; unsigned long flags; int rc; diff --git a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd_modparams.c b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd_modparams.c index f8fdd4a..fdc2f3b 100644 --- a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd_modparams.c +++ b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd_modparams.c @@ -145,7 +145,7 @@ static int use_privileged_port = 1; module_param(use_privileged_port, int, 0644); MODULE_PARM_DESC(use_privileged_port, "use privileged port when initiating connection"); -kib_tunables_t kiblnd_tunables = { +struct kib_tunables kiblnd_tunables = { .kib_dev_failover = &dev_failover, .kib_service = &service, .kib_cksum = &cksum, -- cgit v0.10.2 From ff13fd40f2ffe4fc471d68fb7955f38a32852c20 Mon Sep 17 00:00:00 2001 From: James Simmons Date: Fri, 10 Jun 2016 16:14:23 -0400 Subject: staging: lustre: socklnd: remove typedefs Remove all remaining typedefs in socklnd driver. Signed-off-by: James Simmons Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/lustre/lnet/klnds/socklnd/socklnd.c b/drivers/staging/lustre/lnet/klnds/socklnd/socklnd.c index 406c0e7..0fdc37c 100644 --- a/drivers/staging/lustre/lnet/klnds/socklnd/socklnd.c +++ b/drivers/staging/lustre/lnet/klnds/socklnd/socklnd.c @@ -44,14 +44,14 @@ #include "socklnd.h" static lnd_t the_ksocklnd; -ksock_nal_data_t ksocknal_data; +struct ksock_nal_data ksocknal_data; -static ksock_interface_t * +static struct ksock_interface * ksocknal_ip2iface(lnet_ni_t *ni, __u32 ip) { - ksock_net_t *net = ni->ni_data; + struct ksock_net *net = ni->ni_data; int i; - ksock_interface_t *iface; + struct ksock_interface *iface; for (i = 0; i < net->ksnn_ninterfaces; i++) { LASSERT(i < LNET_MAX_INTERFACES); @@ -64,10 +64,10 @@ ksocknal_ip2iface(lnet_ni_t *ni, __u32 ip) return NULL; } -static ksock_route_t * +static struct ksock_route * ksocknal_create_route(__u32 ipaddr, int port) { - ksock_route_t *route; + struct ksock_route *route; LIBCFS_ALLOC(route, sizeof(*route)); if (!route) @@ -89,7 +89,7 @@ ksocknal_create_route(__u32 ipaddr, int port) } void -ksocknal_destroy_route(ksock_route_t *route) +ksocknal_destroy_route(struct ksock_route *route) { LASSERT(!atomic_read(&route->ksnr_refcount)); @@ -100,11 +100,11 @@ ksocknal_destroy_route(ksock_route_t *route) } static int -ksocknal_create_peer(ksock_peer_t **peerp, lnet_ni_t *ni, lnet_process_id_t id) +ksocknal_create_peer(struct ksock_peer **peerp, lnet_ni_t *ni, lnet_process_id_t id) { int cpt = lnet_cpt_of_nid(id.nid); - ksock_net_t *net = ni->ni_data; - ksock_peer_t *peer; + struct ksock_net *net = ni->ni_data; + struct ksock_peer *peer; LASSERT(id.nid != LNET_NID_ANY); LASSERT(id.pid != LNET_PID_ANY); @@ -148,9 +148,9 @@ ksocknal_create_peer(ksock_peer_t **peerp, lnet_ni_t *ni, lnet_process_id_t id) } void -ksocknal_destroy_peer(ksock_peer_t *peer) +ksocknal_destroy_peer(struct ksock_peer *peer) { - ksock_net_t *net = peer->ksnp_ni->ni_data; + struct ksock_net *net = peer->ksnp_ni->ni_data; CDEBUG(D_NET, "peer %s %p deleted\n", libcfs_id2str(peer->ksnp_id), peer); @@ -175,15 +175,15 @@ ksocknal_destroy_peer(ksock_peer_t *peer) spin_unlock_bh(&net->ksnn_lock); } -ksock_peer_t * +struct ksock_peer * ksocknal_find_peer_locked(lnet_ni_t *ni, lnet_process_id_t id) { struct list_head *peer_list = ksocknal_nid2peerlist(id.nid); struct list_head *tmp; - ksock_peer_t *peer; + struct ksock_peer *peer; list_for_each(tmp, peer_list) { - peer = list_entry(tmp, ksock_peer_t, ksnp_list); + peer = list_entry(tmp, struct ksock_peer, ksnp_list); LASSERT(!peer->ksnp_closing); @@ -202,10 +202,10 @@ ksocknal_find_peer_locked(lnet_ni_t *ni, lnet_process_id_t id) return NULL; } -ksock_peer_t * +struct ksock_peer * ksocknal_find_peer(lnet_ni_t *ni, lnet_process_id_t id) { - ksock_peer_t *peer; + struct ksock_peer *peer; read_lock(&ksocknal_data.ksnd_global_lock); peer = ksocknal_find_peer_locked(ni, id); @@ -217,11 +217,11 @@ ksocknal_find_peer(lnet_ni_t *ni, lnet_process_id_t id) } static void -ksocknal_unlink_peer_locked(ksock_peer_t *peer) +ksocknal_unlink_peer_locked(struct ksock_peer *peer) { int i; __u32 ip; - ksock_interface_t *iface; + struct ksock_interface *iface; for (i = 0; i < peer->ksnp_n_passive_ips; i++) { LASSERT(i < LNET_MAX_INTERFACES); @@ -253,9 +253,9 @@ ksocknal_get_peer_info(lnet_ni_t *ni, int index, lnet_process_id_t *id, __u32 *myip, __u32 *peer_ip, int *port, int *conn_count, int *share_count) { - ksock_peer_t *peer; + struct ksock_peer *peer; struct list_head *ptmp; - ksock_route_t *route; + struct ksock_route *route; struct list_head *rtmp; int i; int j; @@ -265,7 +265,7 @@ ksocknal_get_peer_info(lnet_ni_t *ni, int index, for (i = 0; i < ksocknal_data.ksnd_peer_hash_size; i++) { list_for_each(ptmp, &ksocknal_data.ksnd_peers[i]) { - peer = list_entry(ptmp, ksock_peer_t, ksnp_list); + peer = list_entry(ptmp, struct ksock_peer, ksnp_list); if (peer->ksnp_ni != ni) continue; @@ -303,7 +303,7 @@ ksocknal_get_peer_info(lnet_ni_t *ni, int index, if (index-- > 0) continue; - route = list_entry(rtmp, ksock_route_t, + route = list_entry(rtmp, struct ksock_route, ksnr_list); *id = peer->ksnp_id; @@ -323,11 +323,11 @@ ksocknal_get_peer_info(lnet_ni_t *ni, int index, } static void -ksocknal_associate_route_conn_locked(ksock_route_t *route, ksock_conn_t *conn) +ksocknal_associate_route_conn_locked(struct ksock_route *route, struct ksock_conn *conn) { - ksock_peer_t *peer = route->ksnr_peer; + struct ksock_peer *peer = route->ksnr_peer; int type = conn->ksnc_type; - ksock_interface_t *iface; + struct ksock_interface *iface; conn->ksnc_route = route; ksocknal_route_addref(route); @@ -369,11 +369,11 @@ ksocknal_associate_route_conn_locked(ksock_route_t *route, ksock_conn_t *conn) } static void -ksocknal_add_route_locked(ksock_peer_t *peer, ksock_route_t *route) +ksocknal_add_route_locked(struct ksock_peer *peer, struct ksock_route *route) { struct list_head *tmp; - ksock_conn_t *conn; - ksock_route_t *route2; + struct ksock_conn *conn; + struct ksock_route *route2; LASSERT(!peer->ksnp_closing); LASSERT(!route->ksnr_peer); @@ -383,7 +383,7 @@ ksocknal_add_route_locked(ksock_peer_t *peer, ksock_route_t *route) /* LASSERT(unique) */ list_for_each(tmp, &peer->ksnp_routes) { - route2 = list_entry(tmp, ksock_route_t, ksnr_list); + route2 = list_entry(tmp, struct ksock_route, ksnr_list); if (route2->ksnr_ipaddr == route->ksnr_ipaddr) { CERROR("Duplicate route %s %pI4h\n", @@ -399,7 +399,7 @@ ksocknal_add_route_locked(ksock_peer_t *peer, ksock_route_t *route) list_add_tail(&route->ksnr_list, &peer->ksnp_routes); list_for_each(tmp, &peer->ksnp_conns) { - conn = list_entry(tmp, ksock_conn_t, ksnc_list); + conn = list_entry(tmp, struct ksock_conn, ksnc_list); if (conn->ksnc_ipaddr != route->ksnr_ipaddr) continue; @@ -410,11 +410,11 @@ ksocknal_add_route_locked(ksock_peer_t *peer, ksock_route_t *route) } static void -ksocknal_del_route_locked(ksock_route_t *route) +ksocknal_del_route_locked(struct ksock_route *route) { - ksock_peer_t *peer = route->ksnr_peer; - ksock_interface_t *iface; - ksock_conn_t *conn; + struct ksock_peer *peer = route->ksnr_peer; + struct ksock_interface *iface; + struct ksock_conn *conn; struct list_head *ctmp; struct list_head *cnxt; @@ -422,7 +422,7 @@ ksocknal_del_route_locked(ksock_route_t *route) /* Close associated conns */ list_for_each_safe(ctmp, cnxt, &peer->ksnp_conns) { - conn = list_entry(ctmp, ksock_conn_t, ksnc_list); + conn = list_entry(ctmp, struct ksock_conn, ksnc_list); if (conn->ksnc_route != route) continue; @@ -455,10 +455,10 @@ int ksocknal_add_peer(lnet_ni_t *ni, lnet_process_id_t id, __u32 ipaddr, int port) { struct list_head *tmp; - ksock_peer_t *peer; - ksock_peer_t *peer2; - ksock_route_t *route; - ksock_route_t *route2; + struct ksock_peer *peer; + struct ksock_peer *peer2; + struct ksock_route *route; + struct ksock_route *route2; int rc; if (id.nid == LNET_NID_ANY || @@ -479,7 +479,7 @@ ksocknal_add_peer(lnet_ni_t *ni, lnet_process_id_t id, __u32 ipaddr, int port) write_lock_bh(&ksocknal_data.ksnd_global_lock); /* always called with a ref on ni, so shutdown can't have started */ - LASSERT(!((ksock_net_t *) ni->ni_data)->ksnn_shutdown); + LASSERT(!((struct ksock_net *) ni->ni_data)->ksnn_shutdown); peer2 = ksocknal_find_peer_locked(ni, id); if (peer2) { @@ -493,7 +493,7 @@ ksocknal_add_peer(lnet_ni_t *ni, lnet_process_id_t id, __u32 ipaddr, int port) route2 = NULL; list_for_each(tmp, &peer->ksnp_routes) { - route2 = list_entry(tmp, ksock_route_t, ksnr_list); + route2 = list_entry(tmp, struct ksock_route, ksnr_list); if (route2->ksnr_ipaddr == ipaddr) break; @@ -514,10 +514,10 @@ ksocknal_add_peer(lnet_ni_t *ni, lnet_process_id_t id, __u32 ipaddr, int port) } static void -ksocknal_del_peer_locked(ksock_peer_t *peer, __u32 ip) +ksocknal_del_peer_locked(struct ksock_peer *peer, __u32 ip) { - ksock_conn_t *conn; - ksock_route_t *route; + struct ksock_conn *conn; + struct ksock_route *route; struct list_head *tmp; struct list_head *nxt; int nshared; @@ -528,7 +528,7 @@ ksocknal_del_peer_locked(ksock_peer_t *peer, __u32 ip) ksocknal_peer_addref(peer); list_for_each_safe(tmp, nxt, &peer->ksnp_routes) { - route = list_entry(tmp, ksock_route_t, ksnr_list); + route = list_entry(tmp, struct ksock_route, ksnr_list); /* no match */ if (!(!ip || route->ksnr_ipaddr == ip)) @@ -541,7 +541,7 @@ ksocknal_del_peer_locked(ksock_peer_t *peer, __u32 ip) nshared = 0; list_for_each_safe(tmp, nxt, &peer->ksnp_routes) { - route = list_entry(tmp, ksock_route_t, ksnr_list); + route = list_entry(tmp, struct ksock_route, ksnr_list); nshared += route->ksnr_share_count; } @@ -551,7 +551,7 @@ ksocknal_del_peer_locked(ksock_peer_t *peer, __u32 ip) * left */ list_for_each_safe(tmp, nxt, &peer->ksnp_routes) { - route = list_entry(tmp, ksock_route_t, ksnr_list); + route = list_entry(tmp, struct ksock_route, ksnr_list); /* we should only be removing auto-entries */ LASSERT(!route->ksnr_share_count); @@ -559,7 +559,7 @@ ksocknal_del_peer_locked(ksock_peer_t *peer, __u32 ip) } list_for_each_safe(tmp, nxt, &peer->ksnp_conns) { - conn = list_entry(tmp, ksock_conn_t, ksnc_list); + conn = list_entry(tmp, struct ksock_conn, ksnc_list); ksocknal_close_conn_locked(conn, 0); } @@ -575,7 +575,7 @@ ksocknal_del_peer(lnet_ni_t *ni, lnet_process_id_t id, __u32 ip) LIST_HEAD(zombies); struct list_head *ptmp; struct list_head *pnxt; - ksock_peer_t *peer; + struct ksock_peer *peer; int lo; int hi; int i; @@ -593,7 +593,7 @@ ksocknal_del_peer(lnet_ni_t *ni, lnet_process_id_t id, __u32 ip) for (i = lo; i <= hi; i++) { list_for_each_safe(ptmp, pnxt, &ksocknal_data.ksnd_peers[i]) { - peer = list_entry(ptmp, ksock_peer_t, ksnp_list); + peer = list_entry(ptmp, struct ksock_peer, ksnp_list); if (peer->ksnp_ni != ni) continue; @@ -628,12 +628,12 @@ ksocknal_del_peer(lnet_ni_t *ni, lnet_process_id_t id, __u32 ip) return rc; } -static ksock_conn_t * +static struct ksock_conn * ksocknal_get_conn_by_idx(lnet_ni_t *ni, int index) { - ksock_peer_t *peer; + struct ksock_peer *peer; struct list_head *ptmp; - ksock_conn_t *conn; + struct ksock_conn *conn; struct list_head *ctmp; int i; @@ -641,7 +641,7 @@ ksocknal_get_conn_by_idx(lnet_ni_t *ni, int index) for (i = 0; i < ksocknal_data.ksnd_peer_hash_size; i++) { list_for_each(ptmp, &ksocknal_data.ksnd_peers[i]) { - peer = list_entry(ptmp, ksock_peer_t, ksnp_list); + peer = list_entry(ptmp, struct ksock_peer, ksnp_list); LASSERT(!peer->ksnp_closing); @@ -652,7 +652,7 @@ ksocknal_get_conn_by_idx(lnet_ni_t *ni, int index) if (index-- > 0) continue; - conn = list_entry(ctmp, ksock_conn_t, + conn = list_entry(ctmp, struct ksock_conn, ksnc_list); ksocknal_conn_addref(conn); read_unlock(&ksocknal_data.ksnd_global_lock); @@ -665,11 +665,11 @@ ksocknal_get_conn_by_idx(lnet_ni_t *ni, int index) return NULL; } -static ksock_sched_t * +static struct ksock_sched * ksocknal_choose_scheduler_locked(unsigned int cpt) { struct ksock_sched_info *info = ksocknal_data.ksnd_sched_info[cpt]; - ksock_sched_t *sched; + struct ksock_sched *sched; int i; LASSERT(info->ksi_nthreads > 0); @@ -691,7 +691,7 @@ ksocknal_choose_scheduler_locked(unsigned int cpt) static int ksocknal_local_ipvec(lnet_ni_t *ni, __u32 *ipaddrs) { - ksock_net_t *net = ni->ni_data; + struct ksock_net *net = ni->ni_data; int i; int nip; @@ -719,7 +719,7 @@ ksocknal_local_ipvec(lnet_ni_t *ni, __u32 *ipaddrs) } static int -ksocknal_match_peerip(ksock_interface_t *iface, __u32 *ips, int nips) +ksocknal_match_peerip(struct ksock_interface *iface, __u32 *ips, int nips) { int best_netmatch = 0; int best_xor = 0; @@ -751,12 +751,12 @@ ksocknal_match_peerip(ksock_interface_t *iface, __u32 *ips, int nips) } static int -ksocknal_select_ips(ksock_peer_t *peer, __u32 *peerips, int n_peerips) +ksocknal_select_ips(struct ksock_peer *peer, __u32 *peerips, int n_peerips) { rwlock_t *global_lock = &ksocknal_data.ksnd_global_lock; - ksock_net_t *net = peer->ksnp_ni->ni_data; - ksock_interface_t *iface; - ksock_interface_t *best_iface; + struct ksock_net *net = peer->ksnp_ni->ni_data; + struct ksock_interface *iface; + struct ksock_interface *best_iface; int n_ips; int i; int j; @@ -862,17 +862,17 @@ ksocknal_select_ips(ksock_peer_t *peer, __u32 *peerips, int n_peerips) } static void -ksocknal_create_routes(ksock_peer_t *peer, int port, +ksocknal_create_routes(struct ksock_peer *peer, int port, __u32 *peer_ipaddrs, int npeer_ipaddrs) { - ksock_route_t *newroute = NULL; + struct ksock_route *newroute = NULL; rwlock_t *global_lock = &ksocknal_data.ksnd_global_lock; lnet_ni_t *ni = peer->ksnp_ni; - ksock_net_t *net = ni->ni_data; + struct ksock_net *net = ni->ni_data; struct list_head *rtmp; - ksock_route_t *route; - ksock_interface_t *iface; - ksock_interface_t *best_iface; + struct ksock_route *route; + struct ksock_interface *iface; + struct ksock_interface *best_iface; int best_netmatch; int this_netmatch; int best_nroutes; @@ -919,7 +919,7 @@ ksocknal_create_routes(ksock_peer_t *peer, int port, /* Already got a route? */ route = NULL; list_for_each(rtmp, &peer->ksnp_routes) { - route = list_entry(rtmp, ksock_route_t, ksnr_list); + route = list_entry(rtmp, struct ksock_route, ksnr_list); if (route->ksnr_ipaddr == newroute->ksnr_ipaddr) break; @@ -941,7 +941,7 @@ ksocknal_create_routes(ksock_peer_t *peer, int port, /* Using this interface already? */ list_for_each(rtmp, &peer->ksnp_routes) { - route = list_entry(rtmp, ksock_route_t, + route = list_entry(rtmp, struct ksock_route, ksnr_list); if (route->ksnr_myipaddr == iface->ksni_ipaddr) @@ -985,7 +985,7 @@ ksocknal_create_routes(ksock_peer_t *peer, int port, int ksocknal_accept(lnet_ni_t *ni, struct socket *sock) { - ksock_connreq_t *cr; + struct ksock_connreq *cr; int rc; __u32 peer_ip; int peer_port; @@ -1014,9 +1014,9 @@ ksocknal_accept(lnet_ni_t *ni, struct socket *sock) } static int -ksocknal_connecting(ksock_peer_t *peer, __u32 ipaddr) +ksocknal_connecting(struct ksock_peer *peer, __u32 ipaddr) { - ksock_route_t *route; + struct ksock_route *route; list_for_each_entry(route, &peer->ksnp_routes, ksnr_list) { if (route->ksnr_ipaddr == ipaddr) @@ -1026,7 +1026,7 @@ ksocknal_connecting(ksock_peer_t *peer, __u32 ipaddr) } int -ksocknal_create_conn(lnet_ni_t *ni, ksock_route_t *route, +ksocknal_create_conn(lnet_ni_t *ni, struct ksock_route *route, struct socket *sock, int type) { rwlock_t *global_lock = &ksocknal_data.ksnd_global_lock; @@ -1034,15 +1034,15 @@ ksocknal_create_conn(lnet_ni_t *ni, ksock_route_t *route, lnet_process_id_t peerid; struct list_head *tmp; __u64 incarnation; - ksock_conn_t *conn; - ksock_conn_t *conn2; - ksock_peer_t *peer = NULL; - ksock_peer_t *peer2; - ksock_sched_t *sched; + struct ksock_conn *conn; + struct ksock_conn *conn2; + struct ksock_peer *peer = NULL; + struct ksock_peer *peer2; + struct ksock_sched *sched; ksock_hello_msg_t *hello; int cpt; - ksock_tx_t *tx; - ksock_tx_t *txtmp; + struct ksock_tx *tx; + struct ksock_tx *txtmp; int rc; int active; char *warn = NULL; @@ -1150,7 +1150,7 @@ ksocknal_create_conn(lnet_ni_t *ni, ksock_route_t *route, write_lock_bh(global_lock); /* called with a ref on ni, so shutdown can't have started */ - LASSERT(!((ksock_net_t *) ni->ni_data)->ksnn_shutdown); + LASSERT(!((struct ksock_net *) ni->ni_data)->ksnn_shutdown); peer2 = ksocknal_find_peer_locked(ni, peerid); if (!peer2) { @@ -1233,7 +1233,7 @@ ksocknal_create_conn(lnet_ni_t *ni, ksock_route_t *route, */ if (conn->ksnc_ipaddr != conn->ksnc_myipaddr) { list_for_each(tmp, &peer->ksnp_conns) { - conn2 = list_entry(tmp, ksock_conn_t, ksnc_list); + conn2 = list_entry(tmp, struct ksock_conn, ksnc_list); if (conn2->ksnc_ipaddr != conn->ksnc_ipaddr || conn2->ksnc_myipaddr != conn->ksnc_myipaddr || @@ -1273,7 +1273,7 @@ ksocknal_create_conn(lnet_ni_t *ni, ksock_route_t *route, * continually create duplicate routes. */ list_for_each(tmp, &peer->ksnp_routes) { - route = list_entry(tmp, ksock_route_t, ksnr_list); + route = list_entry(tmp, struct ksock_route, ksnr_list); if (route->ksnr_ipaddr != conn->ksnc_ipaddr) continue; @@ -1432,16 +1432,16 @@ failed_0: } void -ksocknal_close_conn_locked(ksock_conn_t *conn, int error) +ksocknal_close_conn_locked(struct ksock_conn *conn, int error) { /* * This just does the immmediate housekeeping, and queues the * connection for the reaper to terminate. * Caller holds ksnd_global_lock exclusively in irq context */ - ksock_peer_t *peer = conn->ksnc_peer; - ksock_route_t *route; - ksock_conn_t *conn2; + struct ksock_peer *peer = conn->ksnc_peer; + struct ksock_route *route; + struct ksock_conn *conn2; struct list_head *tmp; LASSERT(!peer->ksnp_error); @@ -1459,7 +1459,7 @@ ksocknal_close_conn_locked(ksock_conn_t *conn, int error) conn2 = NULL; list_for_each(tmp, &peer->ksnp_conns) { - conn2 = list_entry(tmp, ksock_conn_t, ksnc_list); + conn2 = list_entry(tmp, struct ksock_conn, ksnc_list); if (conn2->ksnc_route == route && conn2->ksnc_type == conn->ksnc_type) @@ -1484,7 +1484,7 @@ ksocknal_close_conn_locked(ksock_conn_t *conn, int error) /* No more connections to this peer */ if (!list_empty(&peer->ksnp_tx_queue)) { - ksock_tx_t *tx; + struct ksock_tx *tx; LASSERT(conn->ksnc_proto == &ksocknal_protocol_v3x); @@ -1524,7 +1524,7 @@ ksocknal_close_conn_locked(ksock_conn_t *conn, int error) } void -ksocknal_peer_failed(ksock_peer_t *peer) +ksocknal_peer_failed(struct ksock_peer *peer) { int notify = 0; unsigned long last_alive = 0; @@ -1552,12 +1552,12 @@ ksocknal_peer_failed(ksock_peer_t *peer) } void -ksocknal_finalize_zcreq(ksock_conn_t *conn) +ksocknal_finalize_zcreq(struct ksock_conn *conn) { - ksock_peer_t *peer = conn->ksnc_peer; - ksock_tx_t *tx; - ksock_tx_t *temp; - ksock_tx_t *tmp; + struct ksock_peer *peer = conn->ksnc_peer; + struct ksock_tx *tx; + struct ksock_tx *temp; + struct ksock_tx *tmp; LIST_HEAD(zlist); /* @@ -1589,7 +1589,7 @@ ksocknal_finalize_zcreq(ksock_conn_t *conn) } void -ksocknal_terminate_conn(ksock_conn_t *conn) +ksocknal_terminate_conn(struct ksock_conn *conn) { /* * This gets called by the reaper (guaranteed thread context) to @@ -1597,8 +1597,8 @@ ksocknal_terminate_conn(ksock_conn_t *conn) * ksnc_refcount will eventually hit zero, and then the reaper will * destroy it. */ - ksock_peer_t *peer = conn->ksnc_peer; - ksock_sched_t *sched = conn->ksnc_scheduler; + struct ksock_peer *peer = conn->ksnc_peer; + struct ksock_sched *sched = conn->ksnc_scheduler; int failed = 0; LASSERT(conn->ksnc_closing); @@ -1656,7 +1656,7 @@ ksocknal_terminate_conn(ksock_conn_t *conn) } void -ksocknal_queue_zombie_conn(ksock_conn_t *conn) +ksocknal_queue_zombie_conn(struct ksock_conn *conn) { /* Queue the conn for the reaper to destroy */ @@ -1670,7 +1670,7 @@ ksocknal_queue_zombie_conn(ksock_conn_t *conn) } void -ksocknal_destroy_conn(ksock_conn_t *conn) +ksocknal_destroy_conn(struct ksock_conn *conn) { unsigned long last_rcv; @@ -1730,15 +1730,15 @@ ksocknal_destroy_conn(ksock_conn_t *conn) } int -ksocknal_close_peer_conns_locked(ksock_peer_t *peer, __u32 ipaddr, int why) +ksocknal_close_peer_conns_locked(struct ksock_peer *peer, __u32 ipaddr, int why) { - ksock_conn_t *conn; + struct ksock_conn *conn; struct list_head *ctmp; struct list_head *cnxt; int count = 0; list_for_each_safe(ctmp, cnxt, &peer->ksnp_conns) { - conn = list_entry(ctmp, ksock_conn_t, ksnc_list); + conn = list_entry(ctmp, struct ksock_conn, ksnc_list); if (!ipaddr || conn->ksnc_ipaddr == ipaddr) { count++; @@ -1750,9 +1750,9 @@ ksocknal_close_peer_conns_locked(ksock_peer_t *peer, __u32 ipaddr, int why) } int -ksocknal_close_conn_and_siblings(ksock_conn_t *conn, int why) +ksocknal_close_conn_and_siblings(struct ksock_conn *conn, int why) { - ksock_peer_t *peer = conn->ksnc_peer; + struct ksock_peer *peer = conn->ksnc_peer; __u32 ipaddr = conn->ksnc_ipaddr; int count; @@ -1768,7 +1768,7 @@ ksocknal_close_conn_and_siblings(ksock_conn_t *conn, int why) int ksocknal_close_matching_conns(lnet_process_id_t id, __u32 ipaddr) { - ksock_peer_t *peer; + struct ksock_peer *peer; struct list_head *ptmp; struct list_head *pnxt; int lo; @@ -1789,7 +1789,7 @@ ksocknal_close_matching_conns(lnet_process_id_t id, __u32 ipaddr) for (i = lo; i <= hi; i++) { list_for_each_safe(ptmp, pnxt, &ksocknal_data.ksnd_peers[i]) { - peer = list_entry(ptmp, ksock_peer_t, ksnp_list); + peer = list_entry(ptmp, struct ksock_peer, ksnp_list); if (!((id.nid == LNET_NID_ANY || id.nid == peer->ksnp_id.nid) && (id.pid == LNET_PID_ANY || id.pid == peer->ksnp_id.pid))) @@ -1844,7 +1844,7 @@ ksocknal_query(lnet_ni_t *ni, lnet_nid_t nid, unsigned long *when) int connect = 1; unsigned long last_alive = 0; unsigned long now = cfs_time_current(); - ksock_peer_t *peer = NULL; + struct ksock_peer *peer = NULL; rwlock_t *glock = &ksocknal_data.ksnd_global_lock; lnet_process_id_t id = { .nid = nid, @@ -1856,11 +1856,11 @@ ksocknal_query(lnet_ni_t *ni, lnet_nid_t nid, unsigned long *when) peer = ksocknal_find_peer_locked(ni, id); if (peer) { struct list_head *tmp; - ksock_conn_t *conn; + struct ksock_conn *conn; int bufnob; list_for_each(tmp, &peer->ksnp_conns) { - conn = list_entry(tmp, ksock_conn_t, ksnc_list); + conn = list_entry(tmp, struct ksock_conn, ksnc_list); bufnob = conn->ksnc_sock->sk->sk_wmem_queued; if (bufnob < conn->ksnc_tx_bufnob) { @@ -1902,12 +1902,12 @@ ksocknal_query(lnet_ni_t *ni, lnet_nid_t nid, unsigned long *when) } static void -ksocknal_push_peer(ksock_peer_t *peer) +ksocknal_push_peer(struct ksock_peer *peer) { int index; int i; struct list_head *tmp; - ksock_conn_t *conn; + struct ksock_conn *conn; for (index = 0; ; index++) { read_lock(&ksocknal_data.ksnd_global_lock); @@ -1917,7 +1917,7 @@ ksocknal_push_peer(ksock_peer_t *peer) list_for_each(tmp, &peer->ksnp_conns) { if (i++ == index) { - conn = list_entry(tmp, ksock_conn_t, + conn = list_entry(tmp, struct ksock_conn, ksnc_list); ksocknal_conn_addref(conn); break; @@ -1954,7 +1954,7 @@ static int ksocknal_push(lnet_ni_t *ni, lnet_process_id_t id) int peer_off; /* searching offset in peer hash table */ for (peer_off = 0; ; peer_off++) { - ksock_peer_t *peer; + struct ksock_peer *peer; int i = 0; read_lock(&ksocknal_data.ksnd_global_lock); @@ -1986,15 +1986,15 @@ static int ksocknal_push(lnet_ni_t *ni, lnet_process_id_t id) static int ksocknal_add_interface(lnet_ni_t *ni, __u32 ipaddress, __u32 netmask) { - ksock_net_t *net = ni->ni_data; - ksock_interface_t *iface; + struct ksock_net *net = ni->ni_data; + struct ksock_interface *iface; int rc; int i; int j; struct list_head *ptmp; - ksock_peer_t *peer; + struct ksock_peer *peer; struct list_head *rtmp; - ksock_route_t *route; + struct ksock_route *route; if (!ipaddress || !netmask) return -EINVAL; @@ -2017,7 +2017,7 @@ ksocknal_add_interface(lnet_ni_t *ni, __u32 ipaddress, __u32 netmask) for (i = 0; i < ksocknal_data.ksnd_peer_hash_size; i++) { list_for_each(ptmp, &ksocknal_data.ksnd_peers[i]) { - peer = list_entry(ptmp, ksock_peer_t, + peer = list_entry(ptmp, struct ksock_peer, ksnp_list); for (j = 0; j < peer->ksnp_n_passive_ips; j++) @@ -2025,7 +2025,7 @@ ksocknal_add_interface(lnet_ni_t *ni, __u32 ipaddress, __u32 netmask) iface->ksni_npeers++; list_for_each(rtmp, &peer->ksnp_routes) { - route = list_entry(rtmp, ksock_route_t, + route = list_entry(rtmp, struct ksock_route, ksnr_list); if (route->ksnr_myipaddr == ipaddress) @@ -2044,12 +2044,12 @@ ksocknal_add_interface(lnet_ni_t *ni, __u32 ipaddress, __u32 netmask) } static void -ksocknal_peer_del_interface_locked(ksock_peer_t *peer, __u32 ipaddr) +ksocknal_peer_del_interface_locked(struct ksock_peer *peer, __u32 ipaddr) { struct list_head *tmp; struct list_head *nxt; - ksock_route_t *route; - ksock_conn_t *conn; + struct ksock_route *route; + struct ksock_conn *conn; int i; int j; @@ -2063,7 +2063,7 @@ ksocknal_peer_del_interface_locked(ksock_peer_t *peer, __u32 ipaddr) } list_for_each_safe(tmp, nxt, &peer->ksnp_routes) { - route = list_entry(tmp, ksock_route_t, ksnr_list); + route = list_entry(tmp, struct ksock_route, ksnr_list); if (route->ksnr_myipaddr != ipaddr) continue; @@ -2077,7 +2077,7 @@ ksocknal_peer_del_interface_locked(ksock_peer_t *peer, __u32 ipaddr) } list_for_each_safe(tmp, nxt, &peer->ksnp_conns) { - conn = list_entry(tmp, ksock_conn_t, ksnc_list); + conn = list_entry(tmp, struct ksock_conn, ksnc_list); if (conn->ksnc_myipaddr == ipaddr) ksocknal_close_conn_locked(conn, 0); @@ -2087,11 +2087,11 @@ ksocknal_peer_del_interface_locked(ksock_peer_t *peer, __u32 ipaddr) static int ksocknal_del_interface(lnet_ni_t *ni, __u32 ipaddress) { - ksock_net_t *net = ni->ni_data; + struct ksock_net *net = ni->ni_data; int rc = -ENOENT; struct list_head *tmp; struct list_head *nxt; - ksock_peer_t *peer; + struct ksock_peer *peer; __u32 this_ip; int i; int j; @@ -2115,7 +2115,7 @@ ksocknal_del_interface(lnet_ni_t *ni, __u32 ipaddress) for (j = 0; j < ksocknal_data.ksnd_peer_hash_size; j++) { list_for_each_safe(tmp, nxt, &ksocknal_data.ksnd_peers[j]) { - peer = list_entry(tmp, ksock_peer_t, ksnp_list); + peer = list_entry(tmp, struct ksock_peer, ksnp_list); if (peer->ksnp_ni != ni) continue; @@ -2139,8 +2139,8 @@ ksocknal_ctl(lnet_ni_t *ni, unsigned int cmd, void *arg) switch (cmd) { case IOC_LIBCFS_GET_INTERFACE: { - ksock_net_t *net = ni->ni_data; - ksock_interface_t *iface; + struct ksock_net *net = ni->ni_data; + struct ksock_interface *iface; read_lock(&ksocknal_data.ksnd_global_lock); @@ -2209,7 +2209,7 @@ ksocknal_ctl(lnet_ni_t *ni, unsigned int cmd, void *arg) int txmem; int rxmem; int nagle; - ksock_conn_t *conn = ksocknal_get_conn_by_idx(ni, data->ioc_count); + struct ksock_conn *conn = ksocknal_get_conn_by_idx(ni, data->ioc_count); if (!conn) return -ENOENT; @@ -2284,8 +2284,8 @@ ksocknal_free_buffers(void) if (!list_empty(&ksocknal_data.ksnd_idle_noop_txs)) { struct list_head zlist; - ksock_tx_t *tx; - ksock_tx_t *temp; + struct ksock_tx *tx; + struct ksock_tx *temp; list_add(&zlist, &ksocknal_data.ksnd_idle_noop_txs); list_del_init(&ksocknal_data.ksnd_idle_noop_txs); @@ -2304,7 +2304,7 @@ static void ksocknal_base_shutdown(void) { struct ksock_sched_info *info; - ksock_sched_t *sched; + struct ksock_sched *sched; int i; int j; @@ -2446,7 +2446,7 @@ ksocknal_base_startup(void) goto failed; cfs_percpt_for_each(info, i, ksocknal_data.ksnd_sched_info) { - ksock_sched_t *sched; + struct ksock_sched *sched; int nthrs; nthrs = cfs_cpt_weight(lnet_cpt_table(), i); @@ -2534,7 +2534,7 @@ ksocknal_base_startup(void) static void ksocknal_debug_peerhash(lnet_ni_t *ni) { - ksock_peer_t *peer = NULL; + struct ksock_peer *peer = NULL; struct list_head *tmp; int i; @@ -2542,7 +2542,7 @@ ksocknal_debug_peerhash(lnet_ni_t *ni) for (i = 0; i < ksocknal_data.ksnd_peer_hash_size; i++) { list_for_each(tmp, &ksocknal_data.ksnd_peers[i]) { - peer = list_entry(tmp, ksock_peer_t, ksnp_list); + peer = list_entry(tmp, struct ksock_peer, ksnp_list); if (peer->ksnp_ni == ni) break; @@ -2552,8 +2552,8 @@ ksocknal_debug_peerhash(lnet_ni_t *ni) } if (peer) { - ksock_route_t *route; - ksock_conn_t *conn; + struct ksock_route *route; + struct ksock_conn *conn; CWARN("Active peer on shutdown: %s, ref %d, scnt %d, closing %d, accepting %d, err %d, zcookie %llu, txq %d, zc_req %d\n", libcfs_id2str(peer->ksnp_id), @@ -2565,7 +2565,7 @@ ksocknal_debug_peerhash(lnet_ni_t *ni) !list_empty(&peer->ksnp_zc_req_list)); list_for_each(tmp, &peer->ksnp_routes) { - route = list_entry(tmp, ksock_route_t, ksnr_list); + route = list_entry(tmp, struct ksock_route, ksnr_list); CWARN("Route: ref %d, schd %d, conn %d, cnted %d, del %d\n", atomic_read(&route->ksnr_refcount), route->ksnr_scheduled, route->ksnr_connecting, @@ -2573,7 +2573,7 @@ ksocknal_debug_peerhash(lnet_ni_t *ni) } list_for_each(tmp, &peer->ksnp_conns) { - conn = list_entry(tmp, ksock_conn_t, ksnc_list); + conn = list_entry(tmp, struct ksock_conn, ksnc_list); CWARN("Conn: ref %d, sref %d, t %d, c %d\n", atomic_read(&conn->ksnc_conn_refcount), atomic_read(&conn->ksnc_sock_refcount), @@ -2587,7 +2587,7 @@ ksocknal_debug_peerhash(lnet_ni_t *ni) void ksocknal_shutdown(lnet_ni_t *ni) { - ksock_net_t *net = ni->ni_data; + struct ksock_net *net = ni->ni_data; int i; lnet_process_id_t anyid = {0}; @@ -2637,7 +2637,7 @@ ksocknal_shutdown(lnet_ni_t *ni) } static int -ksocknal_enumerate_interfaces(ksock_net_t *net) +ksocknal_enumerate_interfaces(struct ksock_net *net) { char **names; int i; @@ -2694,7 +2694,7 @@ ksocknal_enumerate_interfaces(ksock_net_t *net) } static int -ksocknal_search_new_ipif(ksock_net_t *net) +ksocknal_search_new_ipif(struct ksock_net *net) { int new_ipif = 0; int i; @@ -2703,7 +2703,7 @@ ksocknal_search_new_ipif(ksock_net_t *net) char *ifnam = &net->ksnn_interfaces[i].ksni_name[0]; char *colon = strchr(ifnam, ':'); int found = 0; - ksock_net_t *tmp; + struct ksock_net *tmp; int j; if (colon) /* ignore alias device */ @@ -2760,7 +2760,7 @@ ksocknal_start_schedulers(struct ksock_sched_info *info) for (i = 0; i < nthrs; i++) { long id; char name[20]; - ksock_sched_t *sched; + struct ksock_sched *sched; id = KSOCK_THREAD_ID(info->ksi_cpt, info->ksi_nthreads + i); sched = &info->ksi_scheds[KSOCK_THREAD_SID(id)]; @@ -2782,7 +2782,7 @@ ksocknal_start_schedulers(struct ksock_sched_info *info) } static int -ksocknal_net_start_threads(ksock_net_t *net, __u32 *cpts, int ncpts) +ksocknal_net_start_threads(struct ksock_net *net, __u32 *cpts, int ncpts) { int newif = ksocknal_search_new_ipif(net); int rc; @@ -2810,7 +2810,7 @@ ksocknal_net_start_threads(ksock_net_t *net, __u32 *cpts, int ncpts) int ksocknal_startup(lnet_ni_t *ni) { - ksock_net_t *net; + struct ksock_net *net; int rc; int i; diff --git a/drivers/staging/lustre/lnet/klnds/socklnd/socklnd.h b/drivers/staging/lustre/lnet/klnds/socklnd/socklnd.h index a60d72f..a56632b 100644 --- a/drivers/staging/lustre/lnet/klnds/socklnd/socklnd.h +++ b/drivers/staging/lustre/lnet/klnds/socklnd/socklnd.h @@ -77,8 +77,7 @@ struct ksock_sched_info; -typedef struct /* per scheduler state */ -{ +struct ksock_sched { /* per scheduler state */ spinlock_t kss_lock; /* serialise */ struct list_head kss_rx_conns; /* conn waiting to be read */ struct list_head kss_tx_conns; /* conn waiting to be written */ @@ -89,13 +88,13 @@ typedef struct /* per scheduler state */ struct ksock_sched_info *kss_info; /* owner of it */ struct page *kss_rx_scratch_pgs[LNET_MAX_IOV]; struct kvec kss_scratch_iov[LNET_MAX_IOV]; -} ksock_sched_t; +}; struct ksock_sched_info { int ksi_nthreads_max; /* max allowed threads */ int ksi_nthreads; /* number of threads */ int ksi_cpt; /* CPT id */ - ksock_sched_t *ksi_scheds; /* array of schedulers */ + struct ksock_sched *ksi_scheds; /* array of schedulers */ }; #define KSOCK_CPT_SHIFT 16 @@ -103,16 +102,15 @@ struct ksock_sched_info { #define KSOCK_THREAD_CPT(id) ((id) >> KSOCK_CPT_SHIFT) #define KSOCK_THREAD_SID(id) ((id) & ((1UL << KSOCK_CPT_SHIFT) - 1)) -typedef struct /* in-use interface */ -{ +struct ksock_interface { /* in-use interface */ __u32 ksni_ipaddr; /* interface's IP address */ __u32 ksni_netmask; /* interface's network mask */ int ksni_nroutes; /* # routes using (active) */ int ksni_npeers; /* # peers using (passive) */ char ksni_name[IFNAMSIZ]; /* interface name */ -} ksock_interface_t; +}; -typedef struct { +struct ksock_tunables { int *ksnd_timeout; /* "stuck" socket timeout * (seconds) */ int *ksnd_nscheds; /* # scheduler threads in each @@ -155,24 +153,24 @@ typedef struct { * Chelsio TOE) */ int *ksnd_zc_recv_min_nfrags; /* minimum # of fragments to * enable ZC receive */ -} ksock_tunables_t; +}; -typedef struct { +struct ksock_net { __u64 ksnn_incarnation; /* my epoch */ spinlock_t ksnn_lock; /* serialise */ struct list_head ksnn_list; /* chain on global list */ int ksnn_npeers; /* # peers */ int ksnn_shutdown; /* shutting down? */ int ksnn_ninterfaces; /* IP interfaces */ - ksock_interface_t ksnn_interfaces[LNET_MAX_INTERFACES]; -} ksock_net_t; + struct ksock_interface ksnn_interfaces[LNET_MAX_INTERFACES]; +}; /** connd timeout */ #define SOCKNAL_CONND_TIMEOUT 120 /** reserved thread for accepting & creating new connd */ #define SOCKNAL_CONND_RESV 1 -typedef struct { +struct ksock_nal_data { int ksnd_init; /* initialisation state */ int ksnd_nnets; /* # networks set up */ @@ -229,7 +227,7 @@ typedef struct { spinlock_t ksnd_tx_lock; /* serialise, g_lock * unsafe */ -} ksock_nal_data_t; +}; #define SOCKNAL_INIT_NOTHING 0 #define SOCKNAL_INIT_DATA 1 @@ -250,8 +248,7 @@ struct ksock_peer; /* forward ref */ struct ksock_route; /* forward ref */ struct ksock_proto; /* forward ref */ -typedef struct /* transmit packet */ -{ +struct ksock_tx { /* transmit packet */ struct list_head tx_list; /* queue on conn for transmission etc */ struct list_head tx_zc_list; /* queue on peer for ZC request */ @@ -281,20 +278,20 @@ typedef struct /* transmit packet */ struct kvec iov[1]; /* virt hdr + payload */ } virt; } tx_frags; -} ksock_tx_t; +}; -#define KSOCK_NOOP_TX_SIZE (offsetof(ksock_tx_t, tx_frags.paged.kiov[0])) +#define KSOCK_NOOP_TX_SIZE (offsetof(struct ksock_tx, tx_frags.paged.kiov[0])) -/* network zero copy callback descriptor embedded in ksock_tx_t */ +/* network zero copy callback descriptor embedded in struct ksock_tx */ /* * space for the rx frag descriptors; we either read a single contiguous * header, or up to LNET_MAX_IOV frags of payload of either type. */ -typedef union { +union ksock_rxiovspace { struct kvec iov[LNET_MAX_IOV]; lnet_kiov_t kiov[LNET_MAX_IOV]; -} ksock_rxiovspace_t; +}; #define SOCKNAL_RX_KSM_HEADER 1 /* reading ksock message header */ #define SOCKNAL_RX_LNET_HEADER 2 /* reading lnet message header */ @@ -303,7 +300,7 @@ typedef union { #define SOCKNAL_RX_LNET_PAYLOAD 5 /* reading lnet payload (to deliver here) */ #define SOCKNAL_RX_SLOP 6 /* skipping body */ -typedef struct ksock_conn { +struct ksock_conn { struct ksock_peer *ksnc_peer; /* owning peer */ struct ksock_route *ksnc_route; /* owning route */ struct list_head ksnc_list; /* stash on peer's conn list */ @@ -314,8 +311,8 @@ typedef struct ksock_conn { * write_space() callback */ atomic_t ksnc_conn_refcount;/* conn refcount */ atomic_t ksnc_sock_refcount;/* sock refcount */ - ksock_sched_t *ksnc_scheduler; /* who schedules this connection - */ + struct ksock_sched *ksnc_scheduler; /* who schedules this connection + */ __u32 ksnc_myipaddr; /* my IP */ __u32 ksnc_ipaddr; /* peer's IP */ int ksnc_port; /* peer's port */ @@ -341,7 +338,7 @@ typedef struct ksock_conn { struct kvec *ksnc_rx_iov; /* the iovec frags */ int ksnc_rx_nkiov; /* # page frags */ lnet_kiov_t *ksnc_rx_kiov; /* the page frags */ - ksock_rxiovspace_t ksnc_rx_iov_space; /* space for frag descriptors */ + union ksock_rxiovspace ksnc_rx_iov_space; /* space for frag descriptors */ __u32 ksnc_rx_csum; /* partial checksum for incoming * data */ void *ksnc_cookie; /* rx lnet_finalize passthru arg @@ -357,7 +354,7 @@ typedef struct ksock_conn { struct list_head ksnc_tx_list; /* where I enq waiting for output * space */ struct list_head ksnc_tx_queue; /* packets waiting to be sent */ - ksock_tx_t *ksnc_tx_carrier; /* next TX that can carry a LNet + struct ksock_tx *ksnc_tx_carrier; /* next TX that can carry a LNet * message or ZC-ACK */ unsigned long ksnc_tx_deadline; /* when (in jiffies) tx times out */ @@ -367,9 +364,9 @@ typedef struct ksock_conn { int ksnc_tx_scheduled; /* being progressed */ unsigned long ksnc_tx_last_post; /* time stamp of the last posted * TX */ -} ksock_conn_t; +}; -typedef struct ksock_route { +struct ksock_route { struct list_head ksnr_list; /* chain on peer route list */ struct list_head ksnr_connd_list; /* chain on ksnr_connd_routes */ struct ksock_peer *ksnr_peer; /* owning peer */ @@ -389,11 +386,11 @@ typedef struct ksock_route { unsigned int ksnr_share_count; /* created explicitly? */ int ksnr_conn_count; /* # conns established by this * route */ -} ksock_route_t; +}; #define SOCKNAL_KEEPALIVE_PING 1 /* cookie for keepalive ping */ -typedef struct ksock_peer { +struct ksock_peer { struct list_head ksnp_list; /* stash on global peer list */ unsigned long ksnp_last_alive; /* when (in jiffies) I was last * alive */ @@ -420,49 +417,49 @@ typedef struct ksock_peer { /* preferred local interfaces */ __u32 ksnp_passive_ips[LNET_MAX_INTERFACES]; -} ksock_peer_t; +}; -typedef struct ksock_connreq { +struct ksock_connreq { struct list_head ksncr_list; /* stash on ksnd_connd_connreqs */ lnet_ni_t *ksncr_ni; /* chosen NI */ struct socket *ksncr_sock; /* accepted socket */ -} ksock_connreq_t; +}; -extern ksock_nal_data_t ksocknal_data; -extern ksock_tunables_t ksocknal_tunables; +extern struct ksock_nal_data ksocknal_data; +extern struct ksock_tunables ksocknal_tunables; #define SOCKNAL_MATCH_NO 0 /* TX can't match type of connection */ #define SOCKNAL_MATCH_YES 1 /* TX matches type of connection */ #define SOCKNAL_MATCH_MAY 2 /* TX can be sent on the connection, but not * preferred */ -typedef struct ksock_proto { +struct ksock_proto { /* version number of protocol */ int pro_version; /* handshake function */ - int (*pro_send_hello)(ksock_conn_t *, ksock_hello_msg_t *); + int (*pro_send_hello)(struct ksock_conn *, ksock_hello_msg_t *); /* handshake function */ - int (*pro_recv_hello)(ksock_conn_t *, ksock_hello_msg_t *, int); + int (*pro_recv_hello)(struct ksock_conn *, ksock_hello_msg_t *, int); /* message pack */ - void (*pro_pack)(ksock_tx_t *); + void (*pro_pack)(struct ksock_tx *); /* message unpack */ void (*pro_unpack)(ksock_msg_t *); /* queue tx on the connection */ - ksock_tx_t *(*pro_queue_tx_msg)(ksock_conn_t *, ksock_tx_t *); + struct ksock_tx *(*pro_queue_tx_msg)(struct ksock_conn *, struct ksock_tx *); /* queue ZC ack on the connection */ - int (*pro_queue_tx_zcack)(ksock_conn_t *, ksock_tx_t *, __u64); + int (*pro_queue_tx_zcack)(struct ksock_conn *, struct ksock_tx *, __u64); /* handle ZC request */ - int (*pro_handle_zcreq)(ksock_conn_t *, __u64, int); + int (*pro_handle_zcreq)(struct ksock_conn *, __u64, int); /* handle ZC ACK */ - int (*pro_handle_zcack)(ksock_conn_t *, __u64, __u64); + int (*pro_handle_zcack)(struct ksock_conn *, __u64, __u64); /* * msg type matches the connection type: @@ -471,12 +468,12 @@ typedef struct ksock_proto { * return MATCH_YES : matching type * return MATCH_MAY : can be backup */ - int (*pro_match_tx)(ksock_conn_t *, ksock_tx_t *, int); -} ksock_proto_t; + int (*pro_match_tx)(struct ksock_conn *, struct ksock_tx *, int); +}; -extern ksock_proto_t ksocknal_protocol_v1x; -extern ksock_proto_t ksocknal_protocol_v2x; -extern ksock_proto_t ksocknal_protocol_v3x; +extern struct ksock_proto ksocknal_protocol_v1x; +extern struct ksock_proto ksocknal_protocol_v2x; +extern struct ksock_proto ksocknal_protocol_v3x; #define KSOCK_PROTO_V1_MAJOR LNET_PROTO_TCP_VERSION_MAJOR #define KSOCK_PROTO_V1_MINOR LNET_PROTO_TCP_VERSION_MINOR @@ -517,17 +514,17 @@ ksocknal_nid2peerlist(lnet_nid_t nid) } static inline void -ksocknal_conn_addref(ksock_conn_t *conn) +ksocknal_conn_addref(struct ksock_conn *conn) { LASSERT(atomic_read(&conn->ksnc_conn_refcount) > 0); atomic_inc(&conn->ksnc_conn_refcount); } -void ksocknal_queue_zombie_conn(ksock_conn_t *conn); -void ksocknal_finalize_zcreq(ksock_conn_t *conn); +void ksocknal_queue_zombie_conn(struct ksock_conn *conn); +void ksocknal_finalize_zcreq(struct ksock_conn *conn); static inline void -ksocknal_conn_decref(ksock_conn_t *conn) +ksocknal_conn_decref(struct ksock_conn *conn) { LASSERT(atomic_read(&conn->ksnc_conn_refcount) > 0); if (atomic_dec_and_test(&conn->ksnc_conn_refcount)) @@ -535,7 +532,7 @@ ksocknal_conn_decref(ksock_conn_t *conn) } static inline int -ksocknal_connsock_addref(ksock_conn_t *conn) +ksocknal_connsock_addref(struct ksock_conn *conn) { int rc = -ESHUTDOWN; @@ -551,7 +548,7 @@ ksocknal_connsock_addref(ksock_conn_t *conn) } static inline void -ksocknal_connsock_decref(ksock_conn_t *conn) +ksocknal_connsock_decref(struct ksock_conn *conn) { LASSERT(atomic_read(&conn->ksnc_sock_refcount) > 0); if (atomic_dec_and_test(&conn->ksnc_sock_refcount)) { @@ -563,17 +560,17 @@ ksocknal_connsock_decref(ksock_conn_t *conn) } static inline void -ksocknal_tx_addref(ksock_tx_t *tx) +ksocknal_tx_addref(struct ksock_tx *tx) { LASSERT(atomic_read(&tx->tx_refcount) > 0); atomic_inc(&tx->tx_refcount); } -void ksocknal_tx_prep(ksock_conn_t *, ksock_tx_t *tx); -void ksocknal_tx_done(lnet_ni_t *ni, ksock_tx_t *tx); +void ksocknal_tx_prep(struct ksock_conn *, struct ksock_tx *tx); +void ksocknal_tx_done(lnet_ni_t *ni, struct ksock_tx *tx); static inline void -ksocknal_tx_decref(ksock_tx_t *tx) +ksocknal_tx_decref(struct ksock_tx *tx) { LASSERT(atomic_read(&tx->tx_refcount) > 0); if (atomic_dec_and_test(&tx->tx_refcount)) @@ -581,16 +578,16 @@ ksocknal_tx_decref(ksock_tx_t *tx) } static inline void -ksocknal_route_addref(ksock_route_t *route) +ksocknal_route_addref(struct ksock_route *route) { LASSERT(atomic_read(&route->ksnr_refcount) > 0); atomic_inc(&route->ksnr_refcount); } -void ksocknal_destroy_route(ksock_route_t *route); +void ksocknal_destroy_route(struct ksock_route *route); static inline void -ksocknal_route_decref(ksock_route_t *route) +ksocknal_route_decref(struct ksock_route *route) { LASSERT(atomic_read(&route->ksnr_refcount) > 0); if (atomic_dec_and_test(&route->ksnr_refcount)) @@ -598,16 +595,16 @@ ksocknal_route_decref(ksock_route_t *route) } static inline void -ksocknal_peer_addref(ksock_peer_t *peer) +ksocknal_peer_addref(struct ksock_peer *peer) { LASSERT(atomic_read(&peer->ksnp_refcount) > 0); atomic_inc(&peer->ksnp_refcount); } -void ksocknal_destroy_peer(ksock_peer_t *peer); +void ksocknal_destroy_peer(struct ksock_peer *peer); static inline void -ksocknal_peer_decref(ksock_peer_t *peer) +ksocknal_peer_decref(struct ksock_peer *peer) { LASSERT(atomic_read(&peer->ksnp_refcount) > 0); if (atomic_dec_and_test(&peer->ksnp_refcount)) @@ -625,71 +622,71 @@ int ksocknal_recv(lnet_ni_t *ni, void *private, lnet_msg_t *lntmsg, int ksocknal_accept(lnet_ni_t *ni, struct socket *sock); int ksocknal_add_peer(lnet_ni_t *ni, lnet_process_id_t id, __u32 ip, int port); -ksock_peer_t *ksocknal_find_peer_locked(lnet_ni_t *ni, lnet_process_id_t id); -ksock_peer_t *ksocknal_find_peer(lnet_ni_t *ni, lnet_process_id_t id); -void ksocknal_peer_failed(ksock_peer_t *peer); -int ksocknal_create_conn(lnet_ni_t *ni, ksock_route_t *route, +struct ksock_peer *ksocknal_find_peer_locked(lnet_ni_t *ni, lnet_process_id_t id); +struct ksock_peer *ksocknal_find_peer(lnet_ni_t *ni, lnet_process_id_t id); +void ksocknal_peer_failed(struct ksock_peer *peer); +int ksocknal_create_conn(lnet_ni_t *ni, struct ksock_route *route, struct socket *sock, int type); -void ksocknal_close_conn_locked(ksock_conn_t *conn, int why); -void ksocknal_terminate_conn(ksock_conn_t *conn); -void ksocknal_destroy_conn(ksock_conn_t *conn); -int ksocknal_close_peer_conns_locked(ksock_peer_t *peer, +void ksocknal_close_conn_locked(struct ksock_conn *conn, int why); +void ksocknal_terminate_conn(struct ksock_conn *conn); +void ksocknal_destroy_conn(struct ksock_conn *conn); +int ksocknal_close_peer_conns_locked(struct ksock_peer *peer, __u32 ipaddr, int why); -int ksocknal_close_conn_and_siblings(ksock_conn_t *conn, int why); +int ksocknal_close_conn_and_siblings(struct ksock_conn *conn, int why); int ksocknal_close_matching_conns(lnet_process_id_t id, __u32 ipaddr); -ksock_conn_t *ksocknal_find_conn_locked(ksock_peer_t *peer, - ksock_tx_t *tx, int nonblk); +struct ksock_conn *ksocknal_find_conn_locked(struct ksock_peer *peer, + struct ksock_tx *tx, int nonblk); -int ksocknal_launch_packet(lnet_ni_t *ni, ksock_tx_t *tx, +int ksocknal_launch_packet(lnet_ni_t *ni, struct ksock_tx *tx, lnet_process_id_t id); -ksock_tx_t *ksocknal_alloc_tx(int type, int size); -void ksocknal_free_tx(ksock_tx_t *tx); -ksock_tx_t *ksocknal_alloc_tx_noop(__u64 cookie, int nonblk); -void ksocknal_next_tx_carrier(ksock_conn_t *conn); -void ksocknal_queue_tx_locked(ksock_tx_t *tx, ksock_conn_t *conn); +struct ksock_tx *ksocknal_alloc_tx(int type, int size); +void ksocknal_free_tx(struct ksock_tx *tx); +struct ksock_tx *ksocknal_alloc_tx_noop(__u64 cookie, int nonblk); +void ksocknal_next_tx_carrier(struct ksock_conn *conn); +void ksocknal_queue_tx_locked(struct ksock_tx *tx, struct ksock_conn *conn); void ksocknal_txlist_done(lnet_ni_t *ni, struct list_head *txlist, int error); void ksocknal_notify(lnet_ni_t *ni, lnet_nid_t gw_nid, int alive); void ksocknal_query(struct lnet_ni *ni, lnet_nid_t nid, unsigned long *when); int ksocknal_thread_start(int (*fn)(void *arg), void *arg, char *name); void ksocknal_thread_fini(void); -void ksocknal_launch_all_connections_locked(ksock_peer_t *peer); -ksock_route_t *ksocknal_find_connectable_route_locked(ksock_peer_t *peer); -ksock_route_t *ksocknal_find_connecting_route_locked(ksock_peer_t *peer); -int ksocknal_new_packet(ksock_conn_t *conn, int skip); +void ksocknal_launch_all_connections_locked(struct ksock_peer *peer); +struct ksock_route *ksocknal_find_connectable_route_locked(struct ksock_peer *peer); +struct ksock_route *ksocknal_find_connecting_route_locked(struct ksock_peer *peer); +int ksocknal_new_packet(struct ksock_conn *conn, int skip); int ksocknal_scheduler(void *arg); int ksocknal_connd(void *arg); int ksocknal_reaper(void *arg); -int ksocknal_send_hello(lnet_ni_t *ni, ksock_conn_t *conn, +int ksocknal_send_hello(lnet_ni_t *ni, struct ksock_conn *conn, lnet_nid_t peer_nid, ksock_hello_msg_t *hello); -int ksocknal_recv_hello(lnet_ni_t *ni, ksock_conn_t *conn, +int ksocknal_recv_hello(lnet_ni_t *ni, struct ksock_conn *conn, ksock_hello_msg_t *hello, lnet_process_id_t *id, __u64 *incarnation); -void ksocknal_read_callback(ksock_conn_t *conn); -void ksocknal_write_callback(ksock_conn_t *conn); - -int ksocknal_lib_zc_capable(ksock_conn_t *conn); -void ksocknal_lib_save_callback(struct socket *sock, ksock_conn_t *conn); -void ksocknal_lib_set_callback(struct socket *sock, ksock_conn_t *conn); -void ksocknal_lib_reset_callback(struct socket *sock, ksock_conn_t *conn); -void ksocknal_lib_push_conn(ksock_conn_t *conn); -int ksocknal_lib_get_conn_addrs(ksock_conn_t *conn); +void ksocknal_read_callback(struct ksock_conn *conn); +void ksocknal_write_callback(struct ksock_conn *conn); + +int ksocknal_lib_zc_capable(struct ksock_conn *conn); +void ksocknal_lib_save_callback(struct socket *sock, struct ksock_conn *conn); +void ksocknal_lib_set_callback(struct socket *sock, struct ksock_conn *conn); +void ksocknal_lib_reset_callback(struct socket *sock, struct ksock_conn *conn); +void ksocknal_lib_push_conn(struct ksock_conn *conn); +int ksocknal_lib_get_conn_addrs(struct ksock_conn *conn); int ksocknal_lib_setup_sock(struct socket *so); -int ksocknal_lib_send_iov(ksock_conn_t *conn, ksock_tx_t *tx); -int ksocknal_lib_send_kiov(ksock_conn_t *conn, ksock_tx_t *tx); -void ksocknal_lib_eager_ack(ksock_conn_t *conn); -int ksocknal_lib_recv_iov(ksock_conn_t *conn); -int ksocknal_lib_recv_kiov(ksock_conn_t *conn); -int ksocknal_lib_get_conn_tunables(ksock_conn_t *conn, int *txmem, +int ksocknal_lib_send_iov(struct ksock_conn *conn, struct ksock_tx *tx); +int ksocknal_lib_send_kiov(struct ksock_conn *conn, struct ksock_tx *tx); +void ksocknal_lib_eager_ack(struct ksock_conn *conn); +int ksocknal_lib_recv_iov(struct ksock_conn *conn); +int ksocknal_lib_recv_kiov(struct ksock_conn *conn); +int ksocknal_lib_get_conn_tunables(struct ksock_conn *conn, int *txmem, int *rxmem, int *nagle); -void ksocknal_read_callback(ksock_conn_t *conn); -void ksocknal_write_callback(ksock_conn_t *conn); +void ksocknal_read_callback(struct ksock_conn *conn); +void ksocknal_write_callback(struct ksock_conn *conn); int ksocknal_tunables_init(void); -void ksocknal_lib_csum_tx(ksock_tx_t *tx); +void ksocknal_lib_csum_tx(struct ksock_tx *tx); -int ksocknal_lib_memory_pressure(ksock_conn_t *conn); +int ksocknal_lib_memory_pressure(struct ksock_conn *conn); int ksocknal_lib_bind_thread_to_cpu(int id); #endif /* _SOCKLND_SOCKLND_H_ */ diff --git a/drivers/staging/lustre/lnet/klnds/socklnd/socklnd_cb.c b/drivers/staging/lustre/lnet/klnds/socklnd/socklnd_cb.c index 976fd78..e63d29b 100644 --- a/drivers/staging/lustre/lnet/klnds/socklnd/socklnd_cb.c +++ b/drivers/staging/lustre/lnet/klnds/socklnd/socklnd_cb.c @@ -23,10 +23,10 @@ #include "socklnd.h" -ksock_tx_t * +struct ksock_tx * ksocknal_alloc_tx(int type, int size) { - ksock_tx_t *tx = NULL; + struct ksock_tx *tx = NULL; if (type == KSOCK_MSG_NOOP) { LASSERT(size == KSOCK_NOOP_TX_SIZE); @@ -36,7 +36,7 @@ ksocknal_alloc_tx(int type, int size) if (!list_empty(&ksocknal_data.ksnd_idle_noop_txs)) { tx = list_entry(ksocknal_data.ksnd_idle_noop_txs. \ - next, ksock_tx_t, tx_list); + next, struct ksock_tx, tx_list); LASSERT(tx->tx_desc_size == size); list_del(&tx->tx_list); } @@ -61,10 +61,10 @@ ksocknal_alloc_tx(int type, int size) return tx; } -ksock_tx_t * +struct ksock_tx * ksocknal_alloc_tx_noop(__u64 cookie, int nonblk) { - ksock_tx_t *tx; + struct ksock_tx *tx; tx = ksocknal_alloc_tx(KSOCK_MSG_NOOP, KSOCK_NOOP_TX_SIZE); if (!tx) { @@ -87,7 +87,7 @@ ksocknal_alloc_tx_noop(__u64 cookie, int nonblk) } void -ksocknal_free_tx(ksock_tx_t *tx) +ksocknal_free_tx(struct ksock_tx *tx) { atomic_dec(&ksocknal_data.ksnd_nactive_txs); @@ -104,7 +104,7 @@ ksocknal_free_tx(ksock_tx_t *tx) } static int -ksocknal_send_iov(ksock_conn_t *conn, ksock_tx_t *tx) +ksocknal_send_iov(struct ksock_conn *conn, struct ksock_tx *tx) { struct kvec *iov = tx->tx_iov; int nob; @@ -141,7 +141,7 @@ ksocknal_send_iov(ksock_conn_t *conn, ksock_tx_t *tx) } static int -ksocknal_send_kiov(ksock_conn_t *conn, ksock_tx_t *tx) +ksocknal_send_kiov(struct ksock_conn *conn, struct ksock_tx *tx) { lnet_kiov_t *kiov = tx->tx_kiov; int nob; @@ -179,7 +179,7 @@ ksocknal_send_kiov(ksock_conn_t *conn, ksock_tx_t *tx) } static int -ksocknal_transmit(ksock_conn_t *conn, ksock_tx_t *tx) +ksocknal_transmit(struct ksock_conn *conn, struct ksock_tx *tx) { int rc; int bufnob; @@ -247,7 +247,7 @@ ksocknal_transmit(ksock_conn_t *conn, ksock_tx_t *tx) } static int -ksocknal_recv_iov(ksock_conn_t *conn) +ksocknal_recv_iov(struct ksock_conn *conn) { struct kvec *iov = conn->ksnc_rx_iov; int nob; @@ -294,7 +294,7 @@ ksocknal_recv_iov(ksock_conn_t *conn) } static int -ksocknal_recv_kiov(ksock_conn_t *conn) +ksocknal_recv_kiov(struct ksock_conn *conn) { lnet_kiov_t *kiov = conn->ksnc_rx_kiov; int nob; @@ -341,7 +341,7 @@ ksocknal_recv_kiov(ksock_conn_t *conn) } static int -ksocknal_receive(ksock_conn_t *conn) +ksocknal_receive(struct ksock_conn *conn) { /* * Return 1 on success, 0 on EOF, < 0 on error. @@ -391,7 +391,7 @@ ksocknal_receive(ksock_conn_t *conn) } void -ksocknal_tx_done(lnet_ni_t *ni, ksock_tx_t *tx) +ksocknal_tx_done(lnet_ni_t *ni, struct ksock_tx *tx) { lnet_msg_t *lnetmsg = tx->tx_lnetmsg; int rc = (!tx->tx_resid && !tx->tx_zc_aborted) ? 0 : -EIO; @@ -412,10 +412,10 @@ ksocknal_tx_done(lnet_ni_t *ni, ksock_tx_t *tx) void ksocknal_txlist_done(lnet_ni_t *ni, struct list_head *txlist, int error) { - ksock_tx_t *tx; + struct ksock_tx *tx; while (!list_empty(txlist)) { - tx = list_entry(txlist->next, ksock_tx_t, tx_list); + tx = list_entry(txlist->next, struct ksock_tx, tx_list); if (error && tx->tx_lnetmsg) { CNETERR("Deleting packet type %d len %d %s->%s\n", @@ -435,10 +435,10 @@ ksocknal_txlist_done(lnet_ni_t *ni, struct list_head *txlist, int error) } static void -ksocknal_check_zc_req(ksock_tx_t *tx) +ksocknal_check_zc_req(struct ksock_tx *tx) { - ksock_conn_t *conn = tx->tx_conn; - ksock_peer_t *peer = conn->ksnc_peer; + struct ksock_conn *conn = tx->tx_conn; + struct ksock_peer *peer = conn->ksnc_peer; /* * Set tx_msg.ksm_zc_cookies[0] to a unique non-zero cookie and add tx @@ -482,9 +482,9 @@ ksocknal_check_zc_req(ksock_tx_t *tx) } static void -ksocknal_uncheck_zc_req(ksock_tx_t *tx) +ksocknal_uncheck_zc_req(struct ksock_tx *tx) { - ksock_peer_t *peer = tx->tx_conn->ksnc_peer; + struct ksock_peer *peer = tx->tx_conn->ksnc_peer; LASSERT(tx->tx_msg.ksm_type != KSOCK_MSG_NOOP); LASSERT(tx->tx_zc_capable); @@ -508,7 +508,7 @@ ksocknal_uncheck_zc_req(ksock_tx_t *tx) } static int -ksocknal_process_transmit(ksock_conn_t *conn, ksock_tx_t *tx) +ksocknal_process_transmit(struct ksock_conn *conn, struct ksock_tx *tx) { int rc; @@ -583,7 +583,7 @@ ksocknal_process_transmit(ksock_conn_t *conn, ksock_tx_t *tx) } static void -ksocknal_launch_connection_locked(ksock_route_t *route) +ksocknal_launch_connection_locked(struct ksock_route *route) { /* called holding write lock on ksnd_global_lock */ @@ -604,9 +604,9 @@ ksocknal_launch_connection_locked(ksock_route_t *route) } void -ksocknal_launch_all_connections_locked(ksock_peer_t *peer) +ksocknal_launch_all_connections_locked(struct ksock_peer *peer) { - ksock_route_t *route; + struct ksock_route *route; /* called holding write lock on ksnd_global_lock */ for (;;) { @@ -619,18 +619,18 @@ ksocknal_launch_all_connections_locked(ksock_peer_t *peer) } } -ksock_conn_t * -ksocknal_find_conn_locked(ksock_peer_t *peer, ksock_tx_t *tx, int nonblk) +struct ksock_conn * +ksocknal_find_conn_locked(struct ksock_peer *peer, struct ksock_tx *tx, int nonblk) { struct list_head *tmp; - ksock_conn_t *conn; - ksock_conn_t *typed = NULL; - ksock_conn_t *fallback = NULL; + struct ksock_conn *conn; + struct ksock_conn *typed = NULL; + struct ksock_conn *fallback = NULL; int tnob = 0; int fnob = 0; list_for_each(tmp, &peer->ksnp_conns) { - ksock_conn_t *c = list_entry(tmp, ksock_conn_t, ksnc_list); + struct ksock_conn *c = list_entry(tmp, struct ksock_conn, ksnc_list); int nob = atomic_read(&c->ksnc_tx_nob) + c->ksnc_sock->sk->sk_wmem_queued; int rc; @@ -677,7 +677,7 @@ ksocknal_find_conn_locked(ksock_peer_t *peer, ksock_tx_t *tx, int nonblk) } void -ksocknal_tx_prep(ksock_conn_t *conn, ksock_tx_t *tx) +ksocknal_tx_prep(struct ksock_conn *conn, struct ksock_tx *tx) { conn->ksnc_proto->pro_pack(tx); @@ -687,11 +687,11 @@ ksocknal_tx_prep(ksock_conn_t *conn, ksock_tx_t *tx) } void -ksocknal_queue_tx_locked(ksock_tx_t *tx, ksock_conn_t *conn) +ksocknal_queue_tx_locked(struct ksock_tx *tx, struct ksock_conn *conn) { - ksock_sched_t *sched = conn->ksnc_scheduler; + struct ksock_sched *sched = conn->ksnc_scheduler; ksock_msg_t *msg = &tx->tx_msg; - ksock_tx_t *ztx = NULL; + struct ksock_tx *ztx = NULL; int bufnob = 0; /* @@ -784,15 +784,15 @@ ksocknal_queue_tx_locked(ksock_tx_t *tx, ksock_conn_t *conn) spin_unlock_bh(&sched->kss_lock); } -ksock_route_t * -ksocknal_find_connectable_route_locked(ksock_peer_t *peer) +struct ksock_route * +ksocknal_find_connectable_route_locked(struct ksock_peer *peer) { unsigned long now = cfs_time_current(); struct list_head *tmp; - ksock_route_t *route; + struct ksock_route *route; list_for_each(tmp, &peer->ksnp_routes) { - route = list_entry(tmp, ksock_route_t, ksnr_list); + route = list_entry(tmp, struct ksock_route, ksnr_list); LASSERT(!route->ksnr_connecting || route->ksnr_scheduled); @@ -820,14 +820,14 @@ ksocknal_find_connectable_route_locked(ksock_peer_t *peer) return NULL; } -ksock_route_t * -ksocknal_find_connecting_route_locked(ksock_peer_t *peer) +struct ksock_route * +ksocknal_find_connecting_route_locked(struct ksock_peer *peer) { struct list_head *tmp; - ksock_route_t *route; + struct ksock_route *route; list_for_each(tmp, &peer->ksnp_routes) { - route = list_entry(tmp, ksock_route_t, ksnr_list); + route = list_entry(tmp, struct ksock_route, ksnr_list); LASSERT(!route->ksnr_connecting || route->ksnr_scheduled); @@ -839,10 +839,10 @@ ksocknal_find_connecting_route_locked(ksock_peer_t *peer) } int -ksocknal_launch_packet(lnet_ni_t *ni, ksock_tx_t *tx, lnet_process_id_t id) +ksocknal_launch_packet(lnet_ni_t *ni, struct ksock_tx *tx, lnet_process_id_t id) { - ksock_peer_t *peer; - ksock_conn_t *conn; + struct ksock_peer *peer; + struct ksock_conn *conn; rwlock_t *g_lock; int retry; int rc; @@ -942,7 +942,7 @@ ksocknal_send(lnet_ni_t *ni, void *private, lnet_msg_t *lntmsg) lnet_kiov_t *payload_kiov = lntmsg->msg_kiov; unsigned int payload_offset = lntmsg->msg_offset; unsigned int payload_nob = lntmsg->msg_len; - ksock_tx_t *tx; + struct ksock_tx *tx; int desc_size; int rc; @@ -960,10 +960,10 @@ ksocknal_send(lnet_ni_t *ni, void *private, lnet_msg_t *lntmsg) LASSERT(!in_interrupt()); if (payload_iov) - desc_size = offsetof(ksock_tx_t, + desc_size = offsetof(struct ksock_tx, tx_frags.virt.iov[1 + payload_niov]); else - desc_size = offsetof(ksock_tx_t, + desc_size = offsetof(struct ksock_tx, tx_frags.paged.kiov[payload_niov]); if (lntmsg->msg_vmflush) @@ -1037,7 +1037,7 @@ ksocknal_thread_fini(void) } int -ksocknal_new_packet(ksock_conn_t *conn, int nob_to_skip) +ksocknal_new_packet(struct ksock_conn *conn, int nob_to_skip) { static char ksocknal_slop_buffer[4096]; @@ -1120,7 +1120,7 @@ ksocknal_new_packet(ksock_conn_t *conn, int nob_to_skip) } static int -ksocknal_process_receive(ksock_conn_t *conn) +ksocknal_process_receive(struct ksock_conn *conn) { lnet_hdr_t *lhdr; lnet_process_id_t *id; @@ -1328,8 +1328,8 @@ ksocknal_recv(lnet_ni_t *ni, void *private, lnet_msg_t *msg, int delayed, unsigned int niov, struct kvec *iov, lnet_kiov_t *kiov, unsigned int offset, unsigned int mlen, unsigned int rlen) { - ksock_conn_t *conn = private; - ksock_sched_t *sched = conn->ksnc_scheduler; + struct ksock_conn *conn = private; + struct ksock_sched *sched = conn->ksnc_scheduler; LASSERT(mlen <= rlen); LASSERT(niov <= LNET_MAX_IOV); @@ -1382,7 +1382,7 @@ ksocknal_recv(lnet_ni_t *ni, void *private, lnet_msg_t *msg, int delayed, } static inline int -ksocknal_sched_cansleep(ksock_sched_t *sched) +ksocknal_sched_cansleep(struct ksock_sched *sched) { int rc; @@ -1399,9 +1399,9 @@ ksocknal_sched_cansleep(ksock_sched_t *sched) int ksocknal_scheduler(void *arg) { struct ksock_sched_info *info; - ksock_sched_t *sched; - ksock_conn_t *conn; - ksock_tx_t *tx; + struct ksock_sched *sched; + struct ksock_conn *conn; + struct ksock_tx *tx; int rc; int nloops = 0; long id = (long)arg; @@ -1426,7 +1426,7 @@ int ksocknal_scheduler(void *arg) if (!list_empty(&sched->kss_rx_conns)) { conn = list_entry(sched->kss_rx_conns.next, - ksock_conn_t, ksnc_rx_list); + struct ksock_conn, ksnc_rx_list); list_del(&conn->ksnc_rx_list); LASSERT(conn->ksnc_rx_scheduled); @@ -1481,7 +1481,7 @@ int ksocknal_scheduler(void *arg) } conn = list_entry(sched->kss_tx_conns.next, - ksock_conn_t, ksnc_tx_list); + struct ksock_conn, ksnc_tx_list); list_del(&conn->ksnc_tx_list); LASSERT(conn->ksnc_tx_scheduled); @@ -1489,7 +1489,7 @@ int ksocknal_scheduler(void *arg) LASSERT(!list_empty(&conn->ksnc_tx_queue)); tx = list_entry(conn->ksnc_tx_queue.next, - ksock_tx_t, tx_list); + struct ksock_tx, tx_list); if (conn->ksnc_tx_carrier == tx) ksocknal_next_tx_carrier(conn); @@ -1575,9 +1575,9 @@ int ksocknal_scheduler(void *arg) * Add connection to kss_rx_conns of scheduler * and wakeup the scheduler. */ -void ksocknal_read_callback(ksock_conn_t *conn) +void ksocknal_read_callback(struct ksock_conn *conn) { - ksock_sched_t *sched; + struct ksock_sched *sched; sched = conn->ksnc_scheduler; @@ -1600,9 +1600,9 @@ void ksocknal_read_callback(ksock_conn_t *conn) * Add connection to kss_tx_conns of scheduler * and wakeup the scheduler. */ -void ksocknal_write_callback(ksock_conn_t *conn) +void ksocknal_write_callback(struct ksock_conn *conn) { - ksock_sched_t *sched; + struct ksock_sched *sched; sched = conn->ksnc_scheduler; @@ -1623,7 +1623,7 @@ void ksocknal_write_callback(ksock_conn_t *conn) spin_unlock_bh(&sched->kss_lock); } -static ksock_proto_t * +static struct ksock_proto * ksocknal_parse_proto_version(ksock_hello_msg_t *hello) { __u32 version = 0; @@ -1666,11 +1666,11 @@ ksocknal_parse_proto_version(ksock_hello_msg_t *hello) } int -ksocknal_send_hello(lnet_ni_t *ni, ksock_conn_t *conn, +ksocknal_send_hello(lnet_ni_t *ni, struct ksock_conn *conn, lnet_nid_t peer_nid, ksock_hello_msg_t *hello) { /* CAVEAT EMPTOR: this byte flips 'ipaddrs' */ - ksock_net_t *net = (ksock_net_t *)ni->ni_data; + struct ksock_net *net = (struct ksock_net *)ni->ni_data; LASSERT(hello->kshm_nips <= LNET_MAX_INTERFACES); @@ -1704,7 +1704,7 @@ ksocknal_invert_type(int type) } int -ksocknal_recv_hello(lnet_ni_t *ni, ksock_conn_t *conn, +ksocknal_recv_hello(lnet_ni_t *ni, struct ksock_conn *conn, ksock_hello_msg_t *hello, lnet_process_id_t *peerid, __u64 *incarnation) { @@ -1718,7 +1718,7 @@ ksocknal_recv_hello(lnet_ni_t *ni, ksock_conn_t *conn, int timeout; int proto_match; int rc; - ksock_proto_t *proto; + struct ksock_proto *proto; lnet_process_id_t recv_id; /* socket type set on active connections - not set on passive */ @@ -1847,10 +1847,10 @@ ksocknal_recv_hello(lnet_ni_t *ni, ksock_conn_t *conn, } static int -ksocknal_connect(ksock_route_t *route) +ksocknal_connect(struct ksock_route *route) { LIST_HEAD(zombies); - ksock_peer_t *peer = route->ksnr_peer; + struct ksock_peer *peer = route->ksnr_peer; int type; int wanted; struct socket *sock; @@ -1989,7 +1989,7 @@ ksocknal_connect(ksock_route_t *route) if (!list_empty(&peer->ksnp_tx_queue) && !peer->ksnp_accepting && !ksocknal_find_connecting_route_locked(peer)) { - ksock_conn_t *conn; + struct ksock_conn *conn; /* * ksnp_tx_queue is queued on a conn on successful @@ -1997,7 +1997,7 @@ ksocknal_connect(ksock_route_t *route) */ if (!list_empty(&peer->ksnp_conns)) { conn = list_entry(peer->ksnp_conns.next, - ksock_conn_t, ksnc_list); + struct ksock_conn, ksnc_list); LASSERT(conn->ksnc_proto == &ksocknal_protocol_v3x); } @@ -2131,10 +2131,10 @@ ksocknal_connd_check_stop(time64_t sec, long *timeout) * Go through connd_routes queue looking for a route that we can process * right now, @timeout_p can be updated if we need to come back later */ -static ksock_route_t * +static struct ksock_route * ksocknal_connd_get_route_locked(signed long *timeout_p) { - ksock_route_t *route; + struct ksock_route *route; unsigned long now; now = cfs_time_current(); @@ -2158,7 +2158,7 @@ int ksocknal_connd(void *arg) { spinlock_t *connd_lock = &ksocknal_data.ksnd_connd_lock; - ksock_connreq_t *cr; + struct ksock_connreq *cr; wait_queue_t wait; int nloops = 0; int cons_retry = 0; @@ -2174,7 +2174,7 @@ ksocknal_connd(void *arg) ksocknal_data.ksnd_connd_running++; while (!ksocknal_data.ksnd_shuttingdown) { - ksock_route_t *route = NULL; + struct ksock_route *route = NULL; time64_t sec = ktime_get_real_seconds(); long timeout = MAX_SCHEDULE_TIMEOUT; int dropped_lock = 0; @@ -2192,8 +2192,8 @@ ksocknal_connd(void *arg) if (!list_empty(&ksocknal_data.ksnd_connd_connreqs)) { /* Connection accepted by the listener */ - cr = list_entry(ksocknal_data.ksnd_connd_connreqs. \ - next, ksock_connreq_t, ksncr_list); + cr = list_entry(ksocknal_data.ksnd_connd_connreqs.next, + struct ksock_connreq, ksncr_list); list_del(&cr->ksncr_list); spin_unlock_bh(connd_lock); @@ -2267,17 +2267,17 @@ ksocknal_connd(void *arg) return 0; } -static ksock_conn_t * -ksocknal_find_timed_out_conn(ksock_peer_t *peer) +static struct ksock_conn * +ksocknal_find_timed_out_conn(struct ksock_peer *peer) { /* We're called with a shared lock on ksnd_global_lock */ - ksock_conn_t *conn; + struct ksock_conn *conn; struct list_head *ctmp; list_for_each(ctmp, &peer->ksnp_conns) { int error; - conn = list_entry(ctmp, ksock_conn_t, ksnc_list); + conn = list_entry(ctmp, struct ksock_conn, ksnc_list); /* Don't need the {get,put}connsock dance to deref ksnc_sock */ LASSERT(!conn->ksnc_closing); @@ -2351,10 +2351,10 @@ ksocknal_find_timed_out_conn(ksock_peer_t *peer) } static inline void -ksocknal_flush_stale_txs(ksock_peer_t *peer) +ksocknal_flush_stale_txs(struct ksock_peer *peer) { - ksock_tx_t *tx; - ksock_tx_t *tmp; + struct ksock_tx *tx; + struct ksock_tx *tmp; LIST_HEAD(stale_txs); write_lock_bh(&ksocknal_data.ksnd_global_lock); @@ -2374,12 +2374,12 @@ ksocknal_flush_stale_txs(ksock_peer_t *peer) } static int -ksocknal_send_keepalive_locked(ksock_peer_t *peer) +ksocknal_send_keepalive_locked(struct ksock_peer *peer) __must_hold(&ksocknal_data.ksnd_global_lock) { - ksock_sched_t *sched; - ksock_conn_t *conn; - ksock_tx_t *tx; + struct ksock_sched *sched; + struct ksock_conn *conn; + struct ksock_tx *tx; if (list_empty(&peer->ksnp_conns)) /* last_alive will be updated by create_conn */ return 0; @@ -2440,9 +2440,9 @@ static void ksocknal_check_peer_timeouts(int idx) { struct list_head *peers = &ksocknal_data.ksnd_peers[idx]; - ksock_peer_t *peer; - ksock_conn_t *conn; - ksock_tx_t *tx; + struct ksock_peer *peer; + struct ksock_conn *conn; + struct ksock_tx *tx; again: /* @@ -2483,8 +2483,8 @@ ksocknal_check_peer_timeouts(int idx) * holding only shared lock */ if (!list_empty(&peer->ksnp_tx_queue)) { - ksock_tx_t *tx = list_entry(peer->ksnp_tx_queue.next, - ksock_tx_t, tx_list); + struct ksock_tx *tx = list_entry(peer->ksnp_tx_queue.next, + struct ksock_tx, tx_list); if (cfs_time_aftereq(cfs_time_current(), tx->tx_deadline)) { @@ -2518,7 +2518,7 @@ ksocknal_check_peer_timeouts(int idx) } tx = list_entry(peer->ksnp_zc_req_list.next, - ksock_tx_t, tx_zc_list); + struct ksock_tx, tx_zc_list); deadline = tx->tx_deadline; resid = tx->tx_resid; conn = tx->tx_conn; @@ -2544,8 +2544,8 @@ int ksocknal_reaper(void *arg) { wait_queue_t wait; - ksock_conn_t *conn; - ksock_sched_t *sched; + struct ksock_conn *conn; + struct ksock_sched *sched; struct list_head enomem_conns; int nenomem_conns; long timeout; @@ -2563,7 +2563,7 @@ ksocknal_reaper(void *arg) while (!ksocknal_data.ksnd_shuttingdown) { if (!list_empty(&ksocknal_data.ksnd_deathrow_conns)) { conn = list_entry(ksocknal_data.ksnd_deathrow_conns.next, - ksock_conn_t, ksnc_list); + struct ksock_conn, ksnc_list); list_del(&conn->ksnc_list); spin_unlock_bh(&ksocknal_data.ksnd_reaper_lock); @@ -2577,7 +2577,7 @@ ksocknal_reaper(void *arg) if (!list_empty(&ksocknal_data.ksnd_zombie_conns)) { conn = list_entry(ksocknal_data.ksnd_zombie_conns.next, - ksock_conn_t, ksnc_list); + struct ksock_conn, ksnc_list); list_del(&conn->ksnc_list); spin_unlock_bh(&ksocknal_data.ksnd_reaper_lock); @@ -2599,7 +2599,7 @@ ksocknal_reaper(void *arg) /* reschedule all the connections that stalled with ENOMEM... */ nenomem_conns = 0; while (!list_empty(&enomem_conns)) { - conn = list_entry(enomem_conns.next, ksock_conn_t, + conn = list_entry(enomem_conns.next, struct ksock_conn, ksnc_tx_list); list_del(&conn->ksnc_tx_list); diff --git a/drivers/staging/lustre/lnet/klnds/socklnd/socklnd_lib.c b/drivers/staging/lustre/lnet/klnds/socklnd/socklnd_lib.c index 964b4e3..44d417b 100644 --- a/drivers/staging/lustre/lnet/klnds/socklnd/socklnd_lib.c +++ b/drivers/staging/lustre/lnet/klnds/socklnd/socklnd_lib.c @@ -37,7 +37,7 @@ #include "socklnd.h" int -ksocknal_lib_get_conn_addrs(ksock_conn_t *conn) +ksocknal_lib_get_conn_addrs(struct ksock_conn *conn) { int rc = lnet_sock_getaddr(conn->ksnc_sock, 1, &conn->ksnc_ipaddr, &conn->ksnc_port); @@ -60,7 +60,7 @@ ksocknal_lib_get_conn_addrs(ksock_conn_t *conn) } int -ksocknal_lib_zc_capable(ksock_conn_t *conn) +ksocknal_lib_zc_capable(struct ksock_conn *conn) { int caps = conn->ksnc_sock->sk->sk_route_caps; @@ -75,7 +75,7 @@ ksocknal_lib_zc_capable(ksock_conn_t *conn) } int -ksocknal_lib_send_iov(ksock_conn_t *conn, ksock_tx_t *tx) +ksocknal_lib_send_iov(struct ksock_conn *conn, struct ksock_tx *tx) { struct socket *sock = conn->ksnc_sock; int nob; @@ -118,7 +118,7 @@ ksocknal_lib_send_iov(ksock_conn_t *conn, ksock_tx_t *tx) } int -ksocknal_lib_send_kiov(ksock_conn_t *conn, ksock_tx_t *tx) +ksocknal_lib_send_kiov(struct ksock_conn *conn, struct ksock_tx *tx) { struct socket *sock = conn->ksnc_sock; lnet_kiov_t *kiov = tx->tx_kiov; @@ -187,7 +187,7 @@ ksocknal_lib_send_kiov(ksock_conn_t *conn, ksock_tx_t *tx) } void -ksocknal_lib_eager_ack(ksock_conn_t *conn) +ksocknal_lib_eager_ack(struct ksock_conn *conn) { int opt = 1; struct socket *sock = conn->ksnc_sock; @@ -203,7 +203,7 @@ ksocknal_lib_eager_ack(ksock_conn_t *conn) } int -ksocknal_lib_recv_iov(ksock_conn_t *conn) +ksocknal_lib_recv_iov(struct ksock_conn *conn) { #if SOCKNAL_SINGLE_FRAG_RX struct kvec scratch; @@ -309,7 +309,7 @@ ksocknal_lib_kiov_vmap(lnet_kiov_t *kiov, int niov, } int -ksocknal_lib_recv_kiov(ksock_conn_t *conn) +ksocknal_lib_recv_kiov(struct ksock_conn *conn) { #if SOCKNAL_SINGLE_FRAG_RX || !SOCKNAL_RISK_KMAP_DEADLOCK struct kvec scratch; @@ -393,7 +393,7 @@ ksocknal_lib_recv_kiov(ksock_conn_t *conn) } void -ksocknal_lib_csum_tx(ksock_tx_t *tx) +ksocknal_lib_csum_tx(struct ksock_tx *tx) { int i; __u32 csum; @@ -432,7 +432,7 @@ ksocknal_lib_csum_tx(ksock_tx_t *tx) } int -ksocknal_lib_get_conn_tunables(ksock_conn_t *conn, int *txmem, int *rxmem, int *nagle) +ksocknal_lib_get_conn_tunables(struct ksock_conn *conn, int *txmem, int *rxmem, int *nagle) { struct socket *sock = conn->ksnc_sock; int len; @@ -562,7 +562,7 @@ ksocknal_lib_setup_sock(struct socket *sock) } void -ksocknal_lib_push_conn(ksock_conn_t *conn) +ksocknal_lib_push_conn(struct ksock_conn *conn) { struct sock *sk; struct tcp_sock *tp; @@ -599,7 +599,7 @@ ksocknal_lib_push_conn(ksock_conn_t *conn) static void ksocknal_data_ready(struct sock *sk) { - ksock_conn_t *conn; + struct ksock_conn *conn; /* interleave correctly with closing sockets... */ LASSERT(!in_irq()); @@ -619,7 +619,7 @@ ksocknal_data_ready(struct sock *sk) static void ksocknal_write_space(struct sock *sk) { - ksock_conn_t *conn; + struct ksock_conn *conn; int wspace; int min_wpace; @@ -663,14 +663,14 @@ ksocknal_write_space(struct sock *sk) } void -ksocknal_lib_save_callback(struct socket *sock, ksock_conn_t *conn) +ksocknal_lib_save_callback(struct socket *sock, struct ksock_conn *conn) { conn->ksnc_saved_data_ready = sock->sk->sk_data_ready; conn->ksnc_saved_write_space = sock->sk->sk_write_space; } void -ksocknal_lib_set_callback(struct socket *sock, ksock_conn_t *conn) +ksocknal_lib_set_callback(struct socket *sock, struct ksock_conn *conn) { sock->sk->sk_user_data = conn; sock->sk->sk_data_ready = ksocknal_data_ready; @@ -678,7 +678,7 @@ ksocknal_lib_set_callback(struct socket *sock, ksock_conn_t *conn) } void -ksocknal_lib_reset_callback(struct socket *sock, ksock_conn_t *conn) +ksocknal_lib_reset_callback(struct socket *sock, struct ksock_conn *conn) { /* * Remove conn's network callbacks. @@ -697,10 +697,10 @@ ksocknal_lib_reset_callback(struct socket *sock, ksock_conn_t *conn) } int -ksocknal_lib_memory_pressure(ksock_conn_t *conn) +ksocknal_lib_memory_pressure(struct ksock_conn *conn) { int rc = 0; - ksock_sched_t *sched; + struct ksock_sched *sched; sched = conn->ksnc_scheduler; spin_lock_bh(&sched->kss_lock); diff --git a/drivers/staging/lustre/lnet/klnds/socklnd/socklnd_modparams.c b/drivers/staging/lustre/lnet/klnds/socklnd/socklnd_modparams.c index 6329cbe..fc7eec8 100644 --- a/drivers/staging/lustre/lnet/klnds/socklnd/socklnd_modparams.c +++ b/drivers/staging/lustre/lnet/klnds/socklnd/socklnd_modparams.c @@ -139,7 +139,7 @@ module_param(protocol, int, 0644); MODULE_PARM_DESC(protocol, "protocol version"); #endif -ksock_tunables_t ksocknal_tunables; +struct ksock_tunables ksocknal_tunables; int ksocknal_tunables_init(void) { diff --git a/drivers/staging/lustre/lnet/klnds/socklnd/socklnd_proto.c b/drivers/staging/lustre/lnet/klnds/socklnd/socklnd_proto.c index 32cc31e..e1bf910 100644 --- a/drivers/staging/lustre/lnet/klnds/socklnd/socklnd_proto.c +++ b/drivers/staging/lustre/lnet/klnds/socklnd/socklnd_proto.c @@ -38,8 +38,8 @@ * pro_match_tx() : Called holding glock */ -static ksock_tx_t * -ksocknal_queue_tx_msg_v1(ksock_conn_t *conn, ksock_tx_t *tx_msg) +static struct ksock_tx * +ksocknal_queue_tx_msg_v1(struct ksock_conn *conn, struct ksock_tx *tx_msg) { /* V1.x, just enqueue it */ list_add_tail(&tx_msg->tx_list, &conn->ksnc_tx_queue); @@ -47,9 +47,9 @@ ksocknal_queue_tx_msg_v1(ksock_conn_t *conn, ksock_tx_t *tx_msg) } void -ksocknal_next_tx_carrier(ksock_conn_t *conn) +ksocknal_next_tx_carrier(struct ksock_conn *conn) { - ksock_tx_t *tx = conn->ksnc_tx_carrier; + struct ksock_tx *tx = conn->ksnc_tx_carrier; /* Called holding BH lock: conn->ksnc_scheduler->kss_lock */ LASSERT(!list_empty(&conn->ksnc_tx_queue)); @@ -66,10 +66,10 @@ ksocknal_next_tx_carrier(ksock_conn_t *conn) } static int -ksocknal_queue_tx_zcack_v2(ksock_conn_t *conn, - ksock_tx_t *tx_ack, __u64 cookie) +ksocknal_queue_tx_zcack_v2(struct ksock_conn *conn, + struct ksock_tx *tx_ack, __u64 cookie) { - ksock_tx_t *tx = conn->ksnc_tx_carrier; + struct ksock_tx *tx = conn->ksnc_tx_carrier; LASSERT(!tx_ack || tx_ack->tx_msg.ksm_type == KSOCK_MSG_NOOP); @@ -112,10 +112,10 @@ ksocknal_queue_tx_zcack_v2(ksock_conn_t *conn, return 1; } -static ksock_tx_t * -ksocknal_queue_tx_msg_v2(ksock_conn_t *conn, ksock_tx_t *tx_msg) +static struct ksock_tx * +ksocknal_queue_tx_msg_v2(struct ksock_conn *conn, struct ksock_tx *tx_msg) { - ksock_tx_t *tx = conn->ksnc_tx_carrier; + struct ksock_tx *tx = conn->ksnc_tx_carrier; /* * Enqueue tx_msg: @@ -149,10 +149,10 @@ ksocknal_queue_tx_msg_v2(ksock_conn_t *conn, ksock_tx_t *tx_msg) } static int -ksocknal_queue_tx_zcack_v3(ksock_conn_t *conn, - ksock_tx_t *tx_ack, __u64 cookie) +ksocknal_queue_tx_zcack_v3(struct ksock_conn *conn, + struct ksock_tx *tx_ack, __u64 cookie) { - ksock_tx_t *tx; + struct ksock_tx *tx; if (conn->ksnc_type != SOCKLND_CONN_ACK) return ksocknal_queue_tx_zcack_v2(conn, tx_ack, cookie); @@ -267,7 +267,7 @@ ksocknal_queue_tx_zcack_v3(ksock_conn_t *conn, } static int -ksocknal_match_tx(ksock_conn_t *conn, ksock_tx_t *tx, int nonblk) +ksocknal_match_tx(struct ksock_conn *conn, struct ksock_tx *tx, int nonblk) { int nob; @@ -311,7 +311,7 @@ ksocknal_match_tx(ksock_conn_t *conn, ksock_tx_t *tx, int nonblk) } static int -ksocknal_match_tx_v3(ksock_conn_t *conn, ksock_tx_t *tx, int nonblk) +ksocknal_match_tx_v3(struct ksock_conn *conn, struct ksock_tx *tx, int nonblk) { int nob; @@ -355,18 +355,18 @@ ksocknal_match_tx_v3(ksock_conn_t *conn, ksock_tx_t *tx, int nonblk) /* (Sink) handle incoming ZC request from sender */ static int -ksocknal_handle_zcreq(ksock_conn_t *c, __u64 cookie, int remote) +ksocknal_handle_zcreq(struct ksock_conn *c, __u64 cookie, int remote) { - ksock_peer_t *peer = c->ksnc_peer; - ksock_conn_t *conn; - ksock_tx_t *tx; + struct ksock_peer *peer = c->ksnc_peer; + struct ksock_conn *conn; + struct ksock_tx *tx; int rc; read_lock(&ksocknal_data.ksnd_global_lock); conn = ksocknal_find_conn_locked(peer, NULL, !!remote); if (conn) { - ksock_sched_t *sched = conn->ksnc_scheduler; + struct ksock_sched *sched = conn->ksnc_scheduler; LASSERT(conn->ksnc_proto->pro_queue_tx_zcack); @@ -399,12 +399,12 @@ ksocknal_handle_zcreq(ksock_conn_t *c, __u64 cookie, int remote) /* (Sender) handle ZC_ACK from sink */ static int -ksocknal_handle_zcack(ksock_conn_t *conn, __u64 cookie1, __u64 cookie2) +ksocknal_handle_zcack(struct ksock_conn *conn, __u64 cookie1, __u64 cookie2) { - ksock_peer_t *peer = conn->ksnc_peer; - ksock_tx_t *tx; - ksock_tx_t *temp; - ksock_tx_t *tmp; + struct ksock_peer *peer = conn->ksnc_peer; + struct ksock_tx *tx; + struct ksock_tx *temp; + struct ksock_tx *tmp; LIST_HEAD(zlist); int count; @@ -446,7 +446,7 @@ ksocknal_handle_zcack(ksock_conn_t *conn, __u64 cookie1, __u64 cookie2) } static int -ksocknal_send_hello_v1(ksock_conn_t *conn, ksock_hello_msg_t *hello) +ksocknal_send_hello_v1(struct ksock_conn *conn, ksock_hello_msg_t *hello) { struct socket *sock = conn->ksnc_sock; lnet_hdr_t *hdr; @@ -521,7 +521,7 @@ out: } static int -ksocknal_send_hello_v2(ksock_conn_t *conn, ksock_hello_msg_t *hello) +ksocknal_send_hello_v2(struct ksock_conn *conn, ksock_hello_msg_t *hello) { struct socket *sock = conn->ksnc_sock; int rc; @@ -563,7 +563,7 @@ ksocknal_send_hello_v2(ksock_conn_t *conn, ksock_hello_msg_t *hello) } static int -ksocknal_recv_hello_v1(ksock_conn_t *conn, ksock_hello_msg_t *hello, +ksocknal_recv_hello_v1(struct ksock_conn *conn, ksock_hello_msg_t *hello, int timeout) { struct socket *sock = conn->ksnc_sock; @@ -639,7 +639,7 @@ out: } static int -ksocknal_recv_hello_v2(ksock_conn_t *conn, ksock_hello_msg_t *hello, int timeout) +ksocknal_recv_hello_v2(struct ksock_conn *conn, ksock_hello_msg_t *hello, int timeout) { struct socket *sock = conn->ksnc_sock; int rc; @@ -705,7 +705,7 @@ ksocknal_recv_hello_v2(ksock_conn_t *conn, ksock_hello_msg_t *hello, int timeout } static void -ksocknal_pack_msg_v1(ksock_tx_t *tx) +ksocknal_pack_msg_v1(struct ksock_tx *tx) { /* V1.x has no KSOCK_MSG_NOOP */ LASSERT(tx->tx_msg.ksm_type != KSOCK_MSG_NOOP); @@ -719,7 +719,7 @@ ksocknal_pack_msg_v1(ksock_tx_t *tx) } static void -ksocknal_pack_msg_v2(ksock_tx_t *tx) +ksocknal_pack_msg_v2(struct ksock_tx *tx) { tx->tx_iov[0].iov_base = &tx->tx_msg; @@ -755,7 +755,7 @@ ksocknal_unpack_msg_v2(ksock_msg_t *msg) return; /* Do nothing */ } -ksock_proto_t ksocknal_protocol_v1x = { +struct ksock_proto ksocknal_protocol_v1x = { .pro_version = KSOCK_PROTO_V1, .pro_send_hello = ksocknal_send_hello_v1, .pro_recv_hello = ksocknal_recv_hello_v1, @@ -768,7 +768,7 @@ ksock_proto_t ksocknal_protocol_v1x = { .pro_match_tx = ksocknal_match_tx }; -ksock_proto_t ksocknal_protocol_v2x = { +struct ksock_proto ksocknal_protocol_v2x = { .pro_version = KSOCK_PROTO_V2, .pro_send_hello = ksocknal_send_hello_v2, .pro_recv_hello = ksocknal_recv_hello_v2, @@ -781,7 +781,7 @@ ksock_proto_t ksocknal_protocol_v2x = { .pro_match_tx = ksocknal_match_tx }; -ksock_proto_t ksocknal_protocol_v3x = { +struct ksock_proto ksocknal_protocol_v3x = { .pro_version = KSOCK_PROTO_V3, .pro_send_hello = ksocknal_send_hello_v2, .pro_recv_hello = ksocknal_recv_hello_v2, -- cgit v0.10.2 From ed4df35478b84c8873b1d3f50f23eecacd22d859 Mon Sep 17 00:00:00 2001 From: Oleg Drokin Date: Tue, 14 Jun 2016 23:33:39 -0400 Subject: staging/lustre: Remove the "Please contact SUN for GPL" from headers Since SUN is no longer around and there's no point in contacting them, just remove that whole thing. Copy of GPL is available online anyway (URLs to be updated in next patch). This patch was generated with: find drivers/staging/lustre -name "*.[ch]" -exec perl -0777 -i -pe 's/ \* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,\n \* CA 95054 USA or visit www.sun.com if you need additional information or\n \* have any questions.\n \*\n//igs' {} \; Signed-off-by: Oleg Drokin Reported-by: Xose Vazquez Perez Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/lustre/include/linux/libcfs/curproc.h b/drivers/staging/lustre/include/linux/libcfs/curproc.h index 1edfca5..c673dfc 100644 --- a/drivers/staging/lustre/include/linux/libcfs/curproc.h +++ b/drivers/staging/lustre/include/linux/libcfs/curproc.h @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/include/linux/libcfs/libcfs.h b/drivers/staging/lustre/include/linux/libcfs/libcfs.h index 4141afb..c93d58e 100644 --- a/drivers/staging/lustre/include/linux/libcfs/libcfs.h +++ b/drivers/staging/lustre/include/linux/libcfs/libcfs.h @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/include/linux/libcfs/libcfs_debug.h b/drivers/staging/lustre/include/linux/libcfs/libcfs_debug.h index 455c54d..ae8175c 100644 --- a/drivers/staging/lustre/include/linux/libcfs/libcfs_debug.h +++ b/drivers/staging/lustre/include/linux/libcfs/libcfs_debug.h @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/include/linux/libcfs/libcfs_hash.h b/drivers/staging/lustre/include/linux/libcfs/libcfs_hash.h index 119986b..6a4387b 100644 --- a/drivers/staging/lustre/include/linux/libcfs/libcfs_hash.h +++ b/drivers/staging/lustre/include/linux/libcfs/libcfs_hash.h @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/include/linux/libcfs/libcfs_ioctl.h b/drivers/staging/lustre/include/linux/libcfs/libcfs_ioctl.h index 4b9102b..9bdff3f 100644 --- a/drivers/staging/lustre/include/linux/libcfs/libcfs_ioctl.h +++ b/drivers/staging/lustre/include/linux/libcfs/libcfs_ioctl.h @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/include/linux/libcfs/libcfs_prim.h b/drivers/staging/lustre/include/linux/libcfs/libcfs_prim.h index ac4e8cf..881aae0 100644 --- a/drivers/staging/lustre/include/linux/libcfs/libcfs_prim.h +++ b/drivers/staging/lustre/include/linux/libcfs/libcfs_prim.h @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/include/linux/libcfs/libcfs_private.h b/drivers/staging/lustre/include/linux/libcfs/libcfs_private.h index 2fd2a96..c44e11d 100644 --- a/drivers/staging/lustre/include/linux/libcfs/libcfs_private.h +++ b/drivers/staging/lustre/include/linux/libcfs/libcfs_private.h @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/include/linux/libcfs/libcfs_string.h b/drivers/staging/lustre/include/linux/libcfs/libcfs_string.h index e02cde5..03939ce 100644 --- a/drivers/staging/lustre/include/linux/libcfs/libcfs_string.h +++ b/drivers/staging/lustre/include/linux/libcfs/libcfs_string.h @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/include/linux/libcfs/libcfs_time.h b/drivers/staging/lustre/include/linux/libcfs/libcfs_time.h index 2c7ec2d..3f0ec7a 100644 --- a/drivers/staging/lustre/include/linux/libcfs/libcfs_time.h +++ b/drivers/staging/lustre/include/linux/libcfs/libcfs_time.h @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/include/linux/libcfs/libcfs_workitem.h b/drivers/staging/lustre/include/linux/libcfs/libcfs_workitem.h index f9b20c5..5ff23bb 100644 --- a/drivers/staging/lustre/include/linux/libcfs/libcfs_workitem.h +++ b/drivers/staging/lustre/include/linux/libcfs/libcfs_workitem.h @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/include/linux/libcfs/linux/libcfs.h b/drivers/staging/lustre/include/linux/libcfs/linux/libcfs.h index a268ef7..3652119 100644 --- a/drivers/staging/lustre/include/linux/libcfs/linux/libcfs.h +++ b/drivers/staging/lustre/include/linux/libcfs/linux/libcfs.h @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/include/linux/libcfs/linux/linux-time.h b/drivers/staging/lustre/include/linux/libcfs/linux/linux-time.h index 7656b09..887811b 100644 --- a/drivers/staging/lustre/include/linux/libcfs/linux/linux-time.h +++ b/drivers/staging/lustre/include/linux/libcfs/linux/linux-time.h @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c index 3f3a9c1..f0c0669 100644 --- a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c +++ b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.h b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.h index 4bac2b7..69711ee 100644 --- a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.h +++ b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.h @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd_cb.c b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd_cb.c index b3cf62f..5dde5ff 100644 --- a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd_cb.c +++ b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd_cb.c @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd_modparams.c b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd_modparams.c index fdc2f3b..24de544 100644 --- a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd_modparams.c +++ b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd_modparams.c @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lnet/klnds/socklnd/socklnd.c b/drivers/staging/lustre/lnet/klnds/socklnd/socklnd.c index 0fdc37c..67d8bf2 100644 --- a/drivers/staging/lustre/lnet/klnds/socklnd/socklnd.c +++ b/drivers/staging/lustre/lnet/klnds/socklnd/socklnd.c @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lnet/klnds/socklnd/socklnd_lib.c b/drivers/staging/lustre/lnet/klnds/socklnd/socklnd_lib.c index 44d417b..defe041 100644 --- a/drivers/staging/lustre/lnet/klnds/socklnd/socklnd_lib.c +++ b/drivers/staging/lustre/lnet/klnds/socklnd/socklnd_lib.c @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lnet/libcfs/debug.c b/drivers/staging/lustre/lnet/libcfs/debug.c index 8c260c3..0079a4c 100644 --- a/drivers/staging/lustre/lnet/libcfs/debug.c +++ b/drivers/staging/lustre/lnet/libcfs/debug.c @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lnet/libcfs/hash.c b/drivers/staging/lustre/lnet/libcfs/hash.c index cc45ed8..db51124 100644 --- a/drivers/staging/lustre/lnet/libcfs/hash.c +++ b/drivers/staging/lustre/lnet/libcfs/hash.c @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lnet/libcfs/libcfs_string.c b/drivers/staging/lustre/lnet/libcfs/libcfs_string.c index 50ac153..750691c 100644 --- a/drivers/staging/lustre/lnet/libcfs/libcfs_string.c +++ b/drivers/staging/lustre/lnet/libcfs/libcfs_string.c @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lnet/libcfs/linux/linux-curproc.c b/drivers/staging/lustre/lnet/libcfs/linux/linux-curproc.c index 13d31e8..4fe58dd 100644 --- a/drivers/staging/lustre/lnet/libcfs/linux/linux-curproc.c +++ b/drivers/staging/lustre/lnet/libcfs/linux/linux-curproc.c @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lnet/libcfs/linux/linux-debug.c b/drivers/staging/lustre/lnet/libcfs/linux/linux-debug.c index 638e4b3..808d09b 100644 --- a/drivers/staging/lustre/lnet/libcfs/linux/linux-debug.c +++ b/drivers/staging/lustre/lnet/libcfs/linux/linux-debug.c @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lnet/libcfs/linux/linux-module.c b/drivers/staging/lustre/lnet/libcfs/linux/linux-module.c index d89f71e..8caee5b 100644 --- a/drivers/staging/lustre/lnet/libcfs/linux/linux-module.c +++ b/drivers/staging/lustre/lnet/libcfs/linux/linux-module.c @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lnet/libcfs/linux/linux-prim.c b/drivers/staging/lustre/lnet/libcfs/linux/linux-prim.c index bbe19a6..c1152e6 100644 --- a/drivers/staging/lustre/lnet/libcfs/linux/linux-prim.c +++ b/drivers/staging/lustre/lnet/libcfs/linux/linux-prim.c @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lnet/libcfs/linux/linux-tracefile.c b/drivers/staging/lustre/lnet/libcfs/linux/linux-tracefile.c index 91c2ae8..6c9e3976 100644 --- a/drivers/staging/lustre/lnet/libcfs/linux/linux-tracefile.c +++ b/drivers/staging/lustre/lnet/libcfs/linux/linux-tracefile.c @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lnet/libcfs/module.c b/drivers/staging/lustre/lnet/libcfs/module.c index f2d0411..065f968 100644 --- a/drivers/staging/lustre/lnet/libcfs/module.c +++ b/drivers/staging/lustre/lnet/libcfs/module.c @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lnet/libcfs/prng.c b/drivers/staging/lustre/lnet/libcfs/prng.c index c75ae9a..f2e8426 100644 --- a/drivers/staging/lustre/lnet/libcfs/prng.c +++ b/drivers/staging/lustre/lnet/libcfs/prng.c @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lnet/libcfs/tracefile.c b/drivers/staging/lustre/lnet/libcfs/tracefile.c index 7739b94..ba0e7c3 100644 --- a/drivers/staging/lustre/lnet/libcfs/tracefile.c +++ b/drivers/staging/lustre/lnet/libcfs/tracefile.c @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lnet/libcfs/tracefile.h b/drivers/staging/lustre/lnet/libcfs/tracefile.h index ac84e7f..ae1c614 100644 --- a/drivers/staging/lustre/lnet/libcfs/tracefile.h +++ b/drivers/staging/lustre/lnet/libcfs/tracefile.h @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lnet/libcfs/workitem.c b/drivers/staging/lustre/lnet/libcfs/workitem.c index 92236ae..c51f389 100644 --- a/drivers/staging/lustre/lnet/libcfs/workitem.c +++ b/drivers/staging/lustre/lnet/libcfs/workitem.c @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lnet/lnet/acceptor.c b/drivers/staging/lustre/lnet/lnet/acceptor.c index 1452bb3..4456286 100644 --- a/drivers/staging/lustre/lnet/lnet/acceptor.c +++ b/drivers/staging/lustre/lnet/lnet/acceptor.c @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lnet/lnet/api-ni.c b/drivers/staging/lustre/lnet/lnet/api-ni.c index fe0dbe7..7662c3b 100644 --- a/drivers/staging/lustre/lnet/lnet/api-ni.c +++ b/drivers/staging/lustre/lnet/lnet/api-ni.c @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lnet/lnet/config.c b/drivers/staging/lustre/lnet/lnet/config.c index 480cc9c..358e5cf 100644 --- a/drivers/staging/lustre/lnet/lnet/config.c +++ b/drivers/staging/lustre/lnet/lnet/config.c @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lnet/lnet/lib-eq.c b/drivers/staging/lustre/lnet/lnet/lib-eq.c index adbcadb..d04c687 100644 --- a/drivers/staging/lustre/lnet/lnet/lib-eq.c +++ b/drivers/staging/lustre/lnet/lnet/lib-eq.c @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lnet/lnet/lib-md.c b/drivers/staging/lustre/lnet/lnet/lib-md.c index 75d3121..51145f1 100644 --- a/drivers/staging/lustre/lnet/lnet/lib-md.c +++ b/drivers/staging/lustre/lnet/lnet/lib-md.c @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lnet/lnet/lib-me.c b/drivers/staging/lustre/lnet/lnet/lib-me.c index e671aed..1c370f4 100644 --- a/drivers/staging/lustre/lnet/lnet/lib-me.c +++ b/drivers/staging/lustre/lnet/lnet/lib-me.c @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lnet/lnet/lib-move.c b/drivers/staging/lustre/lnet/lnet/lib-move.c index c5d5bed..f5c6eac 100644 --- a/drivers/staging/lustre/lnet/lnet/lib-move.c +++ b/drivers/staging/lustre/lnet/lnet/lib-move.c @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lnet/lnet/lib-msg.c b/drivers/staging/lustre/lnet/lnet/lib-msg.c index f879d7f..77ae4e6 100644 --- a/drivers/staging/lustre/lnet/lnet/lib-msg.c +++ b/drivers/staging/lustre/lnet/lnet/lib-msg.c @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lnet/lnet/lo.c b/drivers/staging/lustre/lnet/lnet/lo.c index 468eda6..6441ef3 100644 --- a/drivers/staging/lustre/lnet/lnet/lo.c +++ b/drivers/staging/lustre/lnet/lnet/lo.c @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lnet/lnet/module.c b/drivers/staging/lustre/lnet/lnet/module.c index 246b5c1..40f3c52 100644 --- a/drivers/staging/lustre/lnet/lnet/module.c +++ b/drivers/staging/lustre/lnet/lnet/module.c @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lnet/lnet/nidstrings.c b/drivers/staging/lustre/lnet/lnet/nidstrings.c index ebf468f..74bfda1 100644 --- a/drivers/staging/lustre/lnet/lnet/nidstrings.c +++ b/drivers/staging/lustre/lnet/lnet/nidstrings.c @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lnet/lnet/peer.c b/drivers/staging/lustre/lnet/lnet/peer.c index b026fee..5fde05a 100644 --- a/drivers/staging/lustre/lnet/lnet/peer.c +++ b/drivers/staging/lustre/lnet/lnet/peer.c @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lnet/selftest/brw_test.c b/drivers/staging/lustre/lnet/selftest/brw_test.c index a63d86c..6e25e1a 100644 --- a/drivers/staging/lustre/lnet/selftest/brw_test.c +++ b/drivers/staging/lustre/lnet/selftest/brw_test.c @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lnet/selftest/conctl.c b/drivers/staging/lustre/lnet/selftest/conctl.c index 408c614..9a22f33 100644 --- a/drivers/staging/lustre/lnet/selftest/conctl.c +++ b/drivers/staging/lustre/lnet/selftest/conctl.c @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lnet/selftest/conrpc.c b/drivers/staging/lustre/lnet/selftest/conrpc.c index 6f68758..e649d37 100644 --- a/drivers/staging/lustre/lnet/selftest/conrpc.c +++ b/drivers/staging/lustre/lnet/selftest/conrpc.c @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lnet/selftest/conrpc.h b/drivers/staging/lustre/lnet/selftest/conrpc.h index 90c3385..1d8bb63 100644 --- a/drivers/staging/lustre/lnet/selftest/conrpc.h +++ b/drivers/staging/lustre/lnet/selftest/conrpc.h @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lnet/selftest/console.c b/drivers/staging/lustre/lnet/selftest/console.c index a03e52d..31001f4 100644 --- a/drivers/staging/lustre/lnet/selftest/console.c +++ b/drivers/staging/lustre/lnet/selftest/console.c @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lnet/selftest/console.h b/drivers/staging/lustre/lnet/selftest/console.h index becd22e..b099946 100644 --- a/drivers/staging/lustre/lnet/selftest/console.h +++ b/drivers/staging/lustre/lnet/selftest/console.h @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lnet/selftest/framework.c b/drivers/staging/lustre/lnet/selftest/framework.c index 30e4f71..0d53307 100644 --- a/drivers/staging/lustre/lnet/selftest/framework.c +++ b/drivers/staging/lustre/lnet/selftest/framework.c @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lnet/selftest/module.c b/drivers/staging/lustre/lnet/selftest/module.c index cc046b1..b6a3bdf 100644 --- a/drivers/staging/lustre/lnet/selftest/module.c +++ b/drivers/staging/lustre/lnet/selftest/module.c @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lnet/selftest/ping_test.c b/drivers/staging/lustre/lnet/selftest/ping_test.c index ad26fe9..3030c07 100644 --- a/drivers/staging/lustre/lnet/selftest/ping_test.c +++ b/drivers/staging/lustre/lnet/selftest/ping_test.c @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lnet/selftest/rpc.c b/drivers/staging/lustre/lnet/selftest/rpc.c index 3c45a7c..e7aba01 100644 --- a/drivers/staging/lustre/lnet/selftest/rpc.c +++ b/drivers/staging/lustre/lnet/selftest/rpc.c @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lnet/selftest/rpc.h b/drivers/staging/lustre/lnet/selftest/rpc.h index c9b904c..3254f5d 100644 --- a/drivers/staging/lustre/lnet/selftest/rpc.h +++ b/drivers/staging/lustre/lnet/selftest/rpc.h @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lnet/selftest/selftest.h b/drivers/staging/lustre/lnet/selftest/selftest.h index 4eac1c9..4a1d2b2 100644 --- a/drivers/staging/lustre/lnet/selftest/selftest.h +++ b/drivers/staging/lustre/lnet/selftest/selftest.h @@ -18,10 +18,6 @@ * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * copy of GPLv2]. * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lnet/selftest/timer.c b/drivers/staging/lustre/lnet/selftest/timer.c index b6c4aae..c73ded9 100644 --- a/drivers/staging/lustre/lnet/selftest/timer.c +++ b/drivers/staging/lustre/lnet/selftest/timer.c @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lnet/selftest/timer.h b/drivers/staging/lustre/lnet/selftest/timer.h index f1fbebd..e86e44e 100644 --- a/drivers/staging/lustre/lnet/selftest/timer.h +++ b/drivers/staging/lustre/lnet/selftest/timer.h @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/fid/fid_internal.h b/drivers/staging/lustre/lustre/fid/fid_internal.h index b79a813..d6aebb3 100644 --- a/drivers/staging/lustre/lustre/fid/fid_internal.h +++ b/drivers/staging/lustre/lustre/fid/fid_internal.h @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/fid/fid_lib.c b/drivers/staging/lustre/lustre/fid/fid_lib.c index dd65159..ee7b272 100644 --- a/drivers/staging/lustre/lustre/fid/fid_lib.c +++ b/drivers/staging/lustre/lustre/fid/fid_lib.c @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/fid/fid_request.c b/drivers/staging/lustre/lustre/fid/fid_request.c index 9db21ba..00b19c7 100644 --- a/drivers/staging/lustre/lustre/fid/fid_request.c +++ b/drivers/staging/lustre/lustre/fid/fid_request.c @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/fid/lproc_fid.c b/drivers/staging/lustre/lustre/fid/lproc_fid.c index 1f0e786..0103af5 100644 --- a/drivers/staging/lustre/lustre/fid/lproc_fid.c +++ b/drivers/staging/lustre/lustre/fid/lproc_fid.c @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/fld/fld_cache.c b/drivers/staging/lustre/lustre/fld/fld_cache.c index 5a04e99..cb33d41 100644 --- a/drivers/staging/lustre/lustre/fld/fld_cache.c +++ b/drivers/staging/lustre/lustre/fld/fld_cache.c @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/fld/fld_internal.h b/drivers/staging/lustre/lustre/fld/fld_internal.h index 75d6a48..a85d86a 100644 --- a/drivers/staging/lustre/lustre/fld/fld_internal.h +++ b/drivers/staging/lustre/lustre/fld/fld_internal.h @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/fld/fld_request.c b/drivers/staging/lustre/lustre/fld/fld_request.c index 304c0ec..5f43af4 100644 --- a/drivers/staging/lustre/lustre/fld/fld_request.c +++ b/drivers/staging/lustre/lustre/fld/fld_request.c @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/fld/lproc_fld.c b/drivers/staging/lustre/lustre/fld/lproc_fld.c index ca898be..1b96880 100644 --- a/drivers/staging/lustre/lustre/fld/lproc_fld.c +++ b/drivers/staging/lustre/lustre/fld/lproc_fld.c @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/include/cl_object.h b/drivers/staging/lustre/lustre/include/cl_object.h index d4c33dd..a5a28f5 100644 --- a/drivers/staging/lustre/lustre/include/cl_object.h +++ b/drivers/staging/lustre/lustre/include/cl_object.h @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/include/interval_tree.h b/drivers/staging/lustre/lustre/include/interval_tree.h index f6df3f3..64cab4b 100644 --- a/drivers/staging/lustre/lustre/include/interval_tree.h +++ b/drivers/staging/lustre/lustre/include/interval_tree.h @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/include/linux/lustre_compat25.h b/drivers/staging/lustre/lustre/include/linux/lustre_compat25.h index 79d8f93..7690fa7 100644 --- a/drivers/staging/lustre/lustre/include/linux/lustre_compat25.h +++ b/drivers/staging/lustre/lustre/include/linux/lustre_compat25.h @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/include/linux/lustre_lite.h b/drivers/staging/lustre/lustre/include/linux/lustre_lite.h index 3420cfd..abefa93 100644 --- a/drivers/staging/lustre/lustre/include/linux/lustre_lite.h +++ b/drivers/staging/lustre/lustre/include/linux/lustre_lite.h @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/include/linux/lustre_patchless_compat.h b/drivers/staging/lustre/lustre/include/linux/lustre_patchless_compat.h index c6c7f54..6d138b2 100644 --- a/drivers/staging/lustre/lustre/include/linux/lustre_patchless_compat.h +++ b/drivers/staging/lustre/lustre/include/linux/lustre_patchless_compat.h @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/include/linux/lustre_user.h b/drivers/staging/lustre/lustre/include/linux/lustre_user.h index 9cc2849..7403139 100644 --- a/drivers/staging/lustre/lustre/include/linux/lustre_user.h +++ b/drivers/staging/lustre/lustre/include/linux/lustre_user.h @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/include/lprocfs_status.h b/drivers/staging/lustre/lustre/include/lprocfs_status.h index 4146c9c..4f5ab54 100644 --- a/drivers/staging/lustre/lustre/include/lprocfs_status.h +++ b/drivers/staging/lustre/lustre/include/lprocfs_status.h @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/include/lu_object.h b/drivers/staging/lustre/lustre/include/lu_object.h index 2816512..b7bfe39 100644 --- a/drivers/staging/lustre/lustre/include/lu_object.h +++ b/drivers/staging/lustre/lustre/include/lu_object.h @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/include/lustre/ll_fiemap.h b/drivers/staging/lustre/lustre/include/lustre/ll_fiemap.h index 07d45de..664f135 100644 --- a/drivers/staging/lustre/lustre/include/lustre/ll_fiemap.h +++ b/drivers/staging/lustre/lustre/include/lustre/ll_fiemap.h @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/include/lustre/lustre_idl.h b/drivers/staging/lustre/lustre/include/lustre/lustre_idl.h index 9c53c17..e5031b1 100644 --- a/drivers/staging/lustre/lustre/include/lustre/lustre_idl.h +++ b/drivers/staging/lustre/lustre/include/lustre/lustre_idl.h @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/include/lustre/lustre_user.h b/drivers/staging/lustre/lustre/include/lustre/lustre_user.h index 59ba48a..3b48ba5 100644 --- a/drivers/staging/lustre/lustre/include/lustre/lustre_user.h +++ b/drivers/staging/lustre/lustre/include/lustre/lustre_user.h @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/include/lustre_acl.h b/drivers/staging/lustre/lustre/include/lustre_acl.h index aa4cfa7..9773db7 100644 --- a/drivers/staging/lustre/lustre/include/lustre_acl.h +++ b/drivers/staging/lustre/lustre/include/lustre_acl.h @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/include/lustre_cfg.h b/drivers/staging/lustre/lustre/include/lustre_cfg.h index e229e91..f532af6 100644 --- a/drivers/staging/lustre/lustre/include/lustre_cfg.h +++ b/drivers/staging/lustre/lustre/include/lustre_cfg.h @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/include/lustre_debug.h b/drivers/staging/lustre/lustre/include/lustre_debug.h index 8a08941..bd531ff 100644 --- a/drivers/staging/lustre/lustre/include/lustre_debug.h +++ b/drivers/staging/lustre/lustre/include/lustre_debug.h @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/include/lustre_disk.h b/drivers/staging/lustre/lustre/include/lustre_disk.h index b36821f..f30c601 100644 --- a/drivers/staging/lustre/lustre/include/lustre_disk.h +++ b/drivers/staging/lustre/lustre/include/lustre_disk.h @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/include/lustre_dlm.h b/drivers/staging/lustre/lustre/include/lustre_dlm.h index 9cade14..bdc1da7 100644 --- a/drivers/staging/lustre/lustre/include/lustre_dlm.h +++ b/drivers/staging/lustre/lustre/include/lustre_dlm.h @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/include/lustre_eacl.h b/drivers/staging/lustre/lustre/include/lustre_eacl.h index 0b66593..caab6e3 100644 --- a/drivers/staging/lustre/lustre/include/lustre_eacl.h +++ b/drivers/staging/lustre/lustre/include/lustre_eacl.h @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/include/lustre_export.h b/drivers/staging/lustre/lustre/include/lustre_export.h index 3014d27..41b6a7c 100644 --- a/drivers/staging/lustre/lustre/include/lustre_export.h +++ b/drivers/staging/lustre/lustre/include/lustre_export.h @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/include/lustre_fid.h b/drivers/staging/lustre/lustre/include/lustre_fid.h index 12e8b58..e3794d6 100644 --- a/drivers/staging/lustre/lustre/include/lustre_fid.h +++ b/drivers/staging/lustre/lustre/include/lustre_fid.h @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/include/lustre_fld.h b/drivers/staging/lustre/lustre/include/lustre_fld.h index 4cf2b0e..6a91cbc 100644 --- a/drivers/staging/lustre/lustre/include/lustre_fld.h +++ b/drivers/staging/lustre/lustre/include/lustre_fld.h @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/include/lustre_ha.h b/drivers/staging/lustre/lustre/include/lustre_ha.h index 5488a69..152b0ee 100644 --- a/drivers/staging/lustre/lustre/include/lustre_ha.h +++ b/drivers/staging/lustre/lustre/include/lustre_ha.h @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/include/lustre_handles.h b/drivers/staging/lustre/lustre/include/lustre_handles.h index 27f169d..c1906c2 100644 --- a/drivers/staging/lustre/lustre/include/lustre_handles.h +++ b/drivers/staging/lustre/lustre/include/lustre_handles.h @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/include/lustre_import.h b/drivers/staging/lustre/lustre/include/lustre_import.h index 8325c82..d4f7680 100644 --- a/drivers/staging/lustre/lustre/include/lustre_import.h +++ b/drivers/staging/lustre/lustre/include/lustre_import.h @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/include/lustre_intent.h b/drivers/staging/lustre/lustre/include/lustre_intent.h index c491d52..d5b15a4 100644 --- a/drivers/staging/lustre/lustre/include/lustre_intent.h +++ b/drivers/staging/lustre/lustre/include/lustre_intent.h @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/include/lustre_lib.h b/drivers/staging/lustre/lustre/include/lustre_lib.h index 00b9767..f7b0ce8 100644 --- a/drivers/staging/lustre/lustre/include/lustre_lib.h +++ b/drivers/staging/lustre/lustre/include/lustre_lib.h @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/include/lustre_lite.h b/drivers/staging/lustre/lustre/include/lustre_lite.h index fcc5ebb..bd328e5 100644 --- a/drivers/staging/lustre/lustre/include/lustre_lite.h +++ b/drivers/staging/lustre/lustre/include/lustre_lite.h @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/include/lustre_log.h b/drivers/staging/lustre/lustre/include/lustre_log.h index 49618e1..7a3940a 100644 --- a/drivers/staging/lustre/lustre/include/lustre_log.h +++ b/drivers/staging/lustre/lustre/include/lustre_log.h @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/include/lustre_mdc.h b/drivers/staging/lustre/lustre/include/lustre_mdc.h index f267ff8..cc4158c 100644 --- a/drivers/staging/lustre/lustre/include/lustre_mdc.h +++ b/drivers/staging/lustre/lustre/include/lustre_mdc.h @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/include/lustre_mds.h b/drivers/staging/lustre/lustre/include/lustre_mds.h index 95d27dd..9bcd3cd 100644 --- a/drivers/staging/lustre/lustre/include/lustre_mds.h +++ b/drivers/staging/lustre/lustre/include/lustre_mds.h @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/include/lustre_net.h b/drivers/staging/lustre/lustre/include/lustre_net.h index a7973d5..ce31181 100644 --- a/drivers/staging/lustre/lustre/include/lustre_net.h +++ b/drivers/staging/lustre/lustre/include/lustre_net.h @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/include/lustre_param.h b/drivers/staging/lustre/lustre/include/lustre_param.h index a42cf90..dc6f2b2 100644 --- a/drivers/staging/lustre/lustre/include/lustre_param.h +++ b/drivers/staging/lustre/lustre/include/lustre_param.h @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/include/lustre_req_layout.h b/drivers/staging/lustre/lustre/include/lustre_req_layout.h index 0aac439..acbc310 100644 --- a/drivers/staging/lustre/lustre/include/lustre_req_layout.h +++ b/drivers/staging/lustre/lustre/include/lustre_req_layout.h @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/include/lustre_sec.h b/drivers/staging/lustre/lustre/include/lustre_sec.h index 01b4e67..7ca6204 100644 --- a/drivers/staging/lustre/lustre/include/lustre_sec.h +++ b/drivers/staging/lustre/lustre/include/lustre_sec.h @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/include/obd.h b/drivers/staging/lustre/lustre/include/obd.h index 2d926e0..6c94fa4 100644 --- a/drivers/staging/lustre/lustre/include/obd.h +++ b/drivers/staging/lustre/lustre/include/obd.h @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/include/obd_cksum.h b/drivers/staging/lustre/lustre/include/obd_cksum.h index f6c18df..02705a5 100644 --- a/drivers/staging/lustre/lustre/include/obd_cksum.h +++ b/drivers/staging/lustre/lustre/include/obd_cksum.h @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/include/obd_class.h b/drivers/staging/lustre/lustre/include/obd_class.h index 32863bc..c7a71b2 100644 --- a/drivers/staging/lustre/lustre/include/obd_class.h +++ b/drivers/staging/lustre/lustre/include/obd_class.h @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/include/obd_support.h b/drivers/staging/lustre/lustre/include/obd_support.h index 60034d3..ce5be73 100644 --- a/drivers/staging/lustre/lustre/include/obd_support.h +++ b/drivers/staging/lustre/lustre/include/obd_support.h @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/ldlm/interval_tree.c b/drivers/staging/lustre/lustre/ldlm/interval_tree.c index 3230606..59bb066 100644 --- a/drivers/staging/lustre/lustre/ldlm/interval_tree.c +++ b/drivers/staging/lustre/lustre/ldlm/interval_tree.c @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/ldlm/l_lock.c b/drivers/staging/lustre/lustre/ldlm/l_lock.c index 621323f..c6f7dfd 100644 --- a/drivers/staging/lustre/lustre/ldlm/l_lock.c +++ b/drivers/staging/lustre/lustre/ldlm/l_lock.c @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/ldlm/ldlm_extent.c b/drivers/staging/lustre/lustre/ldlm/ldlm_extent.c index cf1f178..16c1621 100644 --- a/drivers/staging/lustre/lustre/ldlm/ldlm_extent.c +++ b/drivers/staging/lustre/lustre/ldlm/ldlm_extent.c @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/ldlm/ldlm_flock.c b/drivers/staging/lustre/lustre/ldlm/ldlm_flock.c index 349bfcc..6c0dd7a 100644 --- a/drivers/staging/lustre/lustre/ldlm/ldlm_flock.c +++ b/drivers/staging/lustre/lustre/ldlm/ldlm_flock.c @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/ldlm/ldlm_inodebits.c b/drivers/staging/lustre/lustre/ldlm/ldlm_inodebits.c index b1bed1e..d98243d 100644 --- a/drivers/staging/lustre/lustre/ldlm/ldlm_inodebits.c +++ b/drivers/staging/lustre/lustre/ldlm/ldlm_inodebits.c @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/ldlm/ldlm_internal.h b/drivers/staging/lustre/lustre/ldlm/ldlm_internal.h index 32f227f..cc5e654 100644 --- a/drivers/staging/lustre/lustre/ldlm/ldlm_internal.h +++ b/drivers/staging/lustre/lustre/ldlm/ldlm_internal.h @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/ldlm/ldlm_lib.c b/drivers/staging/lustre/lustre/ldlm/ldlm_lib.c index b6a90b0..1a7eee3 100644 --- a/drivers/staging/lustre/lustre/ldlm/ldlm_lib.c +++ b/drivers/staging/lustre/lustre/ldlm/ldlm_lib.c @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/ldlm/ldlm_lock.c b/drivers/staging/lustre/lustre/ldlm/ldlm_lock.c index bff94ea..88e9192 100644 --- a/drivers/staging/lustre/lustre/ldlm/ldlm_lock.c +++ b/drivers/staging/lustre/lustre/ldlm/ldlm_lock.c @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/ldlm/ldlm_lockd.c b/drivers/staging/lustre/lustre/ldlm/ldlm_lockd.c index 3303ffa..1da0eb2 100644 --- a/drivers/staging/lustre/lustre/ldlm/ldlm_lockd.c +++ b/drivers/staging/lustre/lustre/ldlm/ldlm_lockd.c @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/ldlm/ldlm_plain.c b/drivers/staging/lustre/lustre/ldlm/ldlm_plain.c index 0c1965d..621a490 100644 --- a/drivers/staging/lustre/lustre/ldlm/ldlm_plain.c +++ b/drivers/staging/lustre/lustre/ldlm/ldlm_plain.c @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/ldlm/ldlm_pool.c b/drivers/staging/lustre/lustre/ldlm/ldlm_pool.c index b913ba9..1d9ca31 100644 --- a/drivers/staging/lustre/lustre/ldlm/ldlm_pool.c +++ b/drivers/staging/lustre/lustre/ldlm/ldlm_pool.c @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/ldlm/ldlm_request.c b/drivers/staging/lustre/lustre/ldlm/ldlm_request.c index 107314e..f6b30f6 100644 --- a/drivers/staging/lustre/lustre/ldlm/ldlm_request.c +++ b/drivers/staging/lustre/lustre/ldlm/ldlm_request.c @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/ldlm/ldlm_resource.c b/drivers/staging/lustre/lustre/ldlm/ldlm_resource.c index e99c89c..771c1f8 100644 --- a/drivers/staging/lustre/lustre/ldlm/ldlm_resource.c +++ b/drivers/staging/lustre/lustre/ldlm/ldlm_resource.c @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/llite/dcache.c b/drivers/staging/lustre/lustre/llite/dcache.c index 1b6f82a..908bdc6 100644 --- a/drivers/staging/lustre/lustre/llite/dcache.c +++ b/drivers/staging/lustre/lustre/llite/dcache.c @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/llite/dir.c b/drivers/staging/lustre/lustre/llite/dir.c index 85c50e0..8854029a 100644 --- a/drivers/staging/lustre/lustre/llite/dir.c +++ b/drivers/staging/lustre/lustre/llite/dir.c @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/llite/file.c b/drivers/staging/lustre/lustre/llite/file.c index 26c6cd6..104129b 100644 --- a/drivers/staging/lustre/lustre/llite/file.c +++ b/drivers/staging/lustre/lustre/llite/file.c @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/llite/glimpse.c b/drivers/staging/lustre/lustre/llite/glimpse.c index d8ea754..8788ee0 100644 --- a/drivers/staging/lustre/lustre/llite/glimpse.c +++ b/drivers/staging/lustre/lustre/llite/glimpse.c @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/llite/lcommon_cl.c b/drivers/staging/lustre/lustre/llite/lcommon_cl.c index 6c00715..28b7482 100644 --- a/drivers/staging/lustre/lustre/llite/lcommon_cl.c +++ b/drivers/staging/lustre/lustre/llite/lcommon_cl.c @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/llite/lcommon_misc.c b/drivers/staging/lustre/lustre/llite/lcommon_misc.c index 12f3e71..e45bd6d 100644 --- a/drivers/staging/lustre/lustre/llite/lcommon_misc.c +++ b/drivers/staging/lustre/lustre/llite/lcommon_misc.c @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/llite/llite_close.c b/drivers/staging/lustre/lustre/llite/llite_close.c index 2df551d..2e2abc7 100644 --- a/drivers/staging/lustre/lustre/llite/llite_close.c +++ b/drivers/staging/lustre/lustre/llite/llite_close.c @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/llite/llite_internal.h b/drivers/staging/lustre/lustre/llite/llite_internal.h index 7fb949a..f541634 100644 --- a/drivers/staging/lustre/lustre/llite/llite_internal.h +++ b/drivers/staging/lustre/lustre/llite/llite_internal.h @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/llite/llite_lib.c b/drivers/staging/lustre/lustre/llite/llite_lib.c index b260f60..f513b74 100644 --- a/drivers/staging/lustre/lustre/llite/llite_lib.c +++ b/drivers/staging/lustre/lustre/llite/llite_lib.c @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/llite/llite_mmap.c b/drivers/staging/lustre/lustre/llite/llite_mmap.c index 7610799..b569df3 100644 --- a/drivers/staging/lustre/lustre/llite/llite_mmap.c +++ b/drivers/staging/lustre/lustre/llite/llite_mmap.c @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/llite/llite_nfs.c b/drivers/staging/lustre/lustre/llite/llite_nfs.c index c1eef61..086e827 100644 --- a/drivers/staging/lustre/lustre/llite/llite_nfs.c +++ b/drivers/staging/lustre/lustre/llite/llite_nfs.c @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/llite/llite_rmtacl.c b/drivers/staging/lustre/lustre/llite/llite_rmtacl.c index 8509b07..bae3ff0 100644 --- a/drivers/staging/lustre/lustre/llite/llite_rmtacl.c +++ b/drivers/staging/lustre/lustre/llite/llite_rmtacl.c @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/llite/lproc_llite.c b/drivers/staging/lustre/lustre/llite/lproc_llite.c index 55d62eb..2b3a777 100644 --- a/drivers/staging/lustre/lustre/llite/lproc_llite.c +++ b/drivers/staging/lustre/lustre/llite/lproc_llite.c @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/llite/namei.c b/drivers/staging/lustre/lustre/llite/namei.c index 95643bc..b7ec512 100644 --- a/drivers/staging/lustre/lustre/llite/namei.c +++ b/drivers/staging/lustre/lustre/llite/namei.c @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/llite/remote_perm.c b/drivers/staging/lustre/lustre/llite/remote_perm.c index e9d2531..0b96175 100644 --- a/drivers/staging/lustre/lustre/llite/remote_perm.c +++ b/drivers/staging/lustre/lustre/llite/remote_perm.c @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/llite/rw.c b/drivers/staging/lustre/lustre/llite/rw.c index fa42869..df6cb54 100644 --- a/drivers/staging/lustre/lustre/llite/rw.c +++ b/drivers/staging/lustre/lustre/llite/rw.c @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/llite/rw26.c b/drivers/staging/lustre/lustre/llite/rw26.c index 947a4f5..d45fdcb 100644 --- a/drivers/staging/lustre/lustre/llite/rw26.c +++ b/drivers/staging/lustre/lustre/llite/rw26.c @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/llite/statahead.c b/drivers/staging/lustre/lustre/llite/statahead.c index 6322f88..d533954 100644 --- a/drivers/staging/lustre/lustre/llite/statahead.c +++ b/drivers/staging/lustre/lustre/llite/statahead.c @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/llite/super25.c b/drivers/staging/lustre/lustre/llite/super25.c index 415750b..f7f8e23 100644 --- a/drivers/staging/lustre/lustre/llite/super25.c +++ b/drivers/staging/lustre/lustre/llite/super25.c @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/llite/symlink.c b/drivers/staging/lustre/lustre/llite/symlink.c index 3fc736c..12f945e 100644 --- a/drivers/staging/lustre/lustre/llite/symlink.c +++ b/drivers/staging/lustre/lustre/llite/symlink.c @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/llite/vvp_dev.c b/drivers/staging/lustre/lustre/llite/vvp_dev.c index c63def9..da84d95 100644 --- a/drivers/staging/lustre/lustre/llite/vvp_dev.c +++ b/drivers/staging/lustre/lustre/llite/vvp_dev.c @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/llite/vvp_internal.h b/drivers/staging/lustre/lustre/llite/vvp_internal.h index 27b9b0a..6708841 100644 --- a/drivers/staging/lustre/lustre/llite/vvp_internal.h +++ b/drivers/staging/lustre/lustre/llite/vvp_internal.h @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/llite/vvp_io.c b/drivers/staging/lustre/lustre/llite/vvp_io.c index 763d336..2200d57 100644 --- a/drivers/staging/lustre/lustre/llite/vvp_io.c +++ b/drivers/staging/lustre/lustre/llite/vvp_io.c @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/llite/vvp_lock.c b/drivers/staging/lustre/lustre/llite/vvp_lock.c index f5bd6c2..b5c307f 100644 --- a/drivers/staging/lustre/lustre/llite/vvp_lock.c +++ b/drivers/staging/lustre/lustre/llite/vvp_lock.c @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/llite/vvp_object.c b/drivers/staging/lustre/lustre/llite/vvp_object.c index 18c9df7..11c3004 100644 --- a/drivers/staging/lustre/lustre/llite/vvp_object.c +++ b/drivers/staging/lustre/lustre/llite/vvp_object.c @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/llite/vvp_page.c b/drivers/staging/lustre/lustre/llite/vvp_page.c index 6cd2af7..ae36c75 100644 --- a/drivers/staging/lustre/lustre/llite/vvp_page.c +++ b/drivers/staging/lustre/lustre/llite/vvp_page.c @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/llite/xattr.c b/drivers/staging/lustre/lustre/llite/xattr.c index 608014b..a286635 100644 --- a/drivers/staging/lustre/lustre/llite/xattr.c +++ b/drivers/staging/lustre/lustre/llite/xattr.c @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/lmv/lmv_fld.c b/drivers/staging/lustre/lustre/lmv/lmv_fld.c index 378691b..fcf1b1c 100644 --- a/drivers/staging/lustre/lustre/lmv/lmv_fld.c +++ b/drivers/staging/lustre/lustre/lmv/lmv_fld.c @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/lmv/lmv_intent.c b/drivers/staging/lustre/lustre/lmv/lmv_intent.c index e0958ea..bdf28cd 100644 --- a/drivers/staging/lustre/lustre/lmv/lmv_intent.c +++ b/drivers/staging/lustre/lustre/lmv/lmv_intent.c @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/lmv/lmv_internal.h b/drivers/staging/lustre/lustre/lmv/lmv_internal.h index 7007e4c..267deef 100644 --- a/drivers/staging/lustre/lustre/lmv/lmv_internal.h +++ b/drivers/staging/lustre/lustre/lmv/lmv_internal.h @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/lmv/lmv_obd.c b/drivers/staging/lustre/lustre/lmv/lmv_obd.c index 1d9875e..800033d 100644 --- a/drivers/staging/lustre/lustre/lmv/lmv_obd.c +++ b/drivers/staging/lustre/lustre/lmv/lmv_obd.c @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/lmv/lproc_lmv.c b/drivers/staging/lustre/lustre/lmv/lproc_lmv.c index b39e364..aa68623 100644 --- a/drivers/staging/lustre/lustre/lmv/lproc_lmv.c +++ b/drivers/staging/lustre/lustre/lmv/lproc_lmv.c @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/lov/lov_cl_internal.h b/drivers/staging/lustre/lustre/lov/lov_cl_internal.h index ac9744e..9a2e5e2 100644 --- a/drivers/staging/lustre/lustre/lov/lov_cl_internal.h +++ b/drivers/staging/lustre/lustre/lov/lov_cl_internal.h @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/lov/lov_dev.c b/drivers/staging/lustre/lustre/lov/lov_dev.c index dae8e89..21e3054 100644 --- a/drivers/staging/lustre/lustre/lov/lov_dev.c +++ b/drivers/staging/lustre/lustre/lov/lov_dev.c @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/lov/lov_ea.c b/drivers/staging/lustre/lustre/lov/lov_ea.c index 460f0fa..2f8972f 100644 --- a/drivers/staging/lustre/lustre/lov/lov_ea.c +++ b/drivers/staging/lustre/lustre/lov/lov_ea.c @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/lov/lov_internal.h b/drivers/staging/lustre/lustre/lov/lov_internal.h index eef9afa..55fb5bf 100644 --- a/drivers/staging/lustre/lustre/lov/lov_internal.h +++ b/drivers/staging/lustre/lustre/lov/lov_internal.h @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/lov/lov_io.c b/drivers/staging/lustre/lustre/lov/lov_io.c index 86cb3f8..cc70eeb 100644 --- a/drivers/staging/lustre/lustre/lov/lov_io.c +++ b/drivers/staging/lustre/lustre/lov/lov_io.c @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/lov/lov_lock.c b/drivers/staging/lustre/lustre/lov/lov_lock.c index 1b203d1..2d87cfa 100644 --- a/drivers/staging/lustre/lustre/lov/lov_lock.c +++ b/drivers/staging/lustre/lustre/lov/lov_lock.c @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/lov/lov_merge.c b/drivers/staging/lustre/lustre/lov/lov_merge.c index 56ef41d..f020656 100644 --- a/drivers/staging/lustre/lustre/lov/lov_merge.c +++ b/drivers/staging/lustre/lustre/lov/lov_merge.c @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/lov/lov_obd.c b/drivers/staging/lustre/lustre/lov/lov_obd.c index c179b31..9ca7e63 100644 --- a/drivers/staging/lustre/lustre/lov/lov_obd.c +++ b/drivers/staging/lustre/lustre/lov/lov_obd.c @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/lov/lov_object.c b/drivers/staging/lustre/lustre/lov/lov_object.c index 561d493..08f3d5c 100644 --- a/drivers/staging/lustre/lustre/lov/lov_object.c +++ b/drivers/staging/lustre/lustre/lov/lov_object.c @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/lov/lov_offset.c b/drivers/staging/lustre/lustre/lov/lov_offset.c index 7636bfa..2f568b5 100644 --- a/drivers/staging/lustre/lustre/lov/lov_offset.c +++ b/drivers/staging/lustre/lustre/lov/lov_offset.c @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/lov/lov_pack.c b/drivers/staging/lustre/lustre/lov/lov_pack.c index 0215ea5..69f4a68 100644 --- a/drivers/staging/lustre/lustre/lov/lov_pack.c +++ b/drivers/staging/lustre/lustre/lov/lov_pack.c @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/lov/lov_page.c b/drivers/staging/lustre/lustre/lov/lov_page.c index 0306f00..6c97e6f 100644 --- a/drivers/staging/lustre/lustre/lov/lov_page.c +++ b/drivers/staging/lustre/lustre/lov/lov_page.c @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/lov/lov_pool.c b/drivers/staging/lustre/lustre/lov/lov_pool.c index 690292e..75660c5 100644 --- a/drivers/staging/lustre/lustre/lov/lov_pool.c +++ b/drivers/staging/lustre/lustre/lov/lov_pool.c @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see [sun.com URL with a * copy of GPLv2]. * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/lov/lov_request.c b/drivers/staging/lustre/lustre/lov/lov_request.c index 1be4b92..83cd6e4 100644 --- a/drivers/staging/lustre/lustre/lov/lov_request.c +++ b/drivers/staging/lustre/lustre/lov/lov_request.c @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/lov/lovsub_dev.c b/drivers/staging/lustre/lustre/lov/lovsub_dev.c index 35f6b1d..cddf3d6 100644 --- a/drivers/staging/lustre/lustre/lov/lovsub_dev.c +++ b/drivers/staging/lustre/lustre/lov/lovsub_dev.c @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/lov/lovsub_io.c b/drivers/staging/lustre/lustre/lov/lovsub_io.c index 783ec68..c927406 100644 --- a/drivers/staging/lustre/lustre/lov/lovsub_io.c +++ b/drivers/staging/lustre/lustre/lov/lovsub_io.c @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/lov/lovsub_lock.c b/drivers/staging/lustre/lustre/lov/lovsub_lock.c index e92edfb..06bfdf9 100644 --- a/drivers/staging/lustre/lustre/lov/lovsub_lock.c +++ b/drivers/staging/lustre/lustre/lov/lovsub_lock.c @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/lov/lovsub_object.c b/drivers/staging/lustre/lustre/lov/lovsub_object.c index bcaae1e..a1a0f08 100644 --- a/drivers/staging/lustre/lustre/lov/lovsub_object.c +++ b/drivers/staging/lustre/lustre/lov/lovsub_object.c @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/lov/lovsub_page.c b/drivers/staging/lustre/lustre/lov/lovsub_page.c index 9badedc..e8e3475 100644 --- a/drivers/staging/lustre/lustre/lov/lovsub_page.c +++ b/drivers/staging/lustre/lustre/lov/lovsub_page.c @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/lov/lproc_lov.c b/drivers/staging/lustre/lustre/lov/lproc_lov.c index 0dcb6b6..c5f7aac 100644 --- a/drivers/staging/lustre/lustre/lov/lproc_lov.c +++ b/drivers/staging/lustre/lustre/lov/lproc_lov.c @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/mdc/lproc_mdc.c b/drivers/staging/lustre/lustre/mdc/lproc_mdc.c index 5c7a15d..95a8fcd 100644 --- a/drivers/staging/lustre/lustre/mdc/lproc_mdc.c +++ b/drivers/staging/lustre/lustre/mdc/lproc_mdc.c @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/mdc/mdc_internal.h b/drivers/staging/lustre/lustre/mdc/mdc_internal.h index c5519ae..cd57233 100644 --- a/drivers/staging/lustre/lustre/mdc/mdc_internal.h +++ b/drivers/staging/lustre/lustre/mdc/mdc_internal.h @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/mdc/mdc_lib.c b/drivers/staging/lustre/lustre/mdc/mdc_lib.c index 856c54e..8411729 100644 --- a/drivers/staging/lustre/lustre/mdc/mdc_lib.c +++ b/drivers/staging/lustre/lustre/mdc/mdc_lib.c @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/mdc/mdc_locks.c b/drivers/staging/lustre/lustre/mdc/mdc_locks.c index 3b1bc91..c14c9df 100644 --- a/drivers/staging/lustre/lustre/mdc/mdc_locks.c +++ b/drivers/staging/lustre/lustre/mdc/mdc_locks.c @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/mdc/mdc_reint.c b/drivers/staging/lustre/lustre/mdc/mdc_reint.c index 4ef3db1..8380c56 100644 --- a/drivers/staging/lustre/lustre/mdc/mdc_reint.c +++ b/drivers/staging/lustre/lustre/mdc/mdc_reint.c @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/mdc/mdc_request.c b/drivers/staging/lustre/lustre/mdc/mdc_request.c index 86b7445..e152429 100644 --- a/drivers/staging/lustre/lustre/mdc/mdc_request.c +++ b/drivers/staging/lustre/lustre/mdc/mdc_request.c @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/mgc/lproc_mgc.c b/drivers/staging/lustre/lustre/mgc/lproc_mgc.c index 8d5bc5a..c77e120 100644 --- a/drivers/staging/lustre/lustre/mgc/lproc_mgc.c +++ b/drivers/staging/lustre/lustre/mgc/lproc_mgc.c @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/mgc/mgc_internal.h b/drivers/staging/lustre/lustre/mgc/mgc_internal.h index 82fb8f4..0eb31cc 100644 --- a/drivers/staging/lustre/lustre/mgc/mgc_internal.h +++ b/drivers/staging/lustre/lustre/mgc/mgc_internal.h @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/mgc/mgc_request.c b/drivers/staging/lustre/lustre/mgc/mgc_request.c index 2311a43..2a80d85 100644 --- a/drivers/staging/lustre/lustre/mgc/mgc_request.c +++ b/drivers/staging/lustre/lustre/mgc/mgc_request.c @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/obdclass/acl.c b/drivers/staging/lustre/lustre/obdclass/acl.c index 0e02ae9..9f4eaba 100644 --- a/drivers/staging/lustre/lustre/obdclass/acl.c +++ b/drivers/staging/lustre/lustre/obdclass/acl.c @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/obdclass/cl_internal.h b/drivers/staging/lustre/lustre/obdclass/cl_internal.h index 7eb0ad7..09a1884 100644 --- a/drivers/staging/lustre/lustre/obdclass/cl_internal.h +++ b/drivers/staging/lustre/lustre/obdclass/cl_internal.h @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/obdclass/cl_io.c b/drivers/staging/lustre/lustre/obdclass/cl_io.c index 583fb5f..dcc1b4e 100644 --- a/drivers/staging/lustre/lustre/obdclass/cl_io.c +++ b/drivers/staging/lustre/lustre/obdclass/cl_io.c @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/obdclass/cl_lock.c b/drivers/staging/lustre/lustre/obdclass/cl_lock.c index 26a576b..737612a 100644 --- a/drivers/staging/lustre/lustre/obdclass/cl_lock.c +++ b/drivers/staging/lustre/lustre/obdclass/cl_lock.c @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/obdclass/cl_object.c b/drivers/staging/lustre/lustre/obdclass/cl_object.c index 5940f30..14da4b1 100644 --- a/drivers/staging/lustre/lustre/obdclass/cl_object.c +++ b/drivers/staging/lustre/lustre/obdclass/cl_object.c @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/obdclass/cl_page.c b/drivers/staging/lustre/lustre/obdclass/cl_page.c index b754f51..c014b69 100644 --- a/drivers/staging/lustre/lustre/obdclass/cl_page.c +++ b/drivers/staging/lustre/lustre/obdclass/cl_page.c @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/obdclass/class_obd.c b/drivers/staging/lustre/lustre/obdclass/class_obd.c index f48816a..b8dd638 100644 --- a/drivers/staging/lustre/lustre/obdclass/class_obd.c +++ b/drivers/staging/lustre/lustre/obdclass/class_obd.c @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/obdclass/debug.c b/drivers/staging/lustre/lustre/obdclass/debug.c index e4edfb2..0786683 100644 --- a/drivers/staging/lustre/lustre/obdclass/debug.c +++ b/drivers/staging/lustre/lustre/obdclass/debug.c @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/obdclass/genops.c b/drivers/staging/lustre/lustre/obdclass/genops.c index d95f11d..2ec9eae 100644 --- a/drivers/staging/lustre/lustre/obdclass/genops.c +++ b/drivers/staging/lustre/lustre/obdclass/genops.c @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/obdclass/kernelcomm.c b/drivers/staging/lustre/lustre/obdclass/kernelcomm.c index 8405ecc..407c41e 100644 --- a/drivers/staging/lustre/lustre/obdclass/kernelcomm.c +++ b/drivers/staging/lustre/lustre/obdclass/kernelcomm.c @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/obdclass/linux/linux-module.c b/drivers/staging/lustre/lustre/obdclass/linux/linux-module.c index 2cd4522..e7beee4 100644 --- a/drivers/staging/lustre/lustre/obdclass/linux/linux-module.c +++ b/drivers/staging/lustre/lustre/obdclass/linux/linux-module.c @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/obdclass/linux/linux-obdo.c b/drivers/staging/lustre/lustre/obdclass/linux/linux-obdo.c index b41b65e..1d4a8d6 100644 --- a/drivers/staging/lustre/lustre/obdclass/linux/linux-obdo.c +++ b/drivers/staging/lustre/lustre/obdclass/linux/linux-obdo.c @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/obdclass/linux/linux-sysctl.c b/drivers/staging/lustre/lustre/obdclass/linux/linux-sysctl.c index e6bf414..58d1a44 100644 --- a/drivers/staging/lustre/lustre/obdclass/linux/linux-sysctl.c +++ b/drivers/staging/lustre/lustre/obdclass/linux/linux-sysctl.c @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/obdclass/llog.c b/drivers/staging/lustre/lustre/obdclass/llog.c index 55a9755..e100ada 100644 --- a/drivers/staging/lustre/lustre/obdclass/llog.c +++ b/drivers/staging/lustre/lustre/obdclass/llog.c @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/obdclass/llog_cat.c b/drivers/staging/lustre/lustre/obdclass/llog_cat.c index c27d4ec..e64a5e5 100644 --- a/drivers/staging/lustre/lustre/obdclass/llog_cat.c +++ b/drivers/staging/lustre/lustre/obdclass/llog_cat.c @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/obdclass/llog_internal.h b/drivers/staging/lustre/lustre/obdclass/llog_internal.h index 7fb48dd..bce65fe 100644 --- a/drivers/staging/lustre/lustre/obdclass/llog_internal.h +++ b/drivers/staging/lustre/lustre/obdclass/llog_internal.h @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/obdclass/llog_obd.c b/drivers/staging/lustre/lustre/obdclass/llog_obd.c index 826623f..b06dfe3 100644 --- a/drivers/staging/lustre/lustre/obdclass/llog_obd.c +++ b/drivers/staging/lustre/lustre/obdclass/llog_obd.c @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/obdclass/llog_swab.c b/drivers/staging/lustre/lustre/obdclass/llog_swab.c index 967ba2e..b5281d8 100644 --- a/drivers/staging/lustre/lustre/obdclass/llog_swab.c +++ b/drivers/staging/lustre/lustre/obdclass/llog_swab.c @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/obdclass/lprocfs_status.c b/drivers/staging/lustre/lustre/obdclass/lprocfs_status.c index 5a1eae1..849deb1 100644 --- a/drivers/staging/lustre/lustre/obdclass/lprocfs_status.c +++ b/drivers/staging/lustre/lustre/obdclass/lprocfs_status.c @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/obdclass/lu_object.c b/drivers/staging/lustre/lustre/obdclass/lu_object.c index e043857..1deaa2b 100644 --- a/drivers/staging/lustre/lustre/obdclass/lu_object.c +++ b/drivers/staging/lustre/lustre/obdclass/lu_object.c @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/obdclass/lu_ref.c b/drivers/staging/lustre/lustre/obdclass/lu_ref.c index 993697b..6363292 100644 --- a/drivers/staging/lustre/lustre/obdclass/lu_ref.c +++ b/drivers/staging/lustre/lustre/obdclass/lu_ref.c @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/obdclass/lustre_handles.c b/drivers/staging/lustre/lustre/obdclass/lustre_handles.c index 403ceea..6df2940 100644 --- a/drivers/staging/lustre/lustre/obdclass/lustre_handles.c +++ b/drivers/staging/lustre/lustre/obdclass/lustre_handles.c @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/obdclass/lustre_peer.c b/drivers/staging/lustre/lustre/obdclass/lustre_peer.c index b1abe02..e0e3a46 100644 --- a/drivers/staging/lustre/lustre/obdclass/lustre_peer.c +++ b/drivers/staging/lustre/lustre/obdclass/lustre_peer.c @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/obdclass/obd_config.c b/drivers/staging/lustre/lustre/obdclass/obd_config.c index cb1d65c..39cfbc51 100644 --- a/drivers/staging/lustre/lustre/obdclass/obd_config.c +++ b/drivers/staging/lustre/lustre/obdclass/obd_config.c @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/obdclass/obd_mount.c b/drivers/staging/lustre/lustre/obdclass/obd_mount.c index bc4e1e4..7dbf40e 100644 --- a/drivers/staging/lustre/lustre/obdclass/obd_mount.c +++ b/drivers/staging/lustre/lustre/obdclass/obd_mount.c @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/obdclass/obdo.c b/drivers/staging/lustre/lustre/obdclass/obdo.c index 748e33f..a62bf2b 100644 --- a/drivers/staging/lustre/lustre/obdclass/obdo.c +++ b/drivers/staging/lustre/lustre/obdclass/obdo.c @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/obdclass/statfs_pack.c b/drivers/staging/lustre/lustre/obdclass/statfs_pack.c index fb4e3ae..d633e22 100644 --- a/drivers/staging/lustre/lustre/obdclass/statfs_pack.c +++ b/drivers/staging/lustre/lustre/obdclass/statfs_pack.c @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/obdclass/uuid.c b/drivers/staging/lustre/lustre/obdclass/uuid.c index b0b0157..0dfa444 100644 --- a/drivers/staging/lustre/lustre/obdclass/uuid.c +++ b/drivers/staging/lustre/lustre/obdclass/uuid.c @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/obdecho/echo_client.c b/drivers/staging/lustre/lustre/obdecho/echo_client.c index 91ef06f..d92d85c 100644 --- a/drivers/staging/lustre/lustre/obdecho/echo_client.c +++ b/drivers/staging/lustre/lustre/obdecho/echo_client.c @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/osc/lproc_osc.c b/drivers/staging/lustre/lustre/osc/lproc_osc.c index 33a1132..f7bdd0a 100644 --- a/drivers/staging/lustre/lustre/osc/lproc_osc.c +++ b/drivers/staging/lustre/lustre/osc/lproc_osc.c @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/osc/osc_cache.c b/drivers/staging/lustre/lustre/osc/osc_cache.c index 2ca5045..4eb1f2af 100644 --- a/drivers/staging/lustre/lustre/osc/osc_cache.c +++ b/drivers/staging/lustre/lustre/osc/osc_cache.c @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/osc/osc_cl_internal.h b/drivers/staging/lustre/lustre/osc/osc_cl_internal.h index 7359fcb..78cab86 100644 --- a/drivers/staging/lustre/lustre/osc/osc_cl_internal.h +++ b/drivers/staging/lustre/lustre/osc/osc_cl_internal.h @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/osc/osc_dev.c b/drivers/staging/lustre/lustre/osc/osc_dev.c index d4fe507..1d2938d 100644 --- a/drivers/staging/lustre/lustre/osc/osc_dev.c +++ b/drivers/staging/lustre/lustre/osc/osc_dev.c @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/osc/osc_internal.h b/drivers/staging/lustre/lustre/osc/osc_internal.h index 7fad827..439118a 100644 --- a/drivers/staging/lustre/lustre/osc/osc_internal.h +++ b/drivers/staging/lustre/lustre/osc/osc_internal.h @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/osc/osc_io.c b/drivers/staging/lustre/lustre/osc/osc_io.c index d3bce45..79159d9 100644 --- a/drivers/staging/lustre/lustre/osc/osc_io.c +++ b/drivers/staging/lustre/lustre/osc/osc_io.c @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/osc/osc_lock.c b/drivers/staging/lustre/lustre/osc/osc_lock.c index d30ed2f..fef695b 100644 --- a/drivers/staging/lustre/lustre/osc/osc_lock.c +++ b/drivers/staging/lustre/lustre/osc/osc_lock.c @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/osc/osc_object.c b/drivers/staging/lustre/lustre/osc/osc_object.c index 738ab10..2a8b3c2 100644 --- a/drivers/staging/lustre/lustre/osc/osc_object.c +++ b/drivers/staging/lustre/lustre/osc/osc_object.c @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/osc/osc_page.c b/drivers/staging/lustre/lustre/osc/osc_page.c index 5a3e694..9ed91c4 100644 --- a/drivers/staging/lustre/lustre/osc/osc_page.c +++ b/drivers/staging/lustre/lustre/osc/osc_page.c @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/osc/osc_request.c b/drivers/staging/lustre/lustre/osc/osc_request.c index 7b1fc7e..740c362 100644 --- a/drivers/staging/lustre/lustre/osc/osc_request.c +++ b/drivers/staging/lustre/lustre/osc/osc_request.c @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/ptlrpc/client.c b/drivers/staging/lustre/lustre/ptlrpc/client.c index 8336ed1..325cce1 100644 --- a/drivers/staging/lustre/lustre/ptlrpc/client.c +++ b/drivers/staging/lustre/lustre/ptlrpc/client.c @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/ptlrpc/connection.c b/drivers/staging/lustre/lustre/ptlrpc/connection.c index a14daff..a1f7d8c 100644 --- a/drivers/staging/lustre/lustre/ptlrpc/connection.c +++ b/drivers/staging/lustre/lustre/ptlrpc/connection.c @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/ptlrpc/events.c b/drivers/staging/lustre/lustre/ptlrpc/events.c index fdcde9b..af841cc 100644 --- a/drivers/staging/lustre/lustre/ptlrpc/events.c +++ b/drivers/staging/lustre/lustre/ptlrpc/events.c @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/ptlrpc/import.c b/drivers/staging/lustre/lustre/ptlrpc/import.c index a236e38..2930193 100644 --- a/drivers/staging/lustre/lustre/ptlrpc/import.c +++ b/drivers/staging/lustre/lustre/ptlrpc/import.c @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/ptlrpc/layout.c b/drivers/staging/lustre/lustre/ptlrpc/layout.c index c0ecd16..f0dca8e 100644 --- a/drivers/staging/lustre/lustre/ptlrpc/layout.c +++ b/drivers/staging/lustre/lustre/ptlrpc/layout.c @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/ptlrpc/llog_client.c b/drivers/staging/lustre/lustre/ptlrpc/llog_client.c index a23ac5f..f335b1f 100644 --- a/drivers/staging/lustre/lustre/ptlrpc/llog_client.c +++ b/drivers/staging/lustre/lustre/ptlrpc/llog_client.c @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/ptlrpc/llog_net.c b/drivers/staging/lustre/lustre/ptlrpc/llog_net.c index fbccb62..ed3e88f 100644 --- a/drivers/staging/lustre/lustre/ptlrpc/llog_net.c +++ b/drivers/staging/lustre/lustre/ptlrpc/llog_net.c @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/ptlrpc/lproc_ptlrpc.c b/drivers/staging/lustre/lustre/ptlrpc/lproc_ptlrpc.c index ff40be2..8d67108 100644 --- a/drivers/staging/lustre/lustre/ptlrpc/lproc_ptlrpc.c +++ b/drivers/staging/lustre/lustre/ptlrpc/lproc_ptlrpc.c @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/ptlrpc/niobuf.c b/drivers/staging/lustre/lustre/ptlrpc/niobuf.c index 10b8fe8..17dd6ea 100644 --- a/drivers/staging/lustre/lustre/ptlrpc/niobuf.c +++ b/drivers/staging/lustre/lustre/ptlrpc/niobuf.c @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/ptlrpc/pack_generic.c b/drivers/staging/lustre/lustre/ptlrpc/pack_generic.c index 811acf6..e7187a4 100644 --- a/drivers/staging/lustre/lustre/ptlrpc/pack_generic.c +++ b/drivers/staging/lustre/lustre/ptlrpc/pack_generic.c @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/ptlrpc/pers.c b/drivers/staging/lustre/lustre/ptlrpc/pers.c index ec3af10..14608ef 100644 --- a/drivers/staging/lustre/lustre/ptlrpc/pers.c +++ b/drivers/staging/lustre/lustre/ptlrpc/pers.c @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/ptlrpc/pinger.c b/drivers/staging/lustre/lustre/ptlrpc/pinger.c index d9d4ca2..8ae6fd1 100644 --- a/drivers/staging/lustre/lustre/ptlrpc/pinger.c +++ b/drivers/staging/lustre/lustre/ptlrpc/pinger.c @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/ptlrpc/ptlrpc_internal.h b/drivers/staging/lustre/lustre/ptlrpc/ptlrpc_internal.h index 6ca26c9..52eda29 100644 --- a/drivers/staging/lustre/lustre/ptlrpc/ptlrpc_internal.h +++ b/drivers/staging/lustre/lustre/ptlrpc/ptlrpc_internal.h @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/ptlrpc/ptlrpc_module.c b/drivers/staging/lustre/lustre/ptlrpc/ptlrpc_module.c index a8ec0e9..e7443f3 100644 --- a/drivers/staging/lustre/lustre/ptlrpc/ptlrpc_module.c +++ b/drivers/staging/lustre/lustre/ptlrpc/ptlrpc_module.c @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/ptlrpc/ptlrpcd.c b/drivers/staging/lustre/lustre/ptlrpc/ptlrpcd.c index 76a355a..fd343819 100644 --- a/drivers/staging/lustre/lustre/ptlrpc/ptlrpcd.c +++ b/drivers/staging/lustre/lustre/ptlrpc/ptlrpcd.c @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/ptlrpc/recover.c b/drivers/staging/lustre/lustre/ptlrpc/recover.c index 30d9a16..5c69309 100644 --- a/drivers/staging/lustre/lustre/ptlrpc/recover.c +++ b/drivers/staging/lustre/lustre/ptlrpc/recover.c @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/ptlrpc/sec.c b/drivers/staging/lustre/lustre/ptlrpc/sec.c index 657b41f..9ec6417 100644 --- a/drivers/staging/lustre/lustre/ptlrpc/sec.c +++ b/drivers/staging/lustre/lustre/ptlrpc/sec.c @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/ptlrpc/sec_bulk.c b/drivers/staging/lustre/lustre/ptlrpc/sec_bulk.c index 02e6cda..34e2972 100644 --- a/drivers/staging/lustre/lustre/ptlrpc/sec_bulk.c +++ b/drivers/staging/lustre/lustre/ptlrpc/sec_bulk.c @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/ptlrpc/sec_config.c b/drivers/staging/lustre/lustre/ptlrpc/sec_config.c index a51b18b..f7210c8 100644 --- a/drivers/staging/lustre/lustre/ptlrpc/sec_config.c +++ b/drivers/staging/lustre/lustre/ptlrpc/sec_config.c @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/ptlrpc/sec_gc.c b/drivers/staging/lustre/lustre/ptlrpc/sec_gc.c index 9082da0..15d0586 100644 --- a/drivers/staging/lustre/lustre/ptlrpc/sec_gc.c +++ b/drivers/staging/lustre/lustre/ptlrpc/sec_gc.c @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/ptlrpc/sec_lproc.c b/drivers/staging/lustre/lustre/ptlrpc/sec_lproc.c index e610a8d..bba4adf 100644 --- a/drivers/staging/lustre/lustre/ptlrpc/sec_lproc.c +++ b/drivers/staging/lustre/lustre/ptlrpc/sec_lproc.c @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/ptlrpc/sec_null.c b/drivers/staging/lustre/lustre/ptlrpc/sec_null.c index af92e9e..04381af 100644 --- a/drivers/staging/lustre/lustre/ptlrpc/sec_null.c +++ b/drivers/staging/lustre/lustre/ptlrpc/sec_null.c @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/ptlrpc/sec_plain.c b/drivers/staging/lustre/lustre/ptlrpc/sec_plain.c index ec8edbf..a2dd435 100644 --- a/drivers/staging/lustre/lustre/ptlrpc/sec_plain.c +++ b/drivers/staging/lustre/lustre/ptlrpc/sec_plain.c @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/ptlrpc/service.c b/drivers/staging/lustre/lustre/ptlrpc/service.c index 17c7b97..f369a5e 100644 --- a/drivers/staging/lustre/lustre/ptlrpc/service.c +++ b/drivers/staging/lustre/lustre/ptlrpc/service.c @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lustre/ptlrpc/wiretest.c b/drivers/staging/lustre/lustre/ptlrpc/wiretest.c index aacc810..4b9a23e 100644 --- a/drivers/staging/lustre/lustre/ptlrpc/wiretest.c +++ b/drivers/staging/lustre/lustre/ptlrpc/wiretest.c @@ -17,10 +17,6 @@ * version 2 along with this program; If not, see * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* -- cgit v0.10.2 From 6a5b99a46bedc2cfbba96dec6d255c4b90af9ff8 Mon Sep 17 00:00:00 2001 From: Oleg Drokin Date: Tue, 14 Jun 2016 23:33:40 -0400 Subject: staging/lustre: Replace sun.com GPLv2 URL with gnu.org one. http://www.sun.com/software/products/lustre/docs/GPLv2.pdf is no longer around, so replae it with (hopefully more permanent) http://http://www.gnu.org/licenses/gpl-2.0.html Signed-off-by: Oleg Drokin Reported-by: Xose Vazquez Perez Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/lustre/include/linux/libcfs/curproc.h b/drivers/staging/lustre/include/linux/libcfs/curproc.h index c673dfc..be0675d 100644 --- a/drivers/staging/lustre/include/linux/libcfs/curproc.h +++ b/drivers/staging/lustre/include/linux/libcfs/curproc.h @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/include/linux/libcfs/libcfs.h b/drivers/staging/lustre/include/linux/libcfs/libcfs.h index c93d58e..3f6447c 100644 --- a/drivers/staging/lustre/include/linux/libcfs/libcfs.h +++ b/drivers/staging/lustre/include/linux/libcfs/libcfs.h @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/include/linux/libcfs/libcfs_debug.h b/drivers/staging/lustre/include/linux/libcfs/libcfs_debug.h index ae8175c..25adab1 100644 --- a/drivers/staging/lustre/include/linux/libcfs/libcfs_debug.h +++ b/drivers/staging/lustre/include/linux/libcfs/libcfs_debug.h @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/include/linux/libcfs/libcfs_hash.h b/drivers/staging/lustre/include/linux/libcfs/libcfs_hash.h index 6a4387b..6949a18 100644 --- a/drivers/staging/lustre/include/linux/libcfs/libcfs_hash.h +++ b/drivers/staging/lustre/include/linux/libcfs/libcfs_hash.h @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/include/linux/libcfs/libcfs_ioctl.h b/drivers/staging/lustre/include/linux/libcfs/libcfs_ioctl.h index 9bdff3f..cce6b58 100644 --- a/drivers/staging/lustre/include/linux/libcfs/libcfs_ioctl.h +++ b/drivers/staging/lustre/include/linux/libcfs/libcfs_ioctl.h @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/include/linux/libcfs/libcfs_prim.h b/drivers/staging/lustre/include/linux/libcfs/libcfs_prim.h index 881aae0..8c75d50 100644 --- a/drivers/staging/lustre/include/linux/libcfs/libcfs_prim.h +++ b/drivers/staging/lustre/include/linux/libcfs/libcfs_prim.h @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/include/linux/libcfs/libcfs_private.h b/drivers/staging/lustre/include/linux/libcfs/libcfs_private.h index c44e11d..4daa382 100644 --- a/drivers/staging/lustre/include/linux/libcfs/libcfs_private.h +++ b/drivers/staging/lustre/include/linux/libcfs/libcfs_private.h @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/include/linux/libcfs/libcfs_string.h b/drivers/staging/lustre/include/linux/libcfs/libcfs_string.h index 03939ce..0ee60ff 100644 --- a/drivers/staging/lustre/include/linux/libcfs/libcfs_string.h +++ b/drivers/staging/lustre/include/linux/libcfs/libcfs_string.h @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/include/linux/libcfs/libcfs_time.h b/drivers/staging/lustre/include/linux/libcfs/libcfs_time.h index 3f0ec7a..008da44 100644 --- a/drivers/staging/lustre/include/linux/libcfs/libcfs_time.h +++ b/drivers/staging/lustre/include/linux/libcfs/libcfs_time.h @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/include/linux/libcfs/libcfs_workitem.h b/drivers/staging/lustre/include/linux/libcfs/libcfs_workitem.h index 5ff23bb..a7e1340 100644 --- a/drivers/staging/lustre/include/linux/libcfs/libcfs_workitem.h +++ b/drivers/staging/lustre/include/linux/libcfs/libcfs_workitem.h @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/include/linux/libcfs/linux/libcfs.h b/drivers/staging/lustre/include/linux/libcfs/linux/libcfs.h index 3652119..e8695e4 100644 --- a/drivers/staging/lustre/include/linux/libcfs/linux/libcfs.h +++ b/drivers/staging/lustre/include/linux/libcfs/linux/libcfs.h @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/include/linux/libcfs/linux/linux-time.h b/drivers/staging/lustre/include/linux/libcfs/linux/linux-time.h index 887811b..b646acd 100644 --- a/drivers/staging/lustre/include/linux/libcfs/linux/linux-time.h +++ b/drivers/staging/lustre/include/linux/libcfs/linux/linux-time.h @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c index f0c0669..4f5978b 100644 --- a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c +++ b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.h b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.h index 69711ee..b66ab79 100644 --- a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.h +++ b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.h @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd_cb.c b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd_cb.c index 5dde5ff..adc346a 100644 --- a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd_cb.c +++ b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd_cb.c @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd_modparams.c b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd_modparams.c index 24de544..44e960f 100644 --- a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd_modparams.c +++ b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd_modparams.c @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lnet/klnds/socklnd/socklnd.c b/drivers/staging/lustre/lnet/klnds/socklnd/socklnd.c index 67d8bf2..d4e7dae 100644 --- a/drivers/staging/lustre/lnet/klnds/socklnd/socklnd.c +++ b/drivers/staging/lustre/lnet/klnds/socklnd/socklnd.c @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lnet/klnds/socklnd/socklnd_lib.c b/drivers/staging/lustre/lnet/klnds/socklnd/socklnd_lib.c index defe041..6a17757 100644 --- a/drivers/staging/lustre/lnet/klnds/socklnd/socklnd_lib.c +++ b/drivers/staging/lustre/lnet/klnds/socklnd/socklnd_lib.c @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lnet/libcfs/debug.c b/drivers/staging/lustre/lnet/libcfs/debug.c index 0079a4c..75a2a42 100644 --- a/drivers/staging/lustre/lnet/libcfs/debug.c +++ b/drivers/staging/lustre/lnet/libcfs/debug.c @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lnet/libcfs/hash.c b/drivers/staging/lustre/lnet/libcfs/hash.c index db51124..23283b6 100644 --- a/drivers/staging/lustre/lnet/libcfs/hash.c +++ b/drivers/staging/lustre/lnet/libcfs/hash.c @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lnet/libcfs/libcfs_string.c b/drivers/staging/lustre/lnet/libcfs/libcfs_string.c index 750691c..fc697cd 100644 --- a/drivers/staging/lustre/lnet/libcfs/libcfs_string.c +++ b/drivers/staging/lustre/lnet/libcfs/libcfs_string.c @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lnet/libcfs/linux/linux-curproc.c b/drivers/staging/lustre/lnet/libcfs/linux/linux-curproc.c index 4fe58dd..3e22cad 100644 --- a/drivers/staging/lustre/lnet/libcfs/linux/linux-curproc.c +++ b/drivers/staging/lustre/lnet/libcfs/linux/linux-curproc.c @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lnet/libcfs/linux/linux-debug.c b/drivers/staging/lustre/lnet/libcfs/linux/linux-debug.c index 808d09b..435b784 100644 --- a/drivers/staging/lustre/lnet/libcfs/linux/linux-debug.c +++ b/drivers/staging/lustre/lnet/libcfs/linux/linux-debug.c @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lnet/libcfs/linux/linux-mem.c b/drivers/staging/lustre/lnet/libcfs/linux/linux-mem.c index 86f32ff..a6a76a6 100644 --- a/drivers/staging/lustre/lnet/libcfs/linux/linux-mem.c +++ b/drivers/staging/lustre/lnet/libcfs/linux/linux-mem.c @@ -11,7 +11,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * */ /* diff --git a/drivers/staging/lustre/lnet/libcfs/linux/linux-module.c b/drivers/staging/lustre/lnet/libcfs/linux/linux-module.c index 8caee5b..38308f8 100644 --- a/drivers/staging/lustre/lnet/libcfs/linux/linux-module.c +++ b/drivers/staging/lustre/lnet/libcfs/linux/linux-module.c @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lnet/libcfs/linux/linux-prim.c b/drivers/staging/lustre/lnet/libcfs/linux/linux-prim.c index c1152e6..291d286 100644 --- a/drivers/staging/lustre/lnet/libcfs/linux/linux-prim.c +++ b/drivers/staging/lustre/lnet/libcfs/linux/linux-prim.c @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lnet/libcfs/linux/linux-tracefile.c b/drivers/staging/lustre/lnet/libcfs/linux/linux-tracefile.c index 6c9e3976..8b551d27 100644 --- a/drivers/staging/lustre/lnet/libcfs/linux/linux-tracefile.c +++ b/drivers/staging/lustre/lnet/libcfs/linux/linux-tracefile.c @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lnet/libcfs/module.c b/drivers/staging/lustre/lnet/libcfs/module.c index 065f968..86b4d25 100644 --- a/drivers/staging/lustre/lnet/libcfs/module.c +++ b/drivers/staging/lustre/lnet/libcfs/module.c @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lnet/libcfs/prng.c b/drivers/staging/lustre/lnet/libcfs/prng.c index f2e8426..a9bdb28 100644 --- a/drivers/staging/lustre/lnet/libcfs/prng.c +++ b/drivers/staging/lustre/lnet/libcfs/prng.c @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lnet/libcfs/tracefile.c b/drivers/staging/lustre/lnet/libcfs/tracefile.c index ba0e7c3..1c7efdf 100644 --- a/drivers/staging/lustre/lnet/libcfs/tracefile.c +++ b/drivers/staging/lustre/lnet/libcfs/tracefile.c @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lnet/libcfs/tracefile.h b/drivers/staging/lustre/lnet/libcfs/tracefile.h index ae1c614..d878676 100644 --- a/drivers/staging/lustre/lnet/libcfs/tracefile.h +++ b/drivers/staging/lustre/lnet/libcfs/tracefile.h @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lnet/libcfs/workitem.c b/drivers/staging/lustre/lnet/libcfs/workitem.c index c51f389..e98c818 100644 --- a/drivers/staging/lustre/lnet/libcfs/workitem.c +++ b/drivers/staging/lustre/lnet/libcfs/workitem.c @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lnet/lnet/acceptor.c b/drivers/staging/lustre/lnet/lnet/acceptor.c index 4456286..8c50c99 100644 --- a/drivers/staging/lustre/lnet/lnet/acceptor.c +++ b/drivers/staging/lustre/lnet/lnet/acceptor.c @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lnet/lnet/api-ni.c b/drivers/staging/lustre/lnet/lnet/api-ni.c index 7662c3b..48327ca 100644 --- a/drivers/staging/lustre/lnet/lnet/api-ni.c +++ b/drivers/staging/lustre/lnet/lnet/api-ni.c @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lnet/lnet/config.c b/drivers/staging/lustre/lnet/lnet/config.c index 358e5cf..a72afdf 100644 --- a/drivers/staging/lustre/lnet/lnet/config.c +++ b/drivers/staging/lustre/lnet/lnet/config.c @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lnet/lnet/lib-eq.c b/drivers/staging/lustre/lnet/lnet/lib-eq.c index d04c687..d05c6cc 100644 --- a/drivers/staging/lustre/lnet/lnet/lib-eq.c +++ b/drivers/staging/lustre/lnet/lnet/lib-eq.c @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lnet/lnet/lib-md.c b/drivers/staging/lustre/lnet/lnet/lib-md.c index 51145f1..1834bf7 100644 --- a/drivers/staging/lustre/lnet/lnet/lib-md.c +++ b/drivers/staging/lustre/lnet/lnet/lib-md.c @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lnet/lnet/lib-me.c b/drivers/staging/lustre/lnet/lnet/lib-me.c index 1c370f4..b430046 100644 --- a/drivers/staging/lustre/lnet/lnet/lib-me.c +++ b/drivers/staging/lustre/lnet/lnet/lib-me.c @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lnet/lnet/lib-move.c b/drivers/staging/lustre/lnet/lnet/lib-move.c index f5c6eac..e6d3b80 100644 --- a/drivers/staging/lustre/lnet/lnet/lib-move.c +++ b/drivers/staging/lustre/lnet/lnet/lib-move.c @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lnet/lnet/lib-msg.c b/drivers/staging/lustre/lnet/lnet/lib-msg.c index 77ae4e6..910e106 100644 --- a/drivers/staging/lustre/lnet/lnet/lib-msg.c +++ b/drivers/staging/lustre/lnet/lnet/lib-msg.c @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lnet/lnet/lo.c b/drivers/staging/lustre/lnet/lnet/lo.c index 6441ef3..08402712 100644 --- a/drivers/staging/lustre/lnet/lnet/lo.c +++ b/drivers/staging/lustre/lnet/lnet/lo.c @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lnet/lnet/module.c b/drivers/staging/lustre/lnet/lnet/module.c index 40f3c52..58cf246 100644 --- a/drivers/staging/lustre/lnet/lnet/module.c +++ b/drivers/staging/lustre/lnet/lnet/module.c @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lnet/lnet/nidstrings.c b/drivers/staging/lustre/lnet/lnet/nidstrings.c index 74bfda1..a6d7a61 100644 --- a/drivers/staging/lustre/lnet/lnet/nidstrings.c +++ b/drivers/staging/lustre/lnet/lnet/nidstrings.c @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lnet/lnet/peer.c b/drivers/staging/lustre/lnet/lnet/peer.c index 5fde05a..e806191 100644 --- a/drivers/staging/lustre/lnet/lnet/peer.c +++ b/drivers/staging/lustre/lnet/lnet/peer.c @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lnet/selftest/brw_test.c b/drivers/staging/lustre/lnet/selftest/brw_test.c index 6e25e1a..13d0454 100644 --- a/drivers/staging/lustre/lnet/selftest/brw_test.c +++ b/drivers/staging/lustre/lnet/selftest/brw_test.c @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lnet/selftest/conctl.c b/drivers/staging/lustre/lnet/selftest/conctl.c index 9a22f33..b786f8b 100644 --- a/drivers/staging/lustre/lnet/selftest/conctl.c +++ b/drivers/staging/lustre/lnet/selftest/conctl.c @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lnet/selftest/conrpc.c b/drivers/staging/lustre/lnet/selftest/conrpc.c index e649d37..1be3cad 100644 --- a/drivers/staging/lustre/lnet/selftest/conrpc.c +++ b/drivers/staging/lustre/lnet/selftest/conrpc.c @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lnet/selftest/conrpc.h b/drivers/staging/lustre/lnet/selftest/conrpc.h index 1d8bb63..7ec6fc9 100644 --- a/drivers/staging/lustre/lnet/selftest/conrpc.h +++ b/drivers/staging/lustre/lnet/selftest/conrpc.h @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lnet/selftest/console.c b/drivers/staging/lustre/lnet/selftest/console.c index 31001f4..4c33621 100644 --- a/drivers/staging/lustre/lnet/selftest/console.c +++ b/drivers/staging/lustre/lnet/selftest/console.c @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lnet/selftest/console.h b/drivers/staging/lustre/lnet/selftest/console.h index b099946..78b1477 100644 --- a/drivers/staging/lustre/lnet/selftest/console.h +++ b/drivers/staging/lustre/lnet/selftest/console.h @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lnet/selftest/framework.c b/drivers/staging/lustre/lnet/selftest/framework.c index 0d53307..c2f121f 100644 --- a/drivers/staging/lustre/lnet/selftest/framework.c +++ b/drivers/staging/lustre/lnet/selftest/framework.c @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lnet/selftest/module.c b/drivers/staging/lustre/lnet/selftest/module.c index b6a3bdf..71485f9 100644 --- a/drivers/staging/lustre/lnet/selftest/module.c +++ b/drivers/staging/lustre/lnet/selftest/module.c @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lnet/selftest/ping_test.c b/drivers/staging/lustre/lnet/selftest/ping_test.c index 3030c07..9331ca4 100644 --- a/drivers/staging/lustre/lnet/selftest/ping_test.c +++ b/drivers/staging/lustre/lnet/selftest/ping_test.c @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lnet/selftest/rpc.c b/drivers/staging/lustre/lnet/selftest/rpc.c index e7aba01..3b26d6e 100644 --- a/drivers/staging/lustre/lnet/selftest/rpc.c +++ b/drivers/staging/lustre/lnet/selftest/rpc.c @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lnet/selftest/rpc.h b/drivers/staging/lustre/lnet/selftest/rpc.h index 3254f5d..4ab2ee2 100644 --- a/drivers/staging/lustre/lnet/selftest/rpc.h +++ b/drivers/staging/lustre/lnet/selftest/rpc.h @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lnet/selftest/selftest.h b/drivers/staging/lustre/lnet/selftest/selftest.h index 4a1d2b2..1b21a1a 100644 --- a/drivers/staging/lustre/lnet/selftest/selftest.h +++ b/drivers/staging/lustre/lnet/selftest/selftest.h @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * copy of GPLv2]. * * GPL HEADER END diff --git a/drivers/staging/lustre/lnet/selftest/timer.c b/drivers/staging/lustre/lnet/selftest/timer.c index c73ded9..dcd2258 100644 --- a/drivers/staging/lustre/lnet/selftest/timer.c +++ b/drivers/staging/lustre/lnet/selftest/timer.c @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lnet/selftest/timer.h b/drivers/staging/lustre/lnet/selftest/timer.h index e86e44e..441d6d6 100644 --- a/drivers/staging/lustre/lnet/selftest/timer.h +++ b/drivers/staging/lustre/lnet/selftest/timer.h @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/fid/fid_internal.h b/drivers/staging/lustre/lustre/fid/fid_internal.h index d6aebb3..5c53773 100644 --- a/drivers/staging/lustre/lustre/fid/fid_internal.h +++ b/drivers/staging/lustre/lustre/fid/fid_internal.h @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/fid/fid_lib.c b/drivers/staging/lustre/lustre/fid/fid_lib.c index ee7b272..99ae7eb 100644 --- a/drivers/staging/lustre/lustre/fid/fid_lib.c +++ b/drivers/staging/lustre/lustre/fid/fid_lib.c @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/fid/fid_request.c b/drivers/staging/lustre/lustre/fid/fid_request.c index 00b19c7..454744d 100644 --- a/drivers/staging/lustre/lustre/fid/fid_request.c +++ b/drivers/staging/lustre/lustre/fid/fid_request.c @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/fid/lproc_fid.c b/drivers/staging/lustre/lustre/fid/lproc_fid.c index 0103af5..81b7ca9 100644 --- a/drivers/staging/lustre/lustre/fid/lproc_fid.c +++ b/drivers/staging/lustre/lustre/fid/lproc_fid.c @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/fld/fld_cache.c b/drivers/staging/lustre/lustre/fld/fld_cache.c index cb33d41..0100a93 100644 --- a/drivers/staging/lustre/lustre/fld/fld_cache.c +++ b/drivers/staging/lustre/lustre/fld/fld_cache.c @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/fld/fld_internal.h b/drivers/staging/lustre/lustre/fld/fld_internal.h index a85d86a..f0efe5b 100644 --- a/drivers/staging/lustre/lustre/fld/fld_internal.h +++ b/drivers/staging/lustre/lustre/fld/fld_internal.h @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/fld/fld_request.c b/drivers/staging/lustre/lustre/fld/fld_request.c index 5f43af4..e59d626 100644 --- a/drivers/staging/lustre/lustre/fld/fld_request.c +++ b/drivers/staging/lustre/lustre/fld/fld_request.c @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/fld/lproc_fld.c b/drivers/staging/lustre/lustre/fld/lproc_fld.c index 1b96880..61ac420 100644 --- a/drivers/staging/lustre/lustre/fld/lproc_fld.c +++ b/drivers/staging/lustre/lustre/fld/lproc_fld.c @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/include/cl_object.h b/drivers/staging/lustre/lustre/include/cl_object.h index a5a28f5..36ca935 100644 --- a/drivers/staging/lustre/lustre/include/cl_object.h +++ b/drivers/staging/lustre/lustre/include/cl_object.h @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/include/interval_tree.h b/drivers/staging/lustre/lustre/include/interval_tree.h index 64cab4b..4a15228 100644 --- a/drivers/staging/lustre/lustre/include/interval_tree.h +++ b/drivers/staging/lustre/lustre/include/interval_tree.h @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/include/linux/lustre_compat25.h b/drivers/staging/lustre/lustre/include/linux/lustre_compat25.h index 7690fa7..1eb64ec 100644 --- a/drivers/staging/lustre/lustre/include/linux/lustre_compat25.h +++ b/drivers/staging/lustre/lustre/include/linux/lustre_compat25.h @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/include/linux/lustre_lite.h b/drivers/staging/lustre/lustre/include/linux/lustre_lite.h index abefa93..d18e8a7 100644 --- a/drivers/staging/lustre/lustre/include/linux/lustre_lite.h +++ b/drivers/staging/lustre/lustre/include/linux/lustre_lite.h @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/include/linux/lustre_patchless_compat.h b/drivers/staging/lustre/lustre/include/linux/lustre_patchless_compat.h index 6d138b2..5842cb1 100644 --- a/drivers/staging/lustre/lustre/include/linux/lustre_patchless_compat.h +++ b/drivers/staging/lustre/lustre/include/linux/lustre_patchless_compat.h @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/include/linux/lustre_user.h b/drivers/staging/lustre/lustre/include/linux/lustre_user.h index 7403139..e967950 100644 --- a/drivers/staging/lustre/lustre/include/linux/lustre_user.h +++ b/drivers/staging/lustre/lustre/include/linux/lustre_user.h @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/include/lprocfs_status.h b/drivers/staging/lustre/lustre/include/lprocfs_status.h index 4f5ab54..d68e60e 100644 --- a/drivers/staging/lustre/lustre/include/lprocfs_status.h +++ b/drivers/staging/lustre/lustre/include/lprocfs_status.h @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/include/lu_object.h b/drivers/staging/lustre/lustre/include/lu_object.h index b7bfe39..c6281e6 100644 --- a/drivers/staging/lustre/lustre/include/lu_object.h +++ b/drivers/staging/lustre/lustre/include/lu_object.h @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/include/lustre/ll_fiemap.h b/drivers/staging/lustre/lustre/include/lustre/ll_fiemap.h index 664f135..c2340d6 100644 --- a/drivers/staging/lustre/lustre/include/lustre/ll_fiemap.h +++ b/drivers/staging/lustre/lustre/include/lustre/ll_fiemap.h @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/include/lustre/lustre_idl.h b/drivers/staging/lustre/lustre/include/lustre/lustre_idl.h index e5031b1..bf8a0cd 100644 --- a/drivers/staging/lustre/lustre/include/lustre/lustre_idl.h +++ b/drivers/staging/lustre/lustre/include/lustre/lustre_idl.h @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/include/lustre/lustre_user.h b/drivers/staging/lustre/lustre/include/lustre/lustre_user.h index 3b48ba5..a6e351a 100644 --- a/drivers/staging/lustre/lustre/include/lustre/lustre_user.h +++ b/drivers/staging/lustre/lustre/include/lustre/lustre_user.h @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/include/lustre_acl.h b/drivers/staging/lustre/lustre/include/lustre_acl.h index 9773db7..fecabe1 100644 --- a/drivers/staging/lustre/lustre/include/lustre_acl.h +++ b/drivers/staging/lustre/lustre/include/lustre_acl.h @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/include/lustre_cfg.h b/drivers/staging/lustre/lustre/include/lustre_cfg.h index f532af6..95a0be1 100644 --- a/drivers/staging/lustre/lustre/include/lustre_cfg.h +++ b/drivers/staging/lustre/lustre/include/lustre_cfg.h @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/include/lustre_debug.h b/drivers/staging/lustre/lustre/include/lustre_debug.h index bd531ff..93c1bda 100644 --- a/drivers/staging/lustre/lustre/include/lustre_debug.h +++ b/drivers/staging/lustre/lustre/include/lustre_debug.h @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/include/lustre_disk.h b/drivers/staging/lustre/lustre/include/lustre_disk.h index f30c601..8886458 100644 --- a/drivers/staging/lustre/lustre/include/lustre_disk.h +++ b/drivers/staging/lustre/lustre/include/lustre_disk.h @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/include/lustre_dlm.h b/drivers/staging/lustre/lustre/include/lustre_dlm.h index bdc1da7..63085a0 100644 --- a/drivers/staging/lustre/lustre/include/lustre_dlm.h +++ b/drivers/staging/lustre/lustre/include/lustre_dlm.h @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/include/lustre_eacl.h b/drivers/staging/lustre/lustre/include/lustre_eacl.h index caab6e3..e5eadc4 100644 --- a/drivers/staging/lustre/lustre/include/lustre_eacl.h +++ b/drivers/staging/lustre/lustre/include/lustre_eacl.h @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/include/lustre_export.h b/drivers/staging/lustre/lustre/include/lustre_export.h index 41b6a7c..7c3ed55 100644 --- a/drivers/staging/lustre/lustre/include/lustre_export.h +++ b/drivers/staging/lustre/lustre/include/lustre_export.h @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/include/lustre_fid.h b/drivers/staging/lustre/lustre/include/lustre_fid.h index e3794d6..cbdd91a 100644 --- a/drivers/staging/lustre/lustre/include/lustre_fid.h +++ b/drivers/staging/lustre/lustre/include/lustre_fid.h @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/include/lustre_fld.h b/drivers/staging/lustre/lustre/include/lustre_fld.h index 6a91cbc..932410d 100644 --- a/drivers/staging/lustre/lustre/include/lustre_fld.h +++ b/drivers/staging/lustre/lustre/include/lustre_fld.h @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/include/lustre_ha.h b/drivers/staging/lustre/lustre/include/lustre_ha.h index 152b0ee..cde7ed7 100644 --- a/drivers/staging/lustre/lustre/include/lustre_ha.h +++ b/drivers/staging/lustre/lustre/include/lustre_ha.h @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/include/lustre_handles.h b/drivers/staging/lustre/lustre/include/lustre_handles.h index c1906c2..1a63a6b 100644 --- a/drivers/staging/lustre/lustre/include/lustre_handles.h +++ b/drivers/staging/lustre/lustre/include/lustre_handles.h @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/include/lustre_import.h b/drivers/staging/lustre/lustre/include/lustre_import.h index d4f7680..4445be7 100644 --- a/drivers/staging/lustre/lustre/include/lustre_import.h +++ b/drivers/staging/lustre/lustre/include/lustre_import.h @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/include/lustre_intent.h b/drivers/staging/lustre/lustre/include/lustre_intent.h index d5b15a4..fdc6236 100644 --- a/drivers/staging/lustre/lustre/include/lustre_intent.h +++ b/drivers/staging/lustre/lustre/include/lustre_intent.h @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/include/lustre_lib.h b/drivers/staging/lustre/lustre/include/lustre_lib.h index f7b0ce8..06958f2 100644 --- a/drivers/staging/lustre/lustre/include/lustre_lib.h +++ b/drivers/staging/lustre/lustre/include/lustre_lib.h @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/include/lustre_lite.h b/drivers/staging/lustre/lustre/include/lustre_lite.h index bd328e5..b168977 100644 --- a/drivers/staging/lustre/lustre/include/lustre_lite.h +++ b/drivers/staging/lustre/lustre/include/lustre_lite.h @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/include/lustre_log.h b/drivers/staging/lustre/lustre/include/lustre_log.h index 7a3940a..b96e023 100644 --- a/drivers/staging/lustre/lustre/include/lustre_log.h +++ b/drivers/staging/lustre/lustre/include/lustre_log.h @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/include/lustre_mdc.h b/drivers/staging/lustre/lustre/include/lustre_mdc.h index cc4158c..0ef4226 100644 --- a/drivers/staging/lustre/lustre/include/lustre_mdc.h +++ b/drivers/staging/lustre/lustre/include/lustre_mdc.h @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/include/lustre_mds.h b/drivers/staging/lustre/lustre/include/lustre_mds.h index 9bcd3cd..4104bd9 100644 --- a/drivers/staging/lustre/lustre/include/lustre_mds.h +++ b/drivers/staging/lustre/lustre/include/lustre_mds.h @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/include/lustre_net.h b/drivers/staging/lustre/lustre/include/lustre_net.h index ce31181..dba4d1d 100644 --- a/drivers/staging/lustre/lustre/include/lustre_net.h +++ b/drivers/staging/lustre/lustre/include/lustre_net.h @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/include/lustre_param.h b/drivers/staging/lustre/lustre/include/lustre_param.h index dc6f2b2..82aadd3 100644 --- a/drivers/staging/lustre/lustre/include/lustre_param.h +++ b/drivers/staging/lustre/lustre/include/lustre_param.h @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/include/lustre_req_layout.h b/drivers/staging/lustre/lustre/include/lustre_req_layout.h index acbc310..d00aae5 100644 --- a/drivers/staging/lustre/lustre/include/lustre_req_layout.h +++ b/drivers/staging/lustre/lustre/include/lustre_req_layout.h @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/include/lustre_sec.h b/drivers/staging/lustre/lustre/include/lustre_sec.h index 7ca6204..ed4b4c7 100644 --- a/drivers/staging/lustre/lustre/include/lustre_sec.h +++ b/drivers/staging/lustre/lustre/include/lustre_sec.h @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/include/obd.h b/drivers/staging/lustre/lustre/include/obd.h index 6c94fa4..e654d42 100644 --- a/drivers/staging/lustre/lustre/include/obd.h +++ b/drivers/staging/lustre/lustre/include/obd.h @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/include/obd_cksum.h b/drivers/staging/lustre/lustre/include/obd_cksum.h index 02705a5..a8a81e6 100644 --- a/drivers/staging/lustre/lustre/include/obd_cksum.h +++ b/drivers/staging/lustre/lustre/include/obd_cksum.h @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/include/obd_class.h b/drivers/staging/lustre/lustre/include/obd_class.h index c7a71b2..2196744 100644 --- a/drivers/staging/lustre/lustre/include/obd_class.h +++ b/drivers/staging/lustre/lustre/include/obd_class.h @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/include/obd_support.h b/drivers/staging/lustre/lustre/include/obd_support.h index ce5be73..cdf20d6 100644 --- a/drivers/staging/lustre/lustre/include/obd_support.h +++ b/drivers/staging/lustre/lustre/include/obd_support.h @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/ldlm/interval_tree.c b/drivers/staging/lustre/lustre/ldlm/interval_tree.c index 59bb066..f4a70eb 100644 --- a/drivers/staging/lustre/lustre/ldlm/interval_tree.c +++ b/drivers/staging/lustre/lustre/ldlm/interval_tree.c @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/ldlm/l_lock.c b/drivers/staging/lustre/lustre/ldlm/l_lock.c index c6f7dfd..ea8840c 100644 --- a/drivers/staging/lustre/lustre/ldlm/l_lock.c +++ b/drivers/staging/lustre/lustre/ldlm/l_lock.c @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/ldlm/ldlm_extent.c b/drivers/staging/lustre/lustre/ldlm/ldlm_extent.c index 16c1621..f5023d9 100644 --- a/drivers/staging/lustre/lustre/ldlm/ldlm_extent.c +++ b/drivers/staging/lustre/lustre/ldlm/ldlm_extent.c @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/ldlm/ldlm_flock.c b/drivers/staging/lustre/lustre/ldlm/ldlm_flock.c index 6c0dd7a..38c507f 100644 --- a/drivers/staging/lustre/lustre/ldlm/ldlm_flock.c +++ b/drivers/staging/lustre/lustre/ldlm/ldlm_flock.c @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/ldlm/ldlm_inodebits.c b/drivers/staging/lustre/lustre/ldlm/ldlm_inodebits.c index d98243d..79f4e6f 100644 --- a/drivers/staging/lustre/lustre/ldlm/ldlm_inodebits.c +++ b/drivers/staging/lustre/lustre/ldlm/ldlm_inodebits.c @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/ldlm/ldlm_internal.h b/drivers/staging/lustre/lustre/ldlm/ldlm_internal.h index cc5e654..e4cf65d 100644 --- a/drivers/staging/lustre/lustre/ldlm/ldlm_internal.h +++ b/drivers/staging/lustre/lustre/ldlm/ldlm_internal.h @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/ldlm/ldlm_lib.c b/drivers/staging/lustre/lustre/ldlm/ldlm_lib.c index 1a7eee3..7c832aa 100644 --- a/drivers/staging/lustre/lustre/ldlm/ldlm_lib.c +++ b/drivers/staging/lustre/lustre/ldlm/ldlm_lib.c @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/ldlm/ldlm_lock.c b/drivers/staging/lustre/lustre/ldlm/ldlm_lock.c index 88e9192..1ecdfa2 100644 --- a/drivers/staging/lustre/lustre/ldlm/ldlm_lock.c +++ b/drivers/staging/lustre/lustre/ldlm/ldlm_lock.c @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/ldlm/ldlm_lockd.c b/drivers/staging/lustre/lustre/ldlm/ldlm_lockd.c index 1da0eb2..3eab059 100644 --- a/drivers/staging/lustre/lustre/ldlm/ldlm_lockd.c +++ b/drivers/staging/lustre/lustre/ldlm/ldlm_lockd.c @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/ldlm/ldlm_plain.c b/drivers/staging/lustre/lustre/ldlm/ldlm_plain.c index 621a490..0aed39c 100644 --- a/drivers/staging/lustre/lustre/ldlm/ldlm_plain.c +++ b/drivers/staging/lustre/lustre/ldlm/ldlm_plain.c @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/ldlm/ldlm_pool.c b/drivers/staging/lustre/lustre/ldlm/ldlm_pool.c index 1d9ca31..657ed40 100644 --- a/drivers/staging/lustre/lustre/ldlm/ldlm_pool.c +++ b/drivers/staging/lustre/lustre/ldlm/ldlm_pool.c @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/ldlm/ldlm_request.c b/drivers/staging/lustre/lustre/ldlm/ldlm_request.c index f6b30f6..471ab08 100644 --- a/drivers/staging/lustre/lustre/ldlm/ldlm_request.c +++ b/drivers/staging/lustre/lustre/ldlm/ldlm_request.c @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/ldlm/ldlm_resource.c b/drivers/staging/lustre/lustre/ldlm/ldlm_resource.c index 771c1f8..f7c95b7 100644 --- a/drivers/staging/lustre/lustre/ldlm/ldlm_resource.c +++ b/drivers/staging/lustre/lustre/ldlm/ldlm_resource.c @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/llite/dcache.c b/drivers/staging/lustre/lustre/llite/dcache.c index 908bdc6..9d13d5e 100644 --- a/drivers/staging/lustre/lustre/llite/dcache.c +++ b/drivers/staging/lustre/lustre/llite/dcache.c @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/llite/dir.c b/drivers/staging/lustre/lustre/llite/dir.c index 8854029a..99735f6 100644 --- a/drivers/staging/lustre/lustre/llite/dir.c +++ b/drivers/staging/lustre/lustre/llite/dir.c @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/llite/file.c b/drivers/staging/lustre/lustre/llite/file.c index 104129b..4602596 100644 --- a/drivers/staging/lustre/lustre/llite/file.c +++ b/drivers/staging/lustre/lustre/llite/file.c @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/llite/glimpse.c b/drivers/staging/lustre/lustre/llite/glimpse.c index 8788ee0..92004a0 100644 --- a/drivers/staging/lustre/lustre/llite/glimpse.c +++ b/drivers/staging/lustre/lustre/llite/glimpse.c @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/llite/lcommon_cl.c b/drivers/staging/lustre/lustre/llite/lcommon_cl.c index 28b7482..396e4e4f 100644 --- a/drivers/staging/lustre/lustre/llite/lcommon_cl.c +++ b/drivers/staging/lustre/lustre/llite/lcommon_cl.c @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/llite/lcommon_misc.c b/drivers/staging/lustre/lustre/llite/lcommon_misc.c index e45bd6d..8a508ed 100644 --- a/drivers/staging/lustre/lustre/llite/lcommon_misc.c +++ b/drivers/staging/lustre/lustre/llite/lcommon_misc.c @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/llite/llite_close.c b/drivers/staging/lustre/lustre/llite/llite_close.c index 2e2abc7..2326b40 100644 --- a/drivers/staging/lustre/lustre/llite/llite_close.c +++ b/drivers/staging/lustre/lustre/llite/llite_close.c @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/llite/llite_internal.h b/drivers/staging/lustre/lustre/llite/llite_internal.h index f541634..7c1a3254 100644 --- a/drivers/staging/lustre/lustre/llite/llite_internal.h +++ b/drivers/staging/lustre/lustre/llite/llite_internal.h @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/llite/llite_lib.c b/drivers/staging/lustre/lustre/llite/llite_lib.c index f513b74..ac833db 100644 --- a/drivers/staging/lustre/lustre/llite/llite_lib.c +++ b/drivers/staging/lustre/lustre/llite/llite_lib.c @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/llite/llite_mmap.c b/drivers/staging/lustre/lustre/llite/llite_mmap.c index b569df3..fb1c3b6 100644 --- a/drivers/staging/lustre/lustre/llite/llite_mmap.c +++ b/drivers/staging/lustre/lustre/llite/llite_mmap.c @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/llite/llite_nfs.c b/drivers/staging/lustre/lustre/llite/llite_nfs.c index 086e827..d7878e5 100644 --- a/drivers/staging/lustre/lustre/llite/llite_nfs.c +++ b/drivers/staging/lustre/lustre/llite/llite_nfs.c @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/llite/llite_rmtacl.c b/drivers/staging/lustre/lustre/llite/llite_rmtacl.c index bae3ff0..edb92f9 100644 --- a/drivers/staging/lustre/lustre/llite/llite_rmtacl.c +++ b/drivers/staging/lustre/lustre/llite/llite_rmtacl.c @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/llite/lproc_llite.c b/drivers/staging/lustre/lustre/llite/lproc_llite.c index 2b3a777..6e9a8a5 100644 --- a/drivers/staging/lustre/lustre/llite/lproc_llite.c +++ b/drivers/staging/lustre/lustre/llite/lproc_llite.c @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/llite/namei.c b/drivers/staging/lustre/lustre/llite/namei.c index b7ec512..d7459bd 100644 --- a/drivers/staging/lustre/lustre/llite/namei.c +++ b/drivers/staging/lustre/lustre/llite/namei.c @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/llite/remote_perm.c b/drivers/staging/lustre/lustre/llite/remote_perm.c index 0b96175..9df9e784 100644 --- a/drivers/staging/lustre/lustre/llite/remote_perm.c +++ b/drivers/staging/lustre/lustre/llite/remote_perm.c @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/llite/rw.c b/drivers/staging/lustre/lustre/llite/rw.c index df6cb54..87393c4 100644 --- a/drivers/staging/lustre/lustre/llite/rw.c +++ b/drivers/staging/lustre/lustre/llite/rw.c @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/llite/rw26.c b/drivers/staging/lustre/lustre/llite/rw26.c index d45fdcb..d98c7ac 100644 --- a/drivers/staging/lustre/lustre/llite/rw26.c +++ b/drivers/staging/lustre/lustre/llite/rw26.c @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/llite/statahead.c b/drivers/staging/lustre/lustre/llite/statahead.c index d533954..03ad858 100644 --- a/drivers/staging/lustre/lustre/llite/statahead.c +++ b/drivers/staging/lustre/lustre/llite/statahead.c @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/llite/super25.c b/drivers/staging/lustre/lustre/llite/super25.c index f7f8e23..b40ea79 100644 --- a/drivers/staging/lustre/lustre/llite/super25.c +++ b/drivers/staging/lustre/lustre/llite/super25.c @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/llite/symlink.c b/drivers/staging/lustre/lustre/llite/symlink.c index 12f945e..8c8bdfe 100644 --- a/drivers/staging/lustre/lustre/llite/symlink.c +++ b/drivers/staging/lustre/lustre/llite/symlink.c @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/llite/vvp_dev.c b/drivers/staging/lustre/lustre/llite/vvp_dev.c index da84d95..6c09fb2 100644 --- a/drivers/staging/lustre/lustre/llite/vvp_dev.c +++ b/drivers/staging/lustre/lustre/llite/vvp_dev.c @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/llite/vvp_internal.h b/drivers/staging/lustre/lustre/llite/vvp_internal.h index 6708841..79fc428 100644 --- a/drivers/staging/lustre/lustre/llite/vvp_internal.h +++ b/drivers/staging/lustre/lustre/llite/vvp_internal.h @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/llite/vvp_io.c b/drivers/staging/lustre/lustre/llite/vvp_io.c index 2200d57..94916dc 100644 --- a/drivers/staging/lustre/lustre/llite/vvp_io.c +++ b/drivers/staging/lustre/lustre/llite/vvp_io.c @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/llite/vvp_lock.c b/drivers/staging/lustre/lustre/llite/vvp_lock.c index b5c307f..64be0c9 100644 --- a/drivers/staging/lustre/lustre/llite/vvp_lock.c +++ b/drivers/staging/lustre/lustre/llite/vvp_lock.c @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/llite/vvp_object.c b/drivers/staging/lustre/lustre/llite/vvp_object.c index 11c3004..2c520b0 100644 --- a/drivers/staging/lustre/lustre/llite/vvp_object.c +++ b/drivers/staging/lustre/lustre/llite/vvp_object.c @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/llite/vvp_page.c b/drivers/staging/lustre/lustre/llite/vvp_page.c index ae36c75..2e566d9 100644 --- a/drivers/staging/lustre/lustre/llite/vvp_page.c +++ b/drivers/staging/lustre/lustre/llite/vvp_page.c @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/llite/xattr.c b/drivers/staging/lustre/lustre/llite/xattr.c index a286635..6ce790e 100644 --- a/drivers/staging/lustre/lustre/llite/xattr.c +++ b/drivers/staging/lustre/lustre/llite/xattr.c @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/lmv/lmv_fld.c b/drivers/staging/lustre/lustre/lmv/lmv_fld.c index fcf1b1c..a3d170a 100644 --- a/drivers/staging/lustre/lustre/lmv/lmv_fld.c +++ b/drivers/staging/lustre/lustre/lmv/lmv_fld.c @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/lmv/lmv_intent.c b/drivers/staging/lustre/lustre/lmv/lmv_intent.c index bdf28cd..980c9d4 100644 --- a/drivers/staging/lustre/lustre/lmv/lmv_intent.c +++ b/drivers/staging/lustre/lustre/lmv/lmv_intent.c @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/lmv/lmv_internal.h b/drivers/staging/lustre/lustre/lmv/lmv_internal.h index 267deef..0beafc4 100644 --- a/drivers/staging/lustre/lustre/lmv/lmv_internal.h +++ b/drivers/staging/lustre/lustre/lmv/lmv_internal.h @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/lmv/lmv_obd.c b/drivers/staging/lustre/lustre/lmv/lmv_obd.c index 800033d..ab4f4fb 100644 --- a/drivers/staging/lustre/lustre/lmv/lmv_obd.c +++ b/drivers/staging/lustre/lustre/lmv/lmv_obd.c @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/lmv/lproc_lmv.c b/drivers/staging/lustre/lustre/lmv/lproc_lmv.c index aa68623..c29c361 100644 --- a/drivers/staging/lustre/lustre/lmv/lproc_lmv.c +++ b/drivers/staging/lustre/lustre/lmv/lproc_lmv.c @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/lov/lov_cl_internal.h b/drivers/staging/lustre/lustre/lov/lov_cl_internal.h index 9a2e5e2..9740568 100644 --- a/drivers/staging/lustre/lustre/lov/lov_cl_internal.h +++ b/drivers/staging/lustre/lustre/lov/lov_cl_internal.h @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/lov/lov_dev.c b/drivers/staging/lustre/lustre/lov/lov_dev.c index 21e3054..b1f260d 100644 --- a/drivers/staging/lustre/lustre/lov/lov_dev.c +++ b/drivers/staging/lustre/lustre/lov/lov_dev.c @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/lov/lov_ea.c b/drivers/staging/lustre/lustre/lov/lov_ea.c index 2f8972f..5053dea 100644 --- a/drivers/staging/lustre/lustre/lov/lov_ea.c +++ b/drivers/staging/lustre/lustre/lov/lov_ea.c @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/lov/lov_internal.h b/drivers/staging/lustre/lustre/lov/lov_internal.h index 55fb5bf..12bd511 100644 --- a/drivers/staging/lustre/lustre/lov/lov_internal.h +++ b/drivers/staging/lustre/lustre/lov/lov_internal.h @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/lov/lov_io.c b/drivers/staging/lustre/lustre/lov/lov_io.c index cc70eeb..84032a5 100644 --- a/drivers/staging/lustre/lustre/lov/lov_io.c +++ b/drivers/staging/lustre/lustre/lov/lov_io.c @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/lov/lov_lock.c b/drivers/staging/lustre/lustre/lov/lov_lock.c index 2d87cfa..f3a0583 100644 --- a/drivers/staging/lustre/lustre/lov/lov_lock.c +++ b/drivers/staging/lustre/lustre/lov/lov_lock.c @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/lov/lov_merge.c b/drivers/staging/lustre/lustre/lov/lov_merge.c index f020656..b9c9086 100644 --- a/drivers/staging/lustre/lustre/lov/lov_merge.c +++ b/drivers/staging/lustre/lustre/lov/lov_merge.c @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/lov/lov_obd.c b/drivers/staging/lustre/lustre/lov/lov_obd.c index 9ca7e63..c87096e 100644 --- a/drivers/staging/lustre/lustre/lov/lov_obd.c +++ b/drivers/staging/lustre/lustre/lov/lov_obd.c @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/lov/lov_object.c b/drivers/staging/lustre/lustre/lov/lov_object.c index 08f3d5c..ec55b88 100644 --- a/drivers/staging/lustre/lustre/lov/lov_object.c +++ b/drivers/staging/lustre/lustre/lov/lov_object.c @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/lov/lov_offset.c b/drivers/staging/lustre/lustre/lov/lov_offset.c index 2f568b5..ecca74f 100644 --- a/drivers/staging/lustre/lustre/lov/lov_offset.c +++ b/drivers/staging/lustre/lustre/lov/lov_offset.c @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/lov/lov_pack.c b/drivers/staging/lustre/lustre/lov/lov_pack.c index 69f4a68..869ef41 100644 --- a/drivers/staging/lustre/lustre/lov/lov_pack.c +++ b/drivers/staging/lustre/lustre/lov/lov_pack.c @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/lov/lov_page.c b/drivers/staging/lustre/lustre/lov/lov_page.c index 6c97e6f..c17026f 100644 --- a/drivers/staging/lustre/lustre/lov/lov_page.c +++ b/drivers/staging/lustre/lustre/lov/lov_page.c @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/lov/lov_request.c b/drivers/staging/lustre/lustre/lov/lov_request.c index 83cd6e4..4099b51 100644 --- a/drivers/staging/lustre/lustre/lov/lov_request.c +++ b/drivers/staging/lustre/lustre/lov/lov_request.c @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/lov/lovsub_dev.c b/drivers/staging/lustre/lustre/lov/lovsub_dev.c index cddf3d6..b519a19 100644 --- a/drivers/staging/lustre/lustre/lov/lovsub_dev.c +++ b/drivers/staging/lustre/lustre/lov/lovsub_dev.c @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/lov/lovsub_io.c b/drivers/staging/lustre/lustre/lov/lovsub_io.c index c927406..6a98202 100644 --- a/drivers/staging/lustre/lustre/lov/lovsub_io.c +++ b/drivers/staging/lustre/lustre/lov/lovsub_io.c @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/lov/lovsub_lock.c b/drivers/staging/lustre/lustre/lov/lovsub_lock.c index 06bfdf9..38f9b73 100644 --- a/drivers/staging/lustre/lustre/lov/lovsub_lock.c +++ b/drivers/staging/lustre/lustre/lov/lovsub_lock.c @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/lov/lovsub_object.c b/drivers/staging/lustre/lustre/lov/lovsub_object.c index a1a0f08..fb2f266 100644 --- a/drivers/staging/lustre/lustre/lov/lovsub_object.c +++ b/drivers/staging/lustre/lustre/lov/lovsub_object.c @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/lov/lovsub_page.c b/drivers/staging/lustre/lustre/lov/lovsub_page.c index e8e3475..b2e68c3 100644 --- a/drivers/staging/lustre/lustre/lov/lovsub_page.c +++ b/drivers/staging/lustre/lustre/lov/lovsub_page.c @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/lov/lproc_lov.c b/drivers/staging/lustre/lustre/lov/lproc_lov.c index c5f7aac..eb6d30d 100644 --- a/drivers/staging/lustre/lustre/lov/lproc_lov.c +++ b/drivers/staging/lustre/lustre/lov/lproc_lov.c @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/mdc/lproc_mdc.c b/drivers/staging/lustre/lustre/mdc/lproc_mdc.c index 95a8fcd..98d15fb 100644 --- a/drivers/staging/lustre/lustre/mdc/lproc_mdc.c +++ b/drivers/staging/lustre/lustre/mdc/lproc_mdc.c @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/mdc/mdc_internal.h b/drivers/staging/lustre/lustre/mdc/mdc_internal.h index cd57233..58f2841 100644 --- a/drivers/staging/lustre/lustre/mdc/mdc_internal.h +++ b/drivers/staging/lustre/lustre/mdc/mdc_internal.h @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/mdc/mdc_lib.c b/drivers/staging/lustre/lustre/mdc/mdc_lib.c index 8411729..2703113 100644 --- a/drivers/staging/lustre/lustre/mdc/mdc_lib.c +++ b/drivers/staging/lustre/lustre/mdc/mdc_lib.c @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/mdc/mdc_locks.c b/drivers/staging/lustre/lustre/mdc/mdc_locks.c index c14c9df..b395420 100644 --- a/drivers/staging/lustre/lustre/mdc/mdc_locks.c +++ b/drivers/staging/lustre/lustre/mdc/mdc_locks.c @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/mdc/mdc_reint.c b/drivers/staging/lustre/lustre/mdc/mdc_reint.c index 8380c56..661488e 100644 --- a/drivers/staging/lustre/lustre/mdc/mdc_reint.c +++ b/drivers/staging/lustre/lustre/mdc/mdc_reint.c @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/mdc/mdc_request.c b/drivers/staging/lustre/lustre/mdc/mdc_request.c index e152429..12cb238 100644 --- a/drivers/staging/lustre/lustre/mdc/mdc_request.c +++ b/drivers/staging/lustre/lustre/mdc/mdc_request.c @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/mgc/lproc_mgc.c b/drivers/staging/lustre/lustre/mgc/lproc_mgc.c index c77e120..0735220 100644 --- a/drivers/staging/lustre/lustre/mgc/lproc_mgc.c +++ b/drivers/staging/lustre/lustre/mgc/lproc_mgc.c @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/mgc/mgc_internal.h b/drivers/staging/lustre/lustre/mgc/mgc_internal.h index 0eb31cc..f146f75 100644 --- a/drivers/staging/lustre/lustre/mgc/mgc_internal.h +++ b/drivers/staging/lustre/lustre/mgc/mgc_internal.h @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/mgc/mgc_request.c b/drivers/staging/lustre/lustre/mgc/mgc_request.c index 2a80d85..69f5337 100644 --- a/drivers/staging/lustre/lustre/mgc/mgc_request.c +++ b/drivers/staging/lustre/lustre/mgc/mgc_request.c @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/obdclass/acl.c b/drivers/staging/lustre/lustre/obdclass/acl.c index 9f4eaba..30d8b42 100644 --- a/drivers/staging/lustre/lustre/obdclass/acl.c +++ b/drivers/staging/lustre/lustre/obdclass/acl.c @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/obdclass/cl_internal.h b/drivers/staging/lustre/lustre/obdclass/cl_internal.h index 09a1884..e866754 100644 --- a/drivers/staging/lustre/lustre/obdclass/cl_internal.h +++ b/drivers/staging/lustre/lustre/obdclass/cl_internal.h @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/obdclass/cl_io.c b/drivers/staging/lustre/lustre/obdclass/cl_io.c index dcc1b4e..e72f1fc 100644 --- a/drivers/staging/lustre/lustre/obdclass/cl_io.c +++ b/drivers/staging/lustre/lustre/obdclass/cl_io.c @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/obdclass/cl_lock.c b/drivers/staging/lustre/lustre/obdclass/cl_lock.c index 737612a..9d7b593 100644 --- a/drivers/staging/lustre/lustre/obdclass/cl_lock.c +++ b/drivers/staging/lustre/lustre/obdclass/cl_lock.c @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/obdclass/cl_object.c b/drivers/staging/lustre/lustre/obdclass/cl_object.c index 14da4b1..615158a 100644 --- a/drivers/staging/lustre/lustre/obdclass/cl_object.c +++ b/drivers/staging/lustre/lustre/obdclass/cl_object.c @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/obdclass/cl_page.c b/drivers/staging/lustre/lustre/obdclass/cl_page.c index c014b69..71bff49 100644 --- a/drivers/staging/lustre/lustre/obdclass/cl_page.c +++ b/drivers/staging/lustre/lustre/obdclass/cl_page.c @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/obdclass/class_obd.c b/drivers/staging/lustre/lustre/obdclass/class_obd.c index b8dd638..d9d2a19 100644 --- a/drivers/staging/lustre/lustre/obdclass/class_obd.c +++ b/drivers/staging/lustre/lustre/obdclass/class_obd.c @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/obdclass/debug.c b/drivers/staging/lustre/lustre/obdclass/debug.c index 0786683..8acf672 100644 --- a/drivers/staging/lustre/lustre/obdclass/debug.c +++ b/drivers/staging/lustre/lustre/obdclass/debug.c @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/obdclass/genops.c b/drivers/staging/lustre/lustre/obdclass/genops.c index 2ec9eae..99c2da6 100644 --- a/drivers/staging/lustre/lustre/obdclass/genops.c +++ b/drivers/staging/lustre/lustre/obdclass/genops.c @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/obdclass/kernelcomm.c b/drivers/staging/lustre/lustre/obdclass/kernelcomm.c index 407c41e..a0f65c4 100644 --- a/drivers/staging/lustre/lustre/obdclass/kernelcomm.c +++ b/drivers/staging/lustre/lustre/obdclass/kernelcomm.c @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/obdclass/linux/linux-module.c b/drivers/staging/lustre/lustre/obdclass/linux/linux-module.c index e7beee4..33342bf 100644 --- a/drivers/staging/lustre/lustre/obdclass/linux/linux-module.c +++ b/drivers/staging/lustre/lustre/obdclass/linux/linux-module.c @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/obdclass/linux/linux-obdo.c b/drivers/staging/lustre/lustre/obdclass/linux/linux-obdo.c index 1d4a8d6..c6cc6a7 100644 --- a/drivers/staging/lustre/lustre/obdclass/linux/linux-obdo.c +++ b/drivers/staging/lustre/lustre/obdclass/linux/linux-obdo.c @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/obdclass/linux/linux-sysctl.c b/drivers/staging/lustre/lustre/obdclass/linux/linux-sysctl.c index 58d1a44..8f70dd2 100644 --- a/drivers/staging/lustre/lustre/obdclass/linux/linux-sysctl.c +++ b/drivers/staging/lustre/lustre/obdclass/linux/linux-sysctl.c @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/obdclass/llog.c b/drivers/staging/lustre/lustre/obdclass/llog.c index e100ada..1784ca0 100644 --- a/drivers/staging/lustre/lustre/obdclass/llog.c +++ b/drivers/staging/lustre/lustre/obdclass/llog.c @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/obdclass/llog_cat.c b/drivers/staging/lustre/lustre/obdclass/llog_cat.c index e64a5e5..a82a295 100644 --- a/drivers/staging/lustre/lustre/obdclass/llog_cat.c +++ b/drivers/staging/lustre/lustre/obdclass/llog_cat.c @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/obdclass/llog_internal.h b/drivers/staging/lustre/lustre/obdclass/llog_internal.h index bce65fe..f794952 100644 --- a/drivers/staging/lustre/lustre/obdclass/llog_internal.h +++ b/drivers/staging/lustre/lustre/obdclass/llog_internal.h @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/obdclass/llog_obd.c b/drivers/staging/lustre/lustre/obdclass/llog_obd.c index b06dfe3..6ace7e0 100644 --- a/drivers/staging/lustre/lustre/obdclass/llog_obd.c +++ b/drivers/staging/lustre/lustre/obdclass/llog_obd.c @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/obdclass/llog_swab.c b/drivers/staging/lustre/lustre/obdclass/llog_swab.c index b5281d8..f7b9b19 100644 --- a/drivers/staging/lustre/lustre/obdclass/llog_swab.c +++ b/drivers/staging/lustre/lustre/obdclass/llog_swab.c @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/obdclass/lprocfs_status.c b/drivers/staging/lustre/lustre/obdclass/lprocfs_status.c index 849deb1..279b625 100644 --- a/drivers/staging/lustre/lustre/obdclass/lprocfs_status.c +++ b/drivers/staging/lustre/lustre/obdclass/lprocfs_status.c @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/obdclass/lu_object.c b/drivers/staging/lustre/lustre/obdclass/lu_object.c index 1deaa2b..9b03059 100644 --- a/drivers/staging/lustre/lustre/obdclass/lu_object.c +++ b/drivers/staging/lustre/lustre/obdclass/lu_object.c @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/obdclass/lu_ref.c b/drivers/staging/lustre/lustre/obdclass/lu_ref.c index 6363292..e9f6040 100644 --- a/drivers/staging/lustre/lustre/obdclass/lu_ref.c +++ b/drivers/staging/lustre/lustre/obdclass/lu_ref.c @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/obdclass/lustre_handles.c b/drivers/staging/lustre/lustre/obdclass/lustre_handles.c index 6df2940..082f530 100644 --- a/drivers/staging/lustre/lustre/obdclass/lustre_handles.c +++ b/drivers/staging/lustre/lustre/obdclass/lustre_handles.c @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/obdclass/lustre_peer.c b/drivers/staging/lustre/lustre/obdclass/lustre_peer.c index e0e3a46..5974a9b 100644 --- a/drivers/staging/lustre/lustre/obdclass/lustre_peer.c +++ b/drivers/staging/lustre/lustre/obdclass/lustre_peer.c @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/obdclass/obd_config.c b/drivers/staging/lustre/lustre/obdclass/obd_config.c index 39cfbc51..694c58e 100644 --- a/drivers/staging/lustre/lustre/obdclass/obd_config.c +++ b/drivers/staging/lustre/lustre/obdclass/obd_config.c @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/obdclass/obd_mount.c b/drivers/staging/lustre/lustre/obdclass/obd_mount.c index 7dbf40e..aa84a50e 100644 --- a/drivers/staging/lustre/lustre/obdclass/obd_mount.c +++ b/drivers/staging/lustre/lustre/obdclass/obd_mount.c @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/obdclass/obdo.c b/drivers/staging/lustre/lustre/obdclass/obdo.c index a62bf2b..8583a4a 100644 --- a/drivers/staging/lustre/lustre/obdclass/obdo.c +++ b/drivers/staging/lustre/lustre/obdclass/obdo.c @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/obdclass/statfs_pack.c b/drivers/staging/lustre/lustre/obdclass/statfs_pack.c index d633e22..4bad1fa 100644 --- a/drivers/staging/lustre/lustre/obdclass/statfs_pack.c +++ b/drivers/staging/lustre/lustre/obdclass/statfs_pack.c @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/obdclass/uuid.c b/drivers/staging/lustre/lustre/obdclass/uuid.c index 0dfa444..abd9b1a 100644 --- a/drivers/staging/lustre/lustre/obdclass/uuid.c +++ b/drivers/staging/lustre/lustre/obdclass/uuid.c @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/obdecho/echo_client.c b/drivers/staging/lustre/lustre/obdecho/echo_client.c index d92d85c..5b29c4a 100644 --- a/drivers/staging/lustre/lustre/obdecho/echo_client.c +++ b/drivers/staging/lustre/lustre/obdecho/echo_client.c @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/osc/lproc_osc.c b/drivers/staging/lustre/lustre/osc/lproc_osc.c index f7bdd0a..7e83d39 100644 --- a/drivers/staging/lustre/lustre/osc/lproc_osc.c +++ b/drivers/staging/lustre/lustre/osc/lproc_osc.c @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/osc/osc_cache.c b/drivers/staging/lustre/lustre/osc/osc_cache.c index 4eb1f2af..1a6df43 100644 --- a/drivers/staging/lustre/lustre/osc/osc_cache.c +++ b/drivers/staging/lustre/lustre/osc/osc_cache.c @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/osc/osc_cl_internal.h b/drivers/staging/lustre/lustre/osc/osc_cl_internal.h index 78cab86..437c659 100644 --- a/drivers/staging/lustre/lustre/osc/osc_cl_internal.h +++ b/drivers/staging/lustre/lustre/osc/osc_cl_internal.h @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/osc/osc_dev.c b/drivers/staging/lustre/lustre/osc/osc_dev.c index 1d2938d..83d30c1 100644 --- a/drivers/staging/lustre/lustre/osc/osc_dev.c +++ b/drivers/staging/lustre/lustre/osc/osc_dev.c @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/osc/osc_internal.h b/drivers/staging/lustre/lustre/osc/osc_internal.h index 439118a..7a27f09 100644 --- a/drivers/staging/lustre/lustre/osc/osc_internal.h +++ b/drivers/staging/lustre/lustre/osc/osc_internal.h @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/osc/osc_io.c b/drivers/staging/lustre/lustre/osc/osc_io.c index 79159d9..6e3dcd3 100644 --- a/drivers/staging/lustre/lustre/osc/osc_io.c +++ b/drivers/staging/lustre/lustre/osc/osc_io.c @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/osc/osc_lock.c b/drivers/staging/lustre/lustre/osc/osc_lock.c index fef695b..42def38 100644 --- a/drivers/staging/lustre/lustre/osc/osc_lock.c +++ b/drivers/staging/lustre/lustre/osc/osc_lock.c @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/osc/osc_object.c b/drivers/staging/lustre/lustre/osc/osc_object.c index 2a8b3c2..d211d19 100644 --- a/drivers/staging/lustre/lustre/osc/osc_object.c +++ b/drivers/staging/lustre/lustre/osc/osc_object.c @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/osc/osc_page.c b/drivers/staging/lustre/lustre/osc/osc_page.c index 9ed91c4..57d8a5a 100644 --- a/drivers/staging/lustre/lustre/osc/osc_page.c +++ b/drivers/staging/lustre/lustre/osc/osc_page.c @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/osc/osc_request.c b/drivers/staging/lustre/lustre/osc/osc_request.c index 740c362..7260027 100644 --- a/drivers/staging/lustre/lustre/osc/osc_request.c +++ b/drivers/staging/lustre/lustre/osc/osc_request.c @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/ptlrpc/client.c b/drivers/staging/lustre/lustre/ptlrpc/client.c index 325cce1..22bf893 100644 --- a/drivers/staging/lustre/lustre/ptlrpc/client.c +++ b/drivers/staging/lustre/lustre/ptlrpc/client.c @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/ptlrpc/connection.c b/drivers/staging/lustre/lustre/ptlrpc/connection.c index a1f7d8c..177a379 100644 --- a/drivers/staging/lustre/lustre/ptlrpc/connection.c +++ b/drivers/staging/lustre/lustre/ptlrpc/connection.c @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/ptlrpc/events.c b/drivers/staging/lustre/lustre/ptlrpc/events.c index af841cc..b8ca7d6 100644 --- a/drivers/staging/lustre/lustre/ptlrpc/events.c +++ b/drivers/staging/lustre/lustre/ptlrpc/events.c @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/ptlrpc/import.c b/drivers/staging/lustre/lustre/ptlrpc/import.c index 2930193..914bbd2 100644 --- a/drivers/staging/lustre/lustre/ptlrpc/import.c +++ b/drivers/staging/lustre/lustre/ptlrpc/import.c @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/ptlrpc/layout.c b/drivers/staging/lustre/lustre/ptlrpc/layout.c index f0dca8e..e6ff97d 100644 --- a/drivers/staging/lustre/lustre/ptlrpc/layout.c +++ b/drivers/staging/lustre/lustre/ptlrpc/layout.c @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/ptlrpc/llog_client.c b/drivers/staging/lustre/lustre/ptlrpc/llog_client.c index f335b1f..0f55c01 100644 --- a/drivers/staging/lustre/lustre/ptlrpc/llog_client.c +++ b/drivers/staging/lustre/lustre/ptlrpc/llog_client.c @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/ptlrpc/llog_net.c b/drivers/staging/lustre/lustre/ptlrpc/llog_net.c index ed3e88f..bccdace 100644 --- a/drivers/staging/lustre/lustre/ptlrpc/llog_net.c +++ b/drivers/staging/lustre/lustre/ptlrpc/llog_net.c @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/ptlrpc/lproc_ptlrpc.c b/drivers/staging/lustre/lustre/ptlrpc/lproc_ptlrpc.c index 8d67108..fe6f7a6 100644 --- a/drivers/staging/lustre/lustre/ptlrpc/lproc_ptlrpc.c +++ b/drivers/staging/lustre/lustre/ptlrpc/lproc_ptlrpc.c @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/ptlrpc/niobuf.c b/drivers/staging/lustre/lustre/ptlrpc/niobuf.c index 17dd6ea..ff9a95c 100644 --- a/drivers/staging/lustre/lustre/ptlrpc/niobuf.c +++ b/drivers/staging/lustre/lustre/ptlrpc/niobuf.c @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/ptlrpc/pack_generic.c b/drivers/staging/lustre/lustre/ptlrpc/pack_generic.c index e7187a4..9ff58a1 100644 --- a/drivers/staging/lustre/lustre/ptlrpc/pack_generic.c +++ b/drivers/staging/lustre/lustre/ptlrpc/pack_generic.c @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/ptlrpc/pers.c b/drivers/staging/lustre/lustre/ptlrpc/pers.c index 14608ef..6c820e9 100644 --- a/drivers/staging/lustre/lustre/ptlrpc/pers.c +++ b/drivers/staging/lustre/lustre/ptlrpc/pers.c @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/ptlrpc/pinger.c b/drivers/staging/lustre/lustre/ptlrpc/pinger.c index 8ae6fd1..c0529d8 100644 --- a/drivers/staging/lustre/lustre/ptlrpc/pinger.c +++ b/drivers/staging/lustre/lustre/ptlrpc/pinger.c @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/ptlrpc/ptlrpc_internal.h b/drivers/staging/lustre/lustre/ptlrpc/ptlrpc_internal.h index 52eda29..97e97e2 100644 --- a/drivers/staging/lustre/lustre/ptlrpc/ptlrpc_internal.h +++ b/drivers/staging/lustre/lustre/ptlrpc/ptlrpc_internal.h @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/ptlrpc/ptlrpc_module.c b/drivers/staging/lustre/lustre/ptlrpc/ptlrpc_module.c index e7443f3..a70d584 100644 --- a/drivers/staging/lustre/lustre/ptlrpc/ptlrpc_module.c +++ b/drivers/staging/lustre/lustre/ptlrpc/ptlrpc_module.c @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/ptlrpc/ptlrpcd.c b/drivers/staging/lustre/lustre/ptlrpc/ptlrpcd.c index fd343819..b0cf585 100644 --- a/drivers/staging/lustre/lustre/ptlrpc/ptlrpcd.c +++ b/drivers/staging/lustre/lustre/ptlrpc/ptlrpcd.c @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/ptlrpc/recover.c b/drivers/staging/lustre/lustre/ptlrpc/recover.c index 5c69309..718b3a8 100644 --- a/drivers/staging/lustre/lustre/ptlrpc/recover.c +++ b/drivers/staging/lustre/lustre/ptlrpc/recover.c @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/ptlrpc/sec.c b/drivers/staging/lustre/lustre/ptlrpc/sec.c index 9ec6417..7ab3ae9 100644 --- a/drivers/staging/lustre/lustre/ptlrpc/sec.c +++ b/drivers/staging/lustre/lustre/ptlrpc/sec.c @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/ptlrpc/sec_bulk.c b/drivers/staging/lustre/lustre/ptlrpc/sec_bulk.c index 34e2972..b3e3ed9 100644 --- a/drivers/staging/lustre/lustre/ptlrpc/sec_bulk.c +++ b/drivers/staging/lustre/lustre/ptlrpc/sec_bulk.c @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/ptlrpc/sec_config.c b/drivers/staging/lustre/lustre/ptlrpc/sec_config.c index f7210c8..303bf96 100644 --- a/drivers/staging/lustre/lustre/ptlrpc/sec_config.c +++ b/drivers/staging/lustre/lustre/ptlrpc/sec_config.c @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/ptlrpc/sec_gc.c b/drivers/staging/lustre/lustre/ptlrpc/sec_gc.c index 15d0586..9b9801e 100644 --- a/drivers/staging/lustre/lustre/ptlrpc/sec_gc.c +++ b/drivers/staging/lustre/lustre/ptlrpc/sec_gc.c @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/ptlrpc/sec_lproc.c b/drivers/staging/lustre/lustre/ptlrpc/sec_lproc.c index bba4adf..07273f5 100644 --- a/drivers/staging/lustre/lustre/ptlrpc/sec_lproc.c +++ b/drivers/staging/lustre/lustre/ptlrpc/sec_lproc.c @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/ptlrpc/sec_null.c b/drivers/staging/lustre/lustre/ptlrpc/sec_null.c index 04381af..3306233 100644 --- a/drivers/staging/lustre/lustre/ptlrpc/sec_null.c +++ b/drivers/staging/lustre/lustre/ptlrpc/sec_null.c @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/ptlrpc/sec_plain.c b/drivers/staging/lustre/lustre/ptlrpc/sec_plain.c index a2dd435..ea79b15 100644 --- a/drivers/staging/lustre/lustre/ptlrpc/sec_plain.c +++ b/drivers/staging/lustre/lustre/ptlrpc/sec_plain.c @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/ptlrpc/service.c b/drivers/staging/lustre/lustre/ptlrpc/service.c index f369a5e..4788c49 100644 --- a/drivers/staging/lustre/lustre/ptlrpc/service.c +++ b/drivers/staging/lustre/lustre/ptlrpc/service.c @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ diff --git a/drivers/staging/lustre/lustre/ptlrpc/wiretest.c b/drivers/staging/lustre/lustre/ptlrpc/wiretest.c index 4b9a23e..9fd9de9 100644 --- a/drivers/staging/lustre/lustre/ptlrpc/wiretest.c +++ b/drivers/staging/lustre/lustre/ptlrpc/wiretest.c @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ -- cgit v0.10.2 From 06894eed50785979228f0068e135131aebd03ff1 Mon Sep 17 00:00:00 2001 From: Oleg Drokin Date: Tue, 14 Jun 2016 23:33:41 -0400 Subject: staging/lustre/lov: Fix gpl URL in lov_pool.c There's no longer a matching sun.com URL, so refer to gnu.org copy. Signed-off-by: Oleg Drokin Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/lustre/lustre/lov/lov_pool.c b/drivers/staging/lustre/lustre/lov/lov_pool.c index 75660c5..4c2d217 100644 --- a/drivers/staging/lustre/lustre/lov/lov_pool.c +++ b/drivers/staging/lustre/lustre/lov/lov_pool.c @@ -14,8 +14,8 @@ * in the LICENSE file that accompanied this code). * * You should have received a copy of the GNU General Public License - * version 2 along with this program; If not, see [sun.com URL with a - * copy of GPLv2]. + * version 2 along with this program; If not, see + * http://http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ -- cgit v0.10.2 From 837e4e6e51622e8714b670058b400bcbfcfe934c Mon Sep 17 00:00:00 2001 From: Oleg Drokin Date: Tue, 14 Jun 2016 23:33:42 -0400 Subject: staging/lustre: Remove stray line from selftest/selftest.h The 'copy of GPLv2]' is an ending from template that's no longer needed, so remove it to avoid any extra confusion. Signed-off-by: Oleg Drokin Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/lustre/lnet/selftest/selftest.h b/drivers/staging/lustre/lnet/selftest/selftest.h index 1b21a1a..d033ac0 100644 --- a/drivers/staging/lustre/lnet/selftest/selftest.h +++ b/drivers/staging/lustre/lnet/selftest/selftest.h @@ -16,7 +16,6 @@ * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see * http://www.gnu.org/licenses/gpl-2.0.html - * copy of GPLv2]. * * GPL HEADER END */ -- cgit v0.10.2 From 82ce9365ced9a4c454bfd64ba403ab7e1f33a110 Mon Sep 17 00:00:00 2001 From: Oleg Drokin Date: Tue, 14 Jun 2016 23:33:43 -0400 Subject: staging/lustre/libcfs: Remove "Please contact Oracle" from header The "Please contact Oracle Corporation" lines are removed since not only Oracle has nothing to do with Lustre anymore, there's a pointer to GPL already that's independent of any particular company. Signed-off-by: Oleg Drokin Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/lustre/include/linux/libcfs/libcfs_fail.h b/drivers/staging/lustre/include/linux/libcfs/libcfs_fail.h index 2e008bf..d3f9a60 100644 --- a/drivers/staging/lustre/include/linux/libcfs/libcfs_fail.h +++ b/drivers/staging/lustre/include/linux/libcfs/libcfs_fail.h @@ -16,10 +16,6 @@ * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see http://www.gnu.org/licenses * - * Please contact Oracle Corporation, Inc., 500 Oracle Parkway, Redwood Shores, - * CA 94065 USA or visit www.oracle.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* diff --git a/drivers/staging/lustre/lnet/libcfs/fail.c b/drivers/staging/lustre/lnet/libcfs/fail.c index 086e690..9288ee0 100644 --- a/drivers/staging/lustre/lnet/libcfs/fail.c +++ b/drivers/staging/lustre/lnet/libcfs/fail.c @@ -16,10 +16,6 @@ * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see http://www.gnu.org/licenses * - * Please contact Oracle Corporation, Inc., 500 Oracle Parkway, Redwood Shores, - * CA 94065 USA or visit www.oracle.com if you need additional information or - * have any questions. - * * GPL HEADER END */ /* -- cgit v0.10.2 From 7e573494b8940dd9089de734f47e6933fb46474d Mon Sep 17 00:00:00 2001 From: H Hartley Sweeten Date: Tue, 3 May 2016 12:29:39 -0700 Subject: staging: comedi: das16m1: tidy up copyright and comedi comments Fix the checkpatch.pl issue: WARNING: Block comments use * on subsequent lines Signed-off-by: H Hartley Sweeten Reviewed-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/comedi/drivers/das16m1.c b/drivers/staging/comedi/drivers/das16m1.c index 3a37373..90d3869 100644 --- a/drivers/staging/comedi/drivers/das16m1.c +++ b/drivers/staging/comedi/drivers/das16m1.c @@ -1,56 +1,52 @@ /* - comedi/drivers/das16m1.c - CIO-DAS16/M1 driver - Author: Frank Mori Hess, based on code from the das16 - driver. - Copyright (C) 2001 Frank Mori Hess - - COMEDI - Linux Control and Measurement Device Interface - Copyright (C) 2000 David A. Schleef - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. -*/ + * Comedi driver for CIO-DAS16/M1 + * Author: Frank Mori Hess, based on code from the das16 driver. + * Copyright (C) 2001 Frank Mori Hess + * + * COMEDI - Linux Control and Measurement Device Interface + * Copyright (C) 2000 David A. Schleef + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + /* -Driver: das16m1 -Description: CIO-DAS16/M1 -Author: Frank Mori Hess -Devices: [Measurement Computing] CIO-DAS16/M1 (das16m1) -Status: works - -This driver supports a single board - the CIO-DAS16/M1. -As far as I know, there are no other boards that have -the same register layout. Even the CIO-DAS16/M1/16 is -significantly different. - -I was _barely_ able to reach the full 1 MHz capability -of this board, using a hard real-time interrupt -(set the TRIG_RT flag in your struct comedi_cmd and use -rtlinux or RTAI). The board can't do dma, so the bottleneck is -pulling the data across the ISA bus. I timed the interrupt -handler, and it took my computer ~470 microseconds to pull 512 -samples from the board. So at 1 Mhz sampling rate, -expect your CPU to be spending almost all of its -time in the interrupt handler. - -This board has some unusual restrictions for its channel/gain list. If the -list has 2 or more channels in it, then two conditions must be satisfied: -(1) - even/odd channels must appear at even/odd indices in the list -(2) - the list must have an even number of entries. - -Options: - [0] - base io address - [1] - irq (optional, but you probably want it) - -irq can be omitted, although the cmd interface will not work without it. -*/ + * Driver: das16m1 + * Description: CIO-DAS16/M1 + * Author: Frank Mori Hess + * Devices: [Measurement Computing] CIO-DAS16/M1 (das16m1) + * Status: works + * + * This driver supports a single board - the CIO-DAS16/M1. As far as I know, + * there are no other boards that have the same register layout. Even the + * CIO-DAS16/M1/16 is significantly different. + * + * I was _barely_ able to reach the full 1 MHz capability of this board, using + * a hard real-time interrupt (set the TRIG_RT flag in your struct comedi_cmd + * and use rtlinux or RTAI). The board can't do dma, so the bottleneck is + * pulling the data across the ISA bus. I timed the interrupt handler, and it + * took my computer ~470 microseconds to pull 512 samples from the board. So + * at 1 Mhz sampling rate, expect your CPU to be spending almost all of its + * time in the interrupt handler. + * + * This board has some unusual restrictions for its channel/gain list. If the + * list has 2 or more channels in it, then two conditions must be satisfied: + * (1) - even/odd channels must appear at even/odd indices in the list + * (2) - the list must have an even number of entries. + * + * Configuration options: + * [0] - base io address + * [1] - irq (optional, but you probably want it) + * + * irq can be omitted, although the cmd interface will not work without it. + */ #include #include -- cgit v0.10.2 From 27eeef415d2b0a3f07bfc5c5c2446a35ab87e5f7 Mon Sep 17 00:00:00 2001 From: H Hartley Sweeten Date: Tue, 3 May 2016 12:29:40 -0700 Subject: staging: comedi: das16m1: tidy up comments in das16m1_handler() Fix the checkpatch.pl issue: WARNING: Block comments use a trailing */ on a separate line Signed-off-by: H Hartley Sweeten Reviewed-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/comedi/drivers/das16m1.c b/drivers/staging/comedi/drivers/das16m1.c index 90d3869..75e096a 100644 --- a/drivers/staging/comedi/drivers/das16m1.c +++ b/drivers/staging/comedi/drivers/das16m1.c @@ -405,20 +405,24 @@ static void das16m1_handler(struct comedi_device *dev, unsigned int status) /* figure out how many samples are in fifo */ hw_counter = comedi_8254_read(devpriv->counter, 1); - /* make sure hardware counter reading is not bogus due to initial value - * not having been loaded yet */ + /* + * Make sure hardware counter reading is not bogus due to initial + * value not having been loaded yet. + */ if (devpriv->adc_count == 0 && hw_counter == devpriv->initial_hw_count) { num_samples = 0; } else { - /* The calculation of num_samples looks odd, but it uses the + /* + * The calculation of num_samples looks odd, but it uses the * following facts. 16 bit hardware counter is initialized with * value of zero (which really means 0x1000). The counter * decrements by one on each conversion (when the counter * decrements from zero it goes to 0xffff). num_samples is a * 16 bit variable, so it will roll over in a similar fashion * to the hardware counter. Work it out, and this is what you - * get. */ + * get. + */ num_samples = -hw_counter - devpriv->adc_count; } /* check if we only need some of the points */ @@ -441,8 +445,10 @@ static void das16m1_handler(struct comedi_device *dev, unsigned int status) } } - /* this probably won't catch overruns since the card doesn't generate - * overrun interrupts, but we might as well try */ + /* + * This probably won't catch overruns since the card doesn't generate + * overrun interrupts, but we might as well try. + */ if (status & OVRUN) { async->events |= COMEDI_CB_ERROR; dev_err(dev->class_dev, "fifo overflow\n"); -- cgit v0.10.2 From 50ac3ae33bff7ffa20b47bba4c372f6976ea2be3 Mon Sep 17 00:00:00 2001 From: H Hartley Sweeten Date: Tue, 3 May 2016 12:29:41 -0700 Subject: staging: comedi: das16m1: tidy up comment in das16m1_cmd_exec() Fix the checkpatch.pl issue: WARNING: Block comments use a trailing */ on a separate line Signed-off-by: H Hartley Sweeten Reviewed-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/comedi/drivers/das16m1.c b/drivers/staging/comedi/drivers/das16m1.c index 75e096a..05ceb13 100644 --- a/drivers/staging/comedi/drivers/das16m1.c +++ b/drivers/staging/comedi/drivers/das16m1.c @@ -291,8 +291,10 @@ static int das16m1_cmd_exec(struct comedi_device *dev, /* set control & status register */ byte = 0; - /* if we are using external start trigger (also board dislikes having - * both start and conversion triggers external simultaneously) */ + /* + * If we are using external start trigger (also board dislikes having + * both start and conversion triggers external simultaneously). + */ if (cmd->start_src == TRIG_EXT && cmd->convert_src != TRIG_EXT) byte |= EXT_TRIG_BIT; -- cgit v0.10.2 From 3cea946df7ba1ad96512ba0fb7609683eafb66c9 Mon Sep 17 00:00:00 2001 From: H Hartley Sweeten Date: Tue, 3 May 2016 12:29:42 -0700 Subject: staging: comedi: das16m1: remove unnecessary private data comments These comments are just extra cruft. Removing them also fixes a checkpatch.pl issue: WARNING: Block comments use a trailing */ on a separate line Signed-off-by: H Hartley Sweeten Reviewed-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/comedi/drivers/das16m1.c b/drivers/staging/comedi/drivers/das16m1.c index 05ceb13..078b26e 100644 --- a/drivers/staging/comedi/drivers/das16m1.c +++ b/drivers/staging/comedi/drivers/das16m1.c @@ -120,10 +120,7 @@ static const struct comedi_lrange range_das16m1 = { struct das16m1_private_struct { struct comedi_8254 *counter; unsigned int control_state; - unsigned int adc_count; /* number of samples completed */ - /* initial value in lower half of hardware conversion counter, - * needed to keep track of whether new count has been loaded into - * counter yet (loaded by first sample conversion) */ + unsigned int adc_count; u16 initial_hw_count; unsigned short ai_buffer[FIFO_SIZE]; unsigned long extra_iobase; -- cgit v0.10.2 From 07cbd594f02abe3b414a9318578fd44be1be51b7 Mon Sep 17 00:00:00 2001 From: H Hartley Sweeten Date: Tue, 3 May 2016 12:29:43 -0700 Subject: staging: comedi: das16m1: tidy up register map comment The comment about all the registers is not neccessary. The defines give the same information. This also fixes a checkpatch.pl issue: WARNING: Block comments use * on subsequent lines Signed-off-by: H Hartley Sweeten Reviewed-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/comedi/drivers/das16m1.c b/drivers/staging/comedi/drivers/das16m1.c index 078b26e..6638a9a 100644 --- a/drivers/staging/comedi/drivers/das16m1.c +++ b/drivers/staging/comedi/drivers/das16m1.c @@ -61,25 +61,8 @@ #define FIFO_SIZE 1024 /* 1024 sample fifo */ /* - CIO-DAS16_M1.pdf - - "cio-das16/m1" - - 0 a/d bits 0-3, mux start 12 bit - 1 a/d bits 4-11 unused - 2 status control - 3 di 4 bit do 4 bit - 4 unused clear interrupt - 5 interrupt, pacer - 6 channel/gain queue address - 7 channel/gain queue data - 89ab 8254 - cdef 8254 - 400 8255 - 404-407 8254 - -*/ - + * Register map (dev->iobase) + */ #define DAS16M1_AI 0 /* 16-bit wide register */ #define AI_CHAN(x) ((x) & 0xf) #define DAS16M1_CS 2 -- cgit v0.10.2 From a782a851e3ba67e4bd8360b1429cde3ece7d6957 Mon Sep 17 00:00:00 2001 From: H Hartley Sweeten Date: Tue, 3 May 2016 12:29:44 -0700 Subject: staging: comedi: das16m1: tidy up analog input data register defines Convert the inline helper munge_sample() into a macro and rename the defines for the analog input data register/bits. Use the register define when accessing this register instead of just dev->iobase. Signed-off-by: H Hartley Sweeten Reviewed-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/comedi/drivers/das16m1.c b/drivers/staging/comedi/drivers/das16m1.c index 6638a9a..2c7c86c 100644 --- a/drivers/staging/comedi/drivers/das16m1.c +++ b/drivers/staging/comedi/drivers/das16m1.c @@ -63,8 +63,9 @@ /* * Register map (dev->iobase) */ -#define DAS16M1_AI 0 /* 16-bit wide register */ -#define AI_CHAN(x) ((x) & 0xf) +#define DAS16M1_AI_REG 0x00 /* 16-bit register */ +#define DAS16M1_AI_TO_CHAN(x) (((x) >> 0) & 0xf) +#define DAS16M1_AI_TO_SAMPLE(x) (((x) >> 4) & 0xfff) #define DAS16M1_CS 2 #define EXT_TRIG_BIT 0x1 #define OVRUN 0x20 @@ -109,17 +110,12 @@ struct das16m1_private_struct { unsigned long extra_iobase; }; -static inline unsigned short munge_sample(unsigned short data) -{ - return (data >> 4) & 0xfff; -} - static void munge_sample_array(unsigned short *array, unsigned int num_elements) { unsigned int i; for (i = 0; i < num_elements; i++) - array[i] = munge_sample(array[i]); + array[i] = DAS16M1_AI_TO_SAMPLE(array[i]); } static int das16m1_ai_check_chanlist(struct comedi_device *dev, @@ -331,16 +327,19 @@ static int das16m1_ai_rinsn(struct comedi_device *dev, outb(byte, dev->iobase + DAS16M1_QUEUE_DATA); for (n = 0; n < insn->n; n++) { + unsigned short val; + /* clear IRQDATA bit */ outb(0, dev->iobase + DAS16M1_CLEAR_INTR); /* trigger conversion */ - outb(0, dev->iobase); + outb(0, dev->iobase + DAS16M1_AI_REG); ret = comedi_timeout(dev, s, insn, das16m1_ai_eoc, 0); if (ret) return ret; - data[n] = munge_sample(inw(dev->iobase)); + val = inw(dev->iobase + DAS16M1_AI_REG); + data[n] = DAS16M1_AI_TO_SAMPLE(val); } return n; -- cgit v0.10.2 From cec60bf6ce8a33ce50afd6a5d26ec61d0d36136f Mon Sep 17 00:00:00 2001 From: H Hartley Sweeten Date: Tue, 3 May 2016 12:29:45 -0700 Subject: staging: comedi: das16m1: tidy up control/status register defines Rename the defines for the control/status register/bits. Use the BIT macro to define the bits. Signed-off-by: H Hartley Sweeten Reviewed-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/comedi/drivers/das16m1.c b/drivers/staging/comedi/drivers/das16m1.c index 2c7c86c..49eb829 100644 --- a/drivers/staging/comedi/drivers/das16m1.c +++ b/drivers/staging/comedi/drivers/das16m1.c @@ -66,10 +66,10 @@ #define DAS16M1_AI_REG 0x00 /* 16-bit register */ #define DAS16M1_AI_TO_CHAN(x) (((x) >> 0) & 0xf) #define DAS16M1_AI_TO_SAMPLE(x) (((x) >> 4) & 0xfff) -#define DAS16M1_CS 2 -#define EXT_TRIG_BIT 0x1 -#define OVRUN 0x20 -#define IRQDATA 0x80 +#define DAS16M1_CS_REG 0x02 +#define DAS16M1_CS_EXT_TRIG BIT(0) +#define DAS16M1_CS_OVRUN BIT(5) +#define DAS16M1_CS_IRQDATA BIT(7) #define DAS16M1_DIO 3 #define DAS16M1_CLEAR_INTR 4 #define DAS16M1_INTR_CONTROL 5 @@ -272,9 +272,9 @@ static int das16m1_cmd_exec(struct comedi_device *dev, * both start and conversion triggers external simultaneously). */ if (cmd->start_src == TRIG_EXT && cmd->convert_src != TRIG_EXT) - byte |= EXT_TRIG_BIT; + byte |= DAS16M1_CS_EXT_TRIG; - outb(byte, dev->iobase + DAS16M1_CS); + outb(byte, dev->iobase + DAS16M1_CS_REG); /* clear interrupt bit */ outb(0, dev->iobase + DAS16M1_CLEAR_INTR); @@ -301,8 +301,8 @@ static int das16m1_ai_eoc(struct comedi_device *dev, { unsigned int status; - status = inb(dev->iobase + DAS16M1_CS); - if (status & IRQDATA) + status = inb(dev->iobase + DAS16M1_CS_REG); + if (status & DAS16M1_CS_IRQDATA) return 0; return -EBUSY; } @@ -329,7 +329,7 @@ static int das16m1_ai_rinsn(struct comedi_device *dev, for (n = 0; n < insn->n; n++) { unsigned short val; - /* clear IRQDATA bit */ + /* clear DAS16M1_CS_IRQDATA bit */ outb(0, dev->iobase + DAS16M1_CLEAR_INTR); /* trigger conversion */ outb(0, dev->iobase + DAS16M1_AI_REG); @@ -430,7 +430,7 @@ static void das16m1_handler(struct comedi_device *dev, unsigned int status) * This probably won't catch overruns since the card doesn't generate * overrun interrupts, but we might as well try. */ - if (status & OVRUN) { + if (status & DAS16M1_CS_OVRUN) { async->events |= COMEDI_CB_ERROR; dev_err(dev->class_dev, "fifo overflow\n"); } @@ -445,7 +445,7 @@ static int das16m1_poll(struct comedi_device *dev, struct comedi_subdevice *s) /* prevent race with interrupt handler */ spin_lock_irqsave(&dev->spinlock, flags); - status = inb(dev->iobase + DAS16M1_CS); + status = inb(dev->iobase + DAS16M1_CS_REG); das16m1_handler(dev, status); spin_unlock_irqrestore(&dev->spinlock, flags); @@ -464,9 +464,9 @@ static irqreturn_t das16m1_interrupt(int irq, void *d) /* prevent race with comedi_poll() */ spin_lock(&dev->spinlock); - status = inb(dev->iobase + DAS16M1_CS); + status = inb(dev->iobase + DAS16M1_CS_REG); - if ((status & (IRQDATA | OVRUN)) == 0) { + if ((status & (DAS16M1_CS_IRQDATA | DAS16M1_CS_OVRUN)) == 0) { dev_err(dev->class_dev, "spurious interrupt\n"); spin_unlock(&dev->spinlock); return IRQ_NONE; -- cgit v0.10.2 From 4246a637e781dc8a7f90db1efd7058bd5e452ea3 Mon Sep 17 00:00:00 2001 From: H Hartley Sweeten Date: Tue, 3 May 2016 12:29:46 -0700 Subject: staging: comedi: das16m1: tidy up digital input/output register defines The digtial inputs and outputs are read/written using the same register offset but they are different logical registers. Physically they are the same register with the hi 4 bits returning the inputs and the lo 4 bits driving the outputs. For aesthetics, use two different defines for the registers. Signed-off-by: H Hartley Sweeten Reviewed-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/comedi/drivers/das16m1.c b/drivers/staging/comedi/drivers/das16m1.c index 49eb829..e85d989 100644 --- a/drivers/staging/comedi/drivers/das16m1.c +++ b/drivers/staging/comedi/drivers/das16m1.c @@ -70,7 +70,8 @@ #define DAS16M1_CS_EXT_TRIG BIT(0) #define DAS16M1_CS_OVRUN BIT(5) #define DAS16M1_CS_IRQDATA BIT(7) -#define DAS16M1_DIO 3 +#define DAS16M1_DI_REG 0x03 +#define DAS16M1_DO_REG 0x03 #define DAS16M1_CLEAR_INTR 4 #define DAS16M1_INTR_CONTROL 5 #define EXT_PACER 0x2 @@ -351,7 +352,7 @@ static int das16m1_di_rbits(struct comedi_device *dev, { unsigned int bits; - bits = inb(dev->iobase + DAS16M1_DIO) & 0xf; + bits = inb(dev->iobase + DAS16M1_DI_REG) & 0xf; data[1] = bits; data[0] = 0; @@ -364,7 +365,7 @@ static int das16m1_do_wbits(struct comedi_device *dev, unsigned int *data) { if (comedi_dio_update_state(s, data)) - outb(s->state, dev->iobase + DAS16M1_DIO); + outb(s->state, dev->iobase + DAS16M1_DO_REG); data[1] = s->state; @@ -596,7 +597,7 @@ static int das16m1_attach(struct comedi_device *dev, return ret; /* initialize digital output lines */ - outb(0, dev->iobase + DAS16M1_DIO); + outb(0, dev->iobase + DAS16M1_DO_REG); /* set the interrupt level */ devpriv->control_state = das16m1_irq_bits(dev->irq) << 4; -- cgit v0.10.2 From 6b62e7578b82c797897f960680cebe3c858780d6 Mon Sep 17 00:00:00 2001 From: H Hartley Sweeten Date: Tue, 3 May 2016 12:29:47 -0700 Subject: staging: comedi: das16m1: tidy up clear interrupt register define Rename this define and use a consistent comment throughout the code. Signed-off-by: H Hartley Sweeten Reviewed-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/comedi/drivers/das16m1.c b/drivers/staging/comedi/drivers/das16m1.c index e85d989..dcec4e2 100644 --- a/drivers/staging/comedi/drivers/das16m1.c +++ b/drivers/staging/comedi/drivers/das16m1.c @@ -72,7 +72,7 @@ #define DAS16M1_CS_IRQDATA BIT(7) #define DAS16M1_DI_REG 0x03 #define DAS16M1_DO_REG 0x03 -#define DAS16M1_CLEAR_INTR 4 +#define DAS16M1_CLR_INTR_REG 0x04 #define DAS16M1_INTR_CONTROL 5 #define EXT_PACER 0x2 #define INT_PACER 0x3 @@ -276,8 +276,9 @@ static int das16m1_cmd_exec(struct comedi_device *dev, byte |= DAS16M1_CS_EXT_TRIG; outb(byte, dev->iobase + DAS16M1_CS_REG); - /* clear interrupt bit */ - outb(0, dev->iobase + DAS16M1_CLEAR_INTR); + + /* clear interrupt */ + outb(0, dev->iobase + DAS16M1_CLR_INTR_REG); devpriv->control_state |= INTE; outb(devpriv->control_state, dev->iobase + DAS16M1_INTR_CONTROL); @@ -330,8 +331,8 @@ static int das16m1_ai_rinsn(struct comedi_device *dev, for (n = 0; n < insn->n; n++) { unsigned short val; - /* clear DAS16M1_CS_IRQDATA bit */ - outb(0, dev->iobase + DAS16M1_CLEAR_INTR); + /* clear interrupt */ + outb(0, dev->iobase + DAS16M1_CLR_INTR_REG); /* trigger conversion */ outb(0, dev->iobase + DAS16M1_AI_REG); @@ -476,7 +477,7 @@ static irqreturn_t das16m1_interrupt(int irq, void *d) das16m1_handler(dev, status); /* clear interrupt */ - outb(0, dev->iobase + DAS16M1_CLEAR_INTR); + outb(0, dev->iobase + DAS16M1_CLR_INTR_REG); spin_unlock(&dev->spinlock); return IRQ_HANDLED; -- cgit v0.10.2 From ceb6a45de22f51174e5f508eb403679a7aa127e4 Mon Sep 17 00:00:00 2001 From: H Hartley Sweeten Date: Tue, 3 May 2016 12:29:48 -0700 Subject: staging: comedi: das16m1: remove unnecessary ai 'cancel' operations The comedi core will only call the (*insn_read) and (*do_cmd) functions if the subdevice is not "busy". All async commands are terminated by a (*cancel) operation which clears the INTE and PACER_MASK bits in the interrupt control register. These bits are also cleared when the driver first attaches. There is no need for the (*insn_read) or (*do_cmd) to duplicate the cancel. Signed-off-by: H Hartley Sweeten Reviewed-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/comedi/drivers/das16m1.c b/drivers/staging/comedi/drivers/das16m1.c index dcec4e2..ce788ae 100644 --- a/drivers/staging/comedi/drivers/das16m1.c +++ b/drivers/staging/comedi/drivers/das16m1.c @@ -226,10 +226,6 @@ static int das16m1_cmd_exec(struct comedi_device *dev, struct comedi_cmd *cmd = &async->cmd; unsigned int byte, i; - /* disable interrupts and internal pacer */ - devpriv->control_state &= ~INTE & ~PACER_MASK; - outb(devpriv->control_state, dev->iobase + DAS16M1_INTR_CONTROL); - /* set software count */ devpriv->adc_count = 0; @@ -313,15 +309,10 @@ static int das16m1_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { - struct das16m1_private_struct *devpriv = dev->private; int ret; int n; int byte; - /* disable interrupts and internal pacer */ - devpriv->control_state &= ~INTE & ~PACER_MASK; - outb(devpriv->control_state, dev->iobase + DAS16M1_INTR_CONTROL); - /* setup channel/gain queue */ outb(0, dev->iobase + DAS16M1_QUEUE_ADDR); byte = -- cgit v0.10.2 From 7ca99ee40ea738a607d04c888468882d1bd16e95 Mon Sep 17 00:00:00 2001 From: H Hartley Sweeten Date: Tue, 3 May 2016 12:29:49 -0700 Subject: staging: comedi: das16m1: tidy up interrupt control register defines Rename these defines and use the BIT macro to define the bits. Define some macros for the multi-bit fields in the register. Rename the private data 'control_state' member to better match the register name. Signed-off-by: H Hartley Sweeten Reviewed-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/comedi/drivers/das16m1.c b/drivers/staging/comedi/drivers/das16m1.c index ce788ae..5b1d1fc 100644 --- a/drivers/staging/comedi/drivers/das16m1.c +++ b/drivers/staging/comedi/drivers/das16m1.c @@ -73,11 +73,13 @@ #define DAS16M1_DI_REG 0x03 #define DAS16M1_DO_REG 0x03 #define DAS16M1_CLR_INTR_REG 0x04 -#define DAS16M1_INTR_CONTROL 5 -#define EXT_PACER 0x2 -#define INT_PACER 0x3 -#define PACER_MASK 0x3 -#define INTE 0x80 +#define DAS16M1_INTR_CTRL_REG 0x05 +#define DAS16M1_INTR_CTRL_PACER(x) (((x) & 0x3) << 0) +#define DAS16M1_INTR_CTRL_PACER_EXT DAS16M1_INTR_CTRL_PACER(2) +#define DAS16M1_INTR_CTRL_PACER_INT DAS16M1_INTR_CTRL_PACER(3) +#define DAS16M1_INTR_CTRL_PACER_MASK DAS16M1_INTR_CTRL_PACER(3) +#define DAS16M1_INTR_CTRL_IRQ(x) (((x) & 0x7) << 4) +#define DAS16M1_INTR_CTRL_INTE BIT(7) #define DAS16M1_QUEUE_ADDR 6 #define DAS16M1_QUEUE_DATA 7 #define Q_CHAN(x) ((x) & 0x7) @@ -104,7 +106,7 @@ static const struct comedi_lrange range_das16m1 = { struct das16m1_private_struct { struct comedi_8254 *counter; - unsigned int control_state; + unsigned int intr_ctrl; unsigned int adc_count; u16 initial_hw_count; unsigned short ai_buffer[FIFO_SIZE]; @@ -253,13 +255,13 @@ static int das16m1_cmd_exec(struct comedi_device *dev, } /* enable interrupts and set internal pacer counter mode and counts */ - devpriv->control_state &= ~PACER_MASK; + devpriv->intr_ctrl &= ~DAS16M1_INTR_CTRL_PACER_MASK; if (cmd->convert_src == TRIG_TIMER) { comedi_8254_update_divisors(dev->pacer); comedi_8254_pacer_enable(dev->pacer, 1, 2, true); - devpriv->control_state |= INT_PACER; + devpriv->intr_ctrl |= DAS16M1_INTR_CTRL_PACER_INT; } else { /* TRIG_EXT */ - devpriv->control_state |= EXT_PACER; + devpriv->intr_ctrl |= DAS16M1_INTR_CTRL_PACER_EXT; } /* set control & status register */ @@ -276,8 +278,8 @@ static int das16m1_cmd_exec(struct comedi_device *dev, /* clear interrupt */ outb(0, dev->iobase + DAS16M1_CLR_INTR_REG); - devpriv->control_state |= INTE; - outb(devpriv->control_state, dev->iobase + DAS16M1_INTR_CONTROL); + devpriv->intr_ctrl |= DAS16M1_INTR_CTRL_INTE; + outb(devpriv->intr_ctrl, dev->iobase + DAS16M1_INTR_CTRL_REG); return 0; } @@ -286,8 +288,10 @@ static int das16m1_cancel(struct comedi_device *dev, struct comedi_subdevice *s) { struct das16m1_private_struct *devpriv = dev->private; - devpriv->control_state &= ~INTE & ~PACER_MASK; - outb(devpriv->control_state, dev->iobase + DAS16M1_INTR_CONTROL); + /* disable interrupts and pacer */ + devpriv->intr_ctrl &= ~(DAS16M1_INTR_CTRL_INTE | + DAS16M1_INTR_CTRL_PACER_MASK); + outb(devpriv->intr_ctrl, dev->iobase + DAS16M1_INTR_CTRL_REG); return 0; } @@ -592,8 +596,8 @@ static int das16m1_attach(struct comedi_device *dev, outb(0, dev->iobase + DAS16M1_DO_REG); /* set the interrupt level */ - devpriv->control_state = das16m1_irq_bits(dev->irq) << 4; - outb(devpriv->control_state, dev->iobase + DAS16M1_INTR_CONTROL); + devpriv->intr_ctrl = DAS16M1_INTR_CTRL_IRQ(das16m1_irq_bits(dev->irq)); + outb(devpriv->intr_ctrl, dev->iobase + DAS16M1_INTR_CTRL_REG); return 0; } -- cgit v0.10.2 From c9a050cfbe2c05399c6a27b9ed6a73529e8b6666 Mon Sep 17 00:00:00 2001 From: H Hartley Sweeten Date: Tue, 3 May 2016 12:29:50 -0700 Subject: staging: comedi: das16m1: tidy up queue register defines Rename these defines. Signed-off-by: H Hartley Sweeten Reviewed-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/comedi/drivers/das16m1.c b/drivers/staging/comedi/drivers/das16m1.c index 5b1d1fc..1a8cf92 100644 --- a/drivers/staging/comedi/drivers/das16m1.c +++ b/drivers/staging/comedi/drivers/das16m1.c @@ -80,11 +80,10 @@ #define DAS16M1_INTR_CTRL_PACER_MASK DAS16M1_INTR_CTRL_PACER(3) #define DAS16M1_INTR_CTRL_IRQ(x) (((x) & 0x7) << 4) #define DAS16M1_INTR_CTRL_INTE BIT(7) -#define DAS16M1_QUEUE_ADDR 6 -#define DAS16M1_QUEUE_DATA 7 -#define Q_CHAN(x) ((x) & 0x7) -#define Q_RANGE(x) (((x) & 0xf) << 4) -#define UNIPOLAR 0x40 +#define DAS16M1_Q_ADDR_REG 0x06 +#define DAS16M1_Q_REG 0x07 +#define DAS16M1_Q_CHAN(x) (((x) & 0x7) << 0) +#define DAS16M1_Q_RANGE(x) (((x) & 0xf) << 4) #define DAS16M1_8254_FIRST 0x8 #define DAS16M1_8254_SECOND 0xc #define DAS16M1_82C55 0x400 @@ -247,11 +246,11 @@ static int das16m1_cmd_exec(struct comedi_device *dev, /* setup channel/gain queue */ for (i = 0; i < cmd->chanlist_len; i++) { - outb(i, dev->iobase + DAS16M1_QUEUE_ADDR); + outb(i, dev->iobase + DAS16M1_Q_ADDR_REG); byte = - Q_CHAN(CR_CHAN(cmd->chanlist[i])) | - Q_RANGE(CR_RANGE(cmd->chanlist[i])); - outb(byte, dev->iobase + DAS16M1_QUEUE_DATA); + DAS16M1_Q_CHAN(CR_CHAN(cmd->chanlist[i])) | + DAS16M1_Q_RANGE(CR_RANGE(cmd->chanlist[i])); + outb(byte, dev->iobase + DAS16M1_Q_REG); } /* enable interrupts and set internal pacer counter mode and counts */ @@ -318,10 +317,10 @@ static int das16m1_ai_rinsn(struct comedi_device *dev, int byte; /* setup channel/gain queue */ - outb(0, dev->iobase + DAS16M1_QUEUE_ADDR); - byte = - Q_CHAN(CR_CHAN(insn->chanspec)) | Q_RANGE(CR_RANGE(insn->chanspec)); - outb(byte, dev->iobase + DAS16M1_QUEUE_DATA); + outb(0, dev->iobase + DAS16M1_Q_ADDR_REG); + byte = DAS16M1_Q_CHAN(CR_CHAN(insn->chanspec)) | + DAS16M1_Q_RANGE(CR_RANGE(insn->chanspec)); + outb(byte, dev->iobase + DAS16M1_Q_REG); for (n = 0; n < insn->n; n++) { unsigned short val; -- cgit v0.10.2 From a70615894a091687d9b219d471362fc37e98f07b Mon Sep 17 00:00:00 2001 From: H Hartley Sweeten Date: Tue, 3 May 2016 12:29:51 -0700 Subject: staging: comedi: das16m1: introduce das16m1_ai_set_queue() Introduce a helper function to handle writing the channel/gain data to the queue for single channel reads, (*insn_read), and multi-channel scans, (*do_cmd). Signed-off-by: H Hartley Sweeten Reviewed-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/comedi/drivers/das16m1.c b/drivers/staging/comedi/drivers/das16m1.c index 1a8cf92..b941dcf 100644 --- a/drivers/staging/comedi/drivers/das16m1.c +++ b/drivers/staging/comedi/drivers/das16m1.c @@ -112,6 +112,21 @@ struct das16m1_private_struct { unsigned long extra_iobase; }; +static void das16m1_ai_set_queue(struct comedi_device *dev, + unsigned int *chanspec, unsigned int len) +{ + unsigned int i; + + for (i = 0; i < len; i++) { + unsigned int chan = CR_CHAN(chanspec[i]); + unsigned int range = CR_RANGE(chanspec[i]); + + outb(i, dev->iobase + DAS16M1_Q_ADDR_REG); + outb(DAS16M1_Q_CHAN(chan) | DAS16M1_Q_RANGE(range), + dev->iobase + DAS16M1_Q_REG); + } +} + static void munge_sample_array(unsigned short *array, unsigned int num_elements) { unsigned int i; @@ -225,7 +240,7 @@ static int das16m1_cmd_exec(struct comedi_device *dev, struct das16m1_private_struct *devpriv = dev->private; struct comedi_async *async = s->async; struct comedi_cmd *cmd = &async->cmd; - unsigned int byte, i; + unsigned int byte; /* set software count */ devpriv->adc_count = 0; @@ -244,14 +259,7 @@ static int das16m1_cmd_exec(struct comedi_device *dev, */ devpriv->initial_hw_count = comedi_8254_read(devpriv->counter, 1); - /* setup channel/gain queue */ - for (i = 0; i < cmd->chanlist_len; i++) { - outb(i, dev->iobase + DAS16M1_Q_ADDR_REG); - byte = - DAS16M1_Q_CHAN(CR_CHAN(cmd->chanlist[i])) | - DAS16M1_Q_RANGE(CR_RANGE(cmd->chanlist[i])); - outb(byte, dev->iobase + DAS16M1_Q_REG); - } + das16m1_ai_set_queue(dev, cmd->chanlist, cmd->chanlist_len); /* enable interrupts and set internal pacer counter mode and counts */ devpriv->intr_ctrl &= ~DAS16M1_INTR_CTRL_PACER_MASK; @@ -314,13 +322,8 @@ static int das16m1_ai_rinsn(struct comedi_device *dev, { int ret; int n; - int byte; - /* setup channel/gain queue */ - outb(0, dev->iobase + DAS16M1_Q_ADDR_REG); - byte = DAS16M1_Q_CHAN(CR_CHAN(insn->chanspec)) | - DAS16M1_Q_RANGE(CR_RANGE(insn->chanspec)); - outb(byte, dev->iobase + DAS16M1_Q_REG); + das16m1_ai_set_queue(dev, &insn->chanspec, 1); for (n = 0; n < insn->n; n++) { unsigned short val; -- cgit v0.10.2 From 5c8694d699d44dfe4fa0631f74280c359935d8c5 Mon Sep 17 00:00:00 2001 From: H Hartley Sweeten Date: Tue, 3 May 2016 12:29:52 -0700 Subject: staging: comedi: das16m1: tidy up analog input subdevice init Add some whitespace to the subdevice init and rename the support functions. Signed-off-by: H Hartley Sweeten Reviewed-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/comedi/drivers/das16m1.c b/drivers/staging/comedi/drivers/das16m1.c index b941dcf..b19715c 100644 --- a/drivers/staging/comedi/drivers/das16m1.c +++ b/drivers/staging/comedi/drivers/das16m1.c @@ -163,8 +163,9 @@ static int das16m1_ai_check_chanlist(struct comedi_device *dev, return 0; } -static int das16m1_cmd_test(struct comedi_device *dev, - struct comedi_subdevice *s, struct comedi_cmd *cmd) +static int das16m1_ai_cmdtest(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_cmd *cmd) { int err = 0; @@ -234,8 +235,8 @@ static int das16m1_cmd_test(struct comedi_device *dev, return 0; } -static int das16m1_cmd_exec(struct comedi_device *dev, - struct comedi_subdevice *s) +static int das16m1_ai_cmd(struct comedi_device *dev, + struct comedi_subdevice *s) { struct das16m1_private_struct *devpriv = dev->private; struct comedi_async *async = s->async; @@ -291,7 +292,8 @@ static int das16m1_cmd_exec(struct comedi_device *dev, return 0; } -static int das16m1_cancel(struct comedi_device *dev, struct comedi_subdevice *s) +static int das16m1_ai_cancel(struct comedi_device *dev, + struct comedi_subdevice *s) { struct das16m1_private_struct *devpriv = dev->private; @@ -316,9 +318,10 @@ static int das16m1_ai_eoc(struct comedi_device *dev, return -EBUSY; } -static int das16m1_ai_rinsn(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static int das16m1_ai_insn_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { int ret; int n; @@ -437,7 +440,8 @@ static void das16m1_handler(struct comedi_device *dev, unsigned int status) comedi_handle_events(dev, s); } -static int das16m1_poll(struct comedi_device *dev, struct comedi_subdevice *s) +static int das16m1_ai_poll(struct comedi_device *dev, + struct comedi_subdevice *s) { unsigned long flags; unsigned int status; @@ -552,22 +556,22 @@ static int das16m1_attach(struct comedi_device *dev, if (ret) return ret; + /* Analog Input subdevice */ s = &dev->subdevices[0]; - /* ai */ - s->type = COMEDI_SUBD_AI; - s->subdev_flags = SDF_READABLE | SDF_DIFF; - s->n_chan = 8; - s->maxdata = (1 << 12) - 1; - s->range_table = &range_das16m1; - s->insn_read = das16m1_ai_rinsn; + s->type = COMEDI_SUBD_AI; + s->subdev_flags = SDF_READABLE | SDF_DIFF; + s->n_chan = 8; + s->maxdata = 0x0fff; + s->range_table = &range_das16m1; + s->insn_read = das16m1_ai_insn_read; if (dev->irq) { dev->read_subdev = s; - s->subdev_flags |= SDF_CMD_READ; - s->len_chanlist = 256; - s->do_cmdtest = das16m1_cmd_test; - s->do_cmd = das16m1_cmd_exec; - s->cancel = das16m1_cancel; - s->poll = das16m1_poll; + s->subdev_flags |= SDF_CMD_READ; + s->len_chanlist = 256; + s->do_cmdtest = das16m1_ai_cmdtest; + s->do_cmd = das16m1_ai_cmd; + s->cancel = das16m1_ai_cancel; + s->poll = das16m1_ai_poll; } s = &dev->subdevices[1]; -- cgit v0.10.2 From fdb68f9abd17c8008f36801cf940fd59e7683556 Mon Sep 17 00:00:00 2001 From: H Hartley Sweeten Date: Tue, 3 May 2016 12:29:53 -0700 Subject: staging: comedi: das16m1: tidy up digital input subdevice init Add some whitespace to the subdevice init and rename the support function. Signed-off-by: H Hartley Sweeten Reviewed-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/comedi/drivers/das16m1.c b/drivers/staging/comedi/drivers/das16m1.c index b19715c..f51da80 100644 --- a/drivers/staging/comedi/drivers/das16m1.c +++ b/drivers/staging/comedi/drivers/das16m1.c @@ -347,9 +347,10 @@ static int das16m1_ai_insn_read(struct comedi_device *dev, return n; } -static int das16m1_di_rbits(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static int das16m1_di_insn_bits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { unsigned int bits; @@ -574,14 +575,14 @@ static int das16m1_attach(struct comedi_device *dev, s->poll = das16m1_ai_poll; } + /* Digital Input subdevice */ s = &dev->subdevices[1]; - /* di */ - s->type = COMEDI_SUBD_DI; - s->subdev_flags = SDF_READABLE; - s->n_chan = 4; - s->maxdata = 1; - s->range_table = &range_digital; - s->insn_bits = das16m1_di_rbits; + s->type = COMEDI_SUBD_DI; + s->subdev_flags = SDF_READABLE; + s->n_chan = 4; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_bits = das16m1_di_insn_bits; s = &dev->subdevices[2]; /* do */ -- cgit v0.10.2 From 8500b75c1dbe126df6f1a4b396853769986b155e Mon Sep 17 00:00:00 2001 From: H Hartley Sweeten Date: Tue, 3 May 2016 12:29:54 -0700 Subject: staging: comedi: das16m1: tidy up das16m1_di_insn_bits() The (*insn_bits) for a digital input subdevice only needs to return the state of the inputs in data[1]. Remove the cruft. Signed-off-by: H Hartley Sweeten Reviewed-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/comedi/drivers/das16m1.c b/drivers/staging/comedi/drivers/das16m1.c index f51da80..538544b 100644 --- a/drivers/staging/comedi/drivers/das16m1.c +++ b/drivers/staging/comedi/drivers/das16m1.c @@ -352,11 +352,7 @@ static int das16m1_di_insn_bits(struct comedi_device *dev, struct comedi_insn *insn, unsigned int *data) { - unsigned int bits; - - bits = inb(dev->iobase + DAS16M1_DI_REG) & 0xf; - data[1] = bits; - data[0] = 0; + data[1] = inb(dev->iobase + DAS16M1_DI_REG) & 0xf; return insn->n; } -- cgit v0.10.2 From 702907d7ab040eb9cf9d311878aad4bd64362ef0 Mon Sep 17 00:00:00 2001 From: H Hartley Sweeten Date: Tue, 3 May 2016 12:29:55 -0700 Subject: staging: comedi: das16m1: tidy up digital output subdevice init Add some whitespace to the subdevice init and rename the support function. Signed-off-by: H Hartley Sweeten Reviewed-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/comedi/drivers/das16m1.c b/drivers/staging/comedi/drivers/das16m1.c index 538544b..cb5cd5e 100644 --- a/drivers/staging/comedi/drivers/das16m1.c +++ b/drivers/staging/comedi/drivers/das16m1.c @@ -357,10 +357,10 @@ static int das16m1_di_insn_bits(struct comedi_device *dev, return insn->n; } -static int das16m1_do_wbits(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) +static int das16m1_do_insn_bits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { if (comedi_dio_update_state(s, data)) outb(s->state, dev->iobase + DAS16M1_DO_REG); @@ -580,14 +580,14 @@ static int das16m1_attach(struct comedi_device *dev, s->range_table = &range_digital; s->insn_bits = das16m1_di_insn_bits; + /* Digital Output subdevice */ s = &dev->subdevices[2]; - /* do */ - s->type = COMEDI_SUBD_DO; - s->subdev_flags = SDF_WRITABLE; - s->n_chan = 4; - s->maxdata = 1; - s->range_table = &range_digital; - s->insn_bits = das16m1_do_wbits; + s->type = COMEDI_SUBD_DO; + s->subdev_flags = SDF_WRITABLE; + s->n_chan = 4; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_bits = das16m1_do_insn_bits; s = &dev->subdevices[3]; /* 8255 */ -- cgit v0.10.2 From 255d302dc88f4f00603c5681a01d8c2e7ceaca95 Mon Sep 17 00:00:00 2001 From: H Hartley Sweeten Date: Tue, 3 May 2016 12:29:56 -0700 Subject: staging: comedi: das16m1: tidy up 8254/8255 register defines For aesthetics, rename these defines. Signed-off-by: H Hartley Sweeten Reviewed-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/comedi/drivers/das16m1.c b/drivers/staging/comedi/drivers/das16m1.c index cb5cd5e..824cc94 100644 --- a/drivers/staging/comedi/drivers/das16m1.c +++ b/drivers/staging/comedi/drivers/das16m1.c @@ -84,10 +84,10 @@ #define DAS16M1_Q_REG 0x07 #define DAS16M1_Q_CHAN(x) (((x) & 0x7) << 0) #define DAS16M1_Q_RANGE(x) (((x) & 0xf) << 4) -#define DAS16M1_8254_FIRST 0x8 -#define DAS16M1_8254_SECOND 0xc -#define DAS16M1_82C55 0x400 -#define DAS16M1_8254_THIRD 0x404 +#define DAS16M1_8254_IOBASE1 0x08 +#define DAS16M1_8254_IOBASE2 0x0c +#define DAS16M1_8255_IOBASE 0x400 +#define DAS16M1_8254_IOBASE3 0x404 static const struct comedi_lrange range_das16m1 = { 9, { @@ -524,12 +524,12 @@ static int das16m1_attach(struct comedi_device *dev, ret = comedi_request_region(dev, it->options[0], 0x10); if (ret) return ret; - /* Request an additional region for the 8255 */ - ret = __comedi_request_region(dev, dev->iobase + DAS16M1_82C55, + /* Request an additional region for the 8255 and 3rd 8254 */ + ret = __comedi_request_region(dev, dev->iobase + DAS16M1_8255_IOBASE, DAS16M1_SIZE2); if (ret) return ret; - devpriv->extra_iobase = dev->iobase + DAS16M1_82C55; + devpriv->extra_iobase = dev->iobase + DAS16M1_8255_IOBASE; /* only irqs 2, 3, 4, 5, 6, 7, 10, 11, 12, 14, and 15 are valid */ if ((1 << it->options[1]) & 0xdcfc) { @@ -539,12 +539,12 @@ static int das16m1_attach(struct comedi_device *dev, dev->irq = it->options[1]; } - dev->pacer = comedi_8254_init(dev->iobase + DAS16M1_8254_SECOND, + dev->pacer = comedi_8254_init(dev->iobase + DAS16M1_8254_IOBASE2, I8254_OSC_BASE_10MHZ, I8254_IO8, 0); if (!dev->pacer) return -ENOMEM; - devpriv->counter = comedi_8254_init(dev->iobase + DAS16M1_8254_FIRST, + devpriv->counter = comedi_8254_init(dev->iobase + DAS16M1_8254_IOBASE1, 0, I8254_IO8, 0); if (!devpriv->counter) return -ENOMEM; @@ -589,9 +589,9 @@ static int das16m1_attach(struct comedi_device *dev, s->range_table = &range_digital; s->insn_bits = das16m1_do_insn_bits; + /* Digital I/O subdevice (8255) */ s = &dev->subdevices[3]; - /* 8255 */ - ret = subdev_8255_init(dev, s, NULL, DAS16M1_82C55); + ret = subdev_8255_init(dev, s, NULL, DAS16M1_8255_IOBASE); if (ret) return ret; -- cgit v0.10.2 From 4a026c2ebb8c8dd190c2dd60435a60bb8dfc6ebf Mon Sep 17 00:00:00 2001 From: H Hartley Sweeten Date: Tue, 3 May 2016 12:29:57 -0700 Subject: staging: comedi: das16m1: tidy up misc. defines For aesthetics, move these after the register map defines and rename the FIFO_SIZE define. Signed-off-by: H Hartley Sweeten Reviewed-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/comedi/drivers/das16m1.c b/drivers/staging/comedi/drivers/das16m1.c index 824cc94..6797da1 100644 --- a/drivers/staging/comedi/drivers/das16m1.c +++ b/drivers/staging/comedi/drivers/das16m1.c @@ -56,10 +56,6 @@ #include "8255.h" #include "comedi_8254.h" -#define DAS16M1_SIZE2 8 - -#define FIFO_SIZE 1024 /* 1024 sample fifo */ - /* * Register map (dev->iobase) */ @@ -89,6 +85,10 @@ #define DAS16M1_8255_IOBASE 0x400 #define DAS16M1_8254_IOBASE3 0x404 +#define DAS16M1_SIZE2 0x08 + +#define DAS16M1_AI_FIFO_SZ 1024 /* # samples */ + static const struct comedi_lrange range_das16m1 = { 9, { BIP_RANGE(5), @@ -108,7 +108,7 @@ struct das16m1_private_struct { unsigned int intr_ctrl; unsigned int adc_count; u16 initial_hw_count; - unsigned short ai_buffer[FIFO_SIZE]; + unsigned short ai_buffer[DAS16M1_AI_FIFO_SZ]; unsigned long extra_iobase; }; @@ -411,8 +411,8 @@ static void das16m1_handler(struct comedi_device *dev, unsigned int status) num_samples = cmd->stop_arg * cmd->chanlist_len; } /* make sure we dont try to get too many points if fifo has overrun */ - if (num_samples > FIFO_SIZE) - num_samples = FIFO_SIZE; + if (num_samples > DAS16M1_AI_FIFO_SZ) + num_samples = DAS16M1_AI_FIFO_SZ; insw(dev->iobase, devpriv->ai_buffer, num_samples); munge_sample_array(devpriv->ai_buffer, num_samples); comedi_buf_write_samples(s, devpriv->ai_buffer, num_samples); -- cgit v0.10.2 From 300b31c22503393c6c41c8dbe80281a446f54ca2 Mon Sep 17 00:00:00 2001 From: H Hartley Sweeten Date: Tue, 3 May 2016 12:29:58 -0700 Subject: staging: comedi: das16m1: remove an unnecessery comment The configuration options are listed in the comedi comment block. Signed-off-by: H Hartley Sweeten Reviewed-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/comedi/drivers/das16m1.c b/drivers/staging/comedi/drivers/das16m1.c index 6797da1..3a62f5a 100644 --- a/drivers/staging/comedi/drivers/das16m1.c +++ b/drivers/staging/comedi/drivers/das16m1.c @@ -505,11 +505,6 @@ static int das16m1_irq_bits(unsigned int irq) } } -/* - * Options list: - * 0 I/O base - * 1 IRQ - */ static int das16m1_attach(struct comedi_device *dev, struct comedi_devconfig *it) { -- cgit v0.10.2 From b31cf3126474e71192282c97ae88a6f60b17bea0 Mon Sep 17 00:00:00 2001 From: H Hartley Sweeten Date: Tue, 3 May 2016 12:29:59 -0700 Subject: staging: comedi: das16m1: init local variables when declared For aesthetics, init the comedi_subdevice, comedi_async, and comedi_cmd pointers when the local variables are declared. Signed-off-by: H Hartley Sweeten Reviewed-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/comedi/drivers/das16m1.c b/drivers/staging/comedi/drivers/das16m1.c index 3a62f5a..d4b1b92 100644 --- a/drivers/staging/comedi/drivers/das16m1.c +++ b/drivers/staging/comedi/drivers/das16m1.c @@ -373,16 +373,12 @@ static int das16m1_do_insn_bits(struct comedi_device *dev, static void das16m1_handler(struct comedi_device *dev, unsigned int status) { struct das16m1_private_struct *devpriv = dev->private; - struct comedi_subdevice *s; - struct comedi_async *async; - struct comedi_cmd *cmd; + struct comedi_subdevice *s = dev->read_subdev; + struct comedi_async *async = s->async; + struct comedi_cmd *cmd = &async->cmd; u16 num_samples; u16 hw_counter; - s = dev->read_subdev; - async = s->async; - cmd = &async->cmd; - /* figure out how many samples are in fifo */ hw_counter = comedi_8254_read(devpriv->counter, 1); /* -- cgit v0.10.2 From d0e50e6588e236c17f494b3055be986344692af9 Mon Sep 17 00:00:00 2001 From: H Hartley Sweeten Date: Tue, 3 May 2016 12:30:00 -0700 Subject: staging: comedi: das16m1: minor cleanup to das16m1_ai_insn_read() The (*insn_read) functions return the number of data values read. The 'n' value is correct but for clarity change the return to 'insn->n'. For aesthetics, change the 'n' loop variable name to 'i'. That's more common in comedi drivers. Signed-off-by: H Hartley Sweeten Reviewed-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/comedi/drivers/das16m1.c b/drivers/staging/comedi/drivers/das16m1.c index d4b1b92..c0f2796 100644 --- a/drivers/staging/comedi/drivers/das16m1.c +++ b/drivers/staging/comedi/drivers/das16m1.c @@ -324,11 +324,11 @@ static int das16m1_ai_insn_read(struct comedi_device *dev, unsigned int *data) { int ret; - int n; + int i; das16m1_ai_set_queue(dev, &insn->chanspec, 1); - for (n = 0; n < insn->n; n++) { + for (i = 0; i < insn->n; i++) { unsigned short val; /* clear interrupt */ @@ -341,10 +341,10 @@ static int das16m1_ai_insn_read(struct comedi_device *dev, return ret; val = inw(dev->iobase + DAS16M1_AI_REG); - data[n] = DAS16M1_AI_TO_SAMPLE(val); + data[i] = DAS16M1_AI_TO_SAMPLE(val); } - return n; + return insn->n; } static int das16m1_di_insn_bits(struct comedi_device *dev, -- cgit v0.10.2 From 243c701308e9798d3bdd55cc2446cbbdbc44ea28 Mon Sep 17 00:00:00 2001 From: H Hartley Sweeten Date: Tue, 3 May 2016 12:30:01 -0700 Subject: staging: comedi: das16m1: convert munge_sample_array() into a subdevice (*munge) For aesthetics, convert this function into a subdevice (*munge) function and let the comedi core handle the munging. Add a comment about why the data needs to be munged. Signed-off-by: H Hartley Sweeten Reviewed-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/comedi/drivers/das16m1.c b/drivers/staging/comedi/drivers/das16m1.c index c0f2796..a803032 100644 --- a/drivers/staging/comedi/drivers/das16m1.c +++ b/drivers/staging/comedi/drivers/das16m1.c @@ -127,11 +127,21 @@ static void das16m1_ai_set_queue(struct comedi_device *dev, } } -static void munge_sample_array(unsigned short *array, unsigned int num_elements) +static void das16m1_ai_munge(struct comedi_device *dev, + struct comedi_subdevice *s, + void *data, unsigned int num_bytes, + unsigned int start_chan_index) { + unsigned short *array = data; + unsigned int nsamples = comedi_bytes_to_samples(s, num_bytes); unsigned int i; - for (i = 0; i < num_elements; i++) + /* + * The fifo values have the channel number in the lower 4-bits and + * the sample in the upper 12-bits. This just shifts the values + * to remove the channel numbers. + */ + for (i = 0; i < nsamples; i++) array[i] = DAS16M1_AI_TO_SAMPLE(array[i]); } @@ -410,7 +420,6 @@ static void das16m1_handler(struct comedi_device *dev, unsigned int status) if (num_samples > DAS16M1_AI_FIFO_SZ) num_samples = DAS16M1_AI_FIFO_SZ; insw(dev->iobase, devpriv->ai_buffer, num_samples); - munge_sample_array(devpriv->ai_buffer, num_samples); comedi_buf_write_samples(s, devpriv->ai_buffer, num_samples); devpriv->adc_count += num_samples; @@ -560,6 +569,7 @@ static int das16m1_attach(struct comedi_device *dev, s->do_cmd = das16m1_ai_cmd; s->cancel = das16m1_ai_cancel; s->poll = das16m1_ai_poll; + s->munge = das16m1_ai_munge; } /* Digital Input subdevice */ -- cgit v0.10.2 From cd99cfbe84b2a070b4c2e792b89bec533c668d17 Mon Sep 17 00:00:00 2001 From: H Hartley Sweeten Date: Tue, 3 May 2016 12:30:02 -0700 Subject: staging: comedi: das16m1: rename struct das16m1_private_struct For aesthetics, remove the redundant '_struct' suffix. Signed-off-by: H Hartley Sweeten Reviewed-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/comedi/drivers/das16m1.c b/drivers/staging/comedi/drivers/das16m1.c index a803032..7185b85 100644 --- a/drivers/staging/comedi/drivers/das16m1.c +++ b/drivers/staging/comedi/drivers/das16m1.c @@ -103,7 +103,7 @@ static const struct comedi_lrange range_das16m1 = { } }; -struct das16m1_private_struct { +struct das16m1_private { struct comedi_8254 *counter; unsigned int intr_ctrl; unsigned int adc_count; @@ -248,7 +248,7 @@ static int das16m1_ai_cmdtest(struct comedi_device *dev, static int das16m1_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) { - struct das16m1_private_struct *devpriv = dev->private; + struct das16m1_private *devpriv = dev->private; struct comedi_async *async = s->async; struct comedi_cmd *cmd = &async->cmd; unsigned int byte; @@ -305,7 +305,7 @@ static int das16m1_ai_cmd(struct comedi_device *dev, static int das16m1_ai_cancel(struct comedi_device *dev, struct comedi_subdevice *s) { - struct das16m1_private_struct *devpriv = dev->private; + struct das16m1_private *devpriv = dev->private; /* disable interrupts and pacer */ devpriv->intr_ctrl &= ~(DAS16M1_INTR_CTRL_INTE | @@ -382,7 +382,7 @@ static int das16m1_do_insn_bits(struct comedi_device *dev, static void das16m1_handler(struct comedi_device *dev, unsigned int status) { - struct das16m1_private_struct *devpriv = dev->private; + struct das16m1_private *devpriv = dev->private; struct comedi_subdevice *s = dev->read_subdev; struct comedi_async *async = s->async; struct comedi_cmd *cmd = &async->cmd; @@ -513,7 +513,7 @@ static int das16m1_irq_bits(unsigned int irq) static int das16m1_attach(struct comedi_device *dev, struct comedi_devconfig *it) { - struct das16m1_private_struct *devpriv; + struct das16m1_private *devpriv; struct comedi_subdevice *s; int ret; @@ -608,7 +608,7 @@ static int das16m1_attach(struct comedi_device *dev, static void das16m1_detach(struct comedi_device *dev) { - struct das16m1_private_struct *devpriv = dev->private; + struct das16m1_private *devpriv = dev->private; if (devpriv) { if (devpriv->extra_iobase) -- cgit v0.10.2 From d1aee5dd118f6d0f76db6527ae9734347ca185c0 Mon Sep 17 00:00:00 2001 From: H Hartley Sweeten Date: Tue, 3 May 2016 12:30:03 -0700 Subject: staging: comedi: das16m1: update the MODULE_DESCRIPTION Change the MODULE_DESCRIPTION to something more usefull than the generic "Comedi low-level driver". Signed-off-by: H Hartley Sweeten Reviewed-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/comedi/drivers/das16m1.c b/drivers/staging/comedi/drivers/das16m1.c index 7185b85..bb8d6ec 100644 --- a/drivers/staging/comedi/drivers/das16m1.c +++ b/drivers/staging/comedi/drivers/das16m1.c @@ -627,5 +627,5 @@ static struct comedi_driver das16m1_driver = { module_comedi_driver(das16m1_driver); MODULE_AUTHOR("Comedi http://www.comedi.org"); -MODULE_DESCRIPTION("Comedi low-level driver"); +MODULE_DESCRIPTION("Comedi driver for CIO-DAS16/M1 ISA cards"); MODULE_LICENSE("GPL"); -- cgit v0.10.2 From f7ede00d609d24dae6ef47d294630e81b8ce3091 Mon Sep 17 00:00:00 2001 From: Nikita Eshkeev Date: Tue, 3 May 2016 18:22:23 +0300 Subject: staging:comedi:Use unsigned int instead of unsigned This patch fixed the checkpatch.pl warning: WARNING: Prefer 'unsigned int' to bare use of 'unsigned' Signed-off-by: Nikita Eshkeev Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/comedi/comedi.h b/drivers/staging/comedi/comedi.h index ad5297f..08fb26b 100644 --- a/drivers/staging/comedi/comedi.h +++ b/drivers/staging/comedi/comedi.h @@ -779,7 +779,7 @@ struct comedi_subdinfo { unsigned int flags; unsigned int range_type; unsigned int settling_time_0; - unsigned insn_bits_support; + unsigned int insn_bits_support; unsigned int unused[8]; }; diff --git a/drivers/staging/comedi/drivers/comedi_bond.c b/drivers/staging/comedi/drivers/comedi_bond.c index 50b76ec..64a5ea3 100644 --- a/drivers/staging/comedi/drivers/comedi_bond.c +++ b/drivers/staging/comedi/drivers/comedi_bond.c @@ -55,16 +55,16 @@ struct bonded_device { struct comedi_device *dev; - unsigned minor; - unsigned subdev; - unsigned nchans; + unsigned int minor; + unsigned int subdev; + unsigned int nchans; }; struct comedi_bond_private { char name[256]; struct bonded_device **devs; - unsigned ndevs; - unsigned nchans; + unsigned int ndevs; + unsigned int nchans; }; static int bonding_dio_insn_bits(struct comedi_device *dev, diff --git a/drivers/staging/comedi/drivers/das800.c b/drivers/staging/comedi/drivers/das800.c index b02f122..9059872 100644 --- a/drivers/staging/comedi/drivers/das800.c +++ b/drivers/staging/comedi/drivers/das800.c @@ -218,7 +218,7 @@ struct das800_private { }; static void das800_ind_write(struct comedi_device *dev, - unsigned val, unsigned reg) + unsigned int val, unsigned int reg) { /* * Select dev->iobase + 2 to be desired register @@ -228,7 +228,7 @@ static void das800_ind_write(struct comedi_device *dev, outb(val, dev->iobase + 2); } -static unsigned das800_ind_read(struct comedi_device *dev, unsigned reg) +static unsigned int das800_ind_read(struct comedi_device *dev, unsigned int reg) { /* * Select dev->iobase + 7 to be desired register diff --git a/drivers/staging/comedi/drivers/ni_65xx.c b/drivers/staging/comedi/drivers/ni_65xx.c index 251117b..07f38e3 100644 --- a/drivers/staging/comedi/drivers/ni_65xx.c +++ b/drivers/staging/comedi/drivers/ni_65xx.c @@ -151,10 +151,10 @@ enum ni_65xx_boardid { struct ni_65xx_board { const char *name; - unsigned num_dio_ports; - unsigned num_di_ports; - unsigned num_do_ports; - unsigned legacy_invert:1; + unsigned int num_dio_ports; + unsigned int num_di_ports; + unsigned int num_do_ports; + unsigned int legacy_invert:1; }; static const struct ni_65xx_board ni_65xx_boards[] = { @@ -360,7 +360,7 @@ static int ni_65xx_dio_insn_config(struct comedi_device *dev, unsigned long base_port = (unsigned long)s->private; unsigned int chan = CR_CHAN(insn->chanspec); unsigned int chan_mask = NI_65XX_CHAN_TO_MASK(chan); - unsigned port = base_port + NI_65XX_CHAN_TO_PORT(chan); + unsigned int port = base_port + NI_65XX_CHAN_TO_PORT(chan); unsigned int interval; unsigned int val; @@ -428,14 +428,14 @@ static int ni_65xx_dio_insn_bits(struct comedi_device *dev, unsigned long base_port = (unsigned long)s->private; unsigned int base_chan = CR_CHAN(insn->chanspec); int last_port_offset = NI_65XX_CHAN_TO_PORT(s->n_chan - 1); - unsigned read_bits = 0; + unsigned int read_bits = 0; int port_offset; for (port_offset = NI_65XX_CHAN_TO_PORT(base_chan); port_offset <= last_port_offset; port_offset++) { - unsigned port = base_port + port_offset; + unsigned int port = base_port + port_offset; int base_port_channel = NI_65XX_PORT_TO_CHAN(port_offset); - unsigned port_mask, port_data, bits; + unsigned int port_mask, port_data, bits; int bitshift = base_port_channel - base_chan; if (bitshift >= 32) @@ -640,7 +640,7 @@ static int ni_65xx_auto_attach(struct comedi_device *dev, struct pci_dev *pcidev = comedi_to_pci_dev(dev); const struct ni_65xx_board *board = NULL; struct comedi_subdevice *s; - unsigned i; + unsigned int i; int ret; if (context < ARRAY_SIZE(ni_65xx_boards)) diff --git a/drivers/staging/comedi/drivers/ni_pcidio.c b/drivers/staging/comedi/drivers/ni_pcidio.c index 02a5329..35ef192 100644 --- a/drivers/staging/comedi/drivers/ni_pcidio.c +++ b/drivers/staging/comedi/drivers/ni_pcidio.c @@ -170,12 +170,12 @@ comedi_nonfree_firmware tarball available from http://www.comedi.org #define DMA_Line_Control_Group1 76 #define DMA_Line_Control_Group2 108 /* channel zero is none */ -static inline unsigned primary_DMAChannel_bits(unsigned channel) +static inline unsigned int primary_DMAChannel_bits(unsigned int channel) { return channel & 0x3; } -static inline unsigned secondary_DMAChannel_bits(unsigned channel) +static inline unsigned int secondary_DMAChannel_bits(unsigned int channel) { return (channel << 2) & 0xc; } diff --git a/drivers/staging/comedi/drivers/ni_pcimio.c b/drivers/staging/comedi/drivers/ni_pcimio.c index 344aa34..d891739 100644 --- a/drivers/staging/comedi/drivers/ni_pcimio.c +++ b/drivers/staging/comedi/drivers/ni_pcimio.c @@ -1064,12 +1064,12 @@ static void m_series_init_eeprom_buffer(struct comedi_device *dev) struct mite *mite = devpriv->mite; resource_size_t daq_phys_addr; static const int Start_Cal_EEPROM = 0x400; - static const unsigned window_size = 10; + static const unsigned int window_size = 10; static const int serial_number_eeprom_offset = 0x4; static const int serial_number_eeprom_length = 0x4; - unsigned old_iodwbsr_bits; - unsigned old_iodwbsr1_bits; - unsigned old_iodwcr1_bits; + unsigned int old_iodwbsr_bits; + unsigned int old_iodwbsr1_bits; + unsigned int old_iodwcr1_bits; int i; /* IO Window 1 needs to be temporarily mapped to read the eeprom */ diff --git a/drivers/staging/comedi/drivers/pcmuio.c b/drivers/staging/comedi/drivers/pcmuio.c index 7ea8130..8ad64f2 100644 --- a/drivers/staging/comedi/drivers/pcmuio.c +++ b/drivers/staging/comedi/drivers/pcmuio.c @@ -307,7 +307,7 @@ static void pcmuio_stop_intr(struct comedi_device *dev, static void pcmuio_handle_intr_subdev(struct comedi_device *dev, struct comedi_subdevice *s, - unsigned triggered) + unsigned int triggered) { struct pcmuio_private *devpriv = dev->private; int asic = pcmuio_subdevice_to_asic(s); diff --git a/drivers/staging/comedi/drivers/quatech_daqp_cs.c b/drivers/staging/comedi/drivers/quatech_daqp_cs.c index e9e4313..802f51e 100644 --- a/drivers/staging/comedi/drivers/quatech_daqp_cs.c +++ b/drivers/staging/comedi/drivers/quatech_daqp_cs.c @@ -643,7 +643,7 @@ static int daqp_ao_insn_write(struct comedi_device *dev, outb(0, dev->iobase + DAQP_AUX_REG); for (i = 0; i > insn->n; i++) { - unsigned val = data[i]; + unsigned int val = data[i]; int ret; /* D/A transfer rate is about 8ms */ diff --git a/drivers/staging/comedi/drivers/rtd520.c b/drivers/staging/comedi/drivers/rtd520.c index 9b6c567..0990f62 100644 --- a/drivers/staging/comedi/drivers/rtd520.c +++ b/drivers/staging/comedi/drivers/rtd520.c @@ -362,7 +362,7 @@ struct rtd_private { long ai_count; /* total transfer size (samples) */ int xfer_count; /* # to transfer data. 0->1/2FIFO */ int flags; /* flag event modes */ - unsigned fifosz; + unsigned int fifosz; /* 8254 Timer/Counter gate and clock sources */ unsigned char timer_gate_src[3]; @@ -491,9 +491,9 @@ static void rtd_load_channelgain_list(struct comedi_device *dev, static int rtd520_probe_fifo_depth(struct comedi_device *dev) { unsigned int chanspec = CR_PACK(0, 0, AREF_GROUND); - unsigned i; - static const unsigned limit = 0x2000; - unsigned fifo_size = 0; + unsigned int i; + static const unsigned int limit = 0x2000; + unsigned int fifo_size = 0; writel(0, dev->mmio + LAS0_ADC_FIFO_CLEAR); rtd_load_channelgain_list(dev, 1, &chanspec); @@ -501,7 +501,7 @@ static int rtd520_probe_fifo_depth(struct comedi_device *dev) writel(0, dev->mmio + LAS0_ADC_CONVERSION); /* convert samples */ for (i = 0; i < limit; ++i) { - unsigned fifo_status; + unsigned int fifo_status; /* trigger conversion */ writew(0, dev->mmio + LAS0_ADC); usleep_range(1, 1000); diff --git a/drivers/staging/comedi/drivers/s626.c b/drivers/staging/comedi/drivers/s626.c index c5e0863..4a87b4b 100644 --- a/drivers/staging/comedi/drivers/s626.c +++ b/drivers/staging/comedi/drivers/s626.c @@ -708,7 +708,7 @@ static uint16_t s626_get_mode_a(struct comedi_device *dev, uint16_t cra; uint16_t crb; uint16_t setup; - unsigned cntsrc, clkmult, clkpol, encmode; + unsigned int cntsrc, clkmult, clkpol, encmode; /* Fetch CRA and CRB register images. */ cra = s626_debi_read(dev, S626_LP_CRA(chan)); @@ -763,7 +763,7 @@ static uint16_t s626_get_mode_b(struct comedi_device *dev, uint16_t cra; uint16_t crb; uint16_t setup; - unsigned cntsrc, clkmult, clkpol, encmode; + unsigned int cntsrc, clkmult, clkpol, encmode; /* Fetch CRA and CRB register images. */ cra = s626_debi_read(dev, S626_LP_CRA(chan)); @@ -838,7 +838,7 @@ static void s626_set_mode_a(struct comedi_device *dev, struct s626_private *devpriv = dev->private; uint16_t cra; uint16_t crb; - unsigned cntsrc, clkmult, clkpol; + unsigned int cntsrc, clkmult, clkpol; /* Initialize CRA and CRB images. */ /* Preload trigger is passed through. */ @@ -916,7 +916,7 @@ static void s626_set_mode_b(struct comedi_device *dev, struct s626_private *devpriv = dev->private; uint16_t cra; uint16_t crb; - unsigned cntsrc, clkmult, clkpol; + unsigned int cntsrc, clkmult, clkpol; /* Initialize CRA and CRB images. */ /* IndexSrc is passed through. */ -- cgit v0.10.2 From 8a8f5489db6d54f31cd73177c31de20e40357271 Mon Sep 17 00:00:00 2001 From: H Hartley Sweeten Date: Wed, 4 May 2016 12:47:06 -0700 Subject: staging: comedi: dt2811: tidy up copyright and comedi comments Fix the checkpatch.pl issue: WARNING: Block comments use * on subsequent lines Signed-off-by: H Hartley Sweeten Reviewed-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/comedi/drivers/dt2811.c b/drivers/staging/comedi/drivers/dt2811.c index a807732..499637b 100644 --- a/drivers/staging/comedi/drivers/dt2811.c +++ b/drivers/staging/comedi/drivers/dt2811.c @@ -1,45 +1,45 @@ /* - comedi/drivers/dt2811.c - Hardware driver for Data Translation DT2811 - - COMEDI - Linux Control and Measurement Device Interface - History: - Base Version - David A. Schleef - December 1998 - Updated to work. David does not have a DT2811 - board any longer so this was suffering from bitrot. - Updated performed by ... - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. + * Comedi driver for Data Translation DT2811 + * + * COMEDI - Linux Control and Measurement Device Interface + * History: + * Base Version - David A. Schleef + * December 1998 - Updated to work. David does not have a DT2811 + * board any longer so this was suffering from bitrot. + * Updated performed by ... + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. */ + /* -Driver: dt2811 -Description: Data Translation DT2811 -Author: ds -Devices: [Data Translation] DT2811-PGL (dt2811-pgl), DT2811-PGH (dt2811-pgh) -Status: works - -Configuration options: - [0] - I/O port base address - [1] - IRQ, although this is currently unused - [2] - A/D reference - 0 = signle-ended - 1 = differential - 2 = pseudo-differential (common reference) - [3] - A/D range - 0 = [-5, 5] - 1 = [-2.5, 2.5] - 2 = [0, 5] - [4] - D/A 0 range (same choices) - [4] - D/A 1 range (same choices) -*/ + * Driver: dt2811 + * Description: Data Translation DT2811 + * Author: ds + * Devices: [Data Translation] DT2811-PGL (dt2811-pgl), DT2811-PGH (dt2811-pgh) + * Status: works + * + * Configuration options: + * [0] - I/O port base address + * [1] - IRQ, although this is currently unused + * [2] - A/D reference + * 0 = single-ended + * 1 = differential + * 2 = pseudo-differential (common reference) + * [3] - A/D range + * 0 = [-5, 5] + * 1 = [-2.5, 2.5] + * 2 = [0, 5] + * [4] - D/A 0 range (same as A/D range) + * [5] - D/A 1 range (same as A/D range) + */ #include #include "../comedidev.h" -- cgit v0.10.2 From a40ff88e58d60336aec32e0acf40e3e0fca4ca03 Mon Sep 17 00:00:00 2001 From: H Hartley Sweeten Date: Wed, 4 May 2016 12:47:07 -0700 Subject: staging: comedi: dt2811: remove redundant block comment The configuration options are listed in the comedi comment block. Signed-off-by: H Hartley Sweeten Reviewed-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/comedi/drivers/dt2811.c b/drivers/staging/comedi/drivers/dt2811.c index 499637b..5d550d1 100644 --- a/drivers/staging/comedi/drivers/dt2811.c +++ b/drivers/staging/comedi/drivers/dt2811.c @@ -297,26 +297,6 @@ static int dt2811_do_insn_bits(struct comedi_device *dev, return insn->n; } -/* - options[0] Board base address - options[1] IRQ - options[2] Input configuration - 0 == single-ended - 1 == differential - 2 == pseudo-differential - options[3] Analog input range configuration - 0 == bipolar 5 (-5V -- +5V) - 1 == bipolar 2.5V (-2.5V -- +2.5V) - 2 == unipolar 5V (0V -- +5V) - options[4] Analog output 0 range configuration - 0 == bipolar 5 (-5V -- +5V) - 1 == bipolar 2.5V (-2.5V -- +2.5V) - 2 == unipolar 5V (0V -- +5V) - options[5] Analog output 1 range configuration - 0 == bipolar 5 (-5V -- +5V) - 1 == bipolar 2.5V (-2.5V -- +2.5V) - 2 == unipolar 5V (0V -- +5V) -*/ static int dt2811_attach(struct comedi_device *dev, struct comedi_devconfig *it) { /* int i; */ -- cgit v0.10.2 From 6e4e38b5e6a1a28fda8cf54f124b386d1df73fcd Mon Sep 17 00:00:00 2001 From: H Hartley Sweeten Date: Wed, 4 May 2016 12:47:08 -0700 Subject: staging: comedi: dt2811: remove disabled code There is no reason the (*attach) should be trying to read an analog input sample. Remove this disabled code. Signed-off-by: H Hartley Sweeten Reviewed-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/comedi/drivers/dt2811.c b/drivers/staging/comedi/drivers/dt2811.c index 5d550d1..3cd9fe5 100644 --- a/drivers/staging/comedi/drivers/dt2811.c +++ b/drivers/staging/comedi/drivers/dt2811.c @@ -299,23 +299,15 @@ static int dt2811_do_insn_bits(struct comedi_device *dev, static int dt2811_attach(struct comedi_device *dev, struct comedi_devconfig *it) { - /* int i; */ const struct dt2811_board *board = dev->board_ptr; struct dt2811_private *devpriv; - int ret; struct comedi_subdevice *s; + int ret; ret = comedi_request_region(dev, it->options[0], 0x8); if (ret) return ret; -#if 0 - outb(0, dev->iobase + DT2811_ADCSR); - udelay(100); - i = inb(dev->iobase + DT2811_ADDATLO); - i = inb(dev->iobase + DT2811_ADDATHI); -#endif - ret = comedi_alloc_subdevices(dev, 4); if (ret) return ret; -- cgit v0.10.2 From 022ac9529986e494b39386ab59eb97c99d2e4983 Mon Sep 17 00:00:00 2001 From: H Hartley Sweeten Date: Wed, 4 May 2016 12:47:09 -0700 Subject: staging: comedi: dt2811: tidy up A/D Control/Status register defines Cleanup the defines for this register and its bits and remove the redundant information in the comment. Signed-off-by: H Hartley Sweeten Reviewed-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/comedi/drivers/dt2811.c b/drivers/staging/comedi/drivers/dt2811.c index 3cd9fe5..433cfd1 100644 --- a/drivers/staging/comedi/drivers/dt2811.c +++ b/drivers/staging/comedi/drivers/dt2811.c @@ -44,6 +44,25 @@ #include #include "../comedidev.h" +/* + * Register I/O map + */ +#define DT2811_ADCSR_REG 0x00 /* r/w A/D Control/Status */ +#define DT2811_ADCSR_ADDONE BIT(7) /* r 1=A/D conv done */ +#define DT2811_ADCSR_ADERROR BIT(6) /* r 1=A/D error */ +#define DT2811_ADCSR_ADBUSY BIT(5) /* r 1=A/D busy */ +#define DT2811_ADCSR_CLRERROR BIT(4) +#define DT2811_ADCSR_INTENB BIT(2) /* r/w 1=interupts ena */ +#define DT2811_ADCSR_ADMODE(x) (((x) & 0x3) << 0) +/* single conversion on ADGCR load */ +#define DT2811_ADCSR_ADMODE_SINGLE DT2811_ADCSR_ADMODE(0) +/* continuous conversion, internal clock, (clock enabled on ADGCR load) */ +#define DT2811_ADCSR_ADMODE_CONT DT2811_ADCSR_ADMODE(1) +/* continuous conversion, internal clock, external trigger */ +#define DT2811_ADCSR_ADMODE_EXT_TRIG DT2811_ADCSR_ADMODE(2) +/* continuous conversion, external clock, external trigger */ +#define DT2811_ADCSR_ADMODE_EXT DT2811_ADCSR_ADMODE(3) + static const struct comedi_lrange range_dt2811_pgh_ai_5_unipolar = { 4, { UNI_RANGE(5), @@ -100,28 +119,6 @@ static const struct comedi_lrange range_dt2811_pgl_ai_5_bipolar = { /* - 0x00 ADCSR R/W A/D Control/Status Register - bit 7 - (R) 1 indicates A/D conversion done - reading ADDAT clears bit - (W) ignored - bit 6 - (R) 1 indicates A/D error - (W) ignored - bit 5 - (R) 1 indicates A/D busy, cleared at end - of conversion - (W) ignored - bit 4 - (R) 0 - (W) - bit 3 - (R) 0 - bit 2 - (R/W) 1 indicates interrupts enabled - bits 1,0 - (R/W) mode bits - 00 single conversion on ADGCR load - 01 continuous conversion, internal clock, - (clock enabled on ADGCR load) - 10 continuous conversion, internal clock, - external trigger - 11 continuous conversion, external clock, - external trigger - 0x01 ADGCR R/W A/D Gain/Channel Register bit 6,7 - (R/W) gain select 00 gain=1, both PGH, PGL models @@ -169,7 +166,6 @@ static const struct comedi_lrange range_dt2811_pgl_ai_5_bipolar = { #define TIMEOUT 10000 -#define DT2811_ADCSR 0 #define DT2811_ADGCR 1 #define DT2811_ADDATLO 2 #define DT2811_ADDATHI 3 @@ -180,19 +176,6 @@ static const struct comedi_lrange range_dt2811_pgl_ai_5_bipolar = { #define DT2811_DIO 6 #define DT2811_TMRCTR 7 -/* - * flags - */ - -/* ADCSR */ - -#define DT2811_ADDONE 0x80 -#define DT2811_ADERROR 0x40 -#define DT2811_ADBUSY 0x20 -#define DT2811_CLRERROR 0x10 -#define DT2811_INTENB 0x04 -#define DT2811_ADMODE 0x03 - struct dt2811_board { const char *name; const struct comedi_lrange *bip_5; @@ -227,8 +210,8 @@ static int dt2811_ai_eoc(struct comedi_device *dev, { unsigned int status; - status = inb(dev->iobase + DT2811_ADCSR); - if ((status & DT2811_ADBUSY) == 0) + status = inb(dev->iobase + DT2811_ADCSR_REG); + if ((status & DT2811_ADCSR_ADBUSY) == 0) return 0; return -EBUSY; } -- cgit v0.10.2 From b99c859b8fc3db534c7ef7700c1627d0e3df4dbe Mon Sep 17 00:00:00 2001 From: H Hartley Sweeten Date: Wed, 4 May 2016 12:47:10 -0700 Subject: staging: comedi: dt2811: tidy up A/D Gain/Channel register defines Cleanup the defines for this register and its bits and remove the redundant information in the comment. Make the (*insn_read) use the range to set the gain bits correctly. Currently the gain is always set to 1. Signed-off-by: H Hartley Sweeten Reviewed-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/comedi/drivers/dt2811.c b/drivers/staging/comedi/drivers/dt2811.c index 433cfd1..f72d6c8 100644 --- a/drivers/staging/comedi/drivers/dt2811.c +++ b/drivers/staging/comedi/drivers/dt2811.c @@ -63,6 +63,10 @@ /* continuous conversion, external clock, external trigger */ #define DT2811_ADCSR_ADMODE_EXT DT2811_ADCSR_ADMODE(3) +#define DT2811_ADGCR_REG 0x01 /* r/w A/D Gain/Channel */ +#define DT2811_ADGCR_GAIN(x) (((x) & 0x3) << 6) +#define DT2811_ADGCR_CHAN(x) (((x) & 0xf) << 0) + static const struct comedi_lrange range_dt2811_pgh_ai_5_unipolar = { 4, { UNI_RANGE(5), @@ -119,16 +123,6 @@ static const struct comedi_lrange range_dt2811_pgl_ai_5_bipolar = { /* - 0x01 ADGCR R/W A/D Gain/Channel Register - bit 6,7 - (R/W) gain select - 00 gain=1, both PGH, PGL models - 01 gain=2 PGH, 10 PGL - 10 gain=4 PGH, 100 PGL - 11 gain=8 PGH, 500 PGL - bit 4,5 - reserved - bit 3-0 - (R/W) channel select - channel number from 0-15 - 0x02,0x03 (R) ADDAT A/D Data Register (W) DADAT0 D/A Data Register 0 0x02 low byte @@ -166,7 +160,6 @@ static const struct comedi_lrange range_dt2811_pgl_ai_5_bipolar = { #define TIMEOUT 10000 -#define DT2811_ADGCR 1 #define DT2811_ADDATLO 2 #define DT2811_ADDATHI 3 #define DT2811_DADAT0LO 2 @@ -219,12 +212,15 @@ static int dt2811_ai_eoc(struct comedi_device *dev, static int dt2811_ai_insn(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { - int chan = CR_CHAN(insn->chanspec); + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int range = CR_RANGE(insn->chanspec); int ret; int i; for (i = 0; i < insn->n; i++) { - outb(chan, dev->iobase + DT2811_ADGCR); + /* select channel/gain and trigger conversion */ + outb(DT2811_ADGCR_CHAN(chan) | DT2811_ADGCR_GAIN(range), + dev->iobase + DT2811_ADGCR_REG); ret = comedi_timeout(dev, s, insn, dt2811_ai_eoc, 0); if (ret) -- cgit v0.10.2 From d82985fa4c2e2cc6f10f45a4e62a92ab2bce4cd0 Mon Sep 17 00:00:00 2001 From: H Hartley Sweeten Date: Wed, 4 May 2016 12:47:11 -0700 Subject: staging: comedi: dt2811: tidy up A/D Data register defines Cleanup the defines for these registers and and remove the redundant information in the comment. Tidy up the reading of the data registers in the (*insn_read). Signed-off-by: H Hartley Sweeten Reviewed-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/comedi/drivers/dt2811.c b/drivers/staging/comedi/drivers/dt2811.c index f72d6c8..0c0b7b7 100644 --- a/drivers/staging/comedi/drivers/dt2811.c +++ b/drivers/staging/comedi/drivers/dt2811.c @@ -67,6 +67,9 @@ #define DT2811_ADGCR_GAIN(x) (((x) & 0x3) << 6) #define DT2811_ADGCR_CHAN(x) (((x) & 0xf) << 0) +#define DT2811_ADDATA_LO_REG 0x02 /* r A/D Data low byte */ +#define DT2811_ADDATA_HI_REG 0x03 /* r A/D Data high byte */ + static const struct comedi_lrange range_dt2811_pgh_ai_5_unipolar = { 4, { UNI_RANGE(5), @@ -123,7 +126,7 @@ static const struct comedi_lrange range_dt2811_pgl_ai_5_bipolar = { /* - 0x02,0x03 (R) ADDAT A/D Data Register + 0x02,0x03 (W) DADAT0 D/A Data Register 0 0x02 low byte 0x03 high byte @@ -160,8 +163,6 @@ static const struct comedi_lrange range_dt2811_pgl_ai_5_bipolar = { #define TIMEOUT 10000 -#define DT2811_ADDATLO 2 -#define DT2811_ADDATHI 3 #define DT2811_DADAT0LO 2 #define DT2811_DADAT0HI 3 #define DT2811_DADAT1LO 4 @@ -218,6 +219,8 @@ static int dt2811_ai_insn(struct comedi_device *dev, struct comedi_subdevice *s, int i; for (i = 0; i < insn->n; i++) { + unsigned int val; + /* select channel/gain and trigger conversion */ outb(DT2811_ADGCR_CHAN(chan) | DT2811_ADGCR_GAIN(range), dev->iobase + DT2811_ADGCR_REG); @@ -226,9 +229,11 @@ static int dt2811_ai_insn(struct comedi_device *dev, struct comedi_subdevice *s, if (ret) return ret; - data[i] = inb(dev->iobase + DT2811_ADDATLO); - data[i] |= inb(dev->iobase + DT2811_ADDATHI) << 8; - data[i] &= 0xfff; + val = inb(dev->iobase + DT2811_ADDATA_LO_REG) | + (inb(dev->iobase + DT2811_ADDATA_HI_REG) << 8); + val &= s->maxdata; + + data[i] = val; } return i; -- cgit v0.10.2 From addb85bd6e8ae5a343b991afbed72350435bba00 Mon Sep 17 00:00:00 2001 From: H Hartley Sweeten Date: Wed, 4 May 2016 12:47:12 -0700 Subject: staging: comedi: dt2811: tidy up D/A Data register defines Cleanup the defines for these registers and and remove the redundant information in the comment. Signed-off-by: H Hartley Sweeten Reviewed-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/comedi/drivers/dt2811.c b/drivers/staging/comedi/drivers/dt2811.c index 0c0b7b7..1717281 100644 --- a/drivers/staging/comedi/drivers/dt2811.c +++ b/drivers/staging/comedi/drivers/dt2811.c @@ -70,6 +70,9 @@ #define DT2811_ADDATA_LO_REG 0x02 /* r A/D Data low byte */ #define DT2811_ADDATA_HI_REG 0x03 /* r A/D Data high byte */ +#define DT2811_DADATA_LO_REG(x) (0x02 + ((x) * 2)) /* w D/A Data low */ +#define DT2811_DADATA_HI_REG(x) (0x03 + ((x) * 2)) /* w D/A Data high */ + static const struct comedi_lrange range_dt2811_pgh_ai_5_unipolar = { 4, { UNI_RANGE(5), @@ -125,14 +128,6 @@ static const struct comedi_lrange range_dt2811_pgl_ai_5_bipolar = { }; /* - - 0x02,0x03 - (W) DADAT0 D/A Data Register 0 - 0x02 low byte - 0x03 high byte - - 0x04,0x05 (W) DADAT0 D/A Data Register 1 - 0x06 (R) DIO0 Digital Input Port 0 (W) DIO1 Digital Output Port 1 @@ -163,10 +158,6 @@ static const struct comedi_lrange range_dt2811_pgl_ai_5_bipolar = { #define TIMEOUT 10000 -#define DT2811_DADAT0LO 2 -#define DT2811_DADAT0HI 3 -#define DT2811_DADAT1LO 4 -#define DT2811_DADAT1HI 5 #define DT2811_DIO 6 #define DT2811_TMRCTR 7 @@ -250,9 +241,9 @@ static int dt2811_ao_insn_write(struct comedi_device *dev, for (i = 0; i < insn->n; i++) { val = data[i]; - outb(val & 0xff, dev->iobase + DT2811_DADAT0LO + 2 * chan); + outb(val & 0xff, dev->iobase + DT2811_DADATA_LO_REG(chan)); outb((val >> 8) & 0xff, - dev->iobase + DT2811_DADAT0HI + 2 * chan); + dev->iobase + DT2811_DADATA_HI_REG(chan)); } s->readback[chan] = val; -- cgit v0.10.2 From 3d6dc7838ca1a553628f53a4fb59aa456b3b4195 Mon Sep 17 00:00:00 2001 From: H Hartley Sweeten Date: Wed, 4 May 2016 12:47:13 -0700 Subject: staging: comedi: dt2811: tidy up Digital Input/Output register defines The digital input and outputs are separate ports even though they share the same register offset. For aesthetics, define then separately and remove the redundant information in the comment. Signed-off-by: H Hartley Sweeten Reviewed-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/comedi/drivers/dt2811.c b/drivers/staging/comedi/drivers/dt2811.c index 1717281..61aa323 100644 --- a/drivers/staging/comedi/drivers/dt2811.c +++ b/drivers/staging/comedi/drivers/dt2811.c @@ -73,6 +73,9 @@ #define DT2811_DADATA_LO_REG(x) (0x02 + ((x) * 2)) /* w D/A Data low */ #define DT2811_DADATA_HI_REG(x) (0x03 + ((x) * 2)) /* w D/A Data high */ +#define DT2811_DI_REG 0x06 /* r Digital Input Port 0 */ +#define DT2811_DO_REG 0x06 /* w Digital Output Port 1 */ + static const struct comedi_lrange range_dt2811_pgh_ai_5_unipolar = { 4, { UNI_RANGE(5), @@ -128,9 +131,6 @@ static const struct comedi_lrange range_dt2811_pgl_ai_5_bipolar = { }; /* - 0x06 (R) DIO0 Digital Input Port 0 - (W) DIO1 Digital Output Port 1 - 0x07 TMRCTR (R/W) Timer/Counter Register bits 6,7 - reserved bits 5-3 - Timer frequency control (mantissa) @@ -158,7 +158,6 @@ static const struct comedi_lrange range_dt2811_pgl_ai_5_bipolar = { #define TIMEOUT 10000 -#define DT2811_DIO 6 #define DT2811_TMRCTR 7 struct dt2811_board { @@ -254,7 +253,7 @@ static int dt2811_di_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { - data[1] = inb(dev->iobase + DT2811_DIO); + data[1] = inb(dev->iobase + DT2811_DI_REG); return insn->n; } @@ -265,7 +264,7 @@ static int dt2811_do_insn_bits(struct comedi_device *dev, unsigned int *data) { if (comedi_dio_update_state(s, data)) - outb(s->state, dev->iobase + DT2811_DIO); + outb(s->state, dev->iobase + DT2811_DO_REG); data[1] = s->state; -- cgit v0.10.2 From ef0af0ca910b937f277dea75be4a3e1ea1ed3df5 Mon Sep 17 00:00:00 2001 From: H Hartley Sweeten Date: Wed, 4 May 2016 12:47:14 -0700 Subject: staging: comedi: dt2811: tidy up Timer/Counter register defines This register currently is not being used. For aesthetics, cleanup the define and the comment about the frequency control. Signed-off-by: H Hartley Sweeten Reviewed-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/comedi/drivers/dt2811.c b/drivers/staging/comedi/drivers/dt2811.c index 61aa323..6ea1ad4 100644 --- a/drivers/staging/comedi/drivers/dt2811.c +++ b/drivers/staging/comedi/drivers/dt2811.c @@ -76,6 +76,23 @@ #define DT2811_DI_REG 0x06 /* r Digital Input Port 0 */ #define DT2811_DO_REG 0x06 /* w Digital Output Port 1 */ +/* + * Timer frequency control: + * DT2811_TMRCTR_MANTISSA DT2811_TMRCTR_EXPONENT + * val divisor frequency val multiply divisor/divide frequency by + * 0 1 600 kHz 0 1 + * 1 10 60 kHz 1 10 + * 2 2 300 kHz 2 100 + * 3 3 200 kHz 3 1000 + * 4 4 150 kHz 4 10000 + * 5 5 120 kHz 5 100000 + * 6 6 100 kHz 6 1000000 + * 7 12 50 kHz 7 10000000 + */ +#define DT2811_TMRCTR_REG 0x07 /* r/w Timer/Counter */ +#define DT2811_TMRCTR_MANTISSA(x) (((x) & 0x7) << 3) +#define DT2811_TMRCTR_EXPONENT(x) (((x) & 0x7) << 0) + static const struct comedi_lrange range_dt2811_pgh_ai_5_unipolar = { 4, { UNI_RANGE(5), @@ -130,36 +147,8 @@ static const struct comedi_lrange range_dt2811_pgl_ai_5_bipolar = { } }; -/* - 0x07 TMRCTR (R/W) Timer/Counter Register - bits 6,7 - reserved - bits 5-3 - Timer frequency control (mantissa) - 543 divisor freqency (kHz) - 000 1 600 - 001 10 60 - 010 2 300 - 011 3 200 - 100 4 150 - 101 5 120 - 110 6 100 - 111 12 50 - bits 2-0 - Timer frequency control (exponent) - 210 multiply divisor/divide frequency by - 000 1 - 001 10 - 010 100 - 011 1000 - 100 10000 - 101 100000 - 110 1000000 - 111 10000000 - - */ - #define TIMEOUT 10000 -#define DT2811_TMRCTR 7 - struct dt2811_board { const char *name; const struct comedi_lrange *bip_5; -- cgit v0.10.2 From 1d1209fea1f47ae48f15c23d2df55e2e57ac1088 Mon Sep 17 00:00:00 2001 From: H Hartley Sweeten Date: Wed, 4 May 2016 12:47:15 -0700 Subject: staging: comedi: dt2811: tidy up the digital subdevices Add some whitespace to the digital input and output subdevice initialization. Reorder the initialization a bit. Signed-off-by: H Hartley Sweeten Reviewed-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/comedi/drivers/dt2811.c b/drivers/staging/comedi/drivers/dt2811.c index 6ea1ad4..0512d70 100644 --- a/drivers/staging/comedi/drivers/dt2811.c +++ b/drivers/staging/comedi/drivers/dt2811.c @@ -240,7 +240,8 @@ static int dt2811_ao_insn_write(struct comedi_device *dev, static int dt2811_di_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { data[1] = inb(dev->iobase + DT2811_DI_REG); @@ -357,24 +358,23 @@ static int dt2811_attach(struct comedi_device *dev, struct comedi_devconfig *it) if (ret) return ret; + /* Digital Input subdevice */ s = &dev->subdevices[2]; - /* di subdevice */ - s->type = COMEDI_SUBD_DI; - s->subdev_flags = SDF_READABLE; - s->n_chan = 8; - s->insn_bits = dt2811_di_insn_bits; - s->maxdata = 1; - s->range_table = &range_digital; - + s->type = COMEDI_SUBD_DI; + s->subdev_flags = SDF_READABLE; + s->n_chan = 8; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_bits = dt2811_di_insn_bits; + + /* Digital Output subdevice */ s = &dev->subdevices[3]; - /* do subdevice */ - s->type = COMEDI_SUBD_DO; - s->subdev_flags = SDF_WRITABLE; - s->n_chan = 8; - s->insn_bits = dt2811_do_insn_bits; - s->maxdata = 1; - s->state = 0; - s->range_table = &range_digital; + s->type = COMEDI_SUBD_DO; + s->subdev_flags = SDF_WRITABLE; + s->n_chan = 8; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_bits = dt2811_do_insn_bits; return 0; } -- cgit v0.10.2 From 5fba273959d2143bd3b22b34c698ecbffa90d3f1 Mon Sep 17 00:00:00 2001 From: H Hartley Sweeten Date: Wed, 4 May 2016 12:47:16 -0700 Subject: staging: comedi: dt2811: simplify analog output range options The D/A ranges are not programmable. Currently this driver uses some configuration options to select the comedi_lrange for each channel. This is a bit messy and it requires the user to make sure the correct option value is used. The range information isn't used by the driver. The user space library uses it to convert between raw data values and physical units. If the user passed an incorrect option when attaching the driver the conversion will be incorrect. Simplify the analog output ranges by providing a range_table that contains all the possible output ranges. The user can then select the correct range when converting values. Signed-off-by: H Hartley Sweeten Reviewed-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/comedi/drivers/dt2811.c b/drivers/staging/comedi/drivers/dt2811.c index 0512d70..6850eb8 100644 --- a/drivers/staging/comedi/drivers/dt2811.c +++ b/drivers/staging/comedi/drivers/dt2811.c @@ -37,8 +37,14 @@ * 0 = [-5, 5] * 1 = [-2.5, 2.5] * 2 = [0, 5] - * [4] - D/A 0 range (same as A/D range) - * [5] - D/A 1 range (same as A/D range) + * [4] - D/A 0 range (deprecated, see below) + * [5] - D/A 1 range (deprecated, see below) + * + * Notes: + * - D/A ranges are not programmable. The AO subdevice has a range_table + * containing all the possible analog output ranges. Use the range + * that matches your board configuration to convert between data + * values and physical units. */ #include @@ -147,6 +153,23 @@ static const struct comedi_lrange range_dt2811_pgl_ai_5_bipolar = { } }; +/* + * The Analog Output range is set per-channel using jumpers on the board. + * + * DAC0 Jumpers DAC1 Jumpers + * Output Range W5 W6 W7 W8 W1 W2 W3 W4 + * -5V to +5V In Out In Out In Out In Out + * -2.5V to +2.5V In Out Out In In Out Out In + * 0 to +5V Out In Out In Out In Out In + */ +static const struct comedi_lrange dt2811_ao_ranges = { + 3, { + BIP_RANGE(5), /* default setting from factory */ + BIP_RANGE(2.5), + UNI_RANGE(5) + } +}; + #define TIMEOUT 10000 struct dt2811_board { @@ -164,16 +187,6 @@ struct dt2811_private { enum { adc_singleended, adc_diff, adc_pseudo_diff } adc_mux; - enum { - dac_bipolar_5, dac_bipolar_2_5, dac_unipolar_5 - } dac_range[2]; - const struct comedi_lrange *range_type_list[2]; -}; - -static const struct comedi_lrange *dac_range_types[] = { - &range_bipolar5, - &range_bipolar2_5, - &range_unipolar5 }; static int dt2811_ai_eoc(struct comedi_device *dev, @@ -294,34 +307,6 @@ static int dt2811_attach(struct comedi_device *dev, struct comedi_devconfig *it) devpriv->adc_mux = adc_singleended; break; } - switch (it->options[4]) { - case 0: - devpriv->dac_range[0] = dac_bipolar_5; - break; - case 1: - devpriv->dac_range[0] = dac_bipolar_2_5; - break; - case 2: - devpriv->dac_range[0] = dac_unipolar_5; - break; - default: - devpriv->dac_range[0] = dac_bipolar_5; - break; - } - switch (it->options[5]) { - case 0: - devpriv->dac_range[1] = dac_bipolar_5; - break; - case 1: - devpriv->dac_range[1] = dac_bipolar_2_5; - break; - case 2: - devpriv->dac_range[1] = dac_unipolar_5; - break; - default: - devpriv->dac_range[1] = dac_bipolar_5; - break; - } s = &dev->subdevices[0]; /* initialize the ADC subdevice */ @@ -349,9 +334,7 @@ static int dt2811_attach(struct comedi_device *dev, struct comedi_devconfig *it) s->subdev_flags = SDF_WRITABLE; s->n_chan = 2; s->maxdata = 0xfff; - s->range_table_list = devpriv->range_type_list; - devpriv->range_type_list[0] = dac_range_types[devpriv->dac_range[0]]; - devpriv->range_type_list[1] = dac_range_types[devpriv->dac_range[1]]; + s->range_table = &dt2811_ao_ranges; s->insn_write = dt2811_ao_insn_write; ret = comedi_alloc_subdev_readback(s); -- cgit v0.10.2 From dedfdf9009fde19dbb1e1da9cc42c6dab6795135 Mon Sep 17 00:00:00 2001 From: H Hartley Sweeten Date: Wed, 4 May 2016 12:47:17 -0700 Subject: staging: comedi: dt2811: tidy up analog output subdevice init Add some whitespace to the analog output subdevice initialization. Signed-off-by: H Hartley Sweeten Reviewed-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/comedi/drivers/dt2811.c b/drivers/staging/comedi/drivers/dt2811.c index 6850eb8..b60ee74 100644 --- a/drivers/staging/comedi/drivers/dt2811.c +++ b/drivers/staging/comedi/drivers/dt2811.c @@ -328,14 +328,14 @@ static int dt2811_attach(struct comedi_device *dev, struct comedi_devconfig *it) break; } + /* Analog Output subdevice */ s = &dev->subdevices[1]; - /* ao subdevice */ - s->type = COMEDI_SUBD_AO; - s->subdev_flags = SDF_WRITABLE; - s->n_chan = 2; - s->maxdata = 0xfff; - s->range_table = &dt2811_ao_ranges; - s->insn_write = dt2811_ao_insn_write; + s->type = COMEDI_SUBD_AO; + s->subdev_flags = SDF_WRITABLE; + s->n_chan = 2; + s->maxdata = 0x0fff; + s->range_table = &dt2811_ao_ranges; + s->insn_write = dt2811_ao_insn_write; ret = comedi_alloc_subdev_readback(s); if (ret) -- cgit v0.10.2 From 7c9574090d30609df66d5c39139c82e6b6e98f9c Mon Sep 17 00:00:00 2001 From: H Hartley Sweeten Date: Wed, 4 May 2016 12:47:18 -0700 Subject: staging: comedi: dt2811: simplify A/D reference configuration The analog inputs are confgured with jumpers on the board to be: * 16 single-ended inputs * 8 differential inputs * 16 pseudo-differential inputs (common ground) Simplify the handling of this configuration option and properly set the subdev_flags based on the selected input mode. Signed-off-by: H Hartley Sweeten Reviewed-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/comedi/drivers/dt2811.c b/drivers/staging/comedi/drivers/dt2811.c index b60ee74..1fe657c 100644 --- a/drivers/staging/comedi/drivers/dt2811.c +++ b/drivers/staging/comedi/drivers/dt2811.c @@ -29,10 +29,10 @@ * Configuration options: * [0] - I/O port base address * [1] - IRQ, although this is currently unused - * [2] - A/D reference - * 0 = single-ended - * 1 = differential - * 2 = pseudo-differential (common reference) + * [2] - A/D reference (# of analog inputs) + * 0 = single-ended (16 channels) + * 1 = differential (8 channels) + * 2 = pseudo-differential (16 channels) * [3] - A/D range * 0 = [-5, 5] * 1 = [-2.5, 2.5] @@ -184,9 +184,6 @@ enum { card_2811_pgh, card_2811_pgl }; struct dt2811_private { int ntrig; int curadchan; - enum { - adc_singleended, adc_diff, adc_pseudo_diff - } adc_mux; }; static int dt2811_ai_eoc(struct comedi_device *dev, @@ -293,26 +290,13 @@ static int dt2811_attach(struct comedi_device *dev, struct comedi_devconfig *it) if (!devpriv) return -ENOMEM; - switch (it->options[2]) { - case 0: - devpriv->adc_mux = adc_singleended; - break; - case 1: - devpriv->adc_mux = adc_diff; - break; - case 2: - devpriv->adc_mux = adc_pseudo_diff; - break; - default: - devpriv->adc_mux = adc_singleended; - break; - } - s = &dev->subdevices[0]; /* initialize the ADC subdevice */ s->type = COMEDI_SUBD_AI; - s->subdev_flags = SDF_READABLE | SDF_GROUND; - s->n_chan = devpriv->adc_mux == adc_diff ? 8 : 16; + s->subdev_flags = SDF_READABLE | + (it->options[2] == 1) ? SDF_DIFF : + (it->options[2] == 2) ? SDF_COMMON : SDF_GROUND; + s->n_chan = (it->options[2] == 1) ? 8 : 16; s->insn_read = dt2811_ai_insn; s->maxdata = 0xfff; switch (it->options[3]) { -- cgit v0.10.2 From acd356f9fc4eda5d4523bcede2f461480fc49fe8 Mon Sep 17 00:00:00 2001 From: H Hartley Sweeten Date: Wed, 4 May 2016 12:47:19 -0700 Subject: staging: comedi: dt2811: remove private data The remaining members of the private data are not used by the driver. Remove it and the allocation. Signed-off-by: H Hartley Sweeten Reviewed-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/comedi/drivers/dt2811.c b/drivers/staging/comedi/drivers/dt2811.c index 1fe657c..379b7d5 100644 --- a/drivers/staging/comedi/drivers/dt2811.c +++ b/drivers/staging/comedi/drivers/dt2811.c @@ -181,11 +181,6 @@ struct dt2811_board { enum { card_2811_pgh, card_2811_pgl }; -struct dt2811_private { - int ntrig; - int curadchan; -}; - static int dt2811_ai_eoc(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, @@ -274,7 +269,6 @@ static int dt2811_do_insn_bits(struct comedi_device *dev, static int dt2811_attach(struct comedi_device *dev, struct comedi_devconfig *it) { const struct dt2811_board *board = dev->board_ptr; - struct dt2811_private *devpriv; struct comedi_subdevice *s; int ret; @@ -286,10 +280,6 @@ static int dt2811_attach(struct comedi_device *dev, struct comedi_devconfig *it) if (ret) return ret; - devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); - if (!devpriv) - return -ENOMEM; - s = &dev->subdevices[0]; /* initialize the ADC subdevice */ s->type = COMEDI_SUBD_AI; -- cgit v0.10.2 From 048e27aac962b1079920ab856c7b36c109be8386 Mon Sep 17 00:00:00 2001 From: H Hartley Sweeten Date: Wed, 4 May 2016 12:47:20 -0700 Subject: staging: comedi: dt2811: simplify analog input range options The A/D ranges are not programmable but the gain is. Currently this driver uses a configuration option to select the comedi_lrange that will be used for the analog input subdevice. This requires that the user makes sure the correct option value is used. The user space library uses the range information to convert between raw values and physical units. If the user passed an incorrect option when attaching the driver the conversion will be incorrect. A previous patch allowed the gain to be set based on the chanspec range. Prior to that the gain was always set to 1 so any conversion with a gain that is not 1 would be incorrect anyway. Simplify the analog input ranges by providing a range_table for the pgh and pgl boards that contain all the possible range/gain options. The user can then select the correct range (and gain) when converting values or reading the analog inputs. Signed-off-by: H Hartley Sweeten Reviewed-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/comedi/drivers/dt2811.c b/drivers/staging/comedi/drivers/dt2811.c index 379b7d5..f0b3c5e 100644 --- a/drivers/staging/comedi/drivers/dt2811.c +++ b/drivers/staging/comedi/drivers/dt2811.c @@ -33,14 +33,17 @@ * 0 = single-ended (16 channels) * 1 = differential (8 channels) * 2 = pseudo-differential (16 channels) - * [3] - A/D range - * 0 = [-5, 5] - * 1 = [-2.5, 2.5] - * 2 = [0, 5] + * [3] - A/D range (deprecated, see below) * [4] - D/A 0 range (deprecated, see below) * [5] - D/A 1 range (deprecated, see below) * * Notes: + * - A/D ranges are not programmable but the gain is. The AI subdevice has + * a range_table containing all the possible analog input range/gain + * options for the dt2811-pgh or dt2811-pgl. Use the range that matches + * your board configuration and the desired gain to correctly convert + * between data values and physical units and to set the correct output + * gain. * - D/A ranges are not programmable. The AO subdevice has a range_table * containing all the possible analog output ranges. Use the range * that matches your board configuration to convert between data @@ -99,57 +102,52 @@ #define DT2811_TMRCTR_MANTISSA(x) (((x) & 0x7) << 3) #define DT2811_TMRCTR_EXPONENT(x) (((x) & 0x7) << 0) -static const struct comedi_lrange range_dt2811_pgh_ai_5_unipolar = { - 4, { - UNI_RANGE(5), - UNI_RANGE(2.5), - UNI_RANGE(1.25), - UNI_RANGE(0.625) - } -}; - -static const struct comedi_lrange range_dt2811_pgh_ai_2_5_bipolar = { - 4, { - BIP_RANGE(2.5), - BIP_RANGE(1.25), - BIP_RANGE(0.625), - BIP_RANGE(0.3125) - } -}; - -static const struct comedi_lrange range_dt2811_pgh_ai_5_bipolar = { - 4, { - BIP_RANGE(5), - BIP_RANGE(2.5), - BIP_RANGE(1.25), - BIP_RANGE(0.625) - } -}; - -static const struct comedi_lrange range_dt2811_pgl_ai_5_unipolar = { - 4, { - UNI_RANGE(5), - UNI_RANGE(0.5), - UNI_RANGE(0.05), - UNI_RANGE(0.01) - } -}; - -static const struct comedi_lrange range_dt2811_pgl_ai_2_5_bipolar = { - 4, { - BIP_RANGE(2.5), - BIP_RANGE(0.25), - BIP_RANGE(0.025), - BIP_RANGE(0.005) +/* + * The Analog Input range is set using jumpers on the board. + * + * Input Range W9 W10 + * -5V to +5V In Out + * -2.5V to +2.5V In In + * 0V to +5V Out In + * + * The gain may be set to 1, 2, 4, or 8 (on the dt2811-pgh) or to + * 1, 10, 100, 500 (on the dt2811-pgl). + */ +static const struct comedi_lrange dt2811_pgh_ai_ranges = { + 12, { + BIP_RANGE(5), /* range 0: gain=1 */ + BIP_RANGE(2.5), /* range 1: gain=2 */ + BIP_RANGE(1.25), /* range 2: gain=4 */ + BIP_RANGE(0.625), /* range 3: gain=8 */ + + BIP_RANGE(2.5), /* range 0+4: gain=1 */ + BIP_RANGE(1.25), /* range 1+4: gain=2 */ + BIP_RANGE(0.625), /* range 2+4: gain=4 */ + BIP_RANGE(0.3125), /* range 3+4: gain=8 */ + + UNI_RANGE(5), /* range 0+8: gain=1 */ + UNI_RANGE(2.5), /* range 1+8: gain=2 */ + UNI_RANGE(1.25), /* range 2+8: gain=4 */ + UNI_RANGE(0.625) /* range 3+8: gain=8 */ } }; -static const struct comedi_lrange range_dt2811_pgl_ai_5_bipolar = { - 4, { - BIP_RANGE(5), - BIP_RANGE(0.5), - BIP_RANGE(0.05), - BIP_RANGE(0.01) +static const struct comedi_lrange dt2811_pgl_ai_ranges = { + 12, { + BIP_RANGE(5), /* range 0: gain=1 */ + BIP_RANGE(0.5), /* range 1: gain=10 */ + BIP_RANGE(0.05), /* range 2: gain=100 */ + BIP_RANGE(0.01), /* range 3: gain=500 */ + + BIP_RANGE(2.5), /* range 0+4: gain=1 */ + BIP_RANGE(0.25), /* range 1+4: gain=10 */ + BIP_RANGE(0.025), /* range 2+4: gain=100 */ + BIP_RANGE(0.005), /* range 3+4: gain=500 */ + + UNI_RANGE(5), /* range 0+8: gain=1 */ + UNI_RANGE(0.5), /* range 1+8: gain=10 */ + UNI_RANGE(0.05), /* range 2+8: gain=100 */ + UNI_RANGE(0.01) /* range 3+8: gain=500 */ } }; @@ -174,12 +172,17 @@ static const struct comedi_lrange dt2811_ao_ranges = { struct dt2811_board { const char *name; - const struct comedi_lrange *bip_5; - const struct comedi_lrange *bip_2_5; - const struct comedi_lrange *unip_5; + unsigned int is_pgh:1; }; -enum { card_2811_pgh, card_2811_pgl }; +static const struct dt2811_board boardtypes[] = { + { + .name = "dt2811-pgh", + .is_pgh = 1, + }, { + .name = "dt2811-pgl", + }, +}; static int dt2811_ai_eoc(struct comedi_device *dev, struct comedi_subdevice *s, @@ -289,18 +292,8 @@ static int dt2811_attach(struct comedi_device *dev, struct comedi_devconfig *it) s->n_chan = (it->options[2] == 1) ? 8 : 16; s->insn_read = dt2811_ai_insn; s->maxdata = 0xfff; - switch (it->options[3]) { - case 0: - default: - s->range_table = board->bip_5; - break; - case 1: - s->range_table = board->bip_2_5; - break; - case 2: - s->range_table = board->unip_5; - break; - } + s->range_table = board->is_pgh ? &dt2811_pgh_ai_ranges + : &dt2811_pgl_ai_ranges; /* Analog Output subdevice */ s = &dev->subdevices[1]; @@ -336,20 +329,6 @@ static int dt2811_attach(struct comedi_device *dev, struct comedi_devconfig *it) return 0; } -static const struct dt2811_board boardtypes[] = { - { - .name = "dt2811-pgh", - .bip_5 = &range_dt2811_pgh_ai_5_bipolar, - .bip_2_5 = &range_dt2811_pgh_ai_2_5_bipolar, - .unip_5 = &range_dt2811_pgh_ai_5_unipolar, - }, { - .name = "dt2811-pgl", - .bip_5 = &range_dt2811_pgl_ai_5_bipolar, - .bip_2_5 = &range_dt2811_pgl_ai_2_5_bipolar, - .unip_5 = &range_dt2811_pgl_ai_5_unipolar, - }, -}; - static struct comedi_driver dt2811_driver = { .driver_name = "dt2811", .module = THIS_MODULE, -- cgit v0.10.2 From f52e8d0cae9a1b18da9304487395b730f08422b8 Mon Sep 17 00:00:00 2001 From: H Hartley Sweeten Date: Wed, 4 May 2016 12:47:21 -0700 Subject: staging: comedi: dt2811: tidy up analog input subdevice init Add some whitespace to the analog output subdevice initialization and rename the (*insn_read) function. Signed-off-by: H Hartley Sweeten Reviewed-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/comedi/drivers/dt2811.c b/drivers/staging/comedi/drivers/dt2811.c index f0b3c5e..44afa78 100644 --- a/drivers/staging/comedi/drivers/dt2811.c +++ b/drivers/staging/comedi/drivers/dt2811.c @@ -197,8 +197,10 @@ static int dt2811_ai_eoc(struct comedi_device *dev, return -EBUSY; } -static int dt2811_ai_insn(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static int dt2811_ai_insn_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { unsigned int chan = CR_CHAN(insn->chanspec); unsigned int range = CR_RANGE(insn->chanspec); @@ -283,17 +285,17 @@ static int dt2811_attach(struct comedi_device *dev, struct comedi_devconfig *it) if (ret) return ret; + /* Analog Input subdevice */ s = &dev->subdevices[0]; - /* initialize the ADC subdevice */ - s->type = COMEDI_SUBD_AI; - s->subdev_flags = SDF_READABLE | + s->type = COMEDI_SUBD_AI; + s->subdev_flags = SDF_READABLE | (it->options[2] == 1) ? SDF_DIFF : (it->options[2] == 2) ? SDF_COMMON : SDF_GROUND; - s->n_chan = (it->options[2] == 1) ? 8 : 16; - s->insn_read = dt2811_ai_insn; - s->maxdata = 0xfff; + s->n_chan = (it->options[2] == 1) ? 8 : 16; + s->maxdata = 0x0fff; s->range_table = board->is_pgh ? &dt2811_pgh_ai_ranges : &dt2811_pgl_ai_ranges; + s->insn_read = dt2811_ai_insn_read; /* Analog Output subdevice */ s = &dev->subdevices[1]; -- cgit v0.10.2 From a426744c74314054fbf8c3036eaba8d779eb3086 Mon Sep 17 00:00:00 2001 From: H Hartley Sweeten Date: Wed, 4 May 2016 12:47:22 -0700 Subject: staging: comedi: dt2811: remove unused define This define is not used by the driver. Remove it. Signed-off-by: H Hartley Sweeten Reviewed-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/comedi/drivers/dt2811.c b/drivers/staging/comedi/drivers/dt2811.c index 44afa78..b1926e7 100644 --- a/drivers/staging/comedi/drivers/dt2811.c +++ b/drivers/staging/comedi/drivers/dt2811.c @@ -168,8 +168,6 @@ static const struct comedi_lrange dt2811_ao_ranges = { } }; -#define TIMEOUT 10000 - struct dt2811_board { const char *name; unsigned int is_pgh:1; -- cgit v0.10.2 From 9910131ceb8b798a044244fe7dd0e4838e2923b4 Mon Sep 17 00:00:00 2001 From: H Hartley Sweeten Date: Wed, 4 May 2016 12:47:23 -0700 Subject: staging: comedi: dt2811: rename 'boardtypes' Rename this array so it has namespace associated with the driver. Signed-off-by: H Hartley Sweeten Reviewed-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/comedi/drivers/dt2811.c b/drivers/staging/comedi/drivers/dt2811.c index b1926e7..312403f 100644 --- a/drivers/staging/comedi/drivers/dt2811.c +++ b/drivers/staging/comedi/drivers/dt2811.c @@ -173,7 +173,7 @@ struct dt2811_board { unsigned int is_pgh:1; }; -static const struct dt2811_board boardtypes[] = { +static const struct dt2811_board dt2811_boards[] = { { .name = "dt2811-pgh", .is_pgh = 1, @@ -334,8 +334,8 @@ static struct comedi_driver dt2811_driver = { .module = THIS_MODULE, .attach = dt2811_attach, .detach = comedi_legacy_detach, - .board_name = &boardtypes[0].name, - .num_names = ARRAY_SIZE(boardtypes), + .board_name = &dt2811_boards[0].name, + .num_names = ARRAY_SIZE(dt2811_boards), .offset = sizeof(struct dt2811_board), }; module_comedi_driver(dt2811_driver); -- cgit v0.10.2 From 277b861349d1fda79e124a3d0fd81f5d6e594b3f Mon Sep 17 00:00:00 2001 From: H Hartley Sweeten Date: Wed, 4 May 2016 12:47:24 -0700 Subject: staging: comedi: dt2811: update the MODULE_DESCRIPTION Change the MODULE_DESCRIPTION to something more useful than the generic "Comedi low-level driver". Signed-off-by: H Hartley Sweeten Reviewed-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/comedi/drivers/dt2811.c b/drivers/staging/comedi/drivers/dt2811.c index 312403f..415512b 100644 --- a/drivers/staging/comedi/drivers/dt2811.c +++ b/drivers/staging/comedi/drivers/dt2811.c @@ -341,5 +341,5 @@ static struct comedi_driver dt2811_driver = { module_comedi_driver(dt2811_driver); MODULE_AUTHOR("Comedi http://www.comedi.org"); -MODULE_DESCRIPTION("Comedi low-level driver"); +MODULE_DESCRIPTION("Comedi driver for Data Translation DT2811 series boards"); MODULE_LICENSE("GPL"); -- cgit v0.10.2 From 34d3473263250c4c0883d7d6d95e8f122d8d348d Mon Sep 17 00:00:00 2001 From: Shyam Saini Date: Tue, 10 May 2016 21:21:07 +0530 Subject: Staging: comedi: comedi_fops.c: Fixed coding style issue Fixed following checkpatch.pl warnings WARNING: Prefer WRITE_ONCE(, ) over ACCESS_ONCE() = WARNING: Prefer READ_ONCE() over ACCESS_ONCE() Signed-off-by: Shyam Saini Reviewed-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/comedi/comedi_fops.c b/drivers/staging/comedi/comedi_fops.c index 629080f..4d87596 100644 --- a/drivers/staging/comedi/comedi_fops.c +++ b/drivers/staging/comedi/comedi_fops.c @@ -312,8 +312,8 @@ static void comedi_file_reset(struct file *file) } cfp->last_attached = dev->attached; cfp->last_detach_count = dev->detach_count; - ACCESS_ONCE(cfp->read_subdev) = read_s; - ACCESS_ONCE(cfp->write_subdev) = write_s; + WRITE_ONCE(cfp->read_subdev, read_s); + WRITE_ONCE(cfp->write_subdev, write_s); } static void comedi_file_check(struct file *file) @@ -331,7 +331,7 @@ static struct comedi_subdevice *comedi_file_read_subdevice(struct file *file) struct comedi_file *cfp = file->private_data; comedi_file_check(file); - return ACCESS_ONCE(cfp->read_subdev); + return READ_ONCE(cfp->read_subdev); } static struct comedi_subdevice *comedi_file_write_subdevice(struct file *file) @@ -339,7 +339,7 @@ static struct comedi_subdevice *comedi_file_write_subdevice(struct file *file) struct comedi_file *cfp = file->private_data; comedi_file_check(file); - return ACCESS_ONCE(cfp->write_subdev); + return READ_ONCE(cfp->write_subdev); } static int resize_async_buffer(struct comedi_device *dev, @@ -1992,7 +1992,7 @@ static int do_setrsubd_ioctl(struct comedi_device *dev, unsigned long arg, !(s_old->async->cmd.flags & CMDF_WRITE)) return -EBUSY; - ACCESS_ONCE(cfp->read_subdev) = s_new; + WRITE_ONCE(cfp->read_subdev, s_new); return 0; } @@ -2034,7 +2034,7 @@ static int do_setwsubd_ioctl(struct comedi_device *dev, unsigned long arg, (s_old->async->cmd.flags & CMDF_WRITE)) return -EBUSY; - ACCESS_ONCE(cfp->write_subdev) = s_new; + WRITE_ONCE(cfp->write_subdev, s_new); return 0; } -- cgit v0.10.2 From f2975a9b2ab9a9243f2ca2e99d8209e01138cdfc Mon Sep 17 00:00:00 2001 From: H Hartley Sweeten Date: Wed, 4 May 2016 15:25:38 -0700 Subject: staging: comedi: dt2811: add async command support for AI subdevice The interrupt support available on this board is pretty limited but its simple enough to give basic async command support. This allows reading a single channel continuously using either the internal or an external clock to trigger each conversion. The command can also use the external trigger input to start the command if the external clock is being used for conversions. Signed-off-by: H Hartley Sweeten Reviewed-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/comedi/drivers/dt2811.c b/drivers/staging/comedi/drivers/dt2811.c index 415512b..904f6377 100644 --- a/drivers/staging/comedi/drivers/dt2811.c +++ b/drivers/staging/comedi/drivers/dt2811.c @@ -2,11 +2,7 @@ * Comedi driver for Data Translation DT2811 * * COMEDI - Linux Control and Measurement Device Interface - * History: - * Base Version - David A. Schleef - * December 1998 - Updated to work. David does not have a DT2811 - * board any longer so this was suffering from bitrot. - * Updated performed by ... + * Copyright (C) David A. Schleef * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -28,7 +24,7 @@ * * Configuration options: * [0] - I/O port base address - * [1] - IRQ, although this is currently unused + * [1] - IRQ (optional, needed for async command support) * [2] - A/D reference (# of analog inputs) * 0 = single-ended (16 channels) * 1 = differential (8 channels) @@ -51,6 +47,9 @@ */ #include +#include +#include + #include "../comedidev.h" /* @@ -61,16 +60,9 @@ #define DT2811_ADCSR_ADERROR BIT(6) /* r 1=A/D error */ #define DT2811_ADCSR_ADBUSY BIT(5) /* r 1=A/D busy */ #define DT2811_ADCSR_CLRERROR BIT(4) -#define DT2811_ADCSR_INTENB BIT(2) /* r/w 1=interupts ena */ +#define DT2811_ADCSR_DMAENB BIT(3) /* r/w 1=dma ena */ +#define DT2811_ADCSR_INTENB BIT(2) /* r/w 1=interupts ena */ #define DT2811_ADCSR_ADMODE(x) (((x) & 0x3) << 0) -/* single conversion on ADGCR load */ -#define DT2811_ADCSR_ADMODE_SINGLE DT2811_ADCSR_ADMODE(0) -/* continuous conversion, internal clock, (clock enabled on ADGCR load) */ -#define DT2811_ADCSR_ADMODE_CONT DT2811_ADCSR_ADMODE(1) -/* continuous conversion, internal clock, external trigger */ -#define DT2811_ADCSR_ADMODE_EXT_TRIG DT2811_ADCSR_ADMODE(2) -/* continuous conversion, external clock, external trigger */ -#define DT2811_ADCSR_ADMODE_EXT DT2811_ADCSR_ADMODE(3) #define DT2811_ADGCR_REG 0x01 /* r/w A/D Gain/Channel */ #define DT2811_ADGCR_GAIN(x) (((x) & 0x3) << 6) @@ -85,6 +77,12 @@ #define DT2811_DI_REG 0x06 /* r Digital Input Port 0 */ #define DT2811_DO_REG 0x06 /* w Digital Output Port 1 */ +#define DT2811_TMRCTR_REG 0x07 /* r/w Timer/Counter */ +#define DT2811_TMRCTR_MANTISSA(x) (((x) & 0x7) << 3) +#define DT2811_TMRCTR_EXPONENT(x) (((x) & 0x7) << 0) + +#define DT2811_OSC_BASE 1666 /* 600 kHz = 1666.6667ns */ + /* * Timer frequency control: * DT2811_TMRCTR_MANTISSA DT2811_TMRCTR_EXPONENT @@ -98,9 +96,13 @@ * 6 6 100 kHz 6 1000000 * 7 12 50 kHz 7 10000000 */ -#define DT2811_TMRCTR_REG 0x07 /* r/w Timer/Counter */ -#define DT2811_TMRCTR_MANTISSA(x) (((x) & 0x7) << 3) -#define DT2811_TMRCTR_EXPONENT(x) (((x) & 0x7) << 0) +const unsigned int dt2811_clk_dividers[] = { + 1, 10, 2, 3, 4, 5, 6, 12 +}; + +const unsigned int dt2811_clk_multipliers[] = { + 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000 +}; /* * The Analog Input range is set using jumpers on the board. @@ -182,6 +184,287 @@ static const struct dt2811_board dt2811_boards[] = { }, }; +struct dt2811_private { + unsigned int ai_divisor; +}; + +static unsigned int dt2811_ai_read_sample(struct comedi_device *dev, + struct comedi_subdevice *s) +{ + unsigned int val; + + val = inb(dev->iobase + DT2811_ADDATA_LO_REG) | + (inb(dev->iobase + DT2811_ADDATA_HI_REG) << 8); + + return val & s->maxdata; +} + +static irqreturn_t dt2811_interrupt(int irq, void *d) +{ + struct comedi_device *dev = d; + struct comedi_subdevice *s = dev->read_subdev; + struct comedi_async *async = s->async; + struct comedi_cmd *cmd = &async->cmd; + unsigned int status; + + if (!dev->attached) + return IRQ_NONE; + + status = inb(dev->iobase + DT2811_ADCSR_REG); + + if (status & DT2811_ADCSR_ADERROR) { + async->events |= COMEDI_CB_OVERFLOW; + + outb(status | DT2811_ADCSR_CLRERROR, + dev->iobase + DT2811_ADCSR_REG); + } + + if (status & DT2811_ADCSR_ADDONE) { + unsigned short val; + + val = dt2811_ai_read_sample(dev, s); + comedi_buf_write_samples(s, &val, 1); + } + + if (cmd->stop_src == TRIG_COUNT && async->scans_done >= cmd->stop_arg) + async->events |= COMEDI_CB_EOA; + + comedi_handle_events(dev, s); + + return IRQ_HANDLED; +} + +static int dt2811_ai_cancel(struct comedi_device *dev, + struct comedi_subdevice *s) +{ + /* + * Mode 0 + * Single conversion + * + * Loading a chanspec will trigger a conversion. + */ + outb(DT2811_ADCSR_ADMODE(0), dev->iobase + DT2811_ADCSR_REG); + + return 0; +} + +static void dt2811_ai_set_chanspec(struct comedi_device *dev, + unsigned int chanspec) +{ + unsigned int chan = CR_CHAN(chanspec); + unsigned int range = CR_RANGE(chanspec); + + outb(DT2811_ADGCR_CHAN(chan) | DT2811_ADGCR_GAIN(range), + dev->iobase + DT2811_ADGCR_REG); +} + +static int dt2811_ai_cmd(struct comedi_device *dev, + struct comedi_subdevice *s) +{ + struct dt2811_private *devpriv = dev->private; + struct comedi_cmd *cmd = &s->async->cmd; + unsigned int mode; + + if (cmd->start_src == TRIG_NOW) { + /* + * Mode 1 + * Continuous conversion, internal trigger and clock + * + * This resets the trigger flip-flop, disabling A/D strobes. + * The timer/counter register is loaded with the division + * ratio which will give the required sample rate. + * + * Loading the first chanspec sets the trigger flip-flop, + * enabling the timer/counter. A/D strobes are then generated + * at the rate set by the internal clock/divider. + */ + mode = DT2811_ADCSR_ADMODE(1); + } else { /* TRIG_EXT */ + if (cmd->convert_src == TRIG_TIMER) { + /* + * Mode 2 + * Continuous conversion, external trigger + * + * Similar to Mode 1, with the exception that the + * trigger flip-flop must be set by a negative edge + * on the external trigger input. + */ + mode = DT2811_ADCSR_ADMODE(2); + } else { /* TRIG_EXT */ + /* + * Mode 3 + * Continuous conversion, external trigger, clock + * + * Similar to Mode 2, with the exception that the + * conversion rate is set by the frequency on the + * external clock/divider. + */ + mode = DT2811_ADCSR_ADMODE(3); + } + } + outb(mode | DT2811_ADCSR_INTENB, dev->iobase + DT2811_ADCSR_REG); + + /* load timer */ + outb(devpriv->ai_divisor, dev->iobase + DT2811_TMRCTR_REG); + + /* load chanspec - enables timer */ + dt2811_ai_set_chanspec(dev, cmd->chanlist[0]); + + return 0; +} + +static unsigned int dt2811_ns_to_timer(unsigned int *nanosec, + unsigned int flags) +{ + unsigned long long ns = *nanosec; + unsigned int ns_lo = COMEDI_MIN_SPEED; + unsigned int ns_hi = 0; + unsigned int divisor_hi = 0; + unsigned int divisor_lo = 0; + unsigned int _div; + unsigned int _mult; + + /* + * Work through all the divider/multiplier values to find the two + * closest divisors to generate the requested nanosecond timing. + */ + for (_div = 0; _div <= 7; _div++) { + for (_mult = 0; _mult <= 7; _mult++) { + unsigned int div = dt2811_clk_dividers[_div]; + unsigned int mult = dt2811_clk_multipliers[_mult]; + unsigned long long divider = div * mult; + unsigned int divisor = DT2811_TMRCTR_MANTISSA(_div) | + DT2811_TMRCTR_EXPONENT(_mult); + + /* + * The timer can be configured to run at a slowest + * speed of 0.005hz (600 Khz/120000000), which requires + * 37-bits to represent the nanosecond value. Limit the + * slowest timing to what comedi handles (32-bits). + */ + ns = divider * DT2811_OSC_BASE; + if (ns > COMEDI_MIN_SPEED) + continue; + + /* Check for fastest found timing */ + if (ns <= *nanosec && ns > ns_hi) { + ns_hi = ns; + divisor_hi = divisor; + } + /* Check for slowest found timing */ + if (ns >= *nanosec && ns < ns_lo) { + ns_lo = ns; + divisor_lo = divisor; + } + } + } + + /* + * The slowest found timing will be invalid if the requested timing + * is faster than what can be generated by the timer. Fix it so that + * CMDF_ROUND_UP returns valid timing. + */ + if (ns_lo == COMEDI_MIN_SPEED) { + ns_lo = ns_hi; + divisor_lo = divisor_hi; + } + /* + * The fastest found timing will be invalid if the requested timing + * is less than what can be generated by the timer. Fix it so that + * CMDF_ROUND_NEAREST and CMDF_ROUND_DOWN return valid timing. + */ + if (ns_hi == 0) { + ns_hi = ns_lo; + divisor_hi = divisor_lo; + } + + switch (flags & CMDF_ROUND_MASK) { + case CMDF_ROUND_NEAREST: + default: + if (ns_hi - *nanosec < *nanosec - ns_lo) { + *nanosec = ns_lo; + return divisor_lo; + } + *nanosec = ns_hi; + return divisor_hi; + case CMDF_ROUND_UP: + *nanosec = ns_lo; + return divisor_lo; + case CMDF_ROUND_DOWN: + *nanosec = ns_hi; + return divisor_hi; + } +} + +static int dt2811_ai_cmdtest(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_cmd *cmd) +{ + struct dt2811_private *devpriv = dev->private; + unsigned int arg; + int err = 0; + + /* Step 1 : check if triggers are trivially valid */ + + err |= comedi_check_trigger_src(&cmd->start_src, TRIG_NOW | TRIG_EXT); + err |= comedi_check_trigger_src(&cmd->scan_begin_src, TRIG_FOLLOW); + err |= comedi_check_trigger_src(&cmd->convert_src, + TRIG_TIMER | TRIG_EXT); + err |= comedi_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT); + err |= comedi_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE); + + if (err) + return 1; + + /* Step 2a : make sure trigger sources are unique */ + + err |= comedi_check_trigger_is_unique(cmd->start_src); + err |= comedi_check_trigger_is_unique(cmd->convert_src); + err |= comedi_check_trigger_is_unique(cmd->stop_src); + + /* Step 2b : and mutually compatible */ + + if (cmd->convert_src == TRIG_EXT && cmd->start_src != TRIG_EXT) + err |= -EINVAL; + + if (err) + return 2; + + /* Step 3: check if arguments are trivially valid */ + + err |= comedi_check_trigger_arg_is(&cmd->start_arg, 0); + err |= comedi_check_trigger_arg_is(&cmd->scan_begin_arg, 0); + if (cmd->convert_src == TRIG_TIMER) + err |= comedi_check_trigger_arg_min(&cmd->convert_arg, 12500); + err |= comedi_check_trigger_arg_is(&cmd->scan_end_arg, + cmd->chanlist_len); + if (cmd->stop_src == TRIG_COUNT) + err |= comedi_check_trigger_arg_min(&cmd->stop_arg, 1); + else /* TRIG_NONE */ + err |= comedi_check_trigger_arg_is(&cmd->stop_arg, 0); + + if (err) + return 3; + + /* Step 4: fix up any arguments */ + + if (cmd->convert_src == TRIG_TIMER) { + arg = cmd->convert_arg; + devpriv->ai_divisor = dt2811_ns_to_timer(&arg, cmd->flags); + err |= comedi_check_trigger_arg_is(&cmd->convert_arg, arg); + } else { /* TRIG_EXT */ + /* The convert_arg is used to set the divisor. */ + devpriv->ai_divisor = cmd->convert_arg; + } + + if (err) + return 4; + + /* Step 5: check channel list if it exists */ + + return 0; +} + static int dt2811_ai_eoc(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, @@ -200,30 +483,22 @@ static int dt2811_ai_insn_read(struct comedi_device *dev, struct comedi_insn *insn, unsigned int *data) { - unsigned int chan = CR_CHAN(insn->chanspec); - unsigned int range = CR_RANGE(insn->chanspec); int ret; int i; + /* We will already be in Mode 0 */ for (i = 0; i < insn->n; i++) { - unsigned int val; - - /* select channel/gain and trigger conversion */ - outb(DT2811_ADGCR_CHAN(chan) | DT2811_ADGCR_GAIN(range), - dev->iobase + DT2811_ADGCR_REG); + /* load chanspec and trigger conversion */ + dt2811_ai_set_chanspec(dev, insn->chanspec); ret = comedi_timeout(dev, s, insn, dt2811_ai_eoc, 0); if (ret) return ret; - val = inb(dev->iobase + DT2811_ADDATA_LO_REG) | - (inb(dev->iobase + DT2811_ADDATA_HI_REG) << 8); - val &= s->maxdata; - - data[i] = val; + data[i] = dt2811_ai_read_sample(dev, s); } - return i; + return insn->n; } static int dt2811_ao_insn_write(struct comedi_device *dev, @@ -269,16 +544,42 @@ static int dt2811_do_insn_bits(struct comedi_device *dev, return insn->n; } +static void dt2811_reset(struct comedi_device *dev) +{ + /* This is the initialization sequence from the users manual */ + outb(DT2811_ADCSR_ADMODE(0), dev->iobase + DT2811_ADCSR_REG); + usleep_range(100, 1000); + inb(dev->iobase + DT2811_ADDATA_LO_REG); + inb(dev->iobase + DT2811_ADDATA_HI_REG); + outb(DT2811_ADCSR_ADMODE(0) | DT2811_ADCSR_CLRERROR, + dev->iobase + DT2811_ADCSR_REG); +} + static int dt2811_attach(struct comedi_device *dev, struct comedi_devconfig *it) { const struct dt2811_board *board = dev->board_ptr; + struct dt2811_private *devpriv; struct comedi_subdevice *s; int ret; + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); + if (!devpriv) + return -ENOMEM; + ret = comedi_request_region(dev, it->options[0], 0x8); if (ret) return ret; + dt2811_reset(dev); + + /* IRQ's 2,3,5,7 are valid for async command support */ + if (it->options[1] <= 7 && (BIT(it->options[1]) & 0xac)) { + ret = request_irq(it->options[1], dt2811_interrupt, 0, + dev->board_name, dev); + if (ret == 0) + dev->irq = it->options[1]; + } + ret = comedi_alloc_subdevices(dev, 4); if (ret) return ret; @@ -294,6 +595,14 @@ static int dt2811_attach(struct comedi_device *dev, struct comedi_devconfig *it) s->range_table = board->is_pgh ? &dt2811_pgh_ai_ranges : &dt2811_pgl_ai_ranges; s->insn_read = dt2811_ai_insn_read; + if (dev->irq) { + dev->read_subdev = s; + s->subdev_flags |= SDF_CMD_READ; + s->len_chanlist = 1; + s->do_cmdtest = dt2811_ai_cmdtest; + s->do_cmd = dt2811_ai_cmd; + s->cancel = dt2811_ai_cancel; + } /* Analog Output subdevice */ s = &dev->subdevices[1]; -- cgit v0.10.2 From 805c5f93286f2e5b5ab53fb23501768b47314aea Mon Sep 17 00:00:00 2001 From: Ravishankar Karkala Mallikarjunayya Date: Wed, 8 Jun 2016 15:18:54 +0530 Subject: Staging: comedi: s626: fix comment issue This fixes up a WARNING: 'Block comments use a trailing */ on a separate line'found by the checkpatch.pl tool. Signed-off-by: Ravishankar Karkala Mallikarjunayya Reviewed-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/comedi/drivers/s626.h b/drivers/staging/comedi/drivers/s626.h index b83424e..6a00a64 100644 --- a/drivers/staging/comedi/drivers/s626.h +++ b/drivers/staging/comedi/drivers/s626.h @@ -29,8 +29,10 @@ #define S626_ENCODER_CHANNELS 6 #define S626_DIO_CHANNELS 48 #define S626_DIO_BANKS 3 /* Number of DIO groups. */ -#define S626_DIO_EXTCHANS 40 /* Number of extended-capability - * DIO channels. */ +#define S626_DIO_EXTCHANS 40 /* + * Number of extended-capability + * DIO channels. + */ #define S626_NUM_TRIMDACS 12 /* Number of valid TrimDAC channels. */ @@ -48,21 +50,29 @@ #define S626_GSEL_BIPOLAR10V 0x00A0 /* S626_LP_GSEL setting 10V bipolar. */ /* Error codes that must be visible to this base class. */ -#define S626_ERR_ILLEGAL_PARM 0x00010000 /* Illegal function parameter - * value was specified. */ +#define S626_ERR_ILLEGAL_PARM 0x00010000 /* + * Illegal function parameter + * value was specified. + */ #define S626_ERR_I2C 0x00020000 /* I2C error. */ -#define S626_ERR_COUNTERSETUP 0x00200000 /* Illegal setup specified for - * counter channel. */ +#define S626_ERR_COUNTERSETUP 0x00200000 /* + * Illegal setup specified for + * counter channel. + */ #define S626_ERR_DEBI_TIMEOUT 0x00400000 /* DEBI transfer timed out. */ /* * Organization (physical order) and size (in DWORDs) of logical DMA buffers * contained by ANA_DMABUF. */ -#define S626_ADC_DMABUF_DWORDS 40 /* ADC DMA buffer must hold 16 samples, - * plus pre/post garbage samples. */ -#define S626_DAC_WDMABUF_DWORDS 1 /* DAC output DMA buffer holds a single - * sample. */ +#define S626_ADC_DMABUF_DWORDS 40 /* + * ADC DMA buffer must hold 16 samples, + * plus pre/post garbage samples. + */ +#define S626_DAC_WDMABUF_DWORDS 1 /* + * DAC output DMA buffer holds a single + * sample. + */ /* All remaining space in 4KB DMA buffer is available for the RPS1 program. */ @@ -95,60 +105,90 @@ #define S626_RPS_IRQ 0x60000000 /* IRQ */ #define S626_RPS_LOGICAL_OR 0x08000000 /* Logical OR conditionals. */ -#define S626_RPS_INVERT 0x04000000 /* Test for negated - * semaphores. */ +#define S626_RPS_INVERT 0x04000000 /* + * Test for negated + * semaphores. + */ #define S626_RPS_DEBI 0x00000002 /* DEBI done */ -#define S626_RPS_SIG0 0x00200000 /* RPS semaphore 0 - * (used by ADC). */ -#define S626_RPS_SIG1 0x00400000 /* RPS semaphore 1 - * (used by DAC). */ -#define S626_RPS_SIG2 0x00800000 /* RPS semaphore 2 - * (not used). */ +#define S626_RPS_SIG0 0x00200000 /* + * RPS semaphore 0 + * (used by ADC). + */ +#define S626_RPS_SIG1 0x00400000 /* + * RPS semaphore 1 + * (used by DAC). + */ +#define S626_RPS_SIG2 0x00800000 /* + * RPS semaphore 2 + * (not used). + */ #define S626_RPS_GPIO2 0x00080000 /* RPS GPIO2 */ #define S626_RPS_GPIO3 0x00100000 /* RPS GPIO3 */ -#define S626_RPS_SIGADC S626_RPS_SIG0 /* Trigger/status for - * ADC's RPS program. */ -#define S626_RPS_SIGDAC S626_RPS_SIG1 /* Trigger/status for - * DAC's RPS program. */ +#define S626_RPS_SIGADC S626_RPS_SIG0 /* + * Trigger/status for + * ADC's RPS program. + */ +#define S626_RPS_SIGDAC S626_RPS_SIG1 /* + * Trigger/status for + * DAC's RPS program. + */ /* RPS clock parameters. */ -#define S626_RPSCLK_SCALAR 8 /* This is apparent ratio of - * PCI/RPS clks (undocumented!!). */ +#define S626_RPSCLK_SCALAR 8 /* + * This is apparent ratio of + * PCI/RPS clks (undocumented!!). + */ #define S626_RPSCLK_PER_US (33 / S626_RPSCLK_SCALAR) - /* Number of RPS clocks in one - * microsecond. */ + /* + * Number of RPS clocks in one + * microsecond. + */ /* Event counter source addresses. */ #define S626_SBA_RPS_A0 0x27 /* Time of RPS0 busy, in PCI clocks. */ /* GPIO constants. */ -#define S626_GPIO_BASE 0x10004000 /* GPIO 0,2,3 = inputs, - * GPIO3 = IRQ; GPIO1 = out. */ +#define S626_GPIO_BASE 0x10004000 /* + * GPIO 0,2,3 = inputs, + * GPIO3 = IRQ; GPIO1 = out. + */ #define S626_GPIO1_LO 0x00000000 /* GPIO1 set to LOW. */ #define S626_GPIO1_HI 0x00001000 /* GPIO1 set to HIGH. */ /* Primary Status Register (PSR) constants. */ #define S626_PSR_DEBI_E 0x00040000 /* DEBI event flag. */ #define S626_PSR_DEBI_S 0x00080000 /* DEBI status flag. */ -#define S626_PSR_A2_IN 0x00008000 /* Audio output DMA2 protection - * address reached. */ -#define S626_PSR_AFOU 0x00000800 /* Audio FIFO under/overflow - * detected. */ -#define S626_PSR_GPIO2 0x00000020 /* GPIO2 input pin: 0=AdcBusy, - * 1=AdcIdle. */ -#define S626_PSR_EC0S 0x00000001 /* Event counter 0 threshold - * reached. */ +#define S626_PSR_A2_IN 0x00008000 /* + * Audio output DMA2 protection + * address reached. + */ +#define S626_PSR_AFOU 0x00000800 /* + * Audio FIFO under/overflow + * detected. + */ +#define S626_PSR_GPIO2 0x00000020 /* + * GPIO2 input pin: 0=AdcBusy, + * 1=AdcIdle. + */ +#define S626_PSR_EC0S 0x00000001 /* + * Event counter 0 threshold + * reached. + */ /* Secondary Status Register (SSR) constants. */ -#define S626_SSR_AF2_OUT 0x00000200 /* Audio 2 output FIFO - * under/overflow detected. */ +#define S626_SSR_AF2_OUT 0x00000200 /* + * Audio 2 output FIFO + * under/overflow detected. + */ /* Master Control Register 1 (MC1) constants. */ #define S626_MC1_SOFT_RESET 0x80000000 /* Invoke 7146 soft reset. */ -#define S626_MC1_SHUTDOWN 0x3FFF0000 /* Shut down all MC1-controlled - * enables. */ +#define S626_MC1_SHUTDOWN 0x3FFF0000 /* + * Shut down all MC1-controlled + * enables. + */ #define S626_MC1_ERPS1 0x2000 /* Enab/disable RPS task 1. */ #define S626_MC1_ERPS0 0x1000 /* Enab/disable RPS task 0. */ @@ -177,15 +217,23 @@ #define S626_P_DEBIAD 0x0088 /* DEBI target address. */ #define S626_P_I2CCTRL 0x008C /* I2C control. */ #define S626_P_I2CSTAT 0x0090 /* I2C status. */ -#define S626_P_BASEA2_IN 0x00AC /* Audio input 2 base physical DMAbuf - * address. */ -#define S626_P_PROTA2_IN 0x00B0 /* Audio input 2 physical DMAbuf - * protection address. */ +#define S626_P_BASEA2_IN 0x00AC /* + * Audio input 2 base physical DMAbuf + * address. + */ +#define S626_P_PROTA2_IN 0x00B0 /* + * Audio input 2 physical DMAbuf + * protection address. + */ #define S626_P_PAGEA2_IN 0x00B4 /* Audio input 2 paging attributes. */ -#define S626_P_BASEA2_OUT 0x00B8 /* Audio output 2 base physical DMAbuf - * address. */ -#define S626_P_PROTA2_OUT 0x00BC /* Audio output 2 physical DMAbuf - * protection address. */ +#define S626_P_BASEA2_OUT 0x00B8 /* + * Audio output 2 base physical DMAbuf + * address. + */ +#define S626_P_PROTA2_OUT 0x00BC /* + * Audio output 2 physical DMAbuf + * protection address. + */ #define S626_P_PAGEA2_OUT 0x00C0 /* Audio output 2 paging attributes. */ #define S626_P_RPSPAGE0 0x00C4 /* RPS0 page. */ #define S626_P_RPSPAGE1 0x00C8 /* RPS1 page. */ @@ -205,8 +253,10 @@ #define S626_P_PSR 0x0110 /* Primary status. */ #define S626_P_SSR 0x0114 /* Secondary status. */ #define S626_P_EC1R 0x0118 /* Event counter set 1. */ -#define S626_P_ADP4 0x0138 /* Logical audio DMA pointer of audio - * input FIFO A2_IN. */ +#define S626_P_ADP4 0x0138 /* + * Logical audio DMA pointer of audio + * input FIFO A2_IN. + */ #define S626_P_FB_BUFFER1 0x0144 /* Audio feedback buffer 1. */ #define S626_P_FB_BUFFER2 0x0148 /* Audio feedback buffer 2. */ #define S626_P_TSL1 0x0180 /* Audio time slot list 1. */ @@ -243,13 +293,19 @@ #define S626_LP_RDMISC2 0x0082 /* Read Misc2. */ /* Bit masks for MISC1 register that are the same for reads and writes. */ -#define S626_MISC1_WENABLE 0x8000 /* enab writes to MISC2 (except Clear - * Watchdog bit). */ +#define S626_MISC1_WENABLE 0x8000 /* + * enab writes to MISC2 (except Clear + * Watchdog bit). + */ #define S626_MISC1_WDISABLE 0x0000 /* Disable writes to MISC2. */ -#define S626_MISC1_EDCAP 0x1000 /* Enable edge capture on DIO chans - * specified by S626_LP_WRCAPSELx. */ -#define S626_MISC1_NOEDCAP 0x0000 /* Disable edge capture on specified - * DIO chans. */ +#define S626_MISC1_EDCAP 0x1000 /* + * Enable edge capture on DIO chans + * specified by S626_LP_WRCAPSELx. + */ +#define S626_MISC1_NOEDCAP 0x0000 /* + * Disable edge capture on specified + * DIO chans. + */ /* Bit masks for MISC1 register reads. */ #define S626_RDMISC1_WDTIMEOUT 0x4000 /* Watchdog timer timed out. */ @@ -268,35 +324,49 @@ #define S626_A1_RUN 0x20000000 /* Run A1 based on TSL1. */ #define S626_A1_SWAP 0x00200000 /* Use big-endian for A1. */ #define S626_A2_SWAP 0x00100000 /* Use big-endian for A2. */ -#define S626_WS_MODES 0x00019999 /* WS0 = TSL1 trigger input, - * WS1-WS4 = CS* outputs. */ - -#if S626_PLATFORM == S626_INTEL /* Base ACON1 config: always run - * A1 based on TSL1. */ +#define S626_WS_MODES 0x00019999 /* + * WS0 = TSL1 trigger input, + * WS1-WS4 = CS* outputs. + */ + +#if S626_PLATFORM == S626_INTEL /* + * Base ACON1 config: always run + * A1 based on TSL1. + */ #define S626_ACON1_BASE (S626_WS_MODES | S626_A1_RUN) #elif S626_PLATFORM == S626_MOTOROLA #define S626_ACON1_BASE \ (S626_WS_MODES | S626_A1_RUN | S626_A1_SWAP | S626_A2_SWAP) #endif -#define S626_ACON1_ADCSTART S626_ACON1_BASE /* Start ADC: run A1 - * based on TSL1. */ +#define S626_ACON1_ADCSTART S626_ACON1_BASE /* + * Start ADC: run A1 + * based on TSL1. + */ #define S626_ACON1_DACSTART (S626_ACON1_BASE | S626_A2_RUN) /* Start transmit to DAC: run A2 based on TSL2. */ #define S626_ACON1_DACSTOP S626_ACON1_BASE /* Halt A2. */ /* Bit masks for ACON2 register. */ #define S626_A1_CLKSRC_BCLK1 0x00000000 /* A1 bit rate = BCLK1 (ADC). */ -#define S626_A2_CLKSRC_X1 0x00800000 /* A2 bit rate = ACLK/1 - * (DACs). */ -#define S626_A2_CLKSRC_X2 0x00C00000 /* A2 bit rate = ACLK/2 - * (DACs). */ -#define S626_A2_CLKSRC_X4 0x01400000 /* A2 bit rate = ACLK/4 - * (DACs). */ +#define S626_A2_CLKSRC_X1 0x00800000 /* + * A2 bit rate = ACLK/1 + * (DACs). + */ +#define S626_A2_CLKSRC_X2 0x00C00000 /* + * A2 bit rate = ACLK/2 + * (DACs). + */ +#define S626_A2_CLKSRC_X4 0x01400000 /* + * A2 bit rate = ACLK/4 + * (DACs). + */ #define S626_INVERT_BCLK2 0x00100000 /* Invert BCLK2 (DACs). */ #define S626_BCLK2_OE 0x00040000 /* Enable BCLK2 (DACs). */ -#define S626_ACON2_XORMASK 0x000C0000 /* XOR mask for ACON2 - * active-low bits. */ +#define S626_ACON2_XORMASK 0x000C0000 /* + * XOR mask for ACON2 + * active-low bits. + */ #define S626_ACON2_INIT (S626_ACON2_XORMASK ^ \ (S626_A1_CLKSRC_BCLK1 | S626_A2_CLKSRC_X2 | \ @@ -308,12 +378,18 @@ #define S626_WS3 0x10000000 #define S626_WS4 0x08000000 #define S626_RSD1 0x01000000 /* Shift A1 data in on SD1. */ -#define S626_SDW_A1 0x00800000 /* Store rcv'd char at next char - * slot of DWORD1 buffer. */ -#define S626_SIB_A1 0x00400000 /* Store rcv'd char at next - * char slot of FB1 buffer. */ -#define S626_SF_A1 0x00200000 /* Write unsigned long - * buffer to input FIFO. */ +#define S626_SDW_A1 0x00800000 /* + * Store rcv'd char at next char + * slot of DWORD1 buffer. + */ +#define S626_SIB_A1 0x00400000 /* + * Store rcv'd char at next + * char slot of FB1 buffer. + */ +#define S626_SF_A1 0x00200000 /* + * Write unsigned long + * buffer to input FIFO. + */ /* Select parallel-to-serial converter's data source: */ #define S626_XFIFO_0 0x00000000 /* Data fifo byte 0. */ @@ -324,31 +400,45 @@ #define S626_XFB1 0x00000050 /* FB_BUFFER byte 1. */ #define S626_XFB2 0x00000060 /* FB_BUFFER byte 2. */ #define S626_XFB3 0x00000070 /* FB_BUFFER byte 3. */ -#define S626_SIB_A2 0x00000200 /* Store next dword from A2's +#define S626_SIB_A2 0x00000200 /* + * Store next dword from A2's * input shifter to FB2 - * buffer. */ -#define S626_SF_A2 0x00000100 /* Store next dword from A2's + * buffer. + */ +#define S626_SF_A2 0x00000100 /* + * Store next dword from A2's * input shifter to its input - * fifo. */ -#define S626_LF_A2 0x00000080 /* Load next dword from A2's + * fifo. + */ +#define S626_LF_A2 0x00000080 /* + * Load next dword from A2's * output fifo into its - * output dword buffer. */ + * output dword buffer. + */ #define S626_XSD2 0x00000008 /* Shift data out on SD2. */ #define S626_RSD3 0x00001800 /* Shift data in on SD3. */ #define S626_RSD2 0x00001000 /* Shift data in on SD2. */ -#define S626_LOW_A2 0x00000002 /* Drive last SD low for 7 clks, - * then tri-state. */ +#define S626_LOW_A2 0x00000002 /* + * Drive last SD low for 7 clks, + * then tri-state. + */ #define S626_EOS 0x00000001 /* End of superframe. */ /* I2C configuration constants. */ -#define S626_I2C_CLKSEL 0x0400 /* I2C bit rate = - * PCIclk/480 = 68.75 KHz. */ -#define S626_I2C_BITRATE 68.75 /* I2C bus data bit rate +#define S626_I2C_CLKSEL 0x0400 /* + * I2C bit rate = + * PCIclk/480 = 68.75 KHz. + */ +#define S626_I2C_BITRATE 68.75 /* + * I2C bus data bit rate * (determined by - * S626_I2C_CLKSEL) in KHz. */ -#define S626_I2C_WRTIME 15.0 /* Worst case time, in msec, + * S626_I2C_CLKSEL) in KHz. + */ +#define S626_I2C_WRTIME 15.0 /* + * Worst case time, in msec, * for EEPROM internal write - * op. */ + * op. + */ /* I2C manifest constants. */ @@ -368,8 +458,10 @@ #define S626_I2C_B0(ATTR, VAL) (((ATTR) << 2) | ((VAL) << 8)) /* DEBI command constants. */ -#define S626_DEBI_CMD_SIZE16 (2 << 17) /* Transfer size is always - * 2 bytes. */ +#define S626_DEBI_CMD_SIZE16 (2 << 17) /* + * Transfer size is always + * 2 bytes. + */ #define S626_DEBI_CMD_READ 0x00010000 /* Read operation. */ #define S626_DEBI_CMD_WRITE 0x00000000 /* Write operation. */ @@ -380,42 +472,58 @@ #define S626_DEBI_CMD_WRWORD (S626_DEBI_CMD_WRITE | S626_DEBI_CMD_SIZE16) /* DEBI configuration constants. */ -#define S626_DEBI_CFG_XIRQ_EN 0x80000000 /* Enable external interrupt - * on GPIO3. */ +#define S626_DEBI_CFG_XIRQ_EN 0x80000000 /* + * Enable external interrupt + * on GPIO3. + */ #define S626_DEBI_CFG_XRESUME 0x40000000 /* Resume block */ - /* Transfer when XIRQ - * deasserted. */ + /* + * Transfer when XIRQ + * deasserted. + */ #define S626_DEBI_CFG_TOQ 0x03C00000 /* Timeout (15 PCI cycles). */ #define S626_DEBI_CFG_FAST 0x10000000 /* Fast mode enable. */ /* 4-bit field that specifies DEBI timeout value in PCI clock cycles: */ -#define S626_DEBI_CFG_TOUT_BIT 22 /* Finish DEBI cycle after this many - * clocks. */ +#define S626_DEBI_CFG_TOUT_BIT 22 /* + * Finish DEBI cycle after this many + * clocks. + */ /* 2-bit field that specifies Endian byte lane steering: */ -#define S626_DEBI_CFG_SWAP_NONE 0x00000000 /* Straight - don't swap any - * bytes (Intel). */ +#define S626_DEBI_CFG_SWAP_NONE 0x00000000 /* + * Straight - don't swap any + * bytes (Intel). + */ #define S626_DEBI_CFG_SWAP_2 0x00100000 /* 2-byte swap (Motorola). */ #define S626_DEBI_CFG_SWAP_4 0x00200000 /* 4-byte swap. */ -#define S626_DEBI_CFG_SLAVE16 0x00080000 /* Slave is able to serve - * 16-bit cycles. */ -#define S626_DEBI_CFG_INC 0x00040000 /* Enable address increment - * for block transfers. */ +#define S626_DEBI_CFG_SLAVE16 0x00080000 /* + * Slave is able to serve + * 16-bit cycles. + */ +#define S626_DEBI_CFG_INC 0x00040000 /* + * Enable address increment + * for block transfers. + */ #define S626_DEBI_CFG_INTEL 0x00020000 /* Intel style local bus. */ #define S626_DEBI_CFG_TIMEROFF 0x00010000 /* Disable timer. */ #if S626_PLATFORM == S626_INTEL -#define S626_DEBI_TOUT 7 /* Wait 7 PCI clocks (212 ns) before - * polling RDY. */ +#define S626_DEBI_TOUT 7 /* + * Wait 7 PCI clocks (212 ns) before + * polling RDY. + */ /* Intel byte lane steering (pass through all byte lanes). */ #define S626_DEBI_SWAP S626_DEBI_CFG_SWAP_NONE #elif S626_PLATFORM == S626_MOTOROLA -#define S626_DEBI_TOUT 15 /* Wait 15 PCI clocks (454 ns) maximum - * before timing out. */ +#define S626_DEBI_TOUT 15 /* + * Wait 15 PCI clocks (454 ns) maximum + * before timing out. + */ /* Motorola byte lane steering. */ #define S626_DEBI_SWAP S626_DEBI_CFG_SWAP_2 @@ -429,10 +537,14 @@ /* LoadSrc values: */ #define S626_LOADSRC_INDX 0 /* Preload core in response to Index. */ -#define S626_LOADSRC_OVER 1 /* Preload core in response to - * Overflow. */ -#define S626_LOADSRCB_OVERA 2 /* Preload B core in response to - * A Overflow. */ +#define S626_LOADSRC_OVER 1 /* + * Preload core in response to + * Overflow. + */ +#define S626_LOADSRCB_OVERA 2 /* + * Preload B core in response to + * A Overflow. + */ #define S626_LOADSRC_NONE 3 /* Never preload core. */ /* IntSrc values: */ @@ -469,10 +581,14 @@ #define S626_CNTSRC_SYSCLK_DOWN 3 /* System clock down */ /* ClkPol values: */ -#define S626_CLKPOL_POS 0 /* Counter/Extender clock is - * active high. */ -#define S626_CLKPOL_NEG 1 /* Counter/Extender clock is - * active low. */ +#define S626_CLKPOL_POS 0 /* + * Counter/Extender clock is + * active high. + */ +#define S626_CLKPOL_NEG 1 /* + * Counter/Extender clock is + * active low. + */ #define S626_CNTDIR_UP 0 /* Timer counts up. */ #define S626_CNTDIR_DOWN 1 /* Timer counts down. */ @@ -488,8 +604,10 @@ /* Sanity-check limits for parameters. */ -#define S626_NUM_COUNTERS 6 /* Maximum valid counter - * logical channel number. */ +#define S626_NUM_COUNTERS 6 /* + * Maximum valid counter + * logical channel number. + */ #define S626_NUM_INTSOURCES 4 #define S626_NUM_LATCHSOURCES 4 #define S626_NUM_CLKMULTS 4 -- cgit v0.10.2 From 9c84ae6b69d29f5f2b2aeb12d701034a20584a7c Mon Sep 17 00:00:00 2001 From: Ravishankar Karkala Mallikarjunayya Date: Tue, 17 May 2016 15:43:57 +0530 Subject: Staging: comedi: Fix WARNING issue in dt2801.c This is a patch to the dt2801.c file that fixes up a Block comments issues found by the checkpatch.pl tool. i.e. Block comments use a trailing */ on a separate line Signed-off-by: Ravishankar Karkala Mallikarjunayya Reviewed-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/comedi/drivers/dt2801.c b/drivers/staging/comedi/drivers/dt2801.c index 6c7b4d2..c2ce1eb 100644 --- a/drivers/staging/comedi/drivers/dt2801.c +++ b/drivers/staging/comedi/drivers/dt2801.c @@ -4,30 +4,30 @@ * */ /* -Driver: dt2801 -Description: Data Translation DT2801 series and DT01-EZ -Author: ds -Status: works -Devices: [Data Translation] DT2801 (dt2801), DT2801-A, DT2801/5716A, - DT2805, DT2805/5716A, DT2808, DT2818, DT2809, DT01-EZ - -This driver can autoprobe the type of board. - -Configuration options: - [0] - I/O port base address - [1] - unused - [2] - A/D reference 0=differential, 1=single-ended - [3] - A/D range - 0 = [-10, 10] - 1 = [0,10] - [4] - D/A 0 range - 0 = [-10, 10] - 1 = [-5,5] - 2 = [-2.5,2.5] - 3 = [0,10] - 4 = [0,5] - [5] - D/A 1 range (same choices) -*/ + * Driver: dt2801 + * Description: Data Translation DT2801 series and DT01-EZ + * Author: ds + * Status: works + * Devices: [Data Translation] DT2801 (dt2801), DT2801-A, DT2801/5716A, + * DT2805, DT2805/5716A, DT2808, DT2818, DT2809, DT01-EZ + * + * This driver can autoprobe the type of board. + * + * Configuration options: + * [0] - I/O port base address + * [1] - unused + * [2] - A/D reference 0=differential, 1=single-ended + * [3] - A/D range + * 0 = [-10, 10] + * 1 = [0,10] + * [4] - D/A 0 range + * 0 = [-10, 10] + * 1 = [-5,5] + * 2 = [-2.5,2.5] + * 3 = [0,10] + * 4 = [0,5] + * [5] - D/A 1 range (same choices) + */ #include #include "../comedidev.h" @@ -65,9 +65,10 @@ Configuration options: #define DT_C_SET_AD 0xd #define DT_C_READ_AD 0xe -/* Command modifiers (only used with read/write), EXTTRIG can be - used with some other commands. -*/ +/* + * Command modifiers (only used with read/write), EXTTRIG can be + * used with some other commands. + */ #define DT_MOD_DMA BIT(4) #define DT_MOD_CONT BIT(5) #define DT_MOD_EXTCLK BIT(6) @@ -135,9 +136,10 @@ struct dt2801_board { int dabits; }; -/* Typeid's for the different boards of the DT2801-series - (taken from the test-software, that comes with the board) - */ +/* + * Typeid's for the different boards of the DT2801-series + * (taken from the test-software, that comes with the board) + */ static const struct dt2801_board boardtypes[] = { { .name = "dt2801", @@ -209,15 +211,18 @@ struct dt2801_private { const struct comedi_lrange *dac_range_types[2]; }; -/* These are the low-level routines: - writecommand: write a command to the board - writedata: write data byte - readdata: read data byte +/* + * These are the low-level routines: + * writecommand: write a command to the board + * writedata: write data byte + * readdata: read data byte */ -/* Only checks DataOutReady-flag, not the Ready-flag as it is done - in the examples of the manual. I don't see why this should be - necessary. */ +/* + * Only checks DataOutReady-flag, not the Ready-flag as it is done + * in the examples of the manual. I don't see why this should be + * necessary. + */ static int dt2801_readdata(struct comedi_device *dev, int *data) { int stat = 0; @@ -517,14 +522,14 @@ static int dt2801_dio_insn_config(struct comedi_device *dev, } /* - options: - [0] - i/o base - [1] - unused - [2] - a/d 0=differential, 1=single-ended - [3] - a/d range 0=[-10,10], 1=[0,10] - [4] - dac0 range 0=[-10,10], 1=[-5,5], 2=[-2.5,2.5] 3=[0,10], 4=[0,5] - [5] - dac1 range 0=[-10,10], 1=[-5,5], 2=[-2.5,2.5] 3=[0,10], 4=[0,5] -*/ + * options: + * [0] - i/o base + * [1] - unused + * [2] - a/d 0=differential, 1=single-ended + * [3] - a/d range 0=[-10,10], 1=[0,10] + * [4] - dac0 range 0=[-10,10], 1=[-5,5], 2=[-2.5,2.5] 3=[0,10], 4=[0,5] + * [5] - dac1 range 0=[-10,10], 1=[-5,5], 2=[-2.5,2.5] 3=[0,10], 4=[0,5] + */ static int dt2801_attach(struct comedi_device *dev, struct comedi_devconfig *it) { const struct dt2801_board *board; -- cgit v0.10.2 From 1694830640d4573e8535dd6798b6f4cf00f680fd Mon Sep 17 00:00:00 2001 From: Ravishankar Karkala Mallikarjunayya Date: Wed, 18 May 2016 10:27:29 +0530 Subject: Staging: comedi: fix CHECK: Prefer using the BIT macro issues in pcmmio.c This patch Replace all occurences of (1< Reviewed-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/comedi/drivers/pcmmio.c b/drivers/staging/comedi/drivers/pcmmio.c index 10472e6..70ad497 100644 --- a/drivers/staging/comedi/drivers/pcmmio.c +++ b/drivers/staging/comedi/drivers/pcmmio.c @@ -84,25 +84,25 @@ #define PCMMIO_AI_LSB_REG 0x00 #define PCMMIO_AI_MSB_REG 0x01 #define PCMMIO_AI_CMD_REG 0x02 -#define PCMMIO_AI_CMD_SE (1 << 7) -#define PCMMIO_AI_CMD_ODD_CHAN (1 << 6) +#define PCMMIO_AI_CMD_SE BIT(7) +#define PCMMIO_AI_CMD_ODD_CHAN BIT(6) #define PCMMIO_AI_CMD_CHAN_SEL(x) (((x) & 0x3) << 4) #define PCMMIO_AI_CMD_RANGE(x) (((x) & 0x3) << 2) #define PCMMIO_RESOURCE_REG 0x02 #define PCMMIO_RESOURCE_IRQ(x) (((x) & 0xf) << 0) #define PCMMIO_AI_STATUS_REG 0x03 -#define PCMMIO_AI_STATUS_DATA_READY (1 << 7) -#define PCMMIO_AI_STATUS_DATA_DMA_PEND (1 << 6) -#define PCMMIO_AI_STATUS_CMD_DMA_PEND (1 << 5) -#define PCMMIO_AI_STATUS_IRQ_PEND (1 << 4) -#define PCMMIO_AI_STATUS_DATA_DRQ_ENA (1 << 2) -#define PCMMIO_AI_STATUS_REG_SEL (1 << 3) -#define PCMMIO_AI_STATUS_CMD_DRQ_ENA (1 << 1) -#define PCMMIO_AI_STATUS_IRQ_ENA (1 << 0) +#define PCMMIO_AI_STATUS_DATA_READY BIT(7) +#define PCMMIO_AI_STATUS_DATA_DMA_PEND BIT(6) +#define PCMMIO_AI_STATUS_CMD_DMA_PEND BIT(5) +#define PCMMIO_AI_STATUS_IRQ_PEND BIT(4) +#define PCMMIO_AI_STATUS_DATA_DRQ_ENA BIT(2) +#define PCMMIO_AI_STATUS_REG_SEL BIT(3) +#define PCMMIO_AI_STATUS_CMD_DRQ_ENA BIT(1) +#define PCMMIO_AI_STATUS_IRQ_ENA BIT(0) #define PCMMIO_AI_RES_ENA_REG 0x03 #define PCMMIO_AI_RES_ENA_CMD_REG_ACCESS (0 << 3) -#define PCMMIO_AI_RES_ENA_AI_RES_ACCESS (1 << 3) -#define PCMMIO_AI_RES_ENA_DIO_RES_ACCESS (1 << 4) +#define PCMMIO_AI_RES_ENA_AI_RES_ACCESS BIT(3) +#define PCMMIO_AI_RES_ENA_DIO_RES_ACCESS BIT(4) #define PCMMIO_AI_2ND_ADC_OFFSET 0x04 #define PCMMIO_AO_LSB_REG 0x08 @@ -125,14 +125,14 @@ #define PCMMIO_AO_CMD_CHAN_SEL(x) (((x) & 0x03) << 1) #define PCMMIO_AO_CMD_CHAN_SEL_ALL (0x0f << 0) #define PCMMIO_AO_STATUS_REG 0x0b -#define PCMMIO_AO_STATUS_DATA_READY (1 << 7) -#define PCMMIO_AO_STATUS_DATA_DMA_PEND (1 << 6) -#define PCMMIO_AO_STATUS_CMD_DMA_PEND (1 << 5) -#define PCMMIO_AO_STATUS_IRQ_PEND (1 << 4) -#define PCMMIO_AO_STATUS_DATA_DRQ_ENA (1 << 2) -#define PCMMIO_AO_STATUS_REG_SEL (1 << 3) -#define PCMMIO_AO_STATUS_CMD_DRQ_ENA (1 << 1) -#define PCMMIO_AO_STATUS_IRQ_ENA (1 << 0) +#define PCMMIO_AO_STATUS_DATA_READY BIT(7) +#define PCMMIO_AO_STATUS_DATA_DMA_PEND BIT(6) +#define PCMMIO_AO_STATUS_CMD_DMA_PEND BIT(5) +#define PCMMIO_AO_STATUS_IRQ_PEND BIT(4) +#define PCMMIO_AO_STATUS_DATA_DRQ_ENA BIT(2) +#define PCMMIO_AO_STATUS_REG_SEL BIT(3) +#define PCMMIO_AO_STATUS_CMD_DRQ_ENA BIT(1) +#define PCMMIO_AO_STATUS_IRQ_ENA BIT(0) #define PCMMIO_AO_RESOURCE_ENA_REG 0x0b #define PCMMIO_AO_2ND_DAC_OFFSET 0x04 -- cgit v0.10.2 From 269452dc6c5a415f0b24e62f894cb45d0c08a6fe Mon Sep 17 00:00:00 2001 From: Ian Abbott Date: Thu, 19 May 2016 19:15:14 +0100 Subject: staging: comedi: daqboard2000: remove commented out code Remove some commented out code. Some of it uses constructs that don't exist in the driver, and probably come from the source code for the MS Windows driver. Signed-off-by: Ian Abbott Reviewed-by: H Hartley Sweeten Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/comedi/drivers/daqboard2000.c b/drivers/staging/comedi/drivers/daqboard2000.c index a536a15..a68506f 100644 --- a/drivers/staging/comedi/drivers/daqboard2000.c +++ b/drivers/staging/comedi/drivers/daqboard2000.c @@ -278,9 +278,7 @@ struct daqboard2000_private { static void writeAcqScanListEntry(struct comedi_device *dev, u16 entry) { - /* udelay(4); */ writew(entry & 0x00ff, dev->mmio + acqScanListFIFO); - /* udelay(4); */ writew((entry >> 8) & 0x00ff, dev->mmio + acqScanListFIFO); } @@ -315,13 +313,9 @@ static void setup_sampling(struct comedi_device *dev, int chan, int gain) word3 = 0; break; } -/* - dev->eeprom.correctionDACSE[i][j][k].offset = 0x800; - dev->eeprom.correctionDACSE[i][j][k].gain = 0xc00; -*/ /* These should be read from EEPROM */ - word2 |= 0x0800; - word3 |= 0xc000; + word2 |= 0x0800; /* offset */ + word3 |= 0xc000; /* gain */ writeAcqScanListEntry(dev, word0); writeAcqScanListEntry(dev, word1); writeAcqScanListEntry(dev, word2); -- cgit v0.10.2 From 77a574ec7b10afc1b3a9145f5aa6143bb9b9ca3a Mon Sep 17 00:00:00 2001 From: Ian Abbott Date: Thu, 19 May 2016 19:15:15 +0100 Subject: staging: comedi: daqboard2000: use usual block comment style Reformat one of the block comments to conform to the usual style (it's the only one that doesn't). Signed-off-by: Ian Abbott Reviewed-by: H Hartley Sweeten Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/comedi/drivers/daqboard2000.c b/drivers/staging/comedi/drivers/daqboard2000.c index a68506f..7b550ce 100644 --- a/drivers/staging/comedi/drivers/daqboard2000.c +++ b/drivers/staging/comedi/drivers/daqboard2000.c @@ -359,10 +359,12 @@ static int daqboard2000_ai_insn_read(struct comedi_device *dev, gain = CR_RANGE(insn->chanspec); chan = CR_CHAN(insn->chanspec); - /* This doesn't look efficient. I decided to take the conservative + /* + * This doesn't look efficient. I decided to take the conservative * approach when I did the insn conversion. Perhaps it would be * better to have broken it completely, then someone would have been - * forced to fix it. --ds */ + * forced to fix it. --ds + */ for (i = 0; i < insn->n; i++) { setup_sampling(dev, chan, gain); /* Enable reading from the scanlist FIFO */ -- cgit v0.10.2 From 0f2ee9bea701d1712aa505eee8ddf5e98870c3f6 Mon Sep 17 00:00:00 2001 From: Ian Abbott Date: Thu, 19 May 2016 19:15:16 +0100 Subject: staging: comedi: daqboard2000: CHECK: spaces preferred around that '*' Fix checkpatch issues of the form "CHECK: spaces preferred around that '*' (ctx:VxV)". Signed-off-by: Ian Abbott Reviewed-by: H Hartley Sweeten Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/comedi/drivers/daqboard2000.c b/drivers/staging/comedi/drivers/daqboard2000.c index 7b550ce..a45f318 100644 --- a/drivers/staging/comedi/drivers/daqboard2000.c +++ b/drivers/staging/comedi/drivers/daqboard2000.c @@ -169,17 +169,17 @@ static const struct comedi_lrange range_daqboard2000_ai = { #define dioP3hsioData 0x32 /* s16 */ #define dioP3Control 0x34 /* u16 */ #define calEepromControl 0x36 /* u16 */ -#define dacSetting(x) (0x38 + (x)*2) /* s16 */ +#define dacSetting(x) (0x38 + (x) * 2) /* s16 */ #define dioP2ExpansionIO8Bit 0x40 /* s16 */ #define ctrTmrControl 0x80 /* u16 */ -#define ctrInput(x) (0x88 + (x)*2) /* s16 */ -#define timerDivisor(x) (0xa0 + (x)*2) /* u16 */ +#define ctrInput(x) (0x88 + (x) * 2) /* s16 */ +#define timerDivisor(x) (0xa0 + (x) * 2) /* u16 */ #define dmaControl 0xb0 /* u16 */ #define trigControl 0xb2 /* u16 */ #define calEeprom 0xb8 /* u16 */ #define acqDigitalMark 0xba /* u16 */ #define trigDacs 0xbc /* u16 */ -#define dioP2ExpansionIO16Bit(x) (0xc0 + (x)*2) /* s16 */ +#define dioP2ExpansionIO16Bit(x) (0xc0 + (x) * 2) /* s16 */ /* Scan Sequencer programming */ #define DAQBOARD2000_SeqStartScanList 0x0011 -- cgit v0.10.2 From 4044ceb454c88b1a3d2c2baad5bcf0e425bdd651 Mon Sep 17 00:00:00 2001 From: Ian Abbott Date: Thu, 19 May 2016 19:15:17 +0100 Subject: staging: comedi: daqboard2000: add blank line after struct declaration Fix checkpatch issue: "CHECK: Please use a blank line after function/struct/union/enum declarations". Signed-off-by: Ian Abbott Reviewed-by: H Hartley Sweeten Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/comedi/drivers/daqboard2000.c b/drivers/staging/comedi/drivers/daqboard2000.c index a45f318..677d586 100644 --- a/drivers/staging/comedi/drivers/daqboard2000.c +++ b/drivers/staging/comedi/drivers/daqboard2000.c @@ -264,6 +264,7 @@ struct daq200_boardtype { const char *name; int id; }; + static const struct daq200_boardtype boardtypes[] = { {"ids2", DAQBOARD2000_SUBSYSTEM_IDS2}, {"ids4", DAQBOARD2000_SUBSYSTEM_IDS4}, -- cgit v0.10.2 From ff2ca4f0e89245680ef5f835b685fde3720ee83e Mon Sep 17 00:00:00 2001 From: Ian Abbott Date: Thu, 19 May 2016 19:15:18 +0100 Subject: staging: comedi: daqboard2000: rename serial EEPROM register macros Rename the macros defining values for the Serial EEPROM Control Register to avoid CamelCase. Signed-off-by: Ian Abbott Reviewed-by: H Hartley Sweeten Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/comedi/drivers/daqboard2000.c b/drivers/staging/comedi/drivers/daqboard2000.c index 677d586..c99773d 100644 --- a/drivers/staging/comedi/drivers/daqboard2000.c +++ b/drivers/staging/comedi/drivers/daqboard2000.c @@ -116,12 +116,12 @@ #define DAQBOARD2000_SUBSYSTEM_IDS4 0x0004 /* Daqboard/2000 - 4 Dacs */ /* Initialization bits for the Serial EEPROM Control Register */ -#define DAQBOARD2000_SECRProgPinHi 0x8001767e -#define DAQBOARD2000_SECRProgPinLo 0x8000767e -#define DAQBOARD2000_SECRLocalBusHi 0xc000767e -#define DAQBOARD2000_SECRLocalBusLo 0x8000767e -#define DAQBOARD2000_SECRReloadHi 0xa000767e -#define DAQBOARD2000_SECRReloadLo 0x8000767e +#define DB2K_SECR_PROG_PIN_HI 0x8001767e +#define DB2K_SECR_PROG_PIN_LO 0x8000767e +#define DB2K_SECR_LOCAL_BUS_HI 0xc000767e +#define DB2K_SECR_LOCAL_BUS_LO 0x8000767e +#define DB2K_SECR_RELOAD_HI 0xa000767e +#define DB2K_SECR_RELOAD_LO 0x8000767e /* SECR status bits */ #define DAQBOARD2000_EEPROM_PRESENT 0x10000000 @@ -438,9 +438,9 @@ static void daqboard2000_resetLocalBus(struct comedi_device *dev) { struct daqboard2000_private *devpriv = dev->private; - writel(DAQBOARD2000_SECRLocalBusHi, devpriv->plx + 0x6c); + writel(DB2K_SECR_LOCAL_BUS_HI, devpriv->plx + 0x6c); mdelay(10); - writel(DAQBOARD2000_SECRLocalBusLo, devpriv->plx + 0x6c); + writel(DB2K_SECR_LOCAL_BUS_LO, devpriv->plx + 0x6c); mdelay(10); } @@ -448,11 +448,11 @@ static void daqboard2000_reloadPLX(struct comedi_device *dev) { struct daqboard2000_private *devpriv = dev->private; - writel(DAQBOARD2000_SECRReloadLo, devpriv->plx + 0x6c); + writel(DB2K_SECR_RELOAD_LO, devpriv->plx + 0x6c); mdelay(10); - writel(DAQBOARD2000_SECRReloadHi, devpriv->plx + 0x6c); + writel(DB2K_SECR_RELOAD_HI, devpriv->plx + 0x6c); mdelay(10); - writel(DAQBOARD2000_SECRReloadLo, devpriv->plx + 0x6c); + writel(DB2K_SECR_RELOAD_LO, devpriv->plx + 0x6c); mdelay(10); } @@ -460,9 +460,9 @@ static void daqboard2000_pulseProgPin(struct comedi_device *dev) { struct daqboard2000_private *devpriv = dev->private; - writel(DAQBOARD2000_SECRProgPinHi, devpriv->plx + 0x6c); + writel(DB2K_SECR_PROG_PIN_HI, devpriv->plx + 0x6c); mdelay(10); - writel(DAQBOARD2000_SECRProgPinLo, devpriv->plx + 0x6c); + writel(DB2K_SECR_PROG_PIN_LO, devpriv->plx + 0x6c); mdelay(10); /* Not in the original code, but I like symmetry... */ } -- cgit v0.10.2 From 1e33538596ed153d0be3e0f9fffd224a0ac765a6 Mon Sep 17 00:00:00 2001 From: Ian Abbott Date: Thu, 19 May 2016 19:15:19 +0100 Subject: staging: comedi: daqboard2000: rename register offset macros Rename the macros defining register offsets to avoid CamelCase, and to use namespace associated with the driver. Signed-off-by: Ian Abbott Reviewed-by: H Hartley Sweeten Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/comedi/drivers/daqboard2000.c b/drivers/staging/comedi/drivers/daqboard2000.c index c99773d..32053ee 100644 --- a/drivers/staging/comedi/drivers/daqboard2000.c +++ b/drivers/staging/comedi/drivers/daqboard2000.c @@ -151,35 +151,35 @@ static const struct comedi_lrange range_daqboard2000_ai = { /* * Register Memory Map */ -#define acqControl 0x00 /* u16 */ -#define acqScanListFIFO 0x02 /* u16 */ -#define acqPacerClockDivLow 0x04 /* u32 */ -#define acqScanCounter 0x08 /* u16 */ -#define acqPacerClockDivHigh 0x0a /* u16 */ -#define acqTriggerCount 0x0c /* u16 */ -#define acqResultsFIFO 0x10 /* u16 */ -#define acqResultsShadow 0x14 /* u16 */ -#define acqAdcResult 0x18 /* u16 */ -#define dacScanCounter 0x1c /* u16 */ -#define dacControl 0x20 /* u16 */ -#define dacFIFO 0x24 /* s16 */ -#define dacPacerClockDiv 0x2a /* u16 */ -#define refDacs 0x2c /* u16 */ -#define dioControl 0x30 /* u16 */ -#define dioP3hsioData 0x32 /* s16 */ -#define dioP3Control 0x34 /* u16 */ -#define calEepromControl 0x36 /* u16 */ -#define dacSetting(x) (0x38 + (x) * 2) /* s16 */ -#define dioP2ExpansionIO8Bit 0x40 /* s16 */ -#define ctrTmrControl 0x80 /* u16 */ -#define ctrInput(x) (0x88 + (x) * 2) /* s16 */ -#define timerDivisor(x) (0xa0 + (x) * 2) /* u16 */ -#define dmaControl 0xb0 /* u16 */ -#define trigControl 0xb2 /* u16 */ -#define calEeprom 0xb8 /* u16 */ -#define acqDigitalMark 0xba /* u16 */ -#define trigDacs 0xbc /* u16 */ -#define dioP2ExpansionIO16Bit(x) (0xc0 + (x) * 2) /* s16 */ +#define DB2K_REG_ACQ_CONTROL 0x00 /* u16 */ +#define DB2K_REG_ACQ_SCAN_LIST_FIFO 0x02 /* u16 */ +#define DB2K_REG_ACQ_PACER_CLOCK_DIV_LOW 0x04 /* u32 */ +#define DB2K_REG_ACQ_SCAN_COUNTER 0x08 /* u16 */ +#define DB2K_REG_ACQ_PACER_CLOCK_DIV_HIGH 0x0a /* u16 */ +#define DB2K_REG_ACQ_TRIGGER_COUNT 0x0c /* u16 */ +#define DB2K_REG_ACQ_RESULTS_FIFO 0x10 /* u16 */ +#define DB2K_REG_ACQ_RESULTS_SHADOW 0x14 /* u16 */ +#define DB2K_REG_ACQ_ADC_RESULT 0x18 /* u16 */ +#define DB2K_REG_DAC_SCAN_COUNTER 0x1c /* u16 */ +#define DB2K_REG_DAC_CONTROL 0x20 /* u16 */ +#define DB2K_REG_DAC_FIFO 0x24 /* s16 */ +#define DB2K_REG_DAC_PACER_CLOCK_DIV 0x2a /* u16 */ +#define DB2K_REG_REF_DACS 0x2c /* u16 */ +#define DB2K_REG_DIO_CONTROL 0x30 /* u16 */ +#define DB2K_REG_P3_HSIO_DATA 0x32 /* s16 */ +#define DB2K_REG_P3_CONTROL 0x34 /* u16 */ +#define DB2K_REG_CAL_EEPROM_CONTROL 0x36 /* u16 */ +#define DB2K_REG_DAC_SETTING(x) (0x38 + (x) * 2) /* s16 */ +#define DB2K_REG_DIO_P2_EXP_IO_8_BIT 0x40 /* s16 */ +#define DB2K_REG_COUNTER_TIMER_CONTROL 0x80 /* u16 */ +#define DB2K_REG_COUNTER_INPUT(x) (0x88 + (x) * 2) /* s16 */ +#define DB2K_REG_TIMER_DIV(x) (0xa0 + (x) * 2) /* u16 */ +#define DB2K_REG_DMA_CONTROL 0xb0 /* u16 */ +#define DB2K_REG_TRIG_CONTROL 0xb2 /* u16 */ +#define DB2K_REG_CAL_EEPROM 0xb8 /* u16 */ +#define DB2K_REG_ACQ_DIGITAL_MARK 0xba /* u16 */ +#define DB2K_REG_TRIG_DACS 0xbc /* u16 */ +#define DB2K_REG_DIO_P2_EXP_IO_16_BIT(x) (0xc0 + (x) * 2) /* s16 */ /* Scan Sequencer programming */ #define DAQBOARD2000_SeqStartScanList 0x0011 @@ -279,8 +279,9 @@ struct daqboard2000_private { static void writeAcqScanListEntry(struct comedi_device *dev, u16 entry) { - writew(entry & 0x00ff, dev->mmio + acqScanListFIFO); - writew((entry >> 8) & 0x00ff, dev->mmio + acqScanListFIFO); + writew(entry & 0x00ff, dev->mmio + DB2K_REG_ACQ_SCAN_LIST_FIFO); + writew((entry >> 8) & 0x00ff, + dev->mmio + DB2K_REG_ACQ_SCAN_LIST_FIFO); } static void setup_sampling(struct comedi_device *dev, int chan, int gain) @@ -330,7 +331,7 @@ static int daqboard2000_ai_status(struct comedi_device *dev, { unsigned int status; - status = readw(dev->mmio + acqControl); + status = readw(dev->mmio + DB2K_REG_ACQ_CONTROL); if (status & context) return 0; return -EBUSY; @@ -347,15 +348,16 @@ static int daqboard2000_ai_insn_read(struct comedi_device *dev, writew(DAQBOARD2000_AcqResetScanListFifo | DAQBOARD2000_AcqResetResultsFifo | - DAQBOARD2000_AcqResetConfigPipe, dev->mmio + acqControl); + DAQBOARD2000_AcqResetConfigPipe, + dev->mmio + DB2K_REG_ACQ_CONTROL); /* * If pacer clock is not set to some high value (> 10 us), we * risk multiple samples to be put into the result FIFO. */ /* 1 second, should be long enough */ - writel(1000000, dev->mmio + acqPacerClockDivLow); - writew(0, dev->mmio + acqPacerClockDivHigh); + writel(1000000, dev->mmio + DB2K_REG_ACQ_PACER_CLOCK_DIV_LOW); + writew(0, dev->mmio + DB2K_REG_ACQ_PACER_CLOCK_DIV_HIGH); gain = CR_RANGE(insn->chanspec); chan = CR_CHAN(insn->chanspec); @@ -369,14 +371,16 @@ static int daqboard2000_ai_insn_read(struct comedi_device *dev, for (i = 0; i < insn->n; i++) { setup_sampling(dev, chan, gain); /* Enable reading from the scanlist FIFO */ - writew(DAQBOARD2000_SeqStartScanList, dev->mmio + acqControl); + writew(DAQBOARD2000_SeqStartScanList, + dev->mmio + DB2K_REG_ACQ_CONTROL); ret = comedi_timeout(dev, s, insn, daqboard2000_ai_status, DAQBOARD2000_AcqConfigPipeFull); if (ret) return ret; - writew(DAQBOARD2000_AdcPacerEnable, dev->mmio + acqControl); + writew(DAQBOARD2000_AdcPacerEnable, + dev->mmio + DB2K_REG_ACQ_CONTROL); ret = comedi_timeout(dev, s, insn, daqboard2000_ai_status, DAQBOARD2000_AcqLogicScanning); @@ -388,9 +392,11 @@ static int daqboard2000_ai_insn_read(struct comedi_device *dev, if (ret) return ret; - data[i] = readw(dev->mmio + acqResultsFIFO); - writew(DAQBOARD2000_AdcPacerDisable, dev->mmio + acqControl); - writew(DAQBOARD2000_SeqStopScanList, dev->mmio + acqControl); + data[i] = readw(dev->mmio + DB2K_REG_ACQ_RESULTS_FIFO); + writew(DAQBOARD2000_AdcPacerDisable, + dev->mmio + DB2K_REG_ACQ_CONTROL); + writew(DAQBOARD2000_SeqStopScanList, + dev->mmio + DB2K_REG_ACQ_CONTROL); } return i; @@ -404,7 +410,7 @@ static int daqboard2000_ao_eoc(struct comedi_device *dev, unsigned int chan = CR_CHAN(insn->chanspec); unsigned int status; - status = readw(dev->mmio + dacControl); + status = readw(dev->mmio + DB2K_REG_DAC_CONTROL); if ((status & ((chan + 1) * 0x0010)) == 0) return 0; return -EBUSY; @@ -422,7 +428,7 @@ static int daqboard2000_ao_insn_write(struct comedi_device *dev, unsigned int val = data[i]; int ret; - writew(val, dev->mmio + dacSetting(chan)); + writew(val, dev->mmio + DB2K_REG_DAC_SETTING(chan)); ret = comedi_timeout(dev, s, insn, daqboard2000_ao_eoc, 0); if (ret) @@ -550,18 +556,20 @@ static void daqboard2000_adcDisarm(struct comedi_device *dev) /* Disable hardware triggers */ udelay(2); writew(DAQBOARD2000_TrigAnalog | DAQBOARD2000_TrigDisable, - dev->mmio + trigControl); + dev->mmio + DB2K_REG_TRIG_CONTROL); udelay(2); writew(DAQBOARD2000_TrigTTL | DAQBOARD2000_TrigDisable, - dev->mmio + trigControl); + dev->mmio + DB2K_REG_TRIG_CONTROL); /* Stop the scan list FIFO from loading the configuration pipe */ udelay(2); - writew(DAQBOARD2000_SeqStopScanList, dev->mmio + acqControl); + writew(DAQBOARD2000_SeqStopScanList, + dev->mmio + DB2K_REG_ACQ_CONTROL); /* Stop the pacer clock */ udelay(2); - writew(DAQBOARD2000_AdcPacerDisable, dev->mmio + acqControl); + writew(DAQBOARD2000_AdcPacerDisable, + dev->mmio + DB2K_REG_ACQ_CONTROL); /* Stop the input dma (abort channel 1) */ daqboard2000_adcStopDmaTransfer(dev); @@ -573,18 +581,20 @@ static void daqboard2000_activateReferenceDacs(struct comedi_device *dev) int timeout; /* Set the + reference dac value in the FPGA */ - writew(0x80 | DAQBOARD2000_PosRefDacSelect, dev->mmio + refDacs); + writew(0x80 | DAQBOARD2000_PosRefDacSelect, + dev->mmio + DB2K_REG_REF_DACS); for (timeout = 0; timeout < 20; timeout++) { - val = readw(dev->mmio + dacControl); + val = readw(dev->mmio + DB2K_REG_DAC_CONTROL); if ((val & DAQBOARD2000_RefBusy) == 0) break; udelay(2); } /* Set the - reference dac value in the FPGA */ - writew(0x80 | DAQBOARD2000_NegRefDacSelect, dev->mmio + refDacs); + writew(0x80 | DAQBOARD2000_NegRefDacSelect, + dev->mmio + DB2K_REG_REF_DACS); for (timeout = 0; timeout < 20; timeout++) { - val = readw(dev->mmio + dacControl); + val = readw(dev->mmio + DB2K_REG_DAC_CONTROL); if ((val & DAQBOARD2000_RefBusy) == 0) break; udelay(2); @@ -711,7 +721,7 @@ static int daqboard2000_auto_attach(struct comedi_device *dev, s = &dev->subdevices[2]; return subdev_8255_init(dev, s, daqboard2000_8255_cb, - dioP2ExpansionIO8Bit); + DB2K_REG_DIO_P2_EXP_IO_8_BIT); } static void daqboard2000_detach(struct comedi_device *dev) -- cgit v0.10.2 From f1ee5d86d66a91dfd8d8280e6adc5589034fd19e Mon Sep 17 00:00:00 2001 From: Ian Abbott Date: Thu, 19 May 2016 19:15:20 +0100 Subject: staging: comedi: daqboard2000: rename acquisition control register macros Rename the macros defining values for the acquisition control register to avoid CamelCase, and to make it clearer which register they are associated with. Signed-off-by: Ian Abbott Reviewed-by: H Hartley Sweeten Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/comedi/drivers/daqboard2000.c b/drivers/staging/comedi/drivers/daqboard2000.c index 32053ee..483b131 100644 --- a/drivers/staging/comedi/drivers/daqboard2000.c +++ b/drivers/staging/comedi/drivers/daqboard2000.c @@ -182,13 +182,13 @@ static const struct comedi_lrange range_daqboard2000_ai = { #define DB2K_REG_DIO_P2_EXP_IO_16_BIT(x) (0xc0 + (x) * 2) /* s16 */ /* Scan Sequencer programming */ -#define DAQBOARD2000_SeqStartScanList 0x0011 -#define DAQBOARD2000_SeqStopScanList 0x0010 +#define DB2K_ACQ_CONTROL_SEQ_START_SCAN_LIST 0x0011 +#define DB2K_ACQ_CONTROL_SEQ_STOP_SCAN_LIST 0x0010 /* Prepare for acquisition */ -#define DAQBOARD2000_AcqResetScanListFifo 0x0004 -#define DAQBOARD2000_AcqResetResultsFifo 0x0002 -#define DAQBOARD2000_AcqResetConfigPipe 0x0001 +#define DB2K_ACQ_CONTROL_RESET_SCAN_LIST_FIFO 0x0004 +#define DB2K_ACQ_CONTROL_RESET_RESULTS_FIFO 0x0002 +#define DB2K_ACQ_CONTROL_RESET_CONFIG_PIPE 0x0001 /* Acqusition status bits */ #define DAQBOARD2000_AcqResultsFIFOMore1Sample 0x0001 @@ -203,20 +203,16 @@ static const struct comedi_lrange range_daqboard2000_ai = { #define DAQBOARD2000_DacPacerOverrun 0x0200 #define DAQBOARD2000_AcqHardwareError 0x01c0 -/* Scan Sequencer programming */ -#define DAQBOARD2000_SeqStartScanList 0x0011 -#define DAQBOARD2000_SeqStopScanList 0x0010 - /* Pacer Clock Control */ -#define DAQBOARD2000_AdcPacerInternal 0x0030 -#define DAQBOARD2000_AdcPacerExternal 0x0032 -#define DAQBOARD2000_AdcPacerEnable 0x0031 -#define DAQBOARD2000_AdcPacerEnableDacPacer 0x0034 -#define DAQBOARD2000_AdcPacerDisable 0x0030 -#define DAQBOARD2000_AdcPacerNormalMode 0x0060 -#define DAQBOARD2000_AdcPacerCompatibilityMode 0x0061 -#define DAQBOARD2000_AdcPacerInternalOutEnable 0x0008 -#define DAQBOARD2000_AdcPacerExternalRising 0x0100 +#define DB2K_ACQ_CONTROL_ADC_PACER_INTERNAL 0x0030 +#define DB2K_ACQ_CONTROL_ADC_PACER_EXTERNAL 0x0032 +#define DB2K_ACQ_CONTROL_ADC_PACER_ENABLE 0x0031 +#define DB2K_ACQ_CONTROL_ADC_PACER_ENABLE_DAC_PACER 0x0034 +#define DB2K_ACQ_CONTROL_ADC_PACER_DISABLE 0x0030 +#define DB2K_ACQ_CONTROL_ADC_PACER_NORMAL_MODE 0x0060 +#define DB2K_ACQ_CONTROL_ADC_PACER_COMPATIBILITY_MODE 0x0061 +#define DB2K_ACQ_CONTROL_ADC_PACER_INTERNAL_OUT_ENABLE 0x0008 +#define DB2K_ACQ_CONTROL_ADC_PACER_EXTERNAL_RISING 0x0100 /* DAC status */ #define DAQBOARD2000_DacFull 0x0001 @@ -346,9 +342,9 @@ static int daqboard2000_ai_insn_read(struct comedi_device *dev, int ret; int i; - writew(DAQBOARD2000_AcqResetScanListFifo | - DAQBOARD2000_AcqResetResultsFifo | - DAQBOARD2000_AcqResetConfigPipe, + writew(DB2K_ACQ_CONTROL_RESET_SCAN_LIST_FIFO | + DB2K_ACQ_CONTROL_RESET_RESULTS_FIFO | + DB2K_ACQ_CONTROL_RESET_CONFIG_PIPE, dev->mmio + DB2K_REG_ACQ_CONTROL); /* @@ -371,7 +367,7 @@ static int daqboard2000_ai_insn_read(struct comedi_device *dev, for (i = 0; i < insn->n; i++) { setup_sampling(dev, chan, gain); /* Enable reading from the scanlist FIFO */ - writew(DAQBOARD2000_SeqStartScanList, + writew(DB2K_ACQ_CONTROL_SEQ_START_SCAN_LIST, dev->mmio + DB2K_REG_ACQ_CONTROL); ret = comedi_timeout(dev, s, insn, daqboard2000_ai_status, @@ -379,7 +375,7 @@ static int daqboard2000_ai_insn_read(struct comedi_device *dev, if (ret) return ret; - writew(DAQBOARD2000_AdcPacerEnable, + writew(DB2K_ACQ_CONTROL_ADC_PACER_ENABLE, dev->mmio + DB2K_REG_ACQ_CONTROL); ret = comedi_timeout(dev, s, insn, daqboard2000_ai_status, @@ -393,9 +389,9 @@ static int daqboard2000_ai_insn_read(struct comedi_device *dev, return ret; data[i] = readw(dev->mmio + DB2K_REG_ACQ_RESULTS_FIFO); - writew(DAQBOARD2000_AdcPacerDisable, + writew(DB2K_ACQ_CONTROL_ADC_PACER_DISABLE, dev->mmio + DB2K_REG_ACQ_CONTROL); - writew(DAQBOARD2000_SeqStopScanList, + writew(DB2K_ACQ_CONTROL_SEQ_STOP_SCAN_LIST, dev->mmio + DB2K_REG_ACQ_CONTROL); } @@ -563,12 +559,12 @@ static void daqboard2000_adcDisarm(struct comedi_device *dev) /* Stop the scan list FIFO from loading the configuration pipe */ udelay(2); - writew(DAQBOARD2000_SeqStopScanList, + writew(DB2K_ACQ_CONTROL_SEQ_STOP_SCAN_LIST, dev->mmio + DB2K_REG_ACQ_CONTROL); /* Stop the pacer clock */ udelay(2); - writew(DAQBOARD2000_AdcPacerDisable, + writew(DB2K_ACQ_CONTROL_ADC_PACER_DISABLE, dev->mmio + DB2K_REG_ACQ_CONTROL); /* Stop the input dma (abort channel 1) */ -- cgit v0.10.2 From 34d49fc07c19e2172d57ac69d516db783aeed902 Mon Sep 17 00:00:00 2001 From: Ian Abbott Date: Thu, 19 May 2016 19:15:21 +0100 Subject: staging: comedi: daqboard2000: rename acq status register macros Rename the macros associated with the acquisition status register to avoid CamelCase and to make it clear which register they are associated with. Add a macro to define the offset of the read-only acquisition status register. It's the same offset as the acquisition control register, which is write-only. Signed-off-by: Ian Abbott Reviewed-by: H Hartley Sweeten Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/comedi/drivers/daqboard2000.c b/drivers/staging/comedi/drivers/daqboard2000.c index 483b131..fd35ddf 100644 --- a/drivers/staging/comedi/drivers/daqboard2000.c +++ b/drivers/staging/comedi/drivers/daqboard2000.c @@ -151,7 +151,8 @@ static const struct comedi_lrange range_daqboard2000_ai = { /* * Register Memory Map */ -#define DB2K_REG_ACQ_CONTROL 0x00 /* u16 */ +#define DB2K_REG_ACQ_CONTROL 0x00 /* u16 (w) */ +#define DB2K_REG_ACQ_STATUS 0x00 /* u16 (r) */ #define DB2K_REG_ACQ_SCAN_LIST_FIFO 0x02 /* u16 */ #define DB2K_REG_ACQ_PACER_CLOCK_DIV_LOW 0x04 /* u32 */ #define DB2K_REG_ACQ_SCAN_COUNTER 0x08 /* u16 */ @@ -190,19 +191,6 @@ static const struct comedi_lrange range_daqboard2000_ai = { #define DB2K_ACQ_CONTROL_RESET_RESULTS_FIFO 0x0002 #define DB2K_ACQ_CONTROL_RESET_CONFIG_PIPE 0x0001 -/* Acqusition status bits */ -#define DAQBOARD2000_AcqResultsFIFOMore1Sample 0x0001 -#define DAQBOARD2000_AcqResultsFIFOHasValidData 0x0002 -#define DAQBOARD2000_AcqResultsFIFOOverrun 0x0004 -#define DAQBOARD2000_AcqLogicScanning 0x0008 -#define DAQBOARD2000_AcqConfigPipeFull 0x0010 -#define DAQBOARD2000_AcqScanListFIFOEmpty 0x0020 -#define DAQBOARD2000_AcqAdcNotReady 0x0040 -#define DAQBOARD2000_ArbitrationFailure 0x0080 -#define DAQBOARD2000_AcqPacerOverrun 0x0100 -#define DAQBOARD2000_DacPacerOverrun 0x0200 -#define DAQBOARD2000_AcqHardwareError 0x01c0 - /* Pacer Clock Control */ #define DB2K_ACQ_CONTROL_ADC_PACER_INTERNAL 0x0030 #define DB2K_ACQ_CONTROL_ADC_PACER_EXTERNAL 0x0032 @@ -214,6 +202,18 @@ static const struct comedi_lrange range_daqboard2000_ai = { #define DB2K_ACQ_CONTROL_ADC_PACER_INTERNAL_OUT_ENABLE 0x0008 #define DB2K_ACQ_CONTROL_ADC_PACER_EXTERNAL_RISING 0x0100 +/* Acquisition status bits */ +#define DB2K_ACQ_STATUS_RESULTS_FIFO_MORE_1_SAMPLE 0x0001 +#define DB2K_ACQ_STATUS_RESULTS_FIFO_HAS_DATA 0x0002 +#define DB2K_ACQ_STATUS_RESULTS_FIFO_OVERRUN 0x0004 +#define DB2K_ACQ_STATUS_LOGIC_SCANNING 0x0008 +#define DB2K_ACQ_STATUS_CONFIG_PIPE_FULL 0x0010 +#define DB2K_ACQ_STATUS_SCAN_LIST_FIFO_EMPTY 0x0020 +#define DB2K_ACQ_STATUS_ADC_NOT_READY 0x0040 +#define DB2K_ACQ_STATUS_ARBITRATION_FAILURE 0x0080 +#define DB2K_ACQ_STATUS_ADC_PACER_OVERRUN 0x0100 +#define DB2K_ACQ_STATUS_DAC_PACER_OVERRUN 0x0200 + /* DAC status */ #define DAQBOARD2000_DacFull 0x0001 #define DAQBOARD2000_RefBusy 0x0002 @@ -327,7 +327,7 @@ static int daqboard2000_ai_status(struct comedi_device *dev, { unsigned int status; - status = readw(dev->mmio + DB2K_REG_ACQ_CONTROL); + status = readw(dev->mmio + DB2K_REG_ACQ_STATUS); if (status & context) return 0; return -EBUSY; @@ -371,7 +371,7 @@ static int daqboard2000_ai_insn_read(struct comedi_device *dev, dev->mmio + DB2K_REG_ACQ_CONTROL); ret = comedi_timeout(dev, s, insn, daqboard2000_ai_status, - DAQBOARD2000_AcqConfigPipeFull); + DB2K_ACQ_STATUS_CONFIG_PIPE_FULL); if (ret) return ret; @@ -379,12 +379,13 @@ static int daqboard2000_ai_insn_read(struct comedi_device *dev, dev->mmio + DB2K_REG_ACQ_CONTROL); ret = comedi_timeout(dev, s, insn, daqboard2000_ai_status, - DAQBOARD2000_AcqLogicScanning); + DB2K_ACQ_STATUS_LOGIC_SCANNING); if (ret) return ret; - ret = comedi_timeout(dev, s, insn, daqboard2000_ai_status, - DAQBOARD2000_AcqResultsFIFOHasValidData); + ret = + comedi_timeout(dev, s, insn, daqboard2000_ai_status, + DB2K_ACQ_STATUS_RESULTS_FIFO_HAS_DATA); if (ret) return ret; -- cgit v0.10.2 From ab8a4dc8595c8d4559420fe10e56a6a58b2982ac Mon Sep 17 00:00:00 2001 From: Ian Abbott Date: Thu, 19 May 2016 19:15:22 +0100 Subject: staging: comedi: daqboard2000: redo DAC control register macros Rename the macros used to define values for the DAC control register to avoid CamelCase and to make it clearer which register they are associated with. Refactor the macros used to define values to enable or disable DAC channels to use the channel number as a parameter. None of these macros are currently used by the driver. Signed-off-by: Ian Abbott Reviewed-by: H Hartley Sweeten Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/comedi/drivers/daqboard2000.c b/drivers/staging/comedi/drivers/daqboard2000.c index fd35ddf..7d5f647 100644 --- a/drivers/staging/comedi/drivers/daqboard2000.c +++ b/drivers/staging/comedi/drivers/daqboard2000.c @@ -225,20 +225,13 @@ static const struct comedi_lrange range_daqboard2000_ai = { #define DAQBOARD2000_Dac3Busy 0x0080 /* DAC control */ -#define DAQBOARD2000_Dac0Enable 0x0021 -#define DAQBOARD2000_Dac1Enable 0x0031 -#define DAQBOARD2000_Dac2Enable 0x0041 -#define DAQBOARD2000_Dac3Enable 0x0051 -#define DAQBOARD2000_DacEnableBit 0x0001 -#define DAQBOARD2000_Dac0Disable 0x0020 -#define DAQBOARD2000_Dac1Disable 0x0030 -#define DAQBOARD2000_Dac2Disable 0x0040 -#define DAQBOARD2000_Dac3Disable 0x0050 -#define DAQBOARD2000_DacResetFifo 0x0004 -#define DAQBOARD2000_DacPatternDisable 0x0060 -#define DAQBOARD2000_DacPatternEnable 0x0061 -#define DAQBOARD2000_DacSelectSignedData 0x0002 -#define DAQBOARD2000_DacSelectUnsignedData 0x0000 +#define DB2K_DAC_CONTROL_ENABLE_BIT 0x0001 +#define DB2K_DAC_CONTROL_DATA_IS_SIGNED 0x0002 +#define DB2K_DAC_CONTROL_RESET_FIFO 0x0004 +#define DB2K_DAC_CONTROL_DAC_DISABLE(x) (0x0020 + ((x) << 4)) +#define DB2K_DAC_CONTROL_DAC_ENABLE(x) (0x0021 + ((x) << 4)) +#define DB2K_DAC_CONTROL_PATTERN_DISABLE 0x0060 +#define DB2K_DAC_CONTROL_PATTERN_ENABLE 0x0061 /* Trigger Control */ #define DAQBOARD2000_TrigAnalog 0x0000 -- cgit v0.10.2 From 944f0d7f4b79433c07ab4f575330b9c747b90493 Mon Sep 17 00:00:00 2001 From: Ian Abbott Date: Thu, 19 May 2016 19:15:23 +0100 Subject: staging: comedi: daqboard2000: redo DAC status macros and fix busy Rename the macros defining values for the DAC status register to avoid CamelCase, and to make it clear which register they are associated with. Refactor the macros defining the regular DAC channel "busy" bits into a single macro that takes the DAC channel number as a parameter. Add a macro to define the offset of the read-only DAC status register. It is the same offset as the DAC control register, which is write-only. The code in `daqboard2000_ao_eoc()` that checks the status for completion of the DAC conversion looks wrong. The register has a "busy" bit for each channel, but the existing code only works for channels 0 and 1. The driver only supports two DAC channels at the moment, so the bug is currently harmless, but fix it so we can support four DAC channels on some board models. Signed-off-by: Ian Abbott Reviewed-by: H Hartley Sweeten Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/comedi/drivers/daqboard2000.c b/drivers/staging/comedi/drivers/daqboard2000.c index 7d5f647..2fd664d 100644 --- a/drivers/staging/comedi/drivers/daqboard2000.c +++ b/drivers/staging/comedi/drivers/daqboard2000.c @@ -162,7 +162,8 @@ static const struct comedi_lrange range_daqboard2000_ai = { #define DB2K_REG_ACQ_RESULTS_SHADOW 0x14 /* u16 */ #define DB2K_REG_ACQ_ADC_RESULT 0x18 /* u16 */ #define DB2K_REG_DAC_SCAN_COUNTER 0x1c /* u16 */ -#define DB2K_REG_DAC_CONTROL 0x20 /* u16 */ +#define DB2K_REG_DAC_CONTROL 0x20 /* u16 (w) */ +#define DB2K_REG_DAC_STATUS 0x20 /* u16 (r) */ #define DB2K_REG_DAC_FIFO 0x24 /* s16 */ #define DB2K_REG_DAC_PACER_CLOCK_DIV 0x2a /* u16 */ #define DB2K_REG_REF_DACS 0x2c /* u16 */ @@ -215,14 +216,11 @@ static const struct comedi_lrange range_daqboard2000_ai = { #define DB2K_ACQ_STATUS_DAC_PACER_OVERRUN 0x0200 /* DAC status */ -#define DAQBOARD2000_DacFull 0x0001 -#define DAQBOARD2000_RefBusy 0x0002 -#define DAQBOARD2000_TrgBusy 0x0004 -#define DAQBOARD2000_CalBusy 0x0008 -#define DAQBOARD2000_Dac0Busy 0x0010 -#define DAQBOARD2000_Dac1Busy 0x0020 -#define DAQBOARD2000_Dac2Busy 0x0040 -#define DAQBOARD2000_Dac3Busy 0x0080 +#define DB2K_DAC_STATUS_DAC_FULL 0x0001 +#define DB2K_DAC_STATUS_REF_BUSY 0x0002 +#define DB2K_DAC_STATUS_TRIG_BUSY 0x0004 +#define DB2K_DAC_STATUS_CAL_BUSY 0x0008 +#define DB2K_DAC_STATUS_DAC_BUSY(x) (0x0010 << (x)) /* DAC control */ #define DB2K_DAC_CONTROL_ENABLE_BIT 0x0001 @@ -400,8 +398,8 @@ static int daqboard2000_ao_eoc(struct comedi_device *dev, unsigned int chan = CR_CHAN(insn->chanspec); unsigned int status; - status = readw(dev->mmio + DB2K_REG_DAC_CONTROL); - if ((status & ((chan + 1) * 0x0010)) == 0) + status = readw(dev->mmio + DB2K_REG_DAC_STATUS); + if ((status & DB2K_DAC_STATUS_DAC_BUSY(chan)) == 0) return 0; return -EBUSY; } @@ -574,8 +572,8 @@ static void daqboard2000_activateReferenceDacs(struct comedi_device *dev) writew(0x80 | DAQBOARD2000_PosRefDacSelect, dev->mmio + DB2K_REG_REF_DACS); for (timeout = 0; timeout < 20; timeout++) { - val = readw(dev->mmio + DB2K_REG_DAC_CONTROL); - if ((val & DAQBOARD2000_RefBusy) == 0) + val = readw(dev->mmio + DB2K_REG_DAC_STATUS); + if ((val & DB2K_DAC_STATUS_REF_BUSY) == 0) break; udelay(2); } @@ -584,8 +582,8 @@ static void daqboard2000_activateReferenceDacs(struct comedi_device *dev) writew(0x80 | DAQBOARD2000_NegRefDacSelect, dev->mmio + DB2K_REG_REF_DACS); for (timeout = 0; timeout < 20; timeout++) { - val = readw(dev->mmio + DB2K_REG_DAC_CONTROL); - if ((val & DAQBOARD2000_RefBusy) == 0) + val = readw(dev->mmio + DB2K_REG_DAC_STATUS); + if ((val & DB2K_DAC_STATUS_REF_BUSY) == 0) break; udelay(2); } -- cgit v0.10.2 From 77b9634cbdbf62c0aa12f783df7b2c48cf1e5ba3 Mon Sep 17 00:00:00 2001 From: Ian Abbott Date: Thu, 19 May 2016 19:15:24 +0100 Subject: staging: comedi: daqboard2000: rename trigger control register macros Rename the macros that define values for the trigger control register to avoid CamelCase, and to make it clearer which register they are associated with. Signed-off-by: Ian Abbott Reviewed-by: H Hartley Sweeten Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/comedi/drivers/daqboard2000.c b/drivers/staging/comedi/drivers/daqboard2000.c index 2fd664d..6f991e7 100644 --- a/drivers/staging/comedi/drivers/daqboard2000.c +++ b/drivers/staging/comedi/drivers/daqboard2000.c @@ -232,16 +232,16 @@ static const struct comedi_lrange range_daqboard2000_ai = { #define DB2K_DAC_CONTROL_PATTERN_ENABLE 0x0061 /* Trigger Control */ -#define DAQBOARD2000_TrigAnalog 0x0000 -#define DAQBOARD2000_TrigTTL 0x0010 -#define DAQBOARD2000_TrigTransHiLo 0x0004 -#define DAQBOARD2000_TrigTransLoHi 0x0000 -#define DAQBOARD2000_TrigAbove 0x0000 -#define DAQBOARD2000_TrigBelow 0x0004 -#define DAQBOARD2000_TrigLevelSense 0x0002 -#define DAQBOARD2000_TrigEdgeSense 0x0000 -#define DAQBOARD2000_TrigEnable 0x0001 -#define DAQBOARD2000_TrigDisable 0x0000 +#define DB2K_TRIG_CONTROL_TYPE_ANALOG 0x0000 +#define DB2K_TRIG_CONTROL_TYPE_TTL 0x0010 +#define DB2K_TRIG_CONTROL_EDGE_HI_LO 0x0004 +#define DB2K_TRIG_CONTROL_EDGE_LO_HI 0x0000 +#define DB2K_TRIG_CONTROL_LEVEL_ABOVE 0x0000 +#define DB2K_TRIG_CONTROL_LEVEL_BELOW 0x0004 +#define DB2K_TRIG_CONTROL_SENSE_LEVEL 0x0002 +#define DB2K_TRIG_CONTROL_SENSE_EDGE 0x0000 +#define DB2K_TRIG_CONTROL_ENABLE 0x0001 +#define DB2K_TRIG_CONTROL_DISABLE 0x0000 /* Reference Dac Selection */ #define DAQBOARD2000_PosRefDacSelect 0x0100 @@ -543,10 +543,10 @@ static void daqboard2000_adcDisarm(struct comedi_device *dev) { /* Disable hardware triggers */ udelay(2); - writew(DAQBOARD2000_TrigAnalog | DAQBOARD2000_TrigDisable, + writew(DB2K_TRIG_CONTROL_TYPE_ANALOG | DB2K_TRIG_CONTROL_DISABLE, dev->mmio + DB2K_REG_TRIG_CONTROL); udelay(2); - writew(DAQBOARD2000_TrigTTL | DAQBOARD2000_TrigDisable, + writew(DB2K_TRIG_CONTROL_TYPE_TTL | DB2K_TRIG_CONTROL_DISABLE, dev->mmio + DB2K_REG_TRIG_CONTROL); /* Stop the scan list FIFO from loading the configuration pipe */ -- cgit v0.10.2 From 2c7aab274d648dffa99122af79b2edf09943f960 Mon Sep 17 00:00:00 2001 From: Ian Abbott Date: Thu, 19 May 2016 19:15:25 +0100 Subject: staging: comedi: daqboard2000: rename reference DACs register macros Rename the macros that define values for the reference DACs register to avoid CamelCase, and to make it clearer which register they are associated with. Add a macro `DB2K_REG_DACS_SET` for the value `0x0080` that triggers setting one of the references. Signed-off-by: Ian Abbott Reviewed-by: H Hartley Sweeten Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/comedi/drivers/daqboard2000.c b/drivers/staging/comedi/drivers/daqboard2000.c index 6f991e7..2876710 100644 --- a/drivers/staging/comedi/drivers/daqboard2000.c +++ b/drivers/staging/comedi/drivers/daqboard2000.c @@ -244,8 +244,9 @@ static const struct comedi_lrange range_daqboard2000_ai = { #define DB2K_TRIG_CONTROL_DISABLE 0x0000 /* Reference Dac Selection */ -#define DAQBOARD2000_PosRefDacSelect 0x0100 -#define DAQBOARD2000_NegRefDacSelect 0x0000 +#define DB2K_REF_DACS_SET 0x0080 +#define DB2K_REF_DACS_SELECT_POS_REF 0x0100 +#define DB2K_REF_DACS_SELECT_NEG_REF 0x0000 struct daq200_boardtype { const char *name; @@ -569,7 +570,7 @@ static void daqboard2000_activateReferenceDacs(struct comedi_device *dev) int timeout; /* Set the + reference dac value in the FPGA */ - writew(0x80 | DAQBOARD2000_PosRefDacSelect, + writew(DB2K_REF_DACS_SET | DB2K_REF_DACS_SELECT_POS_REF, dev->mmio + DB2K_REG_REF_DACS); for (timeout = 0; timeout < 20; timeout++) { val = readw(dev->mmio + DB2K_REG_DAC_STATUS); @@ -579,7 +580,7 @@ static void daqboard2000_activateReferenceDacs(struct comedi_device *dev) } /* Set the - reference dac value in the FPGA */ - writew(0x80 | DAQBOARD2000_NegRefDacSelect, + writew(DB2K_REF_DACS_SET | DB2K_REF_DACS_SELECT_NEG_REF, dev->mmio + DB2K_REG_REF_DACS); for (timeout = 0; timeout < 20; timeout++) { val = readw(dev->mmio + DB2K_REG_DAC_STATUS); -- cgit v0.10.2 From 0ef613473f8902708f7ea75d63e5dadb7c4a988c Mon Sep 17 00:00:00 2001 From: Ian Abbott Date: Thu, 19 May 2016 19:15:26 +0100 Subject: staging: comedi: daqboard2000: rename CamelCase functions Rename functions to avoid CamelCase warnings from checkpatch, and to use namespace associated with the driver. Signed-off-by: Ian Abbott Reviewed-by: H Hartley Sweeten Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/comedi/drivers/daqboard2000.c b/drivers/staging/comedi/drivers/daqboard2000.c index 2876710..6bc5bfe 100644 --- a/drivers/staging/comedi/drivers/daqboard2000.c +++ b/drivers/staging/comedi/drivers/daqboard2000.c @@ -265,14 +265,16 @@ struct daqboard2000_private { void __iomem *plx; }; -static void writeAcqScanListEntry(struct comedi_device *dev, u16 entry) +static void daqboard2000_write_acq_scan_list_entry(struct comedi_device *dev, + u16 entry) { writew(entry & 0x00ff, dev->mmio + DB2K_REG_ACQ_SCAN_LIST_FIFO); writew((entry >> 8) & 0x00ff, dev->mmio + DB2K_REG_ACQ_SCAN_LIST_FIFO); } -static void setup_sampling(struct comedi_device *dev, int chan, int gain) +static void daqboard2000_setup_sampling(struct comedi_device *dev, int chan, + int gain) { u16 word0, word1, word2, word3; @@ -306,10 +308,10 @@ static void setup_sampling(struct comedi_device *dev, int chan, int gain) /* These should be read from EEPROM */ word2 |= 0x0800; /* offset */ word3 |= 0xc000; /* gain */ - writeAcqScanListEntry(dev, word0); - writeAcqScanListEntry(dev, word1); - writeAcqScanListEntry(dev, word2); - writeAcqScanListEntry(dev, word3); + daqboard2000_write_acq_scan_list_entry(dev, word0); + daqboard2000_write_acq_scan_list_entry(dev, word1); + daqboard2000_write_acq_scan_list_entry(dev, word2); + daqboard2000_write_acq_scan_list_entry(dev, word3); } static int daqboard2000_ai_status(struct comedi_device *dev, @@ -357,7 +359,7 @@ static int daqboard2000_ai_insn_read(struct comedi_device *dev, * forced to fix it. --ds */ for (i = 0; i < insn->n; i++) { - setup_sampling(dev, chan, gain); + daqboard2000_setup_sampling(dev, chan, gain); /* Enable reading from the scanlist FIFO */ writew(DB2K_ACQ_CONTROL_SEQ_START_SCAN_LIST, dev->mmio + DB2K_REG_ACQ_CONTROL); @@ -429,7 +431,7 @@ static int daqboard2000_ao_insn_write(struct comedi_device *dev, return insn->n; } -static void daqboard2000_resetLocalBus(struct comedi_device *dev) +static void daqboard2000_reset_local_bus(struct comedi_device *dev) { struct daqboard2000_private *devpriv = dev->private; @@ -439,7 +441,7 @@ static void daqboard2000_resetLocalBus(struct comedi_device *dev) mdelay(10); } -static void daqboard2000_reloadPLX(struct comedi_device *dev) +static void daqboard2000_reload_plx(struct comedi_device *dev) { struct daqboard2000_private *devpriv = dev->private; @@ -451,7 +453,7 @@ static void daqboard2000_reloadPLX(struct comedi_device *dev) mdelay(10); } -static void daqboard2000_pulseProgPin(struct comedi_device *dev) +static void daqboard2000_pulse_prog_pin(struct comedi_device *dev) { struct daqboard2000_private *devpriv = dev->private; @@ -461,7 +463,7 @@ static void daqboard2000_pulseProgPin(struct comedi_device *dev) mdelay(10); /* Not in the original code, but I like symmetry... */ } -static int daqboard2000_pollCPLD(struct comedi_device *dev, int mask) +static int daqboard2000_poll_cpld(struct comedi_device *dev, int mask) { int result = 0; int i; @@ -480,7 +482,7 @@ static int daqboard2000_pollCPLD(struct comedi_device *dev, int mask) return result; } -static int daqboard2000_writeCPLD(struct comedi_device *dev, int data) +static int daqboard2000_write_cpld(struct comedi_device *dev, int data) { int result = 0; @@ -493,9 +495,9 @@ static int daqboard2000_writeCPLD(struct comedi_device *dev, int data) return result; } -static int initialize_daqboard2000(struct comedi_device *dev, - const u8 *cpld_array, size_t len, - unsigned long context) +static int daqboard2000_load_firmware(struct comedi_device *dev, + const u8 *cpld_array, size_t len, + unsigned long context) { struct daqboard2000_private *devpriv = dev->private; int result = -EIO; @@ -510,10 +512,10 @@ static int initialize_daqboard2000(struct comedi_device *dev, return -EIO; for (retry = 0; retry < 3; retry++) { - daqboard2000_resetLocalBus(dev); - daqboard2000_reloadPLX(dev); - daqboard2000_pulseProgPin(dev); - if (daqboard2000_pollCPLD(dev, DAQBOARD2000_CPLD_INIT)) { + daqboard2000_reset_local_bus(dev); + daqboard2000_reload_plx(dev); + daqboard2000_pulse_prog_pin(dev); + if (daqboard2000_poll_cpld(dev, DAQBOARD2000_CPLD_INIT)) { for (i = 0; i < len; i++) { if (cpld_array[i] == 0xff && cpld_array[i + 1] == 0x20) @@ -522,12 +524,12 @@ static int initialize_daqboard2000(struct comedi_device *dev, for (; i < len; i += 2) { int data = (cpld_array[i] << 8) + cpld_array[i + 1]; - if (!daqboard2000_writeCPLD(dev, data)) + if (!daqboard2000_write_cpld(dev, data)) break; } if (i >= len) { - daqboard2000_resetLocalBus(dev); - daqboard2000_reloadPLX(dev); + daqboard2000_reset_local_bus(dev); + daqboard2000_reload_plx(dev); result = 0; break; } @@ -536,11 +538,11 @@ static int initialize_daqboard2000(struct comedi_device *dev, return result; } -static void daqboard2000_adcStopDmaTransfer(struct comedi_device *dev) +static void daqboard2000_adc_stop_dma_transfer(struct comedi_device *dev) { } -static void daqboard2000_adcDisarm(struct comedi_device *dev) +static void daqboard2000_adc_disarm(struct comedi_device *dev) { /* Disable hardware triggers */ udelay(2); @@ -561,10 +563,10 @@ static void daqboard2000_adcDisarm(struct comedi_device *dev) dev->mmio + DB2K_REG_ACQ_CONTROL); /* Stop the input dma (abort channel 1) */ - daqboard2000_adcStopDmaTransfer(dev); + daqboard2000_adc_stop_dma_transfer(dev); } -static void daqboard2000_activateReferenceDacs(struct comedi_device *dev) +static void daqboard2000_activate_reference_dacs(struct comedi_device *dev) { unsigned int val; int timeout; @@ -590,29 +592,29 @@ static void daqboard2000_activateReferenceDacs(struct comedi_device *dev) } } -static void daqboard2000_initializeCtrs(struct comedi_device *dev) +static void daqboard2000_initialize_ctrs(struct comedi_device *dev) { } -static void daqboard2000_initializeTmrs(struct comedi_device *dev) +static void daqboard2000_initialize_tmrs(struct comedi_device *dev) { } -static void daqboard2000_dacDisarm(struct comedi_device *dev) +static void daqboard2000_dac_disarm(struct comedi_device *dev) { } -static void daqboard2000_initializeAdc(struct comedi_device *dev) +static void daqboard2000_initialize_adc(struct comedi_device *dev) { - daqboard2000_adcDisarm(dev); - daqboard2000_activateReferenceDacs(dev); - daqboard2000_initializeCtrs(dev); - daqboard2000_initializeTmrs(dev); + daqboard2000_adc_disarm(dev); + daqboard2000_activate_reference_dacs(dev); + daqboard2000_initialize_ctrs(dev); + daqboard2000_initialize_tmrs(dev); } -static void daqboard2000_initializeDac(struct comedi_device *dev) +static void daqboard2000_initialize_dac(struct comedi_device *dev) { - daqboard2000_dacDisarm(dev); + daqboard2000_dac_disarm(dev); } static int daqboard2000_8255_cb(struct comedi_device *dev, @@ -679,12 +681,12 @@ static int daqboard2000_auto_attach(struct comedi_device *dev, result = comedi_load_firmware(dev, &comedi_to_pci_dev(dev)->dev, DAQBOARD2000_FIRMWARE, - initialize_daqboard2000, 0); + daqboard2000_load_firmware, 0); if (result < 0) return result; - daqboard2000_initializeAdc(dev); - daqboard2000_initializeDac(dev); + daqboard2000_initialize_adc(dev); + daqboard2000_initialize_dac(dev); s = &dev->subdevices[0]; /* ai subdevice */ -- cgit v0.10.2 From cda2315000d257fb169e8e15675b667264634a74 Mon Sep 17 00:00:00 2001 From: Ian Abbott Date: Thu, 19 May 2016 19:15:27 +0100 Subject: staging: comedi: daqboard2000: prefer usleep_range() The checkpatch.pl warns about two `udelay(x)` calls, one of 100 microseconds, and one of 10 microseconds. The 100 microseconds one is used when waiting for FPGA to become ready to accept firmware, and is not that critical, so replace it with a call to `usleep_range(100, 1000)`. The 10 microseconds one is called as each 16-bit word of firmware data is written. Replace it with a fairly tight `usleep_range(10, 20)` to avoid slowing down firmware loading too much. The firmware is fairly short, so this would only slow it down firmware loading by about 20 milliseconds or so. Signed-off-by: Ian Abbott Reviewed-by: H Hartley Sweeten Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/comedi/drivers/daqboard2000.c b/drivers/staging/comedi/drivers/daqboard2000.c index 6bc5bfe..65daef0 100644 --- a/drivers/staging/comedi/drivers/daqboard2000.c +++ b/drivers/staging/comedi/drivers/daqboard2000.c @@ -476,7 +476,7 @@ static int daqboard2000_poll_cpld(struct comedi_device *dev, int mask) result = 1; break; } - udelay(100); + usleep_range(100, 1000); } udelay(5); return result; @@ -486,7 +486,7 @@ static int daqboard2000_write_cpld(struct comedi_device *dev, int data) { int result = 0; - udelay(10); + usleep_range(10, 20); writew(data, dev->mmio + 0x1000); if ((readw(dev->mmio + 0x1000) & DAQBOARD2000_CPLD_INIT) == DAQBOARD2000_CPLD_INIT) { -- cgit v0.10.2 From 66906590caef4de2932577a6f8d46071613bbd21 Mon Sep 17 00:00:00 2001 From: Ian Abbott Date: Fri, 20 May 2016 14:49:03 +0100 Subject: staging: comedi: plx9080.h: correct LRNG_IO_MASK and LMAP_IO_MASK For the PLX local address space range registers, LAS0RR and LAS1RR, bit 0 indicates whether the local address space will be mapped to memory space or I/O space. If mapped to I/O space, bit 1 must be set to 0, and bits 31 to 2 form the address decoding mask, which should be -2^N mod 2^32 for a range of length 2^N. The `LRNG_IO_MASK` macro is supposed to specify the address decoding bits for I/O space. It currently has the value `0xfffffffa`, but should be `0xfffffffc`, or possibly `0xfffffffe` (it doesn't really matter, since bit 1 is required to be set to 0). Change it to `0xfffffffc`. Similarly, for the PLX local address space local base address (remap) registers, LAS0BA and LAS1BA, bits 31 to 2, masked with the corresponding "range" register form the local base address for the local address space. The `LMAP_IO_MASK` macro is supposed to mask the valid bits for I/O space. Change its value from `0xfffffffa` to `0xfffffffc` to match `LRNG_IO_MASK`. Signed-off-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/comedi/drivers/plx9080.h b/drivers/staging/comedi/drivers/plx9080.h index 8d1aee00b1..7d6311c 100644 --- a/drivers/staging/comedi/drivers/plx9080.h +++ b/drivers/staging/comedi/drivers/plx9080.h @@ -60,7 +60,7 @@ struct plx_dma_desc { /* bits that specify range for memory io */ #define LRNG_MEM_MASK 0xfffffff0 /* bits that specify range for normal io */ -#define LRNG_IO_MASK 0xfffffffa +#define LRNG_IO_MASK 0xfffffffc /* L, Local Addr Space 0 Remap Register */ #define PLX_LAS0MAP_REG 0x0004 /* L, Local Addr Space 1 Remap Register */ @@ -69,7 +69,7 @@ struct plx_dma_desc { /* bits that specify decode for memory io */ #define LMAP_MEM_MASK 0xfffffff0 /* bits that specify decode bits for normal io */ -#define LMAP_IO_MASK 0xfffffffa +#define LMAP_IO_MASK 0xfffffffc /* * Mode/Arbitration Register. -- cgit v0.10.2 From dc895b42871065dd2ddf162a99b083cf6892d507 Mon Sep 17 00:00:00 2001 From: Ian Abbott Date: Fri, 20 May 2016 14:49:04 +0100 Subject: staging: comedi: plx9080.h: remove Power-Up Test Suite stuff The defines related to the Power-Up Test Suite (PUTS) are just cruft that has nothing to do with the PLX PCI-9080 chip. They seem to have been inherited from "drivers/net/plx9060.h" in the kernel 2.2.16 sources for use by the "wanxl" driver. Remove them. Signed-off-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/comedi/drivers/plx9080.h b/drivers/staging/comedi/drivers/plx9080.h index 7d6311c..3759a19 100644 --- a/drivers/staging/comedi/drivers/plx9080.h +++ b/drivers/staging/comedi/drivers/plx9080.h @@ -294,126 +294,6 @@ enum bigend_bits { #define PLX_PREFETCH 32 -/* - * The PCI Interface, via the PCI-9060 Chip, has up to eight (8) Mailbox - * Registers. The PUTS (Power-Up Test Suite) handles the board-side - * interface/interaction using the first 4 registers. Specifications for - * the use of the full PUTS' command and status interface is contained - * within a separate SBE PUTS Manual. The Host-Side Device Driver only - * uses a subset of the full PUTS interface. - */ - -/*****************************************/ -/*** MAILBOX #(-1) - MEM ACCESS STS ***/ -/*****************************************/ - -#define MBX_STS_VALID 0x57584744 /* 'WXGD' */ -#define MBX_STS_DILAV 0x44475857 /* swapped = 'DGXW' */ - -/*****************************************/ -/*** MAILBOX #0 - PUTS STATUS ***/ -/*****************************************/ - -#define MBX_STS_MASK 0x000000ff /* PUTS Status Register bits */ -#define MBX_STS_TMASK 0x0000000f /* register bits for TEST number */ - -#define MBX_STS_PCIRESET 0x00000100 /* Host issued PCI reset request */ -#define MBX_STS_BUSY 0x00000080 /* PUTS is in progress */ -#define MBX_STS_ERROR 0x00000040 /* PUTS has failed */ -/* - * Undefined -> status in transition. We are in process of changing bits; - * we SET Error bit before RESET of Busy bit - */ -#define MBX_STS_RESERVED 0x000000c0 - -#define MBX_RESERVED_5 0x00000020 /* FYI: reserved/unused bit */ -#define MBX_RESERVED_4 0x00000010 /* FYI: reserved/unused bit */ - -/******************************************/ -/*** MAILBOX #1 - PUTS COMMANDS ***/ -/******************************************/ - -/* - * Any attempt to execute an unimplement command results in the PUTS - * interface executing a NOOP and continuing as if the offending command - * completed normally. Note: this supplies a simple method to interrogate - * mailbox command processing functionality. - */ - -#define MBX_CMD_MASK 0xffff0000 /* PUTS Command Register bits */ - -#define MBX_CMD_ABORTJ 0x85000000 /* abort and jump */ -#define MBX_CMD_RESETP 0x86000000 /* reset and pause at start */ -#define MBX_CMD_PAUSE 0x87000000 /* pause immediately */ -#define MBX_CMD_PAUSEC 0x88000000 /* pause on completion */ -#define MBX_CMD_RESUME 0x89000000 /* resume operation */ -#define MBX_CMD_STEP 0x8a000000 /* single step tests */ - -#define MBX_CMD_BSWAP 0x8c000000 /* identify byte swap scheme */ -#define MBX_CMD_BSWAP_0 0x8c000000 /* use scheme 0 */ -#define MBX_CMD_BSWAP_1 0x8c000001 /* use scheme 1 */ - -/* setup host memory access window size */ -#define MBX_CMD_SETHMS 0x8d000000 -/* setup host memory access base address */ -#define MBX_CMD_SETHBA 0x8e000000 -/* perform memory setup and continue (IE. Done) */ -#define MBX_CMD_MGO 0x8f000000 -#define MBX_CMD_NOOP 0xFF000000 /* dummy, illegal command */ - -/*****************************************/ -/*** MAILBOX #2 - MEMORY SIZE ***/ -/*****************************************/ - -#define MBX_MEMSZ_MASK 0xffff0000 /* PUTS Memory Size Register bits */ - -#define MBX_MEMSZ_128KB 0x00020000 /* 128 kilobyte board */ -#define MBX_MEMSZ_256KB 0x00040000 /* 256 kilobyte board */ -#define MBX_MEMSZ_512KB 0x00080000 /* 512 kilobyte board */ -#define MBX_MEMSZ_1MB 0x00100000 /* 1 megabyte board */ -#define MBX_MEMSZ_2MB 0x00200000 /* 2 megabyte board */ -#define MBX_MEMSZ_4MB 0x00400000 /* 4 megabyte board */ -#define MBX_MEMSZ_8MB 0x00800000 /* 8 megabyte board */ -#define MBX_MEMSZ_16MB 0x01000000 /* 16 megabyte board */ - -/***************************************/ -/*** MAILBOX #2 - BOARD TYPE ***/ -/***************************************/ - -#define MBX_BTYPE_MASK 0x0000ffff /* PUTS Board Type Register */ -/* PUTS Board Family Register */ -#define MBX_BTYPE_FAMILY_MASK 0x0000ff00 -#define MBX_BTYPE_SUBTYPE_MASK 0x000000ff /* PUTS Board Subtype */ - -#define MBX_BTYPE_PLX9060 0x00000100 /* PLX family type */ -#define MBX_BTYPE_PLX9080 0x00000300 /* PLX wanXL100s family type */ - -#define MBX_BTYPE_WANXL_4 0x00000104 /* wanXL400, 4-port */ -#define MBX_BTYPE_WANXL_2 0x00000102 /* wanXL200, 2-port */ -#define MBX_BTYPE_WANXL_1s 0x00000301 /* wanXL100s, 1-port */ -#define MBX_BTYPE_WANXL_1t 0x00000401 /* wanXL100T1, 1-port */ - -/*****************************************/ -/*** MAILBOX #3 - SHMQ MAILBOX ***/ -/*****************************************/ - -#define MBX_SMBX_MASK 0x000000ff /* PUTS SHMQ Mailbox bits */ - -/***************************************/ -/*** GENERIC HOST-SIDE DRIVER ***/ -/***************************************/ - -#define MBX_ERR 0 -#define MBX_OK 1 - -/* mailbox check routine - type of testing */ -#define MBXCHK_STS 0x00 /* check for PUTS status */ -#define MBXCHK_NOWAIT 0x01 /* dont care about PUTS status */ - -/* system allocates this many bytes for address mapping mailbox space */ -#define MBX_ADDR_SPACE_360 0x80 /* wanXL100s/200/400 */ -#define MBX_ADDR_MASK_360 (MBX_ADDR_SPACE_360 - 1) - static inline int plx9080_abort_dma(void __iomem *iobase, unsigned int channel) { void __iomem *dma_cs_addr; -- cgit v0.10.2 From c644a11aae6e36b6dbae425cdfa9630d2abaaa16 Mon Sep 17 00:00:00 2001 From: Ian Abbott Date: Fri, 20 May 2016 14:49:05 +0100 Subject: staging: comedi: drivers: rename PLX PCI 9080 register offsets Rename the macros in "plx9080.h" that define the offsets of registers, following the pattern `PLX_REG_`, where `` is the register name from the PLX PCI 9080 Data Book. Add defines for the "Mailbox" registers, and add parameterized macros for the mailbox registers and the DMA control registers. Make use of the parameterized versions of the macros where it seems appropriate. The registers for supporting the I2O (Intelligent Input/Output) feature are largely left undefined, just defining enough to allow the I2O feature to be disabled. Signed-off-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/comedi/drivers/cb_pcidas64.c b/drivers/staging/comedi/drivers/cb_pcidas64.c index c773b8c..d9468db 100644 --- a/drivers/staging/comedi/drivers/cb_pcidas64.c +++ b/drivers/staging/comedi/drivers/cb_pcidas64.c @@ -1238,7 +1238,7 @@ static void disable_plx_interrupts(struct comedi_device *dev) devpriv->plx_intcsr_bits = 0; writel(devpriv->plx_intcsr_bits, - devpriv->plx9080_iobase + PLX_INTRCS_REG); + devpriv->plx9080_iobase + PLX_REG_INTCSR); } static void disable_ai_interrupts(struct comedi_device *dev) @@ -1291,14 +1291,14 @@ static void init_plx9080(struct comedi_device *dev) void __iomem *plx_iobase = devpriv->plx9080_iobase; devpriv->plx_control_bits = - readl(devpriv->plx9080_iobase + PLX_CONTROL_REG); + readl(devpriv->plx9080_iobase + PLX_REG_CNTRL); #ifdef __BIG_ENDIAN bits = BIGEND_DMA0 | BIGEND_DMA1; #else bits = 0; #endif - writel(bits, devpriv->plx9080_iobase + PLX_BIGEND_REG); + writel(bits, devpriv->plx9080_iobase + PLX_REG_BIGEND); disable_plx_interrupts(dev); @@ -1330,16 +1330,16 @@ static void init_plx9080(struct comedi_device *dev) bits |= PLX_LOCAL_BUS_32_WIDE_BITS; else /* localspace0 bus is 16 bits wide */ bits |= PLX_LOCAL_BUS_16_WIDE_BITS; - writel(bits, plx_iobase + PLX_DMA1_MODE_REG); + writel(bits, plx_iobase + PLX_REG_DMAMODE1); if (ao_cmd_is_supported(board)) - writel(bits, plx_iobase + PLX_DMA0_MODE_REG); + writel(bits, plx_iobase + PLX_REG_DMAMODE0); /* enable interrupts on plx 9080 */ devpriv->plx_intcsr_bits |= ICS_AERR | ICS_PERR | ICS_PIE | ICS_PLIE | ICS_PAIE | ICS_LIE | ICS_DMA0_E | ICS_DMA1_E; writel(devpriv->plx_intcsr_bits, - devpriv->plx9080_iobase + PLX_INTRCS_REG); + devpriv->plx9080_iobase + PLX_REG_INTCSR); } static void disable_ai_pacing(struct comedi_device *dev) @@ -1615,7 +1615,7 @@ static void i2c_set_sda(struct comedi_device *dev, int state) struct pcidas64_private *devpriv = dev->private; static const int data_bit = CTL_EE_W; void __iomem *plx_control_addr = devpriv->plx9080_iobase + - PLX_CONTROL_REG; + PLX_REG_CNTRL; if (state) { /* set data line high */ @@ -1636,7 +1636,7 @@ static void i2c_set_scl(struct comedi_device *dev, int state) struct pcidas64_private *devpriv = dev->private; static const int clock_bit = CTL_USERO; void __iomem *plx_control_addr = devpriv->plx9080_iobase + - PLX_CONTROL_REG; + PLX_REG_CNTRL; if (state) { /* set clock line high */ @@ -2367,14 +2367,8 @@ static inline void dma_start_sync(struct comedi_device *dev, /* spinlock for plx dma control/status reg */ spin_lock_irqsave(&dev->spinlock, flags); - if (channel) - writeb(PLX_DMA_EN_BIT | PLX_DMA_START_BIT | - PLX_CLEAR_DMA_INTR_BIT, - devpriv->plx9080_iobase + PLX_DMA1_CS_REG); - else - writeb(PLX_DMA_EN_BIT | PLX_DMA_START_BIT | - PLX_CLEAR_DMA_INTR_BIT, - devpriv->plx9080_iobase + PLX_DMA0_CS_REG); + writeb(PLX_DMA_EN_BIT | PLX_DMA_START_BIT | PLX_CLEAR_DMA_INTR_BIT, + devpriv->plx9080_iobase + PLX_REG_DMACSR(channel)); spin_unlock_irqrestore(&dev->spinlock, flags); } @@ -2552,21 +2546,17 @@ static inline void load_first_dma_descriptor(struct comedi_device *dev, * block. Initializing them to zero seems to fix the problem. */ if (dma_channel) { - writel(0, - devpriv->plx9080_iobase + PLX_DMA1_TRANSFER_SIZE_REG); - writel(0, devpriv->plx9080_iobase + PLX_DMA1_PCI_ADDRESS_REG); - writel(0, - devpriv->plx9080_iobase + PLX_DMA1_LOCAL_ADDRESS_REG); + writel(0, devpriv->plx9080_iobase + PLX_REG_DMASIZ1); + writel(0, devpriv->plx9080_iobase + PLX_REG_DMAPADR1); + writel(0, devpriv->plx9080_iobase + PLX_REG_DMALADR1); writel(descriptor_bits, - devpriv->plx9080_iobase + PLX_DMA1_DESCRIPTOR_REG); + devpriv->plx9080_iobase + PLX_REG_DMADPR1); } else { - writel(0, - devpriv->plx9080_iobase + PLX_DMA0_TRANSFER_SIZE_REG); - writel(0, devpriv->plx9080_iobase + PLX_DMA0_PCI_ADDRESS_REG); - writel(0, - devpriv->plx9080_iobase + PLX_DMA0_LOCAL_ADDRESS_REG); + writel(0, devpriv->plx9080_iobase + PLX_REG_DMASIZ0); + writel(0, devpriv->plx9080_iobase + PLX_REG_DMAPADR0); + writel(0, devpriv->plx9080_iobase + PLX_REG_DMALADR0); writel(descriptor_bits, - devpriv->plx9080_iobase + PLX_DMA0_DESCRIPTOR_REG); + devpriv->plx9080_iobase + PLX_REG_DMADPR0); } } @@ -2803,12 +2793,7 @@ static void drain_dma_buffers(struct comedi_device *dev, unsigned int channel) int num_samples = 0; void __iomem *pci_addr_reg; - if (channel) - pci_addr_reg = - devpriv->plx9080_iobase + PLX_DMA1_PCI_ADDRESS_REG; - else - pci_addr_reg = - devpriv->plx9080_iobase + PLX_DMA0_PCI_ADDRESS_REG; + pci_addr_reg = devpriv->plx9080_iobase + PLX_REG_DMAPADR(channel); /* loop until we have read all the full buffers */ for (j = 0, next_transfer_addr = readl(pci_addr_reg); @@ -2850,10 +2835,10 @@ static void handle_ai_interrupt(struct comedi_device *dev, } /* spin lock makes sure no one else changes plx dma control reg */ spin_lock_irqsave(&dev->spinlock, flags); - dma1_status = readb(devpriv->plx9080_iobase + PLX_DMA1_CS_REG); + dma1_status = readb(devpriv->plx9080_iobase + PLX_REG_DMACSR1); if (plx_status & ICS_DMA1_A) { /* dma chan 1 interrupt */ writeb((dma1_status & PLX_DMA_EN_BIT) | PLX_CLEAR_DMA_INTR_BIT, - devpriv->plx9080_iobase + PLX_DMA1_CS_REG); + devpriv->plx9080_iobase + PLX_REG_DMACSR1); if (dma1_status & PLX_DMA_EN_BIT) drain_dma_buffers(dev, 1); @@ -2902,12 +2887,12 @@ static int last_ao_dma_load_completed(struct comedi_device *dev) unsigned short dma_status; buffer_index = prev_ao_dma_index(dev); - dma_status = readb(devpriv->plx9080_iobase + PLX_DMA0_CS_REG); + dma_status = readb(devpriv->plx9080_iobase + PLX_REG_DMACSR0); if ((dma_status & PLX_DMA_DONE_BIT) == 0) return 0; transfer_address = - readl(devpriv->plx9080_iobase + PLX_DMA0_PCI_ADDRESS_REG); + readl(devpriv->plx9080_iobase + PLX_REG_DMAPADR0); if (transfer_address != devpriv->ao_buffer_bus_addr[buffer_index]) return 0; @@ -2931,8 +2916,7 @@ static void restart_ao_dma(struct comedi_device *dev) struct pcidas64_private *devpriv = dev->private; unsigned int dma_desc_bits; - dma_desc_bits = - readl(devpriv->plx9080_iobase + PLX_DMA0_DESCRIPTOR_REG); + dma_desc_bits = readl(devpriv->plx9080_iobase + PLX_REG_DMADPR0); dma_desc_bits &= ~PLX_END_OF_CHAIN_BIT; load_first_dma_descriptor(dev, 0, dma_desc_bits); @@ -2994,8 +2978,7 @@ static void load_ao_dma(struct comedi_device *dev, const struct comedi_cmd *cmd) struct pcidas64_private *devpriv = dev->private; unsigned int num_bytes; unsigned int next_transfer_addr; - void __iomem *pci_addr_reg = - devpriv->plx9080_iobase + PLX_DMA0_PCI_ADDRESS_REG; + void __iomem *pci_addr_reg = devpriv->plx9080_iobase + PLX_REG_DMAPADR0; unsigned int buffer_index; do { @@ -3030,15 +3013,16 @@ static void handle_ao_interrupt(struct comedi_device *dev, /* spin lock makes sure no one else changes plx dma control reg */ spin_lock_irqsave(&dev->spinlock, flags); - dma0_status = readb(devpriv->plx9080_iobase + PLX_DMA0_CS_REG); + dma0_status = readb(devpriv->plx9080_iobase + PLX_REG_DMACSR0); if (plx_status & ICS_DMA0_A) { /* dma chan 0 interrupt */ if ((dma0_status & PLX_DMA_EN_BIT) && - !(dma0_status & PLX_DMA_DONE_BIT)) + !(dma0_status & PLX_DMA_DONE_BIT)) { writeb(PLX_DMA_EN_BIT | PLX_CLEAR_DMA_INTR_BIT, - devpriv->plx9080_iobase + PLX_DMA0_CS_REG); - else + devpriv->plx9080_iobase + PLX_REG_DMACSR0); + } else { writeb(PLX_CLEAR_DMA_INTR_BIT, - devpriv->plx9080_iobase + PLX_DMA0_CS_REG); + devpriv->plx9080_iobase + PLX_REG_DMACSR0); + } spin_unlock_irqrestore(&dev->spinlock, flags); if (dma0_status & PLX_DMA_EN_BIT) { load_ao_dma(dev, cmd); @@ -3069,7 +3053,7 @@ static irqreturn_t handle_interrupt(int irq, void *d) uint32_t plx_status; uint32_t plx_bits; - plx_status = readl(devpriv->plx9080_iobase + PLX_INTRCS_REG); + plx_status = readl(devpriv->plx9080_iobase + PLX_REG_INTCSR); status = readw(devpriv->main_iobase + HW_STATUS_REG); /* @@ -3085,8 +3069,8 @@ static irqreturn_t handle_interrupt(int irq, void *d) /* clear possible plx9080 interrupt sources */ if (plx_status & ICS_LDIA) { /* clear local doorbell interrupt */ - plx_bits = readl(devpriv->plx9080_iobase + PLX_DBR_OUT_REG); - writel(plx_bits, devpriv->plx9080_iobase + PLX_DBR_OUT_REG); + plx_bits = readl(devpriv->plx9080_iobase + PLX_REG_L2PDBELL); + writel(plx_bits, devpriv->plx9080_iobase + PLX_REG_L2PDBELL); } return IRQ_HANDLED; @@ -3725,7 +3709,7 @@ static uint16_t read_eeprom(struct comedi_device *dev, uint8_t address) unsigned int bitstream = (read_command << 8) | address; unsigned int bit; void __iomem * const plx_control_addr = - devpriv->plx9080_iobase + PLX_CONTROL_REG; + devpriv->plx9080_iobase + PLX_REG_CNTRL; uint16_t value; static const int value_length = 16; static const int eeprom_udelay = 1; @@ -3962,7 +3946,7 @@ static int setup_subdevices(struct comedi_device *dev) /* serial EEPROM, if present */ s = &dev->subdevices[8]; - if (readl(devpriv->plx9080_iobase + PLX_CONTROL_REG) & CTL_EECHK) { + if (readl(devpriv->plx9080_iobase + PLX_REG_CNTRL) & CTL_EECHK) { s->type = COMEDI_SUBD_MEMORY; s->subdev_flags = SDF_READABLE | SDF_INTERNAL; s->n_chan = 128; @@ -4019,15 +4003,15 @@ static int auto_attach(struct comedi_device *dev, } /* figure out what local addresses are */ - local_range = readl(devpriv->plx9080_iobase + PLX_LAS0RNG_REG) & + local_range = readl(devpriv->plx9080_iobase + PLX_REG_LAS0RR) & LRNG_MEM_MASK; - local_decode = readl(devpriv->plx9080_iobase + PLX_LAS0MAP_REG) & + local_decode = readl(devpriv->plx9080_iobase + PLX_REG_LAS0BA) & local_range & LMAP_MEM_MASK; devpriv->local0_iobase = ((uint32_t)devpriv->main_phys_iobase & ~local_range) | local_decode; - local_range = readl(devpriv->plx9080_iobase + PLX_LAS1RNG_REG) & + local_range = readl(devpriv->plx9080_iobase + PLX_REG_LAS1RR) & LRNG_MEM_MASK; - local_decode = readl(devpriv->plx9080_iobase + PLX_LAS1MAP_REG) & + local_decode = readl(devpriv->plx9080_iobase + PLX_REG_LAS1BA) & local_range & LMAP_MEM_MASK; devpriv->local1_iobase = ((uint32_t)devpriv->dio_counter_phys_iobase & ~local_range) | local_decode; diff --git a/drivers/staging/comedi/drivers/gsc_hpdi.c b/drivers/staging/comedi/drivers/gsc_hpdi.c index 63b5cbc..e2831e1 100644 --- a/drivers/staging/comedi/drivers/gsc_hpdi.c +++ b/drivers/staging/comedi/drivers/gsc_hpdi.c @@ -158,10 +158,7 @@ static void gsc_hpdi_drain_dma(struct comedi_device *dev, unsigned int channel) unsigned int size; unsigned int next; - if (channel) - next = readl(devpriv->plx9080_mmio + PLX_DMA1_PCI_ADDRESS_REG); - else - next = readl(devpriv->plx9080_mmio + PLX_DMA0_PCI_ADDRESS_REG); + next = readl(devpriv->plx9080_mmio + PLX_REG_DMAPADR(channel)); idx = devpriv->dma_desc_index; start = le32_to_cpu(devpriv->dma_desc[idx].pci_start_addr); @@ -201,7 +198,7 @@ static irqreturn_t gsc_hpdi_interrupt(int irq, void *d) if (!dev->attached) return IRQ_NONE; - plx_status = readl(devpriv->plx9080_mmio + PLX_INTRCS_REG); + plx_status = readl(devpriv->plx9080_mmio + PLX_REG_INTCSR); if ((plx_status & (ICS_DMA0_A | ICS_DMA1_A | ICS_LIA)) == 0) return IRQ_NONE; @@ -213,11 +210,11 @@ static irqreturn_t gsc_hpdi_interrupt(int irq, void *d) /* spin lock makes sure no one else changes plx dma control reg */ spin_lock_irqsave(&dev->spinlock, flags); - dma0_status = readb(devpriv->plx9080_mmio + PLX_DMA0_CS_REG); + dma0_status = readb(devpriv->plx9080_mmio + PLX_REG_DMACSR0); if (plx_status & ICS_DMA0_A) { /* dma chan 0 interrupt */ writeb((dma0_status & PLX_DMA_EN_BIT) | PLX_CLEAR_DMA_INTR_BIT, - devpriv->plx9080_mmio + PLX_DMA0_CS_REG); + devpriv->plx9080_mmio + PLX_REG_DMACSR0); if (dma0_status & PLX_DMA_EN_BIT) gsc_hpdi_drain_dma(dev, 0); @@ -226,19 +223,19 @@ static irqreturn_t gsc_hpdi_interrupt(int irq, void *d) /* spin lock makes sure no one else changes plx dma control reg */ spin_lock_irqsave(&dev->spinlock, flags); - dma1_status = readb(devpriv->plx9080_mmio + PLX_DMA1_CS_REG); + dma1_status = readb(devpriv->plx9080_mmio + PLX_REG_DMACSR1); if (plx_status & ICS_DMA1_A) { /* XXX */ /* dma chan 1 interrupt */ writeb((dma1_status & PLX_DMA_EN_BIT) | PLX_CLEAR_DMA_INTR_BIT, - devpriv->plx9080_mmio + PLX_DMA1_CS_REG); + devpriv->plx9080_mmio + PLX_REG_DMACSR1); } spin_unlock_irqrestore(&dev->spinlock, flags); /* clear possible plx9080 interrupt sources */ if (plx_status & ICS_LDIA) { /* clear local doorbell interrupt */ - plx_bits = readl(devpriv->plx9080_mmio + PLX_DBR_OUT_REG); - writel(plx_bits, devpriv->plx9080_mmio + PLX_DBR_OUT_REG); + plx_bits = readl(devpriv->plx9080_mmio + PLX_REG_L2PDBELL); + writel(plx_bits, devpriv->plx9080_mmio + PLX_REG_L2PDBELL); } if (hpdi_board_status & RX_OVERRUN_BIT) { @@ -307,19 +304,19 @@ static int gsc_hpdi_cmd(struct comedi_device *dev, * occasionally cause problems with transfer of first dma * block. Initializing them to zero seems to fix the problem. */ - writel(0, devpriv->plx9080_mmio + PLX_DMA0_TRANSFER_SIZE_REG); - writel(0, devpriv->plx9080_mmio + PLX_DMA0_PCI_ADDRESS_REG); - writel(0, devpriv->plx9080_mmio + PLX_DMA0_LOCAL_ADDRESS_REG); + writel(0, devpriv->plx9080_mmio + PLX_REG_DMASIZ0); + writel(0, devpriv->plx9080_mmio + PLX_REG_DMAPADR0); + writel(0, devpriv->plx9080_mmio + PLX_REG_DMALADR0); /* give location of first dma descriptor */ bits = devpriv->dma_desc_phys_addr | PLX_DESC_IN_PCI_BIT | PLX_INTR_TERM_COUNT | PLX_XFER_LOCAL_TO_PCI; - writel(bits, devpriv->plx9080_mmio + PLX_DMA0_DESCRIPTOR_REG); + writel(bits, devpriv->plx9080_mmio + PLX_REG_DMADPR0); /* enable dma transfer */ spin_lock_irqsave(&dev->spinlock, flags); writeb(PLX_DMA_EN_BIT | PLX_DMA_START_BIT | PLX_CLEAR_DMA_INTR_BIT, - devpriv->plx9080_mmio + PLX_DMA0_CS_REG); + devpriv->plx9080_mmio + PLX_REG_DMACSR0); spin_unlock_irqrestore(&dev->spinlock, flags); if (cmd->stop_src == TRIG_COUNT) @@ -538,7 +535,7 @@ static int gsc_hpdi_init(struct comedi_device *dev) plx_intcsr_bits = ICS_AERR | ICS_PERR | ICS_PIE | ICS_PLIE | ICS_PAIE | ICS_LIE | ICS_DMA0_E; - writel(plx_intcsr_bits, devpriv->plx9080_mmio + PLX_INTRCS_REG); + writel(plx_intcsr_bits, devpriv->plx9080_mmio + PLX_REG_INTCSR); return 0; } @@ -554,9 +551,9 @@ static void gsc_hpdi_init_plx9080(struct comedi_device *dev) #else bits = 0; #endif - writel(bits, devpriv->plx9080_mmio + PLX_BIGEND_REG); + writel(bits, devpriv->plx9080_mmio + PLX_REG_BIGEND); - writel(0, devpriv->plx9080_mmio + PLX_INTRCS_REG); + writel(0, devpriv->plx9080_mmio + PLX_REG_INTCSR); gsc_hpdi_abort_dma(dev, 0); gsc_hpdi_abort_dma(dev, 1); @@ -584,7 +581,7 @@ static void gsc_hpdi_init_plx9080(struct comedi_device *dev) /* enable local burst mode */ bits |= PLX_DMA_LOCAL_BURST_EN_BIT; bits |= PLX_LOCAL_BUS_32_WIDE_BITS; - writel(bits, plx_iobase + PLX_DMA0_MODE_REG); + writel(bits, plx_iobase + PLX_REG_DMAMODE0); } static int gsc_hpdi_auto_attach(struct comedi_device *dev, @@ -680,7 +677,7 @@ static void gsc_hpdi_detach(struct comedi_device *dev) free_irq(dev->irq, dev); if (devpriv) { if (devpriv->plx9080_mmio) { - writel(0, devpriv->plx9080_mmio + PLX_INTRCS_REG); + writel(0, devpriv->plx9080_mmio + PLX_REG_INTCSR); iounmap(devpriv->plx9080_mmio); } if (dev->mmio) diff --git a/drivers/staging/comedi/drivers/plx9080.h b/drivers/staging/comedi/drivers/plx9080.h index 3759a19..92d2480 100644 --- a/drivers/staging/comedi/drivers/plx9080.h +++ b/drivers/staging/comedi/drivers/plx9080.h @@ -36,7 +36,7 @@ struct plx_dma_desc { __le32 transfer_size; /* * address of next descriptor (quad word aligned), plus some - * additional bits (see PLX_DMA0_DESCRIPTOR_REG) + * additional bits (see PLX_REG_DMADPR) */ __le32 next; }; @@ -49,10 +49,11 @@ struct plx_dma_desc { ** **********************************************************************/ -/* L, Local Addr Space 0 Range Register */ -#define PLX_LAS0RNG_REG 0x0000 -/* L, Local Addr Space 1 Range Register */ -#define PLX_LAS1RNG_REG 0x00f0 +/* Local Address Space 0 Range Register */ +#define PLX_REG_LAS0RR 0x0000 +/* Local Address Space 1 Range Register */ +#define PLX_REG_LAS1RR 0x00f0 + #define LRNG_IO 0x00000001 /* Map to: 1=I/O, 0=Mem */ #define LRNG_ANY32 0x00000000 /* Locate anywhere in 32 bit */ #define LRNG_LT1MB 0x00000002 /* Locate in 1st meg */ @@ -61,21 +62,23 @@ struct plx_dma_desc { #define LRNG_MEM_MASK 0xfffffff0 /* bits that specify range for normal io */ #define LRNG_IO_MASK 0xfffffffc -/* L, Local Addr Space 0 Remap Register */ -#define PLX_LAS0MAP_REG 0x0004 -/* L, Local Addr Space 1 Remap Register */ -#define PLX_LAS1MAP_REG 0x00f4 + +/* Local Address Space 0 Local Base Address (Remap) Register */ +#define PLX_REG_LAS0BA 0x0004 +/* Local Address Space 1 Local Base Address (Remap) Register */ +#define PLX_REG_LAS1BA 0x00f4 + #define LMAP_EN 0x00000001 /* Enable slave decode */ /* bits that specify decode for memory io */ #define LMAP_MEM_MASK 0xfffffff0 /* bits that specify decode bits for normal io */ #define LMAP_IO_MASK 0xfffffffc -/* - * Mode/Arbitration Register. - */ -#define PLX_MARB_REG 0x8 /* L, Local Arbitration Register */ -#define PLX_DMAARB_REG 0xac +/* Mode/Arbitration Register */ +#define PLX_REG_MARBR 0x0008 +/* DMA Arbitration Register (alias of MARBR). */ +#define PLX_REG_DMAARB 0x00ac + enum marb_bits { MARB_LLT_MASK = 0x000000ff, /* Local Bus Latency Timer */ MARB_LPT_MASK = 0x0000ff00, /* Local Bus Pause Timer */ @@ -97,7 +100,9 @@ enum marb_bits { MARB_USE_SUBSYSTEM_IDS = 0x20000000, }; -#define PLX_BIGEND_REG 0xc +/* Big/Little Endian Descriptor Register */ +#define PLX_REG_BIGEND 0x000c + enum bigend_bits { /* use big endian ordering for configuration register accesses */ BIGEND_CONFIG = 0x1, @@ -119,11 +124,16 @@ enum bigend_bits { ** This expansion ROM code is executed by the host CPU at boot time. ** For this reason no bit definitions are provided here. */ -#define PLX_ROMRNG_REG 0x0010 /* L, Expn ROM Space Range Register */ -/* L, Local Addr Space Range Register */ -#define PLX_ROMMAP_REG 0x0014 +/* Expansion ROM Range Register */ +#define PLX_REG_EROMRR 0x0010 +/* Expansion ROM Local Base Address (Remap) Register */ +#define PLX_REG_EROMBA 0x0014 + +/* Local Address Space 0/Expansion ROM Bus Region Descriptor Register */ +#define PLX_REG_LBRD0 0x0018 +/* Local Address Space 1 Bus Region Descriptor Register */ +#define PLX_REG_LBRD1 0x00f8 -#define PLX_REGION0_REG 0x0018 /* L, Local Bus Region 0 Descriptor */ #define RGN_WIDTH 0x00000002 /* Local bus width bits */ #define RGN_8BITS 0x00000000 /* 08 bit Local Bus */ #define RGN_16BITS 0x00000001 /* 16 bit Local Bus */ @@ -149,15 +159,18 @@ enum bigend_bits { #define RGN_THROT 0x08000000 /* De-assert TRDY when FIFO full */ #define RGN_TRD 0xF0000000 /* Target Ready Delay /8 */ -#define PLX_REGION1_REG 0x00f8 /* L, Local Bus Region 1 Descriptor */ +/* Local Range Register for Direct Master to PCI */ +#define PLX_REG_DMRR 0x001c -#define PLX_DMRNG_REG 0x001C /* L, Direct Master Range Register */ +/* Local Bus Base Address Register for Direct Master to PCI Memory */ +#define PLX_REG_DMLBAM 0x0020 -#define PLX_LBAPMEM_REG 0x0020 /* L, Lcl Base Addr for PCI mem space */ +/* Local Base Address Register for Direct Master to PCI IO/CFG */ +#define PLX_REG_DMLBAI 0x0024 -#define PLX_LBAPIO_REG 0x0024 /* L, Lcl Base Addr for PCI I/O space */ +/* PCI Base Address (Remap) Register for Direct Master to PCI Memory */ +#define PLX_REG_DMPBAM 0x0028 -#define PLX_DMMAP_REG 0x0028 /* L, Direct Master Remap Register */ #define DMM_MAE 0x00000001 /* Direct Mstr Memory Acc Enable */ #define DMM_IAE 0x00000002 /* Direct Mstr I/O Acc Enable */ #define DMM_LCK 0x00000004 /* LOCK Input Enable */ @@ -173,7 +186,9 @@ enum bigend_bits { #define DMM_PAF7 0x000000D0 /* Programmable Almost fill level */ #define DMM_MAP 0xFFFF0000 /* Remap Address Bits */ -#define PLX_CAR_REG 0x002C /* L, Configuration Address Register */ +/* PCI Configuration Address Register for Direct Master to PCI IO/CFG */ +#define PLX_REG_DMCFGA 0x002c + #define CAR_CT0 0x00000000 /* Config Type 0 */ #define CAR_CT1 0x00000001 /* Config Type 1 */ #define CAR_REG 0x000000FC /* Register Number Bits */ @@ -182,11 +197,38 @@ enum bigend_bits { #define CAR_BUS 0x00FF0000 /* Bus Number Bits */ #define CAR_CFG 0x80000000 /* Config Spc Access Enable */ -#define PLX_DBR_IN_REG 0x0060 /* L, PCI to Local Doorbell Register */ - -#define PLX_DBR_OUT_REG 0x0064 /* L, Local to PCI Doorbell Register */ +/* + * Mailbox Register N (N <= 7) + * + * Note that if the I2O feature is enabled (QSR[0] is set), Mailbox Register 0 + * is replaced by the Inbound Queue Port, and Mailbox Register 1 is replaced + * by the Outbound Queue Port. However, Mailbox Register 0 and 1 are always + * accessible at alternative offsets if the I2O feature is enabled. + */ +#define PLX_REG_MBOX(n) (0x0040 + (n) * 4) +#define PLX_REG_MBOX0 PLX_REG_MBOX(0) +#define PLX_REG_MBOX1 PLX_REG_MBOX(1) +#define PLX_REG_MBOX2 PLX_REG_MBOX(2) +#define PLX_REG_MBOX3 PLX_REG_MBOX(3) +#define PLX_REG_MBOX4 PLX_REG_MBOX(4) +#define PLX_REG_MBOX5 PLX_REG_MBOX(5) +#define PLX_REG_MBOX6 PLX_REG_MBOX(6) +#define PLX_REG_MBOX7 PLX_REG_MBOX(7) + +/* Alternative offsets for Mailbox Registers 0 and 1 (in case I2O is enabled) */ +#define PLX_REG_ALT_MBOX(n) ((n) < 2 ? 0x0078 + (n) * 4 : PLX_REG_MBOX(n)) +#define PLX_REG_ALT_MBOX0 PLX_REG_ALT_MBOX(0) +#define PLX_REG_ALT_MBOX1 PLX_REG_ALT_MBOX(1) + +/* PCI-to-Local Doorbell Register */ +#define PLX_REG_P2LDBELL 0x0060 + +/* Local-to-PCI Doorbell Register */ +#define PLX_REG_L2PDBELL 0x0064 + +/* Interrupt Control/Status Register */ +#define PLX_REG_INTCSR 0x0068 -#define PLX_INTRCS_REG 0x0068 /* L, Interrupt Control/Status Reg */ #define ICS_AERR 0x00000001 /* Assert LSERR on ABORT */ #define ICS_PERR 0x00000002 /* Assert LSERR on Parity Error */ #define ICS_SERR 0x00000004 /* Generate PCI SERR# */ @@ -214,7 +256,12 @@ enum bigend_bits { /* mailbox x is active */ #define ICS_MBIA(x) (0x10000000 << ((x) & 0x3)) -#define PLX_CONTROL_REG 0x006C /* L, EEPROM Cntl & PCI Cmd Codes */ +/* + * Serial EEPROM Control, PCI Command Codes, User I/O Control, + * Init Control Register + */ +#define PLX_REG_CNTRL 0x006c + #define CTL_RDMA 0x0000000E /* DMA Read Command */ #define CTL_WDMA 0x00000070 /* DMA Write Command */ #define CTL_RMEM 0x00000600 /* Memory Read Command */ @@ -230,12 +277,17 @@ enum bigend_bits { #define CTL_RESET 0x40000000 /* !! Adapter Reset !! */ #define CTL_READY 0x80000000 /* Local Init Done */ -#define PLX_ID_REG 0x70 /* hard-coded plx vendor and device ids */ +/* PCI Permanent Configuration ID Register (hard-coded PLX vendor and device) */ +#define PLX_REG_PCIHIDR 0x0070 + +/* PCI Permanent Revision ID Register (hard-coded silicon revision) (8-bit). */ +#define PLX_REG_PCIHREV 0x0074 -#define PLX_REVISION_REG 0x74 /* silicon revision */ +/* DMA Channel N Mode Register (N <= 1) */ +#define PLX_REG_DMAMODE(n) ((n) ? PLX_REG_DMAMODE1 : PLX_REG_DMAMODE0) +#define PLX_REG_DMAMODE0 0x0080 +#define PLX_REG_DMAMODE1 0x0094 -#define PLX_DMA0_MODE_REG 0x80 /* dma channel 0 mode register */ -#define PLX_DMA1_MODE_REG 0x94 /* dma channel 0 mode register */ #define PLX_LOCAL_BUS_16_WIDE_BITS 0x1 #define PLX_LOCAL_BUS_32_WIDE_BITS 0x3 #define PLX_LOCAL_BUS_WIDTH_MASK 0x3 @@ -254,20 +306,26 @@ enum bigend_bits { /* routes dma interrupt to pci bus (instead of local bus) */ #define PLX_DMA_INTR_PCI_BIT 0x20000 -/* pci address that dma transfers start at */ -#define PLX_DMA0_PCI_ADDRESS_REG 0x84 -#define PLX_DMA1_PCI_ADDRESS_REG 0x98 +/* DMA Channel N PCI Address Register (N <= 1) */ +#define PLX_REG_DMAPADR(n) ((n) ? PLX_REG_DMAPADR1 : PLX_REG_DMAPADR0) +#define PLX_REG_DMAPADR0 0x0084 +#define PLX_REG_DMAPADR1 0x0098 + +/* DMA Channel N Local Address Register (N <= 1) */ +#define PLX_REG_DMALADR(n) ((n) ? PLX_REG_DMALADR1 : PLX_REG_DMALADR0) +#define PLX_REG_DMALADR0 0x0088 +#define PLX_REG_DMALADR1 0x009c -/* local address that dma transfers start at */ -#define PLX_DMA0_LOCAL_ADDRESS_REG 0x88 -#define PLX_DMA1_LOCAL_ADDRESS_REG 0x9c +/* DMA Channel N Transfer Size (Bytes) Register (N <= 1) (first 23 bits) */ +#define PLX_REG_DMASIZ(n) ((n) ? PLX_REG_DMASIZ1 : PLX_REG_DMASIZ0) +#define PLX_REG_DMASIZ0 0x008c +#define PLX_REG_DMASIZ1 0x00a0 -/* number of bytes to transfer (first 23 bits) */ -#define PLX_DMA0_TRANSFER_SIZE_REG 0x8c -#define PLX_DMA1_TRANSFER_SIZE_REG 0xa0 +/* DMA Channel N Descriptor Pointer Register (N <= 1) */ +#define PLX_REG_DMADPR(n) ((n) ? PLX_REG_DMADPR1 : PLX_REG_DMADPR0) +#define PLX_REG_DMADPR0 0x0090 +#define PLX_REG_DMADPR1 0x00a4 -#define PLX_DMA0_DESCRIPTOR_REG 0x90 /* descriptor pointer register */ -#define PLX_DMA1_DESCRIPTOR_REG 0xa4 /* descriptor is located in pci space (not local space) */ #define PLX_DESC_IN_PCI_BIT 0x1 #define PLX_END_OF_CHAIN_BIT 0x2 /* end of chain bit */ @@ -276,15 +334,33 @@ enum bigend_bits { /* transfer from local to pci bus (not pci to local) */ #define PLX_XFER_LOCAL_TO_PCI 0x8 -#define PLX_DMA0_CS_REG 0xa8 /* command status register */ -#define PLX_DMA1_CS_REG 0xa9 +/* DMA Channel N Command/Status Register (N <= 1) (8-bit) */ +#define PLX_REG_DMACSR(n) ((n) ? PLX_REG_DMACSR1 : PLX_REG_DMACSR0) +#define PLX_REG_DMACSR0 0x00a8 +#define PLX_REG_DMACSR1 0x00a9 + #define PLX_DMA_EN_BIT 0x1 /* enable dma channel */ #define PLX_DMA_START_BIT 0x2 /* start dma transfer */ #define PLX_DMA_ABORT_BIT 0x4 /* abort dma transfer */ #define PLX_CLEAR_DMA_INTR_BIT 0x8 /* clear dma interrupt */ #define PLX_DMA_DONE_BIT 0x10 /* transfer done status bit */ -#define PLX_DMA0_THRESHOLD_REG 0xb0 /* command status register */ +/* DMA Threshold Register */ +#define PLX_REG_DMATHR 0x00b0 + +/* + * Messaging Queue Registers OPLFIS, OPLFIM, IQP, OQP, MQCR, QBAR, IFHPR, + * IFTPR, IPHPR, IPTPR, OFHPR, OFTPR, OPHPR, OPTPR, and QSR have been omitted. + * They are used by the I2O feature. (IQP and OQP occupy the usual offsets of + * the MBOX0 and MBOX1 registers if the I2O feature is enabled, but MBOX0 and + * MBOX1 are accessible via alternative offsets. + */ + +/* Queue Status/Control Register */ +#define PLX_REG_QSR 0x00e8 + +/* Value of QSR after reset - disables I2O feature completely. */ +#define PLX_QSR_VALUE_AFTER_RESET 0x00000050 /* * Accesses near the end of memory can cause the PLX chip @@ -301,10 +377,7 @@ static inline int plx9080_abort_dma(void __iomem *iobase, unsigned int channel) const int timeout = 10000; unsigned int i; - if (channel) - dma_cs_addr = iobase + PLX_DMA1_CS_REG; - else - dma_cs_addr = iobase + PLX_DMA0_CS_REG; + dma_cs_addr = iobase + PLX_REG_DMACSR(channel); /* abort dma transfer if necessary */ dma_status = readb(dma_cs_addr); diff --git a/drivers/staging/comedi/drivers/rtd520.c b/drivers/staging/comedi/drivers/rtd520.c index 0990f62..236f6ad 100644 --- a/drivers/staging/comedi/drivers/rtd520.c +++ b/drivers/staging/comedi/drivers/rtd520.c @@ -1175,7 +1175,7 @@ static void rtd_reset(struct comedi_device *dev) writel(0, dev->mmio + LAS0_BOARD_RESET); usleep_range(100, 1000); /* needed? */ - writel(0, devpriv->lcfg + PLX_INTRCS_REG); + writel(0, devpriv->lcfg + PLX_REG_INTCSR); writew(0, dev->mmio + LAS0_IT); writew(~0, dev->mmio + LAS0_CLEAR); readw(dev->mmio + LAS0_CLEAR); @@ -1316,7 +1316,7 @@ static int rtd_auto_attach(struct comedi_device *dev, devpriv->fifosz = ret; if (dev->irq) - writel(ICS_PIE | ICS_PLIE, devpriv->lcfg + PLX_INTRCS_REG); + writel(ICS_PIE | ICS_PLIE, devpriv->lcfg + PLX_REG_INTCSR); return 0; } -- cgit v0.10.2 From be13e14e31c6ce247fa4d6635f53d9755a545d4b Mon Sep 17 00:00:00 2001 From: Ian Abbott Date: Fri, 20 May 2016 14:49:06 +0100 Subject: staging: comedi: drivers: re-do macros for PLX PCI 9080 LASxRR values Rename the macros for the PLX PCI 9080 LAS0RR and LAS1RR registers in "plx9080.h", using the prefix `PLX_LASRR_`. Make use of the `BIT(x)` and `GENMASK(h,l)` macros to define the values. Define a macro `PLX_LASRR_PREFETCH` for the "prefetchable memory" bit in this register, and define a macro `PLX_LASRR_MLOC_MASK` to mask the PCI memory location control bits. Signed-off-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/comedi/drivers/cb_pcidas64.c b/drivers/staging/comedi/drivers/cb_pcidas64.c index d9468db..59d81e8 100644 --- a/drivers/staging/comedi/drivers/cb_pcidas64.c +++ b/drivers/staging/comedi/drivers/cb_pcidas64.c @@ -4004,13 +4004,13 @@ static int auto_attach(struct comedi_device *dev, /* figure out what local addresses are */ local_range = readl(devpriv->plx9080_iobase + PLX_REG_LAS0RR) & - LRNG_MEM_MASK; + PLX_LASRR_MEM_MASK; local_decode = readl(devpriv->plx9080_iobase + PLX_REG_LAS0BA) & local_range & LMAP_MEM_MASK; devpriv->local0_iobase = ((uint32_t)devpriv->main_phys_iobase & ~local_range) | local_decode; local_range = readl(devpriv->plx9080_iobase + PLX_REG_LAS1RR) & - LRNG_MEM_MASK; + PLX_LASRR_MEM_MASK; local_decode = readl(devpriv->plx9080_iobase + PLX_REG_LAS1BA) & local_range & LMAP_MEM_MASK; devpriv->local1_iobase = ((uint32_t)devpriv->dio_counter_phys_iobase & diff --git a/drivers/staging/comedi/drivers/plx9080.h b/drivers/staging/comedi/drivers/plx9080.h index 92d2480..8788117 100644 --- a/drivers/staging/comedi/drivers/plx9080.h +++ b/drivers/staging/comedi/drivers/plx9080.h @@ -54,14 +54,16 @@ struct plx_dma_desc { /* Local Address Space 1 Range Register */ #define PLX_REG_LAS1RR 0x00f0 -#define LRNG_IO 0x00000001 /* Map to: 1=I/O, 0=Mem */ -#define LRNG_ANY32 0x00000000 /* Locate anywhere in 32 bit */ -#define LRNG_LT1MB 0x00000002 /* Locate in 1st meg */ -#define LRNG_ANY64 0x00000004 /* Locate anywhere in 64 bit */ -/* bits that specify range for memory io */ -#define LRNG_MEM_MASK 0xfffffff0 -/* bits that specify range for normal io */ -#define LRNG_IO_MASK 0xfffffffc +#define PLX_LASRR_IO BIT(0) /* Map to: 1=I/O, 0=Mem */ +#define PLX_LASRR_ANY32 (BIT(1) * 0) /* Locate anywhere in 32 bit */ +#define PLX_LASRR_LT1MB (BIT(1) * 1) /* Locate in 1st meg */ +#define PLX_LASRR_ANY64 (BIT(1) * 2) /* Locate anywhere in 64 bit */ +#define PLX_LASRR_MLOC_MASK GENMASK(2, 1) /* Memory location bits */ +#define PLX_LASRR_PREFETCH BIT(3) /* Memory is prefetchable */ +/* bits that specify range for memory space decode bits */ +#define PLX_LASRR_MEM_MASK GENMASK(31, 4) +/* bits that specify range for i/o space decode bits */ +#define PLX_LASRR_IO_MASK GENMASK(31, 2) /* Local Address Space 0 Local Base Address (Remap) Register */ #define PLX_REG_LAS0BA 0x0004 -- cgit v0.10.2 From 5eaa593dbf4830cb7e2513dbbcf5bbb274da0ccd Mon Sep 17 00:00:00 2001 From: Ian Abbott Date: Fri, 20 May 2016 14:49:07 +0100 Subject: staging: comedi: drivers: re-do macros for PLX PCI 9080 LASxBA values Replace the existing macros in "plx9080.h" that define values for the LAS0BA and LAS1BA registers. Use the prefix `PLX_LASBA_` for the macros. Make use of the `BIT(x)` and `GENMASK(h,l)` macros to define the macros. Signed-off-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/comedi/drivers/cb_pcidas64.c b/drivers/staging/comedi/drivers/cb_pcidas64.c index 59d81e8..f997c1f 100644 --- a/drivers/staging/comedi/drivers/cb_pcidas64.c +++ b/drivers/staging/comedi/drivers/cb_pcidas64.c @@ -4006,13 +4006,13 @@ static int auto_attach(struct comedi_device *dev, local_range = readl(devpriv->plx9080_iobase + PLX_REG_LAS0RR) & PLX_LASRR_MEM_MASK; local_decode = readl(devpriv->plx9080_iobase + PLX_REG_LAS0BA) & - local_range & LMAP_MEM_MASK; + local_range & PLX_LASBA_MEM_MASK; devpriv->local0_iobase = ((uint32_t)devpriv->main_phys_iobase & ~local_range) | local_decode; local_range = readl(devpriv->plx9080_iobase + PLX_REG_LAS1RR) & PLX_LASRR_MEM_MASK; local_decode = readl(devpriv->plx9080_iobase + PLX_REG_LAS1BA) & - local_range & LMAP_MEM_MASK; + local_range & PLX_LASBA_MEM_MASK; devpriv->local1_iobase = ((uint32_t)devpriv->dio_counter_phys_iobase & ~local_range) | local_decode; diff --git a/drivers/staging/comedi/drivers/plx9080.h b/drivers/staging/comedi/drivers/plx9080.h index 8788117..140135c 100644 --- a/drivers/staging/comedi/drivers/plx9080.h +++ b/drivers/staging/comedi/drivers/plx9080.h @@ -70,11 +70,11 @@ struct plx_dma_desc { /* Local Address Space 1 Local Base Address (Remap) Register */ #define PLX_REG_LAS1BA 0x00f4 -#define LMAP_EN 0x00000001 /* Enable slave decode */ -/* bits that specify decode for memory io */ -#define LMAP_MEM_MASK 0xfffffff0 -/* bits that specify decode bits for normal io */ -#define LMAP_IO_MASK 0xfffffffc +#define PLX_LASBA_EN BIT(0) /* Enable slave decode */ +/* bits that specify local base address for memory space */ +#define PLX_LASBA_MEM_MASK GENMASK(31, 4) +/* bits that specify local base address for i/o space */ +#define PLX_LASBA_IO_MASK GENMASK(31, 2) /* Mode/Arbitration Register */ #define PLX_REG_MARBR 0x0008 -- cgit v0.10.2 From b5dcdceafa750e933abdf4a7a1be097ccab8fcc7 Mon Sep 17 00:00:00 2001 From: Ian Abbott Date: Fri, 20 May 2016 14:49:08 +0100 Subject: staging: comedi: drivers: re-do PLX PCI 9080 MARBR register values Replace `enum marb_bits` in "plx9080.h" with a bunch of macros defining values for the MARBR and DMAARB registers (which are the same Mode/Arbitation register at two different offsets). Use the prefix `PLX_MARBR_` for the macros. Make use of the `BIT(x)` and `GENMASK(h,l)` macros to define the values. Signed-off-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/comedi/drivers/plx9080.h b/drivers/staging/comedi/drivers/plx9080.h index 140135c..0bcdbad 100644 --- a/drivers/staging/comedi/drivers/plx9080.h +++ b/drivers/staging/comedi/drivers/plx9080.h @@ -81,26 +81,46 @@ struct plx_dma_desc { /* DMA Arbitration Register (alias of MARBR). */ #define PLX_REG_DMAARB 0x00ac -enum marb_bits { - MARB_LLT_MASK = 0x000000ff, /* Local Bus Latency Timer */ - MARB_LPT_MASK = 0x0000ff00, /* Local Bus Pause Timer */ - MARB_LTEN = 0x00010000, /* Latency Timer Enable */ - MARB_LPEN = 0x00020000, /* Pause Timer Enable */ - MARB_BREQ = 0x00040000, /* Local Bus BREQ Enable */ - MARB_DMA_PRIORITY_MASK = 0x00180000, - /* local bus direct slave give up bus mode */ - MARB_LBDS_GIVE_UP_BUS_MODE = 0x00200000, - /* direct slave LLOCKo# enable */ - MARB_DS_LLOCK_ENABLE = 0x00400000, - MARB_PCI_REQUEST_MODE = 0x00800000, - MARB_PCIV21_MODE = 0x01000000, /* pci specification v2.1 mode */ - MARB_PCI_READ_NO_WRITE_MODE = 0x02000000, - MARB_PCI_READ_WITH_WRITE_FLUSH_MODE = 0x04000000, - /* gate local bus latency timer with BREQ */ - MARB_GATE_TIMER_WITH_BREQ = 0x08000000, - MARB_PCI_READ_NO_FLUSH_MODE = 0x10000000, - MARB_USE_SUBSYSTEM_IDS = 0x20000000, -}; +/* Local Bus Latency Timer */ +#define PLX_MARBR_LT(x) (BIT(0) * ((x) & 0xff)) +#define PLX_MARBR_LT_MASK GENMASK(7, 0) +#define PLX_MARBR_LT_SHIFT 0 +/* Local Bus Pause Timer */ +#define PLX_MARBR_PT(x) (BIT(8) * ((x) & 0xff)) +#define PLX_MARBR_PT_MASK GENMASK(15, 8) +#define PLX_MARBR_PT_SHIFT 8 +/* Local Bus Latency Timer Enable */ +#define PLX_MARBR_LTEN BIT(16) +/* Local Bus Pause Timer Enable */ +#define PLX_MARBR_PTEN BIT(17) +/* Local Bus BREQ Enable */ +#define PLX_MARBR_BREQEN BIT(18) +/* DMA Channel Priority */ +#define PLX_MARBR_PRIO_ROT (BIT(19) * 0) /* Rotational priority */ +#define PLX_MARBR_PRIO_DMA0 (BIT(19) * 1) /* DMA channel 0 has priority */ +#define PLX_MARBR_PRIO_DMA1 (BIT(19) * 2) /* DMA channel 1 has priority */ +#define PLX_MARBR_PRIO_MASK GENMASK(20, 19) +/* Local Bus Direct Slave Give Up Bus Mode */ +#define PLX_MARBR_DSGUBM BIT(21) +/* Direct Slace LLOCKo# Enable */ +#define PLX_MARBR_DSLLOCKOEN BIT(22) +/* PCI Request Mode */ +#define PLX_MARBR_PCIREQM BIT(23) +/* PCI Specification v2.1 Mode */ +#define PLX_MARBR_PCIV21M BIT(24) +/* PCI Read No Write Mode */ +#define PLX_MARBR_PCIRNWM BIT(25) +/* PCI Read with Write Flush Mode */ +#define PLX_MARBR_PCIRWFM BIT(26) +/* Gate Local Bus Latency Timer with BREQ */ +#define PLX_MARBR_GLTBREQ BIT(27) +/* PCI Read No Flush Mode */ +#define PLX_MARBR_PCIRNFM BIT(28) +/* + * Make reads from PCI Configuration register 0 return Subsystem ID and + * Subsystem Vendor ID instead of Device ID and Vendor ID + */ +#define PLX_MARBR_SUBSYSIDS BIT(29) /* Big/Little Endian Descriptor Register */ #define PLX_REG_BIGEND 0x000c -- cgit v0.10.2 From a9c254a763e4641d41c4e4b7665d979180c8af27 Mon Sep 17 00:00:00 2001 From: Ian Abbott Date: Fri, 20 May 2016 14:49:09 +0100 Subject: staging: comedi: drivers: re-do PLX PCI 9080 BIGEND register values Replace `enum bigend_bits` in "plx9080.h" with a bunch of macros defining values for the BIGEND register. Use the prefix `PLX_BIGEND_` for the macro names. Make use of the `BIT(x)` and `GENMASK(h,l)` macros to define the values. Signed-off-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/comedi/drivers/cb_pcidas64.c b/drivers/staging/comedi/drivers/cb_pcidas64.c index f997c1f..4a8e88a 100644 --- a/drivers/staging/comedi/drivers/cb_pcidas64.c +++ b/drivers/staging/comedi/drivers/cb_pcidas64.c @@ -1294,7 +1294,7 @@ static void init_plx9080(struct comedi_device *dev) readl(devpriv->plx9080_iobase + PLX_REG_CNTRL); #ifdef __BIG_ENDIAN - bits = BIGEND_DMA0 | BIGEND_DMA1; + bits = PLX_BIGEND_DMA0 | PLX_BIGEND_DMA1; #else bits = 0; #endif diff --git a/drivers/staging/comedi/drivers/gsc_hpdi.c b/drivers/staging/comedi/drivers/gsc_hpdi.c index e2831e1..536bebe 100644 --- a/drivers/staging/comedi/drivers/gsc_hpdi.c +++ b/drivers/staging/comedi/drivers/gsc_hpdi.c @@ -547,7 +547,7 @@ static void gsc_hpdi_init_plx9080(struct comedi_device *dev) void __iomem *plx_iobase = devpriv->plx9080_mmio; #ifdef __BIG_ENDIAN - bits = BIGEND_DMA0 | BIGEND_DMA1; + bits = PLX_BIGEND_DMA0 | PLX_BIGEND_DMA1; #else bits = 0; #endif diff --git a/drivers/staging/comedi/drivers/plx9080.h b/drivers/staging/comedi/drivers/plx9080.h index 0bcdbad..84dd366 100644 --- a/drivers/staging/comedi/drivers/plx9080.h +++ b/drivers/staging/comedi/drivers/plx9080.h @@ -125,21 +125,24 @@ struct plx_dma_desc { /* Big/Little Endian Descriptor Register */ #define PLX_REG_BIGEND 0x000c -enum bigend_bits { - /* use big endian ordering for configuration register accesses */ - BIGEND_CONFIG = 0x1, - BIGEND_DIRECT_MASTER = 0x2, - BIGEND_DIRECT_SLAVE_LOCAL0 = 0x4, - BIGEND_ROM = 0x8, - /* - * use byte lane consisting of most significant bits instead of - * least significant - */ - BIGEND_BYTE_LANE = 0x10, - BIGEND_DIRECT_SLAVE_LOCAL1 = 0x20, - BIGEND_DMA1 = 0x40, - BIGEND_DMA0 = 0x80, -}; +/* Configuration Register Big Endian Mode */ +#define PLX_BIGEND_CONFIG BIT(0) +/* Direct Master Big Endian Mode */ +#define PLX_BIGEND_DM BIT(1) +/* Direct Slave Address Space 0 Big Endian Mode */ +#define PLX_BIGEND_DSAS0 BIT(2) +/* Direct Slave Expansion ROM Big Endian Mode */ +#define PLX_BIGEND_EROM BIT(3) +/* Big Endian Byte Lane Mode - use most significant byte lanes */ +#define PLX_BIGEND_BEBLM BIT(4) +/* Direct Slave Address Space 1 Big Endian Mode */ +#define PLX_BIGEND_DSAS1 BIT(5) +/* DMA Channel 1 Big Endian Mode */ +#define PLX_BIGEND_DMA1 BIT(6) +/* DMA Channel 0 Big Endian Mode */ +#define PLX_BIGEND_DMA0 BIT(7) +/* DMA Channel N Big Endian Mode (N <= 1) */ +#define PLX_BIGEND_DMA(n) ((n) ? PLX_BIGEND_DMA1 : PLX_BIGEND_DMA0) /* ** Note: The Expansion ROM stuff is only relevant to the PC environment. -- cgit v0.10.2 From 1ddb95d3c4820644df28ba1e5251e87dd46e4830 Mon Sep 17 00:00:00 2001 From: Ian Abbott Date: Fri, 20 May 2016 14:49:10 +0100 Subject: staging: comedi: drivers: re-do PLX PCI 9080 LBRDx register values Replace the existing macros in "plx9080.h" that define values for the LBRD0 and LBRD1 registers. Use the prefix `PLX_LBRD_` for macros that apply to both registers, `PLX_LBRD0_` for macros that apply only to the LBRD0 register, and `PLX_LBRD1_` for macros that apply only to the LBRD1 register. Make use of the `BIT(x)` and `GENMASK(h,l)` macros to define the values. Signed-off-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/comedi/drivers/plx9080.h b/drivers/staging/comedi/drivers/plx9080.h index 84dd366..93b2e89 100644 --- a/drivers/staging/comedi/drivers/plx9080.h +++ b/drivers/staging/comedi/drivers/plx9080.h @@ -159,30 +159,62 @@ struct plx_dma_desc { /* Local Address Space 1 Bus Region Descriptor Register */ #define PLX_REG_LBRD1 0x00f8 -#define RGN_WIDTH 0x00000002 /* Local bus width bits */ -#define RGN_8BITS 0x00000000 /* 08 bit Local Bus */ -#define RGN_16BITS 0x00000001 /* 16 bit Local Bus */ -#define RGN_32BITS 0x00000002 /* 32 bit Local Bus */ -#define RGN_MWS 0x0000003C /* Memory Access Wait States */ -#define RGN_0MWS 0x00000000 -#define RGN_1MWS 0x00000004 -#define RGN_2MWS 0x00000008 -#define RGN_3MWS 0x0000000C -#define RGN_4MWS 0x00000010 -#define RGN_6MWS 0x00000018 -#define RGN_8MWS 0x00000020 -#define RGN_MRE 0x00000040 /* Memory Space Ready Input Enable */ -#define RGN_MBE 0x00000080 /* Memory Space Bterm Input Enable */ -#define RGN_READ_PREFETCH_DISABLE 0x00000100 -#define RGN_ROM_PREFETCH_DISABLE 0x00000200 -#define RGN_READ_PREFETCH_COUNT_ENABLE 0x00000400 -#define RGN_RWS 0x003C0000 /* Expn ROM Wait States */ -#define RGN_RRE 0x00400000 /* ROM Space Ready Input Enable */ -#define RGN_RBE 0x00800000 /* ROM Space Bterm Input Enable */ -#define RGN_MBEN 0x01000000 /* Memory Space Burst Enable */ -#define RGN_RBEN 0x04000000 /* ROM Space Burst Enable */ -#define RGN_THROT 0x08000000 /* De-assert TRDY when FIFO full */ -#define RGN_TRD 0xF0000000 /* Target Ready Delay /8 */ +/* Memory Space Local Bus Width */ +#define PLX_LBRD_MSWIDTH8 (BIT(0) * 0) /* 8 bits wide */ +#define PLX_LBRD_MSWIDTH16 (BIT(0) * 1) /* 16 bits wide */ +#define PLX_LBRD_MSWIDTH32 (BIT(0) * 2) /* 32 bits wide */ +#define PLX_LBRD_MSWIDTH32A (BIT(0) * 3) /* 32 bits wide */ +#define PLX_LBRD_MSWIDTH_MASK GENMASK(1, 0) +#define PLX_LBRD_MSWIDTH_SHIFT 0 +/* Memory Space Internal Wait States */ +#define PLX_LBRD_MSIWS(x) (BIT(2) * ((x) & 0xf)) +#define PLX_LBRD_MSIWS_MASK GENMASK(5, 2) +#define PLX_LBRD_MSIWS_SHIFT 2 +/* Memory Space Ready Input Enable */ +#define PLX_LBRD_MSREADYIEN BIT(6) +/* Memory Space BTERM# Input Enable */ +#define PLX_LBRD_MSBTERMIEN BIT(7) +/* Memory Space 0 Prefetch Disable (LBRD0 only) */ +#define PLX_LBRD0_MSPREDIS BIT(8) +/* Memory Space 1 Burst Enable (LBRD1 only) */ +#define PLX_LBRD1_MSBURSTEN BIT(8) +/* Expansion ROM Space Prefetch Disable (LBRD0 only) */ +#define PLX_LBRD0_EROMPREDIS BIT(9) +/* Memory Space 1 Prefetch Disable (LBRD1 only) */ +#define PLX_LBRD1_MSPREDIS BIT(9) +/* Read Prefetch Count Enable */ +#define PLX_LBRD_RPFCOUNTEN BIT(10) +/* Prefetch Counter */ +#define PLX_LBRD_PFCOUNT(x) (BIT(11) * ((x) & 0xf)) +#define PLX_LBRD_PFCOUNT_MASK GENMASK(14, 11) +#define PLX_LBRD_PFCOUNT_SHIFT 11 +/* Expansion ROM Space Local Bus Width (LBRD0 only) */ +#define PLX_LBRD0_EROMWIDTH8 (BIT(16) * 0) /* 8 bits wide */ +#define PLX_LBRD0_EROMWIDTH16 (BIT(16) * 1) /* 16 bits wide */ +#define PLX_LBRD0_EROMWIDTH32 (BIT(16) * 2) /* 32 bits wide */ +#define PLX_LBRD0_EROMWIDTH32A (BIT(16) * 3) /* 32 bits wide */ +#define PLX_LBRD0_EROMWIDTH_MASK GENMASK(17, 16) +#define PLX_LBRD0_EROMWIDTH_SHIFT 16 +/* Expansion ROM Space Internal Wait States (LBRD0 only) */ +#define PLX_LBRD0_EROMIWS(x) (BIT(18) * ((x) & 0xf)) +#define PLX_LBRD0_EROMIWS_MASK GENMASK(21, 18) +#define PLX_LBRD0_EROMIWS_SHIFT 18 +/* Expansion ROM Space Ready Input Enable (LBDR0 only) */ +#define PLX_LBRD0_EROMREADYIEN BIT(22) +/* Expansion ROM Space BTERM# Input Enable (LBRD0 only) */ +#define PLX_LBRD0_EROMBTERMIEN BIT(23) +/* Memory Space 0 Burst Enable (LBRD0 only) */ +#define PLX_LBRD0_MSBURSTEN BIT(24) +/* Extra Long Load From Serial EEPROM (LBRD0 only) */ +#define PLX_LBRD0_EELONGLOAD BIT(25) +/* Expansion ROM Space Burst Enable (LBRD0 only) */ +#define PLX_LBRD0_EROMBURSTEN BIT(26) +/* Direct Slave PCI Write Mode - assert TRDY# when FIFO full (LBRD0 only) */ +#define PLX_LBRD0_DSWMTRDY BIT(27) +/* PCI Target Retry Delay Clocks / 8 (LBRD0 only) */ +#define PLX_LBRD0_TRDELAY(x) (BIT(28) * ((x) & 0xF)) +#define PLX_LBRD0_TRDELAY_MASK GENMASK(31, 28) +#define PLX_LBRD0_TRDELAY_SHIFT 28 /* Local Range Register for Direct Master to PCI */ #define PLX_REG_DMRR 0x001c -- cgit v0.10.2 From e0045472e0d9a398d68b8570b748a49a091b12fa Mon Sep 17 00:00:00 2001 From: Ian Abbott Date: Fri, 20 May 2016 14:49:11 +0100 Subject: staging: comedi: drivers: re-do PLX PCI 9080 DMPBAM register values Replace the existing macros in "plx9080.h" that define values for the DMPBAM register. Use the prefix `PLX_DMPBAM_` for the macros. Make use of the `BIT(x)` and `GENMASK(h,l)` macros to define the values. Signed-off-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/comedi/drivers/plx9080.h b/drivers/staging/comedi/drivers/plx9080.h index 93b2e89..ab90837 100644 --- a/drivers/staging/comedi/drivers/plx9080.h +++ b/drivers/staging/comedi/drivers/plx9080.h @@ -228,20 +228,40 @@ struct plx_dma_desc { /* PCI Base Address (Remap) Register for Direct Master to PCI Memory */ #define PLX_REG_DMPBAM 0x0028 -#define DMM_MAE 0x00000001 /* Direct Mstr Memory Acc Enable */ -#define DMM_IAE 0x00000002 /* Direct Mstr I/O Acc Enable */ -#define DMM_LCK 0x00000004 /* LOCK Input Enable */ -#define DMM_PF4 0x00000008 /* Prefetch 4 Mode Enable */ -#define DMM_THROT 0x00000010 /* Assert IRDY when read FIFO full */ -#define DMM_PAF0 0x00000000 /* Programmable Almost fill level */ -#define DMM_PAF1 0x00000020 /* Programmable Almost fill level */ -#define DMM_PAF2 0x00000040 /* Programmable Almost fill level */ -#define DMM_PAF3 0x00000060 /* Programmable Almost fill level */ -#define DMM_PAF4 0x00000080 /* Programmable Almost fill level */ -#define DMM_PAF5 0x000000A0 /* Programmable Almost fill level */ -#define DMM_PAF6 0x000000C0 /* Programmable Almost fill level */ -#define DMM_PAF7 0x000000D0 /* Programmable Almost fill level */ -#define DMM_MAP 0xFFFF0000 /* Remap Address Bits */ +/* Direct Master Memory Access Enable */ +#define PLX_DMPBAM_MEMACCEN BIT(0) +/* Direct Master I/O Access Enable */ +#define PLX_DMPBAM_IOACCEN BIT(1) +/* LLOCK# Input Enable */ +#define PLX_DMPBAM_LLOCKIEN BIT(2) +/* Direct Master Read Prefetch Size Control (bits 12, 3) */ +#define PLX_DMPBAM_RPSIZECONT ((BIT(12) * 0) | (BIT(3) * 0)) +#define PLX_DMPBAM_RPSIZE4 ((BIT(12) * 0) | (BIT(3) * 1)) +#define PLX_DMPBAM_RPSIZE8 ((BIT(12) * 1) | (BIT(3) * 0)) +#define PLX_DMPBAM_RPSIZE16 ((BIT(12) * 1) | (BIT(3) * 1)) +#define PLX_DMPBAM_RPSIZE_MASK (BIT(12) | BIT(3)) +/* Direct Master PCI Read Mode - deassert IRDY when FIFO full */ +#define PLX_DMPBAM_RMIRDY BIT(4) +/* Programmable Almost Full Level (bits 10, 8:5) */ +#define PLX_DMPBAM_PAFL(x) ((BIT(10) * !!((x) & 0x10)) | \ + (BIT(5) * ((x) & 0xf))) +#define PLX_DMPBAM_TO_PAFL(v) ((((BIT(10) & (v)) >> 1) | \ + (GENMASK(8, 5) & (v))) >> 5) +#define PLX_DMPBAM_PAFL_MASK (BIT(10) | GENMASK(8, 5)) +/* Write And Invalidate Mode */ +#define PLX_DMPBAM_WIM BIT(9) +/* Direct Master Prefetch Limit */ +#define PLX_DBPBAM_PFLIMIT BIT(11) +/* I/O Remap Select */ +#define PLX_DMPBAM_IOREMAPSEL BIT(13) +/* Direct Master Write Delay */ +#define PLX_DMPBAM_WDELAYNONE (BIT(14) * 0) +#define PLX_DMPBAM_WDELAY4 (BIT(14) * 1) +#define PLX_DMPBAM_WDELAY8 (BIT(14) * 2) +#define PLX_DMPBAM_WDELAY16 (BIT(14) * 3) +#define PLX_DMPBAM_WDELAY_MASK GENMASK(15, 14) +/* Remap of Local-to-PCI Space Into PCI Address Space */ +#define PLX_DMPBAM_REMAP_MASK GENMASK(31, 16) /* PCI Configuration Address Register for Direct Master to PCI IO/CFG */ #define PLX_REG_DMCFGA 0x002c -- cgit v0.10.2 From ed5df5db92b3148a94bfa9b025a8e21c6a9518e6 Mon Sep 17 00:00:00 2001 From: Ian Abbott Date: Fri, 20 May 2016 14:49:12 +0100 Subject: staging: comedi: drivers: re-do PLX PCI 9080 DMCFGA register values Replace the existing macros in "plx9080.h" that define values for the DMCFGA register. Use the prefix `PLX_DMCFGA_` for the macros. Make use of the `BIT(x)` and `GENMASK(h,l)` macros to define the values. Signed-off-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/comedi/drivers/plx9080.h b/drivers/staging/comedi/drivers/plx9080.h index ab90837..e544327 100644 --- a/drivers/staging/comedi/drivers/plx9080.h +++ b/drivers/staging/comedi/drivers/plx9080.h @@ -266,13 +266,28 @@ struct plx_dma_desc { /* PCI Configuration Address Register for Direct Master to PCI IO/CFG */ #define PLX_REG_DMCFGA 0x002c -#define CAR_CT0 0x00000000 /* Config Type 0 */ -#define CAR_CT1 0x00000001 /* Config Type 1 */ -#define CAR_REG 0x000000FC /* Register Number Bits */ -#define CAR_FUN 0x00000700 /* Function Number Bits */ -#define CAR_DEV 0x0000F800 /* Device Number Bits */ -#define CAR_BUS 0x00FF0000 /* Bus Number Bits */ -#define CAR_CFG 0x80000000 /* Config Spc Access Enable */ +/* Congiguration Type */ +#define PLX_DMCFGA_TYPE0 (BIT(0) * 0) +#define PLX_DMCFGA_TYPE1 (BIT(0) * 1) +#define PLX_DMCFGA_TYPE_MASK GENMASK(1, 0) +/* Register Number */ +#define PLX_DMCFGA_REGNUM(x) (BIT(2) * ((x) & 0x3f)) +#define PLX_DMCFGA_REGNUM_MASK GENMASK(7, 2) +#define PLX_DMCFGA_REGNUM_SHIFT 2 +/* Function Number */ +#define PLX_DMCFGA_FUNCNUM(x) (BIT(8) * ((x) & 0x7)) +#define PLX_DMCFGA_FUNCNUM_MASK GENMASK(10, 8) +#define PLX_DMCFGA_FUNCNUM_SHIFT 8 +/* Device Number */ +#define PLX_DMCFGA_DEVNUM(x) (BIT(11) * ((x) & 0x1f)) +#define PLX_DMCFGA_DEVNUM_MASK GENMASK(15, 11) +#define PLX_DMCFGA_DEVNUM_SHIFT 11 +/* Bus Number */ +#define PLX_DMCFGA_BUSNUM(x) (BIT(16) * ((x) & 0xff)) +#define PLX_DMCFGA_BUSNUM_MASK GENMASK(23, 16) +#define PLX_DMCFGA_BUSNUM_SHIFT 16 +/* Configuration Enable */ +#define PLX_DMCFGA_CONFIGEN BIT(31) /* * Mailbox Register N (N <= 7) -- cgit v0.10.2 From 9dc53852b10888f9032baf78d672b45ab4d791fe Mon Sep 17 00:00:00 2001 From: Ian Abbott Date: Fri, 20 May 2016 14:49:13 +0100 Subject: staging: comedi: drivers: re-do PLX PCI 9080 INTCSR register values Replace the existing macros in "plx9080.h" that define values for the INTCSR register. Use the prefix `PLX_INTCSR_` for the macros. Make use of the `BIT(x)` and `GENMASK(h,l)` macros to define the values. Signed-off-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/comedi/drivers/cb_pcidas64.c b/drivers/staging/comedi/drivers/cb_pcidas64.c index 4a8e88a..6b3f4dc 100644 --- a/drivers/staging/comedi/drivers/cb_pcidas64.c +++ b/drivers/staging/comedi/drivers/cb_pcidas64.c @@ -1336,8 +1336,9 @@ static void init_plx9080(struct comedi_device *dev) /* enable interrupts on plx 9080 */ devpriv->plx_intcsr_bits |= - ICS_AERR | ICS_PERR | ICS_PIE | ICS_PLIE | ICS_PAIE | ICS_LIE | - ICS_DMA0_E | ICS_DMA1_E; + PLX_INTCSR_LSEABORTEN | PLX_INTCSR_LSEPARITYEN | PLX_INTCSR_PIEN | + PLX_INTCSR_PLIEN | PLX_INTCSR_PABORTIEN | PLX_INTCSR_LIOEN | + PLX_INTCSR_DMA0IEN | PLX_INTCSR_DMA1IEN; writel(devpriv->plx_intcsr_bits, devpriv->plx9080_iobase + PLX_REG_INTCSR); } @@ -2836,7 +2837,7 @@ static void handle_ai_interrupt(struct comedi_device *dev, /* spin lock makes sure no one else changes plx dma control reg */ spin_lock_irqsave(&dev->spinlock, flags); dma1_status = readb(devpriv->plx9080_iobase + PLX_REG_DMACSR1); - if (plx_status & ICS_DMA1_A) { /* dma chan 1 interrupt */ + if (plx_status & PLX_INTCSR_DMA1IA) { /* dma chan 1 interrupt */ writeb((dma1_status & PLX_DMA_EN_BIT) | PLX_CLEAR_DMA_INTR_BIT, devpriv->plx9080_iobase + PLX_REG_DMACSR1); @@ -3014,7 +3015,7 @@ static void handle_ao_interrupt(struct comedi_device *dev, /* spin lock makes sure no one else changes plx dma control reg */ spin_lock_irqsave(&dev->spinlock, flags); dma0_status = readb(devpriv->plx9080_iobase + PLX_REG_DMACSR0); - if (plx_status & ICS_DMA0_A) { /* dma chan 0 interrupt */ + if (plx_status & PLX_INTCSR_DMA0IA) { /* dma chan 0 interrupt */ if ((dma0_status & PLX_DMA_EN_BIT) && !(dma0_status & PLX_DMA_DONE_BIT)) { writeb(PLX_DMA_EN_BIT | PLX_CLEAR_DMA_INTR_BIT, @@ -3067,8 +3068,9 @@ static irqreturn_t handle_interrupt(int irq, void *d) handle_ai_interrupt(dev, status, plx_status); handle_ao_interrupt(dev, status, plx_status); - /* clear possible plx9080 interrupt sources */ - if (plx_status & ICS_LDIA) { /* clear local doorbell interrupt */ + /* clear possible plx9080 interrupt sources */ + if (plx_status & PLX_INTCSR_LDBIA) { + /* clear local doorbell interrupt */ plx_bits = readl(devpriv->plx9080_iobase + PLX_REG_L2PDBELL); writel(plx_bits, devpriv->plx9080_iobase + PLX_REG_L2PDBELL); } diff --git a/drivers/staging/comedi/drivers/gsc_hpdi.c b/drivers/staging/comedi/drivers/gsc_hpdi.c index 536bebe..e288798 100644 --- a/drivers/staging/comedi/drivers/gsc_hpdi.c +++ b/drivers/staging/comedi/drivers/gsc_hpdi.c @@ -199,7 +199,8 @@ static irqreturn_t gsc_hpdi_interrupt(int irq, void *d) return IRQ_NONE; plx_status = readl(devpriv->plx9080_mmio + PLX_REG_INTCSR); - if ((plx_status & (ICS_DMA0_A | ICS_DMA1_A | ICS_LIA)) == 0) + if ((plx_status & + (PLX_INTCSR_DMA0IA | PLX_INTCSR_DMA1IA | PLX_INTCSR_PLIA)) == 0) return IRQ_NONE; hpdi_intr_status = readl(dev->mmio + INTERRUPT_STATUS_REG); @@ -211,7 +212,7 @@ static irqreturn_t gsc_hpdi_interrupt(int irq, void *d) /* spin lock makes sure no one else changes plx dma control reg */ spin_lock_irqsave(&dev->spinlock, flags); dma0_status = readb(devpriv->plx9080_mmio + PLX_REG_DMACSR0); - if (plx_status & ICS_DMA0_A) { + if (plx_status & PLX_INTCSR_DMA0IA) { /* dma chan 0 interrupt */ writeb((dma0_status & PLX_DMA_EN_BIT) | PLX_CLEAR_DMA_INTR_BIT, devpriv->plx9080_mmio + PLX_REG_DMACSR0); @@ -224,7 +225,7 @@ static irqreturn_t gsc_hpdi_interrupt(int irq, void *d) /* spin lock makes sure no one else changes plx dma control reg */ spin_lock_irqsave(&dev->spinlock, flags); dma1_status = readb(devpriv->plx9080_mmio + PLX_REG_DMACSR1); - if (plx_status & ICS_DMA1_A) { + if (plx_status & PLX_INTCSR_DMA1IA) { /* XXX */ /* dma chan 1 interrupt */ writeb((dma1_status & PLX_DMA_EN_BIT) | PLX_CLEAR_DMA_INTR_BIT, devpriv->plx9080_mmio + PLX_REG_DMACSR1); @@ -232,7 +233,7 @@ static irqreturn_t gsc_hpdi_interrupt(int irq, void *d) spin_unlock_irqrestore(&dev->spinlock, flags); /* clear possible plx9080 interrupt sources */ - if (plx_status & ICS_LDIA) { + if (plx_status & PLX_INTCSR_LDBIA) { /* clear local doorbell interrupt */ plx_bits = readl(devpriv->plx9080_mmio + PLX_REG_L2PDBELL); writel(plx_bits, devpriv->plx9080_mmio + PLX_REG_L2PDBELL); @@ -533,8 +534,9 @@ static int gsc_hpdi_init(struct comedi_device *dev) /* enable interrupts */ plx_intcsr_bits = - ICS_AERR | ICS_PERR | ICS_PIE | ICS_PLIE | ICS_PAIE | ICS_LIE | - ICS_DMA0_E; + PLX_INTCSR_LSEABORTEN | PLX_INTCSR_LSEPARITYEN | PLX_INTCSR_PIEN | + PLX_INTCSR_PLIEN | PLX_INTCSR_PABORTIEN | PLX_INTCSR_LIOEN | + PLX_INTCSR_DMA0IEN; writel(plx_intcsr_bits, devpriv->plx9080_mmio + PLX_REG_INTCSR); return 0; diff --git a/drivers/staging/comedi/drivers/plx9080.h b/drivers/staging/comedi/drivers/plx9080.h index e544327..e9f1b9c 100644 --- a/drivers/staging/comedi/drivers/plx9080.h +++ b/drivers/staging/comedi/drivers/plx9080.h @@ -321,32 +321,71 @@ struct plx_dma_desc { /* Interrupt Control/Status Register */ #define PLX_REG_INTCSR 0x0068 -#define ICS_AERR 0x00000001 /* Assert LSERR on ABORT */ -#define ICS_PERR 0x00000002 /* Assert LSERR on Parity Error */ -#define ICS_SERR 0x00000004 /* Generate PCI SERR# */ -#define ICS_MBIE 0x00000008 /* mailbox interrupt enable */ -#define ICS_PIE 0x00000100 /* PCI Interrupt Enable */ -#define ICS_PDIE 0x00000200 /* PCI Doorbell Interrupt Enable */ -#define ICS_PAIE 0x00000400 /* PCI Abort Interrupt Enable */ -#define ICS_PLIE 0x00000800 /* PCI Local Int Enable */ -#define ICS_RAE 0x00001000 /* Retry Abort Enable */ -#define ICS_PDIA 0x00002000 /* PCI Doorbell Interrupt Active */ -#define ICS_PAIA 0x00004000 /* PCI Abort Interrupt Active */ -#define ICS_LIA 0x00008000 /* Local Interrupt Active */ -#define ICS_LIE 0x00010000 /* Local Interrupt Enable */ -#define ICS_LDIE 0x00020000 /* Local Doorbell Int Enable */ -#define ICS_DMA0_E 0x00040000 /* DMA #0 Interrupt Enable */ -#define ICS_DMA1_E 0x00080000 /* DMA #1 Interrupt Enable */ -#define ICS_LDIA 0x00100000 /* Local Doorbell Int Active */ -#define ICS_DMA0_A 0x00200000 /* DMA #0 Interrupt Active */ -#define ICS_DMA1_A 0x00400000 /* DMA #1 Interrupt Active */ -#define ICS_BIA 0x00800000 /* BIST Interrupt Active */ -#define ICS_TA_DM 0x01000000 /* Target Abort - Direct Master */ -#define ICS_TA_DMA0 0x02000000 /* Target Abort - DMA #0 */ -#define ICS_TA_DMA1 0x04000000 /* Target Abort - DMA #1 */ -#define ICS_TA_RA 0x08000000 /* Target Abort - Retry Timeout */ -/* mailbox x is active */ -#define ICS_MBIA(x) (0x10000000 << ((x) & 0x3)) +/* Enable Local Bus LSERR# when PCI Bus Target Abort or Master Abort occurs */ +#define PLX_INTCSR_LSEABORTEN BIT(0) +/* Enable Local Bus LSERR# when PCI parity error occurs */ +#define PLX_INTCSR_LSEPARITYEN BIT(1) +/* Generate PCI Bus SERR# when set to 1 */ +#define PLX_INTCSR_GENSERR BIT(2) +/* Mailbox Interrupt Enable (local bus interrupts on PCI write to MBOX0-3) */ +#define PLX_INTCSR_MBIEN BIT(3) +/* PCI Interrupt Enable */ +#define PLX_INTCSR_PIEN BIT(8) +/* PCI Doorbell Interrupt Enable */ +#define PLX_INTCSR_PDBIEN BIT(9) +/* PCI Abort Interrupt Enable */ +#define PLX_INTCSR_PABORTIEN BIT(10) +/* PCI Local Interrupt Enable */ +#define PLX_INTCSR_PLIEN BIT(11) +/* Retry Abort Enable (for diagnostic purposes only) */ +#define PLX_INTCSR_RAEN BIT(12) +/* PCI Doorbell Interrupt Active (read-only) */ +#define PLX_INTCSR_PDBIA BIT(13) +/* PCI Abort Interrupt Active (read-only) */ +#define PLX_INTCSR_PABORTIA BIT(14) +/* Local Interrupt (LINTi#) Active (read-only) */ +#define PLX_INTCSR_PLIA BIT(15) +/* Local Interrupt Output (LINTo#) Enable */ +#define PLX_INTCSR_LIOEN BIT(16) +/* Local Doorbell Interrupt Enable */ +#define PLX_INTCSR_LDBIEN BIT(17) +/* DMA Channel 0 Interrupt Enable */ +#define PLX_INTCSR_DMA0IEN BIT(18) +/* DMA Channel 1 Interrupt Enable */ +#define PLX_INTCSR_DMA1IEN BIT(19) +/* DMA Channel N Interrupt Enable (N <= 1) */ +#define PLX_INTCSR_DMAIEN(n) ((n) ? PLX_INTCSR_DMA1IEN : PLX_INTCSR_DMA0IEN) +/* Local Doorbell Interrupt Active (read-only) */ +#define PLX_INTCSR_LDBIA BIT(20) +/* DMA Channel 0 Interrupt Active (read-only) */ +#define PLX_INTCSR_DMA0IA BIT(21) +/* DMA Channel 1 Interrupt Active (read-only) */ +#define PLX_INTCSR_DMA1IA BIT(22) +/* DMA Channel N Interrupt Active (N <= 1) (read-only) */ +#define PLX_INTCSR_DMAIA(n) ((n) ? PLX_INTCSR_DMA1IA : PLX_INTCSR_DMA0IA) +/* BIST Interrupt Active (read-only) */ +#define PLX_INTCSR_BISTIA BIT(23) +/* Direct Master Not Bus Master During Master Or Target Abort (read-only) */ +#define PLX_INTCSR_ABNOTDM BIT(24) +/* DMA Channel 0 Not Bus Master During Master Or Target Abort (read-only) */ +#define PLX_INTCSR_ABNOTDMA0 BIT(25) +/* DMA Channel 1 Not Bus Master During Master Or Target Abort (read-only) */ +#define PLX_INTCSR_ABNOTDMA1 BIT(26) +/* DMA Channel N Not Bus Master During Master Or Target Abort (read-only) */ +#define PLX_INTCSR_ABNOTDMA(n) ((n) ? PLX_INTCSR_ABNOTDMA1 \ + : PLX_INTCSR_ABNOTDMA0) +/* Target Abort Not Generated After 256 Master Retries (read-only) */ +#define PLX_INTCSR_ABNOTRETRY BIT(27) +/* PCI Wrote Mailbox 0 (enabled if bit 3 set) (read-only) */ +#define PLX_INTCSR_MB0IA BIT(28) +/* PCI Wrote Mailbox 1 (enabled if bit 3 set) (read-only) */ +#define PLX_INTCSR_MB1IA BIT(29) +/* PCI Wrote Mailbox 2 (enabled if bit 3 set) (read-only) */ +#define PLX_INTCSR_MB2IA BIT(30) +/* PCI Wrote Mailbox 3 (enabled if bit 3 set) (read-only) */ +#define PLX_INTCSR_MB3IA BIT(31) +/* PCI Wrote Mailbox N (N <= 3) (enabled if bit 3 set) (read-only) */ +#define PLX_INTCSR_MBIA(n) BIT(28 + (n)) /* * Serial EEPROM Control, PCI Command Codes, User I/O Control, diff --git a/drivers/staging/comedi/drivers/rtd520.c b/drivers/staging/comedi/drivers/rtd520.c index 236f6ad..e00e9c6 100644 --- a/drivers/staging/comedi/drivers/rtd520.c +++ b/drivers/staging/comedi/drivers/rtd520.c @@ -1316,7 +1316,8 @@ static int rtd_auto_attach(struct comedi_device *dev, devpriv->fifosz = ret; if (dev->irq) - writel(ICS_PIE | ICS_PLIE, devpriv->lcfg + PLX_REG_INTCSR); + writel(PLX_INTCSR_PIEN | PLX_INTCSR_PLIEN, + devpriv->lcfg + PLX_REG_INTCSR); return 0; } -- cgit v0.10.2 From a3228bc8b7a07e7abf74b8833f3778586e30cb2f Mon Sep 17 00:00:00 2001 From: Ian Abbott Date: Fri, 20 May 2016 14:49:14 +0100 Subject: staging: comedi: drivers: re-do PLX PCI 9080 CNTRL register values Replace the existing macros in "plx9080.h" that define values for the CNTRL register. Use the prefix `PLX_CNTRL_` for the macros. Make use of the `BIT(x)` and `GENMASK(h,l)` macros to define the values. Signed-off-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/comedi/drivers/cb_pcidas64.c b/drivers/staging/comedi/drivers/cb_pcidas64.c index 6b3f4dc..dfb2ae8 100644 --- a/drivers/staging/comedi/drivers/cb_pcidas64.c +++ b/drivers/staging/comedi/drivers/cb_pcidas64.c @@ -1614,7 +1614,7 @@ static const int i2c_low_udelay = 10; static void i2c_set_sda(struct comedi_device *dev, int state) { struct pcidas64_private *devpriv = dev->private; - static const int data_bit = CTL_EE_W; + static const int data_bit = PLX_CNTRL_EEWB; void __iomem *plx_control_addr = devpriv->plx9080_iobase + PLX_REG_CNTRL; @@ -1635,7 +1635,7 @@ static void i2c_set_sda(struct comedi_device *dev, int state) static void i2c_set_scl(struct comedi_device *dev, int state) { struct pcidas64_private *devpriv = dev->private; - static const int clock_bit = CTL_USERO; + static const int clock_bit = PLX_CNTRL_USERO; void __iomem *plx_control_addr = devpriv->plx9080_iobase + PLX_REG_CNTRL; @@ -1708,7 +1708,7 @@ static void i2c_write(struct comedi_device *dev, unsigned int address, */ /* make sure we dont send anything to eeprom */ - devpriv->plx_control_bits &= ~CTL_EE_CS; + devpriv->plx_control_bits &= ~PLX_CNTRL_EECS; i2c_stop(dev); i2c_start(dev); @@ -3717,13 +3717,13 @@ static uint16_t read_eeprom(struct comedi_device *dev, uint8_t address) static const int eeprom_udelay = 1; udelay(eeprom_udelay); - devpriv->plx_control_bits &= ~CTL_EE_CLK & ~CTL_EE_CS; + devpriv->plx_control_bits &= ~PLX_CNTRL_EESK & ~PLX_CNTRL_EECS; /* make sure we don't send anything to the i2c bus on 4020 */ - devpriv->plx_control_bits |= CTL_USERO; + devpriv->plx_control_bits |= PLX_CNTRL_USERO; writel(devpriv->plx_control_bits, plx_control_addr); /* activate serial eeprom */ udelay(eeprom_udelay); - devpriv->plx_control_bits |= CTL_EE_CS; + devpriv->plx_control_bits |= PLX_CNTRL_EECS; writel(devpriv->plx_control_bits, plx_control_addr); /* write read command and desired memory address */ @@ -3731,16 +3731,16 @@ static uint16_t read_eeprom(struct comedi_device *dev, uint8_t address) /* set bit to be written */ udelay(eeprom_udelay); if (bitstream & bit) - devpriv->plx_control_bits |= CTL_EE_W; + devpriv->plx_control_bits |= PLX_CNTRL_EEWB; else - devpriv->plx_control_bits &= ~CTL_EE_W; + devpriv->plx_control_bits &= ~PLX_CNTRL_EEWB; writel(devpriv->plx_control_bits, plx_control_addr); /* clock in bit */ udelay(eeprom_udelay); - devpriv->plx_control_bits |= CTL_EE_CLK; + devpriv->plx_control_bits |= PLX_CNTRL_EESK; writel(devpriv->plx_control_bits, plx_control_addr); udelay(eeprom_udelay); - devpriv->plx_control_bits &= ~CTL_EE_CLK; + devpriv->plx_control_bits &= ~PLX_CNTRL_EESK; writel(devpriv->plx_control_bits, plx_control_addr); } /* read back value from eeprom memory location */ @@ -3748,19 +3748,19 @@ static uint16_t read_eeprom(struct comedi_device *dev, uint8_t address) for (bit = 1 << (value_length - 1); bit; bit >>= 1) { /* clock out bit */ udelay(eeprom_udelay); - devpriv->plx_control_bits |= CTL_EE_CLK; + devpriv->plx_control_bits |= PLX_CNTRL_EESK; writel(devpriv->plx_control_bits, plx_control_addr); udelay(eeprom_udelay); - devpriv->plx_control_bits &= ~CTL_EE_CLK; + devpriv->plx_control_bits &= ~PLX_CNTRL_EESK; writel(devpriv->plx_control_bits, plx_control_addr); udelay(eeprom_udelay); - if (readl(plx_control_addr) & CTL_EE_R) + if (readl(plx_control_addr) & PLX_CNTRL_EERB) value |= bit; } /* deactivate eeprom serial input */ udelay(eeprom_udelay); - devpriv->plx_control_bits &= ~CTL_EE_CS; + devpriv->plx_control_bits &= ~PLX_CNTRL_EECS; writel(devpriv->plx_control_bits, plx_control_addr); return value; @@ -3948,7 +3948,8 @@ static int setup_subdevices(struct comedi_device *dev) /* serial EEPROM, if present */ s = &dev->subdevices[8]; - if (readl(devpriv->plx9080_iobase + PLX_REG_CNTRL) & CTL_EECHK) { + if (readl(devpriv->plx9080_iobase + PLX_REG_CNTRL) & + PLX_CNTRL_EEPRESENT) { s->type = COMEDI_SUBD_MEMORY; s->subdev_flags = SDF_READABLE | SDF_INTERNAL; s->n_chan = 128; diff --git a/drivers/staging/comedi/drivers/plx9080.h b/drivers/staging/comedi/drivers/plx9080.h index e9f1b9c..4ad9464 100644 --- a/drivers/staging/comedi/drivers/plx9080.h +++ b/drivers/staging/comedi/drivers/plx9080.h @@ -393,20 +393,55 @@ struct plx_dma_desc { */ #define PLX_REG_CNTRL 0x006c -#define CTL_RDMA 0x0000000E /* DMA Read Command */ -#define CTL_WDMA 0x00000070 /* DMA Write Command */ -#define CTL_RMEM 0x00000600 /* Memory Read Command */ -#define CTL_WMEM 0x00007000 /* Memory Write Command */ -#define CTL_USERO 0x00010000 /* USERO output pin control bit */ -#define CTL_USERI 0x00020000 /* USERI input pin bit */ -#define CTL_EE_CLK 0x01000000 /* EEPROM Clock line */ -#define CTL_EE_CS 0x02000000 /* EEPROM Chip Select */ -#define CTL_EE_W 0x04000000 /* EEPROM Write bit */ -#define CTL_EE_R 0x08000000 /* EEPROM Read bit */ -#define CTL_EECHK 0x10000000 /* EEPROM Present bit */ -#define CTL_EERLD 0x20000000 /* EEPROM Reload Register */ -#define CTL_RESET 0x40000000 /* !! Adapter Reset !! */ -#define CTL_READY 0x80000000 /* Local Init Done */ +/* PCI Read Command Code For DMA */ +#define PLX_CNTRL_CCRDMA(x) (BIT(0) * ((x) & 0xf)) +#define PLX_CNTRL_CCRDMA_MASK GENMASK(3, 0) +#define PLX_CNTRL_CCRDMA_SHIFT 0 +#define PLX_CNTRL_CCRDMA_NORMAL PLX_CNTRL_CCRDMA(14) /* value after reset */ +/* PCI Write Command Code For DMA 0 */ +#define PLX_CNTRL_CCWDMA(x) (BIT(4) * ((x) & 0xf)) +#define PLX_CNTRL_CCWDMA_MASK GENMASK(7, 4) +#define PLX_CNTRL_CCWDMA_SHIFT 4 +#define PLX_CNTRL_CCWDMA_NORMAL PLX_CNTRL_CCWDMA(7) /* value after reset */ +/* PCI Memory Read Command Code For Direct Master */ +#define PLX_CNTRL_CCRDM(x) (BIT(8) * ((x) & 0xf)) +#define PLX_CNTRL_CCRDM_MASK GENMASK(11, 8) +#define PLX_CNTRL_CCRDM_SHIFT 8 +#define PLX_CNTRL_CCRDM_NORMAL PLX_CNTRL_CCRDM(6) /* value after reset */ +/* PCI Memory Write Command Code For Direct Master */ +#define PLX_CNTRL_CCWDM(x) (BIT(12) * ((x) & 0xf)) +#define PLX_CNTRL_CCWDM_MASK GENMASK(15, 12) +#define PLX_CNTRL_CCWDM_SHIFT 12 +#define PLX_CNTRL_CCWDM_NORMAL PLX_CNTRL_CCWDM(7) /* value after reset */ +/* General Purpose Output (USERO) */ +#define PLX_CNTRL_USERO BIT(16) +/* General Purpose Input (USERI) (read-only) */ +#define PLX_CNTRL_USERI BIT(17) +/* Serial EEPROM Clock Output (EESK) */ +#define PLX_CNTRL_EESK BIT(24) +/* Serial EEPROM Chip Select Output (EECS) */ +#define PLX_CNTRL_EECS BIT(25) +/* Serial EEPROM Data Write Bit (EEDI (sic)) */ +#define PLX_CNTRL_EEWB BIT(26) +/* Serial EEPROM Data Read Bit (EEDO (sic)) (read-only) */ +#define PLX_CNTRL_EERB BIT(27) +/* Serial EEPROM Present (read-only) */ +#define PLX_CNTRL_EEPRESENT BIT(28) +/* Reload Configuration Registers from EEPROM */ +#define PLX_CNTRL_EERELOAD BIT(29) +/* PCI Adapter Software Reset (asserts LRESETo#) */ +#define PLX_CNTRL_RESET BIT(30) +/* Local Init Status (read-only) */ +#define PLX_CNTRL_INITDONE BIT(31) +/* + * Combined command code stuff for convenience. + */ +#define PLX_CNTRL_CC_MASK \ + (PLX_CNTRL_CCRDMA_MASK | PLX_CNTRL_CCWDMA_MASK | \ + PLX_CNTRL_CCRDM_MASK | PLX_CNTRL_CCWDM_MASK) +#define PLX_CNTRL_CC_NORMAL \ + (PLX_CNTRL_CCRDMA_NORMAL | PLX_CNTRL_CCWDMA_NORMAL | \ + PLX_CNTRL_CCRDM_NORMAL | PLX_CNTRL_CCWDM_NORMAL) /* val after reset */ /* PCI Permanent Configuration ID Register (hard-coded PLX vendor and device) */ #define PLX_REG_PCIHIDR 0x0070 -- cgit v0.10.2 From df04d3aa028a5feb905b1b0871c000ed51535eef Mon Sep 17 00:00:00 2001 From: Ian Abbott Date: Fri, 20 May 2016 14:49:15 +0100 Subject: staging: comedi: plx9080.h: add hard-coded PCIHIDR register value For the PLX PCI 9080, the read-only PCIHIDR register is hard-coded with the value `0x908010b5`. Add a macro `PLX_PCIHIDR_9080` that expands to this value. Signed-off-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/comedi/drivers/plx9080.h b/drivers/staging/comedi/drivers/plx9080.h index 4ad9464..c70af5e 100644 --- a/drivers/staging/comedi/drivers/plx9080.h +++ b/drivers/staging/comedi/drivers/plx9080.h @@ -446,6 +446,9 @@ struct plx_dma_desc { /* PCI Permanent Configuration ID Register (hard-coded PLX vendor and device) */ #define PLX_REG_PCIHIDR 0x0070 +/* Hard-coded ID for PLX PCI 9080 */ +#define PLX_PCIHIDR_9080 0x908010b5 + /* PCI Permanent Revision ID Register (hard-coded silicon revision) (8-bit). */ #define PLX_REG_PCIHREV 0x0074 -- cgit v0.10.2 From 65bf53de830063520cfbdedd56d80f1125d62271 Mon Sep 17 00:00:00 2001 From: Ian Abbott Date: Fri, 20 May 2016 14:49:16 +0100 Subject: staging: comedi: drivers: re-do PLX PCI 9080 DMAMODEx register values Replace the existing macros in "plx9080.h" that define values for the DMAMODE0 and DMAMODE1 registers. Use the prefix `PLX_DMAMODE_` for the macros. Make use of the `BIT(x)` and `GENMASK(h,l)` macros to define the values. Signed-off-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/comedi/drivers/cb_pcidas64.c b/drivers/staging/comedi/drivers/cb_pcidas64.c index dfb2ae8..48aca06 100644 --- a/drivers/staging/comedi/drivers/cb_pcidas64.c +++ b/drivers/staging/comedi/drivers/cb_pcidas64.c @@ -1308,28 +1308,28 @@ static void init_plx9080(struct comedi_device *dev) /* configure dma0 mode */ bits = 0; /* enable ready input, not sure if this is necessary */ - bits |= PLX_DMA_EN_READYIN_BIT; + bits |= PLX_DMAMODE_READYIEN; /* enable bterm, not sure if this is necessary */ - bits |= PLX_EN_BTERM_BIT; + bits |= PLX_DMAMODE_BTERMIEN; /* enable dma chaining */ - bits |= PLX_EN_CHAIN_BIT; + bits |= PLX_DMAMODE_CHAINEN; /* enable interrupt on dma done * (probably don't need this, since chain never finishes) */ - bits |= PLX_EN_DMA_DONE_INTR_BIT; + bits |= PLX_DMAMODE_DONEIEN; /* don't increment local address during transfers * (we are transferring from a fixed fifo register) */ - bits |= PLX_LOCAL_ADDR_CONST_BIT; + bits |= PLX_DMAMODE_LACONST; /* route dma interrupt to pci bus */ - bits |= PLX_DMA_INTR_PCI_BIT; + bits |= PLX_DMAMODE_INTRPCI; /* enable demand mode */ - bits |= PLX_DEMAND_MODE_BIT; + bits |= PLX_DMAMODE_DEMAND; /* enable local burst mode */ - bits |= PLX_DMA_LOCAL_BURST_EN_BIT; + bits |= PLX_DMAMODE_BURSTEN; /* 4020 uses 32 bit dma */ if (board->layout == LAYOUT_4020) - bits |= PLX_LOCAL_BUS_32_WIDE_BITS; + bits |= PLX_DMAMODE_WIDTH32; else /* localspace0 bus is 16 bits wide */ - bits |= PLX_LOCAL_BUS_16_WIDE_BITS; + bits |= PLX_DMAMODE_WIDTH16; writel(bits, plx_iobase + PLX_REG_DMAMODE1); if (ao_cmd_is_supported(board)) writel(bits, plx_iobase + PLX_REG_DMAMODE0); diff --git a/drivers/staging/comedi/drivers/gsc_hpdi.c b/drivers/staging/comedi/drivers/gsc_hpdi.c index e288798..d63dc46 100644 --- a/drivers/staging/comedi/drivers/gsc_hpdi.c +++ b/drivers/staging/comedi/drivers/gsc_hpdi.c @@ -563,26 +563,26 @@ static void gsc_hpdi_init_plx9080(struct comedi_device *dev) /* configure dma0 mode */ bits = 0; /* enable ready input */ - bits |= PLX_DMA_EN_READYIN_BIT; + bits |= PLX_DMAMODE_READYIEN; /* enable dma chaining */ - bits |= PLX_EN_CHAIN_BIT; + bits |= PLX_DMAMODE_CHAINEN; /* * enable interrupt on dma done * (probably don't need this, since chain never finishes) */ - bits |= PLX_EN_DMA_DONE_INTR_BIT; + bits |= PLX_DMAMODE_DONEIEN; /* * don't increment local address during transfers * (we are transferring from a fixed fifo register) */ - bits |= PLX_LOCAL_ADDR_CONST_BIT; + bits |= PLX_DMAMODE_LACONST; /* route dma interrupt to pci bus */ - bits |= PLX_DMA_INTR_PCI_BIT; + bits |= PLX_DMAMODE_INTRPCI; /* enable demand mode */ - bits |= PLX_DEMAND_MODE_BIT; + bits |= PLX_DMAMODE_DEMAND; /* enable local burst mode */ - bits |= PLX_DMA_LOCAL_BURST_EN_BIT; - bits |= PLX_LOCAL_BUS_32_WIDE_BITS; + bits |= PLX_DMAMODE_BURSTEN; + bits |= PLX_DMAMODE_WIDTH32; writel(bits, plx_iobase + PLX_REG_DMAMODE0); } diff --git a/drivers/staging/comedi/drivers/plx9080.h b/drivers/staging/comedi/drivers/plx9080.h index c70af5e..99c075c 100644 --- a/drivers/staging/comedi/drivers/plx9080.h +++ b/drivers/staging/comedi/drivers/plx9080.h @@ -457,23 +457,41 @@ struct plx_dma_desc { #define PLX_REG_DMAMODE0 0x0080 #define PLX_REG_DMAMODE1 0x0094 -#define PLX_LOCAL_BUS_16_WIDE_BITS 0x1 -#define PLX_LOCAL_BUS_32_WIDE_BITS 0x3 -#define PLX_LOCAL_BUS_WIDTH_MASK 0x3 -#define PLX_DMA_EN_READYIN_BIT 0x40 /* enable ready in input */ -#define PLX_EN_BTERM_BIT 0x80 /* enable BTERM# input */ -#define PLX_DMA_LOCAL_BURST_EN_BIT 0x100 /* enable local burst mode */ -#define PLX_EN_CHAIN_BIT 0x200 /* enables chaining */ -/* enables interrupt on dma done */ -#define PLX_EN_DMA_DONE_INTR_BIT 0x400 -/* hold local address constant (don't increment) */ -#define PLX_LOCAL_ADDR_CONST_BIT 0x800 -/* enables demand-mode for dma transfer */ -#define PLX_DEMAND_MODE_BIT 0x1000 -#define PLX_EOT_ENABLE_BIT 0x4000 -#define PLX_STOP_MODE_BIT 0x8000 -/* routes dma interrupt to pci bus (instead of local bus) */ -#define PLX_DMA_INTR_PCI_BIT 0x20000 +/* Local Bus Width */ +#define PLX_DMAMODE_WIDTH8 (BIT(0) * 0) /* 8 bits wide */ +#define PLX_DMAMODE_WIDTH16 (BIT(0) * 1) /* 16 bits wide */ +#define PLX_DMAMODE_WIDTH32 (BIT(0) * 2) /* 32 bits wide */ +#define PLX_DMAMODE_WIDTH32A (BIT(0) * 3) /* 32 bits wide */ +#define PLX_DMAMODE_WIDTH_MASK GENMASK(1, 0) +#define PLX_DMAMODE_WIDTH_SHIFT 0 +/* Internal Wait States */ +#define PLX_DMAMODE_IWS(x) (BIT(2) * ((x) & 0xf)) +#define PLX_DMAMODE_IWS_MASK GENMASK(5, 2) +#define PLX_DMAMODE_SHIFT 2 +/* Ready Input Enable */ +#define PLX_DMAMODE_READYIEN BIT(6) +/* BTERM# Input Enable */ +#define PLX_DMAMODE_BTERMIEN BIT(7) +/* Local Burst Enable */ +#define PLX_DMAMODE_BURSTEN BIT(8) +/* Chaining Enable */ +#define PLX_DMAMODE_CHAINEN BIT(9) +/* Done Interrupt Enable */ +#define PLX_DMAMODE_DONEIEN BIT(10) +/* Hold Local Address Constant */ +#define PLX_DMAMODE_LACONST BIT(11) +/* Demand Mode */ +#define PLX_DMAMODE_DEMAND BIT(12) +/* Write And Invalidate Mode */ +#define PLX_DMAMODE_WINVALIDATE BIT(13) +/* DMA EOT Enable - enables EOT0# or EOT1# input pin */ +#define PLX_DMAMODE_EOTEN BIT(14) +/* DMA Stop Data Transfer Mode - 0:BLAST; 1:EOT asserted or DREQ deasserted */ +#define PLX_DMAMODE_STOP BIT(15) +/* DMA Clear Count Mode - count in descriptor cleared on completion */ +#define PLX_DMAMODE_CLRCOUNT BIT(16) +/* DMA Channel Interrupt Select - 0:local bus interrupt; 1:PCI interrupt */ +#define PLX_DMAMODE_INTRPCI BIT(17) /* DMA Channel N PCI Address Register (N <= 1) */ #define PLX_REG_DMAPADR(n) ((n) ? PLX_REG_DMAPADR1 : PLX_REG_DMAPADR0) -- cgit v0.10.2 From dde90d89ae5a98a3f1420b6c20c7f58dd95ccfa3 Mon Sep 17 00:00:00 2001 From: Ian Abbott Date: Fri, 20 May 2016 14:49:17 +0100 Subject: staging: comedi: drivers: re-do PLX PCI 9080 DMADPRx register values Replace the existing macros in "plx9080.h" that define values for the DMADPR0 and DMADPR1 registers. (A little-endian version of the register value is also placed in the `next` member of `struct plx_dma_desc`.) Use the prefix `PLX_DMADPR_` for the macros. Make use of the `BIT(x)` and `GENMASK(h,l)` macros to define the values. Signed-off-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/comedi/drivers/cb_pcidas64.c b/drivers/staging/comedi/drivers/cb_pcidas64.c index 48aca06..a4d10a3 100644 --- a/drivers/staging/comedi/drivers/cb_pcidas64.c +++ b/drivers/staging/comedi/drivers/cb_pcidas64.c @@ -1534,8 +1534,8 @@ static int alloc_and_init_dma_members(struct comedi_device *dev) cpu_to_le32((devpriv->ai_dma_desc_bus_addr + ((i + 1) % ai_dma_ring_count(board)) * sizeof(devpriv->ai_dma_desc[0])) | - PLX_DESC_IN_PCI_BIT | PLX_INTR_TERM_COUNT | - PLX_XFER_LOCAL_TO_PCI); + PLX_DMADPR_DESCPCI | PLX_DMADPR_TCINTR | + PLX_DMADPR_XFERL2P); } if (ao_cmd_is_supported(board)) { for (i = 0; i < AO_DMA_RING_COUNT; i++) { @@ -1549,8 +1549,8 @@ static int alloc_and_init_dma_members(struct comedi_device *dev) cpu_to_le32((devpriv->ao_dma_desc_bus_addr + ((i + 1) % (AO_DMA_RING_COUNT)) * sizeof(devpriv->ao_dma_desc[0])) | - PLX_DESC_IN_PCI_BIT | - PLX_INTR_TERM_COUNT); + PLX_DMADPR_DESCPCI | + PLX_DMADPR_TCINTR); } } return 0; @@ -2634,9 +2634,9 @@ static int ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) /* give location of first dma descriptor */ load_first_dma_descriptor(dev, 1, devpriv->ai_dma_desc_bus_addr | - PLX_DESC_IN_PCI_BIT | - PLX_INTR_TERM_COUNT | - PLX_XFER_LOCAL_TO_PCI); + PLX_DMADPR_DESCPCI | + PLX_DMADPR_TCINTR | + PLX_DMADPR_XFERL2P); dma_start_sync(dev, 1); } @@ -2918,7 +2918,7 @@ static void restart_ao_dma(struct comedi_device *dev) unsigned int dma_desc_bits; dma_desc_bits = readl(devpriv->plx9080_iobase + PLX_REG_DMADPR0); - dma_desc_bits &= ~PLX_END_OF_CHAIN_BIT; + dma_desc_bits &= ~PLX_DMADPR_CHAINEND; load_first_dma_descriptor(dev, 0, dma_desc_bits); dma_start_sync(dev, 0); @@ -2959,14 +2959,14 @@ static unsigned int load_ao_dma_buffer(struct comedi_device *dev, devpriv->ao_dma_desc[buffer_index].transfer_size = cpu_to_le32(nbytes); /* set end of chain bit so we catch underruns */ next_bits = le32_to_cpu(devpriv->ao_dma_desc[buffer_index].next); - next_bits |= PLX_END_OF_CHAIN_BIT; + next_bits |= PLX_DMADPR_CHAINEND; devpriv->ao_dma_desc[buffer_index].next = cpu_to_le32(next_bits); /* * clear end of chain bit on previous buffer now that we have set it * for the last buffer */ next_bits = le32_to_cpu(devpriv->ao_dma_desc[prev_buffer_index].next); - next_bits &= ~PLX_END_OF_CHAIN_BIT; + next_bits &= ~PLX_DMADPR_CHAINEND; devpriv->ao_dma_desc[prev_buffer_index].next = cpu_to_le32(next_bits); devpriv->ao_dma_index = (buffer_index + 1) % AO_DMA_RING_COUNT; @@ -3310,7 +3310,7 @@ static int ao_cmd(struct comedi_device *dev, struct comedi_subdevice *s) set_dac_select_reg(dev, cmd); set_dac_interval_regs(dev, cmd); load_first_dma_descriptor(dev, 0, devpriv->ao_dma_desc_bus_addr | - PLX_DESC_IN_PCI_BIT | PLX_INTR_TERM_COUNT); + PLX_DMADPR_DESCPCI | PLX_DMADPR_TCINTR); set_dac_control1_reg(dev, cmd); s->async->inttrig = ao_inttrig; diff --git a/drivers/staging/comedi/drivers/gsc_hpdi.c b/drivers/staging/comedi/drivers/gsc_hpdi.c index d63dc46..f2f1874 100644 --- a/drivers/staging/comedi/drivers/gsc_hpdi.c +++ b/drivers/staging/comedi/drivers/gsc_hpdi.c @@ -310,8 +310,8 @@ static int gsc_hpdi_cmd(struct comedi_device *dev, writel(0, devpriv->plx9080_mmio + PLX_REG_DMALADR0); /* give location of first dma descriptor */ - bits = devpriv->dma_desc_phys_addr | PLX_DESC_IN_PCI_BIT | - PLX_INTR_TERM_COUNT | PLX_XFER_LOCAL_TO_PCI; + bits = devpriv->dma_desc_phys_addr | PLX_DMADPR_DESCPCI | + PLX_DMADPR_TCINTR | PLX_DMADPR_XFERL2P; writel(bits, devpriv->plx9080_mmio + PLX_REG_DMADPR0); /* enable dma transfer */ @@ -422,8 +422,8 @@ static int gsc_hpdi_setup_dma_descriptors(struct comedi_device *dev, { struct hpdi_private *devpriv = dev->private; dma_addr_t phys_addr = devpriv->dma_desc_phys_addr; - u32 next_bits = PLX_DESC_IN_PCI_BIT | PLX_INTR_TERM_COUNT | - PLX_XFER_LOCAL_TO_PCI; + u32 next_bits = PLX_DMADPR_DESCPCI | PLX_DMADPR_TCINTR | + PLX_DMADPR_XFERL2P; unsigned int offset = 0; unsigned int idx = 0; unsigned int i; diff --git a/drivers/staging/comedi/drivers/plx9080.h b/drivers/staging/comedi/drivers/plx9080.h index 99c075c..2fe1a4d 100644 --- a/drivers/staging/comedi/drivers/plx9080.h +++ b/drivers/staging/comedi/drivers/plx9080.h @@ -513,13 +513,16 @@ struct plx_dma_desc { #define PLX_REG_DMADPR0 0x0090 #define PLX_REG_DMADPR1 0x00a4 -/* descriptor is located in pci space (not local space) */ -#define PLX_DESC_IN_PCI_BIT 0x1 -#define PLX_END_OF_CHAIN_BIT 0x2 /* end of chain bit */ -/* interrupt when this descriptor's transfer is finished */ -#define PLX_INTR_TERM_COUNT 0x4 -/* transfer from local to pci bus (not pci to local) */ -#define PLX_XFER_LOCAL_TO_PCI 0x8 +/* Descriptor Located In PCI Address Space (not local address space) */ +#define PLX_DMADPR_DESCPCI BIT(0) +/* End Of Chain */ +#define PLX_DMADPR_CHAINEND BIT(1) +/* Interrupt After Terminal Count */ +#define PLX_DMADPR_TCINTR BIT(2) +/* Direction Of Transfer Local Bus To PCI (not PCI to local) */ +#define PLX_DMADPR_XFERL2P BIT(3) +/* Next Descriptor Address Bits 31:4 (16 byte boundary) */ +#define PLX_DMADPR_NEXT_MASK GENMASK(31, 4) /* DMA Channel N Command/Status Register (N <= 1) (8-bit) */ #define PLX_REG_DMACSR(n) ((n) ? PLX_REG_DMACSR1 : PLX_REG_DMACSR0) -- cgit v0.10.2 From 3dcf1b5596603076cf127a3efdf3a33a276d8b9e Mon Sep 17 00:00:00 2001 From: Ian Abbott Date: Fri, 20 May 2016 14:49:18 +0100 Subject: staging: comedi: drivers: re-do PLX PCI 9080 DMACSRx register values Replace the existing macros in "plx9080.h" that define values for the DMACSR0 and DMACSR0 registers. Use the prefix `PLX_DMACSR_` for the macros. Make use of the `BIT(x)` macro to define the values. Signed-off-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/comedi/drivers/cb_pcidas64.c b/drivers/staging/comedi/drivers/cb_pcidas64.c index a4d10a3..1f9c08a 100644 --- a/drivers/staging/comedi/drivers/cb_pcidas64.c +++ b/drivers/staging/comedi/drivers/cb_pcidas64.c @@ -2368,7 +2368,7 @@ static inline void dma_start_sync(struct comedi_device *dev, /* spinlock for plx dma control/status reg */ spin_lock_irqsave(&dev->spinlock, flags); - writeb(PLX_DMA_EN_BIT | PLX_DMA_START_BIT | PLX_CLEAR_DMA_INTR_BIT, + writeb(PLX_DMACSR_ENABLE | PLX_DMACSR_START | PLX_DMACSR_CLEARINTR, devpriv->plx9080_iobase + PLX_REG_DMACSR(channel)); spin_unlock_irqrestore(&dev->spinlock, flags); } @@ -2838,10 +2838,10 @@ static void handle_ai_interrupt(struct comedi_device *dev, spin_lock_irqsave(&dev->spinlock, flags); dma1_status = readb(devpriv->plx9080_iobase + PLX_REG_DMACSR1); if (plx_status & PLX_INTCSR_DMA1IA) { /* dma chan 1 interrupt */ - writeb((dma1_status & PLX_DMA_EN_BIT) | PLX_CLEAR_DMA_INTR_BIT, + writeb((dma1_status & PLX_DMACSR_ENABLE) | PLX_DMACSR_CLEARINTR, devpriv->plx9080_iobase + PLX_REG_DMACSR1); - if (dma1_status & PLX_DMA_EN_BIT) + if (dma1_status & PLX_DMACSR_ENABLE) drain_dma_buffers(dev, 1); } spin_unlock_irqrestore(&dev->spinlock, flags); @@ -2889,7 +2889,7 @@ static int last_ao_dma_load_completed(struct comedi_device *dev) buffer_index = prev_ao_dma_index(dev); dma_status = readb(devpriv->plx9080_iobase + PLX_REG_DMACSR0); - if ((dma_status & PLX_DMA_DONE_BIT) == 0) + if ((dma_status & PLX_DMACSR_DONE) == 0) return 0; transfer_address = @@ -2903,8 +2903,8 @@ static int last_ao_dma_load_completed(struct comedi_device *dev) static inline int ao_dma_needs_restart(struct comedi_device *dev, unsigned short dma_status) { - if ((dma_status & PLX_DMA_DONE_BIT) == 0 || - (dma_status & PLX_DMA_EN_BIT) == 0) + if ((dma_status & PLX_DMACSR_DONE) == 0 || + (dma_status & PLX_DMACSR_ENABLE) == 0) return 0; if (last_ao_dma_load_completed(dev)) return 0; @@ -3016,16 +3016,16 @@ static void handle_ao_interrupt(struct comedi_device *dev, spin_lock_irqsave(&dev->spinlock, flags); dma0_status = readb(devpriv->plx9080_iobase + PLX_REG_DMACSR0); if (plx_status & PLX_INTCSR_DMA0IA) { /* dma chan 0 interrupt */ - if ((dma0_status & PLX_DMA_EN_BIT) && - !(dma0_status & PLX_DMA_DONE_BIT)) { - writeb(PLX_DMA_EN_BIT | PLX_CLEAR_DMA_INTR_BIT, + if ((dma0_status & PLX_DMACSR_ENABLE) && + !(dma0_status & PLX_DMACSR_DONE)) { + writeb(PLX_DMACSR_ENABLE | PLX_DMACSR_CLEARINTR, devpriv->plx9080_iobase + PLX_REG_DMACSR0); } else { - writeb(PLX_CLEAR_DMA_INTR_BIT, + writeb(PLX_DMACSR_CLEARINTR, devpriv->plx9080_iobase + PLX_REG_DMACSR0); } spin_unlock_irqrestore(&dev->spinlock, flags); - if (dma0_status & PLX_DMA_EN_BIT) { + if (dma0_status & PLX_DMACSR_ENABLE) { load_ao_dma(dev, cmd); /* try to recover from dma end-of-chain event */ if (ao_dma_needs_restart(dev, dma0_status)) diff --git a/drivers/staging/comedi/drivers/gsc_hpdi.c b/drivers/staging/comedi/drivers/gsc_hpdi.c index f2f1874..af4b417 100644 --- a/drivers/staging/comedi/drivers/gsc_hpdi.c +++ b/drivers/staging/comedi/drivers/gsc_hpdi.c @@ -214,10 +214,10 @@ static irqreturn_t gsc_hpdi_interrupt(int irq, void *d) dma0_status = readb(devpriv->plx9080_mmio + PLX_REG_DMACSR0); if (plx_status & PLX_INTCSR_DMA0IA) { /* dma chan 0 interrupt */ - writeb((dma0_status & PLX_DMA_EN_BIT) | PLX_CLEAR_DMA_INTR_BIT, + writeb((dma0_status & PLX_DMACSR_ENABLE) | PLX_DMACSR_CLEARINTR, devpriv->plx9080_mmio + PLX_REG_DMACSR0); - if (dma0_status & PLX_DMA_EN_BIT) + if (dma0_status & PLX_DMACSR_ENABLE) gsc_hpdi_drain_dma(dev, 0); } spin_unlock_irqrestore(&dev->spinlock, flags); @@ -227,7 +227,7 @@ static irqreturn_t gsc_hpdi_interrupt(int irq, void *d) dma1_status = readb(devpriv->plx9080_mmio + PLX_REG_DMACSR1); if (plx_status & PLX_INTCSR_DMA1IA) { /* XXX */ /* dma chan 1 interrupt */ - writeb((dma1_status & PLX_DMA_EN_BIT) | PLX_CLEAR_DMA_INTR_BIT, + writeb((dma1_status & PLX_DMACSR_ENABLE) | PLX_DMACSR_CLEARINTR, devpriv->plx9080_mmio + PLX_REG_DMACSR1); } spin_unlock_irqrestore(&dev->spinlock, flags); @@ -316,7 +316,7 @@ static int gsc_hpdi_cmd(struct comedi_device *dev, /* enable dma transfer */ spin_lock_irqsave(&dev->spinlock, flags); - writeb(PLX_DMA_EN_BIT | PLX_DMA_START_BIT | PLX_CLEAR_DMA_INTR_BIT, + writeb(PLX_DMACSR_ENABLE | PLX_DMACSR_START | PLX_DMACSR_CLEARINTR, devpriv->plx9080_mmio + PLX_REG_DMACSR0); spin_unlock_irqrestore(&dev->spinlock, flags); diff --git a/drivers/staging/comedi/drivers/plx9080.h b/drivers/staging/comedi/drivers/plx9080.h index 2fe1a4d..9e76342 100644 --- a/drivers/staging/comedi/drivers/plx9080.h +++ b/drivers/staging/comedi/drivers/plx9080.h @@ -529,11 +529,16 @@ struct plx_dma_desc { #define PLX_REG_DMACSR0 0x00a8 #define PLX_REG_DMACSR1 0x00a9 -#define PLX_DMA_EN_BIT 0x1 /* enable dma channel */ -#define PLX_DMA_START_BIT 0x2 /* start dma transfer */ -#define PLX_DMA_ABORT_BIT 0x4 /* abort dma transfer */ -#define PLX_CLEAR_DMA_INTR_BIT 0x8 /* clear dma interrupt */ -#define PLX_DMA_DONE_BIT 0x10 /* transfer done status bit */ +/* Channel Enable */ +#define PLX_DMACSR_ENABLE BIT(0) +/* Channel Start - write 1 to start transfer (write-only) */ +#define PLX_DMACSR_START BIT(1) +/* Channel Abort - write 1 to abort transfer (write-only) */ +#define PLX_DMACSR_ABORT BIT(2) +/* Clear Interrupt - write 1 to clear DMA Channel Interrupt (write-only) */ +#define PLX_DMACSR_CLEARINTR BIT(3) +/* Channel Done - transfer complete/inactive (read-only) */ +#define PLX_DMACSR_DONE BIT(4) /* DMA Threshold Register */ #define PLX_REG_DMATHR 0x00b0 @@ -571,11 +576,11 @@ static inline int plx9080_abort_dma(void __iomem *iobase, unsigned int channel) /* abort dma transfer if necessary */ dma_status = readb(dma_cs_addr); - if ((dma_status & PLX_DMA_EN_BIT) == 0) + if ((dma_status & PLX_DMACSR_ENABLE) == 0) return 0; /* wait to make sure done bit is zero */ - for (i = 0; (dma_status & PLX_DMA_DONE_BIT) && i < timeout; i++) { + for (i = 0; (dma_status & PLX_DMACSR_DONE) && i < timeout; i++) { udelay(1); dma_status = readb(dma_cs_addr); } @@ -583,10 +588,10 @@ static inline int plx9080_abort_dma(void __iomem *iobase, unsigned int channel) return -ETIMEDOUT; /* disable and abort channel */ - writeb(PLX_DMA_ABORT_BIT, dma_cs_addr); + writeb(PLX_DMACSR_ABORT, dma_cs_addr); /* wait for dma done bit */ dma_status = readb(dma_cs_addr); - for (i = 0; (dma_status & PLX_DMA_DONE_BIT) == 0 && i < timeout; i++) { + for (i = 0; (dma_status & PLX_DMACSR_DONE) == 0 && i < timeout; i++) { udelay(1); dma_status = readb(dma_cs_addr); } -- cgit v0.10.2 From eb89333146c3f86aed85944c65c08ad8250668d5 Mon Sep 17 00:00:00 2001 From: Ian Abbott Date: Fri, 20 May 2016 14:49:19 +0100 Subject: staging: comedi: drivers: add PLX PCI 9080 DMATHR register values Add macros in "plx9080.h" that define values for the DMATHR register values. Use the prefix `PLX_DMATHR_` for the macros. Make use of the `BIT(x)` and `GENMASK(h,l)` macros to define the values. Signed-off-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/comedi/drivers/plx9080.h b/drivers/staging/comedi/drivers/plx9080.h index 9e76342..50d0b1b 100644 --- a/drivers/staging/comedi/drivers/plx9080.h +++ b/drivers/staging/comedi/drivers/plx9080.h @@ -544,6 +544,47 @@ struct plx_dma_desc { #define PLX_REG_DMATHR 0x00b0 /* + * DMA Threshold constraints: + * (C0PLAF + 1) + (C0PLAE + 1) <= 32 + * (C0LPAF + 1) + (C0LPAE + 1) <= 32 + * (C1PLAF + 1) + (C1PLAE + 1) <= 16 + * (C1LPAF + 1) + (C1LPAE + 1) <= 16 + */ + +/* DMA Channel 0 PCI-to-Local Almost Full (divided by 2, minus 1) */ +#define PLX_DMATHR_C0PLAF(x) (BIT(0) * ((x) & 0xf)) +#define PLX_DMATHR_C0PLAF_MASK GENMASK(3, 0) +#define PLX_DMATHR_C0PLAF_SHIFT 0 +/* DMA Channel 0 Local-to-PCI Almost Empty (divided by 2, minus 1) */ +#define PLX_DMATHR_C0LPAE(x) (BIT(4) * ((x) & 0xf)) +#define PLX_DMATHR_C0LPAE_MASK GENMASK(7, 4) +#define PLX_DMATHR_C0LPAE_SHIFT 4 +/* DMA Channel 0 Local-to-PCI Almost Full (divided by 2, minus 1) */ +#define PLX_DMATHR_C0LPAF(x) (BIT(8) * ((x) & 0xf)) +#define PLX_DMATHR_C0LPAF_MASK GENMASK(11, 8) +#define PLX_DMATHR_C0LPAF_SHIFT 8 +/* DMA Channel 0 PCI-to-Local Almost Empty (divided by 2, minus 1) */ +#define PLX_DMATHR_C0PLAE(x) (BIT(12) * ((x) & 0xf)) +#define PLX_DMATHR_C0PLAE_MASK GENMASK(15, 12) +#define PLX_DMATHR_C0PLAE_SHIFT 12 +/* DMA Channel 1 PCI-to-Local Almost Full (divided by 2, minus 1) */ +#define PLX_DMATHR_C1PLAF(x) (BIT(16) * ((x) & 0xf)) +#define PLX_DMATHR_C1PLAF_MASK GENMASK(19, 16) +#define PLX_DMATHR_C1PLAF_SHIFT 16 +/* DMA Channel 1 Local-to-PCI Almost Empty (divided by 2, minus 1) */ +#define PLX_DMATHR_C1LPAE(x) (BIT(20) * ((x) & 0xf)) +#define PLX_DMATHR_C1LPAE_MASK GENMASK(23, 20) +#define PLX_DMATHR_C1LPAE_SHIFT 20 +/* DMA Channel 1 Local-to-PCI Almost Full (divided by 2, minus 1) */ +#define PLX_DMATHR_C1LPAF(x) (BIT(24) * ((x) & 0xf)) +#define PLX_DMATHR_C1LPAF_MASK GENMASK(27, 24) +#define PLX_DMATHR_C1LPAF_SHIFT 24 +/* DMA Channel 1 PCI-to-Local Almost Empty (divided by 2, minus 1) */ +#define PLX_DMATHR_C1PLAE(x) (BIT(28) * ((x) & 0xf)) +#define PLX_DMATHR_C1PLAE_MASK GENMASK(31, 28) +#define PLX_DMATHR_C1PLAE_SHIFT 28 + +/* * Messaging Queue Registers OPLFIS, OPLFIM, IQP, OQP, MQCR, QBAR, IFHPR, * IFTPR, IPHPR, IPTPR, OFHPR, OFTPR, OPHPR, OPTPR, and QSR have been omitted. * They are used by the I2O feature. (IQP and OQP occupy the usual offsets of -- cgit v0.10.2 From 457bec0f73d87dcbab6657c6ba2fce78f1325022 Mon Sep 17 00:00:00 2001 From: Ian Abbott Date: Fri, 20 May 2016 14:49:20 +0100 Subject: staging: comedi: plx9080.h: tidy up some comments Use the usual block comment style and remove some excess spaces from single-line comments. Remove some obvious stuff about register offsets being zero relative. Remove some text about the original history of the file, as it bears hardly any resemblance to it now. Signed-off-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/comedi/drivers/plx9080.h b/drivers/staging/comedi/drivers/plx9080.h index 50d0b1b..d701b15 100644 --- a/drivers/staging/comedi/drivers/plx9080.h +++ b/drivers/staging/comedi/drivers/plx9080.h @@ -3,15 +3,6 @@ * * Copyright (C) 2002,2003 Frank Mori Hess * - * I modified this file from the plx9060.h header for the - * wanXL device driver in the linux kernel, - * for the register offsets and bit definitions. Made minor modifications, - * added plx9080 registers and - * stripped out stuff that was specifically for the wanXL driver. - * Note: I've only made sure the definitions are correct as far - * as I make use of them. There are still various plx9060-isms - * left in this header file. - * ******************************************************************** * * Copyright (C) 1999 RG Studio s.c. @@ -28,7 +19,7 @@ #ifndef __COMEDI_PLX9080_H #define __COMEDI_PLX9080_H -/* descriptor block used for chained dma transfers */ +/* descriptor block used for chained dma transfers */ struct plx_dma_desc { __le32 pci_start_addr; __le32 local_start_addr; @@ -41,13 +32,9 @@ struct plx_dma_desc { __le32 next; }; -/********************************************************************** -** Register Offsets and Bit Definitions -** -** Note: All offsets zero relative. IE. Some standard base address -** must be added to the Register Number to properly access the register. -** -**********************************************************************/ +/* + * Register Offsets and Bit Definitions + */ /* Local Address Space 0 Range Register */ #define PLX_REG_LAS0RR 0x0000 @@ -145,10 +132,11 @@ struct plx_dma_desc { #define PLX_BIGEND_DMA(n) ((n) ? PLX_BIGEND_DMA1 : PLX_BIGEND_DMA0) /* -** Note: The Expansion ROM stuff is only relevant to the PC environment. -** This expansion ROM code is executed by the host CPU at boot time. -** For this reason no bit definitions are provided here. + * Note: The Expansion ROM stuff is only relevant to the PC environment. + * This expansion ROM code is executed by the host CPU at boot time. + * For this reason no bit definitions are provided here. */ + /* Expansion ROM Range Register */ #define PLX_REG_EROMRR 0x0010 /* Expansion ROM Local Base Address (Remap) Register */ @@ -615,12 +603,12 @@ static inline int plx9080_abort_dma(void __iomem *iobase, unsigned int channel) dma_cs_addr = iobase + PLX_REG_DMACSR(channel); - /* abort dma transfer if necessary */ + /* abort dma transfer if necessary */ dma_status = readb(dma_cs_addr); if ((dma_status & PLX_DMACSR_ENABLE) == 0) return 0; - /* wait to make sure done bit is zero */ + /* wait to make sure done bit is zero */ for (i = 0; (dma_status & PLX_DMACSR_DONE) && i < timeout; i++) { udelay(1); dma_status = readb(dma_cs_addr); @@ -628,9 +616,9 @@ static inline int plx9080_abort_dma(void __iomem *iobase, unsigned int channel) if (i == timeout) return -ETIMEDOUT; - /* disable and abort channel */ + /* disable and abort channel */ writeb(PLX_DMACSR_ABORT, dma_cs_addr); - /* wait for dma done bit */ + /* wait for dma done bit */ dma_status = readb(dma_cs_addr); for (i = 0; (dma_status & PLX_DMACSR_DONE) == 0 && i < timeout; i++) { udelay(1); -- cgit v0.10.2 From 6a64877f6318c6db63beb5ae1397c8afc09e8628 Mon Sep 17 00:00:00 2001 From: Ian Abbott Date: Fri, 20 May 2016 14:49:21 +0100 Subject: staging: comedi: plx9080.h: Add kerneldoc comments Document the DMA descriptor `struct plx_dma_desc`, and the DMA abort function `plx9080_abort_dma()`. Signed-off-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/comedi/drivers/plx9080.h b/drivers/staging/comedi/drivers/plx9080.h index d701b15..f67f9d7 100644 --- a/drivers/staging/comedi/drivers/plx9080.h +++ b/drivers/staging/comedi/drivers/plx9080.h @@ -19,16 +19,27 @@ #ifndef __COMEDI_PLX9080_H #define __COMEDI_PLX9080_H -/* descriptor block used for chained dma transfers */ +/** + * struct plx_dma_desc - DMA descriptor format for PLX PCI 9080 + * @pci_start_addr: PCI Bus address for transfer (DMAPADR). + * @local_start_addr: Local Bus address for transfer (DMALADR). + * @transfer_size: Transfer size in bytes (max 8 MiB) (DMASIZ). + * @next: Address of next descriptor + flags (DMADPR). + * + * Describes the format of a scatter-gather DMA descriptor for the PLX + * PCI 9080. All members are raw, little-endian register values that + * will be transferred by the DMA engine from local or PCI memory into + * corresponding registers for the DMA channel. + * + * The DMA descriptors must be aligned on a 16-byte boundary. Bits 3:0 + * of @next contain flags describing the address space of the next + * descriptor (local or PCI), an "end of chain" marker, an "interrupt on + * terminal count" bit, and a data transfer direction. + */ struct plx_dma_desc { __le32 pci_start_addr; __le32 local_start_addr; - /* transfer_size is in bytes, only first 23 bits of register are used */ __le32 transfer_size; - /* - * address of next descriptor (quad word aligned), plus some - * additional bits (see PLX_REG_DMADPR) - */ __le32 next; }; @@ -594,6 +605,18 @@ struct plx_dma_desc { #define PLX_PREFETCH 32 +/** + * plx9080_abort_dma - Abort a PLX PCI 9080 DMA transfer + * @iobase: Remapped base address of configuration registers. + * @channel: DMA channel number (0 or 1). + * + * Aborts the DMA transfer on the channel, which must have been enabled + * and started beforehand. + * + * Return: + * %0 on success. + * -%ETIMEDOUT if timed out waiting for abort to complete. + */ static inline int plx9080_abort_dma(void __iomem *iobase, unsigned int channel) { void __iomem *dma_cs_addr; -- cgit v0.10.2 From 52caeb4ad1f38d6984c9ce456169669fae363cfc Mon Sep 17 00:00:00 2001 From: Ian Abbott Date: Fri, 20 May 2016 14:49:22 +0100 Subject: staging: comedi: plx9080.h: include headers for declarations Add `#include` lines to declare stuff used by "plx9080.h" itself. Signed-off-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/comedi/drivers/plx9080.h b/drivers/staging/comedi/drivers/plx9080.h index f67f9d7..0e20cc5 100644 --- a/drivers/staging/comedi/drivers/plx9080.h +++ b/drivers/staging/comedi/drivers/plx9080.h @@ -19,6 +19,13 @@ #ifndef __COMEDI_PLX9080_H #define __COMEDI_PLX9080_H +#include +#include +#include +#include +#include +#include + /** * struct plx_dma_desc - DMA descriptor format for PLX PCI 9080 * @pci_start_addr: PCI Bus address for transfer (DMAPADR). -- cgit v0.10.2 From 931987a0c6da7404f64e650fa3fd2d5659c61280 Mon Sep 17 00:00:00 2001 From: H Hartley Sweeten Date: Wed, 8 Jun 2016 11:26:38 -0700 Subject: staging: comedi: addi_apci_1564: clarify change-of-state interrupt support This board supports change-of-state interrupts on digital inputs 4 to 19 not 0 to 15. The current code "works" but it could set inappropriate bits in the mode1 and mode2 registers that setup which channels are enabled. It also doesn't return the status of the upper 4 channels (19 to 16). Fix the comment and mask the mode1/mode2 values so that only the interrupt capable channels can be enabled. Add the SDF_LSAMPL flag to the subdevice so that 32-bit samples are used instead of 16-bit ones. This allows returning the upper 4 channels. Use the remaining bits in the sample to return "event" flags to the user. The timer and counter subdevices can also generate interrupts and are a bit hacked. They don't currently follow the comedi API and they use send_sig() to let the task that know that the interrupt occured. The "event" flags will be used instead when these subdevices are fixed. Signed-off-by: H Hartley Sweeten Reviewed-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/comedi/drivers/addi_apci_1564.c b/drivers/staging/comedi/drivers/addi_apci_1564.c index f1ccfbd..9350f59 100644 --- a/drivers/staging/comedi/drivers/addi_apci_1564.c +++ b/drivers/staging/comedi/drivers/addi_apci_1564.c @@ -77,6 +77,7 @@ #define APCI1564_DI_REG 0x00 #define APCI1564_DI_INT_MODE1_REG 0x04 #define APCI1564_DI_INT_MODE2_REG 0x08 +#define APCI1564_DI_INT_MODE_MASK 0x000ffff0 /* chans [19:4] */ #define APCI1564_DI_INT_STATUS_REG 0x0c #define APCI1564_DI_IRQ_REG 0x10 #define APCI1564_DI_IRQ_ENA BIT(2) @@ -111,11 +112,18 @@ */ #define APCI1564_COUNTER(x) ((x) * 0x20) +/* + * The dev->read_subdev is used to return the interrupt events along with + * the state of the interrupt capable inputs. + */ +#define APCI1564_EVENT_COS BIT(31) +#define APCI1564_EVENT_MASK 0xfff0000f /* all but [19:4] */ + struct apci1564_private { unsigned long eeprom; /* base address of EEPROM register */ unsigned long timer; /* base address of 12-bit timer */ unsigned long counters; /* base address of 32-bit counters */ - unsigned int mode1; /* riding-edge/high level channels */ + unsigned int mode1; /* rising-edge/high level channels */ unsigned int mode2; /* falling-edge/low level channels */ unsigned int ctrl; /* interrupt mode OR (edge) . AND (level) */ struct task_struct *tsk_current; @@ -165,18 +173,18 @@ static irqreturn_t apci1564_interrupt(int irq, void *d) unsigned int ctrl; unsigned int chan; + s->state &= ~APCI1564_EVENT_MASK; + status = inl(dev->iobase + APCI1564_DI_IRQ_REG); if (status & APCI1564_DI_IRQ_ENA) { - /* disable the interrupt */ + /* get the COS interrupt state and set the event flag */ + s->state = inl(dev->iobase + APCI1564_DI_INT_STATUS_REG); + s->state &= APCI1564_DI_INT_MODE_MASK; + s->state |= APCI1564_EVENT_COS; + + /* clear the interrupt */ outl(status & ~APCI1564_DI_IRQ_ENA, dev->iobase + APCI1564_DI_IRQ_REG); - - s->state = inl(dev->iobase + APCI1564_DI_INT_STATUS_REG) & - 0xffff; - comedi_buf_write_samples(s, &s->state, 1); - comedi_handle_events(dev, s); - - /* enable the interrupt */ outl(status, dev->iobase + APCI1564_DI_IRQ_REG); } @@ -214,6 +222,11 @@ static irqreturn_t apci1564_interrupt(int irq, void *d) } } + if (s->state & APCI1564_EVENT_MASK) { + comedi_buf_write_samples(s, &s->state, 1); + comedi_handle_events(dev, s); + } + return IRQ_HANDLED; } @@ -255,7 +268,7 @@ static int apci1564_diag_insn_bits(struct comedi_device *dev, /* * Change-Of-State (COS) interrupt configuration * - * Channels 0 to 15 are interruptible. These channels can be configured + * Channels 4 to 19 are interruptible. These channels can be configured * to generate interrupts based on AND/OR logic for the desired channels. * * OR logic @@ -343,6 +356,10 @@ static int apci1564_cos_insn_config(struct comedi_device *dev, default: return -EINVAL; } + + /* ensure the mode bits are in-range for channels [19:4] */ + devpriv->mode1 &= APCI1564_DI_INT_MODE_MASK; + devpriv->mode2 &= APCI1564_DI_INT_MODE_MASK; break; default: return -EINVAL; @@ -409,7 +426,7 @@ static int apci1564_cos_cmd(struct comedi_device *dev, { struct apci1564_private *devpriv = dev->private; - if (!devpriv->ctrl) { + if (!devpriv->ctrl && !(devpriv->mode1 || devpriv->mode2)) { dev_warn(dev->class_dev, "Interrupts disabled due to mode configuration!\n"); return -EINVAL; @@ -501,7 +518,7 @@ static int apci1564_auto_attach(struct comedi_device *dev, if (dev->irq) { dev->read_subdev = s; s->type = COMEDI_SUBD_DI; - s->subdev_flags = SDF_READABLE | SDF_CMD_READ; + s->subdev_flags = SDF_READABLE | SDF_CMD_READ | SDF_LSAMPL; s->n_chan = 1; s->maxdata = 1; s->range_table = &range_digital; -- cgit v0.10.2 From ff9842b651c501a2f13295035c5eb48d4b8e49b3 Mon Sep 17 00:00:00 2001 From: H Hartley Sweeten Date: Wed, 8 Jun 2016 11:26:39 -0700 Subject: staging: comedi: addi_apci_1564: use comedi_handle_event() for timer The timer subdevice can generate an interrupt. Currently send_sig() is used to let the task know when the interrupt occurs. Use the dev->read_subdev and comedi_handle_events() instead. Signed-off-by: H Hartley Sweeten Reviewed-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/comedi/drivers/addi_apci_1564.c b/drivers/staging/comedi/drivers/addi_apci_1564.c index 9350f59..45c1558 100644 --- a/drivers/staging/comedi/drivers/addi_apci_1564.c +++ b/drivers/staging/comedi/drivers/addi_apci_1564.c @@ -117,6 +117,7 @@ * the state of the interrupt capable inputs. */ #define APCI1564_EVENT_COS BIT(31) +#define APCI1564_EVENT_TIMER BIT(30) #define APCI1564_EVENT_MASK 0xfff0000f /* all but [19:4] */ struct apci1564_private { @@ -189,15 +190,12 @@ static irqreturn_t apci1564_interrupt(int irq, void *d) } status = inl(devpriv->timer + ADDI_TCW_IRQ_REG); - if (status & 0x01) { - /* Disable Timer Interrupt */ + if (status & ADDI_TCW_IRQ) { + s->state |= APCI1564_EVENT_TIMER; + + /* clear the interrupt */ ctrl = inl(devpriv->timer + ADDI_TCW_CTRL_REG); outl(0x0, devpriv->timer + ADDI_TCW_CTRL_REG); - - /* Send a signal to from kernel to user space */ - send_sig(SIGIO, devpriv->tsk_current, 0); - - /* Enable Timer Interrupt */ outl(ctrl, devpriv->timer + ADDI_TCW_CTRL_REG); } -- cgit v0.10.2 From a23b85a5ab9f19936ac673104f0e5b57a7ab13a1 Mon Sep 17 00:00:00 2001 From: H Hartley Sweeten Date: Wed, 8 Jun 2016 11:26:40 -0700 Subject: staging: comedi: addi_apci_1564: use comedi_handle_event() for counters The counter subdevice can generate an interrupt. Currently send_sig() is used to let the task know when the interrupt occurs. Use the dev->read_subdev and comedi_handle_events() instead. Remove the, now unused, 'tsk_current' member from the private data and the unnecessary include of . Signed-off-by: H Hartley Sweeten Reviewed-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1564.c b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1564.c index f0c0d58..d6b2880 100644 --- a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1564.c +++ b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1564.c @@ -6,8 +6,6 @@ static int apci1564_timer_insn_config(struct comedi_device *dev, struct apci1564_private *devpriv = dev->private; unsigned int ctrl; - devpriv->tsk_current = current; - /* Stop the timer */ ctrl = inl(devpriv->timer + ADDI_TCW_CTRL_REG); ctrl &= ~(ADDI_TCW_CTRL_GATE | ADDI_TCW_CTRL_TRIG | @@ -101,8 +99,6 @@ static int apci1564_counter_insn_config(struct comedi_device *dev, unsigned long iobase = devpriv->counters + APCI1564_COUNTER(chan); unsigned int ctrl; - devpriv->tsk_current = current; - /* Stop The Timer */ ctrl = inl(iobase + ADDI_TCW_CTRL_REG); ctrl &= ~(ADDI_TCW_CTRL_GATE | ADDI_TCW_CTRL_TRIG | diff --git a/drivers/staging/comedi/drivers/addi_apci_1564.c b/drivers/staging/comedi/drivers/addi_apci_1564.c index 45c1558..4af45d8 100644 --- a/drivers/staging/comedi/drivers/addi_apci_1564.c +++ b/drivers/staging/comedi/drivers/addi_apci_1564.c @@ -23,7 +23,6 @@ #include #include -#include #include "../comedi_pci.h" #include "addi_tcw.h" @@ -118,6 +117,7 @@ */ #define APCI1564_EVENT_COS BIT(31) #define APCI1564_EVENT_TIMER BIT(30) +#define APCI1564_EVENT_COUNTER(x) BIT(27 + (x)) /* counter 0-2 */ #define APCI1564_EVENT_MASK 0xfff0000f /* all but [19:4] */ struct apci1564_private { @@ -127,7 +127,6 @@ struct apci1564_private { unsigned int mode1; /* rising-edge/high level channels */ unsigned int mode2; /* falling-edge/low level channels */ unsigned int ctrl; /* interrupt mode OR (edge) . AND (level) */ - struct task_struct *tsk_current; }; #include "addi-data/hwdrv_apci1564.c" @@ -200,21 +199,18 @@ static irqreturn_t apci1564_interrupt(int irq, void *d) } if (devpriv->counters) { - for (chan = 0; chan < 4; chan++) { + for (chan = 0; chan < 3; chan++) { unsigned long iobase; iobase = devpriv->counters + APCI1564_COUNTER(chan); status = inl(iobase + ADDI_TCW_IRQ_REG); - if (status & 0x01) { - /* Disable Counter Interrupt */ + if (status & ADDI_TCW_IRQ) { + s->state |= APCI1564_EVENT_COUNTER(chan); + + /* clear the interrupt */ ctrl = inl(iobase + ADDI_TCW_CTRL_REG); outl(0x0, iobase + ADDI_TCW_CTRL_REG); - - /* Send a signal to from kernel to user space */ - send_sig(SIGIO, devpriv->tsk_current, 0); - - /* Enable Counter Interrupt */ outl(ctrl, iobase + ADDI_TCW_CTRL_REG); } } -- cgit v0.10.2 From 05704ffafaea7b5176b4469d48487c86cba4861b Mon Sep 17 00:00:00 2001 From: H Hartley Sweeten Date: Wed, 8 Jun 2016 11:26:41 -0700 Subject: staging: comedi: addi_apci_1564: rewrite the timer subdevice support The support functions for the timer subdevice are broken. 1) The (*insn_write) assumes that insn->n is always 2 (data[1] is used) 2) The (*insn_read) assumes that insn->n is always 2 (data can be returned in data[0] and data[1]). 3) The (*insn_config) does not follow the API. It assumes insn->n is always 4 (data[1], data[2] and data[3] are used). It also doesn't use data[0] to determine what the config "instruction" is. Rewrite the code to follow the comedi API and add the missing comedi driver comment block. The new implementation is based on the (minimal) datasheet I have from ADDI-DATA. Signed-off-by: H Hartley Sweeten Reviewed-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1564.c b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1564.c index d6b2880..a1df66d 100644 --- a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1564.c +++ b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1564.c @@ -1,94 +1,3 @@ -static int apci1564_timer_insn_config(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) -{ - struct apci1564_private *devpriv = dev->private; - unsigned int ctrl; - - /* Stop the timer */ - ctrl = inl(devpriv->timer + ADDI_TCW_CTRL_REG); - ctrl &= ~(ADDI_TCW_CTRL_GATE | ADDI_TCW_CTRL_TRIG | - ADDI_TCW_CTRL_ENA); - outl(ctrl, devpriv->timer + ADDI_TCW_CTRL_REG); - - if (data[1] == 1) { - /* Enable timer int & disable all the other int sources */ - outl(ADDI_TCW_CTRL_IRQ_ENA, - devpriv->timer + ADDI_TCW_CTRL_REG); - outl(0x0, dev->iobase + APCI1564_DI_IRQ_REG); - outl(0x0, dev->iobase + APCI1564_DO_IRQ_REG); - outl(0x0, dev->iobase + APCI1564_WDOG_IRQ_REG); - if (devpriv->counters) { - unsigned long iobase; - - iobase = devpriv->counters + ADDI_TCW_IRQ_REG; - outl(0x0, iobase + APCI1564_COUNTER(0)); - outl(0x0, iobase + APCI1564_COUNTER(1)); - outl(0x0, iobase + APCI1564_COUNTER(2)); - } - } else { - /* disable Timer interrupt */ - outl(0x0, devpriv->timer + ADDI_TCW_CTRL_REG); - } - - /* Loading Timebase */ - outl(data[2], devpriv->timer + ADDI_TCW_TIMEBASE_REG); - - /* Loading the Reload value */ - outl(data[3], devpriv->timer + ADDI_TCW_RELOAD_REG); - - ctrl = inl(devpriv->timer + ADDI_TCW_CTRL_REG); - ctrl &= ~(ADDI_TCW_CTRL_CNTR_ENA | ADDI_TCW_CTRL_MODE_MASK | - ADDI_TCW_CTRL_GATE | ADDI_TCW_CTRL_TRIG | - ADDI_TCW_CTRL_TIMER_ENA | ADDI_TCW_CTRL_RESET_ENA | - ADDI_TCW_CTRL_WARN_ENA | ADDI_TCW_CTRL_ENA); - ctrl |= ADDI_TCW_CTRL_MODE(2) | ADDI_TCW_CTRL_TIMER_ENA; - outl(ctrl, devpriv->timer + ADDI_TCW_CTRL_REG); - - return insn->n; -} - -static int apci1564_timer_insn_write(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) -{ - struct apci1564_private *devpriv = dev->private; - unsigned int ctrl; - - ctrl = inl(devpriv->timer + ADDI_TCW_CTRL_REG); - ctrl &= ~(ADDI_TCW_CTRL_GATE | ADDI_TCW_CTRL_TRIG); - switch (data[1]) { - case 0: /* Stop The Timer */ - ctrl &= ~ADDI_TCW_CTRL_ENA; - break; - case 1: /* Enable the Timer */ - ctrl |= ADDI_TCW_CTRL_ENA; - break; - } - outl(ctrl, devpriv->timer + ADDI_TCW_CTRL_REG); - - return insn->n; -} - -static int apci1564_timer_insn_read(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) -{ - struct apci1564_private *devpriv = dev->private; - - /* Stores the status of the Timer */ - data[0] = inl(devpriv->timer + ADDI_TCW_STATUS_REG) & - ADDI_TCW_STATUS_OVERFLOW; - - /* Stores the Actual value of the Timer */ - data[1] = inl(devpriv->timer + ADDI_TCW_VAL_REG); - - return insn->n; -} - static int apci1564_counter_insn_config(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, diff --git a/drivers/staging/comedi/drivers/addi_apci_1564.c b/drivers/staging/comedi/drivers/addi_apci_1564.c index 4af45d8..3e8ac67 100644 --- a/drivers/staging/comedi/drivers/addi_apci_1564.c +++ b/drivers/staging/comedi/drivers/addi_apci_1564.c @@ -21,6 +21,54 @@ * details. */ +/* + * Driver: addi_apci_1564 + * Description: ADDI-DATA APCI-1564 Digital I/O board + * Devices: [ADDI-DATA] APCI-1564 (addi_apci_1564) + * Author: H Hartley Sweeten + * Updated: Thu, 02 Jun 2016 13:12:46 -0700 + * Status: untested + * + * Configuration Options: not applicable, uses comedi PCI auto config + * + * This board has the following features: + * - 32 optically isolated digital inputs (24V), 16 of which can + * generate change-of-state (COS) interrupts (channels 4 to 19) + * - 32 optically isolated digital outputs (10V to 36V) + * - 1 8-bit watchdog for resetting the outputs + * - 1 12-bit timer + * - 3 32-bit counters + * - 2 diagnostic inputs + * + * The COS, timer, and counter subdevices all use the dev->read_subdev to + * return the interrupt status. The sample data is updated and returned when + * any of these subdevices generate an interrupt. The sample data format is: + * + * Bit Description + * ----- ------------------------------------------ + * 31 COS interrupt + * 30 timer interrupt + * 29 counter 2 interrupt + * 28 counter 1 interrupt + * 27 counter 0 interrupt + * 26:20 not used + * 19:4 COS digital input state (channels 19 to 4) + * 3:0 not used + * + * The COS interrupts must be configured using an INSN_CONFIG_DIGITAL_TRIG + * instruction before they can be enabled by an async command. The COS + * interrupts will stay active until canceled. + * + * The timer subdevice does not use an async command. All control is handled + * by the (*insn_config). + * + * FIXME: The format of the ADDI_TCW_TIMEBASE_REG is not descibed in the + * datasheet I have. The INSN_CONFIG_SET_CLOCK_SRC currently just writes + * the raw data[1] to this register along with the raw data[2] value to the + * ADDI_TCW_RELOAD_REG. If anyone tests this and can determine the actual + * timebase/reload operation please let me know. + */ + #include #include @@ -444,6 +492,87 @@ static int apci1564_cos_cancel(struct comedi_device *dev, return 0; } +static int apci1564_timer_insn_config(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + struct apci1564_private *devpriv = dev->private; + unsigned int val; + + switch (data[0]) { + case INSN_CONFIG_ARM: + if (data[1] > s->maxdata) + return -EINVAL; + outl(data[1], devpriv->timer + ADDI_TCW_RELOAD_REG); + outl(ADDI_TCW_CTRL_IRQ_ENA | ADDI_TCW_CTRL_TIMER_ENA, + devpriv->timer + ADDI_TCW_CTRL_REG); + break; + case INSN_CONFIG_DISARM: + outl(0x0, devpriv->timer + ADDI_TCW_CTRL_REG); + break; + case INSN_CONFIG_GET_COUNTER_STATUS: + data[1] = 0; + val = inl(devpriv->timer + ADDI_TCW_CTRL_REG); + if (val & ADDI_TCW_CTRL_IRQ_ENA) + data[1] |= COMEDI_COUNTER_ARMED; + if (val & ADDI_TCW_CTRL_TIMER_ENA) + data[1] |= COMEDI_COUNTER_COUNTING; + val = inl(devpriv->timer + ADDI_TCW_STATUS_REG); + if (val & ADDI_TCW_STATUS_OVERFLOW) + data[1] |= COMEDI_COUNTER_TERMINAL_COUNT; + data[2] = COMEDI_COUNTER_ARMED | COMEDI_COUNTER_COUNTING | + COMEDI_COUNTER_TERMINAL_COUNT; + break; + case INSN_CONFIG_SET_CLOCK_SRC: + if (data[2] > s->maxdata) + return -EINVAL; + outl(data[1], devpriv->timer + ADDI_TCW_TIMEBASE_REG); + outl(data[2], devpriv->timer + ADDI_TCW_RELOAD_REG); + break; + case INSN_CONFIG_GET_CLOCK_SRC: + data[1] = inl(devpriv->timer + ADDI_TCW_TIMEBASE_REG); + data[2] = inl(devpriv->timer + ADDI_TCW_RELOAD_REG); + break; + default: + return -EINVAL; + } + + return insn->n; +} + +static int apci1564_timer_insn_write(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + struct apci1564_private *devpriv = dev->private; + + /* just write the last last to the reload register */ + if (insn->n) { + unsigned int val = data[insn->n - 1]; + + outl(val, devpriv->timer + ADDI_TCW_RELOAD_REG); + } + + return insn->n; +} + +static int apci1564_timer_insn_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + struct apci1564_private *devpriv = dev->private; + int i; + + /* return the actual value of the timer */ + for (i = 0; i < insn->n; i++) + data[i] = inl(devpriv->timer + ADDI_TCW_VAL_REG); + + return insn->n; +} + static int apci1564_auto_attach(struct comedi_device *dev, unsigned long context_unused) { -- cgit v0.10.2 From 2ec19efbc8d4c5646b8205564678568fa26e4b32 Mon Sep 17 00:00:00 2001 From: H Hartley Sweeten Date: Wed, 8 Jun 2016 11:26:42 -0700 Subject: staging: comedi: addi_apci_1564: rewrite the counter subdevice support Like the timer, the support functions for the counter subdevice are broken. Rewrite the code to follow the comedi API. The new implementation is based on the (minimal) datasheet I have from ADDI-DATA. Signed-off-by: H Hartley Sweeten Reviewed-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1564.c b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1564.c deleted file mode 100644 index a1df66d..0000000 --- a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1564.c +++ /dev/null @@ -1,92 +0,0 @@ -static int apci1564_counter_insn_config(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) -{ - struct apci1564_private *devpriv = dev->private; - unsigned int chan = CR_CHAN(insn->chanspec); - unsigned long iobase = devpriv->counters + APCI1564_COUNTER(chan); - unsigned int ctrl; - - /* Stop The Timer */ - ctrl = inl(iobase + ADDI_TCW_CTRL_REG); - ctrl &= ~(ADDI_TCW_CTRL_GATE | ADDI_TCW_CTRL_TRIG | - ADDI_TCW_CTRL_ENA); - outl(ctrl, iobase + ADDI_TCW_CTRL_REG); - - /* Set the reload value */ - outl(data[3], iobase + ADDI_TCW_RELOAD_REG); - - /* Set the mode */ - ctrl &= ~(ADDI_TCW_CTRL_EXT_CLK_MASK | ADDI_TCW_CTRL_MODE_MASK | - ADDI_TCW_CTRL_TIMER_ENA | ADDI_TCW_CTRL_RESET_ENA | - ADDI_TCW_CTRL_WARN_ENA); - ctrl |= ADDI_TCW_CTRL_CNTR_ENA | ADDI_TCW_CTRL_MODE(data[4]); - outl(ctrl, iobase + ADDI_TCW_CTRL_REG); - - /* Enable or Disable Interrupt */ - if (data[1]) - ctrl |= ADDI_TCW_CTRL_IRQ_ENA; - else - ctrl &= ~ADDI_TCW_CTRL_IRQ_ENA; - outl(ctrl, iobase + ADDI_TCW_CTRL_REG); - - /* Set the Up/Down selection */ - if (data[6]) - ctrl |= ADDI_TCW_CTRL_CNT_UP; - else - ctrl &= ~ADDI_TCW_CTRL_CNT_UP; - outl(ctrl, iobase + ADDI_TCW_CTRL_REG); - - return insn->n; -} - -static int apci1564_counter_insn_write(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) -{ - struct apci1564_private *devpriv = dev->private; - unsigned int chan = CR_CHAN(insn->chanspec); - unsigned long iobase = devpriv->counters + APCI1564_COUNTER(chan); - unsigned int ctrl; - - ctrl = inl(iobase + ADDI_TCW_CTRL_REG); - ctrl &= ~(ADDI_TCW_CTRL_GATE | ADDI_TCW_CTRL_TRIG); - switch (data[1]) { - case 0: /* Stops the Counter subdevice */ - ctrl = 0; - break; - case 1: /* Start the Counter subdevice */ - ctrl |= ADDI_TCW_CTRL_ENA; - break; - case 2: /* Clears the Counter subdevice */ - ctrl |= ADDI_TCW_CTRL_GATE; - break; - } - outl(ctrl, iobase + ADDI_TCW_CTRL_REG); - - return insn->n; -} - -static int apci1564_counter_insn_read(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) -{ - struct apci1564_private *devpriv = dev->private; - unsigned int chan = CR_CHAN(insn->chanspec); - unsigned long iobase = devpriv->counters + APCI1564_COUNTER(chan); - unsigned int status; - - /* Read the Counter Actual Value. */ - data[0] = inl(iobase + ADDI_TCW_VAL_REG); - - status = inl(iobase + ADDI_TCW_STATUS_REG); - data[1] = (status & ADDI_TCW_STATUS_SOFT_TRIG) ? 1 : 0; - data[2] = (status & ADDI_TCW_STATUS_HARDWARE_TRIG) ? 1 : 0; - data[3] = (status & ADDI_TCW_STATUS_SOFT_CLR) ? 1 : 0; - data[4] = (status & ADDI_TCW_STATUS_OVERFLOW) ? 1 : 0; - - return insn->n; -} diff --git a/drivers/staging/comedi/drivers/addi_apci_1564.c b/drivers/staging/comedi/drivers/addi_apci_1564.c index 3e8ac67..5813de5 100644 --- a/drivers/staging/comedi/drivers/addi_apci_1564.c +++ b/drivers/staging/comedi/drivers/addi_apci_1564.c @@ -67,6 +67,12 @@ * the raw data[1] to this register along with the raw data[2] value to the * ADDI_TCW_RELOAD_REG. If anyone tests this and can determine the actual * timebase/reload operation please let me know. + * + * The counter subdevice also does not use an async command. All control is + * handled by the (*insn_config). + * + * FIXME: The operation of the counters is not really described in the + * datasheet I have. The (*insn_config) needs more work. */ #include @@ -177,8 +183,6 @@ struct apci1564_private { unsigned int ctrl; /* interrupt mode OR (edge) . AND (level) */ }; -#include "addi-data/hwdrv_apci1564.c" - static int apci1564_reset(struct comedi_device *dev) { struct apci1564_private *devpriv = dev->private; @@ -573,6 +577,92 @@ static int apci1564_timer_insn_read(struct comedi_device *dev, return insn->n; } +static int apci1564_counter_insn_config(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + struct apci1564_private *devpriv = dev->private; + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned long iobase = devpriv->counters + APCI1564_COUNTER(chan); + unsigned int val; + + switch (data[0]) { + case INSN_CONFIG_ARM: + val = inl(iobase + ADDI_TCW_CTRL_REG); + val |= ADDI_TCW_CTRL_IRQ_ENA | ADDI_TCW_CTRL_CNTR_ENA; + outl(data[1], iobase + ADDI_TCW_RELOAD_REG); + outl(val, iobase + ADDI_TCW_CTRL_REG); + break; + case INSN_CONFIG_DISARM: + val = inl(iobase + ADDI_TCW_CTRL_REG); + val &= ~(ADDI_TCW_CTRL_IRQ_ENA | ADDI_TCW_CTRL_CNTR_ENA); + outl(val, iobase + ADDI_TCW_CTRL_REG); + break; + case INSN_CONFIG_SET_COUNTER_MODE: + /* + * FIXME: The counter operation is not described in the + * datasheet. For now just write the raw data[1] value to + * the control register. + */ + outl(data[1], iobase + ADDI_TCW_CTRL_REG); + break; + case INSN_CONFIG_GET_COUNTER_STATUS: + data[1] = 0; + val = inl(iobase + ADDI_TCW_CTRL_REG); + if (val & ADDI_TCW_CTRL_IRQ_ENA) + data[1] |= COMEDI_COUNTER_ARMED; + if (val & ADDI_TCW_CTRL_CNTR_ENA) + data[1] |= COMEDI_COUNTER_COUNTING; + val = inl(iobase + ADDI_TCW_STATUS_REG); + if (val & ADDI_TCW_STATUS_OVERFLOW) + data[1] |= COMEDI_COUNTER_TERMINAL_COUNT; + data[2] = COMEDI_COUNTER_ARMED | COMEDI_COUNTER_COUNTING | + COMEDI_COUNTER_TERMINAL_COUNT; + break; + default: + return -EINVAL; + } + + return insn->n; +} + +static int apci1564_counter_insn_write(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + struct apci1564_private *devpriv = dev->private; + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned long iobase = devpriv->counters + APCI1564_COUNTER(chan); + + /* just write the last last to the reload register */ + if (insn->n) { + unsigned int val = data[insn->n - 1]; + + outl(val, iobase + ADDI_TCW_RELOAD_REG); + } + + return insn->n; +} + +static int apci1564_counter_insn_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + struct apci1564_private *devpriv = dev->private; + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned long iobase = devpriv->counters + APCI1564_COUNTER(chan); + int i; + + /* return the actual value of the counter */ + for (i = 0; i < insn->n; i++) + data[i] = inl(iobase + ADDI_TCW_VAL_REG); + + return insn->n; +} + static int apci1564_auto_attach(struct comedi_device *dev, unsigned long context_unused) { -- cgit v0.10.2 From 20cefae2d278a056417c24315d0b0cd8d3e97c9a Mon Sep 17 00:00:00 2001 From: H Hartley Sweeten Date: Wed, 8 Jun 2016 11:26:43 -0700 Subject: staging: comedi: addi_apci_1564: remove unnecessary wdog register defines The watchdog subdevice is supported using the addi_watchdog module and it uses the register defines from addi_tcw.h. The only register define needed it the iobase offset to the register block. Remove the unnecessary defines and rename the iobase define. Signed-off-by: H Hartley Sweeten Reviewed-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/comedi/drivers/addi_apci_1564.c b/drivers/staging/comedi/drivers/addi_apci_1564.c index 5813de5..9bfb79c 100644 --- a/drivers/staging/comedi/drivers/addi_apci_1564.c +++ b/drivers/staging/comedi/drivers/addi_apci_1564.c @@ -144,14 +144,7 @@ #define APCI1564_DO_INT_STATUS_VCC BIT(0) #define APCI1564_DO_IRQ_REG 0x20 #define APCI1564_DO_IRQ_INTR BIT(0) -#define APCI1564_WDOG_REG 0x24 -#define APCI1564_WDOG_RELOAD_REG 0x28 -#define APCI1564_WDOG_TIMEBASE_REG 0x2c -#define APCI1564_WDOG_CTRL_REG 0x30 -#define APCI1564_WDOG_STATUS_REG 0x34 -#define APCI1564_WDOG_IRQ_REG 0x38 -#define APCI1564_WDOG_WARN_TIMEVAL_REG 0x3c -#define APCI1564_WDOG_WARN_TIMEBASE_REG 0x40 +#define APCI1564_WDOG_IOBASE 0x24 /* * devpriv->timer Register Map (see addi_tcw.h for register/bit defines) @@ -198,7 +191,7 @@ static int apci1564_reset(struct comedi_device *dev) outl(0x0, dev->iobase + APCI1564_DO_INT_CTRL_REG); /* Reset the watchdog registers */ - addi_watchdog_reset(dev->iobase + APCI1564_WDOG_REG); + addi_watchdog_reset(dev->iobase + APCI1564_WDOG_IOBASE); /* Reset the timer registers */ outl(0x0, devpriv->timer + ADDI_TCW_CTRL_REG); @@ -773,7 +766,7 @@ static int apci1564_auto_attach(struct comedi_device *dev, /* Initialize the watchdog subdevice */ s = &dev->subdevices[5]; - ret = addi_watchdog_init(s, dev->iobase + APCI1564_WDOG_REG); + ret = addi_watchdog_init(s, dev->iobase + APCI1564_WDOG_IOBASE); if (ret) return ret; -- cgit v0.10.2 From 6f594b82038d0f9d72f8a6dce1a72e3c88d9961a Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Sat, 4 Jun 2016 06:35:20 +0100 Subject: staging: comedi: adl_pci9118: fix spelling mistake "acqusition" -> "acquisition" trivial fix to spelling mistake Signed-off-by: Colin Ian King Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/comedi/drivers/adl_pci9118.c b/drivers/staging/comedi/drivers/adl_pci9118.c index 4437ea3..be70bd3 100644 --- a/drivers/staging/comedi/drivers/adl_pci9118.c +++ b/drivers/staging/comedi/drivers/adl_pci9118.c @@ -570,7 +570,7 @@ static int pci9118_ai_cancel(struct comedi_device *dev, /* set default config (disable burst and triggers) */ devpriv->ai_cfg = PCI9118_AI_CFG_PDTRG | PCI9118_AI_CFG_PETRG; outl(devpriv->ai_cfg, dev->iobase + PCI9118_AI_CFG_REG); - /* reset acqusition control */ + /* reset acquisition control */ devpriv->ai_ctrl = 0; outl(devpriv->ai_ctrl, dev->iobase + PCI9118_AI_CTRL_REG); outl(0, dev->iobase + PCI9118_AI_BURST_NUM_REG); @@ -1022,12 +1022,12 @@ static int pci9118_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) /* * Configure analog input and load the chanlist. - * The acqusition control bits are enabled later. + * The acquisition control bits are enabled later. */ pci9118_set_chanlist(dev, s, cmd->chanlist_len, cmd->chanlist, devpriv->ai_add_front, devpriv->ai_add_back); - /* Determine acqusition mode and calculate timing */ + /* Determine acquisition mode and calculate timing */ devpriv->ai_do = 0; if (cmd->scan_begin_src != TRIG_TIMER && cmd->convert_src == TRIG_TIMER) { @@ -1097,7 +1097,7 @@ static int pci9118_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) if (devpriv->ai_do == 0) { dev_err(dev->class_dev, - "Unable to determine acqusition mode! BUG in (*do_cmdtest)?\n"); + "Unable to determine acquisition mode! BUG in (*do_cmdtest)?\n"); return -EINVAL; } -- cgit v0.10.2 From 45de2688191fb276fee4cd6bc35805e20e484e41 Mon Sep 17 00:00:00 2001 From: Ravishankar Karkala Mallikarjunayya Date: Mon, 6 Jun 2016 16:31:15 +0530 Subject: Staging: comedi: Indentation issue in mpc624.c This is a patch to the mpc624.c file that fixes up a WARNING: 'Statements should start on a tabstop' found by the checkpatch.pl tool. Signed-off-by: Ravishankar Karkala Mallikarjunayya Reviewed-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/comedi/drivers/mpc624.c b/drivers/staging/comedi/drivers/mpc624.c index 826e439..9bda761 100644 --- a/drivers/staging/comedi/drivers/mpc624.c +++ b/drivers/staging/comedi/drivers/mpc624.c @@ -103,7 +103,7 @@ static const struct comedi_lrange range_mpc624_bipolar1 = { /* BIP_RANGE(1.01) this is correct, */ /* but my MPC-624 actually seems to have a range of 2.02 */ BIP_RANGE(2.02) - } + } }; static const struct comedi_lrange range_mpc624_bipolar10 = { @@ -112,7 +112,7 @@ static const struct comedi_lrange range_mpc624_bipolar10 = { /* BIP_RANGE(10.1) this is correct, */ /* but my MPC-624 actually seems to have a range of 20.2 */ BIP_RANGE(20.2) - } + } }; static unsigned int mpc624_ai_get_sample(struct comedi_device *dev, -- cgit v0.10.2 From e31eae76185cb4f86e5edf4f1f26b728863ded6b Mon Sep 17 00:00:00 2001 From: Ravishankar Karkala Mallikarjunayya Date: Mon, 6 Jun 2016 16:31:16 +0530 Subject: Staging: comedi:Fix a warning issues in me_daq.c This is a patch to the me_daq.c file that fixes up a WARNING: Prefer 'unsigned int' to bare use of 'unsigned' found by the checkpatch.pl tool. Signed-off-by: Ravishankar Karkala Mallikarjunayya Reviewed-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/comedi/drivers/me_daq.c b/drivers/staging/comedi/drivers/me_daq.c index 3bf0caa..c0b7a30 100644 --- a/drivers/staging/comedi/drivers/me_daq.c +++ b/drivers/staging/comedi/drivers/me_daq.c @@ -150,7 +150,7 @@ struct me_private_data { unsigned short dac_ctrl; /* Mirror of the DAC_CONTROL register */ }; -static inline void sleep(unsigned sec) +static inline void sleep(unsigned int sec) { schedule_timeout_interruptible(sec * HZ); } -- cgit v0.10.2 From fb999e7fab6cdf6dee6df087159a0acc2f3b236b Mon Sep 17 00:00:00 2001 From: Ravishankar Karkala Mallikarjunayya Date: Mon, 6 Jun 2016 16:31:17 +0530 Subject: Staging: comedi: Fix comment issues in jr3_pci.c This is a patch to the jr3_pci.c file that fixes up a WARNING: 'Block comments use a trailing */ on a separate line' found by the checkpatch.pl tool. Signed-off-by: Ravishankar Karkala Mallikarjunayya Reviewed-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/comedi/drivers/jr3_pci.c b/drivers/staging/comedi/drivers/jr3_pci.c index b87192e..fa0d4b1 100644 --- a/drivers/staging/comedi/drivers/jr3_pci.c +++ b/drivers/staging/comedi/drivers/jr3_pci.c @@ -1,20 +1,20 @@ /* - comedi/drivers/jr3_pci.c - hardware driver for JR3/PCI force sensor board - - COMEDI - Linux Control and Measurement Device Interface - Copyright (C) 2007 Anders Blomdell - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. -*/ + * comedi/drivers/jr3_pci.c + * hardware driver for JR3/PCI force sensor board + * + * COMEDI - Linux Control and Measurement Device Interface + * Copyright (C) 2007 Anders Blomdell + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ /* * Driver: jr3_pci * Description: JR3/PCI force sensor board -- cgit v0.10.2 From 86c7815e9773bab44d244428d083a43e5a6f7aca Mon Sep 17 00:00:00 2001 From: Ravishankar Karkala Mallikarjunayya Date: Mon, 6 Jun 2016 16:31:18 +0530 Subject: Staging: comedi: Prefer using the BIT macro issue in das16.c This patch Replace all occurences of (1< Reviewed-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/comedi/drivers/das16.c b/drivers/staging/comedi/drivers/das16.c index fd8e0b7..69133e3 100644 --- a/drivers/staging/comedi/drivers/das16.c +++ b/drivers/staging/comedi/drivers/das16.c @@ -92,37 +92,37 @@ #define DAS16_AO_LSB_REG(x) ((x) ? 0x06 : 0x04) #define DAS16_AO_MSB_REG(x) ((x) ? 0x07 : 0x05) #define DAS16_STATUS_REG 0x08 -#define DAS16_STATUS_BUSY (1 << 7) -#define DAS16_STATUS_UNIPOLAR (1 << 6) -#define DAS16_STATUS_MUXBIT (1 << 5) -#define DAS16_STATUS_INT (1 << 4) +#define DAS16_STATUS_BUSY BIT(7) +#define DAS16_STATUS_UNIPOLAR BIT(6) +#define DAS16_STATUS_MUXBIT BIT(5) +#define DAS16_STATUS_INT BIT(4) #define DAS16_CTRL_REG 0x09 -#define DAS16_CTRL_INTE (1 << 7) +#define DAS16_CTRL_INTE BIT(7) #define DAS16_CTRL_IRQ(x) (((x) & 0x7) << 4) -#define DAS16_CTRL_DMAE (1 << 2) +#define DAS16_CTRL_DMAE BIT(2) #define DAS16_CTRL_PACING_MASK (3 << 0) #define DAS16_CTRL_INT_PACER (3 << 0) #define DAS16_CTRL_EXT_PACER (2 << 0) #define DAS16_CTRL_SOFT_PACER (0 << 0) #define DAS16_PACER_REG 0x0a #define DAS16_PACER_BURST_LEN(x) (((x) & 0xf) << 4) -#define DAS16_PACER_CTR0 (1 << 1) -#define DAS16_PACER_TRIG0 (1 << 0) +#define DAS16_PACER_CTR0 BIT(1) +#define DAS16_PACER_TRIG0 BIT(0) #define DAS16_GAIN_REG 0x0b #define DAS16_TIMER_BASE_REG 0x0c /* to 0x0f */ #define DAS1600_CONV_REG 0x404 -#define DAS1600_CONV_DISABLE (1 << 6) +#define DAS1600_CONV_DISABLE BIT(6) #define DAS1600_BURST_REG 0x405 -#define DAS1600_BURST_VAL (1 << 6) +#define DAS1600_BURST_VAL BIT(6) #define DAS1600_ENABLE_REG 0x406 -#define DAS1600_ENABLE_VAL (1 << 6) +#define DAS1600_ENABLE_VAL BIT(6) #define DAS1600_STATUS_REG 0x407 -#define DAS1600_STATUS_BME (1 << 6) -#define DAS1600_STATUS_ME (1 << 5) -#define DAS1600_STATUS_CD (1 << 4) -#define DAS1600_STATUS_WS (1 << 1) -#define DAS1600_STATUS_CLK_10MHZ (1 << 0) +#define DAS1600_STATUS_BME BIT(6) +#define DAS1600_STATUS_ME BIT(5) +#define DAS1600_STATUS_CD BIT(4) +#define DAS1600_STATUS_WS BIT(1) +#define DAS1600_STATUS_CLK_10MHZ BIT(0) static const struct comedi_lrange range_das1x01_bip = { 4, { -- cgit v0.10.2 From 2c81ab4304d2b09bd4e1cde34b045a16d907974b Mon Sep 17 00:00:00 2001 From: Ravishankar Karkala Mallikarjunayya Date: Mon, 6 Jun 2016 16:31:20 +0530 Subject: Staging: comedi: fix BIT macro issue in das6402.c This patch Replace all occurences of (1< Reviewed-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/comedi/drivers/das6402.c b/drivers/staging/comedi/drivers/das6402.c index 1701294..0fdf5e0 100644 --- a/drivers/staging/comedi/drivers/das6402.c +++ b/drivers/staging/comedi/drivers/das6402.c @@ -50,48 +50,50 @@ #define DAS6402_AO_LSB_REG(x) (0x04 + ((x) * 2)) #define DAS6402_AO_MSB_REG(x) (0x05 + ((x) * 2)) #define DAS6402_STATUS_REG 0x08 -#define DAS6402_STATUS_FFNE (1 << 0) -#define DAS6402_STATUS_FHALF (1 << 1) -#define DAS6402_STATUS_FFULL (1 << 2) -#define DAS6402_STATUS_XINT (1 << 3) -#define DAS6402_STATUS_INT (1 << 4) -#define DAS6402_STATUS_XTRIG (1 << 5) -#define DAS6402_STATUS_INDGT (1 << 6) -#define DAS6402_STATUS_10MHZ (1 << 7) -#define DAS6402_STATUS_W_CLRINT (1 << 0) -#define DAS6402_STATUS_W_CLRXTR (1 << 1) -#define DAS6402_STATUS_W_CLRXIN (1 << 2) -#define DAS6402_STATUS_W_EXTEND (1 << 4) -#define DAS6402_STATUS_W_ARMED (1 << 5) -#define DAS6402_STATUS_W_POSTMODE (1 << 6) -#define DAS6402_STATUS_W_10MHZ (1 << 7) +#define DAS6402_STATUS_FFNE BIT(0) +#define DAS6402_STATUS_FHALF BIT(1) +#define DAS6402_STATUS_FFULL BIT(2) +#define DAS6402_STATUS_XINT BIT(3) +#define DAS6402_STATUS_INT BIT(4) +#define DAS6402_STATUS_XTRIG BIT(5) +#define DAS6402_STATUS_INDGT BIT(6) +#define DAS6402_STATUS_10MHZ BIT(7) +#define DAS6402_STATUS_W_CLRINT BIT(0) +#define DAS6402_STATUS_W_CLRXTR BIT(1) +#define DAS6402_STATUS_W_CLRXIN BIT(2) +#define DAS6402_STATUS_W_EXTEND BIT(4) +#define DAS6402_STATUS_W_ARMED BIT(5) +#define DAS6402_STATUS_W_POSTMODE BIT(6) +#define DAS6402_STATUS_W_10MHZ BIT(7) #define DAS6402_CTRL_REG 0x09 -#define DAS6402_CTRL_SOFT_TRIG (0 << 0) -#define DAS6402_CTRL_EXT_FALL_TRIG (1 << 0) -#define DAS6402_CTRL_EXT_RISE_TRIG (2 << 0) -#define DAS6402_CTRL_PACER_TRIG (3 << 0) -#define DAS6402_CTRL_BURSTEN (1 << 2) -#define DAS6402_CTRL_XINTE (1 << 3) +#define DAS6402_CTRL_TRIG(x) ((x) << 0) +#define DAS6402_CTRL_SOFT_TRIG DAS6402_CTRL_TRIG(0) +#define DAS6402_CTRL_EXT_FALL_TRIG DAS6402_CTRL_TRIG(1) +#define DAS6402_CTRL_EXT_RISE_TRIG DAS6402_CTRL_TRIG(2) +#define DAS6402_CTRL_PACER_TRIG DAS6402_CTRL_TRIG(3) +#define DAS6402_CTRL_BURSTEN BIT(2) +#define DAS6402_CTRL_XINTE BIT(3) #define DAS6402_CTRL_IRQ(x) ((x) << 4) -#define DAS6402_CTRL_INTE (1 << 7) +#define DAS6402_CTRL_INTE BIT(7) #define DAS6402_TRIG_REG 0x0a -#define DAS6402_TRIG_TGEN (1 << 0) -#define DAS6402_TRIG_TGSEL (1 << 1) -#define DAS6402_TRIG_TGPOL (1 << 2) -#define DAS6402_TRIG_PRETRIG (1 << 3) +#define DAS6402_TRIG_TGEN BIT(0) +#define DAS6402_TRIG_TGSEL BIT(1) +#define DAS6402_TRIG_TGPOL BIT(2) +#define DAS6402_TRIG_PRETRIG BIT(3) #define DAS6402_AO_RANGE(_chan, _range) ((_range) << ((_chan) ? 6 : 4)) #define DAS6402_AO_RANGE_MASK(_chan) (3 << ((_chan) ? 6 : 4)) #define DAS6402_MODE_REG 0x0b -#define DAS6402_MODE_RANGE(x) ((x) << 0) -#define DAS6402_MODE_POLLED (0 << 2) -#define DAS6402_MODE_FIFONEPTY (1 << 2) -#define DAS6402_MODE_FIFOHFULL (2 << 2) -#define DAS6402_MODE_EOB (3 << 2) -#define DAS6402_MODE_ENHANCED (1 << 4) -#define DAS6402_MODE_SE (1 << 5) -#define DAS6402_MODE_UNI (1 << 6) -#define DAS6402_MODE_DMA1 (0 << 7) -#define DAS6402_MODE_DMA3 (1 << 7) +#define DAS6402_MODE_RANGE(x) ((x) << 2) +#define DAS6402_MODE_POLLED DAS6402_MODE_RANGE(0) +#define DAS6402_MODE_FIFONEPTY DAS6402_MODE_RANGE(1) +#define DAS6402_MODE_FIFOHFULL DAS6402_MODE_RANGE(2) +#define DAS6402_MODE_EOB DAS6402_MODE_RANGE(3) +#define DAS6402_MODE_ENHANCED BIT(4) +#define DAS6402_MODE_SE BIT(5) +#define DAS6402_MODE_UNI BIT(6) +#define DAS6402_MODE_DMA(x) ((x) << 7) +#define DAS6402_MODE_DMA1 DAS6402_MODE_DMA(0) +#define DAS6402_MODE_DMA3 DAS6402_MODE_DMA(1) #define DAS6402_TIMER_BASE 0x0c static const struct comedi_lrange das6402_ai_ranges = { -- cgit v0.10.2 From 5efe11599e78600d4af230c9d1574bc2728428bd Mon Sep 17 00:00:00 2001 From: Ravishankar Karkala Mallikarjunayya Date: Mon, 6 Jun 2016 16:31:23 +0530 Subject: Staging: comedi: Used unsigned int instead of unsigned issue in jr3_pci.c This is a patch to the jr3_pci.c file that fixes up a WARNING: Prefer 'unsigned int' to bare use of 'unsigned' found by the checkpatch.pl tool. Signed-off-by: Ravishankar Karkala Mallikarjunayya Reviewed-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/comedi/drivers/jr3_pci.c b/drivers/staging/comedi/drivers/jr3_pci.c index fa0d4b1..6c4ff02 100644 --- a/drivers/staging/comedi/drivers/jr3_pci.c +++ b/drivers/staging/comedi/drivers/jr3_pci.c @@ -231,7 +231,7 @@ static unsigned int jr3_pci_ai_read_chan(struct comedi_device *dev, if (chan < 56) { unsigned int axis = chan % 8; - unsigned filter = chan / 8; + unsigned int filter = chan / 8; switch (axis) { case 0: @@ -690,7 +690,7 @@ static int jr3_pci_auto_attach(struct comedi_device *dev, if (sizeof(struct jr3_channel) != 0xc00) { dev_err(dev->class_dev, "sizeof(struct jr3_channel) = %x [expected %x]\n", - (unsigned)sizeof(struct jr3_channel), 0xc00); + (unsigned int)sizeof(struct jr3_channel), 0xc00); return -EINVAL; } -- cgit v0.10.2 From d9b9c9a0339fb3f5b6c6365b144f1fa717f5b147 Mon Sep 17 00:00:00 2001 From: Ravishankar Karkala Mallikarjunayya Date: Tue, 14 Jun 2016 11:23:22 +0530 Subject: Staging: comedi: dmm32at: fix BIT macro issue. This Replace all occurences of (1< Reviewed-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/comedi/drivers/dmm32at.c b/drivers/staging/comedi/drivers/dmm32at.c index 958c0d4..b8606de 100644 --- a/drivers/staging/comedi/drivers/dmm32at.c +++ b/drivers/staging/comedi/drivers/dmm32at.c @@ -46,73 +46,75 @@ #define DMM32AT_AI_START_CONV_REG 0x00 #define DMM32AT_AI_LSB_REG 0x00 #define DMM32AT_AUX_DOUT_REG 0x01 -#define DMM32AT_AUX_DOUT2 (1 << 2) /* J3.42 - OUT2 (OUT2EN) */ -#define DMM32AT_AUX_DOUT1 (1 << 1) /* J3.43 */ -#define DMM32AT_AUX_DOUT0 (1 << 0) /* J3.44 - OUT0 (OUT0EN) */ +#define DMM32AT_AUX_DOUT2 BIT(2) /* J3.42 - OUT2 (OUT2EN) */ +#define DMM32AT_AUX_DOUT1 BIT(1) /* J3.43 */ +#define DMM32AT_AUX_DOUT0 BIT(0) /* J3.44 - OUT0 (OUT0EN) */ #define DMM32AT_AI_MSB_REG 0x01 #define DMM32AT_AI_LO_CHAN_REG 0x02 #define DMM32AT_AI_HI_CHAN_REG 0x03 #define DMM32AT_AUX_DI_REG 0x04 -#define DMM32AT_AUX_DI_DACBUSY (1 << 7) -#define DMM32AT_AUX_DI_CALBUSY (1 << 6) -#define DMM32AT_AUX_DI3 (1 << 3) /* J3.45 - ADCLK (CLKSEL) */ -#define DMM32AT_AUX_DI2 (1 << 2) /* J3.46 - GATE12 (GT12EN) */ -#define DMM32AT_AUX_DI1 (1 << 1) /* J3.47 - GATE0 (GT0EN) */ -#define DMM32AT_AUX_DI0 (1 << 0) /* J3.48 - CLK0 (SRC0) */ +#define DMM32AT_AUX_DI_DACBUSY BIT(7) +#define DMM32AT_AUX_DI_CALBUSY BIT(6) +#define DMM32AT_AUX_DI3 BIT(3) /* J3.45 - ADCLK (CLKSEL) */ +#define DMM32AT_AUX_DI2 BIT(2) /* J3.46 - GATE12 (GT12EN) */ +#define DMM32AT_AUX_DI1 BIT(1) /* J3.47 - GATE0 (GT0EN) */ +#define DMM32AT_AUX_DI0 BIT(0) /* J3.48 - CLK0 (SRC0) */ #define DMM32AT_AO_LSB_REG 0x04 #define DMM32AT_AO_MSB_REG 0x05 #define DMM32AT_AO_MSB_DACH(x) ((x) << 6) #define DMM32AT_FIFO_DEPTH_REG 0x06 #define DMM32AT_FIFO_CTRL_REG 0x07 -#define DMM32AT_FIFO_CTRL_FIFOEN (1 << 3) -#define DMM32AT_FIFO_CTRL_SCANEN (1 << 2) -#define DMM32AT_FIFO_CTRL_FIFORST (1 << 1) +#define DMM32AT_FIFO_CTRL_FIFOEN BIT(3) +#define DMM32AT_FIFO_CTRL_SCANEN BIT(2) +#define DMM32AT_FIFO_CTRL_FIFORST BIT(1) #define DMM32AT_FIFO_STATUS_REG 0x07 -#define DMM32AT_FIFO_STATUS_EF (1 << 7) -#define DMM32AT_FIFO_STATUS_HF (1 << 6) -#define DMM32AT_FIFO_STATUS_FF (1 << 5) -#define DMM32AT_FIFO_STATUS_OVF (1 << 4) -#define DMM32AT_FIFO_STATUS_FIFOEN (1 << 3) -#define DMM32AT_FIFO_STATUS_SCANEN (1 << 2) +#define DMM32AT_FIFO_STATUS_EF BIT(7) +#define DMM32AT_FIFO_STATUS_HF BIT(6) +#define DMM32AT_FIFO_STATUS_FF BIT(5) +#define DMM32AT_FIFO_STATUS_OVF BIT(4) +#define DMM32AT_FIFO_STATUS_FIFOEN BIT(3) +#define DMM32AT_FIFO_STATUS_SCANEN BIT(2) #define DMM32AT_FIFO_STATUS_PAGE_MASK (3 << 0) #define DMM32AT_CTRL_REG 0x08 -#define DMM32AT_CTRL_RESETA (1 << 5) -#define DMM32AT_CTRL_RESETD (1 << 4) -#define DMM32AT_CTRL_INTRST (1 << 3) -#define DMM32AT_CTRL_PAGE_8254 (0 << 0) -#define DMM32AT_CTRL_PAGE_8255 (1 << 0) -#define DMM32AT_CTRL_PAGE_CALIB (3 << 0) +#define DMM32AT_CTRL_RESETA BIT(5) +#define DMM32AT_CTRL_RESETD BIT(4) +#define DMM32AT_CTRL_INTRST BIT(3) +#define DMM32AT_CTRL_PAGE(x) ((x) << 0) +#define DMM32AT_CTRL_PAGE_8254 DMM32AT_CTRL_PAGE(0) +#define DMM32AT_CTRL_PAGE_8255 DMM32AT_CTRL_PAGE(1) +#define DMM32AT_CTRL_PAGE_CALIB DMM32AT_CTRL_PAGE(3) #define DMM32AT_AI_STATUS_REG 0x08 -#define DMM32AT_AI_STATUS_STS (1 << 7) -#define DMM32AT_AI_STATUS_SD1 (1 << 6) -#define DMM32AT_AI_STATUS_SD0 (1 << 5) +#define DMM32AT_AI_STATUS_STS BIT(7) +#define DMM32AT_AI_STATUS_SD1 BIT(6) +#define DMM32AT_AI_STATUS_SD0 BIT(5) #define DMM32AT_AI_STATUS_ADCH_MASK (0x1f << 0) #define DMM32AT_INTCLK_REG 0x09 -#define DMM32AT_INTCLK_ADINT (1 << 7) -#define DMM32AT_INTCLK_DINT (1 << 6) -#define DMM32AT_INTCLK_TINT (1 << 5) -#define DMM32AT_INTCLK_CLKEN (1 << 1) /* 1=see below 0=software */ -#define DMM32AT_INTCLK_CLKSEL (1 << 0) /* 1=OUT2 0=EXTCLK */ +#define DMM32AT_INTCLK_ADINT BIT(7) +#define DMM32AT_INTCLK_DINT BIT(6) +#define DMM32AT_INTCLK_TINT BIT(5) +#define DMM32AT_INTCLK_CLKEN BIT(1) /* 1=see below 0=software */ +#define DMM32AT_INTCLK_CLKSEL BIT(0) /* 1=OUT2 0=EXTCLK */ #define DMM32AT_CTRDIO_CFG_REG 0x0a -#define DMM32AT_CTRDIO_CFG_FREQ12 (1 << 7) /* CLK12 1=100KHz 0=10MHz */ -#define DMM32AT_CTRDIO_CFG_FREQ0 (1 << 6) /* CLK0 1=10KHz 0=10MHz */ -#define DMM32AT_CTRDIO_CFG_OUT2EN (1 << 5) /* J3.42 1=OUT2 is DOUT2 */ -#define DMM32AT_CTRDIO_CFG_OUT0EN (1 << 4) /* J3,44 1=OUT0 is DOUT0 */ -#define DMM32AT_CTRDIO_CFG_GT0EN (1 << 2) /* J3.47 1=DIN1 is GATE0 */ -#define DMM32AT_CTRDIO_CFG_SRC0 (1 << 1) /* CLK0 is 0=FREQ0 1=J3.48 */ -#define DMM32AT_CTRDIO_CFG_GT12EN (1 << 0) /* J3.46 1=DIN2 is GATE12 */ +#define DMM32AT_CTRDIO_CFG_FREQ12 BIT(7) /* CLK12 1=100KHz 0=10MHz */ +#define DMM32AT_CTRDIO_CFG_FREQ0 BIT(6) /* CLK0 1=10KHz 0=10MHz */ +#define DMM32AT_CTRDIO_CFG_OUT2EN BIT(5) /* J3.42 1=OUT2 is DOUT2 */ +#define DMM32AT_CTRDIO_CFG_OUT0EN BIT(4) /* J3,44 1=OUT0 is DOUT0 */ +#define DMM32AT_CTRDIO_CFG_GT0EN BIT(2) /* J3.47 1=DIN1 is GATE0 */ +#define DMM32AT_CTRDIO_CFG_SRC0 BIT(1) /* CLK0 is 0=FREQ0 1=J3.48 */ +#define DMM32AT_CTRDIO_CFG_GT12EN BIT(0) /* J3.46 1=DIN2 is GATE12 */ #define DMM32AT_AI_CFG_REG 0x0b -#define DMM32AT_AI_CFG_SCINT_20US (0 << 4) -#define DMM32AT_AI_CFG_SCINT_15US (1 << 4) -#define DMM32AT_AI_CFG_SCINT_10US (2 << 4) -#define DMM32AT_AI_CFG_SCINT_5US (3 << 4) -#define DMM32AT_AI_CFG_RANGE (1 << 3) /* 0=5V 1=10V */ -#define DMM32AT_AI_CFG_ADBU (1 << 2) /* 0=bipolar 1=unipolar */ +#define DMM32AT_AI_CFG_SCINT(x) ((x) << 4) +#define DMM32AT_AI_CFG_SCINT_20US DMM32AT_AI_CFG_SCINT(0) +#define DMM32AT_AI_CFG_SCINT_15US DMM32AT_AI_CFG_SCINT(1) +#define DMM32AT_AI_CFG_SCINT_10US DMM32AT_AI_CFG_SCINT(2) +#define DMM32AT_AI_CFG_SCINT_5US DMM32AT_AI_CFG_SCINT(3) +#define DMM32AT_AI_CFG_RANGE BIT(3) /* 0=5V 1=10V */ +#define DMM32AT_AI_CFG_ADBU BIT(2) /* 0=bipolar 1=unipolar */ #define DMM32AT_AI_CFG_GAIN(x) ((x) << 0) #define DMM32AT_AI_READBACK_REG 0x0b -#define DMM32AT_AI_READBACK_WAIT (1 << 7) /* DMM32AT_AI_STATUS_STS */ -#define DMM32AT_AI_READBACK_RANGE (1 << 3) -#define DMM32AT_AI_READBACK_ADBU (1 << 2) +#define DMM32AT_AI_READBACK_WAIT BIT(7) /* DMM32AT_AI_STATUS_STS */ +#define DMM32AT_AI_READBACK_RANGE BIT(3) +#define DMM32AT_AI_READBACK_ADBU BIT(2) #define DMM32AT_AI_READBACK_GAIN_MASK (3 << 0) #define DMM32AT_CLK1 0x0d -- cgit v0.10.2 From d855c3a41ff6d4b907cf24bea136a96d70e02893 Mon Sep 17 00:00:00 2001 From: Ravishankar Karkala Mallikarjunayya Date: Tue, 7 Jun 2016 14:06:16 +0530 Subject: Staging: comedi: fix blank line issue in das16.c This is a patch to the das16.c file that fixes up a blank line after function/struct/union/enum check found by the checkpatch.pl tool Signed-off-by: Ravishankar Karkala Mallikarjunayya Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/comedi/drivers/das16.c b/drivers/staging/comedi/drivers/das16.c index 69133e3..8b037bd 100644 --- a/drivers/staging/comedi/drivers/das16.c +++ b/drivers/staging/comedi/drivers/das16.c @@ -198,6 +198,7 @@ enum { das16_pg_1601, das16_pg_1602, }; + static const int *const das16_gainlists[] = { NULL, das16jr_gainlist, -- cgit v0.10.2 From 55cc6164eecfa72777d34b789e066f618eb1fd93 Mon Sep 17 00:00:00 2001 From: Ravishankar Karkala Mallikarjunayya Date: Tue, 7 Jun 2016 14:06:17 +0530 Subject: Staging: comedi: Block comment issue fixed for das16.c This is a patch to the das16.c file that fixes up a WARNING: 'Block comments use a trailing */ on a separate line' found by the checkpatch.pl tool. Signed-off-by: Ravishankar Karkala Mallikarjunayya Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/comedi/drivers/das16.c b/drivers/staging/comedi/drivers/das16.c index 8b037bd..5d15795 100644 --- a/drivers/staging/comedi/drivers/das16.c +++ b/drivers/staging/comedi/drivers/das16.c @@ -429,8 +429,10 @@ static const struct das16_board das16_boards[] = { }, }; -/* Period for timer interrupt in jiffies. It's a function - * to deal with possibility of dynamic HZ patches */ +/* + * Period for timer interrupt in jiffies. It's a function + * to deal with possibility of dynamic HZ patches + */ static inline int timer_period(void) { return HZ / 20; -- cgit v0.10.2 From deecca61b3d33221bd3d30241dd083d53de67aa1 Mon Sep 17 00:00:00 2001 From: Ravishankar Karkala Mallikarjunayya Date: Tue, 7 Jun 2016 14:06:18 +0530 Subject: Staging: comedi: fix comment issue fixed for das800.c This is a patch to the das800.c file that fixes up a WARNING: 'Block comments use a trailing */ on a separate line' found by the checkpatch.pl tool Signed-off-by: Ravishankar Karkala Mallikarjunayya Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/comedi/drivers/das800.c b/drivers/staging/comedi/drivers/das800.c index 9059872..fd4cb49 100644 --- a/drivers/staging/comedi/drivers/das800.c +++ b/drivers/staging/comedi/drivers/das800.c @@ -1,56 +1,56 @@ /* - comedi/drivers/das800.c - Driver for Keitley das800 series boards and compatibles - Copyright (C) 2000 Frank Mori Hess - - COMEDI - Linux Control and Measurement Device Interface - Copyright (C) 2000 David A. Schleef - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. -*/ + * comedi/drivers/das800.c + * Driver for Keitley das800 series boards and compatibles + * Copyright (C) 2000 Frank Mori Hess + * + * COMEDI - Linux Control and Measurement Device Interface + * Copyright (C) 2000 David A. Schleef + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ /* -Driver: das800 -Description: Keithley Metrabyte DAS800 (& compatibles) -Author: Frank Mori Hess -Devices: [Keithley Metrabyte] DAS-800 (das-800), DAS-801 (das-801), - DAS-802 (das-802), - [Measurement Computing] CIO-DAS800 (cio-das800), - CIO-DAS801 (cio-das801), CIO-DAS802 (cio-das802), - CIO-DAS802/16 (cio-das802/16) -Status: works, cio-das802/16 untested - email me if you have tested it - -Configuration options: - [0] - I/O port base address - [1] - IRQ (optional, required for timed or externally triggered conversions) - -Notes: - IRQ can be omitted, although the cmd interface will not work without it. - - All entries in the channel/gain list must use the same gain and be - consecutive channels counting upwards in channel number (these are - hardware limitations.) - - I've never tested the gain setting stuff since I only have a - DAS-800 board with fixed gain. - - The cio-das802/16 does not have a fifo-empty status bit! Therefore - only fifo-half-full transfers are possible with this card. - -cmd triggers supported: - start_src: TRIG_NOW | TRIG_EXT - scan_begin_src: TRIG_FOLLOW - scan_end_src: TRIG_COUNT - convert_src: TRIG_TIMER | TRIG_EXT - stop_src: TRIG_NONE | TRIG_COUNT -*/ + * Driver: das800 + * Description: Keithley Metrabyte DAS800 (& compatibles) + * Author: Frank Mori Hess + * Devices: [Keithley Metrabyte] DAS-800 (das-800), DAS-801 (das-801), + * DAS-802 (das-802), + * [Measurement Computing] CIO-DAS800 (cio-das800), + * CIO-DAS801 (cio-das801), CIO-DAS802 (cio-das802), + * CIO-DAS802/16 (cio-das802/16) + * Status: works, cio-das802/16 untested - email me if you have tested it + * + * Configuration options: + * [0] - I/O port base address + * [1] - IRQ (optional, required for timed or externally triggered conversions) + * + * Notes: + * IRQ can be omitted, although the cmd interface will not work without it. + * + * All entries in the channel/gain list must use the same gain and be + * consecutive channels counting upwards in channel number (these are + * hardware limitations.) + * + * I've never tested the gain setting stuff since I only have a + * DAS-800 board with fixed gain. + * + * The cio-das802/16 does not have a fifo-empty status bit! Therefore + * only fifo-half-full transfers are possible with this card. + * + * cmd triggers supported: + * start_src: TRIG_NOW | TRIG_EXT + * scan_begin_src: TRIG_FOLLOW + * scan_end_src: TRIG_COUNT + * convert_src: TRIG_TIMER | TRIG_EXT + * stop_src: TRIG_NONE | TRIG_COUNT + */ #include #include -- cgit v0.10.2 From 2e3d417c02ceadd7feea0b34b37a36a1ffda96f1 Mon Sep 17 00:00:00 2001 From: Chris Cesare Date: Thu, 9 Jun 2016 15:39:02 -0400 Subject: staging: comedi: serial2002: Fix bare unsigned styling issue checkpatch.pl warns about a bare unsigned. Add type int to make explicit and suit the coding style. Signed-off-by Chris Cesare Reviewed-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/comedi/drivers/serial2002.c b/drivers/staging/comedi/drivers/serial2002.c index 7a1defc..b777946 100644 --- a/drivers/staging/comedi/drivers/serial2002.c +++ b/drivers/staging/comedi/drivers/serial2002.c @@ -95,7 +95,7 @@ struct serial_data { #define S2002_CFG_SIGN(x) (((x) >> 13) & 0x1) #define S2002_CFG_BASE(x) (((x) >> 14) & 0xfffff) -static long serial2002_tty_ioctl(struct file *f, unsigned op, +static long serial2002_tty_ioctl(struct file *f, unsigned int op, unsigned long param) { if (f->f_op->unlocked_ioctl) -- cgit v0.10.2 From c9b0f2b63f47ec35ca5e6588df488bb7e51efb43 Mon Sep 17 00:00:00 2001 From: Chris Cesare Date: Thu, 9 Jun 2016 15:39:03 -0400 Subject: staging: comedi: serial2002: Fix unnecessary cast styling issue checkpatch.pl warns that a cast of 1 to (long long) is unnecessary. Remove the cast and also add code to check and make sure that maxdata_list[chan] is not shifted too far, as suggested by Ian Abbott. Signed-off-by Chris Cesare Reviewed-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/comedi/drivers/serial2002.c b/drivers/staging/comedi/drivers/serial2002.c index b777946..0d33e52 100644 --- a/drivers/staging/comedi/drivers/serial2002.c +++ b/drivers/staging/comedi/drivers/serial2002.c @@ -379,7 +379,10 @@ static int serial2002_setup_subdevice(struct comedi_subdevice *s, range_table_list[chan] = (const struct comedi_lrange *)&range[j]; } - maxdata_list[chan] = ((long long)1 << cfg[j].bits) - 1; + if (cfg[j].bits < 32) + maxdata_list[chan] = (1u << cfg[j].bits) - 1; + else + maxdata_list[chan] = 0xffffffff; chan++; } } -- cgit v0.10.2 From 6adb21c2759ad8316f9e47244ac96d3d5d866ecf Mon Sep 17 00:00:00 2001 From: Ravishankar Karkala Mallikarjunayya Date: Fri, 17 Jun 2016 16:56:17 +0530 Subject: Staging: comedi: dt2814: Block comment issue fixed This fixes up a WARNING: 'Block comments use a trailing */ on a separate line' found by the checkpatch.pl tool. Signed-off-by: Ravishankar Karkala Mallikarjunayya Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/comedi/drivers/dt2814.c b/drivers/staging/comedi/drivers/dt2814.c index 66705f9..2f903be 100644 --- a/drivers/staging/comedi/drivers/dt2814.c +++ b/drivers/staging/comedi/drivers/dt2814.c @@ -1,38 +1,38 @@ /* - comedi/drivers/dt2814.c - Hardware driver for Data Translation DT2814 - - COMEDI - Linux Control and Measurement Device Interface - Copyright (C) 1998 David A. Schleef - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. -*/ + * comedi/drivers/dt2814.c + * Hardware driver for Data Translation DT2814 + * + * COMEDI - Linux Control and Measurement Device Interface + * Copyright (C) 1998 David A. Schleef + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ /* -Driver: dt2814 -Description: Data Translation DT2814 -Author: ds -Status: complete -Devices: [Data Translation] DT2814 (dt2814) - -Configuration options: - [0] - I/O port base address - [1] - IRQ - -This card has 16 analog inputs multiplexed onto a 12 bit ADC. There -is a minimally useful onboard clock. The base frequency for the -clock is selected by jumpers, and the clock divider can be selected -via programmed I/O. Unfortunately, the clock divider can only be -a power of 10, from 1 to 10^7, of which only 3 or 4 are useful. In -addition, the clock does not seem to be very accurate. -*/ + * Driver: dt2814 + * Description: Data Translation DT2814 + * Author: ds + * Status: complete + * Devices: [Data Translation] DT2814 (dt2814) + * + * Configuration options: + * [0] - I/O port base address + * [1] - IRQ + * + * This card has 16 analog inputs multiplexed onto a 12 bit ADC. There + * is a minimally useful onboard clock. The base frequency for the + * clock is selected by jumpers, and the clock divider can be selected + * via programmed I/O. Unfortunately, the clock divider can only be + * a power of 10, from 1 to 10^7, of which only 3 or 4 are useful. In + * addition, the clock does not seem to be very accurate. + */ #include #include @@ -215,8 +215,10 @@ static irqreturn_t dt2814_interrupt(int irq, void *d) int i; outb(0, dev->iobase + DT2814_CSR); - /* note: turning off timed mode triggers another - sample. */ + /* + * note: turning off timed mode triggers another + * sample. + */ for (i = 0; i < DT2814_TIMEOUT; i++) { if (inb(dev->iobase + DT2814_CSR) & DT2814_FINISH) -- cgit v0.10.2 From 62c701d794d2fdad48140f9c82ca228917131342 Mon Sep 17 00:00:00 2001 From: Ravishankar Karkala Mallikarjunayya Date: Fri, 17 Jun 2016 16:56:18 +0530 Subject: Staging: comedi: dt2815: Comment issue fixed This fixes up a WARNING: 'Block comments use a trailing */ on a separate line' found by the checkpatch.pl tool. Signed-off-by: Ravishankar Karkala Mallikarjunayya Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/comedi/drivers/dt2815.c b/drivers/staging/comedi/drivers/dt2815.c index fb08569..0be77cc 100644 --- a/drivers/staging/comedi/drivers/dt2815.c +++ b/drivers/staging/comedi/drivers/dt2815.c @@ -1,55 +1,55 @@ /* - comedi/drivers/dt2815.c - Hardware driver for Data Translation DT2815 - - COMEDI - Linux Control and Measurement Device Interface - Copyright (C) 1999 Anders Blomdell - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. + * comedi/drivers/dt2815.c + * Hardware driver for Data Translation DT2815 + * + * COMEDI - Linux Control and Measurement Device Interface + * Copyright (C) 1999 Anders Blomdell + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. */ /* -Driver: dt2815 -Description: Data Translation DT2815 -Author: ds -Status: mostly complete, untested -Devices: [Data Translation] DT2815 (dt2815) - -I'm not sure anyone has ever tested this board. If you have information -contrary, please update. - -Configuration options: - [0] - I/O port base base address - [1] - IRQ (unused) - [2] - Voltage unipolar/bipolar configuration - 0 == unipolar 5V (0V -- +5V) - 1 == bipolar 5V (-5V -- +5V) - [3] - Current offset configuration - 0 == disabled (0mA -- +32mAV) - 1 == enabled (+4mA -- +20mAV) - [4] - Firmware program configuration - 0 == program 1 (see manual table 5-4) - 1 == program 2 (see manual table 5-4) - 2 == program 3 (see manual table 5-4) - 3 == program 4 (see manual table 5-4) - [5] - Analog output 0 range configuration - 0 == voltage - 1 == current - [6] - Analog output 1 range configuration (same options) - [7] - Analog output 2 range configuration (same options) - [8] - Analog output 3 range configuration (same options) - [9] - Analog output 4 range configuration (same options) - [10] - Analog output 5 range configuration (same options) - [11] - Analog output 6 range configuration (same options) - [12] - Analog output 7 range configuration (same options) -*/ + * Driver: dt2815 + * Description: Data Translation DT2815 + * Author: ds + * Status: mostly complete, untested + * Devices: [Data Translation] DT2815 (dt2815) + * + * I'm not sure anyone has ever tested this board. If you have information + * contrary, please update. + * + * Configuration options: + * [0] - I/O port base base address + * [1] - IRQ (unused) + * [2] - Voltage unipolar/bipolar configuration + * 0 == unipolar 5V (0V -- +5V) + * 1 == bipolar 5V (-5V -- +5V) + * [3] - Current offset configuration + * 0 == disabled (0mA -- +32mAV) + * 1 == enabled (+4mA -- +20mAV) + * [4] - Firmware program configuration + * 0 == program 1 (see manual table 5-4) + * 1 == program 2 (see manual table 5-4) + * 2 == program 3 (see manual table 5-4) + * 3 == program 4 (see manual table 5-4) + * [5] - Analog output 0 range configuration + * 0 == voltage + * 1 == current + * [6] - Analog output 1 range configuration (same options) + * [7] - Analog output 2 range configuration (same options) + * [8] - Analog output 3 range configuration (same options) + * [9] - Analog output 4 range configuration (same options) + * [10] - Analog output 5 range configuration (same options) + * [11] - Analog output 6 range configuration (same options) + * [12] - Analog output 7 range configuration (same options) + */ #include #include "../comedidev.h" @@ -120,27 +120,27 @@ static int dt2815_ao_insn(struct comedi_device *dev, struct comedi_subdevice *s, } /* - options[0] Board base address - options[1] IRQ (not applicable) - options[2] Voltage unipolar/bipolar configuration - 0 == unipolar 5V (0V -- +5V) - 1 == bipolar 5V (-5V -- +5V) - options[3] Current offset configuration - 0 == disabled (0mA -- +32mAV) - 1 == enabled (+4mA -- +20mAV) - options[4] Firmware program configuration - 0 == program 1 (see manual table 5-4) - 1 == program 2 (see manual table 5-4) - 2 == program 3 (see manual table 5-4) - 3 == program 4 (see manual table 5-4) - options[5] Analog output 0 range configuration - 0 == voltage - 1 == current - options[6] Analog output 1 range configuration - ... - options[12] Analog output 7 range configuration - 0 == voltage - 1 == current + * options[0] Board base address + * options[1] IRQ (not applicable) + * options[2] Voltage unipolar/bipolar configuration + * 0 == unipolar 5V (0V -- +5V) + * 1 == bipolar 5V (-5V -- +5V) + * options[3] Current offset configuration + * 0 == disabled (0mA -- +32mAV) + * 1 == enabled (+4mA -- +20mAV) + * options[4] Firmware program configuration + * 0 == program 1 (see manual table 5-4) + * 1 == program 2 (see manual table 5-4) + * 2 == program 3 (see manual table 5-4) + * 3 == program 4 (see manual table 5-4) + * options[5] Analog output 0 range configuration + * 0 == voltage + * 1 == current + * options[6] Analog output 1 range configuration + * ... + * options[12] Analog output 7 range configuration + * 0 == voltage + * 1 == current */ static int dt2815_attach(struct comedi_device *dev, struct comedi_devconfig *it) -- cgit v0.10.2 From 533364c7c6af7c995d8e2868b93883e6015812b4 Mon Sep 17 00:00:00 2001 From: Ravishankar Karkala Mallikarjunayya Date: Fri, 17 Jun 2016 16:56:20 +0530 Subject: Staging: comedi: dt2817: Coding style issue fixed. This fixes up a WARNING: 'Block comments use a trailing */ on a separate line' found by the checkpatch.pl tool. Signed-off-by: Ravishankar Karkala Mallikarjunayya Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/comedi/drivers/dt2817.c b/drivers/staging/comedi/drivers/dt2817.c index 5131dee..39d2566 100644 --- a/drivers/staging/comedi/drivers/dt2817.c +++ b/drivers/staging/comedi/drivers/dt2817.c @@ -1,37 +1,37 @@ /* - comedi/drivers/dt2817.c - Hardware driver for Data Translation DT2817 - - COMEDI - Linux Control and Measurement Device Interface - Copyright (C) 1998 David A. Schleef - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. -*/ + * comedi/drivers/dt2817.c + * Hardware driver for Data Translation DT2817 + * + * COMEDI - Linux Control and Measurement Device Interface + * Copyright (C) 1998 David A. Schleef + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ /* -Driver: dt2817 -Description: Data Translation DT2817 -Author: ds -Status: complete -Devices: [Data Translation] DT2817 (dt2817) - -A very simple digital I/O card. Four banks of 8 lines, each bank -is configurable for input or output. One wonders why it takes a -50 page manual to describe this thing. - -The driver (which, btw, is much less than 50 pages) has 1 subdevice -with 32 channels, configurable in groups of 8. - -Configuration options: - [0] - I/O port base base address -*/ + * Driver: dt2817 + * Description: Data Translation DT2817 + * Author: ds + * Status: complete + * Devices: [Data Translation] DT2817 (dt2817) + * + * A very simple digital I/O card. Four banks of 8 lines, each bank + * is configurable for input or output. One wonders why it takes a + * 50 page manual to describe this thing. + * + * The driver (which, btw, is much less than 50 pages) has 1 subdevice + * with 32 channels, configurable in groups of 8. + * + * Configuration options: + * [0] - I/O port base base address + */ #include #include "../comedidev.h" -- cgit v0.10.2 From 70db384cd6dd780a32197c194ad41735630d265e Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Fri, 17 Jun 2016 21:56:15 +0200 Subject: staging: comedi: avoid using timeval Comedi uses 32-bit seconds for its timestamps, on both 32-bit and 64-bit machines. For all I can tell, this was originally meant as a 'timespec', which would overflow in 2038 because of the use of a signed 'long' on 32-bit machines, but it is now used as an array of two unsigned 'lsampl_t' values in comedilib, which will only overflow in 2106, on both 32-bit and 64-bit machines. In an effort to get rid of all uses of 'struct timeval' in the kernel, this replaces the internal code with a call to ktime_get_real_ts64() and a comment at the location of the conversion. Signed-off-by: Arnd Bergmann Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/comedi/comedi_fops.c b/drivers/staging/comedi/comedi_fops.c index 4d87596..1999eed 100644 --- a/drivers/staging/comedi/comedi_fops.c +++ b/drivers/staging/comedi/comedi_fops.c @@ -1256,16 +1256,17 @@ static int parse_insn(struct comedi_device *dev, struct comedi_insn *insn, switch (insn->insn) { case INSN_GTOD: { - struct timeval tv; + struct timespec64 tv; if (insn->n != 2) { ret = -EINVAL; break; } - do_gettimeofday(&tv); - data[0] = tv.tv_sec; - data[1] = tv.tv_usec; + ktime_get_real_ts64(&tv); + /* unsigned data safe until 2106 */ + data[0] = (unsigned int)tv.tv_sec; + data[1] = tv.tv_nsec / NSEC_PER_USEC; ret = 2; break; -- cgit v0.10.2 From 63bb0bc1b19d125c052e3b199421a0ca4d67e021 Mon Sep 17 00:00:00 2001 From: Gustavo Padovan Date: Tue, 31 May 2016 16:58:56 -0300 Subject: staging/android: store last signaled value on sync timeline Now fence timeline is aware of the last signaled fence, as it receives the increment to the current value in sync_timeline_signal(). That allow us to remove .has_signaled() from timeline_ops as we can directly compare using timeline->value and fence->seqno in sync.c Signed-off-by: Gustavo Padovan Reviewed-by: Daniel Vetter Reviewed-by: Sumit Semwal Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/android/sw_sync.c b/drivers/staging/android/sw_sync.c index af39ff5..428e22c 100644 --- a/drivers/staging/android/sw_sync.c +++ b/drivers/staging/android/sw_sync.c @@ -30,7 +30,7 @@ struct fence *sw_sync_pt_create(struct sw_sync_timeline *obj, u32 value) struct sw_sync_pt *pt; pt = (struct sw_sync_pt *) - sync_pt_create(&obj->obj, sizeof(struct sw_sync_pt)); + sync_pt_create(&obj->obj, sizeof(struct sw_sync_pt), value); pt->value = value; @@ -38,15 +38,6 @@ struct fence *sw_sync_pt_create(struct sw_sync_timeline *obj, u32 value) } EXPORT_SYMBOL(sw_sync_pt_create); -static int sw_sync_fence_has_signaled(struct fence *fence) -{ - struct sw_sync_pt *pt = (struct sw_sync_pt *)fence; - struct sw_sync_timeline *obj = - (struct sw_sync_timeline *)fence_parent(fence); - - return (pt->value > obj->value) ? 0 : 1; -} - static void sw_sync_timeline_value_str(struct sync_timeline *sync_timeline, char *str, int size) { @@ -64,7 +55,6 @@ static void sw_sync_fence_value_str(struct fence *fence, char *str, int size) static struct sync_timeline_ops sw_sync_timeline_ops = { .driver_name = "sw_sync", - .has_signaled = sw_sync_fence_has_signaled, .timeline_value_str = sw_sync_timeline_value_str, .fence_value_str = sw_sync_fence_value_str, }; @@ -82,8 +72,6 @@ EXPORT_SYMBOL(sw_sync_timeline_create); void sw_sync_timeline_inc(struct sw_sync_timeline *obj, u32 inc) { - obj->value += inc; - - sync_timeline_signal(&obj->obj); + sync_timeline_signal(&obj->obj, inc); } EXPORT_SYMBOL(sw_sync_timeline_inc); diff --git a/drivers/staging/android/sync.c b/drivers/staging/android/sync.c index 1d14c83..8dd2181 100644 --- a/drivers/staging/android/sync.c +++ b/drivers/staging/android/sync.c @@ -90,7 +90,7 @@ void sync_timeline_destroy(struct sync_timeline *obj) } EXPORT_SYMBOL(sync_timeline_destroy); -void sync_timeline_signal(struct sync_timeline *obj) +void sync_timeline_signal(struct sync_timeline *obj, unsigned int inc) { unsigned long flags; struct fence *fence, *next; @@ -99,6 +99,8 @@ void sync_timeline_signal(struct sync_timeline *obj) spin_lock_irqsave(&obj->child_list_lock, flags); + obj->value += inc; + list_for_each_entry_safe(fence, next, &obj->active_list_head, active_list) { if (fence_is_signaled_locked(fence)) @@ -109,7 +111,8 @@ void sync_timeline_signal(struct sync_timeline *obj) } EXPORT_SYMBOL(sync_timeline_signal); -struct fence *sync_pt_create(struct sync_timeline *obj, int size) +struct fence *sync_pt_create(struct sync_timeline *obj, int size, + unsigned int value) { unsigned long flags; struct fence *fence; @@ -124,7 +127,7 @@ struct fence *sync_pt_create(struct sync_timeline *obj, int size) spin_lock_irqsave(&obj->child_list_lock, flags); sync_timeline_get(obj); fence_init(fence, &android_fence_ops, &obj->child_list_lock, - obj->context, ++obj->value); + obj->context, value); list_add_tail(&fence->child_list, &obj->child_list_head); INIT_LIST_HEAD(&fence->active_list); spin_unlock_irqrestore(&obj->child_list_lock, flags); @@ -164,12 +167,8 @@ static void android_fence_release(struct fence *fence) static bool android_fence_signaled(struct fence *fence) { struct sync_timeline *parent = fence_parent(fence); - int ret; - ret = parent->ops->has_signaled(fence); - if (ret < 0) - fence->status = ret; - return ret; + return (fence->seqno > parent->value) ? false : true; } static bool android_fence_enable_signaling(struct fence *fence) diff --git a/drivers/staging/android/sync.h b/drivers/staging/android/sync.h index b56885c..627525c 100644 --- a/drivers/staging/android/sync.h +++ b/drivers/staging/android/sync.h @@ -28,19 +28,12 @@ struct sync_timeline; /** * struct sync_timeline_ops - sync object implementation ops * @driver_name: name of the implementation - * @has_signaled: returns: - * 1 if pt has signaled - * 0 if pt has not signaled - * <0 on error * @timeline_value_str: fill str with the value of the sync_timeline's counter * @fence_value_str: fill str with the value of the fence */ struct sync_timeline_ops { const char *driver_name; - /* required */ - int (*has_signaled)(struct fence *fence); - /* optional */ void (*timeline_value_str)(struct sync_timeline *timeline, char *str, int size); @@ -117,23 +110,26 @@ void sync_timeline_destroy(struct sync_timeline *obj); /** * sync_timeline_signal() - signal a status change on a sync_timeline * @obj: sync_timeline to signal + * @inc: num to increment on timeline->value * * A sync implementation should call this any time one of it's fences * has signaled or has an error condition. */ -void sync_timeline_signal(struct sync_timeline *obj); +void sync_timeline_signal(struct sync_timeline *obj, unsigned int inc); /** * sync_pt_create() - creates a sync pt * @parent: fence's parent sync_timeline * @size: size to allocate for this pt + * @inc: value of the fence * * Creates a new fence as a child of @parent. @size bytes will be * allocated allowing for implementation specific data to be kept after * the generic sync_timeline struct. Returns the fence object or * NULL in case of error. */ -struct fence *sync_pt_create(struct sync_timeline *parent, int size); +struct fence *sync_pt_create(struct sync_timeline *parent, int size, + unsigned int inc); #ifdef CONFIG_DEBUG_FS -- cgit v0.10.2 From 5c1401f83a16b7ee3762c9044ab56ed3f3cdcdcd Mon Sep 17 00:00:00 2001 From: Gustavo Padovan Date: Tue, 31 May 2016 16:58:57 -0300 Subject: staging/android: remove .{fence, timeline}_value_str() from timeline_ops Now that the value of fence and the timeline are not stored by sw_sync anymore we can remove this extra abstraction to retrieve this data. This patch changes both fence_ops (.fence_value_str and .timeline_value_str) to return the str directly. It also clean up struct sync_timeline_ops by removing both ops from there. Signed-off-by: Gustavo Padovan Reviewed-by: Daniel Vetter Reviewed-by: Sumit Semwal Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/android/sw_sync.c b/drivers/staging/android/sw_sync.c index 428e22c..4200b12 100644 --- a/drivers/staging/android/sw_sync.c +++ b/drivers/staging/android/sw_sync.c @@ -38,25 +38,8 @@ struct fence *sw_sync_pt_create(struct sw_sync_timeline *obj, u32 value) } EXPORT_SYMBOL(sw_sync_pt_create); -static void sw_sync_timeline_value_str(struct sync_timeline *sync_timeline, - char *str, int size) -{ - struct sw_sync_timeline *timeline = - (struct sw_sync_timeline *)sync_timeline; - snprintf(str, size, "%d", timeline->value); -} - -static void sw_sync_fence_value_str(struct fence *fence, char *str, int size) -{ - struct sw_sync_pt *pt = (struct sw_sync_pt *)fence; - - snprintf(str, size, "%d", pt->value); -} - static struct sync_timeline_ops sw_sync_timeline_ops = { .driver_name = "sw_sync", - .timeline_value_str = sw_sync_timeline_value_str, - .fence_value_str = sw_sync_fence_value_str, }; struct sw_sync_timeline *sw_sync_timeline_create(const char *name) diff --git a/drivers/staging/android/sync.c b/drivers/staging/android/sync.c index 8dd2181..c75d1e6 100644 --- a/drivers/staging/android/sync.c +++ b/drivers/staging/android/sync.c @@ -185,14 +185,7 @@ static bool android_fence_enable_signaling(struct fence *fence) static void android_fence_value_str(struct fence *fence, char *str, int size) { - struct sync_timeline *parent = fence_parent(fence); - - if (!parent->ops->fence_value_str) { - if (size) - *str = 0; - return; - } - parent->ops->fence_value_str(fence, str, size); + snprintf(str, size, "%d", fence->seqno); } static void android_fence_timeline_value_str(struct fence *fence, @@ -200,12 +193,7 @@ static void android_fence_timeline_value_str(struct fence *fence, { struct sync_timeline *parent = fence_parent(fence); - if (!parent->ops->timeline_value_str) { - if (size) - *str = 0; - return; - } - parent->ops->timeline_value_str(parent, str, size); + snprintf(str, size, "%d", parent->value); } static const struct fence_ops android_fence_ops = { diff --git a/drivers/staging/android/sync.h b/drivers/staging/android/sync.h index 627525c..29f8c19 100644 --- a/drivers/staging/android/sync.h +++ b/drivers/staging/android/sync.h @@ -28,18 +28,9 @@ struct sync_timeline; /** * struct sync_timeline_ops - sync object implementation ops * @driver_name: name of the implementation - * @timeline_value_str: fill str with the value of the sync_timeline's counter - * @fence_value_str: fill str with the value of the fence */ struct sync_timeline_ops { const char *driver_name; - - /* optional */ - void (*timeline_value_str)(struct sync_timeline *timeline, char *str, - int size); - - /* optional */ - void (*fence_value_str)(struct fence *fence, char *str, int size); }; /** diff --git a/drivers/staging/android/sync_debug.c b/drivers/staging/android/sync_debug.c index 5f57499..c532457 100644 --- a/drivers/staging/android/sync_debug.c +++ b/drivers/staging/android/sync_debug.c @@ -133,16 +133,8 @@ static void sync_print_obj(struct seq_file *s, struct sync_timeline *obj) struct list_head *pos; unsigned long flags; - seq_printf(s, "%s %s", obj->name, obj->ops->driver_name); - - if (obj->ops->timeline_value_str) { - char value[64]; - - obj->ops->timeline_value_str(obj, value, sizeof(value)); - seq_printf(s, ": %s", value); - } - - seq_puts(s, "\n"); + seq_printf(s, "%s %s: %d\n", obj->name, obj->ops->driver_name, + obj->value); spin_lock_irqsave(&obj->child_list_lock, flags); list_for_each(pos, &obj->child_list_head) { diff --git a/drivers/staging/android/trace/sync.h b/drivers/staging/android/trace/sync.h index a0f80f4..d7f6457f 100644 --- a/drivers/staging/android/trace/sync.h +++ b/drivers/staging/android/trace/sync.h @@ -15,21 +15,15 @@ TRACE_EVENT(sync_timeline, TP_STRUCT__entry( __string(name, timeline->name) - __array(char, value, 32) + __field(u32, value) ), TP_fast_assign( __assign_str(name, timeline->name); - if (timeline->ops->timeline_value_str) { - timeline->ops->timeline_value_str(timeline, - __entry->value, - sizeof(__entry->value)); - } else { - __entry->value[0] = '\0'; - } + __entry->value = timeline->value; ), - TP_printk("name=%s value=%s", __get_str(name), __entry->value) + TP_printk("name=%s value=%d", __get_str(name), __entry->value) ); #endif /* if !defined(_TRACE_SYNC_H) || defined(TRACE_HEADER_MULTI_READ) */ -- cgit v0.10.2 From ef30afefeaf624c483e56c63e60e0dda8c42a0ef Mon Sep 17 00:00:00 2001 From: Gustavo Padovan Date: Tue, 31 May 2016 16:58:58 -0300 Subject: staging/android: remove struct sync_timeline_ops Move drv_name, the last field of sync_timeline_ops, to sync_timeline and remove sync_timeline_ops. struct sync_timeline_ops was just an extra abstraction on top of fence_ops, and in the last few commits we removed all it ops in favor of cleaner fence_ops. Signed-off-by: Gustavo Padovan Reviewed-by: Daniel Vetter Reviewed-by: Sumit Semwal Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/android/sw_sync.c b/drivers/staging/android/sw_sync.c index 4200b12..c5e92c6 100644 --- a/drivers/staging/android/sw_sync.c +++ b/drivers/staging/android/sw_sync.c @@ -38,16 +38,11 @@ struct fence *sw_sync_pt_create(struct sw_sync_timeline *obj, u32 value) } EXPORT_SYMBOL(sw_sync_pt_create); -static struct sync_timeline_ops sw_sync_timeline_ops = { - .driver_name = "sw_sync", -}; - struct sw_sync_timeline *sw_sync_timeline_create(const char *name) { struct sw_sync_timeline *obj = (struct sw_sync_timeline *) - sync_timeline_create(&sw_sync_timeline_ops, - sizeof(struct sw_sync_timeline), - name); + sync_timeline_create(sizeof(struct sw_sync_timeline), + "sw_sync", name); return obj; } diff --git a/drivers/staging/android/sync.c b/drivers/staging/android/sync.c index c75d1e6..b3efcaa 100644 --- a/drivers/staging/android/sync.c +++ b/drivers/staging/android/sync.c @@ -30,8 +30,8 @@ static const struct fence_ops android_fence_ops; -struct sync_timeline *sync_timeline_create(const struct sync_timeline_ops *ops, - int size, const char *name) +struct sync_timeline *sync_timeline_create(int size, const char *drv_name, + const char *name) { struct sync_timeline *obj; @@ -43,9 +43,9 @@ struct sync_timeline *sync_timeline_create(const struct sync_timeline_ops *ops, return NULL; kref_init(&obj->kref); - obj->ops = ops; obj->context = fence_context_alloc(1); strlcpy(obj->name, name, sizeof(obj->name)); + strlcpy(obj->drv_name, drv_name, sizeof(obj->drv_name)); INIT_LIST_HEAD(&obj->child_list_head); INIT_LIST_HEAD(&obj->active_list_head); @@ -139,7 +139,7 @@ static const char *android_fence_get_driver_name(struct fence *fence) { struct sync_timeline *parent = fence_parent(fence); - return parent->ops->driver_name; + return parent->drv_name; } static const char *android_fence_get_timeline_name(struct fence *fence) diff --git a/drivers/staging/android/sync.h b/drivers/staging/android/sync.h index 29f8c19..f003e97 100644 --- a/drivers/staging/android/sync.h +++ b/drivers/staging/android/sync.h @@ -23,20 +23,10 @@ #include #include -struct sync_timeline; - -/** - * struct sync_timeline_ops - sync object implementation ops - * @driver_name: name of the implementation - */ -struct sync_timeline_ops { - const char *driver_name; -}; - /** * struct sync_timeline - sync object * @kref: reference count on fence. - * @ops: ops that define the implementation of the sync_timeline + * @drv_name: drv_name of the driver using the sync_timeline * @name: name of the sync_timeline. Useful for debugging * @destroyed: set when sync_timeline is destroyed * @child_list_head: list of children sync_pts for this sync_timeline @@ -47,7 +37,7 @@ struct sync_timeline_ops { */ struct sync_timeline { struct kref kref; - const struct sync_timeline_ops *ops; + char drv_name[32]; char name[32]; /* protected by child_list_lock */ @@ -76,17 +66,17 @@ static inline struct sync_timeline *fence_parent(struct fence *fence) /** * sync_timeline_create() - creates a sync object - * @ops: specifies the implementation ops for the object * @size: size to allocate for this obj + * @drv_name: sync_timeline driver name * @name: sync_timeline name * - * Creates a new sync_timeline which will use the implementation specified by - * @ops. @size bytes will be allocated allowing for implementation specific - * data to be kept after the generic sync_timeline struct. Returns the - * sync_timeline object or NULL in case of error. + * Creates a new sync_timeline. @size bytes will be allocated allowing + * for implementation specific data to be kept after the generic + * sync_timeline struct. Returns the sync_timeline object or NULL in + * case of error. */ -struct sync_timeline *sync_timeline_create(const struct sync_timeline_ops *ops, - int size, const char *name); +struct sync_timeline *sync_timeline_create(int size, const char *drv_name, + const char *name); /** * sync_timeline_destroy() - destroys a sync object diff --git a/drivers/staging/android/sync_debug.c b/drivers/staging/android/sync_debug.c index c532457..e5634f2 100644 --- a/drivers/staging/android/sync_debug.c +++ b/drivers/staging/android/sync_debug.c @@ -133,8 +133,7 @@ static void sync_print_obj(struct seq_file *s, struct sync_timeline *obj) struct list_head *pos; unsigned long flags; - seq_printf(s, "%s %s: %d\n", obj->name, obj->ops->driver_name, - obj->value); + seq_printf(s, "%s %s: %d\n", obj->name, obj->drv_name, obj->value); spin_lock_irqsave(&obj->child_list_lock, flags); list_for_each(pos, &obj->child_list_head) { -- cgit v0.10.2 From dcc280803e8a803643b6d12b2f35df608623c7fd Mon Sep 17 00:00:00 2001 From: Gustavo Padovan Date: Tue, 31 May 2016 16:58:59 -0300 Subject: staging/android: remove sw_sync_timeline and sw_sync_pt As we moved value storage to sync_timeline and fence those two structs became useless and can be removed now. Signed-off-by: Gustavo Padovan Reviewed-by: Daniel Vetter Reviewed-by: Sumit Semwal Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/android/sw_sync.c b/drivers/staging/android/sw_sync.c index c5e92c6..461dbd9 100644 --- a/drivers/staging/android/sw_sync.c +++ b/drivers/staging/android/sw_sync.c @@ -25,31 +25,21 @@ #include "sw_sync.h" -struct fence *sw_sync_pt_create(struct sw_sync_timeline *obj, u32 value) +struct fence *sw_sync_pt_create(struct sync_timeline *obj, u32 value) { - struct sw_sync_pt *pt; - - pt = (struct sw_sync_pt *) - sync_pt_create(&obj->obj, sizeof(struct sw_sync_pt), value); - - pt->value = value; - - return (struct fence *)pt; + return sync_pt_create(obj, sizeof(struct fence), value); } EXPORT_SYMBOL(sw_sync_pt_create); -struct sw_sync_timeline *sw_sync_timeline_create(const char *name) +struct sync_timeline *sw_sync_timeline_create(const char *name) { - struct sw_sync_timeline *obj = (struct sw_sync_timeline *) - sync_timeline_create(sizeof(struct sw_sync_timeline), - "sw_sync", name); - - return obj; + return sync_timeline_create(sizeof(struct sync_timeline), + "sw_sync", name); } EXPORT_SYMBOL(sw_sync_timeline_create); -void sw_sync_timeline_inc(struct sw_sync_timeline *obj, u32 inc) +void sw_sync_timeline_inc(struct sync_timeline *obj, u32 inc) { - sync_timeline_signal(&obj->obj, inc); + sync_timeline_signal(obj, inc); } EXPORT_SYMBOL(sw_sync_timeline_inc); diff --git a/drivers/staging/android/sw_sync.h b/drivers/staging/android/sw_sync.h index e18667b..9f26c62 100644 --- a/drivers/staging/android/sw_sync.h +++ b/drivers/staging/android/sw_sync.h @@ -22,34 +22,22 @@ #include "sync.h" #include "uapi/sw_sync.h" -struct sw_sync_timeline { - struct sync_timeline obj; - - u32 value; -}; - -struct sw_sync_pt { - struct fence pt; - - u32 value; -}; - #if IS_ENABLED(CONFIG_SW_SYNC) -struct sw_sync_timeline *sw_sync_timeline_create(const char *name); -void sw_sync_timeline_inc(struct sw_sync_timeline *obj, u32 inc); +struct sync_timeline *sw_sync_timeline_create(const char *name); +void sw_sync_timeline_inc(struct sync_timeline *obj, u32 inc); -struct fence *sw_sync_pt_create(struct sw_sync_timeline *obj, u32 value); +struct fence *sw_sync_pt_create(struct sync_timeline *obj, u32 value); #else -static inline struct sw_sync_timeline *sw_sync_timeline_create(const char *name) +static inline struct sync_timeline *sw_sync_timeline_create(const char *name) { return NULL; } -static inline void sw_sync_timeline_inc(struct sw_sync_timeline *obj, u32 inc) +static inline void sw_sync_timeline_inc(struct sync_timeline *obj, u32 inc) { } -static inline struct fence *sw_sync_pt_create(struct sw_sync_timeline *obj, +static inline struct fence *sw_sync_pt_create(struct sync_timeline *obj, u32 value) { return NULL; diff --git a/drivers/staging/android/sync_debug.c b/drivers/staging/android/sync_debug.c index e5634f2..e207a4d 100644 --- a/drivers/staging/android/sync_debug.c +++ b/drivers/staging/android/sync_debug.c @@ -209,7 +209,7 @@ static const struct file_operations sync_info_debugfs_fops = { /* opening sw_sync create a new sync obj */ static int sw_sync_debugfs_open(struct inode *inode, struct file *file) { - struct sw_sync_timeline *obj; + struct sync_timeline *obj; char task_comm[TASK_COMM_LEN]; get_task_comm(task_comm, current); @@ -225,13 +225,13 @@ static int sw_sync_debugfs_open(struct inode *inode, struct file *file) static int sw_sync_debugfs_release(struct inode *inode, struct file *file) { - struct sw_sync_timeline *obj = file->private_data; + struct sync_timeline *obj = file->private_data; - sync_timeline_destroy(&obj->obj); + sync_timeline_destroy(obj); return 0; } -static long sw_sync_ioctl_create_fence(struct sw_sync_timeline *obj, +static long sw_sync_ioctl_create_fence(struct sync_timeline *obj, unsigned long arg) { int fd = get_unused_fd_flags(O_CLOEXEC); @@ -277,7 +277,7 @@ err: return err; } -static long sw_sync_ioctl_inc(struct sw_sync_timeline *obj, unsigned long arg) +static long sw_sync_ioctl_inc(struct sync_timeline *obj, unsigned long arg) { u32 value; @@ -292,7 +292,7 @@ static long sw_sync_ioctl_inc(struct sw_sync_timeline *obj, unsigned long arg) static long sw_sync_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { - struct sw_sync_timeline *obj = file->private_data; + struct sync_timeline *obj = file->private_data; switch (cmd) { case SW_SYNC_IOC_CREATE_FENCE: -- cgit v0.10.2 From d21858fdb3269e98aa62d522efec7ce2865368e6 Mon Sep 17 00:00:00 2001 From: Gustavo Padovan Date: Tue, 31 May 2016 16:59:00 -0300 Subject: staging/android: remove sw_sync.[ch] files We can glue the sw_sync file operations directly on the sync framework without the need to pass through sw_sync wrappers. It only builds sw_sync debugfs file support if CONFIG_SW_SYNC is enabled. Signed-off-by: Gustavo Padovan Reviewed-by: Daniel Vetter Reviewed-by: Sumit Semwal Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/android/Makefile b/drivers/staging/android/Makefile index 980d6dc..bf45967 100644 --- a/drivers/staging/android/Makefile +++ b/drivers/staging/android/Makefile @@ -5,4 +5,3 @@ obj-y += ion/ obj-$(CONFIG_ASHMEM) += ashmem.o obj-$(CONFIG_ANDROID_LOW_MEMORY_KILLER) += lowmemorykiller.o obj-$(CONFIG_SYNC) += sync.o sync_debug.o -obj-$(CONFIG_SW_SYNC) += sw_sync.o diff --git a/drivers/staging/android/sw_sync.c b/drivers/staging/android/sw_sync.c deleted file mode 100644 index 461dbd9..0000000 --- a/drivers/staging/android/sw_sync.c +++ /dev/null @@ -1,45 +0,0 @@ -/* - * drivers/base/sw_sync.c - * - * Copyright (C) 2012 Google, Inc. - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "sw_sync.h" - -struct fence *sw_sync_pt_create(struct sync_timeline *obj, u32 value) -{ - return sync_pt_create(obj, sizeof(struct fence), value); -} -EXPORT_SYMBOL(sw_sync_pt_create); - -struct sync_timeline *sw_sync_timeline_create(const char *name) -{ - return sync_timeline_create(sizeof(struct sync_timeline), - "sw_sync", name); -} -EXPORT_SYMBOL(sw_sync_timeline_create); - -void sw_sync_timeline_inc(struct sync_timeline *obj, u32 inc) -{ - sync_timeline_signal(obj, inc); -} -EXPORT_SYMBOL(sw_sync_timeline_inc); diff --git a/drivers/staging/android/sw_sync.h b/drivers/staging/android/sw_sync.h deleted file mode 100644 index 9f26c62..0000000 --- a/drivers/staging/android/sw_sync.h +++ /dev/null @@ -1,47 +0,0 @@ -/* - * include/linux/sw_sync.h - * - * Copyright (C) 2012 Google, Inc. - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ - -#ifndef _LINUX_SW_SYNC_H -#define _LINUX_SW_SYNC_H - -#include -#include -#include "sync.h" -#include "uapi/sw_sync.h" - -#if IS_ENABLED(CONFIG_SW_SYNC) -struct sync_timeline *sw_sync_timeline_create(const char *name); -void sw_sync_timeline_inc(struct sync_timeline *obj, u32 inc); - -struct fence *sw_sync_pt_create(struct sync_timeline *obj, u32 value); -#else -static inline struct sync_timeline *sw_sync_timeline_create(const char *name) -{ - return NULL; -} - -static inline void sw_sync_timeline_inc(struct sync_timeline *obj, u32 inc) -{ -} - -static inline struct fence *sw_sync_pt_create(struct sync_timeline *obj, - u32 value) -{ - return NULL; -} -#endif /* IS_ENABLED(CONFIG_SW_SYNC) */ - -#endif /* _LINUX_SW_SYNC_H */ diff --git a/drivers/staging/android/sync_debug.c b/drivers/staging/android/sync_debug.c index e207a4d..dc85d5f 100644 --- a/drivers/staging/android/sync_debug.c +++ b/drivers/staging/android/sync_debug.c @@ -27,7 +27,11 @@ #include #include #include -#include "sw_sync.h" +#include +#include + +#include "uapi/sw_sync.h" +#include "sync.h" #ifdef CONFIG_DEBUG_FS @@ -200,6 +204,7 @@ static const struct file_operations sync_info_debugfs_fops = { .release = single_release, }; +#if IS_ENABLED(CONFIG_SW_SYNC) /* * *WARNING* * @@ -214,7 +219,7 @@ static int sw_sync_debugfs_open(struct inode *inode, struct file *file) get_task_comm(task_comm, current); - obj = sw_sync_timeline_create(task_comm); + obj = sync_timeline_create(sizeof(*obj), "sw_sync", task_comm); if (!obj) return -ENOMEM; @@ -248,7 +253,7 @@ static long sw_sync_ioctl_create_fence(struct sync_timeline *obj, goto err; } - fence = sw_sync_pt_create(obj, data.value); + fence = sync_pt_create(obj, sizeof(*fence), data.value); if (!fence) { err = -ENOMEM; goto err; @@ -284,7 +289,7 @@ static long sw_sync_ioctl_inc(struct sync_timeline *obj, unsigned long arg) if (copy_from_user(&value, (void __user *)arg, sizeof(value))) return -EFAULT; - sw_sync_timeline_inc(obj, value); + sync_timeline_signal(obj, value); return 0; } @@ -312,14 +317,18 @@ static const struct file_operations sw_sync_debugfs_fops = { .unlocked_ioctl = sw_sync_ioctl, .compat_ioctl = sw_sync_ioctl, }; +#endif static __init int sync_debugfs_init(void) { dbgfs = debugfs_create_dir("sync", NULL); debugfs_create_file("info", 0444, dbgfs, NULL, &sync_info_debugfs_fops); + +#if IS_ENABLED(CONFIG_SW_SYNC) debugfs_create_file("sw_sync", 0644, dbgfs, NULL, &sw_sync_debugfs_fops); +#endif return 0; } -- cgit v0.10.2 From 4be6e00cd34210d5b3d37ddb7bf46137cf5a99b1 Mon Sep 17 00:00:00 2001 From: Gustavo Padovan Date: Tue, 31 May 2016 16:59:01 -0300 Subject: staging/android: rename android_fence to timeline_fence We are moving out of staging/android so rename it to a name that is not related to android anymore. Signed-off-by: Gustavo Padovan Reviewed-by: Daniel Vetter Reviewed-by: Sumit Semwal Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/android/sync.c b/drivers/staging/android/sync.c index b3efcaa..442d808 100644 --- a/drivers/staging/android/sync.c +++ b/drivers/staging/android/sync.c @@ -28,7 +28,7 @@ #define CREATE_TRACE_POINTS #include "trace/sync.h" -static const struct fence_ops android_fence_ops; +static const struct fence_ops timeline_fence_ops; struct sync_timeline *sync_timeline_create(int size, const char *drv_name, const char *name) @@ -126,7 +126,7 @@ struct fence *sync_pt_create(struct sync_timeline *obj, int size, spin_lock_irqsave(&obj->child_list_lock, flags); sync_timeline_get(obj); - fence_init(fence, &android_fence_ops, &obj->child_list_lock, + fence_init(fence, &timeline_fence_ops, &obj->child_list_lock, obj->context, value); list_add_tail(&fence->child_list, &obj->child_list_head); INIT_LIST_HEAD(&fence->active_list); @@ -135,21 +135,21 @@ struct fence *sync_pt_create(struct sync_timeline *obj, int size, } EXPORT_SYMBOL(sync_pt_create); -static const char *android_fence_get_driver_name(struct fence *fence) +static const char *timeline_fence_get_driver_name(struct fence *fence) { struct sync_timeline *parent = fence_parent(fence); return parent->drv_name; } -static const char *android_fence_get_timeline_name(struct fence *fence) +static const char *timeline_fence_get_timeline_name(struct fence *fence) { struct sync_timeline *parent = fence_parent(fence); return parent->name; } -static void android_fence_release(struct fence *fence) +static void timeline_fence_release(struct fence *fence) { struct sync_timeline *parent = fence_parent(fence); unsigned long flags; @@ -164,31 +164,31 @@ static void android_fence_release(struct fence *fence) fence_free(fence); } -static bool android_fence_signaled(struct fence *fence) +static bool timeline_fence_signaled(struct fence *fence) { struct sync_timeline *parent = fence_parent(fence); return (fence->seqno > parent->value) ? false : true; } -static bool android_fence_enable_signaling(struct fence *fence) +static bool timeline_fence_enable_signaling(struct fence *fence) { struct sync_timeline *parent = fence_parent(fence); - if (android_fence_signaled(fence)) + if (timeline_fence_signaled(fence)) return false; list_add_tail(&fence->active_list, &parent->active_list_head); return true; } -static void android_fence_value_str(struct fence *fence, +static void timeline_fence_value_str(struct fence *fence, char *str, int size) { snprintf(str, size, "%d", fence->seqno); } -static void android_fence_timeline_value_str(struct fence *fence, +static void timeline_fence_timeline_value_str(struct fence *fence, char *str, int size) { struct sync_timeline *parent = fence_parent(fence); @@ -196,13 +196,13 @@ static void android_fence_timeline_value_str(struct fence *fence, snprintf(str, size, "%d", parent->value); } -static const struct fence_ops android_fence_ops = { - .get_driver_name = android_fence_get_driver_name, - .get_timeline_name = android_fence_get_timeline_name, - .enable_signaling = android_fence_enable_signaling, - .signaled = android_fence_signaled, +static const struct fence_ops timeline_fence_ops = { + .get_driver_name = timeline_fence_get_driver_name, + .get_timeline_name = timeline_fence_get_timeline_name, + .enable_signaling = timeline_fence_enable_signaling, + .signaled = timeline_fence_signaled, .wait = fence_default_wait, - .release = android_fence_release, - .fence_value_str = android_fence_value_str, - .timeline_value_str = android_fence_timeline_value_str, + .release = timeline_fence_release, + .fence_value_str = timeline_fence_value_str, + .timeline_value_str = timeline_fence_timeline_value_str, }; -- cgit v0.10.2 From 724812d6a66e3a1524f7eb78b900bc0624b6d7dc Mon Sep 17 00:00:00 2001 From: Gustavo Padovan Date: Tue, 31 May 2016 16:59:02 -0300 Subject: staging/android: remove unnecessary check for fence When we call sync_print_fence() fence is always valid. Signed-off-by: Gustavo Padovan Reviewed-by: Daniel Vetter Reviewed-by: Sumit Semwal Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/android/sync_debug.c b/drivers/staging/android/sync_debug.c index dc85d5f..6282046 100644 --- a/drivers/staging/android/sync_debug.c +++ b/drivers/staging/android/sync_debug.c @@ -109,7 +109,7 @@ static void sync_print_fence(struct seq_file *s, struct fence *fence, bool show) seq_printf(s, "@%lld.%09ld", (s64)ts64.tv_sec, ts64.tv_nsec); } - if ((!fence || fence->ops->timeline_value_str) && + if (fence->ops->timeline_value_str && fence->ops->fence_value_str) { char value[64]; bool success; @@ -117,10 +117,9 @@ static void sync_print_fence(struct seq_file *s, struct fence *fence, bool show) fence->ops->fence_value_str(fence, value, sizeof(value)); success = strlen(value); - if (success) + if (success) { seq_printf(s, ": %s", value); - if (success && fence) { fence->ops->timeline_value_str(fence, value, sizeof(value)); -- cgit v0.10.2 From 62627c8f61e09a6204cd77de30df9a83ff158812 Mon Sep 17 00:00:00 2001 From: Gustavo Padovan Date: Tue, 31 May 2016 16:59:03 -0300 Subject: staging/android: remove size arg of sync_timeline_create() After we removed sw_sync_timeline this arg has not been really used by anyone, all its users pass the size of struct sync_timeline there. So simplify this function but not requiring the size anymore. Signed-off-by: Gustavo Padovan Reviewed-by: Daniel Vetter Reviewed-by: Sumit Semwal Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/android/sync.c b/drivers/staging/android/sync.c index 442d808..c83a599 100644 --- a/drivers/staging/android/sync.c +++ b/drivers/staging/android/sync.c @@ -30,15 +30,12 @@ static const struct fence_ops timeline_fence_ops; -struct sync_timeline *sync_timeline_create(int size, const char *drv_name, +struct sync_timeline *sync_timeline_create(const char *drv_name, const char *name) { struct sync_timeline *obj; - if (size < sizeof(struct sync_timeline)) - return NULL; - - obj = kzalloc(size, GFP_KERNEL); + obj = kzalloc(sizeof(*obj), GFP_KERNEL); if (!obj) return NULL; diff --git a/drivers/staging/android/sync.h b/drivers/staging/android/sync.h index f003e97..f2fbf98 100644 --- a/drivers/staging/android/sync.h +++ b/drivers/staging/android/sync.h @@ -66,16 +66,13 @@ static inline struct sync_timeline *fence_parent(struct fence *fence) /** * sync_timeline_create() - creates a sync object - * @size: size to allocate for this obj * @drv_name: sync_timeline driver name * @name: sync_timeline name * - * Creates a new sync_timeline. @size bytes will be allocated allowing - * for implementation specific data to be kept after the generic - * sync_timeline struct. Returns the sync_timeline object or NULL in + * Creates a new sync_timeline. Returns the sync_timeline object or NULL in * case of error. */ -struct sync_timeline *sync_timeline_create(int size, const char *drv_name, +struct sync_timeline *sync_timeline_create(const char *drv_name, const char *name); /** diff --git a/drivers/staging/android/sync_debug.c b/drivers/staging/android/sync_debug.c index 6282046..cb0f888 100644 --- a/drivers/staging/android/sync_debug.c +++ b/drivers/staging/android/sync_debug.c @@ -218,7 +218,7 @@ static int sw_sync_debugfs_open(struct inode *inode, struct file *file) get_task_comm(task_comm, current); - obj = sync_timeline_create(sizeof(*obj), "sw_sync", task_comm); + obj = sync_timeline_create("sw_sync", task_comm); if (!obj) return -ENOMEM; -- cgit v0.10.2 From 0431b9065f28ecf6c320fefebe0241620049984f Mon Sep 17 00:00:00 2001 From: Gustavo Padovan Date: Tue, 31 May 2016 16:59:04 -0300 Subject: staging/android: bring struct sync_pt back Move the list_head members from sync_pt to struct fence was a mistake, they will not be used by struct fence as planned before, so here we create sync_pt again to bring the list heads back. Signed-off-by: Gustavo Padovan Reviewed-by: Daniel Vetter Reviewed-by: Sumit Semwal Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/android/sync.c b/drivers/staging/android/sync.c index c83a599..aab80ec 100644 --- a/drivers/staging/android/sync.c +++ b/drivers/staging/android/sync.c @@ -28,8 +28,6 @@ #define CREATE_TRACE_POINTS #include "trace/sync.h" -static const struct fence_ops timeline_fence_ops; - struct sync_timeline *sync_timeline_create(const char *drv_name, const char *name) { @@ -90,7 +88,7 @@ EXPORT_SYMBOL(sync_timeline_destroy); void sync_timeline_signal(struct sync_timeline *obj, unsigned int inc) { unsigned long flags; - struct fence *fence, *next; + struct sync_pt *pt, *next; trace_sync_timeline(obj); @@ -98,37 +96,37 @@ void sync_timeline_signal(struct sync_timeline *obj, unsigned int inc) obj->value += inc; - list_for_each_entry_safe(fence, next, &obj->active_list_head, + list_for_each_entry_safe(pt, next, &obj->active_list_head, active_list) { - if (fence_is_signaled_locked(fence)) - list_del_init(&fence->active_list); + if (fence_is_signaled_locked(&pt->base)) + list_del_init(&pt->active_list); } spin_unlock_irqrestore(&obj->child_list_lock, flags); } EXPORT_SYMBOL(sync_timeline_signal); -struct fence *sync_pt_create(struct sync_timeline *obj, int size, +struct sync_pt *sync_pt_create(struct sync_timeline *obj, int size, unsigned int value) { unsigned long flags; - struct fence *fence; + struct sync_pt *pt; - if (size < sizeof(*fence)) + if (size < sizeof(*pt)) return NULL; - fence = kzalloc(size, GFP_KERNEL); - if (!fence) + pt = kzalloc(size, GFP_KERNEL); + if (!pt) return NULL; spin_lock_irqsave(&obj->child_list_lock, flags); sync_timeline_get(obj); - fence_init(fence, &timeline_fence_ops, &obj->child_list_lock, + fence_init(&pt->base, &timeline_fence_ops, &obj->child_list_lock, obj->context, value); - list_add_tail(&fence->child_list, &obj->child_list_head); - INIT_LIST_HEAD(&fence->active_list); + list_add_tail(&pt->child_list, &obj->child_list_head); + INIT_LIST_HEAD(&pt->active_list); spin_unlock_irqrestore(&obj->child_list_lock, flags); - return fence; + return pt; } EXPORT_SYMBOL(sync_pt_create); @@ -148,13 +146,14 @@ static const char *timeline_fence_get_timeline_name(struct fence *fence) static void timeline_fence_release(struct fence *fence) { + struct sync_pt *pt = fence_to_sync_pt(fence); struct sync_timeline *parent = fence_parent(fence); unsigned long flags; spin_lock_irqsave(fence->lock, flags); - list_del(&fence->child_list); - if (WARN_ON_ONCE(!list_empty(&fence->active_list))) - list_del(&fence->active_list); + list_del(&pt->child_list); + if (WARN_ON_ONCE(!list_empty(&pt->active_list))) + list_del(&pt->active_list); spin_unlock_irqrestore(fence->lock, flags); sync_timeline_put(parent); @@ -170,12 +169,13 @@ static bool timeline_fence_signaled(struct fence *fence) static bool timeline_fence_enable_signaling(struct fence *fence) { + struct sync_pt *pt = fence_to_sync_pt(fence); struct sync_timeline *parent = fence_parent(fence); if (timeline_fence_signaled(fence)) return false; - list_add_tail(&fence->active_list, &parent->active_list_head); + list_add_tail(&pt->active_list, &parent->active_list_head); return true; } @@ -193,7 +193,7 @@ static void timeline_fence_timeline_value_str(struct fence *fence, snprintf(str, size, "%d", parent->value); } -static const struct fence_ops timeline_fence_ops = { +const struct fence_ops timeline_fence_ops = { .get_driver_name = timeline_fence_get_driver_name, .get_timeline_name = timeline_fence_get_timeline_name, .enable_signaling = timeline_fence_enable_signaling, diff --git a/drivers/staging/android/sync.h b/drivers/staging/android/sync.h index f2fbf98..14b61cb 100644 --- a/drivers/staging/android/sync.h +++ b/drivers/staging/android/sync.h @@ -60,6 +60,27 @@ static inline struct sync_timeline *fence_parent(struct fence *fence) child_list_lock); } +/** + * struct sync_pt - sync_pt object + * @base: base fence object + * @child_list: sync timeline child's list + * @active_list: sync timeline active child's list + */ +struct sync_pt { + struct fence base; + struct list_head child_list; + struct list_head active_list; +}; + +extern const struct fence_ops timeline_fence_ops; + +static inline struct sync_pt *fence_to_sync_pt(struct fence *fence) +{ + if (fence->ops != &timeline_fence_ops) + return NULL; + return container_of(fence, struct sync_pt, base); +} + /* * API for sync_timeline implementers */ @@ -101,13 +122,13 @@ void sync_timeline_signal(struct sync_timeline *obj, unsigned int inc); * @size: size to allocate for this pt * @inc: value of the fence * - * Creates a new fence as a child of @parent. @size bytes will be + * Creates a new sync_pt as a child of @parent. @size bytes will be * allocated allowing for implementation specific data to be kept after - * the generic sync_timeline struct. Returns the fence object or + * the generic sync_timeline struct. Returns the sync_pt object or * NULL in case of error. */ -struct fence *sync_pt_create(struct sync_timeline *parent, int size, - unsigned int inc); +struct sync_pt *sync_pt_create(struct sync_timeline *parent, int size, + unsigned int inc); #ifdef CONFIG_DEBUG_FS diff --git a/drivers/staging/android/sync_debug.c b/drivers/staging/android/sync_debug.c index cb0f888..703f198 100644 --- a/drivers/staging/android/sync_debug.c +++ b/drivers/staging/android/sync_debug.c @@ -140,9 +140,9 @@ static void sync_print_obj(struct seq_file *s, struct sync_timeline *obj) spin_lock_irqsave(&obj->child_list_lock, flags); list_for_each(pos, &obj->child_list_head) { - struct fence *fence = - container_of(pos, struct fence, child_list); - sync_print_fence(s, fence, false); + struct sync_pt *pt = + container_of(pos, struct sync_pt, child_list); + sync_print_fence(s, &pt->base, false); } spin_unlock_irqrestore(&obj->child_list_lock, flags); } @@ -240,7 +240,7 @@ static long sw_sync_ioctl_create_fence(struct sync_timeline *obj, { int fd = get_unused_fd_flags(O_CLOEXEC); int err; - struct fence *fence; + struct sync_pt *pt; struct sync_file *sync_file; struct sw_sync_create_fence_data data; @@ -252,15 +252,15 @@ static long sw_sync_ioctl_create_fence(struct sync_timeline *obj, goto err; } - fence = sync_pt_create(obj, sizeof(*fence), data.value); - if (!fence) { + pt = sync_pt_create(obj, sizeof(*pt), data.value); + if (!pt) { err = -ENOMEM; goto err; } - sync_file = sync_file_create(fence); + sync_file = sync_file_create(&pt->base); if (!sync_file) { - fence_put(fence); + fence_put(&pt->base); err = -ENOMEM; goto err; } diff --git a/include/linux/fence.h b/include/linux/fence.h index 2056e9f..1de1b3f 100644 --- a/include/linux/fence.h +++ b/include/linux/fence.h @@ -81,8 +81,6 @@ struct fence { unsigned long flags; ktime_t timestamp; int status; - struct list_head child_list; - struct list_head active_list; }; enum fence_flag_bits { -- cgit v0.10.2 From 1867a23b13b25d0a228b0509ade20fb977dcb601 Mon Sep 17 00:00:00 2001 From: Gustavo Padovan Date: Tue, 31 May 2016 16:59:05 -0300 Subject: staging/android: move sw_sync related code to sw_sync.c Split sync_debug and sw_sync in two different files. Signed-off-by: Gustavo Padovan Reviewed-by: Daniel Vetter Reviewed-by: Sumit Semwal Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/android/Makefile b/drivers/staging/android/Makefile index bf45967..980d6dc 100644 --- a/drivers/staging/android/Makefile +++ b/drivers/staging/android/Makefile @@ -5,3 +5,4 @@ obj-y += ion/ obj-$(CONFIG_ASHMEM) += ashmem.o obj-$(CONFIG_ANDROID_LOW_MEMORY_KILLER) += lowmemorykiller.o obj-$(CONFIG_SYNC) += sync.o sync_debug.o +obj-$(CONFIG_SW_SYNC) += sw_sync.o diff --git a/drivers/staging/android/sw_sync.c b/drivers/staging/android/sw_sync.c new file mode 100644 index 0000000..90e3ee5 --- /dev/null +++ b/drivers/staging/android/sw_sync.c @@ -0,0 +1,136 @@ +/* + * drivers/dma-buf/sw_sync.c + * + * Copyright (C) 2012 Google, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include +#include +#include +#include + +#include "uapi/sw_sync.h" +#include "sync.h" + +/* + * *WARNING* + * + * improper use of this can result in deadlocking kernel drivers from userspace. + */ + +/* opening sw_sync create a new sync obj */ +static int sw_sync_debugfs_open(struct inode *inode, struct file *file) +{ + struct sync_timeline *obj; + char task_comm[TASK_COMM_LEN]; + + get_task_comm(task_comm, current); + + obj = sync_timeline_create("sw_sync", task_comm); + if (!obj) + return -ENOMEM; + + file->private_data = obj; + + return 0; +} + +static int sw_sync_debugfs_release(struct inode *inode, struct file *file) +{ + struct sync_timeline *obj = file->private_data; + + sync_timeline_destroy(obj); + return 0; +} + +static long sw_sync_ioctl_create_fence(struct sync_timeline *obj, + unsigned long arg) +{ + int fd = get_unused_fd_flags(O_CLOEXEC); + int err; + struct sync_pt *pt; + struct sync_file *sync_file; + struct sw_sync_create_fence_data data; + + if (fd < 0) + return fd; + + if (copy_from_user(&data, (void __user *)arg, sizeof(data))) { + err = -EFAULT; + goto err; + } + + pt = sync_pt_create(obj, sizeof(*pt), data.value); + if (!pt) { + err = -ENOMEM; + goto err; + } + + sync_file = sync_file_create(&pt->base); + if (!sync_file) { + fence_put(&pt->base); + err = -ENOMEM; + goto err; + } + + data.fence = fd; + if (copy_to_user((void __user *)arg, &data, sizeof(data))) { + fput(sync_file->file); + err = -EFAULT; + goto err; + } + + fd_install(fd, sync_file->file); + + return 0; + +err: + put_unused_fd(fd); + return err; +} + +static long sw_sync_ioctl_inc(struct sync_timeline *obj, unsigned long arg) +{ + u32 value; + + if (copy_from_user(&value, (void __user *)arg, sizeof(value))) + return -EFAULT; + + sync_timeline_signal(obj, value); + + return 0; +} + +static long sw_sync_ioctl(struct file *file, unsigned int cmd, + unsigned long arg) +{ + struct sync_timeline *obj = file->private_data; + + switch (cmd) { + case SW_SYNC_IOC_CREATE_FENCE: + return sw_sync_ioctl_create_fence(obj, arg); + + case SW_SYNC_IOC_INC: + return sw_sync_ioctl_inc(obj, arg); + + default: + return -ENOTTY; + } +} + +const struct file_operations sw_sync_debugfs_fops = { + .open = sw_sync_debugfs_open, + .release = sw_sync_debugfs_release, + .unlocked_ioctl = sw_sync_ioctl, + .compat_ioctl = sw_sync_ioctl, +}; diff --git a/drivers/staging/android/sync.h b/drivers/staging/android/sync.h index 14b61cb..02ecf44 100644 --- a/drivers/staging/android/sync.h +++ b/drivers/staging/android/sync.h @@ -132,6 +132,8 @@ struct sync_pt *sync_pt_create(struct sync_timeline *parent, int size, #ifdef CONFIG_DEBUG_FS +extern const struct file_operations sw_sync_debugfs_fops; + void sync_timeline_debug_add(struct sync_timeline *obj); void sync_timeline_debug_remove(struct sync_timeline *obj); void sync_file_debug_add(struct sync_file *fence); diff --git a/drivers/staging/android/sync_debug.c b/drivers/staging/android/sync_debug.c index 703f198..2733cc3 100644 --- a/drivers/staging/android/sync_debug.c +++ b/drivers/staging/android/sync_debug.c @@ -203,121 +203,6 @@ static const struct file_operations sync_info_debugfs_fops = { .release = single_release, }; -#if IS_ENABLED(CONFIG_SW_SYNC) -/* - * *WARNING* - * - * improper use of this can result in deadlocking kernel drivers from userspace. - */ - -/* opening sw_sync create a new sync obj */ -static int sw_sync_debugfs_open(struct inode *inode, struct file *file) -{ - struct sync_timeline *obj; - char task_comm[TASK_COMM_LEN]; - - get_task_comm(task_comm, current); - - obj = sync_timeline_create("sw_sync", task_comm); - if (!obj) - return -ENOMEM; - - file->private_data = obj; - - return 0; -} - -static int sw_sync_debugfs_release(struct inode *inode, struct file *file) -{ - struct sync_timeline *obj = file->private_data; - - sync_timeline_destroy(obj); - return 0; -} - -static long sw_sync_ioctl_create_fence(struct sync_timeline *obj, - unsigned long arg) -{ - int fd = get_unused_fd_flags(O_CLOEXEC); - int err; - struct sync_pt *pt; - struct sync_file *sync_file; - struct sw_sync_create_fence_data data; - - if (fd < 0) - return fd; - - if (copy_from_user(&data, (void __user *)arg, sizeof(data))) { - err = -EFAULT; - goto err; - } - - pt = sync_pt_create(obj, sizeof(*pt), data.value); - if (!pt) { - err = -ENOMEM; - goto err; - } - - sync_file = sync_file_create(&pt->base); - if (!sync_file) { - fence_put(&pt->base); - err = -ENOMEM; - goto err; - } - - data.fence = fd; - if (copy_to_user((void __user *)arg, &data, sizeof(data))) { - fput(sync_file->file); - err = -EFAULT; - goto err; - } - - fd_install(fd, sync_file->file); - - return 0; - -err: - put_unused_fd(fd); - return err; -} - -static long sw_sync_ioctl_inc(struct sync_timeline *obj, unsigned long arg) -{ - u32 value; - - if (copy_from_user(&value, (void __user *)arg, sizeof(value))) - return -EFAULT; - - sync_timeline_signal(obj, value); - - return 0; -} - -static long sw_sync_ioctl(struct file *file, unsigned int cmd, - unsigned long arg) -{ - struct sync_timeline *obj = file->private_data; - - switch (cmd) { - case SW_SYNC_IOC_CREATE_FENCE: - return sw_sync_ioctl_create_fence(obj, arg); - - case SW_SYNC_IOC_INC: - return sw_sync_ioctl_inc(obj, arg); - - default: - return -ENOTTY; - } -} - -static const struct file_operations sw_sync_debugfs_fops = { - .open = sw_sync_debugfs_open, - .release = sw_sync_debugfs_release, - .unlocked_ioctl = sw_sync_ioctl, - .compat_ioctl = sw_sync_ioctl, -}; -#endif - static __init int sync_debugfs_init(void) { dbgfs = debugfs_create_dir("sync", NULL); -- cgit v0.10.2 From d79892ad0b97ec23645cffa5406edb4eb18cb553 Mon Sep 17 00:00:00 2001 From: Gustavo Padovan Date: Tue, 31 May 2016 16:59:06 -0300 Subject: staging/android: clean up #includes in the sync framework Most of the includes there are not necessary anymore. Signed-off-by: Gustavo Padovan Reviewed-by: Daniel Vetter Reviewed-by: Sumit Semwal Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/android/sync.c b/drivers/staging/android/sync.c index aab80ec..bb12d86 100644 --- a/drivers/staging/android/sync.c +++ b/drivers/staging/android/sync.c @@ -14,14 +14,8 @@ * */ -#include #include -#include -#include -#include #include -#include -#include #include "sync.h" diff --git a/drivers/staging/android/sync.h b/drivers/staging/android/sync.h index 02ecf44..54c515b 100644 --- a/drivers/staging/android/sync.h +++ b/drivers/staging/android/sync.h @@ -13,9 +13,6 @@ #ifndef _LINUX_SYNC_H #define _LINUX_SYNC_H -#include -#include -#include #include #include #include diff --git a/drivers/staging/android/sync_debug.c b/drivers/staging/android/sync_debug.c index 2733cc3..864ad01 100644 --- a/drivers/staging/android/sync_debug.c +++ b/drivers/staging/android/sync_debug.c @@ -15,22 +15,6 @@ */ #include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "uapi/sw_sync.h" #include "sync.h" #ifdef CONFIG_DEBUG_FS -- cgit v0.10.2 From aff9da10e218c54f5ffc8bcb66c9837135074190 Mon Sep 17 00:00:00 2001 From: Gustavo Padovan Date: Tue, 31 May 2016 16:59:07 -0300 Subject: staging/android: make sync_timeline internal to sw_sync The only use sync_timeline will have in upstream kernel is for debugging through the SW_SYNC interface. So make it internal to SW_SYNC to avoid people use it in the future. Signed-off-by: Gustavo Padovan Reviewed-by: Daniel Vetter Reviewed-by: Sumit Semwal Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/android/Kconfig b/drivers/staging/android/Kconfig index 6480f60..f52c682 100644 --- a/drivers/staging/android/Kconfig +++ b/drivers/staging/android/Kconfig @@ -24,26 +24,18 @@ config ANDROID_LOW_MEMORY_KILLER scripts (/init.rc), and it defines priority values with minimum free memory size for each priority. -config SYNC - bool "Synchronization framework" - default n - select ANON_INODES - select DMA_SHARED_BUFFER - ---help--- - This option enables the framework for synchronization between multiple - drivers. Sync implementations can take advantage of hardware - synchronization built into devices like GPUs. - config SW_SYNC - bool "Software synchronization objects" + bool "Software synchronization framework" default n - depends on SYNC depends on SYNC_FILE ---help--- A sync object driver that uses a 32bit counter to coordinate synchronization. Useful when there is no hardware primitive backing the synchronization. + WARNING: improper use of this can result in deadlocking kernel + drivers from userspace. Intended for test and debug only. + source "drivers/staging/android/ion/Kconfig" endif # if ANDROID diff --git a/drivers/staging/android/Makefile b/drivers/staging/android/Makefile index 980d6dc..7ca61b7 100644 --- a/drivers/staging/android/Makefile +++ b/drivers/staging/android/Makefile @@ -4,5 +4,4 @@ obj-y += ion/ obj-$(CONFIG_ASHMEM) += ashmem.o obj-$(CONFIG_ANDROID_LOW_MEMORY_KILLER) += lowmemorykiller.o -obj-$(CONFIG_SYNC) += sync.o sync_debug.o -obj-$(CONFIG_SW_SYNC) += sw_sync.o +obj-$(CONFIG_SW_SYNC) += sw_sync.o sync_debug.o diff --git a/drivers/staging/android/sw_sync.c b/drivers/staging/android/sw_sync.c index 90e3ee5..c149ac90 100644 --- a/drivers/staging/android/sw_sync.c +++ b/drivers/staging/android/sw_sync.c @@ -17,11 +17,231 @@ #include #include #include +#include #include #include "uapi/sw_sync.h" #include "sync.h" +#define CREATE_TRACE_POINTS +#include "trace/sync.h" + +static const struct fence_ops timeline_fence_ops; + +static inline struct sync_pt *fence_to_sync_pt(struct fence *fence) +{ + if (fence->ops != &timeline_fence_ops) + return NULL; + return container_of(fence, struct sync_pt, base); +} + +/** + * sync_timeline_create() - creates a sync object + * @drv_name: sync_timeline driver name + * @name: sync_timeline name + * + * Creates a new sync_timeline. Returns the sync_timeline object or NULL in + * case of error. + */ +struct sync_timeline *sync_timeline_create(const char *drv_name, + const char *name) +{ + struct sync_timeline *obj; + + obj = kzalloc(sizeof(*obj), GFP_KERNEL); + if (!obj) + return NULL; + + kref_init(&obj->kref); + obj->context = fence_context_alloc(1); + strlcpy(obj->name, name, sizeof(obj->name)); + strlcpy(obj->drv_name, drv_name, sizeof(obj->drv_name)); + + INIT_LIST_HEAD(&obj->child_list_head); + INIT_LIST_HEAD(&obj->active_list_head); + spin_lock_init(&obj->child_list_lock); + + sync_timeline_debug_add(obj); + + return obj; +} + +static void sync_timeline_free(struct kref *kref) +{ + struct sync_timeline *obj = + container_of(kref, struct sync_timeline, kref); + + sync_timeline_debug_remove(obj); + + kfree(obj); +} + +static void sync_timeline_get(struct sync_timeline *obj) +{ + kref_get(&obj->kref); +} + +static void sync_timeline_put(struct sync_timeline *obj) +{ + kref_put(&obj->kref, sync_timeline_free); +} + +/** + * sync_timeline_destroy() - destroys a sync object + * @obj: sync_timeline to destroy + * + * A sync implementation should call this when the @obj is going away + * (i.e. module unload.) @obj won't actually be freed until all its children + * fences are freed. + */ +static void sync_timeline_destroy(struct sync_timeline *obj) +{ + obj->destroyed = true; + /* + * Ensure timeline is marked as destroyed before + * changing timeline's fences status. + */ + smp_wmb(); + + sync_timeline_put(obj); +} + +/** + * sync_timeline_signal() - signal a status change on a sync_timeline + * @obj: sync_timeline to signal + * @inc: num to increment on timeline->value + * + * A sync implementation should call this any time one of it's fences + * has signaled or has an error condition. + */ +static void sync_timeline_signal(struct sync_timeline *obj, unsigned int inc) +{ + unsigned long flags; + struct sync_pt *pt, *next; + + trace_sync_timeline(obj); + + spin_lock_irqsave(&obj->child_list_lock, flags); + + obj->value += inc; + + list_for_each_entry_safe(pt, next, &obj->active_list_head, + active_list) { + if (fence_is_signaled_locked(&pt->base)) + list_del_init(&pt->active_list); + } + + spin_unlock_irqrestore(&obj->child_list_lock, flags); +} + +/** + * sync_pt_create() - creates a sync pt + * @parent: fence's parent sync_timeline + * @size: size to allocate for this pt + * @inc: value of the fence + * + * Creates a new sync_pt as a child of @parent. @size bytes will be + * allocated allowing for implementation specific data to be kept after + * the generic sync_timeline struct. Returns the sync_pt object or + * NULL in case of error. + */ +static struct sync_pt *sync_pt_create(struct sync_timeline *obj, int size, + unsigned int value) +{ + unsigned long flags; + struct sync_pt *pt; + + if (size < sizeof(*pt)) + return NULL; + + pt = kzalloc(size, GFP_KERNEL); + if (!pt) + return NULL; + + spin_lock_irqsave(&obj->child_list_lock, flags); + sync_timeline_get(obj); + fence_init(&pt->base, &timeline_fence_ops, &obj->child_list_lock, + obj->context, value); + list_add_tail(&pt->child_list, &obj->child_list_head); + INIT_LIST_HEAD(&pt->active_list); + spin_unlock_irqrestore(&obj->child_list_lock, flags); + return pt; +} + +static const char *timeline_fence_get_driver_name(struct fence *fence) +{ + struct sync_timeline *parent = fence_parent(fence); + + return parent->drv_name; +} + +static const char *timeline_fence_get_timeline_name(struct fence *fence) +{ + struct sync_timeline *parent = fence_parent(fence); + + return parent->name; +} + +static void timeline_fence_release(struct fence *fence) +{ + struct sync_pt *pt = fence_to_sync_pt(fence); + struct sync_timeline *parent = fence_parent(fence); + unsigned long flags; + + spin_lock_irqsave(fence->lock, flags); + list_del(&pt->child_list); + if (WARN_ON_ONCE(!list_empty(&pt->active_list))) + list_del(&pt->active_list); + spin_unlock_irqrestore(fence->lock, flags); + + sync_timeline_put(parent); + fence_free(fence); +} + +static bool timeline_fence_signaled(struct fence *fence) +{ + struct sync_timeline *parent = fence_parent(fence); + + return (fence->seqno > parent->value) ? false : true; +} + +static bool timeline_fence_enable_signaling(struct fence *fence) +{ + struct sync_pt *pt = fence_to_sync_pt(fence); + struct sync_timeline *parent = fence_parent(fence); + + if (timeline_fence_signaled(fence)) + return false; + + list_add_tail(&pt->active_list, &parent->active_list_head); + return true; +} + +static void timeline_fence_value_str(struct fence *fence, + char *str, int size) +{ + snprintf(str, size, "%d", fence->seqno); +} + +static void timeline_fence_timeline_value_str(struct fence *fence, + char *str, int size) +{ + struct sync_timeline *parent = fence_parent(fence); + + snprintf(str, size, "%d", parent->value); +} + +static const struct fence_ops timeline_fence_ops = { + .get_driver_name = timeline_fence_get_driver_name, + .get_timeline_name = timeline_fence_get_timeline_name, + .enable_signaling = timeline_fence_enable_signaling, + .signaled = timeline_fence_signaled, + .wait = fence_default_wait, + .release = timeline_fence_release, + .fence_value_str = timeline_fence_value_str, + .timeline_value_str = timeline_fence_timeline_value_str, +}; + /* * *WARNING* * diff --git a/drivers/staging/android/sync.c b/drivers/staging/android/sync.c deleted file mode 100644 index bb12d86..0000000 --- a/drivers/staging/android/sync.c +++ /dev/null @@ -1,199 +0,0 @@ -/* - * drivers/base/sync.c - * - * Copyright (C) 2012 Google, Inc. - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ - -#include -#include - -#include "sync.h" - -#define CREATE_TRACE_POINTS -#include "trace/sync.h" - -struct sync_timeline *sync_timeline_create(const char *drv_name, - const char *name) -{ - struct sync_timeline *obj; - - obj = kzalloc(sizeof(*obj), GFP_KERNEL); - if (!obj) - return NULL; - - kref_init(&obj->kref); - obj->context = fence_context_alloc(1); - strlcpy(obj->name, name, sizeof(obj->name)); - strlcpy(obj->drv_name, drv_name, sizeof(obj->drv_name)); - - INIT_LIST_HEAD(&obj->child_list_head); - INIT_LIST_HEAD(&obj->active_list_head); - spin_lock_init(&obj->child_list_lock); - - sync_timeline_debug_add(obj); - - return obj; -} -EXPORT_SYMBOL(sync_timeline_create); - -static void sync_timeline_free(struct kref *kref) -{ - struct sync_timeline *obj = - container_of(kref, struct sync_timeline, kref); - - sync_timeline_debug_remove(obj); - - kfree(obj); -} - -static void sync_timeline_get(struct sync_timeline *obj) -{ - kref_get(&obj->kref); -} - -static void sync_timeline_put(struct sync_timeline *obj) -{ - kref_put(&obj->kref, sync_timeline_free); -} - -void sync_timeline_destroy(struct sync_timeline *obj) -{ - obj->destroyed = true; - /* - * Ensure timeline is marked as destroyed before - * changing timeline's fences status. - */ - smp_wmb(); - - sync_timeline_put(obj); -} -EXPORT_SYMBOL(sync_timeline_destroy); - -void sync_timeline_signal(struct sync_timeline *obj, unsigned int inc) -{ - unsigned long flags; - struct sync_pt *pt, *next; - - trace_sync_timeline(obj); - - spin_lock_irqsave(&obj->child_list_lock, flags); - - obj->value += inc; - - list_for_each_entry_safe(pt, next, &obj->active_list_head, - active_list) { - if (fence_is_signaled_locked(&pt->base)) - list_del_init(&pt->active_list); - } - - spin_unlock_irqrestore(&obj->child_list_lock, flags); -} -EXPORT_SYMBOL(sync_timeline_signal); - -struct sync_pt *sync_pt_create(struct sync_timeline *obj, int size, - unsigned int value) -{ - unsigned long flags; - struct sync_pt *pt; - - if (size < sizeof(*pt)) - return NULL; - - pt = kzalloc(size, GFP_KERNEL); - if (!pt) - return NULL; - - spin_lock_irqsave(&obj->child_list_lock, flags); - sync_timeline_get(obj); - fence_init(&pt->base, &timeline_fence_ops, &obj->child_list_lock, - obj->context, value); - list_add_tail(&pt->child_list, &obj->child_list_head); - INIT_LIST_HEAD(&pt->active_list); - spin_unlock_irqrestore(&obj->child_list_lock, flags); - return pt; -} -EXPORT_SYMBOL(sync_pt_create); - -static const char *timeline_fence_get_driver_name(struct fence *fence) -{ - struct sync_timeline *parent = fence_parent(fence); - - return parent->drv_name; -} - -static const char *timeline_fence_get_timeline_name(struct fence *fence) -{ - struct sync_timeline *parent = fence_parent(fence); - - return parent->name; -} - -static void timeline_fence_release(struct fence *fence) -{ - struct sync_pt *pt = fence_to_sync_pt(fence); - struct sync_timeline *parent = fence_parent(fence); - unsigned long flags; - - spin_lock_irqsave(fence->lock, flags); - list_del(&pt->child_list); - if (WARN_ON_ONCE(!list_empty(&pt->active_list))) - list_del(&pt->active_list); - spin_unlock_irqrestore(fence->lock, flags); - - sync_timeline_put(parent); - fence_free(fence); -} - -static bool timeline_fence_signaled(struct fence *fence) -{ - struct sync_timeline *parent = fence_parent(fence); - - return (fence->seqno > parent->value) ? false : true; -} - -static bool timeline_fence_enable_signaling(struct fence *fence) -{ - struct sync_pt *pt = fence_to_sync_pt(fence); - struct sync_timeline *parent = fence_parent(fence); - - if (timeline_fence_signaled(fence)) - return false; - - list_add_tail(&pt->active_list, &parent->active_list_head); - return true; -} - -static void timeline_fence_value_str(struct fence *fence, - char *str, int size) -{ - snprintf(str, size, "%d", fence->seqno); -} - -static void timeline_fence_timeline_value_str(struct fence *fence, - char *str, int size) -{ - struct sync_timeline *parent = fence_parent(fence); - - snprintf(str, size, "%d", parent->value); -} - -const struct fence_ops timeline_fence_ops = { - .get_driver_name = timeline_fence_get_driver_name, - .get_timeline_name = timeline_fence_get_timeline_name, - .enable_signaling = timeline_fence_enable_signaling, - .signaled = timeline_fence_signaled, - .wait = fence_default_wait, - .release = timeline_fence_release, - .fence_value_str = timeline_fence_value_str, - .timeline_value_str = timeline_fence_timeline_value_str, -}; diff --git a/drivers/staging/android/sync.h b/drivers/staging/android/sync.h index 54c515b..3a50851 100644 --- a/drivers/staging/android/sync.h +++ b/drivers/staging/android/sync.h @@ -69,64 +69,6 @@ struct sync_pt { struct list_head active_list; }; -extern const struct fence_ops timeline_fence_ops; - -static inline struct sync_pt *fence_to_sync_pt(struct fence *fence) -{ - if (fence->ops != &timeline_fence_ops) - return NULL; - return container_of(fence, struct sync_pt, base); -} - -/* - * API for sync_timeline implementers - */ - -/** - * sync_timeline_create() - creates a sync object - * @drv_name: sync_timeline driver name - * @name: sync_timeline name - * - * Creates a new sync_timeline. Returns the sync_timeline object or NULL in - * case of error. - */ -struct sync_timeline *sync_timeline_create(const char *drv_name, - const char *name); - -/** - * sync_timeline_destroy() - destroys a sync object - * @obj: sync_timeline to destroy - * - * A sync implementation should call this when the @obj is going away - * (i.e. module unload.) @obj won't actually be freed until all its children - * fences are freed. - */ -void sync_timeline_destroy(struct sync_timeline *obj); - -/** - * sync_timeline_signal() - signal a status change on a sync_timeline - * @obj: sync_timeline to signal - * @inc: num to increment on timeline->value - * - * A sync implementation should call this any time one of it's fences - * has signaled or has an error condition. - */ -void sync_timeline_signal(struct sync_timeline *obj, unsigned int inc); - -/** - * sync_pt_create() - creates a sync pt - * @parent: fence's parent sync_timeline - * @size: size to allocate for this pt - * @inc: value of the fence - * - * Creates a new sync_pt as a child of @parent. @size bytes will be - * allocated allowing for implementation specific data to be kept after - * the generic sync_timeline struct. Returns the sync_pt object or - * NULL in case of error. - */ -struct sync_pt *sync_pt_create(struct sync_timeline *parent, int size, - unsigned int inc); - #ifdef CONFIG_DEBUG_FS extern const struct file_operations sw_sync_debugfs_fops; diff --git a/drivers/staging/android/sync_debug.c b/drivers/staging/android/sync_debug.c index 864ad01..77386d2 100644 --- a/drivers/staging/android/sync_debug.c +++ b/drivers/staging/android/sync_debug.c @@ -193,10 +193,8 @@ static __init int sync_debugfs_init(void) debugfs_create_file("info", 0444, dbgfs, NULL, &sync_info_debugfs_fops); -#if IS_ENABLED(CONFIG_SW_SYNC) debugfs_create_file("sw_sync", 0644, dbgfs, NULL, &sw_sync_debugfs_fops); -#endif return 0; } -- cgit v0.10.2 From 6f65aa8925f7a908eb4d08339c03c40a300ac461 Mon Sep 17 00:00:00 2001 From: Gustavo Padovan Date: Tue, 31 May 2016 16:59:08 -0300 Subject: staging/android: make sw_ioctl info internal to sw_sync.c We don't want to export this from the kernel. This is interface is only for testing and debug. So testers shall copy the ioctl info in their own projects. Signed-off-by: Gustavo Padovan Reviewed-by: Daniel Vetter Reviewed-by: Sumit Semwal Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/android/sw_sync.c b/drivers/staging/android/sw_sync.c index c149ac90..72262ba 100644 --- a/drivers/staging/android/sw_sync.c +++ b/drivers/staging/android/sw_sync.c @@ -20,12 +20,23 @@ #include #include -#include "uapi/sw_sync.h" #include "sync.h" #define CREATE_TRACE_POINTS #include "trace/sync.h" +struct sw_sync_create_fence_data { + __u32 value; + char name[32]; + __s32 fence; /* fd of new fence */ +}; + +#define SW_SYNC_IOC_MAGIC 'W' + +#define SW_SYNC_IOC_CREATE_FENCE _IOWR(SW_SYNC_IOC_MAGIC, 0,\ + struct sw_sync_create_fence_data) +#define SW_SYNC_IOC_INC _IOW(SW_SYNC_IOC_MAGIC, 1, __u32) + static const struct fence_ops timeline_fence_ops; static inline struct sync_pt *fence_to_sync_pt(struct fence *fence) diff --git a/drivers/staging/android/uapi/sw_sync.h b/drivers/staging/android/uapi/sw_sync.h deleted file mode 100644 index 9b5d486..0000000 --- a/drivers/staging/android/uapi/sw_sync.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright (C) 2012 Google, Inc. - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ - -#ifndef _UAPI_LINUX_SW_SYNC_H -#define _UAPI_LINUX_SW_SYNC_H - -#include - -struct sw_sync_create_fence_data { - __u32 value; - char name[32]; - __s32 fence; /* fd of new fence */ -}; - -#define SW_SYNC_IOC_MAGIC 'W' - -#define SW_SYNC_IOC_CREATE_FENCE _IOWR(SW_SYNC_IOC_MAGIC, 0,\ - struct sw_sync_create_fence_data) -#define SW_SYNC_IOC_INC _IOW(SW_SYNC_IOC_MAGIC, 1, __u32) - -#endif /* _UAPI_LINUX_SW_SYNC_H */ -- cgit v0.10.2 From 342952d3a5c4d128649c7fd8e34d7d5eb6d036aa Mon Sep 17 00:00:00 2001 From: Gustavo Padovan Date: Tue, 31 May 2016 16:59:09 -0300 Subject: staging/android: remove 'destroyed' member from struct sync_timeline 'destroyed' was set but not used ny anyone. Signed-off-by: Gustavo Padovan Reviewed-by: Daniel Vetter Reviewed-by: Sumit Semwal Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/android/sw_sync.c b/drivers/staging/android/sw_sync.c index 72262ba..1f956b9 100644 --- a/drivers/staging/android/sw_sync.c +++ b/drivers/staging/android/sw_sync.c @@ -107,11 +107,6 @@ static void sync_timeline_put(struct sync_timeline *obj) */ static void sync_timeline_destroy(struct sync_timeline *obj) { - obj->destroyed = true; - /* - * Ensure timeline is marked as destroyed before - * changing timeline's fences status. - */ smp_wmb(); sync_timeline_put(obj); diff --git a/drivers/staging/android/sync.h b/drivers/staging/android/sync.h index 3a50851..3c551f5 100644 --- a/drivers/staging/android/sync.h +++ b/drivers/staging/android/sync.h @@ -25,10 +25,8 @@ * @kref: reference count on fence. * @drv_name: drv_name of the driver using the sync_timeline * @name: name of the sync_timeline. Useful for debugging - * @destroyed: set when sync_timeline is destroyed * @child_list_head: list of children sync_pts for this sync_timeline - * @child_list_lock: lock protecting @child_list_head, destroyed, and - * fence.status + * @child_list_lock: lock protecting @child_list_head and fence.status * @active_list_head: list of active (unsignaled/errored) sync_pts * @sync_timeline_list: membership in global sync_timeline_list */ @@ -38,7 +36,6 @@ struct sync_timeline { char name[32]; /* protected by child_list_lock */ - bool destroyed; int context, value; struct list_head child_list_head; -- cgit v0.10.2 From 711102325302d793aa0eee493be79ce9c32ae426 Mon Sep 17 00:00:00 2001 From: Gustavo Padovan Date: Tue, 31 May 2016 16:59:10 -0300 Subject: staging/android: remove sync_timeline_destroy() This function was just used by the file release function, so we just fold its content there and remove sync_timeline_destroy(). Signed-off-by: Gustavo Padovan Reviewed-by: Daniel Vetter Reviewed-by: Sumit Semwal Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/android/sw_sync.c b/drivers/staging/android/sw_sync.c index 1f956b9..cf4de27 100644 --- a/drivers/staging/android/sw_sync.c +++ b/drivers/staging/android/sw_sync.c @@ -98,21 +98,6 @@ static void sync_timeline_put(struct sync_timeline *obj) } /** - * sync_timeline_destroy() - destroys a sync object - * @obj: sync_timeline to destroy - * - * A sync implementation should call this when the @obj is going away - * (i.e. module unload.) @obj won't actually be freed until all its children - * fences are freed. - */ -static void sync_timeline_destroy(struct sync_timeline *obj) -{ - smp_wmb(); - - sync_timeline_put(obj); -} - -/** * sync_timeline_signal() - signal a status change on a sync_timeline * @obj: sync_timeline to signal * @inc: num to increment on timeline->value @@ -275,7 +260,9 @@ static int sw_sync_debugfs_release(struct inode *inode, struct file *file) { struct sync_timeline *obj = file->private_data; - sync_timeline_destroy(obj); + smp_wmb(); + + sync_timeline_put(obj); return 0; } -- cgit v0.10.2 From b9bc2b7b658a4bee8884e2c339a0a27f4bfa7f22 Mon Sep 17 00:00:00 2001 From: Gustavo Padovan Date: Tue, 31 May 2016 16:59:11 -0300 Subject: staging/android: remove drv_name from sync_timeline As it is internal to sw_sync now this value will always be "sw_sync". Signed-off-by: Gustavo Padovan Reviewed-by: Daniel Vetter Reviewed-by: Sumit Semwal Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/android/sw_sync.c b/drivers/staging/android/sw_sync.c index cf4de27..ae56ece 100644 --- a/drivers/staging/android/sw_sync.c +++ b/drivers/staging/android/sw_sync.c @@ -48,14 +48,12 @@ static inline struct sync_pt *fence_to_sync_pt(struct fence *fence) /** * sync_timeline_create() - creates a sync object - * @drv_name: sync_timeline driver name * @name: sync_timeline name * * Creates a new sync_timeline. Returns the sync_timeline object or NULL in * case of error. */ -struct sync_timeline *sync_timeline_create(const char *drv_name, - const char *name) +struct sync_timeline *sync_timeline_create(const char *name) { struct sync_timeline *obj; @@ -66,7 +64,6 @@ struct sync_timeline *sync_timeline_create(const char *drv_name, kref_init(&obj->kref); obj->context = fence_context_alloc(1); strlcpy(obj->name, name, sizeof(obj->name)); - strlcpy(obj->drv_name, drv_name, sizeof(obj->drv_name)); INIT_LIST_HEAD(&obj->child_list_head); INIT_LIST_HEAD(&obj->active_list_head); @@ -161,9 +158,7 @@ static struct sync_pt *sync_pt_create(struct sync_timeline *obj, int size, static const char *timeline_fence_get_driver_name(struct fence *fence) { - struct sync_timeline *parent = fence_parent(fence); - - return parent->drv_name; + return "sw_sync"; } static const char *timeline_fence_get_timeline_name(struct fence *fence) @@ -247,7 +242,7 @@ static int sw_sync_debugfs_open(struct inode *inode, struct file *file) get_task_comm(task_comm, current); - obj = sync_timeline_create("sw_sync", task_comm); + obj = sync_timeline_create(task_comm); if (!obj) return -ENOMEM; diff --git a/drivers/staging/android/sync.h b/drivers/staging/android/sync.h index 3c551f5..48e2d1c 100644 --- a/drivers/staging/android/sync.h +++ b/drivers/staging/android/sync.h @@ -23,7 +23,6 @@ /** * struct sync_timeline - sync object * @kref: reference count on fence. - * @drv_name: drv_name of the driver using the sync_timeline * @name: name of the sync_timeline. Useful for debugging * @child_list_head: list of children sync_pts for this sync_timeline * @child_list_lock: lock protecting @child_list_head and fence.status @@ -32,7 +31,6 @@ */ struct sync_timeline { struct kref kref; - char drv_name[32]; char name[32]; /* protected by child_list_lock */ diff --git a/drivers/staging/android/sync_debug.c b/drivers/staging/android/sync_debug.c index 77386d2..b2697a1 100644 --- a/drivers/staging/android/sync_debug.c +++ b/drivers/staging/android/sync_debug.c @@ -120,7 +120,7 @@ static void sync_print_obj(struct seq_file *s, struct sync_timeline *obj) struct list_head *pos; unsigned long flags; - seq_printf(s, "%s %s: %d\n", obj->name, obj->drv_name, obj->value); + seq_printf(s, "%s: %d\n", obj->name, obj->value); spin_lock_irqsave(&obj->child_list_lock, flags); list_for_each(pos, &obj->child_list_head) { -- cgit v0.10.2 From 1fe82e2e148697fd1fbbb2944e143b182c51e227 Mon Sep 17 00:00:00 2001 From: Gustavo Padovan Date: Tue, 31 May 2016 16:59:12 -0300 Subject: staging/android: rename sync.h to sync_debug.h This header file only contains information for debugging and SW_SYNC, so rename it to sync_debug.h instead of having a more generic name. Signed-off-by: Gustavo Padovan Reviewed-by: Daniel Vetter Reviewed-by: Sumit Semwal Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/android/sw_sync.c b/drivers/staging/android/sw_sync.c index ae56ece..115c917 100644 --- a/drivers/staging/android/sw_sync.c +++ b/drivers/staging/android/sw_sync.c @@ -20,7 +20,7 @@ #include #include -#include "sync.h" +#include "sync_debug.h" #define CREATE_TRACE_POINTS #include "trace/sync.h" diff --git a/drivers/staging/android/sync.h b/drivers/staging/android/sync.h deleted file mode 100644 index 48e2d1c..0000000 --- a/drivers/staging/android/sync.h +++ /dev/null @@ -1,85 +0,0 @@ -/* - * include/linux/sync.h - * - * Copyright (C) 2012 Google, Inc. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ - -#ifndef _LINUX_SYNC_H -#define _LINUX_SYNC_H - -#include -#include -#include - -#include -#include - -/** - * struct sync_timeline - sync object - * @kref: reference count on fence. - * @name: name of the sync_timeline. Useful for debugging - * @child_list_head: list of children sync_pts for this sync_timeline - * @child_list_lock: lock protecting @child_list_head and fence.status - * @active_list_head: list of active (unsignaled/errored) sync_pts - * @sync_timeline_list: membership in global sync_timeline_list - */ -struct sync_timeline { - struct kref kref; - char name[32]; - - /* protected by child_list_lock */ - int context, value; - - struct list_head child_list_head; - spinlock_t child_list_lock; - - struct list_head active_list_head; - -#ifdef CONFIG_DEBUG_FS - struct list_head sync_timeline_list; -#endif -}; - -static inline struct sync_timeline *fence_parent(struct fence *fence) -{ - return container_of(fence->lock, struct sync_timeline, - child_list_lock); -} - -/** - * struct sync_pt - sync_pt object - * @base: base fence object - * @child_list: sync timeline child's list - * @active_list: sync timeline active child's list - */ -struct sync_pt { - struct fence base; - struct list_head child_list; - struct list_head active_list; -}; - -#ifdef CONFIG_DEBUG_FS - -extern const struct file_operations sw_sync_debugfs_fops; - -void sync_timeline_debug_add(struct sync_timeline *obj); -void sync_timeline_debug_remove(struct sync_timeline *obj); -void sync_file_debug_add(struct sync_file *fence); -void sync_file_debug_remove(struct sync_file *fence); -void sync_dump(void); - -#else -# define sync_timeline_debug_add(obj) -# define sync_timeline_debug_remove(obj) -# define sync_file_debug_add(fence) -# define sync_file_debug_remove(fence) -# define sync_dump() -#endif - -#endif /* _LINUX_SYNC_H */ diff --git a/drivers/staging/android/sync_debug.c b/drivers/staging/android/sync_debug.c index b2697a1..b760226 100644 --- a/drivers/staging/android/sync_debug.c +++ b/drivers/staging/android/sync_debug.c @@ -15,7 +15,7 @@ */ #include -#include "sync.h" +#include "sync_debug.h" #ifdef CONFIG_DEBUG_FS diff --git a/drivers/staging/android/sync_debug.h b/drivers/staging/android/sync_debug.h new file mode 100644 index 0000000..48e2d1c --- /dev/null +++ b/drivers/staging/android/sync_debug.h @@ -0,0 +1,85 @@ +/* + * include/linux/sync.h + * + * Copyright (C) 2012 Google, Inc. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef _LINUX_SYNC_H +#define _LINUX_SYNC_H + +#include +#include +#include + +#include +#include + +/** + * struct sync_timeline - sync object + * @kref: reference count on fence. + * @name: name of the sync_timeline. Useful for debugging + * @child_list_head: list of children sync_pts for this sync_timeline + * @child_list_lock: lock protecting @child_list_head and fence.status + * @active_list_head: list of active (unsignaled/errored) sync_pts + * @sync_timeline_list: membership in global sync_timeline_list + */ +struct sync_timeline { + struct kref kref; + char name[32]; + + /* protected by child_list_lock */ + int context, value; + + struct list_head child_list_head; + spinlock_t child_list_lock; + + struct list_head active_list_head; + +#ifdef CONFIG_DEBUG_FS + struct list_head sync_timeline_list; +#endif +}; + +static inline struct sync_timeline *fence_parent(struct fence *fence) +{ + return container_of(fence->lock, struct sync_timeline, + child_list_lock); +} + +/** + * struct sync_pt - sync_pt object + * @base: base fence object + * @child_list: sync timeline child's list + * @active_list: sync timeline active child's list + */ +struct sync_pt { + struct fence base; + struct list_head child_list; + struct list_head active_list; +}; + +#ifdef CONFIG_DEBUG_FS + +extern const struct file_operations sw_sync_debugfs_fops; + +void sync_timeline_debug_add(struct sync_timeline *obj); +void sync_timeline_debug_remove(struct sync_timeline *obj); +void sync_file_debug_add(struct sync_file *fence); +void sync_file_debug_remove(struct sync_file *fence); +void sync_dump(void); + +#else +# define sync_timeline_debug_add(obj) +# define sync_timeline_debug_remove(obj) +# define sync_file_debug_add(fence) +# define sync_file_debug_remove(fence) +# define sync_dump() +#endif + +#endif /* _LINUX_SYNC_H */ diff --git a/drivers/staging/android/trace/sync.h b/drivers/staging/android/trace/sync.h index d7f6457f..6b5ce96 100644 --- a/drivers/staging/android/trace/sync.h +++ b/drivers/staging/android/trace/sync.h @@ -5,7 +5,7 @@ #if !defined(_TRACE_SYNC_H) || defined(TRACE_HEADER_MULTI_READ) #define _TRACE_SYNC_H -#include "../sync.h" +#include "../sync_debug.h" #include TRACE_EVENT(sync_timeline, -- cgit v0.10.2 From b1f656044a9936880d5a7460cd8784b2e124ab87 Mon Sep 17 00:00:00 2001 From: Gustavo Padovan Date: Tue, 31 May 2016 16:59:13 -0300 Subject: staging/android: add DEBUG_FS dependence on Kconfig SW_SYNC only works with DEBUG_FS so state it in the Kconfig file. Signed-off-by: Gustavo Padovan Reviewed-by: Daniel Vetter Reviewed-by: Sumit Semwal Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/android/Kconfig b/drivers/staging/android/Kconfig index f52c682..06e41d2 100644 --- a/drivers/staging/android/Kconfig +++ b/drivers/staging/android/Kconfig @@ -28,6 +28,7 @@ config SW_SYNC bool "Software synchronization framework" default n depends on SYNC_FILE + depends on DEBUG_FS ---help--- A sync object driver that uses a 32bit counter to coordinate synchronization. Useful when there is no hardware primitive backing diff --git a/drivers/staging/android/sync_debug.c b/drivers/staging/android/sync_debug.c index b760226..9032969 100644 --- a/drivers/staging/android/sync_debug.c +++ b/drivers/staging/android/sync_debug.c @@ -17,8 +17,6 @@ #include #include "sync_debug.h" -#ifdef CONFIG_DEBUG_FS - static struct dentry *dbgfs; static LIST_HEAD(sync_timeline_list_head); @@ -225,5 +223,3 @@ void sync_dump(void) } } } - -#endif diff --git a/drivers/staging/android/sync_debug.h b/drivers/staging/android/sync_debug.h index 48e2d1c..425ebc5 100644 --- a/drivers/staging/android/sync_debug.h +++ b/drivers/staging/android/sync_debug.h @@ -41,9 +41,7 @@ struct sync_timeline { struct list_head active_list_head; -#ifdef CONFIG_DEBUG_FS struct list_head sync_timeline_list; -#endif }; static inline struct sync_timeline *fence_parent(struct fence *fence) @@ -64,7 +62,7 @@ struct sync_pt { struct list_head active_list; }; -#ifdef CONFIG_DEBUG_FS +#ifdef CONFIG_SW_SYNC extern const struct file_operations sw_sync_debugfs_fops; -- cgit v0.10.2 From 0fd9da9a979aecfb9df40dfb3304db2b16fa7e05 Mon Sep 17 00:00:00 2001 From: Nicolai Stange Date: Fri, 27 May 2016 20:03:54 +0200 Subject: staging/android: sync_debug: unproxify debugfs files' fops Since commit 49d200deaa68 ("debugfs: prevent access to removed files' private data"), a debugfs file's file_operations methods get proxied through lifetime aware wrappers. However, only a certain subset of the file_operations members is supported by debugfs and ->compat_ioctl isn't among them -- it appears to be NULL from the VFS layer's perspective. This behaviour breaks the /sys/kernel/debug/sync/sw_sync file introduced concurrently with commit a44eb74cd413 ("staging/android: move SW_SYNC_USER to a debugfs file"). Since that file never gets removed, there is no file removal race and thus, a lifetime checking proxy isn't needed. Avoid the proxying for /sys/kernel/debug/sync/sw_sync by creating it via debugfs_create_file_unsafe() rather than debugfs_create_file(). For consistency, do the same for /sys/kernel/debug/sync/info. Fixes: 49d200deaa68 ("debugfs: prevent access to removed files' private data") Fixes: a44eb74cd413 ("staging/android: move SW_SYNC_USER to a debugfs file") Signed-off-by: Nicolai Stange Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/android/sync_debug.c b/drivers/staging/android/sync_debug.c index 9032969..4c5a855 100644 --- a/drivers/staging/android/sync_debug.c +++ b/drivers/staging/android/sync_debug.c @@ -189,10 +189,15 @@ static __init int sync_debugfs_init(void) { dbgfs = debugfs_create_dir("sync", NULL); - debugfs_create_file("info", 0444, dbgfs, NULL, &sync_info_debugfs_fops); - - debugfs_create_file("sw_sync", 0644, dbgfs, NULL, - &sw_sync_debugfs_fops); + /* + * The debugfs files won't ever get removed and thus, there is + * no need to protect it against removal races. The use of + * debugfs_create_file_unsafe() is actually safe here. + */ + debugfs_create_file_unsafe("info", 0444, dbgfs, NULL, + &sync_info_debugfs_fops); + debugfs_create_file_unsafe("sw_sync", 0644, dbgfs, NULL, + &sw_sync_debugfs_fops); return 0; } -- cgit v0.10.2 From edd14cfebc4404698544d407ecf8eda6e19aa19e Mon Sep 17 00:00:00 2001 From: Keith Busch Date: Fri, 17 Jun 2016 16:00:20 -0600 Subject: genirq: Add untracked irq handler This adds a software irq handler for controllers that multiplex interrupts from multiple devices, but don't know which device generated the interrupt. For these devices, the irq handler that demuxes must check every action for every software irq using the same h/w irq in order to find out which device generated the interrupt. This will inevitably trigger spurious interrupt detection if we are noting the irq. The new irq handler does not track the handling for spurious interrupt detection. An irq that uses this also won't get stats tracked since it didn't generate the interrupt, nor added to randomness since they are not random. Signed-off-by: Keith Busch Cc: Bjorn Helgaas Cc: linux-pci@vger.kernel.org Cc: Jon Derrick Link: http://lkml.kernel.org/r/1466200821-29159-1-git-send-email-keith.busch@intel.com Signed-off-by: Thomas Gleixner diff --git a/include/linux/irq.h b/include/linux/irq.h index 6c92a84..562cef0 100644 --- a/include/linux/irq.h +++ b/include/linux/irq.h @@ -484,6 +484,7 @@ extern void handle_fasteoi_irq(struct irq_desc *desc); extern void handle_edge_irq(struct irq_desc *desc); extern void handle_edge_eoi_irq(struct irq_desc *desc); extern void handle_simple_irq(struct irq_desc *desc); +extern void handle_untracked_irq(struct irq_desc *desc); extern void handle_percpu_irq(struct irq_desc *desc); extern void handle_percpu_devid_irq(struct irq_desc *desc); extern void handle_bad_irq(struct irq_desc *desc); diff --git a/kernel/irq/chip.c b/kernel/irq/chip.c index ad81314..b4c1bc7 100644 --- a/kernel/irq/chip.c +++ b/kernel/irq/chip.c @@ -426,6 +426,49 @@ out_unlock: } EXPORT_SYMBOL_GPL(handle_simple_irq); +/** + * handle_untracked_irq - Simple and software-decoded IRQs. + * @desc: the interrupt description structure for this irq + * + * Untracked interrupts are sent from a demultiplexing interrupt + * handler when the demultiplexer does not know which device it its + * multiplexed irq domain generated the interrupt. IRQ's handled + * through here are not subjected to stats tracking, randomness, or + * spurious interrupt detection. + * + * Note: Like handle_simple_irq, the caller is expected to handle + * the ack, clear, mask and unmask issues if necessary. + */ +void handle_untracked_irq(struct irq_desc *desc) +{ + unsigned int flags = 0; + + raw_spin_lock(&desc->lock); + + if (!irq_may_run(desc)) + goto out_unlock; + + desc->istate &= ~(IRQS_REPLAY | IRQS_WAITING); + + if (unlikely(!desc->action || irqd_irq_disabled(&desc->irq_data))) { + desc->istate |= IRQS_PENDING; + goto out_unlock; + } + + desc->istate &= ~IRQS_PENDING; + irqd_set(&desc->irq_data, IRQD_IRQ_INPROGRESS); + raw_spin_unlock(&desc->lock); + + __handle_irq_event_percpu(desc, &flags); + + raw_spin_lock(&desc->lock); + irqd_clear(&desc->irq_data, IRQD_IRQ_INPROGRESS); + +out_unlock: + raw_spin_unlock(&desc->lock); +} +EXPORT_SYMBOL_GPL(handle_untracked_irq); + /* * Called unconditionally from handle_level_irq() and only for oneshot * interrupts from handle_fasteoi_irq() diff --git a/kernel/irq/handle.c b/kernel/irq/handle.c index a15b548..d3f2490 100644 --- a/kernel/irq/handle.c +++ b/kernel/irq/handle.c @@ -132,10 +132,10 @@ void __irq_wake_thread(struct irq_desc *desc, struct irqaction *action) wake_up_process(action->thread); } -irqreturn_t handle_irq_event_percpu(struct irq_desc *desc) +irqreturn_t __handle_irq_event_percpu(struct irq_desc *desc, unsigned int *flags) { irqreturn_t retval = IRQ_NONE; - unsigned int flags = 0, irq = desc->irq_data.irq; + unsigned int irq = desc->irq_data.irq; struct irqaction *action; for_each_action_of_desc(desc, action) { @@ -164,7 +164,7 @@ irqreturn_t handle_irq_event_percpu(struct irq_desc *desc) /* Fall through to add to randomness */ case IRQ_HANDLED: - flags |= action->flags; + *flags |= action->flags; break; default: @@ -174,7 +174,17 @@ irqreturn_t handle_irq_event_percpu(struct irq_desc *desc) retval |= res; } - add_interrupt_randomness(irq, flags); + return retval; +} + +irqreturn_t handle_irq_event_percpu(struct irq_desc *desc) +{ + irqreturn_t retval; + unsigned int flags = 0; + + retval = __handle_irq_event_percpu(desc, &flags); + + add_interrupt_randomness(desc->irq_data.irq, flags); if (!noirqdebug) note_interrupt(desc, retval); diff --git a/kernel/irq/internals.h b/kernel/irq/internals.h index d5edcdc..0c6f35b 100644 --- a/kernel/irq/internals.h +++ b/kernel/irq/internals.h @@ -84,6 +84,7 @@ extern void irq_mark_irq(unsigned int irq); extern void init_kstat_irqs(struct irq_desc *desc, int node, int nr); +irqreturn_t __handle_irq_event_percpu(struct irq_desc *desc, unsigned int *flags); irqreturn_t handle_irq_event_percpu(struct irq_desc *desc); irqreturn_t handle_irq_event(struct irq_desc *desc); -- cgit v0.10.2 From 30ce0350381351646ef86b64e6d3840b3869833b Mon Sep 17 00:00:00 2001 From: Keith Busch Date: Fri, 17 Jun 2016 16:00:21 -0600 Subject: x86/PCI/VMD: Use untracked irq handler There is no way to know which device in a VMD triggered an interrupt without invoking every registered driver's actions. This uses the untracked irq handler so that a less used device does not trigger spurious interrupt. We have been previously recommending users to enable "noirqdebug", but do not want to force a system setting just to keep this domain functional. Signed-off-by: Keith Busch Acked-by: Bjorn Helgaas Cc: linux-pci@vger.kernel.org Cc: Jon Derrick Link: http://lkml.kernel.org/r/1466200821-29159-2-git-send-email-keith.busch@intel.com Signed-off-by: Thomas Gleixner diff --git a/arch/x86/pci/vmd.c b/arch/x86/pci/vmd.c index 7792aba..613cac7 100644 --- a/arch/x86/pci/vmd.c +++ b/arch/x86/pci/vmd.c @@ -195,7 +195,7 @@ static int vmd_msi_init(struct irq_domain *domain, struct msi_domain_info *info, vmdirq->virq = virq; irq_domain_set_info(domain, virq, vmdirq->irq->vmd_vector, info->chip, - vmdirq, handle_simple_irq, vmd, NULL); + vmdirq, handle_untracked_irq, vmd, NULL); return 0; } -- cgit v0.10.2 From a1141e0b5ca6ee3e5e35d5f1a310a5ecb9c96ce5 Mon Sep 17 00:00:00 2001 From: Fenghua Yu Date: Fri, 20 May 2016 10:47:05 -0700 Subject: x86/fpu/xstate: Define and use 'fpu_user_xstate_size' The kernel xstate area can be in standard or compacted format; it is always in standard format for user mode. When XSAVES is enabled, the kernel uses the compacted format and it is necessary to use a separate fpu_user_xstate_size for signal/ptrace frames. Signed-off-by: Fenghua Yu [ Rebased the patch and cleaned up the naming. ] Signed-off-by: Yu-cheng Yu Reviewed-by: Dave Hansen Cc: Andy Lutomirski Cc: Borislav Petkov Cc: Brian Gerst Cc: Dave Hansen Cc: Denys Vlasenko Cc: H. Peter Anvin Cc: Linus Torvalds Cc: Oleg Nesterov Cc: Peter Zijlstra Cc: Quentin Casasnovas Cc: Ravi V. Shankar Cc: Sai Praneeth Prakhya Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/8756ec34dabddfc727cda5743195eb81e8caf91c.1463760376.git.yu-cheng.yu@intel.com Signed-off-by: Ingo Molnar diff --git a/arch/x86/include/asm/fpu/xstate.h b/arch/x86/include/asm/fpu/xstate.h index 38951b0..16df2c4 100644 --- a/arch/x86/include/asm/fpu/xstate.h +++ b/arch/x86/include/asm/fpu/xstate.h @@ -39,7 +39,6 @@ #define REX_PREFIX #endif -extern unsigned int xstate_size; extern u64 xfeatures_mask; extern u64 xstate_fx_sw_bytes[USER_XSTATE_FX_SW_WORDS]; diff --git a/arch/x86/include/asm/processor.h b/arch/x86/include/asm/processor.h index 62c6cc3..0a16a16 100644 --- a/arch/x86/include/asm/processor.h +++ b/arch/x86/include/asm/processor.h @@ -368,6 +368,7 @@ DECLARE_PER_CPU(struct irq_stack *, softirq_stack); #endif /* X86_64 */ extern unsigned int xstate_size; +extern unsigned int fpu_user_xstate_size; struct perf_event; diff --git a/arch/x86/kernel/fpu/init.c b/arch/x86/kernel/fpu/init.c index aacfd7a..5b1928c 100644 --- a/arch/x86/kernel/fpu/init.c +++ b/arch/x86/kernel/fpu/init.c @@ -195,7 +195,7 @@ static void __init fpu__init_task_struct_size(void) } /* - * Set up the xstate_size based on the legacy FPU context size. + * Set up the user and kernel xstate_size based on the legacy FPU context size. * * We set this up first, and later it will be overwritten by * fpu__init_system_xstate() if the CPU knows about xstates. @@ -226,6 +226,9 @@ static void __init fpu__init_system_xstate_size_legacy(void) else xstate_size = sizeof(struct fregs_state); } + + fpu_user_xstate_size = xstate_size; + /* * Quirk: we don't yet handle the XSAVES* instructions * correctly, as we don't correctly convert between diff --git a/arch/x86/kernel/fpu/signal.c b/arch/x86/kernel/fpu/signal.c index c6f2a3c..0d29d4d 100644 --- a/arch/x86/kernel/fpu/signal.c +++ b/arch/x86/kernel/fpu/signal.c @@ -32,7 +32,7 @@ static inline int check_for_xstate(struct fxregs_state __user *buf, /* Check for the first magic field and other error scenarios. */ if (fx_sw->magic1 != FP_XSTATE_MAGIC1 || fx_sw->xstate_size < min_xstate_size || - fx_sw->xstate_size > xstate_size || + fx_sw->xstate_size > fpu_user_xstate_size || fx_sw->xstate_size > fx_sw->extended_size) return -1; @@ -89,7 +89,8 @@ static inline int save_xstate_epilog(void __user *buf, int ia32_frame) if (!use_xsave()) return err; - err |= __put_user(FP_XSTATE_MAGIC2, (__u32 *)(buf + xstate_size)); + err |= __put_user(FP_XSTATE_MAGIC2, + (__u32 *)(buf + fpu_user_xstate_size)); /* * Read the xfeatures which we copied (directly from the cpu or @@ -126,7 +127,7 @@ static inline int copy_fpregs_to_sigframe(struct xregs_state __user *buf) else err = copy_fregs_to_user((struct fregs_state __user *) buf); - if (unlikely(err) && __clear_user(buf, xstate_size)) + if (unlikely(err) && __clear_user(buf, fpu_user_xstate_size)) err = -EFAULT; return err; } @@ -176,8 +177,19 @@ int copy_fpstate_to_sigframe(void __user *buf, void __user *buf_fx, int size) if (ia32_fxstate) copy_fxregs_to_kernel(&tsk->thread.fpu); } else { + /* + * It is a *bug* if kernel uses compacted-format for xsave + * area and we copy it out directly to a signal frame. It + * should have been handled above by saving the registers + * directly. + */ + if (boot_cpu_has(X86_FEATURE_XSAVES)) { + WARN_ONCE(1, "x86/fpu: saving compacted-format xsave area to a signal frame!\n"); + return -1; + } + fpstate_sanitize_xstate(&tsk->thread.fpu); - if (__copy_to_user(buf_fx, xsave, xstate_size)) + if (__copy_to_user(buf_fx, xsave, fpu_user_xstate_size)) return -1; } @@ -344,7 +356,8 @@ static int __fpu__restore_sig(void __user *buf, void __user *buf_fx, int size) static inline int xstate_sigframe_size(void) { - return use_xsave() ? xstate_size + FP_XSTATE_MAGIC2_SIZE : xstate_size; + return use_xsave() ? fpu_user_xstate_size + FP_XSTATE_MAGIC2_SIZE : + fpu_user_xstate_size; } /* @@ -388,12 +401,12 @@ fpu__alloc_mathframe(unsigned long sp, int ia32_frame, */ void fpu__init_prepare_fx_sw_frame(void) { - int size = xstate_size + FP_XSTATE_MAGIC2_SIZE; + int size = fpu_user_xstate_size + FP_XSTATE_MAGIC2_SIZE; fx_sw_reserved.magic1 = FP_XSTATE_MAGIC1; fx_sw_reserved.extended_size = size; fx_sw_reserved.xfeatures = xfeatures_mask; - fx_sw_reserved.xstate_size = xstate_size; + fx_sw_reserved.xstate_size = fpu_user_xstate_size; if (config_enabled(CONFIG_IA32_EMULATION) || config_enabled(CONFIG_X86_32)) { diff --git a/arch/x86/kernel/fpu/xstate.c b/arch/x86/kernel/fpu/xstate.c index 4ea2a59..9c4da35 100644 --- a/arch/x86/kernel/fpu/xstate.c +++ b/arch/x86/kernel/fpu/xstate.c @@ -44,6 +44,13 @@ static unsigned int xstate_sizes[XFEATURE_MAX] = { [ 0 ... XFEATURE_MAX - 1] = static unsigned int xstate_comp_offsets[sizeof(xfeatures_mask)*8]; /* + * The XSAVE area of kernel can be in standard or compacted format; + * it is always in standard format for user mode. This is the user + * mode standard format size used for signal and ptrace frames. + */ +unsigned int fpu_user_xstate_size; + +/* * Clear all of the X86_FEATURE_* bits that are unavailable * when the CPU has no XSAVE support. */ @@ -171,7 +178,7 @@ void fpstate_sanitize_xstate(struct fpu *fpu) */ while (xfeatures) { if (xfeatures & 0x1) { - int offset = xstate_offsets[feature_bit]; + int offset = xstate_comp_offsets[feature_bit]; int size = xstate_sizes[feature_bit]; memcpy((void *)fx + offset, @@ -533,8 +540,9 @@ static void do_extra_xstate_size_checks(void) XSTATE_WARN_ON(paranoid_xstate_size != xstate_size); } + /* - * Calculate total size of enabled xstates in XCR0/xfeatures_mask. + * Get total size of enabled xstates in XCR0/xfeatures_mask. * * Note the SDM's wording here. "sub-function 0" only enumerates * the size of the *user* states. If we use it to size a buffer @@ -544,34 +552,33 @@ static void do_extra_xstate_size_checks(void) * Note that we do not currently set any bits on IA32_XSS so * 'XCR0 | IA32_XSS == XCR0' for now. */ -static unsigned int __init calculate_xstate_size(void) +static unsigned int __init get_xsaves_size(void) { unsigned int eax, ebx, ecx, edx; - unsigned int calculated_xstate_size; + /* + * - CPUID function 0DH, sub-function 1: + * EBX enumerates the size (in bytes) required by + * the XSAVES instruction for an XSAVE area + * containing all the state components + * corresponding to bits currently set in + * XCR0 | IA32_XSS. + */ + cpuid_count(XSTATE_CPUID, 1, &eax, &ebx, &ecx, &edx); + return ebx; +} - if (!boot_cpu_has(X86_FEATURE_XSAVES)) { - /* - * - CPUID function 0DH, sub-function 0: - * EBX enumerates the size (in bytes) required by - * the XSAVE instruction for an XSAVE area - * containing all the *user* state components - * corresponding to bits currently set in XCR0. - */ - cpuid_count(XSTATE_CPUID, 0, &eax, &ebx, &ecx, &edx); - calculated_xstate_size = ebx; - } else { - /* - * - CPUID function 0DH, sub-function 1: - * EBX enumerates the size (in bytes) required by - * the XSAVES instruction for an XSAVE area - * containing all the state components - * corresponding to bits currently set in - * XCR0 | IA32_XSS. - */ - cpuid_count(XSTATE_CPUID, 1, &eax, &ebx, &ecx, &edx); - calculated_xstate_size = ebx; - } - return calculated_xstate_size; +static unsigned int __init get_xsave_size(void) +{ + unsigned int eax, ebx, ecx, edx; + /* + * - CPUID function 0DH, sub-function 0: + * EBX enumerates the size (in bytes) required by + * the XSAVE instruction for an XSAVE area + * containing all the *user* state components + * corresponding to bits currently set in XCR0. + */ + cpuid_count(XSTATE_CPUID, 0, &eax, &ebx, &ecx, &edx); + return ebx; } /* @@ -591,7 +598,15 @@ static bool is_supported_xstate_size(unsigned int test_xstate_size) static int init_xstate_size(void) { /* Recompute the context size for enabled features: */ - unsigned int possible_xstate_size = calculate_xstate_size(); + unsigned int possible_xstate_size; + unsigned int xsave_size; + + xsave_size = get_xsave_size(); + + if (boot_cpu_has(X86_FEATURE_XSAVES)) + possible_xstate_size = get_xsaves_size(); + else + possible_xstate_size = xsave_size; /* Ensure we have the space to store all enabled: */ if (!is_supported_xstate_size(possible_xstate_size)) @@ -603,6 +618,11 @@ static int init_xstate_size(void) */ xstate_size = possible_xstate_size; do_extra_xstate_size_checks(); + + /* + * User space is always in standard format. + */ + fpu_user_xstate_size = xsave_size; return 0; } -- cgit v0.10.2 From bf15a8cf8d14879b785c548728415d36ccb6a33b Mon Sep 17 00:00:00 2001 From: Fenghua Yu Date: Fri, 20 May 2016 10:47:06 -0700 Subject: x86/fpu/xstate: Rename 'xstate_size' to 'fpu_kernel_xstate_size', to distinguish it from 'fpu_user_xstate_size' User space uses standard format xsave area. fpstate in signal frame should have standard format size. To explicitly distinguish between xstate size in kernel space and the one in user space, we rename 'xstate_size' to 'fpu_kernel_xstate_size'. Cleanup only, no change in functionality. Signed-off-by: Fenghua Yu [ Rebased the patch and cleaned up the naming. ] Signed-off-by: Yu-cheng Yu Reviewed-by: Dave Hansen Cc: Andy Lutomirski Cc: Borislav Petkov Cc: Brian Gerst Cc: Dave Hansen Cc: Denys Vlasenko Cc: H. Peter Anvin Cc: Linus Torvalds Cc: Oleg Nesterov Cc: Peter Zijlstra Cc: Quentin Casasnovas Cc: Ravi V. Shankar Cc: Sai Praneeth Prakhya Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/2ecbae347a5152d94be52adf7d0f3b7305d90d99.1463760376.git.yu-cheng.yu@intel.com Signed-off-by: Ingo Molnar diff --git a/arch/x86/include/asm/processor.h b/arch/x86/include/asm/processor.h index 0a16a16..965c5d2 100644 --- a/arch/x86/include/asm/processor.h +++ b/arch/x86/include/asm/processor.h @@ -367,7 +367,7 @@ DECLARE_PER_CPU(struct irq_stack *, hardirq_stack); DECLARE_PER_CPU(struct irq_stack *, softirq_stack); #endif /* X86_64 */ -extern unsigned int xstate_size; +extern unsigned int fpu_kernel_xstate_size; extern unsigned int fpu_user_xstate_size; struct perf_event; diff --git a/arch/x86/kernel/fpu/core.c b/arch/x86/kernel/fpu/core.c index 7d56474..c759bd0 100644 --- a/arch/x86/kernel/fpu/core.c +++ b/arch/x86/kernel/fpu/core.c @@ -227,7 +227,7 @@ void fpstate_init(union fpregs_state *state) return; } - memset(state, 0, xstate_size); + memset(state, 0, fpu_kernel_xstate_size); if (static_cpu_has(X86_FEATURE_FXSR)) fpstate_init_fxstate(&state->fxsave); @@ -252,7 +252,7 @@ int fpu__copy(struct fpu *dst_fpu, struct fpu *src_fpu) * leak into the child task: */ if (use_eager_fpu()) - memset(&dst_fpu->state.xsave, 0, xstate_size); + memset(&dst_fpu->state.xsave, 0, fpu_kernel_xstate_size); /* * Save current FPU registers directly into the child @@ -271,7 +271,8 @@ int fpu__copy(struct fpu *dst_fpu, struct fpu *src_fpu) */ preempt_disable(); if (!copy_fpregs_to_fpstate(dst_fpu)) { - memcpy(&src_fpu->state, &dst_fpu->state, xstate_size); + memcpy(&src_fpu->state, &dst_fpu->state, + fpu_kernel_xstate_size); if (use_eager_fpu()) copy_kernel_to_fpregs(&src_fpu->state); diff --git a/arch/x86/kernel/fpu/init.c b/arch/x86/kernel/fpu/init.c index 5b1928c..60f3839 100644 --- a/arch/x86/kernel/fpu/init.c +++ b/arch/x86/kernel/fpu/init.c @@ -145,8 +145,8 @@ static void __init fpu__init_system_generic(void) * This is inherent to the XSAVE architecture which puts all state * components into a single, continuous memory block: */ -unsigned int xstate_size; -EXPORT_SYMBOL_GPL(xstate_size); +unsigned int fpu_kernel_xstate_size; +EXPORT_SYMBOL_GPL(fpu_kernel_xstate_size); /* Get alignment of the TYPE. */ #define TYPE_ALIGN(TYPE) offsetof(struct { char x; TYPE test; }, test) @@ -178,7 +178,7 @@ static void __init fpu__init_task_struct_size(void) * Add back the dynamically-calculated register state * size. */ - task_size += xstate_size; + task_size += fpu_kernel_xstate_size; /* * We dynamically size 'struct fpu', so we require that @@ -195,7 +195,7 @@ static void __init fpu__init_task_struct_size(void) } /* - * Set up the user and kernel xstate_size based on the legacy FPU context size. + * Set up the user and kernel xstate sizes based on the legacy FPU context size. * * We set this up first, and later it will be overwritten by * fpu__init_system_xstate() if the CPU knows about xstates. @@ -208,7 +208,7 @@ static void __init fpu__init_system_xstate_size_legacy(void) on_boot_cpu = 0; /* - * Note that xstate_size might be overwriten later during + * Note that xstate sizes might be overwritten later during * fpu__init_system_xstate(). */ @@ -219,15 +219,17 @@ static void __init fpu__init_system_xstate_size_legacy(void) */ setup_clear_cpu_cap(X86_FEATURE_XSAVE); setup_clear_cpu_cap(X86_FEATURE_XSAVEOPT); - xstate_size = sizeof(struct swregs_state); + fpu_kernel_xstate_size = sizeof(struct swregs_state); } else { if (boot_cpu_has(X86_FEATURE_FXSR)) - xstate_size = sizeof(struct fxregs_state); + fpu_kernel_xstate_size = + sizeof(struct fxregs_state); else - xstate_size = sizeof(struct fregs_state); + fpu_kernel_xstate_size = + sizeof(struct fregs_state); } - fpu_user_xstate_size = xstate_size; + fpu_user_xstate_size = fpu_kernel_xstate_size; /* * Quirk: we don't yet handle the XSAVES* instructions diff --git a/arch/x86/kernel/fpu/signal.c b/arch/x86/kernel/fpu/signal.c index 0d29d4d..06d80f6 100644 --- a/arch/x86/kernel/fpu/signal.c +++ b/arch/x86/kernel/fpu/signal.c @@ -263,7 +263,7 @@ static int __fpu__restore_sig(void __user *buf, void __user *buf_fx, int size) int ia32_fxstate = (buf != buf_fx); struct task_struct *tsk = current; struct fpu *fpu = &tsk->thread.fpu; - int state_size = xstate_size; + int state_size = fpu_kernel_xstate_size; u64 xfeatures = 0; int fx_only = 0; diff --git a/arch/x86/kernel/fpu/xstate.c b/arch/x86/kernel/fpu/xstate.c index 9c4da35..46abfaf 100644 --- a/arch/x86/kernel/fpu/xstate.c +++ b/arch/x86/kernel/fpu/xstate.c @@ -537,7 +537,7 @@ static void do_extra_xstate_size_checks(void) */ paranoid_xstate_size += xfeature_size(i); } - XSTATE_WARN_ON(paranoid_xstate_size != xstate_size); + XSTATE_WARN_ON(paranoid_xstate_size != fpu_kernel_xstate_size); } @@ -616,7 +616,7 @@ static int init_xstate_size(void) * The size is OK, we are definitely going to use xsave, * make it known to the world that we need more space. */ - xstate_size = possible_xstate_size; + fpu_kernel_xstate_size = possible_xstate_size; do_extra_xstate_size_checks(); /* @@ -679,14 +679,14 @@ void __init fpu__init_system_xstate(void) return; } - update_regset_xstate_info(xstate_size, xfeatures_mask); + update_regset_xstate_info(fpu_kernel_xstate_size, xfeatures_mask); fpu__init_prepare_fx_sw_frame(); setup_init_fpu_buf(); setup_xstate_comp(); pr_info("x86/fpu: Enabled xstate features 0x%llx, context size is %d bytes, using '%s' format.\n", xfeatures_mask, - xstate_size, + fpu_kernel_xstate_size, boot_cpu_has(X86_FEATURE_XSAVES) ? "compacted" : "standard"); } -- cgit v0.10.2 From 7d9370607d28afd454775c623d5447603473a3c3 Mon Sep 17 00:00:00 2001 From: Fenghua Yu Date: Fri, 20 May 2016 10:47:07 -0700 Subject: x86/fpu/xstate: Keep init_fpstate.xsave.header.xfeatures as zero for init optimization Keep init_fpstate.xsave.header.xfeatures as zero for init optimization. This is important for init optimization that is implemented in processor. If a bit corresponding to an xstate in xstate_bv is 0, it means the xstate is in init status and will not be read from memory to the processor during XRSTOR/XRSTORS instruction. This largely impacts context switch performance. Signed-off-by: Fenghua Yu Signed-off-by: Yu-cheng Yu Reviewed-by: Dave Hansen Cc: Andy Lutomirski Cc: Borislav Petkov Cc: Brian Gerst Cc: Dave Hansen Cc: Denys Vlasenko Cc: H. Peter Anvin Cc: Linus Torvalds Cc: Oleg Nesterov Cc: Peter Zijlstra Cc: Quentin Casasnovas Cc: Ravi V. Shankar Cc: Sai Praneeth Prakhya Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/2fb4ec7f18b76e8cda057a8c0038def74a9b8044.1463760376.git.yu-cheng.yu@intel.com Signed-off-by: Ingo Molnar diff --git a/arch/x86/kernel/fpu/xstate.c b/arch/x86/kernel/fpu/xstate.c index 46abfaf..dbfef1b 100644 --- a/arch/x86/kernel/fpu/xstate.c +++ b/arch/x86/kernel/fpu/xstate.c @@ -329,13 +329,11 @@ static void __init setup_init_fpu_buf(void) setup_xstate_features(); print_xstate_features(); - if (boot_cpu_has(X86_FEATURE_XSAVES)) { + if (boot_cpu_has(X86_FEATURE_XSAVES)) init_fpstate.xsave.header.xcomp_bv = (u64)1 << 63 | xfeatures_mask; - init_fpstate.xsave.header.xfeatures = xfeatures_mask; - } /* - * Init all the features state with header_bv being 0x0 + * Init all the features state with header.xfeatures being 0x0 */ copy_kernel_to_xregs_booting(&init_fpstate.xsave); -- cgit v0.10.2 From 99aa22d0d8f70d9317727ab40c85b2ead740a6ca Mon Sep 17 00:00:00 2001 From: Yu-cheng Yu Date: Fri, 20 May 2016 10:47:08 -0700 Subject: x86/fpu/xstate: Copy xstate registers directly to the signal frame when compacted format is in use XSAVES is a kernel instruction and uses a compacted format. When working with user space, the kernel should provide standard-format, non-supervisor state data. We cannot do __copy_to_user() from a compacted-format kernel xstate area to a signal frame. Dave Hansen proposes this method to simplify copy xstate directly to user. This patch is based on an earlier patch from Fenghua Yu Originally-from: Fenghua Yu Signed-off-by: Yu-cheng Yu Reviewed-by: Dave Hansen Cc: Andy Lutomirski Cc: Borislav Petkov Cc: Brian Gerst Cc: Dave Hansen Cc: Denys Vlasenko Cc: Fenghua Yu Cc: H. Peter Anvin Cc: Linus Torvalds Cc: Oleg Nesterov Cc: Peter Zijlstra Cc: Quentin Casasnovas Cc: Ravi V. Shankar Cc: Sai Praneeth Prakhya Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/c36f419d525517d04209a28dd8e1e5af9000036e.1463760376.git.yu-cheng.yu@intel.com Signed-off-by: Ingo Molnar diff --git a/arch/x86/include/asm/fpu/xstate.h b/arch/x86/include/asm/fpu/xstate.h index 16df2c4..d812cf3 100644 --- a/arch/x86/include/asm/fpu/xstate.h +++ b/arch/x86/include/asm/fpu/xstate.h @@ -47,5 +47,6 @@ extern void update_regset_xstate_info(unsigned int size, u64 xstate_mask); void fpu__xstate_clear_all_cpu_caps(void); void *get_xsave_addr(struct xregs_state *xsave, int xstate); const void *get_xsave_field_ptr(int xstate_field); +int using_compacted_format(void); #endif diff --git a/arch/x86/kernel/fpu/signal.c b/arch/x86/kernel/fpu/signal.c index 06d80f6..8aa96cb 100644 --- a/arch/x86/kernel/fpu/signal.c +++ b/arch/x86/kernel/fpu/signal.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include @@ -169,7 +170,7 @@ int copy_fpstate_to_sigframe(void __user *buf, void __user *buf_fx, int size) sizeof(struct user_i387_ia32_struct), NULL, (struct _fpstate_32 __user *) buf) ? -1 : 1; - if (fpregs_active()) { + if (fpregs_active() || using_compacted_format()) { /* Save the live register state to the user directly. */ if (copy_fpregs_to_sigframe(buf_fx)) return -1; diff --git a/arch/x86/kernel/fpu/xstate.c b/arch/x86/kernel/fpu/xstate.c index dbfef1b..0b01f00 100644 --- a/arch/x86/kernel/fpu/xstate.c +++ b/arch/x86/kernel/fpu/xstate.c @@ -420,7 +420,7 @@ static int xfeature_size(int xfeature_nr) * that it is obvious which aspect of 'XSAVES' is being handled * by the calling code. */ -static int using_compacted_format(void) +int using_compacted_format(void) { return boot_cpu_has(X86_FEATURE_XSAVES); } -- cgit v0.10.2 From d4f56c7773483b8829e89cfc739b7a5a071f6da0 Mon Sep 17 00:00:00 2001 From: Sricharan R Date: Fri, 10 Jun 2016 23:38:20 +0530 Subject: i2c: qup: Fix wrong value of index variable index gets incremented during check to determine if the messages can be transferred with dma. But not reset after that, resulting in wrong start value in subsequent loop, causing failure. Fix it. Signed-off-by: Sricharan R Signed-off-by: Wolfram Sang Cc: stable@kernel.org diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c index cc6439a..041050e 100644 --- a/drivers/i2c/busses/i2c-qup.c +++ b/drivers/i2c/busses/i2c-qup.c @@ -1268,6 +1268,8 @@ static int qup_i2c_xfer_v2(struct i2c_adapter *adap, } } + idx = 0; + do { if (msgs[idx].len == 0) { ret = -EINVAL; -- cgit v0.10.2 From 6ee9169b407f70334f59cdf5a40a72a5d27f0ec2 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Fri, 17 Jun 2016 10:46:52 +0200 Subject: staging: ks7010: remove cfg file handling I verified that all but two settings from the config file can be set up also via 'iwconfig' or 'iwpriv'. The two missing are ROM_FILE and PhyInformationTimer. ROM_FILE can be easily dropped. There is only one known firmware floating on the net, so, the name is fix and we can make this constant. Frankly, I don't know when PhyInformationTimer needs to be set to non-zero. But if we need it somewhen, there is already (currently commented out) code to add this as another private method, so we could use that. Summa summarum: We can remove the config file handling and the example config file. The only useful action, initialization of the configuration struct, is now moved to the sdio main file. Signed-off-by: Wolfram Sang Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/ks7010/Makefile b/drivers/staging/ks7010/Makefile index f6a2cc8..69fcf8d 100644 --- a/drivers/staging/ks7010/Makefile +++ b/drivers/staging/ks7010/Makefile @@ -1,5 +1,4 @@ obj-$(CONFIG_KS7010) += ks7010.o ccflags-y += -DKS_WLAN_DEBUG=0 -ks7010-y := michael_mic.o ks_hostif.o ks_wlan_net.o \ - ks7010_sdio.o ks7010_config.o +ks7010-y := michael_mic.o ks_hostif.o ks_wlan_net.o ks7010_sdio.o diff --git a/drivers/staging/ks7010/TODO b/drivers/staging/ks7010/TODO index 5cbb4ca..2938d35 100644 --- a/drivers/staging/ks7010/TODO +++ b/drivers/staging/ks7010/TODO @@ -26,7 +26,6 @@ Now the TODOs: - fix codechecker warnings (checkpatch, sparse, smatch). But PLEASE make sure that you are not only silencing the warning but really fixing code. You should understand the change you submit. -- drop using a config file and use an upstream technique for configuration - fix the 'card removal' event when card is inserted when booting - check what other upstream wireless mechanisms can be used instead of the custom ones here diff --git a/drivers/staging/ks7010/ks7010_config.c b/drivers/staging/ks7010/ks7010_config.c deleted file mode 100644 index 4b495cb..0000000 --- a/drivers/staging/ks7010/ks7010_config.c +++ /dev/null @@ -1,500 +0,0 @@ -#include -#include - -#include "ks_wlan.h" -#include "ks_hostif.h" -#include "ks_wlan_ioctl.h" - -static int wep_on_off; -#define WEP_OFF 0 -#define WEP_ON_64BIT 1 -#define WEP_ON_128BIT 2 - -static int wep_type; -#define WEP_KEY_CHARACTER 0 -#define WEP_KEY_HEX 1 - -static -void analyze_character_wep_key(struct ks_wlan_parameter *param, - int wep_key_index, char *value) -{ - int i; - unsigned char wep_key[26], key_length; - - key_length = (wep_on_off == WEP_ON_64BIT) ? 5 : 13; - /* 64bit key_length = 5; 128bit key_length = 13; */ - - for (i = 0; i < key_length; i++) { - wep_key[i] = value[i]; - } - - if (wep_key_index < 0 || wep_key_index > 3) - return; - - param->wep_key[wep_key_index].size = key_length; - for (i = 0; i < (param->wep_key[wep_key_index].size); i++) { - param->wep_key[wep_key_index].val[i] = wep_key[i]; - } -} - -static -void analyze_hex_wep_key(struct ks_wlan_parameter *param, int wep_key_index, - char *value) -{ - unsigned char wep_end[26], i, j, key_length; - - key_length = (wep_on_off == WEP_ON_64BIT) ? 10 : 26; - /* 64bit key_length = 10; 128bit key_length = 26; */ - - for (i = 0; i < key_length; i++) { - wep_end[i] = value[i]; - if (i % 2) { - /* Odd */ - for (j = 0x00; j < 0x10; j++) { - if (j < 0x0a) { - if (wep_end[i] == j + 0x30) - wep_end[i] = j; - } else { - if ((wep_end[i] == - j + 0x37) | (wep_end[i] == - j + 0x57)) - wep_end[i] = j; - } - } - } else { - /* Even */ - for (j = 0x00; j < 0x10; j++) { - if (j < 0x0a) { - if (wep_end[i] == j + 0x30) { - wep_end[i] = j * 16; - } - } else { - if ((wep_end[i] == - j + 0x37) | (wep_end[i] == - j + 0x57)) - wep_end[i] = j * 16; - } - } - } - } - - for (i = 0; i < key_length / 2; i++) { - wep_end[i] = wep_end[i * 2] + wep_end[(i * 2) + 1]; - } - - if (wep_key_index < 0 || wep_key_index > 3) - return; - - param->wep_key[wep_key_index].size = key_length / 2; - for (i = 0; i < (param->wep_key[wep_key_index].size); i++) { - param->wep_key[wep_key_index].val[i] = wep_end[i]; - } - -} - -static -int rate_set_configuration(struct ks_wlan_private *priv, char *value) -{ - int rc = 0; - - priv->reg.tx_rate = TX_RATE_FIXED; - priv->reg.rate_set.size = 1; - - switch (*value) { - case '1': /* 1M 11M 12M 18M */ - if (*(value + 1) == '8') { - priv->reg.rate_set.body[0] = TX_RATE_18M; - } else if (*(value + 1) == '2') { - priv->reg.rate_set.body[0] = TX_RATE_12M | BASIC_RATE; - } else if (*(value + 1) == '1') { - priv->reg.rate_set.body[0] = TX_RATE_11M | BASIC_RATE; - } else { - priv->reg.rate_set.body[0] = TX_RATE_1M | BASIC_RATE; - } - break; - case '2': /* 2M 24M */ - if (*(value + 1) == '4') { - priv->reg.rate_set.body[0] = TX_RATE_24M | BASIC_RATE; - } else { - priv->reg.rate_set.body[0] = TX_RATE_2M | BASIC_RATE; - } - break; - case '3': /* 36M */ - priv->reg.rate_set.body[0] = TX_RATE_36M; - break; - case '4': /* 48M */ - priv->reg.rate_set.body[0] = TX_RATE_48M; - break; - case '5': /* 5.5M 54M */ - if (*(value + 1) == '4') { - priv->reg.rate_set.body[0] = TX_RATE_54M; - } else { - priv->reg.rate_set.body[0] = TX_RATE_5M | BASIC_RATE; - } - break; - case '6': /* 6M */ - priv->reg.rate_set.body[0] = TX_RATE_6M | BASIC_RATE; - break; - case '9': /* 9M */ - priv->reg.rate_set.body[0] = TX_RATE_9M; - break; - case 'K': - priv->reg.rate_set.body[6] = TX_RATE_36M; - priv->reg.rate_set.body[5] = TX_RATE_18M; - priv->reg.rate_set.body[4] = TX_RATE_24M | BASIC_RATE; - priv->reg.rate_set.body[3] = TX_RATE_12M | BASIC_RATE; - priv->reg.rate_set.body[2] = TX_RATE_6M | BASIC_RATE; - priv->reg.rate_set.body[1] = TX_RATE_11M | BASIC_RATE; - priv->reg.rate_set.body[0] = TX_RATE_2M | BASIC_RATE; - priv->reg.tx_rate = TX_RATE_FULL_AUTO; - priv->reg.rate_set.size = 7; - break; - default: - priv->reg.rate_set.body[11] = TX_RATE_54M; - priv->reg.rate_set.body[10] = TX_RATE_48M; - priv->reg.rate_set.body[9] = TX_RATE_36M; - priv->reg.rate_set.body[8] = TX_RATE_18M; - priv->reg.rate_set.body[7] = TX_RATE_9M; - priv->reg.rate_set.body[6] = TX_RATE_24M | BASIC_RATE; - priv->reg.rate_set.body[5] = TX_RATE_12M | BASIC_RATE; - priv->reg.rate_set.body[4] = TX_RATE_6M | BASIC_RATE; - priv->reg.rate_set.body[3] = TX_RATE_11M | BASIC_RATE; - priv->reg.rate_set.body[2] = TX_RATE_5M | BASIC_RATE; - priv->reg.rate_set.body[1] = TX_RATE_2M | BASIC_RATE; - priv->reg.rate_set.body[0] = TX_RATE_1M | BASIC_RATE; - priv->reg.tx_rate = TX_RATE_FULL_AUTO; - priv->reg.rate_set.size = 12; - break; - } - return rc; -} - -#include -int ks_wlan_read_config_file(struct ks_wlan_private *priv) -{ - struct { - const int key_len; - const char *key; - const char *val; - } cfg_tbl[] = { - {15, "BeaconLostCount", "20"}, /* 0 */ - {7, "Channel", "1"}, /* 1 */ - {17, "FragmentThreshold", "2346"}, /* 2 */ - {13, "OperationMode", "Infrastructure"}, /* 3 */ - {19, "PowerManagementMode", "ACTIVE"}, /* 4 */ - {12, "RTSThreshold", "2347"}, /* 5 */ - {4, "SSID", "default"}, /* 6 */ - {6, "TxRate", "Auto"}, /* 7 */ - {23, "AuthenticationAlgorithm", ""}, /* 8 */ - {12, "WepKeyValue1", ""}, /* 9 */ - {12, "WepKeyValue2", ""}, /* 10 */ - {12, "WepKeyValue3", ""}, /* 11 */ - {12, "WepKeyValue4", ""}, /* 12 */ - {8, "WepIndex", "1"}, /* 13 */ - {7, "WepType", "STRING"}, /* 14 */ - {3, "Wep", "OFF"}, /* 15 */ - {13, "PREAMBLE_TYPE", "LONG"}, /* 16 */ - {8, "ScanType", "ACTIVE_SCAN"}, /* 17 */ - {8, "ROM_FILE", ROM_FILE}, /* 18 */ - {7, "PhyType", "BG_MODE"}, /* 19 */ - {7, "CtsMode", "FALSE"}, /* 20 */ - {19, "PhyInformationTimer", "0"}, /* 21 */ - {0, "", ""}, - }; - - const struct firmware *fw_entry; - struct device *dev = NULL; - char cfg_file[] = CFG_FILE; - char *cur_p, *end_p; - char wk_buff[256], *wk_p; - - /* Initialize Variable */ - priv->reg.operation_mode = MODE_INFRASTRUCTURE; /* Infrastructure */ - priv->reg.channel = 10; /* 10 */ - memset(priv->reg.bssid, 0x0, ETH_ALEN); /* BSSID */ - priv->reg.ssid.body[0] = '\0'; /* SSID */ - priv->reg.ssid.size = 0; /* SSID size */ - priv->reg.tx_rate = TX_RATE_AUTO; /* TxRate Fully Auto */ - priv->reg.preamble = LONG_PREAMBLE; /* Preamble = LONG */ - priv->reg.powermgt = POWMGT_ACTIVE_MODE; /* POWMGT_ACTIVE_MODE */ - priv->reg.scan_type = ACTIVE_SCAN; /* Active */ - priv->reg.beacon_lost_count = 20; /* Beacon Lost Count */ - priv->reg.rts = 2347UL; /* RTS Threashold */ - priv->reg.fragment = 2346UL; /* Fragmentation Threashold */ - - strcpy(&priv->reg.rom_file[0], ROM_FILE); - - priv->skb = NULL; - - priv->reg.authenticate_type = AUTH_TYPE_OPEN_SYSTEM; /* AuthenticationAlgorithm */ - - priv->reg.privacy_invoked = 0x00; /* WEP */ - priv->reg.wep_index = 0; - memset(&priv->reg.wep_key[0], 0, sizeof(priv->reg.wep_key[0])); - memset(&priv->reg.wep_key[1], 0, sizeof(priv->reg.wep_key[0])); - memset(&priv->reg.wep_key[2], 0, sizeof(priv->reg.wep_key[0])); - memset(&priv->reg.wep_key[3], 0, sizeof(priv->reg.wep_key[0])); - - priv->reg.phy_type = D_11BG_COMPATIBLE_MODE; - priv->reg.cts_mode = CTS_MODE_FALSE; - priv->reg.phy_info_timer = 0; - priv->reg.rate_set.body[11] = TX_RATE_54M; - priv->reg.rate_set.body[10] = TX_RATE_48M; - priv->reg.rate_set.body[9] = TX_RATE_36M; - priv->reg.rate_set.body[8] = TX_RATE_18M; - priv->reg.rate_set.body[7] = TX_RATE_9M; - priv->reg.rate_set.body[6] = TX_RATE_24M | BASIC_RATE; - priv->reg.rate_set.body[5] = TX_RATE_12M | BASIC_RATE; - priv->reg.rate_set.body[4] = TX_RATE_6M | BASIC_RATE; - priv->reg.rate_set.body[3] = TX_RATE_11M | BASIC_RATE; - priv->reg.rate_set.body[2] = TX_RATE_5M | BASIC_RATE; - priv->reg.rate_set.body[1] = TX_RATE_2M | BASIC_RATE; - priv->reg.rate_set.body[0] = TX_RATE_1M | BASIC_RATE; - priv->reg.tx_rate = TX_RATE_FULL_AUTO; - priv->reg.rate_set.size = 12; - - dev = &priv->ks_wlan_hw.sdio_card->func->dev; - /* If no cfg file, stay with the defaults */ - if (request_firmware_direct(&fw_entry, cfg_file, dev)) - return 0; - - DPRINTK(4, "success request_firmware() file=%s size=%zu\n", cfg_file, - fw_entry->size); - cur_p = fw_entry->data; - end_p = cur_p + fw_entry->size; - *end_p = '\0'; - - while (cur_p < end_p) { - int i, j, len; - - len = end_p - cur_p; - for (i = 0; cfg_tbl[i].key_len != 0; i++) { - if (*cur_p == '#') { - break; - } - if (len < cfg_tbl[i].key_len) { - continue; - } - if (!strncmp(cfg_tbl[i].key, cur_p, cfg_tbl[i].key_len)) { - break; - } - } - if ((*cur_p == '#') || (cfg_tbl[i].key_len == 0)) { - while (*cur_p != '\n') { - if (cur_p >= end_p) { - break; - } - cur_p++; - } - cur_p++; - } else { - cur_p += cfg_tbl[i].key_len; - if (*cur_p != '=') { - while (*cur_p != '\n') { - if (cur_p >= end_p) { - break; - } - cur_p++; - } - continue; - } - cur_p++; - - for (j = 0, wk_p = cur_p; *wk_p != '\n' && wk_p < end_p; - j++, wk_p++) { - wk_buff[j] = *wk_p; - } - wk_buff[j] = '\0'; - cur_p = wk_p; - DPRINTK(4, "%s=%s\n", cfg_tbl[i].key, wk_buff); - wk_p = wk_buff; - - switch (i) { - case 0: /* "BeaconLostCount", "10" */ - priv->reg.beacon_lost_count = - simple_strtol(wk_buff, NULL, 10); - break; - case 1: /* "Channel", "1" */ - priv->reg.channel = - simple_strtol(wk_buff, NULL, 10); - break; - case 2: /* "FragmentThreshold","2346" */ - j = simple_strtol(wk_buff, NULL, 10); - priv->reg.fragment = (unsigned long)j; - break; - case 3: /* "OperationMode","Infrastructure" */ - switch (*wk_buff) { - case 'P': - priv->reg.operation_mode = - MODE_PSEUDO_ADHOC; - break; - case 'I': - priv->reg.operation_mode = - MODE_INFRASTRUCTURE; - break; - case '8': - priv->reg.operation_mode = MODE_ADHOC; - break; - default: - priv->reg.operation_mode = - MODE_INFRASTRUCTURE; - } - break; - case 4: /* "PowerManagementMode","POWER_ACTIVE" */ - if (!strncmp(wk_buff, "SAVE1", 5)) { - priv->reg.powermgt = POWMGT_SAVE1_MODE; - } else if (!strncmp(wk_buff, "SAVE2", 5)) { - priv->reg.powermgt = POWMGT_SAVE2_MODE; - } else { - priv->reg.powermgt = POWMGT_ACTIVE_MODE; - } - break; - case 5: /* "RTSThreshold","2347" */ - j = simple_strtol(wk_buff, NULL, 10); - priv->reg.rts = (unsigned long)j; - break; - case 6: /* "SSID","" */ - if (*wk_p != '"') - break; - wk_p++; - for (j = 0; *wk_p != '"'; j++) { - if (wk_p == '\0') { - break; - } - priv->reg.ssid.body[j] = *wk_p++; - } - priv->reg.ssid.body[j] = '\0'; - priv->reg.ssid.size = j; - wk_p++; - break; - case 7: /* "TxRate","Auto" */ - rate_set_configuration(priv, wk_p); - break; - case 8: /* "AuthenticationAlgorithm","OPEN_SYSTEM" */ - switch (*wk_p) { - case 'O': /* Authenticate System : Open System */ - priv->reg.authenticate_type = - AUTH_TYPE_OPEN_SYSTEM; - break; - case 'S': /* Authenticate System : Shared Key */ - priv->reg.authenticate_type = - AUTH_TYPE_SHARED_KEY; - break; - } - break; - case 9: /* "WepKeyValue1","" */ - case 10: /* "WepKeyValue2","" */ - case 11: /* "WepKeyValue3","" */ - case 12: /* "WepKeyValue4","" */ - if (wep_on_off != WEP_OFF) { - switch (wep_type) { - case WEP_KEY_CHARACTER: - analyze_character_wep_key - (&priv->reg, (i - 9), wk_p); - break; - case WEP_KEY_HEX: - analyze_hex_wep_key(&priv->reg, - (i - 9), - wk_p); - break; - } - } - break; - case 13: /* "WepIndex","1"->0 (So, Zero Origin) */ - priv->reg.wep_index = - simple_strtol(wk_buff, NULL, 10) - 1; - break; - case 14: /* "WepType","STRING" */ - if (!strncmp(wk_buff, "STRING", 6)) { - wep_type = WEP_KEY_CHARACTER; - } else { - wep_type = WEP_KEY_HEX; - } - break; - case 15: /* "Wep","OFF" */ - if (!strncmp(wk_buff, "OFF", 3)) { - priv->reg.privacy_invoked = 0x00; - wep_on_off = WEP_OFF; - } else { /* 64bit or 128bit */ - priv->reg.privacy_invoked = 0x01; - if (*wk_buff == '6') { /* 64bit */ - wep_on_off = WEP_ON_64BIT; - } else { /* 128bit */ - wep_on_off = WEP_ON_128BIT; - } - } - break; - case 16: /* "PREAMBLE_TYPE","LONG" */ - if (!strncmp(wk_buff, "SHORT", 5)) { - priv->reg.preamble = SHORT_PREAMBLE; - } else { /* "LONG" */ - priv->reg.preamble = LONG_PREAMBLE; - } - break; - case 17: /* "ScanType","ACTIVE_SCAN" */ - if (!strncmp(wk_buff, "PASSIVE_SCAN", 12)) { - priv->reg.scan_type = PASSIVE_SCAN; - } else { /* "ACTIVE_SCAN" */ - priv->reg.scan_type = ACTIVE_SCAN; - } - break; - case 18: // "ROM_FILE",ROMFILE - if (*wk_p != '"') - break; - wk_p++; - for (j = 0; *wk_p != '"'; j++) { - if (wk_p == '\0') { - break; - } - priv->reg.rom_file[j] = *wk_p++; - } - priv->reg.rom_file[j] = '\0'; - wk_p++; - break; - case 19: /*"PhyType", "BG_MODE" */ - if (!strncmp(wk_buff, "B_MODE", 6)) { - priv->reg.phy_type = D_11B_ONLY_MODE; - } else if (!strncmp(wk_buff, "G_MODE", 6)) { - priv->reg.phy_type = D_11G_ONLY_MODE; - } else { - priv->reg.phy_type = - D_11BG_COMPATIBLE_MODE; - } - break; - case 20: /* "CtsMode", "FALSE" */ - if (!strncmp(wk_buff, "TRUE", 4)) { - priv->reg.cts_mode = CTS_MODE_TRUE; - } else { - priv->reg.cts_mode = CTS_MODE_FALSE; - } - break; - case 21: /* "PhyInformationTimer", "0" */ - j = simple_strtol(wk_buff, NULL, 10); - priv->reg.phy_info_timer = (uint16_t) j; - break; - default: - break; - } - if (cur_p >= end_p) { - break; - } - cur_p++; - } - - } - release_firmware(fw_entry); - - DPRINTK(3, - "\n operation_mode = %d\n channel = %d\n ssid = %s\n tx_rate = %d\n \ - preamble = %d\n powermgt = %d\n scan_type = %d\n beacon_lost_count = %d\n rts = %d\n \ - fragment = %d\n privacy_invoked = %d\n wep_type = %d\n wep_on_off = %d\n wep_index = %d\n romfile = %s\n", - priv->reg.operation_mode, priv->reg.channel, &priv->reg.ssid.body[0], priv->reg.tx_rate, priv->reg.preamble, priv->reg.powermgt, priv->reg.scan_type, priv->reg.beacon_lost_count, priv->reg.rts, priv->reg.fragment, priv->reg.privacy_invoked, wep_type, wep_on_off, - priv->reg.wep_index, &priv->reg.rom_file[0] - ); - DPRINTK(3, - "\n phy_type = %d\n cts_mode = %d\n tx_rate = %d\n phy_info_timer = %d\n", - priv->reg.phy_type, priv->reg.cts_mode, priv->reg.tx_rate, - priv->reg.phy_info_timer); - - return (0); -} diff --git a/drivers/staging/ks7010/ks7010_sdio.c b/drivers/staging/ks7010/ks7010_sdio.c index c340254..d4cce78 100644 --- a/drivers/staging/ks7010/ks7010_sdio.c +++ b/drivers/staging/ks7010/ks7010_sdio.c @@ -807,15 +807,10 @@ static int ks79xx_upload_firmware(struct ks_wlan_private *priv, goto error_out0; } - if (request_firmware - (&fw_entry, priv->reg.rom_file, - &priv->ks_wlan_hw.sdio_card->func->dev) != 0) { - DPRINTK(1, "error request_firmware() file=%s\n", - priv->reg.rom_file); - return 1; - } - DPRINTK(4, "success request_firmware() file=%s size=%zu\n", - priv->reg.rom_file, fw_entry->size); + retval = request_firmware(&fw_entry, ROM_FILE, &priv->ks_wlan_hw.sdio_card->func->dev); + if (retval) + return retval; + length = fw_entry->size; /* Load Program */ @@ -966,6 +961,33 @@ static struct sdio_driver ks7010_sdio_driver = { extern int ks_wlan_net_start(struct net_device *dev); extern int ks_wlan_net_stop(struct net_device *dev); +static void ks7010_init_defaults(struct ks_wlan_private *priv) +{ + priv->reg.tx_rate = TX_RATE_AUTO; + priv->reg.preamble = LONG_PREAMBLE; + priv->reg.powermgt = POWMGT_ACTIVE_MODE; + priv->reg.scan_type = ACTIVE_SCAN; + priv->reg.beacon_lost_count = 20; + priv->reg.rts = 2347UL; + priv->reg.fragment = 2346UL; + priv->reg.phy_type = D_11BG_COMPATIBLE_MODE; + priv->reg.cts_mode = CTS_MODE_FALSE; + priv->reg.rate_set.body[11] = TX_RATE_54M; + priv->reg.rate_set.body[10] = TX_RATE_48M; + priv->reg.rate_set.body[9] = TX_RATE_36M; + priv->reg.rate_set.body[8] = TX_RATE_18M; + priv->reg.rate_set.body[7] = TX_RATE_9M; + priv->reg.rate_set.body[6] = TX_RATE_24M | BASIC_RATE; + priv->reg.rate_set.body[5] = TX_RATE_12M | BASIC_RATE; + priv->reg.rate_set.body[4] = TX_RATE_6M | BASIC_RATE; + priv->reg.rate_set.body[3] = TX_RATE_11M | BASIC_RATE; + priv->reg.rate_set.body[2] = TX_RATE_5M | BASIC_RATE; + priv->reg.rate_set.body[1] = TX_RATE_2M | BASIC_RATE; + priv->reg.rate_set.body[0] = TX_RATE_1M | BASIC_RATE; + priv->reg.tx_rate = TX_RATE_FULL_AUTO; + priv->reg.rate_set.size = 12; +} + static int ks7910_sdio_probe(struct sdio_func *func, const struct sdio_device_id *device) { @@ -1069,14 +1091,7 @@ static int ks7910_sdio_probe(struct sdio_func *func, hostif_init(priv); ks_wlan_net_start(netdev); - /* Read config file */ - ret = ks_wlan_read_config_file(priv); - if (ret) { - printk(KERN_ERR - "ks79xx: read configuration file failed !! retern code = %d\n", - ret); - goto error_free_read_buf; - } + ks7010_init_defaults(priv); /* Upload firmware */ ret = ks79xx_upload_firmware(priv, card); /* firmware load */ diff --git a/drivers/staging/ks7010/ks7010_sdio.h b/drivers/staging/ks7010/ks7010_sdio.h index 987cfa7..815ecf80 100644 --- a/drivers/staging/ks7010/ks7010_sdio.h +++ b/drivers/staging/ks7010/ks7010_sdio.h @@ -142,7 +142,6 @@ struct rx_device { spinlock_t rx_dev_lock; }; #define ROM_FILE "ks7010sd.rom" -#define CFG_FILE "ks79xx.cfg" #define KS_WLAN_DRIVER_VERSION_INFO "ks7010 sdio linux 007" #endif /* _KS7010_SDIO_H */ diff --git a/drivers/staging/ks7010/ks79xx.cfg b/drivers/staging/ks7010/ks79xx.cfg deleted file mode 100644 index 0f2d24d..0000000 --- a/drivers/staging/ks7010/ks79xx.cfg +++ /dev/null @@ -1,116 +0,0 @@ -#ks79xx.cfg -#KS79xx configuration file -# - -# -#BeaconLostCount default 20 -BeaconLostCount=20 -# - -# -#Ap List Scan Type default ACTIVE_SCAN ACTIVE_SCAN or PASSIVE_SCAN -ScanType=ACTIVE_SCAN -# - -# -#Channel default 10 min 1 max 14 -Channel=10 -# - -# -#FragmentThreshold default 2346 min 256 max 2346 -FragmentThreshold=2346 -# - -# -#OperationMode default Infrastructure Pseudo-Ad-Hoc or 802.11-Ad-Hoc or Infrastructure -OperationMode=Infrastructure -# - -# -#PowerManagementMode default ACTIVE ACTIVE or SAVE1 or SAVE2 -PowerManagementMode=ACTIVE -# - -# -#RTSThreshold default 2347 min 0 max 2347 -RTSThreshold=2347 -# - -# -#SSID default "" max 32 character -SSID="default" -# - -# -#TxRate default Auto 1, 2, 5.5, 11 ex. TxRate=1,2 TxRate=11 TxRate=Auto ... -TxRate=Auto -# - -# -#Wep default OFF OFF or 64bit or 128bit -Wep=OFF -# - -# -#WepType default STRING STRING or HEX -WepType=STRING -# - -# -#WepIndex=1 -# - -# -#WepKeyValue1 -# character_wep_key:64bit key_length = 5; 128bit key_length = 13 -# hex_wep_key:64bit key_length = 10; 128bit key_length = 26 -# - -# -#WepKeyValue2 -# character_wep_key:64bit key_length = 5; 128bit key_length = 13 -# hex_wep_key:64bit key_length = 10; 128bit key_length = 26 -# - -# -#WepKeyValue3 -# character_wep_key:64bit key_length = 5; 128bit key_length = 13 -# hex_wep_key:64bit key_length = 10; 128bit key_length = 26 -# - -# -#WepKeyValue4 -# character_wep_key:64bit key_length = 5; 128bit key_length = 13 -# hex_wep_key:64bit key_length = 10; 128bit key_length = 26 -# - -# -#AuthenticationAlgorithm default OPEN_SYSTEM OPEN_SYSTEM or SHARED_KEY -AuthenticationAlgorithm=OPEN_SYSTEM -# - -# -#PREAMBLE_TYPE default LONG LONG or SHORT -PREAMBLE_TYPE=SHORT -# - -# -# PhyType default BG_MODE B_MODE, G_MODE or BG_MODE -PhyType=BG_MODE -# - -# -# CtsMode defalut FALSE TURE or FALSE -CtsMode=FALSE -# - -# -# PhyInformationTimer defalut 0 uint 100msec -PhyInformationTimer=0 -# - -# -#ROM_FILE default "ks7010sd.rom" -ROM_FILE="ks7010sd.rom" -# diff --git a/drivers/staging/ks7010/ks_wlan.h b/drivers/staging/ks7010/ks_wlan.h index c42d99c..019c430 100644 --- a/drivers/staging/ks7010/ks_wlan.h +++ b/drivers/staging/ks7010/ks_wlan.h @@ -73,7 +73,6 @@ struct ks_wlan_parameter { uint16_t phy_type; /* 11b/11g/11bg mode type */ uint16_t cts_mode; /* for 11g/11bg mode cts mode */ uint16_t phy_info_timer; /* phy information timer */ - char rom_file[256]; }; enum { -- cgit v0.10.2 From 30776cf921cd9033d88da56d33707515ce892a8a Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Fri, 17 Jun 2016 10:46:53 +0200 Subject: staging: ks7010: function declaration should be in a header file Signed-off-by: Wolfram Sang Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/ks7010/ks7010_sdio.c b/drivers/staging/ks7010/ks7010_sdio.c index d4cce78..714f933 100644 --- a/drivers/staging/ks7010/ks7010_sdio.c +++ b/drivers/staging/ks7010/ks7010_sdio.c @@ -958,9 +958,6 @@ static struct sdio_driver ks7010_sdio_driver = { .remove = ks7910_sdio_remove, }; -extern int ks_wlan_net_start(struct net_device *dev); -extern int ks_wlan_net_stop(struct net_device *dev); - static void ks7010_init_defaults(struct ks_wlan_private *priv) { priv->reg.tx_rate = TX_RATE_AUTO; diff --git a/drivers/staging/ks7010/ks_wlan.h b/drivers/staging/ks7010/ks_wlan.h index 019c430..f05dc01 100644 --- a/drivers/staging/ks7010/ks_wlan.h +++ b/drivers/staging/ks7010/ks_wlan.h @@ -499,4 +499,7 @@ struct ks_wlan_private { uint wakeup_count; /* for detect wakeup loop */ }; +extern int ks_wlan_net_start(struct net_device *dev); +extern int ks_wlan_net_stop(struct net_device *dev); + #endif /* _KS_WLAN_H */ -- cgit v0.10.2 From 1c013a5ca630eba9ee532eaa77aa67ad4164c298 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Fri, 17 Jun 2016 10:46:54 +0200 Subject: staging: ks7010: collect all includes and sort them Includes probably need a driver-wide clean up, but for now let's at least group all includes from the sdio file together. Signed-off-by: Wolfram Sang Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/ks7010/ks7010_sdio.c b/drivers/staging/ks7010/ks7010_sdio.c index 714f933..b3c98eb 100644 --- a/drivers/staging/ks7010/ks7010_sdio.c +++ b/drivers/staging/ks7010/ks7010_sdio.c @@ -10,15 +10,15 @@ * published by the Free Software Foundation. */ -#include -#include +#include #include #include +#include +#include #include "ks_wlan.h" #include "ks_wlan_ioctl.h" #include "ks_hostif.h" - #include "ks7010_sdio.h" #define KS7010_FUNC_NUM 1 @@ -777,7 +777,6 @@ static int ks7010_sdio_data_compare(struct ks_wlan_private *priv, u32 address, return rc; } -#include static int ks79xx_upload_firmware(struct ks_wlan_private *priv, struct ks_sdio_card *card) { -- cgit v0.10.2 From f9b5bd05a1b43de072da29649b192130411a982c Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Fri, 17 Jun 2016 10:46:55 +0200 Subject: staging: ks7010: export sdio ids So the module will be loaded automatically on card insertion. Rename the array while here. Signed-off-by: Wolfram Sang Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/ks7010/ks7010_sdio.c b/drivers/staging/ks7010/ks7010_sdio.c index b3c98eb..280cbfb 100644 --- a/drivers/staging/ks7010/ks7010_sdio.c +++ b/drivers/staging/ks7010/ks7010_sdio.c @@ -27,11 +27,12 @@ static int reg_net = 0; -static const struct sdio_device_id if_sdio_ids[] = { +static const struct sdio_device_id ks7010_sdio_ids[] = { {SDIO_DEVICE(SDIO_VENDOR_ID_KS_CODE_A, SDIO_DEVICE_ID_KS_7010)}, {SDIO_DEVICE(SDIO_VENDOR_ID_KS_CODE_B, SDIO_DEVICE_ID_KS_7010)}, { /* all zero */ } }; +MODULE_DEVICE_TABLE(sdio, ks7010_sdio_ids); static int ks7910_sdio_probe(struct sdio_func *function, const struct sdio_device_id *device); @@ -952,7 +953,7 @@ static void ks7010_card_init(struct ks_wlan_private *priv) static struct sdio_driver ks7010_sdio_driver = { .name = "ks7910_sdio", - .id_table = if_sdio_ids, + .id_table = ks7010_sdio_ids, .probe = ks7910_sdio_probe, .remove = ks7910_sdio_remove, }; -- cgit v0.10.2 From c4730a92766dacc336f6740c5c1e6181334ef316 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Fri, 17 Jun 2016 10:46:56 +0200 Subject: staging: ks7010: unify naming to ks7010 No 79xx anymore, this is confusing. Add a comment saying that old versions were probably named 7910/79xx. Signed-off-by: Wolfram Sang Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/ks7010/ks7010_sdio.c b/drivers/staging/ks7010/ks7010_sdio.c index 280cbfb..8c2b62b 100644 --- a/drivers/staging/ks7010/ks7010_sdio.c +++ b/drivers/staging/ks7010/ks7010_sdio.c @@ -34,9 +34,9 @@ static const struct sdio_device_id ks7010_sdio_ids[] = { }; MODULE_DEVICE_TABLE(sdio, ks7010_sdio_ids); -static int ks7910_sdio_probe(struct sdio_func *function, +static int ks7010_sdio_probe(struct sdio_func *function, const struct sdio_device_id *device); -static void ks7910_sdio_remove(struct sdio_func *function); +static void ks7010_sdio_remove(struct sdio_func *function); static void ks7010_rw_function(struct work_struct *work); static int ks7010_sdio_read(struct ks_wlan_private *priv, unsigned int address, unsigned char *buffer, int length); @@ -778,7 +778,7 @@ static int ks7010_sdio_data_compare(struct ks_wlan_private *priv, u32 address, return rc; } -static int ks79xx_upload_firmware(struct ks_wlan_private *priv, +static int ks7010_upload_firmware(struct ks_wlan_private *priv, struct ks_sdio_card *card) { unsigned int size, offset, n = 0; @@ -952,10 +952,10 @@ static void ks7010_card_init(struct ks_wlan_private *priv) } static struct sdio_driver ks7010_sdio_driver = { - .name = "ks7910_sdio", + .name = "ks7010_sdio", .id_table = ks7010_sdio_ids, - .probe = ks7910_sdio_probe, - .remove = ks7910_sdio_remove, + .probe = ks7010_sdio_probe, + .remove = ks7010_sdio_remove, }; static void ks7010_init_defaults(struct ks_wlan_private *priv) @@ -985,7 +985,7 @@ static void ks7010_init_defaults(struct ks_wlan_private *priv) priv->reg.rate_set.size = 12; } -static int ks7910_sdio_probe(struct sdio_func *func, +static int ks7010_sdio_probe(struct sdio_func *func, const struct sdio_device_id *device) { struct ks_wlan_private *priv; @@ -994,7 +994,7 @@ static int ks7910_sdio_probe(struct sdio_func *func, unsigned char rw_data; int ret; - DPRINTK(5, "ks7910_sdio_probe()\n"); + DPRINTK(5, "ks7010_sdio_probe()\n"); priv = NULL; netdev = NULL; @@ -1049,11 +1049,11 @@ static int ks7910_sdio_probe(struct sdio_func *func, /* private memory allocate */ netdev = alloc_etherdev(sizeof(*priv)); if (netdev == NULL) { - printk(KERN_ERR "ks79xx : Unable to alloc new net device\n"); + printk(KERN_ERR "ks7010 : Unable to alloc new net device\n"); goto error_release_irq; } if (dev_alloc_name(netdev, netdev->name) < 0) { - printk(KERN_ERR "ks79xx : Couldn't get name!\n"); + printk(KERN_ERR "ks7010 : Couldn't get name!\n"); goto error_free_netdev; } @@ -1091,10 +1091,10 @@ static int ks7910_sdio_probe(struct sdio_func *func, ks7010_init_defaults(priv); /* Upload firmware */ - ret = ks79xx_upload_firmware(priv, card); /* firmware load */ + ret = ks7010_upload_firmware(priv, card); /* firmware load */ if (ret) { printk(KERN_ERR - "ks79xx: firmware load failed !! retern code = %d\n", + "ks7010: firmware load failed !! retern code = %d\n", ret); goto error_free_read_buf; } @@ -1151,13 +1151,13 @@ static int ks7910_sdio_probe(struct sdio_func *func, return -ENODEV; } -static void ks7910_sdio_remove(struct sdio_func *func) +static void ks7010_sdio_remove(struct sdio_func *func) { int ret; struct ks_sdio_card *card; struct ks_wlan_private *priv; struct net_device *netdev; - DPRINTK(1, "ks7910_sdio_remove()\n"); + DPRINTK(1, "ks7010_sdio_remove()\n"); card = sdio_get_drvdata(func); diff --git a/drivers/staging/ks7010/ks7010_sdio.h b/drivers/staging/ks7010/ks7010_sdio.h index 815ecf80..e71c097 100644 --- a/drivers/staging/ks7010/ks7010_sdio.h +++ b/drivers/staging/ks7010/ks7010_sdio.h @@ -19,6 +19,7 @@ /* SDIO KeyStream vendor and device */ #define SDIO_VENDOR_ID_KS_CODE_A 0x005b #define SDIO_VENDOR_ID_KS_CODE_B 0x0023 +/* Older sources suggest earlier versions were named 7910 or 79xx */ #define SDIO_DEVICE_ID_KS_7010 0x7910 /* Read Status Register */ -- cgit v0.10.2 From 4c0d46d2cf62c9cd199cc3323d0b670e7b755650 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Fri, 17 Jun 2016 10:46:57 +0200 Subject: staging: ks7010: sdio: remove forward declarations Move read/write functions to the top and driver struct to the end, so we can remove all forward declarations. Signed-off-by: Wolfram Sang Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/ks7010/ks7010_sdio.c b/drivers/staging/ks7010/ks7010_sdio.c index 8c2b62b..16b9d76 100644 --- a/drivers/staging/ks7010/ks7010_sdio.c +++ b/drivers/staging/ks7010/ks7010_sdio.c @@ -34,14 +34,6 @@ static const struct sdio_device_id ks7010_sdio_ids[] = { }; MODULE_DEVICE_TABLE(sdio, ks7010_sdio_ids); -static int ks7010_sdio_probe(struct sdio_func *function, - const struct sdio_device_id *device); -static void ks7010_sdio_remove(struct sdio_func *function); -static void ks7010_rw_function(struct work_struct *work); -static int ks7010_sdio_read(struct ks_wlan_private *priv, unsigned int address, - unsigned char *buffer, int length); -static int ks7010_sdio_write(struct ks_wlan_private *priv, unsigned int address, - unsigned char *buffer, int length); /* macro */ #define inc_txqhead(priv) \ @@ -58,6 +50,45 @@ static int ks7010_sdio_write(struct ks_wlan_private *priv, unsigned int address, #define cnt_rxqbody(priv) \ (((priv->rx_dev.qtail + RX_DEVICE_BUFF_SIZE) - (priv->rx_dev.qhead)) % RX_DEVICE_BUFF_SIZE ) +static int ks7010_sdio_read(struct ks_wlan_private *priv, unsigned int address, + unsigned char *buffer, int length) +{ + struct ks_sdio_card *card; + int rc; + + card = priv->ks_wlan_hw.sdio_card; + + if (length == 1) /* CMD52 */ + *buffer = sdio_readb(card->func, address, &rc); + else /* CMD53 multi-block transfer */ + rc = sdio_memcpy_fromio(card->func, buffer, address, length); + + if (rc != 0) + DPRINTK(1, "sdio error=%d size=%d\n", rc, length); + + return rc; +} + +static int ks7010_sdio_write(struct ks_wlan_private *priv, unsigned int address, + unsigned char *buffer, int length) +{ + struct ks_sdio_card *card; + int rc; + + card = priv->ks_wlan_hw.sdio_card; + + if (length == 1) /* CMD52 */ + sdio_writeb(card->func, *buffer, (unsigned int)address, &rc); + else /* CMD53 */ + rc = sdio_memcpy_toio(card->func, (unsigned int)address, buffer, + length); + + if (rc != 0) + DPRINTK(1, "sdio error=%d size=%d\n", rc, length); + + return rc; +} + void ks_wlan_hw_sleep_doze_request(struct ks_wlan_private *priv) { unsigned char rw_data; @@ -230,45 +261,6 @@ int ks_wlan_hw_power_save(struct ks_wlan_private *priv) return 0; } -static int ks7010_sdio_read(struct ks_wlan_private *priv, unsigned int address, - unsigned char *buffer, int length) -{ - struct ks_sdio_card *card; - int rc; - - card = priv->ks_wlan_hw.sdio_card; - - if (length == 1) /* CMD52 */ - *buffer = sdio_readb(card->func, address, &rc); - else /* CMD53 multi-block transfer */ - rc = sdio_memcpy_fromio(card->func, buffer, address, length); - - if (rc != 0) - DPRINTK(1, "sdio error=%d size=%d\n", rc, length); - - return rc; -} - -static int ks7010_sdio_write(struct ks_wlan_private *priv, unsigned int address, - unsigned char *buffer, int length) -{ - struct ks_sdio_card *card; - int rc; - - card = priv->ks_wlan_hw.sdio_card; - - if (length == 1) /* CMD52 */ - sdio_writeb(card->func, *buffer, (unsigned int)address, &rc); - else /* CMD53 */ - rc = sdio_memcpy_toio(card->func, (unsigned int)address, buffer, - length); - - if (rc != 0) - DPRINTK(1, "sdio error=%d size=%d\n", rc, length); - - return rc; -} - static int enqueue_txdev(struct ks_wlan_private *priv, unsigned char *p, unsigned long size, void (*complete_handler) (void *arg1, void *arg2), @@ -951,13 +943,6 @@ static void ks7010_card_init(struct ks_wlan_private *priv) } } -static struct sdio_driver ks7010_sdio_driver = { - .name = "ks7010_sdio", - .id_table = ks7010_sdio_ids, - .probe = ks7010_sdio_probe, - .remove = ks7010_sdio_remove, -}; - static void ks7010_init_defaults(struct ks_wlan_private *priv) { priv->reg.tx_rate = TX_RATE_AUTO; @@ -1239,6 +1224,13 @@ static void ks7010_sdio_remove(struct sdio_func *func) return; } +static struct sdio_driver ks7010_sdio_driver = { + .name = "ks7010_sdio", + .id_table = ks7010_sdio_ids, + .probe = ks7010_sdio_probe, + .remove = ks7010_sdio_remove, +}; + module_driver(ks7010_sdio_driver, sdio_register_driver, sdio_unregister_driver); MODULE_AUTHOR("Sang Engineering, Qi-Hardware, KeyStream"); MODULE_DESCRIPTION("Driver for KeyStream KS7010 based SDIO cards"); -- cgit v0.10.2 From 3fb54d7590a4a4d4cf99279c5c228bea788b9628 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Fri, 17 Jun 2016 10:46:58 +0200 Subject: staging: ks7010: bail out when registering netdevice fails There is no need to continue then. Also, this enables us to remove an ugly static variable. Signed-off-by: Wolfram Sang Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/ks7010/ks7010_sdio.c b/drivers/staging/ks7010/ks7010_sdio.c index 16b9d76..c3035b8 100644 --- a/drivers/staging/ks7010/ks7010_sdio.c +++ b/drivers/staging/ks7010/ks7010_sdio.c @@ -25,8 +25,6 @@ #define KS7010_IO_BLOCK_SIZE 512 #define KS7010_MAX_CLOCK 25000000 -static int reg_net = 0; - static const struct sdio_device_id ks7010_sdio_ids[] = { {SDIO_DEVICE(SDIO_VENDOR_ID_KS_CODE_A, SDIO_DEVICE_ID_KS_7010)}, {SDIO_DEVICE(SDIO_VENDOR_ID_KS_CODE_B, SDIO_DEVICE_ID_KS_7010)}, @@ -936,8 +934,6 @@ static void ks7010_card_init(struct ks_wlan_private *priv) if (priv->dev_state >= DEVICE_STATE_PREINIT) { DPRINTK(1, "DEVICE READY!!\n"); priv->dev_state = DEVICE_STATE_READY; - reg_net = register_netdev(priv->net_dev); - DPRINTK(3, "register_netdev=%d\n", reg_net); } else { DPRINTK(1, "dev_state=%d\n", priv->dev_state); } @@ -1115,6 +1111,10 @@ static int ks7010_sdio_probe(struct sdio_func *func, INIT_DELAYED_WORK(&priv->ks_wlan_hw.rw_wq, ks7010_rw_function); ks7010_card_init(priv); + ret = register_netdev(priv->net_dev); + if (ret) + goto error_free_read_buf; + return 0; error_free_read_buf: @@ -1196,9 +1196,7 @@ static void ks7010_sdio_remove(struct sdio_func *func) hostif_exit(priv); DPRINTK(1, "hostif_exit\n"); - if (!reg_net) - unregister_netdev(netdev); - DPRINTK(1, "unregister_netdev\n"); + unregister_netdev(netdev); trx_device_exit(priv); if (priv->ks_wlan_hw.read_buf) { -- cgit v0.10.2 From 6634cff1b545b8a6353e347c7871302353e5b7ca Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Fri, 17 Jun 2016 10:46:59 +0200 Subject: staging: ks7010: report interface as wlan not eth Until we switch to cfg80211 (if ever), we must do this manually. Signed-off-by: Wolfram Sang Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/ks7010/ks7010_sdio.c b/drivers/staging/ks7010/ks7010_sdio.c index c3035b8..b7337fd 100644 --- a/drivers/staging/ks7010/ks7010_sdio.c +++ b/drivers/staging/ks7010/ks7010_sdio.c @@ -1033,7 +1033,7 @@ static int ks7010_sdio_probe(struct sdio_func *func, printk(KERN_ERR "ks7010 : Unable to alloc new net device\n"); goto error_release_irq; } - if (dev_alloc_name(netdev, netdev->name) < 0) { + if (dev_alloc_name(netdev, "wlan%d") < 0) { printk(KERN_ERR "ks7010 : Couldn't get name!\n"); goto error_free_netdev; } -- cgit v0.10.2 From 516a4f04a39712cdb0d3cee263158853603376aa Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Fri, 17 Jun 2016 10:47:00 +0200 Subject: staging: ks7010: drop private handler for driver version We are upstream now, we don't need seperate driver versioning. Signed-off-by: Wolfram Sang Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/ks7010/ks7010_sdio.h b/drivers/staging/ks7010/ks7010_sdio.h index e71c097..c72064b 100644 --- a/drivers/staging/ks7010/ks7010_sdio.h +++ b/drivers/staging/ks7010/ks7010_sdio.h @@ -143,6 +143,5 @@ struct rx_device { spinlock_t rx_dev_lock; }; #define ROM_FILE "ks7010sd.rom" -#define KS_WLAN_DRIVER_VERSION_INFO "ks7010 sdio linux 007" #endif /* _KS7010_SDIO_H */ diff --git a/drivers/staging/ks7010/ks_wlan_ioctl.h b/drivers/staging/ks7010/ks_wlan_ioctl.h index f1fb2dd..49369e4 100644 --- a/drivers/staging/ks7010/ks_wlan_ioctl.h +++ b/drivers/staging/ks7010/ks_wlan_ioctl.h @@ -16,7 +16,7 @@ /* The low order bit identify a SET (0) or a GET (1) ioctl. */ /* SIOCIWFIRSTPRIV+0 */ -#define KS_WLAN_GET_DRIVER_VERSION SIOCIWFIRSTPRIV+1 +/* former KS_WLAN_GET_DRIVER_VERSION SIOCIWFIRSTPRIV+1 */ /* SIOCIWFIRSTPRIV+2 */ #define KS_WLAN_GET_FIRM_VERSION SIOCIWFIRSTPRIV+3 #ifdef WPS diff --git a/drivers/staging/ks7010/ks_wlan_net.c b/drivers/staging/ks7010/ks_wlan_net.c index 8ef0f11..26dbb75 100644 --- a/drivers/staging/ks7010/ks_wlan_net.c +++ b/drivers/staging/ks7010/ks_wlan_net.c @@ -2199,17 +2199,6 @@ static int ks_wlan_set_mlme(struct net_device *dev, } /*------------------------------------------------------------------*/ -/* Private handler : get driver version */ -static int ks_wlan_get_driver_version(struct net_device *dev, - struct iw_request_info *info, - struct iw_point *dwrq, char *extra) -{ - strcpy(extra, KS_WLAN_DRIVER_VERSION_INFO); - dwrq->length = strlen(KS_WLAN_DRIVER_VERSION_INFO) + 1; - return 0; -} - -/*------------------------------------------------------------------*/ /* Private handler : get firemware version */ static int ks_wlan_get_firmware_version(struct net_device *dev, struct iw_request_info *info, @@ -3128,8 +3117,6 @@ static int ks_wlan_hostt(struct net_device *dev, struct iw_request_info *info, static const struct iw_priv_args ks_wlan_private_args[] = { /*{ cmd, set_args, get_args, name[16] } */ - {KS_WLAN_GET_DRIVER_VERSION, IW_PRIV_TYPE_NONE, - IW_PRIV_TYPE_CHAR | (128 + 1), "GetDriverVer"}, {KS_WLAN_GET_FIRM_VERSION, IW_PRIV_TYPE_NONE, IW_PRIV_TYPE_CHAR | (128 + 1), "GetFirmwareVer"}, #ifdef WPS @@ -3258,7 +3245,7 @@ static const iw_handler ks_wlan_handler[] = { /* private_handler */ static const iw_handler ks_wlan_private_handler[] = { (iw_handler) NULL, /* 0 */ - (iw_handler) ks_wlan_get_driver_version, /* 1 KS_WLAN_GET_DRIVER_VERSION */ + (iw_handler) NULL, /* 1, used to be: KS_WLAN_GET_DRIVER_VERSION */ (iw_handler) NULL, /* 2 */ (iw_handler) ks_wlan_get_firmware_version, /* 3 KS_WLAN_GET_FIRM_VERSION */ #ifdef WPS -- cgit v0.10.2 From 453e102db531ac1ffa55f3e03c4907c063125859 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Tue, 14 Jun 2016 14:17:02 +0300 Subject: staging: ks7010: remove bogus NULL checks enc->rx_seq[] and enc->key[] are arrays, not pointers and they can't be NULL. Let's remove these NULL checks. Signed-off-by: Dan Carpenter Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/ks7010/ks_wlan_net.c b/drivers/staging/ks7010/ks_wlan_net.c index 26dbb75..1e21eb1 100644 --- a/drivers/staging/ks7010/ks_wlan_net.c +++ b/drivers/staging/ks7010/ks_wlan_net.c @@ -1910,11 +1910,8 @@ static int ks_wlan_set_encode_ext(struct net_device *dev, priv->wpa.txkey = index; commit |= SME_WEP_INDEX; } else if (enc->ext_flags & IW_ENCODE_EXT_RX_SEQ_VALID) { - if (enc->rx_seq) - memcpy(&priv->wpa.key[index].rx_seq[0], - enc->rx_seq, IW_ENCODE_SEQ_MAX_SIZE); - else - return -EINVAL; + memcpy(&priv->wpa.key[index].rx_seq[0], + enc->rx_seq, IW_ENCODE_SEQ_MAX_SIZE); } memcpy(&priv->wpa.key[index].addr.sa_data[0], @@ -1935,7 +1932,7 @@ static int ks_wlan_set_encode_ext(struct net_device *dev, priv->reg.privacy_invoked = 0x01; commit |= SME_WEP_FLAG; } - if (enc->key && enc->key_len) { + if (enc->key_len) { memcpy(&priv->wpa.key[index].key_val[0], &enc->key[0], enc->key_len); priv->wpa.key[index].key_len = enc->key_len; @@ -1947,7 +1944,7 @@ static int ks_wlan_set_encode_ext(struct net_device *dev, priv->reg.privacy_invoked = 0x01; commit |= SME_WEP_FLAG; } - if (enc->key && enc->key_len == 32) { + if (enc->key_len == 32) { memcpy(&priv->wpa.key[index].key_val[0], &enc->key[0], enc->key_len - 16); priv->wpa.key[index].key_len = -- cgit v0.10.2 From 2fe9262e7e024b089d6f1962fe1fa06b383d2991 Mon Sep 17 00:00:00 2001 From: Salah Triki Date: Wed, 4 May 2016 04:42:40 +0100 Subject: staging: rtl8192u: check return value of read_nic_word_E The call of read_nic_word_E may fail, therefore its return value must be checked and propagated in the case of error. Signed-off-by: Salah Triki Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/rtl8192u/r8180_93cx6.c b/drivers/staging/rtl8192u/r8180_93cx6.c index 97d9b3f..2c53132 100644 --- a/drivers/staging/rtl8192u/r8180_93cx6.c +++ b/drivers/staging/rtl8192u/r8180_93cx6.c @@ -23,8 +23,11 @@ static void eprom_cs(struct net_device *dev, short bit) { u8 cmdreg; + int err; - read_nic_byte_E(dev, EPROM_CMD, &cmdreg); + err = read_nic_byte_E(dev, EPROM_CMD, &cmdreg); + if (err) + return; if (bit) /* enable EPROM */ write_nic_byte_E(dev, EPROM_CMD, cmdreg | EPROM_CS_BIT); @@ -40,8 +43,11 @@ static void eprom_cs(struct net_device *dev, short bit) static void eprom_ck_cycle(struct net_device *dev) { u8 cmdreg; + int err; - read_nic_byte_E(dev, EPROM_CMD, &cmdreg); + err = read_nic_byte_E(dev, EPROM_CMD, &cmdreg); + if (err) + return; write_nic_byte_E(dev, EPROM_CMD, cmdreg | EPROM_CK_BIT); force_pci_posting(dev); udelay(EPROM_DELAY); @@ -56,8 +62,11 @@ static void eprom_ck_cycle(struct net_device *dev) static void eprom_w(struct net_device *dev, short bit) { u8 cmdreg; + int err; - read_nic_byte_E(dev, EPROM_CMD, &cmdreg); + err = read_nic_byte_E(dev, EPROM_CMD, &cmdreg); + if (err) + return; if (bit) write_nic_byte_E(dev, EPROM_CMD, cmdreg | EPROM_W_BIT); else @@ -71,8 +80,12 @@ static void eprom_w(struct net_device *dev, short bit) static short eprom_r(struct net_device *dev) { u8 bit; + int err; + + err = read_nic_byte_E(dev, EPROM_CMD, &bit); + if (err) + return err; - read_nic_byte_E(dev, EPROM_CMD, &bit); udelay(EPROM_DELAY); if (bit & EPROM_R_BIT) -- cgit v0.10.2 From 6ceb65b83771ec860478061479ba54b7093c2ee2 Mon Sep 17 00:00:00 2001 From: Salah Triki Date: Wed, 4 May 2016 04:42:41 +0100 Subject: staging: rtl8192u: propagate errors in eprom_read Propagate error from eprom_r and change the return type of eprom_read from u32 to int. Signed-off-by: Salah Triki Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/rtl8192u/r8180_93cx6.c b/drivers/staging/rtl8192u/r8180_93cx6.c index 2c53132..f35defc 100644 --- a/drivers/staging/rtl8192u/r8180_93cx6.c +++ b/drivers/staging/rtl8192u/r8180_93cx6.c @@ -106,7 +106,7 @@ static void eprom_send_bits_string(struct net_device *dev, short b[], int len) } -u32 eprom_read(struct net_device *dev, u32 addr) +int eprom_read(struct net_device *dev, u32 addr) { struct r8192_priv *priv = ieee80211_priv(dev); short read_cmd[] = {1, 1, 0}; @@ -114,6 +114,7 @@ u32 eprom_read(struct net_device *dev, u32 addr) int i; int addr_len; u32 ret; + int err; ret = 0; /* enable EPROM programming */ @@ -157,7 +158,11 @@ u32 eprom_read(struct net_device *dev, u32 addr) * and reading data. (eeprom outs a dummy 0) */ eprom_ck_cycle(dev); - ret |= (eprom_r(dev)<<(15-i)); + err = eprom_r(dev); + if (err < 0) + return err; + + ret |= err<<(15-i); } eprom_cs(dev, 0); diff --git a/drivers/staging/rtl8192u/r8180_93cx6.h b/drivers/staging/rtl8192u/r8180_93cx6.h index b840348..9cf7f58 100644 --- a/drivers/staging/rtl8192u/r8180_93cx6.h +++ b/drivers/staging/rtl8192u/r8180_93cx6.h @@ -40,4 +40,4 @@ #define EPROM_TXPW1 0x3d -u32 eprom_read(struct net_device *dev, u32 addr); /* reads a 16 bits word */ +int eprom_read(struct net_device *dev, u32 addr); /* reads a 16 bits word */ -- cgit v0.10.2 From 16feab644fd18726e4a1629334d5630d583865c4 Mon Sep 17 00:00:00 2001 From: Salah Triki Date: Wed, 4 May 2016 04:42:42 +0100 Subject: staging: rtl8192u: check return value eprom_read The call of eprom_read may fail, therefore its return value must be checked Signed-off-by: Salah Triki Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/rtl8192u/r8192U_core.c b/drivers/staging/rtl8192u/r8192U_core.c index 8c1d737..950107c 100644 --- a/drivers/staging/rtl8192u/r8192U_core.c +++ b/drivers/staging/rtl8192u/r8192U_core.c @@ -2429,9 +2429,13 @@ static void rtl8192_read_eeprom_info(struct net_device *dev) struct r8192_priv *priv = ieee80211_priv(dev); u16 tmpValue = 0; int i; + int ret; RT_TRACE(COMP_EPROM, "===========>%s()\n", __func__); - wEPROM_ID = eprom_read(dev, 0); /* first read EEPROM ID out; */ + ret = eprom_read(dev, 0); /* first read EEPROM ID out; */ + if (ret < 0) + return; + wEPROM_ID = (u16)ret; RT_TRACE(COMP_EPROM, "EEPROM ID is 0x%x\n", wEPROM_ID); if (wEPROM_ID != RTL8190_EEPROM_ID) @@ -2443,13 +2447,25 @@ static void rtl8192_read_eeprom_info(struct net_device *dev) if (bLoad_From_EEPOM) { tmpValue = eprom_read(dev, EEPROM_VID >> 1); + ret = eprom_read(dev, EEPROM_VID >> 1); + if (ret < 0) + return; + tmpValue = (u16)ret; priv->eeprom_vid = endian_swap(&tmpValue); - priv->eeprom_pid = eprom_read(dev, EEPROM_PID >> 1); - tmpValue = eprom_read(dev, EEPROM_ChannelPlan >> 1); + ret = eprom_read(dev, EEPROM_PID >> 1); + if (ret < 0) + return; + priv->eeprom_pid = (u16)ret; + ret = eprom_read(dev, EEPROM_ChannelPlan >> 1); + if (ret < 0) + return; + tmpValue = (u16)ret; priv->eeprom_ChannelPlan = (tmpValue & 0xff00) >> 8; priv->btxpowerdata_readfromEEPORM = true; - priv->eeprom_CustomerID = - eprom_read(dev, (EEPROM_Customer_ID >> 1)) >> 8; + ret = eprom_read(dev, (EEPROM_Customer_ID >> 1)) >> 8; + if (ret < 0) + return; + priv->eeprom_CustomerID = (u16)ret; } else { priv->eeprom_vid = 0; priv->eeprom_pid = 0; @@ -2467,10 +2483,10 @@ static void rtl8192_read_eeprom_info(struct net_device *dev) int i; for (i = 0; i < 6; i += 2) { - u16 tmp = 0; - - tmp = eprom_read(dev, (u16)((EEPROM_NODE_ADDRESS_BYTE_0 + i) >> 1)); - *(u16 *)(&dev->dev_addr[i]) = tmp; + ret = eprom_read(dev, (u16)((EEPROM_NODE_ADDRESS_BYTE_0 + i) >> 1)); + if (ret < 0) + return; + *(u16 *)(&dev->dev_addr[i]) = (u16)ret; } } else { memcpy(dev->dev_addr, bMac_Tmp_Addr, 6); @@ -2482,52 +2498,72 @@ static void rtl8192_read_eeprom_info(struct net_device *dev) if (priv->card_8192_version == (u8)VERSION_819xU_A) { /* read Tx power gain offset of legacy OFDM to HT rate */ - if (bLoad_From_EEPOM) - priv->EEPROMTxPowerDiff = (eprom_read(dev, (EEPROM_TxPowerDiff >> 1)) & 0xff00) >> 8; - else + if (bLoad_From_EEPOM) { + ret = eprom_read(dev, (EEPROM_TxPowerDiff >> 1)); + if (ret < 0) + return; + priv->EEPROMTxPowerDiff = ((u16)ret & 0xff00) >> 8; + } else priv->EEPROMTxPowerDiff = EEPROM_Default_TxPower; RT_TRACE(COMP_EPROM, "TxPowerDiff:%d\n", priv->EEPROMTxPowerDiff); /* read ThermalMeter from EEPROM */ - if (bLoad_From_EEPOM) - priv->EEPROMThermalMeter = (u8)(eprom_read(dev, (EEPROM_ThermalMeter >> 1)) & 0x00ff); - else + if (bLoad_From_EEPOM) { + ret = eprom_read(dev, (EEPROM_ThermalMeter >> 1)); + if (ret < 0) + return; + priv->EEPROMThermalMeter = (u8)((u16)ret & 0x00ff); + } else priv->EEPROMThermalMeter = EEPROM_Default_ThermalMeter; RT_TRACE(COMP_EPROM, "ThermalMeter:%d\n", priv->EEPROMThermalMeter); /* for tx power track */ priv->TSSI_13dBm = priv->EEPROMThermalMeter * 100; /* read antenna tx power offset of B/C/D to A from EEPROM */ - if (bLoad_From_EEPOM) - priv->EEPROMPwDiff = (eprom_read(dev, (EEPROM_PwDiff >> 1)) & 0x0f00) >> 8; - else + if (bLoad_From_EEPOM) { + ret = eprom_read(dev, (EEPROM_PwDiff >> 1)); + if (ret < 0) + return; + priv->EEPROMPwDiff = ((u16)ret & 0x0f00) >> 8; + } else priv->EEPROMPwDiff = EEPROM_Default_PwDiff; RT_TRACE(COMP_EPROM, "TxPwDiff:%d\n", priv->EEPROMPwDiff); /* Read CrystalCap from EEPROM */ - if (bLoad_From_EEPOM) - priv->EEPROMCrystalCap = (eprom_read(dev, (EEPROM_CrystalCap >> 1)) & 0x0f); - else + if (bLoad_From_EEPOM) { + ret = eprom_read(dev, (EEPROM_CrystalCap >> 1)); + if (ret < 0) + return; + priv->EEPROMCrystalCap = (u16)ret & 0x0f; + } else priv->EEPROMCrystalCap = EEPROM_Default_CrystalCap; RT_TRACE(COMP_EPROM, "CrystalCap = %d\n", priv->EEPROMCrystalCap); /* get per-channel Tx power level */ - if (bLoad_From_EEPOM) - priv->EEPROM_Def_Ver = (eprom_read(dev, (EEPROM_TxPwIndex_Ver >> 1)) & 0xff00) >> 8; - else + if (bLoad_From_EEPOM) { + ret = eprom_read(dev, (EEPROM_TxPwIndex_Ver >> 1)); + if (ret < 0) + return; + priv->EEPROM_Def_Ver = ((u16)ret & 0xff00) >> 8; + } else priv->EEPROM_Def_Ver = 1; RT_TRACE(COMP_EPROM, "EEPROM_DEF_VER:%d\n", priv->EEPROM_Def_Ver); if (priv->EEPROM_Def_Ver == 0) { /* old eeprom definition */ int i; - if (bLoad_From_EEPOM) - priv->EEPROMTxPowerLevelCCK = (eprom_read(dev, (EEPROM_TxPwIndex_CCK >> 1)) & 0xff) >> 8; - else + if (bLoad_From_EEPOM) { + ret = eprom_read(dev, (EEPROM_TxPwIndex_CCK >> 1)); + if (ret < 0) + return; + priv->EEPROMTxPowerLevelCCK = ((u16)ret & 0xff) >> 8; + } else priv->EEPROMTxPowerLevelCCK = 0x10; RT_TRACE(COMP_EPROM, "CCK Tx Power Levl: 0x%02x\n", priv->EEPROMTxPowerLevelCCK); for (i = 0; i < 3; i++) { if (bLoad_From_EEPOM) { - tmpValue = eprom_read(dev, (EEPROM_TxPwIndex_OFDM_24G + i) >> 1); + ret = eprom_read(dev, (EEPROM_TxPwIndex_OFDM_24G + i) >> 1); + if ( ret < 0) + return; if (((EEPROM_TxPwIndex_OFDM_24G + i) % 2) == 0) - tmpValue = tmpValue & 0x00ff; + tmpValue = (u16)ret & 0x00ff; else - tmpValue = (tmpValue & 0xff00) >> 8; + tmpValue = ((u16)ret & 0xff00) >> 8; } else { tmpValue = 0x10; } @@ -2536,17 +2572,21 @@ static void rtl8192_read_eeprom_info(struct net_device *dev) } } else if (priv->EEPROM_Def_Ver == 1) { if (bLoad_From_EEPOM) { - tmpValue = eprom_read(dev, - EEPROM_TxPwIndex_CCK_V1 >> 1); - tmpValue = (tmpValue & 0xff00) >> 8; + ret = eprom_read(dev, EEPROM_TxPwIndex_CCK_V1 >> 1); + if (ret < 0) + return; + tmpValue = ((u16)ret & 0xff00) >> 8; } else { tmpValue = 0x10; } priv->EEPROMTxPowerLevelCCK_V1[0] = (u8)tmpValue; - if (bLoad_From_EEPOM) - tmpValue = eprom_read(dev, (EEPROM_TxPwIndex_CCK_V1 + 2) >> 1); - else + if (bLoad_From_EEPOM) { + ret = eprom_read(dev, (EEPROM_TxPwIndex_CCK_V1 + 2) >> 1); + if (ret < 0) + return; + tmpValue = (u16)ret; + } else tmpValue = 0x1010; *((u16 *)(&priv->EEPROMTxPowerLevelCCK_V1[1])) = tmpValue; if (bLoad_From_EEPOM) -- cgit v0.10.2 From eafe8261c1f82aa9b7da9fc6f6a4ba624ea708b9 Mon Sep 17 00:00:00 2001 From: Salah Triki Date: Wed, 4 May 2016 04:42:43 +0100 Subject: staging: rtl8192u: propagate errors in rtl8192_read_eeprom_info Propagate error from eprom_read and change the return type of rtl8192_read_eeprom_info from void to int. Signed-off-by: Salah Triki Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/rtl8192u/r8192U_core.c b/drivers/staging/rtl8192u/r8192U_core.c index 950107c..89b6372 100644 --- a/drivers/staging/rtl8192u/r8192U_core.c +++ b/drivers/staging/rtl8192u/r8192U_core.c @@ -2421,7 +2421,7 @@ static inline u16 endian_swap(u16 *data) return *data; } -static void rtl8192_read_eeprom_info(struct net_device *dev) +static int rtl8192_read_eeprom_info(struct net_device *dev) { u16 wEPROM_ID = 0; u8 bMac_Tmp_Addr[6] = {0x00, 0xe0, 0x4c, 0x00, 0x00, 0x02}; @@ -2434,7 +2434,7 @@ static void rtl8192_read_eeprom_info(struct net_device *dev) RT_TRACE(COMP_EPROM, "===========>%s()\n", __func__); ret = eprom_read(dev, 0); /* first read EEPROM ID out; */ if (ret < 0) - return; + return ret; wEPROM_ID = (u16)ret; RT_TRACE(COMP_EPROM, "EEPROM ID is 0x%x\n", wEPROM_ID); @@ -2449,22 +2449,22 @@ static void rtl8192_read_eeprom_info(struct net_device *dev) tmpValue = eprom_read(dev, EEPROM_VID >> 1); ret = eprom_read(dev, EEPROM_VID >> 1); if (ret < 0) - return; + return ret; tmpValue = (u16)ret; priv->eeprom_vid = endian_swap(&tmpValue); ret = eprom_read(dev, EEPROM_PID >> 1); if (ret < 0) - return; + return ret; priv->eeprom_pid = (u16)ret; ret = eprom_read(dev, EEPROM_ChannelPlan >> 1); if (ret < 0) - return; + return ret; tmpValue = (u16)ret; priv->eeprom_ChannelPlan = (tmpValue & 0xff00) >> 8; priv->btxpowerdata_readfromEEPORM = true; ret = eprom_read(dev, (EEPROM_Customer_ID >> 1)) >> 8; if (ret < 0) - return; + return ret; priv->eeprom_CustomerID = (u16)ret; } else { priv->eeprom_vid = 0; @@ -2485,7 +2485,7 @@ static void rtl8192_read_eeprom_info(struct net_device *dev) for (i = 0; i < 6; i += 2) { ret = eprom_read(dev, (u16)((EEPROM_NODE_ADDRESS_BYTE_0 + i) >> 1)); if (ret < 0) - return; + return ret; *(u16 *)(&dev->dev_addr[i]) = (u16)ret; } } else { @@ -2501,7 +2501,7 @@ static void rtl8192_read_eeprom_info(struct net_device *dev) if (bLoad_From_EEPOM) { ret = eprom_read(dev, (EEPROM_TxPowerDiff >> 1)); if (ret < 0) - return; + return ret; priv->EEPROMTxPowerDiff = ((u16)ret & 0xff00) >> 8; } else priv->EEPROMTxPowerDiff = EEPROM_Default_TxPower; @@ -2510,7 +2510,7 @@ static void rtl8192_read_eeprom_info(struct net_device *dev) if (bLoad_From_EEPOM) { ret = eprom_read(dev, (EEPROM_ThermalMeter >> 1)); if (ret < 0) - return; + return ret; priv->EEPROMThermalMeter = (u8)((u16)ret & 0x00ff); } else priv->EEPROMThermalMeter = EEPROM_Default_ThermalMeter; @@ -2521,7 +2521,7 @@ static void rtl8192_read_eeprom_info(struct net_device *dev) if (bLoad_From_EEPOM) { ret = eprom_read(dev, (EEPROM_PwDiff >> 1)); if (ret < 0) - return; + return ret; priv->EEPROMPwDiff = ((u16)ret & 0x0f00) >> 8; } else priv->EEPROMPwDiff = EEPROM_Default_PwDiff; @@ -2530,7 +2530,7 @@ static void rtl8192_read_eeprom_info(struct net_device *dev) if (bLoad_From_EEPOM) { ret = eprom_read(dev, (EEPROM_CrystalCap >> 1)); if (ret < 0) - return; + return ret; priv->EEPROMCrystalCap = (u16)ret & 0x0f; } else priv->EEPROMCrystalCap = EEPROM_Default_CrystalCap; @@ -2539,7 +2539,7 @@ static void rtl8192_read_eeprom_info(struct net_device *dev) if (bLoad_From_EEPOM) { ret = eprom_read(dev, (EEPROM_TxPwIndex_Ver >> 1)); if (ret < 0) - return; + return ret; priv->EEPROM_Def_Ver = ((u16)ret & 0xff00) >> 8; } else priv->EEPROM_Def_Ver = 1; @@ -2550,7 +2550,7 @@ static void rtl8192_read_eeprom_info(struct net_device *dev) if (bLoad_From_EEPOM) { ret = eprom_read(dev, (EEPROM_TxPwIndex_CCK >> 1)); if (ret < 0) - return; + return ret; priv->EEPROMTxPowerLevelCCK = ((u16)ret & 0xff) >> 8; } else priv->EEPROMTxPowerLevelCCK = 0x10; @@ -2559,7 +2559,7 @@ static void rtl8192_read_eeprom_info(struct net_device *dev) if (bLoad_From_EEPOM) { ret = eprom_read(dev, (EEPROM_TxPwIndex_OFDM_24G + i) >> 1); if ( ret < 0) - return; + return ret; if (((EEPROM_TxPwIndex_OFDM_24G + i) % 2) == 0) tmpValue = (u16)ret & 0x00ff; else @@ -2574,7 +2574,7 @@ static void rtl8192_read_eeprom_info(struct net_device *dev) if (bLoad_From_EEPOM) { ret = eprom_read(dev, EEPROM_TxPwIndex_CCK_V1 >> 1); if (ret < 0) - return; + return ret; tmpValue = ((u16)ret & 0xff00) >> 8; } else { tmpValue = 0x10; @@ -2584,7 +2584,7 @@ static void rtl8192_read_eeprom_info(struct net_device *dev) if (bLoad_From_EEPOM) { ret = eprom_read(dev, (EEPROM_TxPwIndex_CCK_V1 + 2) >> 1); if (ret < 0) - return; + return ret; tmpValue = (u16)ret; } else tmpValue = 0x1010; @@ -2684,6 +2684,8 @@ static void rtl8192_read_eeprom_info(struct net_device *dev) init_rate_adaptive(dev); RT_TRACE(COMP_EPROM, "<===========%s()\n", __func__); + + return 0; } static short rtl8192_get_channel_map(struct net_device *dev) -- cgit v0.10.2 From 4dc2abb852ca447ee5f6836ed410676ee0447c33 Mon Sep 17 00:00:00 2001 From: Salah Triki Date: Wed, 4 May 2016 04:42:44 +0100 Subject: staging: rtl8192u: check return value of rtl8192_read_eeprom_info The call of rtl8192_read_eeprom_info may fail, therefore its return value must be checked and propagated in the case of error Signed-off-by: Salah Triki Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/rtl8192u/r8192U_core.c b/drivers/staging/rtl8192u/r8192U_core.c index 89b6372..74cf9e7 100644 --- a/drivers/staging/rtl8192u/r8192U_core.c +++ b/drivers/staging/rtl8192u/r8192U_core.c @@ -2706,6 +2706,7 @@ static short rtl8192_get_channel_map(struct net_device *dev) static short rtl8192_init(struct net_device *dev) { struct r8192_priv *priv = ieee80211_priv(dev); + int err; memset(&(priv->stats), 0, sizeof(struct Stats)); memset(priv->txqueue_to_outpipemap, 0, 9); @@ -2727,7 +2728,14 @@ static short rtl8192_init(struct net_device *dev) rtl8192_init_priv_lock(priv); rtl8192_init_priv_task(dev); rtl8192_get_eeprom_size(dev); - rtl8192_read_eeprom_info(dev); + err = rtl8192_read_eeprom_info(dev); + if (err) { + DMESG("Reading EEPROM info failed"); + kfree(priv->pFirmware); + priv->pFirmware = NULL; + free_ieee80211(dev); + return err; + } rtl8192_get_channel_map(dev); init_hal_dm(dev); setup_timer(&priv->watch_dog_timer, watch_dog_timer_callback, -- cgit v0.10.2 From ba15f657cec028ac375c5ca3f901719b46a55cbd Mon Sep 17 00:00:00 2001 From: Salah Triki Date: Wed, 4 May 2016 04:42:45 +0100 Subject: staging: rtl8192u: propagate errors in write_nic_byte Propagate errors from kzalloc and usb_control_msg and change the return type of write_nic_byte from void to int. Signed-off-by: Salah Triki Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/rtl8192u/r8192U.h b/drivers/staging/rtl8192u/r8192U.h index ee1c722..da9b92b 100644 --- a/drivers/staging/rtl8192u/r8192U.h +++ b/drivers/staging/rtl8192u/r8192U.h @@ -1129,7 +1129,7 @@ int read_nic_byte(struct net_device *dev, int x, u8 *data); int read_nic_byte_E(struct net_device *dev, int x, u8 *data); int read_nic_dword(struct net_device *dev, int x, u32 *data); int read_nic_word(struct net_device *dev, int x, u16 *data); -void write_nic_byte(struct net_device *dev, int x, u8 y); +int write_nic_byte(struct net_device *dev, int x, u8 y); void write_nic_byte_E(struct net_device *dev, int x, u8 y); void write_nic_word(struct net_device *dev, int x, u16 y); void write_nic_dword(struct net_device *dev, int x, u32 y); diff --git a/drivers/staging/rtl8192u/r8192U_core.c b/drivers/staging/rtl8192u/r8192U_core.c index 74cf9e7..30c87c2 100644 --- a/drivers/staging/rtl8192u/r8192U_core.c +++ b/drivers/staging/rtl8192u/r8192U_core.c @@ -299,7 +299,7 @@ int read_nic_byte_E(struct net_device *dev, int indx, u8 *data) } /* as 92U has extend page from 4 to 16, so modify functions below. */ -void write_nic_byte(struct net_device *dev, int indx, u8 data) +int write_nic_byte(struct net_device *dev, int indx, u8 data) { int status; @@ -308,7 +308,7 @@ void write_nic_byte(struct net_device *dev, int indx, u8 data) u8 *usbdata = kzalloc(sizeof(data), GFP_KERNEL); if (!usbdata) - return; + return -ENOMEM; *usbdata = data; status = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), @@ -317,8 +317,12 @@ void write_nic_byte(struct net_device *dev, int indx, u8 data) usbdata, 1, HZ / 2); kfree(usbdata); - if (status < 0) + if (status < 0) { netdev_err(dev, "write_nic_byte TimeOut! status: %d\n", status); + return status; + } + + return 0; } -- cgit v0.10.2 From 6ae4e4b3028b277ab9bcf776bcbe4db8681af317 Mon Sep 17 00:00:00 2001 From: Salah Triki Date: Wed, 4 May 2016 04:42:46 +0100 Subject: staging: rtl8192u: propagate errors in write_nic_byte_E Propagate errors from kzalloc and usb_control_msg and change the return type of write_nic_byte_E from void to int. Signed-off-by: Salah Triki Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/rtl8192u/r8192U.h b/drivers/staging/rtl8192u/r8192U.h index da9b92b..e0abcf5 100644 --- a/drivers/staging/rtl8192u/r8192U.h +++ b/drivers/staging/rtl8192u/r8192U.h @@ -1130,7 +1130,7 @@ int read_nic_byte_E(struct net_device *dev, int x, u8 *data); int read_nic_dword(struct net_device *dev, int x, u32 *data); int read_nic_word(struct net_device *dev, int x, u16 *data); int write_nic_byte(struct net_device *dev, int x, u8 y); -void write_nic_byte_E(struct net_device *dev, int x, u8 y); +int write_nic_byte_E(struct net_device *dev, int x, u8 y); void write_nic_word(struct net_device *dev, int x, u16 y); void write_nic_dword(struct net_device *dev, int x, u32 y); void force_pci_posting(struct net_device *dev); diff --git a/drivers/staging/rtl8192u/r8192U_core.c b/drivers/staging/rtl8192u/r8192U_core.c index 30c87c2..675e898 100644 --- a/drivers/staging/rtl8192u/r8192U_core.c +++ b/drivers/staging/rtl8192u/r8192U_core.c @@ -253,7 +253,7 @@ u32 read_cam(struct net_device *dev, u8 addr) return data; } -void write_nic_byte_E(struct net_device *dev, int indx, u8 data) +int write_nic_byte_E(struct net_device *dev, int indx, u8 data) { int status; struct r8192_priv *priv = (struct r8192_priv *)ieee80211_priv(dev); @@ -261,7 +261,7 @@ void write_nic_byte_E(struct net_device *dev, int indx, u8 data) u8 *usbdata = kzalloc(sizeof(data), GFP_KERNEL); if (!usbdata) - return; + return -ENOMEM; *usbdata = data; status = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), @@ -269,9 +269,12 @@ void write_nic_byte_E(struct net_device *dev, int indx, u8 data) indx | 0xfe00, 0, usbdata, 1, HZ / 2); kfree(usbdata); - if (status < 0) + if (status < 0){ netdev_err(dev, "write_nic_byte_E TimeOut! status: %d\n", status); + return status; + } + return 0; } int read_nic_byte_E(struct net_device *dev, int indx, u8 *data) -- cgit v0.10.2 From 28d653d7d17e774afa375b08fb55c4c0e22795ea Mon Sep 17 00:00:00 2001 From: Salah Triki Date: Wed, 4 May 2016 04:42:47 +0100 Subject: staging: rtl8192u: propagate errors in write_nic_word Propagate errors from kzalloc and usb_control_msg and change the return type of write_nic_word from void to int. Signed-off-by: Salah Triki Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/rtl8192u/r8192U.h b/drivers/staging/rtl8192u/r8192U.h index e0abcf5..27f9aa5 100644 --- a/drivers/staging/rtl8192u/r8192U.h +++ b/drivers/staging/rtl8192u/r8192U.h @@ -1131,7 +1131,7 @@ int read_nic_dword(struct net_device *dev, int x, u32 *data); int read_nic_word(struct net_device *dev, int x, u16 *data); int write_nic_byte(struct net_device *dev, int x, u8 y); int write_nic_byte_E(struct net_device *dev, int x, u8 y); -void write_nic_word(struct net_device *dev, int x, u16 y); +int write_nic_word(struct net_device *dev, int x, u16 y); void write_nic_dword(struct net_device *dev, int x, u32 y); void force_pci_posting(struct net_device *dev); diff --git a/drivers/staging/rtl8192u/r8192U_core.c b/drivers/staging/rtl8192u/r8192U_core.c index 675e898..10eeb1c 100644 --- a/drivers/staging/rtl8192u/r8192U_core.c +++ b/drivers/staging/rtl8192u/r8192U_core.c @@ -329,7 +329,7 @@ int write_nic_byte(struct net_device *dev, int indx, u8 data) } -void write_nic_word(struct net_device *dev, int indx, u16 data) +int write_nic_word(struct net_device *dev, int indx, u16 data) { int status; @@ -338,7 +338,7 @@ void write_nic_word(struct net_device *dev, int indx, u16 data) u16 *usbdata = kzalloc(sizeof(data), GFP_KERNEL); if (!usbdata) - return; + return -ENOMEM; *usbdata = data; status = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), @@ -347,8 +347,12 @@ void write_nic_word(struct net_device *dev, int indx, u16 data) usbdata, 2, HZ / 2); kfree(usbdata); - if (status < 0) + if (status < 0) { netdev_err(dev, "write_nic_word TimeOut! status: %d\n", status); + return status; + } + + return 0; } -- cgit v0.10.2 From ec06d48f2443a681ff02d353bd188002d0df18f9 Mon Sep 17 00:00:00 2001 From: Salah Triki Date: Wed, 4 May 2016 04:42:48 +0100 Subject: staging: rtl8192u: propagate errors in write_nic_dword Propagate errors from kzalloc and usb_control_msg and change the return type of write_nic_dword from void to int. Signed-off-by: Salah Triki Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/rtl8192u/r8192U.h b/drivers/staging/rtl8192u/r8192U.h index 27f9aa5..eb0c351 100644 --- a/drivers/staging/rtl8192u/r8192U.h +++ b/drivers/staging/rtl8192u/r8192U.h @@ -1132,7 +1132,7 @@ int read_nic_word(struct net_device *dev, int x, u16 *data); int write_nic_byte(struct net_device *dev, int x, u8 y); int write_nic_byte_E(struct net_device *dev, int x, u8 y); int write_nic_word(struct net_device *dev, int x, u16 y); -void write_nic_dword(struct net_device *dev, int x, u32 y); +int write_nic_dword(struct net_device *dev, int x, u32 y); void force_pci_posting(struct net_device *dev); void rtl8192_rtx_disable(struct net_device *); diff --git a/drivers/staging/rtl8192u/r8192U_core.c b/drivers/staging/rtl8192u/r8192U_core.c index 10eeb1c..646049d 100644 --- a/drivers/staging/rtl8192u/r8192U_core.c +++ b/drivers/staging/rtl8192u/r8192U_core.c @@ -356,7 +356,7 @@ int write_nic_word(struct net_device *dev, int indx, u16 data) } -void write_nic_dword(struct net_device *dev, int indx, u32 data) +int write_nic_dword(struct net_device *dev, int indx, u32 data) { int status; @@ -365,7 +365,7 @@ void write_nic_dword(struct net_device *dev, int indx, u32 data) u32 *usbdata = kzalloc(sizeof(data), GFP_KERNEL); if (!usbdata) - return; + return -ENOMEM; *usbdata = data; status = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), @@ -375,9 +375,13 @@ void write_nic_dword(struct net_device *dev, int indx, u32 data) kfree(usbdata); - if (status < 0) + if (status < 0) { netdev_err(dev, "write_nic_dword TimeOut! status: %d\n", status); + return status; + } + + return 0; } -- cgit v0.10.2 From 75deebb42d8a50ea19617eaaee5e8e7792aecf19 Mon Sep 17 00:00:00 2001 From: Binoy Jayan Date: Thu, 2 Jun 2016 16:22:59 +0530 Subject: rtl8192u: r8192_priv: Replace semaphore wx_sem with mutex The semaphore 'wx_sem' in r8192_priv is a simple mutex, so it should be written as one. Semaphores are going away in the future. Signed-off-by: Binoy Jayan Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/rtl8192u/r8192U.h b/drivers/staging/rtl8192u/r8192U.h index eb0c351..65587ac 100644 --- a/drivers/staging/rtl8192u/r8192U.h +++ b/drivers/staging/rtl8192u/r8192U.h @@ -879,7 +879,7 @@ typedef struct r8192_priv { /* If 1, allow bad crc frame, reception in monitor mode */ short crcmon; - struct semaphore wx_sem; + struct mutex wx_mutex; struct semaphore rf_sem; /* Used to lock rf write operation */ u8 rf_type; /* 0: 1T2R, 1: 2T4R */ diff --git a/drivers/staging/rtl8192u/r8192U_core.c b/drivers/staging/rtl8192u/r8192U_core.c index 646049d..621cabb 100644 --- a/drivers/staging/rtl8192u/r8192U_core.c +++ b/drivers/staging/rtl8192u/r8192U_core.c @@ -2376,7 +2376,7 @@ static void rtl8192_init_priv_lock(struct r8192_priv *priv) { spin_lock_init(&priv->tx_lock); spin_lock_init(&priv->irq_lock); - sema_init(&priv->wx_sem, 1); + mutex_init(&priv->wx_mutex); sema_init(&priv->rf_sem, 1); mutex_init(&priv->mutex); } @@ -3368,12 +3368,12 @@ RESET_START: /* Set the variable for reset. */ priv->ResetProgress = RESET_TYPE_SILENT; - down(&priv->wx_sem); + mutex_lock(&priv->wx_mutex); if (priv->up == 0) { RT_TRACE(COMP_ERR, "%s():the driver is not up! return\n", __func__); - up(&priv->wx_sem); + mutex_unlock(&priv->wx_mutex); return; } priv->up = 0; @@ -3400,7 +3400,7 @@ RESET_START: netdev_dbg(dev, "ieee->state is NOT LINKED\n"); ieee80211_softmac_stop_protocol(priv->ieee80211); } - up(&priv->wx_sem); + mutex_unlock(&priv->wx_mutex); RT_TRACE(COMP_RESET, "%s():<==========down process is finished\n", __func__); @@ -3598,9 +3598,9 @@ static int rtl8192_open(struct net_device *dev) struct r8192_priv *priv = ieee80211_priv(dev); int ret; - down(&priv->wx_sem); + mutex_lock(&priv->wx_mutex); ret = rtl8192_up(dev); - up(&priv->wx_sem); + mutex_unlock(&priv->wx_mutex); return ret; } @@ -3621,11 +3621,11 @@ static int rtl8192_close(struct net_device *dev) struct r8192_priv *priv = ieee80211_priv(dev); int ret; - down(&priv->wx_sem); + mutex_lock(&priv->wx_mutex); ret = rtl8192_down(dev); - up(&priv->wx_sem); + mutex_unlock(&priv->wx_mutex); return ret; } @@ -3697,11 +3697,11 @@ static void rtl8192_restart(struct work_struct *work) reset_wq); struct net_device *dev = priv->ieee80211->dev; - down(&priv->wx_sem); + mutex_lock(&priv->wx_mutex); rtl8192_commit(dev); - up(&priv->wx_sem); + mutex_unlock(&priv->wx_mutex); } static void r8192_set_multicast(struct net_device *dev) @@ -3724,12 +3724,12 @@ static int r8192_set_mac_adr(struct net_device *dev, void *mac) struct r8192_priv *priv = ieee80211_priv(dev); struct sockaddr *addr = mac; - down(&priv->wx_sem); + mutex_lock(&priv->wx_mutex); ether_addr_copy(dev->dev_addr, addr->sa_data); schedule_work(&priv->reset_wq); - up(&priv->wx_sem); + mutex_unlock(&priv->wx_mutex); return 0; } @@ -3746,7 +3746,7 @@ static int rtl8192_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) struct iw_point *p = &wrq->u.data; struct ieee_param *ipw = NULL; - down(&priv->wx_sem); + mutex_lock(&priv->wx_mutex); if (p->length < sizeof(struct ieee_param) || !p->pointer) { @@ -3839,7 +3839,7 @@ static int rtl8192_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) kfree(ipw); ipw = NULL; out: - up(&priv->wx_sem); + mutex_unlock(&priv->wx_mutex); return ret; } diff --git a/drivers/staging/rtl8192u/r8192U_wx.c b/drivers/staging/rtl8192u/r8192U_wx.c index 837704d..d2f2f24 100644 --- a/drivers/staging/rtl8192u/r8192U_wx.c +++ b/drivers/staging/rtl8192u/r8192U_wx.c @@ -67,11 +67,11 @@ static int r8192_wx_set_rate(struct net_device *dev, int ret; struct r8192_priv *priv = ieee80211_priv(dev); - down(&priv->wx_sem); + mutex_lock(&priv->wx_mutex); ret = ieee80211_wx_set_rate(priv->ieee80211, info, wrqu, extra); - up(&priv->wx_sem); + mutex_unlock(&priv->wx_mutex); return ret; } @@ -83,11 +83,11 @@ static int r8192_wx_set_rts(struct net_device *dev, int ret; struct r8192_priv *priv = ieee80211_priv(dev); - down(&priv->wx_sem); + mutex_lock(&priv->wx_mutex); ret = ieee80211_wx_set_rts(priv->ieee80211, info, wrqu, extra); - up(&priv->wx_sem); + mutex_unlock(&priv->wx_mutex); return ret; } @@ -108,11 +108,11 @@ static int r8192_wx_set_power(struct net_device *dev, int ret; struct r8192_priv *priv = ieee80211_priv(dev); - down(&priv->wx_sem); + mutex_lock(&priv->wx_mutex); ret = ieee80211_wx_set_power(priv->ieee80211, info, wrqu, extra); - up(&priv->wx_sem); + mutex_unlock(&priv->wx_mutex); return ret; } @@ -132,11 +132,11 @@ static int r8192_wx_force_reset(struct net_device *dev, { struct r8192_priv *priv = ieee80211_priv(dev); - down(&priv->wx_sem); + mutex_lock(&priv->wx_mutex); netdev_dbg(dev, "%s(): force reset ! extra is %d\n", __func__, *extra); priv->force_reset = *extra; - up(&priv->wx_sem); + mutex_unlock(&priv->wx_mutex); return 0; } @@ -148,11 +148,11 @@ static int r8192_wx_set_rawtx(struct net_device *dev, struct r8192_priv *priv = ieee80211_priv(dev); int ret; - down(&priv->wx_sem); + mutex_lock(&priv->wx_mutex); ret = ieee80211_wx_set_rawtx(priv->ieee80211, info, wrqu, extra); - up(&priv->wx_sem); + mutex_unlock(&priv->wx_mutex); return ret; @@ -166,7 +166,7 @@ static int r8192_wx_set_crcmon(struct net_device *dev, int *parms = (int *)extra; int enable = (parms[0] > 0); - down(&priv->wx_sem); + mutex_lock(&priv->wx_mutex); if (enable) priv->crcmon = 1; @@ -176,7 +176,7 @@ static int r8192_wx_set_crcmon(struct net_device *dev, DMESG("bad CRC in monitor mode are %s", priv->crcmon ? "accepted" : "rejected"); - up(&priv->wx_sem); + mutex_unlock(&priv->wx_mutex); return 0; } @@ -187,13 +187,13 @@ static int r8192_wx_set_mode(struct net_device *dev, struct iw_request_info *a, struct r8192_priv *priv = ieee80211_priv(dev); int ret; - down(&priv->wx_sem); + mutex_lock(&priv->wx_mutex); ret = ieee80211_wx_set_mode(priv->ieee80211, a, wrqu, b); rtl8192_set_rxconf(dev); - up(&priv->wx_sem); + mutex_unlock(&priv->wx_mutex); return ret; } @@ -338,7 +338,7 @@ static int r8192_wx_set_scan(struct net_device *dev, struct iw_request_info *a, } } - down(&priv->wx_sem); + mutex_lock(&priv->wx_mutex); if (priv->ieee80211->state != IEEE80211_LINKED) { priv->ieee80211->scanning = 0; ieee80211_softmac_scan_syncro(priv->ieee80211); @@ -346,7 +346,7 @@ static int r8192_wx_set_scan(struct net_device *dev, struct iw_request_info *a, } else { ret = ieee80211_wx_set_scan(priv->ieee80211, a, wrqu, b); } - up(&priv->wx_sem); + mutex_unlock(&priv->wx_mutex); return ret; } @@ -361,11 +361,11 @@ static int r8192_wx_get_scan(struct net_device *dev, struct iw_request_info *a, if (!priv->up) return -ENETDOWN; - down(&priv->wx_sem); + mutex_lock(&priv->wx_mutex); ret = ieee80211_wx_get_scan(priv->ieee80211, a, wrqu, b); - up(&priv->wx_sem); + mutex_unlock(&priv->wx_mutex); return ret; } @@ -377,11 +377,11 @@ static int r8192_wx_set_essid(struct net_device *dev, struct r8192_priv *priv = ieee80211_priv(dev); int ret; - down(&priv->wx_sem); + mutex_lock(&priv->wx_mutex); ret = ieee80211_wx_set_essid(priv->ieee80211, a, wrqu, b); - up(&priv->wx_sem); + mutex_unlock(&priv->wx_mutex); return ret; } @@ -393,11 +393,11 @@ static int r8192_wx_get_essid(struct net_device *dev, int ret; struct r8192_priv *priv = ieee80211_priv(dev); - down(&priv->wx_sem); + mutex_lock(&priv->wx_mutex); ret = ieee80211_wx_get_essid(priv->ieee80211, a, wrqu, b); - up(&priv->wx_sem); + mutex_unlock(&priv->wx_mutex); return ret; } @@ -408,11 +408,11 @@ static int r8192_wx_set_freq(struct net_device *dev, struct iw_request_info *a, int ret; struct r8192_priv *priv = ieee80211_priv(dev); - down(&priv->wx_sem); + mutex_lock(&priv->wx_mutex); ret = ieee80211_wx_set_freq(priv->ieee80211, a, wrqu, b); - up(&priv->wx_sem); + mutex_unlock(&priv->wx_mutex); return ret; } @@ -468,11 +468,11 @@ static int r8192_wx_set_wap(struct net_device *dev, int ret; struct r8192_priv *priv = ieee80211_priv(dev); /* struct sockaddr *temp = (struct sockaddr *)awrq; */ - down(&priv->wx_sem); + mutex_lock(&priv->wx_mutex); ret = ieee80211_wx_set_wap(priv->ieee80211, info, awrq, extra); - up(&priv->wx_sem); + mutex_unlock(&priv->wx_mutex); return ret; @@ -515,12 +515,12 @@ static int r8192_wx_set_enc(struct net_device *dev, if (!priv->up) return -ENETDOWN; - down(&priv->wx_sem); + mutex_lock(&priv->wx_mutex); RT_TRACE(COMP_SEC, "Setting SW wep key"); ret = ieee80211_wx_set_encode(priv->ieee80211, info, wrqu, key); - up(&priv->wx_sem); + mutex_unlock(&priv->wx_mutex); @@ -619,7 +619,7 @@ static int r8192_wx_set_retry(struct net_device *dev, struct r8192_priv *priv = ieee80211_priv(dev); int err = 0; - down(&priv->wx_sem); + mutex_lock(&priv->wx_mutex); if (wrqu->retry.flags & IW_RETRY_LIFETIME || wrqu->retry.disabled){ @@ -652,7 +652,7 @@ static int r8192_wx_set_retry(struct net_device *dev, rtl8192_commit(dev); exit: - up(&priv->wx_sem); + mutex_unlock(&priv->wx_mutex); return err; } @@ -701,7 +701,7 @@ static int r8192_wx_set_sens(struct net_device *dev, struct r8192_priv *priv = ieee80211_priv(dev); short err = 0; - down(&priv->wx_sem); + mutex_lock(&priv->wx_mutex); if (priv->rf_set_sens == NULL) { err = -1; /* we have not this support for this radio */ goto exit; @@ -712,7 +712,7 @@ static int r8192_wx_set_sens(struct net_device *dev, err = -EINVAL; exit: - up(&priv->wx_sem); + mutex_unlock(&priv->wx_mutex); return err; } @@ -727,7 +727,7 @@ static int r8192_wx_set_enc_ext(struct net_device *dev, struct ieee80211_device *ieee = priv->ieee80211; - down(&priv->wx_sem); + mutex_lock(&priv->wx_mutex); ret = ieee80211_wx_set_encode_ext(priv->ieee80211, info, wrqu, extra); { @@ -790,7 +790,7 @@ static int r8192_wx_set_enc_ext(struct net_device *dev, end_hw_sec: - up(&priv->wx_sem); + mutex_unlock(&priv->wx_mutex); return ret; } @@ -801,9 +801,9 @@ static int r8192_wx_set_auth(struct net_device *dev, int ret = 0; struct r8192_priv *priv = ieee80211_priv(dev); - down(&priv->wx_sem); + mutex_lock(&priv->wx_mutex); ret = ieee80211_wx_set_auth(priv->ieee80211, info, &(data->param), extra); - up(&priv->wx_sem); + mutex_unlock(&priv->wx_mutex); return ret; } @@ -815,10 +815,10 @@ static int r8192_wx_set_mlme(struct net_device *dev, int ret = 0; struct r8192_priv *priv = ieee80211_priv(dev); - down(&priv->wx_sem); + mutex_lock(&priv->wx_mutex); ret = ieee80211_wx_set_mlme(priv->ieee80211, info, wrqu, extra); - up(&priv->wx_sem); + mutex_unlock(&priv->wx_mutex); return ret; } @@ -829,9 +829,9 @@ static int r8192_wx_set_gen_ie(struct net_device *dev, int ret = 0; struct r8192_priv *priv = ieee80211_priv(dev); - down(&priv->wx_sem); + mutex_lock(&priv->wx_mutex); ret = ieee80211_wx_set_gen_ie(priv->ieee80211, extra, data->data.length); - up(&priv->wx_sem); + mutex_unlock(&priv->wx_mutex); return ret; -- cgit v0.10.2 From e379a9a87952f5b16cbad8f89a8826c4df2fcb31 Mon Sep 17 00:00:00 2001 From: Binoy Jayan Date: Thu, 2 Jun 2016 16:23:00 +0530 Subject: rtl8192u: ieee80211_device: Replace semaphore wx_sem with mutex The semaphore 'wx_sem' in ieee80211_device is a simple mutex, so it should be written as one. Semaphores are going away in the future. Signed-off-by: Binoy Jayan Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/rtl8192u/ieee80211/ieee80211.h b/drivers/staging/rtl8192u/ieee80211/ieee80211.h index 68931e5..ef9ae22 100644 --- a/drivers/staging/rtl8192u/ieee80211/ieee80211.h +++ b/drivers/staging/rtl8192u/ieee80211/ieee80211.h @@ -1799,7 +1799,7 @@ struct ieee80211_device { short scanning; short proto_started; - struct semaphore wx_sem; + struct mutex wx_mutex; struct semaphore scan_sem; spinlock_t mgmt_tx_lock; diff --git a/drivers/staging/rtl8192u/ieee80211/ieee80211_softmac.c b/drivers/staging/rtl8192u/ieee80211/ieee80211_softmac.c index d705595..664664b 100644 --- a/drivers/staging/rtl8192u/ieee80211/ieee80211_softmac.c +++ b/drivers/staging/rtl8192u/ieee80211/ieee80211_softmac.c @@ -621,7 +621,7 @@ static void ieee80211_start_scan(struct ieee80211_device *ieee) } -/* called with wx_sem held */ +/* called with wx_mutex held */ void ieee80211_start_scan_syncro(struct ieee80211_device *ieee) { if (IS_DOT11D_ENABLE(ieee) ) @@ -1389,7 +1389,7 @@ static void ieee80211_associate_procedure_wq(struct work_struct *work) { struct ieee80211_device *ieee = container_of(work, struct ieee80211_device, associate_procedure_wq); ieee->sync_scan_hurryup = 1; - down(&ieee->wx_sem); + mutex_lock(&ieee->wx_mutex); if (ieee->data_hard_stop) ieee->data_hard_stop(ieee->dev); @@ -1402,7 +1402,7 @@ static void ieee80211_associate_procedure_wq(struct work_struct *work) ieee->associate_seq = 1; ieee80211_associate_step1(ieee); - up(&ieee->wx_sem); + mutex_unlock(&ieee->wx_mutex); } inline void ieee80211_softmac_new_net(struct ieee80211_device *ieee, struct ieee80211_network *net) @@ -2331,7 +2331,7 @@ static void ieee80211_start_ibss_wq(struct work_struct *work) struct ieee80211_device *ieee = container_of(dwork, struct ieee80211_device, start_ibss_wq); /* iwconfig mode ad-hoc will schedule this and return * on the other hand this will block further iwconfig SET - * operations because of the wx_sem hold. + * operations because of the wx_mutex hold. * Anyway some most set operations set a flag to speed-up * (abort) this wq (when syncro scanning) before sleeping * on the semaphore @@ -2340,7 +2340,7 @@ static void ieee80211_start_ibss_wq(struct work_struct *work) printk("==========oh driver down return\n"); return; } - down(&ieee->wx_sem); + mutex_lock(&ieee->wx_mutex); if (ieee->current_network.ssid_len == 0) { strcpy(ieee->current_network.ssid, IEEE80211_DEFAULT_TX_ESSID); @@ -2431,7 +2431,7 @@ static void ieee80211_start_ibss_wq(struct work_struct *work) ieee->data_hard_resume(ieee->dev); netif_carrier_on(ieee->dev); - up(&ieee->wx_sem); + mutex_unlock(&ieee->wx_mutex); } inline void ieee80211_start_ibss(struct ieee80211_device *ieee) @@ -2439,7 +2439,7 @@ inline void ieee80211_start_ibss(struct ieee80211_device *ieee) schedule_delayed_work(&ieee->start_ibss_wq, 150); } -/* this is called only in user context, with wx_sem held */ +/* this is called only in user context, with wx_mutex held */ void ieee80211_start_bss(struct ieee80211_device *ieee) { unsigned long flags; @@ -2505,7 +2505,7 @@ static void ieee80211_associate_retry_wq(struct work_struct *work) struct ieee80211_device *ieee = container_of(dwork, struct ieee80211_device, associate_retry_wq); unsigned long flags; - down(&ieee->wx_sem); + mutex_lock(&ieee->wx_mutex); if(!ieee->proto_started) goto exit; @@ -2537,7 +2537,7 @@ static void ieee80211_associate_retry_wq(struct work_struct *work) spin_unlock_irqrestore(&ieee->lock, flags); exit: - up(&ieee->wx_sem); + mutex_unlock(&ieee->wx_mutex); } struct sk_buff *ieee80211_get_beacon_(struct ieee80211_device *ieee) @@ -2583,9 +2583,9 @@ EXPORT_SYMBOL(ieee80211_get_beacon); void ieee80211_softmac_stop_protocol(struct ieee80211_device *ieee) { ieee->sync_scan_hurryup = 1; - down(&ieee->wx_sem); + mutex_lock(&ieee->wx_mutex); ieee80211_stop_protocol(ieee); - up(&ieee->wx_sem); + mutex_unlock(&ieee->wx_mutex); } EXPORT_SYMBOL(ieee80211_softmac_stop_protocol); @@ -2609,9 +2609,9 @@ void ieee80211_stop_protocol(struct ieee80211_device *ieee) void ieee80211_softmac_start_protocol(struct ieee80211_device *ieee) { ieee->sync_scan_hurryup = 0; - down(&ieee->wx_sem); + mutex_lock(&ieee->wx_mutex); ieee80211_start_protocol(ieee); - up(&ieee->wx_sem); + mutex_unlock(&ieee->wx_mutex); } EXPORT_SYMBOL(ieee80211_softmac_start_protocol); @@ -2728,7 +2728,7 @@ void ieee80211_softmac_init(struct ieee80211_device *ieee) INIT_WORK(&ieee->wx_sync_scan_wq, ieee80211_wx_sync_scan_wq); - sema_init(&ieee->wx_sem, 1); + mutex_init(&ieee->wx_mutex); sema_init(&ieee->scan_sem, 1); spin_lock_init(&ieee->mgmt_tx_lock); @@ -2742,14 +2742,14 @@ void ieee80211_softmac_init(struct ieee80211_device *ieee) void ieee80211_softmac_free(struct ieee80211_device *ieee) { - down(&ieee->wx_sem); + mutex_lock(&ieee->wx_mutex); kfree(ieee->pDot11dInfo); ieee->pDot11dInfo = NULL; del_timer_sync(&ieee->associate_timer); cancel_delayed_work(&ieee->associate_retry_wq); - up(&ieee->wx_sem); + mutex_unlock(&ieee->wx_mutex); } /******************************************************** @@ -3138,7 +3138,7 @@ int ieee80211_wpa_supplicant_ioctl(struct ieee80211_device *ieee, struct iw_poin struct ieee_param *param; int ret=0; - down(&ieee->wx_sem); + mutex_lock(&ieee->wx_mutex); //IEEE_DEBUG_INFO("wpa_supplicant: len=%d\n", p->length); if (p->length < sizeof(struct ieee_param) || !p->pointer) { @@ -3183,7 +3183,7 @@ int ieee80211_wpa_supplicant_ioctl(struct ieee80211_device *ieee, struct iw_poin kfree(param); out: - up(&ieee->wx_sem); + mutex_unlock(&ieee->wx_mutex); return ret; } diff --git a/drivers/staging/rtl8192u/ieee80211/ieee80211_softmac_wx.c b/drivers/staging/rtl8192u/ieee80211/ieee80211_softmac_wx.c index aad288a..21bd0dc 100644 --- a/drivers/staging/rtl8192u/ieee80211/ieee80211_softmac_wx.c +++ b/drivers/staging/rtl8192u/ieee80211/ieee80211_softmac_wx.c @@ -34,7 +34,7 @@ int ieee80211_wx_set_freq(struct ieee80211_device *ieee, struct iw_request_info int ret; struct iw_freq *fwrq = &wrqu->freq; - down(&ieee->wx_sem); + mutex_lock(&ieee->wx_mutex); if (ieee->iw_mode == IW_MODE_INFRA) { ret = -EOPNOTSUPP; @@ -79,7 +79,7 @@ int ieee80211_wx_set_freq(struct ieee80211_device *ieee, struct iw_request_info ret = 0; out: - up(&ieee->wx_sem); + mutex_unlock(&ieee->wx_mutex); return ret; } EXPORT_SYMBOL(ieee80211_wx_set_freq); @@ -145,7 +145,7 @@ int ieee80211_wx_set_wap(struct ieee80211_device *ieee, ieee->sync_scan_hurryup = 1; - down(&ieee->wx_sem); + mutex_lock(&ieee->wx_mutex); /* use ifconfig hw ether */ if (ieee->iw_mode == IW_MODE_MASTER) { ret = -1; @@ -173,7 +173,7 @@ int ieee80211_wx_set_wap(struct ieee80211_device *ieee, if (ifup) ieee80211_start_protocol(ieee); out: - up(&ieee->wx_sem); + mutex_unlock(&ieee->wx_mutex); return ret; } EXPORT_SYMBOL(ieee80211_wx_set_wap); @@ -274,7 +274,7 @@ int ieee80211_wx_set_mode(struct ieee80211_device *ieee, struct iw_request_info ieee->sync_scan_hurryup = 1; - down(&ieee->wx_sem); + mutex_lock(&ieee->wx_mutex); if (wrqu->mode == ieee->iw_mode) goto out; @@ -293,7 +293,7 @@ int ieee80211_wx_set_mode(struct ieee80211_device *ieee, struct iw_request_info } out: - up(&ieee->wx_sem); + mutex_unlock(&ieee->wx_mutex); return 0; } EXPORT_SYMBOL(ieee80211_wx_set_mode); @@ -353,7 +353,7 @@ void ieee80211_wx_sync_scan_wq(struct work_struct *work) ieee80211_start_send_beacons(ieee); netif_carrier_on(ieee->dev); - up(&ieee->wx_sem); + mutex_unlock(&ieee->wx_mutex); } @@ -362,7 +362,7 @@ int ieee80211_wx_set_scan(struct ieee80211_device *ieee, struct iw_request_info { int ret = 0; - down(&ieee->wx_sem); + mutex_lock(&ieee->wx_mutex); if (ieee->iw_mode == IW_MODE_MONITOR || !(ieee->proto_started)) { ret = -1; @@ -376,7 +376,7 @@ int ieee80211_wx_set_scan(struct ieee80211_device *ieee, struct iw_request_info } out: - up(&ieee->wx_sem); + mutex_unlock(&ieee->wx_mutex); return ret; } EXPORT_SYMBOL(ieee80211_wx_set_scan); @@ -391,7 +391,7 @@ int ieee80211_wx_set_essid(struct ieee80211_device *ieee, unsigned long flags; ieee->sync_scan_hurryup = 1; - down(&ieee->wx_sem); + mutex_lock(&ieee->wx_mutex); proto_started = ieee->proto_started; @@ -430,7 +430,7 @@ int ieee80211_wx_set_essid(struct ieee80211_device *ieee, if (proto_started) ieee80211_start_protocol(ieee); out: - up(&ieee->wx_sem); + mutex_unlock(&ieee->wx_mutex); return ret; } EXPORT_SYMBOL(ieee80211_wx_set_essid); @@ -453,7 +453,7 @@ int ieee80211_wx_set_rawtx(struct ieee80211_device *ieee, int enable = (parms[0] > 0); short prev = ieee->raw_tx; - down(&ieee->wx_sem); + mutex_lock(&ieee->wx_mutex); if (enable) ieee->raw_tx = 1; @@ -475,7 +475,7 @@ int ieee80211_wx_set_rawtx(struct ieee80211_device *ieee, netif_carrier_off(ieee->dev); } - up(&ieee->wx_sem); + mutex_unlock(&ieee->wx_mutex); return 0; } @@ -514,7 +514,7 @@ int ieee80211_wx_set_power(struct ieee80211_device *ieee, { int ret = 0; - down(&ieee->wx_sem); + mutex_lock(&ieee->wx_mutex); if (wrqu->power.disabled) { ieee->ps = IEEE80211_PS_DISABLED; @@ -553,7 +553,7 @@ int ieee80211_wx_set_power(struct ieee80211_device *ieee, } exit: - up(&ieee->wx_sem); + mutex_unlock(&ieee->wx_mutex); return ret; } @@ -564,7 +564,7 @@ int ieee80211_wx_get_power(struct ieee80211_device *ieee, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - down(&ieee->wx_sem); + mutex_lock(&ieee->wx_mutex); if (ieee->ps == IEEE80211_PS_DISABLED) { wrqu->power.disabled = 1; @@ -592,7 +592,7 @@ int ieee80211_wx_get_power(struct ieee80211_device *ieee, wrqu->power.flags |= IW_POWER_UNICAST_R; exit: - up(&ieee->wx_sem); + mutex_unlock(&ieee->wx_mutex); return 0; } diff --git a/drivers/staging/rtl8192u/ieee80211/ieee80211_wx.c b/drivers/staging/rtl8192u/ieee80211/ieee80211_wx.c index 208be5f..563d7fe 100644 --- a/drivers/staging/rtl8192u/ieee80211/ieee80211_wx.c +++ b/drivers/staging/rtl8192u/ieee80211/ieee80211_wx.c @@ -253,7 +253,7 @@ int ieee80211_wx_get_scan(struct ieee80211_device *ieee, int i = 0; int err = 0; IEEE80211_DEBUG_WX("Getting scan\n"); - down(&ieee->wx_sem); + mutex_lock(&ieee->wx_mutex); spin_lock_irqsave(&ieee->lock, flags); list_for_each_entry(network, &ieee->network_list, list) { @@ -262,7 +262,7 @@ int ieee80211_wx_get_scan(struct ieee80211_device *ieee, { err = -E2BIG; break; - } + } if (ieee->scan_age == 0 || time_after(network->last_scanned + ieee->scan_age, jiffies)) ev = rtl819x_translate_scan(ieee, ev, stop, network, info); @@ -277,7 +277,7 @@ int ieee80211_wx_get_scan(struct ieee80211_device *ieee, } spin_unlock_irqrestore(&ieee->lock, flags); - up(&ieee->wx_sem); + mutex_unlock(&ieee->wx_mutex); wrqu->data.length = ev - extra; wrqu->data.flags = 0; diff --git a/drivers/staging/rtl8192u/r8192U_core.c b/drivers/staging/rtl8192u/r8192U_core.c index 621cabb..f9c465c 100644 --- a/drivers/staging/rtl8192u/r8192U_core.c +++ b/drivers/staging/rtl8192u/r8192U_core.c @@ -3388,14 +3388,14 @@ RESET_START: ieee->sync_scan_hurryup = 1; if (ieee->state == IEEE80211_LINKED) { - down(&ieee->wx_sem); + mutex_lock(&ieee->wx_mutex); netdev_dbg(dev, "ieee->state is IEEE80211_LINKED\n"); ieee80211_stop_send_beacons(priv->ieee80211); del_timer_sync(&ieee->associate_timer); cancel_delayed_work(&ieee->associate_retry_wq); ieee80211_stop_scan(ieee); netif_carrier_off(dev); - up(&ieee->wx_sem); + mutex_unlock(&ieee->wx_mutex); } else { netdev_dbg(dev, "ieee->state is NOT LINKED\n"); ieee80211_softmac_stop_protocol(priv->ieee80211); -- cgit v0.10.2 From 87d63bcc0f98248be03a1eb8cb3431b7c395bcae Mon Sep 17 00:00:00 2001 From: Binoy Jayan Date: Thu, 2 Jun 2016 16:23:01 +0530 Subject: rtl8192u: Replace semaphore scan_sem with mutex The semaphore 'scan_sem' in rtl8192u is a simple mutex, so it should be written as one. Semaphores are going away in the future. Signed-off-by: Binoy Jayan Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/rtl8192u/ieee80211/ieee80211.h b/drivers/staging/rtl8192u/ieee80211/ieee80211.h index ef9ae22..09e9499 100644 --- a/drivers/staging/rtl8192u/ieee80211/ieee80211.h +++ b/drivers/staging/rtl8192u/ieee80211/ieee80211.h @@ -1800,7 +1800,7 @@ struct ieee80211_device { short proto_started; struct mutex wx_mutex; - struct semaphore scan_sem; + struct mutex scan_mutex; spinlock_t mgmt_tx_lock; spinlock_t beacon_lock; diff --git a/drivers/staging/rtl8192u/ieee80211/ieee80211_softmac.c b/drivers/staging/rtl8192u/ieee80211/ieee80211_softmac.c index 664664b..49db1b7 100644 --- a/drivers/staging/rtl8192u/ieee80211/ieee80211_softmac.c +++ b/drivers/staging/rtl8192u/ieee80211/ieee80211_softmac.c @@ -427,7 +427,7 @@ void ieee80211_softmac_scan_syncro(struct ieee80211_device *ieee) short ch = 0; u8 channel_map[MAX_CHANNEL_NUMBER+1]; memcpy(channel_map, GET_DOT11D_INFO(ieee)->channel_map, MAX_CHANNEL_NUMBER+1); - down(&ieee->scan_sem); + mutex_lock(&ieee->scan_mutex); while(1) { @@ -475,13 +475,13 @@ void ieee80211_softmac_scan_syncro(struct ieee80211_device *ieee) out: if(ieee->state < IEEE80211_LINKED){ ieee->actscanning = false; - up(&ieee->scan_sem); + mutex_unlock(&ieee->scan_mutex); } else{ ieee->sync_scan_hurryup = 0; if(IS_DOT11D_ENABLE(ieee)) DOT11D_ScanComplete(ieee); - up(&ieee->scan_sem); + mutex_unlock(&ieee->scan_mutex); } } EXPORT_SYMBOL(ieee80211_softmac_scan_syncro); @@ -495,7 +495,7 @@ static void ieee80211_softmac_scan_wq(struct work_struct *work) memcpy(channel_map, GET_DOT11D_INFO(ieee)->channel_map, MAX_CHANNEL_NUMBER+1); if(!ieee->ieee_up) return; - down(&ieee->scan_sem); + mutex_lock(&ieee->scan_mutex); do{ ieee->current_network.channel = (ieee->current_network.channel + 1) % MAX_CHANNEL_NUMBER; @@ -517,7 +517,7 @@ static void ieee80211_softmac_scan_wq(struct work_struct *work) schedule_delayed_work(&ieee->softmac_scan_wq, IEEE80211_SOFTMAC_SCAN_TIME); - up(&ieee->scan_sem); + mutex_unlock(&ieee->scan_mutex); return; out: if(IS_DOT11D_ENABLE(ieee)) @@ -525,7 +525,7 @@ out: ieee->actscanning = false; watchdog = 0; ieee->scanning = 0; - up(&ieee->scan_sem); + mutex_unlock(&ieee->scan_mutex); } @@ -579,7 +579,7 @@ static void ieee80211_softmac_stop_scan(struct ieee80211_device *ieee) //ieee->sync_scan_hurryup = 1; - down(&ieee->scan_sem); + mutex_lock(&ieee->scan_mutex); // spin_lock_irqsave(&ieee->lock, flags); if (ieee->scanning == 1) { @@ -589,7 +589,7 @@ static void ieee80211_softmac_stop_scan(struct ieee80211_device *ieee) } // spin_unlock_irqrestore(&ieee->lock, flags); - up(&ieee->scan_sem); + mutex_unlock(&ieee->scan_mutex); } void ieee80211_stop_scan(struct ieee80211_device *ieee) @@ -2729,7 +2729,7 @@ void ieee80211_softmac_init(struct ieee80211_device *ieee) mutex_init(&ieee->wx_mutex); - sema_init(&ieee->scan_sem, 1); + mutex_init(&ieee->scan_mutex); spin_lock_init(&ieee->mgmt_tx_lock); spin_lock_init(&ieee->beacon_lock); -- cgit v0.10.2 From b53628cbf9200586a2584cf5ec3bf4e003052178 Mon Sep 17 00:00:00 2001 From: Binoy Jayan Date: Thu, 2 Jun 2016 16:23:02 +0530 Subject: rtl8192u: Remove unused semaphore rf_sem The semaphore 'rf_sem' in rtl8192u has no users, hence removing it. Signed-off-by: Binoy Jayan Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/rtl8192u/r8192U.h b/drivers/staging/rtl8192u/r8192U.h index 65587ac..821afc0 100644 --- a/drivers/staging/rtl8192u/r8192U.h +++ b/drivers/staging/rtl8192u/r8192U.h @@ -880,7 +880,6 @@ typedef struct r8192_priv { short crcmon; struct mutex wx_mutex; - struct semaphore rf_sem; /* Used to lock rf write operation */ u8 rf_type; /* 0: 1T2R, 1: 2T4R */ RT_RF_TYPE_819xU rf_chip; diff --git a/drivers/staging/rtl8192u/r8192U_core.c b/drivers/staging/rtl8192u/r8192U_core.c index f9c465c..dd0970f 100644 --- a/drivers/staging/rtl8192u/r8192U_core.c +++ b/drivers/staging/rtl8192u/r8192U_core.c @@ -2377,7 +2377,6 @@ static void rtl8192_init_priv_lock(struct r8192_priv *priv) spin_lock_init(&priv->tx_lock); spin_lock_init(&priv->irq_lock); mutex_init(&priv->wx_mutex); - sema_init(&priv->rf_sem, 1); mutex_init(&priv->mutex); } -- cgit v0.10.2 From f1b91de88a8b39f76caa74100cf44828226e00df Mon Sep 17 00:00:00 2001 From: Emoly Liu Date: Sat, 18 Jun 2016 23:53:10 -0400 Subject: staging/lustre: Fix blank line before EXPORT_SYMBOL() This patch fixes one checkpatch warning in lustre: WARNING: EXPORT_SYMBOL(foo); should immediately follow its function/variable Signed-off-by: Emoly Liu Signed-off-by: Oleg Drokin Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/lustre/lustre/ptlrpc/lproc_ptlrpc.c b/drivers/staging/lustre/lustre/ptlrpc/lproc_ptlrpc.c index fe6f7a6..bc93b75 100644 --- a/drivers/staging/lustre/lustre/ptlrpc/lproc_ptlrpc.c +++ b/drivers/staging/lustre/lustre/ptlrpc/lproc_ptlrpc.c @@ -1158,7 +1158,6 @@ void ptlrpc_lprocfs_brw(struct ptlrpc_request *req, int bytes) lprocfs_counter_add(svc_stats, idx, bytes); } - EXPORT_SYMBOL(ptlrpc_lprocfs_brw); void ptlrpc_lprocfs_unregister_service(struct ptlrpc_service *svc) -- cgit v0.10.2 From d719d2ddd12f0c7e1706d086786647190378f6e0 Mon Sep 17 00:00:00 2001 From: Emoly Liu Date: Sat, 18 Jun 2016 23:53:11 -0400 Subject: staging/lustre: Keep logical continuations on the previous line This patch fixes all checkpatch occurences of "CHECK: Logical continuations should be on the previous line" in Lustre code. Signed-off-by: Emoly Liu Signed-off-by: Oleg Drokin Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/lustre/lustre/ldlm/ldlm_flock.c b/drivers/staging/lustre/lustre/ldlm/ldlm_flock.c index 38c507f..d6b61bc 100644 --- a/drivers/staging/lustre/lustre/ldlm/ldlm_flock.c +++ b/drivers/staging/lustre/lustre/ldlm/ldlm_flock.c @@ -255,14 +255,13 @@ reprocess: * overflow and underflow. */ if ((new->l_policy_data.l_flock.start > - (lock->l_policy_data.l_flock.end + 1)) - && (lock->l_policy_data.l_flock.end != - OBD_OBJECT_EOF)) + (lock->l_policy_data.l_flock.end + 1)) && + (lock->l_policy_data.l_flock.end != OBD_OBJECT_EOF)) continue; if ((new->l_policy_data.l_flock.end < - (lock->l_policy_data.l_flock.start - 1)) - && (lock->l_policy_data.l_flock.start != 0)) + (lock->l_policy_data.l_flock.start - 1)) && + (lock->l_policy_data.l_flock.start != 0)) break; if (new->l_policy_data.l_flock.start < diff --git a/drivers/staging/lustre/lustre/obdclass/obd_config.c b/drivers/staging/lustre/lustre/obdclass/obd_config.c index 694c58e..f1c41a1 100644 --- a/drivers/staging/lustre/lustre/obdclass/obd_config.c +++ b/drivers/staging/lustre/lustre/obdclass/obd_config.c @@ -1017,8 +1017,8 @@ int class_process_proc_param(char *prefix, struct lprocfs_vars *lvars, /* Search proc entries */ while (lvars[j].name) { var = &lvars[j]; - if (!class_match_param(key, var->name, NULL) - && keylen == strlen(var->name)) { + if (!class_match_param(key, var->name, NULL) && + keylen == strlen(var->name)) { matched++; rc = -EROFS; if (var->fops && var->fops->write) { -- cgit v0.10.2 From 9797fb0e25f5f1f6e714006cf05390b76228e839 Mon Sep 17 00:00:00 2001 From: Oleg Drokin Date: Sat, 18 Jun 2016 23:53:12 -0400 Subject: staging/lustre: Remove unnecessary space after a cast This patch fixes all checkpatch occurences of "CHECK: No space is necessary after a cast" in Lustre code. Signed-off-by: Emoly Liu Signed-off-by: Oleg Drokin Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/lustre/include/linux/lnet/lib-dlc.h b/drivers/staging/lustre/include/linux/lnet/lib-dlc.h index 6ce9acc..dfff170 100644 --- a/drivers/staging/lustre/include/linux/lnet/lib-dlc.h +++ b/drivers/staging/lustre/include/linux/lnet/lib-dlc.h @@ -35,7 +35,7 @@ #define MAX_NUM_SHOW_ENTRIES 32 #define LNET_MAX_STR_LEN 128 #define LNET_MAX_SHOW_NUM_CPT 128 -#define LNET_UNDEFINED_HOPS ((__u32) -1) +#define LNET_UNDEFINED_HOPS ((__u32)(-1)) struct lnet_ioctl_config_lnd_cmn_tunables { __u32 lct_version; diff --git a/drivers/staging/lustre/include/linux/lnet/types.h b/drivers/staging/lustre/include/linux/lnet/types.h index 1c679cb..e098b6c 100644 --- a/drivers/staging/lustre/include/linux/lnet/types.h +++ b/drivers/staging/lustre/include/linux/lnet/types.h @@ -68,9 +68,9 @@ typedef __u64 lnet_nid_t; typedef __u32 lnet_pid_t; /** wildcard NID that matches any end-point address */ -#define LNET_NID_ANY ((lnet_nid_t) -1) +#define LNET_NID_ANY ((lnet_nid_t)(-1)) /** wildcard PID that matches any lnet_pid_t */ -#define LNET_PID_ANY ((lnet_pid_t) -1) +#define LNET_PID_ANY ((lnet_pid_t)(-1)) #define LNET_PID_RESERVED 0xf0000000 /* reserved bits in PID */ #define LNET_PID_USERFLAG 0x80000000 /* set in userspace peers */ diff --git a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.h b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.h index b66ab79..078a0c3 100644 --- a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.h +++ b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.h @@ -98,7 +98,7 @@ extern struct kib_tunables kiblnd_tunables; #define IBLND_CREDIT_HIGHWATER_V1 7 /* V1 only : when eagerly to return credits */ #define IBLND_CREDITS_DEFAULT 8 /* default # of peer credits */ -#define IBLND_CREDITS_MAX ((typeof(((struct kib_msg *) 0)->ibm_credits)) - 1) /* Max # of peer credits */ +#define IBLND_CREDITS_MAX ((typeof(((struct kib_msg *)0)->ibm_credits)) - 1) /* Max # of peer credits */ /* when eagerly to return credits */ #define IBLND_CREDITS_HIGHWATER(t, v) ((v) == IBLND_MSG_VERSION_1 ? \ diff --git a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd_cb.c b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd_cb.c index adc346a..e32e43b 100644 --- a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd_cb.c +++ b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd_cb.c @@ -1103,7 +1103,7 @@ kiblnd_init_rdma(struct kib_conn *conn, struct kib_tx *tx, int type, wrknob = min(min(kiblnd_rd_frag_size(srcrd, srcidx), kiblnd_rd_frag_size(dstrd, dstidx)), - (__u32) resid); + (__u32)resid); sge = &tx->tx_sge[tx->tx_nwrq]; sge->addr = kiblnd_rd_frag_addr(srcrd, srcidx); diff --git a/drivers/staging/lustre/lnet/klnds/socklnd/socklnd.c b/drivers/staging/lustre/lnet/klnds/socklnd/socklnd.c index d4e7dae..07ec540 100644 --- a/drivers/staging/lustre/lnet/klnds/socklnd/socklnd.c +++ b/drivers/staging/lustre/lnet/klnds/socklnd/socklnd.c @@ -475,7 +475,7 @@ ksocknal_add_peer(lnet_ni_t *ni, lnet_process_id_t id, __u32 ipaddr, int port) write_lock_bh(&ksocknal_data.ksnd_global_lock); /* always called with a ref on ni, so shutdown can't have started */ - LASSERT(!((struct ksock_net *) ni->ni_data)->ksnn_shutdown); + LASSERT(!((struct ksock_net *)ni->ni_data)->ksnn_shutdown); peer2 = ksocknal_find_peer_locked(ni, id); if (peer2) { @@ -1146,7 +1146,7 @@ ksocknal_create_conn(lnet_ni_t *ni, struct ksock_route *route, write_lock_bh(global_lock); /* called with a ref on ni, so shutdown can't have started */ - LASSERT(!((struct ksock_net *) ni->ni_data)->ksnn_shutdown); + LASSERT(!((struct ksock_net *)ni->ni_data)->ksnn_shutdown); peer2 = ksocknal_find_peer_locked(ni, peerid); if (!peer2) { diff --git a/drivers/staging/lustre/lnet/klnds/socklnd/socklnd_cb.c b/drivers/staging/lustre/lnet/klnds/socklnd/socklnd_cb.c index e63d29b..303576d 100644 --- a/drivers/staging/lustre/lnet/klnds/socklnd/socklnd_cb.c +++ b/drivers/staging/lustre/lnet/klnds/socklnd/socklnd_cb.c @@ -126,7 +126,7 @@ ksocknal_send_iov(struct ksock_conn *conn, struct ksock_tx *tx) do { LASSERT(tx->tx_niov > 0); - if (nob < (int) iov->iov_len) { + if (nob < (int)iov->iov_len) { iov->iov_base = (void *)((char *)iov->iov_base + nob); iov->iov_len -= nob; return rc; @@ -326,7 +326,7 @@ ksocknal_recv_kiov(struct ksock_conn *conn) do { LASSERT(conn->ksnc_rx_nkiov > 0); - if (nob < (int) kiov->kiov_len) { + if (nob < (int)kiov->kiov_len) { kiov->kiov_offset += nob; kiov->kiov_len -= nob; return -EAGAIN; diff --git a/drivers/staging/lustre/lnet/klnds/socklnd/socklnd_proto.c b/drivers/staging/lustre/lnet/klnds/socklnd/socklnd_proto.c index e1bf910..82e174f 100644 --- a/drivers/staging/lustre/lnet/klnds/socklnd/socklnd_proto.c +++ b/drivers/staging/lustre/lnet/klnds/socklnd/socklnd_proto.c @@ -503,7 +503,7 @@ ksocknal_send_hello_v1(struct ksock_conn *conn, ksock_hello_msg_t *hello) if (!hello->kshm_nips) goto out; - for (i = 0; i < (int) hello->kshm_nips; i++) + for (i = 0; i < (int)hello->kshm_nips; i++) hello->kshm_ips[i] = __cpu_to_le32(hello->kshm_ips[i]); rc = lnet_sock_write(sock, hello->kshm_ips, @@ -622,7 +622,7 @@ ksocknal_recv_hello_v1(struct ksock_conn *conn, ksock_hello_msg_t *hello, goto out; } - for (i = 0; i < (int) hello->kshm_nips; i++) { + for (i = 0; i < (int)hello->kshm_nips; i++) { hello->kshm_ips[i] = __le32_to_cpu(hello->kshm_ips[i]); if (!hello->kshm_ips[i]) { @@ -690,7 +690,7 @@ ksocknal_recv_hello_v2(struct ksock_conn *conn, ksock_hello_msg_t *hello, int ti return rc; } - for (i = 0; i < (int) hello->kshm_nips; i++) { + for (i = 0; i < (int)hello->kshm_nips; i++) { if (conn->ksnc_flip) __swab32s(&hello->kshm_ips[i]); diff --git a/drivers/staging/lustre/lnet/lnet/api-ni.c b/drivers/staging/lustre/lnet/lnet/api-ni.c index 48327ca..346db89 100644 --- a/drivers/staging/lustre/lnet/lnet/api-ni.c +++ b/drivers/staging/lustre/lnet/lnet/api-ni.c @@ -1673,7 +1673,7 @@ lnet_fill_ni_info(struct lnet_ni *ni, struct lnet_ioctl_config_data *config) if (!ni || !config) return; - net_config = (struct lnet_ioctl_net_config *) config->cfg_bulk; + net_config = (struct lnet_ioctl_net_config *)config->cfg_bulk; if (!net_config) return; diff --git a/drivers/staging/lustre/lnet/lnet/module.c b/drivers/staging/lustre/lnet/lnet/module.c index 58cf246..4ffbd3e 100644 --- a/drivers/staging/lustre/lnet/lnet/module.c +++ b/drivers/staging/lustre/lnet/lnet/module.c @@ -196,7 +196,7 @@ static int __init lnet_init(void) * Have to schedule a separate thread to avoid deadlocking * in modload */ - (void) kthread_run(lnet_configure, NULL, "lnet_initd"); + (void)kthread_run(lnet_configure, NULL, "lnet_initd"); } return 0; diff --git a/drivers/staging/lustre/lustre/include/lustre_sec.h b/drivers/staging/lustre/lustre/include/lustre_sec.h index ed4b4c7..90c1834 100644 --- a/drivers/staging/lustre/lustre/include/lustre_sec.h +++ b/drivers/staging/lustre/lustre/include/lustre_sec.h @@ -217,13 +217,13 @@ enum sptlrpc_bulk_service { #define SPTLRPC_FLVR_DEFAULT SPTLRPC_FLVR_NULL -#define SPTLRPC_FLVR_INVALID ((__u32) 0xFFFFFFFF) -#define SPTLRPC_FLVR_ANY ((__u32) 0xFFF00000) +#define SPTLRPC_FLVR_INVALID ((__u32)0xFFFFFFFF) +#define SPTLRPC_FLVR_ANY ((__u32)0xFFF00000) /** * extract the useful part from wire flavor */ -#define WIRE_FLVR(wflvr) (((__u32) (wflvr)) & 0x000FFFFF) +#define WIRE_FLVR(wflvr) (((__u32)(wflvr)) & 0x000FFFFF) /** @} flavor */ diff --git a/drivers/staging/lustre/lustre/llite/file.c b/drivers/staging/lustre/lustre/llite/file.c index 4602596..b0c4548 100644 --- a/drivers/staging/lustre/lustre/llite/file.c +++ b/drivers/staging/lustre/lustre/llite/file.c @@ -1413,7 +1413,7 @@ out_unlock: out: return rc; out_req_free: - ptlrpc_req_finished((struct ptlrpc_request *) oit.d.lustre.it_data); + ptlrpc_req_finished((struct ptlrpc_request *)oit.d.lustre.it_data); goto out; } diff --git a/drivers/staging/lustre/lustre/llite/vvp_dev.c b/drivers/staging/lustre/lustre/llite/vvp_dev.c index 6c09fb2..e623216 100644 --- a/drivers/staging/lustre/lustre/llite/vvp_dev.c +++ b/drivers/staging/lustre/lustre/llite/vvp_dev.c @@ -560,7 +560,7 @@ static int vvp_pgcache_show(struct seq_file *f, void *v) env = cl_env_get(&refcheck); if (!IS_ERR(env)) { - pos = *(loff_t *) v; + pos = *(loff_t *)v; vvp_pgcache_id_unpack(pos, &id); sbi = f->private; clob = vvp_pgcache_obj(env, &sbi->ll_cl->cd_lu_dev, &id); diff --git a/drivers/staging/lustre/lustre/mdc/mdc_request.c b/drivers/staging/lustre/lustre/mdc/mdc_request.c index 12cb238..f371e1d 100644 --- a/drivers/staging/lustre/lustre/mdc/mdc_request.c +++ b/drivers/staging/lustre/lustre/mdc/mdc_request.c @@ -1803,7 +1803,7 @@ static int mdc_iocontrol(unsigned int cmd, struct obd_export *exp, int len, case IOC_OBD_STATFS: { struct obd_statfs stat_buf = {0}; - if (*((__u32 *) data->ioc_inlbuf2) != 0) { + if (*((__u32 *)data->ioc_inlbuf2) != 0) { rc = -ENODEV; goto out; } @@ -1997,7 +1997,7 @@ static int mdc_hsm_copytool_send(int len, void *val) if (len < sizeof(*lh) + sizeof(*hal)) { CERROR("Short HSM message %d < %d\n", len, - (int) (sizeof(*lh) + sizeof(*hal))); + (int)(sizeof(*lh) + sizeof(*hal))); return -EPROTO; } if (lh->kuc_magic == __swab16(KUC_MAGIC)) { diff --git a/drivers/staging/lustre/lustre/mgc/mgc_request.c b/drivers/staging/lustre/lustre/mgc/mgc_request.c index 69f5337..fbbf276 100644 --- a/drivers/staging/lustre/lustre/mgc/mgc_request.c +++ b/drivers/staging/lustre/lustre/mgc/mgc_request.c @@ -1030,7 +1030,7 @@ static int mgc_set_info_async(const struct lu_env *env, struct obd_export *exp, rc = sptlrpc_parse_flavor(val, &flvr); if (rc) { CERROR("invalid sptlrpc flavor %s to MGS\n", - (char *) val); + (char *)val); return rc; } @@ -1046,7 +1046,7 @@ static int mgc_set_info_async(const struct lu_env *env, struct obd_export *exp, sptlrpc_flavor2name(&cli->cl_flvr_mgc, str, sizeof(str)); LCONSOLE_ERROR("asking sptlrpc flavor %s to MGS but currently %s is in use\n", - (char *) val, str); + (char *)val, str); rc = -EPERM; } return rc; diff --git a/drivers/staging/lustre/lustre/obdclass/cl_object.c b/drivers/staging/lustre/lustre/obdclass/cl_object.c index 615158a..91a5806 100644 --- a/drivers/staging/lustre/lustre/obdclass/cl_object.c +++ b/drivers/staging/lustre/lustre/obdclass/cl_object.c @@ -573,7 +573,7 @@ static inline struct cl_env *cl_env_fetch(void) { struct cl_env *cle; - cle = cfs_hash_lookup(cl_env_hash, (void *) (long) current->pid); + cle = cfs_hash_lookup(cl_env_hash, (void *)(long)current->pid); LASSERT(ergo(cle, cle->ce_magic == &cl_env_init0)); return cle; } @@ -584,7 +584,7 @@ static inline void cl_env_attach(struct cl_env *cle) int rc; LASSERT(!cle->ce_owner); - cle->ce_owner = (void *) (long) current->pid; + cle->ce_owner = (void *)(long)current->pid; rc = cfs_hash_add_unique(cl_env_hash, cle->ce_owner, &cle->ce_node); LASSERT(rc == 0); @@ -595,7 +595,7 @@ static inline void cl_env_do_detach(struct cl_env *cle) { void *cookie; - LASSERT(cle->ce_owner == (void *) (long) current->pid); + LASSERT(cle->ce_owner == (void *)(long)current->pid); cookie = cfs_hash_del(cl_env_hash, cle->ce_owner, &cle->ce_node); LASSERT(cookie == cle); diff --git a/drivers/staging/lustre/lustre/obdclass/obd_config.c b/drivers/staging/lustre/lustre/obdclass/obd_config.c index f1c41a1..0eab123 100644 --- a/drivers/staging/lustre/lustre/obdclass/obd_config.c +++ b/drivers/staging/lustre/lustre/obdclass/obd_config.c @@ -1073,7 +1073,7 @@ int class_config_llog_handler(const struct lu_env *env, { struct config_llog_instance *clli = data; int cfg_len = rec->lrh_len; - char *cfg_buf = (char *) (rec + 1); + char *cfg_buf = (char *)(rec + 1); int rc = 0; switch (rec->lrh_type) { diff --git a/drivers/staging/lustre/lustre/ptlrpc/nrs.c b/drivers/staging/lustre/lustre/ptlrpc/nrs.c index c444f51..d88faf6 100644 --- a/drivers/staging/lustre/lustre/ptlrpc/nrs.c +++ b/drivers/staging/lustre/lustre/ptlrpc/nrs.c @@ -769,7 +769,7 @@ static int nrs_policy_register(struct ptlrpc_nrs *nrs, spin_unlock(&nrs->nrs_lock); if (rc != 0) - (void) nrs_policy_unregister(nrs, policy->pol_desc->pd_name); + (void)nrs_policy_unregister(nrs, policy->pol_desc->pd_name); return rc; } diff --git a/drivers/staging/lustre/lustre/ptlrpc/sec.c b/drivers/staging/lustre/lustre/ptlrpc/sec.c index 7ab3ae9..f3b4773 100644 --- a/drivers/staging/lustre/lustre/ptlrpc/sec.c +++ b/drivers/staging/lustre/lustre/ptlrpc/sec.c @@ -1100,7 +1100,7 @@ int sptlrpc_cli_unwrap_early_reply(struct ptlrpc_request *req, early_req->rq_flvr = req->rq_flvr; early_req->rq_repbuf = early_buf; early_req->rq_repbuf_len = early_bufsz; - early_req->rq_repdata = (struct lustre_msg *) early_buf; + early_req->rq_repdata = (struct lustre_msg *)early_buf; early_req->rq_repdata_len = early_size; early_req->rq_early = 1; early_req->rq_reqmsg = req->rq_reqmsg; @@ -1552,7 +1552,7 @@ void _sptlrpc_enlarge_msg_inplace(struct lustre_msg *msg, /* move from segment + 1 to end segment */ LASSERT(msg->lm_magic == LUSTRE_MSG_MAGIC_V2); oldmsg_size = lustre_msg_size_v2(msg->lm_bufcount, msg->lm_buflens); - movesize = oldmsg_size - ((unsigned long) src - (unsigned long) msg); + movesize = oldmsg_size - ((unsigned long)src - (unsigned long)msg); LASSERT(movesize >= 0); if (movesize) diff --git a/drivers/staging/lustre/lustre/ptlrpc/sec_bulk.c b/drivers/staging/lustre/lustre/ptlrpc/sec_bulk.c index b3e3ed9..5f4d797 100644 --- a/drivers/staging/lustre/lustre/ptlrpc/sec_bulk.c +++ b/drivers/staging/lustre/lustre/ptlrpc/sec_bulk.c @@ -269,7 +269,7 @@ static unsigned long enc_pools_shrink_scan(struct shrinker *s, static inline int npages_to_npools(unsigned long npages) { - return (int) ((npages + PAGES_PER_POOL - 1) / PAGES_PER_POOL); + return (int)((npages + PAGES_PER_POOL - 1) / PAGES_PER_POOL); } /* diff --git a/drivers/staging/lustre/lustre/ptlrpc/sec_config.c b/drivers/staging/lustre/lustre/ptlrpc/sec_config.c index 303bf96..1238c87 100644 --- a/drivers/staging/lustre/lustre/ptlrpc/sec_config.c +++ b/drivers/staging/lustre/lustre/ptlrpc/sec_config.c @@ -644,7 +644,7 @@ static int logname2fsname(const char *logname, char *buf, int buflen) return -EINVAL; } - len = min((int) (ptr - logname), buflen - 1); + len = min((int)(ptr - logname), buflen - 1); memcpy(buf, logname, len); buf[len] = '\0'; diff --git a/drivers/staging/lustre/lustre/ptlrpc/sec_null.c b/drivers/staging/lustre/lustre/ptlrpc/sec_null.c index 3306233..70a61e1 100644 --- a/drivers/staging/lustre/lustre/ptlrpc/sec_null.c +++ b/drivers/staging/lustre/lustre/ptlrpc/sec_null.c @@ -56,7 +56,7 @@ static struct ptlrpc_svc_ctx null_svc_ctx; static inline void null_encode_sec_part(struct lustre_msg *msg, enum lustre_sec_part sp) { - msg->lm_secflvr |= (((__u32) sp) & 0xFF) << 24; + msg->lm_secflvr |= (((__u32)sp) & 0xFF) << 24; } static inline @@ -326,7 +326,7 @@ int null_alloc_rs(struct ptlrpc_request *req, int msgsize) rs->rs_svc_ctx = req->rq_svc_ctx; atomic_inc(&req->rq_svc_ctx->sc_refcount); - rs->rs_repbuf = (struct lustre_msg *) (rs + 1); + rs->rs_repbuf = (struct lustre_msg *)(rs + 1); rs->rs_repbuf_len = rs_size - sizeof(*rs); rs->rs_msg = rs->rs_repbuf; diff --git a/drivers/staging/lustre/lustre/ptlrpc/sec_plain.c b/drivers/staging/lustre/lustre/ptlrpc/sec_plain.c index ea79b15..5c4590b 100644 --- a/drivers/staging/lustre/lustre/ptlrpc/sec_plain.c +++ b/drivers/staging/lustre/lustre/ptlrpc/sec_plain.c @@ -294,7 +294,7 @@ int plain_cli_wrap_bulk(struct ptlrpc_cli_ctx *ctx, LASSERT(req->rq_reqbuf->lm_bufcount == PLAIN_PACK_SEGMENTS); bsd = lustre_msg_buf(req->rq_reqbuf, PLAIN_PACK_BULK_OFF, 0); - token = (struct plain_bulk_token *) bsd->bsd_data; + token = (struct plain_bulk_token *)bsd->bsd_data; bsd->bsd_version = 0; bsd->bsd_flags = 0; @@ -339,7 +339,7 @@ int plain_cli_unwrap_bulk(struct ptlrpc_cli_ctx *ctx, LASSERT(req->rq_repdata->lm_bufcount == PLAIN_PACK_SEGMENTS); bsdv = lustre_msg_buf(req->rq_repdata, PLAIN_PACK_BULK_OFF, 0); - tokenv = (struct plain_bulk_token *) bsdv->bsd_data; + tokenv = (struct plain_bulk_token *)bsdv->bsd_data; if (req->rq_bulk_write) { if (bsdv->bsd_flags & BSD_FL_ERR) @@ -811,7 +811,7 @@ int plain_alloc_rs(struct ptlrpc_request *req, int msgsize) rs->rs_svc_ctx = req->rq_svc_ctx; atomic_inc(&req->rq_svc_ctx->sc_refcount); - rs->rs_repbuf = (struct lustre_msg *) (rs + 1); + rs->rs_repbuf = (struct lustre_msg *)(rs + 1); rs->rs_repbuf_len = rs_size - sizeof(*rs); lustre_init_msg_v2(rs->rs_repbuf, PLAIN_PACK_SEGMENTS, buflens, NULL); @@ -891,7 +891,7 @@ int plain_svc_unwrap_bulk(struct ptlrpc_request *req, LASSERT(req->rq_pack_bulk); bsdr = lustre_msg_buf(req->rq_reqbuf, PLAIN_PACK_BULK_OFF, 0); - tokenr = (struct plain_bulk_token *) bsdr->bsd_data; + tokenr = (struct plain_bulk_token *)bsdr->bsd_data; bsdv = lustre_msg_buf(rs->rs_repbuf, PLAIN_PACK_BULK_OFF, 0); bsdv->bsd_version = 0; @@ -926,7 +926,7 @@ int plain_svc_wrap_bulk(struct ptlrpc_request *req, bsdr = lustre_msg_buf(req->rq_reqbuf, PLAIN_PACK_BULK_OFF, 0); bsdv = lustre_msg_buf(rs->rs_repbuf, PLAIN_PACK_BULK_OFF, 0); - tokenv = (struct plain_bulk_token *) bsdv->bsd_data; + tokenv = (struct plain_bulk_token *)bsdv->bsd_data; bsdv->bsd_version = 0; bsdv->bsd_type = SPTLRPC_BULK_DEFAULT; -- cgit v0.10.2 From 25ed6a5e97809129a1bc852b6b5c7d03baa112c4 Mon Sep 17 00:00:00 2001 From: Oleg Drokin Date: Sat, 18 Jun 2016 23:53:13 -0400 Subject: staging/lustre: Update FID documentation link. When OpenSFS took over lustre.org, there was some reshuffling. FIDs on ZFS document is now at http://wiki.old.lustre.org/index.php/Architecture_-_Interoperability_fids_zfs instead of the old location, so update comments accordingly. Signed-off-by: Oleg Drokin Reported-by: Xose Vazquez Perez Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/lustre/lustre/include/lustre/lustre_idl.h b/drivers/staging/lustre/lustre/include/lustre/lustre_idl.h index bf8a0cd..fac7215 100644 --- a/drivers/staging/lustre/lustre/include/lustre/lustre_idl.h +++ b/drivers/staging/lustre/lustre/include/lustre/lustre_idl.h @@ -382,7 +382,7 @@ static inline __u64 fid_ver_oid(const struct lu_fid *fid) * used for other purposes and not risk collisions with existing inodes. * * Different FID Format - * http://arch.lustre.org/index.php?title=Interoperability_fids_zfs#NEW.0 + * http://wiki.old.lustre.org/index.php/Architecture_-_Interoperability_fids_zfs */ enum fid_seq { FID_SEQ_OST_MDT0 = 0, @@ -700,7 +700,7 @@ static inline int fid_set_id(struct lu_fid *fid, __u64 oid) * be passed through unchanged. Only legacy OST objects in "group 0" * will be mapped into the IDIF namespace so that they can fit into the * struct lu_fid fields without loss. For reference see: - * http://arch.lustre.org/index.php?title=Interoperability_fids_zfs + * http://wiki.old.lustre.org/index.php/Architecture_-_Interoperability_fids_zfs */ static inline int ostid_to_fid(struct lu_fid *fid, struct ost_id *ostid, __u32 ost_idx) diff --git a/drivers/staging/lustre/lustre/include/lustre_fid.h b/drivers/staging/lustre/lustre/include/lustre_fid.h index cbdd91a..743671a 100644 --- a/drivers/staging/lustre/lustre/include/lustre_fid.h +++ b/drivers/staging/lustre/lustre/include/lustre_fid.h @@ -41,7 +41,7 @@ * * @{ * - * http://wiki.lustre.org/index.php/Architecture_-_Interoperability_fids_zfs + * http://wiki.old.lustre.org/index.php/Architecture_-_Interoperability_fids_zfs * describes the FID namespace and interoperability requirements for FIDs. * The important parts of that document are included here for reference. * -- cgit v0.10.2 From 5abe9b26847c65a698f38744a52635b287514294 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Tue, 7 Jun 2016 16:52:27 -0700 Subject: i2c: remove __init from i2c_register_board_info() As of next-20160607 with allyesconfig we get this linker failure: MODPOST vmlinux.o WARNING: vmlinux.o(.text+0x21bc0d): Section mismatch in reference from the function intel_scu_devices_create() to the function .init.text:i2c_register_board_info() This is caused by the fact that intel_scu_devices_create() calls i2c_register_board_info() and intel_scu_devices_create() is not annotated with __init. This typically involves manual code inspection and if one is certain this is correct we would just peg intel_scu_devices_create() with a __ref annotation. In this case this would be wrong though as the intel_scu_devices_create() call is exported, and used in the ipc_probe() on drivers/platform/x86/intel_scu_ipc.c. The issue is that even though builtin_pci_driver(ipc_driver) is used this just exposes the probe routine, which can occur at any point in time if this bus supports hotplug. A race can happen between kernel_init_freeable() that calls the init calls (in this case registeres the intel_scu_ipc.c driver, and later free_initmem(), which would free the i2c_register_board_info(). If a probe happens later in boot i2c_register_board_info() would not be present and we should get a page fault. Signed-off-by: Luis R. Rodriguez [wsa: made function declaration a one-liner] Signed-off-by: Wolfram Sang diff --git a/drivers/i2c/i2c-boardinfo.c b/drivers/i2c/i2c-boardinfo.c index e33022e..6e5fac6 100644 --- a/drivers/i2c/i2c-boardinfo.c +++ b/drivers/i2c/i2c-boardinfo.c @@ -56,9 +56,7 @@ EXPORT_SYMBOL_GPL(__i2c_first_dynamic_bus_num); * The board info passed can safely be __initdata, but be careful of embedded * pointers (for platform_data, functions, etc) since that won't be copied. */ -int __init -i2c_register_board_info(int busnum, - struct i2c_board_info const *info, unsigned len) +int i2c_register_board_info(int busnum, struct i2c_board_info const *info, unsigned len) { int status; -- cgit v0.10.2 From 4aef66c8ae91d00affeeb24cfb176b53354ac969 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Fri, 17 Jun 2016 17:02:01 +0200 Subject: locking/atomic, arch/arc: Fix build Resolve conflict between commits: fbffe892e525 ("locking/atomic, arch/arc: Implement atomic_fetch_{add,sub,and,andnot,or,xor}()") and: ed6aefed726a ("Revert "ARCv2: spinlock/rwlock/atomics: Delayed retry of failed SCOND with exponential backoff"") Reported-by: Guenter Roeck Signed-off-by: Peter Zijlstra (Intel) Cc: Linus Torvalds Cc: Nigel Topham Cc: Noam Camus Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: Vineet Gupta Cc: linux-kernel@vger.kernel.org Cc: linux-snps-arc@lists.infradead.org Signed-off-by: Ingo Molnar diff --git a/arch/arc/include/asm/atomic.h b/arch/arc/include/asm/atomic.h index bd9c51c..4e3c1b6 100644 --- a/arch/arc/include/asm/atomic.h +++ b/arch/arc/include/asm/atomic.h @@ -71,7 +71,6 @@ static inline int atomic_##op##_return(int i, atomic_t *v) \ static inline int atomic_fetch_##op(int i, atomic_t *v) \ { \ unsigned int val, orig; \ - SCOND_FAIL_RETRY_VAR_DEF \ \ /* \ * Explicit full memory barrier needed before/after as \ @@ -84,11 +83,8 @@ static inline int atomic_fetch_##op(int i, atomic_t *v) \ " " #asm_op " %[val], %[orig], %[i] \n" \ " scond %[val], [%[ctr]] \n" \ " \n" \ - SCOND_FAIL_RETRY_ASM \ - \ : [val] "=&r" (val), \ [orig] "=&r" (orig) \ - SCOND_FAIL_RETRY_VARS \ : [ctr] "r" (&v->counter), \ [i] "ir" (i) \ : "cc"); \ @@ -199,10 +195,6 @@ ATOMIC_OPS(andnot, &= ~, bic) ATOMIC_OPS(or, |=, or) ATOMIC_OPS(xor, ^=, xor) -#undef SCOND_FAIL_RETRY_VAR_DEF -#undef SCOND_FAIL_RETRY_ASM -#undef SCOND_FAIL_RETRY_VARS - #else /* CONFIG_ARC_PLAT_EZNPS */ static inline int atomic_read(const atomic_t *v) -- cgit v0.10.2 From 86a664d58f3ba2398a378dc9da6d4cfa737d2281 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Fri, 17 Jun 2016 17:05:38 +0200 Subject: locking/atomic, arch/m68k: Remove comment I misread the inline asm. It uses a rare construct to provide an input to a previously declared output to do the atomic_read(). Reported-by: Geert Uytterhoeven Signed-off-by: Peter Zijlstra (Intel) Cc: Andreas Schwab Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: linux-kernel@vger.kernel.org Cc: linux-m68k@lists.linux-m68k.org Signed-off-by: Ingo Molnar diff --git a/arch/m68k/include/asm/atomic.h b/arch/m68k/include/asm/atomic.h index 3e03de7..cf4c3a7 100644 --- a/arch/m68k/include/asm/atomic.h +++ b/arch/m68k/include/asm/atomic.h @@ -38,13 +38,6 @@ static inline void atomic_##op(int i, atomic_t *v) \ #ifdef CONFIG_RMW_INSNS -/* - * Am I reading these CAS loops right in that %2 is the old value and the first - * iteration uses an uninitialized value? - * - * Would it not make sense to add: tmp = atomic_read(v); to avoid this? - */ - #define ATOMIC_OP_RETURN(op, c_op, asm_op) \ static inline int atomic_##op##_return(int i, atomic_t *v) \ { \ -- cgit v0.10.2 From fe5a6c48fd954489f51aab151d5dad9254c76419 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Thu, 12 May 2016 16:06:41 +0300 Subject: usb: gadget: storage: get rid of fsg_num_buffers_validate() valid range for storage buffers is encoded in Kconfig already. Instead of checking again, let's drop fsg_num_buffers_validate() altogether. Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/function/f_mass_storage.c b/drivers/usb/gadget/function/f_mass_storage.c index 5c6d4d7..2505117 100644 --- a/drivers/usb/gadget/function/f_mass_storage.c +++ b/drivers/usb/gadget/function/f_mass_storage.c @@ -2655,18 +2655,6 @@ void fsg_common_put(struct fsg_common *common) } EXPORT_SYMBOL_GPL(fsg_common_put); -/* check if fsg_num_buffers is within a valid range */ -static inline int fsg_num_buffers_validate(unsigned int fsg_num_buffers) -{ -#define FSG_MAX_NUM_BUFFERS 32 - - if (fsg_num_buffers >= 2 && fsg_num_buffers <= FSG_MAX_NUM_BUFFERS) - return 0; - pr_err("fsg_num_buffers %u is out of range (%d to %d)\n", - fsg_num_buffers, 2, FSG_MAX_NUM_BUFFERS); - return -EINVAL; -} - static struct fsg_common *fsg_common_setup(struct fsg_common *common) { if (!common) { @@ -2709,11 +2697,7 @@ static void _fsg_common_free_buffers(struct fsg_buffhd *buffhds, unsigned n) int fsg_common_set_num_buffers(struct fsg_common *common, unsigned int n) { struct fsg_buffhd *bh, *buffhds; - int i, rc; - - rc = fsg_num_buffers_validate(n); - if (rc != 0) - return rc; + int i; buffhds = kcalloc(n, sizeof(*buffhds), GFP_KERNEL); if (!buffhds) @@ -3401,10 +3385,6 @@ static ssize_t fsg_opts_num_buffers_store(struct config_item *item, if (ret) goto end; - ret = fsg_num_buffers_validate(num); - if (ret) - goto end; - fsg_common_set_num_buffers(opts->common, num); ret = len; -- cgit v0.10.2 From d8877fc7e7ec3eb4515a4e6b947599bdda058323 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Thu, 12 May 2016 15:02:29 +0300 Subject: usb: gadget: storage: increase maximum storage num buffers With a default size of 16kiB and with maximum of 32 buffers, we can transfer up to 512kiB, however Linux can transfer up to 1MiB in a single mass storage block transfer to USB3 storage devices. Because of this, 1MiB block transfers end up being slower than 512kiB block transfers. Let's increase maximum number of storage buffers to a ridiculous amount (256) so that anybody wanting to test maximum achievable throughput can do so. Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index 2057add..3c3f31c 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -114,7 +114,7 @@ config USB_GADGET_VBUS_DRAW config USB_GADGET_STORAGE_NUM_BUFFERS int "Number of storage pipeline buffers" - range 2 32 + range 2 256 default 2 help Usually 2 buffers are enough to establish a good buffering -- cgit v0.10.2 From 5185c91385d73cdf79836eb8548e4726e43ae831 Mon Sep 17 00:00:00 2001 From: Tim Harvey Date: Mon, 23 May 2016 06:58:41 -0700 Subject: usb: gadget: net2280: add USB2380 support The PLX USB2380 is a PCIe version of the NET2280 and behaves more like the USB338x but without the USB3.0 superspeed support. This was tested with g_ether, g_serial, g_mass_storage on a Gateworks Ventana GW2383. Cc: Justin DeFields Signed-off-by: Tim Harvey Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/udc/Kconfig b/drivers/usb/gadget/udc/Kconfig index 7c28941..658b8da 100644 --- a/drivers/usb/gadget/udc/Kconfig +++ b/drivers/usb/gadget/udc/Kconfig @@ -312,7 +312,7 @@ config USB_NET2272_DMA If unsure, say "N" here. The driver works fine in PIO mode. config USB_NET2280 - tristate "NetChip 228x / PLX USB338x" + tristate "NetChip NET228x / PLX USB3x8x" depends on PCI help NetChip 2280 / 2282 is a PCI based USB peripheral controller which @@ -322,6 +322,8 @@ config USB_NET2280 (for control transfers) and several endpoints with dedicated functions. + PLX 2380 is a PCIe version of the PLX 2380. + PLX 3380 / 3382 is a PCIe based USB peripheral controller which supports full, high speed USB 2.0 and super speed USB 3.0 data transfers. diff --git a/drivers/usb/gadget/udc/net2280.c b/drivers/usb/gadget/udc/net2280.c index c894b94..614ab951 100644 --- a/drivers/usb/gadget/udc/net2280.c +++ b/drivers/usb/gadget/udc/net2280.c @@ -211,7 +211,7 @@ net2280_enable(struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc) goto print_err; } - if (dev->quirks & PLX_SUPERSPEED) { + if (dev->quirks & PLX_PCIE) { if ((desc->bEndpointAddress & 0x0f) >= 0x0c) { ret = -EDOM; goto print_err; @@ -245,7 +245,7 @@ net2280_enable(struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc) /* set type, direction, address; reset fifo counters */ writel(BIT(FIFO_FLUSH), &ep->regs->ep_stat); - if ((dev->quirks & PLX_SUPERSPEED) && dev->enhanced_mode) { + if ((dev->quirks & PLX_PCIE) && dev->enhanced_mode) { tmp = readl(&ep->cfg->ep_cfg); /* If USB ep number doesn't match hardware ep number */ if ((tmp & 0xf) != usb_endpoint_num(desc)) { @@ -316,7 +316,7 @@ net2280_enable(struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc) BIT(CLEAR_NAK_OUT_PACKETS_MODE), &ep->regs->ep_rsp); } - if (dev->quirks & PLX_SUPERSPEED) + if (dev->quirks & PLX_PCIE) ep_clear_seqnum(ep); writel(tmp, &ep->cfg->ep_cfg); @@ -527,7 +527,7 @@ static int net2280_disable(struct usb_ep *_ep) spin_lock_irqsave(&ep->dev->lock, flags); nuke(ep); - if (ep->dev->quirks & PLX_SUPERSPEED) + if (ep->dev->quirks & PLX_PCIE) ep_reset_338x(ep->dev->regs, ep); else ep_reset_228x(ep->dev->regs, ep); @@ -862,7 +862,7 @@ static void start_queue(struct net2280_ep *ep, u32 dmactl, u32 td_dma) writel(readl(&dma->dmastat), &dma->dmastat); writel(td_dma, &dma->dmadesc); - if (ep->dev->quirks & PLX_SUPERSPEED) + if (ep->dev->quirks & PLX_PCIE) dmactl |= BIT(DMA_REQUEST_OUTSTANDING); writel(dmactl, &dma->dmactl); @@ -1046,7 +1046,7 @@ net2280_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags) /* kickstart this i/o queue? */ if (list_empty(&ep->queue) && !ep->stopped && - !((dev->quirks & PLX_SUPERSPEED) && ep->dma && + !((dev->quirks & PLX_PCIE) && ep->dma && (readl(&ep->regs->ep_rsp) & BIT(CLEAR_ENDPOINT_HALT)))) { /* use DMA if the endpoint supports it, else pio */ @@ -1169,7 +1169,7 @@ static void scan_dma_completions(struct net2280_ep *ep) break; } else if (!ep->is_in && (req->req.length % ep->ep.maxpacket) && - !(ep->dev->quirks & PLX_SUPERSPEED)) { + !(ep->dev->quirks & PLX_PCIE)) { tmp = readl(&ep->regs->ep_stat); /* AVOID TROUBLE HERE by not issuing short reads from @@ -1367,7 +1367,7 @@ net2280_set_halt_and_wedge(struct usb_ep *_ep, int value, int wedged) ep->wedged = 1; } else { clear_halt(ep); - if (ep->dev->quirks & PLX_SUPERSPEED && + if (ep->dev->quirks & PLX_PCIE && !list_empty(&ep->queue) && ep->td_dma) restart_dma(ep); ep->wedged = 0; @@ -2394,7 +2394,7 @@ static int net2280_start(struct usb_gadget *_gadget, */ net2280_led_active(dev, 1); - if ((dev->quirks & PLX_SUPERSPEED) && !dev->bug7734_patched) + if ((dev->quirks & PLX_PCIE) && !dev->bug7734_patched) defect7374_enable_data_eps_zero(dev); ep0_start(dev); @@ -3063,7 +3063,7 @@ static void handle_stat0_irqs(struct net2280 *dev, u32 stat) } ep->stopped = 0; dev->protocol_stall = 0; - if (!(dev->quirks & PLX_SUPERSPEED)) { + if (!(dev->quirks & PLX_PCIE)) { if (ep->dev->quirks & PLX_2280) tmp = BIT(FIFO_OVERFLOW) | BIT(FIFO_UNDERFLOW); @@ -3090,7 +3090,7 @@ static void handle_stat0_irqs(struct net2280 *dev, u32 stat) cpu_to_le32s(&u.raw[0]); cpu_to_le32s(&u.raw[1]); - if ((dev->quirks & PLX_SUPERSPEED) && !dev->bug7734_patched) + if ((dev->quirks & PLX_PCIE) && !dev->bug7734_patched) defect7374_workaround(dev, u.r); tmp = 0; @@ -3173,7 +3173,7 @@ static void handle_stat0_irqs(struct net2280 *dev, u32 stat) } else { ep_vdbg(dev, "%s clear halt\n", e->ep.name); clear_halt(e); - if ((ep->dev->quirks & PLX_SUPERSPEED) && + if ((ep->dev->quirks & PLX_PCIE) && !list_empty(&e->queue) && e->td_dma) restart_dma(e); } @@ -3195,7 +3195,7 @@ static void handle_stat0_irqs(struct net2280 *dev, u32 stat) if (e->ep.name == ep0name) goto do_stall; set_halt(e); - if ((dev->quirks & PLX_SUPERSPEED) && e->dma) + if ((dev->quirks & PLX_PCIE) && e->dma) abort_dma(e); allow_status(ep); ep_vdbg(dev, "%s set halt\n", ep->ep.name); @@ -3234,7 +3234,7 @@ do_stall: #undef w_length next_endpoints: - if ((dev->quirks & PLX_SUPERSPEED) && dev->enhanced_mode) { + if ((dev->quirks & PLX_PCIE) && dev->enhanced_mode) { u32 mask = (BIT(ENDPOINT_0_INTERRUPT) | USB3380_IRQSTAT0_EP_INTR_MASK_IN | USB3380_IRQSTAT0_EP_INTR_MASK_OUT); @@ -3399,7 +3399,7 @@ __acquires(dev->lock) writel(tmp, &dma->dmastat); /* dma sync*/ - if (dev->quirks & PLX_SUPERSPEED) { + if (dev->quirks & PLX_PCIE) { u32 r_dmacount = readl(&dma->dmacount); if (!ep->is_in && (r_dmacount & 0x00FFFFFF) && (tmp & BIT(DMA_TRANSACTION_DONE_INTERRUPT))) @@ -3468,7 +3468,7 @@ static irqreturn_t net2280_irq(int irq, void *_dev) /* control requests and PIO */ handle_stat0_irqs(dev, readl(&dev->regs->irqstat0)); - if (dev->quirks & PLX_SUPERSPEED) { + if (dev->quirks & PLX_PCIE) { /* re-enable interrupt to trigger any possible new interrupt */ u32 pciirqenb1 = readl(&dev->regs->pciirqenb1); writel(pciirqenb1 & 0x7FFFFFFF, &dev->regs->pciirqenb1); @@ -3513,7 +3513,7 @@ static void net2280_remove(struct pci_dev *pdev) } if (dev->got_irq) free_irq(pdev->irq, dev); - if (dev->quirks & PLX_SUPERSPEED) + if (dev->quirks & PLX_PCIE) pci_disable_msi(pdev); if (dev->regs) iounmap(dev->regs); @@ -3593,7 +3593,7 @@ static int net2280_probe(struct pci_dev *pdev, const struct pci_device_id *id) dev->dep = (struct net2280_dep_regs __iomem *) (base + 0x0200); dev->epregs = (struct net2280_ep_regs __iomem *) (base + 0x0300); - if (dev->quirks & PLX_SUPERSPEED) { + if (dev->quirks & PLX_PCIE) { u32 fsmvalue; u32 usbstat; dev->usb_ext = (struct usb338x_usb_ext_regs __iomem *) @@ -3637,7 +3637,7 @@ static int net2280_probe(struct pci_dev *pdev, const struct pci_device_id *id) goto done; } - if (dev->quirks & PLX_SUPERSPEED) + if (dev->quirks & PLX_PCIE) if (pci_enable_msi(pdev)) ep_err(dev, "Failed to enable MSI mode\n"); @@ -3755,10 +3755,19 @@ static const struct pci_device_id pci_ids[] = { { .class = PCI_CLASS_SERIAL_USB_DEVICE, .class_mask = ~0, .vendor = PCI_VENDOR_ID_PLX, + .device = 0x2380, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .driver_data = PLX_PCIE, + }, + { + .class = ((PCI_CLASS_SERIAL_USB << 8) | 0xfe), + .class_mask = ~0, + .vendor = PCI_VENDOR_ID_PLX, .device = 0x3380, .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, - .driver_data = PLX_SUPERSPEED, + .driver_data = PLX_PCIE | PLX_SUPERSPEED, }, { .class = PCI_CLASS_SERIAL_USB_DEVICE, @@ -3767,7 +3776,7 @@ static const struct pci_device_id pci_ids[] = { { .device = 0x3382, .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, - .driver_data = PLX_SUPERSPEED, + .driver_data = PLX_PCIE | PLX_SUPERSPEED, }, { /* end: all zeroes */ } }; diff --git a/drivers/usb/gadget/udc/net2280.h b/drivers/usb/gadget/udc/net2280.h index 0d32052..2736a95 100644 --- a/drivers/usb/gadget/udc/net2280.h +++ b/drivers/usb/gadget/udc/net2280.h @@ -47,6 +47,7 @@ set_idx_reg(struct net2280_regs __iomem *regs, u32 index, u32 value) #define PLX_LEGACY BIT(0) #define PLX_2280 BIT(1) #define PLX_SUPERSPEED BIT(2) +#define PLX_PCIE BIT(3) #define REG_DIAG 0x0 #define RETRY_COUNTER 16 -- cgit v0.10.2 From d7be295243bbe53649986d869b398403eaa41bb7 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Wed, 4 May 2016 15:49:37 +0300 Subject: usb: dwc3: gadget: re-factor ->udc_start and ->udc_stop we will be re-using it for suspend/resume, so instead of duplicating code, let's just re-factor the functions so they can be re-used. Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 07248ff..54e36b7 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -1616,37 +1616,12 @@ static void dwc3_gadget_disable_irq(struct dwc3 *dwc) static irqreturn_t dwc3_interrupt(int irq, void *_dwc); static irqreturn_t dwc3_thread_interrupt(int irq, void *_dwc); -static int dwc3_gadget_start(struct usb_gadget *g, - struct usb_gadget_driver *driver) +static int __dwc3_gadget_start(struct dwc3 *dwc) { - struct dwc3 *dwc = gadget_to_dwc(g); struct dwc3_ep *dep; - unsigned long flags; int ret = 0; - int irq; u32 reg; - irq = platform_get_irq(to_platform_device(dwc->dev), 0); - ret = request_threaded_irq(irq, dwc3_interrupt, dwc3_thread_interrupt, - IRQF_SHARED, "dwc3", dwc->ev_buf); - if (ret) { - dev_err(dwc->dev, "failed to request irq #%d --> %d\n", - irq, ret); - goto err0; - } - - spin_lock_irqsave(&dwc->lock, flags); - - if (dwc->gadget_driver) { - dev_err(dwc->dev, "%s is already bound to %s\n", - dwc->gadget.name, - dwc->gadget_driver->driver.name); - ret = -EBUSY; - goto err1; - } - - dwc->gadget_driver = driver; - reg = dwc3_readl(dwc->regs, DWC3_DCFG); reg &= ~(DWC3_DCFG_SPEED_MASK); @@ -1709,7 +1684,7 @@ static int dwc3_gadget_start(struct usb_gadget *g, false); if (ret) { dev_err(dwc->dev, "failed to enable %s\n", dep->name); - goto err2; + goto err0; } dep = dwc->eps[1]; @@ -1717,7 +1692,7 @@ static int dwc3_gadget_start(struct usb_gadget *g, false); if (ret) { dev_err(dwc->dev, "failed to enable %s\n", dep->name); - goto err3; + goto err1; } /* begin to receive SETUP packets */ @@ -1726,39 +1701,72 @@ static int dwc3_gadget_start(struct usb_gadget *g, dwc3_gadget_enable_irq(dwc); - spin_unlock_irqrestore(&dwc->lock, flags); - return 0; -err3: - __dwc3_gadget_ep_disable(dwc->eps[0]); - -err2: - dwc->gadget_driver = NULL; - err1: - spin_unlock_irqrestore(&dwc->lock, flags); - - free_irq(irq, dwc->ev_buf); + __dwc3_gadget_ep_disable(dwc->eps[0]); err0: return ret; } -static int dwc3_gadget_stop(struct usb_gadget *g) +static int dwc3_gadget_start(struct usb_gadget *g, + struct usb_gadget_driver *driver) { struct dwc3 *dwc = gadget_to_dwc(g); unsigned long flags; + int ret = 0; int irq; + irq = platform_get_irq(to_platform_device(dwc->dev), 0); + ret = request_threaded_irq(irq, dwc3_interrupt, dwc3_thread_interrupt, + IRQF_SHARED, "dwc3", dwc->ev_buf); + if (ret) { + dev_err(dwc->dev, "failed to request irq #%d --> %d\n", + irq, ret); + goto err0; + } + spin_lock_irqsave(&dwc->lock, flags); + if (dwc->gadget_driver) { + dev_err(dwc->dev, "%s is already bound to %s\n", + dwc->gadget.name, + dwc->gadget_driver->driver.name); + ret = -EBUSY; + goto err1; + } + + dwc->gadget_driver = driver; + __dwc3_gadget_start(dwc); + spin_unlock_irqrestore(&dwc->lock, flags); + + return 0; + +err1: + spin_unlock_irqrestore(&dwc->lock, flags); + free_irq(irq, dwc); + +err0: + return ret; +} + +static void __dwc3_gadget_stop(struct dwc3 *dwc) +{ dwc3_gadget_disable_irq(dwc); __dwc3_gadget_ep_disable(dwc->eps[0]); __dwc3_gadget_ep_disable(dwc->eps[1]); +} - dwc->gadget_driver = NULL; +static int dwc3_gadget_stop(struct usb_gadget *g) +{ + struct dwc3 *dwc = gadget_to_dwc(g); + unsigned long flags; + int irq; + spin_lock_irqsave(&dwc->lock, flags); + __dwc3_gadget_stop(dwc); + dwc->gadget_driver = NULL; spin_unlock_irqrestore(&dwc->lock, flags); irq = platform_get_irq(to_platform_device(dwc->dev), 0); -- cgit v0.10.2 From 9f8a67b65a49d0e35c6ca782136c84541d948a64 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Wed, 4 May 2016 15:50:27 +0300 Subject: usb: dwc3: gadget: fix gadget suspend/resume Instead of trying hard to stay connected to the host, it's best (and far easier) to disconnect from the host already. Anything relying on KEEP_CONNECT will just have that ignored, but we don't have proper hibernation implementation yet, so there are no regressions. In any case, hibernation is only useful for runtime PM, not system sleep. While at that, also remove dwc3.dcfg which has been rendered unnecessary. Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index 6540506..c881c82 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -819,7 +819,6 @@ struct dwc3 { enum usb_dr_mode dr_mode; /* used for suspend/resume */ - u32 dcfg; u32 gctl; u32 nr_scratch; diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 54e36b7..ae55f50 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -2943,60 +2943,40 @@ void dwc3_gadget_exit(struct dwc3 *dwc) int dwc3_gadget_suspend(struct dwc3 *dwc) { + int ret; + if (!dwc->gadget_driver) return 0; - if (dwc->pullups_connected) { - dwc3_gadget_disable_irq(dwc); - dwc3_gadget_run_stop(dwc, true, true); - } - - __dwc3_gadget_ep_disable(dwc->eps[0]); - __dwc3_gadget_ep_disable(dwc->eps[1]); + ret = dwc3_gadget_run_stop(dwc, false, false); + if (ret < 0) + return ret; - dwc->dcfg = dwc3_readl(dwc->regs, DWC3_DCFG); + dwc3_disconnect_gadget(dwc); + __dwc3_gadget_stop(dwc); return 0; } int dwc3_gadget_resume(struct dwc3 *dwc) { - struct dwc3_ep *dep; int ret; if (!dwc->gadget_driver) return 0; - /* Start with SuperSpeed Default */ - dwc3_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(512); - - dep = dwc->eps[0]; - ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL, false, - false); - if (ret) + ret = __dwc3_gadget_start(dwc); + if (ret < 0) goto err0; - dep = dwc->eps[1]; - ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL, false, - false); - if (ret) + ret = dwc3_gadget_run_stop(dwc, true, false); + if (ret < 0) goto err1; - /* begin to receive SETUP packets */ - dwc->ep0state = EP0_SETUP_PHASE; - dwc3_ep0_out_start(dwc); - - dwc3_writel(dwc->regs, DWC3_DCFG, dwc->dcfg); - - if (dwc->pullups_connected) { - dwc3_gadget_enable_irq(dwc); - dwc3_gadget_run_stop(dwc, true, false); - } - return 0; err1: - __dwc3_gadget_ep_disable(dwc->eps[0]); + __dwc3_gadget_stop(dwc); err0: return ret; -- cgit v0.10.2 From 7f370ed0cfe9aa1520696c1c71e8a51e2c0bbcc1 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Mon, 9 May 2016 15:27:01 +0300 Subject: usb: dwc3: core: get rid of DWC3_PM_OPS macro that macro is unnecessary and just adds pointless obfuscation. Let's remove it. Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index a590cd2..245f4ff 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -1209,16 +1209,12 @@ err_usb2phy_power: return ret; } +#endif /* CONFIG_PM_SLEEP */ static const struct dev_pm_ops dwc3_dev_pm_ops = { SET_SYSTEM_SLEEP_PM_OPS(dwc3_suspend, dwc3_resume) }; -#define DWC3_PM_OPS &(dwc3_dev_pm_ops) -#else -#define DWC3_PM_OPS NULL -#endif - #ifdef CONFIG_OF static const struct of_device_id of_dwc3_match[] = { { @@ -1250,7 +1246,7 @@ static struct platform_driver dwc3_driver = { .name = "dwc3", .of_match_table = of_match_ptr(of_dwc3_match), .acpi_match_table = ACPI_PTR(dwc3_acpi_match), - .pm = DWC3_PM_OPS, + .pm = &dwc3_dev_pm_ops, }, }; -- cgit v0.10.2 From c4233573f6ee611033faa9116fc7003775a450b9 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Thu, 12 May 2016 14:08:34 +0300 Subject: usb: dwc3: gadget: prepare TRBs on update transfers too If we're updating transfers, we can also prepare as many TRBs as we can fit in the ring. Let's start doing that. This patch 'solves' a limitation of how many TRBs we can prepare when we're getting close the end of the ring. Instead driver to prepare only up to end of the ring, we check if we have space to wrap around the ring properly. Note that this only happens when our enqueue and dequeue pointers are equal (which is the case for bulk endpoints after an XferComplete event). Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index ae55f50..236c231 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -880,16 +880,40 @@ static void dwc3_prepare_one_trb(struct dwc3_ep *dep, trace_dwc3_prepare_trb(dep, trb); } +static u32 dwc3_calc_trbs_left(struct dwc3_ep *dep) +{ + struct dwc3_trb *tmp; + + /* + * If enqueue & dequeue are equal than it is either full or empty. + * + * One way to know for sure is if the TRB right before us has HWO bit + * set or not. If it has, then we're definitely full and can't fit any + * more transfers in our ring. + */ + if (dep->trb_enqueue == dep->trb_dequeue) { + /* If we're full, enqueue/dequeue are > 0 */ + if (dep->trb_enqueue) { + tmp = &dep->trb_pool[dep->trb_enqueue - 1]; + if (tmp->ctrl & DWC3_TRB_CTRL_HWO) + return 0; + } + + return DWC3_TRB_NUM - 1; + } + + return dep->trb_dequeue - dep->trb_enqueue; +} + /* * dwc3_prepare_trbs - setup TRBs from requests * @dep: endpoint for which requests are being prepared - * @starting: true if the endpoint is idle and no requests are queued. * * The function goes through the requests list and sets up TRBs for the * transfers. The function returns once there are no more TRBs available or * it runs out of requests. */ -static void dwc3_prepare_trbs(struct dwc3_ep *dep, bool starting) +static void dwc3_prepare_trbs(struct dwc3_ep *dep) { struct dwc3_request *req, *n; u32 trbs_left; @@ -897,23 +921,7 @@ static void dwc3_prepare_trbs(struct dwc3_ep *dep, bool starting) BUILD_BUG_ON_NOT_POWER_OF_2(DWC3_TRB_NUM); - trbs_left = dep->trb_dequeue - dep->trb_enqueue; - - /* - * If enqueue & dequeue are equal than it is either full or empty. If we - * are starting to process requests then we are empty. Otherwise we are - * full and don't do anything - */ - if (!trbs_left) { - if (!starting) - return; - - trbs_left = DWC3_TRB_NUM; - } - - /* The last TRB is a link TRB, not used for xfer */ - if (trbs_left <= 1) - return; + trbs_left = dwc3_calc_trbs_left(dep); list_for_each_entry_safe(req, n, &dep->pending_list, list) { unsigned length; @@ -996,12 +1004,12 @@ static int __dwc3_gadget_kick_transfer(struct dwc3_ep *dep, u16 cmd_param, */ if (start_new) { if (list_empty(&dep->started_list)) - dwc3_prepare_trbs(dep, start_new); + dwc3_prepare_trbs(dep); /* req points to the first request which will be sent */ req = next_request(&dep->started_list); } else { - dwc3_prepare_trbs(dep, start_new); + dwc3_prepare_trbs(dep); /* * req points to the first request where HWO changed from 0 to 1 -- cgit v0.10.2 From 4fae2e3e15157ac312b91234389e79f7a76667b3 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Thu, 12 May 2016 16:53:59 +0300 Subject: usb: dwc3: gadget: simplify __dwc3_gadget_kick_transfer() as it turns out, we don't need the extra 'start_new' argument as that can be inferred from DWC3_EP_BUSY flag. Because of that, we can simplify __dwc3_gadget_kick_transfer() by quite a bit, even allowing us to prepare more TRBs unconditionally. Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 236c231..f828820 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -984,38 +984,19 @@ static void dwc3_prepare_trbs(struct dwc3_ep *dep) } } -static int __dwc3_gadget_kick_transfer(struct dwc3_ep *dep, u16 cmd_param, - int start_new) +static int __dwc3_gadget_kick_transfer(struct dwc3_ep *dep, u16 cmd_param) { struct dwc3_gadget_ep_cmd_params params; struct dwc3_request *req; struct dwc3 *dwc = dep->dwc; + int starting; int ret; u32 cmd; - if (start_new && (dep->flags & DWC3_EP_BUSY)) { - dwc3_trace(trace_dwc3_gadget, "%s: endpoint busy", dep->name); - return -EBUSY; - } - - /* - * If we are getting here after a short-out-packet we don't enqueue any - * new requests as we try to set the IOC bit only on the last request. - */ - if (start_new) { - if (list_empty(&dep->started_list)) - dwc3_prepare_trbs(dep); + starting = !(dep->flags & DWC3_EP_BUSY); - /* req points to the first request which will be sent */ - req = next_request(&dep->started_list); - } else { - dwc3_prepare_trbs(dep); - - /* - * req points to the first request where HWO changed from 0 to 1 - */ - req = next_request(&dep->started_list); - } + dwc3_prepare_trbs(dep); + req = next_request(&dep->started_list); if (!req) { dep->flags |= DWC3_EP_PENDING_REQUEST; return 0; @@ -1023,7 +1004,7 @@ static int __dwc3_gadget_kick_transfer(struct dwc3_ep *dep, u16 cmd_param, memset(¶ms, 0, sizeof(params)); - if (start_new) { + if (starting) { params.param0 = upper_32_bits(req->trb_dma); params.param1 = lower_32_bits(req->trb_dma); cmd = DWC3_DEPCMD_STARTTRANSFER; @@ -1047,7 +1028,7 @@ static int __dwc3_gadget_kick_transfer(struct dwc3_ep *dep, u16 cmd_param, dep->flags |= DWC3_EP_BUSY; - if (start_new) { + if (starting) { dep->resource_index = dwc3_gadget_ep_get_transfer_index(dwc, dep->number); WARN_ON_ONCE(!dep->resource_index); @@ -1072,7 +1053,7 @@ static void __dwc3_gadget_start_isoc(struct dwc3 *dwc, /* 4 micro frames in the future */ uf = cur_uf + dep->interval * 4; - __dwc3_gadget_kick_transfer(dep, uf, 1); + __dwc3_gadget_kick_transfer(dep, uf); } static void dwc3_gadget_start_isoc(struct dwc3 *dwc, @@ -1141,7 +1122,7 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req) if (!usb_endpoint_xfer_isoc(dep->endpoint.desc) && !usb_endpoint_xfer_int(dep->endpoint.desc) && !(dep->flags & DWC3_EP_BUSY)) { - ret = __dwc3_gadget_kick_transfer(dep, 0, true); + ret = __dwc3_gadget_kick_transfer(dep, 0); goto out; } @@ -1171,7 +1152,7 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req) return 0; } - ret = __dwc3_gadget_kick_transfer(dep, 0, true); + ret = __dwc3_gadget_kick_transfer(dep, 0); if (!ret) dep->flags &= ~DWC3_EP_PENDING_REQUEST; @@ -1187,8 +1168,7 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req) (dep->flags & DWC3_EP_BUSY) && !(dep->flags & DWC3_EP_MISSED_ISOC)) { WARN_ON_ONCE(!dep->resource_index); - ret = __dwc3_gadget_kick_transfer(dep, dep->resource_index, - false); + ret = __dwc3_gadget_kick_transfer(dep, dep->resource_index); goto out; } @@ -1198,7 +1178,7 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req) * handled. */ if (dep->stream_capable) - ret = __dwc3_gadget_kick_transfer(dep, 0, true); + ret = __dwc3_gadget_kick_transfer(dep, 0); out: if (ret && ret != -EBUSY) @@ -2087,7 +2067,7 @@ static void dwc3_endpoint_transfer_complete(struct dwc3 *dwc, if (!usb_endpoint_xfer_isoc(dep->endpoint.desc)) { int ret; - ret = __dwc3_gadget_kick_transfer(dep, 0, is_xfer_complete); + ret = __dwc3_gadget_kick_transfer(dep, 0); if (!ret || ret == -EBUSY) return; } @@ -2138,7 +2118,7 @@ static void dwc3_endpoint_interrupt(struct dwc3 *dwc, dep->name, active ? "Transfer Active" : "Transfer Not Active"); - ret = __dwc3_gadget_kick_transfer(dep, 0, !active); + ret = __dwc3_gadget_kick_transfer(dep, 0); if (!ret || ret == -EBUSY) return; -- cgit v0.10.2 From 6aff483295950abcf3be1a99f56f308bd6a1bab4 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Fri, 13 May 2016 10:07:47 +0300 Subject: usb: dwc3: gadget: rely on sg_is_last() and list_is_last() sg_is_last() and list_is_last() will encode the required information for the driver to make decisions WRT CHN and LST bits. While at that, also replace '1' with 'true' for consistency. Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index f828820..8ca3855 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -940,10 +940,10 @@ static void dwc3_prepare_trbs(struct dwc3_ep *dep) length = sg_dma_len(s); dma = sg_dma_address(s); - if (i == (request->num_mapped_sgs - 1) || - sg_is_last(s)) { - if (list_empty(&dep->pending_list)) + if (sg_is_last(s)) { + if (list_is_last(&req->list, &dep->pending_list)) last_one = true; + chain = false; } @@ -969,11 +969,11 @@ static void dwc3_prepare_trbs(struct dwc3_ep *dep) trbs_left--; if (!trbs_left) - last_one = 1; + last_one = true; /* Is this the last request? */ if (list_is_last(&req->list, &dep->pending_list)) - last_one = 1; + last_one = true; dwc3_prepare_one_trb(dep, req, dma, length, last_one, false, 0); -- cgit v0.10.2 From b43bba96b9036e42b2c2c71ee15e1f77b0b37aec Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Fri, 13 May 2016 10:11:59 +0300 Subject: usb: dwc3: gadget: remove udelay(1) when sending ep cmds When we send an endpoint command, we want that to complete as soon as possible, so let's remove the unnecessary udelay(1) call. Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 8ca3855..79d1882 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -334,8 +334,6 @@ int dwc3_send_gadget_ep_cmd(struct dwc3 *dwc, unsigned ep, ret = -ETIMEDOUT; break; } - - udelay(1); } while (1); if (unlikely(susphy)) { -- cgit v0.10.2 From 6b74289937f624439c87135cfabb3deb2955fb53 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Fri, 13 May 2016 10:19:42 +0300 Subject: usb: dwc3: gadget: return 0 if we try to Wakeup in superspeed Instead of returning -EINVAL when someone calls __dwc3_gadget_wakeup() in speeds > highspeed, let's return 0. There are no problems for the driver for calling it in superspeed as we cleanly just return. This avoids an annoying WARN_ONCE() always triggering during superspeed enumeration with LPM enabled. Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 79d1882..4c9fe7b 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -1431,7 +1431,7 @@ static int __dwc3_gadget_wakeup(struct dwc3 *dwc) if ((speed == DWC3_DSTS_SUPERSPEED) || (speed == DWC3_DSTS_SUPERSPEED_PLUS)) { dwc3_trace(trace_dwc3_gadget, "no wakeup on SuperSpeed\n"); - return -EINVAL; + return 0; } link_state = DWC3_DSTS_USBLNKST(reg); -- cgit v0.10.2 From 5ee85d890f8de5c6f1ab22ba13734a63fdf3ff2d Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Fri, 13 May 2016 12:42:44 +0300 Subject: usb: dwc3: gadget: split __dwc3_gadget_kick_transfer() To aid code readability, we're gonna split __dwc3_gadget_kick_transfer() into its constituent parts: scatter gather and linear buffers. That way, it's easier to follow the code and focus debug effort when one or the other fails. Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 4c9fe7b..bff2c35 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -903,6 +903,65 @@ static u32 dwc3_calc_trbs_left(struct dwc3_ep *dep) return dep->trb_dequeue - dep->trb_enqueue; } +static void dwc3_prepare_one_trb_sg(struct dwc3_ep *dep, + struct dwc3_request *req, unsigned int trbs_left) +{ + struct usb_request *request = &req->request; + struct scatterlist *sg = request->sg; + struct scatterlist *s; + unsigned int last = false; + unsigned int length; + dma_addr_t dma; + int i; + + for_each_sg(sg, s, request->num_mapped_sgs, i) { + unsigned chain = true; + + length = sg_dma_len(s); + dma = sg_dma_address(s); + + if (sg_is_last(s)) { + if (list_is_last(&req->list, &dep->pending_list)) + last = true; + + chain = false; + } + + if (!trbs_left) + last = true; + + if (last) + chain = false; + + dwc3_prepare_one_trb(dep, req, dma, length, + last, chain, i); + + if (last) + break; + } +} + +static void dwc3_prepare_one_trb_linear(struct dwc3_ep *dep, + struct dwc3_request *req, unsigned int trbs_left) +{ + unsigned int last = false; + unsigned int length; + dma_addr_t dma; + + dma = req->request.dma; + length = req->request.length; + + if (!trbs_left) + last = true; + + /* Is this the last request? */ + if (list_is_last(&req->list, &dep->pending_list)) + last = true; + + dwc3_prepare_one_trb(dep, req, dma, length, + last, false, 0); +} + /* * dwc3_prepare_trbs - setup TRBs from requests * @dep: endpoint for which requests are being prepared @@ -915,70 +974,19 @@ static void dwc3_prepare_trbs(struct dwc3_ep *dep) { struct dwc3_request *req, *n; u32 trbs_left; - unsigned int last_one = 0; BUILD_BUG_ON_NOT_POWER_OF_2(DWC3_TRB_NUM); trbs_left = dwc3_calc_trbs_left(dep); list_for_each_entry_safe(req, n, &dep->pending_list, list) { - unsigned length; - dma_addr_t dma; - last_one = false; - - if (req->request.num_mapped_sgs > 0) { - struct usb_request *request = &req->request; - struct scatterlist *sg = request->sg; - struct scatterlist *s; - int i; - - for_each_sg(sg, s, request->num_mapped_sgs, i) { - unsigned chain = true; - - length = sg_dma_len(s); - dma = sg_dma_address(s); - - if (sg_is_last(s)) { - if (list_is_last(&req->list, &dep->pending_list)) - last_one = true; - - chain = false; - } - - trbs_left--; - if (!trbs_left) - last_one = true; - - if (last_one) - chain = false; - - dwc3_prepare_one_trb(dep, req, dma, length, - last_one, chain, i); - - if (last_one) - break; - } - - if (last_one) - break; - } else { - dma = req->request.dma; - length = req->request.length; - trbs_left--; - - if (!trbs_left) - last_one = true; - - /* Is this the last request? */ - if (list_is_last(&req->list, &dep->pending_list)) - last_one = true; - - dwc3_prepare_one_trb(dep, req, dma, length, - last_one, false, 0); + if (req->request.num_mapped_sgs > 0) + dwc3_prepare_one_trb_sg(dep, req, trbs_left--); + else + dwc3_prepare_one_trb_linear(dep, req, trbs_left--); - if (last_one) - break; - } + if (!trbs_left) + return; } } -- cgit v0.10.2 From 4e99472bc10bda9906526d725ff6d5f27b4ddca1 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Fri, 13 May 2016 14:09:59 +0300 Subject: usb: dwc3: gadget: initialize NUMP based on RxFIFO Size Instead of using burst size to configure NUMP, we should be using RxFIFO Size instead. DWC3 is smart enough to know that it shouldn't burst in case burst size is 0. Reported-by: John Youn Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index c881c82..f4bec06 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -231,6 +231,14 @@ #define DWC3_GEVNTSIZ_INTMASK (1 << 31) #define DWC3_GEVNTSIZ_SIZE(n) ((n) & 0xffff) +/* Global HWPARAMS0 Register */ +#define DWC3_GHWPARAMS0_USB3_MODE(n) ((n) & 0x3) +#define DWC3_GHWPARAMS0_MBUS_TYPE(n) (((n) >> 3) & 0x7) +#define DWC3_GHWPARAMS0_SBUS_TYPE(n) (((n) >> 6) & 0x3) +#define DWC3_GHWPARAMS0_MDWIDTH(n) (((n) >> 8) & 0xff) +#define DWC3_GHWPARAMS0_SDWIDTH(n) (((n) >> 16) & 0xff) +#define DWC3_GHWPARAMS0_AWIDTH(n) (((n) >> 24) & 0xff) + /* Global HWPARAMS1 Register */ #define DWC3_GHWPARAMS1_EN_PWROPT(n) (((n) & (3 << 24)) >> 24) #define DWC3_GHWPARAMS1_EN_PWROPT_NO 0 @@ -260,6 +268,10 @@ /* Global HWPARAMS6 Register */ #define DWC3_GHWPARAMS6_EN_FPGA (1 << 7) +/* Global HWPARAMS7 Register */ +#define DWC3_GHWPARAMS7_RAM1_DEPTH(n) ((n) & 0xffff) +#define DWC3_GHWPARAMS7_RAM2_DEPTH(n) (((n) >> 16) & 0xffff) + /* Global Frame Length Adjustment Register */ #define DWC3_GFLADJ_30MHZ_SDBND_SEL (1 << 7) #define DWC3_GFLADJ_30MHZ_MASK 0x3f diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index bff2c35..eb28326 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -485,17 +485,6 @@ static int dwc3_gadget_set_ep_config(struct dwc3 *dwc, struct dwc3_ep *dep, /* Burst size is only needed in SuperSpeed mode */ if (dwc->gadget.speed >= USB_SPEED_SUPER) { u32 burst = dep->endpoint.maxburst; - u32 nump; - u32 reg; - - /* update NumP */ - reg = dwc3_readl(dwc->regs, DWC3_DCFG); - nump = DWC3_DCFG_NUMP(reg); - nump = max(nump, burst); - reg &= ~DWC3_DCFG_NUMP_MASK; - reg |= nump << DWC3_DCFG_NUMP_SHIFT; - dwc3_writel(dwc->regs, DWC3_DCFG, reg); - params.param0 |= DWC3_DEPCFG_BURST_SIZE(burst - 1); } @@ -1610,6 +1599,47 @@ static void dwc3_gadget_disable_irq(struct dwc3 *dwc) static irqreturn_t dwc3_interrupt(int irq, void *_dwc); static irqreturn_t dwc3_thread_interrupt(int irq, void *_dwc); +/** + * dwc3_gadget_setup_nump - Calculate and initialize NUMP field of DCFG + * dwc: pointer to our context structure + * + * The following looks like complex but it's actually very simple. In order to + * calculate the number of packets we can burst at once on OUT transfers, we're + * gonna use RxFIFO size. + * + * To calculate RxFIFO size we need two numbers: + * MDWIDTH = size, in bits, of the internal memory bus + * RAM2_DEPTH = depth, in MDWIDTH, of internal RAM2 (where RxFIFO sits) + * + * Given these two numbers, the formula is simple: + * + * RxFIFO Size = (RAM2_DEPTH * MDWIDTH / 8) - 24 - 16; + * + * 24 bytes is for 3x SETUP packets + * 16 bytes is a clock domain crossing tolerance + * + * Given RxFIFO Size, NUMP = RxFIFOSize / 1024; + */ +static void dwc3_gadget_setup_nump(struct dwc3 *dwc) +{ + u32 ram2_depth; + u32 mdwidth; + u32 nump; + u32 reg; + + ram2_depth = DWC3_GHWPARAMS7_RAM2_DEPTH(dwc->hwparams.hwparams7); + mdwidth = DWC3_GHWPARAMS0_MDWIDTH(dwc->hwparams.hwparams0); + + nump = ((ram2_depth * mdwidth / 8) - 24 - 16) / 1024; + nump = min_t(u32, nump, 16); + + /* update NumP */ + reg = dwc3_readl(dwc->regs, DWC3_DCFG); + reg &= ~DWC3_DCFG_NUMP_MASK; + reg |= nump << DWC3_DCFG_NUMP_SHIFT; + dwc3_writel(dwc->regs, DWC3_DCFG, reg); +} + static int __dwc3_gadget_start(struct dwc3 *dwc) { struct dwc3_ep *dep; @@ -1670,6 +1700,8 @@ static int __dwc3_gadget_start(struct dwc3 *dwc) reg &= ~DWC3_GRXTHRCFG_PKTCNTSEL; dwc3_writel(dwc->regs, DWC3_GRXTHRCFG, reg); + dwc3_gadget_setup_nump(dwc); + /* Start with SuperSpeed Default */ dwc3_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(512); -- cgit v0.10.2 From 2cd4718d0bbe1906fcf517f0b254fbd7c072383a Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Tue, 12 Apr 2016 16:42:43 +0300 Subject: usb: dwc3: gadget: pass dep as argument to endpoint command In all call sites of dwc3_send_gadget_ep_cmd() we already had a valid dep pointer, so instead of passing dwc and dep->number, which would be used to fetch the same pointer we already had, just pass dep directly. In other words, we're changing: struct dwc3_ep *dep = dwc[dep->number]; to just passing struct dwc3_ep *dep as argument. Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index f4bec06..27afe14 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -1105,8 +1105,8 @@ void dwc3_gadget_exit(struct dwc3 *dwc); int dwc3_gadget_set_test_mode(struct dwc3 *dwc, int mode); int dwc3_gadget_get_link_state(struct dwc3 *dwc); int dwc3_gadget_set_link_state(struct dwc3 *dwc, enum dwc3_link_state state); -int dwc3_send_gadget_ep_cmd(struct dwc3 *dwc, unsigned ep, - unsigned cmd, struct dwc3_gadget_ep_cmd_params *params); +int dwc3_send_gadget_ep_cmd(struct dwc3_ep *dep, unsigned cmd, + struct dwc3_gadget_ep_cmd_params *params); int dwc3_send_gadget_generic_command(struct dwc3 *dwc, unsigned cmd, u32 param); #else static inline int dwc3_gadget_init(struct dwc3 *dwc) @@ -1121,8 +1121,8 @@ static inline int dwc3_gadget_set_link_state(struct dwc3 *dwc, enum dwc3_link_state state) { return 0; } -static inline int dwc3_send_gadget_ep_cmd(struct dwc3 *dwc, unsigned ep, - unsigned cmd, struct dwc3_gadget_ep_cmd_params *params) +static inline int dwc3_send_gadget_ep_cmd(struct dwc3_ep *dep, unsigned cmd, + struct dwc3_gadget_ep_cmd_params *params) { return 0; } static inline int dwc3_send_gadget_generic_command(struct dwc3 *dwc, int cmd, u32 param) diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c index 51b52a7..e08150a 100644 --- a/drivers/usb/dwc3/ep0.c +++ b/drivers/usb/dwc3/ep0.c @@ -98,8 +98,7 @@ static int dwc3_ep0_start_trans(struct dwc3 *dwc, u8 epnum, dma_addr_t buf_dma, trace_dwc3_prepare_trb(dep, trb); - ret = dwc3_send_gadget_ep_cmd(dwc, dep->number, - DWC3_DEPCMD_STARTTRANSFER, ¶ms); + ret = dwc3_send_gadget_ep_cmd(dep, DWC3_DEPCMD_STARTTRANSFER, ¶ms); if (ret < 0) { dwc3_trace(trace_dwc3_ep0, "%s STARTTRANSFER failed", dep->name); @@ -1058,7 +1057,7 @@ static void dwc3_ep0_end_control_data(struct dwc3 *dwc, struct dwc3_ep *dep) cmd |= DWC3_DEPCMD_CMDIOC; cmd |= DWC3_DEPCMD_PARAM(dep->resource_index); memset(¶ms, 0, sizeof(params)); - ret = dwc3_send_gadget_ep_cmd(dwc, dep->number, cmd, ¶ms); + ret = dwc3_send_gadget_ep_cmd(dep, cmd, ¶ms); WARN_ON_ONCE(ret); dep->resource_index = 0; } diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index eb28326..5225f0e 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -238,16 +238,18 @@ int dwc3_send_gadget_generic_command(struct dwc3 *dwc, unsigned cmd, u32 param) static int __dwc3_gadget_wakeup(struct dwc3 *dwc); -int dwc3_send_gadget_ep_cmd(struct dwc3 *dwc, unsigned ep, - unsigned cmd, struct dwc3_gadget_ep_cmd_params *params) +int dwc3_send_gadget_ep_cmd(struct dwc3_ep *dep, unsigned cmd, + struct dwc3_gadget_ep_cmd_params *params) { - struct dwc3_ep *dep = dwc->eps[ep]; + struct dwc3 *dwc = dep->dwc; u32 timeout = 500; u32 reg; int susphy = false; int ret = -EINVAL; + unsigned ep = dep->number; + trace_dwc3_gadget_ep_cmd(dep, cmd, params); /* @@ -364,7 +366,7 @@ static int dwc3_send_clear_stall_ep_cmd(struct dwc3_ep *dep) memset(¶ms, 0, sizeof(params)); - return dwc3_send_gadget_ep_cmd(dwc, dep->number, cmd, ¶ms); + return dwc3_send_gadget_ep_cmd(dep, cmd, ¶ms); } static dma_addr_t dwc3_trb_dma_offset(struct dwc3_ep *dep, @@ -452,7 +454,7 @@ static int dwc3_gadget_start_config(struct dwc3 *dwc, struct dwc3_ep *dep) memset(¶ms, 0x00, sizeof(params)); cmd = DWC3_DEPCMD_DEPSTARTCFG; - ret = dwc3_send_gadget_ep_cmd(dwc, 0, cmd, ¶ms); + ret = dwc3_send_gadget_ep_cmd(dep, cmd, ¶ms); if (ret) return ret; @@ -528,8 +530,7 @@ static int dwc3_gadget_set_ep_config(struct dwc3 *dwc, struct dwc3_ep *dep, dep->interval = 1 << (desc->bInterval - 1); } - return dwc3_send_gadget_ep_cmd(dwc, dep->number, - DWC3_DEPCMD_SETEPCONFIG, ¶ms); + return dwc3_send_gadget_ep_cmd(dep, DWC3_DEPCMD_SETEPCONFIG, ¶ms); } static int dwc3_gadget_set_xfer_resource(struct dwc3 *dwc, struct dwc3_ep *dep) @@ -540,8 +541,8 @@ static int dwc3_gadget_set_xfer_resource(struct dwc3 *dwc, struct dwc3_ep *dep) params.param0 = DWC3_DEPXFERCFG_NUM_XFER_RES(1); - return dwc3_send_gadget_ep_cmd(dwc, dep->number, - DWC3_DEPCMD_SETTRANSFRESOURCE, ¶ms); + return dwc3_send_gadget_ep_cmd(dep, DWC3_DEPCMD_SETTRANSFRESOURCE, + ¶ms); } /** @@ -1008,7 +1009,7 @@ static int __dwc3_gadget_kick_transfer(struct dwc3_ep *dep, u16 cmd_param) } cmd |= DWC3_DEPCMD_PARAM(cmd_param); - ret = dwc3_send_gadget_ep_cmd(dwc, dep->number, cmd, ¶ms); + ret = dwc3_send_gadget_ep_cmd(dep, cmd, ¶ms); if (ret < 0) { /* * FIXME we need to iterate over the list of requests @@ -1311,14 +1312,15 @@ int __dwc3_gadget_ep_set_halt(struct dwc3_ep *dep, int value, int protocol) return -EAGAIN; } - ret = dwc3_send_gadget_ep_cmd(dwc, dep->number, - DWC3_DEPCMD_SETSTALL, ¶ms); + ret = dwc3_send_gadget_ep_cmd(dep, DWC3_DEPCMD_SETSTALL, + ¶ms); if (ret) dev_err(dwc->dev, "failed to set STALL on %s\n", dep->name); else dep->flags |= DWC3_EP_STALL; } else { + ret = dwc3_send_clear_stall_ep_cmd(dep); if (ret) dev_err(dwc->dev, "failed to clear STALL on %s\n", @@ -2271,7 +2273,7 @@ static void dwc3_stop_active_transfer(struct dwc3 *dwc, u32 epnum, bool force) cmd |= DWC3_DEPCMD_CMDIOC; cmd |= DWC3_DEPCMD_PARAM(dep->resource_index); memset(¶ms, 0, sizeof(params)); - ret = dwc3_send_gadget_ep_cmd(dwc, dep->number, cmd, ¶ms); + ret = dwc3_send_gadget_ep_cmd(dep, cmd, ¶ms); WARN_ON_ONCE(ret); dep->resource_index = 0; dep->flags &= ~DWC3_EP_BUSY; -- cgit v0.10.2 From 2eb8801650b315394ca376a56be2971c867aa9ec Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Tue, 12 Apr 2016 16:53:39 +0300 Subject: usb: dwc3: gadget: add a pointer to endpoint registers By adding a pointer to endpoint registers' base address, we can avoid using our controller-wide struct dwc3 pointer for everything. At some point this will allow us to have per-endpoint locks which will, in turn, let us queue requests to separate endpoints in parallel. Because of this change our debugfs interface and io accessors need to be changed accordingly. Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index 27afe14..02990ab 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -138,10 +138,12 @@ #define DWC3_DGCMDPAR 0xc710 #define DWC3_DGCMD 0xc714 #define DWC3_DALEPENA 0xc720 -#define DWC3_DEPCMDPAR2(n) (0xc800 + (n * 0x10)) -#define DWC3_DEPCMDPAR1(n) (0xc804 + (n * 0x10)) -#define DWC3_DEPCMDPAR0(n) (0xc808 + (n * 0x10)) -#define DWC3_DEPCMD(n) (0xc80c + (n * 0x10)) + +#define DWC3_DEP_BASE(n) (0xc800 + (n * 0x10)) +#define DWC3_DEPCMDPAR2 0x00 +#define DWC3_DEPCMDPAR1 0x04 +#define DWC3_DEPCMDPAR0 0x08 +#define DWC3_DEPCMD 0x0c /* OTG Registers */ #define DWC3_OCFG 0xcc00 @@ -480,6 +482,7 @@ struct dwc3_event_buffer { * @endpoint: usb endpoint * @pending_list: list of pending requests for this endpoint * @started_list: list of started requests on this endpoint + * @regs: pointer to first endpoint register * @trb_pool: array of transaction buffers * @trb_pool_dma: dma address of @trb_pool * @trb_enqueue: enqueue 'pointer' into TRB array @@ -501,6 +504,8 @@ struct dwc3_ep { struct list_head pending_list; struct list_head started_list; + void __iomem *regs; + struct dwc3_trb *trb_pool; dma_addr_t trb_pool_dma; const struct usb_ss_ep_comp_descriptor *comp_desc; diff --git a/drivers/usb/dwc3/debugfs.c b/drivers/usb/dwc3/debugfs.c index b1dd3c6..89c26e0 100644 --- a/drivers/usb/dwc3/debugfs.c +++ b/drivers/usb/dwc3/debugfs.c @@ -36,9 +36,32 @@ #define dump_register(nm) \ { \ .name = __stringify(nm), \ - .offset = DWC3_ ##nm - DWC3_GLOBALS_REGS_START, \ + .offset = DWC3_ ##nm, \ } +#define dump_ep_register_set(n) \ + { \ + .name = "DEPCMDPAR2("__stringify(n)")", \ + .offset = DWC3_DEP_BASE(n) + \ + DWC3_DEPCMDPAR2, \ + }, \ + { \ + .name = "DEPCMDPAR1("__stringify(n)")", \ + .offset = DWC3_DEP_BASE(n) + \ + DWC3_DEPCMDPAR1, \ + }, \ + { \ + .name = "DEPCMDPAR0("__stringify(n)")", \ + .offset = DWC3_DEP_BASE(n) + \ + DWC3_DEPCMDPAR0, \ + }, \ + { \ + .name = "DEPCMD("__stringify(n)")", \ + .offset = DWC3_DEP_BASE(n) + \ + DWC3_DEPCMD, \ + } + + static const struct debugfs_reg32 dwc3_regs[] = { dump_register(GSBUSCFG0), dump_register(GSBUSCFG1), @@ -218,137 +241,38 @@ static const struct debugfs_reg32 dwc3_regs[] = { dump_register(DGCMD), dump_register(DALEPENA), - dump_register(DEPCMDPAR2(0)), - dump_register(DEPCMDPAR2(1)), - dump_register(DEPCMDPAR2(2)), - dump_register(DEPCMDPAR2(3)), - dump_register(DEPCMDPAR2(4)), - dump_register(DEPCMDPAR2(5)), - dump_register(DEPCMDPAR2(6)), - dump_register(DEPCMDPAR2(7)), - dump_register(DEPCMDPAR2(8)), - dump_register(DEPCMDPAR2(9)), - dump_register(DEPCMDPAR2(10)), - dump_register(DEPCMDPAR2(11)), - dump_register(DEPCMDPAR2(12)), - dump_register(DEPCMDPAR2(13)), - dump_register(DEPCMDPAR2(14)), - dump_register(DEPCMDPAR2(15)), - dump_register(DEPCMDPAR2(16)), - dump_register(DEPCMDPAR2(17)), - dump_register(DEPCMDPAR2(18)), - dump_register(DEPCMDPAR2(19)), - dump_register(DEPCMDPAR2(20)), - dump_register(DEPCMDPAR2(21)), - dump_register(DEPCMDPAR2(22)), - dump_register(DEPCMDPAR2(23)), - dump_register(DEPCMDPAR2(24)), - dump_register(DEPCMDPAR2(25)), - dump_register(DEPCMDPAR2(26)), - dump_register(DEPCMDPAR2(27)), - dump_register(DEPCMDPAR2(28)), - dump_register(DEPCMDPAR2(29)), - dump_register(DEPCMDPAR2(30)), - dump_register(DEPCMDPAR2(31)), - - dump_register(DEPCMDPAR1(0)), - dump_register(DEPCMDPAR1(1)), - dump_register(DEPCMDPAR1(2)), - dump_register(DEPCMDPAR1(3)), - dump_register(DEPCMDPAR1(4)), - dump_register(DEPCMDPAR1(5)), - dump_register(DEPCMDPAR1(6)), - dump_register(DEPCMDPAR1(7)), - dump_register(DEPCMDPAR1(8)), - dump_register(DEPCMDPAR1(9)), - dump_register(DEPCMDPAR1(10)), - dump_register(DEPCMDPAR1(11)), - dump_register(DEPCMDPAR1(12)), - dump_register(DEPCMDPAR1(13)), - dump_register(DEPCMDPAR1(14)), - dump_register(DEPCMDPAR1(15)), - dump_register(DEPCMDPAR1(16)), - dump_register(DEPCMDPAR1(17)), - dump_register(DEPCMDPAR1(18)), - dump_register(DEPCMDPAR1(19)), - dump_register(DEPCMDPAR1(20)), - dump_register(DEPCMDPAR1(21)), - dump_register(DEPCMDPAR1(22)), - dump_register(DEPCMDPAR1(23)), - dump_register(DEPCMDPAR1(24)), - dump_register(DEPCMDPAR1(25)), - dump_register(DEPCMDPAR1(26)), - dump_register(DEPCMDPAR1(27)), - dump_register(DEPCMDPAR1(28)), - dump_register(DEPCMDPAR1(29)), - dump_register(DEPCMDPAR1(30)), - dump_register(DEPCMDPAR1(31)), - - dump_register(DEPCMDPAR0(0)), - dump_register(DEPCMDPAR0(1)), - dump_register(DEPCMDPAR0(2)), - dump_register(DEPCMDPAR0(3)), - dump_register(DEPCMDPAR0(4)), - dump_register(DEPCMDPAR0(5)), - dump_register(DEPCMDPAR0(6)), - dump_register(DEPCMDPAR0(7)), - dump_register(DEPCMDPAR0(8)), - dump_register(DEPCMDPAR0(9)), - dump_register(DEPCMDPAR0(10)), - dump_register(DEPCMDPAR0(11)), - dump_register(DEPCMDPAR0(12)), - dump_register(DEPCMDPAR0(13)), - dump_register(DEPCMDPAR0(14)), - dump_register(DEPCMDPAR0(15)), - dump_register(DEPCMDPAR0(16)), - dump_register(DEPCMDPAR0(17)), - dump_register(DEPCMDPAR0(18)), - dump_register(DEPCMDPAR0(19)), - dump_register(DEPCMDPAR0(20)), - dump_register(DEPCMDPAR0(21)), - dump_register(DEPCMDPAR0(22)), - dump_register(DEPCMDPAR0(23)), - dump_register(DEPCMDPAR0(24)), - dump_register(DEPCMDPAR0(25)), - dump_register(DEPCMDPAR0(26)), - dump_register(DEPCMDPAR0(27)), - dump_register(DEPCMDPAR0(28)), - dump_register(DEPCMDPAR0(29)), - dump_register(DEPCMDPAR0(30)), - dump_register(DEPCMDPAR0(31)), - - dump_register(DEPCMD(0)), - dump_register(DEPCMD(1)), - dump_register(DEPCMD(2)), - dump_register(DEPCMD(3)), - dump_register(DEPCMD(4)), - dump_register(DEPCMD(5)), - dump_register(DEPCMD(6)), - dump_register(DEPCMD(7)), - dump_register(DEPCMD(8)), - dump_register(DEPCMD(9)), - dump_register(DEPCMD(10)), - dump_register(DEPCMD(11)), - dump_register(DEPCMD(12)), - dump_register(DEPCMD(13)), - dump_register(DEPCMD(14)), - dump_register(DEPCMD(15)), - dump_register(DEPCMD(16)), - dump_register(DEPCMD(17)), - dump_register(DEPCMD(18)), - dump_register(DEPCMD(19)), - dump_register(DEPCMD(20)), - dump_register(DEPCMD(21)), - dump_register(DEPCMD(22)), - dump_register(DEPCMD(23)), - dump_register(DEPCMD(24)), - dump_register(DEPCMD(25)), - dump_register(DEPCMD(26)), - dump_register(DEPCMD(27)), - dump_register(DEPCMD(28)), - dump_register(DEPCMD(29)), - dump_register(DEPCMD(30)), - dump_register(DEPCMD(31)), + dump_ep_register_set(0), + dump_ep_register_set(1), + dump_ep_register_set(2), + dump_ep_register_set(3), + dump_ep_register_set(4), + dump_ep_register_set(5), + dump_ep_register_set(6), + dump_ep_register_set(7), + dump_ep_register_set(8), + dump_ep_register_set(9), + dump_ep_register_set(10), + dump_ep_register_set(11), + dump_ep_register_set(12), + dump_ep_register_set(13), + dump_ep_register_set(14), + dump_ep_register_set(15), + dump_ep_register_set(16), + dump_ep_register_set(17), + dump_ep_register_set(18), + dump_ep_register_set(19), + dump_ep_register_set(20), + dump_ep_register_set(21), + dump_ep_register_set(22), + dump_ep_register_set(23), + dump_ep_register_set(24), + dump_ep_register_set(25), + dump_ep_register_set(26), + dump_ep_register_set(27), + dump_ep_register_set(28), + dump_ep_register_set(29), + dump_ep_register_set(30), + dump_ep_register_set(31), dump_register(OCFG), dump_register(OCTL), @@ -939,7 +863,7 @@ void dwc3_debugfs_init(struct dwc3 *dwc) dwc->regset->regs = dwc3_regs; dwc->regset->nregs = ARRAY_SIZE(dwc3_regs); - dwc->regset->base = dwc->regs; + dwc->regset->base = dwc->regs - DWC3_GLOBALS_REGS_START; file = debugfs_create_regset32("regdump", S_IRUGO, root, dwc->regset); if (!file) diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c index e08150a..3103a8f 100644 --- a/drivers/usb/dwc3/ep0.c +++ b/drivers/usb/dwc3/ep0.c @@ -106,9 +106,7 @@ static int dwc3_ep0_start_trans(struct dwc3 *dwc, u8 epnum, dma_addr_t buf_dma, } dep->flags |= DWC3_EP_BUSY; - dep->resource_index = dwc3_gadget_ep_get_transfer_index(dwc, - dep->number); - + dep->resource_index = dwc3_gadget_ep_get_transfer_index(dep); dwc->ep0_next_event = DWC3_EP0_COMPLETE; return 0; diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 5225f0e..7ba4287 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -248,8 +248,6 @@ int dwc3_send_gadget_ep_cmd(struct dwc3_ep *dep, unsigned cmd, int susphy = false; int ret = -EINVAL; - unsigned ep = dep->number; - trace_dwc3_gadget_ep_cmd(dep, cmd, params); /* @@ -281,13 +279,13 @@ int dwc3_send_gadget_ep_cmd(struct dwc3_ep *dep, unsigned cmd, } } - dwc3_writel(dwc->regs, DWC3_DEPCMDPAR0(ep), params->param0); - dwc3_writel(dwc->regs, DWC3_DEPCMDPAR1(ep), params->param1); - dwc3_writel(dwc->regs, DWC3_DEPCMDPAR2(ep), params->param2); + dwc3_writel(dep->regs, DWC3_DEPCMDPAR0, params->param0); + dwc3_writel(dep->regs, DWC3_DEPCMDPAR1, params->param1); + dwc3_writel(dep->regs, DWC3_DEPCMDPAR2, params->param2); - dwc3_writel(dwc->regs, DWC3_DEPCMD(ep), cmd | DWC3_DEPCMD_CMDACT); + dwc3_writel(dep->regs, DWC3_DEPCMD, cmd | DWC3_DEPCMD_CMDACT); do { - reg = dwc3_readl(dwc->regs, DWC3_DEPCMD(ep)); + reg = dwc3_readl(dep->regs, DWC3_DEPCMD); if (!(reg & DWC3_DEPCMD_CMDACT)) { int cmd_status = DWC3_DEPCMD_STATUS(reg); @@ -1025,8 +1023,7 @@ static int __dwc3_gadget_kick_transfer(struct dwc3_ep *dep, u16 cmd_param) dep->flags |= DWC3_EP_BUSY; if (starting) { - dep->resource_index = dwc3_gadget_ep_get_transfer_index(dwc, - dep->number); + dep->resource_index = dwc3_gadget_ep_get_transfer_index(dep); WARN_ON_ONCE(!dep->resource_index); } @@ -1830,6 +1827,7 @@ static int dwc3_gadget_init_hw_endpoints(struct dwc3 *dwc, dep->dwc = dwc; dep->number = epnum; dep->direction = !!direction; + dep->regs = dwc->regs + DWC3_DEP_BASE(epnum); dwc->eps[epnum] = dep; snprintf(dep->name, sizeof(dep->name), "ep%d%s", epnum >> 1, diff --git a/drivers/usb/dwc3/gadget.h b/drivers/usb/dwc3/gadget.h index f21c0fc..e4a1d97 100644 --- a/drivers/usb/dwc3/gadget.h +++ b/drivers/usb/dwc3/gadget.h @@ -95,11 +95,11 @@ int __dwc3_gadget_ep_set_halt(struct dwc3_ep *dep, int value, int protocol); * * Caller should take care of locking */ -static inline u32 dwc3_gadget_ep_get_transfer_index(struct dwc3 *dwc, u8 number) +static inline u32 dwc3_gadget_ep_get_transfer_index(struct dwc3_ep *dep) { u32 res_id; - res_id = dwc3_readl(dwc->regs, DWC3_DEPCMD(number)); + res_id = dwc3_readl(dep->regs, DWC3_DEPCMD); return DWC3_DEPCMD_GET_RSC_IDX(res_id); } diff --git a/drivers/usb/dwc3/io.h b/drivers/usb/dwc3/io.h index 6a79c8e..a06f9a8 100644 --- a/drivers/usb/dwc3/io.h +++ b/drivers/usb/dwc3/io.h @@ -26,7 +26,6 @@ static inline u32 dwc3_readl(void __iomem *base, u32 offset) { - u32 offs = offset - DWC3_GLOBALS_REGS_START; u32 value; /* @@ -34,7 +33,7 @@ static inline u32 dwc3_readl(void __iomem *base, u32 offset) * space, see dwc3_probe in core.c. * However, the offsets are given starting from xHCI address space. */ - value = readl(base + offs); + value = readl(base + offset - DWC3_GLOBALS_REGS_START); /* * When tracing we want to make it easy to find the correct address on @@ -49,14 +48,12 @@ static inline u32 dwc3_readl(void __iomem *base, u32 offset) static inline void dwc3_writel(void __iomem *base, u32 offset, u32 value) { - u32 offs = offset - DWC3_GLOBALS_REGS_START; - /* * We requested the mem region starting from the Globals address * space, see dwc3_probe in core.c. * However, the offsets are given starting from xHCI address space. */ - writel(value, base + offs); + writel(value, base + offset - DWC3_GLOBALS_REGS_START); /* * When tracing we want to make it easy to find the correct address on -- cgit v0.10.2 From bcdb3272e889f4d2a5c8efc5e12b0fb2dcbf75e9 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Mon, 16 May 2016 10:42:23 +0300 Subject: usb: dwc3: core: move fladj to dwc3 structure this patch is in preparation for some further re-factoring in dwc3 initialization. No functional changes. Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index 245f4ff..1f4ac35 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -149,9 +149,8 @@ static int dwc3_soft_reset(struct dwc3 *dwc) /* * dwc3_frame_length_adjustment - Adjusts frame length if required * @dwc3: Pointer to our controller context structure - * @fladj: Value of GFLADJ_30MHZ to adjust frame length */ -static void dwc3_frame_length_adjustment(struct dwc3 *dwc, u32 fladj) +static void dwc3_frame_length_adjustment(struct dwc3 *dwc) { u32 reg; u32 dft; @@ -159,15 +158,15 @@ static void dwc3_frame_length_adjustment(struct dwc3 *dwc, u32 fladj) if (dwc->revision < DWC3_REVISION_250A) return; - if (fladj == 0) + if (dwc->fladj == 0) return; reg = dwc3_readl(dwc->regs, DWC3_GFLADJ); dft = reg & DWC3_GFLADJ_30MHZ_MASK; - if (!dev_WARN_ONCE(dwc->dev, dft == fladj, + if (!dev_WARN_ONCE(dwc->dev, dft == dwc->fladj, "request value same as default, ignoring\n")) { reg &= ~DWC3_GFLADJ_30MHZ_MASK; - reg |= DWC3_GFLADJ_30MHZ_SDBND_SEL | fladj; + reg |= DWC3_GFLADJ_30MHZ_SDBND_SEL | dwc->fladj; dwc3_writel(dwc->regs, DWC3_GFLADJ, reg); } } @@ -799,7 +798,6 @@ static int dwc3_probe(struct platform_device *pdev) u8 lpm_nyet_threshold; u8 tx_de_emphasis; u8 hird_threshold; - u32 fladj = 0; int ret; @@ -909,7 +907,7 @@ static int dwc3_probe(struct platform_device *pdev) device_property_read_string(dev, "snps,hsphy_interface", &dwc->hsphy_interface); device_property_read_u32(dev, "snps,quirk-frame-length-adjustment", - &fladj); + &dwc->fladj); if (pdata) { dwc->maximum_speed = pdata->maximum_speed; @@ -941,7 +939,7 @@ static int dwc3_probe(struct platform_device *pdev) tx_de_emphasis = pdata->tx_de_emphasis; dwc->hsphy_interface = pdata->hsphy_interface; - fladj = pdata->fladj_value; + dwc->fladj = pdata->fladj_value; } dwc->lpm_nyet_threshold = lpm_nyet_threshold; @@ -1022,7 +1020,7 @@ static int dwc3_probe(struct platform_device *pdev) } /* Adjust Frame Length */ - dwc3_frame_length_adjustment(dwc, fladj); + dwc3_frame_length_adjustment(dwc); usb_phy_set_suspend(dwc->usb2_phy, 0); usb_phy_set_suspend(dwc->usb3_phy, 0); diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index 02990ab..e01f637 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -729,6 +729,7 @@ struct dwc3_scratchpad_array { * @gadget_driver: pointer to the gadget driver * @regs: base address for our registers * @regs_size: address space size + * @fladj: frame length adjustment * @nr_scratch: number of scratch buffers * @u1u2: only used on revisions <1.83a for workaround * @maximum_speed: maximum speed requested (mainly for testing purposes) @@ -838,6 +839,7 @@ struct dwc3 { /* used for suspend/resume */ u32 gctl; + u32 fladj; u32 nr_scratch; u32 u1u2; u32 maximum_speed; -- cgit v0.10.2 From c499ff71ff2a281366c6ec7a904c547d806cbcd1 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Mon, 16 May 2016 10:49:01 +0300 Subject: usb: dwc3: core: re-factor init and exit paths The idea of this patch is for dwc3_core_init() to abstract all the details about how to initialize dwc3 and dwc3_core_exit() to do the same for teardown. With this, we can simplify suspend/resume operations by a large margin and always know that we're going to start dwc3 from a known starting point. Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index 1f4ac35..cbdefbb 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -506,6 +506,21 @@ static int dwc3_phy_setup(struct dwc3 *dwc) return 0; } +static void dwc3_core_exit(struct dwc3 *dwc) +{ + dwc3_event_buffers_cleanup(dwc); + + usb_phy_shutdown(dwc->usb2_phy); + usb_phy_shutdown(dwc->usb3_phy); + phy_exit(dwc->usb2_generic_phy); + phy_exit(dwc->usb3_generic_phy); + + usb_phy_set_suspend(dwc->usb2_phy, 1); + usb_phy_set_suspend(dwc->usb3_phy, 1); + phy_power_off(dwc->usb2_generic_phy); + phy_power_off(dwc->usb3_generic_phy); +} + /** * dwc3_core_init - Low-level initialization of DWC3 Core * @dwc: Pointer to our controller context structure @@ -555,6 +570,10 @@ static int dwc3_core_init(struct dwc3 *dwc) if (ret) goto err0; + ret = dwc3_phy_setup(dwc); + if (ret) + goto err0; + reg = dwc3_readl(dwc->regs, DWC3_GCTL); reg &= ~DWC3_GCTL_SCALEDOWN_MASK; @@ -621,22 +640,45 @@ static int dwc3_core_init(struct dwc3 *dwc) if (dwc->revision < DWC3_REVISION_190A) reg |= DWC3_GCTL_U2RSTECN; - dwc3_core_num_eps(dwc); - dwc3_writel(dwc->regs, DWC3_GCTL, reg); - ret = dwc3_alloc_scratch_buffers(dwc); - if (ret) - goto err1; + dwc3_core_num_eps(dwc); ret = dwc3_setup_scratch_buffers(dwc); if (ret) + goto err1; + + /* Adjust Frame Length */ + dwc3_frame_length_adjustment(dwc); + + usb_phy_set_suspend(dwc->usb2_phy, 0); + usb_phy_set_suspend(dwc->usb3_phy, 0); + ret = phy_power_on(dwc->usb2_generic_phy); + if (ret < 0) goto err2; + ret = phy_power_on(dwc->usb3_generic_phy); + if (ret < 0) + goto err3; + + ret = dwc3_event_buffers_setup(dwc); + if (ret) { + dev_err(dwc->dev, "failed to setup event buffers\n"); + goto err4; + } + return 0; +err4: + phy_power_off(dwc->usb2_generic_phy); + +err3: + phy_power_off(dwc->usb3_generic_phy); + err2: - dwc3_free_scratch_buffers(dwc); + usb_phy_set_suspend(dwc->usb2_phy, 1); + usb_phy_set_suspend(dwc->usb3_phy, 1); + dwc3_core_exit(dwc); err1: usb_phy_shutdown(dwc->usb2_phy); @@ -648,15 +690,6 @@ err0: return ret; } -static void dwc3_core_exit(struct dwc3 *dwc) -{ - dwc3_free_scratch_buffers(dwc); - usb_phy_shutdown(dwc->usb2_phy); - usb_phy_shutdown(dwc->usb3_phy); - phy_exit(dwc->usb2_generic_phy); - phy_exit(dwc->usb3_generic_phy); -} - static int dwc3_core_get_phy(struct dwc3 *dwc) { struct device *dev = dwc->dev; @@ -951,10 +984,6 @@ static int dwc3_probe(struct platform_device *pdev) platform_set_drvdata(pdev, dwc); dwc3_cache_hwparams(dwc); - ret = dwc3_phy_setup(dwc); - if (ret) - goto err0; - ret = dwc3_core_get_phy(dwc); if (ret) goto err0; @@ -975,7 +1004,7 @@ static int dwc3_probe(struct platform_device *pdev) if (ret) { dev_err(dwc->dev, "failed to allocate event buffers\n"); ret = -ENOMEM; - goto err1; + goto err0; } if (IS_ENABLED(CONFIG_USB_DWC3_HOST)) @@ -986,10 +1015,14 @@ static int dwc3_probe(struct platform_device *pdev) if (dwc->dr_mode == USB_DR_MODE_UNKNOWN) dwc->dr_mode = USB_DR_MODE_OTG; + ret = dwc3_alloc_scratch_buffers(dwc); + if (ret) + goto err1; + ret = dwc3_core_init(dwc); if (ret) { dev_err(dev, "failed to initialize core\n"); - goto err1; + goto err2; } /* Check the maximum_speed parameter */ @@ -1019,47 +1052,20 @@ static int dwc3_probe(struct platform_device *pdev) break; } - /* Adjust Frame Length */ - dwc3_frame_length_adjustment(dwc); - - usb_phy_set_suspend(dwc->usb2_phy, 0); - usb_phy_set_suspend(dwc->usb3_phy, 0); - ret = phy_power_on(dwc->usb2_generic_phy); - if (ret < 0) - goto err2; - - ret = phy_power_on(dwc->usb3_generic_phy); - if (ret < 0) - goto err3; - - ret = dwc3_event_buffers_setup(dwc); - if (ret) { - dev_err(dwc->dev, "failed to setup event buffers\n"); - goto err4; - } - ret = dwc3_core_init_mode(dwc); if (ret) - goto err5; + goto err3; dwc3_debugfs_init(dwc); pm_runtime_allow(dev); return 0; -err5: - dwc3_event_buffers_cleanup(dwc); - -err4: - phy_power_off(dwc->usb3_generic_phy); - err3: - phy_power_off(dwc->usb2_generic_phy); + dwc3_event_buffers_cleanup(dwc); err2: - usb_phy_set_suspend(dwc->usb2_phy, 1); - usb_phy_set_suspend(dwc->usb3_phy, 1); - dwc3_core_exit(dwc); + dwc3_free_scratch_buffers(dwc); err1: dwc3_free_event_buffers(dwc); @@ -1090,17 +1096,13 @@ static int dwc3_remove(struct platform_device *pdev) dwc3_debugfs_exit(dwc); dwc3_core_exit_mode(dwc); - dwc3_event_buffers_cleanup(dwc); - dwc3_free_event_buffers(dwc); - - usb_phy_set_suspend(dwc->usb2_phy, 1); - usb_phy_set_suspend(dwc->usb3_phy, 1); - phy_power_off(dwc->usb2_generic_phy); - phy_power_off(dwc->usb3_generic_phy); dwc3_core_exit(dwc); dwc3_ulpi_exit(dwc); + dwc3_free_event_buffers(dwc); + dwc3_free_scratch_buffers(dwc); + pm_runtime_put_sync(&pdev->dev); pm_runtime_disable(&pdev->dev); -- cgit v0.10.2 From 51f5d49ad6f011ee380b866ea617fd90584189a2 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Mon, 16 May 2016 10:52:58 +0300 Subject: usb: dwc3: core: simplify suspend/resume operations now that we have re-factored dwc3_core_init() and dwc3_core_exit() we can use them for suspend/resume operations. This will help us avoid some common mistakes when patching code when we have duplicated pieces of code doing the same thing. Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index cbdefbb..80e9aff 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -1113,33 +1113,19 @@ static int dwc3_remove(struct platform_device *pdev) static int dwc3_suspend(struct device *dev) { struct dwc3 *dwc = dev_get_drvdata(dev); - unsigned long flags; - - spin_lock_irqsave(&dwc->lock, flags); switch (dwc->dr_mode) { case USB_DR_MODE_PERIPHERAL: case USB_DR_MODE_OTG: dwc3_gadget_suspend(dwc); - /* FALLTHROUGH */ + break; case USB_DR_MODE_HOST: default: - dwc3_event_buffers_cleanup(dwc); + /* do nothing */ break; } - dwc->gctl = dwc3_readl(dwc->regs, DWC3_GCTL); - spin_unlock_irqrestore(&dwc->lock, flags); - - usb_phy_shutdown(dwc->usb3_phy); - usb_phy_shutdown(dwc->usb2_phy); - phy_exit(dwc->usb2_generic_phy); - phy_exit(dwc->usb3_generic_phy); - - usb_phy_set_suspend(dwc->usb2_phy, 1); - usb_phy_set_suspend(dwc->usb3_phy, 1); - WARN_ON(phy_power_off(dwc->usb2_generic_phy) < 0); - WARN_ON(phy_power_off(dwc->usb3_generic_phy) < 0); + dwc3_core_exit(dwc); pinctrl_pm_select_sleep_state(dev); @@ -1149,36 +1135,14 @@ static int dwc3_suspend(struct device *dev) static int dwc3_resume(struct device *dev) { struct dwc3 *dwc = dev_get_drvdata(dev); - unsigned long flags; int ret; pinctrl_pm_select_default_state(dev); - usb_phy_set_suspend(dwc->usb2_phy, 0); - usb_phy_set_suspend(dwc->usb3_phy, 0); - ret = phy_power_on(dwc->usb2_generic_phy); - if (ret < 0) + ret = dwc3_core_init(dwc); + if (ret) return ret; - ret = phy_power_on(dwc->usb3_generic_phy); - if (ret < 0) - goto err_usb2phy_power; - - usb_phy_init(dwc->usb3_phy); - usb_phy_init(dwc->usb2_phy); - ret = phy_init(dwc->usb2_generic_phy); - if (ret < 0) - goto err_usb3phy_power; - - ret = phy_init(dwc->usb3_generic_phy); - if (ret < 0) - goto err_usb2phy_init; - - spin_lock_irqsave(&dwc->lock, flags); - - dwc3_event_buffers_setup(dwc); - dwc3_writel(dwc->regs, DWC3_GCTL, dwc->gctl); - switch (dwc->dr_mode) { case USB_DR_MODE_PERIPHERAL: case USB_DR_MODE_OTG: @@ -1190,24 +1154,11 @@ static int dwc3_resume(struct device *dev) break; } - spin_unlock_irqrestore(&dwc->lock, flags); - pm_runtime_disable(dev); pm_runtime_set_active(dev); pm_runtime_enable(dev); return 0; - -err_usb2phy_init: - phy_exit(dwc->usb2_generic_phy); - -err_usb3phy_power: - phy_power_off(dwc->usb3_generic_phy); - -err_usb2phy_power: - phy_power_off(dwc->usb2_generic_phy); - - return ret; } #endif /* CONFIG_PM_SLEEP */ diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index e01f637..2117295 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -836,9 +836,6 @@ struct dwc3 { enum usb_dr_mode dr_mode; - /* used for suspend/resume */ - u32 gctl; - u32 fladj; u32 nr_scratch; u32 u1u2; -- cgit v0.10.2 From 3f308d17d7abbf35a6d40a7f16dc70cf43f12c98 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Mon, 16 May 2016 14:17:06 +0300 Subject: usb: dwc3: gadget: hold gadget IRQ in dwc->irq_gadget by holding gadget's IRQ number in dwc->irq_gadget, it'll be simpler to free_irq() and disable the IRQ in case an IRQ fires while we are runtime suspended. Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index 2117295..5148c56 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -730,6 +730,7 @@ struct dwc3_scratchpad_array { * @regs: base address for our registers * @regs_size: address space size * @fladj: frame length adjustment + * @irq_gadget: peripheral controller's IRQ number * @nr_scratch: number of scratch buffers * @u1u2: only used on revisions <1.83a for workaround * @maximum_speed: maximum speed requested (mainly for testing purposes) @@ -837,6 +838,7 @@ struct dwc3 { enum usb_dr_mode dr_mode; u32 fladj; + u32 irq_gadget; u32 nr_scratch; u32 u1u2; u32 maximum_speed; diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 7ba4287..378c14c 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -1751,6 +1751,7 @@ static int dwc3_gadget_start(struct usb_gadget *g, irq, ret); goto err0; } + dwc->irq_gadget = irq; spin_lock_irqsave(&dwc->lock, flags); if (dwc->gadget_driver) { @@ -1787,15 +1788,13 @@ static int dwc3_gadget_stop(struct usb_gadget *g) { struct dwc3 *dwc = gadget_to_dwc(g); unsigned long flags; - int irq; spin_lock_irqsave(&dwc->lock, flags); __dwc3_gadget_stop(dwc); dwc->gadget_driver = NULL; spin_unlock_irqrestore(&dwc->lock, flags); - irq = platform_get_irq(to_platform_device(dwc->dev), 0); - free_irq(irq, dwc->ev_buf); + free_irq(dwc->irq_gadget, dwc->ev_buf); return 0; } -- cgit v0.10.2 From ab2a92e7a608c09f13baf1730b9ba24c73c35d52 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Tue, 17 May 2016 14:55:58 +0300 Subject: usb: dwc3: gadget: only resume USB2 PHY in <=HIGHSPEED As a micro-power optimization, let's only resume the USB2 PHY if we're working on <=HIGHSPEED. If we're gonna work on SUPERSPEED or SUPERSPEED+, there's no point in resuming the USB2 PHY. Fixes: 2b0f11df84bb ("usb: dwc3: gadget: clear SUSPHY bit before ep cmds") Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 378c14c..5e7b2ba 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -258,11 +258,13 @@ int dwc3_send_gadget_ep_cmd(struct dwc3_ep *dep, unsigned cmd, * We will also set SUSPHY bit to what it was before returning as stated * by the same section on Synopsys databook. */ - reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0)); - if (unlikely(reg & DWC3_GUSB2PHYCFG_SUSPHY)) { - susphy = true; - reg &= ~DWC3_GUSB2PHYCFG_SUSPHY; - dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg); + if (dwc->gadget.speed <= USB_SPEED_HIGH) { + reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0)); + if (unlikely(reg & DWC3_GUSB2PHYCFG_SUSPHY)) { + susphy = true; + reg &= ~DWC3_GUSB2PHYCFG_SUSPHY; + dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg); + } } if (cmd == DWC3_DEPCMD_STARTTRANSFER) { -- cgit v0.10.2 From 9cad39fe4e4a4fe95d8ea5a7b0692b0a6e89e38b Mon Sep 17 00:00:00 2001 From: Konrad Leszczynski Date: Mon, 8 Feb 2016 16:13:12 +0100 Subject: usb: dwc3: fix for the isoc transfer EP_BUSY flag commit f3af36511e60 ("usb: dwc3: gadget: always enable IOC on bulk/interrupt transfers") ended up regressing Isochronous endpoints by clearing DWC3_EP_BUSY flag too early, which resulted in choppy audio playback over USB. Fix that by partially reverting original commit and making sure that we check for isochronous endpoints. Fixes: f3af36511e60 ("usb: dwc3: gadget: always enable IOC on bulk/interrupt transfers") Cc: Signed-off-by: Konrad Leszczynski Signed-off-by: Rafal Redzimski Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 5e7b2ba..867adc9 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -2058,6 +2058,10 @@ static int dwc3_cleanup_done_reqs(struct dwc3 *dwc, struct dwc3_ep *dep, return 1; } + if (usb_endpoint_xfer_isoc(dep->endpoint.desc)) + if ((event->status & DEPEVT_STATUS_IOC) && + (trb->ctrl & DWC3_TRB_CTRL_IOC)) + return 0; return 1; } -- cgit v0.10.2 From 4cb4221764ef473cd36e1953f1fea11865786d65 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Wed, 18 May 2016 12:37:21 +0300 Subject: usb: dwc3: gadget: fix for possible endpoint disable race when we call dwc3_gadget_giveback(), we end up releasing our controller's lock. Another thread could get scheduled and disable the endpoint, subsequently setting dep->endpoint.desc to NULL. In that case, we would end up dereferencing a NULL pointer which would result in a Kernel Oops. Let's avoid the problem by simply returning early if we have a NULL descriptor. Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 867adc9..b59893c 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -2041,6 +2041,14 @@ static int dwc3_cleanup_done_reqs(struct dwc3 *dwc, struct dwc3_ep *dep, break; } while (1); + /* + * Our endpoint might get disabled by another thread during + * dwc3_gadget_giveback(). If that happens, we're just gonna return 1 + * early on so DWC3_EP_BUSY flag gets cleared + */ + if (!dep->endpoint.desc) + return 1; + if (usb_endpoint_xfer_isoc(dep->endpoint.desc) && list_empty(&dep->started_list)) { if (list_empty(&dep->pending_list)) { @@ -2078,7 +2086,7 @@ static void dwc3_endpoint_transfer_complete(struct dwc3 *dwc, status = -ECONNRESET; clean_busy = dwc3_cleanup_done_reqs(dwc, dep, event, status); - if (clean_busy && (is_xfer_complete || + if (clean_busy && (!dep->endpoint.desc || is_xfer_complete || usb_endpoint_xfer_isoc(dep->endpoint.desc))) dep->flags &= ~DWC3_EP_BUSY; @@ -2107,6 +2115,14 @@ static void dwc3_endpoint_transfer_complete(struct dwc3 *dwc, dwc->u1u2 = 0; } + /* + * Our endpoint might get disabled by another thread during + * dwc3_gadget_giveback(). If that happens, we're just gonna return 1 + * early on so DWC3_EP_BUSY flag gets cleared + */ + if (!dep->endpoint.desc) + return; + if (!usb_endpoint_xfer_isoc(dep->endpoint.desc)) { int ret; -- cgit v0.10.2 From fc8bb91bc83ef82868533e75f5a11abc1158ec81 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Mon, 16 May 2016 13:14:48 +0300 Subject: usb: dwc3: implement runtime PM this patch implements the most basic pm_runtime support for dwc3. Whenever USB cable is dettached, then we will allow core to runtime_suspend. Runtime suspending will involve completely tearing down event buffers and require a full soft-reset of the IP. Note that a further optimization could be implemented once we decide to support hibernation, which is to allow runtime_suspend with cable connected when bus is in U3. That's subject to a separate patch, however. Tested-by: Baolin Wang Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index 80e9aff..bf1789f 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -48,7 +48,7 @@ #include "debug.h" -/* -------------------------------------------------------------------------- */ +#define DWC3_DEFAULT_AUTOSUSPEND_DELAY 5000 /* ms */ void dwc3_set_mode(struct dwc3 *dwc, u32 mode) { @@ -996,6 +996,9 @@ static int dwc3_probe(struct platform_device *pdev) dma_set_coherent_mask(dev, dev->parent->coherent_dma_mask); } + pm_runtime_set_active(dev); + pm_runtime_use_autosuspend(dev); + pm_runtime_set_autosuspend_delay(dev, DWC3_DEFAULT_AUTOSUSPEND_DELAY); pm_runtime_enable(dev); pm_runtime_get_sync(dev); pm_runtime_forbid(dev); @@ -1057,7 +1060,7 @@ static int dwc3_probe(struct platform_device *pdev) goto err3; dwc3_debugfs_init(dwc); - pm_runtime_allow(dev); + pm_runtime_put(dev); return 0; @@ -1087,6 +1090,7 @@ static int dwc3_remove(struct platform_device *pdev) struct dwc3 *dwc = platform_get_drvdata(pdev); struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + pm_runtime_get_sync(&pdev->dev); /* * restore res->start back to its original value so that, in case the * probe is deferred, we don't end up getting error in request the @@ -1100,24 +1104,27 @@ static int dwc3_remove(struct platform_device *pdev) dwc3_core_exit(dwc); dwc3_ulpi_exit(dwc); - dwc3_free_event_buffers(dwc); - dwc3_free_scratch_buffers(dwc); - pm_runtime_put_sync(&pdev->dev); + pm_runtime_allow(&pdev->dev); pm_runtime_disable(&pdev->dev); + dwc3_free_event_buffers(dwc); + dwc3_free_scratch_buffers(dwc); + return 0; } -#ifdef CONFIG_PM_SLEEP -static int dwc3_suspend(struct device *dev) +#ifdef CONFIG_PM +static int dwc3_suspend_common(struct dwc3 *dwc) { - struct dwc3 *dwc = dev_get_drvdata(dev); + unsigned long flags; switch (dwc->dr_mode) { case USB_DR_MODE_PERIPHERAL: case USB_DR_MODE_OTG: + spin_lock_irqsave(&dwc->lock, flags); dwc3_gadget_suspend(dwc); + spin_unlock_irqrestore(&dwc->lock, flags); break; case USB_DR_MODE_HOST: default: @@ -1127,18 +1134,14 @@ static int dwc3_suspend(struct device *dev) dwc3_core_exit(dwc); - pinctrl_pm_select_sleep_state(dev); - return 0; } -static int dwc3_resume(struct device *dev) +static int dwc3_resume_common(struct dwc3 *dwc) { - struct dwc3 *dwc = dev_get_drvdata(dev); + unsigned long flags; int ret; - pinctrl_pm_select_default_state(dev); - ret = dwc3_core_init(dwc); if (ret) return ret; @@ -1146,7 +1149,9 @@ static int dwc3_resume(struct device *dev) switch (dwc->dr_mode) { case USB_DR_MODE_PERIPHERAL: case USB_DR_MODE_OTG: + spin_lock_irqsave(&dwc->lock, flags); dwc3_gadget_resume(dwc); + spin_unlock_irqrestore(&dwc->lock, flags); /* FALLTHROUGH */ case USB_DR_MODE_HOST: default: @@ -1154,6 +1159,119 @@ static int dwc3_resume(struct device *dev) break; } + return 0; +} + +static int dwc3_runtime_checks(struct dwc3 *dwc) +{ + switch (dwc->dr_mode) { + case USB_DR_MODE_PERIPHERAL: + case USB_DR_MODE_OTG: + if (dwc->connected) + return -EBUSY; + break; + case USB_DR_MODE_HOST: + default: + /* do nothing */ + break; + } + + return 0; +} + +static int dwc3_runtime_suspend(struct device *dev) +{ + struct dwc3 *dwc = dev_get_drvdata(dev); + int ret; + + if (dwc3_runtime_checks(dwc)) + return -EBUSY; + + ret = dwc3_suspend_common(dwc); + if (ret) + return ret; + + device_init_wakeup(dev, true); + + return 0; +} + +static int dwc3_runtime_resume(struct device *dev) +{ + struct dwc3 *dwc = dev_get_drvdata(dev); + int ret; + + device_init_wakeup(dev, false); + + ret = dwc3_resume_common(dwc); + if (ret) + return ret; + + switch (dwc->dr_mode) { + case USB_DR_MODE_PERIPHERAL: + case USB_DR_MODE_OTG: + dwc3_gadget_process_pending_events(dwc); + break; + case USB_DR_MODE_HOST: + default: + /* do nothing */ + break; + } + + pm_runtime_mark_last_busy(dev); + + return 0; +} + +static int dwc3_runtime_idle(struct device *dev) +{ + struct dwc3 *dwc = dev_get_drvdata(dev); + + switch (dwc->dr_mode) { + case USB_DR_MODE_PERIPHERAL: + case USB_DR_MODE_OTG: + if (dwc3_runtime_checks(dwc)) + return -EBUSY; + break; + case USB_DR_MODE_HOST: + default: + /* do nothing */ + break; + } + + pm_runtime_mark_last_busy(dev); + pm_runtime_autosuspend(dev); + + return 0; +} +#endif /* CONFIG_PM */ + +#ifdef CONFIG_PM_SLEEP +static int dwc3_suspend(struct device *dev) +{ + struct dwc3 *dwc = dev_get_drvdata(dev); + int ret; + + ret = dwc3_suspend_common(dwc); + if (ret) + return ret; + + pinctrl_pm_select_sleep_state(dev); + + return 0; +} + +static int dwc3_resume(struct device *dev) +{ + struct dwc3 *dwc = dev_get_drvdata(dev); + int ret; + + pinctrl_pm_select_default_state(dev); + + ret = dwc3_resume_common(dwc); + if (ret) + return ret; + pm_runtime_disable(dev); pm_runtime_set_active(dev); pm_runtime_enable(dev); @@ -1164,6 +1282,8 @@ static int dwc3_resume(struct device *dev) static const struct dev_pm_ops dwc3_dev_pm_ops = { SET_SYSTEM_SLEEP_PM_OPS(dwc3_suspend, dwc3_resume) + SET_RUNTIME_PM_OPS(dwc3_runtime_suspend, dwc3_runtime_resume, + dwc3_runtime_idle) }; #ifdef CONFIG_OF diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index 5148c56..94b9fd2 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -763,6 +763,7 @@ struct dwc3_scratchpad_array { * @lpm_nyet_threshold: LPM NYET response threshold * @hird_threshold: HIRD threshold * @hsphy_interface: "utmi" or "ulpi" + * @connected: true when we're connected to a host, false otherwise * @delayed_status: true when gadget driver asks for delayed status * @ep0_bounced: true when we used bounce buffer * @ep0_expect_in: true when we expect a DATA IN transfer @@ -773,6 +774,7 @@ struct dwc3_scratchpad_array { * 0 - utmi_sleep_n * 1 - utmi_l1_suspend_n * @is_fpga: true when we are using the FPGA board + * @pending_events: true when we have pending IRQs to be handled * @pullups_connected: true when Run/Stop bit is set * @setup_packet_pending: true when there's a Setup Packet in FIFO. Workaround * @start_config_issued: true when StartConfig command has been issued @@ -907,6 +909,7 @@ struct dwc3 { const char *hsphy_interface; + unsigned connected:1; unsigned delayed_status:1; unsigned ep0_bounced:1; unsigned ep0_expect_in:1; @@ -914,6 +917,7 @@ struct dwc3 { unsigned has_lpm_erratum:1; unsigned is_utmi_l1_suspend:1; unsigned is_fpga:1; + unsigned pending_events:1; unsigned pullups_connected:1; unsigned setup_packet_pending:1; unsigned three_stage_setup:1; @@ -1139,6 +1143,7 @@ static inline int dwc3_send_gadget_generic_command(struct dwc3 *dwc, #if !IS_ENABLED(CONFIG_USB_DWC3_HOST) int dwc3_gadget_suspend(struct dwc3 *dwc); int dwc3_gadget_resume(struct dwc3 *dwc); +void dwc3_gadget_process_pending_events(struct dwc3 *dwc); #else static inline int dwc3_gadget_suspend(struct dwc3 *dwc) { @@ -1149,6 +1154,10 @@ static inline int dwc3_gadget_resume(struct dwc3 *dwc) { return 0; } + +static inline void dwc3_gadget_process_pending_events(struct dwc3 *dwc) +{ +} #endif /* !IS_ENABLED(CONFIG_USB_DWC3_HOST) */ #if IS_ENABLED(CONFIG_USB_DWC3_ULPI) diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index b59893c..1947751 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -199,6 +199,9 @@ void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req, spin_unlock(&dwc->lock); usb_gadget_giveback_request(&dep->endpoint, &req->request); spin_lock(&dwc->lock); + + if (dep->number > 1) + pm_runtime_put(dwc->dev); } int dwc3_send_gadget_generic_command(struct dwc3 *dwc, unsigned cmd, u32 param) @@ -1081,6 +1084,8 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req) return -EINVAL; } + pm_runtime_get(dwc->dev); + req->request.actual = 0; req->request.status = -EINPROGRESS; req->direction = dep->direction; @@ -1509,6 +1514,9 @@ static int dwc3_gadget_run_stop(struct dwc3 *dwc, int is_on, int suspend) u32 reg; u32 timeout = 500; + if (pm_runtime_suspended(dwc->dev)) + return 0; + reg = dwc3_readl(dwc->regs, DWC3_DCTL); if (is_on) { if (dwc->revision <= DWC3_REVISION_187A) { @@ -1766,7 +1774,9 @@ static int dwc3_gadget_start(struct usb_gadget *g, dwc->gadget_driver = driver; - __dwc3_gadget_start(dwc); + if (pm_runtime_active(dwc->dev)) + __dwc3_gadget_start(dwc); + spin_unlock_irqrestore(&dwc->lock, flags); return 0; @@ -2355,12 +2365,16 @@ static void dwc3_gadget_disconnect_interrupt(struct dwc3 *dwc) dwc->gadget.speed = USB_SPEED_UNKNOWN; dwc->setup_packet_pending = false; usb_gadget_set_state(&dwc->gadget, USB_STATE_NOTATTACHED); + + dwc->connected = false; } static void dwc3_gadget_reset_interrupt(struct dwc3 *dwc) { u32 reg; + dwc->connected = true; + /* * WORKAROUND: DWC3 revisions <1.88a have an issue which * would cause a missing Disconnect Event if there's a @@ -2822,6 +2836,13 @@ static irqreturn_t dwc3_check_event_buf(struct dwc3_event_buffer *evt) u32 count; u32 reg; + if (pm_runtime_suspended(dwc->dev)) { + pm_runtime_get(dwc->dev); + disable_irq_nosync(dwc->irq_gadget); + dwc->pending_events = true; + return IRQ_HANDLED; + } + count = dwc3_readl(dwc->regs, DWC3_GEVNTCOUNT(0)); count &= DWC3_GEVNTCOUNT_MASK; if (!count) @@ -3028,3 +3049,12 @@ err1: err0: return ret; } + +void dwc3_gadget_process_pending_events(struct dwc3 *dwc) +{ + if (dwc->pending_events) { + dwc3_interrupt(dwc->irq_gadget, dwc->ev_buf); + dwc->pending_events = false; + enable_irq(dwc->irq_gadget); + } +} -- cgit v0.10.2 From e9af9229098d92145d0b894b78878bbc6ac7c910 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Tue, 17 May 2016 10:15:02 +0300 Subject: usb: dwc3: pci: add Power Management dummy hooks Allow for dwc3-pci to reach D3 and enable pm_runtime by providing dummy PM hooks. Without them, PCI subsystem won't put device to D3. Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc3/dwc3-pci.c b/drivers/usb/dwc3/dwc3-pci.c index 14196cd..a7b6a1c 100644 --- a/drivers/usb/dwc3/dwc3-pci.c +++ b/drivers/usb/dwc3/dwc3-pci.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -180,7 +181,11 @@ static int dwc3_pci_probe(struct pci_dev *pci, goto err; } + device_init_wakeup(dev, true); + device_set_run_wake(dev, true); pci_set_drvdata(pci, dwc3); + pm_runtime_put(dev); + return 0; err: platform_device_put(dwc3); @@ -189,6 +194,8 @@ err: static void dwc3_pci_remove(struct pci_dev *pci) { + device_init_wakeup(&pci->dev, false); + pm_runtime_get(&pci->dev); acpi_dev_remove_driver_gpios(ACPI_COMPANION(&pci->dev)); platform_device_unregister(pci_get_drvdata(pci)); } @@ -219,11 +226,43 @@ static const struct pci_device_id dwc3_pci_id_table[] = { }; MODULE_DEVICE_TABLE(pci, dwc3_pci_id_table); +#ifdef CONFIG_PM +static int dwc3_pci_runtime_suspend(struct device *dev) +{ + if (device_run_wake(dev)) + return 0; + + return -EBUSY; +} + +static int dwc3_pci_pm_dummy(struct device *dev) +{ + /* + * There's nothing to do here. No, seriously. Everything is either taken + * care either by PCI subsystem or dwc3/core.c, so we have nothing + * missing here. + * + * So you'd think we didn't need this at all, but PCI subsystem will + * bail out if we don't have a valid callback :-s + */ + return 0; +} +#endif /* CONFIG_PM */ + +static struct dev_pm_ops dwc3_pci_dev_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(dwc3_pci_pm_dummy, dwc3_pci_pm_dummy) + SET_RUNTIME_PM_OPS(dwc3_pci_runtime_suspend, dwc3_pci_pm_dummy, + NULL) +}; + static struct pci_driver dwc3_pci_driver = { .name = "dwc3-pci", .id_table = dwc3_pci_id_table, .probe = dwc3_pci_probe, .remove = dwc3_pci_remove, + .driver = { + .pm = &dwc3_pci_dev_pm_ops, + } }; MODULE_AUTHOR("Felipe Balbi "); -- cgit v0.10.2 From 74674cbf858ff6a83c3f06f4ab0ffa5d3c91bf0b Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Wed, 13 Apr 2016 16:44:39 +0300 Subject: usb: dwc3: gadget: add a per-endpoint request queue lock This will allow us to process several endpoints at a time by making sure that we lock only shared resources. Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index 94b9fd2..484bb5d 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -482,6 +482,7 @@ struct dwc3_event_buffer { * @endpoint: usb endpoint * @pending_list: list of pending requests for this endpoint * @started_list: list of started requests on this endpoint + * @lock: spinlock for endpoint request queue traversal * @regs: pointer to first endpoint register * @trb_pool: array of transaction buffers * @trb_pool_dma: dma address of @trb_pool @@ -504,6 +505,7 @@ struct dwc3_ep { struct list_head pending_list; struct list_head started_list; + spinlock_t lock; void __iomem *regs; struct dwc3_trb *trb_pool; diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 1947751..8b93203 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -1845,6 +1845,7 @@ static int dwc3_gadget_init_hw_endpoints(struct dwc3 *dwc, (epnum & 1) ? "in" : "out"); dep->endpoint.name = dep->name; + spin_lock_init(&dep->lock); dwc3_trace(trace_dwc3_gadget, "initializing %s", dep->name); -- cgit v0.10.2 From 22f2c619a116f120fe57de1225cfe7fdeb0b12d2 Mon Sep 17 00:00:00 2001 From: Janusz Dziedzic Date: Fri, 20 May 2016 10:37:13 +0200 Subject: usb: dwc3: trace: pretty-print TRB's ctrl field Improve trb tracing by showing trb flags, interrupts trb type. trb flags: - h - hardware owner of descriptor - l - last TRB - c - chain buffers - s - continue on short packet interrupt flags: - s - interrupt on short packet - c - interrupt on complete Capital letter means that bit is set, while lowercase letter means bit is cleared. Signed-off-by: Janusz Dziedzic Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc3/trace.h b/drivers/usb/dwc3/trace.h index 3ac7252..8cbe1fc 100644 --- a/drivers/usb/dwc3/trace.h +++ b/drivers/usb/dwc3/trace.h @@ -237,9 +237,45 @@ DECLARE_EVENT_CLASS(dwc3_log_trb, __entry->size = trb->size; __entry->ctrl = trb->ctrl; ), - TP_printk("%s: trb %p bph %08x bpl %08x size %08x ctrl %08x", + TP_printk("%s: trb %p buf %08x%08x size %d ctrl %08x (%c%c%c%c:%c%c:%s)", __get_str(name), __entry->trb, __entry->bph, __entry->bpl, - __entry->size, __entry->ctrl + __entry->size, __entry->ctrl, + __entry->ctrl & DWC3_TRB_CTRL_HWO ? 'H' : 'h', + __entry->ctrl & DWC3_TRB_CTRL_LST ? 'L' : 'l', + __entry->ctrl & DWC3_TRB_CTRL_CHN ? 'C' : 'c', + __entry->ctrl & DWC3_TRB_CTRL_CSP ? 'S' : 's', + __entry->ctrl & DWC3_TRB_CTRL_ISP_IMI ? 'S' : 's', + __entry->ctrl & DWC3_TRB_CTRL_IOC ? 'C' : 'c', + ({char *s; + switch (__entry->ctrl & 0x3f0) { + case DWC3_TRBCTL_NORMAL: + s = "normal"; + break; + case DWC3_TRBCTL_CONTROL_SETUP: + s = "setup"; + break; + case DWC3_TRBCTL_CONTROL_STATUS2: + s = "status2"; + break; + case DWC3_TRBCTL_CONTROL_STATUS3: + s = "status3"; + break; + case DWC3_TRBCTL_CONTROL_DATA: + s = "data"; + break; + case DWC3_TRBCTL_ISOCHRONOUS_FIRST: + s = "isoc-first"; + break; + case DWC3_TRBCTL_ISOCHRONOUS: + s = "isoc"; + break; + case DWC3_TRBCTL_LINK_TRB: + s = "link"; + break; + default: + s = "UNKNOWN"; + break; + } s; }) ) ); -- cgit v0.10.2 From 7ab373aadbd0463c0f020d368947b05e67a20bd5 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Mon, 23 May 2016 11:27:26 +0300 Subject: usb: dwc3: gadget: no more tracking endpoint type with its name I really thought this would be useful, but as it turns out, it creates more problems than fixes. The amount of times we had to fix this because some other commit shuffled things around and ended up regressing this tiny little string manupulation... Might as well remove it, since it has a negligible added benefit. Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 8b93203..0581815 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -591,7 +591,7 @@ static int __dwc3_gadget_ep_enable(struct dwc3_ep *dep, dwc3_writel(dwc->regs, DWC3_DALEPENA, reg); if (usb_endpoint_xfer_control(desc)) - goto out; + return 0; /* Link TRB. The HWO bit is never reset */ trb_st_hw = &dep->trb_pool[0]; @@ -605,24 +605,6 @@ static int __dwc3_gadget_ep_enable(struct dwc3_ep *dep, trb_link->ctrl |= DWC3_TRB_CTRL_HWO; } -out: - switch (usb_endpoint_type(desc)) { - case USB_ENDPOINT_XFER_CONTROL: - /* don't change name */ - break; - case USB_ENDPOINT_XFER_ISOC: - strlcat(dep->name, "-isoc", sizeof(dep->name)); - break; - case USB_ENDPOINT_XFER_BULK: - strlcat(dep->name, "-bulk", sizeof(dep->name)); - break; - case USB_ENDPOINT_XFER_INT: - strlcat(dep->name, "-int", sizeof(dep->name)); - break; - default: - dev_err(dwc->dev, "invalid endpoint transfer type\n"); - } - return 0; } @@ -680,10 +662,6 @@ static int __dwc3_gadget_ep_disable(struct dwc3_ep *dep) dep->type = 0; dep->flags = 0; - snprintf(dep->name, sizeof(dep->name), "ep%d%s", - dep->number >> 1, - (dep->number & 1) ? "in" : "out"); - return 0; } -- cgit v0.10.2 From f75cacc468edc4826305909d6102d60fba55199f Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Mon, 23 May 2016 11:10:08 +0300 Subject: usb: dwc3: trace: fully decode IRQ events This will make it more human-friendly to read trace output from dwc3. Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc3/debug.h b/drivers/usb/dwc3/debug.h index 71e3180..e3e0b41 100644 --- a/drivers/usb/dwc3/debug.h +++ b/drivers/usb/dwc3/debug.h @@ -128,56 +128,112 @@ dwc3_gadget_link_string(enum dwc3_link_state link_state) * dwc3_gadget_event_string - returns event name * @event: the event code */ -static inline const char *dwc3_gadget_event_string(u8 event) +static inline const char * +dwc3_gadget_event_string(const struct dwc3_event_devt *event) { - switch (event) { + static char str[256]; + enum dwc3_link_state state = event->event_info & DWC3_LINK_STATE_MASK; + + switch (event->type) { case DWC3_DEVICE_EVENT_DISCONNECT: - return "Disconnect"; + sprintf(str, "Disconnect: [%s]", + dwc3_gadget_link_string(state)); + break; case DWC3_DEVICE_EVENT_RESET: - return "Reset"; + sprintf(str, "Reset [%s]", dwc3_gadget_link_string(state)); + break; case DWC3_DEVICE_EVENT_CONNECT_DONE: - return "Connection Done"; + sprintf(str, "Connection Done [%s]", + dwc3_gadget_link_string(state)); + break; case DWC3_DEVICE_EVENT_LINK_STATUS_CHANGE: - return "Link Status Change"; + sprintf(str, "Link Change [%s]", + dwc3_gadget_link_string(state)); + break; case DWC3_DEVICE_EVENT_WAKEUP: - return "WakeUp"; + sprintf(str, "WakeUp [%s]", dwc3_gadget_link_string(state)); + break; case DWC3_DEVICE_EVENT_EOPF: - return "End-Of-Frame"; + sprintf(str, "End-Of-Frame [%s]", + dwc3_gadget_link_string(state)); + break; case DWC3_DEVICE_EVENT_SOF: - return "Start-Of-Frame"; + sprintf(str, "Start-Of-Frame [%s]", + dwc3_gadget_link_string(state)); + break; case DWC3_DEVICE_EVENT_ERRATIC_ERROR: - return "Erratic Error"; + sprintf(str, "Erratic Error [%s]", + dwc3_gadget_link_string(state)); + break; case DWC3_DEVICE_EVENT_CMD_CMPL: - return "Command Complete"; + sprintf(str, "Command Complete [%s]", + dwc3_gadget_link_string(state)); + break; case DWC3_DEVICE_EVENT_OVERFLOW: - return "Overflow"; + sprintf(str, "Overflow [%s]", dwc3_gadget_link_string(state)); + break; + default: + sprintf(str, "UNKNOWN"); } - return "UNKNOWN"; + return str; } /** * dwc3_ep_event_string - returns event name * @event: then event code */ -static inline const char *dwc3_ep_event_string(u8 event) +static inline const char * +dwc3_ep_event_string(const struct dwc3_event_depevt *event) { - switch (event) { + u8 epnum = event->endpoint_number; + static char str[256]; + int status; + int ret; + + ret = sprintf(str, "ep%d%s: ", epnum >> 1, + (epnum & 1) ? "in" : "in"); + if (ret < 0) + return "UNKNOWN"; + + switch (event->endpoint_event) { case DWC3_DEPEVT_XFERCOMPLETE: - return "Transfer Complete"; + strcat(str, "Transfer Complete"); + break; case DWC3_DEPEVT_XFERINPROGRESS: - return "Transfer In-Progress"; + strcat(str, "Transfer In-Progress"); + break; case DWC3_DEPEVT_XFERNOTREADY: - return "Transfer Not Ready"; + strcat(str, "Transfer Not Ready"); + status = event->status & DEPEVT_STATUS_TRANSFER_ACTIVE; + strcat(str, status ? " (Active)" : " (Not Active)"); + break; case DWC3_DEPEVT_RXTXFIFOEVT: - return "FIFO"; + strcat(str, "FIFO"); + break; case DWC3_DEPEVT_STREAMEVT: - return "Stream"; + status = event->status; + + switch (status) { + case DEPEVT_STREAMEVT_FOUND: + sprintf(str + ret, " Stream %d Found", + event->parameters); + break; + case DEPEVT_STREAMEVT_NOTFOUND: + default: + strcat(str, " Stream Not Found"); + break; + } + + break; case DWC3_DEPEVT_EPCMDCMPLT: - return "Endpoint Command Complete"; + strcat(str, "Endpoint Command Complete"); + break; + default: + sprintf(str, "UNKNOWN"); } - return "UNKNOWN"; + return str; } /** @@ -214,6 +270,16 @@ static inline const char *dwc3_gadget_event_type_string(u8 event) } } +static inline const char *dwc3_decode_event(u32 event) +{ + const union dwc3_event evt = (union dwc3_event) event; + + if (evt.type.is_devspec) + return dwc3_gadget_event_string(&evt.devt); + else + return dwc3_ep_event_string(&evt.depevt); +} + void dwc3_trace(void (*trace)(struct va_format *), const char *fmt, ...); #ifdef CONFIG_DEBUG_FS diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c index 3103a8f..54628c3 100644 --- a/drivers/usb/dwc3/ep0.c +++ b/drivers/usb/dwc3/ep0.c @@ -1109,11 +1109,8 @@ static void dwc3_ep0_xfernotready(struct dwc3 *dwc, void dwc3_ep0_interrupt(struct dwc3 *dwc, const struct dwc3_event_depevt *event) { - u8 epnum = event->endpoint_number; - - dwc3_trace(trace_dwc3_ep0, "%s while ep%d%s in state '%s'", - dwc3_ep_event_string(event->endpoint_event), - epnum >> 1, (epnum & 1) ? "in" : "out", + dwc3_trace(trace_dwc3_ep0, "%s: state '%s'", + dwc3_ep_event_string(event), dwc3_ep0_state_string(dwc->ep0state)); switch (event->endpoint_event) { diff --git a/drivers/usb/dwc3/trace.h b/drivers/usb/dwc3/trace.h index 8cbe1fc..2389dd8 100644 --- a/drivers/usb/dwc3/trace.h +++ b/drivers/usb/dwc3/trace.h @@ -71,7 +71,8 @@ DECLARE_EVENT_CLASS(dwc3_log_event, TP_fast_assign( __entry->event = event; ), - TP_printk("event %08x", __entry->event) + TP_printk("event (%08x): %s", __entry->event, + dwc3_decode_event(__entry->event)) ); DEFINE_EVENT(dwc3_log_event, dwc3_event, -- cgit v0.10.2 From ba1598410eff646e10be4e42d773e5bdc511d898 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Mon, 23 May 2016 13:50:29 +0300 Subject: usb: dwc3: gadget: fix trace output when command fails We don't need the extra %s when command fails. Let's remove it Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 0581815..e553a7c 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -303,7 +303,7 @@ int dwc3_send_gadget_ep_cmd(struct dwc3_ep *dep, unsigned cmd, ret = 0; break; case DEPEVT_TRANSFER_NO_RESOURCE: - dwc3_trace(trace_dwc3_gadget, "%s: no resource available"); + dwc3_trace(trace_dwc3_gadget, "no resource available"); ret = -EINVAL; break; case DEPEVT_TRANSFER_BUS_EXPIRY: @@ -318,7 +318,7 @@ int dwc3_send_gadget_ep_cmd(struct dwc3_ep *dep, unsigned cmd, * give a hint to the gadget driver that this is * the case by returning -EAGAIN. */ - dwc3_trace(trace_dwc3_gadget, "%s: bus expiry"); + dwc3_trace(trace_dwc3_gadget, "bus expiry"); ret = -EAGAIN; break; default: -- cgit v0.10.2 From f6bb225bb3ca7988ff373c62cc298e56cae1eee5 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Mon, 23 May 2016 13:53:34 +0300 Subject: usb: dwc3: gadget: loop while (timeout) instead of having infinite loop and always checking timeout value as a break condition, we can just decrement timeout inside while's condition. Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index e553a7c..25170fd 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -327,19 +327,13 @@ int dwc3_send_gadget_ep_cmd(struct dwc3_ep *dep, unsigned cmd, break; } + } while (--timeout); - /* - * We can't sleep here, because it is also called from - * interrupt context. - */ - timeout--; - if (!timeout) { - dwc3_trace(trace_dwc3_gadget, - "Command Timed Out"); - ret = -ETIMEDOUT; - break; - } - } while (1); + if (timeout == 0) { + dwc3_trace(trace_dwc3_gadget, + "Command Timed Out"); + ret = -ETIMEDOUT; + } if (unlikely(susphy)) { reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0)); -- cgit v0.10.2 From 0933df159c5c82f97c6bb811b149fa1158a26087 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Mon, 23 May 2016 14:02:33 +0300 Subject: usb: dwc3: trace: print ep cmd status with a single trace Instead of printing command's status with a separate trace printout, let's print it within a single call. Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc3/debug.h b/drivers/usb/dwc3/debug.h index e3e0b41..8eed4c7 100644 --- a/drivers/usb/dwc3/debug.h +++ b/drivers/usb/dwc3/debug.h @@ -280,6 +280,22 @@ static inline const char *dwc3_decode_event(u32 event) return dwc3_ep_event_string(&evt.depevt); } +static inline const char *dwc3_ep_cmd_status_string(int status) +{ + switch (status) { + case -ETIMEDOUT: + return "Timed Out"; + case 0: + return "Successful"; + case DEPEVT_TRANSFER_NO_RESOURCE: + return "No Resource"; + case DEPEVT_TRANSFER_BUS_EXPIRY: + return "Bus Expiry"; + default: + return "UNKNOWN"; + } +} + void dwc3_trace(void (*trace)(struct va_format *), const char *fmt, ...); #ifdef CONFIG_DEBUG_FS diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 25170fd..42eefd7 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -248,11 +248,10 @@ int dwc3_send_gadget_ep_cmd(struct dwc3_ep *dep, unsigned cmd, u32 timeout = 500; u32 reg; + int cmd_status = 0; int susphy = false; int ret = -EINVAL; - trace_dwc3_gadget_ep_cmd(dep, cmd, params); - /* * Synopsys Databook 2.60a states, on section 6.3.2.5.[1-8], that if * we're issuing an endpoint command, we must check if @@ -292,7 +291,7 @@ int dwc3_send_gadget_ep_cmd(struct dwc3_ep *dep, unsigned cmd, do { reg = dwc3_readl(dep->regs, DWC3_DEPCMD); if (!(reg & DWC3_DEPCMD_CMDACT)) { - int cmd_status = DWC3_DEPCMD_STATUS(reg); + cmd_status = DWC3_DEPCMD_STATUS(reg); dwc3_trace(trace_dwc3_gadget, "Command Complete --> %d", @@ -333,8 +332,11 @@ int dwc3_send_gadget_ep_cmd(struct dwc3_ep *dep, unsigned cmd, dwc3_trace(trace_dwc3_gadget, "Command Timed Out"); ret = -ETIMEDOUT; + cmd_status = -ETIMEDOUT; } + trace_dwc3_gadget_ep_cmd(dep, cmd, params, cmd_status); + if (unlikely(susphy)) { reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0)); reg |= DWC3_GUSB2PHYCFG_SUSPHY; diff --git a/drivers/usb/dwc3/trace.h b/drivers/usb/dwc3/trace.h index 2389dd8..040f28b 100644 --- a/drivers/usb/dwc3/trace.h +++ b/drivers/usb/dwc3/trace.h @@ -190,14 +190,15 @@ DEFINE_EVENT(dwc3_log_generic_cmd, dwc3_gadget_generic_cmd, DECLARE_EVENT_CLASS(dwc3_log_gadget_ep_cmd, TP_PROTO(struct dwc3_ep *dep, unsigned int cmd, - struct dwc3_gadget_ep_cmd_params *params), - TP_ARGS(dep, cmd, params), + struct dwc3_gadget_ep_cmd_params *params, int cmd_status), + TP_ARGS(dep, cmd, params, cmd_status), TP_STRUCT__entry( __dynamic_array(char, name, DWC3_MSG_MAX) __field(unsigned int, cmd) __field(u32, param0) __field(u32, param1) __field(u32, param2) + __field(int, cmd_status) ), TP_fast_assign( snprintf(__get_str(name), DWC3_MSG_MAX, "%s", dep->name); @@ -205,18 +206,20 @@ DECLARE_EVENT_CLASS(dwc3_log_gadget_ep_cmd, __entry->param0 = params->param0; __entry->param1 = params->param1; __entry->param2 = params->param2; + __entry->cmd_status = cmd_status; ), - TP_printk("%s: cmd '%s' [%d] params %08x %08x %08x", + TP_printk("%s: cmd '%s' [%d] params %08x %08x %08x --> status: %s", __get_str(name), dwc3_gadget_ep_cmd_string(__entry->cmd), __entry->cmd, __entry->param0, - __entry->param1, __entry->param2 + __entry->param1, __entry->param2, + dwc3_ep_cmd_status_string(__entry->cmd_status) ) ); DEFINE_EVENT(dwc3_log_gadget_ep_cmd, dwc3_gadget_ep_cmd, TP_PROTO(struct dwc3_ep *dep, unsigned int cmd, - struct dwc3_gadget_ep_cmd_params *params), - TP_ARGS(dep, cmd, params) + struct dwc3_gadget_ep_cmd_params *params, int cmd_status), + TP_ARGS(dep, cmd, params, cmd_status) ); DECLARE_EVENT_CLASS(dwc3_log_trb, -- cgit v0.10.2 From 0fe886cdb07aeaf75a61154f34abc8dd6860978e Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Mon, 23 May 2016 14:06:07 +0300 Subject: usb: dwc3: gadget: single return point on generic commands Just like we did for endpoint commands, let's use a single return point for generic commands as well. This aids readability. Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 42eefd7..f148b11 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -207,6 +207,7 @@ void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req, int dwc3_send_gadget_generic_command(struct dwc3 *dwc, unsigned cmd, u32 param) { u32 timeout = 500; + int ret = 0; u32 reg; trace_dwc3_gadget_generic_cmd(cmd, param); @@ -221,22 +222,20 @@ int dwc3_send_gadget_generic_command(struct dwc3 *dwc, unsigned cmd, u32 param) "Command Complete --> %d", DWC3_DGCMD_STATUS(reg)); if (DWC3_DGCMD_STATUS(reg)) - return -EINVAL; - return 0; + ret = -EINVAL; + break; } - /* - * We can't sleep here, because it's also called from - * interrupt context. - */ - timeout--; - if (!timeout) { - dwc3_trace(trace_dwc3_gadget, - "Command Timed Out"); - return -ETIMEDOUT; - } udelay(1); - } while (1); + } while (timeout--); + + if (!timeout) { + dwc3_trace(trace_dwc3_gadget, + "Command Timed Out"); + ret = -ETIMEDOUT; + } + + return ret; } static int __dwc3_gadget_wakeup(struct dwc3 *dwc); -- cgit v0.10.2 From 88811f7b722c417ececbc7f278c26d8df8606d02 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Mon, 23 May 2016 14:08:47 +0300 Subject: usb: dwc3: gadget: remove udelay() from generic cmd We want commands to finish ASAP, so let's remove that udelay() call. Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index f148b11..609acd7 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -225,8 +225,6 @@ int dwc3_send_gadget_generic_command(struct dwc3 *dwc, unsigned cmd, u32 param) ret = -EINVAL; break; } - - udelay(1); } while (timeout--); if (!timeout) { -- cgit v0.10.2 From 71f7e7027028d5a8ef15dccc587dbd6c6b7f544f Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Mon, 23 May 2016 14:16:19 +0300 Subject: usb: dwc3: gadget: improve gcmd trace Just like we did for endpoint commands, let's have a single trace output for the command and its status. This will improve trace readability Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc3/debug.h b/drivers/usb/dwc3/debug.h index 8eed4c7..22dfc3d 100644 --- a/drivers/usb/dwc3/debug.h +++ b/drivers/usb/dwc3/debug.h @@ -296,6 +296,20 @@ static inline const char *dwc3_ep_cmd_status_string(int status) } } +static inline const char *dwc3_gadget_generic_cmd_status_string(int status) +{ + switch (status) { + case -ETIMEDOUT: + return "Timed Out"; + case 0: + return "Successful"; + case 1: + return "Error"; + default: + return "UNKNOWN"; + } +} + void dwc3_trace(void (*trace)(struct va_format *), const char *fmt, ...); #ifdef CONFIG_DEBUG_FS diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 609acd7..6a18b3d 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -207,32 +207,30 @@ void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req, int dwc3_send_gadget_generic_command(struct dwc3 *dwc, unsigned cmd, u32 param) { u32 timeout = 500; + int status = 0; int ret = 0; u32 reg; - trace_dwc3_gadget_generic_cmd(cmd, param); - dwc3_writel(dwc->regs, DWC3_DGCMDPAR, param); dwc3_writel(dwc->regs, DWC3_DGCMD, cmd | DWC3_DGCMD_CMDACT); do { reg = dwc3_readl(dwc->regs, DWC3_DGCMD); if (!(reg & DWC3_DGCMD_CMDACT)) { - dwc3_trace(trace_dwc3_gadget, - "Command Complete --> %d", - DWC3_DGCMD_STATUS(reg)); - if (DWC3_DGCMD_STATUS(reg)) + status = DWC3_DGCMD_STATUS(reg); + if (status) ret = -EINVAL; break; } } while (timeout--); if (!timeout) { - dwc3_trace(trace_dwc3_gadget, - "Command Timed Out"); ret = -ETIMEDOUT; + status = -ETIMEDOUT; } + trace_dwc3_gadget_generic_cmd(cmd, param, status); + return ret; } diff --git a/drivers/usb/dwc3/trace.h b/drivers/usb/dwc3/trace.h index 040f28b..f43f9eb 100644 --- a/drivers/usb/dwc3/trace.h +++ b/drivers/usb/dwc3/trace.h @@ -167,25 +167,28 @@ DEFINE_EVENT(dwc3_log_request, dwc3_gadget_giveback, ); DECLARE_EVENT_CLASS(dwc3_log_generic_cmd, - TP_PROTO(unsigned int cmd, u32 param), - TP_ARGS(cmd, param), + TP_PROTO(unsigned int cmd, u32 param, int status), + TP_ARGS(cmd, param, status), TP_STRUCT__entry( __field(unsigned int, cmd) __field(u32, param) + __field(int, status) ), TP_fast_assign( __entry->cmd = cmd; __entry->param = param; + __entry->status = status; ), - TP_printk("cmd '%s' [%d] param %08x", + TP_printk("cmd '%s' [%d] param %08x --> status: %s", dwc3_gadget_generic_cmd_string(__entry->cmd), - __entry->cmd, __entry->param + __entry->cmd, __entry->param, + dwc3_gadget_generic_cmd_status_string(__entry->status) ) ); DEFINE_EVENT(dwc3_log_generic_cmd, dwc3_gadget_generic_cmd, - TP_PROTO(unsigned int cmd, u32 param), - TP_ARGS(cmd, param) + TP_PROTO(unsigned int cmd, u32 param, int status), + TP_ARGS(cmd, param, status) ); DECLARE_EVENT_CLASS(dwc3_log_gadget_ep_cmd, -- cgit v0.10.2 From 958b9fa7f8cfd5799534e98ba3d05d96a5e7ccb9 Mon Sep 17 00:00:00 2001 From: John Youn Date: Mon, 23 May 2016 11:32:38 -0700 Subject: usb: dwc3: ep0: Fix endianness of wIndex passed to dwc3_wIndex_to_dep The wIndex passed in here is CPU endianness, but the function expects little endian. Found with sparse. Signed-off-by: John Youn Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c index 54628c3..c814dde 100644 --- a/drivers/usb/dwc3/ep0.c +++ b/drivers/usb/dwc3/ep0.c @@ -496,7 +496,7 @@ static int dwc3_ep0_handle_feature(struct dwc3 *dwc, case USB_RECIP_ENDPOINT: switch (wValue) { case USB_ENDPOINT_HALT: - dep = dwc3_wIndex_to_dep(dwc, wIndex); + dep = dwc3_wIndex_to_dep(dwc, ctrl->wIndex); if (!dep) return -EINVAL; if (set == 0 && (dep->flags & DWC3_EP_WEDGE)) -- cgit v0.10.2 From 501058edebf957a3c101c8119c3286e496873840 Mon Sep 17 00:00:00 2001 From: John Youn Date: Mon, 23 May 2016 11:32:40 -0700 Subject: usb: dwc3: ep0: Use the correct type for SET_SEL data u2sel and u2pel should be __le16. Doesn't fix any issue. Found with sparse. Signed-off-by: John Youn Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c index c814dde..93d6cdd 100644 --- a/drivers/usb/dwc3/ep0.c +++ b/drivers/usb/dwc3/ep0.c @@ -619,8 +619,8 @@ static void dwc3_ep0_set_sel_cmpl(struct usb_ep *ep, struct usb_request *req) struct timing { u8 u1sel; u8 u1pel; - u16 u2sel; - u16 u2pel; + __le16 u2sel; + __le16 u2pel; } __packed timing; int ret; -- cgit v0.10.2 From d07fa665c79d85fead080f4b611c3f7645576454 Mon Sep 17 00:00:00 2001 From: John Youn Date: Mon, 23 May 2016 11:32:43 -0700 Subject: usb: dwc3: gadget: Fix usage of bitwise operator Cleans up the sparse warning: warning: dubious: x | !y Since we do want a bitwise OR here, don't use a logical (true/false) value. Probably is not a real issue but it cleans up the warning. Signed-off-by: John Youn Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 6a18b3d..f38db3b 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -1798,7 +1798,7 @@ static int dwc3_gadget_init_hw_endpoints(struct dwc3 *dwc, u8 i; for (i = 0; i < num; i++) { - u8 epnum = (i << 1) | (!!direction); + u8 epnum = (i << 1) | (direction ? 1 : 0); dep = kzalloc(sizeof(*dep), GFP_KERNEL); if (!dep) -- cgit v0.10.2 From 96bedb637a1e1ad8e7ed781fa020550aae2a8f16 Mon Sep 17 00:00:00 2001 From: John Youn Date: Mon, 23 May 2016 11:32:47 -0700 Subject: usb: dwc3: Endianness issue on dwc3_log_ctrl Sparse complains even though it looks ok. Probably it cannot detect that the wValue, wIndex, and wLength are declared __le16 due to the macro magic. Redeclare them as CPU endianness and make the conversion on assignment. Signed-off-by: John Youn Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc3/trace.h b/drivers/usb/dwc3/trace.h index f43f9eb..cafd69f 100644 --- a/drivers/usb/dwc3/trace.h +++ b/drivers/usb/dwc3/trace.h @@ -86,21 +86,21 @@ DECLARE_EVENT_CLASS(dwc3_log_ctrl, TP_STRUCT__entry( __field(__u8, bRequestType) __field(__u8, bRequest) - __field(__le16, wValue) - __field(__le16, wIndex) - __field(__le16, wLength) + __field(__u16, wValue) + __field(__u16, wIndex) + __field(__u16, wLength) ), TP_fast_assign( __entry->bRequestType = ctrl->bRequestType; __entry->bRequest = ctrl->bRequest; - __entry->wValue = ctrl->wValue; - __entry->wIndex = ctrl->wIndex; - __entry->wLength = ctrl->wLength; + __entry->wValue = le16_to_cpu(ctrl->wValue); + __entry->wIndex = le16_to_cpu(ctrl->wIndex); + __entry->wLength = le16_to_cpu(ctrl->wLength); ), TP_printk("bRequestType %02x bRequest %02x wValue %04x wIndex %04x wLength %d", __entry->bRequestType, __entry->bRequest, - le16_to_cpu(__entry->wValue), le16_to_cpu(__entry->wIndex), - le16_to_cpu(__entry->wLength) + __entry->wValue, __entry->wIndex, + __entry->wLength ) ); -- cgit v0.10.2 From dca0119c3ab69fea2429ec2db7e3686614bd1439 Mon Sep 17 00:00:00 2001 From: John Youn Date: Thu, 19 May 2016 17:26:05 -0700 Subject: usb: dwc3: gadget: Simplify skipping of link TRBs Make the skipping of the link TRBS built-in to the increment operation. This simplifies the code wherever we increment the trb index and ensures that we never end up pointing to a link trb. Signed-off-by: John Youn Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index f38db3b..24bb942 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -145,21 +145,29 @@ int dwc3_gadget_set_link_state(struct dwc3 *dwc, enum dwc3_link_state state) return -ETIMEDOUT; } -static void dwc3_ep_inc_enq(struct dwc3_ep *dep) +/** + * dwc3_ep_inc_trb() - Increment a TRB index. + * @index - Pointer to the TRB index to increment. + * + * The index should never point to the link TRB. After incrementing, + * if it is point to the link TRB, wrap around to the beginning. The + * link TRB is always at the last TRB entry. + */ +static void dwc3_ep_inc_trb(u8 *index) { - dep->trb_enqueue++; - dep->trb_enqueue %= DWC3_TRB_NUM; + (*index)++; + if (*index == (DWC3_TRB_NUM - 1)) + *index = 0; } -static void dwc3_ep_inc_deq(struct dwc3_ep *dep) +static void dwc3_ep_inc_enq(struct dwc3_ep *dep) { - dep->trb_dequeue++; - dep->trb_dequeue %= DWC3_TRB_NUM; + dwc3_ep_inc_trb(&dep->trb_enqueue); } -static int dwc3_ep_is_last_trb(unsigned int index) +static void dwc3_ep_inc_deq(struct dwc3_ep *dep) { - return index == DWC3_TRB_NUM - 1; + dwc3_ep_inc_trb(&dep->trb_dequeue); } void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req, @@ -172,13 +180,6 @@ void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req, i = 0; do { dwc3_ep_inc_deq(dep); - /* - * Skip LINK TRB. We can't use req->trb and check for - * DWC3_TRBCTL_LINK_TRB because it points the TRB we - * just completed (not the LINK TRB). - */ - if (dwc3_ep_is_last_trb(dep->trb_dequeue)) - dwc3_ep_inc_deq(dep); } while(++i < req->request.num_mapped_sgs); req->started = false; } @@ -785,9 +786,6 @@ static void dwc3_prepare_one_trb(struct dwc3_ep *dep, } dwc3_ep_inc_enq(dep); - /* Skip the LINK-TRB */ - if (dwc3_ep_is_last_trb(dep->trb_enqueue)) - dwc3_ep_inc_enq(dep); trb->size = DWC3_TRB_SIZE_LENGTH(length); trb->bpl = lower_32_bits(dma); -- cgit v0.10.2 From 0d25744ad107b6c9010153f3ebf8b59672b5b8e7 Mon Sep 17 00:00:00 2001 From: John Youn Date: Thu, 19 May 2016 17:26:08 -0700 Subject: usb: dwc3: gadget: Initialize the TRB ring Clears out all the TRBs in the ring to clean up any stale data that might be in them from the previous time the endpoint was enabled. Also removed the existing clear of the LINK trb since the entire ring is cleard just before. Signed-off-by: John Youn Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 24bb942..6408f7f 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -585,12 +585,16 @@ static int __dwc3_gadget_ep_enable(struct dwc3_ep *dep, if (usb_endpoint_xfer_control(desc)) return 0; + /* Initialize the TRB ring */ + dep->trb_dequeue = 0; + dep->trb_enqueue = 0; + memset(dep->trb_pool, 0, + sizeof(struct dwc3_trb) * DWC3_TRB_NUM); + /* Link TRB. The HWO bit is never reset */ trb_st_hw = &dep->trb_pool[0]; trb_link = &dep->trb_pool[DWC3_TRB_NUM - 1]; - memset(trb_link, 0, sizeof(*trb_link)); - trb_link->bpl = lower_32_bits(dwc3_trb_dma_offset(dep, trb_st_hw)); trb_link->bph = upper_32_bits(dwc3_trb_dma_offset(dep, trb_st_hw)); trb_link->ctrl |= DWC3_TRBCTL_LINK_TRB; -- cgit v0.10.2 From 89bc856e5a7462e47d90d5a3f5396bd5795efd0c Mon Sep 17 00:00:00 2001 From: John Youn Date: Thu, 19 May 2016 17:26:10 -0700 Subject: usb: dwc3: gadget: Don't prepare TRBs if no space If trbs_left == 0, we don't have any space left in the TRB ring so don't prepare anything. Signed-off-by: John Youn Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 6408f7f..663ea9e 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -942,6 +942,8 @@ static void dwc3_prepare_trbs(struct dwc3_ep *dep) BUILD_BUG_ON_NOT_POWER_OF_2(DWC3_TRB_NUM); trbs_left = dwc3_calc_trbs_left(dep); + if (!trbs_left) + return; list_for_each_entry_safe(req, n, &dep->pending_list, list) { if (req->request.num_mapped_sgs > 0) -- cgit v0.10.2 From 32db3d9437b6bd560daeef82a8325436a4ac3366 Mon Sep 17 00:00:00 2001 From: John Youn Date: Thu, 19 May 2016 17:26:12 -0700 Subject: usb: dwc3: gadget: Account for max size in TRB space The current calculation takes dep->trb_dequeue - dep->trb_enqueue to find the TRB space left. If you enqueue 1, that results in: (u8) 0 - (u8) 1 = 0xff = 255 TRBs left. This is correct if DWC3_TRB_NUM == 256. If DWC3_TRB_NUM is less than 256 (but still a power of 2) you need to mod the result by DWC3_TRB_NUM. For example the same calculation with DWC3_TRB_NUM = 8, results in: 255 % 6 = 7 TRBs left. Signed-off-by: John Youn Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 663ea9e..4dea3e0 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -845,6 +845,7 @@ static void dwc3_prepare_one_trb(struct dwc3_ep *dep, static u32 dwc3_calc_trbs_left(struct dwc3_ep *dep) { struct dwc3_trb *tmp; + u8 trbs_left; /* * If enqueue & dequeue are equal than it is either full or empty. @@ -864,7 +865,10 @@ static u32 dwc3_calc_trbs_left(struct dwc3_ep *dep) return DWC3_TRB_NUM - 1; } - return dep->trb_dequeue - dep->trb_enqueue; + trbs_left = dep->trb_dequeue - dep->trb_enqueue; + trbs_left %= DWC3_TRB_NUM; + + return trbs_left; } static void dwc3_prepare_one_trb_sg(struct dwc3_ep *dep, -- cgit v0.10.2 From 7d0a038b130cde7265d6bbc5e148734cb127f341 Mon Sep 17 00:00:00 2001 From: John Youn Date: Thu, 19 May 2016 17:26:15 -0700 Subject: usb: dwc3: gadget: Account for link TRB in TRBs left The TRBs left calculation didn't account for the link TRB taking up one spot. If the trb_dequeue < trb_enqueue, then the result includes the link TRB slot so it must be adjusted. Signed-off-by: John Youn Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 4dea3e0..3c4fd48 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -868,6 +868,9 @@ static u32 dwc3_calc_trbs_left(struct dwc3_ep *dep) trbs_left = dep->trb_dequeue - dep->trb_enqueue; trbs_left %= DWC3_TRB_NUM; + if (dep->trb_dequeue < dep->trb_enqueue) + trbs_left--; + return trbs_left; } -- cgit v0.10.2 From 361572b5f7a95b341a92d34b9bf41f71bbdae34d Mon Sep 17 00:00:00 2001 From: John Youn Date: Thu, 19 May 2016 17:26:17 -0700 Subject: usb: dwc3: gadget: Handle TRB index 0 when full or empty If the trb->enqueue == trb->dequeue, then it could be full or empty. This could also happen at TRB index 0, so modify the check to handle that condition. At index 0, the previous TRB is the one just before the link TRB. Signed-off-by: John Youn Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 3c4fd48..fbc7968 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -842,6 +842,25 @@ static void dwc3_prepare_one_trb(struct dwc3_ep *dep, trace_dwc3_prepare_trb(dep, trb); } +/** + * dwc3_ep_prev_trb() - Returns the previous TRB in the ring + * @dep: The endpoint with the TRB ring + * @index: The index of the current TRB in the ring + * + * Returns the TRB prior to the one pointed to by the index. If the + * index is 0, we will wrap backwards, skip the link TRB, and return + * the one just before that. + */ +static struct dwc3_trb *dwc3_ep_prev_trb(struct dwc3_ep *dep, u8 index) +{ + if (!index) + index = DWC3_TRB_NUM - 2; + else + index = dep->trb_enqueue - 1; + + return &dep->trb_pool[index]; +} + static u32 dwc3_calc_trbs_left(struct dwc3_ep *dep) { struct dwc3_trb *tmp; @@ -855,12 +874,9 @@ static u32 dwc3_calc_trbs_left(struct dwc3_ep *dep) * more transfers in our ring. */ if (dep->trb_enqueue == dep->trb_dequeue) { - /* If we're full, enqueue/dequeue are > 0 */ - if (dep->trb_enqueue) { - tmp = &dep->trb_pool[dep->trb_enqueue - 1]; - if (tmp->ctrl & DWC3_TRB_CTRL_HWO) - return 0; - } + tmp = dwc3_ep_prev_trb(dep, dep->trb_enqueue); + if (tmp->ctrl & DWC3_TRB_CTRL_HWO) + return 0; return DWC3_TRB_NUM - 1; } -- cgit v0.10.2 From 3de2685f0c395a56b909dbefd40fb287c9df31b2 Mon Sep 17 00:00:00 2001 From: John Youn Date: Mon, 23 May 2016 11:32:45 -0700 Subject: usb: dwc3: gadget: Fix truncated cast issue From sparse: warning: cast truncates bits from constant value (100 becomes 0) The DWC3_TRB_NUM constant is too big for u8. Do the calculation a slightly different way that should still be optimized out for the case where DWC3_TRB_NUM == 256. Signed-off-by: John Youn Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index fbc7968..d0f7458 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -882,7 +882,7 @@ static u32 dwc3_calc_trbs_left(struct dwc3_ep *dep) } trbs_left = dep->trb_dequeue - dep->trb_enqueue; - trbs_left %= DWC3_TRB_NUM; + trbs_left &= (DWC3_TRB_NUM - 1); if (dep->trb_dequeue < dep->trb_enqueue) trbs_left--; -- cgit v0.10.2 From 2da9ad761e70c6a22e3a84f9a3e67faeef122a58 Mon Sep 17 00:00:00 2001 From: John Youn Date: Fri, 20 May 2016 16:34:26 -0700 Subject: usb: dwc3: Use the correct speed macros for DSTS/DCFG Correct the use of the DWC3_DSTS_XXX_SPEED and DWC3_DCFG_XXX_SPEED macros. The wrong set of macros were being used in a few places. This is only a cosmetic change as the values for both sets are identical. Signed-off-by: John Youn Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index d0f7458..0c11fd6 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -1672,16 +1672,16 @@ static int __dwc3_gadget_start(struct dwc3 *dwc) } else { switch (dwc->maximum_speed) { case USB_SPEED_LOW: - reg |= DWC3_DSTS_LOWSPEED; + reg |= DWC3_DCFG_LOWSPEED; break; case USB_SPEED_FULL: - reg |= DWC3_DSTS_FULLSPEED1; + reg |= DWC3_DCFG_FULLSPEED1; break; case USB_SPEED_HIGH: - reg |= DWC3_DSTS_HIGHSPEED; + reg |= DWC3_DCFG_HIGHSPEED; break; case USB_SPEED_SUPER_PLUS: - reg |= DWC3_DSTS_SUPERSPEED_PLUS; + reg |= DWC3_DCFG_SUPERSPEED_PLUS; break; default: dev_err(dwc->dev, "invalid dwc->maximum_speed (%d)\n", @@ -2459,12 +2459,12 @@ static void dwc3_gadget_conndone_interrupt(struct dwc3 *dwc) dwc3_update_ram_clk_sel(dwc, speed); switch (speed) { - case DWC3_DCFG_SUPERSPEED_PLUS: + case DWC3_DSTS_SUPERSPEED_PLUS: dwc3_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(512); dwc->gadget.ep0->maxpacket = 512; dwc->gadget.speed = USB_SPEED_SUPER_PLUS; break; - case DWC3_DCFG_SUPERSPEED: + case DWC3_DSTS_SUPERSPEED: /* * WORKAROUND: DWC3 revisions <1.90a have an issue which * would cause a missing USB3 Reset event. @@ -2485,18 +2485,18 @@ static void dwc3_gadget_conndone_interrupt(struct dwc3 *dwc) dwc->gadget.ep0->maxpacket = 512; dwc->gadget.speed = USB_SPEED_SUPER; break; - case DWC3_DCFG_HIGHSPEED: + case DWC3_DSTS_HIGHSPEED: dwc3_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(64); dwc->gadget.ep0->maxpacket = 64; dwc->gadget.speed = USB_SPEED_HIGH; break; - case DWC3_DCFG_FULLSPEED2: - case DWC3_DCFG_FULLSPEED1: + case DWC3_DSTS_FULLSPEED2: + case DWC3_DSTS_FULLSPEED1: dwc3_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(64); dwc->gadget.ep0->maxpacket = 64; dwc->gadget.speed = USB_SPEED_FULL; break; - case DWC3_DCFG_LOWSPEED: + case DWC3_DSTS_LOWSPEED: dwc3_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(8); dwc->gadget.ep0->maxpacket = 8; dwc->gadget.speed = USB_SPEED_LOW; @@ -2506,8 +2506,8 @@ static void dwc3_gadget_conndone_interrupt(struct dwc3 *dwc) /* Enable USB2 LPM Capability */ if ((dwc->revision > DWC3_REVISION_194A) && - (speed != DWC3_DCFG_SUPERSPEED) && - (speed != DWC3_DCFG_SUPERSPEED_PLUS)) { + (speed != DWC3_DSTS_SUPERSPEED) && + (speed != DWC3_DSTS_SUPERSPEED_PLUS)) { reg = dwc3_readl(dwc->regs, DWC3_DCFG); reg |= DWC3_DCFG_LPM_CAP; dwc3_writel(dwc->regs, DWC3_DCFG, reg); -- cgit v0.10.2 From e77c561432bccf5ea9df2f49aa039c015529590e Mon Sep 17 00:00:00 2001 From: John Youn Date: Fri, 20 May 2016 16:34:23 -0700 Subject: usb: dwc3: Fix DWC3_USB31_REVISION_110A definition The DWC3_USB31_REVISION_110A macro uses an invalid constant name in its definition. This is currently not used. Signed-off-by: John Youn Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index 484bb5d..243e7a1 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -881,7 +881,7 @@ struct dwc3 { * just so dwc31 revisions are always larger than dwc3. */ #define DWC3_REVISION_IS_DWC31 0x80000000 -#define DWC3_USB31_REVISION_110A (0x3131302a | DWC3_REVISION_IS_USB31) +#define DWC3_USB31_REVISION_110A (0x3131302a | DWC3_REVISION_IS_DWC31) enum dwc3_ep0_next ep0_next_event; enum dwc3_ep0_state ep0state; -- cgit v0.10.2 From 475c8beb35e129c2f33182f476373db04008892e Mon Sep 17 00:00:00 2001 From: William Wu Date: Fri, 13 May 2016 18:13:46 +0800 Subject: usb: dwc3: add DWC3_GUCTL1 reg for debug GUCTL1 reg has some useful functions which can be written by user. For rockchip platform, we set GUCTL1.DEV_FORCE_20_CLK_FOR_30_CLK (bit26, applicable for the core is programmed to operate in 2.0 device only) to 1 in bootrom, and after start the kernel, we want to check whether this bit can be reset to default 0 after the core reset. Dump GUCTL1 reg from debugfs is more convenient for us. Signed-off-by: William Wu Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index 243e7a1..dcdba14 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -86,6 +86,7 @@ #define DWC3_GCTL 0xc110 #define DWC3_GEVTEN 0xc114 #define DWC3_GSTS 0xc118 +#define DWC3_GUCTL1 0xc11c #define DWC3_GSNPSID 0xc120 #define DWC3_GGPIO 0xc124 #define DWC3_GUID 0xc128 diff --git a/drivers/usb/dwc3/debugfs.c b/drivers/usb/dwc3/debugfs.c index 89c26e0..31926dd 100644 --- a/drivers/usb/dwc3/debugfs.c +++ b/drivers/usb/dwc3/debugfs.c @@ -70,6 +70,7 @@ static const struct debugfs_reg32 dwc3_regs[] = { dump_register(GCTL), dump_register(GEVTEN), dump_register(GSTS), + dump_register(GUCTL1), dump_register(GSNPSID), dump_register(GGPIO), dump_register(GUID), -- cgit v0.10.2 From 3f586c92d87778bc3d550435a31f8ac685541121 Mon Sep 17 00:00:00 2001 From: Roger Quadros Date: Wed, 11 May 2016 17:36:42 +0300 Subject: usb: dwc3: omap: use request_threaded_irq() We intend to share this interrupt with the OTG driver an to ensure that irqflags match for the shared interrupt handlers we use request_threaded_irq() If we don't use request_treaded_irq() then forced threaded irq will set IRQF_ONESHOT and this won't match with the OTG IRQ handler's IRQ flags. NOTE: OTG IRQ handler is yet to be added. This is a preparatory step. Signed-off-by: Roger Quadros Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc3/dwc3-omap.c b/drivers/usb/dwc3/dwc3-omap.c index af26449..0142544 100644 --- a/drivers/usb/dwc3/dwc3-omap.c +++ b/drivers/usb/dwc3/dwc3-omap.c @@ -165,7 +165,7 @@ static void dwc3_omap_write_utmi_ctrl(struct dwc3_omap *omap, u32 value) static u32 dwc3_omap_read_irq0_status(struct dwc3_omap *omap) { - return dwc3_omap_readl(omap->base, USBOTGSS_IRQSTATUS_0 - + return dwc3_omap_readl(omap->base, USBOTGSS_IRQSTATUS_RAW_0 - omap->irq0_offset); } @@ -178,7 +178,7 @@ static void dwc3_omap_write_irq0_status(struct dwc3_omap *omap, u32 value) static u32 dwc3_omap_read_irqmisc_status(struct dwc3_omap *omap) { - return dwc3_omap_readl(omap->base, USBOTGSS_IRQSTATUS_MISC + + return dwc3_omap_readl(omap->base, USBOTGSS_IRQSTATUS_RAW_MISC + omap->irqmisc_offset); } @@ -268,19 +268,38 @@ static void dwc3_omap_set_mailbox(struct dwc3_omap *omap, } } +static void dwc3_omap_enable_irqs(struct dwc3_omap *omap); +static void dwc3_omap_disable_irqs(struct dwc3_omap *omap); + static irqreturn_t dwc3_omap_interrupt(int irq, void *_omap) { struct dwc3_omap *omap = _omap; + + if (dwc3_omap_read_irqmisc_status(omap) || + dwc3_omap_read_irq0_status(omap)) { + /* mask irqs */ + dwc3_omap_disable_irqs(omap); + return IRQ_WAKE_THREAD; + } + + return IRQ_NONE; +} + +static irqreturn_t dwc3_omap_interrupt_thread(int irq, void *_omap) +{ + struct dwc3_omap *omap = _omap; u32 reg; + /* clear irq status flags */ reg = dwc3_omap_read_irqmisc_status(omap); - dwc3_omap_write_irqmisc_status(omap, reg); reg = dwc3_omap_read_irq0_status(omap); - dwc3_omap_write_irq0_status(omap, reg); + /* unmask irqs */ + dwc3_omap_enable_irqs(omap); + return IRQ_HANDLED; } @@ -497,8 +516,9 @@ static int dwc3_omap_probe(struct platform_device *pdev) /* check the DMA Status */ reg = dwc3_omap_readl(omap->base, USBOTGSS_SYSCONFIG); - ret = devm_request_irq(dev, omap->irq, dwc3_omap_interrupt, 0, - "dwc3-omap", omap); + ret = devm_request_threaded_irq(dev, omap->irq, dwc3_omap_interrupt, + dwc3_omap_interrupt_thread, 0, + "dwc3-omap", omap); if (ret) { dev_err(dev, "failed to request IRQ #%d --> %d\n", omap->irq, ret); -- cgit v0.10.2 From 12da8eae208d6f388c3aeecb91955c8b5a468654 Mon Sep 17 00:00:00 2001 From: Roger Quadros Date: Wed, 11 May 2016 17:36:43 +0300 Subject: usb: dwc3: omap: Mark the interrupt handler as shared On OMAPs, OTG events come on the same IRQ so we need to share this IRQ with the OTG device driver. Signed-off-by: Roger Quadros Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc3/dwc3-omap.c b/drivers/usb/dwc3/dwc3-omap.c index 0142544..bde69fc 100644 --- a/drivers/usb/dwc3/dwc3-omap.c +++ b/drivers/usb/dwc3/dwc3-omap.c @@ -517,7 +517,7 @@ static int dwc3_omap_probe(struct platform_device *pdev) reg = dwc3_omap_readl(omap->base, USBOTGSS_SYSCONFIG); ret = devm_request_threaded_irq(dev, omap->irq, dwc3_omap_interrupt, - dwc3_omap_interrupt_thread, 0, + dwc3_omap_interrupt_thread, IRQF_SHARED, "dwc3-omap", omap); if (ret) { dev_err(dev, "failed to request IRQ #%d --> %d\n", -- cgit v0.10.2 From 9ab330bf4dfd677a19d03359af9bc0e168a2c4b2 Mon Sep 17 00:00:00 2001 From: Roger Quadros Date: Wed, 11 May 2016 17:36:44 +0300 Subject: usb: dwc3: omap: Don't set POWERPRESENT TRM [1] recommends that POWERPRESENT bit must not be set and left at it's default value of 0. [1] OMAP542x TRM - http://www.ti.com/lit/pdf/swpu249 Section 23.11.4.5.1 Mailbox VBUS/ID Management "Because PIPE powerpresent has a different meaning in host and in device mode, and because of the redundancy with the UTMI signals, the controller ORes together the appropriate PIPE and UTMI inputs to create its internal VBUS status. For that reason, it is recommended to leave field USBOTGSS_UTMI_OTG_STATUS[9] POWERPRESENT at its default value (=0), and only to fill in the USB2 VBUS status fields in the same register." Signed-off-by: Roger Quadros Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc3/dwc3-omap.c b/drivers/usb/dwc3/dwc3-omap.c index bde69fc..046bb37 100644 --- a/drivers/usb/dwc3/dwc3-omap.c +++ b/drivers/usb/dwc3/dwc3-omap.c @@ -234,8 +234,7 @@ static void dwc3_omap_set_mailbox(struct dwc3_omap *omap, val &= ~(USBOTGSS_UTMI_OTG_CTRL_IDDIG | USBOTGSS_UTMI_OTG_CTRL_VBUSVALID | USBOTGSS_UTMI_OTG_CTRL_SESSEND); - val |= USBOTGSS_UTMI_OTG_CTRL_SESSVALID - | USBOTGSS_UTMI_OTG_CTRL_POWERPRESENT; + val |= USBOTGSS_UTMI_OTG_CTRL_SESSVALID; dwc3_omap_write_utmi_ctrl(omap, val); break; @@ -244,8 +243,7 @@ static void dwc3_omap_set_mailbox(struct dwc3_omap *omap, val &= ~USBOTGSS_UTMI_OTG_CTRL_SESSEND; val |= USBOTGSS_UTMI_OTG_CTRL_IDDIG | USBOTGSS_UTMI_OTG_CTRL_VBUSVALID - | USBOTGSS_UTMI_OTG_CTRL_SESSVALID - | USBOTGSS_UTMI_OTG_CTRL_POWERPRESENT; + | USBOTGSS_UTMI_OTG_CTRL_SESSVALID; dwc3_omap_write_utmi_ctrl(omap, val); break; @@ -256,8 +254,7 @@ static void dwc3_omap_set_mailbox(struct dwc3_omap *omap, case OMAP_DWC3_VBUS_OFF: val = dwc3_omap_read_utmi_ctrl(omap); val &= ~(USBOTGSS_UTMI_OTG_CTRL_SESSVALID - | USBOTGSS_UTMI_OTG_CTRL_VBUSVALID - | USBOTGSS_UTMI_OTG_CTRL_POWERPRESENT); + | USBOTGSS_UTMI_OTG_CTRL_VBUSVALID); val |= USBOTGSS_UTMI_OTG_CTRL_SESSEND | USBOTGSS_UTMI_OTG_CTRL_IDDIG; dwc3_omap_write_utmi_ctrl(omap, val); -- cgit v0.10.2 From d2728fb3e01f9265571a5f7a5feeac4493d2a365 Mon Sep 17 00:00:00 2001 From: Roger Quadros Date: Wed, 11 May 2016 17:36:45 +0300 Subject: usb: dwc3: omap: Pass VBUS and ID events transparently Don't make any decisions regarding VBUS session based on ID status. That is best left to the OTG core. Pass ID and VBUS events independent of each other so that OTG core knows exactly what to do. This makes dual-role with extcon work with OTG irq on OMAP platforms. Signed-off-by: Roger Quadros Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc3/dwc3-omap.c b/drivers/usb/dwc3/dwc3-omap.c index 046bb37..29e80cc 100644 --- a/drivers/usb/dwc3/dwc3-omap.c +++ b/drivers/usb/dwc3/dwc3-omap.c @@ -231,18 +231,14 @@ static void dwc3_omap_set_mailbox(struct dwc3_omap *omap, } val = dwc3_omap_read_utmi_ctrl(omap); - val &= ~(USBOTGSS_UTMI_OTG_CTRL_IDDIG - | USBOTGSS_UTMI_OTG_CTRL_VBUSVALID - | USBOTGSS_UTMI_OTG_CTRL_SESSEND); - val |= USBOTGSS_UTMI_OTG_CTRL_SESSVALID; + val &= ~USBOTGSS_UTMI_OTG_CTRL_IDDIG; dwc3_omap_write_utmi_ctrl(omap, val); break; case OMAP_DWC3_VBUS_VALID: val = dwc3_omap_read_utmi_ctrl(omap); val &= ~USBOTGSS_UTMI_OTG_CTRL_SESSEND; - val |= USBOTGSS_UTMI_OTG_CTRL_IDDIG - | USBOTGSS_UTMI_OTG_CTRL_VBUSVALID + val |= USBOTGSS_UTMI_OTG_CTRL_VBUSVALID | USBOTGSS_UTMI_OTG_CTRL_SESSVALID; dwc3_omap_write_utmi_ctrl(omap, val); break; @@ -250,13 +246,15 @@ static void dwc3_omap_set_mailbox(struct dwc3_omap *omap, case OMAP_DWC3_ID_FLOAT: if (omap->vbus_reg) regulator_disable(omap->vbus_reg); + val = dwc3_omap_read_utmi_ctrl(omap); + val |= USBOTGSS_UTMI_OTG_CTRL_IDDIG; + dwc3_omap_write_utmi_ctrl(omap, val); case OMAP_DWC3_VBUS_OFF: val = dwc3_omap_read_utmi_ctrl(omap); val &= ~(USBOTGSS_UTMI_OTG_CTRL_SESSVALID | USBOTGSS_UTMI_OTG_CTRL_VBUSVALID); - val |= USBOTGSS_UTMI_OTG_CTRL_SESSEND - | USBOTGSS_UTMI_OTG_CTRL_IDDIG; + val |= USBOTGSS_UTMI_OTG_CTRL_SESSEND; dwc3_omap_write_utmi_ctrl(omap, val); break; -- cgit v0.10.2 From 60cfb37ac9bc620334fff6e644a2b09019115939 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Tue, 24 May 2016 13:45:17 +0300 Subject: usb: dwc3: remove trailing newline from dwc3_trace when passing strings to trace, we don't need the trailing newline character. Trace already appends a newline character automatically. Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c index 93d6cdd..fe79d77 100644 --- a/drivers/usb/dwc3/ep0.c +++ b/drivers/usb/dwc3/ep0.c @@ -977,7 +977,7 @@ static void __dwc3_ep0_do_control_data(struct dwc3 *dwc, ret = usb_gadget_map_request(&dwc->gadget, &req->request, dep->number); if (ret) { - dwc3_trace(trace_dwc3_ep0, "failed to map request\n"); + dwc3_trace(trace_dwc3_ep0, "failed to map request"); return; } @@ -1005,7 +1005,7 @@ static void __dwc3_ep0_do_control_data(struct dwc3 *dwc, ret = usb_gadget_map_request(&dwc->gadget, &req->request, dep->number); if (ret) { - dwc3_trace(trace_dwc3_ep0, "failed to map request\n"); + dwc3_trace(trace_dwc3_ep0, "failed to map request"); return; } diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 0c11fd6..61edb665 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -289,16 +289,11 @@ int dwc3_send_gadget_ep_cmd(struct dwc3_ep *dep, unsigned cmd, if (!(reg & DWC3_DEPCMD_CMDACT)) { cmd_status = DWC3_DEPCMD_STATUS(reg); - dwc3_trace(trace_dwc3_gadget, - "Command Complete --> %d", - cmd_status); - switch (cmd_status) { case 0: ret = 0; break; case DEPEVT_TRANSFER_NO_RESOURCE: - dwc3_trace(trace_dwc3_gadget, "no resource available"); ret = -EINVAL; break; case DEPEVT_TRANSFER_BUS_EXPIRY: @@ -313,7 +308,6 @@ int dwc3_send_gadget_ep_cmd(struct dwc3_ep *dep, unsigned cmd, * give a hint to the gadget driver that this is * the case by returning -EAGAIN. */ - dwc3_trace(trace_dwc3_gadget, "bus expiry"); ret = -EAGAIN; break; default: @@ -325,8 +319,6 @@ int dwc3_send_gadget_ep_cmd(struct dwc3_ep *dep, unsigned cmd, } while (--timeout); if (timeout == 0) { - dwc3_trace(trace_dwc3_gadget, - "Command Timed Out"); ret = -ETIMEDOUT; cmd_status = -ETIMEDOUT; } @@ -1068,14 +1060,14 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req) if (!dep->endpoint.desc) { dwc3_trace(trace_dwc3_gadget, - "trying to queue request %p to disabled %s\n", + "trying to queue request %p to disabled %s", &req->request, dep->endpoint.name); return -ESHUTDOWN; } if (WARN(req->dep != dep, "request %p belongs to '%s'\n", &req->request, req->dep->name)) { - dwc3_trace(trace_dwc3_gadget, "request %p belongs to '%s'\n", + dwc3_trace(trace_dwc3_gadget, "request %p belongs to '%s'", &req->request, req->dep->name); return -EINVAL; } @@ -1179,7 +1171,7 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req) out: if (ret && ret != -EBUSY) dwc3_trace(trace_dwc3_gadget, - "%s: failed to kick transfers\n", + "%s: failed to kick transfers", dep->name); if (ret == -EBUSY) ret = 0; @@ -1199,7 +1191,7 @@ static int __dwc3_gadget_ep_queue_zlp(struct dwc3 *dwc, struct dwc3_ep *dep) struct usb_request *request; struct usb_ep *ep = &dep->endpoint; - dwc3_trace(trace_dwc3_gadget, "queueing ZLP\n"); + dwc3_trace(trace_dwc3_gadget, "queueing ZLP"); request = dwc3_gadget_ep_alloc_request(ep, GFP_ATOMIC); if (!request) return -ENOMEM; @@ -1429,7 +1421,7 @@ static int __dwc3_gadget_wakeup(struct dwc3 *dwc) speed = reg & DWC3_DSTS_CONNECTSPD; if ((speed == DWC3_DSTS_SUPERSPEED) || (speed == DWC3_DSTS_SUPERSPEED_PLUS)) { - dwc3_trace(trace_dwc3_gadget, "no wakeup on SuperSpeed\n"); + dwc3_trace(trace_dwc3_gadget, "no wakeup on SuperSpeed"); return 0; } @@ -1441,7 +1433,7 @@ static int __dwc3_gadget_wakeup(struct dwc3 *dwc) break; default: dwc3_trace(trace_dwc3_gadget, - "can't wakeup from '%s'\n", + "can't wakeup from '%s'", dwc3_gadget_link_string(link_state)); return -EINVAL; } @@ -1963,7 +1955,7 @@ static int __dwc3_cleanup_done_trbs(struct dwc3 *dwc, struct dwc3_ep *dep, trb_status = DWC3_TRB_SIZE_TRBSTS(trb->size); if (trb_status == DWC3_TRBSTS_MISSED_ISOC) { dwc3_trace(trace_dwc3_gadget, - "%s: incomplete IN transfer\n", + "%s: incomplete IN transfer", dep->name); /* * If missed isoc occurred and there is @@ -2161,7 +2153,7 @@ static void dwc3_endpoint_interrupt(struct dwc3 *dwc, if (usb_endpoint_xfer_isoc(dep->endpoint.desc)) { dwc3_trace(trace_dwc3_gadget, - "%s is an Isochronous endpoint\n", + "%s is an Isochronous endpoint", dep->name); return; } @@ -2189,7 +2181,7 @@ static void dwc3_endpoint_interrupt(struct dwc3 *dwc, return; dwc3_trace(trace_dwc3_gadget, - "%s: failed to kick transfers\n", + "%s: failed to kick transfers", dep->name); } @@ -2212,11 +2204,11 @@ static void dwc3_endpoint_interrupt(struct dwc3 *dwc, /* FALLTHROUGH */ default: dwc3_trace(trace_dwc3_gadget, - "unable to find suitable stream\n"); + "unable to find suitable stream"); } break; case DWC3_DEPEVT_RXTXFIFOEVT: - dwc3_trace(trace_dwc3_gadget, "%s FIFO Overrun\n", dep->name); + dwc3_trace(trace_dwc3_gadget, "%s FIFO Overrun", dep->name); break; case DWC3_DEPEVT_EPCMDCMPLT: dwc3_trace(trace_dwc3_gadget, "Endpoint Command Complete"); @@ -2934,7 +2926,7 @@ int dwc3_gadget_init(struct dwc3 *dwc) */ if (dwc->revision < DWC3_REVISION_220A) dwc3_trace(trace_dwc3_gadget, - "Changing max_speed on rev %08x\n", + "Changing max_speed on rev %08x", dwc->revision); dwc->gadget.max_speed = dwc->maximum_speed; -- cgit v0.10.2 From cf48305de0c6b556ff6af64e93295cc54c4fe246 Mon Sep 17 00:00:00 2001 From: Heikki Krogerus Date: Fri, 22 Apr 2016 11:17:39 +0300 Subject: usb: dwc3: pci: use build-in properties instead of platform data This should allow the core driver to drop handling of platform data and expect the platform specific details to always come from properties. Tested-by: John Youn Signed-off-by: Heikki Krogerus Cc: Huang Rui CC: John Youn Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc3/dwc3-pci.c b/drivers/usb/dwc3/dwc3-pci.c index a7b6a1c..6bc4c2b 100644 --- a/drivers/usb/dwc3/dwc3-pci.c +++ b/drivers/usb/dwc3/dwc3-pci.c @@ -24,8 +24,7 @@ #include #include #include - -#include "platform_data.h" +#include #define PCI_DEVICE_ID_SYNOPSYS_HAPSUSB3 0xabcd #define PCI_DEVICE_ID_SYNOPSYS_HAPSUSB3_AXI 0xabce @@ -52,33 +51,29 @@ static int dwc3_pci_quirks(struct pci_dev *pdev, struct platform_device *dwc3) { if (pdev->vendor == PCI_VENDOR_ID_AMD && pdev->device == PCI_DEVICE_ID_AMD_NL_USB) { - struct dwc3_platform_data pdata; - - memset(&pdata, 0, sizeof(pdata)); - - pdata.has_lpm_erratum = true; - pdata.lpm_nyet_threshold = 0xf; - - pdata.u2exit_lfps_quirk = true; - pdata.u2ss_inp3_quirk = true; - pdata.req_p1p2p3_quirk = true; - pdata.del_p1p2p3_quirk = true; - pdata.del_phy_power_chg_quirk = true; - pdata.lfps_filter_quirk = true; - pdata.rx_detect_poll_quirk = true; - - pdata.tx_de_emphasis_quirk = true; - pdata.tx_de_emphasis = 1; - - /* - * FIXME these quirks should be removed when AMD NL - * taps out - */ - pdata.disable_scramble_quirk = true; - pdata.dis_u3_susphy_quirk = true; - pdata.dis_u2_susphy_quirk = true; - - return platform_device_add_data(dwc3, &pdata, sizeof(pdata)); + struct property_entry properties[] = { + PROPERTY_ENTRY_BOOL("snps,has-lpm-erratum"), + PROPERTY_ENTRY_U8("snps,lpm-nyet-threshold", 0xf), + PROPERTY_ENTRY_BOOL("snps,u2exit_lfps_quirk"), + PROPERTY_ENTRY_BOOL("snps,u2ss_inp3_quirk"), + PROPERTY_ENTRY_BOOL("snps,req_p1p2p3_quirk"), + PROPERTY_ENTRY_BOOL("snps,del_p1p2p3_quirk"), + PROPERTY_ENTRY_BOOL("snps,del_phy_power_chg_quirk"), + PROPERTY_ENTRY_BOOL("snps,lfps_filter_quirk"), + PROPERTY_ENTRY_BOOL("snps,rx_detect_poll_quirk"), + PROPERTY_ENTRY_BOOL("snps,tx_de_emphasis_quirk"), + PROPERTY_ENTRY_U8("snps,tx_de_emphasis", 1), + /* + * FIXME these quirks should be removed when AMD NL + * tapes out + */ + PROPERTY_ENTRY_BOOL("snps,disable_scramble_quirk"), + PROPERTY_ENTRY_BOOL("snps,dis_u3_susphy_quirk"), + PROPERTY_ENTRY_BOOL("snps,dis_u2_susphy_quirk"), + { }, + }; + + return platform_device_add_properties(dwc3, properties); } if (pdev->vendor == PCI_VENDOR_ID_INTEL && @@ -115,15 +110,14 @@ static int dwc3_pci_quirks(struct pci_dev *pdev, struct platform_device *dwc3) (pdev->device == PCI_DEVICE_ID_SYNOPSYS_HAPSUSB3 || pdev->device == PCI_DEVICE_ID_SYNOPSYS_HAPSUSB3_AXI || pdev->device == PCI_DEVICE_ID_SYNOPSYS_HAPSUSB31)) { - - struct dwc3_platform_data pdata; - - memset(&pdata, 0, sizeof(pdata)); - pdata.usb3_lpm_capable = true; - pdata.has_lpm_erratum = true; - pdata.dis_enblslpm_quirk = true; - - return platform_device_add_data(dwc3, &pdata, sizeof(pdata)); + struct property_entry properties[] = { + PROPERTY_ENTRY_BOOL("snps,usb3_lpm_capable"), + PROPERTY_ENTRY_BOOL("snps,has-lpm-erratum"), + PROPERTY_ENTRY_BOOL("snps,dis_enblslpm_quirk"), + { }, + }; + + return platform_device_add_properties(dwc3, properties); } return 0; -- cgit v0.10.2 From d18e65470a4d9b6f7d7a72a0d102d009b45cf9d4 Mon Sep 17 00:00:00 2001 From: Heikki Krogerus Date: Fri, 22 Apr 2016 11:17:40 +0300 Subject: usb: dwc3: remove handling of platform data No more users for it. Tested-by: John Youn Signed-off-by: Heikki Krogerus Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index bf1789f..9c4e1d8d 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -41,7 +41,6 @@ #include #include -#include "platform_data.h" #include "core.h" #include "gadget.h" #include "io.h" @@ -825,7 +824,6 @@ static void dwc3_core_exit_mode(struct dwc3 *dwc) static int dwc3_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; - struct dwc3_platform_data *pdata = dev_get_platdata(dev); struct resource *res; struct dwc3 *dwc; u8 lpm_nyet_threshold; @@ -942,39 +940,6 @@ static int dwc3_probe(struct platform_device *pdev) device_property_read_u32(dev, "snps,quirk-frame-length-adjustment", &dwc->fladj); - if (pdata) { - dwc->maximum_speed = pdata->maximum_speed; - dwc->has_lpm_erratum = pdata->has_lpm_erratum; - if (pdata->lpm_nyet_threshold) - lpm_nyet_threshold = pdata->lpm_nyet_threshold; - dwc->is_utmi_l1_suspend = pdata->is_utmi_l1_suspend; - if (pdata->hird_threshold) - hird_threshold = pdata->hird_threshold; - - dwc->usb3_lpm_capable = pdata->usb3_lpm_capable; - dwc->dr_mode = pdata->dr_mode; - - dwc->disable_scramble_quirk = pdata->disable_scramble_quirk; - dwc->u2exit_lfps_quirk = pdata->u2exit_lfps_quirk; - dwc->u2ss_inp3_quirk = pdata->u2ss_inp3_quirk; - dwc->req_p1p2p3_quirk = pdata->req_p1p2p3_quirk; - dwc->del_p1p2p3_quirk = pdata->del_p1p2p3_quirk; - dwc->del_phy_power_chg_quirk = pdata->del_phy_power_chg_quirk; - dwc->lfps_filter_quirk = pdata->lfps_filter_quirk; - dwc->rx_detect_poll_quirk = pdata->rx_detect_poll_quirk; - dwc->dis_u3_susphy_quirk = pdata->dis_u3_susphy_quirk; - dwc->dis_u2_susphy_quirk = pdata->dis_u2_susphy_quirk; - dwc->dis_enblslpm_quirk = pdata->dis_enblslpm_quirk; - dwc->dis_rxdet_inp3_quirk = pdata->dis_rxdet_inp3_quirk; - - dwc->tx_de_emphasis_quirk = pdata->tx_de_emphasis_quirk; - if (pdata->tx_de_emphasis) - tx_de_emphasis = pdata->tx_de_emphasis; - - dwc->hsphy_interface = pdata->hsphy_interface; - dwc->fladj = pdata->fladj_value; - } - dwc->lpm_nyet_threshold = lpm_nyet_threshold; dwc->tx_de_emphasis = tx_de_emphasis; diff --git a/drivers/usb/dwc3/platform_data.h b/drivers/usb/dwc3/platform_data.h deleted file mode 100644 index 8826cca..0000000 --- a/drivers/usb/dwc3/platform_data.h +++ /dev/null @@ -1,53 +0,0 @@ -/** - * platform_data.h - USB DWC3 Platform Data Support - * - * Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com - * Author: Felipe Balbi - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 of - * the License as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include -#include - -struct dwc3_platform_data { - enum usb_device_speed maximum_speed; - enum usb_dr_mode dr_mode; - bool usb3_lpm_capable; - - unsigned is_utmi_l1_suspend:1; - u8 hird_threshold; - - u8 lpm_nyet_threshold; - - unsigned disable_scramble_quirk:1; - unsigned has_lpm_erratum:1; - unsigned u2exit_lfps_quirk:1; - unsigned u2ss_inp3_quirk:1; - unsigned req_p1p2p3_quirk:1; - unsigned del_p1p2p3_quirk:1; - unsigned del_phy_power_chg_quirk:1; - unsigned lfps_filter_quirk:1; - unsigned rx_detect_poll_quirk:1; - unsigned dis_u3_susphy_quirk:1; - unsigned dis_u2_susphy_quirk:1; - unsigned dis_enblslpm_quirk:1; - unsigned dis_rxdet_inp3_quirk:1; - - unsigned tx_de_emphasis_quirk:1; - unsigned tx_de_emphasis:2; - - u32 fladj_value; - - const char *hsphy_interface; -}; -- cgit v0.10.2 From b6b1c6db4c7f04ffe3fd411baa9df31f4dd355dd Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Mon, 30 May 2016 13:29:35 +0300 Subject: usb: dwc3: gadget: update transfer needs transfer resource According to SNPS databook, we need to pass transfer resource on update transfer command, let's do it. Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 61edb665..e7e493b 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -994,12 +994,13 @@ static int __dwc3_gadget_kick_transfer(struct dwc3_ep *dep, u16 cmd_param) if (starting) { params.param0 = upper_32_bits(req->trb_dma); params.param1 = lower_32_bits(req->trb_dma); - cmd = DWC3_DEPCMD_STARTTRANSFER; + cmd = DWC3_DEPCMD_STARTTRANSFER | + DWC3_DEPCMD_PARAM(cmd_param); } else { - cmd = DWC3_DEPCMD_UPDATETRANSFER; + cmd = DWC3_DEPCMD_UPDATETRANSFER | + DWC3_DEPCMD_PARAM(dep->resource_index); } - cmd |= DWC3_DEPCMD_PARAM(cmd_param); ret = dwc3_send_gadget_ep_cmd(dep, cmd, ¶ms); if (ret < 0) { /* -- cgit v0.10.2 From 68d34c8a744d16ae449577a71c67b19a4b1100d0 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Mon, 30 May 2016 13:34:58 +0300 Subject: usb: dwc3: gadget: keep track of allocated and queued reqs We will be using this information to change how we figure out when we need LST bit. For now, just update our counters. Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index dcdba14..45d6de5 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -497,6 +497,8 @@ struct dwc3_event_buffer { * @type: set to bmAttributes & USB_ENDPOINT_XFERTYPE_MASK * @resource_index: Resource transfer index * @interval: the interval on which the ISOC transfer is started + * @allocated_requests: number of requests allocated + * @queued_requests: number of requests queued for transfer * @name: a human readable name e.g. ep1out-bulk * @direction: true for TX, false for RX * @stream_capable: true when streams are enabled @@ -541,6 +543,8 @@ struct dwc3_ep { u8 number; u8 type; u8 resource_index; + u32 allocated_requests; + u32 queued_requests; u32 interval; char name[20]; diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index e7e493b..1cd4b50 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -741,6 +741,8 @@ static struct usb_request *dwc3_gadget_ep_alloc_request(struct usb_ep *ep, req->epnum = dep->number; req->dep = dep; + dep->allocated_requests++; + trace_dwc3_alloc_request(req); return &req->request; @@ -750,7 +752,9 @@ static void dwc3_gadget_ep_free_request(struct usb_ep *ep, struct usb_request *request) { struct dwc3_request *req = to_dwc3_request(request); + struct dwc3_ep *dep = to_dwc3_ep(ep); + dep->allocated_requests--; trace_dwc3_free_request(req); kfree(req); } @@ -831,6 +835,8 @@ static void dwc3_prepare_one_trb(struct dwc3_ep *dep, trb->ctrl |= DWC3_TRB_CTRL_HWO; + dep->queued_requests++; + trace_dwc3_prepare_trb(dep, trb); } @@ -1936,6 +1942,7 @@ static int __dwc3_cleanup_done_trbs(struct dwc3 *dwc, struct dwc3_ep *dep, unsigned int s_pkt = 0; unsigned int trb_status; + dep->queued_requests--; trace_dwc3_complete_trb(dep, trb); if ((trb->ctrl & DWC3_TRB_CTRL_HWO) && status != -ESHUTDOWN) diff --git a/drivers/usb/dwc3/trace.h b/drivers/usb/dwc3/trace.h index cafd69f..d24cefd 100644 --- a/drivers/usb/dwc3/trace.h +++ b/drivers/usb/dwc3/trace.h @@ -231,6 +231,8 @@ DECLARE_EVENT_CLASS(dwc3_log_trb, TP_STRUCT__entry( __dynamic_array(char, name, DWC3_MSG_MAX) __field(struct dwc3_trb *, trb) + __field(u32, allocated) + __field(u32, queued) __field(u32, bpl) __field(u32, bph) __field(u32, size) @@ -239,13 +241,16 @@ DECLARE_EVENT_CLASS(dwc3_log_trb, TP_fast_assign( snprintf(__get_str(name), DWC3_MSG_MAX, "%s", dep->name); __entry->trb = trb; + __entry->allocated = dep->allocated_requests; + __entry->queued = dep->queued_requests; __entry->bpl = trb->bpl; __entry->bph = trb->bph; __entry->size = trb->size; __entry->ctrl = trb->ctrl; ), - TP_printk("%s: trb %p buf %08x%08x size %d ctrl %08x (%c%c%c%c:%c%c:%s)", - __get_str(name), __entry->trb, __entry->bph, __entry->bpl, + TP_printk("%s: %d/%d trb %p buf %08x%08x size %d ctrl %08x (%c%c%c%c:%c%c:%s)", + __get_str(name), __entry->queued, __entry->allocated, + __entry->trb, __entry->bph, __entry->bpl, __entry->size, __entry->ctrl, __entry->ctrl & DWC3_TRB_CTRL_HWO ? 'H' : 'h', __entry->ctrl & DWC3_TRB_CTRL_LST ? 'L' : 'l', -- cgit v0.10.2 From 69450c4dc164d9ecbc0b54cb47a2ec80cde45da4 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Mon, 30 May 2016 13:37:02 +0300 Subject: usb: dwc3: gadget: halt and stop based HWO bit Instead of relying on empty list of queued requests, let's rely on the fact that we have a TRB being processed right now. Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 1cd4b50..a7c2548 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -600,8 +600,16 @@ static void dwc3_stop_active_transfer(struct dwc3 *dwc, u32 epnum, bool force); static void dwc3_remove_requests(struct dwc3 *dwc, struct dwc3_ep *dep) { struct dwc3_request *req; + struct dwc3_trb *current_trb; + unsigned transfer_in_flight; - if (!list_empty(&dep->started_list)) { + if (dep->number > 1) + current_trb = &dep->trb_pool[dep->trb_enqueue]; + else + current_trb = &dwc->ep0_trb[dep->trb_enqueue]; + transfer_in_flight = current_trb->ctrl & DWC3_TRB_CTRL_HWO; + + if (transfer_in_flight && !list_empty(&dep->started_list)) { dwc3_stop_active_transfer(dwc, dep->number, true); /* - giveback all requests to gadget driver */ @@ -1302,9 +1310,21 @@ int __dwc3_gadget_ep_set_halt(struct dwc3_ep *dep, int value, int protocol) memset(¶ms, 0x00, sizeof(params)); if (value) { - if (!protocol && ((dep->direction && dep->flags & DWC3_EP_BUSY) || - (!list_empty(&dep->started_list) || - !list_empty(&dep->pending_list)))) { + struct dwc3_trb *trb; + + unsigned transfer_in_flight; + unsigned started; + + if (dep->number > 1) + trb = dwc3_ep_prev_trb(dep, dep->trb_enqueue); + else + trb = &dwc->ep0_trb[dep->trb_enqueue]; + + transfer_in_flight = trb->ctrl & DWC3_TRB_CTRL_HWO; + started = !list_empty(&dep->started_list); + + if (!protocol && ((dep->direction && transfer_in_flight) || + (!dep->direction && started))) { dwc3_trace(trace_dwc3_gadget, "%s: pending request, cannot halt", dep->name); -- cgit v0.10.2 From 55a0237f8f47957163125e20ee9260538c5c341c Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Mon, 30 May 2016 13:38:32 +0300 Subject: usb: dwc3: gadget: use allocated/queued reqs for LST bit Let's only set LST bit when we run out of space in our TRB ring. For all other cases, we keep LST bit unset which will prevent constant allocation and deallocation of endpoint transfer resources. Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index a7c2548..eea4127 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -897,7 +897,8 @@ static u32 dwc3_calc_trbs_left(struct dwc3_ep *dep) } static void dwc3_prepare_one_trb_sg(struct dwc3_ep *dep, - struct dwc3_request *req, unsigned int trbs_left) + struct dwc3_request *req, unsigned int trbs_left, + unsigned int more_coming) { struct usb_request *request = &req->request; struct scatterlist *sg = request->sg; @@ -914,7 +915,8 @@ static void dwc3_prepare_one_trb_sg(struct dwc3_ep *dep, dma = sg_dma_address(s); if (sg_is_last(s)) { - if (list_is_last(&req->list, &dep->pending_list)) + if (usb_endpoint_xfer_int(dep->endpoint.desc) || + !more_coming) last = true; chain = false; @@ -935,7 +937,8 @@ static void dwc3_prepare_one_trb_sg(struct dwc3_ep *dep, } static void dwc3_prepare_one_trb_linear(struct dwc3_ep *dep, - struct dwc3_request *req, unsigned int trbs_left) + struct dwc3_request *req, unsigned int trbs_left, + unsigned int more_coming) { unsigned int last = false; unsigned int length; @@ -948,7 +951,7 @@ static void dwc3_prepare_one_trb_linear(struct dwc3_ep *dep, last = true; /* Is this the last request? */ - if (list_is_last(&req->list, &dep->pending_list)) + if (usb_endpoint_xfer_int(dep->endpoint.desc) || !more_coming) last = true; dwc3_prepare_one_trb(dep, req, dma, length, @@ -966,6 +969,7 @@ static void dwc3_prepare_one_trb_linear(struct dwc3_ep *dep, static void dwc3_prepare_trbs(struct dwc3_ep *dep) { struct dwc3_request *req, *n; + unsigned int more_coming; u32 trbs_left; BUILD_BUG_ON_NOT_POWER_OF_2(DWC3_TRB_NUM); @@ -974,11 +978,15 @@ static void dwc3_prepare_trbs(struct dwc3_ep *dep) if (!trbs_left) return; + more_coming = dep->allocated_requests - dep->queued_requests; + list_for_each_entry_safe(req, n, &dep->pending_list, list) { if (req->request.num_mapped_sgs > 0) - dwc3_prepare_one_trb_sg(dep, req, trbs_left--); + dwc3_prepare_one_trb_sg(dep, req, trbs_left--, + more_coming); else - dwc3_prepare_one_trb_linear(dep, req, trbs_left--); + dwc3_prepare_one_trb_linear(dep, req, trbs_left--, + more_coming); if (!trbs_left) return; -- cgit v0.10.2 From 13fa2e69b1dda31bddb11fe61f250b9415885ead Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Mon, 30 May 2016 13:40:00 +0300 Subject: usb: dwc3: gadget: disable XFER_NOT_READY We don't need this IRQ anymore for interrupt or bulk endpoints. Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index eea4127..126e8b8 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -485,8 +485,10 @@ static int dwc3_gadget_set_ep_config(struct dwc3 *dwc, struct dwc3_ep *dep, params.param2 |= dep->saved_state; } - params.param1 = DWC3_DEPCFG_XFER_COMPLETE_EN - | DWC3_DEPCFG_XFER_NOT_READY_EN; + params.param1 = DWC3_DEPCFG_XFER_COMPLETE_EN; + + if (dep->number <= 1 || usb_endpoint_xfer_isoc(desc)) + params.param1 |= DWC3_DEPCFG_XFER_NOT_READY_EN; if (usb_ss_max_streams(comp_desc) && usb_endpoint_xfer_bulk(desc)) { params.param1 |= DWC3_DEPCFG_STREAM_CAPABLE -- cgit v0.10.2 From ba62c09d5cc240e55eb39e92d88f1036bb1d9221 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Mon, 30 May 2016 13:41:22 +0300 Subject: usb: dwc3: gadget: start Bulk endpoints more frequently Now we can try to issue Update Transfer every time gadget driver queues a new request. This will make sure we keep controller's queue busy for as long as possible. Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 126e8b8..3d2978c 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -1133,8 +1133,7 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req) * little bit faster. */ if (!usb_endpoint_xfer_isoc(dep->endpoint.desc) && - !usb_endpoint_xfer_int(dep->endpoint.desc) && - !(dep->flags & DWC3_EP_BUSY)) { + !usb_endpoint_xfer_int(dep->endpoint.desc)) { ret = __dwc3_gadget_kick_transfer(dep, 0); goto out; } -- cgit v0.10.2 From d6dc2e76a860d6be0129daae43e5f12461531d20 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Mon, 30 May 2016 13:42:33 +0300 Subject: usb: dwc3: gadget: decrement trbs_left for each sg entry If we don't, we will overwrite valid TRBs. Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 3d2978c..d2884a4 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -924,7 +924,7 @@ static void dwc3_prepare_one_trb_sg(struct dwc3_ep *dep, chain = false; } - if (!trbs_left) + if (!trbs_left--) last = true; if (last) -- cgit v0.10.2 From aa5e94a2e13377e374795de5400e346c978f46be Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Mon, 20 Jun 2016 07:42:07 -0700 Subject: Revert "usb: ohci-at91: Forcibly suspend ports while USB suspend" This reverts commit 7150bc9b4d43471fa37b26f5839892d4cf1fe09b. It is not correct, based on review from others. Reported-by: Wenyou Yang Signed-off-by: Greg Kroah-Hartman diff --git a/Documentation/devicetree/bindings/usb/atmel-usb.txt b/Documentation/devicetree/bindings/usb/atmel-usb.txt index 888deaa..5883b73 100644 --- a/Documentation/devicetree/bindings/usb/atmel-usb.txt +++ b/Documentation/devicetree/bindings/usb/atmel-usb.txt @@ -3,10 +3,8 @@ Atmel SOC USB controllers OHCI Required properties: - - compatible: Should be one of the following - "atmel,at91rm9200-ohci" for USB controllers used in host mode. - "atmel,sama5d2-ohci" for USB controllers used in host mode - on SAMA5D2 which can force to suspend. + - compatible: Should be "atmel,at91rm9200-ohci" for USB controllers + used in host mode. - reg: Address and length of the register set for the device - interrupts: Should contain ehci interrupt - clocks: Should reference the peripheral, host and system clocks diff --git a/drivers/usb/host/ohci-at91.c b/drivers/usb/host/ohci-at91.c index 54e8feb..d177372 100644 --- a/drivers/usb/host/ohci-at91.c +++ b/drivers/usb/host/ohci-at91.c @@ -21,11 +21,8 @@ #include #include #include -#include -#include #include #include -#include #include "ohci.h" @@ -48,18 +45,12 @@ struct at91_usbh_data { u8 overcurrent_changed[AT91_MAX_USBH_PORTS]; }; -struct ohci_at91_caps { - bool suspend_ctrl; -}; - struct ohci_at91_priv { struct clk *iclk; struct clk *fclk; struct clk *hclk; bool clocked; bool wakeup; /* Saved wake-up state for resume */ - const struct ohci_at91_caps *caps; - struct regmap *sfr_regmap; }; /* interface and function clocks; sometimes also an AHB clock */ @@ -141,17 +132,6 @@ static void at91_stop_hc(struct platform_device *pdev) /*-------------------------------------------------------------------------*/ -struct regmap *at91_dt_syscon_sfr(void) -{ - struct regmap *regmap; - - regmap = syscon_regmap_lookup_by_compatible("atmel,sama5d2-sfr"); - if (IS_ERR(regmap)) - regmap = NULL; - - return regmap; -} - static void usb_hcd_at91_remove (struct usb_hcd *, struct platform_device *); /* configure so an HC device and id are always provided */ @@ -217,17 +197,6 @@ static int usb_hcd_at91_probe(const struct hc_driver *driver, goto err; } - ohci_at91->caps = (const struct ohci_at91_caps *) - of_device_get_match_data(&pdev->dev); - if (!ohci_at91->caps) - return -ENODEV; - - if (ohci_at91->caps->suspend_ctrl) { - ohci_at91->sfr_regmap = at91_dt_syscon_sfr(); - if (!ohci_at91->sfr_regmap) - dev_warn(dev, "failed to find sfr node\n"); - } - board = hcd->self.controller->platform_data; ohci = hcd_to_ohci(hcd); ohci->num_ports = board->ports; @@ -471,17 +440,8 @@ static irqreturn_t ohci_hcd_at91_overcurrent_irq(int irq, void *data) return IRQ_HANDLED; } -static const struct ohci_at91_caps at91rm9200_caps = { - .suspend_ctrl = false, -}; - -static const struct ohci_at91_caps sama5d2_caps = { - .suspend_ctrl = true, -}; - static const struct of_device_id at91_ohci_dt_ids[] = { - { .compatible = "atmel,at91rm9200-ohci", .data = &at91rm9200_caps }, - { .compatible = "atmel,sama5d2-ohci", .data = &sama5d2_caps }, + { .compatible = "atmel,at91rm9200-ohci" }, { /* sentinel */ } }; @@ -621,38 +581,6 @@ static int ohci_hcd_at91_drv_remove(struct platform_device *pdev) return 0; } -static int ohci_at91_port_ctrl(struct regmap *regmap, bool enable) -{ - u32 regval; - int ret; - - if (!regmap) - return -EINVAL; - - ret = regmap_read(regmap, SFR_OHCIICR, ®val); - if (ret) - return ret; - - if (enable) - regval &= ~SFR_OHCIICR_USB_SUSPEND; - else - regval |= SFR_OHCIICR_USB_SUSPEND; - - regmap_write(regmap, SFR_OHCIICR, regval); - - return 0; -} - -static int ohci_at91_port_suspend(struct regmap *regmap) -{ - return ohci_at91_port_ctrl(regmap, false); -} - -static int ohci_at91_port_resume(struct regmap *regmap) -{ - return ohci_at91_port_ctrl(regmap, true); -} - static int __maybe_unused ohci_hcd_at91_drv_suspend(struct device *dev) { @@ -690,9 +618,6 @@ ohci_hcd_at91_drv_suspend(struct device *dev) ohci_writel(ohci, ohci->hc_control, &ohci->regs->control); ohci->rh_state = OHCI_RH_HALTED; - if (ohci_at91->caps->suspend_ctrl) - ohci_at91_port_suspend(ohci_at91->sfr_regmap); - /* flush the writes */ (void) ohci_readl (ohci, &ohci->regs->control); at91_stop_clock(ohci_at91); @@ -712,9 +637,6 @@ ohci_hcd_at91_drv_resume(struct device *dev) at91_start_clock(ohci_at91); - if (ohci_at91->caps->suspend_ctrl) - ohci_at91_port_resume(ohci_at91->sfr_regmap); - ohci_resume(hcd, false); return 0; } diff --git a/include/soc/at91/at91_sfr.h b/include/soc/at91/at91_sfr.h deleted file mode 100644 index 04a3a1e..0000000 --- a/include/soc/at91/at91_sfr.h +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Header file for the Atmel DDR/SDR SDRAM Controller - * - * Copyright (C) 2016 Atmel Corporation - * - * Author: Wenyou Yang - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - */ -#ifndef __AT91_SFR_H__ -#define __AT91_SFR_H__ - -#define SFR_DDRCFG 0x04 /* DDR Configuration Register */ -/* 0x08 ~ 0x0c: Reserved */ -#define SFR_OHCIICR 0x10 /* OHCI Interrupt Configuration Register */ -#define SFR_OHCIISR 0x14 /* OHCI Interrupt Status Register */ - -#define SFR_OHCIICR_SUSPEND_A BIT(8) -#define SFR_OHCIICR_SUSPEND_B BIT(9) -#define SFR_OHCIICR_SUSPEND_C BIT(10) - -#define SFR_OHCIICR_USB_SUSPEND (SFR_OHCIICR_SUSPEND_A | \ - SFR_OHCIICR_SUSPEND_B | \ - SFR_OHCIICR_SUSPEND_C) - -#endif -- cgit v0.10.2 From c39341cf0d08357f448f4c2fffe2ebcc9495fd01 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sun, 13 Sep 2015 14:15:21 +0200 Subject: ecryptfs: drop null test before destroy functions Remove unneeded NULL test. The semantic patch that makes this change is as follows: (http://coccinelle.lip6.fr/) // @@ expression x; @@ -if (x != NULL) \(kmem_cache_destroy\|mempool_destroy\|dma_pool_destroy\)(x); // Signed-off-by: Julia Lawall Signed-off-by: Tyler Hicks diff --git a/fs/ecryptfs/main.c b/fs/ecryptfs/main.c index 1698132..6120044 100644 --- a/fs/ecryptfs/main.c +++ b/fs/ecryptfs/main.c @@ -738,8 +738,7 @@ static void ecryptfs_free_kmem_caches(void) struct ecryptfs_cache_info *info; info = &ecryptfs_cache_infos[i]; - if (*(info->cache)) - kmem_cache_destroy(*(info->cache)); + kmem_cache_destroy(*(info->cache)); } } -- cgit v0.10.2 From 5f9f2c2abd16fcea6cf7cf87791a24687e2fc345 Mon Sep 17 00:00:00 2001 From: Wei Yuan Date: Wed, 17 Feb 2016 14:50:10 +0800 Subject: eCryptfs: fix typos in comment Signed-off-by: Weiyuan Signed-off-by: Tyler Hicks diff --git a/fs/ecryptfs/crypto.c b/fs/ecryptfs/crypto.c index 0d8eb34..6a69b55 100644 --- a/fs/ecryptfs/crypto.c +++ b/fs/ecryptfs/crypto.c @@ -45,7 +45,7 @@ * ecryptfs_to_hex * @dst: Buffer to take hex character representation of contents of * src; must be at least of size (src_size * 2) - * @src: Buffer to be converted to a hex string respresentation + * @src: Buffer to be converted to a hex string representation * @src_size: number of bytes to convert */ void ecryptfs_to_hex(char *dst, char *src, size_t src_size) @@ -60,7 +60,7 @@ void ecryptfs_to_hex(char *dst, char *src, size_t src_size) * ecryptfs_from_hex * @dst: Buffer to take the bytes from src hex; must be at least of * size (src_size / 2) - * @src: Buffer to be converted from a hex string respresentation to raw value + * @src: Buffer to be converted from a hex string representation to raw value * @dst_size: size of dst buffer, or number of hex characters pairs to convert */ void ecryptfs_from_hex(char *dst, char *src, int dst_size) -- cgit v0.10.2 From 40f0fd372a623e8d32bae0b9361d2a7453ae7a2e Mon Sep 17 00:00:00 2001 From: Chris J Arges Date: Thu, 9 Jun 2016 15:31:29 -0500 Subject: ecryptfs: fix spelling mistakes Noticed some minor spelling errors when looking through the code. Signed-off-by: Chris J Arges Signed-off-by: Tyler Hicks diff --git a/fs/ecryptfs/crypto.c b/fs/ecryptfs/crypto.c index 6a69b55..e5e29f8 100644 --- a/fs/ecryptfs/crypto.c +++ b/fs/ecryptfs/crypto.c @@ -953,7 +953,7 @@ struct ecryptfs_cipher_code_str_map_elem { }; /* Add support for additional ciphers by adding elements here. The - * cipher_code is whatever OpenPGP applicatoins use to identify the + * cipher_code is whatever OpenPGP applications use to identify the * ciphers. List in order of probability. */ static struct ecryptfs_cipher_code_str_map_elem ecryptfs_cipher_code_str_map[] = { @@ -1410,7 +1410,7 @@ int ecryptfs_read_and_validate_xattr_region(struct dentry *dentry, * * Common entry point for reading file metadata. From here, we could * retrieve the header information from the header region of the file, - * the xattr region of the file, or some other repostory that is + * the xattr region of the file, or some other repository that is * stored separately from the file itself. The current implementation * supports retrieving the metadata information from the file contents * and from the xattr region. diff --git a/fs/ecryptfs/file.c b/fs/ecryptfs/file.c index 7000b96..53d0141 100644 --- a/fs/ecryptfs/file.c +++ b/fs/ecryptfs/file.c @@ -171,7 +171,7 @@ out: /** * ecryptfs_open - * @inode: inode speciying file to open + * @inode: inode specifying file to open * @file: Structure to return filled in * * Opens the file specified by inode. @@ -240,7 +240,7 @@ out: /** * ecryptfs_dir_open - * @inode: inode speciying file to open + * @inode: inode specifying file to open * @file: Structure to return filled in * * Opens the file specified by inode. -- cgit v0.10.2 From 0fb71d340d355156818bb53eb36ae79a3f88bda9 Mon Sep 17 00:00:00 2001 From: Minfei Huang Date: Mon, 25 Apr 2016 17:20:28 +0800 Subject: clocksource: Make clocksource insert entry more efficient In clocksource_enqueue(), it is unnecessary to continue looping the list, if we find there is an entry that the value of rating is smaller than the new one. It is safe to be out the loop, because all of entry are inserted in descending order. Cc: Prarit Bhargava Cc: Richard Cochran Cc: Thomas Gleixner Cc: Ingo Molnar Signed-off-by: Minfei Huang Signed-off-by: John Stultz diff --git a/kernel/time/clocksource.c b/kernel/time/clocksource.c index 56ece14..6a5a310 100644 --- a/kernel/time/clocksource.c +++ b/kernel/time/clocksource.c @@ -669,10 +669,12 @@ static void clocksource_enqueue(struct clocksource *cs) struct list_head *entry = &clocksource_list; struct clocksource *tmp; - list_for_each_entry(tmp, &clocksource_list, list) + list_for_each_entry(tmp, &clocksource_list, list) { /* Keep track of the place, where to insert */ - if (tmp->rating >= cs->rating) - entry = &tmp->list; + if (tmp->rating < cs->rating) + break; + entry = &tmp->list; + } list_add(&cs->list, entry); } -- cgit v0.10.2 From 0209b937569a133dedfe930cdfff3a0d1d68c9e9 Mon Sep 17 00:00:00 2001 From: Thomas Graziadei Date: Tue, 31 May 2016 15:06:06 +0200 Subject: timekeeping: Fix 1ns/tick drift with GENERIC_TIME_VSYSCALL_OLD The user notices the problem in a raw and real time drift, calling clock_gettime with CLOCK_REALTIME / CLOCK_MONOTONIC_RAW on a system with no ntp correction taking place (no ntpd or ptp stuff running). The problem is, that old_vsyscall_fixup adds an extra 1ns even though xtime_nsec is already held in full nsecs and the remainder in this case is 0. Do the rounding up buisness only if needed. Cc: Prarit Bhargava Cc: Richard Cochran Cc: Thomas Gleixner Cc: Ingo Molnar Signed-off-by: Thomas Graziadei Signed-off-by: John Stultz diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c index 479d25c..a196e08 100644 --- a/kernel/time/timekeeping.c +++ b/kernel/time/timekeeping.c @@ -480,10 +480,12 @@ static inline void old_vsyscall_fixup(struct timekeeper *tk) * users are removed, this can be killed. */ remainder = tk->tkr_mono.xtime_nsec & ((1ULL << tk->tkr_mono.shift) - 1); - tk->tkr_mono.xtime_nsec -= remainder; - tk->tkr_mono.xtime_nsec += 1ULL << tk->tkr_mono.shift; - tk->ntp_error += remainder << tk->ntp_error_shift; - tk->ntp_error -= (1ULL << tk->tkr_mono.shift) << tk->ntp_error_shift; + if (remainder != 0) { + tk->tkr_mono.xtime_nsec -= remainder; + tk->tkr_mono.xtime_nsec += 1ULL << tk->tkr_mono.shift; + tk->ntp_error += remainder << tk->ntp_error_shift; + tk->ntp_error -= (1ULL << tk->tkr_mono.shift) << tk->ntp_error_shift; + } } #else #define old_vsyscall_fixup(tk) -- cgit v0.10.2 From af4afb40085f04f8b2ea8d28df878f7f0be02f89 Mon Sep 17 00:00:00 2001 From: Pratyush Patel Date: Tue, 14 Jun 2016 11:00:42 +0200 Subject: alarmtimer: Fix comments describing structure fields Updated struct alarm and struct alarm_timer descriptions. Cc: Prarit Bhargava Cc: Richard Cochran Cc: Thomas Gleixner Cc: Ingo Molnar Signed-off-by: Pratyush Patel Signed-off-by: John Stultz diff --git a/include/linux/alarmtimer.h b/include/linux/alarmtimer.h index 52f3b7d..9d80312 100644 --- a/include/linux/alarmtimer.h +++ b/include/linux/alarmtimer.h @@ -26,10 +26,10 @@ enum alarmtimer_restart { * struct alarm - Alarm timer structure * @node: timerqueue node for adding to the event list this value * also includes the expiration time. - * @period: Period for recuring alarms + * @timer: hrtimer used to schedule events while running * @function: Function pointer to be executed when the timer fires. - * @type: Alarm type (BOOTTIME/REALTIME) - * @enabled: Flag that represents if the alarm is set to fire or not + * @type: Alarm type (BOOTTIME/REALTIME). + * @state: Flag that represents if the alarm is set to fire or not. * @data: Internal data value. */ struct alarm { diff --git a/kernel/time/alarmtimer.c b/kernel/time/alarmtimer.c index e840ed8..c3aad68 100644 --- a/kernel/time/alarmtimer.c +++ b/kernel/time/alarmtimer.c @@ -30,7 +30,6 @@ * struct alarm_base - Alarm timer bases * @lock: Lock for syncrhonized access to the base * @timerqueue: Timerqueue head managing the list of events - * @timer: hrtimer used to schedule events while running * @gettime: Function to read the time correlating to the base * @base_clockid: clockid for the base */ -- cgit v0.10.2 From e6c2682a1da36a2e79d9bab470412374434ce89e Mon Sep 17 00:00:00 2001 From: Deepa Dinamani Date: Wed, 8 Jun 2016 22:04:59 -0700 Subject: time: Add time64_to_tm() time_to_tm() takes time_t as an argument. time_t is not y2038 safe. Add time64_to_tm() that takes time64_t as an argument which is y2038 safe. The plan is to eventually replace all calls to time_to_tm() by time64_to_tm(). Cc: Prarit Bhargava Cc: Richard Cochran Cc: Thomas Gleixner Cc: Ingo Molnar Signed-off-by: Deepa Dinamani Signed-off-by: John Stultz diff --git a/include/linux/time.h b/include/linux/time.h index 297f09f..4cea09d 100644 --- a/include/linux/time.h +++ b/include/linux/time.h @@ -205,7 +205,20 @@ struct tm { int tm_yday; }; -void time_to_tm(time_t totalsecs, int offset, struct tm *result); +void time64_to_tm(time64_t totalsecs, int offset, struct tm *result); + +/** + * time_to_tm - converts the calendar time to local broken-down time + * + * @totalsecs the number of seconds elapsed since 00:00:00 on January 1, 1970, + * Coordinated Universal Time (UTC). + * @offset offset seconds adding to totalsecs. + * @result pointer to struct tm variable to receive broken-down time + */ +static inline void time_to_tm(time_t totalsecs, int offset, struct tm *result) +{ + time64_to_tm(totalsecs, offset, result); +} /** * timespec_to_ns - Convert timespec to nanoseconds diff --git a/kernel/time/timeconv.c b/kernel/time/timeconv.c index 86628e7..7142580 100644 --- a/kernel/time/timeconv.c +++ b/kernel/time/timeconv.c @@ -67,20 +67,21 @@ static const unsigned short __mon_yday[2][13] = { #define SECS_PER_DAY (SECS_PER_HOUR * 24) /** - * time_to_tm - converts the calendar time to local broken-down time + * time64_to_tm - converts the calendar time to local broken-down time * * @totalsecs the number of seconds elapsed since 00:00:00 on January 1, 1970, * Coordinated Universal Time (UTC). * @offset offset seconds adding to totalsecs. * @result pointer to struct tm variable to receive broken-down time */ -void time_to_tm(time_t totalsecs, int offset, struct tm *result) +void time64_to_tm(time64_t totalsecs, int offset, struct tm *result) { long days, rem, y; + int remainder; const unsigned short *ip; - days = totalsecs / SECS_PER_DAY; - rem = totalsecs % SECS_PER_DAY; + days = div_s64_rem(totalsecs, SECS_PER_DAY, &remainder); + rem = remainder; rem += offset; while (rem < 0) { rem += SECS_PER_DAY; @@ -124,4 +125,4 @@ void time_to_tm(time_t totalsecs, int offset, struct tm *result) result->tm_mon = y; result->tm_mday = days + 1; } -EXPORT_SYMBOL(time_to_tm); +EXPORT_SYMBOL(time64_to_tm); -- cgit v0.10.2 From 4a19bd3d22d51a0c89db10879dacaffa0f52aecf Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Fri, 17 Jun 2016 18:03:02 +0200 Subject: time: Avoid timespec in udelay_test udelay_test_single() uses ktime_get_ts() to get two timespec values and calculate the difference between them, while udelay_test_show() uses the same to printk() the current monotonic time. Both of these are y2038 safe on all machines, but we want to get rid of struct timespec anyway, so this converts the code to use ktime_get_ns() and ktime_get_ts64() respectively. Cc: Prarit Bhargava Cc: Richard Cochran Cc: Thomas Gleixner Cc: Ingo Molnar Signed-off-by: Arnd Bergmann Signed-off-by: John Stultz diff --git a/kernel/time/test_udelay.c b/kernel/time/test_udelay.c index e622ba3..b0928ab 100644 --- a/kernel/time/test_udelay.c +++ b/kernel/time/test_udelay.c @@ -43,13 +43,13 @@ static int udelay_test_single(struct seq_file *s, int usecs, uint32_t iters) int allowed_error_ns = usecs * 5; for (i = 0; i < iters; ++i) { - struct timespec ts1, ts2; + s64 kt1, kt2; int time_passed; - ktime_get_ts(&ts1); + kt1 = ktime_get_ns(); udelay(usecs); - ktime_get_ts(&ts2); - time_passed = timespec_to_ns(&ts2) - timespec_to_ns(&ts1); + kt2 = ktime_get_ns(); + time_passed = kt2 - kt1; if (i == 0 || time_passed < min) min = time_passed; @@ -87,11 +87,11 @@ static int udelay_test_show(struct seq_file *s, void *v) if (usecs > 0 && iters > 0) { return udelay_test_single(s, usecs, iters); } else if (usecs == 0) { - struct timespec ts; + struct timespec64 ts; - ktime_get_ts(&ts); - seq_printf(s, "udelay() test (lpj=%ld kt=%ld.%09ld)\n", - loops_per_jiffy, ts.tv_sec, ts.tv_nsec); + ktime_get_ts64(&ts); + seq_printf(s, "udelay() test (lpj=%ld kt=%lld.%09ld)\n", + loops_per_jiffy, (s64)ts.tv_sec, ts.tv_nsec); seq_puts(s, "usage:\n"); seq_puts(s, "echo USECS [ITERS] > " DEBUGFS_FILENAME "\n"); seq_puts(s, "cat " DEBUGFS_FILENAME "\n"); -- cgit v0.10.2 From 7c71feb0a6766c7c3a262e3cc33ae231f3953cb6 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Fri, 17 Jun 2016 17:30:47 +0200 Subject: timer: Avoid using timespec The tstats_show() function prints a ktime_t variable by converting it to struct timespec first. The algorithm is ok, but we want to stop using timespec in general because of the 32-bit time_t overflow problem. This changes the code to use struct timespec64, without any functional change. Cc: Prarit Bhargava Cc: Richard Cochran Cc: Thomas Gleixner Cc: Ingo Molnar Signed-off-by: Arnd Bergmann Signed-off-by: John Stultz diff --git a/kernel/time/timer_stats.c b/kernel/time/timer_stats.c index 1adecb4..087204c 100644 --- a/kernel/time/timer_stats.c +++ b/kernel/time/timer_stats.c @@ -279,7 +279,7 @@ static void print_name_offset(struct seq_file *m, unsigned long addr) static int tstats_show(struct seq_file *m, void *v) { - struct timespec period; + struct timespec64 period; struct entry *entry; unsigned long ms; long events = 0; @@ -295,11 +295,11 @@ static int tstats_show(struct seq_file *m, void *v) time = ktime_sub(time_stop, time_start); - period = ktime_to_timespec(time); + period = ktime_to_timespec64(time); ms = period.tv_nsec / 1000000; seq_puts(m, "Timer Stats Version: v0.3\n"); - seq_printf(m, "Sample period: %ld.%03ld s\n", period.tv_sec, ms); + seq_printf(m, "Sample period: %ld.%03ld s\n", (long)period.tv_sec, ms); if (atomic_read(&overflow_count)) seq_printf(m, "Overflow: %d entries\n", atomic_read(&overflow_count)); seq_printf(m, "Collection: %s\n", timer_stats_active ? "active" : "inactive"); -- cgit v0.10.2 From 341f1f0affed1c24712f37c95bb654b3b33ab2c6 Mon Sep 17 00:00:00 2001 From: Fan Yong Date: Sun, 19 Jun 2016 22:53:53 -0400 Subject: staging: lustre: remove remote client support There are several obsolete sub commands for lfs to work with remote client. We do not support that anymore, and should be deleted along with any kernel code related to remote client. Signed-off-by: Fan Yong Intel-bug-id: https://jira.hpdd.intel.com/browse/LU-6971 Reviewed-on: http://review.whamcloud.com/19789 Reviewed-by: Andreas Dilger Reviewed-by: James Simmons Reviewed-by: Lai Siyao Reviewed-by: Oleg Drokin Signed-off-by: James Simmons Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/lustre/lustre/include/lustre/lustre_idl.h b/drivers/staging/lustre/lustre/include/lustre/lustre_idl.h index fac7215..051864c 100644 --- a/drivers/staging/lustre/lustre/include/lustre/lustre_idl.h +++ b/drivers/staging/lustre/lustre/include/lustre/lustre_idl.h @@ -1237,8 +1237,16 @@ void lustre_swab_ptlrpc_body(struct ptlrpc_body *pb); */ #define OBD_CONNECT_ATTRFID 0x4000ULL /*Server can GetAttr By Fid*/ #define OBD_CONNECT_NODEVOH 0x8000ULL /*No open hndl on specl nodes*/ -#define OBD_CONNECT_RMT_CLIENT 0x10000ULL /*Remote client */ -#define OBD_CONNECT_RMT_CLIENT_FORCE 0x20000ULL /*Remote client by force */ +#define OBD_CONNECT_RMT_CLIENT 0x10000ULL /* Remote client, never used + * in production. Removed in + * 2.9. Keep this flag to + * avoid reuse. + */ +#define OBD_CONNECT_RMT_CLIENT_FORCE 0x20000ULL /* Remote client by force, + * never used in production. + * Removed in 2.9. Keep this + * flag to avoid reuse + */ #define OBD_CONNECT_BRW_SIZE 0x40000ULL /*Max bytes per rpc */ #define OBD_CONNECT_QUOTA64 0x80000ULL /*Not used since 2.4 */ #define OBD_CONNECT_MDS_CAPA 0x100000ULL /*MDS capability */ @@ -1699,7 +1707,7 @@ lov_mds_md_max_stripe_count(size_t buf_size, __u32 lmm_magic) #define OBD_MD_FLXATTRLS (0x0000002000000000ULL) /* xattr list */ #define OBD_MD_FLXATTRRM (0x0000004000000000ULL) /* xattr remove */ #define OBD_MD_FLACL (0x0000008000000000ULL) /* ACL */ -#define OBD_MD_FLRMTPERM (0x0000010000000000ULL) /* remote permission */ +/* OBD_MD_FLRMTPERM (0x0000010000000000ULL) remote perm, obsolete */ #define OBD_MD_FLMDSCAPA (0x0000020000000000ULL) /* MDS capability */ #define OBD_MD_FLOSSCAPA (0x0000040000000000ULL) /* OSS capability */ #define OBD_MD_FLCKSPLIT (0x0000080000000000ULL) /* Check split on server */ @@ -1711,10 +1719,10 @@ lov_mds_md_max_stripe_count(size_t buf_size, __u32 lmm_magic) */ #define OBD_MD_FLOBJCOUNT (0x0000400000000000ULL) /* for multiple destroy */ -#define OBD_MD_FLRMTLSETFACL (0x0001000000000000ULL) /* lfs lsetfacl case */ -#define OBD_MD_FLRMTLGETFACL (0x0002000000000000ULL) /* lfs lgetfacl case */ -#define OBD_MD_FLRMTRSETFACL (0x0004000000000000ULL) /* lfs rsetfacl case */ -#define OBD_MD_FLRMTRGETFACL (0x0008000000000000ULL) /* lfs rgetfacl case */ +/* OBD_MD_FLRMTLSETFACL (0x0001000000000000ULL) lfs lsetfacl, obsolete */ +/* OBD_MD_FLRMTLGETFACL (0x0002000000000000ULL) lfs lgetfacl, obsolete */ +/* OBD_MD_FLRMTRSETFACL (0x0004000000000000ULL) lfs rsetfacl, obsolete */ +/* OBD_MD_FLRMTRGETFACL (0x0008000000000000ULL) lfs rgetfacl, obsolete */ #define OBD_MD_FLDATAVERSION (0x0010000000000000ULL) /* iversion sum */ #define OBD_MD_FLRELEASED (0x0020000000000000ULL) /* file released */ @@ -2155,26 +2163,8 @@ enum { CFS_SETUID_PERM = 0x01, CFS_SETGID_PERM = 0x02, CFS_SETGRP_PERM = 0x04, - CFS_RMTACL_PERM = 0x08, - CFS_RMTOWN_PERM = 0x10 -}; - -/* inode access permission for remote user, the inode info are omitted, - * for client knows them. - */ -struct mdt_remote_perm { - __u32 rp_uid; - __u32 rp_gid; - __u32 rp_fsuid; - __u32 rp_fsuid_h; - __u32 rp_fsgid; - __u32 rp_fsgid_h; - __u32 rp_access_perm; /* MAY_READ/WRITE/EXEC */ - __u32 rp_padding; }; -void lustre_swab_mdt_remote_perm(struct mdt_remote_perm *p); - struct mdt_rec_setattr { __u32 sa_opcode; __u32 sa_cap; diff --git a/drivers/staging/lustre/lustre/include/lustre/lustre_user.h b/drivers/staging/lustre/lustre/include/lustre/lustre_user.h index a6e351a..ef6f38f 100644 --- a/drivers/staging/lustre/lustre/include/lustre/lustre_user.h +++ b/drivers/staging/lustre/lustre/include/lustre/lustre_user.h @@ -211,7 +211,7 @@ struct ost_id { #define IOC_OBD_STATFS _IOWR('f', 164, struct obd_statfs *) #define IOC_LOV_GETINFO _IOWR('f', 165, struct lov_user_mds_data *) #define LL_IOC_FLUSHCTX _IOW('f', 166, long) -#define LL_IOC_RMTACL _IOW('f', 167, long) +/* LL_IOC_RMTACL 167 obsolete */ #define LL_IOC_GETOBDCOUNT _IOR('f', 168, long) #define LL_IOC_LLOOP_ATTACH _IOWR('f', 169, long) #define LL_IOC_LLOOP_DETACH _IOWR('f', 170, long) @@ -538,19 +538,6 @@ struct identity_downcall_data { __u32 idd_groups[0]; }; -/* for non-mapped uid/gid */ -#define NOBODY_UID 99 -#define NOBODY_GID 99 - -#define INVALID_ID (-1) - -enum { - RMT_LSETFACL = 1, - RMT_LGETFACL = 2, - RMT_RSETFACL = 3, - RMT_RGETFACL = 4 -}; - /* lustre volatile file support * file name header: .^L^S^T^R:volatile" */ diff --git a/drivers/staging/lustre/lustre/include/lustre_eacl.h b/drivers/staging/lustre/lustre/include/lustre_eacl.h index e5eadc4..d1039e1 100644 --- a/drivers/staging/lustre/lustre/include/lustre_eacl.h +++ b/drivers/staging/lustre/lustre/include/lustre_eacl.h @@ -66,17 +66,6 @@ typedef struct { #define CFS_ACL_XATTR_COUNT(size, prefix) \ (((size) - sizeof(prefix ## _header)) / sizeof(prefix ## _entry)) -extern ext_acl_xattr_header * -lustre_posix_acl_xattr_2ext(posix_acl_xattr_header *header, int size); -extern int -lustre_posix_acl_xattr_filter(posix_acl_xattr_header *header, size_t size, - posix_acl_xattr_header **out); -extern void -lustre_ext_acl_xattr_free(ext_acl_xattr_header *header); -extern ext_acl_xattr_header * -lustre_acl_xattr_merge2ext(posix_acl_xattr_header *posix_header, int size, - ext_acl_xattr_header *ext_header); - #endif /* CONFIG_FS_POSIX_ACL */ /** @} eacl */ diff --git a/drivers/staging/lustre/lustre/include/lustre_export.h b/drivers/staging/lustre/lustre/include/lustre_export.h index 7c3ed55..6e7cc46 100644 --- a/drivers/staging/lustre/lustre/include/lustre_export.h +++ b/drivers/staging/lustre/lustre/include/lustre_export.h @@ -176,19 +176,6 @@ static inline int exp_connect_lru_resize(struct obd_export *exp) return !!(exp_connect_flags(exp) & OBD_CONNECT_LRU_RESIZE); } -static inline int exp_connect_rmtclient(struct obd_export *exp) -{ - return !!(exp_connect_flags(exp) & OBD_CONNECT_RMT_CLIENT); -} - -static inline int client_is_remote(struct obd_export *exp) -{ - struct obd_import *imp = class_exp2cliimp(exp); - - return !!(imp->imp_connect_data.ocd_connect_flags & - OBD_CONNECT_RMT_CLIENT); -} - static inline int exp_connect_vbr(struct obd_export *exp) { return !!(exp_connect_flags(exp) & OBD_CONNECT_VBR); diff --git a/drivers/staging/lustre/lustre/include/lustre_net.h b/drivers/staging/lustre/lustre/include/lustre_net.h index dba4d1d..bdd2ed5 100644 --- a/drivers/staging/lustre/lustre/include/lustre_net.h +++ b/drivers/staging/lustre/lustre/include/lustre_net.h @@ -1384,7 +1384,6 @@ struct ptlrpc_request { rq_bulk_write:1, /* request bulk write */ /* server authentication flags */ rq_auth_gss:1, /* authenticated by gss */ - rq_auth_remote:1, /* authed as remote user */ rq_auth_usr_root:1, /* authed as root */ rq_auth_usr_mdt:1, /* authed as mdt */ rq_auth_usr_ost:1, /* authed as ost */ diff --git a/drivers/staging/lustre/lustre/include/lustre_req_layout.h b/drivers/staging/lustre/lustre/include/lustre_req_layout.h index d00aae5..544a43c 100644 --- a/drivers/staging/lustre/lustre/include/lustre_req_layout.h +++ b/drivers/staging/lustre/lustre/include/lustre_req_layout.h @@ -160,7 +160,7 @@ extern struct req_format RQF_MDS_IS_SUBDIR; extern struct req_format RQF_MDS_DONE_WRITING; extern struct req_format RQF_MDS_REINT; extern struct req_format RQF_MDS_REINT_CREATE; -extern struct req_format RQF_MDS_REINT_CREATE_RMT_ACL; +extern struct req_format RQF_MDS_REINT_CREATE_ACL; extern struct req_format RQF_MDS_REINT_CREATE_SLAVE; extern struct req_format RQF_MDS_REINT_CREATE_SYM; extern struct req_format RQF_MDS_REINT_OPEN; diff --git a/drivers/staging/lustre/lustre/include/obd.h b/drivers/staging/lustre/lustre/include/obd.h index e654d42..9971ee5 100644 --- a/drivers/staging/lustre/lustre/include/obd.h +++ b/drivers/staging/lustre/lustre/include/obd.h @@ -1115,9 +1115,6 @@ struct md_ops { ldlm_policy_data_t *, enum ldlm_mode, enum ldlm_cancel_flags flags, void *opaque); - int (*get_remote_perm)(struct obd_export *, const struct lu_fid *, - __u32, struct ptlrpc_request **); - int (*intent_getattr_async)(struct obd_export *, struct md_enqueue_info *, struct ldlm_enqueue_info *); diff --git a/drivers/staging/lustre/lustre/include/obd_class.h b/drivers/staging/lustre/lustre/include/obd_class.h index 2196744..6482a93 100644 --- a/drivers/staging/lustre/lustre/include/obd_class.h +++ b/drivers/staging/lustre/lustre/include/obd_class.h @@ -1650,16 +1650,6 @@ static inline int md_init_ea_size(struct obd_export *exp, int easize, cookiesize, def_cookiesize); } -static inline int md_get_remote_perm(struct obd_export *exp, - const struct lu_fid *fid, __u32 suppgid, - struct ptlrpc_request **request) -{ - EXP_CHECK_MD_OP(exp, get_remote_perm); - EXP_MD_COUNTER_INCREMENT(exp, get_remote_perm); - return MDP(exp->exp_obd, get_remote_perm)(exp, fid, suppgid, - request); -} - static inline int md_intent_getattr_async(struct obd_export *exp, struct md_enqueue_info *minfo, struct ldlm_enqueue_info *einfo) diff --git a/drivers/staging/lustre/lustre/llite/Makefile b/drivers/staging/lustre/lustre/llite/Makefile index 19701e7..2cbb1b8 100644 --- a/drivers/staging/lustre/lustre/llite/Makefile +++ b/drivers/staging/lustre/lustre/llite/Makefile @@ -1,8 +1,7 @@ obj-$(CONFIG_LUSTRE_FS) += lustre.o lustre-y := dcache.o dir.o file.o llite_close.o llite_lib.o llite_nfs.o \ rw.o namei.o symlink.o llite_mmap.o \ - xattr.o xattr_cache.o remote_perm.o llite_rmtacl.o \ - rw26.o super25.o statahead.o \ + xattr.o xattr_cache.o rw26.o super25.o statahead.o \ glimpse.o lcommon_cl.o lcommon_misc.o \ vvp_dev.o vvp_page.o vvp_lock.o vvp_io.o vvp_object.o vvp_req.o \ lproc_llite.o diff --git a/drivers/staging/lustre/lustre/llite/dir.c b/drivers/staging/lustre/lustre/llite/dir.c index 99735f6..2f2c57e 100644 --- a/drivers/staging/lustre/lustre/llite/dir.c +++ b/drivers/staging/lustre/lustre/llite/dir.c @@ -1097,8 +1097,7 @@ static int quotactl_ioctl(struct ll_sb_info *sbi, struct if_quotactl *qctl) case Q_QUOTAOFF: case Q_SETQUOTA: case Q_SETINFO: - if (!capable(CFS_CAP_SYS_ADMIN) || - sbi->ll_flags & LL_SBI_RMT_CLIENT) + if (!capable(CFS_CAP_SYS_ADMIN)) return -EPERM; break; case Q_GETQUOTA: @@ -1106,8 +1105,7 @@ static int quotactl_ioctl(struct ll_sb_info *sbi, struct if_quotactl *qctl) !uid_eq(current_euid(), make_kuid(&init_user_ns, id))) || (type == GRPQUOTA && !in_egroup_p(make_kgid(&init_user_ns, id)))) && - (!capable(CFS_CAP_SYS_ADMIN) || - sbi->ll_flags & LL_SBI_RMT_CLIENT)) + !capable(CFS_CAP_SYS_ADMIN)) return -EPERM; break; case Q_GETINFO: @@ -1118,9 +1116,6 @@ static int quotactl_ioctl(struct ll_sb_info *sbi, struct if_quotactl *qctl) } if (valid != QC_GENERAL) { - if (sbi->ll_flags & LL_SBI_RMT_CLIENT) - return -EOPNOTSUPP; - if (cmd == Q_GETINFO) qctl->qc_cmd = Q_GETOINFO; else if (cmd == Q_GETQUOTA) @@ -1621,8 +1616,7 @@ free_lmm: struct obd_quotactl *oqctl; int error = 0; - if (!capable(CFS_CAP_SYS_ADMIN) || - sbi->ll_flags & LL_SBI_RMT_CLIENT) + if (!capable(CFS_CAP_SYS_ADMIN)) return -EPERM; oqctl = kzalloc(sizeof(*oqctl), GFP_NOFS); @@ -1645,8 +1639,7 @@ free_lmm: case OBD_IOC_POLL_QUOTACHECK: { struct if_quotacheck *check; - if (!capable(CFS_CAP_SYS_ADMIN) || - sbi->ll_flags & LL_SBI_RMT_CLIENT) + if (!capable(CFS_CAP_SYS_ADMIN)) return -EPERM; check = kzalloc(sizeof(*check), GFP_NOFS); @@ -1703,20 +1696,6 @@ out_quotactl: return ll_get_obd_name(inode, cmd, arg); case LL_IOC_FLUSHCTX: return ll_flush_ctx(inode); -#ifdef CONFIG_FS_POSIX_ACL - case LL_IOC_RMTACL: { - if (sbi->ll_flags & LL_SBI_RMT_CLIENT && is_root_inode(inode)) { - struct ll_file_data *fd = LUSTRE_FPRIVATE(file); - - rc = rct_add(&sbi->ll_rct, current_pid(), arg); - if (!rc) - fd->fd_flags |= LL_FILE_RMTACL; - return rc; - } else { - return 0; - } - } -#endif case LL_IOC_GETOBDCOUNT: { int count, vallen; struct obd_export *exp; diff --git a/drivers/staging/lustre/lustre/llite/file.c b/drivers/staging/lustre/lustre/llite/file.c index b0c4548..2d50d1c 100644 --- a/drivers/staging/lustre/lustre/llite/file.c +++ b/drivers/staging/lustre/lustre/llite/file.c @@ -344,18 +344,6 @@ int ll_file_release(struct inode *inode, struct file *file) CDEBUG(D_VFSTRACE, "VFS Op:inode="DFID"(%p)\n", PFID(ll_inode2fid(inode)), inode); -#ifdef CONFIG_FS_POSIX_ACL - if (sbi->ll_flags & LL_SBI_RMT_CLIENT && is_root_inode(inode)) { - struct ll_file_data *fd = LUSTRE_FPRIVATE(file); - - if (unlikely(fd->fd_flags & LL_FILE_RMTACL)) { - fd->fd_flags &= ~LL_FILE_RMTACL; - rct_del(&sbi->ll_rct, current_pid()); - et_search_free(&sbi->ll_et, current_pid()); - } - } -#endif - if (!is_root_inode(inode)) ll_stats_ops_tally(sbi, LPROC_LL_RELEASE, 1); fd = LUSTRE_FPRIVATE(file); @@ -3156,9 +3144,6 @@ int ll_inode_permission(struct inode *inode, int mask) CDEBUG(D_VFSTRACE, "VFS Op:inode="DFID"(%p), inode mode %x mask %o\n", PFID(ll_inode2fid(inode)), inode, inode->i_mode, mask); - if (ll_i2sbi(inode)->ll_flags & LL_SBI_RMT_CLIENT) - return lustre_check_remote_perm(inode, mask); - ll_stats_ops_tally(ll_i2sbi(inode), LPROC_LL_INODE_PERM, 1); rc = generic_permission(inode, mask); diff --git a/drivers/staging/lustre/lustre/llite/llite_internal.h b/drivers/staging/lustre/lustre/llite/llite_internal.h index 7c1a3254..8fe63bd 100644 --- a/drivers/staging/lustre/lustre/llite/llite_internal.h +++ b/drivers/staging/lustre/lustre/llite/llite_internal.h @@ -72,9 +72,6 @@ struct ll_dentry_data { #define LLI_INODE_MAGIC 0x111d0de5 #define LLI_INODE_DEAD 0xdeadd00d -/* remote client permission cache */ -#define REMOTE_PERM_HASHSIZE 16 - struct ll_getname_data { struct dir_context ctx; char *lgd_name; /* points to a buffer with NAME_MAX+1 size */ @@ -82,19 +79,6 @@ struct ll_getname_data { int lgd_found; /* inode matched? */ }; -/* llite setxid/access permission for user on remote client */ -struct ll_remote_perm { - struct hlist_node lrp_list; - uid_t lrp_uid; - gid_t lrp_gid; - uid_t lrp_fsuid; - gid_t lrp_fsgid; - int lrp_access_perm; /* MAY_READ/WRITE/EXEC, this - * is access permission with - * lrp_fsuid/lrp_fsgid. - */ -}; - struct ll_grouplock { struct lu_env *lg_env; struct cl_io *lg_io; @@ -129,9 +113,6 @@ struct ll_inode_info { spinlock_t lli_lock; struct posix_acl *lli_posix_acl; - struct hlist_head *lli_remote_perms; - struct mutex lli_rmtperm_mutex; - /* identifying fields for both metadata and data stacks. */ struct lu_fid lli_fid; /* Parent fid for accessing default stripe data on parent directory @@ -141,8 +122,6 @@ struct ll_inode_info { struct list_head lli_close_list; - unsigned long lli_rmtperm_time; - /* handle is to be sent to MDS later on done_writing and setattr. * Open handle data are needed for the recovery to reconstruct * the inode state on the MDS. XXX: recovery is not ready yet. @@ -407,7 +386,7 @@ enum stats_track_type { #define LL_SBI_FLOCK 0x04 #define LL_SBI_USER_XATTR 0x08 /* support user xattr */ #define LL_SBI_ACL 0x10 /* support ACL */ -#define LL_SBI_RMT_CLIENT 0x40 /* remote client */ +/* LL_SBI_RMT_CLIENT 0x40 remote client */ #define LL_SBI_MDS_CAPA 0x80 /* support mds capa, obsolete */ #define LL_SBI_OSS_CAPA 0x100 /* support oss capa, obsolete */ #define LL_SBI_LOCALFLOCK 0x200 /* Local flocks support by kernel */ @@ -429,7 +408,7 @@ enum stats_track_type { "xattr", \ "acl", \ "???", \ - "rmt_client", \ + "???", \ "mds_capa", \ "oss_capa", \ "flock", \ @@ -445,26 +424,6 @@ enum stats_track_type { "xattr", \ } -#define RCE_HASHES 32 - -struct rmtacl_ctl_entry { - struct list_head rce_list; - pid_t rce_key; /* hash key */ - int rce_ops; /* acl operation type */ -}; - -struct rmtacl_ctl_table { - spinlock_t rct_lock; - struct list_head rct_entries[RCE_HASHES]; -}; - -#define EE_HASHES 32 - -struct eacl_table { - spinlock_t et_lock; - struct list_head et_entries[EE_HASHES]; -}; - struct ll_sb_info { /* this protects pglist and ra_info. It isn't safe to * grab from interrupt contexts @@ -529,8 +488,6 @@ struct ll_sb_info { dev_t ll_sdev_orig; /* save s_dev before assign for * clustered nfs */ - struct rmtacl_ctl_table ll_rct; - struct eacl_table ll_et; __kernel_fsid_t ll_fsid; struct kobject ll_kobj; /* sysfs object */ struct super_block *ll_sb; /* struct super_block (for sysfs code)*/ @@ -982,14 +939,6 @@ ssize_t ll_getxattr(struct dentry *dentry, struct inode *inode, ssize_t ll_listxattr(struct dentry *dentry, char *buffer, size_t size); int ll_removexattr(struct dentry *dentry, const char *name); -/* llite/remote_perm.c */ -extern struct kmem_cache *ll_remote_perm_cachep; -extern struct kmem_cache *ll_rmtperm_hash_cachep; - -void free_rmtperm_hash(struct hlist_head *hash); -int ll_update_remote_perm(struct inode *inode, struct mdt_remote_perm *perm); -int lustre_check_remote_perm(struct inode *inode, int mask); - /** * Common IO arguments for various VFS I/O interfaces. */ @@ -1003,40 +952,7 @@ void ras_update(struct ll_sb_info *sbi, struct inode *inode, void ll_ra_count_put(struct ll_sb_info *sbi, unsigned long len); void ll_ra_stats_inc(struct inode *inode, enum ra_stat which); -/* llite/llite_rmtacl.c */ -#ifdef CONFIG_FS_POSIX_ACL -struct eacl_entry { - struct list_head ee_list; - pid_t ee_key; /* hash key */ - struct lu_fid ee_fid; - int ee_type; /* ACL type for ACCESS or DEFAULT */ - ext_acl_xattr_header *ee_acl; -}; - -u64 rce_ops2valid(int ops); -struct rmtacl_ctl_entry *rct_search(struct rmtacl_ctl_table *rct, pid_t key); -int rct_add(struct rmtacl_ctl_table *rct, pid_t key, int ops); -int rct_del(struct rmtacl_ctl_table *rct, pid_t key); -void rct_init(struct rmtacl_ctl_table *rct); -void rct_fini(struct rmtacl_ctl_table *rct); - -void ee_free(struct eacl_entry *ee); -int ee_add(struct eacl_table *et, pid_t key, struct lu_fid *fid, int type, - ext_acl_xattr_header *header); -struct eacl_entry *et_search_del(struct eacl_table *et, pid_t key, - struct lu_fid *fid, int type); -void et_search_free(struct eacl_table *et, pid_t key); -void et_init(struct eacl_table *et); -void et_fini(struct eacl_table *et); -#else -static inline u64 rce_ops2valid(int ops) -{ - return 0; -} -#endif - /* statahead.c */ - #define LL_SA_RPC_MIN 2 #define LL_SA_RPC_DEF 32 #define LL_SA_RPC_MAX 8192 diff --git a/drivers/staging/lustre/lustre/llite/llite_lib.c b/drivers/staging/lustre/lustre/llite/llite_lib.c index ac833db..ae6a571 100644 --- a/drivers/staging/lustre/lustre/llite/llite_lib.c +++ b/drivers/staging/lustre/lustre/llite/llite_lib.c @@ -171,8 +171,8 @@ static int client_common_fill_super(struct super_block *sb, char *md, char *dt, OBD_CONNECT_VERSION | OBD_CONNECT_BRW_SIZE | OBD_CONNECT_CANCELSET | OBD_CONNECT_FID | OBD_CONNECT_AT | OBD_CONNECT_LOV_V3 | - OBD_CONNECT_RMT_CLIENT | OBD_CONNECT_VBR | - OBD_CONNECT_FULL20 | OBD_CONNECT_64BITHASH| + OBD_CONNECT_VBR | OBD_CONNECT_FULL20 | + OBD_CONNECT_64BITHASH | OBD_CONNECT_EINPROGRESS | OBD_CONNECT_JOBSTATS | OBD_CONNECT_LVB_TYPE | OBD_CONNECT_LAYOUTLOCK | @@ -213,8 +213,6 @@ static int client_common_fill_super(struct super_block *sb, char *md, char *dt, /* real client */ data->ocd_connect_flags |= OBD_CONNECT_REAL; - if (sbi->ll_flags & LL_SBI_RMT_CLIENT) - data->ocd_connect_flags |= OBD_CONNECT_RMT_CLIENT_FORCE; data->ocd_brw_size = MD_MAX_BRW_SIZE; @@ -307,18 +305,6 @@ static int client_common_fill_super(struct super_block *sb, char *md, char *dt, sbi->ll_flags &= ~LL_SBI_ACL; } - if (data->ocd_connect_flags & OBD_CONNECT_RMT_CLIENT) { - if (!(sbi->ll_flags & LL_SBI_RMT_CLIENT)) { - sbi->ll_flags |= LL_SBI_RMT_CLIENT; - LCONSOLE_INFO("client is set as remote by default.\n"); - } - } else { - if (sbi->ll_flags & LL_SBI_RMT_CLIENT) { - sbi->ll_flags &= ~LL_SBI_RMT_CLIENT; - LCONSOLE_INFO("client claims to be remote, but server rejected, forced to be local.\n"); - } - } - if (data->ocd_connect_flags & OBD_CONNECT_64BITHASH) sbi->ll_flags |= LL_SBI_64BIT_HASH; @@ -352,10 +338,9 @@ static int client_common_fill_super(struct super_block *sb, char *md, char *dt, OBD_CONNECT_REQPORTAL | OBD_CONNECT_BRW_SIZE | OBD_CONNECT_CANCELSET | OBD_CONNECT_FID | OBD_CONNECT_SRVLOCK | OBD_CONNECT_TRUNCLOCK| - OBD_CONNECT_AT | OBD_CONNECT_RMT_CLIENT | - OBD_CONNECT_OSS_CAPA | OBD_CONNECT_VBR| - OBD_CONNECT_FULL20 | OBD_CONNECT_64BITHASH | - OBD_CONNECT_MAXBYTES | + OBD_CONNECT_AT | OBD_CONNECT_OSS_CAPA | + OBD_CONNECT_VBR | OBD_CONNECT_FULL20 | + OBD_CONNECT_64BITHASH | OBD_CONNECT_MAXBYTES | OBD_CONNECT_EINPROGRESS | OBD_CONNECT_JOBSTATS | OBD_CONNECT_LVB_TYPE | OBD_CONNECT_LAYOUTLOCK | OBD_CONNECT_PINGLESS; @@ -378,8 +363,6 @@ static int client_common_fill_super(struct super_block *sb, char *md, char *dt, } data->ocd_connect_flags |= OBD_CONNECT_LRU_RESIZE; - if (sbi->ll_flags & LL_SBI_RMT_CLIENT) - data->ocd_connect_flags |= OBD_CONNECT_RMT_CLIENT_FORCE; CDEBUG(D_RPCTRACE, "ocd_connect_flags: %#llx ocd_version: %d ocd_grant: %d\n", data->ocd_connect_flags, @@ -442,9 +425,7 @@ static int client_common_fill_super(struct super_block *sb, char *md, char *dt, * XXX: move this to after cbd setup? */ valid = OBD_MD_FLGETATTR | OBD_MD_FLBLOCKS | OBD_MD_FLMODEASIZE; - if (sbi->ll_flags & LL_SBI_RMT_CLIENT) - valid |= OBD_MD_FLRMTPERM; - else if (sbi->ll_flags & LL_SBI_ACL) + if (sbi->ll_flags & LL_SBI_ACL) valid |= OBD_MD_FLACL; op_data = kzalloc(sizeof(*op_data), GFP_NOFS); @@ -500,13 +481,6 @@ static int client_common_fill_super(struct super_block *sb, char *md, char *dt, goto out_root; } -#ifdef CONFIG_FS_POSIX_ACL - if (sbi->ll_flags & LL_SBI_RMT_CLIENT) { - rct_init(&sbi->ll_rct); - et_init(&sbi->ll_et); - } -#endif - checksum = sbi->ll_flags & LL_SBI_CHECKSUM; err = obd_set_info_async(NULL, sbi->ll_dt_exp, sizeof(KEY_CHECKSUM), KEY_CHECKSUM, sizeof(checksum), &checksum, @@ -604,13 +578,6 @@ static void client_common_put_super(struct super_block *sb) { struct ll_sb_info *sbi = ll_s2sbi(sb); -#ifdef CONFIG_FS_POSIX_ACL - if (sbi->ll_flags & LL_SBI_RMT_CLIENT) { - et_fini(&sbi->ll_et); - rct_fini(&sbi->ll_rct); - } -#endif - ll_close_thread_shutdown(sbi->ll_lcq); cl_sb_fini(sb); @@ -700,11 +667,6 @@ static int ll_options(char *options, int *flags) *flags &= ~tmp; goto next; } - tmp = ll_set_opt("remote_client", s1, LL_SBI_RMT_CLIENT); - if (tmp) { - *flags |= tmp; - goto next; - } tmp = ll_set_opt("user_fid2path", s1, LL_SBI_USER_FID2PATH); if (tmp) { *flags |= tmp; @@ -788,12 +750,9 @@ void ll_lli_init(struct ll_inode_info *lli) lli->lli_maxbytes = MAX_LFS_FILESIZE; spin_lock_init(&lli->lli_lock); lli->lli_posix_acl = NULL; - lli->lli_remote_perms = NULL; - mutex_init(&lli->lli_rmtperm_mutex); /* Do not set lli_fid, it has been initialized already. */ fid_zero(&lli->lli_pfid); INIT_LIST_HEAD(&lli->lli_close_list); - lli->lli_rmtperm_time = 0; lli->lli_pending_och = NULL; lli->lli_mds_read_och = NULL; lli->lli_mds_write_och = NULL; @@ -1075,17 +1034,9 @@ void ll_clear_inode(struct inode *inode) ll_xattr_cache_destroy(inode); - if (sbi->ll_flags & LL_SBI_RMT_CLIENT) { - LASSERT(!lli->lli_posix_acl); - if (lli->lli_remote_perms) { - free_rmtperm_hash(lli->lli_remote_perms); - lli->lli_remote_perms = NULL; - } - } #ifdef CONFIG_FS_POSIX_ACL - else if (lli->lli_posix_acl) { + if (lli->lli_posix_acl) { LASSERT(atomic_read(&lli->lli_posix_acl->a_refcount) == 1); - LASSERT(!lli->lli_remote_perms); posix_acl_release(lli->lli_posix_acl); lli->lli_posix_acl = NULL; } @@ -1537,12 +1488,8 @@ void ll_update_inode(struct inode *inode, struct lustre_md *md) lli->lli_maxbytes = MAX_LFS_FILESIZE; } - if (sbi->ll_flags & LL_SBI_RMT_CLIENT) { - if (body->valid & OBD_MD_FLRMTPERM) - ll_update_remote_perm(inode, md->remote_perm); - } #ifdef CONFIG_FS_POSIX_ACL - else if (body->valid & OBD_MD_FLACL) { + if (body->valid & OBD_MD_FLACL) { spin_lock(&lli->lli_lock); if (lli->lli_posix_acl) posix_acl_release(lli->lli_posix_acl); diff --git a/drivers/staging/lustre/lustre/llite/llite_rmtacl.c b/drivers/staging/lustre/lustre/llite/llite_rmtacl.c deleted file mode 100644 index edb92f9..0000000 --- a/drivers/staging/lustre/lustre/llite/llite_rmtacl.c +++ /dev/null @@ -1,295 +0,0 @@ -/* - * GPL HEADER START - * - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 only, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License version 2 for more details (a copy is included - * in the LICENSE file that accompanied this code). - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; If not, see - * http://www.gnu.org/licenses/gpl-2.0.html - * - * GPL HEADER END - */ -/* - * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. - * Use is subject to license terms. - * - * Copyright (c) 2012, Intel Corporation. - */ -/* - * This file is part of Lustre, http://www.lustre.org/ - * Lustre is a trademark of Sun Microsystems, Inc. - * - * lustre/llite/llite_rmtacl.c - * - * Lustre Remote User Access Control List. - * - * Author: Fan Yong - */ - -#define DEBUG_SUBSYSTEM S_LLITE - -#ifdef CONFIG_FS_POSIX_ACL - -#include "../include/lustre_lite.h" -#include "../include/lustre_eacl.h" -#include "llite_internal.h" - -static inline __u32 rce_hashfunc(uid_t id) -{ - return id & (RCE_HASHES - 1); -} - -static inline __u32 ee_hashfunc(uid_t id) -{ - return id & (EE_HASHES - 1); -} - -u64 rce_ops2valid(int ops) -{ - switch (ops) { - case RMT_LSETFACL: - return OBD_MD_FLRMTLSETFACL; - case RMT_LGETFACL: - return OBD_MD_FLRMTLGETFACL; - case RMT_RSETFACL: - return OBD_MD_FLRMTRSETFACL; - case RMT_RGETFACL: - return OBD_MD_FLRMTRGETFACL; - default: - return 0; - } -} - -static struct rmtacl_ctl_entry *rce_alloc(pid_t key, int ops) -{ - struct rmtacl_ctl_entry *rce; - - rce = kzalloc(sizeof(*rce), GFP_NOFS); - if (!rce) - return NULL; - - INIT_LIST_HEAD(&rce->rce_list); - rce->rce_key = key; - rce->rce_ops = ops; - - return rce; -} - -static void rce_free(struct rmtacl_ctl_entry *rce) -{ - if (!list_empty(&rce->rce_list)) - list_del(&rce->rce_list); - - kfree(rce); -} - -static struct rmtacl_ctl_entry *__rct_search(struct rmtacl_ctl_table *rct, - pid_t key) -{ - struct rmtacl_ctl_entry *rce; - struct list_head *head = &rct->rct_entries[rce_hashfunc(key)]; - - list_for_each_entry(rce, head, rce_list) - if (rce->rce_key == key) - return rce; - - return NULL; -} - -struct rmtacl_ctl_entry *rct_search(struct rmtacl_ctl_table *rct, pid_t key) -{ - struct rmtacl_ctl_entry *rce; - - spin_lock(&rct->rct_lock); - rce = __rct_search(rct, key); - spin_unlock(&rct->rct_lock); - return rce; -} - -int rct_add(struct rmtacl_ctl_table *rct, pid_t key, int ops) -{ - struct rmtacl_ctl_entry *rce, *e; - - rce = rce_alloc(key, ops); - if (!rce) - return -ENOMEM; - - spin_lock(&rct->rct_lock); - e = __rct_search(rct, key); - if (unlikely(e)) { - CWARN("Unexpected stale rmtacl_entry found: [key: %d] [ops: %d]\n", - (int)key, ops); - rce_free(e); - } - list_add_tail(&rce->rce_list, &rct->rct_entries[rce_hashfunc(key)]); - spin_unlock(&rct->rct_lock); - - return 0; -} - -int rct_del(struct rmtacl_ctl_table *rct, pid_t key) -{ - struct rmtacl_ctl_entry *rce; - - spin_lock(&rct->rct_lock); - rce = __rct_search(rct, key); - if (rce) - rce_free(rce); - spin_unlock(&rct->rct_lock); - - return rce ? 0 : -ENOENT; -} - -void rct_init(struct rmtacl_ctl_table *rct) -{ - int i; - - spin_lock_init(&rct->rct_lock); - for (i = 0; i < RCE_HASHES; i++) - INIT_LIST_HEAD(&rct->rct_entries[i]); -} - -void rct_fini(struct rmtacl_ctl_table *rct) -{ - struct rmtacl_ctl_entry *rce; - int i; - - spin_lock(&rct->rct_lock); - for (i = 0; i < RCE_HASHES; i++) - while (!list_empty(&rct->rct_entries[i])) { - rce = list_entry(rct->rct_entries[i].next, - struct rmtacl_ctl_entry, rce_list); - rce_free(rce); - } - spin_unlock(&rct->rct_lock); -} - -static struct eacl_entry *ee_alloc(pid_t key, struct lu_fid *fid, int type, - ext_acl_xattr_header *header) -{ - struct eacl_entry *ee; - - ee = kzalloc(sizeof(*ee), GFP_NOFS); - if (!ee) - return NULL; - - INIT_LIST_HEAD(&ee->ee_list); - ee->ee_key = key; - ee->ee_fid = *fid; - ee->ee_type = type; - ee->ee_acl = header; - - return ee; -} - -void ee_free(struct eacl_entry *ee) -{ - if (!list_empty(&ee->ee_list)) - list_del(&ee->ee_list); - - if (ee->ee_acl) - lustre_ext_acl_xattr_free(ee->ee_acl); - - kfree(ee); -} - -static struct eacl_entry *__et_search_del(struct eacl_table *et, pid_t key, - struct lu_fid *fid, int type) -{ - struct eacl_entry *ee; - struct list_head *head = &et->et_entries[ee_hashfunc(key)]; - - LASSERT(fid); - list_for_each_entry(ee, head, ee_list) - if (ee->ee_key == key) { - if (lu_fid_eq(&ee->ee_fid, fid) && - ee->ee_type == type) { - list_del_init(&ee->ee_list); - return ee; - } - } - - return NULL; -} - -struct eacl_entry *et_search_del(struct eacl_table *et, pid_t key, - struct lu_fid *fid, int type) -{ - struct eacl_entry *ee; - - spin_lock(&et->et_lock); - ee = __et_search_del(et, key, fid, type); - spin_unlock(&et->et_lock); - return ee; -} - -void et_search_free(struct eacl_table *et, pid_t key) -{ - struct eacl_entry *ee, *next; - struct list_head *head = &et->et_entries[ee_hashfunc(key)]; - - spin_lock(&et->et_lock); - list_for_each_entry_safe(ee, next, head, ee_list) - if (ee->ee_key == key) - ee_free(ee); - - spin_unlock(&et->et_lock); -} - -int ee_add(struct eacl_table *et, pid_t key, struct lu_fid *fid, int type, - ext_acl_xattr_header *header) -{ - struct eacl_entry *ee, *e; - - ee = ee_alloc(key, fid, type, header); - if (!ee) - return -ENOMEM; - - spin_lock(&et->et_lock); - e = __et_search_del(et, key, fid, type); - if (unlikely(e)) { - CWARN("Unexpected stale eacl_entry found: [key: %d] [fid: " DFID "] [type: %d]\n", - (int)key, PFID(fid), type); - ee_free(e); - } - list_add_tail(&ee->ee_list, &et->et_entries[ee_hashfunc(key)]); - spin_unlock(&et->et_lock); - - return 0; -} - -void et_init(struct eacl_table *et) -{ - int i; - - spin_lock_init(&et->et_lock); - for (i = 0; i < EE_HASHES; i++) - INIT_LIST_HEAD(&et->et_entries[i]); -} - -void et_fini(struct eacl_table *et) -{ - struct eacl_entry *ee; - int i; - - spin_lock(&et->et_lock); - for (i = 0; i < EE_HASHES; i++) - while (!list_empty(&et->et_entries[i])) { - ee = list_entry(et->et_entries[i].next, - struct eacl_entry, ee_list); - ee_free(ee); - } - spin_unlock(&et->et_lock); -} - -#endif diff --git a/drivers/staging/lustre/lustre/llite/lproc_llite.c b/drivers/staging/lustre/lustre/llite/lproc_llite.c index 6e9a8a5..18a7775 100644 --- a/drivers/staging/lustre/lustre/llite/lproc_llite.c +++ b/drivers/staging/lustre/lustre/llite/lproc_llite.c @@ -176,11 +176,7 @@ LUSTRE_RO_ATTR(filesfree); static ssize_t client_type_show(struct kobject *kobj, struct attribute *attr, char *buf) { - struct ll_sb_info *sbi = container_of(kobj, struct ll_sb_info, - ll_kobj); - - return sprintf(buf, "%s client\n", - sbi->ll_flags & LL_SBI_RMT_CLIENT ? "remote" : "local"); + return sprintf(buf, "local client\n"); } LUSTRE_RO_ATTR(client_type); diff --git a/drivers/staging/lustre/lustre/llite/remote_perm.c b/drivers/staging/lustre/lustre/llite/remote_perm.c deleted file mode 100644 index 9df9e784..0000000 --- a/drivers/staging/lustre/lustre/llite/remote_perm.c +++ /dev/null @@ -1,320 +0,0 @@ -/* - * GPL HEADER START - * - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 only, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License version 2 for more details (a copy is included - * in the LICENSE file that accompanied this code). - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; If not, see - * http://www.gnu.org/licenses/gpl-2.0.html - * - * GPL HEADER END - */ -/* - * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. - * Use is subject to license terms. - * - * Copyright (c) 2011, 2012, Intel Corporation. - */ -/* - * This file is part of Lustre, http://www.lustre.org/ - * Lustre is a trademark of Sun Microsystems, Inc. - * - * lustre/llite/remote_perm.c - * - * Lustre Permission Cache for Remote Client - * - * Author: Lai Siyao - * Author: Fan Yong - */ - -#define DEBUG_SUBSYSTEM S_LLITE - -#include -#include - -#include "../include/lustre_lite.h" -#include "../include/lustre_ha.h" -#include "../include/lustre_dlm.h" -#include "../include/lprocfs_status.h" -#include "../include/lustre_disk.h" -#include "../include/lustre_param.h" -#include "llite_internal.h" - -struct kmem_cache *ll_remote_perm_cachep; -struct kmem_cache *ll_rmtperm_hash_cachep; - -static inline struct ll_remote_perm *alloc_ll_remote_perm(void) -{ - struct ll_remote_perm *lrp; - - lrp = kmem_cache_zalloc(ll_remote_perm_cachep, GFP_KERNEL); - if (lrp) - INIT_HLIST_NODE(&lrp->lrp_list); - return lrp; -} - -static inline void free_ll_remote_perm(struct ll_remote_perm *lrp) -{ - if (!lrp) - return; - - if (!hlist_unhashed(&lrp->lrp_list)) - hlist_del(&lrp->lrp_list); - kmem_cache_free(ll_remote_perm_cachep, lrp); -} - -static struct hlist_head *alloc_rmtperm_hash(void) -{ - struct hlist_head *hash; - int i; - - hash = kmem_cache_zalloc(ll_rmtperm_hash_cachep, GFP_NOFS); - if (!hash) - return NULL; - - for (i = 0; i < REMOTE_PERM_HASHSIZE; i++) - INIT_HLIST_HEAD(hash + i); - - return hash; -} - -void free_rmtperm_hash(struct hlist_head *hash) -{ - int i; - struct ll_remote_perm *lrp; - struct hlist_node *next; - - if (!hash) - return; - - for (i = 0; i < REMOTE_PERM_HASHSIZE; i++) - hlist_for_each_entry_safe(lrp, next, hash + i, lrp_list) - free_ll_remote_perm(lrp); - kmem_cache_free(ll_rmtperm_hash_cachep, hash); -} - -static inline int remote_perm_hashfunc(uid_t uid) -{ - return uid & (REMOTE_PERM_HASHSIZE - 1); -} - -/* NB: setxid permission is not checked here, instead it's done on - * MDT when client get remote permission. - */ -static int do_check_remote_perm(struct ll_inode_info *lli, int mask) -{ - struct hlist_head *head; - struct ll_remote_perm *lrp; - int found = 0, rc; - - if (!lli->lli_remote_perms) - return -ENOENT; - - head = lli->lli_remote_perms + - remote_perm_hashfunc(from_kuid(&init_user_ns, current_uid())); - - spin_lock(&lli->lli_lock); - hlist_for_each_entry(lrp, head, lrp_list) { - if (lrp->lrp_uid != from_kuid(&init_user_ns, current_uid())) - continue; - if (lrp->lrp_gid != from_kgid(&init_user_ns, current_gid())) - continue; - if (lrp->lrp_fsuid != from_kuid(&init_user_ns, current_fsuid())) - continue; - if (lrp->lrp_fsgid != from_kgid(&init_user_ns, current_fsgid())) - continue; - found = 1; - break; - } - - if (!found) { - rc = -ENOENT; - goto out; - } - - CDEBUG(D_SEC, "found remote perm: %u/%u/%u/%u - %#x\n", - lrp->lrp_uid, lrp->lrp_gid, lrp->lrp_fsuid, lrp->lrp_fsgid, - lrp->lrp_access_perm); - rc = ((lrp->lrp_access_perm & mask) == mask) ? 0 : -EACCES; - -out: - spin_unlock(&lli->lli_lock); - return rc; -} - -int ll_update_remote_perm(struct inode *inode, struct mdt_remote_perm *perm) -{ - struct ll_inode_info *lli = ll_i2info(inode); - struct ll_remote_perm *lrp = NULL, *tmp = NULL; - struct hlist_head *head, *perm_hash = NULL; - - LASSERT(ll_i2sbi(inode)->ll_flags & LL_SBI_RMT_CLIENT); - -#if 0 - if (perm->rp_uid != current->uid || - perm->rp_gid != current->gid || - perm->rp_fsuid != current->fsuid || - perm->rp_fsgid != current->fsgid) { - /* user might setxid in this small period */ - CDEBUG(D_SEC, - "remote perm user %u/%u/%u/%u != current %u/%u/%u/%u\n", - perm->rp_uid, perm->rp_gid, perm->rp_fsuid, - perm->rp_fsgid, current->uid, current->gid, - current->fsuid, current->fsgid); - return -EAGAIN; - } -#endif - - if (!lli->lli_remote_perms) { - perm_hash = alloc_rmtperm_hash(); - if (!perm_hash) { - CERROR("alloc lli_remote_perms failed!\n"); - return -ENOMEM; - } - } - - spin_lock(&lli->lli_lock); - - if (!lli->lli_remote_perms) - lli->lli_remote_perms = perm_hash; - else - free_rmtperm_hash(perm_hash); - - head = lli->lli_remote_perms + remote_perm_hashfunc(perm->rp_uid); - -again: - hlist_for_each_entry(tmp, head, lrp_list) { - if (tmp->lrp_uid != perm->rp_uid) - continue; - if (tmp->lrp_gid != perm->rp_gid) - continue; - if (tmp->lrp_fsuid != perm->rp_fsuid) - continue; - if (tmp->lrp_fsgid != perm->rp_fsgid) - continue; - free_ll_remote_perm(lrp); - lrp = tmp; - break; - } - - if (!lrp) { - spin_unlock(&lli->lli_lock); - lrp = alloc_ll_remote_perm(); - if (!lrp) { - CERROR("alloc memory for ll_remote_perm failed!\n"); - return -ENOMEM; - } - spin_lock(&lli->lli_lock); - goto again; - } - - lrp->lrp_access_perm = perm->rp_access_perm; - if (lrp != tmp) { - lrp->lrp_uid = perm->rp_uid; - lrp->lrp_gid = perm->rp_gid; - lrp->lrp_fsuid = perm->rp_fsuid; - lrp->lrp_fsgid = perm->rp_fsgid; - hlist_add_head(&lrp->lrp_list, head); - } - lli->lli_rmtperm_time = cfs_time_current(); - spin_unlock(&lli->lli_lock); - - CDEBUG(D_SEC, "new remote perm@%p: %u/%u/%u/%u - %#x\n", - lrp, lrp->lrp_uid, lrp->lrp_gid, lrp->lrp_fsuid, lrp->lrp_fsgid, - lrp->lrp_access_perm); - - return 0; -} - -int lustre_check_remote_perm(struct inode *inode, int mask) -{ - struct ll_inode_info *lli = ll_i2info(inode); - struct ll_sb_info *sbi = ll_i2sbi(inode); - struct ptlrpc_request *req = NULL; - struct mdt_remote_perm *perm; - unsigned long save; - int i = 0, rc; - - do { - save = lli->lli_rmtperm_time; - rc = do_check_remote_perm(lli, mask); - if (!rc || (rc != -ENOENT && i)) - break; - - might_sleep(); - - mutex_lock(&lli->lli_rmtperm_mutex); - /* check again */ - if (save != lli->lli_rmtperm_time) { - rc = do_check_remote_perm(lli, mask); - if (!rc || (rc != -ENOENT && i)) { - mutex_unlock(&lli->lli_rmtperm_mutex); - break; - } - } - - if (i++ > 5) { - CERROR("check remote perm falls in dead loop!\n"); - LBUG(); - } - - rc = md_get_remote_perm(sbi->ll_md_exp, ll_inode2fid(inode), - ll_i2suppgid(inode), &req); - if (rc) { - mutex_unlock(&lli->lli_rmtperm_mutex); - break; - } - - perm = req_capsule_server_swab_get(&req->rq_pill, &RMF_ACL, - lustre_swab_mdt_remote_perm); - if (unlikely(!perm)) { - mutex_unlock(&lli->lli_rmtperm_mutex); - rc = -EPROTO; - break; - } - - rc = ll_update_remote_perm(inode, perm); - mutex_unlock(&lli->lli_rmtperm_mutex); - if (rc == -ENOMEM) - break; - - ptlrpc_req_finished(req); - req = NULL; - } while (1); - ptlrpc_req_finished(req); - return rc; -} - -#if 0 /* NB: remote perms can't be freed in ll_mdc_blocking_ast of UPDATE lock, - * because it will fail sanity test 48. - */ -void ll_free_remote_perms(struct inode *inode) -{ - struct ll_inode_info *lli = ll_i2info(inode); - struct hlist_head *hash = lli->lli_remote_perms; - struct ll_remote_perm *lrp; - struct hlist_node *node, *next; - int i; - - LASSERT(hash); - - spin_lock(&lli->lli_lock); - - for (i = 0; i < REMOTE_PERM_HASHSIZE; i++) { - hlist_for_each_entry_safe(lrp, node, next, hash + i, lrp_list) - free_ll_remote_perm(lrp); - } - - spin_unlock(&lli->lli_lock); -} -#endif diff --git a/drivers/staging/lustre/lustre/llite/super25.c b/drivers/staging/lustre/lustre/llite/super25.c index b40ea79..3dd7e0e 100644 --- a/drivers/staging/lustre/lustre/llite/super25.c +++ b/drivers/staging/lustre/lustre/llite/super25.c @@ -114,19 +114,6 @@ static int __init lustre_init(void) if (!ll_file_data_slab) goto out_cache; - ll_remote_perm_cachep = kmem_cache_create("ll_remote_perm_cache", - sizeof(struct ll_remote_perm), - 0, 0, NULL); - if (!ll_remote_perm_cachep) - goto out_cache; - - ll_rmtperm_hash_cachep = kmem_cache_create("ll_rmtperm_hash_cache", - REMOTE_PERM_HASHSIZE * - sizeof(struct list_head), - 0, 0, NULL); - if (!ll_rmtperm_hash_cachep) - goto out_cache; - llite_root = debugfs_create_dir("llite", debugfs_lustre_root); if (IS_ERR_OR_NULL(llite_root)) { rc = llite_root ? PTR_ERR(llite_root) : -ENOMEM; @@ -190,8 +177,6 @@ out_debugfs: out_cache: kmem_cache_destroy(ll_inode_cachep); kmem_cache_destroy(ll_file_data_slab); - kmem_cache_destroy(ll_remote_perm_cachep); - kmem_cache_destroy(ll_rmtperm_hash_cachep); return rc; } @@ -209,10 +194,6 @@ static void __exit lustre_exit(void) vvp_global_fini(); kmem_cache_destroy(ll_inode_cachep); - kmem_cache_destroy(ll_rmtperm_hash_cachep); - - kmem_cache_destroy(ll_remote_perm_cachep); - kmem_cache_destroy(ll_file_data_slab); } diff --git a/drivers/staging/lustre/lustre/llite/xattr.c b/drivers/staging/lustre/lustre/llite/xattr.c index 6ce790e..98303cf 100644 --- a/drivers/staging/lustre/lustre/llite/xattr.c +++ b/drivers/staging/lustre/lustre/llite/xattr.c @@ -107,11 +107,6 @@ int ll_setxattr_common(struct inode *inode, const char *name, struct ll_sb_info *sbi = ll_i2sbi(inode); struct ptlrpc_request *req = NULL; int xattr_type, rc; -#ifdef CONFIG_FS_POSIX_ACL - struct rmtacl_ctl_entry *rce = NULL; - posix_acl_xattr_header *new_value = NULL; - ext_acl_xattr_header *acl = NULL; -#endif const char *pv = value; xattr_type = get_xattr_type(name); @@ -139,62 +134,9 @@ int ll_setxattr_common(struct inode *inode, const char *name, strcmp(name, "security.selinux") == 0) return -EOPNOTSUPP; -#ifdef CONFIG_FS_POSIX_ACL - if (sbi->ll_flags & LL_SBI_RMT_CLIENT && - (xattr_type == XATTR_ACL_ACCESS_T || - xattr_type == XATTR_ACL_DEFAULT_T)) { - rce = rct_search(&sbi->ll_rct, current_pid()); - if (!rce || - (rce->rce_ops != RMT_LSETFACL && - rce->rce_ops != RMT_RSETFACL)) - return -EOPNOTSUPP; - - if (rce->rce_ops == RMT_LSETFACL) { - struct eacl_entry *ee; - - ee = et_search_del(&sbi->ll_et, current_pid(), - ll_inode2fid(inode), xattr_type); - if (valid & OBD_MD_FLXATTR) { - acl = lustre_acl_xattr_merge2ext( - (posix_acl_xattr_header *)value, - size, ee->ee_acl); - if (IS_ERR(acl)) { - ee_free(ee); - return PTR_ERR(acl); - } - size = CFS_ACL_XATTR_SIZE(\ - le32_to_cpu(acl->a_count), \ - ext_acl_xattr); - pv = (const char *)acl; - } - ee_free(ee); - } else if (rce->rce_ops == RMT_RSETFACL) { - rc = lustre_posix_acl_xattr_filter( - (posix_acl_xattr_header *)value, - size, &new_value); - if (unlikely(rc < 0)) - return rc; - size = rc; - - pv = (const char *)new_value; - } else { - return -EOPNOTSUPP; - } - - valid |= rce_ops2valid(rce->rce_ops); - } -#endif rc = md_setxattr(sbi->ll_md_exp, ll_inode2fid(inode), valid, name, pv, size, 0, flags, ll_i2suppgid(inode), &req); -#ifdef CONFIG_FS_POSIX_ACL - /* - * Release the posix ACL space. - */ - kfree(new_value); - if (acl) - lustre_ext_acl_xattr_free(acl); -#endif if (rc) { if (rc == -EOPNOTSUPP && xattr_type == XATTR_USER_T) { LCONSOLE_INFO("Disabling user_xattr feature because it is not supported on the server\n"); @@ -284,7 +226,6 @@ int ll_getxattr_common(struct inode *inode, const char *name, struct mdt_body *body; int xattr_type, rc; void *xdata; - struct rmtacl_ctl_entry *rce = NULL; struct ll_inode_info *lli = ll_i2info(inode); CDEBUG(D_VFSTRACE, "VFS Op:inode="DFID"(%p)\n", @@ -315,24 +256,11 @@ int ll_getxattr_common(struct inode *inode, const char *name, return -EOPNOTSUPP; #ifdef CONFIG_FS_POSIX_ACL - if (sbi->ll_flags & LL_SBI_RMT_CLIENT && - (xattr_type == XATTR_ACL_ACCESS_T || - xattr_type == XATTR_ACL_DEFAULT_T)) { - rce = rct_search(&sbi->ll_rct, current_pid()); - if (!rce || - (rce->rce_ops != RMT_LSETFACL && - rce->rce_ops != RMT_LGETFACL && - rce->rce_ops != RMT_RSETFACL && - rce->rce_ops != RMT_RGETFACL)) - return -EOPNOTSUPP; - } - /* posix acl is under protection of LOOKUP lock. when calling to this, * we just have path resolution to the target inode, so we have great * chance that cached ACL is uptodate. */ - if (xattr_type == XATTR_ACL_ACCESS_T && - !(sbi->ll_flags & LL_SBI_RMT_CLIENT)) { + if (xattr_type == XATTR_ACL_ACCESS_T) { struct posix_acl *acl; spin_lock(&lli->lli_lock); @@ -374,9 +302,7 @@ do_getxattr: } else { getxattr_nocache: rc = md_getxattr(sbi->ll_md_exp, ll_inode2fid(inode), - valid | (rce ? rce_ops2valid(rce->rce_ops) : 0), - name, NULL, 0, size, 0, &req); - + valid, name, NULL, 0, size, 0, &req); if (rc < 0) goto out_xattr; @@ -413,25 +339,6 @@ getxattr_nocache: rc = body->eadatasize; } -#ifdef CONFIG_FS_POSIX_ACL - if (rce && rce->rce_ops == RMT_LSETFACL) { - ext_acl_xattr_header *acl; - - acl = lustre_posix_acl_xattr_2ext(buffer, rc); - if (IS_ERR(acl)) { - rc = PTR_ERR(acl); - goto out; - } - - rc = ee_add(&sbi->ll_et, current_pid(), ll_inode2fid(inode), - xattr_type, acl); - if (unlikely(rc < 0)) { - lustre_ext_acl_xattr_free(acl); - goto out; - } - } -#endif - out_xattr: if (rc == -EOPNOTSUPP && xattr_type == XATTR_USER_T) { LCONSOLE_INFO( diff --git a/drivers/staging/lustre/lustre/lmv/lmv_obd.c b/drivers/staging/lustre/lustre/lmv/lmv_obd.c index ab4f4fb..6483f2c 100644 --- a/drivers/staging/lustre/lustre/lmv/lmv_obd.c +++ b/drivers/staging/lustre/lustre/lmv/lmv_obd.c @@ -2607,27 +2607,6 @@ static int lmv_clear_open_replay_data(struct obd_export *exp, return md_clear_open_replay_data(tgt->ltd_exp, och); } -static int lmv_get_remote_perm(struct obd_export *exp, - const struct lu_fid *fid, - __u32 suppgid, struct ptlrpc_request **request) -{ - struct obd_device *obd = exp->exp_obd; - struct lmv_obd *lmv = &obd->u.lmv; - struct lmv_tgt_desc *tgt; - int rc; - - rc = lmv_check_connect(obd); - if (rc) - return rc; - - tgt = lmv_find_target(lmv, fid); - if (IS_ERR(tgt)) - return PTR_ERR(tgt); - - rc = md_get_remote_perm(tgt->ltd_exp, fid, suppgid, request); - return rc; -} - static int lmv_intent_getattr_async(struct obd_export *exp, struct md_enqueue_info *minfo, struct ldlm_enqueue_info *einfo) @@ -2791,7 +2770,6 @@ static struct md_ops lmv_md_ops = { .free_lustre_md = lmv_free_lustre_md, .set_open_replay_data = lmv_set_open_replay_data, .clear_open_replay_data = lmv_clear_open_replay_data, - .get_remote_perm = lmv_get_remote_perm, .intent_getattr_async = lmv_intent_getattr_async, .revalidate_lock = lmv_revalidate_lock }; diff --git a/drivers/staging/lustre/lustre/mdc/mdc_locks.c b/drivers/staging/lustre/lustre/mdc/mdc_locks.c index b395420..d55a5d8 100644 --- a/drivers/staging/lustre/lustre/mdc/mdc_locks.c +++ b/drivers/staging/lustre/lustre/mdc/mdc_locks.c @@ -343,10 +343,6 @@ static struct ptlrpc_request *mdc_intent_open_pack(struct obd_export *exp, mdc_open_pack(req, op_data, it->it_create_mode, 0, it->it_flags, lmm, lmmsize); - /* for remote client, fetch remote perm for current user */ - if (client_is_remote(exp)) - req_capsule_set_size(&req->rq_pill, &RMF_ACL, RCL_SERVER, - sizeof(struct mdt_remote_perm)); ptlrpc_request_set_replen(req); return req; } @@ -440,9 +436,7 @@ static struct ptlrpc_request *mdc_intent_getattr_pack(struct obd_export *exp, struct obd_device *obddev = class_exp2obd(exp); u64 valid = OBD_MD_FLGETATTR | OBD_MD_FLEASIZE | OBD_MD_FLMODEASIZE | OBD_MD_FLDIREA | - OBD_MD_MEA | - (client_is_remote(exp) ? - OBD_MD_FLRMTPERM : OBD_MD_FLACL); + OBD_MD_MEA | OBD_MD_FLACL; struct ldlm_intent *lit; int rc; int easize; @@ -474,9 +468,6 @@ static struct ptlrpc_request *mdc_intent_getattr_pack(struct obd_export *exp, mdc_getattr_pack(req, valid, it->it_flags, op_data, easize); req_capsule_set_size(&req->rq_pill, &RMF_MDT_MD, RCL_SERVER, easize); - if (client_is_remote(exp)) - req_capsule_set_size(&req->rq_pill, &RMF_ACL, RCL_SERVER, - sizeof(struct mdt_remote_perm)); ptlrpc_request_set_replen(req); return req; } @@ -683,16 +674,6 @@ static int mdc_finish_enqueue(struct obd_export *exp, memcpy(lmm, eadata, body->eadatasize); } } - - if (body->valid & OBD_MD_FLRMTPERM) { - struct mdt_remote_perm *perm; - - LASSERT(client_is_remote(exp)); - perm = req_capsule_server_swab_get(pill, &RMF_ACL, - lustre_swab_mdt_remote_perm); - if (!perm) - return -EPROTO; - } } else if (it->it_op & IT_LAYOUT) { /* maybe the lock was granted right away and layout * is packed into RMF_DLM_LVB of req diff --git a/drivers/staging/lustre/lustre/mdc/mdc_reint.c b/drivers/staging/lustre/lustre/mdc/mdc_reint.c index 661488e..5dba2c8 100644 --- a/drivers/staging/lustre/lustre/mdc/mdc_reint.c +++ b/drivers/staging/lustre/lustre/mdc/mdc_reint.c @@ -230,7 +230,7 @@ rebuild: MDS_INODELOCK_UPDATE); req = ptlrpc_request_alloc(class_exp2cliimp(exp), - &RQF_MDS_REINT_CREATE_RMT_ACL); + &RQF_MDS_REINT_CREATE_ACL); if (!req) { ldlm_lock_list_put(&cancels, l_bl_ast, count); return -ENOMEM; diff --git a/drivers/staging/lustre/lustre/mdc/mdc_request.c b/drivers/staging/lustre/lustre/mdc/mdc_request.c index f371e1d..f7e30b1 100644 --- a/drivers/staging/lustre/lustre/mdc/mdc_request.c +++ b/drivers/staging/lustre/lustre/mdc/mdc_request.c @@ -146,16 +146,6 @@ static int mdc_getattr_common(struct obd_export *exp, return -EPROTO; } - if (body->valid & OBD_MD_FLRMTPERM) { - struct mdt_remote_perm *perm; - - LASSERT(client_is_remote(exp)); - perm = req_capsule_server_swab_get(pill, &RMF_ACL, - lustre_swab_mdt_remote_perm); - if (!perm) - return -EPROTO; - } - return 0; } @@ -186,11 +176,6 @@ static int mdc_getattr(struct obd_export *exp, struct md_op_data *op_data, req_capsule_set_size(&req->rq_pill, &RMF_MDT_MD, RCL_SERVER, op_data->op_mode); - if (op_data->op_valid & OBD_MD_FLRMTPERM) { - LASSERT(client_is_remote(exp)); - req_capsule_set_size(&req->rq_pill, &RMF_ACL, RCL_SERVER, - sizeof(struct mdt_remote_perm)); - } ptlrpc_request_set_replen(req); rc = mdc_getattr_common(exp, req); @@ -535,16 +520,7 @@ static int mdc_get_lustre_md(struct obd_export *exp, } rc = 0; - if (md->body->valid & OBD_MD_FLRMTPERM) { - /* remote permission */ - LASSERT(client_is_remote(exp)); - md->remote_perm = req_capsule_server_swab_get(pill, &RMF_ACL, - lustre_swab_mdt_remote_perm); - if (!md->remote_perm) { - rc = -EPROTO; - goto out; - } - } else if (md->body->valid & OBD_MD_FLACL) { + if (md->body->valid & OBD_MD_FLACL) { /* for ACL, it's possible that FLACL is set but aclsize is zero. * only when aclsize != 0 there's an actual segment for ACL * in reply buffer. @@ -1164,7 +1140,7 @@ static int mdc_ioc_hsm_progress(struct obd_export *exp, goto out; } - mdc_pack_body(req, NULL, OBD_MD_FLRMTPERM, 0, -1, 0); + mdc_pack_body(req, NULL, 0, 0, -1, 0); /* Copy hsm_progress struct */ req_hpk = req_capsule_client_get(&req->rq_pill, &RMF_MDS_HSM_PROGRESS); @@ -1198,7 +1174,7 @@ static int mdc_ioc_hsm_ct_register(struct obd_import *imp, __u32 archives) goto out; } - mdc_pack_body(req, NULL, OBD_MD_FLRMTPERM, 0, -1, 0); + mdc_pack_body(req, NULL, 0, 0, -1, 0); /* Copy hsm_progress struct */ archive_mask = req_capsule_client_get(&req->rq_pill, @@ -1237,7 +1213,7 @@ static int mdc_ioc_hsm_current_action(struct obd_export *exp, return rc; } - mdc_pack_body(req, &op_data->op_fid1, OBD_MD_FLRMTPERM, 0, + mdc_pack_body(req, &op_data->op_fid1, 0, 0, op_data->op_suppgids[0], 0); ptlrpc_request_set_replen(req); @@ -1273,7 +1249,7 @@ static int mdc_ioc_hsm_ct_unregister(struct obd_import *imp) goto out; } - mdc_pack_body(req, NULL, OBD_MD_FLRMTPERM, 0, -1, 0); + mdc_pack_body(req, NULL, 0, 0, -1, 0); ptlrpc_request_set_replen(req); @@ -1302,7 +1278,7 @@ static int mdc_ioc_hsm_state_get(struct obd_export *exp, return rc; } - mdc_pack_body(req, &op_data->op_fid1, OBD_MD_FLRMTPERM, 0, + mdc_pack_body(req, &op_data->op_fid1, 0, 0, op_data->op_suppgids[0], 0); ptlrpc_request_set_replen(req); @@ -1343,7 +1319,7 @@ static int mdc_ioc_hsm_state_set(struct obd_export *exp, return rc; } - mdc_pack_body(req, &op_data->op_fid1, OBD_MD_FLRMTPERM, 0, + mdc_pack_body(req, &op_data->op_fid1, 0, 0, op_data->op_suppgids[0], 0); /* Copy states */ @@ -1390,7 +1366,7 @@ static int mdc_ioc_hsm_request(struct obd_export *exp, return rc; } - mdc_pack_body(req, NULL, OBD_MD_FLRMTPERM, 0, -1, 0); + mdc_pack_body(req, NULL, 0, 0, -1, 0); /* Copy hsm_request struct */ req_hr = req_capsule_client_get(&req->rq_pill, &RMF_MDS_HSM_REQUEST); @@ -2428,41 +2404,6 @@ static int mdc_process_config(struct obd_device *obd, u32 len, void *buf) return rc; } -/* get remote permission for current user on fid */ -static int mdc_get_remote_perm(struct obd_export *exp, const struct lu_fid *fid, - __u32 suppgid, struct ptlrpc_request **request) -{ - struct ptlrpc_request *req; - int rc; - - LASSERT(client_is_remote(exp)); - - *request = NULL; - req = ptlrpc_request_alloc(class_exp2cliimp(exp), &RQF_MDS_GETATTR); - if (!req) - return -ENOMEM; - - rc = ptlrpc_request_pack(req, LUSTRE_MDS_VERSION, MDS_GETATTR); - if (rc) { - ptlrpc_request_free(req); - return rc; - } - - mdc_pack_body(req, fid, OBD_MD_FLRMTPERM, 0, suppgid, 0); - - req_capsule_set_size(&req->rq_pill, &RMF_ACL, RCL_SERVER, - sizeof(struct mdt_remote_perm)); - - ptlrpc_request_set_replen(req); - - rc = ptlrpc_queue_wait(req); - if (rc) - ptlrpc_req_finished(req); - else - *request = req; - return rc; -} - static struct obd_ops mdc_obd_ops = { .owner = THIS_MODULE, .setup = mdc_setup, @@ -2514,7 +2455,6 @@ static struct md_ops mdc_md_ops = { .free_lustre_md = mdc_free_lustre_md, .set_open_replay_data = mdc_set_open_replay_data, .clear_open_replay_data = mdc_clear_open_replay_data, - .get_remote_perm = mdc_get_remote_perm, .intent_getattr_async = mdc_intent_getattr_async, .revalidate_lock = mdc_revalidate_lock }; diff --git a/drivers/staging/lustre/lustre/obdclass/Makefile b/drivers/staging/lustre/lustre/obdclass/Makefile index c404eb3..df7e47f 100644 --- a/drivers/staging/lustre/lustre/obdclass/Makefile +++ b/drivers/staging/lustre/lustre/obdclass/Makefile @@ -5,5 +5,4 @@ obdclass-y := linux/linux-module.o linux/linux-obdo.o linux/linux-sysctl.o \ genops.o uuid.o lprocfs_status.o lprocfs_counters.o \ lustre_handles.o lustre_peer.o statfs_pack.o \ obdo.o obd_config.o obd_mount.o lu_object.o lu_ref.o \ - cl_object.o cl_page.o cl_lock.o cl_io.o \ - acl.o kernelcomm.o + cl_object.o cl_page.o cl_lock.o cl_io.o kernelcomm.o diff --git a/drivers/staging/lustre/lustre/obdclass/acl.c b/drivers/staging/lustre/lustre/obdclass/acl.c deleted file mode 100644 index 30d8b42..0000000 --- a/drivers/staging/lustre/lustre/obdclass/acl.c +++ /dev/null @@ -1,411 +0,0 @@ -/* - * GPL HEADER START - * - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 only, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License version 2 for more details (a copy is included - * in the LICENSE file that accompanied this code). - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; If not, see - * http://www.gnu.org/licenses/gpl-2.0.html - * - * GPL HEADER END - */ -/* - * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. - * Use is subject to license terms. - * - * Copyright (c) 2012, Intel Corporation. - */ -/* - * This file is part of Lustre, http://www.lustre.org/ - * Lustre is a trademark of Sun Microsystems, Inc. - * - * lustre/obdclass/acl.c - * - * Lustre Access Control List. - * - * Author: Fan Yong - */ - -#define DEBUG_SUBSYSTEM S_SEC -#include "../include/lu_object.h" -#include "../include/lustre_acl.h" -#include "../include/lustre_eacl.h" -#include "../include/obd_support.h" - -#ifdef CONFIG_FS_POSIX_ACL - -#define CFS_ACL_XATTR_VERSION POSIX_ACL_XATTR_VERSION - -enum { - ES_UNK = 0, /* unknown stat */ - ES_UNC = 1, /* ACL entry is not changed */ - ES_MOD = 2, /* ACL entry is modified */ - ES_ADD = 3, /* ACL entry is added */ - ES_DEL = 4 /* ACL entry is deleted */ -}; - -static inline void lustre_ext_acl_le_to_cpu(ext_acl_xattr_entry *d, - ext_acl_xattr_entry *s) -{ - d->e_tag = le16_to_cpu(s->e_tag); - d->e_perm = le16_to_cpu(s->e_perm); - d->e_id = le32_to_cpu(s->e_id); - d->e_stat = le32_to_cpu(s->e_stat); -} - -static inline void lustre_ext_acl_cpu_to_le(ext_acl_xattr_entry *d, - ext_acl_xattr_entry *s) -{ - d->e_tag = cpu_to_le16(s->e_tag); - d->e_perm = cpu_to_le16(s->e_perm); - d->e_id = cpu_to_le32(s->e_id); - d->e_stat = cpu_to_le32(s->e_stat); -} - -static inline void lustre_posix_acl_le_to_cpu(posix_acl_xattr_entry *d, - posix_acl_xattr_entry *s) -{ - d->e_tag = le16_to_cpu(s->e_tag); - d->e_perm = le16_to_cpu(s->e_perm); - d->e_id = le32_to_cpu(s->e_id); -} - -static inline void lustre_posix_acl_cpu_to_le(posix_acl_xattr_entry *d, - posix_acl_xattr_entry *s) -{ - d->e_tag = cpu_to_le16(s->e_tag); - d->e_perm = cpu_to_le16(s->e_perm); - d->e_id = cpu_to_le32(s->e_id); -} - -/* if "new_count == 0", then "new = {a_version, NULL}", NOT NULL. */ -static int lustre_posix_acl_xattr_reduce_space(posix_acl_xattr_header **header, - int old_count, int new_count) -{ - int old_size = CFS_ACL_XATTR_SIZE(old_count, posix_acl_xattr); - int new_size = CFS_ACL_XATTR_SIZE(new_count, posix_acl_xattr); - posix_acl_xattr_header *new; - - if (unlikely(old_count <= new_count)) - return old_size; - - new = kmemdup(*header, new_size, GFP_NOFS); - if (unlikely(!new)) - return -ENOMEM; - - kfree(*header); - *header = new; - return new_size; -} - -/* if "new_count == 0", then "new = {0, NULL}", NOT NULL. */ -static int lustre_ext_acl_xattr_reduce_space(ext_acl_xattr_header **header, - int old_count) -{ - int ext_count = le32_to_cpu((*header)->a_count); - int ext_size = CFS_ACL_XATTR_SIZE(ext_count, ext_acl_xattr); - ext_acl_xattr_header *new; - - if (unlikely(old_count <= ext_count)) - return 0; - - new = kmemdup(*header, ext_size, GFP_NOFS); - if (unlikely(!new)) - return -ENOMEM; - - kfree(*header); - *header = new; - return 0; -} - -/* - * Generate new extended ACL based on the posix ACL. - */ -ext_acl_xattr_header * -lustre_posix_acl_xattr_2ext(posix_acl_xattr_header *header, int size) -{ - int count, i, esize; - ext_acl_xattr_header *new; - - if (unlikely(size < 0)) - return ERR_PTR(-EINVAL); - else if (!size) - count = 0; - else - count = CFS_ACL_XATTR_COUNT(size, posix_acl_xattr); - esize = CFS_ACL_XATTR_SIZE(count, ext_acl_xattr); - new = kzalloc(esize, GFP_NOFS); - if (unlikely(!new)) - return ERR_PTR(-ENOMEM); - - new->a_count = cpu_to_le32(count); - for (i = 0; i < count; i++) { - new->a_entries[i].e_tag = header->a_entries[i].e_tag; - new->a_entries[i].e_perm = header->a_entries[i].e_perm; - new->a_entries[i].e_id = header->a_entries[i].e_id; - new->a_entries[i].e_stat = cpu_to_le32(ES_UNK); - } - - return new; -} -EXPORT_SYMBOL(lustre_posix_acl_xattr_2ext); - -/* - * Filter out the "nobody" entries in the posix ACL. - */ -int lustre_posix_acl_xattr_filter(posix_acl_xattr_header *header, size_t size, - posix_acl_xattr_header **out) -{ - int count, i, j, rc = 0; - __u32 id; - posix_acl_xattr_header *new; - - if (!size) - return 0; - if (size < sizeof(*new)) - return -EINVAL; - - new = kzalloc(size, GFP_NOFS); - if (unlikely(!new)) - return -ENOMEM; - - new->a_version = cpu_to_le32(CFS_ACL_XATTR_VERSION); - count = CFS_ACL_XATTR_COUNT(size, posix_acl_xattr); - for (i = 0, j = 0; i < count; i++) { - id = le32_to_cpu(header->a_entries[i].e_id); - switch (le16_to_cpu(header->a_entries[i].e_tag)) { - case ACL_USER_OBJ: - case ACL_GROUP_OBJ: - case ACL_MASK: - case ACL_OTHER: - if (id != ACL_UNDEFINED_ID) { - rc = -EIO; - goto _out; - } - - memcpy(&new->a_entries[j++], &header->a_entries[i], - sizeof(posix_acl_xattr_entry)); - break; - case ACL_USER: - if (id != NOBODY_UID) - memcpy(&new->a_entries[j++], - &header->a_entries[i], - sizeof(posix_acl_xattr_entry)); - break; - case ACL_GROUP: - if (id != NOBODY_GID) - memcpy(&new->a_entries[j++], - &header->a_entries[i], - sizeof(posix_acl_xattr_entry)); - break; - default: - rc = -EIO; - goto _out; - } - } - - /* free unused space. */ - rc = lustre_posix_acl_xattr_reduce_space(&new, count, j); - if (rc >= 0) { - size = rc; - *out = new; - rc = 0; - } - -_out: - if (rc) { - kfree(new); - size = rc; - } - return size; -} -EXPORT_SYMBOL(lustre_posix_acl_xattr_filter); - -/* - * Release the extended ACL space. - */ -void lustre_ext_acl_xattr_free(ext_acl_xattr_header *header) -{ - kfree(header); -} -EXPORT_SYMBOL(lustre_ext_acl_xattr_free); - -static ext_acl_xattr_entry * -lustre_ext_acl_xattr_search(ext_acl_xattr_header *header, - posix_acl_xattr_entry *entry, int *pos) -{ - int once, start, end, i, j, count = le32_to_cpu(header->a_count); - - once = 0; - start = *pos; - end = count; - -again: - for (i = start; i < end; i++) { - if (header->a_entries[i].e_tag == entry->e_tag && - header->a_entries[i].e_id == entry->e_id) { - j = i; - if (++i >= count) - i = 0; - *pos = i; - return &header->a_entries[j]; - } - } - - if (!once) { - once = 1; - start = 0; - end = *pos; - goto again; - } - - return NULL; -} - -/* - * Merge the posix ACL and the extended ACL into new extended ACL. - */ -ext_acl_xattr_header * -lustre_acl_xattr_merge2ext(posix_acl_xattr_header *posix_header, int size, - ext_acl_xattr_header *ext_header) -{ - int ori_ext_count, posix_count, ext_count, ext_size; - int i, j, pos = 0, rc = 0; - posix_acl_xattr_entry pae; - ext_acl_xattr_header *new; - ext_acl_xattr_entry *ee, eae; - - if (unlikely(size < 0)) - return ERR_PTR(-EINVAL); - else if (!size) - posix_count = 0; - else - posix_count = CFS_ACL_XATTR_COUNT(size, posix_acl_xattr); - ori_ext_count = le32_to_cpu(ext_header->a_count); - ext_count = posix_count + ori_ext_count; - ext_size = CFS_ACL_XATTR_SIZE(ext_count, ext_acl_xattr); - - new = kzalloc(ext_size, GFP_NOFS); - if (unlikely(!new)) - return ERR_PTR(-ENOMEM); - - for (i = 0, j = 0; i < posix_count; i++) { - lustre_posix_acl_le_to_cpu(&pae, &posix_header->a_entries[i]); - switch (pae.e_tag) { - case ACL_USER_OBJ: - case ACL_GROUP_OBJ: - case ACL_MASK: - case ACL_OTHER: - if (pae.e_id != ACL_UNDEFINED_ID) { - rc = -EIO; - goto out; - } - case ACL_USER: - /* ignore "nobody" entry. */ - if (pae.e_id == NOBODY_UID) - break; - - new->a_entries[j].e_tag = - posix_header->a_entries[i].e_tag; - new->a_entries[j].e_perm = - posix_header->a_entries[i].e_perm; - new->a_entries[j].e_id = - posix_header->a_entries[i].e_id; - ee = lustre_ext_acl_xattr_search(ext_header, - &posix_header->a_entries[i], &pos); - if (ee) { - if (posix_header->a_entries[i].e_perm != - ee->e_perm) - /* entry modified. */ - ee->e_stat = - new->a_entries[j++].e_stat = - cpu_to_le32(ES_MOD); - else - /* entry unchanged. */ - ee->e_stat = - new->a_entries[j++].e_stat = - cpu_to_le32(ES_UNC); - } else { - /* new entry. */ - new->a_entries[j++].e_stat = - cpu_to_le32(ES_ADD); - } - break; - case ACL_GROUP: - /* ignore "nobody" entry. */ - if (pae.e_id == NOBODY_GID) - break; - new->a_entries[j].e_tag = - posix_header->a_entries[i].e_tag; - new->a_entries[j].e_perm = - posix_header->a_entries[i].e_perm; - new->a_entries[j].e_id = - posix_header->a_entries[i].e_id; - ee = lustre_ext_acl_xattr_search(ext_header, - &posix_header->a_entries[i], &pos); - if (ee) { - if (posix_header->a_entries[i].e_perm != - ee->e_perm) - /* entry modified. */ - ee->e_stat = - new->a_entries[j++].e_stat = - cpu_to_le32(ES_MOD); - else - /* entry unchanged. */ - ee->e_stat = - new->a_entries[j++].e_stat = - cpu_to_le32(ES_UNC); - } else { - /* new entry. */ - new->a_entries[j++].e_stat = - cpu_to_le32(ES_ADD); - } - break; - default: - rc = -EIO; - goto out; - } - } - - /* process deleted entries. */ - for (i = 0; i < ori_ext_count; i++) { - lustre_ext_acl_le_to_cpu(&eae, &ext_header->a_entries[i]); - if (eae.e_stat == ES_UNK) { - /* ignore "nobody" entry. */ - if ((eae.e_tag == ACL_USER && eae.e_id == NOBODY_UID) || - (eae.e_tag == ACL_GROUP && eae.e_id == NOBODY_GID)) - continue; - - new->a_entries[j].e_tag = - ext_header->a_entries[i].e_tag; - new->a_entries[j].e_perm = - ext_header->a_entries[i].e_perm; - new->a_entries[j].e_id = ext_header->a_entries[i].e_id; - new->a_entries[j++].e_stat = cpu_to_le32(ES_DEL); - } - } - - new->a_count = cpu_to_le32(j); - /* free unused space. */ - rc = lustre_ext_acl_xattr_reduce_space(&new, ext_count); - -out: - if (rc) { - kfree(new); - new = ERR_PTR(rc); - } - return new; -} -EXPORT_SYMBOL(lustre_acl_xattr_merge2ext); - -#endif diff --git a/drivers/staging/lustre/lustre/osc/osc_cache.c b/drivers/staging/lustre/lustre/osc/osc_cache.c index 1a6df43..4c78b53 100644 --- a/drivers/staging/lustre/lustre/osc/osc_cache.c +++ b/drivers/staging/lustre/lustre/osc/osc_cache.c @@ -2367,7 +2367,7 @@ int osc_prep_async_page(struct osc_object *osc, struct osc_page *ops, oap->oap_obj_off = offset; LASSERT(!(offset & ~PAGE_MASK)); - if (!client_is_remote(exp) && capable(CFS_CAP_SYS_RESOURCE)) + if (capable(CFS_CAP_SYS_RESOURCE)) oap->oap_brw_flags = OBD_BRW_NOQUOTA; INIT_LIST_HEAD(&oap->oap_pending_item); @@ -2406,8 +2406,7 @@ int osc_queue_async_io(const struct lu_env *env, struct cl_io *io, /* Set the OBD_BRW_SRVLOCK before the page is queued. */ brw_flags |= ops->ops_srvlock ? OBD_BRW_SRVLOCK : 0; - if (!client_is_remote(osc_export(osc)) && - capable(CFS_CAP_SYS_RESOURCE)) { + if (capable(CFS_CAP_SYS_RESOURCE)) { brw_flags |= OBD_BRW_NOQUOTA; cmd |= OBD_BRW_NOQUOTA; } diff --git a/drivers/staging/lustre/lustre/osc/osc_page.c b/drivers/staging/lustre/lustre/osc/osc_page.c index 57d8a5a..18c261b 100644 --- a/drivers/staging/lustre/lustre/osc/osc_page.c +++ b/drivers/staging/lustre/lustre/osc/osc_page.c @@ -357,7 +357,6 @@ void osc_page_submit(const struct lu_env *env, struct osc_page *opg, enum cl_req_type crt, int brw_flags) { struct osc_async_page *oap = &opg->ops_oap; - struct osc_object *obj = oap->oap_obj; LASSERTF(oap->oap_magic == OAP_MAGIC, "Bad oap magic: oap %p, magic 0x%x\n", oap, oap->oap_magic); @@ -372,8 +371,7 @@ void osc_page_submit(const struct lu_env *env, struct osc_page *opg, if (osc_over_unstable_soft_limit(oap->oap_cli)) oap->oap_brw_flags |= OBD_BRW_SOFT_SYNC; - if (!client_is_remote(osc_export(obj)) && - capable(CFS_CAP_SYS_RESOURCE)) { + if (capable(CFS_CAP_SYS_RESOURCE)) { oap->oap_brw_flags |= OBD_BRW_NOQUOTA; oap->oap_cmd |= OBD_BRW_NOQUOTA; } diff --git a/drivers/staging/lustre/lustre/ptlrpc/layout.c b/drivers/staging/lustre/lustre/ptlrpc/layout.c index e6ff97d..ab5d851 100644 --- a/drivers/staging/lustre/lustre/ptlrpc/layout.c +++ b/drivers/staging/lustre/lustre/ptlrpc/layout.c @@ -194,7 +194,7 @@ static const struct req_msg_field *mds_reint_create_slave_client[] = { &RMF_DLM_REQ }; -static const struct req_msg_field *mds_reint_create_rmt_acl_client[] = { +static const struct req_msg_field *mds_reint_create_acl_client[] = { &RMF_PTLRPC_BODY, &RMF_REC_REINT, &RMF_CAPA1, @@ -675,7 +675,7 @@ static struct req_format *req_formats[] = { &RQF_MDS_DONE_WRITING, &RQF_MDS_REINT, &RQF_MDS_REINT_CREATE, - &RQF_MDS_REINT_CREATE_RMT_ACL, + &RQF_MDS_REINT_CREATE_ACL, &RQF_MDS_REINT_CREATE_SLAVE, &RQF_MDS_REINT_CREATE_SYM, &RQF_MDS_REINT_OPEN, @@ -1238,10 +1238,10 @@ struct req_format RQF_MDS_REINT_CREATE = mds_reint_create_client, mdt_body_capa); EXPORT_SYMBOL(RQF_MDS_REINT_CREATE); -struct req_format RQF_MDS_REINT_CREATE_RMT_ACL = - DEFINE_REQ_FMT0("MDS_REINT_CREATE_RMT_ACL", - mds_reint_create_rmt_acl_client, mdt_body_capa); -EXPORT_SYMBOL(RQF_MDS_REINT_CREATE_RMT_ACL); +struct req_format RQF_MDS_REINT_CREATE_ACL = + DEFINE_REQ_FMT0("MDS_REINT_CREATE_ACL", + mds_reint_create_acl_client, mdt_body_capa); +EXPORT_SYMBOL(RQF_MDS_REINT_CREATE_ACL); struct req_format RQF_MDS_REINT_CREATE_SLAVE = DEFINE_REQ_FMT0("MDS_REINT_CREATE_EA", diff --git a/drivers/staging/lustre/lustre/ptlrpc/pack_generic.c b/drivers/staging/lustre/lustre/ptlrpc/pack_generic.c index 9ff58a1..b514f18 100644 --- a/drivers/staging/lustre/lustre/ptlrpc/pack_generic.c +++ b/drivers/staging/lustre/lustre/ptlrpc/pack_generic.c @@ -1802,19 +1802,6 @@ void lustre_swab_obd_quotactl(struct obd_quotactl *q) } EXPORT_SYMBOL(lustre_swab_obd_quotactl); -void lustre_swab_mdt_remote_perm(struct mdt_remote_perm *p) -{ - __swab32s(&p->rp_uid); - __swab32s(&p->rp_gid); - __swab32s(&p->rp_fsuid); - __swab32s(&p->rp_fsuid_h); - __swab32s(&p->rp_fsgid); - __swab32s(&p->rp_fsgid_h); - __swab32s(&p->rp_access_perm); - __swab32s(&p->rp_padding); -}; -EXPORT_SYMBOL(lustre_swab_mdt_remote_perm); - void lustre_swab_fid2path(struct getinfo_fid2path *gf) { lustre_swab_lu_fid(&gf->gf_fid); diff --git a/drivers/staging/lustre/lustre/ptlrpc/wiretest.c b/drivers/staging/lustre/lustre/ptlrpc/wiretest.c index 9fd9de9..6cc2b2e 100644 --- a/drivers/staging/lustre/lustre/ptlrpc/wiretest.c +++ b/drivers/staging/lustre/lustre/ptlrpc/wiretest.c @@ -1265,8 +1265,6 @@ void lustre_assert_wire_constants(void) OBD_MD_FLXATTRRM); LASSERTF(OBD_MD_FLACL == (0x0000008000000000ULL), "found 0x%.16llxULL\n", OBD_MD_FLACL); - LASSERTF(OBD_MD_FLRMTPERM == (0x0000010000000000ULL), "found 0x%.16llxULL\n", - OBD_MD_FLRMTPERM); LASSERTF(OBD_MD_FLMDSCAPA == (0x0000020000000000ULL), "found 0x%.16llxULL\n", OBD_MD_FLMDSCAPA); LASSERTF(OBD_MD_FLOSSCAPA == (0x0000040000000000ULL), "found 0x%.16llxULL\n", @@ -1277,14 +1275,6 @@ void lustre_assert_wire_constants(void) OBD_MD_FLCROSSREF); LASSERTF(OBD_MD_FLGETATTRLOCK == (0x0000200000000000ULL), "found 0x%.16llxULL\n", OBD_MD_FLGETATTRLOCK); - LASSERTF(OBD_MD_FLRMTLSETFACL == (0x0001000000000000ULL), "found 0x%.16llxULL\n", - OBD_MD_FLRMTLSETFACL); - LASSERTF(OBD_MD_FLRMTLGETFACL == (0x0002000000000000ULL), "found 0x%.16llxULL\n", - OBD_MD_FLRMTLGETFACL); - LASSERTF(OBD_MD_FLRMTRSETFACL == (0x0004000000000000ULL), "found 0x%.16llxULL\n", - OBD_MD_FLRMTRSETFACL); - LASSERTF(OBD_MD_FLRMTRGETFACL == (0x0008000000000000ULL), "found 0x%.16llxULL\n", - OBD_MD_FLRMTRGETFACL); LASSERTF(OBD_MD_FLDATAVERSION == (0x0010000000000000ULL), "found 0x%.16llxULL\n", OBD_MD_FLDATAVERSION); CLASSERT(OBD_FL_INLINEDATA == 0x00000001); @@ -1891,44 +1881,6 @@ void lustre_assert_wire_constants(void) LASSERTF((int)sizeof(((struct mdt_ioepoch *)0)->padding) == 4, "found %lld\n", (long long)(int)sizeof(((struct mdt_ioepoch *)0)->padding)); - /* Checks for struct mdt_remote_perm */ - LASSERTF((int)sizeof(struct mdt_remote_perm) == 32, "found %lld\n", - (long long)(int)sizeof(struct mdt_remote_perm)); - LASSERTF((int)offsetof(struct mdt_remote_perm, rp_uid) == 0, "found %lld\n", - (long long)(int)offsetof(struct mdt_remote_perm, rp_uid)); - LASSERTF((int)sizeof(((struct mdt_remote_perm *)0)->rp_uid) == 4, "found %lld\n", - (long long)(int)sizeof(((struct mdt_remote_perm *)0)->rp_uid)); - LASSERTF((int)offsetof(struct mdt_remote_perm, rp_gid) == 4, "found %lld\n", - (long long)(int)offsetof(struct mdt_remote_perm, rp_gid)); - LASSERTF((int)sizeof(((struct mdt_remote_perm *)0)->rp_gid) == 4, "found %lld\n", - (long long)(int)sizeof(((struct mdt_remote_perm *)0)->rp_gid)); - LASSERTF((int)offsetof(struct mdt_remote_perm, rp_fsuid) == 8, "found %lld\n", - (long long)(int)offsetof(struct mdt_remote_perm, rp_fsuid)); - LASSERTF((int)sizeof(((struct mdt_remote_perm *)0)->rp_fsuid) == 4, "found %lld\n", - (long long)(int)sizeof(((struct mdt_remote_perm *)0)->rp_fsuid)); - LASSERTF((int)offsetof(struct mdt_remote_perm, rp_fsgid) == 16, "found %lld\n", - (long long)(int)offsetof(struct mdt_remote_perm, rp_fsgid)); - LASSERTF((int)sizeof(((struct mdt_remote_perm *)0)->rp_fsgid) == 4, "found %lld\n", - (long long)(int)sizeof(((struct mdt_remote_perm *)0)->rp_fsgid)); - LASSERTF((int)offsetof(struct mdt_remote_perm, rp_access_perm) == 24, "found %lld\n", - (long long)(int)offsetof(struct mdt_remote_perm, rp_access_perm)); - LASSERTF((int)sizeof(((struct mdt_remote_perm *)0)->rp_access_perm) == 4, "found %lld\n", - (long long)(int)sizeof(((struct mdt_remote_perm *)0)->rp_access_perm)); - LASSERTF((int)offsetof(struct mdt_remote_perm, rp_padding) == 28, "found %lld\n", - (long long)(int)offsetof(struct mdt_remote_perm, rp_padding)); - LASSERTF((int)sizeof(((struct mdt_remote_perm *)0)->rp_padding) == 4, "found %lld\n", - (long long)(int)sizeof(((struct mdt_remote_perm *)0)->rp_padding)); - LASSERTF(CFS_SETUID_PERM == 0x00000001UL, "found 0x%.8xUL\n", - (unsigned)CFS_SETUID_PERM); - LASSERTF(CFS_SETGID_PERM == 0x00000002UL, "found 0x%.8xUL\n", - (unsigned)CFS_SETGID_PERM); - LASSERTF(CFS_SETGRP_PERM == 0x00000004UL, "found 0x%.8xUL\n", - (unsigned)CFS_SETGRP_PERM); - LASSERTF(CFS_RMTACL_PERM == 0x00000008UL, "found 0x%.8xUL\n", - (unsigned)CFS_RMTACL_PERM); - LASSERTF(CFS_RMTOWN_PERM == 0x00000010UL, "found 0x%.8xUL\n", - (unsigned)CFS_RMTOWN_PERM); - /* Checks for struct mdt_rec_setattr */ LASSERTF((int)sizeof(struct mdt_rec_setattr) == 136, "found %lld\n", (long long)(int)sizeof(struct mdt_rec_setattr)); -- cgit v0.10.2 From 1b02bde3bce415a4c0541b911e6d9b3d98a80740 Mon Sep 17 00:00:00 2001 From: Emoly Liu Date: Mon, 20 Jun 2016 16:55:24 -0400 Subject: staging/lustre/llite: allocate and free client cache asynchronously Since the inflight request holds import refcount as well as export, sometimes obd_disconnect() in client_common_put_super() can't put the last refcount of OSC import (e.g. due to network disconnection), this will cause cl_cache being accessed after free. To fix this issue, ccc_users is used as cl_cache refcount, and lov/llite/osc all hold one cl_cache refcount respectively, to avoid the race that a new OST is being added into the system when the client is mounted. The following cl_cache functions are added: - cl_cache_init(): allocate and initialize cl_cache - cl_cache_incref(): increase cl_cache refcount - cl_cache_decref(): decrease cl_cache refcount and free the cache if refcount=0. Signed-off-by: Emoly Liu Reviewed-on: http://review.whamcloud.com/13746 Intel-bug-id: https://jira.hpdd.intel.com/browse/LU-6173 Reviewed-by: Niu Yawei Signed-off-by: Oleg Drokin Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/lustre/lustre/include/cl_object.h b/drivers/staging/lustre/lustre/include/cl_object.h index 36ca935..3cd4a25 100644 --- a/drivers/staging/lustre/lustre/include/cl_object.h +++ b/drivers/staging/lustre/lustre/include/cl_object.h @@ -2322,7 +2322,8 @@ void cl_lock_descr_print(const struct lu_env *env, void *cookie, */ struct cl_client_cache { /** - * # of users (OSCs) + * # of client cache refcount + * # of users (OSCs) + 2 (held by llite and lov) */ atomic_t ccc_users; /** @@ -2357,6 +2358,13 @@ struct cl_client_cache { }; +/** + * cl_cache functions + */ +struct cl_client_cache *cl_cache_init(unsigned long lru_page_max); +void cl_cache_incref(struct cl_client_cache *cache); +void cl_cache_decref(struct cl_client_cache *cache); + /** @} cl_page */ /** \defgroup cl_lock cl_lock diff --git a/drivers/staging/lustre/lustre/include/obd.h b/drivers/staging/lustre/lustre/include/obd.h index 9971ee5..40909b0 100644 --- a/drivers/staging/lustre/lustre/include/obd.h +++ b/drivers/staging/lustre/lustre/include/obd.h @@ -415,7 +415,7 @@ struct lov_obd { enum lustre_sec_part lov_sp_me; /* Cached LRU and unstable data from upper layer */ - void *lov_cache; + struct cl_client_cache *lov_cache; struct rw_semaphore lov_notify_lock; diff --git a/drivers/staging/lustre/lustre/llite/llite_internal.h b/drivers/staging/lustre/lustre/llite/llite_internal.h index 8fe63bd..657ebd0 100644 --- a/drivers/staging/lustre/lustre/llite/llite_internal.h +++ b/drivers/staging/lustre/lustre/llite/llite_internal.h @@ -452,7 +452,7 @@ struct ll_sb_info { * any page which is sent to a server as part of a bulk request, * but is uncommitted to stable storage. */ - struct cl_client_cache ll_cache; + struct cl_client_cache *ll_cache; struct lprocfs_stats *ll_ra_stats; diff --git a/drivers/staging/lustre/lustre/llite/llite_lib.c b/drivers/staging/lustre/lustre/llite/llite_lib.c index ae6a571..4ab1f2b 100644 --- a/drivers/staging/lustre/lustre/llite/llite_lib.c +++ b/drivers/staging/lustre/lustre/llite/llite_lib.c @@ -83,15 +83,11 @@ static struct ll_sb_info *ll_init_sbi(struct super_block *sb) pages = si.totalram - si.totalhigh; lru_page_max = pages / 2; - /* initialize ll_cache data */ - atomic_set(&sbi->ll_cache.ccc_users, 0); - sbi->ll_cache.ccc_lru_max = lru_page_max; - atomic_set(&sbi->ll_cache.ccc_lru_left, lru_page_max); - spin_lock_init(&sbi->ll_cache.ccc_lru_lock); - INIT_LIST_HEAD(&sbi->ll_cache.ccc_lru); - - atomic_set(&sbi->ll_cache.ccc_unstable_nr, 0); - init_waitqueue_head(&sbi->ll_cache.ccc_unstable_waitq); + sbi->ll_cache = cl_cache_init(lru_page_max); + if (!sbi->ll_cache) { + kfree(sbi); + return NULL; + } sbi->ll_ra_info.ra_max_pages_per_file = min(pages / 32, SBI_DEFAULT_READAHEAD_MAX); @@ -131,6 +127,11 @@ static void ll_free_sbi(struct super_block *sb) { struct ll_sb_info *sbi = ll_s2sbi(sb); + if (sbi->ll_cache) { + cl_cache_decref(sbi->ll_cache); + sbi->ll_cache = NULL; + } + kfree(sbi); } @@ -488,8 +489,8 @@ static int client_common_fill_super(struct super_block *sb, char *md, char *dt, cl_sb_init(sb); err = obd_set_info_async(NULL, sbi->ll_dt_exp, sizeof(KEY_CACHE_SET), - KEY_CACHE_SET, sizeof(sbi->ll_cache), - &sbi->ll_cache, NULL); + KEY_CACHE_SET, sizeof(*sbi->ll_cache), + sbi->ll_cache, NULL); sb->s_root = d_make_root(root); if (!sb->s_root) { @@ -534,8 +535,6 @@ out_lock_cn_cb: out_dt: obd_disconnect(sbi->ll_dt_exp); sbi->ll_dt_exp = NULL; - /* Make sure all OScs are gone, since cl_cache is accessing sbi. */ - obd_zombie_barrier(); out_md_fid: obd_fid_fini(sbi->ll_md_exp->exp_obd); out_md: @@ -585,10 +584,6 @@ static void client_common_put_super(struct super_block *sb) obd_fid_fini(sbi->ll_dt_exp->exp_obd); obd_disconnect(sbi->ll_dt_exp); sbi->ll_dt_exp = NULL; - /* wait till all OSCs are gone, since cl_cache is accessing sbi. - * see LU-2543. - */ - obd_zombie_barrier(); ldebugfs_unregister_mountpoint(sbi); @@ -921,12 +916,12 @@ void ll_put_super(struct super_block *sb) if (!force) { struct l_wait_info lwi = LWI_INTR(LWI_ON_SIGNAL_NOOP, NULL); - rc = l_wait_event(sbi->ll_cache.ccc_unstable_waitq, - !atomic_read(&sbi->ll_cache.ccc_unstable_nr), + rc = l_wait_event(sbi->ll_cache->ccc_unstable_waitq, + !atomic_read(&sbi->ll_cache->ccc_unstable_nr), &lwi); } - ccc_count = atomic_read(&sbi->ll_cache.ccc_unstable_nr); + ccc_count = atomic_read(&sbi->ll_cache->ccc_unstable_nr); if (!force && rc != -EINTR) LASSERTF(!ccc_count, "count: %i\n", ccc_count); diff --git a/drivers/staging/lustre/lustre/llite/lproc_llite.c b/drivers/staging/lustre/lustre/llite/lproc_llite.c index 18a7775..e86bf3c 100644 --- a/drivers/staging/lustre/lustre/llite/lproc_llite.c +++ b/drivers/staging/lustre/lustre/llite/lproc_llite.c @@ -356,7 +356,7 @@ static int ll_max_cached_mb_seq_show(struct seq_file *m, void *v) { struct super_block *sb = m->private; struct ll_sb_info *sbi = ll_s2sbi(sb); - struct cl_client_cache *cache = &sbi->ll_cache; + struct cl_client_cache *cache = sbi->ll_cache; int shift = 20 - PAGE_SHIFT; int max_cached_mb; int unused_mb; @@ -383,7 +383,7 @@ static ssize_t ll_max_cached_mb_seq_write(struct file *file, { struct super_block *sb = ((struct seq_file *)file->private_data)->private; struct ll_sb_info *sbi = ll_s2sbi(sb); - struct cl_client_cache *cache = &sbi->ll_cache; + struct cl_client_cache *cache = sbi->ll_cache; struct lu_env *env; int refcheck; int mult, rc, pages_number; @@ -822,7 +822,7 @@ static ssize_t unstable_stats_show(struct kobject *kobj, { struct ll_sb_info *sbi = container_of(kobj, struct ll_sb_info, ll_kobj); - struct cl_client_cache *cache = &sbi->ll_cache; + struct cl_client_cache *cache = sbi->ll_cache; int pages, mb; pages = atomic_read(&cache->ccc_unstable_nr); diff --git a/drivers/staging/lustre/lustre/lov/lov_obd.c b/drivers/staging/lustre/lustre/lov/lov_obd.c index c87096e..9b92d55 100644 --- a/drivers/staging/lustre/lustre/lov/lov_obd.c +++ b/drivers/staging/lustre/lustre/lov/lov_obd.c @@ -892,6 +892,12 @@ static int lov_cleanup(struct obd_device *obd) kfree(lov->lov_tgts); lov->lov_tgt_size = 0; } + + if (lov->lov_cache) { + cl_cache_decref(lov->lov_cache); + lov->lov_cache = NULL; + } + return 0; } @@ -2121,6 +2127,7 @@ static int lov_set_info_async(const struct lu_env *env, struct obd_export *exp, LASSERT(!lov->lov_cache); lov->lov_cache = val; do_inactive = 1; + cl_cache_incref(lov->lov_cache); } for (i = 0; i < count; i++, val = (char *)val + incr) { diff --git a/drivers/staging/lustre/lustre/obdclass/cl_page.c b/drivers/staging/lustre/lustre/obdclass/cl_page.c index 71bff49..db2dc6b 100644 --- a/drivers/staging/lustre/lustre/obdclass/cl_page.c +++ b/drivers/staging/lustre/lustre/obdclass/cl_page.c @@ -1072,3 +1072,49 @@ void cl_page_slice_add(struct cl_page *page, struct cl_page_slice *slice, slice->cpl_page = page; } EXPORT_SYMBOL(cl_page_slice_add); + +/** + * Allocate and initialize cl_cache, called by ll_init_sbi(). + */ +struct cl_client_cache *cl_cache_init(unsigned long lru_page_max) +{ + struct cl_client_cache *cache = NULL; + + cache = kzalloc(sizeof(*cache), GFP_KERNEL); + if (!cache) + return NULL; + + /* Initialize cache data */ + atomic_set(&cache->ccc_users, 1); + cache->ccc_lru_max = lru_page_max; + atomic_set(&cache->ccc_lru_left, lru_page_max); + spin_lock_init(&cache->ccc_lru_lock); + INIT_LIST_HEAD(&cache->ccc_lru); + + atomic_set(&cache->ccc_unstable_nr, 0); + init_waitqueue_head(&cache->ccc_unstable_waitq); + + return cache; +} +EXPORT_SYMBOL(cl_cache_init); + +/** + * Increase cl_cache refcount + */ +void cl_cache_incref(struct cl_client_cache *cache) +{ + atomic_inc(&cache->ccc_users); +} +EXPORT_SYMBOL(cl_cache_incref); + +/** + * Decrease cl_cache refcount and free the cache if refcount=0. + * Since llite, lov and osc all hold cl_cache refcount, + * the free will not cause race. (LU-6173) + */ +void cl_cache_decref(struct cl_client_cache *cache) +{ + if (atomic_dec_and_test(&cache->ccc_users)) + kfree(cache); +} +EXPORT_SYMBOL(cl_cache_decref); diff --git a/drivers/staging/lustre/lustre/osc/osc_page.c b/drivers/staging/lustre/lustre/osc/osc_page.c index 18c261b..355f496 100644 --- a/drivers/staging/lustre/lustre/osc/osc_page.c +++ b/drivers/staging/lustre/lustre/osc/osc_page.c @@ -412,7 +412,7 @@ static int osc_cache_too_much(struct client_obd *cli) int pages = atomic_read(&cli->cl_lru_in_list); unsigned long budget; - budget = cache->ccc_lru_max / atomic_read(&cache->ccc_users); + budget = cache->ccc_lru_max / (atomic_read(&cache->ccc_users) - 2); /* if it's going to run out LRU slots, we should free some, but not * too much to maintain fairness among OSCs. @@ -712,7 +712,7 @@ int osc_lru_reclaim(struct client_obd *cli) cache->ccc_lru_shrinkers++; list_move_tail(&cli->cl_lru_osc, &cache->ccc_lru); - max_scans = atomic_read(&cache->ccc_users); + max_scans = atomic_read(&cache->ccc_users) - 2; while (--max_scans > 0 && !list_empty(&cache->ccc_lru)) { cli = list_entry(cache->ccc_lru.next, struct client_obd, cl_lru_osc); diff --git a/drivers/staging/lustre/lustre/osc/osc_request.c b/drivers/staging/lustre/lustre/osc/osc_request.c index 7260027..9334349 100644 --- a/drivers/staging/lustre/lustre/osc/osc_request.c +++ b/drivers/staging/lustre/lustre/osc/osc_request.c @@ -2913,7 +2913,7 @@ static int osc_set_info_async(const struct lu_env *env, struct obd_export *exp, LASSERT(!cli->cl_cache); /* only once */ cli->cl_cache = val; - atomic_inc(&cli->cl_cache->ccc_users); + cl_cache_incref(cli->cl_cache); cli->cl_lru_left = &cli->cl_cache->ccc_lru_left; /* add this osc into entity list */ @@ -3293,7 +3293,7 @@ static int osc_cleanup(struct obd_device *obd) list_del_init(&cli->cl_lru_osc); spin_unlock(&cli->cl_cache->ccc_lru_lock); cli->cl_lru_left = NULL; - atomic_dec(&cli->cl_cache->ccc_users); + cl_cache_decref(cli->cl_cache); cli->cl_cache = NULL; } -- cgit v0.10.2 From 411c9699dfe346fe7e70734c34291ea83d9b70b5 Mon Sep 17 00:00:00 2001 From: "John L. Hammond" Date: Mon, 20 Jun 2016 16:55:25 -0400 Subject: staging/lustre/llite: correct request handling after ll_lookup_it() In the FIFO cases of ll_atomic_open() and ll_lookup_nd() remove spurious calls to ptlrpc_req_finished(). Explain that these cases are unreachable in practice anyway. Signed-off-by: John L. Hammond Reviewed-on: http://review.whamcloud.com/17068 Intel-bug-id: https://jira.hpdd.intel.com/browse/LU-7402 Reviewed-by: Dmitry Eremin Reviewed-by: Lai Siyao Signed-off-by: Oleg Drokin Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/lustre/lustre/llite/namei.c b/drivers/staging/lustre/lustre/llite/namei.c index d7459bd..6414d52 100644 --- a/drivers/staging/lustre/lustre/llite/namei.c +++ b/drivers/staging/lustre/lustre/llite/namei.c @@ -622,13 +622,10 @@ static int ll_atomic_open(struct inode *dir, struct dentry *dentry, if (d_really_is_positive(dentry) && it_disposition(it, DISP_OPEN_OPEN)) { /* Open dentry. */ if (S_ISFIFO(d_inode(dentry)->i_mode)) { - /* We cannot call open here as it would - * deadlock. + /* We cannot call open here as it might + * deadlock. This case is unreachable in + * practice because of OBD_CONNECT_NODEVOH. */ - if (it_disposition(it, DISP_ENQ_OPEN_REF)) - ptlrpc_req_finished( - (struct ptlrpc_request *) - it->d.lustre.it_data); rc = finish_no_open(file, de); } else { file->private_data = it; -- cgit v0.10.2 From 2bbec0ed2c957541f22ba99202827b004267ab58 Mon Sep 17 00:00:00 2001 From: Oleg Drokin Date: Mon, 20 Jun 2016 16:55:26 -0400 Subject: staging/lustre/llite: Get rid of ll_lock_dcache/ll_unlock_dcache These are just doing spin_lock/unlock on inode's i_lock, so just do the spinlock directly to make the code more clear Signed-off-by: Oleg Drokin Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/lustre/lustre/llite/dcache.c b/drivers/staging/lustre/lustre/llite/dcache.c index 9d13d5e..f002b3a 100644 --- a/drivers/staging/lustre/lustre/llite/dcache.c +++ b/drivers/staging/lustre/lustre/llite/dcache.c @@ -249,7 +249,7 @@ void ll_invalidate_aliases(struct inode *inode) CDEBUG(D_INODE, "marking dentries for ino "DFID"(%p) invalid\n", PFID(ll_inode2fid(inode)), inode); - ll_lock_dcache(inode); + spin_lock(&inode->i_lock); hlist_for_each_entry(dentry, &inode->i_dentry, d_u.d_alias) { CDEBUG(D_DENTRY, "dentry in drop %pd (%p) parent %p inode %p flags %d\n", dentry, dentry, dentry->d_parent, @@ -257,7 +257,7 @@ void ll_invalidate_aliases(struct inode *inode) d_lustre_invalidate(dentry, 0); } - ll_unlock_dcache(inode); + spin_unlock(&inode->i_lock); } int ll_revalidate_it_finish(struct ptlrpc_request *request, diff --git a/drivers/staging/lustre/lustre/llite/llite_internal.h b/drivers/staging/lustre/lustre/llite/llite_internal.h index 657ebd0..973dcc7 100644 --- a/drivers/staging/lustre/lustre/llite/llite_internal.h +++ b/drivers/staging/lustre/lustre/llite/llite_internal.h @@ -1229,16 +1229,6 @@ static inline void ll_set_lock_data(struct obd_export *exp, struct inode *inode, *bits = it->d.lustre.it_lock_bits; } -static inline void ll_lock_dcache(struct inode *inode) -{ - spin_lock(&inode->i_lock); -} - -static inline void ll_unlock_dcache(struct inode *inode) -{ - spin_unlock(&inode->i_lock); -} - static inline int d_lustre_invalid(const struct dentry *dentry) { struct ll_dentry_data *lld = ll_d2d(dentry); diff --git a/drivers/staging/lustre/lustre/llite/namei.c b/drivers/staging/lustre/lustre/llite/namei.c index 6414d52..e4df510 100644 --- a/drivers/staging/lustre/lustre/llite/namei.c +++ b/drivers/staging/lustre/lustre/llite/namei.c @@ -140,7 +140,7 @@ static void ll_invalidate_negative_children(struct inode *dir) { struct dentry *dentry, *tmp_subdir; - ll_lock_dcache(dir); + spin_lock(&dir->i_lock); hlist_for_each_entry(dentry, &dir->i_dentry, d_u.d_alias) { spin_lock(&dentry->d_lock); if (!list_empty(&dentry->d_subdirs)) { @@ -155,7 +155,7 @@ static void ll_invalidate_negative_children(struct inode *dir) } spin_unlock(&dentry->d_lock); } - ll_unlock_dcache(dir); + spin_unlock(&dir->i_lock); } int ll_md_blocking_ast(struct ldlm_lock *lock, struct ldlm_lock_desc *desc, @@ -317,7 +317,7 @@ static struct dentry *ll_find_alias(struct inode *inode, struct dentry *dentry) discon_alias = NULL; invalid_alias = NULL; - ll_lock_dcache(inode); + spin_lock(&inode->i_lock); hlist_for_each_entry(alias, &inode->i_dentry, d_u.d_alias) { LASSERT(alias != dentry); @@ -342,7 +342,7 @@ static struct dentry *ll_find_alias(struct inode *inode, struct dentry *dentry) dget_dlock(alias); spin_unlock(&alias->d_lock); } - ll_unlock_dcache(inode); + spin_unlock(&inode->i_lock); return alias; } -- cgit v0.10.2 From c9cc8d0f6f770635b206784686a16157db3d43b8 Mon Sep 17 00:00:00 2001 From: Bruno Faccini Date: Mon, 20 Jun 2016 16:55:27 -0400 Subject: staging/lustre/llite: lock i_lock before __d_drop() There has been several Lustre Client crashes reported by sites running with Lustre versions 2.1/2.5, all showing the same dentry->d_hash->next corrupted pointer cause. This patch fixes a regression that has been introduced since a long time by commit : (LU-506 kernel: FC15 - support dcache scalability changes.) where i_lock protection usage has been removed and that is likely to cause racy condition during dentry [un]hashing and to be the root cause of these crashes. Signed-off-by: Bruno Faccini Reviewed-on: http://review.whamcloud.com/19287 Intel-bug-id: https://jira.hpdd.intel.com/browse/LU-7973 Reviewed-by: Lai Siyao Reviewed-by: Yang Sheng Signed-off-by: Oleg Drokin Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/lustre/lustre/llite/file.c b/drivers/staging/lustre/lustre/llite/file.c index 2d50d1c..c46e2ac 100644 --- a/drivers/staging/lustre/lustre/llite/file.c +++ b/drivers/staging/lustre/lustre/llite/file.c @@ -2963,8 +2963,11 @@ static int __ll_inode_revalidate(struct dentry *dentry, __u64 ibits) * here to preserve get_cwd functionality on 2.6. * Bug 10503 */ - if (!d_inode(dentry)->i_nlink) + if (!d_inode(dentry)->i_nlink) { + spin_lock(&inode->i_lock); d_lustre_invalidate(dentry, 0); + spin_unlock(&inode->i_lock); + } ll_lookup_finish_locks(&oit, inode); } else if (!ll_have_md_lock(d_inode(dentry), &ibits, LCK_MINMODE)) { -- cgit v0.10.2 From a6307ff9aaeda8691204dc0ea30cd3680d06f6b3 Mon Sep 17 00:00:00 2001 From: Jinshan Xiong Date: Mon, 20 Jun 2016 16:55:28 -0400 Subject: staging/lustre/osc: osc_lock_weight endless loop fix With huge number of pages to scan by osc_lock_weight() it is likely CLP_GANG_RESCHED is returned from osc_page_gang_lookup() and the scan will be repeated again from the start. To be sure that the scan is progressing across those restarts, next scan should be started from the last scanned page index plus one. Xyratex-bug-id: MRP-2145 Signed-off-by: Alexander Zarochentsev Signed-off-by: Jinshan Xiong Reviewed-on: http://review.whamcloud.com/12362 Intel-bug-id: https://jira.hpdd.intel.com/browse/LU-5781 Reviewed-by: Bobi Jam Reviewed-by: James Simmons Signed-off-by: Oleg Drokin Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/lustre/lustre/osc/osc_lock.c b/drivers/staging/lustre/lustre/osc/osc_lock.c index 42def38..d856775 100644 --- a/drivers/staging/lustre/lustre/osc/osc_lock.c +++ b/drivers/staging/lustre/lustre/osc/osc_lock.c @@ -634,11 +634,10 @@ static int weigh_cb(const struct lu_env *env, struct cl_io *io, if (cl_page_is_vmlocked(env, page) || PageDirty(page->cp_vmpage) || PageWriteback(page->cp_vmpage) - ) { - (*(unsigned long *)cbdata)++; + ) return CLP_GANG_ABORT; - } + *(pgoff_t *)cbdata = osc_index(ops) + 1; return CLP_GANG_OKAY; } @@ -648,7 +647,7 @@ static unsigned long osc_lock_weight(const struct lu_env *env, { struct cl_io *io = &osc_env_info(env)->oti_io; struct cl_object *obj = cl_object_top(&oscobj->oo_cl); - unsigned long npages = 0; + pgoff_t page_index; int result; io->ci_obj = obj; @@ -657,11 +656,12 @@ static unsigned long osc_lock_weight(const struct lu_env *env, if (result != 0) return result; + page_index = cl_index(obj, extent->start); do { result = osc_page_gang_lookup(env, io, oscobj, - cl_index(obj, extent->start), + page_index, cl_index(obj, extent->end), - weigh_cb, (void *)&npages); + weigh_cb, (void *)&page_index); if (result == CLP_GANG_ABORT) break; if (result == CLP_GANG_RESCHED) @@ -669,7 +669,7 @@ static unsigned long osc_lock_weight(const struct lu_env *env, } while (result != CLP_GANG_OKAY); cl_io_fini(env, io); - return npages; + return result == CLP_GANG_ABORT ? 1 : 0; } /** -- cgit v0.10.2 From fbe0456482aa5c482342735f342483a75ada8b96 Mon Sep 17 00:00:00 2001 From: Oleg Drokin Date: Mon, 20 Jun 2016 16:55:29 -0400 Subject: staging/lustre/osc: Fix reverted condition in osc_lock_weight When imprting clio simplification patch, the check for pbject got reversed by mistake when converting from if (obj == NULL) it somehow became (if (obj) which is obviously wrong, and so when it does hit, a crash was happening as result. Fix the condition and all if fine now. Signed-off-by: Oleg Drokin Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/lustre/lustre/osc/osc_lock.c b/drivers/staging/lustre/lustre/osc/osc_lock.c index d856775..5455d9d 100644 --- a/drivers/staging/lustre/lustre/osc/osc_lock.c +++ b/drivers/staging/lustre/lustre/osc/osc_lock.c @@ -699,7 +699,7 @@ unsigned long osc_ldlm_weigh_ast(struct ldlm_lock *dlmlock) LASSERT(dlmlock->l_resource->lr_type == LDLM_EXTENT); obj = dlmlock->l_ast_data; - if (obj) { + if (!obj) { weight = 1; goto out; } -- cgit v0.10.2 From 32c8728d87dcd59949800d838e4e7dce0c625062 Mon Sep 17 00:00:00 2001 From: Liang Zhen Date: Mon, 20 Jun 2016 16:55:30 -0400 Subject: staging/lustre/ptlrpc: reorganize ptlrpc_request ptlrpc_request has some structure members are only for client side, and some others are only for server side, this patch moved these members to different structure then putting into an union. By doing this, size of ptlrpc_request is decreased about 300 bytes, besides saving memory, it also can reduce memory footprint while processing. Signed-off-by: Liang Zhen Reviewed-on: http://review.whamcloud.com/8806 Intel-bug-id: https://jira.hpdd.intel.com/browse/LU-181 Reviewed-by: Andreas Dilger Reviewed-by: Bobi Jam Signed-off-by: Oleg Drokin Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/lustre/lustre/include/lustre_net.h b/drivers/staging/lustre/lustre/include/lustre_net.h index bdd2ed5..65924d9 100644 --- a/drivers/staging/lustre/lustre/include/lustre_net.h +++ b/drivers/staging/lustre/lustre/include/lustre_net.h @@ -266,6 +266,11 @@ /* Macro to hide a typecast. */ #define ptlrpc_req_async_args(req) ((void *)&req->rq_async_args) +struct ptlrpc_replay_async_args { + int praa_old_state; + int praa_old_status; +}; + /** * Structure to single define portal connection. */ @@ -1243,22 +1248,100 @@ struct ptlrpc_hpreq_ops { void (*hpreq_fini)(struct ptlrpc_request *); }; -/** - * Represents remote procedure call. - * - * This is a staple structure used by everybody wanting to send a request - * in Lustre. - */ -struct ptlrpc_request { - /* Request type: one of PTL_RPC_MSG_* */ - int rq_type; - /** Result of request processing */ - int rq_status; +struct ptlrpc_cli_req { + /** For bulk requests on client only: bulk descriptor */ + struct ptlrpc_bulk_desc *cr_bulk; + /** optional time limit for send attempts */ + long cr_delay_limit; + /** time request was first queued */ + time_t cr_queued_time; + /** request sent timeval */ + struct timespec64 cr_sent_tv; + /** time for request really sent out */ + time_t cr_sent_out; + /** when req reply unlink must finish. */ + time_t cr_reply_deadline; + /** when req bulk unlink must finish. */ + time_t cr_bulk_deadline; + /** Portal to which this request would be sent */ + short cr_req_ptl; + /** Portal where to wait for reply and where reply would be sent */ + short cr_rep_ptl; + /** request resending number */ + unsigned int cr_resend_nr; + /** What was import generation when this request was sent */ + int cr_imp_gen; + enum lustre_imp_state cr_send_state; + /** Per-request waitq introduced by bug 21938 for recovery waiting */ + wait_queue_head_t cr_set_waitq; + /** Link item for request set lists */ + struct list_head cr_set_chain; + /** link to waited ctx */ + struct list_head cr_ctx_chain; + + /** client's half ctx */ + struct ptlrpc_cli_ctx *cr_cli_ctx; + /** Link back to the request set */ + struct ptlrpc_request_set *cr_set; + /** outgoing request MD handle */ + lnet_handle_md_t cr_req_md_h; + /** request-out callback parameter */ + struct ptlrpc_cb_id cr_req_cbid; + /** incoming reply MD handle */ + lnet_handle_md_t cr_reply_md_h; + wait_queue_head_t cr_reply_waitq; + /** reply callback parameter */ + struct ptlrpc_cb_id cr_reply_cbid; + /** Async completion handler, called when reply is received */ + ptlrpc_interpterer_t cr_reply_interp; + /** Async completion context */ + union ptlrpc_async_args cr_async_args; + /** Opaq data for replay and commit callbacks. */ + void *cr_cb_data; /** - * Linkage item through which this request is included into - * sending/delayed lists on client and into rqbd list on server + * Commit callback, called when request is committed and about to be + * freed. */ - struct list_head rq_list; + void (*cr_commit_cb)(struct ptlrpc_request *); + /** Replay callback, called after request is replayed at recovery */ + void (*cr_replay_cb)(struct ptlrpc_request *); +}; + +/** client request member alias */ +/* NB: these alias should NOT be used by any new code, instead they should + * be removed step by step to avoid potential abuse + */ +#define rq_bulk rq_cli.cr_bulk +#define rq_delay_limit rq_cli.cr_delay_limit +#define rq_queued_time rq_cli.cr_queued_time +#define rq_sent_tv rq_cli.cr_sent_tv +#define rq_real_sent rq_cli.cr_sent_out +#define rq_reply_deadline rq_cli.cr_reply_deadline +#define rq_bulk_deadline rq_cli.cr_bulk_deadline +#define rq_nr_resend rq_cli.cr_resend_nr +#define rq_request_portal rq_cli.cr_req_ptl +#define rq_reply_portal rq_cli.cr_rep_ptl +#define rq_import_generation rq_cli.cr_imp_gen +#define rq_send_state rq_cli.cr_send_state +#define rq_set_chain rq_cli.cr_set_chain +#define rq_ctx_chain rq_cli.cr_ctx_chain +#define rq_set rq_cli.cr_set +#define rq_set_waitq rq_cli.cr_set_waitq +#define rq_cli_ctx rq_cli.cr_cli_ctx +#define rq_req_md_h rq_cli.cr_req_md_h +#define rq_req_cbid rq_cli.cr_req_cbid +#define rq_reply_md_h rq_cli.cr_reply_md_h +#define rq_reply_waitq rq_cli.cr_reply_waitq +#define rq_reply_cbid rq_cli.cr_reply_cbid +#define rq_interpret_reply rq_cli.cr_reply_interp +#define rq_async_args rq_cli.cr_async_args +#define rq_cb_data rq_cli.cr_cb_data +#define rq_commit_cb rq_cli.cr_commit_cb +#define rq_replay_cb rq_cli.cr_replay_cb + +struct ptlrpc_srv_req { + /** initial thread servicing this request */ + struct ptlrpc_thread *sr_svc_thread; /** * Server side list of incoming unserved requests sorted by arrival * time. Traversed from time to time to notice about to expire @@ -1266,27 +1349,81 @@ struct ptlrpc_request { * know server is alive and well, just very busy to service their * requests in time */ - struct list_head rq_timed_list; - /** server-side history, used for debugging purposes. */ - struct list_head rq_history_list; + struct list_head sr_timed_list; /** server-side per-export list */ - struct list_head rq_exp_list; - /** server-side hp handlers */ - struct ptlrpc_hpreq_ops *rq_ops; - - /** initial thread servicing this request */ - struct ptlrpc_thread *rq_svc_thread; - + struct list_head sr_exp_list; + /** server-side history, used for debuging purposes. */ + struct list_head sr_hist_list; /** history sequence # */ - __u64 rq_history_seq; + __u64 sr_hist_seq; + /** the index of service's srv_at_array into which request is linked */ + time_t sr_at_index; + /** authed uid */ + uid_t sr_auth_uid; + /** authed uid mapped to */ + uid_t sr_auth_mapped_uid; + /** RPC is generated from what part of Lustre */ + enum lustre_sec_part sr_sp_from; + /** request session context */ + struct lu_context sr_ses; /** \addtogroup nrs * @{ */ /** stub for NRS request */ - struct ptlrpc_nrs_request rq_nrq; + struct ptlrpc_nrs_request sr_nrq; /** @} nrs */ - /** the index of service's srv_at_array into which request is linked */ - u32 rq_at_index; + /** request arrival time */ + struct timespec64 sr_arrival_time; + /** server's half ctx */ + struct ptlrpc_svc_ctx *sr_svc_ctx; + /** (server side), pointed directly into req buffer */ + struct ptlrpc_user_desc *sr_user_desc; + /** separated reply state */ + struct ptlrpc_reply_state *sr_reply_state; + /** server-side hp handlers */ + struct ptlrpc_hpreq_ops *sr_ops; + /** incoming request buffer */ + struct ptlrpc_request_buffer_desc *sr_rqbd; +}; + +/** server request member alias */ +/* NB: these alias should NOT be used by any new code, instead they should + * be removed step by step to avoid potential abuse + */ +#define rq_svc_thread rq_srv.sr_svc_thread +#define rq_timed_list rq_srv.sr_timed_list +#define rq_exp_list rq_srv.sr_exp_list +#define rq_history_list rq_srv.sr_hist_list +#define rq_history_seq rq_srv.sr_hist_seq +#define rq_at_index rq_srv.sr_at_index +#define rq_auth_uid rq_srv.sr_auth_uid +#define rq_auth_mapped_uid rq_srv.sr_auth_mapped_uid +#define rq_sp_from rq_srv.sr_sp_from +#define rq_session rq_srv.sr_ses +#define rq_nrq rq_srv.sr_nrq +#define rq_arrival_time rq_srv.sr_arrival_time +#define rq_reply_state rq_srv.sr_reply_state +#define rq_svc_ctx rq_srv.sr_svc_ctx +#define rq_user_desc rq_srv.sr_user_desc +#define rq_ops rq_srv.sr_ops +#define rq_rqbd rq_srv.sr_rqbd + +/** + * Represents remote procedure call. + * + * This is a staple structure used by everybody wanting to send a request + * in Lustre. + */ +struct ptlrpc_request { + /* Request type: one of PTL_RPC_MSG_* */ + int rq_type; + /** Result of request processing */ + int rq_status; + /** + * Linkage item through which this request is included into + * sending/delayed lists on client and into rqbd list on server + */ + struct list_head rq_list; /** Lock to protect request flags and some other important bits, like * rq_list */ @@ -1327,19 +1464,15 @@ struct ptlrpc_request { /* bulk request, sent to server, but uncommitted */ rq_unstable:1; - unsigned int rq_nr_resend; - - enum rq_phase rq_phase; /* one of RQ_PHASE_* */ - enum rq_phase rq_next_phase; /* one of RQ_PHASE_* to be used next */ - atomic_t rq_refcount; /* client-side refcount for SENT race, - * server-side refcount for multiple replies - */ - - /** Portal to which this request would be sent */ - short rq_request_portal; /* XXX FIXME bug 249 */ - /** Portal where to wait for reply and where reply would be sent */ - short rq_reply_portal; /* XXX FIXME bug 249 */ - + /** one of RQ_PHASE_* */ + enum rq_phase rq_phase; + /** one of RQ_PHASE_* to be used next */ + enum rq_phase rq_next_phase; + /** + * client-side refcount for SENT race, server-side refcount + * for multiple replies + */ + atomic_t rq_refcount; /** * client-side: * !rq_truncate : # reply bytes actually received, @@ -1350,6 +1483,8 @@ struct ptlrpc_request { int rq_reqlen; /** Reply length */ int rq_replen; + /** Pool if request is from preallocated list */ + struct ptlrpc_request_pool *rq_pool; /** Request message - what client sent */ struct lustre_msg *rq_reqmsg; /** Reply message - server response */ @@ -1362,19 +1497,20 @@ struct ptlrpc_request { * List item to for replay list. Not yet committed requests get linked * there. * Also see \a rq_replay comment above. + * It's also link chain on obd_export::exp_req_replay_queue */ struct list_head rq_replay_list; - + /** non-shared members for client & server request*/ + union { + struct ptlrpc_cli_req rq_cli; + struct ptlrpc_srv_req rq_srv; + }; /** * security and encryption data * @{ */ - struct ptlrpc_cli_ctx *rq_cli_ctx; /**< client's half ctx */ - struct ptlrpc_svc_ctx *rq_svc_ctx; /**< server's half ctx */ - struct list_head rq_ctx_chain; /**< link to waited ctx */ - - struct sptlrpc_flavor rq_flvr; /**< for client & server */ - enum lustre_sec_part rq_sp_from; + /** description of flavors for client & server */ + struct sptlrpc_flavor rq_flvr; /* client/server security flags */ unsigned int @@ -1392,19 +1528,15 @@ struct ptlrpc_request { rq_pack_bulk:1, /* doesn't expect reply FIXME */ rq_no_reply:1, - rq_pill_init:1; /* pill initialized */ - - uid_t rq_auth_uid; /* authed uid */ - uid_t rq_auth_mapped_uid; /* authed uid mapped to */ - - /* (server side), pointed directly into req buffer */ - struct ptlrpc_user_desc *rq_user_desc; - - /* various buffer pointers */ - struct lustre_msg *rq_reqbuf; /* req wrapper */ - char *rq_repbuf; /* rep buffer */ - struct lustre_msg *rq_repdata; /* rep wrapper msg */ - struct lustre_msg *rq_clrbuf; /* only in priv mode */ + rq_pill_init:1, /* pill initialized */ + rq_srv_req:1; /* server request */ + + /** various buffer pointers */ + struct lustre_msg *rq_reqbuf; /**< req wrapper */ + char *rq_repbuf; /**< rep buffer */ + struct lustre_msg *rq_repdata; /**< rep wrapper msg */ + /** only in priv mode */ + struct lustre_msg *rq_clrbuf; int rq_reqbuf_len; /* req wrapper buf len */ int rq_reqdata_len; /* req wrapper msg len */ int rq_repbuf_len; /* rep buffer len */ @@ -1421,97 +1553,28 @@ struct ptlrpc_request { __u32 rq_req_swab_mask; __u32 rq_rep_swab_mask; - /** What was import generation when this request was sent */ - int rq_import_generation; - enum lustre_imp_state rq_send_state; - /** how many early replies (for stats) */ int rq_early_count; - /** client+server request */ - lnet_handle_md_t rq_req_md_h; - struct ptlrpc_cb_id rq_req_cbid; - /** optional time limit for send attempts */ - long rq_delay_limit; - /** time request was first queued */ - unsigned long rq_queued_time; - - /* server-side... */ - /** request arrival time */ - struct timespec64 rq_arrival_time; - /** separated reply state */ - struct ptlrpc_reply_state *rq_reply_state; - /** incoming request buffer */ - struct ptlrpc_request_buffer_desc *rq_rqbd; - - /** client-only incoming reply */ - lnet_handle_md_t rq_reply_md_h; - wait_queue_head_t rq_reply_waitq; - struct ptlrpc_cb_id rq_reply_cbid; - + /** Server-side, export on which request was received */ + struct obd_export *rq_export; + /** import where request is being sent */ + struct obd_import *rq_import; /** our LNet NID */ lnet_nid_t rq_self; /** Peer description (the other side) */ lnet_process_id_t rq_peer; - /** Server-side, export on which request was received */ - struct obd_export *rq_export; - /** Client side, import where request is being sent */ - struct obd_import *rq_import; - - /** Replay callback, called after request is replayed at recovery */ - void (*rq_replay_cb)(struct ptlrpc_request *); /** - * Commit callback, called when request is committed and about to be - * freed. + * service time estimate (secs) + * If the request is not served by this time, it is marked as timed out. */ - void (*rq_commit_cb)(struct ptlrpc_request *); - /** Opaq data for replay and commit callbacks. */ - void *rq_cb_data; - - /** For bulk requests on client only: bulk descriptor */ - struct ptlrpc_bulk_desc *rq_bulk; - - /** client outgoing req */ + int rq_timeout; /** * when request/reply sent (secs), or time when request should be sent */ time64_t rq_sent; - /** time for request really sent out */ - time64_t rq_real_sent; - - /** when request must finish. volatile - * so that servers' early reply updates to the deadline aren't - * kept in per-cpu cache - */ - volatile time64_t rq_deadline; - /** when req reply unlink must finish. */ - time64_t rq_reply_deadline; - /** when req bulk unlink must finish. */ - time64_t rq_bulk_deadline; - /** - * service time estimate (secs) - * If the requestsis not served by this time, it is marked as timed out. - */ - int rq_timeout; - - /** Multi-rpc bits */ - /** Per-request waitq introduced by bug 21938 for recovery waiting */ - wait_queue_head_t rq_set_waitq; - /** Link item for request set lists */ - struct list_head rq_set_chain; - /** Link back to the request set */ - struct ptlrpc_request_set *rq_set; - /** Async completion handler, called when reply is received */ - ptlrpc_interpterer_t rq_interpret_reply; - /** Async completion context */ - union ptlrpc_async_args rq_async_args; - - /** Pool if request is from preallocated list */ - struct ptlrpc_request_pool *rq_pool; - - struct lu_context rq_session; - struct lu_context rq_recov_session; - + /** when request must finish. */ + time64_t rq_deadline; /** request format description */ struct req_capsule rq_pill; }; diff --git a/drivers/staging/lustre/lustre/ptlrpc/client.c b/drivers/staging/lustre/lustre/ptlrpc/client.c index 22bf893..9abd469 100644 --- a/drivers/staging/lustre/lustre/ptlrpc/client.c +++ b/drivers/staging/lustre/lustre/ptlrpc/client.c @@ -611,7 +611,6 @@ static int __ptlrpc_request_bufs_pack(struct ptlrpc_request *request, lustre_msg_add_version(request->rq_reqmsg, version); request->rq_send_state = LUSTRE_IMP_FULL; request->rq_type = PTL_RPC_MSG_REQUEST; - request->rq_export = NULL; request->rq_req_cbid.cbid_fn = request_out_callback; request->rq_req_cbid.cbid_arg = request; @@ -628,19 +627,7 @@ static int __ptlrpc_request_bufs_pack(struct ptlrpc_request *request, ptlrpc_at_set_req_timeout(request); - spin_lock_init(&request->rq_lock); - INIT_LIST_HEAD(&request->rq_list); - INIT_LIST_HEAD(&request->rq_timed_list); - INIT_LIST_HEAD(&request->rq_replay_list); - INIT_LIST_HEAD(&request->rq_ctx_chain); - INIT_LIST_HEAD(&request->rq_set_chain); - INIT_LIST_HEAD(&request->rq_history_list); - INIT_LIST_HEAD(&request->rq_exp_list); - init_waitqueue_head(&request->rq_reply_waitq); - init_waitqueue_head(&request->rq_set_waitq); request->rq_xid = ptlrpc_next_xid(); - atomic_set(&request->rq_refcount, 1); - lustre_msg_set_opc(request->rq_reqmsg, opcode); return 0; @@ -718,7 +705,9 @@ struct ptlrpc_request *__ptlrpc_request_alloc(struct obd_import *imp, request = ptlrpc_prep_req_from_pool(pool); if (request) { - LASSERTF((unsigned long)imp > 0x1000, "%p\n", imp); + ptlrpc_cli_req_init(request); + + LASSERTF((unsigned long)imp > 0x1000, "%p", imp); LASSERT(imp != LP_POISON); LASSERTF((unsigned long)imp->imp_client > 0x1000, "%p\n", imp->imp_client); @@ -1235,8 +1224,9 @@ static int after_reply(struct ptlrpc_request *req) } ktime_get_real_ts64(&work_start); - timediff = (work_start.tv_sec - req->rq_arrival_time.tv_sec) * USEC_PER_SEC + - (work_start.tv_nsec - req->rq_arrival_time.tv_nsec) / NSEC_PER_USEC; + timediff = (work_start.tv_sec - req->rq_sent_tv.tv_sec) * USEC_PER_SEC + + (work_start.tv_nsec - req->rq_sent_tv.tv_nsec) / + NSEC_PER_USEC; if (obd->obd_svc_stats) { lprocfs_counter_add(obd->obd_svc_stats, PTLRPC_REQWAIT_CNTR, timediff); @@ -2191,11 +2181,11 @@ static void __ptlrpc_free_req(struct ptlrpc_request *request, int locked) { if (!request) return; + LASSERT(!request->rq_srv_req); + LASSERT(!request->rq_export); LASSERTF(!request->rq_receiving_reply, "req %p\n", request); - LASSERTF(!request->rq_rqbd, "req %p\n", request);/* client-side */ LASSERTF(list_empty(&request->rq_list), "req %p\n", request); LASSERTF(list_empty(&request->rq_set_chain), "req %p\n", request); - LASSERTF(list_empty(&request->rq_exp_list), "req %p\n", request); LASSERTF(!request->rq_replay, "req %p\n", request); req_capsule_fini(&request->rq_pill); @@ -2221,10 +2211,7 @@ static void __ptlrpc_free_req(struct ptlrpc_request *request, int locked) if (request->rq_repbuf) sptlrpc_cli_free_repbuf(request); - if (request->rq_export) { - class_export_put(request->rq_export); - request->rq_export = NULL; - } + if (request->rq_import) { class_import_put(request->rq_import); request->rq_import = NULL; @@ -2614,11 +2601,6 @@ int ptlrpc_queue_wait(struct ptlrpc_request *req) } EXPORT_SYMBOL(ptlrpc_queue_wait); -struct ptlrpc_replay_async_args { - int praa_old_state; - int praa_old_status; -}; - /** * Callback used for replayed requests reply processing. * In case of successful reply calls registered request replay callback. @@ -3013,10 +2995,11 @@ void *ptlrpcd_alloc_work(struct obd_import *imp, return ERR_PTR(-ENOMEM); } + ptlrpc_cli_req_init(req); + req->rq_send_state = LUSTRE_IMP_FULL; req->rq_type = PTL_RPC_MSG_REQUEST; req->rq_import = class_import_get(imp); - req->rq_export = NULL; req->rq_interpret_reply = work_interpreter; /* don't want reply */ req->rq_receiving_reply = 0; @@ -3026,16 +3009,6 @@ void *ptlrpcd_alloc_work(struct obd_import *imp, req->rq_no_resend = 1; req->rq_pill.rc_fmt = (void *)&worker_format; - spin_lock_init(&req->rq_lock); - INIT_LIST_HEAD(&req->rq_list); - INIT_LIST_HEAD(&req->rq_replay_list); - INIT_LIST_HEAD(&req->rq_set_chain); - INIT_LIST_HEAD(&req->rq_history_list); - INIT_LIST_HEAD(&req->rq_exp_list); - init_waitqueue_head(&req->rq_reply_waitq); - init_waitqueue_head(&req->rq_set_waitq); - atomic_set(&req->rq_refcount, 1); - CLASSERT(sizeof(*args) <= sizeof(req->rq_async_args)); args = ptlrpc_req_async_args(req); args->cb = cb; diff --git a/drivers/staging/lustre/lustre/ptlrpc/events.c b/drivers/staging/lustre/lustre/ptlrpc/events.c index b8ca7d6..95be4aa 100644 --- a/drivers/staging/lustre/lustre/ptlrpc/events.c +++ b/drivers/staging/lustre/lustre/ptlrpc/events.c @@ -324,6 +324,7 @@ void request_in_callback(lnet_event_t *ev) } } + ptlrpc_srv_req_init(req); /* NB we ABSOLUTELY RELY on req being zeroed, so pointers are NULL, * flags are reset and scalars are zero. We only set the message * size to non-zero if this was a successful receive. @@ -337,10 +338,6 @@ void request_in_callback(lnet_event_t *ev) req->rq_self = ev->target.nid; req->rq_rqbd = rqbd; req->rq_phase = RQ_PHASE_NEW; - spin_lock_init(&req->rq_lock); - INIT_LIST_HEAD(&req->rq_timed_list); - INIT_LIST_HEAD(&req->rq_exp_list); - atomic_set(&req->rq_refcount, 1); if (ev->type == LNET_EVENT_PUT) CDEBUG(D_INFO, "incoming req@%p x%llu msgsize %u\n", req, req->rq_xid, ev->mlength); diff --git a/drivers/staging/lustre/lustre/ptlrpc/niobuf.c b/drivers/staging/lustre/lustre/ptlrpc/niobuf.c index ff9a95c..4e7d68f 100644 --- a/drivers/staging/lustre/lustre/ptlrpc/niobuf.c +++ b/drivers/staging/lustre/lustre/ptlrpc/niobuf.c @@ -633,7 +633,7 @@ int ptl_send_rpc(struct ptlrpc_request *request, int noreply) OBD_FAIL_TIMEOUT(OBD_FAIL_PTLRPC_DELAY_SEND, request->rq_timeout + 5); - ktime_get_real_ts64(&request->rq_arrival_time); + ktime_get_real_ts64(&request->rq_sent_tv); request->rq_sent = ktime_get_real_seconds(); /* We give the server rq_timeout secs to process the req, and * add the network latency for our local timeout. diff --git a/drivers/staging/lustre/lustre/ptlrpc/ptlrpc_internal.h b/drivers/staging/lustre/lustre/ptlrpc/ptlrpc_internal.h index 97e97e2..d3674cb 100644 --- a/drivers/staging/lustre/lustre/ptlrpc/ptlrpc_internal.h +++ b/drivers/staging/lustre/lustre/ptlrpc/ptlrpc_internal.h @@ -288,4 +288,38 @@ static inline void ptlrpc_reqset_put(struct ptlrpc_request_set *set) if (atomic_dec_and_test(&set->set_refcount)) kfree(set); } + +/** initialise ptlrpc common fields */ +static inline void ptlrpc_req_comm_init(struct ptlrpc_request *req) +{ + spin_lock_init(&req->rq_lock); + atomic_set(&req->rq_refcount, 1); + INIT_LIST_HEAD(&req->rq_list); + INIT_LIST_HEAD(&req->rq_replay_list); +} + +/** initialise client side ptlrpc request */ +static inline void ptlrpc_cli_req_init(struct ptlrpc_request *req) +{ + struct ptlrpc_cli_req *cr = &req->rq_cli; + + ptlrpc_req_comm_init(req); + INIT_LIST_HEAD(&cr->cr_set_chain); + INIT_LIST_HEAD(&cr->cr_ctx_chain); + init_waitqueue_head(&cr->cr_reply_waitq); + init_waitqueue_head(&cr->cr_set_waitq); +} + +/** initialise server side ptlrpc request */ +static inline void ptlrpc_srv_req_init(struct ptlrpc_request *req) +{ + struct ptlrpc_srv_req *sr = &req->rq_srv; + + ptlrpc_req_comm_init(req); + req->rq_srv_req = 1; + INIT_LIST_HEAD(&sr->sr_exp_list); + INIT_LIST_HEAD(&sr->sr_timed_list); + INIT_LIST_HEAD(&sr->sr_hist_list); +} + #endif /* PTLRPC_INTERNAL_H */ diff --git a/drivers/staging/lustre/lustre/ptlrpc/ptlrpcd.c b/drivers/staging/lustre/lustre/ptlrpc/ptlrpcd.c index b0cf585..0a374b6 100644 --- a/drivers/staging/lustre/lustre/ptlrpc/ptlrpcd.c +++ b/drivers/staging/lustre/lustre/ptlrpc/ptlrpcd.c @@ -157,9 +157,9 @@ static int ptlrpcd_users; void ptlrpcd_wake(struct ptlrpc_request *req) { - struct ptlrpc_request_set *rq_set = req->rq_set; + struct ptlrpc_request_set *set = req->rq_set; - wake_up(&rq_set->set_waitq); + wake_up(&set->set_waitq); } EXPORT_SYMBOL(ptlrpcd_wake); diff --git a/drivers/staging/lustre/lustre/ptlrpc/sec.c b/drivers/staging/lustre/lustre/ptlrpc/sec.c index f3b4773..dbd819f 100644 --- a/drivers/staging/lustre/lustre/ptlrpc/sec.c +++ b/drivers/staging/lustre/lustre/ptlrpc/sec.c @@ -863,11 +863,9 @@ int sptlrpc_import_check_ctx(struct obd_import *imp) if (!req) return -ENOMEM; - spin_lock_init(&req->rq_lock); + ptlrpc_cli_req_init(req); atomic_set(&req->rq_refcount, 10000); - INIT_LIST_HEAD(&req->rq_ctx_chain); - init_waitqueue_head(&req->rq_reply_waitq); - init_waitqueue_head(&req->rq_set_waitq); + req->rq_import = imp; req->rq_flvr = sec->ps_flvr; req->rq_cli_ctx = ctx; @@ -1047,6 +1045,8 @@ int sptlrpc_cli_unwrap_early_reply(struct ptlrpc_request *req, if (!early_req) return -ENOMEM; + ptlrpc_cli_req_init(early_req); + early_size = req->rq_nob_received; early_bufsz = size_roundup_power2(early_size); early_buf = libcfs_kvzalloc(early_bufsz, GFP_NOFS); @@ -1095,7 +1095,6 @@ int sptlrpc_cli_unwrap_early_reply(struct ptlrpc_request *req, memcpy(early_buf, req->rq_repbuf, early_size); spin_unlock(&req->rq_lock); - spin_lock_init(&early_req->rq_lock); early_req->rq_cli_ctx = sptlrpc_cli_ctx_get(req->rq_cli_ctx); early_req->rq_flvr = req->rq_flvr; early_req->rq_repbuf = early_buf; -- cgit v0.10.2 From 9faa2ade3fdaf00c6c45654071b325d3c88f9230 Mon Sep 17 00:00:00 2001 From: Liang Zhen Date: Mon, 20 Jun 2016 16:55:31 -0400 Subject: staging/lustre/ptlrpc: missing wakeup for ptlrpc_check_set This patch changes a few things: - There is no guarantee that request_out_callback will happen before reply_in_callback, if a request got reply and unlinked reply buffer before request_out_callback is called, then the thread waiting on ptlrpc_request_set will miss wakeup event. This may seriously impact performance of some IO workloads or result in RPC timeout - To make code more easier to understand, this patch changes action-bits "rq_req_unlink" and "rq_reply_unlink" to status-bits "rq_req_unlinked" and "rq_reply_unlinked" Signed-off-by: Liang Zhen Reviewed-on: http://review.whamcloud.com/12158 Intel-bug-id: https://jira.hpdd.intel.com/browse/LU-5696 Reviewed-by: Johann Lombardi Reviewed-by: Li Wei Reviewed-by: Mike Pershin Signed-off-by: Oleg Drokin Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/lustre/lustre/include/lustre_net.h b/drivers/staging/lustre/lustre/include/lustre_net.h index 65924d9..0fedef9 100644 --- a/drivers/staging/lustre/lustre/include/lustre_net.h +++ b/drivers/staging/lustre/lustre/include/lustre_net.h @@ -1428,7 +1428,7 @@ struct ptlrpc_request { * rq_list */ spinlock_t rq_lock; - /** client-side flags are serialized by rq_lock */ + /** client-side flags are serialized by rq_lock @{ */ unsigned int rq_intr:1, rq_replied:1, rq_err:1, rq_timedout:1, rq_resend:1, rq_restart:1, /** @@ -1444,18 +1444,15 @@ struct ptlrpc_request { rq_no_resend:1, rq_waiting:1, rq_receiving_reply:1, rq_no_delay:1, rq_net_err:1, rq_wait_ctx:1, rq_early:1, - rq_req_unlink:1, rq_reply_unlink:1, + rq_req_unlinked:1, /* unlinked request buffer from lnet */ + rq_reply_unlinked:1, /* unlinked reply buffer from lnet */ rq_memalloc:1, /* req originated from "kswapd" */ - /* server-side flags */ - rq_packed_final:1, /* packed final reply */ - rq_hp:1, /* high priority RPC */ - rq_at_linked:1, /* link into service's srv_at_array */ - rq_reply_truncate:1, rq_committed:1, - /* whether the "rq_set" is a valid one */ + rq_reply_truncated:1, + /** whether the "rq_set" is a valid one */ rq_invalid_rqset:1, rq_generation_set:1, - /* do not resend request on -EINPROGRESS */ + /** do not resend request on -EINPROGRESS */ rq_no_retry_einprogress:1, /* allow the req to be sent if the import is in recovery * status @@ -1463,6 +1460,14 @@ struct ptlrpc_request { rq_allow_replay:1, /* bulk request, sent to server, but uncommitted */ rq_unstable:1; + /** @} */ + + /** server-side flags @{ */ + unsigned int + rq_hp:1, /**< high priority RPC */ + rq_at_linked:1, /**< link into service's srv_at_array */ + rq_packed_final:1; /**< packed final reply */ + /** @} */ /** one of RQ_PHASE_* */ enum rq_phase rq_phase; @@ -2784,8 +2789,8 @@ ptlrpc_client_recv_or_unlink(struct ptlrpc_request *req) spin_unlock(&req->rq_lock); return 1; } - rc = req->rq_receiving_reply; - rc = rc || req->rq_req_unlink || req->rq_reply_unlink; + rc = !req->rq_req_unlinked || !req->rq_reply_unlinked || + req->rq_receiving_reply; spin_unlock(&req->rq_lock); return rc; } diff --git a/drivers/staging/lustre/lustre/ptlrpc/client.c b/drivers/staging/lustre/lustre/ptlrpc/client.c index 9abd469..ae1cef3 100644 --- a/drivers/staging/lustre/lustre/ptlrpc/client.c +++ b/drivers/staging/lustre/lustre/ptlrpc/client.c @@ -1148,9 +1148,9 @@ static int after_reply(struct ptlrpc_request *req) LASSERT(obd); /* repbuf must be unlinked */ - LASSERT(!req->rq_receiving_reply && !req->rq_reply_unlink); + LASSERT(!req->rq_receiving_reply && req->rq_reply_unlinked); - if (req->rq_reply_truncate) { + if (req->rq_reply_truncated) { if (ptlrpc_no_resend(req)) { DEBUG_REQ(D_ERROR, req, "reply buffer overflow, expected: %d, actual size: %d", req->rq_nob_received, req->rq_repbuf_len); @@ -2342,9 +2342,10 @@ int ptlrpc_unregister_reply(struct ptlrpc_request *request, int async) LASSERT(rc == -ETIMEDOUT); DEBUG_REQ(D_WARNING, request, - "Unexpectedly long timeout rvcng=%d unlnk=%d/%d", + "Unexpectedly long timeout receiving_reply=%d req_ulinked=%d reply_unlinked=%d", request->rq_receiving_reply, - request->rq_req_unlink, request->rq_reply_unlink); + request->rq_req_unlinked, + request->rq_reply_unlinked); } return 0; } @@ -3002,9 +3003,6 @@ void *ptlrpcd_alloc_work(struct obd_import *imp, req->rq_import = class_import_get(imp); req->rq_interpret_reply = work_interpreter; /* don't want reply */ - req->rq_receiving_reply = 0; - req->rq_req_unlink = 0; - req->rq_reply_unlink = 0; req->rq_no_delay = 1; req->rq_no_resend = 1; req->rq_pill.rc_fmt = (void *)&worker_format; diff --git a/drivers/staging/lustre/lustre/ptlrpc/events.c b/drivers/staging/lustre/lustre/ptlrpc/events.c index 95be4aa..a243342 100644 --- a/drivers/staging/lustre/lustre/ptlrpc/events.c +++ b/drivers/staging/lustre/lustre/ptlrpc/events.c @@ -51,27 +51,33 @@ void request_out_callback(lnet_event_t *ev) { struct ptlrpc_cb_id *cbid = ev->md.user_ptr; struct ptlrpc_request *req = cbid->cbid_arg; + bool wakeup = false; - LASSERT(ev->type == LNET_EVENT_SEND || - ev->type == LNET_EVENT_UNLINK); + LASSERT(ev->type == LNET_EVENT_SEND || ev->type == LNET_EVENT_UNLINK); LASSERT(ev->unlinked); DEBUG_REQ(D_NET, req, "type %d, status %d", ev->type, ev->status); sptlrpc_request_out_callback(req); + spin_lock(&req->rq_lock); req->rq_real_sent = ktime_get_real_seconds(); - if (ev->unlinked) - req->rq_req_unlink = 0; + req->rq_req_unlinked = 1; + /* reply_in_callback happened before request_out_callback? */ + if (req->rq_reply_unlinked) + wakeup = true; if (ev->type == LNET_EVENT_UNLINK || ev->status != 0) { /* Failed send: make it seem like the reply timed out, just * like failing sends in client.c does currently... */ - req->rq_net_err = 1; - ptlrpc_client_wake_req(req); + wakeup = true; } + + if (wakeup) + ptlrpc_client_wake_req(req); + spin_unlock(&req->rq_lock); ptlrpc_req_finished(req); @@ -100,7 +106,7 @@ void reply_in_callback(lnet_event_t *ev) req->rq_receiving_reply = 0; req->rq_early = 0; if (ev->unlinked) - req->rq_reply_unlink = 0; + req->rq_reply_unlinked = 1; if (ev->status) goto out_wake; @@ -114,7 +120,7 @@ void reply_in_callback(lnet_event_t *ev) if (ev->mlength < ev->rlength) { CDEBUG(D_RPCTRACE, "truncate req %p rpc %d - %d+%d\n", req, req->rq_replen, ev->rlength, ev->offset); - req->rq_reply_truncate = 1; + req->rq_reply_truncated = 1; req->rq_replied = 1; req->rq_status = -EOVERFLOW; req->rq_nob_received = ev->rlength + ev->offset; diff --git a/drivers/staging/lustre/lustre/ptlrpc/niobuf.c b/drivers/staging/lustre/lustre/ptlrpc/niobuf.c index 4e7d68f..8c49f5e 100644 --- a/drivers/staging/lustre/lustre/ptlrpc/niobuf.c +++ b/drivers/staging/lustre/lustre/ptlrpc/niobuf.c @@ -577,19 +577,18 @@ int ptl_send_rpc(struct ptlrpc_request *request, int noreply) } spin_lock(&request->rq_lock); - /* If the MD attach succeeds, there _will_ be a reply_in callback */ - request->rq_receiving_reply = !noreply; - request->rq_req_unlink = 1; /* We are responsible for unlinking the reply buffer */ - request->rq_reply_unlink = !noreply; + request->rq_reply_unlinked = noreply; + request->rq_receiving_reply = !noreply; /* Clear any flags that may be present from previous sends. */ + request->rq_req_unlinked = 0; request->rq_replied = 0; request->rq_err = 0; request->rq_timedout = 0; request->rq_net_err = 0; request->rq_resend = 0; request->rq_restart = 0; - request->rq_reply_truncate = 0; + request->rq_reply_truncated = 0; spin_unlock(&request->rq_lock); if (!noreply) { @@ -604,7 +603,7 @@ int ptl_send_rpc(struct ptlrpc_request *request, int noreply) reply_md.user_ptr = &request->rq_reply_cbid; reply_md.eq_handle = ptlrpc_eq_h; - /* We must see the unlink callback to unset rq_reply_unlink, + /* We must see the unlink callback to set rq_reply_unlinked, * so we can't auto-unlink */ rc = LNetMDAttach(reply_me_h, reply_md, LNET_RETAIN, @@ -651,9 +650,10 @@ int ptl_send_rpc(struct ptlrpc_request *request, int noreply) connection, request->rq_request_portal, request->rq_xid, 0); - if (rc == 0) + if (likely(rc == 0)) goto out; + request->rq_req_unlinked = 1; ptlrpc_req_finished(request); if (noreply) goto out; diff --git a/drivers/staging/lustre/lustre/ptlrpc/ptlrpc_internal.h b/drivers/staging/lustre/lustre/ptlrpc/ptlrpc_internal.h index d3674cb..a9831fa 100644 --- a/drivers/staging/lustre/lustre/ptlrpc/ptlrpc_internal.h +++ b/drivers/staging/lustre/lustre/ptlrpc/ptlrpc_internal.h @@ -304,6 +304,15 @@ static inline void ptlrpc_cli_req_init(struct ptlrpc_request *req) struct ptlrpc_cli_req *cr = &req->rq_cli; ptlrpc_req_comm_init(req); + + req->rq_receiving_reply = 0; + req->rq_req_unlinked = 1; + req->rq_reply_unlinked = 1; + + req->rq_receiving_reply = 0; + req->rq_req_unlinked = 1; + req->rq_reply_unlinked = 1; + INIT_LIST_HEAD(&cr->cr_set_chain); INIT_LIST_HEAD(&cr->cr_ctx_chain); init_waitqueue_head(&cr->cr_reply_waitq); -- cgit v0.10.2 From af38abfcd971a10b6f41d03a765e85b59b841cfb Mon Sep 17 00:00:00 2001 From: Vitaly Fertman Date: Mon, 20 Jun 2016 16:55:32 -0400 Subject: staging/lustre/ptlrpc: Early Reply vs Reply MDunlink A race between unregister_reply & early reply. When buffers are busy for the early transfer, they cannon be unlinked by unregister_reply, so the RPC gets into UNREGISTERING state. The coming reply_in_callback for the early RPC already has unlinked flag set due to previous mdunlink attempt, but we handle it properly only for UNILNK event, whereas this is PUT in this case. Signed-off-by: Vitaly Fertman Seagate-bug-id: MRP-3323 Reviewed-by: Alexey Leonidovich Lyashkov Reviewed-by: Andriy Skulysh Tested-by: Parinay Vijayprakash Kondekar Reviewed-on: http://review.whamcloud.com/18934 Intel-bug-id: https://jira.hpdd.intel.com/browse/LU-7434 Reviewed-by: Chris Horn Reviewed-by: Andreas Dilger Signed-off-by: Oleg Drokin Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/lustre/lustre/ptlrpc/events.c b/drivers/staging/lustre/lustre/ptlrpc/events.c index a243342..b1ce725 100644 --- a/drivers/staging/lustre/lustre/ptlrpc/events.c +++ b/drivers/staging/lustre/lustre/ptlrpc/events.c @@ -137,7 +137,8 @@ void reply_in_callback(lnet_event_t *ev) req->rq_early_count++; /* number received, client side */ - if (req->rq_replied) /* already got the real reply */ + /* already got the real reply or buffers are already unlinked */ + if (req->rq_replied || req->rq_reply_unlinked == 1) goto out_wake; req->rq_early = 1; -- cgit v0.10.2 From 63a46519f2b38f2afc7767273460b86792f8d94d Mon Sep 17 00:00:00 2001 From: Ben Evans Date: Mon, 20 Jun 2016 16:55:33 -0400 Subject: staging/lustre/ptlrpc: Remove __ptlrpc_request_bufs_pack Combine __ptlrpc_request_bufs_pack into ptlrpc_request_bufs_pack because it was an unnecessary wrapper otherwise. Signed-off-by: Ben Evans Reviewed-on: http://review.whamcloud.com/16765 Intel-bug-id: https://jira.hpdd.intel.com/browse/LU-7269 Reviewed-by: Frank Zago Reviewed-by: Andreas Dilger Reviewed-by: John L. Hammond Reviewed-by: Chris Horn Signed-off-by: Oleg Drokin Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/lustre/lustre/ptlrpc/client.c b/drivers/staging/lustre/lustre/ptlrpc/client.c index ae1cef3..5d832eb 100644 --- a/drivers/staging/lustre/lustre/ptlrpc/client.c +++ b/drivers/staging/lustre/lustre/ptlrpc/client.c @@ -583,14 +583,19 @@ static void __ptlrpc_free_req_to_pool(struct ptlrpc_request *request) spin_unlock(&pool->prp_lock); } -static int __ptlrpc_request_bufs_pack(struct ptlrpc_request *request, - __u32 version, int opcode, - int count, __u32 *lengths, char **bufs, - struct ptlrpc_cli_ctx *ctx) +int ptlrpc_request_bufs_pack(struct ptlrpc_request *request, + __u32 version, int opcode, char **bufs, + struct ptlrpc_cli_ctx *ctx) { - struct obd_import *imp = request->rq_import; + int count; + struct obd_import *imp; + __u32 *lengths; int rc; + count = req_capsule_filled_sizes(&request->rq_pill, RCL_CLIENT); + imp = request->rq_import; + lengths = request->rq_pill.rc_area[RCL_CLIENT]; + if (unlikely(ctx)) { request->rq_cli_ctx = sptlrpc_cli_ctx_get(ctx); } else { @@ -598,15 +603,12 @@ static int __ptlrpc_request_bufs_pack(struct ptlrpc_request *request, if (rc) goto out_free; } - sptlrpc_req_set_flavor(request, opcode); rc = lustre_pack_request(request, imp->imp_msg_magic, count, lengths, bufs); - if (rc) { - LASSERT(!request->rq_pool); + if (rc) goto out_ctx; - } lustre_msg_add_version(request->rq_reqmsg, version); request->rq_send_state = LUSTRE_IMP_FULL; @@ -631,24 +633,14 @@ static int __ptlrpc_request_bufs_pack(struct ptlrpc_request *request, lustre_msg_set_opc(request->rq_reqmsg, opcode); return 0; + out_ctx: + LASSERT(!request->rq_pool); sptlrpc_cli_ctx_put(request->rq_cli_ctx, 1); out_free: class_import_put(imp); return rc; } - -int ptlrpc_request_bufs_pack(struct ptlrpc_request *request, - __u32 version, int opcode, char **bufs, - struct ptlrpc_cli_ctx *ctx) -{ - int count; - - count = req_capsule_filled_sizes(&request->rq_pill, RCL_CLIENT); - return __ptlrpc_request_bufs_pack(request, version, opcode, count, - request->rq_pill.rc_area[RCL_CLIENT], - bufs, ctx); -} EXPORT_SYMBOL(ptlrpc_request_bufs_pack); /** -- cgit v0.10.2 From 81ea39ecf963fe0c44b8772a19863ecb154782f6 Mon Sep 17 00:00:00 2001 From: Vitaly Fertman Date: Mon, 20 Jun 2016 16:55:34 -0400 Subject: staging/lustre/ptlrpc: lost bulk leads to a hang The reverse order of request_out_callback() and reply_in_callback() puts the RPC into UNREGISTERING state, which is waiting for RPC & bulk md unlink, whereas only RPC md unlink has been called so far. If bulk is lost, even expired_set does not check for UNREGISTERING state. The same for write if server returns an error. This phase is ambiguous, split to UNREG_RPC and UNREG_BULK. Signed-off-by: Vitaly Fertman Seagate-bug-id: MRP-2953, MRP-3206 Reviewed-by: Andriy Skulysh Reviewed-by: Alexey Leonidovich Lyashkov Tested-by: Elena V. Gryaznova Reviewed-on: http://review.whamcloud.com/19953 Reviewed-by: Chris Horn Reviewed-by: Ann Koehler Reviewed-by: Andreas Dilger Signed-off-by: Oleg Drokin Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/lustre/lustre/include/lustre_net.h b/drivers/staging/lustre/lustre/include/lustre_net.h index 0fedef9..d5debd6 100644 --- a/drivers/staging/lustre/lustre/include/lustre_net.h +++ b/drivers/staging/lustre/lustre/include/lustre_net.h @@ -480,8 +480,9 @@ enum rq_phase { RQ_PHASE_BULK = 0xebc0de02, RQ_PHASE_INTERPRET = 0xebc0de03, RQ_PHASE_COMPLETE = 0xebc0de04, - RQ_PHASE_UNREGISTERING = 0xebc0de05, - RQ_PHASE_UNDEFINED = 0xebc0de06 + RQ_PHASE_UNREG_RPC = 0xebc0de05, + RQ_PHASE_UNREG_BULK = 0xebc0de06, + RQ_PHASE_UNDEFINED = 0xebc0de07 }; /** Type of request interpreter call-back */ @@ -1263,6 +1264,8 @@ struct ptlrpc_cli_req { time_t cr_reply_deadline; /** when req bulk unlink must finish. */ time_t cr_bulk_deadline; + /** when req unlink must finish. */ + time_t cr_req_deadline; /** Portal to which this request would be sent */ short cr_req_ptl; /** Portal where to wait for reply and where reply would be sent */ @@ -1318,6 +1321,7 @@ struct ptlrpc_cli_req { #define rq_real_sent rq_cli.cr_sent_out #define rq_reply_deadline rq_cli.cr_reply_deadline #define rq_bulk_deadline rq_cli.cr_bulk_deadline +#define rq_req_deadline rq_cli.cr_req_deadline #define rq_nr_resend rq_cli.cr_resend_nr #define rq_request_portal rq_cli.cr_req_ptl #define rq_reply_portal rq_cli.cr_rep_ptl @@ -1692,8 +1696,10 @@ ptlrpc_phase2str(enum rq_phase phase) return "Interpret"; case RQ_PHASE_COMPLETE: return "Complete"; - case RQ_PHASE_UNREGISTERING: - return "Unregistering"; + case RQ_PHASE_UNREG_RPC: + return "UnregRPC"; + case RQ_PHASE_UNREG_BULK: + return "UnregBULK"; default: return "?Phase?"; } @@ -1720,7 +1726,7 @@ ptlrpc_rqphase2str(struct ptlrpc_request *req) #define DEBUG_REQ_FLAGS(req) \ ptlrpc_rqphase2str(req), \ FLAG(req->rq_intr, "I"), FLAG(req->rq_replied, "R"), \ - FLAG(req->rq_err, "E"), \ + FLAG(req->rq_err, "E"), FLAG(req->rq_net_err, "e"), \ FLAG(req->rq_timedout, "X") /* eXpired */, FLAG(req->rq_resend, "S"), \ FLAG(req->rq_restart, "T"), FLAG(req->rq_replay, "P"), \ FLAG(req->rq_no_resend, "N"), \ @@ -1728,7 +1734,7 @@ ptlrpc_rqphase2str(struct ptlrpc_request *req) FLAG(req->rq_wait_ctx, "C"), FLAG(req->rq_hp, "H"), \ FLAG(req->rq_committed, "M") -#define REQ_FLAGS_FMT "%s:%s%s%s%s%s%s%s%s%s%s%s%s" +#define REQ_FLAGS_FMT "%s:%s%s%s%s%s%s%s%s%s%s%s%s%s" void _debug_req(struct ptlrpc_request *req, struct libcfs_debug_msg_data *data, const char *fmt, ...) @@ -2379,8 +2385,7 @@ static inline int ptlrpc_client_bulk_active(struct ptlrpc_request *req) desc = req->rq_bulk; - if (OBD_FAIL_CHECK(OBD_FAIL_PTLRPC_LONG_BULK_UNLINK) && - req->rq_bulk_deadline > ktime_get_real_seconds()) + if (req->rq_bulk_deadline > ktime_get_real_seconds()) return 1; if (!desc) @@ -2727,13 +2732,20 @@ ptlrpc_rqphase_move(struct ptlrpc_request *req, enum rq_phase new_phase) if (req->rq_phase == new_phase) return; - if (new_phase == RQ_PHASE_UNREGISTERING) { + if (new_phase == RQ_PHASE_UNREG_RPC || + new_phase == RQ_PHASE_UNREG_BULK) { + /* No embedded unregistering phases */ + if (req->rq_phase == RQ_PHASE_UNREG_RPC || + req->rq_phase == RQ_PHASE_UNREG_BULK) + return; + req->rq_next_phase = req->rq_phase; if (req->rq_import) atomic_inc(&req->rq_import->imp_unregistering); } - if (req->rq_phase == RQ_PHASE_UNREGISTERING) { + if (req->rq_phase == RQ_PHASE_UNREG_RPC || + req->rq_phase == RQ_PHASE_UNREG_BULK) { if (req->rq_import) atomic_dec(&req->rq_import->imp_unregistering); } @@ -2750,9 +2762,6 @@ ptlrpc_rqphase_move(struct ptlrpc_request *req, enum rq_phase new_phase) static inline int ptlrpc_client_early(struct ptlrpc_request *req) { - if (OBD_FAIL_CHECK(OBD_FAIL_PTLRPC_LONG_REPL_UNLINK) && - req->rq_reply_deadline > ktime_get_real_seconds()) - return 0; return req->rq_early; } @@ -2762,8 +2771,7 @@ ptlrpc_client_early(struct ptlrpc_request *req) static inline int ptlrpc_client_replied(struct ptlrpc_request *req) { - if (OBD_FAIL_CHECK(OBD_FAIL_PTLRPC_LONG_REPL_UNLINK) && - req->rq_reply_deadline > ktime_get_real_seconds()) + if (req->rq_reply_deadline > ktime_get_real_seconds()) return 0; return req->rq_replied; } @@ -2772,8 +2780,7 @@ ptlrpc_client_replied(struct ptlrpc_request *req) static inline int ptlrpc_client_recv(struct ptlrpc_request *req) { - if (OBD_FAIL_CHECK(OBD_FAIL_PTLRPC_LONG_REPL_UNLINK) && - req->rq_reply_deadline > ktime_get_real_seconds()) + if (req->rq_reply_deadline > ktime_get_real_seconds()) return 1; return req->rq_receiving_reply; } @@ -2784,8 +2791,11 @@ ptlrpc_client_recv_or_unlink(struct ptlrpc_request *req) int rc; spin_lock(&req->rq_lock); - if (OBD_FAIL_CHECK(OBD_FAIL_PTLRPC_LONG_REPL_UNLINK) && - req->rq_reply_deadline > ktime_get_real_seconds()) { + if (req->rq_reply_deadline > ktime_get_real_seconds()) { + spin_unlock(&req->rq_lock); + return 1; + } + if (req->rq_req_deadline > ktime_get_real_seconds()) { spin_unlock(&req->rq_lock); return 1; } diff --git a/drivers/staging/lustre/lustre/include/obd_support.h b/drivers/staging/lustre/lustre/include/obd_support.h index cdf20d6..845e64a 100644 --- a/drivers/staging/lustre/lustre/include/obd_support.h +++ b/drivers/staging/lustre/lustre/include/obd_support.h @@ -364,6 +364,9 @@ extern char obd_jobid_var[]; #define OBD_FAIL_PTLRPC_CLIENT_BULK_CB2 0x515 #define OBD_FAIL_PTLRPC_DELAY_IMP_FULL 0x516 #define OBD_FAIL_PTLRPC_CANCEL_RESEND 0x517 +#define OBD_FAIL_PTLRPC_DROP_BULK 0x51a +#define OBD_FAIL_PTLRPC_LONG_REQ_UNLINK 0x51b +#define OBD_FAIL_PTLRPC_LONG_BOTH_UNLINK 0x51c #define OBD_FAIL_OBD_PING_NET 0x600 #define OBD_FAIL_OBD_LOG_CANCEL_NET 0x601 diff --git a/drivers/staging/lustre/lustre/ptlrpc/client.c b/drivers/staging/lustre/lustre/ptlrpc/client.c index 5d832eb..d4463d7 100644 --- a/drivers/staging/lustre/lustre/ptlrpc/client.c +++ b/drivers/staging/lustre/lustre/ptlrpc/client.c @@ -621,6 +621,8 @@ int ptlrpc_request_bufs_pack(struct ptlrpc_request *request, request->rq_reply_cbid.cbid_arg = request; request->rq_reply_deadline = 0; + request->rq_bulk_deadline = 0; + request->rq_req_deadline = 0; request->rq_phase = RQ_PHASE_NEW; request->rq_next_phase = RQ_PHASE_UNDEFINED; @@ -632,6 +634,37 @@ int ptlrpc_request_bufs_pack(struct ptlrpc_request *request, request->rq_xid = ptlrpc_next_xid(); lustre_msg_set_opc(request->rq_reqmsg, opcode); + /* Let's setup deadline for req/reply/bulk unlink for opcode. */ + if (cfs_fail_val == opcode) { + time_t *fail_t = NULL, *fail2_t = NULL; + + if (CFS_FAIL_CHECK(OBD_FAIL_PTLRPC_LONG_BULK_UNLINK)) { + fail_t = &request->rq_bulk_deadline; + } else if (CFS_FAIL_CHECK(OBD_FAIL_PTLRPC_LONG_REPL_UNLINK)) { + fail_t = &request->rq_reply_deadline; + } else if (CFS_FAIL_CHECK(OBD_FAIL_PTLRPC_LONG_REQ_UNLINK)) { + fail_t = &request->rq_req_deadline; + } else if (CFS_FAIL_CHECK(OBD_FAIL_PTLRPC_LONG_BOTH_UNLINK)) { + fail_t = &request->rq_reply_deadline; + fail2_t = &request->rq_bulk_deadline; + } + + if (fail_t) { + *fail_t = ktime_get_real_seconds() + LONG_UNLINK; + + if (fail2_t) + *fail2_t = ktime_get_real_seconds() + + LONG_UNLINK; + + /* The RPC is infected, let the test change the + * fail_loc + */ + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(cfs_time_seconds(2)); + set_current_state(TASK_RUNNING); + } + } + return 0; out_ctx: @@ -1481,16 +1514,28 @@ int ptlrpc_check_set(const struct lu_env *env, struct ptlrpc_request_set *set) if (!(req->rq_phase == RQ_PHASE_RPC || req->rq_phase == RQ_PHASE_BULK || req->rq_phase == RQ_PHASE_INTERPRET || - req->rq_phase == RQ_PHASE_UNREGISTERING || + req->rq_phase == RQ_PHASE_UNREG_RPC || + req->rq_phase == RQ_PHASE_UNREG_BULK || req->rq_phase == RQ_PHASE_COMPLETE)) { DEBUG_REQ(D_ERROR, req, "bad phase %x", req->rq_phase); LBUG(); } - if (req->rq_phase == RQ_PHASE_UNREGISTERING) { + if (req->rq_phase == RQ_PHASE_UNREG_RPC || + req->rq_phase == RQ_PHASE_UNREG_BULK) { LASSERT(req->rq_next_phase != req->rq_phase); LASSERT(req->rq_next_phase != RQ_PHASE_UNDEFINED); + if (req->rq_req_deadline && + !OBD_FAIL_CHECK(OBD_FAIL_PTLRPC_LONG_REQ_UNLINK)) + req->rq_req_deadline = 0; + if (req->rq_reply_deadline && + !OBD_FAIL_CHECK(OBD_FAIL_PTLRPC_LONG_REPL_UNLINK)) + req->rq_reply_deadline = 0; + if (req->rq_bulk_deadline && + !OBD_FAIL_CHECK(OBD_FAIL_PTLRPC_LONG_BULK_UNLINK)) + req->rq_bulk_deadline = 0; + /* * Skip processing until reply is unlinked. We * can't return to pool before that and we can't @@ -1498,7 +1543,10 @@ int ptlrpc_check_set(const struct lu_env *env, struct ptlrpc_request_set *set) * sure that all rdma transfers finished and will * not corrupt any data. */ - if (ptlrpc_client_recv_or_unlink(req) || + if (req->rq_phase == RQ_PHASE_UNREG_RPC && + ptlrpc_client_recv_or_unlink(req)) + continue; + if (req->rq_phase == RQ_PHASE_UNREG_BULK && ptlrpc_client_bulk_active(req)) continue; @@ -1976,7 +2024,7 @@ void ptlrpc_interrupted_set(void *data) list_entry(tmp, struct ptlrpc_request, rq_set_chain); if (req->rq_phase != RQ_PHASE_RPC && - req->rq_phase != RQ_PHASE_UNREGISTERING) + req->rq_phase != RQ_PHASE_UNREG_RPC) continue; ptlrpc_mark_interrupted(req); @@ -2288,8 +2336,9 @@ int ptlrpc_unregister_reply(struct ptlrpc_request *request, int async) /* Let's setup deadline for reply unlink. */ if (OBD_FAIL_CHECK(OBD_FAIL_PTLRPC_LONG_REPL_UNLINK) && - async && request->rq_reply_deadline == 0) - request->rq_reply_deadline = ktime_get_real_seconds()+LONG_UNLINK; + async && request->rq_reply_deadline == 0 && cfs_fail_val == 0) + request->rq_reply_deadline = + ktime_get_real_seconds() + LONG_UNLINK; /* Nothing left to do. */ if (!ptlrpc_client_recv_or_unlink(request)) @@ -2302,7 +2351,7 @@ int ptlrpc_unregister_reply(struct ptlrpc_request *request, int async) return 1; /* Move to "Unregistering" phase as reply was not unlinked yet. */ - ptlrpc_rqphase_move(request, RQ_PHASE_UNREGISTERING); + ptlrpc_rqphase_move(request, RQ_PHASE_UNREG_RPC); /* Do not wait for unlink to finish. */ if (async) @@ -2932,7 +2981,6 @@ static void ptlrpcd_add_work_req(struct ptlrpc_request *req) req->rq_timeout = obd_timeout; req->rq_sent = ktime_get_real_seconds(); req->rq_deadline = req->rq_sent + req->rq_timeout; - req->rq_reply_deadline = req->rq_deadline; req->rq_phase = RQ_PHASE_INTERPRET; req->rq_next_phase = RQ_PHASE_COMPLETE; req->rq_xid = ptlrpc_next_xid(); diff --git a/drivers/staging/lustre/lustre/ptlrpc/import.c b/drivers/staging/lustre/lustre/ptlrpc/import.c index 914bbd2..3292e6e 100644 --- a/drivers/staging/lustre/lustre/ptlrpc/import.c +++ b/drivers/staging/lustre/lustre/ptlrpc/import.c @@ -356,9 +356,8 @@ void ptlrpc_invalidate_import(struct obd_import *imp) "still on delayed list"); } - CERROR("%s: RPCs in \"%s\" phase found (%d). Network is sluggish? Waiting them to error out.\n", + CERROR("%s: Unregistering RPCs found (%d). Network is sluggish? Waiting them to error out.\n", cli_tgt, - ptlrpc_phase2str(RQ_PHASE_UNREGISTERING), atomic_read(&imp-> imp_unregistering)); } diff --git a/drivers/staging/lustre/lustre/ptlrpc/niobuf.c b/drivers/staging/lustre/lustre/ptlrpc/niobuf.c index 8c49f5e..11ec825 100644 --- a/drivers/staging/lustre/lustre/ptlrpc/niobuf.c +++ b/drivers/staging/lustre/lustre/ptlrpc/niobuf.c @@ -247,7 +247,7 @@ int ptlrpc_unregister_bulk(struct ptlrpc_request *req, int async) /* Let's setup deadline for reply unlink. */ if (OBD_FAIL_CHECK(OBD_FAIL_PTLRPC_LONG_BULK_UNLINK) && - async && req->rq_bulk_deadline == 0) + async && req->rq_bulk_deadline == 0 && cfs_fail_val == 0) req->rq_bulk_deadline = ktime_get_real_seconds() + LONG_UNLINK; if (ptlrpc_client_bulk_active(req) == 0) /* completed or */ @@ -266,7 +266,7 @@ int ptlrpc_unregister_bulk(struct ptlrpc_request *req, int async) return 1; /* never registered */ /* Move to "Unregistering" phase as bulk was not unlinked yet. */ - ptlrpc_rqphase_move(req, RQ_PHASE_UNREGISTERING); + ptlrpc_rqphase_move(req, RQ_PHASE_UNREG_BULK); /* Do not wait for unlink to finish. */ if (async) -- cgit v0.10.2 From 0e5fd06ca069a8edc32a035add93112f6681dd72 Mon Sep 17 00:00:00 2001 From: Patrick Farrell Date: Mon, 20 Jun 2016 16:55:35 -0400 Subject: staging/lustre/llite: take trunc_sem only at vvp layer The lli_trunc_sem is taken in 'read' mode in both ll_page_mkwrite and vvp_io_fault_start. This can lead to a deadlock with another thread which asks for the semaphore in write mode between thse two read calls. Since all users of lli_trunc_sem are in the vvp layer, we can satisfy the requirement to exclude truncate by taking the semaphore only in vvp_io_fault_start. Signed-off-by: Patrick Farrell Reviewed-on: http://review.whamcloud.com/19315 Intel-bug-id: https://jira.hpdd.intel.com/browse/LU-7981 Reviewed-by: Jinshan Xiong Reviewed-by: Andriy Skulysh Signed-off-by: Oleg Drokin Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/lustre/lustre/llite/llite_mmap.c b/drivers/staging/lustre/lustre/llite/llite_mmap.c index fb1c3b6..66ee5db 100644 --- a/drivers/staging/lustre/lustre/llite/llite_mmap.c +++ b/drivers/staging/lustre/lustre/llite/llite_mmap.c @@ -196,18 +196,11 @@ static int ll_page_mkwrite0(struct vm_area_struct *vma, struct page *vmpage, set = cfs_block_sigsinv(sigmask(SIGKILL) | sigmask(SIGTERM)); - /* we grab lli_trunc_sem to exclude truncate case. - * Otherwise, we could add dirty pages into osc cache - * while truncate is on-going. - */ inode = vvp_object_inode(io->ci_obj); lli = ll_i2info(inode); - down_read(&lli->lli_trunc_sem); result = cl_io_loop(env, io); - up_read(&lli->lli_trunc_sem); - cfs_restore_sigs(set); if (result == 0) { -- cgit v0.10.2 From e93876dd730f0d87a6a79b1e867a9e8b4097674f Mon Sep 17 00:00:00 2001 From: Alex Zhuravlev Date: Mon, 20 Jun 2016 16:55:36 -0400 Subject: staging/lustre: LDLM_DEBUG() shouldn't be passed \n as it adds own \n, so any extra \n break log format. Signed-off-by: Alex Zhuravlev Reviewed-on: http://review.whamcloud.com/17494 Intel-bug-id: https://jira.hpdd.intel.com/browse/LU-7521 Reviewed-by: James Simmons Reviewed-by: John L. Hammond Reviewed-by: Andreas Dilger Signed-off-by: Oleg Drokin Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/lustre/lustre/ldlm/ldlm_lock.c b/drivers/staging/lustre/lustre/ldlm/ldlm_lock.c index 1ecdfa2..b7254eb 100644 --- a/drivers/staging/lustre/lustre/ldlm/ldlm_lock.c +++ b/drivers/staging/lustre/lustre/ldlm/ldlm_lock.c @@ -1440,7 +1440,7 @@ int ldlm_fill_lvb(struct ldlm_lock *lock, struct req_capsule *pill, memcpy(data, lvb, size); break; default: - LDLM_ERROR(lock, "Unknown LVB type: %d\n", lock->l_lvb_type); + LDLM_ERROR(lock, "Unknown LVB type: %d", lock->l_lvb_type); dump_stack(); return -EINVAL; } diff --git a/drivers/staging/lustre/lustre/ldlm/ldlm_lockd.c b/drivers/staging/lustre/lustre/ldlm/ldlm_lockd.c index 3eab059..8294703 100644 --- a/drivers/staging/lustre/lustre/ldlm/ldlm_lockd.c +++ b/drivers/staging/lustre/lustre/ldlm/ldlm_lockd.c @@ -637,7 +637,8 @@ static int ldlm_callback_handler(struct ptlrpc_request *req) */ if ((ldlm_is_canceling(lock) && ldlm_is_bl_done(lock)) || ldlm_is_failed(lock)) { - LDLM_DEBUG(lock, "callback on lock %#llx - lock disappeared\n", + LDLM_DEBUG(lock, + "callback on lock %#llx - lock disappeared", dlm_req->lock_handle[0].cookie); unlock_res_and_lock(lock); LDLM_LOCK_RELEASE(lock); diff --git a/drivers/staging/lustre/lustre/ldlm/ldlm_request.c b/drivers/staging/lustre/lustre/ldlm/ldlm_request.c index 471ab08..d3a376e 100644 --- a/drivers/staging/lustre/lustre/ldlm/ldlm_request.c +++ b/drivers/staging/lustre/lustre/ldlm/ldlm_request.c @@ -711,7 +711,7 @@ int ldlm_cli_enqueue(struct obd_export *exp, struct ptlrpc_request **reqp, lock->l_req_extent = policy->l_extent; } - LDLM_DEBUG(lock, "client-side enqueue START, flags %llx\n", + LDLM_DEBUG(lock, "client-side enqueue START, flags %llx", *flags); } diff --git a/drivers/staging/lustre/lustre/ldlm/ldlm_resource.c b/drivers/staging/lustre/lustre/ldlm/ldlm_resource.c index f7c95b7..51a28d9 100644 --- a/drivers/staging/lustre/lustre/ldlm/ldlm_resource.c +++ b/drivers/staging/lustre/lustre/ldlm/ldlm_resource.c @@ -1275,7 +1275,7 @@ void ldlm_resource_add_lock(struct ldlm_resource *res, struct list_head *head, { check_res_locked(res); - LDLM_DEBUG(lock, "About to add this lock:\n"); + LDLM_DEBUG(lock, "About to add this lock:"); if (ldlm_is_destroyed(lock)) { CDEBUG(D_OTHER, "Lock destroyed, not adding to resource\n"); diff --git a/drivers/staging/lustre/lustre/lov/lov_object.c b/drivers/staging/lustre/lustre/lov/lov_object.c index ec55b88..f9621b0 100644 --- a/drivers/staging/lustre/lustre/lov/lov_object.c +++ b/drivers/staging/lustre/lustre/lov/lov_object.c @@ -181,8 +181,8 @@ static int lov_init_sub(const struct lu_env *env, struct lov_object *lov, } LU_OBJECT_DEBUG(mask, env, &stripe->co_lu, - "stripe %d is already owned.\n", idx); - LU_OBJECT_DEBUG(mask, env, old_obj, "owned.\n"); + "stripe %d is already owned.", idx); + LU_OBJECT_DEBUG(mask, env, old_obj, "owned."); LU_OBJECT_HEADER(mask, env, lov2lu(lov), "try to own.\n"); cl_object_put(env, stripe); } diff --git a/drivers/staging/lustre/lustre/mdc/mdc_locks.c b/drivers/staging/lustre/lustre/mdc/mdc_locks.c index d55a5d8..b154aff 100644 --- a/drivers/staging/lustre/lustre/mdc/mdc_locks.c +++ b/drivers/staging/lustre/lustre/mdc/mdc_locks.c @@ -692,7 +692,7 @@ static int mdc_finish_enqueue(struct obd_export *exp, if (lock && ldlm_has_layout(lock) && lvb_data) { void *lmm; - LDLM_DEBUG(lock, "layout lock returned by: %s, lvb_len: %d\n", + LDLM_DEBUG(lock, "layout lock returned by: %s, lvb_len: %d", ldlm_it2str(it->it_op), lvb_len); lmm = libcfs_kvzalloc(lvb_len, GFP_NOFS); diff --git a/drivers/staging/lustre/lustre/osc/osc_cache.c b/drivers/staging/lustre/lustre/osc/osc_cache.c index 4c78b53..d1a7d6b 100644 --- a/drivers/staging/lustre/lustre/osc/osc_cache.c +++ b/drivers/staging/lustre/lustre/osc/osc_cache.c @@ -123,9 +123,9 @@ static const char *oes_strings[] = { /* ----- part 4 ----- */ \ ## __VA_ARGS__); \ if (lvl == D_ERROR && __ext->oe_dlmlock) \ - LDLM_ERROR(__ext->oe_dlmlock, "extent: %p\n", __ext); \ + LDLM_ERROR(__ext->oe_dlmlock, "extent: %p", __ext); \ else \ - LDLM_DEBUG(__ext->oe_dlmlock, "extent: %p\n", __ext); \ + LDLM_DEBUG(__ext->oe_dlmlock, "extent: %p", __ext); \ } while (0) #undef EASSERTF diff --git a/drivers/staging/lustre/lustre/osc/osc_lock.c b/drivers/staging/lustre/lustre/osc/osc_lock.c index 5455d9d..717d3ff 100644 --- a/drivers/staging/lustre/lustre/osc/osc_lock.c +++ b/drivers/staging/lustre/lustre/osc/osc_lock.c @@ -1168,7 +1168,7 @@ int osc_lock_init(const struct lu_env *env, osc_lock_set_writer(env, io, obj, oscl); - LDLM_DEBUG_NOLOCK("lock %p, osc lock %p, flags %llx\n", + LDLM_DEBUG_NOLOCK("lock %p, osc lock %p, flags %llx", lock, oscl, oscl->ols_flags); return 0; -- cgit v0.10.2 From d55d5e8f49574acb034eff08dff6dc250481354b Mon Sep 17 00:00:00 2001 From: Bob Glossman Date: Mon, 20 Jun 2016 16:55:37 -0400 Subject: staging/lustre: Add newline to LU_OBJECT_DEBUG() message LU_OBJECT_DEBUG expects non \n terminated message from the caller, so it should add it's own to keep debug logger happy. Signed-off-by: Bob Glossman Reviewed-on: http://review.whamcloud.com/19960 Intel-bug-id: https://jira.hpdd.intel.com/browse/LU-8094 Reviewed-by: Andreas Dilger Reviewed-by: Alex Zhuravlev Reviewed-by: John L. Hammond Signed-off-by: Oleg Drokin Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/lustre/lustre/include/lu_object.h b/drivers/staging/lustre/lustre/include/lu_object.h index c6281e6..6e25c1b 100644 --- a/drivers/staging/lustre/lustre/include/lu_object.h +++ b/drivers/staging/lustre/lustre/include/lu_object.h @@ -779,7 +779,7 @@ do { \ if (cfs_cdebug_show(mask, DEBUG_SUBSYSTEM)) { \ LIBCFS_DEBUG_MSG_DATA_DECL(msgdata, mask, NULL); \ lu_object_print(env, &msgdata, lu_cdebug_printer, object);\ - CDEBUG(mask, format, ## __VA_ARGS__); \ + CDEBUG(mask, format "\n", ## __VA_ARGS__); \ } \ } while (0) -- cgit v0.10.2 From e476f2e55aa9e6769875795eb1835a3ac7855379 Mon Sep 17 00:00:00 2001 From: "John L. Hammond" Date: Mon, 20 Jun 2016 16:55:38 -0400 Subject: staging/lustre/llite: flatten struct lookup_intent Replace the union in struct lookup_intent with the members of struct lustre_indent_data. Remove the then unused struct lustre_intent_data. Signed-off-by: John L. Hammond Reviewed-on: http://review.whamcloud.com/17069 Intel-bug-id: https://jira.hpdd.intel.com/browse/LU-7403 Reviewed-by: James Simmons Reviewed-by: Dmitry Eremin Reviewed-by: Frank Zago Signed-off-by: Oleg Drokin Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/lustre/lustre/include/lustre_intent.h b/drivers/staging/lustre/lustre/include/lustre_intent.h index fdc6236..41c03d7 100644 --- a/drivers/staging/lustre/lustre/include/lustre_intent.h +++ b/drivers/staging/lustre/lustre/include/lustre_intent.h @@ -34,7 +34,11 @@ #define LUSTRE_INTENT_H /* intent IT_XXX are defined in lustre/include/obd.h */ -struct lustre_intent_data { + +struct lookup_intent { + int it_op; + int it_create_mode; + __u64 it_flags; int it_disposition; int it_status; __u64 it_lock_handle; @@ -46,13 +50,4 @@ struct lustre_intent_data { unsigned int it_lock_set:1; }; -struct lookup_intent { - int it_op; - int it_create_mode; - __u64 it_flags; - union { - struct lustre_intent_data lustre; - } d; -}; - #endif diff --git a/drivers/staging/lustre/lustre/llite/dcache.c b/drivers/staging/lustre/lustre/llite/dcache.c index f002b3a..c5789f7 100644 --- a/drivers/staging/lustre/lustre/llite/dcache.c +++ b/drivers/staging/lustre/lustre/llite/dcache.c @@ -202,27 +202,27 @@ int ll_d_init(struct dentry *de) void ll_intent_drop_lock(struct lookup_intent *it) { - if (it->it_op && it->d.lustre.it_lock_mode) { + if (it->it_op && it->it_lock_mode) { struct lustre_handle handle; - handle.cookie = it->d.lustre.it_lock_handle; + handle.cookie = it->it_lock_handle; CDEBUG(D_DLMTRACE, "releasing lock with cookie %#llx from it %p\n", handle.cookie, it); - ldlm_lock_decref(&handle, it->d.lustre.it_lock_mode); + ldlm_lock_decref(&handle, it->it_lock_mode); /* bug 494: intent_release may be called multiple times, from * this thread and we don't want to double-decref this lock */ - it->d.lustre.it_lock_mode = 0; - if (it->d.lustre.it_remote_lock_mode != 0) { - handle.cookie = it->d.lustre.it_remote_lock_handle; + it->it_lock_mode = 0; + if (it->it_remote_lock_mode != 0) { + handle.cookie = it->it_remote_lock_handle; CDEBUG(D_DLMTRACE, "releasing remote lock with cookie%#llx from it %p\n", handle.cookie, it); ldlm_lock_decref(&handle, - it->d.lustre.it_remote_lock_mode); - it->d.lustre.it_remote_lock_mode = 0; + it->it_remote_lock_mode); + it->it_remote_lock_mode = 0; } } } @@ -233,13 +233,13 @@ void ll_intent_release(struct lookup_intent *it) ll_intent_drop_lock(it); /* We are still holding extra reference on a request, need to free it */ if (it_disposition(it, DISP_ENQ_OPEN_REF)) - ptlrpc_req_finished(it->d.lustre.it_data); /* ll_file_open */ + ptlrpc_req_finished(it->it_data); /* ll_file_open */ if (it_disposition(it, DISP_ENQ_CREATE_REF)) /* create rec */ - ptlrpc_req_finished(it->d.lustre.it_data); + ptlrpc_req_finished(it->it_data); - it->d.lustre.it_disposition = 0; - it->d.lustre.it_data = NULL; + it->it_disposition = 0; + it->it_data = NULL; } void ll_invalidate_aliases(struct inode *inode) @@ -279,7 +279,7 @@ int ll_revalidate_it_finish(struct ptlrpc_request *request, void ll_lookup_finish_locks(struct lookup_intent *it, struct inode *inode) { - if (it->d.lustre.it_lock_mode && inode) { + if (it->it_lock_mode && inode) { struct ll_sb_info *sbi = ll_i2sbi(inode); CDEBUG(D_DLMTRACE, "setting l_data to inode "DFID"(%p)\n", diff --git a/drivers/staging/lustre/lustre/llite/dir.c b/drivers/staging/lustre/lustre/llite/dir.c index 2f2c57e..8839e10 100644 --- a/drivers/staging/lustre/lustre/llite/dir.c +++ b/drivers/staging/lustre/lustre/llite/dir.c @@ -362,7 +362,7 @@ struct page *ll_get_dir_page(struct inode *dir, __u64 hash, ll_finish_md_op_data(op_data); - request = (struct ptlrpc_request *)it.d.lustre.it_data; + request = (struct ptlrpc_request *)it.it_data; if (request) ptlrpc_req_finished(request); if (rc < 0) { @@ -374,7 +374,7 @@ struct page *ll_get_dir_page(struct inode *dir, __u64 hash, CDEBUG(D_INODE, "setting lr_lvb_inode to inode "DFID"(%p)\n", PFID(ll_inode2fid(dir)), dir); md_set_lock_data(ll_i2sbi(dir)->ll_md_exp, - &it.d.lustre.it_lock_handle, dir, NULL); + &it.it_lock_handle, dir, NULL); } else { /* for cross-ref object, l_ast_data of the lock may not be set, * we reset it here diff --git a/drivers/staging/lustre/lustre/llite/file.c b/drivers/staging/lustre/lustre/llite/file.c index c46e2ac..6cee41f 100644 --- a/drivers/staging/lustre/lustre/llite/file.c +++ b/drivers/staging/lustre/lustre/llite/file.c @@ -437,7 +437,7 @@ static int ll_intent_file_open(struct dentry *dentry, void *lmm, } rc = ll_prep_inode(&inode, req, NULL, itp); - if (!rc && itp->d.lustre.it_lock_mode) + if (!rc && itp->it_lock_mode) ll_set_lock_data(sbi->ll_md_exp, inode, itp, NULL); out: @@ -464,13 +464,13 @@ void ll_ioepoch_open(struct ll_inode_info *lli, __u64 ioepoch) static int ll_och_fill(struct obd_export *md_exp, struct lookup_intent *it, struct obd_client_handle *och) { - struct ptlrpc_request *req = it->d.lustre.it_data; + struct ptlrpc_request *req = it->it_data; struct mdt_body *body; body = req_capsule_server_get(&req->rq_pill, &RMF_MDT_BODY); och->och_fh = body->handle; och->och_fid = body->fid1; - och->och_lease_handle.cookie = it->d.lustre.it_lock_handle; + och->och_lease_handle.cookie = it->it_lock_handle; och->och_magic = OBD_CLIENT_HANDLE_MAGIC; och->och_flags = it->it_flags; @@ -488,7 +488,7 @@ static int ll_local_open(struct file *file, struct lookup_intent *it, LASSERT(fd); if (och) { - struct ptlrpc_request *req = it->d.lustre.it_data; + struct ptlrpc_request *req = it->it_data; struct mdt_body *body; int rc; @@ -563,7 +563,7 @@ int ll_file_open(struct inode *inode, struct file *file) return 0; } - if (!it || !it->d.lustre.it_disposition) { + if (!it || !it->it_disposition) { /* Convert f_flags into access mode. We cannot use file->f_mode, * because everything but O_ACCMODE mask was stripped from * there @@ -633,7 +633,7 @@ restart: } } else { LASSERT(*och_usecount == 0); - if (!it->d.lustre.it_disposition) { + if (!it->it_disposition) { /* We cannot just request lock handle now, new ELC code * means that one of other OPEN locks for this file * could be cancelled, and since blocking ast handler @@ -670,7 +670,7 @@ restart: LASSERTF(it_disposition(it, DISP_ENQ_OPEN_REF), "inode %p: disposition %x, status %d\n", inode, - it_disposition(it, ~0), it->d.lustre.it_status); + it_disposition(it, ~0), it->it_status); rc = ll_local_open(file, it, fd, *och_p); if (rc) @@ -713,7 +713,7 @@ out_openerr: } if (it && it_disposition(it, DISP_ENQ_OPEN_REF)) { - ptlrpc_req_finished(it->d.lustre.it_data); + ptlrpc_req_finished(it->it_data); it_clear_disposition(it, DISP_ENQ_OPEN_REF); } @@ -854,12 +854,12 @@ ll_lease_open(struct inode *inode, struct file *file, fmode_t fmode, /* already get lease, handle lease lock */ ll_set_lock_data(sbi->ll_md_exp, inode, &it, NULL); - if (it.d.lustre.it_lock_mode == 0 || - it.d.lustre.it_lock_bits != MDS_INODELOCK_OPEN) { + if (it.it_lock_mode == 0 || + it.it_lock_bits != MDS_INODELOCK_OPEN) { /* open lock must return for lease */ CERROR(DFID "lease granted but no open lock, %d/%llu.\n", - PFID(ll_inode2fid(inode)), it.d.lustre.it_lock_mode, - it.d.lustre.it_lock_bits); + PFID(ll_inode2fid(inode)), it.it_lock_mode, + it.it_lock_bits); rc = -EPROTO; goto out_close; } @@ -869,10 +869,10 @@ ll_lease_open(struct inode *inode, struct file *file, fmode_t fmode, out_close: /* Cancel open lock */ - if (it.d.lustre.it_lock_mode != 0) { + if (it.it_lock_mode != 0) { ldlm_lock_decref_and_cancel(&och->och_lease_handle, - it.d.lustre.it_lock_mode); - it.d.lustre.it_lock_mode = 0; + it.it_lock_mode); + it.it_lock_mode = 0; och->och_lease_handle.cookie = 0ULL; } rc2 = ll_close_inode_openhandle(sbi->ll_md_exp, inode, och, NULL); @@ -1388,7 +1388,7 @@ int ll_lov_setstripe_ea_info(struct inode *inode, struct dentry *dentry, rc = ll_intent_file_open(dentry, lum, lum_size, &oit); if (rc) goto out_unlock; - rc = oit.d.lustre.it_status; + rc = oit.it_status; if (rc < 0) goto out_req_free; @@ -1401,7 +1401,7 @@ out_unlock: out: return rc; out_req_free: - ptlrpc_req_finished((struct ptlrpc_request *)oit.d.lustre.it_data); + ptlrpc_req_finished((struct ptlrpc_request *)oit.it_data); goto out; } @@ -1689,7 +1689,7 @@ int ll_release_openhandle(struct inode *inode, struct lookup_intent *it) out: /* this one is in place of ll_file_open */ if (it_disposition(it, DISP_ENQ_OPEN_REF)) { - ptlrpc_req_finished(it->d.lustre.it_data); + ptlrpc_req_finished(it->it_data); it_clear_disposition(it, DISP_ENQ_OPEN_REF); } return rc; @@ -3595,13 +3595,13 @@ again: rc = md_enqueue(sbi->ll_md_exp, &einfo, &it, op_data, &lockh, NULL, 0, NULL, 0); - ptlrpc_req_finished(it.d.lustre.it_data); - it.d.lustre.it_data = NULL; + ptlrpc_req_finished(it.it_data); + it.it_data = NULL; ll_finish_md_op_data(op_data); - mode = it.d.lustre.it_lock_mode; - it.d.lustre.it_lock_mode = 0; + mode = it.it_lock_mode; + it.it_lock_mode = 0; ll_intent_drop_lock(&it); if (rc == 0) { diff --git a/drivers/staging/lustre/lustre/llite/llite_internal.h b/drivers/staging/lustre/lustre/llite/llite_internal.h index 973dcc7..08cc2c1 100644 --- a/drivers/staging/lustre/lustre/llite/llite_internal.h +++ b/drivers/staging/lustre/lustre/llite/llite_internal.h @@ -1196,7 +1196,7 @@ static inline int ll_file_nolock(const struct file *file) static inline void ll_set_lock_data(struct obd_export *exp, struct inode *inode, struct lookup_intent *it, __u64 *bits) { - if (!it->d.lustre.it_lock_set) { + if (!it->it_lock_set) { struct lustre_handle handle; /* If this inode is a remote object, it will get two @@ -1207,26 +1207,26 @@ static inline void ll_set_lock_data(struct obd_export *exp, struct inode *inode, * LOOKUP and PERM locks, so revoking either locks will * case the dcache being cleared */ - if (it->d.lustre.it_remote_lock_mode) { - handle.cookie = it->d.lustre.it_remote_lock_handle; + if (it->it_remote_lock_mode) { + handle.cookie = it->it_remote_lock_handle; CDEBUG(D_DLMTRACE, "setting l_data to inode "DFID"%p for remote lock %#llx\n", PFID(ll_inode2fid(inode)), inode, handle.cookie); md_set_lock_data(exp, &handle.cookie, inode, NULL); } - handle.cookie = it->d.lustre.it_lock_handle; + handle.cookie = it->it_lock_handle; CDEBUG(D_DLMTRACE, "setting l_data to inode "DFID"%p for lock %#llx\n", PFID(ll_inode2fid(inode)), inode, handle.cookie); md_set_lock_data(exp, &handle.cookie, inode, - &it->d.lustre.it_lock_bits); - it->d.lustre.it_lock_set = 1; + &it->it_lock_bits); + it->it_lock_set = 1; } if (bits) - *bits = it->d.lustre.it_lock_bits; + *bits = it->it_lock_bits; } static inline int d_lustre_invalid(const struct dentry *dentry) diff --git a/drivers/staging/lustre/lustre/llite/llite_lib.c b/drivers/staging/lustre/lustre/llite/llite_lib.c index 4ab1f2b..a741d6a 100644 --- a/drivers/staging/lustre/lustre/llite/llite_lib.c +++ b/drivers/staging/lustre/lustre/llite/llite_lib.c @@ -1945,11 +1945,11 @@ int ll_prep_inode(struct inode **inode, struct ptlrpc_request *req, * 3. proc2: refresh layout and layout lock granted * 4. proc1: to apply a stale layout */ - if (it && it->d.lustre.it_lock_mode != 0) { + if (it && it->it_lock_mode != 0) { struct lustre_handle lockh; struct ldlm_lock *lock; - lockh.cookie = it->d.lustre.it_lock_handle; + lockh.cookie = it->it_lock_handle; lock = ldlm_handle2lock(&lockh); LASSERT(lock); if (ldlm_has_layout(lock)) { diff --git a/drivers/staging/lustre/lustre/llite/namei.c b/drivers/staging/lustre/lustre/llite/namei.c index e4df510..7a6da02 100644 --- a/drivers/staging/lustre/lustre/llite/namei.c +++ b/drivers/staging/lustre/lustre/llite/namei.c @@ -393,7 +393,7 @@ static int ll_lookup_it_finish(struct ptlrpc_request *request, * when I return */ CDEBUG(D_DENTRY, "it %p it_disposition %x\n", it, - it->d.lustre.it_disposition); + it->it_disposition); if (!it_disposition(it, DISP_LOOKUP_NEG)) { rc = ll_prep_inode(&inode, request, (*de)->d_sb, it); if (rc) @@ -445,7 +445,7 @@ static int ll_lookup_it_finish(struct ptlrpc_request *request, /* Check that parent has UPDATE lock. */ struct lookup_intent parent_it = { .it_op = IT_GETATTR, - .d.lustre.it_lock_handle = 0 }; + .it_lock_handle = 0 }; if (md_revalidate_lock(ll_i2mdexp(parent), &parent_it, &ll_i2info(parent)->lli_fid, NULL)) { @@ -656,10 +656,10 @@ static struct inode *ll_create_node(struct inode *dir, struct lookup_intent *it) struct ll_sb_info *sbi = ll_i2sbi(dir); int rc; - LASSERT(it && it->d.lustre.it_disposition); + LASSERT(it && it->it_disposition); LASSERT(it_disposition(it, DISP_ENQ_CREATE_REF)); - request = it->d.lustre.it_data; + request = it->it_data; it_clear_disposition(it, DISP_ENQ_CREATE_REF); rc = ll_prep_inode(&inode, request, dir->i_sb, it); if (rc) { diff --git a/drivers/staging/lustre/lustre/llite/statahead.c b/drivers/staging/lustre/lustre/llite/statahead.c index 03ad858..f775242 100644 --- a/drivers/staging/lustre/lustre/llite/statahead.c +++ b/drivers/staging/lustre/lustre/llite/statahead.c @@ -646,7 +646,7 @@ static void ll_post_statahead(struct ll_statahead_info *sai) } } - it->d.lustre.it_lock_handle = entry->se_handle; + it->it_lock_handle = entry->se_handle; rc = md_revalidate_lock(ll_i2mdexp(dir), it, ll_inode2fid(dir), NULL); if (rc != 1) { rc = -EAGAIN; @@ -700,7 +700,7 @@ static int ll_statahead_interpret(struct ptlrpc_request *req, * process enqueues lock on child with parent lock held, eg. * unlink. */ - handle = it->d.lustre.it_lock_handle; + handle = it->it_lock_handle; ll_intent_drop_lock(it); } @@ -850,7 +850,7 @@ static int do_sa_revalidate(struct inode *dir, struct ll_sa_entry *entry, { struct inode *inode = d_inode(dentry); struct lookup_intent it = { .it_op = IT_GETATTR, - .d.lustre.it_lock_handle = 0 }; + .it_lock_handle = 0 }; struct md_enqueue_info *minfo; struct ldlm_enqueue_info *einfo; int rc; @@ -865,7 +865,7 @@ static int do_sa_revalidate(struct inode *dir, struct ll_sa_entry *entry, rc = md_revalidate_lock(ll_i2mdexp(dir), &it, ll_inode2fid(inode), NULL); if (rc == 1) { - entry->se_handle = it.d.lustre.it_lock_handle; + entry->se_handle = it.it_lock_handle; ll_intent_release(&it); return 1; } @@ -1569,7 +1569,7 @@ int do_statahead_enter(struct inode *dir, struct dentry **dentryp, if (entry->se_stat == SA_ENTRY_SUCC && entry->se_inode) { struct inode *inode = entry->se_inode; struct lookup_intent it = { .it_op = IT_GETATTR, - .d.lustre.it_lock_handle = + .it_lock_handle = entry->se_handle }; __u64 bits; diff --git a/drivers/staging/lustre/lustre/llite/xattr_cache.c b/drivers/staging/lustre/lustre/llite/xattr_cache.c index d7e17ab..0d19645 100644 --- a/drivers/staging/lustre/lustre/llite/xattr_cache.c +++ b/drivers/staging/lustre/lustre/llite/xattr_cache.c @@ -288,8 +288,8 @@ static int ll_xattr_find_get_lock(struct inode *inode, LCK_PR); if (mode != 0) { /* fake oit in mdc_revalidate_lock() manner */ - oit->d.lustre.it_lock_handle = lockh.cookie; - oit->d.lustre.it_lock_mode = mode; + oit->it_lock_handle = lockh.cookie; + oit->it_lock_mode = mode; goto out; } } @@ -315,7 +315,7 @@ static int ll_xattr_find_get_lock(struct inode *inode, return rc; } - *req = (struct ptlrpc_request *)oit->d.lustre.it_data; + *req = (struct ptlrpc_request *)oit->it_data; out: down_write(&lli->lli_xattrs_list_rwsem); mutex_unlock(&lli->lli_xattrs_enq_lock); @@ -362,10 +362,10 @@ static int ll_xattr_cache_refill(struct inode *inode, struct lookup_intent *oit) goto out_maybe_drop; } - if (oit->d.lustre.it_status < 0) { + if (oit->it_status < 0) { CDEBUG(D_CACHE, "getxattr intent returned %d for fid "DFID"\n", - oit->d.lustre.it_status, PFID(ll_inode2fid(inode))); - rc = oit->d.lustre.it_status; + oit->it_status, PFID(ll_inode2fid(inode))); + rc = oit->it_status; /* xattr data is so large that we don't want to cache it */ if (rc == -ERANGE) rc = -EAGAIN; @@ -448,8 +448,8 @@ out_destroy: up_write(&lli->lli_xattrs_list_rwsem); ldlm_lock_decref_and_cancel((struct lustre_handle *) - &oit->d.lustre.it_lock_handle, - oit->d.lustre.it_lock_mode); + &oit->it_lock_handle, + oit->it_lock_mode); goto out_no_unlock; } diff --git a/drivers/staging/lustre/lustre/lmv/lmv_intent.c b/drivers/staging/lustre/lustre/lmv/lmv_intent.c index 980c9d4..b3cff23 100644 --- a/drivers/staging/lustre/lustre/lmv/lmv_intent.c +++ b/drivers/staging/lustre/lustre/lmv/lmv_intent.c @@ -80,11 +80,11 @@ static int lmv_intent_remote(struct obd_export *exp, void *lmm, /* * We got LOOKUP lock, but we really need attrs. */ - pmode = it->d.lustre.it_lock_mode; + pmode = it->it_lock_mode; if (pmode) { - plock.cookie = it->d.lustre.it_lock_handle; - it->d.lustre.it_lock_mode = 0; - it->d.lustre.it_data = NULL; + plock.cookie = it->it_lock_handle; + it->it_lock_mode = 0; + it->it_data = NULL; } LASSERT(fid_is_sane(&body->fid1)); @@ -130,14 +130,14 @@ static int lmv_intent_remote(struct obd_export *exp, void *lmm, * maintain dcache consistency. Thus drop UPDATE|PERM lock here * and put LOOKUP in request. */ - if (it->d.lustre.it_lock_mode != 0) { - it->d.lustre.it_remote_lock_handle = - it->d.lustre.it_lock_handle; - it->d.lustre.it_remote_lock_mode = it->d.lustre.it_lock_mode; + if (it->it_lock_mode != 0) { + it->it_remote_lock_handle = + it->it_lock_handle; + it->it_remote_lock_mode = it->it_lock_mode; } - it->d.lustre.it_lock_handle = plock.cookie; - it->d.lustre.it_lock_mode = pmode; + it->it_lock_handle = plock.cookie; + it->it_lock_mode = pmode; out_free_op_data: kfree(op_data); @@ -197,9 +197,9 @@ static int lmv_intent_open(struct obd_export *exp, struct md_op_data *op_data, * Nothing is found, do not access body->fid1 as it is zero and thus * pointless. */ - if ((it->d.lustre.it_disposition & DISP_LOOKUP_NEG) && - !(it->d.lustre.it_disposition & DISP_OPEN_CREATE) && - !(it->d.lustre.it_disposition & DISP_OPEN_OPEN)) + if ((it->it_disposition & DISP_LOOKUP_NEG) && + !(it->it_disposition & DISP_OPEN_CREATE) && + !(it->it_disposition & DISP_OPEN_OPEN)) return rc; body = req_capsule_server_get(&(*reqp)->rq_pill, &RMF_MDT_BODY); diff --git a/drivers/staging/lustre/lustre/lmv/lmv_obd.c b/drivers/staging/lustre/lustre/lmv/lmv_obd.c index 6483f2c..e6d7efa 100644 --- a/drivers/staging/lustre/lustre/lmv/lmv_obd.c +++ b/drivers/staging/lustre/lustre/lmv/lmv_obd.c @@ -1679,7 +1679,7 @@ lmv_enqueue_remote(struct obd_export *exp, struct ldlm_enqueue_info *einfo, struct lustre_handle *lockh, void *lmm, int lmmsize, __u64 extra_lock_flags) { - struct ptlrpc_request *req = it->d.lustre.it_data; + struct ptlrpc_request *req = it->it_data; struct obd_device *obd = exp->exp_obd; struct lmv_obd *lmv = &obd->u.lmv; struct lustre_handle plock; @@ -1701,11 +1701,11 @@ lmv_enqueue_remote(struct obd_export *exp, struct ldlm_enqueue_info *einfo, /* * We got LOOKUP lock, but we really need attrs. */ - pmode = it->d.lustre.it_lock_mode; + pmode = it->it_lock_mode; LASSERT(pmode != 0); memcpy(&plock, lockh, sizeof(plock)); - it->d.lustre.it_lock_mode = 0; - it->d.lustre.it_data = NULL; + it->it_lock_mode = 0; + it->it_data = NULL; fid1 = body->fid1; ptlrpc_req_finished(req); diff --git a/drivers/staging/lustre/lustre/mdc/mdc_locks.c b/drivers/staging/lustre/lustre/mdc/mdc_locks.c index b154aff..53740d0 100644 --- a/drivers/staging/lustre/lustre/mdc/mdc_locks.c +++ b/drivers/staging/lustre/lustre/mdc/mdc_locks.c @@ -52,19 +52,19 @@ struct mdc_getattr_args { int it_disposition(struct lookup_intent *it, int flag) { - return it->d.lustre.it_disposition & flag; + return it->it_disposition & flag; } EXPORT_SYMBOL(it_disposition); void it_set_disposition(struct lookup_intent *it, int flag) { - it->d.lustre.it_disposition |= flag; + it->it_disposition |= flag; } EXPORT_SYMBOL(it_set_disposition); void it_clear_disposition(struct lookup_intent *it, int flag) { - it->d.lustre.it_disposition &= ~flag; + it->it_disposition &= ~flag; } EXPORT_SYMBOL(it_clear_disposition); @@ -72,39 +72,39 @@ int it_open_error(int phase, struct lookup_intent *it) { if (it_disposition(it, DISP_OPEN_LEASE)) { if (phase >= DISP_OPEN_LEASE) - return it->d.lustre.it_status; + return it->it_status; else return 0; } if (it_disposition(it, DISP_OPEN_OPEN)) { if (phase >= DISP_OPEN_OPEN) - return it->d.lustre.it_status; + return it->it_status; else return 0; } if (it_disposition(it, DISP_OPEN_CREATE)) { if (phase >= DISP_OPEN_CREATE) - return it->d.lustre.it_status; + return it->it_status; else return 0; } if (it_disposition(it, DISP_LOOKUP_EXECD)) { if (phase >= DISP_LOOKUP_EXECD) - return it->d.lustre.it_status; + return it->it_status; else return 0; } if (it_disposition(it, DISP_IT_EXECD)) { if (phase >= DISP_IT_EXECD) - return it->d.lustre.it_status; + return it->it_status; else return 0; } - CERROR("it disp: %X, status: %d\n", it->d.lustre.it_disposition, - it->d.lustre.it_status); + CERROR("it disp: %X, status: %d\n", it->it_disposition, + it->it_status); LBUG(); return 0; } @@ -542,7 +542,6 @@ static int mdc_finish_enqueue(struct obd_export *exp, struct req_capsule *pill = &req->rq_pill; struct ldlm_request *lockreq; struct ldlm_reply *lockrep; - struct lustre_intent_data *intent = &it->d.lustre; struct ldlm_lock *lock; void *lvb_data = NULL; int lvb_len = 0; @@ -576,17 +575,17 @@ static int mdc_finish_enqueue(struct obd_export *exp, lockrep = req_capsule_server_get(pill, &RMF_DLM_REP); - intent->it_disposition = (int)lockrep->lock_policy_res1; - intent->it_status = (int)lockrep->lock_policy_res2; - intent->it_lock_mode = einfo->ei_mode; - intent->it_lock_handle = lockh->cookie; - intent->it_data = req; + it->it_disposition = (int)lockrep->lock_policy_res1; + it->it_status = (int)lockrep->lock_policy_res2; + it->it_lock_mode = einfo->ei_mode; + it->it_lock_handle = lockh->cookie; + it->it_data = req; /* Technically speaking rq_transno must already be zero if * it_status is in error, so the check is a bit redundant */ - if ((!req->rq_transno || intent->it_status < 0) && req->rq_replay) - mdc_clear_replay_flag(req, intent->it_status); + if ((!req->rq_transno || it->it_status < 0) && req->rq_replay) + mdc_clear_replay_flag(req, it->it_status); /* If we're doing an IT_OPEN which did not result in an actual * successful open, then we need to remove the bit which saves @@ -597,11 +596,11 @@ static int mdc_finish_enqueue(struct obd_export *exp, * (bug 3440) */ if (it->it_op & IT_OPEN && req->rq_replay && - (!it_disposition(it, DISP_OPEN_OPEN) || intent->it_status != 0)) - mdc_clear_replay_flag(req, intent->it_status); + (!it_disposition(it, DISP_OPEN_OPEN) || it->it_status != 0)) + mdc_clear_replay_flag(req, it->it_status); DEBUG_REQ(D_RPCTRACE, req, "op: %d disposition: %x, status: %d", - it->it_op, intent->it_disposition, intent->it_status); + it->it_op, it->it_disposition, it->it_status); /* We know what to expect, so we do any byte flipping required here */ if (it->it_op & (IT_OPEN | IT_UNLINK | IT_LOOKUP | IT_GETATTR)) { @@ -900,9 +899,9 @@ resend: } ptlrpc_req_finished(req); - it->d.lustre.it_lock_handle = 0; - it->d.lustre.it_lock_mode = 0; - it->d.lustre.it_data = NULL; + it->it_lock_handle = 0; + it->it_lock_mode = 0; + it->it_data = NULL; } return rc; @@ -926,8 +925,8 @@ static int mdc_finish_intent_lock(struct obd_export *exp, /* The server failed before it even started executing the * intent, i.e. because it couldn't unpack the request. */ - LASSERT(it->d.lustre.it_status != 0); - return it->d.lustre.it_status; + LASSERT(it->it_status != 0); + return it->it_status; } rc = it_open_error(DISP_IT_EXECD, it); if (rc) @@ -1010,15 +1009,15 @@ static int mdc_finish_intent_lock(struct obd_export *exp, LDLM_IBITS, &policy, LCK_NL, &old_lock, 0)) { ldlm_lock_decref_and_cancel(lockh, - it->d.lustre.it_lock_mode); + it->it_lock_mode); memcpy(lockh, &old_lock, sizeof(old_lock)); - it->d.lustre.it_lock_handle = lockh->cookie; + it->it_lock_handle = lockh->cookie; } } CDEBUG(D_DENTRY, "D_IT dentry %.*s intent: %s status %d disp %x rc %d\n", op_data->op_namelen, op_data->op_name, ldlm_it2str(it->it_op), - it->d.lustre.it_status, it->d.lustre.it_disposition, rc); + it->it_status, it->it_disposition, rc); return rc; } @@ -1034,8 +1033,8 @@ int mdc_revalidate_lock(struct obd_export *exp, struct lookup_intent *it, ldlm_policy_data_t policy; enum ldlm_mode mode; - if (it->d.lustre.it_lock_handle) { - lockh.cookie = it->d.lustre.it_lock_handle; + if (it->it_lock_handle) { + lockh.cookie = it->it_lock_handle; mode = ldlm_revalidate_lock_handle(&lockh, bits); } else { fid_build_reg_res_name(fid, &res_id); @@ -1076,11 +1075,11 @@ int mdc_revalidate_lock(struct obd_export *exp, struct lookup_intent *it, } if (mode) { - it->d.lustre.it_lock_handle = lockh.cookie; - it->d.lustre.it_lock_mode = mode; + it->it_lock_handle = lockh.cookie; + it->it_lock_mode = mode; } else { - it->d.lustre.it_lock_handle = 0; - it->d.lustre.it_lock_mode = 0; + it->it_lock_handle = 0; + it->it_lock_mode = 0; } return !!mode; @@ -1102,15 +1101,15 @@ int mdc_revalidate_lock(struct obd_export *exp, struct lookup_intent *it, * ll_create/ll_open gets called. * * The server will return to us, in it_disposition, an indication of - * exactly what d.lustre.it_status refers to. + * exactly what it_status refers to. * - * If DISP_OPEN_OPEN is set, then d.lustre.it_status refers to the open() call, + * If DISP_OPEN_OPEN is set, then it_status refers to the open() call, * otherwise if DISP_OPEN_CREATE is set, then it status is the * creation failure mode. In either case, one of DISP_LOOKUP_NEG or * DISP_LOOKUP_POS will be set, indicating whether the child lookup * was successful. * - * Else, if DISP_LOOKUP_EXECD then d.lustre.it_status is the rc of the + * Else, if DISP_LOOKUP_EXECD then it_status is the rc of the * child lookup. */ int mdc_intent_lock(struct obd_export *exp, struct md_op_data *op_data, @@ -1143,7 +1142,7 @@ int mdc_intent_lock(struct obd_export *exp, struct md_op_data *op_data, * be called in revalidate_it if we already have a lock, let's * verify that. */ - it->d.lustre.it_lock_handle = 0; + it->it_lock_handle = 0; rc = mdc_revalidate_lock(exp, it, &op_data->op_fid2, NULL); /* Only return failure if it was not GETATTR by cfid * (from inode_revalidate) @@ -1165,7 +1164,7 @@ int mdc_intent_lock(struct obd_export *exp, struct md_op_data *op_data, if (rc < 0) return rc; - *reqp = it->d.lustre.it_data; + *reqp = it->it_data; rc = mdc_finish_intent_lock(exp, *reqp, op_data, it, &lockh); return rc; } diff --git a/drivers/staging/lustre/lustre/mdc/mdc_request.c b/drivers/staging/lustre/lustre/mdc/mdc_request.c index f7e30b1..d48910a 100644 --- a/drivers/staging/lustre/lustre/mdc/mdc_request.c +++ b/drivers/staging/lustre/lustre/mdc/mdc_request.c @@ -637,7 +637,7 @@ int mdc_set_open_replay_data(struct obd_export *exp, struct md_open_data *mod; struct mdt_rec_create *rec; struct mdt_body *body; - struct ptlrpc_request *open_req = it->d.lustre.it_data; + struct ptlrpc_request *open_req = it->it_data; struct obd_import *imp = open_req->rq_import; if (!open_req->rq_replay) -- cgit v0.10.2 From 51b39f1d3678604b546a90bb4e813a32c7f7f9ac Mon Sep 17 00:00:00 2001 From: Oleg Drokin Date: Mon, 20 Jun 2016 16:55:39 -0400 Subject: staging/lustre: Inline Lustre intent disposition functions They are just one-liners, so no point in having them exported and called through a different module. Signed-off-by: Oleg Drokin Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/lustre/lustre/include/lustre_intent.h b/drivers/staging/lustre/lustre/include/lustre_intent.h index 41c03d7..3aed810 100644 --- a/drivers/staging/lustre/lustre/include/lustre_intent.h +++ b/drivers/staging/lustre/lustre/include/lustre_intent.h @@ -50,4 +50,19 @@ struct lookup_intent { unsigned int it_lock_set:1; }; +static inline int it_disposition(struct lookup_intent *it, int flag) +{ + return it->it_disposition & flag; +} + +static inline void it_set_disposition(struct lookup_intent *it, int flag) +{ + it->it_disposition |= flag; +} + +static inline void it_clear_disposition(struct lookup_intent *it, int flag) +{ + it->it_disposition &= ~flag; +} + #endif diff --git a/drivers/staging/lustre/lustre/include/lustre_mdc.h b/drivers/staging/lustre/lustre/include/lustre_mdc.h index 0ef4226..fa62b95 100644 --- a/drivers/staging/lustre/lustre/include/lustre_mdc.h +++ b/drivers/staging/lustre/lustre/include/lustre_mdc.h @@ -185,9 +185,6 @@ struct mdc_cache_waiter { }; /* mdc/mdc_locks.c */ -int it_disposition(struct lookup_intent *it, int flag); -void it_clear_disposition(struct lookup_intent *it, int flag); -void it_set_disposition(struct lookup_intent *it, int flag); int it_open_error(int phase, struct lookup_intent *it); static inline bool cl_is_lov_delay_create(unsigned int flags) diff --git a/drivers/staging/lustre/lustre/mdc/mdc_locks.c b/drivers/staging/lustre/lustre/mdc/mdc_locks.c index 53740d0..7c459b5 100644 --- a/drivers/staging/lustre/lustre/mdc/mdc_locks.c +++ b/drivers/staging/lustre/lustre/mdc/mdc_locks.c @@ -50,24 +50,6 @@ struct mdc_getattr_args { struct ldlm_enqueue_info *ga_einfo; }; -int it_disposition(struct lookup_intent *it, int flag) -{ - return it->it_disposition & flag; -} -EXPORT_SYMBOL(it_disposition); - -void it_set_disposition(struct lookup_intent *it, int flag) -{ - it->it_disposition |= flag; -} -EXPORT_SYMBOL(it_set_disposition); - -void it_clear_disposition(struct lookup_intent *it, int flag) -{ - it->it_disposition &= ~flag; -} -EXPORT_SYMBOL(it_clear_disposition); - int it_open_error(int phase, struct lookup_intent *it) { if (it_disposition(it, DISP_OPEN_LEASE)) { -- cgit v0.10.2 From 8bf86fd957e693ba69f63c3db1647e449a58f26d Mon Sep 17 00:00:00 2001 From: "John L. Hammond" Date: Mon, 20 Jun 2016 16:55:40 -0400 Subject: staging/lustre/llite: change it_data to it_request Change the void *it_data member of struct lookup_intent to struct ptlrpc_request *it_request. Signed-off-by: John L. Hammond Reviewed-on: http://review.whamcloud.com/17070 Intel-bug-id: https://jira.hpdd.intel.com/browse/LU-7403 Reviewed-by: Andreas Dilger Reviewed-by: James Simmons Signed-off-by: Oleg Drokin Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/lustre/lustre/include/lustre_intent.h b/drivers/staging/lustre/lustre/include/lustre_intent.h index 3aed810..ed2b6c6 100644 --- a/drivers/staging/lustre/lustre/include/lustre_intent.h +++ b/drivers/staging/lustre/lustre/include/lustre_intent.h @@ -46,7 +46,7 @@ struct lookup_intent { int it_lock_mode; int it_remote_lock_mode; __u64 it_remote_lock_handle; - void *it_data; + struct ptlrpc_request *it_request; unsigned int it_lock_set:1; }; diff --git a/drivers/staging/lustre/lustre/llite/dcache.c b/drivers/staging/lustre/lustre/llite/dcache.c index c5789f7..d964f4f 100644 --- a/drivers/staging/lustre/lustre/llite/dcache.c +++ b/drivers/staging/lustre/lustre/llite/dcache.c @@ -233,13 +233,13 @@ void ll_intent_release(struct lookup_intent *it) ll_intent_drop_lock(it); /* We are still holding extra reference on a request, need to free it */ if (it_disposition(it, DISP_ENQ_OPEN_REF)) - ptlrpc_req_finished(it->it_data); /* ll_file_open */ + ptlrpc_req_finished(it->it_request); /* ll_file_open */ if (it_disposition(it, DISP_ENQ_CREATE_REF)) /* create rec */ - ptlrpc_req_finished(it->it_data); + ptlrpc_req_finished(it->it_request); it->it_disposition = 0; - it->it_data = NULL; + it->it_request = NULL; } void ll_invalidate_aliases(struct inode *inode) diff --git a/drivers/staging/lustre/lustre/llite/dir.c b/drivers/staging/lustre/lustre/llite/dir.c index 8839e10..92b01fd 100644 --- a/drivers/staging/lustre/lustre/llite/dir.c +++ b/drivers/staging/lustre/lustre/llite/dir.c @@ -362,7 +362,7 @@ struct page *ll_get_dir_page(struct inode *dir, __u64 hash, ll_finish_md_op_data(op_data); - request = (struct ptlrpc_request *)it.it_data; + request = (struct ptlrpc_request *)it.it_request; if (request) ptlrpc_req_finished(request); if (rc < 0) { diff --git a/drivers/staging/lustre/lustre/llite/file.c b/drivers/staging/lustre/lustre/llite/file.c index 6cee41f..39c487d 100644 --- a/drivers/staging/lustre/lustre/llite/file.c +++ b/drivers/staging/lustre/lustre/llite/file.c @@ -464,10 +464,9 @@ void ll_ioepoch_open(struct ll_inode_info *lli, __u64 ioepoch) static int ll_och_fill(struct obd_export *md_exp, struct lookup_intent *it, struct obd_client_handle *och) { - struct ptlrpc_request *req = it->it_data; struct mdt_body *body; - body = req_capsule_server_get(&req->rq_pill, &RMF_MDT_BODY); + body = req_capsule_server_get(&it->it_request->rq_pill, &RMF_MDT_BODY); och->och_fh = body->handle; och->och_fid = body->fid1; och->och_lease_handle.cookie = it->it_lock_handle; @@ -488,7 +487,6 @@ static int ll_local_open(struct file *file, struct lookup_intent *it, LASSERT(fd); if (och) { - struct ptlrpc_request *req = it->it_data; struct mdt_body *body; int rc; @@ -496,7 +494,8 @@ static int ll_local_open(struct file *file, struct lookup_intent *it, if (rc != 0) return rc; - body = req_capsule_server_get(&req->rq_pill, &RMF_MDT_BODY); + body = req_capsule_server_get(&it->it_request->rq_pill, + &RMF_MDT_BODY); ll_ioepoch_open(lli, body->ioepoch); } @@ -713,7 +712,7 @@ out_openerr: } if (it && it_disposition(it, DISP_ENQ_OPEN_REF)) { - ptlrpc_req_finished(it->it_data); + ptlrpc_req_finished(it->it_request); it_clear_disposition(it, DISP_ENQ_OPEN_REF); } @@ -1401,7 +1400,7 @@ out_unlock: out: return rc; out_req_free: - ptlrpc_req_finished((struct ptlrpc_request *)oit.it_data); + ptlrpc_req_finished((struct ptlrpc_request *)oit.it_request); goto out; } @@ -1689,7 +1688,7 @@ int ll_release_openhandle(struct inode *inode, struct lookup_intent *it) out: /* this one is in place of ll_file_open */ if (it_disposition(it, DISP_ENQ_OPEN_REF)) { - ptlrpc_req_finished(it->it_data); + ptlrpc_req_finished(it->it_request); it_clear_disposition(it, DISP_ENQ_OPEN_REF); } return rc; @@ -3595,8 +3594,8 @@ again: rc = md_enqueue(sbi->ll_md_exp, &einfo, &it, op_data, &lockh, NULL, 0, NULL, 0); - ptlrpc_req_finished(it.it_data); - it.it_data = NULL; + ptlrpc_req_finished(it.it_request); + it.it_request = NULL; ll_finish_md_op_data(op_data); diff --git a/drivers/staging/lustre/lustre/llite/namei.c b/drivers/staging/lustre/lustre/llite/namei.c index 7a6da02..3664bfd 100644 --- a/drivers/staging/lustre/lustre/llite/namei.c +++ b/drivers/staging/lustre/lustre/llite/namei.c @@ -659,7 +659,7 @@ static struct inode *ll_create_node(struct inode *dir, struct lookup_intent *it) LASSERT(it && it->it_disposition); LASSERT(it_disposition(it, DISP_ENQ_CREATE_REF)); - request = it->it_data; + request = it->it_request; it_clear_disposition(it, DISP_ENQ_CREATE_REF); rc = ll_prep_inode(&inode, request, dir->i_sb, it); if (rc) { diff --git a/drivers/staging/lustre/lustre/llite/xattr_cache.c b/drivers/staging/lustre/lustre/llite/xattr_cache.c index 0d19645..8089da8 100644 --- a/drivers/staging/lustre/lustre/llite/xattr_cache.c +++ b/drivers/staging/lustre/lustre/llite/xattr_cache.c @@ -315,7 +315,7 @@ static int ll_xattr_find_get_lock(struct inode *inode, return rc; } - *req = (struct ptlrpc_request *)oit->it_data; + *req = oit->it_request; out: down_write(&lli->lli_xattrs_list_rwsem); mutex_unlock(&lli->lli_xattrs_enq_lock); diff --git a/drivers/staging/lustre/lustre/lmv/lmv_intent.c b/drivers/staging/lustre/lustre/lmv/lmv_intent.c index b3cff23..2f58fda 100644 --- a/drivers/staging/lustre/lustre/lmv/lmv_intent.c +++ b/drivers/staging/lustre/lustre/lmv/lmv_intent.c @@ -84,7 +84,7 @@ static int lmv_intent_remote(struct obd_export *exp, void *lmm, if (pmode) { plock.cookie = it->it_lock_handle; it->it_lock_mode = 0; - it->it_data = NULL; + it->it_request = NULL; } LASSERT(fid_is_sane(&body->fid1)); diff --git a/drivers/staging/lustre/lustre/lmv/lmv_obd.c b/drivers/staging/lustre/lustre/lmv/lmv_obd.c index e6d7efa..0e1588a 100644 --- a/drivers/staging/lustre/lustre/lmv/lmv_obd.c +++ b/drivers/staging/lustre/lustre/lmv/lmv_obd.c @@ -1679,7 +1679,7 @@ lmv_enqueue_remote(struct obd_export *exp, struct ldlm_enqueue_info *einfo, struct lustre_handle *lockh, void *lmm, int lmmsize, __u64 extra_lock_flags) { - struct ptlrpc_request *req = it->it_data; + struct ptlrpc_request *req = it->it_request; struct obd_device *obd = exp->exp_obd; struct lmv_obd *lmv = &obd->u.lmv; struct lustre_handle plock; @@ -1705,7 +1705,7 @@ lmv_enqueue_remote(struct obd_export *exp, struct ldlm_enqueue_info *einfo, LASSERT(pmode != 0); memcpy(&plock, lockh, sizeof(plock)); it->it_lock_mode = 0; - it->it_data = NULL; + it->it_request = NULL; fid1 = body->fid1; ptlrpc_req_finished(req); diff --git a/drivers/staging/lustre/lustre/mdc/mdc_locks.c b/drivers/staging/lustre/lustre/mdc/mdc_locks.c index 7c459b5..f48b584 100644 --- a/drivers/staging/lustre/lustre/mdc/mdc_locks.c +++ b/drivers/staging/lustre/lustre/mdc/mdc_locks.c @@ -561,7 +561,7 @@ static int mdc_finish_enqueue(struct obd_export *exp, it->it_status = (int)lockrep->lock_policy_res2; it->it_lock_mode = einfo->ei_mode; it->it_lock_handle = lockh->cookie; - it->it_data = req; + it->it_request = req; /* Technically speaking rq_transno must already be zero if * it_status is in error, so the check is a bit redundant @@ -883,7 +883,7 @@ resend: it->it_lock_handle = 0; it->it_lock_mode = 0; - it->it_data = NULL; + it->it_request = NULL; } return rc; @@ -1146,7 +1146,7 @@ int mdc_intent_lock(struct obd_export *exp, struct md_op_data *op_data, if (rc < 0) return rc; - *reqp = it->it_data; + *reqp = it->it_request; rc = mdc_finish_intent_lock(exp, *reqp, op_data, it, &lockh); return rc; } diff --git a/drivers/staging/lustre/lustre/mdc/mdc_request.c b/drivers/staging/lustre/lustre/mdc/mdc_request.c index d48910a..d4cc73b 100644 --- a/drivers/staging/lustre/lustre/mdc/mdc_request.c +++ b/drivers/staging/lustre/lustre/mdc/mdc_request.c @@ -637,7 +637,7 @@ int mdc_set_open_replay_data(struct obd_export *exp, struct md_open_data *mod; struct mdt_rec_create *rec; struct mdt_body *body; - struct ptlrpc_request *open_req = it->it_data; + struct ptlrpc_request *open_req = it->it_request; struct obd_import *imp = open_req->rq_import; if (!open_req->rq_replay) -- cgit v0.10.2 From e8beaf670dc64f7b5601f9285c03d812f842ca2b Mon Sep 17 00:00:00 2001 From: "John L. Hammond" Date: Mon, 20 Jun 2016 16:55:41 -0400 Subject: staging/lustre/ldlm: const qualify struct lustre_handle * params Add a const qualifier to several struct lustre_handle * parameters in the LDLM interface. Signed-off-by: John L. Hammond Reviewed-on: http://review.whamcloud.com/17071 Intel-bug-id: https://jira.hpdd.intel.com/browse/LU-7403 Reviewed-by: Andreas Dilger Reviewed-by: James Simmons Signed-off-by: Oleg Drokin Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/lustre/lustre/include/lustre_dlm.h b/drivers/staging/lustre/lustre/include/lustre_dlm.h index 63085a0..60051a5 100644 --- a/drivers/staging/lustre/lustre/include/lustre_dlm.h +++ b/drivers/staging/lustre/lustre/include/lustre_dlm.h @@ -1073,7 +1073,7 @@ void ldlm_lock2handle(const struct ldlm_lock *lock, struct ldlm_lock *__ldlm_handle2lock(const struct lustre_handle *, __u64 flags); void ldlm_cancel_callback(struct ldlm_lock *); int ldlm_lock_remove_from_lru(struct ldlm_lock *); -int ldlm_lock_set_data(struct lustre_handle *, void *); +int ldlm_lock_set_data(const struct lustre_handle *lockh, void *data); /** * Obtain a lock reference by its handle. @@ -1162,10 +1162,10 @@ do { \ struct ldlm_lock *ldlm_lock_get(struct ldlm_lock *lock); void ldlm_lock_put(struct ldlm_lock *lock); void ldlm_lock2desc(struct ldlm_lock *lock, struct ldlm_lock_desc *desc); -void ldlm_lock_addref(struct lustre_handle *lockh, __u32 mode); -int ldlm_lock_addref_try(struct lustre_handle *lockh, __u32 mode); -void ldlm_lock_decref(struct lustre_handle *lockh, __u32 mode); -void ldlm_lock_decref_and_cancel(struct lustre_handle *lockh, __u32 mode); +void ldlm_lock_addref(const struct lustre_handle *lockh, __u32 mode); +int ldlm_lock_addref_try(const struct lustre_handle *lockh, __u32 mode); +void ldlm_lock_decref(const struct lustre_handle *lockh, __u32 mode); +void ldlm_lock_decref_and_cancel(const struct lustre_handle *lockh, __u32 mode); void ldlm_lock_fail_match_locked(struct ldlm_lock *lock); void ldlm_lock_allow_match(struct ldlm_lock *lock); void ldlm_lock_allow_match_locked(struct ldlm_lock *lock); @@ -1174,10 +1174,10 @@ enum ldlm_mode ldlm_lock_match(struct ldlm_namespace *ns, __u64 flags, enum ldlm_type type, ldlm_policy_data_t *, enum ldlm_mode mode, struct lustre_handle *, int unref); -enum ldlm_mode ldlm_revalidate_lock_handle(struct lustre_handle *lockh, +enum ldlm_mode ldlm_revalidate_lock_handle(const struct lustre_handle *lockh, __u64 *bits); void ldlm_lock_cancel(struct ldlm_lock *lock); -void ldlm_lock_dump_handle(int level, struct lustre_handle *); +void ldlm_lock_dump_handle(int level, const struct lustre_handle *); void ldlm_unlink_lock_skiplist(struct ldlm_lock *req); /* resource.c */ @@ -1251,9 +1251,9 @@ int ldlm_cli_enqueue_fini(struct obd_export *exp, struct ptlrpc_request *req, enum ldlm_type type, __u8 with_policy, enum ldlm_mode mode, __u64 *flags, void *lvb, __u32 lvb_len, - struct lustre_handle *lockh, int rc); + const struct lustre_handle *lockh, int rc); int ldlm_cli_update_pool(struct ptlrpc_request *req); -int ldlm_cli_cancel(struct lustre_handle *lockh, +int ldlm_cli_cancel(const struct lustre_handle *lockh, enum ldlm_cancel_flags cancel_flags); int ldlm_cli_cancel_unused(struct ldlm_namespace *, const struct ldlm_res_id *, enum ldlm_cancel_flags flags, void *opaque); diff --git a/drivers/staging/lustre/lustre/ldlm/ldlm_lock.c b/drivers/staging/lustre/lustre/ldlm/ldlm_lock.c index b7254eb..a5993f7 100644 --- a/drivers/staging/lustre/lustre/ldlm/ldlm_lock.c +++ b/drivers/staging/lustre/lustre/ldlm/ldlm_lock.c @@ -658,7 +658,7 @@ static void ldlm_add_ast_work_item(struct ldlm_lock *lock, * r/w reference type is determined by \a mode * Calls ldlm_lock_addref_internal. */ -void ldlm_lock_addref(struct lustre_handle *lockh, __u32 mode) +void ldlm_lock_addref(const struct lustre_handle *lockh, __u32 mode) { struct ldlm_lock *lock; @@ -700,7 +700,7 @@ void ldlm_lock_addref_internal_nolock(struct ldlm_lock *lock, __u32 mode) * * \retval -EAGAIN lock is being canceled. */ -int ldlm_lock_addref_try(struct lustre_handle *lockh, __u32 mode) +int ldlm_lock_addref_try(const struct lustre_handle *lockh, __u32 mode) { struct ldlm_lock *lock; int result; @@ -832,7 +832,7 @@ void ldlm_lock_decref_internal(struct ldlm_lock *lock, __u32 mode) /** * Decrease reader/writer refcount for LDLM lock with handle \a lockh */ -void ldlm_lock_decref(struct lustre_handle *lockh, __u32 mode) +void ldlm_lock_decref(const struct lustre_handle *lockh, __u32 mode) { struct ldlm_lock *lock = __ldlm_handle2lock(lockh, 0); @@ -849,7 +849,7 @@ EXPORT_SYMBOL(ldlm_lock_decref); * * Typical usage is for GROUP locks which we cannot allow to be cached. */ -void ldlm_lock_decref_and_cancel(struct lustre_handle *lockh, __u32 mode) +void ldlm_lock_decref_and_cancel(const struct lustre_handle *lockh, __u32 mode) { struct ldlm_lock *lock = __ldlm_handle2lock(lockh, 0); @@ -1318,7 +1318,7 @@ enum ldlm_mode ldlm_lock_match(struct ldlm_namespace *ns, __u64 flags, } EXPORT_SYMBOL(ldlm_lock_match); -enum ldlm_mode ldlm_revalidate_lock_handle(struct lustre_handle *lockh, +enum ldlm_mode ldlm_revalidate_lock_handle(const struct lustre_handle *lockh, __u64 *bits) { struct ldlm_lock *lock; @@ -1849,7 +1849,7 @@ EXPORT_SYMBOL(ldlm_lock_cancel); /** * Set opaque data into the lock that only makes sense to upper layer. */ -int ldlm_lock_set_data(struct lustre_handle *lockh, void *data) +int ldlm_lock_set_data(const struct lustre_handle *lockh, void *data) { struct ldlm_lock *lock = ldlm_handle2lock(lockh); int rc = -EINVAL; @@ -1875,7 +1875,7 @@ struct export_cl_data { * * Used when printing all locks on a resource for debug purposes. */ -void ldlm_lock_dump_handle(int level, struct lustre_handle *lockh) +void ldlm_lock_dump_handle(int level, const struct lustre_handle *lockh) { struct ldlm_lock *lock; diff --git a/drivers/staging/lustre/lustre/ldlm/ldlm_lockd.c b/drivers/staging/lustre/lustre/ldlm/ldlm_lockd.c index 8294703..821939f 100644 --- a/drivers/staging/lustre/lustre/ldlm/ldlm_lockd.c +++ b/drivers/staging/lustre/lustre/ldlm/ldlm_lockd.c @@ -499,7 +499,7 @@ static int ldlm_handle_setinfo(struct ptlrpc_request *req) static inline void ldlm_callback_errmsg(struct ptlrpc_request *req, const char *msg, int rc, - struct lustre_handle *handle) + const struct lustre_handle *handle) { DEBUG_REQ((req->rq_no_reply || rc) ? D_WARNING : D_DLMTRACE, req, "%s: [nid %s] [rc %d] [lock %#llx]", diff --git a/drivers/staging/lustre/lustre/ldlm/ldlm_request.c b/drivers/staging/lustre/lustre/ldlm/ldlm_request.c index d3a376e..af487f9 100644 --- a/drivers/staging/lustre/lustre/ldlm/ldlm_request.c +++ b/drivers/staging/lustre/lustre/ldlm/ldlm_request.c @@ -336,7 +336,7 @@ int ldlm_cli_enqueue_fini(struct obd_export *exp, struct ptlrpc_request *req, enum ldlm_type type, __u8 with_policy, enum ldlm_mode mode, __u64 *flags, void *lvb, __u32 lvb_len, - struct lustre_handle *lockh, int rc) + const struct lustre_handle *lockh, int rc) { struct ldlm_namespace *ns = exp->exp_obd->obd_namespace; int is_replay = *flags & LDLM_FL_REPLAY; @@ -1023,7 +1023,7 @@ EXPORT_SYMBOL(ldlm_cli_update_pool); * * Lock must not have any readers or writers by this time. */ -int ldlm_cli_cancel(struct lustre_handle *lockh, +int ldlm_cli_cancel(const struct lustre_handle *lockh, enum ldlm_cancel_flags cancel_flags) { struct obd_export *exp; -- cgit v0.10.2 From 2323d6d8371d2e29ee159f225aaa1a012a4fc564 Mon Sep 17 00:00:00 2001 From: Yang Sheng Date: Mon, 20 Jun 2016 16:55:42 -0400 Subject: staging/lustre/llite: ensure obd is effective in onu_upcall The watched obd device may still not setup while onu_upcall invoked. So we need verify it in cl_ocd_update. Signed-off-by: Yang Sheng Reviewed-on: http://review.whamcloud.com/19597 Intel-bug-id: https://jira.hpdd.intel.com/browse/LU-8027 Reviewed-by: Niu Yawei Reviewed-by: Lai Siyao Signed-off-by: Oleg Drokin Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/lustre/lustre/llite/lcommon_misc.c b/drivers/staging/lustre/lustre/llite/lcommon_misc.c index 8a508ed..f6be105 100644 --- a/drivers/staging/lustre/lustre/llite/lcommon_misc.c +++ b/drivers/staging/lustre/lustre/llite/lcommon_misc.c @@ -96,7 +96,8 @@ int cl_ocd_update(struct obd_device *host, __u64 flags; int result; - if (!strcmp(watched->obd_type->typ_name, LUSTRE_OSC_NAME)) { + if (!strcmp(watched->obd_type->typ_name, LUSTRE_OSC_NAME) && + watched->obd_set_up && !watched->obd_stopping) { cli = &watched->u.cli; lco = owner; flags = cli->cl_import->imp_connect_data.ocd_connect_flags; @@ -111,9 +112,10 @@ int cl_ocd_update(struct obd_device *host, mutex_unlock(&lco->lco_lock); result = 0; } else { - CERROR("unexpected notification from %s %s!\n", + CERROR("unexpected notification from %s %s (setup:%d,stopping:%d)!\n", watched->obd_type->typ_name, - watched->obd_name); + watched->obd_name, watched->obd_set_up, + watched->obd_stopping); result = -EINVAL; } return result; -- cgit v0.10.2 From aea7ccd985a83d7ce55ebaa815108124c97af258 Mon Sep 17 00:00:00 2001 From: Niu Yawei Date: Mon, 20 Jun 2016 16:55:43 -0400 Subject: staging/lustre/mdc: Zero atime in close RPC While atime on close is supposed to only increase, there's a bug in some older server versions where atime from a client is taken no matter the value that allows a stale client atime to overwrite a correct value. Update atime in close rpc to 0 to help such servers out. Signed-off-by: Niu Yawei Reviewed-on: http://review.whamcloud.com/19932 Intel-bug-id: https://jira.hpdd.intel.com/browse/LU-8041 Reviewed-by: Andreas Dilger Reviewed-by: Jinshan Xiong Signed-off-by: Oleg Drokin Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/lustre/lustre/mdc/mdc_lib.c b/drivers/staging/lustre/lustre/mdc/mdc_lib.c index 2703113..143bd76 100644 --- a/drivers/staging/lustre/lustre/mdc/mdc_lib.c +++ b/drivers/staging/lustre/lustre/mdc/mdc_lib.c @@ -467,6 +467,18 @@ void mdc_close_pack(struct ptlrpc_request *req, struct md_op_data *op_data) rec = req_capsule_client_get(&req->rq_pill, &RMF_REC_REINT); mdc_setattr_pack_rec(rec, op_data); + /* + * The client will zero out local timestamps when losing the IBITS lock + * so any new RPC timestamps will update the client inode's timestamps. + * There was a defect on the server side which allowed the atime to be + * overwritten by a zeroed-out atime packed into the close RPC. + * + * Proactively clear the MDS_ATTR_ATIME flag in the RPC in this case + * to avoid zeroing the atime on old unpatched servers. See LU-8041. + */ + if (rec->sa_atime == 0) + rec->sa_valid &= ~MDS_ATTR_ATIME; + mdc_ioepoch_pack(epoch, op_data); mdc_hsm_release_pack(req, op_data); } -- cgit v0.10.2 From c681528a2ba7c8ceb273c608ff26c38b5ee668e8 Mon Sep 17 00:00:00 2001 From: Sergey Cheremencev Date: Mon, 20 Jun 2016 16:55:44 -0400 Subject: staging/lustre/llite: don't panic when fid is insane LASSERT should never be done on data that is received to over the network. Return EINVAL when server returns invalid fid despite of it_status == 0. Signed-off-by: Sergey Cheremencev Seagate-bug-id: MRP-3073 Reviewed-on: http://review.whamcloud.com/17985 Intel-bug-id: https://jira.hpdd.intel.com/browse/LU-7422 Reviewed-by: John L. Hammond Reviewed-by: Andreas Dilger Signed-off-by: Oleg Drokin Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/lustre/lustre/llite/llite_lib.c b/drivers/staging/lustre/lustre/llite/llite_lib.c index a741d6a..546063e 100644 --- a/drivers/staging/lustre/lustre/llite/llite_lib.c +++ b/drivers/staging/lustre/lustre/llite/llite_lib.c @@ -1918,7 +1918,13 @@ int ll_prep_inode(struct inode **inode, struct ptlrpc_request *req, * At this point server returns to client's same fid as client * generated for creating. So using ->fid1 is okay here. */ - LASSERT(fid_is_sane(&md.body->fid1)); + if (!fid_is_sane(&md.body->fid1)) { + CERROR("%s: Fid is insane " DFID "\n", + ll_get_fsname(sb, NULL, 0), + PFID(&md.body->fid1)); + rc = -EINVAL; + goto out; + } *inode = ll_iget(sb, cl_fid_build_ino(&md.body->fid1, sbi->ll_flags & LL_SBI_32BIT_API), -- cgit v0.10.2 From 6dad4d8903a43b0e34d9527e54a52737b0f69690 Mon Sep 17 00:00:00 2001 From: Oleg Drokin Date: Mon, 20 Jun 2016 16:55:45 -0400 Subject: staging/lustre/llite: Restore proper opencache operations Mark dentries that came to us via NFS in a special way so that we can tell them apart during open and activate open cache (we really don't want to do open/close RPC for every NFS IO). This became needed since dentry revlidate no longer reimplements any RPCs for lookup, and as such if a dentry is valid, ll_revalidate_dentry returns 1 and ll_lookup_it() is never visited during opens, we get straght into ll_file_open() without a valid intent/RPC. This used to be only true for NFS, so opencache was engaged needlessly, and it carries a cost of it's own if there is in fact no repetitive file opening-closing going on Signed-off-by: Oleg Drokin Reviewed-on: http://review.whamcloud.com/20354 Intel-bug-id: https://jira.hpdd.intel.com/browse/LU-8019 Reviewed-by: Andreas Dilger Reviewed-by: Li Xi Signed-off-by: Oleg Drokin Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/lustre/lustre/llite/file.c b/drivers/staging/lustre/lustre/llite/file.c index 39c487d..57281b9 100644 --- a/drivers/staging/lustre/lustre/llite/file.c +++ b/drivers/staging/lustre/lustre/llite/file.c @@ -399,7 +399,19 @@ static int ll_intent_file_open(struct dentry *dentry, void *lmm, * parameters. No need for the open lock */ if (!lmm && lmmsize == 0) { - itp->it_flags |= MDS_OPEN_LOCK; + struct ll_dentry_data *ldd = ll_d2d(dentry); + /* + * If we came via ll_iget_for_nfs, then we need to request + * struct ll_dentry_data *ldd = ll_d2d(file->f_dentry); + * + * NB: when ldd is NULL, it must have come via normal + * lookup path only, since ll_iget_for_nfs always calls + * ll_d_init(). + */ + if (ldd && ldd->lld_nfs_dentry) { + ldd->lld_nfs_dentry = 0; + itp->it_flags |= MDS_OPEN_LOCK; + } if (itp->it_flags & FMODE_WRITE) opc = LUSTRE_OPC_CREATE; } diff --git a/drivers/staging/lustre/lustre/llite/llite_internal.h b/drivers/staging/lustre/lustre/llite/llite_internal.h index 08cc2c1..4d6d589 100644 --- a/drivers/staging/lustre/lustre/llite/llite_internal.h +++ b/drivers/staging/lustre/lustre/llite/llite_internal.h @@ -64,6 +64,7 @@ struct ll_dentry_data { struct lookup_intent *lld_it; unsigned int lld_sa_generation; unsigned int lld_invalid:1; + unsigned int lld_nfs_dentry:1; struct rcu_head lld_rcu_head; }; diff --git a/drivers/staging/lustre/lustre/llite/llite_nfs.c b/drivers/staging/lustre/lustre/llite/llite_nfs.c index d7878e5..65972c8 100644 --- a/drivers/staging/lustre/lustre/llite/llite_nfs.c +++ b/drivers/staging/lustre/lustre/llite/llite_nfs.c @@ -168,6 +168,24 @@ ll_iget_for_nfs(struct super_block *sb, struct lu_fid *fid, struct lu_fid *paren /* N.B. d_obtain_alias() drops inode ref on error */ result = d_obtain_alias(inode); + if (!IS_ERR(result)) { + int rc; + + rc = ll_d_init(result); + if (rc < 0) { + dput(result); + result = ERR_PTR(rc); + } else { + struct ll_dentry_data *ldd = ll_d2d(result); + + /* + * Need to signal to the ll_intent_file_open that + * we came from NFS and so opencache needs to be + * enabled for this one + */ + ldd->lld_nfs_dentry = 1; + } + } return result; } -- cgit v0.10.2 From aae5d55a24f74d429f32895cf73b9839d0d5e6e1 Mon Sep 17 00:00:00 2001 From: Oleg Drokin Date: Mon, 20 Jun 2016 16:55:46 -0400 Subject: staging/lustre/llite: ll_revalidate_dentry update There are a couple of cases in ll_revalidate_dentry() where we are pretty sure the dentry is valid, so check for them early and save more expensive checks for later. Signed-off-by: Oleg Drokin Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/lustre/lustre/llite/dcache.c b/drivers/staging/lustre/lustre/llite/dcache.c index d964f4f..581a63a 100644 --- a/drivers/staging/lustre/lustre/llite/dcache.c +++ b/drivers/staging/lustre/lustre/llite/dcache.c @@ -302,6 +302,17 @@ static int ll_revalidate_dentry(struct dentry *dentry, { struct inode *dir = d_inode(dentry->d_parent); + /* If this is intermediate component path lookup and we were able to get + * to this dentry, then its lock has not been revoked and the + * path component is valid. + */ + if (lookup_flags & LOOKUP_PARENT) + return 1; + + /* Symlink - always valid as long as the dentry was found */ + if (dentry->d_inode && S_ISLNK(dentry->d_inode->i_mode)) + return 1; + /* * if open&create is set, talk to MDS to make sure file is created if * necessary, because we can't do this in ->open() later since that's -- cgit v0.10.2 From d780846e0f3616214c0272ed2445445f69311a2c Mon Sep 17 00:00:00 2001 From: akam kumar bharathi Date: Mon, 20 Jun 2016 16:55:47 -0400 Subject: staging/lustre/llite: IOC_MDC_GETFILEINFO returns the wrong ino req_capsule_server_get() through __req_capsule_get in ll_dir_ioctl() returns a pointer to a PTLRPC request or reply buffer, which is assigned to struct mdt_body. If the command is IOC_MDS_GETFILEINFO then the inode "st.st_ino" should be assigned from one extracted from mdt_body through cl_fid_build_ino(). Signed-off-by: John Hammond Signed-off-by: akam kumar bharathi Reviewed-on: http://review.whamcloud.com/17618 Intel-bug-id: https://jira.hpdd.intel.com/browse/LU-5954 Reviewed-by: Andreas Dilger Signed-off-by: Oleg Drokin Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/lustre/lustre/llite/dir.c b/drivers/staging/lustre/lustre/llite/dir.c index 92b01fd..5b38177 100644 --- a/drivers/staging/lustre/lustre/llite/dir.c +++ b/drivers/staging/lustre/lustre/llite/dir.c @@ -1523,7 +1523,9 @@ skip_lmm: st.st_atime = body->atime; st.st_mtime = body->mtime; st.st_ctime = body->ctime; - st.st_ino = inode->i_ino; + st.st_ino = cl_fid_build_ino(&body->fid1, + sbi->ll_flags & + LL_SBI_32BIT_API); lmdp = (struct lov_user_mds_data __user *)arg; if (copy_to_user(&lmdp->lmd_st, &st, sizeof(st))) { -- cgit v0.10.2 From c32090fce9ed23576d3ee461f10a60777e91f5ee Mon Sep 17 00:00:00 2001 From: Dmitry Eremin Date: Mon, 20 Jun 2016 16:55:48 -0400 Subject: staging/lustre/osc: fix signed one bit field Bit field 'oi_lockless' and 'oi_is_active' has one bit and is signed which is confusing. Signed-off-by: Dmitry Eremin Reviewed-on: http://review.whamcloud.com/19196 Intel-bug-id: https://jira.hpdd.intel.com/browse/LU-7258 Reviewed-by: Andreas Dilger Reviewed-by: James Simmons Reviewed-by: Frank Zago Reviewed-by: John L. Hammond Signed-off-by: Oleg Drokin Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/lustre/lustre/osc/osc_cl_internal.h b/drivers/staging/lustre/lustre/osc/osc_cl_internal.h index 437c659..c8c3f1c 100644 --- a/drivers/staging/lustre/lustre/osc/osc_cl_internal.h +++ b/drivers/staging/lustre/lustre/osc/osc_cl_internal.h @@ -62,7 +62,7 @@ struct osc_io { /** super class */ struct cl_io_slice oi_cl; /** true if this io is lockless. */ - int oi_lockless; + unsigned int oi_lockless; /** how many LRU pages are reserved for this IO */ int oi_lru_reserved; -- cgit v0.10.2 From cb96191ff462214890cd8a0fb96794e42eeead71 Mon Sep 17 00:00:00 2001 From: Oleg Drokin Date: Mon, 20 Jun 2016 16:55:49 -0400 Subject: staging/lustre: Add documentation for unstable_stats in sysfs commit ac5b14810952 ("staging: lustre: osc: Track and limit "unstable" pages") added a new sysfs variable, but corresponding bit of documentation was not forgotten. Signed-off-by: Oleg Drokin Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/lustre/sysfs-fs-lustre b/drivers/staging/lustre/sysfs-fs-lustre index 873e2cf..20206ba 100644 --- a/drivers/staging/lustre/sysfs-fs-lustre +++ b/drivers/staging/lustre/sysfs-fs-lustre @@ -294,6 +294,14 @@ Description: Controls extended attributes client-side cache. 1 to enable, 0 to disable. +What: /sys/fs/lustre/llite/-/unstable_stats +Date: Apr 2016 +Contact: "Oleg Drokin" +Description: + Shows number of pages that were sent and acknowledged by + server but were not yet committed and therefore still + pinned in client memory even though no longer dirty. + What: /sys/fs/lustre/ldlm/cancel_unused_locks_before_replay Date: May 2015 Contact: "Oleg Drokin" -- cgit v0.10.2 From 025fd3c20bfb4e84972f174c7246f86d693f6544 Mon Sep 17 00:00:00 2001 From: Andriy Skulysh Date: Mon, 20 Jun 2016 16:55:50 -0400 Subject: staging/lustre/osc: glimpse lock should match only with granted locks A deadlock is possible during ccc_prep_size()->ldlm_lock_match() vs cl_io_lock() which is waiting for a matched lock and conflicts with already taken lock before ccc_prep_size(). It is better to send an additional lock request to avoid deadlock. Seagate-bug-id: MRP-3312 Signed-off-by: Andriy Skulysh Reviewed-on: http://review.whamcloud.com/18738 Intel-bug-id: https://jira.hpdd.intel.com/browse/LU-7829 Reviewed-by: Jinshan Xiong Reviewed-by: Bobi Jam Signed-off-by: Oleg Drokin Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/lustre/lustre/osc/osc_request.c b/drivers/staging/lustre/lustre/osc/osc_request.c index 9334349..536b868 100644 --- a/drivers/staging/lustre/lustre/osc/osc_request.c +++ b/drivers/staging/lustre/lustre/osc/osc_request.c @@ -2246,7 +2246,7 @@ int osc_enqueue_base(struct obd_export *exp, struct ldlm_res_id *res_id, struct lustre_handle lockh = { 0 }; struct ptlrpc_request *req = NULL; int intent = *flags & LDLM_FL_HAS_INTENT; - __u64 match_lvb = agl ? 0 : LDLM_FL_LVB_READY; + __u64 match_flags = *flags; enum ldlm_mode mode; int rc; @@ -2281,7 +2281,11 @@ int osc_enqueue_base(struct obd_export *exp, struct ldlm_res_id *res_id, mode = einfo->ei_mode; if (einfo->ei_mode == LCK_PR) mode |= LCK_PW; - mode = ldlm_lock_match(obd->obd_namespace, *flags | match_lvb, res_id, + if (agl == 0) + match_flags |= LDLM_FL_LVB_READY; + if (intent != 0) + match_flags |= LDLM_FL_BLOCK_GRANTED; + mode = ldlm_lock_match(obd->obd_namespace, match_flags, res_id, einfo->ei_type, policy, mode, &lockh, 0); if (mode) { struct ldlm_lock *matched; -- cgit v0.10.2 From 281a8273f6d8664b14c9164ff6d659049c43b3f0 Mon Sep 17 00:00:00 2001 From: Oleg Drokin Date: Mon, 20 Jun 2016 16:55:51 -0400 Subject: staging/lustre/libcfs: Do not call kthread_run in wrong state kthread_run might sleep during an allocation, and so it's considered unsafe to call with a state that's not RUNNABLE. Move the state setting to after kthread_run call. Signed-off-by: Oleg Drokin Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/lustre/lnet/libcfs/debug.c b/drivers/staging/lustre/lnet/libcfs/debug.c index 75a2a42..42b15a7 100644 --- a/drivers/staging/lustre/lnet/libcfs/debug.c +++ b/drivers/staging/lustre/lnet/libcfs/debug.c @@ -362,12 +362,12 @@ void libcfs_debug_dumplog(void) * get to schedule() */ init_waitqueue_entry(&wait, current); - set_current_state(TASK_INTERRUPTIBLE); add_wait_queue(&debug_ctlwq, &wait); dumper = kthread_run(libcfs_debug_dumplog_thread, (void *)(long)current_pid(), "libcfs_debug_dumper"); + set_current_state(TASK_INTERRUPTIBLE); if (IS_ERR(dumper)) pr_err("LustreError: cannot start log dump thread: %ld\n", PTR_ERR(dumper)); -- cgit v0.10.2 From 9936913e549bca6721157418bb5014118c3786e0 Mon Sep 17 00:00:00 2001 From: Andreas Dilger Date: Mon, 20 Jun 2016 16:55:52 -0400 Subject: staging: lustre: quiet lockdep recursive lock warning Lockdep complains about potential recursive locking during mount because the client configuration log is holding a lock on the MGC obd_device to prevent it from being torn down, while also getting mutexes on the MDC and OSC devices as they are instantiated: Lustre: Mounted myth-client ============================================= [ INFO: possible recursive locking detected ] 4.7.0-rc2-vm-nfs+ #127 Tainted: G C --------------------------------------------- May be due to missing lock nesting notation 2 locks held by ll_cfg_requeue/5928: #0: (&cli->cl_sem){.+.+.+}, at: mgc_requeue_thread+0x15d/0x730 [mgc] #1: (&cld->cld_lock){+.+.+.}, at: mgc_process_log+0x5e/0xf80 [mgc] CPU: 0 PID: 5928 Comm: ll_cfg_requeue Call Trace: [] dump_stack+0x86/0xc1 [] __lock_acquire+0x726/0x1210 [] lock_acquire+0xfe/0x1f0 [] down_read+0x51/0xa0 [] sptlrpc_conf_client_adapt+0x47/0x150 [ptlrpc] [] mdc_set_info_async+0x2b6/0x470 [mdc] [] class_notify_sptlrpc_conf+0x190/0x360 [obdclass] [] mgc_process_log+0x925/0xf80 [mgc] [] mgc_requeue_thread+0x1fa/0x730 [mgc] [] kthread+0x101/0x120 [] ret_from_fork+0x1f/0x40 Add a separate lock class for the MGC callpath, since it will always be held first, and none of the other obd_device locks should ever be held concurrently. Signed-off-by: Andreas Dilger Signed-off-by: Oleg Drokin Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/lustre/lustre/include/obd.h b/drivers/staging/lustre/lustre/include/obd.h index 40909b0..a1bc2c4 100644 --- a/drivers/staging/lustre/lustre/include/obd.h +++ b/drivers/staging/lustre/lustre/include/obd.h @@ -228,6 +228,12 @@ enum { #define MDC_MAX_RIF_DEFAULT 8 #define MDC_MAX_RIF_MAX 512 +enum obd_cl_sem_lock_class { + OBD_CLI_SEM_NORMAL, + OBD_CLI_SEM_MGC, + OBD_CLI_SEM_MDCOSC, +}; + struct mdc_rpc_lock; struct obd_import; struct client_obd { diff --git a/drivers/staging/lustre/lustre/mgc/mgc_request.c b/drivers/staging/lustre/lustre/mgc/mgc_request.c index fbbf276..9d0bd47 100644 --- a/drivers/staging/lustre/lustre/mgc/mgc_request.c +++ b/drivers/staging/lustre/lustre/mgc/mgc_request.c @@ -496,7 +496,9 @@ static void do_requeue(struct config_llog_data *cld) * export which is being disconnected. Take the client * semaphore to make the check non-racy. */ - down_read(&cld->cld_mgcexp->exp_obd->u.cli.cl_sem); + down_read_nested(&cld->cld_mgcexp->exp_obd->u.cli.cl_sem, + OBD_CLI_SEM_MGC); + if (cld->cld_mgcexp->exp_obd->u.cli.cl_conn_count != 0) { int rc; diff --git a/drivers/staging/lustre/lustre/ptlrpc/sec_config.c b/drivers/staging/lustre/lustre/ptlrpc/sec_config.c index 1238c87..c140354 100644 --- a/drivers/staging/lustre/lustre/ptlrpc/sec_config.c +++ b/drivers/staging/lustre/lustre/ptlrpc/sec_config.c @@ -815,7 +815,7 @@ void sptlrpc_conf_client_adapt(struct obd_device *obd) CDEBUG(D_SEC, "obd %s\n", obd->u.cli.cl_target_uuid.uuid); /* serialize with connect/disconnect import */ - down_read(&obd->u.cli.cl_sem); + down_read_nested(&obd->u.cli.cl_sem, OBD_CLI_SEM_MDCOSC); imp = obd->u.cli.cl_import; if (imp) { -- cgit v0.10.2 From fb67cb0054736bded9d3c8460a7f8b77db39e351 Mon Sep 17 00:00:00 2001 From: Peter Chen Date: Thu, 16 Jun 2016 15:41:40 +0800 Subject: usb: chipidea: Kconfig: improve Kconfig help text Chipidea driver has been updated a lot, and more functions are supported, update Kconfig help text accordingly. Signed-off-by: Peter Chen diff --git a/drivers/usb/chipidea/Kconfig b/drivers/usb/chipidea/Kconfig index 3644a35..5e5b9eb 100644 --- a/drivers/usb/chipidea/Kconfig +++ b/drivers/usb/chipidea/Kconfig @@ -4,8 +4,9 @@ config USB_CHIPIDEA select EXTCON help Say Y here if your system has a dual role high speed USB - controller based on ChipIdea silicon IP. Currently, only the - peripheral mode is supported. + controller based on ChipIdea silicon IP. It supports: + Dual-role switch (ID, OTG FSM, sysfs), Host-only, and + Peripheral-only. When compiled dynamically, the module will be called ci-hdrc.ko. -- cgit v0.10.2 From ebfad91c5da3b32d83aaad280d6918867aea501c Mon Sep 17 00:00:00 2001 From: Jisheng Zhang Date: Thu, 16 Jun 2016 16:13:18 +0800 Subject: dt-bindings: ci-hdrc-usb2: s/gadget-itc-setting/itc-setting in example What the code expect is "itc-setting" rather than "gadget-itc-setting", and this is also correctly described in the optional properties. Signed-off-by: Jisheng Zhang Signed-off-by: Peter Chen Acked-by: Rob Herring diff --git a/Documentation/devicetree/bindings/usb/ci-hdrc-usb2.txt b/Documentation/devicetree/bindings/usb/ci-hdrc-usb2.txt index 1084e2b..341dc67 100644 --- a/Documentation/devicetree/bindings/usb/ci-hdrc-usb2.txt +++ b/Documentation/devicetree/bindings/usb/ci-hdrc-usb2.txt @@ -93,7 +93,7 @@ Example: phys = <&usb_phy0>; phy-names = "usb-phy"; vbus-supply = <®_usb0_vbus>; - gadget-itc-setting = <0x4>; /* 4 micro-frames */ + itc-setting = <0x4>; /* 4 micro-frames */ /* Incremental burst of unspecified length */ ahb-burst-config = <0x0>; tx-burst-size-dword = <0x10>; /* 64 bytes */ -- cgit v0.10.2 From 12bd0f323b855ee548367f48062cf58cae5acda8 Mon Sep 17 00:00:00 2001 From: Grygorii Strashko Date: Wed, 6 Apr 2016 20:32:37 +0300 Subject: extcon: usb-gpio: switch to use pm wakeirq apis Switch to use PM wakeirq APIs which automates wakeup IRQs enabling/disabling and so allows to make code simpler. Signed-off-by: Grygorii Strashko Acked-by: Tony Lindgren Acked-by: Roger Quadros Signed-off-by: Chanwoo Choi diff --git a/drivers/extcon/extcon-usb-gpio.c b/drivers/extcon/extcon-usb-gpio.c index 2b2fecf..bc61d11 100644 --- a/drivers/extcon/extcon-usb-gpio.c +++ b/drivers/extcon/extcon-usb-gpio.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include @@ -141,7 +142,8 @@ static int usb_extcon_probe(struct platform_device *pdev) } platform_set_drvdata(pdev, info); - device_init_wakeup(dev, 1); + device_init_wakeup(dev, true); + dev_pm_set_wake_irq(dev, info->id_irq); /* Perform initial detection */ usb_extcon_detect_cable(&info->wq_detcable.work); @@ -155,6 +157,9 @@ static int usb_extcon_remove(struct platform_device *pdev) cancel_delayed_work_sync(&info->wq_detcable); + dev_pm_clear_wake_irq(&pdev->dev); + device_init_wakeup(&pdev->dev, false); + return 0; } @@ -164,12 +169,6 @@ static int usb_extcon_suspend(struct device *dev) struct usb_extcon_info *info = dev_get_drvdata(dev); int ret = 0; - if (device_may_wakeup(dev)) { - ret = enable_irq_wake(info->id_irq); - if (ret) - return ret; - } - /* * We don't want to process any IRQs after this point * as GPIOs used behind I2C subsystem might not be @@ -185,12 +184,6 @@ static int usb_extcon_resume(struct device *dev) struct usb_extcon_info *info = dev_get_drvdata(dev); int ret = 0; - if (device_may_wakeup(dev)) { - ret = disable_irq_wake(info->id_irq); - if (ret) - return ret; - } - enable_irq(info->id_irq); return ret; -- cgit v0.10.2 From 04c080080855ce84dcd490a2e04805608a21085d Mon Sep 17 00:00:00 2001 From: Roger Quadros Date: Mon, 11 Apr 2016 17:04:45 +0300 Subject: extcon: usb-gpio: Don't miss event during suspend/resume Pin state might have changed during suspend/resume while our interrupts were disabled and if device doesn't support wakeup. Scan for change during resume for such case. Signed-off-by: Roger Quadros Signed-off-by: Chanwoo Choi diff --git a/drivers/extcon/extcon-usb-gpio.c b/drivers/extcon/extcon-usb-gpio.c index bc61d11..bad2159 100644 --- a/drivers/extcon/extcon-usb-gpio.c +++ b/drivers/extcon/extcon-usb-gpio.c @@ -185,6 +185,9 @@ static int usb_extcon_resume(struct device *dev) int ret = 0; enable_irq(info->id_irq); + if (!device_may_wakeup(dev)) + queue_delayed_work(system_power_efficient_wq, + &info->wq_detcable, 0); return ret; } -- cgit v0.10.2 From 058b6659e98ffa8bc2781dba9ca56893be577ca3 Mon Sep 17 00:00:00 2001 From: Lu Baolu Date: Mon, 25 Apr 2016 16:04:47 +0800 Subject: extcon: usb-gpio: add device binding for platform device This is needed to handle the GPIO connected USB ID pin found on Intel Baytrail devices. Signed-off-by: Lu Baolu Reviewed-by: Felipe Balbi Acked-by: Chanwoo Choi Signed-off-by: Chanwoo Choi diff --git a/drivers/extcon/extcon-usb-gpio.c b/drivers/extcon/extcon-usb-gpio.c index bad2159..8969606 100644 --- a/drivers/extcon/extcon-usb-gpio.c +++ b/drivers/extcon/extcon-usb-gpio.c @@ -202,6 +202,12 @@ static const struct of_device_id usb_extcon_dt_match[] = { }; MODULE_DEVICE_TABLE(of, usb_extcon_dt_match); +static const struct platform_device_id usb_extcon_platform_ids[] = { + { .name = "extcon-usb-gpio", }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(platform, usb_extcon_platform_ids); + static struct platform_driver usb_extcon_driver = { .probe = usb_extcon_probe, .remove = usb_extcon_remove, @@ -210,6 +216,7 @@ static struct platform_driver usb_extcon_driver = { .pm = &usb_extcon_pm_ops, .of_match_table = usb_extcon_dt_match, }, + .id_table = usb_extcon_platform_ids, }; module_platform_driver(usb_extcon_driver); -- cgit v0.10.2 From 942c7924a51edb75baf805679141e97140e07218 Mon Sep 17 00:00:00 2001 From: Lu Baolu Date: Tue, 26 Apr 2016 08:35:54 +0900 Subject: extcon: usb-gpio: add support for ACPI gpio interface GPIO resource could be retrieved through APCI as well. Signed-off-by: Lu Baolu Reviewed-by: Felipe Balbi Acked-by: Chanwoo Choi Signed-off-by: Chanwoo Choi diff --git a/drivers/extcon/extcon-usb-gpio.c b/drivers/extcon/extcon-usb-gpio.c index 8969606..2512660 100644 --- a/drivers/extcon/extcon-usb-gpio.c +++ b/drivers/extcon/extcon-usb-gpio.c @@ -27,6 +27,7 @@ #include #include #include +#include #define USB_GPIO_DEBOUNCE_MS 20 /* ms */ @@ -92,7 +93,7 @@ static int usb_extcon_probe(struct platform_device *pdev) struct usb_extcon_info *info; int ret; - if (!np) + if (!np && !ACPI_HANDLE(dev)) return -EINVAL; info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL); -- cgit v0.10.2 From 846d9ce535309798ae6d8c8781b0207f3cb41e6e Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Wed, 1 Jun 2016 16:13:12 +0100 Subject: extcon: arizona: Update binding docs to mention new defines for GPSW Update the binding documentation to mention the defines added for the possible values of wlf,gpsw. Signed-off-by: Charles Keepax Signed-off-by: Chanwoo Choi diff --git a/Documentation/devicetree/bindings/extcon/extcon-arizona.txt b/Documentation/devicetree/bindings/extcon/extcon-arizona.txt index e27341f..7f3d94a 100644 --- a/Documentation/devicetree/bindings/extcon/extcon-arizona.txt +++ b/Documentation/devicetree/bindings/extcon/extcon-arizona.txt @@ -46,7 +46,8 @@ Optional properties: The second cell represents the MICBIAS to be used. The third cell represents the value of the micd-pol-gpio pin. - - wlf,gpsw : Settings for the general purpose switch + - wlf,gpsw : Settings for the general purpose switch, set as one of the + ARIZONA_GPSW_XXX defines. Example: -- cgit v0.10.2 From 5a8d651a2bde01e00caf78496390d6ae46df80af Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Tue, 31 May 2016 13:07:47 +0300 Subject: usb: gadget: move gadget API functions to udc-core instead of defining all functions as static inlines, let's move them to udc-core and export them with EXPORT_SYMBOL_GPL, that way we can make sure that only GPL drivers will use them. As a side effect, it'll be nicer to add tracepoints to the gadget API. While at that, also fix Kconfig dependencies to avoid randconfig build failures. Acked-By: Sebastian Reichel Acked-by: Peter Chen Signed-off-by: Felipe Balbi diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig index b869b98..8d1cfb7 100644 --- a/drivers/phy/Kconfig +++ b/drivers/phy/Kconfig @@ -176,6 +176,7 @@ config TWL4030_USB tristate "TWL4030 USB Transceiver Driver" depends on TWL4030_CORE && REGULATOR_TWL4030 && USB_MUSB_OMAP2PLUS depends on USB_SUPPORT + depends on USB_GADGET || !USB_GADGET # if USB_GADGET=m, this can't 'y' select GENERIC_PHY select USB_PHY help diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig index 421770d..0f11a0f 100644 --- a/drivers/power/Kconfig +++ b/drivers/power/Kconfig @@ -309,6 +309,7 @@ config BATTERY_RX51 config CHARGER_ISP1704 tristate "ISP1704 USB Charger Detection" depends on USB_PHY + depends on USB_GADGET || !USB_GADGET # if USB_GADGET=m, this can't be 'y' help Say Y to enable support for USB Charger Detection with ISP1707/ISP1704 USB transceivers. diff --git a/drivers/usb/gadget/udc/udc-core.c b/drivers/usb/gadget/udc/udc-core.c index e1b2dce..abf0138 100644 --- a/drivers/usb/gadget/udc/udc-core.c +++ b/drivers/usb/gadget/udc/udc-core.c @@ -59,6 +59,579 @@ static int udc_bind_to_driver(struct usb_udc *udc, /* ------------------------------------------------------------------------- */ +/** + * usb_ep_set_maxpacket_limit - set maximum packet size limit for endpoint + * @ep:the endpoint being configured + * @maxpacket_limit:value of maximum packet size limit + * + * This function should be used only in UDC drivers to initialize endpoint + * (usually in probe function). + */ +void usb_ep_set_maxpacket_limit(struct usb_ep *ep, + unsigned maxpacket_limit) +{ + ep->maxpacket_limit = maxpacket_limit; + ep->maxpacket = maxpacket_limit; +} +EXPORT_SYMBOL_GPL(usb_ep_set_maxpacket_limit); + +/** + * usb_ep_enable - configure endpoint, making it usable + * @ep:the endpoint being configured. may not be the endpoint named "ep0". + * drivers discover endpoints through the ep_list of a usb_gadget. + * + * When configurations are set, or when interface settings change, the driver + * will enable or disable the relevant endpoints. while it is enabled, an + * endpoint may be used for i/o until the driver receives a disconnect() from + * the host or until the endpoint is disabled. + * + * the ep0 implementation (which calls this routine) must ensure that the + * hardware capabilities of each endpoint match the descriptor provided + * for it. for example, an endpoint named "ep2in-bulk" would be usable + * for interrupt transfers as well as bulk, but it likely couldn't be used + * for iso transfers or for endpoint 14. some endpoints are fully + * configurable, with more generic names like "ep-a". (remember that for + * USB, "in" means "towards the USB master".) + * + * returns zero, or a negative error code. + */ +int usb_ep_enable(struct usb_ep *ep) +{ + int ret; + + if (ep->enabled) + return 0; + + ret = ep->ops->enable(ep, ep->desc); + if (ret) + return ret; + + ep->enabled = true; + + return 0; +} +EXPORT_SYMBOL_GPL(usb_ep_enable); + +/** + * usb_ep_disable - endpoint is no longer usable + * @ep:the endpoint being unconfigured. may not be the endpoint named "ep0". + * + * no other task may be using this endpoint when this is called. + * any pending and uncompleted requests will complete with status + * indicating disconnect (-ESHUTDOWN) before this call returns. + * gadget drivers must call usb_ep_enable() again before queueing + * requests to the endpoint. + * + * returns zero, or a negative error code. + */ +int usb_ep_disable(struct usb_ep *ep) +{ + int ret; + + if (!ep->enabled) + return 0; + + ret = ep->ops->disable(ep); + if (ret) + return ret; + + ep->enabled = false; + + return 0; +} +EXPORT_SYMBOL_GPL(usb_ep_disable); + +/** + * usb_ep_alloc_request - allocate a request object to use with this endpoint + * @ep:the endpoint to be used with with the request + * @gfp_flags:GFP_* flags to use + * + * Request objects must be allocated with this call, since they normally + * need controller-specific setup and may even need endpoint-specific + * resources such as allocation of DMA descriptors. + * Requests may be submitted with usb_ep_queue(), and receive a single + * completion callback. Free requests with usb_ep_free_request(), when + * they are no longer needed. + * + * Returns the request, or null if one could not be allocated. + */ +struct usb_request *usb_ep_alloc_request(struct usb_ep *ep, + gfp_t gfp_flags) +{ + return ep->ops->alloc_request(ep, gfp_flags); +} +EXPORT_SYMBOL_GPL(usb_ep_alloc_request); + +/** + * usb_ep_free_request - frees a request object + * @ep:the endpoint associated with the request + * @req:the request being freed + * + * Reverses the effect of usb_ep_alloc_request(). + * Caller guarantees the request is not queued, and that it will + * no longer be requeued (or otherwise used). + */ +void usb_ep_free_request(struct usb_ep *ep, + struct usb_request *req) +{ + ep->ops->free_request(ep, req); +} +EXPORT_SYMBOL_GPL(usb_ep_free_request); + +/** + * usb_ep_queue - queues (submits) an I/O request to an endpoint. + * @ep:the endpoint associated with the request + * @req:the request being submitted + * @gfp_flags: GFP_* flags to use in case the lower level driver couldn't + * pre-allocate all necessary memory with the request. + * + * This tells the device controller to perform the specified request through + * that endpoint (reading or writing a buffer). When the request completes, + * including being canceled by usb_ep_dequeue(), the request's completion + * routine is called to return the request to the driver. Any endpoint + * (except control endpoints like ep0) may have more than one transfer + * request queued; they complete in FIFO order. Once a gadget driver + * submits a request, that request may not be examined or modified until it + * is given back to that driver through the completion callback. + * + * Each request is turned into one or more packets. The controller driver + * never merges adjacent requests into the same packet. OUT transfers + * will sometimes use data that's already buffered in the hardware. + * Drivers can rely on the fact that the first byte of the request's buffer + * always corresponds to the first byte of some USB packet, for both + * IN and OUT transfers. + * + * Bulk endpoints can queue any amount of data; the transfer is packetized + * automatically. The last packet will be short if the request doesn't fill it + * out completely. Zero length packets (ZLPs) should be avoided in portable + * protocols since not all usb hardware can successfully handle zero length + * packets. (ZLPs may be explicitly written, and may be implicitly written if + * the request 'zero' flag is set.) Bulk endpoints may also be used + * for interrupt transfers; but the reverse is not true, and some endpoints + * won't support every interrupt transfer. (Such as 768 byte packets.) + * + * Interrupt-only endpoints are less functional than bulk endpoints, for + * example by not supporting queueing or not handling buffers that are + * larger than the endpoint's maxpacket size. They may also treat data + * toggle differently. + * + * Control endpoints ... after getting a setup() callback, the driver queues + * one response (even if it would be zero length). That enables the + * status ack, after transferring data as specified in the response. Setup + * functions may return negative error codes to generate protocol stalls. + * (Note that some USB device controllers disallow protocol stall responses + * in some cases.) When control responses are deferred (the response is + * written after the setup callback returns), then usb_ep_set_halt() may be + * used on ep0 to trigger protocol stalls. Depending on the controller, + * it may not be possible to trigger a status-stage protocol stall when the + * data stage is over, that is, from within the response's completion + * routine. + * + * For periodic endpoints, like interrupt or isochronous ones, the usb host + * arranges to poll once per interval, and the gadget driver usually will + * have queued some data to transfer at that time. + * + * Returns zero, or a negative error code. Endpoints that are not enabled + * report errors; errors will also be + * reported when the usb peripheral is disconnected. + */ +int usb_ep_queue(struct usb_ep *ep, + struct usb_request *req, gfp_t gfp_flags) +{ + if (WARN_ON_ONCE(!ep->enabled && ep->address)) + return -ESHUTDOWN; + + return ep->ops->queue(ep, req, gfp_flags); +} +EXPORT_SYMBOL_GPL(usb_ep_queue); + +/** + * usb_ep_dequeue - dequeues (cancels, unlinks) an I/O request from an endpoint + * @ep:the endpoint associated with the request + * @req:the request being canceled + * + * If the request is still active on the endpoint, it is dequeued and its + * completion routine is called (with status -ECONNRESET); else a negative + * error code is returned. This is guaranteed to happen before the call to + * usb_ep_dequeue() returns. + * + * Note that some hardware can't clear out write fifos (to unlink the request + * at the head of the queue) except as part of disconnecting from usb. Such + * restrictions prevent drivers from supporting configuration changes, + * even to configuration zero (a "chapter 9" requirement). + */ +int usb_ep_dequeue(struct usb_ep *ep, struct usb_request *req) +{ + return ep->ops->dequeue(ep, req); +} +EXPORT_SYMBOL_GPL(usb_ep_dequeue); + +/** + * usb_ep_set_halt - sets the endpoint halt feature. + * @ep: the non-isochronous endpoint being stalled + * + * Use this to stall an endpoint, perhaps as an error report. + * Except for control endpoints, + * the endpoint stays halted (will not stream any data) until the host + * clears this feature; drivers may need to empty the endpoint's request + * queue first, to make sure no inappropriate transfers happen. + * + * Note that while an endpoint CLEAR_FEATURE will be invisible to the + * gadget driver, a SET_INTERFACE will not be. To reset endpoints for the + * current altsetting, see usb_ep_clear_halt(). When switching altsettings, + * it's simplest to use usb_ep_enable() or usb_ep_disable() for the endpoints. + * + * Returns zero, or a negative error code. On success, this call sets + * underlying hardware state that blocks data transfers. + * Attempts to halt IN endpoints will fail (returning -EAGAIN) if any + * transfer requests are still queued, or if the controller hardware + * (usually a FIFO) still holds bytes that the host hasn't collected. + */ +int usb_ep_set_halt(struct usb_ep *ep) +{ + return ep->ops->set_halt(ep, 1); +} +EXPORT_SYMBOL_GPL(usb_ep_set_halt); + +/** + * usb_ep_clear_halt - clears endpoint halt, and resets toggle + * @ep:the bulk or interrupt endpoint being reset + * + * Use this when responding to the standard usb "set interface" request, + * for endpoints that aren't reconfigured, after clearing any other state + * in the endpoint's i/o queue. + * + * Returns zero, or a negative error code. On success, this call clears + * the underlying hardware state reflecting endpoint halt and data toggle. + * Note that some hardware can't support this request (like pxa2xx_udc), + * and accordingly can't correctly implement interface altsettings. + */ +int usb_ep_clear_halt(struct usb_ep *ep) +{ + return ep->ops->set_halt(ep, 0); +} +EXPORT_SYMBOL_GPL(usb_ep_clear_halt); + +/** + * usb_ep_set_wedge - sets the halt feature and ignores clear requests + * @ep: the endpoint being wedged + * + * Use this to stall an endpoint and ignore CLEAR_FEATURE(HALT_ENDPOINT) + * requests. If the gadget driver clears the halt status, it will + * automatically unwedge the endpoint. + * + * Returns zero on success, else negative errno. + */ +int usb_ep_set_wedge(struct usb_ep *ep) +{ + if (ep->ops->set_wedge) + return ep->ops->set_wedge(ep); + else + return ep->ops->set_halt(ep, 1); +} +EXPORT_SYMBOL_GPL(usb_ep_set_wedge); + +/** + * usb_ep_fifo_status - returns number of bytes in fifo, or error + * @ep: the endpoint whose fifo status is being checked. + * + * FIFO endpoints may have "unclaimed data" in them in certain cases, + * such as after aborted transfers. Hosts may not have collected all + * the IN data written by the gadget driver (and reported by a request + * completion). The gadget driver may not have collected all the data + * written OUT to it by the host. Drivers that need precise handling for + * fault reporting or recovery may need to use this call. + * + * This returns the number of such bytes in the fifo, or a negative + * errno if the endpoint doesn't use a FIFO or doesn't support such + * precise handling. + */ +int usb_ep_fifo_status(struct usb_ep *ep) +{ + if (ep->ops->fifo_status) + return ep->ops->fifo_status(ep); + else + return -EOPNOTSUPP; +} +EXPORT_SYMBOL_GPL(usb_ep_fifo_status); + +/** + * usb_ep_fifo_flush - flushes contents of a fifo + * @ep: the endpoint whose fifo is being flushed. + * + * This call may be used to flush the "unclaimed data" that may exist in + * an endpoint fifo after abnormal transaction terminations. The call + * must never be used except when endpoint is not being used for any + * protocol translation. + */ +void usb_ep_fifo_flush(struct usb_ep *ep) +{ + if (ep->ops->fifo_flush) + ep->ops->fifo_flush(ep); +} +EXPORT_SYMBOL_GPL(usb_ep_fifo_flush); + +/* ------------------------------------------------------------------------- */ + +/** + * usb_gadget_frame_number - returns the current frame number + * @gadget: controller that reports the frame number + * + * Returns the usb frame number, normally eleven bits from a SOF packet, + * or negative errno if this device doesn't support this capability. + */ +int usb_gadget_frame_number(struct usb_gadget *gadget) +{ + return gadget->ops->get_frame(gadget); +} +EXPORT_SYMBOL_GPL(usb_gadget_frame_number); + +/** + * usb_gadget_wakeup - tries to wake up the host connected to this gadget + * @gadget: controller used to wake up the host + * + * Returns zero on success, else negative error code if the hardware + * doesn't support such attempts, or its support has not been enabled + * by the usb host. Drivers must return device descriptors that report + * their ability to support this, or hosts won't enable it. + * + * This may also try to use SRP to wake the host and start enumeration, + * even if OTG isn't otherwise in use. OTG devices may also start + * remote wakeup even when hosts don't explicitly enable it. + */ +int usb_gadget_wakeup(struct usb_gadget *gadget) +{ + if (!gadget->ops->wakeup) + return -EOPNOTSUPP; + return gadget->ops->wakeup(gadget); +} +EXPORT_SYMBOL_GPL(usb_gadget_wakeup); + +/** + * usb_gadget_set_selfpowered - sets the device selfpowered feature. + * @gadget:the device being declared as self-powered + * + * this affects the device status reported by the hardware driver + * to reflect that it now has a local power supply. + * + * returns zero on success, else negative errno. + */ +int usb_gadget_set_selfpowered(struct usb_gadget *gadget) +{ + if (!gadget->ops->set_selfpowered) + return -EOPNOTSUPP; + return gadget->ops->set_selfpowered(gadget, 1); +} +EXPORT_SYMBOL_GPL(usb_gadget_set_selfpowered); + +/** + * usb_gadget_clear_selfpowered - clear the device selfpowered feature. + * @gadget:the device being declared as bus-powered + * + * this affects the device status reported by the hardware driver. + * some hardware may not support bus-powered operation, in which + * case this feature's value can never change. + * + * returns zero on success, else negative errno. + */ +int usb_gadget_clear_selfpowered(struct usb_gadget *gadget) +{ + if (!gadget->ops->set_selfpowered) + return -EOPNOTSUPP; + return gadget->ops->set_selfpowered(gadget, 0); +} +EXPORT_SYMBOL_GPL(usb_gadget_clear_selfpowered); + +/** + * usb_gadget_vbus_connect - Notify controller that VBUS is powered + * @gadget:The device which now has VBUS power. + * Context: can sleep + * + * This call is used by a driver for an external transceiver (or GPIO) + * that detects a VBUS power session starting. Common responses include + * resuming the controller, activating the D+ (or D-) pullup to let the + * host detect that a USB device is attached, and starting to draw power + * (8mA or possibly more, especially after SET_CONFIGURATION). + * + * Returns zero on success, else negative errno. + */ +int usb_gadget_vbus_connect(struct usb_gadget *gadget) +{ + if (!gadget->ops->vbus_session) + return -EOPNOTSUPP; + return gadget->ops->vbus_session(gadget, 1); +} +EXPORT_SYMBOL_GPL(usb_gadget_vbus_connect); + +/** + * usb_gadget_vbus_draw - constrain controller's VBUS power usage + * @gadget:The device whose VBUS usage is being described + * @mA:How much current to draw, in milliAmperes. This should be twice + * the value listed in the configuration descriptor bMaxPower field. + * + * This call is used by gadget drivers during SET_CONFIGURATION calls, + * reporting how much power the device may consume. For example, this + * could affect how quickly batteries are recharged. + * + * Returns zero on success, else negative errno. + */ +int usb_gadget_vbus_draw(struct usb_gadget *gadget, unsigned mA) +{ + if (!gadget->ops->vbus_draw) + return -EOPNOTSUPP; + return gadget->ops->vbus_draw(gadget, mA); +} +EXPORT_SYMBOL_GPL(usb_gadget_vbus_draw); + +/** + * usb_gadget_vbus_disconnect - notify controller about VBUS session end + * @gadget:the device whose VBUS supply is being described + * Context: can sleep + * + * This call is used by a driver for an external transceiver (or GPIO) + * that detects a VBUS power session ending. Common responses include + * reversing everything done in usb_gadget_vbus_connect(). + * + * Returns zero on success, else negative errno. + */ +int usb_gadget_vbus_disconnect(struct usb_gadget *gadget) +{ + if (!gadget->ops->vbus_session) + return -EOPNOTSUPP; + return gadget->ops->vbus_session(gadget, 0); +} +EXPORT_SYMBOL_GPL(usb_gadget_vbus_disconnect); + +/** + * usb_gadget_connect - software-controlled connect to USB host + * @gadget:the peripheral being connected + * + * Enables the D+ (or potentially D-) pullup. The host will start + * enumerating this gadget when the pullup is active and a VBUS session + * is active (the link is powered). This pullup is always enabled unless + * usb_gadget_disconnect() has been used to disable it. + * + * Returns zero on success, else negative errno. + */ +int usb_gadget_connect(struct usb_gadget *gadget) +{ + int ret; + + if (!gadget->ops->pullup) + return -EOPNOTSUPP; + + if (gadget->deactivated) { + /* + * If gadget is deactivated we only save new state. + * Gadget will be connected automatically after activation. + */ + gadget->connected = true; + return 0; + } + + ret = gadget->ops->pullup(gadget, 1); + if (!ret) + gadget->connected = 1; + return ret; +} +EXPORT_SYMBOL_GPL(usb_gadget_connect); + +/** + * usb_gadget_disconnect - software-controlled disconnect from USB host + * @gadget:the peripheral being disconnected + * + * Disables the D+ (or potentially D-) pullup, which the host may see + * as a disconnect (when a VBUS session is active). Not all systems + * support software pullup controls. + * + * Returns zero on success, else negative errno. + */ +int usb_gadget_disconnect(struct usb_gadget *gadget) +{ + int ret; + + if (!gadget->ops->pullup) + return -EOPNOTSUPP; + + if (gadget->deactivated) { + /* + * If gadget is deactivated we only save new state. + * Gadget will stay disconnected after activation. + */ + gadget->connected = false; + return 0; + } + + ret = gadget->ops->pullup(gadget, 0); + if (!ret) + gadget->connected = 0; + return ret; +} +EXPORT_SYMBOL_GPL(usb_gadget_disconnect); + +/** + * usb_gadget_deactivate - deactivate function which is not ready to work + * @gadget: the peripheral being deactivated + * + * This routine may be used during the gadget driver bind() call to prevent + * the peripheral from ever being visible to the USB host, unless later + * usb_gadget_activate() is called. For example, user mode components may + * need to be activated before the system can talk to hosts. + * + * Returns zero on success, else negative errno. + */ +int usb_gadget_deactivate(struct usb_gadget *gadget) +{ + int ret; + + if (gadget->deactivated) + return 0; + + if (gadget->connected) { + ret = usb_gadget_disconnect(gadget); + if (ret) + return ret; + /* + * If gadget was being connected before deactivation, we want + * to reconnect it in usb_gadget_activate(). + */ + gadget->connected = true; + } + gadget->deactivated = true; + + return 0; +} +EXPORT_SYMBOL_GPL(usb_gadget_deactivate); + +/** + * usb_gadget_activate - activate function which is not ready to work + * @gadget: the peripheral being activated + * + * This routine activates gadget which was previously deactivated with + * usb_gadget_deactivate() call. It calls usb_gadget_connect() if needed. + * + * Returns zero on success, else negative errno. + */ +int usb_gadget_activate(struct usb_gadget *gadget) +{ + if (!gadget->deactivated) + return 0; + + gadget->deactivated = false; + + /* + * If gadget has been connected before deactivation, or became connected + * while it was being deactivated, we call usb_gadget_connect(). + */ + if (gadget->connected) + return usb_gadget_connect(gadget); + + return 0; +} +EXPORT_SYMBOL_GPL(usb_gadget_activate); + +/* ------------------------------------------------------------------------- */ + #ifdef CONFIG_HAS_DMA int usb_gadget_map_request_by_dev(struct device *dev, diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig index d8f5674..2e710a4 100644 --- a/drivers/usb/host/Kconfig +++ b/drivers/usb/host/Kconfig @@ -180,7 +180,7 @@ config USB_EHCI_MXC config USB_EHCI_HCD_OMAP tristate "EHCI support for OMAP3 and later chips" depends on ARCH_OMAP - select NOP_USB_XCEIV + depends on NOP_USB_XCEIV default y ---help--- Enables support for the on-chip EHCI controller on diff --git a/drivers/usb/phy/Kconfig b/drivers/usb/phy/Kconfig index c690474..b9c409a 100644 --- a/drivers/usb/phy/Kconfig +++ b/drivers/usb/phy/Kconfig @@ -21,6 +21,7 @@ config AB8500_USB config FSL_USB2_OTG bool "Freescale USB OTG Transceiver Driver" depends on USB_EHCI_FSL && USB_FSL_USB2 && USB_OTG_FSM && PM + depends on USB_GADGET || !USB_GADGET # if USB_GADGET=m, this can't be 'y' select USB_PHY help Enable this to support Freescale USB OTG transceiver. @@ -29,6 +30,7 @@ config ISP1301_OMAP tristate "Philips ISP1301 with OMAP OTG" depends on I2C && ARCH_OMAP_OTG depends on USB + depends on USB_GADGET || !USB_GADGET # if USB_GADGET=m, this can't be 'y' select USB_PHY help If you say yes here you get support for the Philips ISP1301 @@ -43,7 +45,7 @@ config ISP1301_OMAP config KEYSTONE_USB_PHY tristate "Keystone USB PHY Driver" depends on ARCH_KEYSTONE || COMPILE_TEST - select NOP_USB_XCEIV + depends on NOP_USB_XCEIV help Enable this to support Keystone USB phy. This driver provides interface to interact with USB 2.0 and USB 3.0 PHY that is part @@ -51,6 +53,7 @@ config KEYSTONE_USB_PHY config NOP_USB_XCEIV tristate "NOP USB Transceiver Driver" + depends on USB_GADGET || !USB_GADGET # if USB_GADGET=m, NOP can't be built-in select USB_PHY help This driver is to be used by all the usb transceiver which are either @@ -63,9 +66,9 @@ config AM335X_CONTROL_USB config AM335X_PHY_USB tristate "AM335x USB PHY Driver" depends on ARM || COMPILE_TEST + depends on NOP_USB_XCEIV select USB_PHY select AM335X_CONTROL_USB - select NOP_USB_XCEIV select USB_COMMON help This driver provides PHY support for that phy which part for the @@ -92,6 +95,7 @@ config TWL6030_USB config USB_GPIO_VBUS tristate "GPIO based peripheral-only VBUS sensing 'transceiver'" depends on GPIOLIB || COMPILE_TEST + depends on USB_GADGET || !USB_GADGET # if USB_GADGET=m, this can't be 'y' select USB_PHY help Provides simple GPIO VBUS sensing for controllers with an @@ -112,6 +116,7 @@ config OMAP_OTG config TAHVO_USB tristate "Tahvo USB transceiver driver" depends on MFD_RETU && EXTCON + depends on USB_GADGET || !USB_GADGET # if USB_GADGET=m, this can't be 'y' select USB_PHY help Enable this to support USB transceiver on Tahvo. This is used @@ -140,6 +145,7 @@ config USB_ISP1301 config USB_MSM_OTG tristate "Qualcomm on-chip USB OTG controller support" depends on (USB || USB_GADGET) && (ARCH_QCOM || COMPILE_TEST) + depends on USB_GADGET || !USB_GADGET # if USB_GADGET=m, this can't be 'y' depends on RESET_CONTROLLER depends on EXTCON select USB_PHY @@ -169,6 +175,7 @@ config USB_QCOM_8X16_PHY config USB_MV_OTG tristate "Marvell USB OTG support" depends on USB_EHCI_MV && USB_MV_UDC && PM && USB_OTG + depends on USB_GADGET || !USB_GADGET # if USB_GADGET=m, this can't be 'y' select USB_PHY help Say Y here if you want to build Marvell USB OTG transciever diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h index fefe8b0..c6e1149 100644 --- a/include/linux/usb/gadget.h +++ b/include/linux/usb/gadget.h @@ -228,307 +228,49 @@ struct usb_ep { /*-------------------------------------------------------------------------*/ -/** - * usb_ep_set_maxpacket_limit - set maximum packet size limit for endpoint - * @ep:the endpoint being configured - * @maxpacket_limit:value of maximum packet size limit - * - * This function should be used only in UDC drivers to initialize endpoint - * (usually in probe function). - */ +#if IS_ENABLED(CONFIG_USB_GADGET) +void usb_ep_set_maxpacket_limit(struct usb_ep *ep, unsigned maxpacket_limit); +int usb_ep_enable(struct usb_ep *ep); +int usb_ep_disable(struct usb_ep *ep); +struct usb_request *usb_ep_alloc_request(struct usb_ep *ep, gfp_t gfp_flags); +void usb_ep_free_request(struct usb_ep *ep, struct usb_request *req); +int usb_ep_queue(struct usb_ep *ep, struct usb_request *req, gfp_t gfp_flags); +int usb_ep_dequeue(struct usb_ep *ep, struct usb_request *req); +int usb_ep_set_halt(struct usb_ep *ep); +int usb_ep_clear_halt(struct usb_ep *ep); +int usb_ep_set_wedge(struct usb_ep *ep); +int usb_ep_fifo_status(struct usb_ep *ep); +void usb_ep_fifo_flush(struct usb_ep *ep); +#else static inline void usb_ep_set_maxpacket_limit(struct usb_ep *ep, - unsigned maxpacket_limit) -{ - ep->maxpacket_limit = maxpacket_limit; - ep->maxpacket = maxpacket_limit; -} - -/** - * usb_ep_enable - configure endpoint, making it usable - * @ep:the endpoint being configured. may not be the endpoint named "ep0". - * drivers discover endpoints through the ep_list of a usb_gadget. - * - * When configurations are set, or when interface settings change, the driver - * will enable or disable the relevant endpoints. while it is enabled, an - * endpoint may be used for i/o until the driver receives a disconnect() from - * the host or until the endpoint is disabled. - * - * the ep0 implementation (which calls this routine) must ensure that the - * hardware capabilities of each endpoint match the descriptor provided - * for it. for example, an endpoint named "ep2in-bulk" would be usable - * for interrupt transfers as well as bulk, but it likely couldn't be used - * for iso transfers or for endpoint 14. some endpoints are fully - * configurable, with more generic names like "ep-a". (remember that for - * USB, "in" means "towards the USB master".) - * - * returns zero, or a negative error code. - */ + unsigned maxpacket_limit) +{ } static inline int usb_ep_enable(struct usb_ep *ep) -{ - int ret; - - if (ep->enabled) - return 0; - - ret = ep->ops->enable(ep, ep->desc); - if (ret) - return ret; - - ep->enabled = true; - - return 0; -} - -/** - * usb_ep_disable - endpoint is no longer usable - * @ep:the endpoint being unconfigured. may not be the endpoint named "ep0". - * - * no other task may be using this endpoint when this is called. - * any pending and uncompleted requests will complete with status - * indicating disconnect (-ESHUTDOWN) before this call returns. - * gadget drivers must call usb_ep_enable() again before queueing - * requests to the endpoint. - * - * returns zero, or a negative error code. - */ +{ return 0; } static inline int usb_ep_disable(struct usb_ep *ep) -{ - int ret; - - if (!ep->enabled) - return 0; - - ret = ep->ops->disable(ep); - if (ret) - return ret; - - ep->enabled = false; - - return 0; -} - -/** - * usb_ep_alloc_request - allocate a request object to use with this endpoint - * @ep:the endpoint to be used with with the request - * @gfp_flags:GFP_* flags to use - * - * Request objects must be allocated with this call, since they normally - * need controller-specific setup and may even need endpoint-specific - * resources such as allocation of DMA descriptors. - * Requests may be submitted with usb_ep_queue(), and receive a single - * completion callback. Free requests with usb_ep_free_request(), when - * they are no longer needed. - * - * Returns the request, or null if one could not be allocated. - */ +{ return 0; } static inline struct usb_request *usb_ep_alloc_request(struct usb_ep *ep, - gfp_t gfp_flags) -{ - return ep->ops->alloc_request(ep, gfp_flags); -} - -/** - * usb_ep_free_request - frees a request object - * @ep:the endpoint associated with the request - * @req:the request being freed - * - * Reverses the effect of usb_ep_alloc_request(). - * Caller guarantees the request is not queued, and that it will - * no longer be requeued (or otherwise used). - */ + gfp_t gfp_flags) +{ return NULL; } static inline void usb_ep_free_request(struct usb_ep *ep, - struct usb_request *req) -{ - ep->ops->free_request(ep, req); -} - -/** - * usb_ep_queue - queues (submits) an I/O request to an endpoint. - * @ep:the endpoint associated with the request - * @req:the request being submitted - * @gfp_flags: GFP_* flags to use in case the lower level driver couldn't - * pre-allocate all necessary memory with the request. - * - * This tells the device controller to perform the specified request through - * that endpoint (reading or writing a buffer). When the request completes, - * including being canceled by usb_ep_dequeue(), the request's completion - * routine is called to return the request to the driver. Any endpoint - * (except control endpoints like ep0) may have more than one transfer - * request queued; they complete in FIFO order. Once a gadget driver - * submits a request, that request may not be examined or modified until it - * is given back to that driver through the completion callback. - * - * Each request is turned into one or more packets. The controller driver - * never merges adjacent requests into the same packet. OUT transfers - * will sometimes use data that's already buffered in the hardware. - * Drivers can rely on the fact that the first byte of the request's buffer - * always corresponds to the first byte of some USB packet, for both - * IN and OUT transfers. - * - * Bulk endpoints can queue any amount of data; the transfer is packetized - * automatically. The last packet will be short if the request doesn't fill it - * out completely. Zero length packets (ZLPs) should be avoided in portable - * protocols since not all usb hardware can successfully handle zero length - * packets. (ZLPs may be explicitly written, and may be implicitly written if - * the request 'zero' flag is set.) Bulk endpoints may also be used - * for interrupt transfers; but the reverse is not true, and some endpoints - * won't support every interrupt transfer. (Such as 768 byte packets.) - * - * Interrupt-only endpoints are less functional than bulk endpoints, for - * example by not supporting queueing or not handling buffers that are - * larger than the endpoint's maxpacket size. They may also treat data - * toggle differently. - * - * Control endpoints ... after getting a setup() callback, the driver queues - * one response (even if it would be zero length). That enables the - * status ack, after transferring data as specified in the response. Setup - * functions may return negative error codes to generate protocol stalls. - * (Note that some USB device controllers disallow protocol stall responses - * in some cases.) When control responses are deferred (the response is - * written after the setup callback returns), then usb_ep_set_halt() may be - * used on ep0 to trigger protocol stalls. Depending on the controller, - * it may not be possible to trigger a status-stage protocol stall when the - * data stage is over, that is, from within the response's completion - * routine. - * - * For periodic endpoints, like interrupt or isochronous ones, the usb host - * arranges to poll once per interval, and the gadget driver usually will - * have queued some data to transfer at that time. - * - * Returns zero, or a negative error code. Endpoints that are not enabled - * report errors; errors will also be - * reported when the usb peripheral is disconnected. - */ -static inline int usb_ep_queue(struct usb_ep *ep, - struct usb_request *req, gfp_t gfp_flags) -{ - if (WARN_ON_ONCE(!ep->enabled && ep->address)) - return -ESHUTDOWN; - - return ep->ops->queue(ep, req, gfp_flags); -} - -/** - * usb_ep_dequeue - dequeues (cancels, unlinks) an I/O request from an endpoint - * @ep:the endpoint associated with the request - * @req:the request being canceled - * - * If the request is still active on the endpoint, it is dequeued and its - * completion routine is called (with status -ECONNRESET); else a negative - * error code is returned. This is guaranteed to happen before the call to - * usb_ep_dequeue() returns. - * - * Note that some hardware can't clear out write fifos (to unlink the request - * at the head of the queue) except as part of disconnecting from usb. Such - * restrictions prevent drivers from supporting configuration changes, - * even to configuration zero (a "chapter 9" requirement). - */ + struct usb_request *req) +{ } +static inline int usb_ep_queue(struct usb_ep *ep, struct usb_request *req, + gfp_t gfp_flags) +{ return 0; } static inline int usb_ep_dequeue(struct usb_ep *ep, struct usb_request *req) -{ - return ep->ops->dequeue(ep, req); -} - -/** - * usb_ep_set_halt - sets the endpoint halt feature. - * @ep: the non-isochronous endpoint being stalled - * - * Use this to stall an endpoint, perhaps as an error report. - * Except for control endpoints, - * the endpoint stays halted (will not stream any data) until the host - * clears this feature; drivers may need to empty the endpoint's request - * queue first, to make sure no inappropriate transfers happen. - * - * Note that while an endpoint CLEAR_FEATURE will be invisible to the - * gadget driver, a SET_INTERFACE will not be. To reset endpoints for the - * current altsetting, see usb_ep_clear_halt(). When switching altsettings, - * it's simplest to use usb_ep_enable() or usb_ep_disable() for the endpoints. - * - * Returns zero, or a negative error code. On success, this call sets - * underlying hardware state that blocks data transfers. - * Attempts to halt IN endpoints will fail (returning -EAGAIN) if any - * transfer requests are still queued, or if the controller hardware - * (usually a FIFO) still holds bytes that the host hasn't collected. - */ +{ return 0; } static inline int usb_ep_set_halt(struct usb_ep *ep) -{ - return ep->ops->set_halt(ep, 1); -} - -/** - * usb_ep_clear_halt - clears endpoint halt, and resets toggle - * @ep:the bulk or interrupt endpoint being reset - * - * Use this when responding to the standard usb "set interface" request, - * for endpoints that aren't reconfigured, after clearing any other state - * in the endpoint's i/o queue. - * - * Returns zero, or a negative error code. On success, this call clears - * the underlying hardware state reflecting endpoint halt and data toggle. - * Note that some hardware can't support this request (like pxa2xx_udc), - * and accordingly can't correctly implement interface altsettings. - */ +{ return 0; } static inline int usb_ep_clear_halt(struct usb_ep *ep) -{ - return ep->ops->set_halt(ep, 0); -} - -/** - * usb_ep_set_wedge - sets the halt feature and ignores clear requests - * @ep: the endpoint being wedged - * - * Use this to stall an endpoint and ignore CLEAR_FEATURE(HALT_ENDPOINT) - * requests. If the gadget driver clears the halt status, it will - * automatically unwedge the endpoint. - * - * Returns zero on success, else negative errno. - */ -static inline int -usb_ep_set_wedge(struct usb_ep *ep) -{ - if (ep->ops->set_wedge) - return ep->ops->set_wedge(ep); - else - return ep->ops->set_halt(ep, 1); -} - -/** - * usb_ep_fifo_status - returns number of bytes in fifo, or error - * @ep: the endpoint whose fifo status is being checked. - * - * FIFO endpoints may have "unclaimed data" in them in certain cases, - * such as after aborted transfers. Hosts may not have collected all - * the IN data written by the gadget driver (and reported by a request - * completion). The gadget driver may not have collected all the data - * written OUT to it by the host. Drivers that need precise handling for - * fault reporting or recovery may need to use this call. - * - * This returns the number of such bytes in the fifo, or a negative - * errno if the endpoint doesn't use a FIFO or doesn't support such - * precise handling. - */ +{ return 0; } +static inline int usb_ep_set_wedge(struct usb_ep *ep) +{ return 0; } static inline int usb_ep_fifo_status(struct usb_ep *ep) -{ - if (ep->ops->fifo_status) - return ep->ops->fifo_status(ep); - else - return -EOPNOTSUPP; -} - -/** - * usb_ep_fifo_flush - flushes contents of a fifo - * @ep: the endpoint whose fifo is being flushed. - * - * This call may be used to flush the "unclaimed data" that may exist in - * an endpoint fifo after abnormal transaction terminations. The call - * must never be used except when endpoint is not being used for any - * protocol translation. - */ +{ return 0; } static inline void usb_ep_fifo_flush(struct usb_ep *ep) -{ - if (ep->ops->fifo_flush) - ep->ops->fifo_flush(ep); -} - +{ } +#endif /* USB_GADGET */ /*-------------------------------------------------------------------------*/ @@ -760,251 +502,44 @@ static inline int gadget_is_otg(struct usb_gadget *g) #endif } -/** - * usb_gadget_frame_number - returns the current frame number - * @gadget: controller that reports the frame number - * - * Returns the usb frame number, normally eleven bits from a SOF packet, - * or negative errno if this device doesn't support this capability. - */ -static inline int usb_gadget_frame_number(struct usb_gadget *gadget) -{ - return gadget->ops->get_frame(gadget); -} +/*-------------------------------------------------------------------------*/ -/** - * usb_gadget_wakeup - tries to wake up the host connected to this gadget - * @gadget: controller used to wake up the host - * - * Returns zero on success, else negative error code if the hardware - * doesn't support such attempts, or its support has not been enabled - * by the usb host. Drivers must return device descriptors that report - * their ability to support this, or hosts won't enable it. - * - * This may also try to use SRP to wake the host and start enumeration, - * even if OTG isn't otherwise in use. OTG devices may also start - * remote wakeup even when hosts don't explicitly enable it. - */ +#if IS_ENABLED(CONFIG_USB_GADGET) +int usb_gadget_frame_number(struct usb_gadget *gadget); +int usb_gadget_wakeup(struct usb_gadget *gadget); +int usb_gadget_set_selfpowered(struct usb_gadget *gadget); +int usb_gadget_clear_selfpowered(struct usb_gadget *gadget); +int usb_gadget_vbus_connect(struct usb_gadget *gadget); +int usb_gadget_vbus_draw(struct usb_gadget *gadget, unsigned mA); +int usb_gadget_vbus_disconnect(struct usb_gadget *gadget); +int usb_gadget_connect(struct usb_gadget *gadget); +int usb_gadget_disconnect(struct usb_gadget *gadget); +int usb_gadget_deactivate(struct usb_gadget *gadget); +int usb_gadget_activate(struct usb_gadget *gadget); +#else +static inline int usb_gadget_frame_number(struct usb_gadget *gadget) +{ return 0; } static inline int usb_gadget_wakeup(struct usb_gadget *gadget) -{ - if (!gadget->ops->wakeup) - return -EOPNOTSUPP; - return gadget->ops->wakeup(gadget); -} - -/** - * usb_gadget_set_selfpowered - sets the device selfpowered feature. - * @gadget:the device being declared as self-powered - * - * this affects the device status reported by the hardware driver - * to reflect that it now has a local power supply. - * - * returns zero on success, else negative errno. - */ +{ return 0; } static inline int usb_gadget_set_selfpowered(struct usb_gadget *gadget) -{ - if (!gadget->ops->set_selfpowered) - return -EOPNOTSUPP; - return gadget->ops->set_selfpowered(gadget, 1); -} - -/** - * usb_gadget_clear_selfpowered - clear the device selfpowered feature. - * @gadget:the device being declared as bus-powered - * - * this affects the device status reported by the hardware driver. - * some hardware may not support bus-powered operation, in which - * case this feature's value can never change. - * - * returns zero on success, else negative errno. - */ +{ return 0; } static inline int usb_gadget_clear_selfpowered(struct usb_gadget *gadget) -{ - if (!gadget->ops->set_selfpowered) - return -EOPNOTSUPP; - return gadget->ops->set_selfpowered(gadget, 0); -} - -/** - * usb_gadget_vbus_connect - Notify controller that VBUS is powered - * @gadget:The device which now has VBUS power. - * Context: can sleep - * - * This call is used by a driver for an external transceiver (or GPIO) - * that detects a VBUS power session starting. Common responses include - * resuming the controller, activating the D+ (or D-) pullup to let the - * host detect that a USB device is attached, and starting to draw power - * (8mA or possibly more, especially after SET_CONFIGURATION). - * - * Returns zero on success, else negative errno. - */ +{ return 0; } static inline int usb_gadget_vbus_connect(struct usb_gadget *gadget) -{ - if (!gadget->ops->vbus_session) - return -EOPNOTSUPP; - return gadget->ops->vbus_session(gadget, 1); -} - -/** - * usb_gadget_vbus_draw - constrain controller's VBUS power usage - * @gadget:The device whose VBUS usage is being described - * @mA:How much current to draw, in milliAmperes. This should be twice - * the value listed in the configuration descriptor bMaxPower field. - * - * This call is used by gadget drivers during SET_CONFIGURATION calls, - * reporting how much power the device may consume. For example, this - * could affect how quickly batteries are recharged. - * - * Returns zero on success, else negative errno. - */ +{ return 0; } static inline int usb_gadget_vbus_draw(struct usb_gadget *gadget, unsigned mA) -{ - if (!gadget->ops->vbus_draw) - return -EOPNOTSUPP; - return gadget->ops->vbus_draw(gadget, mA); -} - -/** - * usb_gadget_vbus_disconnect - notify controller about VBUS session end - * @gadget:the device whose VBUS supply is being described - * Context: can sleep - * - * This call is used by a driver for an external transceiver (or GPIO) - * that detects a VBUS power session ending. Common responses include - * reversing everything done in usb_gadget_vbus_connect(). - * - * Returns zero on success, else negative errno. - */ +{ return 0; } static inline int usb_gadget_vbus_disconnect(struct usb_gadget *gadget) -{ - if (!gadget->ops->vbus_session) - return -EOPNOTSUPP; - return gadget->ops->vbus_session(gadget, 0); -} - -/** - * usb_gadget_connect - software-controlled connect to USB host - * @gadget:the peripheral being connected - * - * Enables the D+ (or potentially D-) pullup. The host will start - * enumerating this gadget when the pullup is active and a VBUS session - * is active (the link is powered). This pullup is always enabled unless - * usb_gadget_disconnect() has been used to disable it. - * - * Returns zero on success, else negative errno. - */ +{ return 0; } static inline int usb_gadget_connect(struct usb_gadget *gadget) -{ - int ret; - - if (!gadget->ops->pullup) - return -EOPNOTSUPP; - - if (gadget->deactivated) { - /* - * If gadget is deactivated we only save new state. - * Gadget will be connected automatically after activation. - */ - gadget->connected = true; - return 0; - } - - ret = gadget->ops->pullup(gadget, 1); - if (!ret) - gadget->connected = 1; - return ret; -} - -/** - * usb_gadget_disconnect - software-controlled disconnect from USB host - * @gadget:the peripheral being disconnected - * - * Disables the D+ (or potentially D-) pullup, which the host may see - * as a disconnect (when a VBUS session is active). Not all systems - * support software pullup controls. - * - * Returns zero on success, else negative errno. - */ +{ return 0; } static inline int usb_gadget_disconnect(struct usb_gadget *gadget) -{ - int ret; - - if (!gadget->ops->pullup) - return -EOPNOTSUPP; - - if (gadget->deactivated) { - /* - * If gadget is deactivated we only save new state. - * Gadget will stay disconnected after activation. - */ - gadget->connected = false; - return 0; - } - - ret = gadget->ops->pullup(gadget, 0); - if (!ret) - gadget->connected = 0; - return ret; -} - -/** - * usb_gadget_deactivate - deactivate function which is not ready to work - * @gadget: the peripheral being deactivated - * - * This routine may be used during the gadget driver bind() call to prevent - * the peripheral from ever being visible to the USB host, unless later - * usb_gadget_activate() is called. For example, user mode components may - * need to be activated before the system can talk to hosts. - * - * Returns zero on success, else negative errno. - */ +{ return 0; } static inline int usb_gadget_deactivate(struct usb_gadget *gadget) -{ - int ret; - - if (gadget->deactivated) - return 0; - - if (gadget->connected) { - ret = usb_gadget_disconnect(gadget); - if (ret) - return ret; - /* - * If gadget was being connected before deactivation, we want - * to reconnect it in usb_gadget_activate(). - */ - gadget->connected = true; - } - gadget->deactivated = true; - - return 0; -} - -/** - * usb_gadget_activate - activate function which is not ready to work - * @gadget: the peripheral being activated - * - * This routine activates gadget which was previously deactivated with - * usb_gadget_deactivate() call. It calls usb_gadget_connect() if needed. - * - * Returns zero on success, else negative errno. - */ +{ return 0; } static inline int usb_gadget_activate(struct usb_gadget *gadget) -{ - if (!gadget->deactivated) - return 0; - - gadget->deactivated = false; - - /* - * If gadget has been connected before deactivation, or became connected - * while it was being deactivated, we call usb_gadget_connect(). - */ - if (gadget->connected) - return usb_gadget_connect(gadget); - - return 0; -} +{ return 0; } +#endif /* CONFIG_USB_GADGET */ /*-------------------------------------------------------------------------*/ -- cgit v0.10.2 From 5e42d710a108c23c104e083900d4ba9398e418b0 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Tue, 31 May 2016 13:39:21 +0300 Subject: usb: gadget: add tracepoints to the gadget API This new set of tracepoints will help all gadget drivers and UDC drivers when problem appears. Note that, in order to be able to add tracepoints to udc-core.c we had to rename that to core.c and statically link it with trace.c to form udc-core.o. This is to make sure that module name stays the same. Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/udc/Makefile b/drivers/usb/gadget/udc/Makefile index dfee534..98e74ed 100644 --- a/drivers/usb/gadget/udc/Makefile +++ b/drivers/usb/gadget/udc/Makefile @@ -1,3 +1,8 @@ +# define_trace.h needs to know how to find our header +CFLAGS_trace.o := -I$(src) + +udc-core-y := core.o trace.o + # # USB peripheral controller drivers # diff --git a/drivers/usb/gadget/udc/core.c b/drivers/usb/gadget/udc/core.c new file mode 100644 index 0000000..ff8685e --- /dev/null +++ b/drivers/usb/gadget/udc/core.c @@ -0,0 +1,1523 @@ +/** + * udc.c - Core UDC Framework + * + * Copyright (C) 2010 Texas Instruments + * Author: Felipe Balbi + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 of + * the License as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "trace.h" + +/** + * struct usb_udc - describes one usb device controller + * @driver - the gadget driver pointer. For use by the class code + * @dev - the child device to the actual controller + * @gadget - the gadget. For use by the class code + * @list - for use by the udc class driver + * @vbus - for udcs who care about vbus status, this value is real vbus status; + * for udcs who do not care about vbus status, this value is always true + * + * This represents the internal data structure which is used by the UDC-class + * to hold information about udc driver and gadget together. + */ +struct usb_udc { + struct usb_gadget_driver *driver; + struct usb_gadget *gadget; + struct device dev; + struct list_head list; + bool vbus; +}; + +static struct class *udc_class; +static LIST_HEAD(udc_list); +static LIST_HEAD(gadget_driver_pending_list); +static DEFINE_MUTEX(udc_lock); + +static int udc_bind_to_driver(struct usb_udc *udc, + struct usb_gadget_driver *driver); + +/* ------------------------------------------------------------------------- */ + +/** + * usb_ep_set_maxpacket_limit - set maximum packet size limit for endpoint + * @ep:the endpoint being configured + * @maxpacket_limit:value of maximum packet size limit + * + * This function should be used only in UDC drivers to initialize endpoint + * (usually in probe function). + */ +void usb_ep_set_maxpacket_limit(struct usb_ep *ep, + unsigned maxpacket_limit) +{ + ep->maxpacket_limit = maxpacket_limit; + ep->maxpacket = maxpacket_limit; + + trace_usb_ep_set_maxpacket_limit(ep, 0); +} +EXPORT_SYMBOL_GPL(usb_ep_set_maxpacket_limit); + +/** + * usb_ep_enable - configure endpoint, making it usable + * @ep:the endpoint being configured. may not be the endpoint named "ep0". + * drivers discover endpoints through the ep_list of a usb_gadget. + * + * When configurations are set, or when interface settings change, the driver + * will enable or disable the relevant endpoints. while it is enabled, an + * endpoint may be used for i/o until the driver receives a disconnect() from + * the host or until the endpoint is disabled. + * + * the ep0 implementation (which calls this routine) must ensure that the + * hardware capabilities of each endpoint match the descriptor provided + * for it. for example, an endpoint named "ep2in-bulk" would be usable + * for interrupt transfers as well as bulk, but it likely couldn't be used + * for iso transfers or for endpoint 14. some endpoints are fully + * configurable, with more generic names like "ep-a". (remember that for + * USB, "in" means "towards the USB master".) + * + * returns zero, or a negative error code. + */ +int usb_ep_enable(struct usb_ep *ep) +{ + int ret = 0; + + if (ep->enabled) + goto out; + + ret = ep->ops->enable(ep, ep->desc); + if (ret) { + ret = ret; + goto out; + } + + ep->enabled = true; + +out: + trace_usb_ep_enable(ep, ret); + + return ret; +} +EXPORT_SYMBOL_GPL(usb_ep_enable); + +/** + * usb_ep_disable - endpoint is no longer usable + * @ep:the endpoint being unconfigured. may not be the endpoint named "ep0". + * + * no other task may be using this endpoint when this is called. + * any pending and uncompleted requests will complete with status + * indicating disconnect (-ESHUTDOWN) before this call returns. + * gadget drivers must call usb_ep_enable() again before queueing + * requests to the endpoint. + * + * returns zero, or a negative error code. + */ +int usb_ep_disable(struct usb_ep *ep) +{ + int ret = 0; + + if (!ep->enabled) + goto out; + + ret = ep->ops->disable(ep); + if (ret) { + ret = ret; + goto out; + } + + ep->enabled = false; + +out: + trace_usb_ep_disable(ep, ret); + + return ret; +} +EXPORT_SYMBOL_GPL(usb_ep_disable); + +/** + * usb_ep_alloc_request - allocate a request object to use with this endpoint + * @ep:the endpoint to be used with with the request + * @gfp_flags:GFP_* flags to use + * + * Request objects must be allocated with this call, since they normally + * need controller-specific setup and may even need endpoint-specific + * resources such as allocation of DMA descriptors. + * Requests may be submitted with usb_ep_queue(), and receive a single + * completion callback. Free requests with usb_ep_free_request(), when + * they are no longer needed. + * + * Returns the request, or null if one could not be allocated. + */ +struct usb_request *usb_ep_alloc_request(struct usb_ep *ep, + gfp_t gfp_flags) +{ + struct usb_request *req = NULL; + + req = ep->ops->alloc_request(ep, gfp_flags); + + trace_usb_ep_alloc_request(ep, req, req ? 0 : -ENOMEM); + + return req; +} +EXPORT_SYMBOL_GPL(usb_ep_alloc_request); + +/** + * usb_ep_free_request - frees a request object + * @ep:the endpoint associated with the request + * @req:the request being freed + * + * Reverses the effect of usb_ep_alloc_request(). + * Caller guarantees the request is not queued, and that it will + * no longer be requeued (or otherwise used). + */ +void usb_ep_free_request(struct usb_ep *ep, + struct usb_request *req) +{ + ep->ops->free_request(ep, req); + trace_usb_ep_free_request(ep, req, 0); +} +EXPORT_SYMBOL_GPL(usb_ep_free_request); + +/** + * usb_ep_queue - queues (submits) an I/O request to an endpoint. + * @ep:the endpoint associated with the request + * @req:the request being submitted + * @gfp_flags: GFP_* flags to use in case the lower level driver couldn't + * pre-allocate all necessary memory with the request. + * + * This tells the device controller to perform the specified request through + * that endpoint (reading or writing a buffer). When the request completes, + * including being canceled by usb_ep_dequeue(), the request's completion + * routine is called to return the request to the driver. Any endpoint + * (except control endpoints like ep0) may have more than one transfer + * request queued; they complete in FIFO order. Once a gadget driver + * submits a request, that request may not be examined or modified until it + * is given back to that driver through the completion callback. + * + * Each request is turned into one or more packets. The controller driver + * never merges adjacent requests into the same packet. OUT transfers + * will sometimes use data that's already buffered in the hardware. + * Drivers can rely on the fact that the first byte of the request's buffer + * always corresponds to the first byte of some USB packet, for both + * IN and OUT transfers. + * + * Bulk endpoints can queue any amount of data; the transfer is packetized + * automatically. The last packet will be short if the request doesn't fill it + * out completely. Zero length packets (ZLPs) should be avoided in portable + * protocols since not all usb hardware can successfully handle zero length + * packets. (ZLPs may be explicitly written, and may be implicitly written if + * the request 'zero' flag is set.) Bulk endpoints may also be used + * for interrupt transfers; but the reverse is not true, and some endpoints + * won't support every interrupt transfer. (Such as 768 byte packets.) + * + * Interrupt-only endpoints are less functional than bulk endpoints, for + * example by not supporting queueing or not handling buffers that are + * larger than the endpoint's maxpacket size. They may also treat data + * toggle differently. + * + * Control endpoints ... after getting a setup() callback, the driver queues + * one response (even if it would be zero length). That enables the + * status ack, after transferring data as specified in the response. Setup + * functions may return negative error codes to generate protocol stalls. + * (Note that some USB device controllers disallow protocol stall responses + * in some cases.) When control responses are deferred (the response is + * written after the setup callback returns), then usb_ep_set_halt() may be + * used on ep0 to trigger protocol stalls. Depending on the controller, + * it may not be possible to trigger a status-stage protocol stall when the + * data stage is over, that is, from within the response's completion + * routine. + * + * For periodic endpoints, like interrupt or isochronous ones, the usb host + * arranges to poll once per interval, and the gadget driver usually will + * have queued some data to transfer at that time. + * + * Returns zero, or a negative error code. Endpoints that are not enabled + * report errors; errors will also be + * reported when the usb peripheral is disconnected. + */ +int usb_ep_queue(struct usb_ep *ep, + struct usb_request *req, gfp_t gfp_flags) +{ + int ret = 0; + + if (WARN_ON_ONCE(!ep->enabled && ep->address)) { + ret = -ESHUTDOWN; + goto out; + } + + ret = ep->ops->queue(ep, req, gfp_flags); + +out: + trace_usb_ep_queue(ep, req, ret); + + return ret; +} +EXPORT_SYMBOL_GPL(usb_ep_queue); + +/** + * usb_ep_dequeue - dequeues (cancels, unlinks) an I/O request from an endpoint + * @ep:the endpoint associated with the request + * @req:the request being canceled + * + * If the request is still active on the endpoint, it is dequeued and its + * completion routine is called (with status -ECONNRESET); else a negative + * error code is returned. This is guaranteed to happen before the call to + * usb_ep_dequeue() returns. + * + * Note that some hardware can't clear out write fifos (to unlink the request + * at the head of the queue) except as part of disconnecting from usb. Such + * restrictions prevent drivers from supporting configuration changes, + * even to configuration zero (a "chapter 9" requirement). + */ +int usb_ep_dequeue(struct usb_ep *ep, struct usb_request *req) +{ + int ret; + + ret = ep->ops->dequeue(ep, req); + trace_usb_ep_dequeue(ep, req, ret); + + return ret; +} +EXPORT_SYMBOL_GPL(usb_ep_dequeue); + +/** + * usb_ep_set_halt - sets the endpoint halt feature. + * @ep: the non-isochronous endpoint being stalled + * + * Use this to stall an endpoint, perhaps as an error report. + * Except for control endpoints, + * the endpoint stays halted (will not stream any data) until the host + * clears this feature; drivers may need to empty the endpoint's request + * queue first, to make sure no inappropriate transfers happen. + * + * Note that while an endpoint CLEAR_FEATURE will be invisible to the + * gadget driver, a SET_INTERFACE will not be. To reset endpoints for the + * current altsetting, see usb_ep_clear_halt(). When switching altsettings, + * it's simplest to use usb_ep_enable() or usb_ep_disable() for the endpoints. + * + * Returns zero, or a negative error code. On success, this call sets + * underlying hardware state that blocks data transfers. + * Attempts to halt IN endpoints will fail (returning -EAGAIN) if any + * transfer requests are still queued, or if the controller hardware + * (usually a FIFO) still holds bytes that the host hasn't collected. + */ +int usb_ep_set_halt(struct usb_ep *ep) +{ + int ret; + + ret = ep->ops->set_halt(ep, 1); + trace_usb_ep_set_halt(ep, ret); + + return ret; +} +EXPORT_SYMBOL_GPL(usb_ep_set_halt); + +/** + * usb_ep_clear_halt - clears endpoint halt, and resets toggle + * @ep:the bulk or interrupt endpoint being reset + * + * Use this when responding to the standard usb "set interface" request, + * for endpoints that aren't reconfigured, after clearing any other state + * in the endpoint's i/o queue. + * + * Returns zero, or a negative error code. On success, this call clears + * the underlying hardware state reflecting endpoint halt and data toggle. + * Note that some hardware can't support this request (like pxa2xx_udc), + * and accordingly can't correctly implement interface altsettings. + */ +int usb_ep_clear_halt(struct usb_ep *ep) +{ + int ret; + + ret = ep->ops->set_halt(ep, 0); + trace_usb_ep_clear_halt(ep, ret); + + return ret; +} +EXPORT_SYMBOL_GPL(usb_ep_clear_halt); + +/** + * usb_ep_set_wedge - sets the halt feature and ignores clear requests + * @ep: the endpoint being wedged + * + * Use this to stall an endpoint and ignore CLEAR_FEATURE(HALT_ENDPOINT) + * requests. If the gadget driver clears the halt status, it will + * automatically unwedge the endpoint. + * + * Returns zero on success, else negative errno. + */ +int usb_ep_set_wedge(struct usb_ep *ep) +{ + int ret; + + if (ep->ops->set_wedge) + ret = ep->ops->set_wedge(ep); + else + ret = ep->ops->set_halt(ep, 1); + + trace_usb_ep_set_wedge(ep, ret); + + return ret; +} +EXPORT_SYMBOL_GPL(usb_ep_set_wedge); + +/** + * usb_ep_fifo_status - returns number of bytes in fifo, or error + * @ep: the endpoint whose fifo status is being checked. + * + * FIFO endpoints may have "unclaimed data" in them in certain cases, + * such as after aborted transfers. Hosts may not have collected all + * the IN data written by the gadget driver (and reported by a request + * completion). The gadget driver may not have collected all the data + * written OUT to it by the host. Drivers that need precise handling for + * fault reporting or recovery may need to use this call. + * + * This returns the number of such bytes in the fifo, or a negative + * errno if the endpoint doesn't use a FIFO or doesn't support such + * precise handling. + */ +int usb_ep_fifo_status(struct usb_ep *ep) +{ + int ret; + + if (ep->ops->fifo_status) + ret = ep->ops->fifo_status(ep); + else + ret = -EOPNOTSUPP; + + trace_usb_ep_fifo_status(ep, ret); + + return ret; +} +EXPORT_SYMBOL_GPL(usb_ep_fifo_status); + +/** + * usb_ep_fifo_flush - flushes contents of a fifo + * @ep: the endpoint whose fifo is being flushed. + * + * This call may be used to flush the "unclaimed data" that may exist in + * an endpoint fifo after abnormal transaction terminations. The call + * must never be used except when endpoint is not being used for any + * protocol translation. + */ +void usb_ep_fifo_flush(struct usb_ep *ep) +{ + if (ep->ops->fifo_flush) + ep->ops->fifo_flush(ep); + + trace_usb_ep_fifo_flush(ep, 0); +} +EXPORT_SYMBOL_GPL(usb_ep_fifo_flush); + +/* ------------------------------------------------------------------------- */ + +/** + * usb_gadget_frame_number - returns the current frame number + * @gadget: controller that reports the frame number + * + * Returns the usb frame number, normally eleven bits from a SOF packet, + * or negative errno if this device doesn't support this capability. + */ +int usb_gadget_frame_number(struct usb_gadget *gadget) +{ + int ret; + + ret = gadget->ops->get_frame(gadget); + + trace_usb_gadget_frame_number(gadget, ret); + + return ret; +} +EXPORT_SYMBOL_GPL(usb_gadget_frame_number); + +/** + * usb_gadget_wakeup - tries to wake up the host connected to this gadget + * @gadget: controller used to wake up the host + * + * Returns zero on success, else negative error code if the hardware + * doesn't support such attempts, or its support has not been enabled + * by the usb host. Drivers must return device descriptors that report + * their ability to support this, or hosts won't enable it. + * + * This may also try to use SRP to wake the host and start enumeration, + * even if OTG isn't otherwise in use. OTG devices may also start + * remote wakeup even when hosts don't explicitly enable it. + */ +int usb_gadget_wakeup(struct usb_gadget *gadget) +{ + int ret = 0; + + if (!gadget->ops->wakeup) { + ret = -EOPNOTSUPP; + goto out; + } + + ret = gadget->ops->wakeup(gadget); + +out: + trace_usb_gadget_wakeup(gadget, ret); + + return ret; +} +EXPORT_SYMBOL_GPL(usb_gadget_wakeup); + +/** + * usb_gadget_set_selfpowered - sets the device selfpowered feature. + * @gadget:the device being declared as self-powered + * + * this affects the device status reported by the hardware driver + * to reflect that it now has a local power supply. + * + * returns zero on success, else negative errno. + */ +int usb_gadget_set_selfpowered(struct usb_gadget *gadget) +{ + int ret = 0; + + if (!gadget->ops->set_selfpowered) { + ret = -EOPNOTSUPP; + goto out; + } + + ret = gadget->ops->set_selfpowered(gadget, 1); + +out: + trace_usb_gadget_set_selfpowered(gadget, ret); + + return ret; +} +EXPORT_SYMBOL_GPL(usb_gadget_set_selfpowered); + +/** + * usb_gadget_clear_selfpowered - clear the device selfpowered feature. + * @gadget:the device being declared as bus-powered + * + * this affects the device status reported by the hardware driver. + * some hardware may not support bus-powered operation, in which + * case this feature's value can never change. + * + * returns zero on success, else negative errno. + */ +int usb_gadget_clear_selfpowered(struct usb_gadget *gadget) +{ + int ret = 0; + + if (!gadget->ops->set_selfpowered) { + ret = -EOPNOTSUPP; + goto out; + } + + ret = gadget->ops->set_selfpowered(gadget, 0); + +out: + trace_usb_gadget_clear_selfpowered(gadget, ret); + + return ret; +} +EXPORT_SYMBOL_GPL(usb_gadget_clear_selfpowered); + +/** + * usb_gadget_vbus_connect - Notify controller that VBUS is powered + * @gadget:The device which now has VBUS power. + * Context: can sleep + * + * This call is used by a driver for an external transceiver (or GPIO) + * that detects a VBUS power session starting. Common responses include + * resuming the controller, activating the D+ (or D-) pullup to let the + * host detect that a USB device is attached, and starting to draw power + * (8mA or possibly more, especially after SET_CONFIGURATION). + * + * Returns zero on success, else negative errno. + */ +int usb_gadget_vbus_connect(struct usb_gadget *gadget) +{ + int ret = 0; + + if (!gadget->ops->vbus_session) { + ret = -EOPNOTSUPP; + goto out; + } + + ret = gadget->ops->vbus_session(gadget, 1); + +out: + trace_usb_gadget_vbus_connect(gadget, ret); + + return ret; +} +EXPORT_SYMBOL_GPL(usb_gadget_vbus_connect); + +/** + * usb_gadget_vbus_draw - constrain controller's VBUS power usage + * @gadget:The device whose VBUS usage is being described + * @mA:How much current to draw, in milliAmperes. This should be twice + * the value listed in the configuration descriptor bMaxPower field. + * + * This call is used by gadget drivers during SET_CONFIGURATION calls, + * reporting how much power the device may consume. For example, this + * could affect how quickly batteries are recharged. + * + * Returns zero on success, else negative errno. + */ +int usb_gadget_vbus_draw(struct usb_gadget *gadget, unsigned mA) +{ + int ret = 0; + + if (!gadget->ops->vbus_draw) { + ret = -EOPNOTSUPP; + goto out; + } + + ret = gadget->ops->vbus_draw(gadget, mA); + if (!ret) + gadget->mA = mA; + +out: + trace_usb_gadget_vbus_draw(gadget, ret); + + return ret; +} +EXPORT_SYMBOL_GPL(usb_gadget_vbus_draw); + +/** + * usb_gadget_vbus_disconnect - notify controller about VBUS session end + * @gadget:the device whose VBUS supply is being described + * Context: can sleep + * + * This call is used by a driver for an external transceiver (or GPIO) + * that detects a VBUS power session ending. Common responses include + * reversing everything done in usb_gadget_vbus_connect(). + * + * Returns zero on success, else negative errno. + */ +int usb_gadget_vbus_disconnect(struct usb_gadget *gadget) +{ + int ret = 0; + + if (!gadget->ops->vbus_session) { + ret = -EOPNOTSUPP; + goto out; + } + + ret = gadget->ops->vbus_session(gadget, 0); + +out: + trace_usb_gadget_vbus_disconnect(gadget, ret); + + return ret; +} +EXPORT_SYMBOL_GPL(usb_gadget_vbus_disconnect); + +/** + * usb_gadget_connect - software-controlled connect to USB host + * @gadget:the peripheral being connected + * + * Enables the D+ (or potentially D-) pullup. The host will start + * enumerating this gadget when the pullup is active and a VBUS session + * is active (the link is powered). This pullup is always enabled unless + * usb_gadget_disconnect() has been used to disable it. + * + * Returns zero on success, else negative errno. + */ +int usb_gadget_connect(struct usb_gadget *gadget) +{ + int ret = 0; + + if (!gadget->ops->pullup) { + ret = -EOPNOTSUPP; + goto out; + } + + if (gadget->deactivated) { + /* + * If gadget is deactivated we only save new state. + * Gadget will be connected automatically after activation. + */ + gadget->connected = true; + goto out; + } + + ret = gadget->ops->pullup(gadget, 1); + if (!ret) + gadget->connected = 1; + +out: + trace_usb_gadget_connect(gadget, ret); + + return ret; +} +EXPORT_SYMBOL_GPL(usb_gadget_connect); + +/** + * usb_gadget_disconnect - software-controlled disconnect from USB host + * @gadget:the peripheral being disconnected + * + * Disables the D+ (or potentially D-) pullup, which the host may see + * as a disconnect (when a VBUS session is active). Not all systems + * support software pullup controls. + * + * Returns zero on success, else negative errno. + */ +int usb_gadget_disconnect(struct usb_gadget *gadget) +{ + int ret = 0; + + if (!gadget->ops->pullup) { + ret = -EOPNOTSUPP; + goto out; + } + + if (gadget->deactivated) { + /* + * If gadget is deactivated we only save new state. + * Gadget will stay disconnected after activation. + */ + gadget->connected = false; + goto out; + } + + ret = gadget->ops->pullup(gadget, 0); + if (!ret) + gadget->connected = 0; + +out: + trace_usb_gadget_disconnect(gadget, ret); + + return ret; +} +EXPORT_SYMBOL_GPL(usb_gadget_disconnect); + +/** + * usb_gadget_deactivate - deactivate function which is not ready to work + * @gadget: the peripheral being deactivated + * + * This routine may be used during the gadget driver bind() call to prevent + * the peripheral from ever being visible to the USB host, unless later + * usb_gadget_activate() is called. For example, user mode components may + * need to be activated before the system can talk to hosts. + * + * Returns zero on success, else negative errno. + */ +int usb_gadget_deactivate(struct usb_gadget *gadget) +{ + int ret = 0; + + if (gadget->deactivated) + goto out; + + if (gadget->connected) { + ret = usb_gadget_disconnect(gadget); + if (ret) + goto out; + + /* + * If gadget was being connected before deactivation, we want + * to reconnect it in usb_gadget_activate(). + */ + gadget->connected = true; + } + gadget->deactivated = true; + +out: + trace_usb_gadget_deactivate(gadget, ret); + + return ret; +} +EXPORT_SYMBOL_GPL(usb_gadget_deactivate); + +/** + * usb_gadget_activate - activate function which is not ready to work + * @gadget: the peripheral being activated + * + * This routine activates gadget which was previously deactivated with + * usb_gadget_deactivate() call. It calls usb_gadget_connect() if needed. + * + * Returns zero on success, else negative errno. + */ +int usb_gadget_activate(struct usb_gadget *gadget) +{ + int ret = 0; + + if (!gadget->deactivated) + goto out; + + gadget->deactivated = false; + + /* + * If gadget has been connected before deactivation, or became connected + * while it was being deactivated, we call usb_gadget_connect(). + */ + if (gadget->connected) + ret = usb_gadget_connect(gadget); + +out: + trace_usb_gadget_activate(gadget, ret); + + return ret; +} +EXPORT_SYMBOL_GPL(usb_gadget_activate); + +/* ------------------------------------------------------------------------- */ + +#ifdef CONFIG_HAS_DMA + +int usb_gadget_map_request_by_dev(struct device *dev, + struct usb_request *req, int is_in) +{ + if (req->length == 0) + return 0; + + if (req->num_sgs) { + int mapped; + + mapped = dma_map_sg(dev, req->sg, req->num_sgs, + is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE); + if (mapped == 0) { + dev_err(dev, "failed to map SGs\n"); + return -EFAULT; + } + + req->num_mapped_sgs = mapped; + } else { + req->dma = dma_map_single(dev, req->buf, req->length, + is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE); + + if (dma_mapping_error(dev, req->dma)) { + dev_err(dev, "failed to map buffer\n"); + return -EFAULT; + } + } + + return 0; +} +EXPORT_SYMBOL_GPL(usb_gadget_map_request_by_dev); + +int usb_gadget_map_request(struct usb_gadget *gadget, + struct usb_request *req, int is_in) +{ + return usb_gadget_map_request_by_dev(gadget->dev.parent, req, is_in); +} +EXPORT_SYMBOL_GPL(usb_gadget_map_request); + +void usb_gadget_unmap_request_by_dev(struct device *dev, + struct usb_request *req, int is_in) +{ + if (req->length == 0) + return; + + if (req->num_mapped_sgs) { + dma_unmap_sg(dev, req->sg, req->num_mapped_sgs, + is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE); + + req->num_mapped_sgs = 0; + } else { + dma_unmap_single(dev, req->dma, req->length, + is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE); + } +} +EXPORT_SYMBOL_GPL(usb_gadget_unmap_request_by_dev); + +void usb_gadget_unmap_request(struct usb_gadget *gadget, + struct usb_request *req, int is_in) +{ + usb_gadget_unmap_request_by_dev(gadget->dev.parent, req, is_in); +} +EXPORT_SYMBOL_GPL(usb_gadget_unmap_request); + +#endif /* CONFIG_HAS_DMA */ + +/* ------------------------------------------------------------------------- */ + +/** + * usb_gadget_giveback_request - give the request back to the gadget layer + * Context: in_interrupt() + * + * This is called by device controller drivers in order to return the + * completed request back to the gadget layer. + */ +void usb_gadget_giveback_request(struct usb_ep *ep, + struct usb_request *req) +{ + if (likely(req->status == 0)) + usb_led_activity(USB_LED_EVENT_GADGET); + + trace_usb_gadget_giveback_request(ep, req, 0); + + req->complete(ep, req); +} +EXPORT_SYMBOL_GPL(usb_gadget_giveback_request); + +/* ------------------------------------------------------------------------- */ + +/** + * gadget_find_ep_by_name - returns ep whose name is the same as sting passed + * in second parameter or NULL if searched endpoint not found + * @g: controller to check for quirk + * @name: name of searched endpoint + */ +struct usb_ep *gadget_find_ep_by_name(struct usb_gadget *g, const char *name) +{ + struct usb_ep *ep; + + gadget_for_each_ep(ep, g) { + if (!strcmp(ep->name, name)) + return ep; + } + + return NULL; +} +EXPORT_SYMBOL_GPL(gadget_find_ep_by_name); + +/* ------------------------------------------------------------------------- */ + +int usb_gadget_ep_match_desc(struct usb_gadget *gadget, + struct usb_ep *ep, struct usb_endpoint_descriptor *desc, + struct usb_ss_ep_comp_descriptor *ep_comp) +{ + u8 type; + u16 max; + int num_req_streams = 0; + + /* endpoint already claimed? */ + if (ep->claimed) + return 0; + + type = usb_endpoint_type(desc); + max = 0x7ff & usb_endpoint_maxp(desc); + + if (usb_endpoint_dir_in(desc) && !ep->caps.dir_in) + return 0; + if (usb_endpoint_dir_out(desc) && !ep->caps.dir_out) + return 0; + + if (max > ep->maxpacket_limit) + return 0; + + /* "high bandwidth" works only at high speed */ + if (!gadget_is_dualspeed(gadget) && usb_endpoint_maxp(desc) & (3<<11)) + return 0; + + switch (type) { + case USB_ENDPOINT_XFER_CONTROL: + /* only support ep0 for portable CONTROL traffic */ + return 0; + case USB_ENDPOINT_XFER_ISOC: + if (!ep->caps.type_iso) + return 0; + /* ISO: limit 1023 bytes full speed, 1024 high/super speed */ + if (!gadget_is_dualspeed(gadget) && max > 1023) + return 0; + break; + case USB_ENDPOINT_XFER_BULK: + if (!ep->caps.type_bulk) + return 0; + if (ep_comp && gadget_is_superspeed(gadget)) { + /* Get the number of required streams from the + * EP companion descriptor and see if the EP + * matches it + */ + num_req_streams = ep_comp->bmAttributes & 0x1f; + if (num_req_streams > ep->max_streams) + return 0; + } + break; + case USB_ENDPOINT_XFER_INT: + /* Bulk endpoints handle interrupt transfers, + * except the toggle-quirky iso-synch kind + */ + if (!ep->caps.type_int && !ep->caps.type_bulk) + return 0; + /* INT: limit 64 bytes full speed, 1024 high/super speed */ + if (!gadget_is_dualspeed(gadget) && max > 64) + return 0; + break; + } + + return 1; +} +EXPORT_SYMBOL_GPL(usb_gadget_ep_match_desc); + +/* ------------------------------------------------------------------------- */ + +static void usb_gadget_state_work(struct work_struct *work) +{ + struct usb_gadget *gadget = work_to_gadget(work); + struct usb_udc *udc = gadget->udc; + + if (udc) + sysfs_notify(&udc->dev.kobj, NULL, "state"); +} + +void usb_gadget_set_state(struct usb_gadget *gadget, + enum usb_device_state state) +{ + gadget->state = state; + schedule_work(&gadget->work); +} +EXPORT_SYMBOL_GPL(usb_gadget_set_state); + +/* ------------------------------------------------------------------------- */ + +static void usb_udc_connect_control(struct usb_udc *udc) +{ + if (udc->vbus) + usb_gadget_connect(udc->gadget); + else + usb_gadget_disconnect(udc->gadget); +} + +/** + * usb_udc_vbus_handler - updates the udc core vbus status, and try to + * connect or disconnect gadget + * @gadget: The gadget which vbus change occurs + * @status: The vbus status + * + * The udc driver calls it when it wants to connect or disconnect gadget + * according to vbus status. + */ +void usb_udc_vbus_handler(struct usb_gadget *gadget, bool status) +{ + struct usb_udc *udc = gadget->udc; + + if (udc) { + udc->vbus = status; + usb_udc_connect_control(udc); + } +} +EXPORT_SYMBOL_GPL(usb_udc_vbus_handler); + +/** + * usb_gadget_udc_reset - notifies the udc core that bus reset occurs + * @gadget: The gadget which bus reset occurs + * @driver: The gadget driver we want to notify + * + * If the udc driver has bus reset handler, it needs to call this when the bus + * reset occurs, it notifies the gadget driver that the bus reset occurs as + * well as updates gadget state. + */ +void usb_gadget_udc_reset(struct usb_gadget *gadget, + struct usb_gadget_driver *driver) +{ + driver->reset(gadget); + usb_gadget_set_state(gadget, USB_STATE_DEFAULT); +} +EXPORT_SYMBOL_GPL(usb_gadget_udc_reset); + +/** + * usb_gadget_udc_start - tells usb device controller to start up + * @udc: The UDC to be started + * + * This call is issued by the UDC Class driver when it's about + * to register a gadget driver to the device controller, before + * calling gadget driver's bind() method. + * + * It allows the controller to be powered off until strictly + * necessary to have it powered on. + * + * Returns zero on success, else negative errno. + */ +static inline int usb_gadget_udc_start(struct usb_udc *udc) +{ + return udc->gadget->ops->udc_start(udc->gadget, udc->driver); +} + +/** + * usb_gadget_udc_stop - tells usb device controller we don't need it anymore + * @gadget: The device we want to stop activity + * @driver: The driver to unbind from @gadget + * + * This call is issued by the UDC Class driver after calling + * gadget driver's unbind() method. + * + * The details are implementation specific, but it can go as + * far as powering off UDC completely and disable its data + * line pullups. + */ +static inline void usb_gadget_udc_stop(struct usb_udc *udc) +{ + udc->gadget->ops->udc_stop(udc->gadget); +} + +/** + * usb_udc_release - release the usb_udc struct + * @dev: the dev member within usb_udc + * + * This is called by driver's core in order to free memory once the last + * reference is released. + */ +static void usb_udc_release(struct device *dev) +{ + struct usb_udc *udc; + + udc = container_of(dev, struct usb_udc, dev); + dev_dbg(dev, "releasing '%s'\n", dev_name(dev)); + kfree(udc); +} + +static const struct attribute_group *usb_udc_attr_groups[]; + +static void usb_udc_nop_release(struct device *dev) +{ + dev_vdbg(dev, "%s\n", __func__); +} + +/** + * usb_add_gadget_udc_release - adds a new gadget to the udc class driver list + * @parent: the parent device to this udc. Usually the controller driver's + * device. + * @gadget: the gadget to be added to the list. + * @release: a gadget release function. + * + * Returns zero on success, negative errno otherwise. + */ +int usb_add_gadget_udc_release(struct device *parent, struct usb_gadget *gadget, + void (*release)(struct device *dev)) +{ + struct usb_udc *udc; + struct usb_gadget_driver *driver; + int ret = -ENOMEM; + + udc = kzalloc(sizeof(*udc), GFP_KERNEL); + if (!udc) + goto err1; + + dev_set_name(&gadget->dev, "gadget"); + INIT_WORK(&gadget->work, usb_gadget_state_work); + gadget->dev.parent = parent; + + if (release) + gadget->dev.release = release; + else + gadget->dev.release = usb_udc_nop_release; + + ret = device_register(&gadget->dev); + if (ret) + goto err2; + + device_initialize(&udc->dev); + udc->dev.release = usb_udc_release; + udc->dev.class = udc_class; + udc->dev.groups = usb_udc_attr_groups; + udc->dev.parent = parent; + ret = dev_set_name(&udc->dev, "%s", kobject_name(&parent->kobj)); + if (ret) + goto err3; + + udc->gadget = gadget; + gadget->udc = udc; + + mutex_lock(&udc_lock); + list_add_tail(&udc->list, &udc_list); + + ret = device_add(&udc->dev); + if (ret) + goto err4; + + usb_gadget_set_state(gadget, USB_STATE_NOTATTACHED); + udc->vbus = true; + + /* pick up one of pending gadget drivers */ + list_for_each_entry(driver, &gadget_driver_pending_list, pending) { + if (!driver->udc_name || strcmp(driver->udc_name, + dev_name(&udc->dev)) == 0) { + ret = udc_bind_to_driver(udc, driver); + if (ret != -EPROBE_DEFER) + list_del(&driver->pending); + if (ret) + goto err4; + break; + } + } + + mutex_unlock(&udc_lock); + + return 0; + +err4: + list_del(&udc->list); + mutex_unlock(&udc_lock); + +err3: + put_device(&udc->dev); + device_del(&gadget->dev); + +err2: + put_device(&gadget->dev); + kfree(udc); + +err1: + return ret; +} +EXPORT_SYMBOL_GPL(usb_add_gadget_udc_release); + +/** + * usb_get_gadget_udc_name - get the name of the first UDC controller + * This functions returns the name of the first UDC controller in the system. + * Please note that this interface is usefull only for legacy drivers which + * assume that there is only one UDC controller in the system and they need to + * get its name before initialization. There is no guarantee that the UDC + * of the returned name will be still available, when gadget driver registers + * itself. + * + * Returns pointer to string with UDC controller name on success, NULL + * otherwise. Caller should kfree() returned string. + */ +char *usb_get_gadget_udc_name(void) +{ + struct usb_udc *udc; + char *name = NULL; + + /* For now we take the first available UDC */ + mutex_lock(&udc_lock); + list_for_each_entry(udc, &udc_list, list) { + if (!udc->driver) { + name = kstrdup(udc->gadget->name, GFP_KERNEL); + break; + } + } + mutex_unlock(&udc_lock); + return name; +} +EXPORT_SYMBOL_GPL(usb_get_gadget_udc_name); + +/** + * usb_add_gadget_udc - adds a new gadget to the udc class driver list + * @parent: the parent device to this udc. Usually the controller + * driver's device. + * @gadget: the gadget to be added to the list + * + * Returns zero on success, negative errno otherwise. + */ +int usb_add_gadget_udc(struct device *parent, struct usb_gadget *gadget) +{ + return usb_add_gadget_udc_release(parent, gadget, NULL); +} +EXPORT_SYMBOL_GPL(usb_add_gadget_udc); + +static void usb_gadget_remove_driver(struct usb_udc *udc) +{ + dev_dbg(&udc->dev, "unregistering UDC driver [%s]\n", + udc->driver->function); + + kobject_uevent(&udc->dev.kobj, KOBJ_CHANGE); + + usb_gadget_disconnect(udc->gadget); + udc->driver->disconnect(udc->gadget); + udc->driver->unbind(udc->gadget); + usb_gadget_udc_stop(udc); + + udc->driver = NULL; + udc->dev.driver = NULL; + udc->gadget->dev.driver = NULL; +} + +/** + * usb_del_gadget_udc - deletes @udc from udc_list + * @gadget: the gadget to be removed. + * + * This, will call usb_gadget_unregister_driver() if + * the @udc is still busy. + */ +void usb_del_gadget_udc(struct usb_gadget *gadget) +{ + struct usb_udc *udc = gadget->udc; + + if (!udc) + return; + + dev_vdbg(gadget->dev.parent, "unregistering gadget\n"); + + mutex_lock(&udc_lock); + list_del(&udc->list); + + if (udc->driver) { + struct usb_gadget_driver *driver = udc->driver; + + usb_gadget_remove_driver(udc); + list_add(&driver->pending, &gadget_driver_pending_list); + } + mutex_unlock(&udc_lock); + + kobject_uevent(&udc->dev.kobj, KOBJ_REMOVE); + flush_work(&gadget->work); + device_unregister(&udc->dev); + device_unregister(&gadget->dev); +} +EXPORT_SYMBOL_GPL(usb_del_gadget_udc); + +/* ------------------------------------------------------------------------- */ + +static int udc_bind_to_driver(struct usb_udc *udc, struct usb_gadget_driver *driver) +{ + int ret; + + dev_dbg(&udc->dev, "registering UDC driver [%s]\n", + driver->function); + + udc->driver = driver; + udc->dev.driver = &driver->driver; + udc->gadget->dev.driver = &driver->driver; + + ret = driver->bind(udc->gadget, driver); + if (ret) + goto err1; + ret = usb_gadget_udc_start(udc); + if (ret) { + driver->unbind(udc->gadget); + goto err1; + } + usb_udc_connect_control(udc); + + kobject_uevent(&udc->dev.kobj, KOBJ_CHANGE); + return 0; +err1: + if (ret != -EISNAM) + dev_err(&udc->dev, "failed to start %s: %d\n", + udc->driver->function, ret); + udc->driver = NULL; + udc->dev.driver = NULL; + udc->gadget->dev.driver = NULL; + return ret; +} + +int usb_gadget_probe_driver(struct usb_gadget_driver *driver) +{ + struct usb_udc *udc = NULL; + int ret = -ENODEV; + + if (!driver || !driver->bind || !driver->setup) + return -EINVAL; + + mutex_lock(&udc_lock); + if (driver->udc_name) { + list_for_each_entry(udc, &udc_list, list) { + ret = strcmp(driver->udc_name, dev_name(&udc->dev)); + if (!ret) + break; + } + if (!ret && !udc->driver) + goto found; + } else { + list_for_each_entry(udc, &udc_list, list) { + /* For now we take the first one */ + if (!udc->driver) + goto found; + } + } + + if (!driver->match_existing_only) { + list_add_tail(&driver->pending, &gadget_driver_pending_list); + pr_info("udc-core: couldn't find an available UDC - added [%s] to list of pending drivers\n", + driver->function); + ret = 0; + } + + mutex_unlock(&udc_lock); + return ret; +found: + ret = udc_bind_to_driver(udc, driver); + mutex_unlock(&udc_lock); + return ret; +} +EXPORT_SYMBOL_GPL(usb_gadget_probe_driver); + +int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) +{ + struct usb_udc *udc = NULL; + int ret = -ENODEV; + + if (!driver || !driver->unbind) + return -EINVAL; + + mutex_lock(&udc_lock); + list_for_each_entry(udc, &udc_list, list) + if (udc->driver == driver) { + usb_gadget_remove_driver(udc); + usb_gadget_set_state(udc->gadget, + USB_STATE_NOTATTACHED); + ret = 0; + break; + } + + if (ret) { + list_del(&driver->pending); + ret = 0; + } + mutex_unlock(&udc_lock); + return ret; +} +EXPORT_SYMBOL_GPL(usb_gadget_unregister_driver); + +/* ------------------------------------------------------------------------- */ + +static ssize_t usb_udc_srp_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t n) +{ + struct usb_udc *udc = container_of(dev, struct usb_udc, dev); + + if (sysfs_streq(buf, "1")) + usb_gadget_wakeup(udc->gadget); + + return n; +} +static DEVICE_ATTR(srp, S_IWUSR, NULL, usb_udc_srp_store); + +static ssize_t usb_udc_softconn_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t n) +{ + struct usb_udc *udc = container_of(dev, struct usb_udc, dev); + + if (!udc->driver) { + dev_err(dev, "soft-connect without a gadget driver\n"); + return -EOPNOTSUPP; + } + + if (sysfs_streq(buf, "connect")) { + usb_gadget_udc_start(udc); + usb_gadget_connect(udc->gadget); + } else if (sysfs_streq(buf, "disconnect")) { + usb_gadget_disconnect(udc->gadget); + udc->driver->disconnect(udc->gadget); + usb_gadget_udc_stop(udc); + } else { + dev_err(dev, "unsupported command '%s'\n", buf); + return -EINVAL; + } + + return n; +} +static DEVICE_ATTR(soft_connect, S_IWUSR, NULL, usb_udc_softconn_store); + +static ssize_t state_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct usb_udc *udc = container_of(dev, struct usb_udc, dev); + struct usb_gadget *gadget = udc->gadget; + + return sprintf(buf, "%s\n", usb_state_string(gadget->state)); +} +static DEVICE_ATTR_RO(state); + +#define USB_UDC_SPEED_ATTR(name, param) \ +ssize_t name##_show(struct device *dev, \ + struct device_attribute *attr, char *buf) \ +{ \ + struct usb_udc *udc = container_of(dev, struct usb_udc, dev); \ + return snprintf(buf, PAGE_SIZE, "%s\n", \ + usb_speed_string(udc->gadget->param)); \ +} \ +static DEVICE_ATTR_RO(name) + +static USB_UDC_SPEED_ATTR(current_speed, speed); +static USB_UDC_SPEED_ATTR(maximum_speed, max_speed); + +#define USB_UDC_ATTR(name) \ +ssize_t name##_show(struct device *dev, \ + struct device_attribute *attr, char *buf) \ +{ \ + struct usb_udc *udc = container_of(dev, struct usb_udc, dev); \ + struct usb_gadget *gadget = udc->gadget; \ + \ + return snprintf(buf, PAGE_SIZE, "%d\n", gadget->name); \ +} \ +static DEVICE_ATTR_RO(name) + +static USB_UDC_ATTR(is_otg); +static USB_UDC_ATTR(is_a_peripheral); +static USB_UDC_ATTR(b_hnp_enable); +static USB_UDC_ATTR(a_hnp_support); +static USB_UDC_ATTR(a_alt_hnp_support); +static USB_UDC_ATTR(is_selfpowered); + +static struct attribute *usb_udc_attrs[] = { + &dev_attr_srp.attr, + &dev_attr_soft_connect.attr, + &dev_attr_state.attr, + &dev_attr_current_speed.attr, + &dev_attr_maximum_speed.attr, + + &dev_attr_is_otg.attr, + &dev_attr_is_a_peripheral.attr, + &dev_attr_b_hnp_enable.attr, + &dev_attr_a_hnp_support.attr, + &dev_attr_a_alt_hnp_support.attr, + &dev_attr_is_selfpowered.attr, + NULL, +}; + +static const struct attribute_group usb_udc_attr_group = { + .attrs = usb_udc_attrs, +}; + +static const struct attribute_group *usb_udc_attr_groups[] = { + &usb_udc_attr_group, + NULL, +}; + +static int usb_udc_uevent(struct device *dev, struct kobj_uevent_env *env) +{ + struct usb_udc *udc = container_of(dev, struct usb_udc, dev); + int ret; + + ret = add_uevent_var(env, "USB_UDC_NAME=%s", udc->gadget->name); + if (ret) { + dev_err(dev, "failed to add uevent USB_UDC_NAME\n"); + return ret; + } + + if (udc->driver) { + ret = add_uevent_var(env, "USB_UDC_DRIVER=%s", + udc->driver->function); + if (ret) { + dev_err(dev, "failed to add uevent USB_UDC_DRIVER\n"); + return ret; + } + } + + return 0; +} + +static int __init usb_udc_init(void) +{ + udc_class = class_create(THIS_MODULE, "udc"); + if (IS_ERR(udc_class)) { + pr_err("failed to create udc class --> %ld\n", + PTR_ERR(udc_class)); + return PTR_ERR(udc_class); + } + + udc_class->dev_uevent = usb_udc_uevent; + return 0; +} +subsys_initcall(usb_udc_init); + +static void __exit usb_udc_exit(void) +{ + class_destroy(udc_class); +} +module_exit(usb_udc_exit); + +MODULE_DESCRIPTION("UDC Framework"); +MODULE_AUTHOR("Felipe Balbi "); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/usb/gadget/udc/trace.c b/drivers/usb/gadget/udc/trace.c new file mode 100644 index 0000000..8c551ab --- /dev/null +++ b/drivers/usb/gadget/udc/trace.c @@ -0,0 +1,18 @@ +/** + * trace.c - USB Gadget Framework Trace Support + * + * Copyright (C) 2016 Intel Corporation + * Author: Felipe Balbi + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 of + * the License as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#define CREATE_TRACE_POINTS +#include "trace.h" diff --git a/drivers/usb/gadget/udc/trace.h b/drivers/usb/gadget/udc/trace.h new file mode 100644 index 0000000..da29874 --- /dev/null +++ b/drivers/usb/gadget/udc/trace.h @@ -0,0 +1,298 @@ +/** + * udc.c - Core UDC Framework + * + * Copyright (C) 2016 Intel Corporation + * Author: Felipe Balbi + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 of + * the License as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#undef TRACE_SYSTEM +#define TRACE_SYSTEM gadget + +#if !defined(__UDC_TRACE_H) || defined(TRACE_HEADER_MULTI_READ) +#define __UDC_TRACE_H + +#include +#include +#include +#include + +DECLARE_EVENT_CLASS(udc_log_gadget, + TP_PROTO(struct usb_gadget *g, int ret), + TP_ARGS(g, ret), + TP_STRUCT__entry( + __field(enum usb_device_speed, speed) + __field(enum usb_device_speed, max_speed) + __field(enum usb_device_state, state) + __field(unsigned, mA) + __field(unsigned, sg_supported) + __field(unsigned, is_otg) + __field(unsigned, is_a_peripheral) + __field(unsigned, b_hnp_enable) + __field(unsigned, a_hnp_support) + __field(unsigned, hnp_polling_support) + __field(unsigned, host_request_flag) + __field(unsigned, quirk_ep_out_aligned_size) + __field(unsigned, quirk_altset_not_supp) + __field(unsigned, quirk_stall_not_supp) + __field(unsigned, quirk_zlp_not_supp) + __field(unsigned, is_selfpowered) + __field(unsigned, deactivated) + __field(unsigned, connected) + __field(int, ret) + ), + TP_fast_assign( + __entry->speed = g->speed; + __entry->max_speed = g->max_speed; + __entry->state = g->state; + __entry->mA = g->mA; + __entry->sg_supported = g->sg_supported; + __entry->is_otg = g->is_otg; + __entry->is_a_peripheral = g->is_a_peripheral; + __entry->b_hnp_enable = g->b_hnp_enable; + __entry->a_hnp_support = g->a_hnp_support; + __entry->hnp_polling_support = g->hnp_polling_support; + __entry->host_request_flag = g->host_request_flag; + __entry->quirk_ep_out_aligned_size = g->quirk_ep_out_aligned_size; + __entry->quirk_altset_not_supp = g->quirk_altset_not_supp; + __entry->quirk_stall_not_supp = g->quirk_stall_not_supp; + __entry->quirk_zlp_not_supp = g->quirk_zlp_not_supp; + __entry->is_selfpowered = g->is_selfpowered; + __entry->deactivated = g->deactivated; + __entry->connected = g->connected; + __entry->ret = ret; + ), + TP_printk("speed %d/%d state %d %dmA [%s%s%s%s%s%s%s%s%s%s%s%s%s%s] --> %d", + __entry->speed, __entry->max_speed, __entry->state, __entry->mA, + __entry->sg_supported ? "sg:" : "", + __entry->is_otg ? "OTG:" : "", + __entry->is_a_peripheral ? "a_peripheral:" : "", + __entry->b_hnp_enable ? "b_hnp:" : "", + __entry->a_hnp_support ? "a_hnp:" : "", + __entry->hnp_polling_support ? "hnp_poll:" : "", + __entry->host_request_flag ? "hostreq:" : "", + __entry->quirk_ep_out_aligned_size ? "out_aligned:" : "", + __entry->quirk_altset_not_supp ? "no_altset:" : "", + __entry->quirk_stall_not_supp ? "no_stall:" : "", + __entry->quirk_zlp_not_supp ? "no_zlp" : "", + __entry->is_selfpowered ? "self-powered:" : "bus-powered:", + __entry->deactivated ? "deactivated:" : "activated:", + __entry->connected ? "connected" : "disconnected", + __entry->ret) +); + +DEFINE_EVENT(udc_log_gadget, usb_gadget_frame_number, + TP_PROTO(struct usb_gadget *g, int ret), + TP_ARGS(g, ret) +); + +DEFINE_EVENT(udc_log_gadget, usb_gadget_wakeup, + TP_PROTO(struct usb_gadget *g, int ret), + TP_ARGS(g, ret) +); + +DEFINE_EVENT(udc_log_gadget, usb_gadget_set_selfpowered, + TP_PROTO(struct usb_gadget *g, int ret), + TP_ARGS(g, ret) +); + +DEFINE_EVENT(udc_log_gadget, usb_gadget_clear_selfpowered, + TP_PROTO(struct usb_gadget *g, int ret), + TP_ARGS(g, ret) +); + +DEFINE_EVENT(udc_log_gadget, usb_gadget_vbus_connect, + TP_PROTO(struct usb_gadget *g, int ret), + TP_ARGS(g, ret) +); + +DEFINE_EVENT(udc_log_gadget, usb_gadget_vbus_draw, + TP_PROTO(struct usb_gadget *g, int ret), + TP_ARGS(g, ret) +); + +DEFINE_EVENT(udc_log_gadget, usb_gadget_vbus_disconnect, + TP_PROTO(struct usb_gadget *g, int ret), + TP_ARGS(g, ret) +); + +DEFINE_EVENT(udc_log_gadget, usb_gadget_connect, + TP_PROTO(struct usb_gadget *g, int ret), + TP_ARGS(g, ret) +); + +DEFINE_EVENT(udc_log_gadget, usb_gadget_disconnect, + TP_PROTO(struct usb_gadget *g, int ret), + TP_ARGS(g, ret) +); + +DEFINE_EVENT(udc_log_gadget, usb_gadget_deactivate, + TP_PROTO(struct usb_gadget *g, int ret), + TP_ARGS(g, ret) +); + +DEFINE_EVENT(udc_log_gadget, usb_gadget_activate, + TP_PROTO(struct usb_gadget *g, int ret), + TP_ARGS(g, ret) +); + +DECLARE_EVENT_CLASS(udc_log_ep, + TP_PROTO(struct usb_ep *ep, int ret), + TP_ARGS(ep, ret), + TP_STRUCT__entry( + __dynamic_array(char, name, UDC_TRACE_STR_MAX) + __field(unsigned, maxpacket) + __field(unsigned, maxpacket_limit) + __field(unsigned, max_streams) + __field(unsigned, mult) + __field(unsigned, maxburst) + __field(u8, address) + __field(bool, claimed) + __field(bool, enabled) + __field(int, ret) + ), + TP_fast_assign( + snprintf(__get_str(name), UDC_TRACE_STR_MAX, "%s", ep->name); + __entry->maxpacket = ep->maxpacket; + __entry->maxpacket_limit = ep->maxpacket_limit; + __entry->max_streams = ep->max_streams; + __entry->mult = ep->mult; + __entry->maxburst = ep->maxburst; + __entry->address = ep->address, + __entry->claimed = ep->claimed; + __entry->enabled = ep->enabled; + __entry->ret = ret; + ), + TP_printk("%s: mps %d/%d streams %d mult %d burst %d addr %02x %s%s --> %d", + __get_str(name), __entry->maxpacket, __entry->maxpacket_limit, + __entry->max_streams, __entry->mult, __entry->maxburst, + __entry->address, __entry->claimed ? "claimed:" : "released:", + __entry->enabled ? "enabled" : "disabled", ret) +); + +DEFINE_EVENT(udc_log_ep, usb_ep_set_maxpacket_limit, + TP_PROTO(struct usb_ep *ep, int ret), + TP_ARGS(ep, ret) +); + +DEFINE_EVENT(udc_log_ep, usb_ep_enable, + TP_PROTO(struct usb_ep *ep, int ret), + TP_ARGS(ep, ret) +); + +DEFINE_EVENT(udc_log_ep, usb_ep_disable, + TP_PROTO(struct usb_ep *ep, int ret), + TP_ARGS(ep, ret) +); + +DEFINE_EVENT(udc_log_ep, usb_ep_set_halt, + TP_PROTO(struct usb_ep *ep, int ret), + TP_ARGS(ep, ret) +); + +DEFINE_EVENT(udc_log_ep, usb_ep_clear_halt, + TP_PROTO(struct usb_ep *ep, int ret), + TP_ARGS(ep, ret) +); + +DEFINE_EVENT(udc_log_ep, usb_ep_set_wedge, + TP_PROTO(struct usb_ep *ep, int ret), + TP_ARGS(ep, ret) +); + +DEFINE_EVENT(udc_log_ep, usb_ep_fifo_status, + TP_PROTO(struct usb_ep *ep, int ret), + TP_ARGS(ep, ret) +); + +DEFINE_EVENT(udc_log_ep, usb_ep_fifo_flush, + TP_PROTO(struct usb_ep *ep, int ret), + TP_ARGS(ep, ret) +); + +DECLARE_EVENT_CLASS(udc_log_req, + TP_PROTO(struct usb_ep *ep, struct usb_request *req, int ret), + TP_ARGS(ep, req, ret), + TP_STRUCT__entry( + __dynamic_array(char, name, UDC_TRACE_STR_MAX) + __field(unsigned, length) + __field(unsigned, actual) + __field(unsigned, num_sgs) + __field(unsigned, num_mapped_sgs) + __field(unsigned, stream_id) + __field(unsigned, no_interrupt) + __field(unsigned, zero) + __field(unsigned, short_not_ok) + __field(int, status) + __field(int, ret) + ), + TP_fast_assign( + snprintf(__get_str(name), UDC_TRACE_STR_MAX, "%s", ep->name); + __entry->length = req->length; + __entry->actual = req->actual; + __entry->num_sgs = req->num_sgs; + __entry->num_mapped_sgs = req->num_mapped_sgs; + __entry->stream_id = req->stream_id; + __entry->no_interrupt = req->no_interrupt; + __entry->zero = req->zero; + __entry->short_not_ok = req->short_not_ok; + __entry->status = req->status; + __entry->ret = ret; + ), + TP_printk("%s: length %d/%d sgs %d/%d stream %d %s%s%s status %d --> %d", + __get_str(name), __entry->actual, __entry->length, + __entry->num_mapped_sgs, __entry->num_sgs, __entry->stream_id, + __entry->zero ? "Z" : "z", + __entry->short_not_ok ? "S" : "s", + __entry->no_interrupt ? "i" : "I", + __entry->status, __entry->ret + ) +); + +DEFINE_EVENT(udc_log_req, usb_ep_alloc_request, + TP_PROTO(struct usb_ep *ep, struct usb_request *req, int ret), + TP_ARGS(ep, req, ret) +); + +DEFINE_EVENT(udc_log_req, usb_ep_free_request, + TP_PROTO(struct usb_ep *ep, struct usb_request *req, int ret), + TP_ARGS(ep, req, ret) +); + +DEFINE_EVENT(udc_log_req, usb_ep_queue, + TP_PROTO(struct usb_ep *ep, struct usb_request *req, int ret), + TP_ARGS(ep, req, ret) +); + +DEFINE_EVENT(udc_log_req, usb_ep_dequeue, + TP_PROTO(struct usb_ep *ep, struct usb_request *req, int ret), + TP_ARGS(ep, req, ret) +); + +DEFINE_EVENT(udc_log_req, usb_gadget_giveback_request, + TP_PROTO(struct usb_ep *ep, struct usb_request *req, int ret), + TP_ARGS(ep, req, ret) +); + +#endif /* __UDC_TRACE_H */ + +/* this part has to be here */ + +#undef TRACE_INCLUDE_PATH +#define TRACE_INCLUDE_PATH . + +#undef TRACE_INCLUDE_FILE +#define TRACE_INCLUDE_FILE trace + +#include diff --git a/drivers/usb/gadget/udc/udc-core.c b/drivers/usb/gadget/udc/udc-core.c deleted file mode 100644 index abf0138..0000000 --- a/drivers/usb/gadget/udc/udc-core.c +++ /dev/null @@ -1,1373 +0,0 @@ -/** - * udc.c - Core UDC Framework - * - * Copyright (C) 2010 Texas Instruments - * Author: Felipe Balbi - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 of - * the License as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -/** - * struct usb_udc - describes one usb device controller - * @driver - the gadget driver pointer. For use by the class code - * @dev - the child device to the actual controller - * @gadget - the gadget. For use by the class code - * @list - for use by the udc class driver - * @vbus - for udcs who care about vbus status, this value is real vbus status; - * for udcs who do not care about vbus status, this value is always true - * - * This represents the internal data structure which is used by the UDC-class - * to hold information about udc driver and gadget together. - */ -struct usb_udc { - struct usb_gadget_driver *driver; - struct usb_gadget *gadget; - struct device dev; - struct list_head list; - bool vbus; -}; - -static struct class *udc_class; -static LIST_HEAD(udc_list); -static LIST_HEAD(gadget_driver_pending_list); -static DEFINE_MUTEX(udc_lock); - -static int udc_bind_to_driver(struct usb_udc *udc, - struct usb_gadget_driver *driver); - -/* ------------------------------------------------------------------------- */ - -/** - * usb_ep_set_maxpacket_limit - set maximum packet size limit for endpoint - * @ep:the endpoint being configured - * @maxpacket_limit:value of maximum packet size limit - * - * This function should be used only in UDC drivers to initialize endpoint - * (usually in probe function). - */ -void usb_ep_set_maxpacket_limit(struct usb_ep *ep, - unsigned maxpacket_limit) -{ - ep->maxpacket_limit = maxpacket_limit; - ep->maxpacket = maxpacket_limit; -} -EXPORT_SYMBOL_GPL(usb_ep_set_maxpacket_limit); - -/** - * usb_ep_enable - configure endpoint, making it usable - * @ep:the endpoint being configured. may not be the endpoint named "ep0". - * drivers discover endpoints through the ep_list of a usb_gadget. - * - * When configurations are set, or when interface settings change, the driver - * will enable or disable the relevant endpoints. while it is enabled, an - * endpoint may be used for i/o until the driver receives a disconnect() from - * the host or until the endpoint is disabled. - * - * the ep0 implementation (which calls this routine) must ensure that the - * hardware capabilities of each endpoint match the descriptor provided - * for it. for example, an endpoint named "ep2in-bulk" would be usable - * for interrupt transfers as well as bulk, but it likely couldn't be used - * for iso transfers or for endpoint 14. some endpoints are fully - * configurable, with more generic names like "ep-a". (remember that for - * USB, "in" means "towards the USB master".) - * - * returns zero, or a negative error code. - */ -int usb_ep_enable(struct usb_ep *ep) -{ - int ret; - - if (ep->enabled) - return 0; - - ret = ep->ops->enable(ep, ep->desc); - if (ret) - return ret; - - ep->enabled = true; - - return 0; -} -EXPORT_SYMBOL_GPL(usb_ep_enable); - -/** - * usb_ep_disable - endpoint is no longer usable - * @ep:the endpoint being unconfigured. may not be the endpoint named "ep0". - * - * no other task may be using this endpoint when this is called. - * any pending and uncompleted requests will complete with status - * indicating disconnect (-ESHUTDOWN) before this call returns. - * gadget drivers must call usb_ep_enable() again before queueing - * requests to the endpoint. - * - * returns zero, or a negative error code. - */ -int usb_ep_disable(struct usb_ep *ep) -{ - int ret; - - if (!ep->enabled) - return 0; - - ret = ep->ops->disable(ep); - if (ret) - return ret; - - ep->enabled = false; - - return 0; -} -EXPORT_SYMBOL_GPL(usb_ep_disable); - -/** - * usb_ep_alloc_request - allocate a request object to use with this endpoint - * @ep:the endpoint to be used with with the request - * @gfp_flags:GFP_* flags to use - * - * Request objects must be allocated with this call, since they normally - * need controller-specific setup and may even need endpoint-specific - * resources such as allocation of DMA descriptors. - * Requests may be submitted with usb_ep_queue(), and receive a single - * completion callback. Free requests with usb_ep_free_request(), when - * they are no longer needed. - * - * Returns the request, or null if one could not be allocated. - */ -struct usb_request *usb_ep_alloc_request(struct usb_ep *ep, - gfp_t gfp_flags) -{ - return ep->ops->alloc_request(ep, gfp_flags); -} -EXPORT_SYMBOL_GPL(usb_ep_alloc_request); - -/** - * usb_ep_free_request - frees a request object - * @ep:the endpoint associated with the request - * @req:the request being freed - * - * Reverses the effect of usb_ep_alloc_request(). - * Caller guarantees the request is not queued, and that it will - * no longer be requeued (or otherwise used). - */ -void usb_ep_free_request(struct usb_ep *ep, - struct usb_request *req) -{ - ep->ops->free_request(ep, req); -} -EXPORT_SYMBOL_GPL(usb_ep_free_request); - -/** - * usb_ep_queue - queues (submits) an I/O request to an endpoint. - * @ep:the endpoint associated with the request - * @req:the request being submitted - * @gfp_flags: GFP_* flags to use in case the lower level driver couldn't - * pre-allocate all necessary memory with the request. - * - * This tells the device controller to perform the specified request through - * that endpoint (reading or writing a buffer). When the request completes, - * including being canceled by usb_ep_dequeue(), the request's completion - * routine is called to return the request to the driver. Any endpoint - * (except control endpoints like ep0) may have more than one transfer - * request queued; they complete in FIFO order. Once a gadget driver - * submits a request, that request may not be examined or modified until it - * is given back to that driver through the completion callback. - * - * Each request is turned into one or more packets. The controller driver - * never merges adjacent requests into the same packet. OUT transfers - * will sometimes use data that's already buffered in the hardware. - * Drivers can rely on the fact that the first byte of the request's buffer - * always corresponds to the first byte of some USB packet, for both - * IN and OUT transfers. - * - * Bulk endpoints can queue any amount of data; the transfer is packetized - * automatically. The last packet will be short if the request doesn't fill it - * out completely. Zero length packets (ZLPs) should be avoided in portable - * protocols since not all usb hardware can successfully handle zero length - * packets. (ZLPs may be explicitly written, and may be implicitly written if - * the request 'zero' flag is set.) Bulk endpoints may also be used - * for interrupt transfers; but the reverse is not true, and some endpoints - * won't support every interrupt transfer. (Such as 768 byte packets.) - * - * Interrupt-only endpoints are less functional than bulk endpoints, for - * example by not supporting queueing or not handling buffers that are - * larger than the endpoint's maxpacket size. They may also treat data - * toggle differently. - * - * Control endpoints ... after getting a setup() callback, the driver queues - * one response (even if it would be zero length). That enables the - * status ack, after transferring data as specified in the response. Setup - * functions may return negative error codes to generate protocol stalls. - * (Note that some USB device controllers disallow protocol stall responses - * in some cases.) When control responses are deferred (the response is - * written after the setup callback returns), then usb_ep_set_halt() may be - * used on ep0 to trigger protocol stalls. Depending on the controller, - * it may not be possible to trigger a status-stage protocol stall when the - * data stage is over, that is, from within the response's completion - * routine. - * - * For periodic endpoints, like interrupt or isochronous ones, the usb host - * arranges to poll once per interval, and the gadget driver usually will - * have queued some data to transfer at that time. - * - * Returns zero, or a negative error code. Endpoints that are not enabled - * report errors; errors will also be - * reported when the usb peripheral is disconnected. - */ -int usb_ep_queue(struct usb_ep *ep, - struct usb_request *req, gfp_t gfp_flags) -{ - if (WARN_ON_ONCE(!ep->enabled && ep->address)) - return -ESHUTDOWN; - - return ep->ops->queue(ep, req, gfp_flags); -} -EXPORT_SYMBOL_GPL(usb_ep_queue); - -/** - * usb_ep_dequeue - dequeues (cancels, unlinks) an I/O request from an endpoint - * @ep:the endpoint associated with the request - * @req:the request being canceled - * - * If the request is still active on the endpoint, it is dequeued and its - * completion routine is called (with status -ECONNRESET); else a negative - * error code is returned. This is guaranteed to happen before the call to - * usb_ep_dequeue() returns. - * - * Note that some hardware can't clear out write fifos (to unlink the request - * at the head of the queue) except as part of disconnecting from usb. Such - * restrictions prevent drivers from supporting configuration changes, - * even to configuration zero (a "chapter 9" requirement). - */ -int usb_ep_dequeue(struct usb_ep *ep, struct usb_request *req) -{ - return ep->ops->dequeue(ep, req); -} -EXPORT_SYMBOL_GPL(usb_ep_dequeue); - -/** - * usb_ep_set_halt - sets the endpoint halt feature. - * @ep: the non-isochronous endpoint being stalled - * - * Use this to stall an endpoint, perhaps as an error report. - * Except for control endpoints, - * the endpoint stays halted (will not stream any data) until the host - * clears this feature; drivers may need to empty the endpoint's request - * queue first, to make sure no inappropriate transfers happen. - * - * Note that while an endpoint CLEAR_FEATURE will be invisible to the - * gadget driver, a SET_INTERFACE will not be. To reset endpoints for the - * current altsetting, see usb_ep_clear_halt(). When switching altsettings, - * it's simplest to use usb_ep_enable() or usb_ep_disable() for the endpoints. - * - * Returns zero, or a negative error code. On success, this call sets - * underlying hardware state that blocks data transfers. - * Attempts to halt IN endpoints will fail (returning -EAGAIN) if any - * transfer requests are still queued, or if the controller hardware - * (usually a FIFO) still holds bytes that the host hasn't collected. - */ -int usb_ep_set_halt(struct usb_ep *ep) -{ - return ep->ops->set_halt(ep, 1); -} -EXPORT_SYMBOL_GPL(usb_ep_set_halt); - -/** - * usb_ep_clear_halt - clears endpoint halt, and resets toggle - * @ep:the bulk or interrupt endpoint being reset - * - * Use this when responding to the standard usb "set interface" request, - * for endpoints that aren't reconfigured, after clearing any other state - * in the endpoint's i/o queue. - * - * Returns zero, or a negative error code. On success, this call clears - * the underlying hardware state reflecting endpoint halt and data toggle. - * Note that some hardware can't support this request (like pxa2xx_udc), - * and accordingly can't correctly implement interface altsettings. - */ -int usb_ep_clear_halt(struct usb_ep *ep) -{ - return ep->ops->set_halt(ep, 0); -} -EXPORT_SYMBOL_GPL(usb_ep_clear_halt); - -/** - * usb_ep_set_wedge - sets the halt feature and ignores clear requests - * @ep: the endpoint being wedged - * - * Use this to stall an endpoint and ignore CLEAR_FEATURE(HALT_ENDPOINT) - * requests. If the gadget driver clears the halt status, it will - * automatically unwedge the endpoint. - * - * Returns zero on success, else negative errno. - */ -int usb_ep_set_wedge(struct usb_ep *ep) -{ - if (ep->ops->set_wedge) - return ep->ops->set_wedge(ep); - else - return ep->ops->set_halt(ep, 1); -} -EXPORT_SYMBOL_GPL(usb_ep_set_wedge); - -/** - * usb_ep_fifo_status - returns number of bytes in fifo, or error - * @ep: the endpoint whose fifo status is being checked. - * - * FIFO endpoints may have "unclaimed data" in them in certain cases, - * such as after aborted transfers. Hosts may not have collected all - * the IN data written by the gadget driver (and reported by a request - * completion). The gadget driver may not have collected all the data - * written OUT to it by the host. Drivers that need precise handling for - * fault reporting or recovery may need to use this call. - * - * This returns the number of such bytes in the fifo, or a negative - * errno if the endpoint doesn't use a FIFO or doesn't support such - * precise handling. - */ -int usb_ep_fifo_status(struct usb_ep *ep) -{ - if (ep->ops->fifo_status) - return ep->ops->fifo_status(ep); - else - return -EOPNOTSUPP; -} -EXPORT_SYMBOL_GPL(usb_ep_fifo_status); - -/** - * usb_ep_fifo_flush - flushes contents of a fifo - * @ep: the endpoint whose fifo is being flushed. - * - * This call may be used to flush the "unclaimed data" that may exist in - * an endpoint fifo after abnormal transaction terminations. The call - * must never be used except when endpoint is not being used for any - * protocol translation. - */ -void usb_ep_fifo_flush(struct usb_ep *ep) -{ - if (ep->ops->fifo_flush) - ep->ops->fifo_flush(ep); -} -EXPORT_SYMBOL_GPL(usb_ep_fifo_flush); - -/* ------------------------------------------------------------------------- */ - -/** - * usb_gadget_frame_number - returns the current frame number - * @gadget: controller that reports the frame number - * - * Returns the usb frame number, normally eleven bits from a SOF packet, - * or negative errno if this device doesn't support this capability. - */ -int usb_gadget_frame_number(struct usb_gadget *gadget) -{ - return gadget->ops->get_frame(gadget); -} -EXPORT_SYMBOL_GPL(usb_gadget_frame_number); - -/** - * usb_gadget_wakeup - tries to wake up the host connected to this gadget - * @gadget: controller used to wake up the host - * - * Returns zero on success, else negative error code if the hardware - * doesn't support such attempts, or its support has not been enabled - * by the usb host. Drivers must return device descriptors that report - * their ability to support this, or hosts won't enable it. - * - * This may also try to use SRP to wake the host and start enumeration, - * even if OTG isn't otherwise in use. OTG devices may also start - * remote wakeup even when hosts don't explicitly enable it. - */ -int usb_gadget_wakeup(struct usb_gadget *gadget) -{ - if (!gadget->ops->wakeup) - return -EOPNOTSUPP; - return gadget->ops->wakeup(gadget); -} -EXPORT_SYMBOL_GPL(usb_gadget_wakeup); - -/** - * usb_gadget_set_selfpowered - sets the device selfpowered feature. - * @gadget:the device being declared as self-powered - * - * this affects the device status reported by the hardware driver - * to reflect that it now has a local power supply. - * - * returns zero on success, else negative errno. - */ -int usb_gadget_set_selfpowered(struct usb_gadget *gadget) -{ - if (!gadget->ops->set_selfpowered) - return -EOPNOTSUPP; - return gadget->ops->set_selfpowered(gadget, 1); -} -EXPORT_SYMBOL_GPL(usb_gadget_set_selfpowered); - -/** - * usb_gadget_clear_selfpowered - clear the device selfpowered feature. - * @gadget:the device being declared as bus-powered - * - * this affects the device status reported by the hardware driver. - * some hardware may not support bus-powered operation, in which - * case this feature's value can never change. - * - * returns zero on success, else negative errno. - */ -int usb_gadget_clear_selfpowered(struct usb_gadget *gadget) -{ - if (!gadget->ops->set_selfpowered) - return -EOPNOTSUPP; - return gadget->ops->set_selfpowered(gadget, 0); -} -EXPORT_SYMBOL_GPL(usb_gadget_clear_selfpowered); - -/** - * usb_gadget_vbus_connect - Notify controller that VBUS is powered - * @gadget:The device which now has VBUS power. - * Context: can sleep - * - * This call is used by a driver for an external transceiver (or GPIO) - * that detects a VBUS power session starting. Common responses include - * resuming the controller, activating the D+ (or D-) pullup to let the - * host detect that a USB device is attached, and starting to draw power - * (8mA or possibly more, especially after SET_CONFIGURATION). - * - * Returns zero on success, else negative errno. - */ -int usb_gadget_vbus_connect(struct usb_gadget *gadget) -{ - if (!gadget->ops->vbus_session) - return -EOPNOTSUPP; - return gadget->ops->vbus_session(gadget, 1); -} -EXPORT_SYMBOL_GPL(usb_gadget_vbus_connect); - -/** - * usb_gadget_vbus_draw - constrain controller's VBUS power usage - * @gadget:The device whose VBUS usage is being described - * @mA:How much current to draw, in milliAmperes. This should be twice - * the value listed in the configuration descriptor bMaxPower field. - * - * This call is used by gadget drivers during SET_CONFIGURATION calls, - * reporting how much power the device may consume. For example, this - * could affect how quickly batteries are recharged. - * - * Returns zero on success, else negative errno. - */ -int usb_gadget_vbus_draw(struct usb_gadget *gadget, unsigned mA) -{ - if (!gadget->ops->vbus_draw) - return -EOPNOTSUPP; - return gadget->ops->vbus_draw(gadget, mA); -} -EXPORT_SYMBOL_GPL(usb_gadget_vbus_draw); - -/** - * usb_gadget_vbus_disconnect - notify controller about VBUS session end - * @gadget:the device whose VBUS supply is being described - * Context: can sleep - * - * This call is used by a driver for an external transceiver (or GPIO) - * that detects a VBUS power session ending. Common responses include - * reversing everything done in usb_gadget_vbus_connect(). - * - * Returns zero on success, else negative errno. - */ -int usb_gadget_vbus_disconnect(struct usb_gadget *gadget) -{ - if (!gadget->ops->vbus_session) - return -EOPNOTSUPP; - return gadget->ops->vbus_session(gadget, 0); -} -EXPORT_SYMBOL_GPL(usb_gadget_vbus_disconnect); - -/** - * usb_gadget_connect - software-controlled connect to USB host - * @gadget:the peripheral being connected - * - * Enables the D+ (or potentially D-) pullup. The host will start - * enumerating this gadget when the pullup is active and a VBUS session - * is active (the link is powered). This pullup is always enabled unless - * usb_gadget_disconnect() has been used to disable it. - * - * Returns zero on success, else negative errno. - */ -int usb_gadget_connect(struct usb_gadget *gadget) -{ - int ret; - - if (!gadget->ops->pullup) - return -EOPNOTSUPP; - - if (gadget->deactivated) { - /* - * If gadget is deactivated we only save new state. - * Gadget will be connected automatically after activation. - */ - gadget->connected = true; - return 0; - } - - ret = gadget->ops->pullup(gadget, 1); - if (!ret) - gadget->connected = 1; - return ret; -} -EXPORT_SYMBOL_GPL(usb_gadget_connect); - -/** - * usb_gadget_disconnect - software-controlled disconnect from USB host - * @gadget:the peripheral being disconnected - * - * Disables the D+ (or potentially D-) pullup, which the host may see - * as a disconnect (when a VBUS session is active). Not all systems - * support software pullup controls. - * - * Returns zero on success, else negative errno. - */ -int usb_gadget_disconnect(struct usb_gadget *gadget) -{ - int ret; - - if (!gadget->ops->pullup) - return -EOPNOTSUPP; - - if (gadget->deactivated) { - /* - * If gadget is deactivated we only save new state. - * Gadget will stay disconnected after activation. - */ - gadget->connected = false; - return 0; - } - - ret = gadget->ops->pullup(gadget, 0); - if (!ret) - gadget->connected = 0; - return ret; -} -EXPORT_SYMBOL_GPL(usb_gadget_disconnect); - -/** - * usb_gadget_deactivate - deactivate function which is not ready to work - * @gadget: the peripheral being deactivated - * - * This routine may be used during the gadget driver bind() call to prevent - * the peripheral from ever being visible to the USB host, unless later - * usb_gadget_activate() is called. For example, user mode components may - * need to be activated before the system can talk to hosts. - * - * Returns zero on success, else negative errno. - */ -int usb_gadget_deactivate(struct usb_gadget *gadget) -{ - int ret; - - if (gadget->deactivated) - return 0; - - if (gadget->connected) { - ret = usb_gadget_disconnect(gadget); - if (ret) - return ret; - /* - * If gadget was being connected before deactivation, we want - * to reconnect it in usb_gadget_activate(). - */ - gadget->connected = true; - } - gadget->deactivated = true; - - return 0; -} -EXPORT_SYMBOL_GPL(usb_gadget_deactivate); - -/** - * usb_gadget_activate - activate function which is not ready to work - * @gadget: the peripheral being activated - * - * This routine activates gadget which was previously deactivated with - * usb_gadget_deactivate() call. It calls usb_gadget_connect() if needed. - * - * Returns zero on success, else negative errno. - */ -int usb_gadget_activate(struct usb_gadget *gadget) -{ - if (!gadget->deactivated) - return 0; - - gadget->deactivated = false; - - /* - * If gadget has been connected before deactivation, or became connected - * while it was being deactivated, we call usb_gadget_connect(). - */ - if (gadget->connected) - return usb_gadget_connect(gadget); - - return 0; -} -EXPORT_SYMBOL_GPL(usb_gadget_activate); - -/* ------------------------------------------------------------------------- */ - -#ifdef CONFIG_HAS_DMA - -int usb_gadget_map_request_by_dev(struct device *dev, - struct usb_request *req, int is_in) -{ - if (req->length == 0) - return 0; - - if (req->num_sgs) { - int mapped; - - mapped = dma_map_sg(dev, req->sg, req->num_sgs, - is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE); - if (mapped == 0) { - dev_err(dev, "failed to map SGs\n"); - return -EFAULT; - } - - req->num_mapped_sgs = mapped; - } else { - req->dma = dma_map_single(dev, req->buf, req->length, - is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE); - - if (dma_mapping_error(dev, req->dma)) { - dev_err(dev, "failed to map buffer\n"); - return -EFAULT; - } - } - - return 0; -} -EXPORT_SYMBOL_GPL(usb_gadget_map_request_by_dev); - -int usb_gadget_map_request(struct usb_gadget *gadget, - struct usb_request *req, int is_in) -{ - return usb_gadget_map_request_by_dev(gadget->dev.parent, req, is_in); -} -EXPORT_SYMBOL_GPL(usb_gadget_map_request); - -void usb_gadget_unmap_request_by_dev(struct device *dev, - struct usb_request *req, int is_in) -{ - if (req->length == 0) - return; - - if (req->num_mapped_sgs) { - dma_unmap_sg(dev, req->sg, req->num_mapped_sgs, - is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE); - - req->num_mapped_sgs = 0; - } else { - dma_unmap_single(dev, req->dma, req->length, - is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE); - } -} -EXPORT_SYMBOL_GPL(usb_gadget_unmap_request_by_dev); - -void usb_gadget_unmap_request(struct usb_gadget *gadget, - struct usb_request *req, int is_in) -{ - usb_gadget_unmap_request_by_dev(gadget->dev.parent, req, is_in); -} -EXPORT_SYMBOL_GPL(usb_gadget_unmap_request); - -#endif /* CONFIG_HAS_DMA */ - -/* ------------------------------------------------------------------------- */ - -/** - * usb_gadget_giveback_request - give the request back to the gadget layer - * Context: in_interrupt() - * - * This is called by device controller drivers in order to return the - * completed request back to the gadget layer. - */ -void usb_gadget_giveback_request(struct usb_ep *ep, - struct usb_request *req) -{ - if (likely(req->status == 0)) - usb_led_activity(USB_LED_EVENT_GADGET); - - req->complete(ep, req); -} -EXPORT_SYMBOL_GPL(usb_gadget_giveback_request); - -/* ------------------------------------------------------------------------- */ - -/** - * gadget_find_ep_by_name - returns ep whose name is the same as sting passed - * in second parameter or NULL if searched endpoint not found - * @g: controller to check for quirk - * @name: name of searched endpoint - */ -struct usb_ep *gadget_find_ep_by_name(struct usb_gadget *g, const char *name) -{ - struct usb_ep *ep; - - gadget_for_each_ep(ep, g) { - if (!strcmp(ep->name, name)) - return ep; - } - - return NULL; -} -EXPORT_SYMBOL_GPL(gadget_find_ep_by_name); - -/* ------------------------------------------------------------------------- */ - -int usb_gadget_ep_match_desc(struct usb_gadget *gadget, - struct usb_ep *ep, struct usb_endpoint_descriptor *desc, - struct usb_ss_ep_comp_descriptor *ep_comp) -{ - u8 type; - u16 max; - int num_req_streams = 0; - - /* endpoint already claimed? */ - if (ep->claimed) - return 0; - - type = usb_endpoint_type(desc); - max = 0x7ff & usb_endpoint_maxp(desc); - - if (usb_endpoint_dir_in(desc) && !ep->caps.dir_in) - return 0; - if (usb_endpoint_dir_out(desc) && !ep->caps.dir_out) - return 0; - - if (max > ep->maxpacket_limit) - return 0; - - /* "high bandwidth" works only at high speed */ - if (!gadget_is_dualspeed(gadget) && usb_endpoint_maxp(desc) & (3<<11)) - return 0; - - switch (type) { - case USB_ENDPOINT_XFER_CONTROL: - /* only support ep0 for portable CONTROL traffic */ - return 0; - case USB_ENDPOINT_XFER_ISOC: - if (!ep->caps.type_iso) - return 0; - /* ISO: limit 1023 bytes full speed, 1024 high/super speed */ - if (!gadget_is_dualspeed(gadget) && max > 1023) - return 0; - break; - case USB_ENDPOINT_XFER_BULK: - if (!ep->caps.type_bulk) - return 0; - if (ep_comp && gadget_is_superspeed(gadget)) { - /* Get the number of required streams from the - * EP companion descriptor and see if the EP - * matches it - */ - num_req_streams = ep_comp->bmAttributes & 0x1f; - if (num_req_streams > ep->max_streams) - return 0; - } - break; - case USB_ENDPOINT_XFER_INT: - /* Bulk endpoints handle interrupt transfers, - * except the toggle-quirky iso-synch kind - */ - if (!ep->caps.type_int && !ep->caps.type_bulk) - return 0; - /* INT: limit 64 bytes full speed, 1024 high/super speed */ - if (!gadget_is_dualspeed(gadget) && max > 64) - return 0; - break; - } - - return 1; -} -EXPORT_SYMBOL_GPL(usb_gadget_ep_match_desc); - -/* ------------------------------------------------------------------------- */ - -static void usb_gadget_state_work(struct work_struct *work) -{ - struct usb_gadget *gadget = work_to_gadget(work); - struct usb_udc *udc = gadget->udc; - - if (udc) - sysfs_notify(&udc->dev.kobj, NULL, "state"); -} - -void usb_gadget_set_state(struct usb_gadget *gadget, - enum usb_device_state state) -{ - gadget->state = state; - schedule_work(&gadget->work); -} -EXPORT_SYMBOL_GPL(usb_gadget_set_state); - -/* ------------------------------------------------------------------------- */ - -static void usb_udc_connect_control(struct usb_udc *udc) -{ - if (udc->vbus) - usb_gadget_connect(udc->gadget); - else - usb_gadget_disconnect(udc->gadget); -} - -/** - * usb_udc_vbus_handler - updates the udc core vbus status, and try to - * connect or disconnect gadget - * @gadget: The gadget which vbus change occurs - * @status: The vbus status - * - * The udc driver calls it when it wants to connect or disconnect gadget - * according to vbus status. - */ -void usb_udc_vbus_handler(struct usb_gadget *gadget, bool status) -{ - struct usb_udc *udc = gadget->udc; - - if (udc) { - udc->vbus = status; - usb_udc_connect_control(udc); - } -} -EXPORT_SYMBOL_GPL(usb_udc_vbus_handler); - -/** - * usb_gadget_udc_reset - notifies the udc core that bus reset occurs - * @gadget: The gadget which bus reset occurs - * @driver: The gadget driver we want to notify - * - * If the udc driver has bus reset handler, it needs to call this when the bus - * reset occurs, it notifies the gadget driver that the bus reset occurs as - * well as updates gadget state. - */ -void usb_gadget_udc_reset(struct usb_gadget *gadget, - struct usb_gadget_driver *driver) -{ - driver->reset(gadget); - usb_gadget_set_state(gadget, USB_STATE_DEFAULT); -} -EXPORT_SYMBOL_GPL(usb_gadget_udc_reset); - -/** - * usb_gadget_udc_start - tells usb device controller to start up - * @udc: The UDC to be started - * - * This call is issued by the UDC Class driver when it's about - * to register a gadget driver to the device controller, before - * calling gadget driver's bind() method. - * - * It allows the controller to be powered off until strictly - * necessary to have it powered on. - * - * Returns zero on success, else negative errno. - */ -static inline int usb_gadget_udc_start(struct usb_udc *udc) -{ - return udc->gadget->ops->udc_start(udc->gadget, udc->driver); -} - -/** - * usb_gadget_udc_stop - tells usb device controller we don't need it anymore - * @gadget: The device we want to stop activity - * @driver: The driver to unbind from @gadget - * - * This call is issued by the UDC Class driver after calling - * gadget driver's unbind() method. - * - * The details are implementation specific, but it can go as - * far as powering off UDC completely and disable its data - * line pullups. - */ -static inline void usb_gadget_udc_stop(struct usb_udc *udc) -{ - udc->gadget->ops->udc_stop(udc->gadget); -} - -/** - * usb_udc_release - release the usb_udc struct - * @dev: the dev member within usb_udc - * - * This is called by driver's core in order to free memory once the last - * reference is released. - */ -static void usb_udc_release(struct device *dev) -{ - struct usb_udc *udc; - - udc = container_of(dev, struct usb_udc, dev); - dev_dbg(dev, "releasing '%s'\n", dev_name(dev)); - kfree(udc); -} - -static const struct attribute_group *usb_udc_attr_groups[]; - -static void usb_udc_nop_release(struct device *dev) -{ - dev_vdbg(dev, "%s\n", __func__); -} - -/** - * usb_add_gadget_udc_release - adds a new gadget to the udc class driver list - * @parent: the parent device to this udc. Usually the controller driver's - * device. - * @gadget: the gadget to be added to the list. - * @release: a gadget release function. - * - * Returns zero on success, negative errno otherwise. - */ -int usb_add_gadget_udc_release(struct device *parent, struct usb_gadget *gadget, - void (*release)(struct device *dev)) -{ - struct usb_udc *udc; - struct usb_gadget_driver *driver; - int ret = -ENOMEM; - - udc = kzalloc(sizeof(*udc), GFP_KERNEL); - if (!udc) - goto err1; - - dev_set_name(&gadget->dev, "gadget"); - INIT_WORK(&gadget->work, usb_gadget_state_work); - gadget->dev.parent = parent; - - if (release) - gadget->dev.release = release; - else - gadget->dev.release = usb_udc_nop_release; - - ret = device_register(&gadget->dev); - if (ret) - goto err2; - - device_initialize(&udc->dev); - udc->dev.release = usb_udc_release; - udc->dev.class = udc_class; - udc->dev.groups = usb_udc_attr_groups; - udc->dev.parent = parent; - ret = dev_set_name(&udc->dev, "%s", kobject_name(&parent->kobj)); - if (ret) - goto err3; - - udc->gadget = gadget; - gadget->udc = udc; - - mutex_lock(&udc_lock); - list_add_tail(&udc->list, &udc_list); - - ret = device_add(&udc->dev); - if (ret) - goto err4; - - usb_gadget_set_state(gadget, USB_STATE_NOTATTACHED); - udc->vbus = true; - - /* pick up one of pending gadget drivers */ - list_for_each_entry(driver, &gadget_driver_pending_list, pending) { - if (!driver->udc_name || strcmp(driver->udc_name, - dev_name(&udc->dev)) == 0) { - ret = udc_bind_to_driver(udc, driver); - if (ret != -EPROBE_DEFER) - list_del(&driver->pending); - if (ret) - goto err4; - break; - } - } - - mutex_unlock(&udc_lock); - - return 0; - -err4: - list_del(&udc->list); - mutex_unlock(&udc_lock); - -err3: - put_device(&udc->dev); - device_del(&gadget->dev); - -err2: - put_device(&gadget->dev); - kfree(udc); - -err1: - return ret; -} -EXPORT_SYMBOL_GPL(usb_add_gadget_udc_release); - -/** - * usb_get_gadget_udc_name - get the name of the first UDC controller - * This functions returns the name of the first UDC controller in the system. - * Please note that this interface is usefull only for legacy drivers which - * assume that there is only one UDC controller in the system and they need to - * get its name before initialization. There is no guarantee that the UDC - * of the returned name will be still available, when gadget driver registers - * itself. - * - * Returns pointer to string with UDC controller name on success, NULL - * otherwise. Caller should kfree() returned string. - */ -char *usb_get_gadget_udc_name(void) -{ - struct usb_udc *udc; - char *name = NULL; - - /* For now we take the first available UDC */ - mutex_lock(&udc_lock); - list_for_each_entry(udc, &udc_list, list) { - if (!udc->driver) { - name = kstrdup(udc->gadget->name, GFP_KERNEL); - break; - } - } - mutex_unlock(&udc_lock); - return name; -} -EXPORT_SYMBOL_GPL(usb_get_gadget_udc_name); - -/** - * usb_add_gadget_udc - adds a new gadget to the udc class driver list - * @parent: the parent device to this udc. Usually the controller - * driver's device. - * @gadget: the gadget to be added to the list - * - * Returns zero on success, negative errno otherwise. - */ -int usb_add_gadget_udc(struct device *parent, struct usb_gadget *gadget) -{ - return usb_add_gadget_udc_release(parent, gadget, NULL); -} -EXPORT_SYMBOL_GPL(usb_add_gadget_udc); - -static void usb_gadget_remove_driver(struct usb_udc *udc) -{ - dev_dbg(&udc->dev, "unregistering UDC driver [%s]\n", - udc->driver->function); - - kobject_uevent(&udc->dev.kobj, KOBJ_CHANGE); - - usb_gadget_disconnect(udc->gadget); - udc->driver->disconnect(udc->gadget); - udc->driver->unbind(udc->gadget); - usb_gadget_udc_stop(udc); - - udc->driver = NULL; - udc->dev.driver = NULL; - udc->gadget->dev.driver = NULL; -} - -/** - * usb_del_gadget_udc - deletes @udc from udc_list - * @gadget: the gadget to be removed. - * - * This, will call usb_gadget_unregister_driver() if - * the @udc is still busy. - */ -void usb_del_gadget_udc(struct usb_gadget *gadget) -{ - struct usb_udc *udc = gadget->udc; - - if (!udc) - return; - - dev_vdbg(gadget->dev.parent, "unregistering gadget\n"); - - mutex_lock(&udc_lock); - list_del(&udc->list); - - if (udc->driver) { - struct usb_gadget_driver *driver = udc->driver; - - usb_gadget_remove_driver(udc); - list_add(&driver->pending, &gadget_driver_pending_list); - } - mutex_unlock(&udc_lock); - - kobject_uevent(&udc->dev.kobj, KOBJ_REMOVE); - flush_work(&gadget->work); - device_unregister(&udc->dev); - device_unregister(&gadget->dev); -} -EXPORT_SYMBOL_GPL(usb_del_gadget_udc); - -/* ------------------------------------------------------------------------- */ - -static int udc_bind_to_driver(struct usb_udc *udc, struct usb_gadget_driver *driver) -{ - int ret; - - dev_dbg(&udc->dev, "registering UDC driver [%s]\n", - driver->function); - - udc->driver = driver; - udc->dev.driver = &driver->driver; - udc->gadget->dev.driver = &driver->driver; - - ret = driver->bind(udc->gadget, driver); - if (ret) - goto err1; - ret = usb_gadget_udc_start(udc); - if (ret) { - driver->unbind(udc->gadget); - goto err1; - } - usb_udc_connect_control(udc); - - kobject_uevent(&udc->dev.kobj, KOBJ_CHANGE); - return 0; -err1: - if (ret != -EISNAM) - dev_err(&udc->dev, "failed to start %s: %d\n", - udc->driver->function, ret); - udc->driver = NULL; - udc->dev.driver = NULL; - udc->gadget->dev.driver = NULL; - return ret; -} - -int usb_gadget_probe_driver(struct usb_gadget_driver *driver) -{ - struct usb_udc *udc = NULL; - int ret = -ENODEV; - - if (!driver || !driver->bind || !driver->setup) - return -EINVAL; - - mutex_lock(&udc_lock); - if (driver->udc_name) { - list_for_each_entry(udc, &udc_list, list) { - ret = strcmp(driver->udc_name, dev_name(&udc->dev)); - if (!ret) - break; - } - if (!ret && !udc->driver) - goto found; - } else { - list_for_each_entry(udc, &udc_list, list) { - /* For now we take the first one */ - if (!udc->driver) - goto found; - } - } - - if (!driver->match_existing_only) { - list_add_tail(&driver->pending, &gadget_driver_pending_list); - pr_info("udc-core: couldn't find an available UDC - added [%s] to list of pending drivers\n", - driver->function); - ret = 0; - } - - mutex_unlock(&udc_lock); - return ret; -found: - ret = udc_bind_to_driver(udc, driver); - mutex_unlock(&udc_lock); - return ret; -} -EXPORT_SYMBOL_GPL(usb_gadget_probe_driver); - -int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) -{ - struct usb_udc *udc = NULL; - int ret = -ENODEV; - - if (!driver || !driver->unbind) - return -EINVAL; - - mutex_lock(&udc_lock); - list_for_each_entry(udc, &udc_list, list) - if (udc->driver == driver) { - usb_gadget_remove_driver(udc); - usb_gadget_set_state(udc->gadget, - USB_STATE_NOTATTACHED); - ret = 0; - break; - } - - if (ret) { - list_del(&driver->pending); - ret = 0; - } - mutex_unlock(&udc_lock); - return ret; -} -EXPORT_SYMBOL_GPL(usb_gadget_unregister_driver); - -/* ------------------------------------------------------------------------- */ - -static ssize_t usb_udc_srp_store(struct device *dev, - struct device_attribute *attr, const char *buf, size_t n) -{ - struct usb_udc *udc = container_of(dev, struct usb_udc, dev); - - if (sysfs_streq(buf, "1")) - usb_gadget_wakeup(udc->gadget); - - return n; -} -static DEVICE_ATTR(srp, S_IWUSR, NULL, usb_udc_srp_store); - -static ssize_t usb_udc_softconn_store(struct device *dev, - struct device_attribute *attr, const char *buf, size_t n) -{ - struct usb_udc *udc = container_of(dev, struct usb_udc, dev); - - if (!udc->driver) { - dev_err(dev, "soft-connect without a gadget driver\n"); - return -EOPNOTSUPP; - } - - if (sysfs_streq(buf, "connect")) { - usb_gadget_udc_start(udc); - usb_gadget_connect(udc->gadget); - } else if (sysfs_streq(buf, "disconnect")) { - usb_gadget_disconnect(udc->gadget); - udc->driver->disconnect(udc->gadget); - usb_gadget_udc_stop(udc); - } else { - dev_err(dev, "unsupported command '%s'\n", buf); - return -EINVAL; - } - - return n; -} -static DEVICE_ATTR(soft_connect, S_IWUSR, NULL, usb_udc_softconn_store); - -static ssize_t state_show(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct usb_udc *udc = container_of(dev, struct usb_udc, dev); - struct usb_gadget *gadget = udc->gadget; - - return sprintf(buf, "%s\n", usb_state_string(gadget->state)); -} -static DEVICE_ATTR_RO(state); - -#define USB_UDC_SPEED_ATTR(name, param) \ -ssize_t name##_show(struct device *dev, \ - struct device_attribute *attr, char *buf) \ -{ \ - struct usb_udc *udc = container_of(dev, struct usb_udc, dev); \ - return snprintf(buf, PAGE_SIZE, "%s\n", \ - usb_speed_string(udc->gadget->param)); \ -} \ -static DEVICE_ATTR_RO(name) - -static USB_UDC_SPEED_ATTR(current_speed, speed); -static USB_UDC_SPEED_ATTR(maximum_speed, max_speed); - -#define USB_UDC_ATTR(name) \ -ssize_t name##_show(struct device *dev, \ - struct device_attribute *attr, char *buf) \ -{ \ - struct usb_udc *udc = container_of(dev, struct usb_udc, dev); \ - struct usb_gadget *gadget = udc->gadget; \ - \ - return snprintf(buf, PAGE_SIZE, "%d\n", gadget->name); \ -} \ -static DEVICE_ATTR_RO(name) - -static USB_UDC_ATTR(is_otg); -static USB_UDC_ATTR(is_a_peripheral); -static USB_UDC_ATTR(b_hnp_enable); -static USB_UDC_ATTR(a_hnp_support); -static USB_UDC_ATTR(a_alt_hnp_support); -static USB_UDC_ATTR(is_selfpowered); - -static struct attribute *usb_udc_attrs[] = { - &dev_attr_srp.attr, - &dev_attr_soft_connect.attr, - &dev_attr_state.attr, - &dev_attr_current_speed.attr, - &dev_attr_maximum_speed.attr, - - &dev_attr_is_otg.attr, - &dev_attr_is_a_peripheral.attr, - &dev_attr_b_hnp_enable.attr, - &dev_attr_a_hnp_support.attr, - &dev_attr_a_alt_hnp_support.attr, - &dev_attr_is_selfpowered.attr, - NULL, -}; - -static const struct attribute_group usb_udc_attr_group = { - .attrs = usb_udc_attrs, -}; - -static const struct attribute_group *usb_udc_attr_groups[] = { - &usb_udc_attr_group, - NULL, -}; - -static int usb_udc_uevent(struct device *dev, struct kobj_uevent_env *env) -{ - struct usb_udc *udc = container_of(dev, struct usb_udc, dev); - int ret; - - ret = add_uevent_var(env, "USB_UDC_NAME=%s", udc->gadget->name); - if (ret) { - dev_err(dev, "failed to add uevent USB_UDC_NAME\n"); - return ret; - } - - if (udc->driver) { - ret = add_uevent_var(env, "USB_UDC_DRIVER=%s", - udc->driver->function); - if (ret) { - dev_err(dev, "failed to add uevent USB_UDC_DRIVER\n"); - return ret; - } - } - - return 0; -} - -static int __init usb_udc_init(void) -{ - udc_class = class_create(THIS_MODULE, "udc"); - if (IS_ERR(udc_class)) { - pr_err("failed to create udc class --> %ld\n", - PTR_ERR(udc_class)); - return PTR_ERR(udc_class); - } - - udc_class->dev_uevent = usb_udc_uevent; - return 0; -} -subsys_initcall(usb_udc_init); - -static void __exit usb_udc_exit(void) -{ - class_destroy(udc_class); -} -module_exit(usb_udc_exit); - -MODULE_DESCRIPTION("UDC Framework"); -MODULE_AUTHOR("Felipe Balbi "); -MODULE_LICENSE("GPL v2"); diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h index c6e1149..612dbdf 100644 --- a/include/linux/usb/gadget.h +++ b/include/linux/usb/gadget.h @@ -25,6 +25,8 @@ #include #include +#define UDC_TRACE_STR_MAX 512 + struct usb_ep; /** @@ -324,6 +326,7 @@ struct usb_gadget_ops { * @dev: Driver model state for this abstract device. * @out_epnum: last used out ep number * @in_epnum: last used in ep number + * @mA: last set mA value * @otg_caps: OTG capabilities of this gadget. * @sg_supported: true if we can handle scatter-gather * @is_otg: True if the USB device port uses a Mini-AB jack, so that the @@ -380,6 +383,7 @@ struct usb_gadget { struct device dev; unsigned out_epnum; unsigned in_epnum; + unsigned mA; struct usb_otg_caps *otg_caps; unsigned sg_supported:1; -- cgit v0.10.2 From 21e64bf20df5e120b37c403b46395d4f0c5d8e86 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Thu, 2 Jun 2016 12:37:31 +0300 Subject: usb: dwc3: gadget: rename 'ignore' argument to 'modify' 'modify' is what the current action is called. Let's rename it so it matches databook. While at that, also make sure to add support 'init' action too. Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index d2884a4..c889ee3 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -462,10 +462,14 @@ static int dwc3_gadget_start_config(struct dwc3 *dwc, struct dwc3_ep *dep) static int dwc3_gadget_set_ep_config(struct dwc3 *dwc, struct dwc3_ep *dep, const struct usb_endpoint_descriptor *desc, const struct usb_ss_ep_comp_descriptor *comp_desc, - bool ignore, bool restore) + bool modify, bool restore) { struct dwc3_gadget_ep_cmd_params params; + if (dev_WARN_ONCE(dwc->dev, modify && restore, + "Can't modify and restore\n")) + return -EINVAL; + memset(¶ms, 0x00, sizeof(params)); params.param0 = DWC3_DEPCFG_EP_TYPE(usb_endpoint_type(desc)) @@ -477,12 +481,13 @@ static int dwc3_gadget_set_ep_config(struct dwc3 *dwc, struct dwc3_ep *dep, params.param0 |= DWC3_DEPCFG_BURST_SIZE(burst - 1); } - if (ignore) - params.param0 |= DWC3_DEPCFG_IGN_SEQ_NUM; - - if (restore) { + if (modify) { + params.param0 |= DWC3_DEPCFG_ACTION_MODIFY; + } else if (restore) { params.param0 |= DWC3_DEPCFG_ACTION_RESTORE; params.param2 |= dep->saved_state; + } else { + params.param0 |= DWC3_DEPCFG_ACTION_INIT; } params.param1 = DWC3_DEPCFG_XFER_COMPLETE_EN; @@ -544,7 +549,7 @@ static int dwc3_gadget_set_xfer_resource(struct dwc3 *dwc, struct dwc3_ep *dep) static int __dwc3_gadget_ep_enable(struct dwc3_ep *dep, const struct usb_endpoint_descriptor *desc, const struct usb_ss_ep_comp_descriptor *comp_desc, - bool ignore, bool restore) + bool modify, bool restore) { struct dwc3 *dwc = dep->dwc; u32 reg; @@ -558,7 +563,7 @@ static int __dwc3_gadget_ep_enable(struct dwc3_ep *dep, return ret; } - ret = dwc3_gadget_set_ep_config(dwc, dep, desc, comp_desc, ignore, + ret = dwc3_gadget_set_ep_config(dwc, dep, desc, comp_desc, modify, restore); if (ret) return ret; -- cgit v0.10.2 From e6fe66fe08cdf9c5d0eb6a6e209621f74f7ee60b Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Tue, 7 Jun 2016 12:49:52 +0300 Subject: usb: dwc3: pci: add dr-mode for Intel dwc3 It's know that Intel's SoCs' dwc3 integration is peripheral-only since Intel implements its own portmux for role-swapping. In order to prevent dwc3 from ever registering and XHCI platform_device, let's just set dr-mode to peripheral-only on Intel SoCs. Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc3/dwc3-pci.c b/drivers/usb/dwc3/dwc3-pci.c index 6bc4c2b..45f5a23 100644 --- a/drivers/usb/dwc3/dwc3-pci.c +++ b/drivers/usb/dwc3/dwc3-pci.c @@ -76,33 +76,45 @@ static int dwc3_pci_quirks(struct pci_dev *pdev, struct platform_device *dwc3) return platform_device_add_properties(dwc3, properties); } - if (pdev->vendor == PCI_VENDOR_ID_INTEL && - pdev->device == PCI_DEVICE_ID_INTEL_BYT) { - struct gpio_desc *gpio; - - acpi_dev_add_driver_gpios(ACPI_COMPANION(&pdev->dev), - acpi_dwc3_byt_gpios); - - /* - * These GPIOs will turn on the USB2 PHY. Note that we have to - * put the gpio descriptors again here because the phy driver - * might want to grab them, too. - */ - gpio = gpiod_get_optional(&pdev->dev, "cs", GPIOD_OUT_LOW); - if (IS_ERR(gpio)) - return PTR_ERR(gpio); - - gpiod_set_value_cansleep(gpio, 1); - gpiod_put(gpio); - - gpio = gpiod_get_optional(&pdev->dev, "reset", GPIOD_OUT_LOW); - if (IS_ERR(gpio)) - return PTR_ERR(gpio); - - if (gpio) { + if (pdev->vendor == PCI_VENDOR_ID_INTEL) { + int ret; + + struct property_entry properties[] = { + PROPERTY_ENTRY_STRING("dr-mode", "peripheral"), + { } + }; + + ret = platform_device_add_properties(dwc3, properties); + if (ret < 0) + return ret; + + if (pdev->device == PCI_DEVICE_ID_INTEL_BYT) { + struct gpio_desc *gpio; + + acpi_dev_add_driver_gpios(ACPI_COMPANION(&pdev->dev), + acpi_dwc3_byt_gpios); + + /* + * These GPIOs will turn on the USB2 PHY. Note that we have to + * put the gpio descriptors again here because the phy driver + * might want to grab them, too. + */ + gpio = gpiod_get_optional(&pdev->dev, "cs", GPIOD_OUT_LOW); + if (IS_ERR(gpio)) + return PTR_ERR(gpio); + gpiod_set_value_cansleep(gpio, 1); gpiod_put(gpio); - usleep_range(10000, 11000); + + gpio = gpiod_get_optional(&pdev->dev, "reset", GPIOD_OUT_LOW); + if (IS_ERR(gpio)) + return PTR_ERR(gpio); + + if (gpio) { + gpiod_set_value_cansleep(gpio, 1); + gpiod_put(gpio); + usleep_range(10000, 11000); + } } } -- cgit v0.10.2 From 5f82279a0c76825bfc6f5fa213ff82c932161462 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Tue, 7 Jun 2016 12:55:19 +0300 Subject: usb: dwc3: core: fixup dr_mode fallback selection We shouldn't change a host-only dwc3 to gadget-only if driver is built as gadget-only. Fix that up here. Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index 9c4e1d8d..8fceeb1 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -975,9 +975,13 @@ static int dwc3_probe(struct platform_device *pdev) goto err0; } - if (IS_ENABLED(CONFIG_USB_DWC3_HOST)) + if (IS_ENABLED(CONFIG_USB_DWC3_HOST) && + (dwc->dr_mode == USB_DR_MODE_OTG || + dwc->dr_mode == USB_DR_MODE_UNKNOWN)) dwc->dr_mode = USB_DR_MODE_HOST; - else if (IS_ENABLED(CONFIG_USB_DWC3_GADGET)) + else if (IS_ENABLED(CONFIG_USB_DWC3_GADGET) && + (dwc->dr_mode == USB_DR_MODE_OTG || + dwc->dr_mode == USB_DR_MODE_UNKNOWN)) dwc->dr_mode = USB_DR_MODE_PERIPHERAL; if (dwc->dr_mode == USB_DR_MODE_UNKNOWN) -- cgit v0.10.2 From d807bdd02845d53047346a4ba6d8934597fba6d6 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Thu, 9 Jun 2016 16:24:08 +0300 Subject: usb: dwc3: gadget: remove udelay() from run_stop() testing shows that udelay() is unnecessary as controller reaches Halted state almost instantenously as can be seen by our timeout variable never actually decrementing. Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index c889ee3..b3b5df6 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -1584,7 +1584,6 @@ static int dwc3_gadget_run_stop(struct dwc3 *dwc, int is_on, int suspend) timeout--; if (!timeout) return -ETIMEDOUT; - udelay(1); } while (1); dwc3_trace(trace_dwc3_gadget, "gadget %s data soft-%s", -- cgit v0.10.2 From f2df679b6c556fd3b0b7ffafea170f1679086455 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Thu, 9 Jun 2016 16:31:34 +0300 Subject: usb: dwc3: gadget: avoid while(1) in run_stop() instead of looping forever and forcing a return if timeout reaches zero, we can just use timeout and loop's break condition directly. Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index b3b5df6..9b9367b 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -1581,10 +1581,10 @@ static int dwc3_gadget_run_stop(struct dwc3 *dwc, int is_on, int suspend) if (reg & DWC3_DSTS_DEVCTRLHLT) break; } - timeout--; - if (!timeout) - return -ETIMEDOUT; - } while (1); + } while (--timeout); + + if (!timeout) + return -ETIMEDOUT; dwc3_trace(trace_dwc3_gadget, "gadget %s data soft-%s", dwc->gadget_driver -- cgit v0.10.2 From b6d4e16e831376b676edb3463f2bdaa192e5f7be Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Thu, 9 Jun 2016 16:47:05 +0300 Subject: usb: dwc3: gadget: simplify run_stop() break condition it's clear now that when is_on=true, we must loop until DWC3_DSTS_DEVCTRLHLT clears; while when is_on=false we must loop until DWC3_DSTS_DEVCTRLHLT gets set. Instead of adding actual if() statements, we can rely on XOR operation to evaluate to true only when the above conditions apply. Then, we can move the break condition back to the while() statement together with our timeout check and the resulting code is very compact and simpler to read. Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 9b9367b..0afaa9d 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -1574,14 +1574,8 @@ static int dwc3_gadget_run_stop(struct dwc3 *dwc, int is_on, int suspend) do { reg = dwc3_readl(dwc->regs, DWC3_DSTS); - if (is_on) { - if (!(reg & DWC3_DSTS_DEVCTRLHLT)) - break; - } else { - if (reg & DWC3_DSTS_DEVCTRLHLT) - break; - } - } while (--timeout); + reg &= DWC3_DSTS_DEVCTRLHLT; + } while (--timeout && !(!is_on ^ !reg)); if (!timeout) return -ETIMEDOUT; -- cgit v0.10.2 From 328082376aea6016b63bca1e5c067a9539f9e8c9 Mon Sep 17 00:00:00 2001 From: Roger Quadros Date: Fri, 10 Jun 2016 14:38:02 +0300 Subject: usb: dwc3: fix runtime PM in error path If there is a failure after pm_runtime_enable/get_sync() we need to call pm_runtime_disable/put_sync(). Otherwise it will lead to an unbalanced pm_runtime_enable() on the subsequent probe if the earlier probe bailed out due to -EPROBE_DEFER. pm_runtime_get_sync() can fail as well so deal with that case too. Signed-off-by: Roger Quadros Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index 8fceeb1..ca22e48 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -965,14 +965,17 @@ static int dwc3_probe(struct platform_device *pdev) pm_runtime_use_autosuspend(dev); pm_runtime_set_autosuspend_delay(dev, DWC3_DEFAULT_AUTOSUSPEND_DELAY); pm_runtime_enable(dev); - pm_runtime_get_sync(dev); + ret = pm_runtime_get_sync(dev); + if (ret < 0) + goto err1; + pm_runtime_forbid(dev); ret = dwc3_alloc_event_buffers(dwc, DWC3_EVENT_BUFFERS_SIZE); if (ret) { dev_err(dwc->dev, "failed to allocate event buffers\n"); ret = -ENOMEM; - goto err0; + goto err2; } if (IS_ENABLED(CONFIG_USB_DWC3_HOST) && @@ -989,12 +992,12 @@ static int dwc3_probe(struct platform_device *pdev) ret = dwc3_alloc_scratch_buffers(dwc); if (ret) - goto err1; + goto err3; ret = dwc3_core_init(dwc); if (ret) { dev_err(dev, "failed to initialize core\n"); - goto err2; + goto err4; } /* Check the maximum_speed parameter */ @@ -1026,23 +1029,30 @@ static int dwc3_probe(struct platform_device *pdev) ret = dwc3_core_init_mode(dwc); if (ret) - goto err3; + goto err5; dwc3_debugfs_init(dwc); pm_runtime_put(dev); return 0; -err3: +err5: dwc3_event_buffers_cleanup(dwc); -err2: +err4: dwc3_free_scratch_buffers(dwc); -err1: +err3: dwc3_free_event_buffers(dwc); dwc3_ulpi_exit(dwc); +err2: + pm_runtime_allow(&pdev->dev); + +err1: + pm_runtime_put_sync(&pdev->dev); + pm_runtime_disable(&pdev->dev); + err0: /* * restore res->start back to its original value so that, in case the -- cgit v0.10.2 From 0e146028eebf989e86d3fe9385b76434e954c84e Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Tue, 21 Jun 2016 10:32:02 +0300 Subject: usb: dwc3: gadget: issue ENDTRANSFER conditional on resource_index Because of recent changes to transfer handling on DWC3, we will not get XferComplete unless we completely fill up our TRB ring. This means that we might get a Reset or Disconnect without getting a XferComplete first. In order to correctly release our allocated Transfer Resource, we must issue ENDTRANSFER command whenever dep->resource_index is valid. Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 0afaa9d..b1fec36 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -607,24 +607,14 @@ static void dwc3_stop_active_transfer(struct dwc3 *dwc, u32 epnum, bool force); static void dwc3_remove_requests(struct dwc3 *dwc, struct dwc3_ep *dep) { struct dwc3_request *req; - struct dwc3_trb *current_trb; - unsigned transfer_in_flight; - if (dep->number > 1) - current_trb = &dep->trb_pool[dep->trb_enqueue]; - else - current_trb = &dwc->ep0_trb[dep->trb_enqueue]; - transfer_in_flight = current_trb->ctrl & DWC3_TRB_CTRL_HWO; - - if (transfer_in_flight && !list_empty(&dep->started_list)) { - dwc3_stop_active_transfer(dwc, dep->number, true); + dwc3_stop_active_transfer(dwc, dep->number, true); - /* - giveback all requests to gadget driver */ - while (!list_empty(&dep->started_list)) { - req = next_request(&dep->started_list); + /* - giveback all requests to gadget driver */ + while (!list_empty(&dep->started_list)) { + req = next_request(&dep->started_list); - dwc3_gadget_giveback(dep, req, -ESHUTDOWN); - } + dwc3_gadget_giveback(dep, req, -ESHUTDOWN); } while (!list_empty(&dep->pending_list)) { -- cgit v0.10.2 From da1410be21bfedd16740aee6d772e669cf4e852f Mon Sep 17 00:00:00 2001 From: Baolin Wang Date: Mon, 20 Jun 2016 16:19:48 +0800 Subject: usb: dwc3: gadget: Add the suspend state checking when stopping gadget It will be crash to stop gadget when the dwc3 device had been into suspend state, thus we need to check if the dwc3 device had been into suspend state when UDC try to stop gadget. Signed-off-by: Baolin Wang Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index b1fec36..b9bc646 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -1803,6 +1803,9 @@ err0: static void __dwc3_gadget_stop(struct dwc3 *dwc) { + if (pm_runtime_suspended(dwc->dev)) + return; + dwc3_gadget_disable_irq(dwc); __dwc3_gadget_ep_disable(dwc->eps[0]); __dwc3_gadget_ep_disable(dwc->eps[1]); -- cgit v0.10.2 From b89e5f1a677f3a711047d686115f2416e1200a3b Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Thu, 16 Jun 2016 13:38:25 +0200 Subject: usb: pxa27x_udc: remove unused function argument We get a warning for this when building with W=1 because the argument gets assigned to something else but never read: drivers/usb/gadget/udc/pxa27x_udc.c: In function 'stop_activity': drivers/usb/gadget/udc/pxa27x_udc.c:1828:74: error: parameter 'driver' set but not used [-Werror=unused-but-set-parameter] This remove the argument entirely. Acked-by: Robert Jarzmik Signed-off-by: Arnd Bergmann Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/udc/pxa27x_udc.c b/drivers/usb/gadget/udc/pxa27x_udc.c index 001a3b7..ad140aa 100644 --- a/drivers/usb/gadget/udc/pxa27x_udc.c +++ b/drivers/usb/gadget/udc/pxa27x_udc.c @@ -1825,13 +1825,10 @@ fail: * Disables all udc endpoints (even control endpoint), report disconnect to * the gadget user. */ -static void stop_activity(struct pxa_udc *udc, struct usb_gadget_driver *driver) +static void stop_activity(struct pxa_udc *udc) { int i; - /* don't disconnect drivers more than once */ - if (udc->gadget.speed == USB_SPEED_UNKNOWN) - driver = NULL; udc->gadget.speed = USB_SPEED_UNKNOWN; for (i = 0; i < NR_USB_ENDPOINTS; i++) @@ -1848,7 +1845,7 @@ static int pxa27x_udc_stop(struct usb_gadget *g) { struct pxa_udc *udc = to_pxa(g); - stop_activity(udc, NULL); + stop_activity(udc); udc_disable(udc); udc->driver = NULL; @@ -2296,7 +2293,7 @@ static void irq_udc_reset(struct pxa_udc *udc) if ((udccr & UDCCR_UDA) == 0) { dev_dbg(udc->dev, "USB reset start\n"); - stop_activity(udc, udc->driver); + stop_activity(udc); } udc->gadget.speed = USB_SPEED_FULL; memset(&udc->stats, 0, sizeof udc->stats); -- cgit v0.10.2 From 106528b21df7dd9da9ca3e5e4ff4e015c33211be Mon Sep 17 00:00:00 2001 From: Vardan Mikayelyan Date: Wed, 25 May 2016 18:06:53 -0700 Subject: usb: dwc2: Add missing register field definitions Added register field definitions, register names are according DWC-OTG databook. Tested-by: John Keeping Signed-off-by: Vardan Mikayelyan Signed-off-by: John Youn Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc2/hw.h b/drivers/usb/dwc2/hw.h index 281b57b..1126141 100644 --- a/drivers/usb/dwc2/hw.h +++ b/drivers/usb/dwc2/hw.h @@ -459,6 +459,9 @@ #define DSTS_SUSPSTS (1 << 0) #define DIEPMSK HSOTG_REG(0x810) +#define DIEPMSK_NAKMSK (1 << 13) +#define DIEPMSK_BNAININTRMSK (1 << 9) +#define DIEPMSK_TXFIFOUNDRNMSK (1 << 8) #define DIEPMSK_TXFIFOEMPTY (1 << 7) #define DIEPMSK_INEPNAKEFFMSK (1 << 6) #define DIEPMSK_INTKNEPMISMSK (1 << 5) @@ -470,6 +473,7 @@ #define DOEPMSK HSOTG_REG(0x814) #define DOEPMSK_BACK2BACKSETUP (1 << 6) +#define DOEPMSK_STSPHSERCVDMSK (1 << 5) #define DOEPMSK_OUTTKNEPDISMSK (1 << 4) #define DOEPMSK_SETUPMSK (1 << 3) #define DOEPMSK_AHBERRMSK (1 << 2) @@ -486,6 +490,7 @@ #define DTKNQR2 HSOTG_REG(0x824) #define DTKNQR3 HSOTG_REG(0x830) #define DTKNQR4 HSOTG_REG(0x834) +#define DIEPEMPMSK HSOTG_REG(0x834) #define DVBUSDIS HSOTG_REG(0x828) #define DVBUSPULSE HSOTG_REG(0x82C) @@ -544,6 +549,14 @@ #define DIEPINT(_a) HSOTG_REG(0x908 + ((_a) * 0x20)) #define DOEPINT(_a) HSOTG_REG(0xB08 + ((_a) * 0x20)) #define DXEPINT_SETUP_RCVD (1 << 15) +#define DXEPINT_NYETINTRPT (1 << 14) +#define DXEPINT_NAKINTRPT (1 << 13) +#define DXEPINT_BBLEERRINTRPT (1 << 12) +#define DXEPINT_PKTDRPSTS (1 << 11) +#define DXEPINT_BNAINTR (1 << 9) +#define DXEPINT_TXFIFOUNDRN (1 << 8) +#define DXEPINT_OUTPKTERR (1 << 8) +#define DXEPINT_TXFEMP (1 << 7) #define DXEPINT_INEPNAKEFF (1 << 6) #define DXEPINT_BACK2BACKSETUP (1 << 6) #define DXEPINT_INTKNEPMIS (1 << 5) -- cgit v0.10.2 From 04cde4787d8d9c56bd7b0bc5ee15af4435275134 Mon Sep 17 00:00:00 2001 From: Vardan Mikayelyan Date: Wed, 25 May 2016 18:06:55 -0700 Subject: usb: dwc2: gadget: Remove unnecessary line Removed "ctrl |= DXEPCTL_USBACTEP" from dwc2_hsotg_start_req() function because this step is done in dwc2_hsotg_ep_enable(). Tested-by: John Keeping Signed-off-by: Vardan Mikayelyan Signed-off-by: John Youn Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc2/gadget.c b/drivers/usb/dwc2/gadget.c index 26cf09d..34c63e9 100644 --- a/drivers/usb/dwc2/gadget.c +++ b/drivers/usb/dwc2/gadget.c @@ -632,7 +632,6 @@ static void dwc2_hsotg_start_req(struct dwc2_hsotg *hsotg, } ctrl |= DXEPCTL_EPENA; /* ensure ep enabled */ - ctrl |= DXEPCTL_USBACTEP; dev_dbg(hsotg->dev, "ep0 state:%d\n", hsotg->ep0_state); -- cgit v0.10.2 From 7c01b99154c5819bb811100738880a1341bca64a Mon Sep 17 00:00:00 2001 From: Vardan Mikayelyan Date: Wed, 25 May 2016 18:06:58 -0700 Subject: usb: dwc2: gadget: Remove unnecessary code This chunk is not needed here. There is no functionality depend on this, so if no-op, I think we do not need to have this interrupt unmasked. Tested-by: John Keeping Signed-off-by: Vardan Mikayelyan Signed-off-by: John Youn Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc2/gadget.c b/drivers/usb/dwc2/gadget.c index 34c63e9..1487968 100644 --- a/drivers/usb/dwc2/gadget.c +++ b/drivers/usb/dwc2/gadget.c @@ -658,14 +658,6 @@ static void dwc2_hsotg_start_req(struct dwc2_hsotg *hsotg, } /* - * clear the INTknTXFEmpMsk when we start request, more as a aide - * to debugging to see what is going on. - */ - if (dir_in) - dwc2_writel(DIEPMSK_INTKNTXFEMPMSK, - hsotg->regs + DIEPINT(index)); - - /* * Note, trying to clear the NAK here causes problems with transmit * on the S3C6400 ending up with the TXFIFO becoming full. */ -- cgit v0.10.2 From 26ddef5da62993fb9189a822d3545fc00451d242 Mon Sep 17 00:00:00 2001 From: Vardan Mikayelyan Date: Wed, 25 May 2016 18:07:00 -0700 Subject: usb: dwc2: gadget: Corrected field names No-op change. Changed field names to prevent misunderstanding. Tested-by: John Keeping Signed-off-by: Vardan Mikayelyan Signed-off-by: John Youn Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc2/gadget.c b/drivers/usb/dwc2/gadget.c index 1487968..7168172 100644 --- a/drivers/usb/dwc2/gadget.c +++ b/drivers/usb/dwc2/gadget.c @@ -2037,20 +2037,20 @@ static void dwc2_hsotg_epint(struct dwc2_hsotg *hsotg, unsigned int idx, if (dir_in && !hs_ep->isochronous) { /* not sure if this is important, but we'll clear it anyway */ - if (ints & DIEPMSK_INTKNTXFEMPMSK) { + if (ints & DXEPINT_INTKNTXFEMP) { dev_dbg(hsotg->dev, "%s: ep%d: INTknTXFEmpMsk\n", __func__, idx); } /* this probably means something bad is happening */ - if (ints & DIEPMSK_INTKNEPMISMSK) { + if (ints & DXEPINT_INTKNEPMIS) { dev_warn(hsotg->dev, "%s: ep%d: INTknEP\n", __func__, idx); } /* FIFO has space or is empty (see GAHBCFG) */ if (hsotg->dedicated_fifos && - ints & DIEPMSK_TXFIFOEMPTY) { + ints & DXEPINT_TXFEMP) { dev_dbg(hsotg->dev, "%s: ep%d: TxFIFOEmpty\n", __func__, idx); if (!using_dma(hsotg)) -- cgit v0.10.2 From 6b58cb07a850f9b6d348feb2455b2c264a515f4a Mon Sep 17 00:00:00 2001 From: Vardan Mikayelyan Date: Wed, 25 May 2016 18:07:02 -0700 Subject: usb: dwc2: gadget: Fix transfer stop programming for out endpoint According DWC-OTG databook, "GOUTNakEff" is read only and can be cleared only by "DCTL.CGOUTNak", but here we do not need to clear it because DWC-OTG programming guide says that before disabling any OUT endpoint, the application must enable Global OUT NAK mode, so if this mode is enabled we can continue without this step. Tested-by: John Keeping Signed-off-by: Vardan Mikayelyan Signed-off-by: John Youn Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc2/gadget.c b/drivers/usb/dwc2/gadget.c index 7168172..54d242b 100644 --- a/drivers/usb/dwc2/gadget.c +++ b/drivers/usb/dwc2/gadget.c @@ -2866,10 +2866,8 @@ static void dwc2_hsotg_ep_stop_xfr(struct dwc2_hsotg *hsotg, dev_warn(hsotg->dev, "%s: timeout DIEPINT.NAKEFF\n", __func__); } else { - /* Clear any pending nak effect interrupt */ - dwc2_writel(GINTSTS_GOUTNAKEFF, hsotg->regs + GINTSTS); - - __orr32(hsotg->regs + DCTL, DCTL_SGOUTNAK); + if (!(dwc2_readl(hsotg->regs + GINTSTS) & GINTSTS_GOUTNAKEFF)) + __orr32(hsotg->regs + DCTL, DCTL_SGOUTNAK); /* Wait for global nak to take effect */ if (dwc2_hsotg_wait_bit_set(hsotg, GINTSTS, -- cgit v0.10.2 From 92d1635d781ac17fc7d886b0c126838083f3c2b9 Mon Sep 17 00:00:00 2001 From: Vardan Mikayelyan Date: Wed, 25 May 2016 18:07:05 -0700 Subject: usb: dwc2: gadget: Add dwc2_gadget_incr_frame_num() Increases and checks targeted frame number of current ep if overrun happened, sets flag and masks with DSTS_SOFFN_LIMIT Added following fields to struct dwc2_hsotg_ep -target_frame: Targeted frame num to setup next ISOC transfer -frame_overrun: Indicates SOF number overrun in DSTS Tested-by: John Keeping Signed-off-by: Vardan Mikayelyan Signed-off-by: John Youn Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc2/core.h b/drivers/usb/dwc2/core.h index dec0b21..5516099 100644 --- a/drivers/usb/dwc2/core.h +++ b/drivers/usb/dwc2/core.h @@ -177,6 +177,8 @@ struct dwc2_hsotg_req; * @fifo_load: The amount of data loaded into the FIFO (periodic IN) * @last_load: The offset of data for the last start of request. * @size_loaded: The last loaded size for DxEPTSIZE for periodic IN + * @target_frame: Targeted frame num to setup next ISOC transfer + * @frame_overrun: Indicates SOF number overrun in DSTS * * This is the driver's state for each registered enpoint, allowing it * to keep track of transactions that need doing. Each endpoint has a @@ -214,6 +216,9 @@ struct dwc2_hsotg_ep { unsigned int isochronous:1; unsigned int send_zlp:1; unsigned int has_correct_parity:1; + unsigned int target_frame; +#define TARGET_FRAME_INITIAL 0xFFFFFFFF + bool frame_overrun; char name[10]; }; diff --git a/drivers/usb/dwc2/gadget.c b/drivers/usb/dwc2/gadget.c index 54d242b..b8f3661 100644 --- a/drivers/usb/dwc2/gadget.c +++ b/drivers/usb/dwc2/gadget.c @@ -97,6 +97,25 @@ static inline bool using_dma(struct dwc2_hsotg *hsotg) } /** + * dwc2_gadget_incr_frame_num - Increments the targeted frame number. + * @hs_ep: The endpoint + * @increment: The value to increment by + * + * This function will also check if the frame number overruns DSTS_SOFFN_LIMIT. + * If an overrun occurs it will wrap the value and set the frame_overrun flag. + */ +static inline void dwc2_gadget_incr_frame_num(struct dwc2_hsotg_ep *hs_ep) +{ + hs_ep->target_frame += hs_ep->interval; + if (hs_ep->target_frame > DSTS_SOFFN_LIMIT) { + hs_ep->frame_overrun = 1; + hs_ep->target_frame &= DSTS_SOFFN_LIMIT; + } else { + hs_ep->frame_overrun = 0; + } +} + +/** * dwc2_hsotg_en_gsint - enable one or more of the general interrupt * @hsotg: The device state * @ints: A bitmask of the interrupts to enable -- cgit v0.10.2 From 142bd33fcd185d850178f7f8697ecbeaaa18e257 Mon Sep 17 00:00:00 2001 From: Vardan Mikayelyan Date: Wed, 25 May 2016 18:07:07 -0700 Subject: usb: dwc2: gadget: Corrected interval calculation Calculate the interval according to the USB 2.0 specification section 9.6.6. Tested-by: John Keeping Signed-off-by: Vardan Mikayelyan Signed-off-by: John Youn Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc2/core.h b/drivers/usb/dwc2/core.h index 5516099..0ba3599 100644 --- a/drivers/usb/dwc2/core.h +++ b/drivers/usb/dwc2/core.h @@ -166,7 +166,7 @@ struct dwc2_hsotg_req; * means that it is sending data to the Host. * @index: The index for the endpoint registers. * @mc: Multi Count - number of transactions per microframe - * @interval - Interval for periodic endpoints + * @interval - Interval for periodic endpoints, in frames or microframes. * @name: The name array passed to the USB core. * @halted: Set if the endpoint has been halted. * @periodic: Set if this is a periodic ep, such as Interrupt diff --git a/drivers/usb/dwc2/gadget.c b/drivers/usb/dwc2/gadget.c index b8f3661..2cef7a9 100644 --- a/drivers/usb/dwc2/gadget.c +++ b/drivers/usb/dwc2/gadget.c @@ -2693,16 +2693,13 @@ static int dwc2_hsotg_ep_enable(struct usb_ep *ep, hs_ep->periodic = 0; hs_ep->halted = 0; hs_ep->interval = desc->bInterval; - hs_ep->has_correct_parity = 0; - - if (hs_ep->interval > 1 && hs_ep->mc > 1) - dev_err(hsotg->dev, "MC > 1 when interval is not 1\n"); switch (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) { case USB_ENDPOINT_XFER_ISOC: epctrl |= DXEPCTL_EPTYPE_ISO; epctrl |= DXEPCTL_SETEVENFR; hs_ep->isochronous = 1; + hs_ep->interval = 1 << (desc->bInterval - 1); if (dir_in) hs_ep->periodic = 1; break; @@ -2715,6 +2712,9 @@ static int dwc2_hsotg_ep_enable(struct usb_ep *ep, if (dir_in) hs_ep->periodic = 1; + if (hsotg->gadget.speed == USB_SPEED_HIGH) + hs_ep->interval = 1 << (desc->bInterval - 1); + epctrl |= DXEPCTL_EPTYPE_INTERRUPT; break; -- cgit v0.10.2 From 326015887b6a1321fd61f7a16816241ad841a03c Mon Sep 17 00:00:00 2001 From: Vardan Mikayelyan Date: Wed, 25 May 2016 18:07:10 -0700 Subject: usb: dwc2: gadget: Add dwc2_gadget_read_ep_interrupts function Reads and returns interrupts for given endpoint, by masking epint_reg with corresponding mask. Tested-by: John Keeping Signed-off-by: Vardan Mikayelyan Signed-off-by: John Youn Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc2/gadget.c b/drivers/usb/dwc2/gadget.c index 2cef7a9..8139efd 100644 --- a/drivers/usb/dwc2/gadget.c +++ b/drivers/usb/dwc2/gadget.c @@ -1947,6 +1947,34 @@ static void dwc2_hsotg_complete_in(struct dwc2_hsotg *hsotg, } /** + * dwc2_gadget_read_ep_interrupts - reads interrupts for given ep + * @hsotg: The device state. + * @idx: Index of ep. + * @dir_in: Endpoint direction 1-in 0-out. + * + * Reads for endpoint with given index and direction, by masking + * epint_reg with coresponding mask. + */ +static u32 dwc2_gadget_read_ep_interrupts(struct dwc2_hsotg *hsotg, + unsigned int idx, int dir_in) +{ + u32 epmsk_reg = dir_in ? DIEPMSK : DOEPMSK; + u32 epint_reg = dir_in ? DIEPINT(idx) : DOEPINT(idx); + u32 ints; + u32 mask; + u32 diepempmsk; + + mask = dwc2_readl(hsotg->regs + epmsk_reg); + diepempmsk = dwc2_readl(hsotg->regs + DIEPEMPMSK); + mask |= ((diepempmsk >> idx) & 0x1) ? DIEPMSK_TXFIFOEMPTY : 0; + mask |= DXEPINT_SETUP_RCVD; + + ints = dwc2_readl(hsotg->regs + epint_reg); + ints &= mask; + return ints; +} + +/** * dwc2_hsotg_epint - handle an in/out endpoint interrupt * @hsotg: The driver state * @idx: The index for the endpoint (0..15) @@ -1964,7 +1992,7 @@ static void dwc2_hsotg_epint(struct dwc2_hsotg *hsotg, unsigned int idx, u32 ints; u32 ctrl; - ints = dwc2_readl(hsotg->regs + epint_reg); + ints = dwc2_gadget_read_ep_interrupts(hsotg, idx, dir_in); ctrl = dwc2_readl(hsotg->regs + epctl_reg); /* Clear endpoint interrupts */ -- cgit v0.10.2 From 41cc4cd2716fa6d18a1a09d740ea075adecfa7dd Mon Sep 17 00:00:00 2001 From: Vardan Mikayelyan Date: Wed, 25 May 2016 18:07:12 -0700 Subject: usb: dwc2: gadget: Add dwc2_gadget_start_next_request function Replaced repeating code with function call. Starts next request from ep queue. If queue is empty and ep is isoc -In case of OUT-EP unmasks OUTTKNEPDIS. OUTTKNEPDIS is masked in it's handler, so we need to unmask it here to be able to do resynchronization. Tested-by: John Keeping Signed-off-by: Vardan Mikayelyan Signed-off-by: John Youn Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc2/gadget.c b/drivers/usb/dwc2/gadget.c index 8139efd..7db9f9f 100644 --- a/drivers/usb/dwc2/gadget.c +++ b/drivers/usb/dwc2/gadget.c @@ -1045,6 +1045,42 @@ static struct dwc2_hsotg_req *get_ep_head(struct dwc2_hsotg_ep *hs_ep) } /** + * dwc2_gadget_start_next_request - Starts next request from ep queue + * @hs_ep: Endpoint structure + * + * If queue is empty and EP is ISOC-OUT - unmasks OUTTKNEPDIS which is masked + * in its handler. Hence we need to unmask it here to be able to do + * resynchronization. + */ +static void dwc2_gadget_start_next_request(struct dwc2_hsotg_ep *hs_ep) +{ + u32 mask; + struct dwc2_hsotg *hsotg = hs_ep->parent; + int dir_in = hs_ep->dir_in; + struct dwc2_hsotg_req *hs_req; + u32 epmsk_reg = dir_in ? DIEPMSK : DOEPMSK; + + if (!list_empty(&hs_ep->queue)) { + hs_req = get_ep_head(hs_ep); + dwc2_hsotg_start_req(hsotg, hs_ep, hs_req, false); + return; + } + if (!hs_ep->isochronous) + return; + + if (dir_in) { + dev_dbg(hsotg->dev, "%s: No more ISOC-IN requests\n", + __func__); + } else { + dev_dbg(hsotg->dev, "%s: No more ISOC-OUT requests\n", + __func__); + mask = dwc2_readl(hsotg->regs + epmsk_reg); + mask |= DOEPMSK_OUTTKNEPDISMSK; + dwc2_writel(mask, hsotg->regs + epmsk_reg); + } +} + +/** * dwc2_hsotg_process_req_feature - process request {SET,CLEAR}_FEATURE * @hsotg: The device state * @ctrl: USB control request @@ -1054,7 +1090,6 @@ static int dwc2_hsotg_process_req_feature(struct dwc2_hsotg *hsotg, { struct dwc2_hsotg_ep *ep0 = hsotg->eps_out[0]; struct dwc2_hsotg_req *hs_req; - bool restart; bool set = (ctrl->bRequest == USB_REQ_SET_FEATURE); struct dwc2_hsotg_ep *ep; int ret; @@ -1137,12 +1172,7 @@ static int dwc2_hsotg_process_req_feature(struct dwc2_hsotg *hsotg, /* If we have pending request, then start it */ if (!ep->req) { - restart = !list_empty(&ep->queue); - if (restart) { - hs_req = get_ep_head(ep); - dwc2_hsotg_start_req(hsotg, ep, - hs_req, false); - } + dwc2_gadget_start_next_request(ep); } } @@ -1383,7 +1413,6 @@ static void dwc2_hsotg_complete_request(struct dwc2_hsotg *hsotg, struct dwc2_hsotg_req *hs_req, int result) { - bool restart; if (!hs_req) { dev_dbg(hsotg->dev, "%s: nothing to complete?\n", __func__); @@ -1427,11 +1456,7 @@ static void dwc2_hsotg_complete_request(struct dwc2_hsotg *hsotg, */ if (!hs_ep->req && result >= 0) { - restart = !list_empty(&hs_ep->queue); - if (restart) { - hs_req = get_ep_head(hs_ep); - dwc2_hsotg_start_req(hsotg, hs_ep, hs_req, false); - } + dwc2_gadget_start_next_request(hs_ep); } } -- cgit v0.10.2 From 5321922cb6fa0f513fdd8ce73b281f4b9957886b Mon Sep 17 00:00:00 2001 From: Vardan Mikayelyan Date: Wed, 25 May 2016 18:07:14 -0700 Subject: usb: dwc2: gadget: Add OUTTKNEPDIS and NAKINTRPT handlers NAKINTRPT interrupt is starting point for isoc-in transfer, synchronization done with first in token received from host, core asserts this interrupt when responds with 0 length data to in token, received from host. The first IN token is asynchronous for device - device does not know when first one token will arrive from host. On first token arrival HW generates 2 interrupts: 'in token received while FIFO empty' and 'NAK'. NAK interrupt for ISOC in means that token has arrived and ZLP was sent in response to that as there was no data in FIFO. SW is basing on this interrupt to obtain frame in which token has come and then based on the interval calculates next frame for transfer. OUTTKNEPDIS interrupt is starting point for isoc-out transfer, synchronization done with first out token received from host while corresponding ep is disabled. For OUTs the reason is same - device does not know initial frame in which out token will come. For this HW generates OUTTKNEPDIS - out token is received while EP is disabled. Upon getting this interrupt SW starts calculation for next transfer frame. Tested-by: John Keeping Signed-off-by: Vardan Mikayelyan Signed-off-by: John Youn Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc2/gadget.c b/drivers/usb/dwc2/gadget.c index 7db9f9f..256c929 100644 --- a/drivers/usb/dwc2/gadget.c +++ b/drivers/usb/dwc2/gadget.c @@ -2000,6 +2000,94 @@ static u32 dwc2_gadget_read_ep_interrupts(struct dwc2_hsotg *hsotg, } /** + * dwc2_gadget_handle_out_token_ep_disabled - handle DXEPINT_OUTTKNEPDIS + * @hs_ep: The endpoint on which interrupt is asserted. + * + * This is starting point for ISOC-OUT transfer, synchronization done with + * first out token received from host while corresponding EP is disabled. + * + * Device does not know initial frame in which out token will come. For this + * HW generates OUTTKNEPDIS - out token is received while EP is disabled. Upon + * getting this interrupt SW starts calculation for next transfer frame. + */ +static void dwc2_gadget_handle_out_token_ep_disabled(struct dwc2_hsotg_ep *ep) +{ + struct dwc2_hsotg *hsotg = ep->parent; + int dir_in = ep->dir_in; + u32 doepmsk; + + if (dir_in || !ep->isochronous) + return; + + dwc2_hsotg_complete_request(hsotg, ep, get_ep_head(ep), -ENODATA); + + if (ep->interval > 1 && + ep->target_frame == TARGET_FRAME_INITIAL) { + u32 dsts; + u32 ctrl; + + dsts = dwc2_readl(hsotg->regs + DSTS); + ep->target_frame = dwc2_hsotg_read_frameno(hsotg); + dwc2_gadget_incr_frame_num(ep); + + ctrl = dwc2_readl(hsotg->regs + DOEPCTL(ep->index)); + if (ep->target_frame & 0x1) + ctrl |= DXEPCTL_SETODDFR; + else + ctrl |= DXEPCTL_SETEVENFR; + + dwc2_writel(ctrl, hsotg->regs + DOEPCTL(ep->index)); + } + + dwc2_gadget_start_next_request(ep); + doepmsk = dwc2_readl(hsotg->regs + DOEPMSK); + doepmsk &= ~DOEPMSK_OUTTKNEPDISMSK; + dwc2_writel(doepmsk, hsotg->regs + DOEPMSK); +} + +/** +* dwc2_gadget_handle_nak - handle NAK interrupt +* @hs_ep: The endpoint on which interrupt is asserted. +* +* This is starting point for ISOC-IN transfer, synchronization done with +* first IN token received from host while corresponding EP is disabled. +* +* Device does not know when first one token will arrive from host. On first +* token arrival HW generates 2 interrupts: 'in token received while FIFO empty' +* and 'NAK'. NAK interrupt for ISOC-IN means that token has arrived and ZLP was +* sent in response to that as there was no data in FIFO. SW is basing on this +* interrupt to obtain frame in which token has come and then based on the +* interval calculates next frame for transfer. +*/ +static void dwc2_gadget_handle_nak(struct dwc2_hsotg_ep *hs_ep) +{ + struct dwc2_hsotg *hsotg = hs_ep->parent; + int dir_in = hs_ep->dir_in; + + if (!dir_in || !hs_ep->isochronous) + return; + + if (hs_ep->target_frame == TARGET_FRAME_INITIAL) { + hs_ep->target_frame = dwc2_hsotg_read_frameno(hsotg); + if (hs_ep->interval > 1) { + u32 ctrl = dwc2_readl(hsotg->regs + + DIEPCTL(hs_ep->index)); + if (hs_ep->target_frame & 0x1) + ctrl |= DXEPCTL_SETODDFR; + else + ctrl |= DXEPCTL_SETEVENFR; + + dwc2_writel(ctrl, hsotg->regs + DIEPCTL(hs_ep->index)); + } + + dwc2_hsotg_complete_request(hsotg, hs_ep, + get_ep_head(hs_ep), 0); + } + + dwc2_gadget_incr_frame_num(hs_ep); +} + +/** * dwc2_hsotg_epint - handle an in/out endpoint interrupt * @hsotg: The driver state * @idx: The index for the endpoint (0..15) @@ -2083,6 +2171,12 @@ static void dwc2_hsotg_epint(struct dwc2_hsotg *hsotg, unsigned int idx, } } + if (ints & DXEPINT_OUTTKNEPDIS) + dwc2_gadget_handle_out_token_ep_disabled(hs_ep); + + if (ints & DXEPINT_NAKINTRPT) + dwc2_gadget_handle_nak(hs_ep); + if (ints & DXEPINT_AHBERR) dev_dbg(hsotg->dev, "%s: AHBErr\n", __func__); -- cgit v0.10.2 From 381fc8f8228923026b3d75c8230fa2ee4d688f32 Mon Sep 17 00:00:00 2001 From: Vardan Mikayelyan Date: Wed, 25 May 2016 18:07:17 -0700 Subject: usb: dwc2: gadget: Add Incomplete ISO IN/OUT Interrupt handlers Incomplete ISO IN interrupt indicates one of the following conditions occurred while transmitting an ISOC transaction. - Corrupted IN Token for ISOC EP. - Packet not complete in FIFO. Incomplete ISO OUT indicates that there is at least one isochronous OUT endpoint on which the transfer is not completed in the current microframe. The following actions will be taken: In case of EP-IN - Determine the EP - Disable EP directly from this handler; when "Endpoint Disabled" interrupt is received flush FIFO In case of EP-OUT - Determine the EP - If target frame elapsed set DCTL_SGOUTNAK, unmask GOUTNAKEFF and proceed as described in section 7.5.1 of DWC-HSOTG Programming Guide Also added dwc2_gadget_target_frame_elapsed() helper function which will be used in Incomplete ISO IN/OUT Interrupt handlers. Tested-by: John Keeping Signed-off-by: Vardan Mikayelyan Signed-off-by: John Youn Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc2/gadget.c b/drivers/usb/dwc2/gadget.c index 256c929..61f913d 100644 --- a/drivers/usb/dwc2/gadget.c +++ b/drivers/usb/dwc2/gadget.c @@ -523,6 +523,23 @@ static unsigned get_ep_limit(struct dwc2_hsotg_ep *hs_ep) } /** +* dwc2_hsotg_read_frameno - read current frame number +* @hsotg: The device instance +* +* Return the current frame number +*/ +static u32 dwc2_hsotg_read_frameno(struct dwc2_hsotg *hsotg) +{ + u32 dsts; + + dsts = dwc2_readl(hsotg->regs + DSTS); + dsts &= DSTS_SOFFN_MASK; + dsts >>= DSTS_SOFFN_SHIFT; + + return dsts; +} + +/** * dwc2_hsotg_start_req - start a USB request from an endpoint's queue * @hsotg: The controller state. * @hs_ep: The endpoint to process a request for @@ -783,6 +800,30 @@ static void dwc2_hsotg_handle_unaligned_buf_complete(struct dwc2_hsotg *hsotg, hs_req->saved_req_buf = NULL; } +/** + * dwc2_gadget_target_frame_elapsed - Checks target frame + * @hs_ep: The driver endpoint to check + * + * Returns 1 if targeted frame elapsed. If returned 1 then we need to drop + * corresponding transfer. + */ +static bool dwc2_gadget_target_frame_elapsed(struct dwc2_hsotg_ep *hs_ep) +{ + struct dwc2_hsotg *hsotg = hs_ep->parent; + u32 target_frame = hs_ep->target_frame; + u32 current_frame = dwc2_hsotg_read_frameno(hsotg); + bool frame_overrun = hs_ep->frame_overrun; + + if (!frame_overrun && current_frame >= target_frame) + return true; + + if (frame_overrun && current_frame >= target_frame && + ((current_frame - target_frame) < DSTS_SOFFN_LIMIT / 2)) + return true; + + return false; +} + static int dwc2_hsotg_ep_queue(struct usb_ep *ep, struct usb_request *req, gfp_t gfp_flags) { @@ -1641,23 +1682,6 @@ static void dwc2_hsotg_handle_outdone(struct dwc2_hsotg *hsotg, int epnum) } /** - * dwc2_hsotg_read_frameno - read current frame number - * @hsotg: The device instance - * - * Return the current frame number - */ -static u32 dwc2_hsotg_read_frameno(struct dwc2_hsotg *hsotg) -{ - u32 dsts; - - dsts = dwc2_readl(hsotg->regs + DSTS); - dsts &= DSTS_SOFFN_MASK; - dsts >>= DSTS_SOFFN_SHIFT; - - return dsts; -} - -/** * dwc2_hsotg_handle_rx - RX FIFO has data * @hsotg: The device instance * @@ -2571,6 +2595,85 @@ void dwc2_hsotg_core_connect(struct dwc2_hsotg *hsotg) } /** + * dwc2_gadget_handle_incomplete_isoc_in - handle incomplete ISO IN Interrupt. + * @hsotg: The device state: + * + * This interrupt indicates one of the following conditions occurred while + * transmitting an ISOC transaction. + * - Corrupted IN Token for ISOC EP. + * - Packet not complete in FIFO. + * + * The following actions will be taken: + * - Determine the EP + * - Disable EP; when 'Endpoint Disabled' interrupt is received Flush FIFO + */ +static void dwc2_gadget_handle_incomplete_isoc_in(struct dwc2_hsotg *hsotg) +{ + struct dwc2_hsotg_ep *hs_ep; + u32 epctrl; + u32 idx; + + dev_dbg(hsotg->dev, "Incomplete isoc in interrupt received:\n"); + + for (idx = 1; idx <= hsotg->num_of_eps; idx++) { + hs_ep = hsotg->eps_in[idx]; + epctrl = dwc2_readl(hsotg->regs + DIEPCTL(idx)); + if ((epctrl & DXEPCTL_EPENA) && hs_ep->isochronous && + dwc2_gadget_target_frame_elapsed(hs_ep)) { + epctrl |= DXEPCTL_SNAK; + epctrl |= DXEPCTL_EPDIS; + dwc2_writel(epctrl, hsotg->regs + DIEPCTL(idx)); + } + } + + /* Clear interrupt */ + dwc2_writel(GINTSTS_INCOMPL_SOIN, hsotg->regs + GINTSTS); +} + +/** + * dwc2_gadget_handle_incomplete_isoc_out - handle incomplete ISO OUT Interrupt + * @hsotg: The device state: + * + * This interrupt indicates one of the following conditions occurred while + * transmitting an ISOC transaction. + * - Corrupted OUT Token for ISOC EP. + * - Packet not complete in FIFO. + * + * The following actions will be taken: + * - Determine the EP + * - Set DCTL_SGOUTNAK and unmask GOUTNAKEFF if target frame elapsed. + */ +static void dwc2_gadget_handle_incomplete_isoc_out(struct dwc2_hsotg *hsotg) +{ + u32 gintsts; + u32 gintmsk; + u32 epctrl; + struct dwc2_hsotg_ep *hs_ep; + int idx; + + dev_dbg(hsotg->dev, "%s: GINTSTS_INCOMPL_SOOUT\n", __func__); + + for (idx = 1; idx <= hsotg->num_of_eps; idx++) { + hs_ep = hsotg->eps_out[idx]; + epctrl = dwc2_readl(hsotg->regs + DOEPCTL(idx)); + if ((epctrl & DXEPCTL_EPENA) && hs_ep->isochronous && + dwc2_gadget_target_frame_elapsed(hs_ep)) { + /* Unmask GOUTNAKEFF interrupt */ + gintmsk = dwc2_readl(hsotg->regs + GINTMSK); + gintmsk |= GINTSTS_GOUTNAKEFF; + dwc2_writel(gintmsk, hsotg->regs + GINTMSK); + + gintsts = dwc2_readl(hsotg->regs + GINTSTS); + if (!(gintsts & GINTSTS_GOUTNAKEFF)) + __orr32(hsotg->regs + DCTL, DCTL_SGOUTNAK); + } + } + + /* Clear interrupt */ + dwc2_writel(GINTSTS_INCOMPL_SOOUT, hsotg->regs + GINTSTS); +} + +/** * dwc2_hsotg_irq - handle device interrupt * @irq: The IRQ number triggered * @pw: The pw value when registered the handler. @@ -2717,39 +2820,11 @@ irq_retry: dwc2_hsotg_dump(hsotg); } - if (gintsts & GINTSTS_INCOMPL_SOIN) { - u32 idx, epctl_reg; - struct dwc2_hsotg_ep *hs_ep; - - dev_dbg(hsotg->dev, "%s: GINTSTS_INCOMPL_SOIN\n", __func__); - for (idx = 1; idx < hsotg->num_of_eps; idx++) { - hs_ep = hsotg->eps_in[idx]; + if (gintsts & GINTSTS_INCOMPL_SOIN) + dwc2_gadget_handle_incomplete_isoc_in(hsotg); - if (!hs_ep->isochronous || hs_ep->has_correct_parity) - continue; - - epctl_reg = DIEPCTL(idx); - dwc2_hsotg_change_ep_iso_parity(hsotg, epctl_reg); - } - dwc2_writel(GINTSTS_INCOMPL_SOIN, hsotg->regs + GINTSTS); - } - - if (gintsts & GINTSTS_INCOMPL_SOOUT) { - u32 idx, epctl_reg; - struct dwc2_hsotg_ep *hs_ep; - - dev_dbg(hsotg->dev, "%s: GINTSTS_INCOMPL_SOOUT\n", __func__); - for (idx = 1; idx < hsotg->num_of_eps; idx++) { - hs_ep = hsotg->eps_out[idx]; - - if (!hs_ep->isochronous || hs_ep->has_correct_parity) - continue; - - epctl_reg = DOEPCTL(idx); - dwc2_hsotg_change_ep_iso_parity(hsotg, epctl_reg); - } - dwc2_writel(GINTSTS_INCOMPL_SOOUT, hsotg->regs + GINTSTS); - } + if (gintsts & GINTSTS_INCOMPL_SOOUT) + dwc2_gadget_handle_incomplete_isoc_out(hsotg); /* * if we've had fifo events, we should try and go around the -- cgit v0.10.2 From bd9971f0a1efe4b3ac6e2f8ec864c75f73ca7829 Mon Sep 17 00:00:00 2001 From: Vardan Mikayelyan Date: Wed, 25 May 2016 18:07:19 -0700 Subject: usb: dwc2: gadget: Add EP disabled interrupt handler Reimplemented EP disabled interrupt handler and moved to corresponding function. This interrupt indicates that the endpoint has been disabled per the application's request. For IN endpoints flushes txfifo, in case of BULK clears DCTL_CGNPINNAK, in case of ISOC completes current request. For ISOC-OUT endpoints completes expired requests. If there is remaining request starts it. This is the part of ISOC-OUT transfer drop flow. When ISOC-OUT transfer expired we must disable ep to drop ongoing transfer. Tested-by: John Keeping Reviewed-by: Vahram Aharonyan Signed-off-by: Vardan Mikayelyan Signed-off-by: John Youn Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc2/gadget.c b/drivers/usb/dwc2/gadget.c index 61f913d..4a6074c 100644 --- a/drivers/usb/dwc2/gadget.c +++ b/drivers/usb/dwc2/gadget.c @@ -2024,6 +2024,74 @@ static u32 dwc2_gadget_read_ep_interrupts(struct dwc2_hsotg *hsotg, } /** + * dwc2_gadget_handle_ep_disabled - handle DXEPINT_EPDISBLD + * @hs_ep: The endpoint on which interrupt is asserted. + * + * This interrupt indicates that the endpoint has been disabled per the + * application's request. + * + * For IN endpoints flushes txfifo, in case of BULK clears DCTL_CGNPINNAK, + * in case of ISOC completes current request. + * + * For ISOC-OUT endpoints completes expired requests. If there is remaining + * request starts it. + */ +static void dwc2_gadget_handle_ep_disabled(struct dwc2_hsotg_ep *hs_ep) +{ + struct dwc2_hsotg *hsotg = hs_ep->parent; + struct dwc2_hsotg_req *hs_req; + unsigned char idx = hs_ep->index; + int dir_in = hs_ep->dir_in; + u32 epctl_reg = dir_in ? DIEPCTL(idx) : DOEPCTL(idx); + int dctl = dwc2_readl(hsotg->regs + DCTL); + + dev_dbg(hsotg->dev, "%s: EPDisbld\n", __func__); + + if (dir_in) { + int epctl = dwc2_readl(hsotg->regs + epctl_reg); + + dwc2_hsotg_txfifo_flush(hsotg, hs_ep->fifo_index); + + if (hs_ep->isochronous) { + dwc2_hsotg_complete_in(hsotg, hs_ep); + return; + } + + if ((epctl & DXEPCTL_STALL) && (epctl & DXEPCTL_EPTYPE_BULK)) { + int dctl = dwc2_readl(hsotg->regs + DCTL); + + dctl |= DCTL_CGNPINNAK; + dwc2_writel(dctl, hsotg->regs + DCTL); + } + return; + } + + if (dctl & DCTL_GOUTNAKSTS) { + dctl |= DCTL_CGOUTNAK; + dwc2_writel(dctl, hsotg->regs + DCTL); + } + + if (!hs_ep->isochronous) + return; + + if (list_empty(&hs_ep->queue)) { + dev_dbg(hsotg->dev, "%s: complete_ep 0x%p, ep->queue empty!\n", + __func__, hs_ep); + return; + } + + do { + hs_req = get_ep_head(hs_ep); + if (hs_req) + dwc2_hsotg_complete_request(hsotg, hs_ep, hs_req, + -ENODATA); + dwc2_gadget_incr_frame_num(hs_ep); + } while (dwc2_gadget_target_frame_elapsed(hs_ep)); + + dwc2_gadget_start_next_request(hs_ep); +} + +/** * dwc2_gadget_handle_out_token_ep_disabled - handle DXEPINT_OUTTKNEPDIS * @hs_ep: The endpoint on which interrupt is asserted. * @@ -2177,23 +2245,8 @@ static void dwc2_hsotg_epint(struct dwc2_hsotg *hsotg, unsigned int idx, } } - if (ints & DXEPINT_EPDISBLD) { - dev_dbg(hsotg->dev, "%s: EPDisbld\n", __func__); - - if (dir_in) { - int epctl = dwc2_readl(hsotg->regs + epctl_reg); - - dwc2_hsotg_txfifo_flush(hsotg, hs_ep->fifo_index); - - if ((epctl & DXEPCTL_STALL) && - (epctl & DXEPCTL_EPTYPE_BULK)) { - int dctl = dwc2_readl(hsotg->regs + DCTL); - - dctl |= DCTL_CGNPINNAK; - dwc2_writel(dctl, hsotg->regs + DCTL); - } - } - } + if (ints & DXEPINT_EPDISBLD) + dwc2_gadget_handle_ep_disabled(hs_ep); if (ints & DXEPINT_OUTTKNEPDIS) dwc2_gadget_handle_out_token_ep_disabled(hs_ep); -- cgit v0.10.2 From 837e9f00bf9966d64abc1bce678271099a72423b Mon Sep 17 00:00:00 2001 From: Vardan Mikayelyan Date: Wed, 25 May 2016 18:07:22 -0700 Subject: usb: dwc2: gadget: Final fixes for BDMA ISOC Done fixes and tested hsotg gadget's BDMA mode. Tested Control, Bulk, Isoc, Inter transfers. Added code for isoc transfers, removed unusable code, done minor fixes. Affected functions and IRQ handlers: - dwc2_hsotg_start_req(), - dwc2_hsotg_ep_enable(), - dwc2_hsotg_ep_queue(), - dwc2_hsotg_handle_outdone(), - GINTSTS_GOUTNAKEFF handler, Removed 'has_correct_parity' flag from 'dwc2_hsotg_ep' struct. Before this patch series, to set the data pid the DWC2 gadget driver was toggling the even/odd until it match, then were leaving it set. But now I have added mechanism to set pid and excluded all code where this flag was set. Tested-by: John Keeping Signed-off-by: Vardan Mikayelyan Signed-off-by: John Youn Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc2/core.h b/drivers/usb/dwc2/core.h index 0ba3599..9fae029 100644 --- a/drivers/usb/dwc2/core.h +++ b/drivers/usb/dwc2/core.h @@ -215,7 +215,6 @@ struct dwc2_hsotg_ep { unsigned int periodic:1; unsigned int isochronous:1; unsigned int send_zlp:1; - unsigned int has_correct_parity:1; unsigned int target_frame; #define TARGET_FRAME_INITIAL 0xFFFFFFFF bool frame_overrun; diff --git a/drivers/usb/dwc2/gadget.c b/drivers/usb/dwc2/gadget.c index 4a6074c..af46adf 100644 --- a/drivers/usb/dwc2/gadget.c +++ b/drivers/usb/dwc2/gadget.c @@ -667,6 +667,16 @@ static void dwc2_hsotg_start_req(struct dwc2_hsotg *hsotg, __func__, &ureq->dma, dma_reg); } + if (hs_ep->isochronous && hs_ep->interval == 1) { + hs_ep->target_frame = dwc2_hsotg_read_frameno(hsotg); + dwc2_gadget_incr_frame_num(hs_ep); + + if (hs_ep->target_frame & 0x1) + ctrl |= DXEPCTL_SETODDFR; + else + ctrl |= DXEPCTL_SETEVENFR; + } + ctrl |= DXEPCTL_EPENA; /* ensure ep enabled */ dev_dbg(hsotg->dev, "ep0 state:%d\n", hsotg->ep0_state); @@ -863,9 +873,18 @@ static int dwc2_hsotg_ep_queue(struct usb_ep *ep, struct usb_request *req, first = list_empty(&hs_ep->queue); list_add_tail(&hs_req->queue, &hs_ep->queue); - if (first) - dwc2_hsotg_start_req(hs, hs_ep, hs_req, false); + if (first) { + if (!hs_ep->isochronous) { + dwc2_hsotg_start_req(hs, hs_ep, hs_req, false); + return 0; + } + while (dwc2_gadget_target_frame_elapsed(hs_ep)) + dwc2_gadget_incr_frame_num(hs_ep); + + if (hs_ep->target_frame != TARGET_FRAME_INITIAL) + dwc2_hsotg_start_req(hs, hs_ep, hs_req, false); + } return 0; } @@ -1673,9 +1692,10 @@ static void dwc2_hsotg_handle_outdone(struct dwc2_hsotg *hsotg, int epnum) * adjust the ISOC parity here. */ if (!using_dma(hsotg)) { - hs_ep->has_correct_parity = 1; if (hs_ep->isochronous && hs_ep->interval == 1) dwc2_hsotg_change_ep_iso_parity(hsotg, DOEPCTL(epnum)); + else if (hs_ep->isochronous && hs_ep->interval > 1) + dwc2_gadget_incr_frame_num(hs_ep); } dwc2_hsotg_complete_request(hsotg, hs_ep, hs_req, result); @@ -2216,11 +2236,10 @@ static void dwc2_hsotg_epint(struct dwc2_hsotg *hsotg, unsigned int idx, if (idx == 0 && (ints & (DXEPINT_SETUP | DXEPINT_SETUP_RCVD))) ints &= ~DXEPINT_XFERCOMPL; - if (ints & DXEPINT_XFERCOMPL) { - hs_ep->has_correct_parity = 1; - if (hs_ep->isochronous && hs_ep->interval == 1) - dwc2_hsotg_change_ep_iso_parity(hsotg, epctl_reg); + if (ints & DXEPINT_STSPHSERCVD) + dev_dbg(hsotg->dev, "%s: StsPhseRcvd asserted\n", __func__); + if (ints & DXEPINT_XFERCOMPL) { dev_dbg(hsotg->dev, "%s: XferCompl: DxEPCTL=0x%08x, DXEPTSIZ=%08x\n", __func__, dwc2_readl(hsotg->regs + epctl_reg), @@ -2231,7 +2250,12 @@ static void dwc2_hsotg_epint(struct dwc2_hsotg *hsotg, unsigned int idx, * at completing IN requests here */ if (dir_in) { + if (hs_ep->isochronous && hs_ep->interval > 1) + dwc2_gadget_incr_frame_num(hs_ep); + dwc2_hsotg_complete_in(hsotg, hs_ep); + if (ints & DXEPINT_NAKINTRPT) + ints &= ~DXEPINT_NAKINTRPT; if (idx == 0 && !hs_ep->req) dwc2_hsotg_enqueue_setup(hsotg); @@ -2240,6 +2264,8 @@ static void dwc2_hsotg_epint(struct dwc2_hsotg *hsotg, unsigned int idx, * We're using DMA, we need to fire an OutDone here * as we ignore the RXFIFO. */ + if (hs_ep->isochronous && hs_ep->interval > 1) + dwc2_gadget_incr_frame_num(hs_ep); dwc2_hsotg_handle_outdone(hsotg, idx); } @@ -2556,18 +2582,16 @@ void dwc2_hsotg_core_init_disconnected(struct dwc2_hsotg *hsotg, dwc2_writel(((hsotg->dedicated_fifos && !using_dma(hsotg)) ? DIEPMSK_TXFIFOEMPTY | DIEPMSK_INTKNTXFEMPMSK : 0) | DIEPMSK_EPDISBLDMSK | DIEPMSK_XFERCOMPLMSK | - DIEPMSK_TIMEOUTMSK | DIEPMSK_AHBERRMSK | - DIEPMSK_INTKNEPMISMSK, + DIEPMSK_TIMEOUTMSK | DIEPMSK_AHBERRMSK, hsotg->regs + DIEPMSK); /* * don't need XferCompl, we get that from RXFIFO in slave mode. In * DMA mode we may need this. */ - dwc2_writel((using_dma(hsotg) ? (DIEPMSK_XFERCOMPLMSK | - DIEPMSK_TIMEOUTMSK) : 0) | + dwc2_writel((using_dma(hsotg) ? (DIEPMSK_XFERCOMPLMSK) : 0) | DOEPMSK_EPDISBLDMSK | DOEPMSK_AHBERRMSK | - DOEPMSK_SETUPMSK, + DOEPMSK_SETUPMSK | DOEPMSK_STSPHSERCVDMSK, hsotg->regs + DOEPMSK); dwc2_writel(0, hsotg->regs + DAINTMSK); @@ -2858,11 +2882,29 @@ irq_retry: */ if (gintsts & GINTSTS_GOUTNAKEFF) { - dev_info(hsotg->dev, "GOUTNakEff triggered\n"); - - __orr32(hsotg->regs + DCTL, DCTL_CGOUTNAK); + u8 idx; + u32 epctrl; + u32 gintmsk; + struct dwc2_hsotg_ep *hs_ep; + + /* Mask this interrupt */ + gintmsk = dwc2_readl(hsotg->regs + GINTMSK); + gintmsk &= ~GINTSTS_GOUTNAKEFF; + dwc2_writel(gintmsk, hsotg->regs + GINTMSK); + + dev_dbg(hsotg->dev, "GOUTNakEff triggered\n"); + for (idx = 1; idx <= hsotg->num_of_eps; idx++) { + hs_ep = hsotg->eps_out[idx]; + epctrl = dwc2_readl(hsotg->regs + DOEPCTL(idx)); + + if ((epctrl & DXEPCTL_EPENA) && hs_ep->isochronous) { + epctrl |= DXEPCTL_SNAK; + epctrl |= DXEPCTL_EPDIS; + dwc2_writel(epctrl, hsotg->regs + DOEPCTL(idx)); + } + } - dwc2_hsotg_dump(hsotg); + /* This interrupt bit is cleared in DXEPINT_EPDISBLD handler */ } if (gintsts & GINTSTS_GINNAKEFF) { @@ -2909,6 +2951,7 @@ static int dwc2_hsotg_ep_enable(struct usb_ep *ep, u32 epctrl_reg; u32 epctrl; u32 mps; + u32 mask; unsigned int dir_in; unsigned int i, val, size; int ret = 0; @@ -2951,15 +2994,6 @@ static int dwc2_hsotg_ep_enable(struct usb_ep *ep, */ epctrl |= DXEPCTL_USBACTEP; - /* - * set the NAK status on the endpoint, otherwise we might try and - * do something with data that we've yet got a request to process - * since the RXFIFO will take data for an endpoint even if the - * size register hasn't been set. - */ - - epctrl |= DXEPCTL_SNAK; - /* update the endpoint state */ dwc2_hsotg_set_ep_maxpacket(hsotg, hs_ep->index, mps, dir_in); @@ -2975,8 +3009,17 @@ static int dwc2_hsotg_ep_enable(struct usb_ep *ep, epctrl |= DXEPCTL_SETEVENFR; hs_ep->isochronous = 1; hs_ep->interval = 1 << (desc->bInterval - 1); - if (dir_in) + hs_ep->target_frame = TARGET_FRAME_INITIAL; + if (dir_in) { hs_ep->periodic = 1; + mask = dwc2_readl(hsotg->regs + DIEPMSK); + mask |= DIEPMSK_NAKMSK; + dwc2_writel(mask, hsotg->regs + DIEPMSK); + } else { + mask = dwc2_readl(hsotg->regs + DOEPMSK); + mask |= DOEPMSK_OUTTKNEPDISMSK; + dwc2_writel(mask, hsotg->regs + DOEPMSK); + } break; case USB_ENDPOINT_XFER_BULK: @@ -3043,7 +3086,7 @@ static int dwc2_hsotg_ep_enable(struct usb_ep *ep, } /* for non control endpoints, set PID to D0 */ - if (index) + if (index && !hs_ep->isochronous) epctrl |= DXEPCTL_SETD0PID; dev_dbg(hsotg->dev, "%s: write DxEPCTL=0x%08x\n", diff --git a/drivers/usb/dwc2/hw.h b/drivers/usb/dwc2/hw.h index 1126141..efc3bcd 100644 --- a/drivers/usb/dwc2/hw.h +++ b/drivers/usb/dwc2/hw.h @@ -560,6 +560,7 @@ #define DXEPINT_INEPNAKEFF (1 << 6) #define DXEPINT_BACK2BACKSETUP (1 << 6) #define DXEPINT_INTKNEPMIS (1 << 5) +#define DXEPINT_STSPHSERCVD (1 << 5) #define DXEPINT_INTKNTXFEMP (1 << 4) #define DXEPINT_OUTTKNEPDIS (1 << 4) #define DXEPINT_TIMEOUT (1 << 3) -- cgit v0.10.2 From 882bd9fc46321c9d4721b376039a142cbfe8a17a Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Mon, 13 Jun 2016 10:47:30 +0200 Subject: usb: gadget: udc: atmel: Also get regmap for at91sam9x5-pmc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The "atmel,at91sam9g45-udc" compatible UDC is also used on at91sam9x5 so it is also necessary to try to get the syscon for at91sam9x5-pmc. Fixes: 4747639f01c9 ("usb: gadget: atmel: access the PMC using regmap") Reported-by: Uwe Kleine-König Signed-off-by: Alexandre Belloni Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/udc/atmel_usba_udc.c b/drivers/usb/gadget/udc/atmel_usba_udc.c index 18569de..bb1f6c8 100644 --- a/drivers/usb/gadget/udc/atmel_usba_udc.c +++ b/drivers/usb/gadget/udc/atmel_usba_udc.c @@ -1920,6 +1920,8 @@ static struct usba_ep * atmel_udc_of_init(struct platform_device *pdev, udc->errata = match->data; udc->pmc = syscon_regmap_lookup_by_compatible("atmel,at91sam9g45-pmc"); + if (IS_ERR(udc->pmc)) + udc->pmc = syscon_regmap_lookup_by_compatible("atmel,at91sam9x5-pmc"); if (udc->errata && IS_ERR(udc->pmc)) return ERR_CAST(udc->pmc); -- cgit v0.10.2 From ce15ed4c5dfb3f7757e6611902aed5db253af977 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Fri, 10 Jun 2016 11:46:25 +0200 Subject: USB: Fix of_usb_get_dr_mode_by_phy with a shared phy block Some SoCs have a single phy-hw-block with multiple phys, this is modelled by a single phy dts node, so we end up with multiple controller nodes with a phys property pointing to the phy-node of the otg-phy. Only one of these controllers typically is an otg controller, yet we were checking the first controller who uses a phy from the block and then end up looking for a dr_mode property in e.g. the ehci controller. This commit fixes this by adding an arg0 parameter to of_usb_get_dr_mode_by_phy and make of_usb_get_dr_mode_by_phy check that this matches the phandle args[0] value when looking for the otg controller. Signed-off-by: Hans de Goede Signed-off-by: Felipe Balbi diff --git a/drivers/usb/common/common.c b/drivers/usb/common/common.c index e3d0161..5ef8da6 100644 --- a/drivers/usb/common/common.c +++ b/drivers/usb/common/common.c @@ -131,15 +131,17 @@ EXPORT_SYMBOL_GPL(usb_get_dr_mode); * of_usb_get_dr_mode_by_phy - Get dual role mode for the controller device * which is associated with the given phy device_node * @np: Pointer to the given phy device_node + * @arg0: phandle args[0] for phy's with #phy-cells >= 1, or -1 for + * phys which do not have phy-cells * * In dts a usb controller associates with phy devices. The function gets * the string from property 'dr_mode' of the controller associated with the * given phy device node, and returns the correspondig enum usb_dr_mode. */ -enum usb_dr_mode of_usb_get_dr_mode_by_phy(struct device_node *phy_np) +enum usb_dr_mode of_usb_get_dr_mode_by_phy(struct device_node *np, int arg0) { struct device_node *controller = NULL; - struct device_node *phy; + struct of_phandle_args args; const char *dr_mode; int index; int err; @@ -148,12 +150,24 @@ enum usb_dr_mode of_usb_get_dr_mode_by_phy(struct device_node *phy_np) controller = of_find_node_with_property(controller, "phys"); index = 0; do { - phy = of_parse_phandle(controller, "phys", index); - of_node_put(phy); - if (phy == phy_np) + if (arg0 == -1) { + args.np = of_parse_phandle(controller, "phys", + index); + args.args_count = 0; + } else { + err = of_parse_phandle_with_args(controller, + "phys", "#phy-cells", + index, &args); + if (err) + break; + } + + of_node_put(args.np); + if (args.np == np && (args.args_count == 0 || + args.args[0] == arg0)) goto finish; index++; - } while (phy); + } while (args.np); } while (controller); finish: diff --git a/drivers/usb/phy/phy-am335x.c b/drivers/usb/phy/phy-am335x.c index a262a43..7e5aece 100644 --- a/drivers/usb/phy/phy-am335x.c +++ b/drivers/usb/phy/phy-am335x.c @@ -54,7 +54,7 @@ static int am335x_phy_probe(struct platform_device *pdev) return am_phy->id; } - am_phy->dr_mode = of_usb_get_dr_mode_by_phy(pdev->dev.of_node); + am_phy->dr_mode = of_usb_get_dr_mode_by_phy(pdev->dev.of_node, -1); ret = usb_phy_gen_create_phy(dev, &am_phy->usb_phy_gen, NULL); if (ret) diff --git a/include/linux/usb/of.h b/include/linux/usb/of.h index de3237f..5ff9032 100644 --- a/include/linux/usb/of.h +++ b/include/linux/usb/of.h @@ -12,7 +12,7 @@ #include #if IS_ENABLED(CONFIG_OF) -enum usb_dr_mode of_usb_get_dr_mode_by_phy(struct device_node *phy_np); +enum usb_dr_mode of_usb_get_dr_mode_by_phy(struct device_node *np, int arg0); bool of_usb_host_tpl_support(struct device_node *np); int of_usb_update_otg_caps(struct device_node *np, struct usb_otg_caps *otg_caps); @@ -20,7 +20,7 @@ struct device_node *usb_of_get_child_node(struct device_node *parent, int portnum); #else static inline enum usb_dr_mode -of_usb_get_dr_mode_by_phy(struct device_node *phy_np) +of_usb_get_dr_mode_by_phy(struct device_node *np, int arg0) { return USB_DR_MODE_UNKNOWN; } -- cgit v0.10.2 From 9522def40065194aa75b0a7b7e1ff5b8e2014724 Mon Sep 17 00:00:00 2001 From: Roger Quadros Date: Fri, 10 Jun 2016 14:48:38 +0300 Subject: usb: dwc3: core: cleanup IRQ resources Implementations might use different IRQs for host, gadget so use named interrupt resources to allow device tree to specify the interrupts. Following are the interrupt names Peripheral Interrupt - peripheral HOST Interrupt - host Maintain backward compatibility for a single named interrupt ("dwc3_usb3") for all interrupts as well as unnamed interrupt at index 0 for all interrupts. As platform_get_irq() variants are used, tackle the -EPROBE_DEFER case as well. Signed-off-by: Roger Quadros Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index ca22e48..9466431 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -766,7 +766,8 @@ static int dwc3_core_init_mode(struct dwc3 *dwc) dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_DEVICE); ret = dwc3_gadget_init(dwc); if (ret) { - dev_err(dev, "failed to initialize gadget\n"); + if (ret != -EPROBE_DEFER) + dev_err(dev, "failed to initialize gadget\n"); return ret; } break; @@ -774,7 +775,8 @@ static int dwc3_core_init_mode(struct dwc3 *dwc) dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_HOST); ret = dwc3_host_init(dwc); if (ret) { - dev_err(dev, "failed to initialize host\n"); + if (ret != -EPROBE_DEFER) + dev_err(dev, "failed to initialize host\n"); return ret; } break; @@ -782,13 +784,15 @@ static int dwc3_core_init_mode(struct dwc3 *dwc) dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_OTG); ret = dwc3_host_init(dwc); if (ret) { - dev_err(dev, "failed to initialize host\n"); + if (ret != -EPROBE_DEFER) + dev_err(dev, "failed to initialize host\n"); return ret; } ret = dwc3_gadget_init(dwc); if (ret) { - dev_err(dev, "failed to initialize gadget\n"); + if (ret != -EPROBE_DEFER) + dev_err(dev, "failed to initialize gadget\n"); return ret; } break; @@ -843,16 +847,6 @@ static int dwc3_probe(struct platform_device *pdev) dwc->mem = mem; dwc->dev = dev; - res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); - if (!res) { - dev_err(dev, "missing IRQ\n"); - return -ENODEV; - } - dwc->xhci_resources[1].start = res->start; - dwc->xhci_resources[1].end = res->end; - dwc->xhci_resources[1].flags = res->flags; - dwc->xhci_resources[1].name = res->name; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) { dev_err(dev, "missing memory resource\n"); diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index b9bc646..f209753 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -1765,7 +1765,7 @@ static int dwc3_gadget_start(struct usb_gadget *g, int ret = 0; int irq; - irq = platform_get_irq(to_platform_device(dwc->dev), 0); + irq = dwc->irq_gadget; ret = request_threaded_irq(irq, dwc3_interrupt, dwc3_thread_interrupt, IRQF_SHARED, "dwc3", dwc->ev_buf); if (ret) { @@ -1773,7 +1773,6 @@ static int dwc3_gadget_start(struct usb_gadget *g, irq, ret); goto err0; } - dwc->irq_gadget = irq; spin_lock_irqsave(&dwc->lock, flags); if (dwc->gadget_driver) { @@ -2891,7 +2890,33 @@ static irqreturn_t dwc3_interrupt(int irq, void *_evt) */ int dwc3_gadget_init(struct dwc3 *dwc) { - int ret; + int ret, irq; + struct platform_device *dwc3_pdev = to_platform_device(dwc->dev); + + irq = platform_get_irq_byname(dwc3_pdev, "peripheral"); + if (irq == -EPROBE_DEFER) + return irq; + + if (irq <= 0) { + irq = platform_get_irq_byname(dwc3_pdev, "dwc_usb3"); + if (irq == -EPROBE_DEFER) + return irq; + + if (irq <= 0) { + irq = platform_get_irq(dwc3_pdev, 0); + if (irq <= 0) { + if (irq != -EPROBE_DEFER) { + dev_err(dwc->dev, + "missing peripheral IRQ\n"); + } + if (!irq) + irq = -EINVAL; + return irq; + } + } + } + + dwc->irq_gadget = irq; dwc->ctrl_req = dma_alloc_coherent(dwc->dev, sizeof(*dwc->ctrl_req), &dwc->ctrl_req_addr, GFP_KERNEL); diff --git a/drivers/usb/dwc3/host.c b/drivers/usb/dwc3/host.c index c679f63..2e960ed 100644 --- a/drivers/usb/dwc3/host.c +++ b/drivers/usb/dwc3/host.c @@ -24,7 +24,48 @@ int dwc3_host_init(struct dwc3 *dwc) { struct platform_device *xhci; struct usb_xhci_pdata pdata; - int ret; + int ret, irq; + struct resource *res; + struct platform_device *dwc3_pdev = to_platform_device(dwc->dev); + + irq = platform_get_irq_byname(dwc3_pdev, "host"); + if (irq == -EPROBE_DEFER) + return irq; + + if (irq <= 0) { + irq = platform_get_irq_byname(dwc3_pdev, "dwc_usb3"); + if (irq == -EPROBE_DEFER) + return irq; + + if (irq <= 0) { + irq = platform_get_irq(dwc3_pdev, 0); + if (irq <= 0) { + if (irq != -EPROBE_DEFER) { + dev_err(dwc->dev, + "missing host IRQ\n"); + } + if (!irq) + irq = -EINVAL; + return irq; + } else { + res = platform_get_resource(dwc3_pdev, + IORESOURCE_IRQ, 0); + } + } else { + res = platform_get_resource_byname(dwc3_pdev, + IORESOURCE_IRQ, + "dwc_usb3"); + } + + } else { + res = platform_get_resource_byname(dwc3_pdev, IORESOURCE_IRQ, + "host"); + } + + dwc->xhci_resources[1].start = irq; + dwc->xhci_resources[1].end = irq; + dwc->xhci_resources[1].flags = res->flags; + dwc->xhci_resources[1].name = res->name; xhci = platform_device_alloc("xhci-hcd", PLATFORM_DEVID_AUTO); if (!xhci) { -- cgit v0.10.2 From 872ce5119524f33fafacc4d9610a431185ea66a2 Mon Sep 17 00:00:00 2001 From: Michal Nazarewicz Date: Tue, 31 May 2016 14:17:21 +0200 Subject: usb: gadget: fix unused-but-set-variale warnings Those are enabled with W=1 make option. The patch leaves of some type-limits warnings which are caused by generic macros used in a way where they produce always-false conditions. Signed-off-by: Michal Nazarewicz Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c index cc33d26..70ed370 100644 --- a/drivers/usb/gadget/function/f_fs.c +++ b/drivers/usb/gadget/function/f_fs.c @@ -2227,8 +2227,8 @@ static int __ffs_data_got_strings(struct ffs_data *ffs, { u32 str_count, needed_count, lang_count; struct usb_gadget_strings **stringtabs, *t; - struct usb_string *strings, *s; const char *data = _data; + struct usb_string *s; ENTER(); @@ -2286,7 +2286,6 @@ static int __ffs_data_got_strings(struct ffs_data *ffs, stringtabs = vla_ptr(vlabuf, d, stringtabs); t = vla_ptr(vlabuf, d, stringtab); s = vla_ptr(vlabuf, d, strings); - strings = s; } /* For each language */ diff --git a/drivers/usb/gadget/function/u_serial.c b/drivers/usb/gadget/function/u_serial.c index 3580f19..6ded634 100644 --- a/drivers/usb/gadget/function/u_serial.c +++ b/drivers/usb/gadget/function/u_serial.c @@ -907,7 +907,6 @@ static int gs_write(struct tty_struct *tty, const unsigned char *buf, int count) { struct gs_port *port = tty->driver_data; unsigned long flags; - int status; pr_vdebug("gs_write: ttyGS%d (%p) writing %d bytes\n", port->port_num, tty, count); @@ -917,7 +916,7 @@ static int gs_write(struct tty_struct *tty, const unsigned char *buf, int count) count = gs_buf_put(&port->port_write_buf, buf, count); /* treat count == 0 as flush_chars() */ if (port->port_usb) - status = gs_start_tx(port); + gs_start_tx(port); spin_unlock_irqrestore(&port->port_lock, flags); return count; diff --git a/drivers/usb/gadget/legacy/g_ffs.c b/drivers/usb/gadget/legacy/g_ffs.c index f85639e..6da7316 100644 --- a/drivers/usb/gadget/legacy/g_ffs.c +++ b/drivers/usb/gadget/legacy/g_ffs.c @@ -265,7 +265,7 @@ static void *functionfs_acquire_dev(struct ffs_dev *dev) { if (!try_module_get(THIS_MODULE)) return ERR_PTR(-ENOENT); - + return NULL; } @@ -275,7 +275,7 @@ static void functionfs_release_dev(struct ffs_dev *dev) } /* - * The caller of this function takes ffs_lock + * The caller of this function takes ffs_lock */ static int functionfs_ready_callback(struct ffs_data *ffs) { @@ -294,12 +294,12 @@ static int functionfs_ready_callback(struct ffs_data *ffs) ++missing_funcs; gfs_registered = false; } - + return ret; } /* - * The caller of this function takes ffs_lock + * The caller of this function takes ffs_lock */ static void functionfs_closed_callback(struct ffs_data *ffs) { @@ -347,17 +347,14 @@ static int gfs_bind(struct usb_composite_dev *cdev) #ifdef CONFIG_USB_FUNCTIONFS_RNDIS { - struct f_rndis_opts *rndis_opts; - fi_rndis = usb_get_function_instance("rndis"); if (IS_ERR(fi_rndis)) { ret = PTR_ERR(fi_rndis); goto error; } - rndis_opts = container_of(fi_rndis, struct f_rndis_opts, - func_inst); #ifndef CONFIG_USB_FUNCTIONFS_ETH - net = rndis_opts->net; + net = container_of(fi_rndis, struct f_rndis_opts, + func_inst)->net; #endif } #endif diff --git a/drivers/usb/gadget/udc/amd5536udc.c b/drivers/usb/gadget/udc/amd5536udc.c index 39d70b4..ea03ca7 100644 --- a/drivers/usb/gadget/udc/amd5536udc.c +++ b/drivers/usb/gadget/udc/amd5536udc.c @@ -2340,7 +2340,6 @@ static irqreturn_t udc_data_in_isr(struct udc *dev, int ep_ix) struct udc_ep *ep; struct udc_request *req; struct udc_data_dma *td; - unsigned dma_done; unsigned len; ep = &dev->ep[ep_ix]; @@ -2385,13 +2384,8 @@ static irqreturn_t udc_data_in_isr(struct udc *dev, int ep_ix) */ if (use_dma_ppb_du) { td = udc_get_last_dma_desc(req); - if (td) { - dma_done = - AMD_GETBITS(td->status, - UDC_DMA_IN_STS_BS); - /* don't care DMA done */ + if (td) req->req.actual = req->req.length; - } } else { /* assume all bytes transferred */ req->req.actual = req->req.length; @@ -3417,4 +3411,3 @@ module_pci_driver(udc_pci_driver); MODULE_DESCRIPTION(UDC_MOD_DESCRIPTION); MODULE_AUTHOR("Thomas Dahlmann"); MODULE_LICENSE("GPL"); - diff --git a/drivers/usb/gadget/udc/bdc/bdc_cmd.c b/drivers/usb/gadget/udc/bdc/bdc_cmd.c index 6a4155c..4d5e918 100644 --- a/drivers/usb/gadget/udc/bdc/bdc_cmd.c +++ b/drivers/usb/gadget/udc/bdc/bdc_cmd.c @@ -57,7 +57,6 @@ static int bdc_submit_cmd(struct bdc *bdc, u32 cmd_sc, u32 param0, u32 param1, u32 param2) { u32 temp, cmd_status; - int reset_bdc = 0; int ret; temp = bdc_readl(bdc->regs, BDC_CMDSC); @@ -94,7 +93,6 @@ static int bdc_submit_cmd(struct bdc *bdc, u32 cmd_sc, case BDC_CMDS_INTL: dev_err(bdc->dev, "BDC Internal error\n"); - reset_bdc = 1; ret = -ECONNRESET; break; @@ -102,7 +100,6 @@ static int bdc_submit_cmd(struct bdc *bdc, u32 cmd_sc, dev_err(bdc->dev, "command timedout waited for %dusec\n", BDC_CMD_TIMEOUT); - reset_bdc = 1; ret = -ECONNRESET; break; default: diff --git a/drivers/usb/gadget/udc/bdc/bdc_ep.c b/drivers/usb/gadget/udc/bdc/bdc_ep.c index d619950..650717e7 100644 --- a/drivers/usb/gadget/udc/bdc/bdc_ep.c +++ b/drivers/usb/gadget/udc/bdc/bdc_ep.c @@ -702,11 +702,9 @@ static int ep0_queue(struct bdc_ep *ep, struct bdc_req *req) /* Queue data stage */ static int ep0_queue_data_stage(struct bdc *bdc) { - struct usb_request *ep0_usb_req; struct bdc_ep *ep; dev_dbg(bdc->dev, "%s\n", __func__); - ep0_usb_req = &bdc->ep0_req.usb_req; ep = bdc->bdc_ep_array[1]; bdc->ep0_req.ep = ep; bdc->ep0_req.usb_req.complete = NULL; @@ -1393,10 +1391,8 @@ static int ep0_set_sel(struct bdc *bdc, { struct bdc_ep *ep; u16 wLength; - u16 wValue; dev_dbg(bdc->dev, "%s\n", __func__); - wValue = le16_to_cpu(setup_pkt->wValue); wLength = le16_to_cpu(setup_pkt->wLength); if (unlikely(wLength != 6)) { dev_err(bdc->dev, "%s Wrong wLength:%d\n", __func__, wLength); diff --git a/drivers/usb/gadget/udc/dummy_hcd.c b/drivers/usb/gadget/udc/dummy_hcd.c index dde4445..77d0790 100644 --- a/drivers/usb/gadget/udc/dummy_hcd.c +++ b/drivers/usb/gadget/udc/dummy_hcd.c @@ -647,12 +647,10 @@ static int dummy_disable(struct usb_ep *_ep) static struct usb_request *dummy_alloc_request(struct usb_ep *_ep, gfp_t mem_flags) { - struct dummy_ep *ep; struct dummy_request *req; if (!_ep) return NULL; - ep = usb_ep_to_dummy_ep(_ep); req = kzalloc(sizeof(*req), mem_flags); if (!req) @@ -2444,9 +2442,6 @@ static int dummy_start(struct usb_hcd *hcd) static void dummy_stop(struct usb_hcd *hcd) { - struct dummy *dum; - - dum = hcd_to_dummy_hcd(hcd)->dum; device_remove_file(dummy_dev(hcd_to_dummy_hcd(hcd)), &dev_attr_urbs); dev_info(dummy_dev(hcd_to_dummy_hcd(hcd)), "stopped\n"); } diff --git a/drivers/usb/gadget/udc/mv_udc_core.c b/drivers/usb/gadget/udc/mv_udc_core.c index 81b6229..ce73b35 100644 --- a/drivers/usb/gadget/udc/mv_udc_core.c +++ b/drivers/usb/gadget/udc/mv_udc_core.c @@ -129,7 +129,7 @@ static int process_ep_req(struct mv_udc *udc, int index, { struct mv_dtd *curr_dtd; struct mv_dqh *curr_dqh; - int td_complete, actual, remaining_length; + int actual, remaining_length; int i, direction; int retval = 0; u32 errors; @@ -139,7 +139,6 @@ static int process_ep_req(struct mv_udc *udc, int index, direction = index % 2; curr_dtd = curr_req->head; - td_complete = 0; actual = curr_req->req.length; for (i = 0; i < curr_req->dtd_count; i++) { @@ -412,11 +411,8 @@ static int req_to_dtd(struct mv_req *req) unsigned count; int is_last, is_first = 1; struct mv_dtd *dtd, *last_dtd = NULL; - struct mv_udc *udc; dma_addr_t dma; - udc = req->ep->udc; - do { dtd = build_dtd(req, &count, &dma, &is_last); if (dtd == NULL) @@ -567,7 +563,7 @@ static int mv_ep_disable(struct usb_ep *_ep) struct mv_udc *udc; struct mv_ep *ep; struct mv_dqh *dqh; - u32 bit_pos, epctrlx, direction; + u32 epctrlx, direction; unsigned long flags; ep = container_of(_ep, struct mv_ep, ep); @@ -582,7 +578,6 @@ static int mv_ep_disable(struct usb_ep *_ep) spin_lock_irqsave(&udc->lock, flags); direction = ep_dir(ep); - bit_pos = 1 << ((direction == EP_DIR_OUT ? 0 : 16) + ep->ep_num); /* Reset the max packet length and the interrupt on Setup */ dqh->max_packet_length = 0; diff --git a/drivers/usb/gadget/udc/net2272.c b/drivers/usb/gadget/udc/net2272.c index 18f5ebd..7c61134 100644 --- a/drivers/usb/gadget/udc/net2272.c +++ b/drivers/usb/gadget/udc/net2272.c @@ -329,12 +329,10 @@ static int net2272_disable(struct usb_ep *_ep) static struct usb_request * net2272_alloc_request(struct usb_ep *_ep, gfp_t gfp_flags) { - struct net2272_ep *ep; struct net2272_request *req; if (!_ep) return NULL; - ep = container_of(_ep, struct net2272_ep, ep); req = kzalloc(sizeof(*req), gfp_flags); if (!req) @@ -348,10 +346,8 @@ net2272_alloc_request(struct usb_ep *_ep, gfp_t gfp_flags) static void net2272_free_request(struct usb_ep *_ep, struct usb_request *_req) { - struct net2272_ep *ep; struct net2272_request *req; - ep = container_of(_ep, struct net2272_ep, ep); if (!_ep || !_req) return; diff --git a/drivers/usb/gadget/udc/pch_udc.c b/drivers/usb/gadget/udc/pch_udc.c index ebc51ec..8ad847a 100644 --- a/drivers/usb/gadget/udc/pch_udc.c +++ b/drivers/usb/gadget/udc/pch_udc.c @@ -1984,9 +1984,8 @@ static int pch_udc_pcd_set_halt(struct usb_ep *usbep, int halt) if (ep->num == PCH_UDC_EP0) ep->dev->stall = 1; pch_udc_ep_set_stall(ep); - pch_udc_enable_ep_interrupts(ep->dev, - PCH_UDC_EPINT(ep->in, - ep->num)); + pch_udc_enable_ep_interrupts( + ep->dev, PCH_UDC_EPINT(ep->in, ep->num)); } else { pch_udc_ep_clear_stall(ep); } @@ -2451,16 +2450,11 @@ static void pch_udc_svc_control_out(struct pch_udc_dev *dev) */ static void pch_udc_postsvc_epinters(struct pch_udc_dev *dev, int ep_num) { - struct pch_udc_ep *ep; - struct pch_udc_request *req; - - ep = &dev->ep[UDC_EPIN_IDX(ep_num)]; - if (!list_empty(&ep->queue)) { - req = list_entry(ep->queue.next, struct pch_udc_request, queue); - pch_udc_enable_ep_interrupts(ep->dev, - PCH_UDC_EPINT(ep->in, ep->num)); - pch_udc_ep_clear_nak(ep); - } + struct pch_udc_ep *ep = &dev->ep[UDC_EPIN_IDX(ep_num)]; + if (list_empty(&ep->queue)) + return; + pch_udc_enable_ep_interrupts(ep->dev, PCH_UDC_EPINT(ep->in, ep->num)); + pch_udc_ep_clear_nak(ep); } /** diff --git a/drivers/usb/gadget/udc/udc-xilinx.c b/drivers/usb/gadget/udc/udc-xilinx.c index 1cbb0ac..f8bf290 100644 --- a/drivers/usb/gadget/udc/udc-xilinx.c +++ b/drivers/usb/gadget/udc/udc-xilinx.c @@ -2055,7 +2055,6 @@ static int xudc_probe(struct platform_device *pdev) struct device_node *np = pdev->dev.of_node; struct resource *res; struct xusb_udc *udc; - struct xusb_ep *ep0; int irq; int ret; u32 ier; @@ -2119,8 +2118,6 @@ static int xudc_probe(struct platform_device *pdev) xudc_eps_init(udc); - ep0 = &udc->ep[0]; - /* Set device address to 0.*/ udc->write_fn(udc->addr, XUSB_ADDRESS_OFFSET, 0); -- cgit v0.10.2 From d58fcf81bb8facc0cd22490c43698f272c1ee07b Mon Sep 17 00:00:00 2001 From: Michal Nazarewicz Date: Tue, 31 May 2016 14:17:22 +0200 Subject: usb: gadget: m66592: fix unused-but-set-variable warnings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch fixes the following (W=1) warnings: drivers/usb/gadget/udc/m66592-udc.c: In function ‘m66592_irq’: drivers/usb/gadget/udc/m66592-udc.c:1203:15: warning: variable ‘nrdyenb’ set but not used [-Wunused-but-set-variable] u16 brdyenb, nrdyenb, bempenb; ^ drivers/usb/gadget/udc/m66592-udc.c:1202:15: warning: variable ‘nrdysts’ set but not used [-Wunused-but-set-variable] u16 brdysts, nrdysts, bempsts; ^ In doing so, it removes calls to m66592_read function which does I/O with the device, but I hope the reads don’t have any side effects that are needed. Signed-off-by: Michal Nazarewicz Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/udc/m66592-udc.c b/drivers/usb/gadget/udc/m66592-udc.c index b1cfa96..6e977dc 100644 --- a/drivers/usb/gadget/udc/m66592-udc.c +++ b/drivers/usb/gadget/udc/m66592-udc.c @@ -1199,8 +1199,6 @@ static irqreturn_t m66592_irq(int irq, void *_m66592) struct m66592 *m66592 = _m66592; u16 intsts0; u16 intenb0; - u16 brdysts, nrdysts, bempsts; - u16 brdyenb, nrdyenb, bempenb; u16 savepipe; u16 mask0; @@ -1224,12 +1222,10 @@ static irqreturn_t m66592_irq(int irq, void *_m66592) mask0 = intsts0 & intenb0; if (mask0) { - brdysts = m66592_read(m66592, M66592_BRDYSTS); - nrdysts = m66592_read(m66592, M66592_NRDYSTS); - bempsts = m66592_read(m66592, M66592_BEMPSTS); - brdyenb = m66592_read(m66592, M66592_BRDYENB); - nrdyenb = m66592_read(m66592, M66592_NRDYENB); - bempenb = m66592_read(m66592, M66592_BEMPENB); + u16 brdysts = m66592_read(m66592, M66592_BRDYSTS); + u16 bempsts = m66592_read(m66592, M66592_BEMPSTS); + u16 brdyenb = m66592_read(m66592, M66592_BRDYENB); + u16 bempenb = m66592_read(m66592, M66592_BEMPENB); if (mask0 & M66592_VBINT) { m66592_write(m66592, 0xffff & ~M66592_VBINT, @@ -1408,28 +1404,20 @@ static int m66592_dequeue(struct usb_ep *_ep, struct usb_request *_req) static int m66592_set_halt(struct usb_ep *_ep, int value) { - struct m66592_ep *ep; - struct m66592_request *req; + struct m66592_ep *ep = container_of(_ep, struct m66592_ep, ep); unsigned long flags; int ret = 0; - ep = container_of(_ep, struct m66592_ep, ep); - req = list_entry(ep->queue.next, struct m66592_request, queue); - spin_lock_irqsave(&ep->m66592->lock, flags); if (!list_empty(&ep->queue)) { ret = -EAGAIN; - goto out; - } - if (value) { + } else if (value) { ep->busy = 1; pipe_stall(ep->m66592, ep->pipenum); } else { ep->busy = 0; pipe_stop(ep->m66592, ep->pipenum); } - -out: spin_unlock_irqrestore(&ep->m66592->lock, flags); return ret; } -- cgit v0.10.2 From 906ae52db2695f8b34b292cc7d74d126f4a4612d Mon Sep 17 00:00:00 2001 From: Michal Nazarewicz Date: Tue, 31 May 2016 14:17:23 +0200 Subject: usb: gadget: r8a66597: fix unused-but-set-variable warnings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch fixes the following (W=1) warnings: drivers/usb/gadget/udc/r8a66597-udc.c: In function ‘r8a66597_irq’: drivers/usb/gadget/udc/r8a66597-udc.c:1468:15: warning: variable ‘nrdyenb’ set but not used [-Wunused-but-set-variable] u16 brdyenb, nrdyenb, bempenb; ^ drivers/usb/gadget/udc/r8a66597-udc.c:1467:15: warning: variable ‘nrdysts’ set but not used [-Wunused-but-set-variable] u16 brdysts, nrdysts, bempsts; ^ In doing so, it removes calls to r8a66597_read function which does I/O with the device, but I hope the reads don’t have any side effects that are needed. Signed-off-by: Michal Nazarewicz Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/udc/r8a66597-udc.c b/drivers/usb/gadget/udc/r8a66597-udc.c index 8b300e6..f2c8862 100644 --- a/drivers/usb/gadget/udc/r8a66597-udc.c +++ b/drivers/usb/gadget/udc/r8a66597-udc.c @@ -1464,8 +1464,6 @@ static irqreturn_t r8a66597_irq(int irq, void *_r8a66597) struct r8a66597 *r8a66597 = _r8a66597; u16 intsts0; u16 intenb0; - u16 brdysts, nrdysts, bempsts; - u16 brdyenb, nrdyenb, bempenb; u16 savepipe; u16 mask0; @@ -1481,12 +1479,10 @@ static irqreturn_t r8a66597_irq(int irq, void *_r8a66597) mask0 = intsts0 & intenb0; if (mask0) { - brdysts = r8a66597_read(r8a66597, BRDYSTS); - nrdysts = r8a66597_read(r8a66597, NRDYSTS); - bempsts = r8a66597_read(r8a66597, BEMPSTS); - brdyenb = r8a66597_read(r8a66597, BRDYENB); - nrdyenb = r8a66597_read(r8a66597, NRDYENB); - bempenb = r8a66597_read(r8a66597, BEMPENB); + u16 brdysts = r8a66597_read(r8a66597, BRDYSTS); + u16 bempsts = r8a66597_read(r8a66597, BEMPSTS); + u16 brdyenb = r8a66597_read(r8a66597, BRDYENB); + u16 bempenb = r8a66597_read(r8a66597, BEMPENB); if (mask0 & VBINT) { r8a66597_write(r8a66597, 0xffff & ~VBINT, @@ -1658,20 +1654,14 @@ static int r8a66597_dequeue(struct usb_ep *_ep, struct usb_request *_req) static int r8a66597_set_halt(struct usb_ep *_ep, int value) { - struct r8a66597_ep *ep; - struct r8a66597_request *req; + struct r8a66597_ep *ep = container_of(_ep, struct r8a66597_ep, ep); unsigned long flags; int ret = 0; - ep = container_of(_ep, struct r8a66597_ep, ep); - req = get_request_from_ep(ep); - spin_lock_irqsave(&ep->r8a66597->lock, flags); if (!list_empty(&ep->queue)) { ret = -EAGAIN; - goto out; - } - if (value) { + } else if (value) { ep->busy = 1; pipe_stall(ep->r8a66597, ep->pipenum); } else { @@ -1679,8 +1669,6 @@ static int r8a66597_set_halt(struct usb_ep *_ep, int value) ep->wedge = 0; pipe_stop(ep->r8a66597, ep->pipenum); } - -out: spin_unlock_irqrestore(&ep->r8a66597->lock, flags); return ret; } -- cgit v0.10.2 From bd8dc7375b7e147de0f09d8be89460d4143daf31 Mon Sep 17 00:00:00 2001 From: Michal Nazarewicz Date: Tue, 31 May 2016 14:17:24 +0200 Subject: usb: gadget: mv_u3d: fix unused-but-set-variable warnings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch fixes the following (W=1) warnings: drivers/usb/gadget/udc/mv_u3d_core.c: In function ‘mv_u3d_process_ep_req’: drivers/usb/gadget/udc/mv_u3d_core.c:124:6: warning: variable ‘trb_complete’ set but not used [-Wunused-but-set-variable] int trb_complete, actual, remaining_length = 0; ^ drivers/usb/gadget/udc/mv_u3d_core.c:123:28: warning: variable ‘curr_ep_context’ set but not used [-Wunused-but-set-variable] struct mv_u3d_ep_context *curr_ep_context; ^ drivers/usb/gadget/udc/mv_u3d_core.c:122:13: warning: variable ‘cur_deq_lo’ set but not used [-Wunused-but-set-variable] dma_addr_t cur_deq_lo; ^ drivers/usb/gadget/udc/mv_u3d_core.c: In function ‘mv_u3d_ep_enable’: drivers/usb/gadget/udc/mv_u3d_core.c:530:28: warning: variable ‘ep_context’ set but not used [-Wunused-but-set-variable] struct mv_u3d_ep_context *ep_context; ^ drivers/usb/gadget/udc/mv_u3d_core.c: In function ‘mv_u3d_ep_disable’: drivers/usb/gadget/udc/mv_u3d_core.c:636:28: warning: variable ‘ep_context’ set but not used [-Wunused-but-set-variable] struct mv_u3d_ep_context *ep_context; ^ In doing so, it removes calls to ioread32 function which does I/O with the device, but I hope the reads don’t have any side effects that are needed. Signed-off-by: Michal Nazarewicz Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/udc/mv_u3d_core.c b/drivers/usb/gadget/udc/mv_u3d_core.c index dafe74e..b9e19a5 100644 --- a/drivers/usb/gadget/udc/mv_u3d_core.c +++ b/drivers/usb/gadget/udc/mv_u3d_core.c @@ -119,18 +119,14 @@ static int mv_u3d_process_ep_req(struct mv_u3d *u3d, int index, struct mv_u3d_req *curr_req) { struct mv_u3d_trb *curr_trb; - dma_addr_t cur_deq_lo; - struct mv_u3d_ep_context *curr_ep_context; - int trb_complete, actual, remaining_length = 0; + int actual, remaining_length = 0; int direction, ep_num; int retval = 0; u32 tmp, status, length; - curr_ep_context = &u3d->ep_context[index]; direction = index % 2; ep_num = index / 2; - trb_complete = 0; actual = curr_req->req.length; while (!list_empty(&curr_req->trb_list)) { @@ -143,15 +139,10 @@ static int mv_u3d_process_ep_req(struct mv_u3d *u3d, int index, } curr_trb->trb_hw->ctrl.own = 0; - if (direction == MV_U3D_EP_DIR_OUT) { + if (direction == MV_U3D_EP_DIR_OUT) tmp = ioread32(&u3d->vuc_regs->rxst[ep_num].statuslo); - cur_deq_lo = - ioread32(&u3d->vuc_regs->rxst[ep_num].curdeqlo); - } else { + else tmp = ioread32(&u3d->vuc_regs->txst[ep_num].statuslo); - cur_deq_lo = - ioread32(&u3d->vuc_regs->txst[ep_num].curdeqlo); - } status = tmp >> MV_U3D_XFERSTATUS_COMPLETE_SHIFT; length = tmp & MV_U3D_XFERSTATUS_TRB_LENGTH_MASK; @@ -527,7 +518,6 @@ static int mv_u3d_ep_enable(struct usb_ep *_ep, { struct mv_u3d *u3d; struct mv_u3d_ep *ep; - struct mv_u3d_ep_context *ep_context; u16 max = 0; unsigned maxburst = 0; u32 epxcr, direction; @@ -548,9 +538,6 @@ static int mv_u3d_ep_enable(struct usb_ep *_ep, _ep->maxburst = 1; maxburst = _ep->maxburst; - /* Get the endpoint context address */ - ep_context = (struct mv_u3d_ep_context *)ep->ep_context; - /* Set the max burst size */ switch (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) { case USB_ENDPOINT_XFER_BULK: @@ -633,7 +620,6 @@ static int mv_u3d_ep_disable(struct usb_ep *_ep) { struct mv_u3d *u3d; struct mv_u3d_ep *ep; - struct mv_u3d_ep_context *ep_context; u32 epxcr, direction; unsigned long flags; @@ -646,9 +632,6 @@ static int mv_u3d_ep_disable(struct usb_ep *_ep) u3d = ep->u3d; - /* Get the endpoint context address */ - ep_context = ep->ep_context; - direction = mv_u3d_ep_dir(ep); /* nuke all pending requests (does flush) */ -- cgit v0.10.2 From f7d74de355976cbab89eeefe0063771c0de71457 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Sat, 4 Jun 2016 06:53:25 +0100 Subject: usb: gadget: bdc: fix spelling mistake: "allocted" -> "allocated" trivial fix to spelling mistake Signed-off-by: Colin Ian King Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/udc/bdc/bdc_ep.c b/drivers/usb/gadget/udc/bdc/bdc_ep.c index 650717e7..ccaa74a 100644 --- a/drivers/usb/gadget/udc/bdc/bdc_ep.c +++ b/drivers/usb/gadget/udc/bdc/bdc_ep.c @@ -81,7 +81,7 @@ static void ep_bd_list_free(struct bdc_ep *ep, u32 num_tabs) continue; } if (!bd_table->start_bd) { - dev_dbg(bdc->dev, "bd dma pool not allocted\n"); + dev_dbg(bdc->dev, "bd dma pool not allocated\n"); continue; } -- cgit v0.10.2 From 7c8b9c318490afe3e8bb244ef7e488265871aba7 Mon Sep 17 00:00:00 2001 From: Sandhya Bankar Date: Tue, 31 May 2016 08:59:44 -0400 Subject: usb: phy: omap-otg: Space required after that ','. Space required after that ','. Reviewed-by: Aaro Koskinen Signed-off-by: Sandhya Bankar Signed-off-by: Felipe Balbi diff --git a/drivers/usb/phy/phy-omap-otg.c b/drivers/usb/phy/phy-omap-otg.c index c4bf2de..6f6d2a7 100644 --- a/drivers/usb/phy/phy-omap-otg.c +++ b/drivers/usb/phy/phy-omap-otg.c @@ -148,7 +148,7 @@ static int omap_otg_remove(struct platform_device *pdev) struct otg_device *otg_dev = platform_get_drvdata(pdev); struct extcon_dev *edev = otg_dev->extcon; - extcon_unregister_notifier(edev, EXTCON_USB_HOST,&otg_dev->id_nb); + extcon_unregister_notifier(edev, EXTCON_USB_HOST, &otg_dev->id_nb); extcon_unregister_notifier(edev, EXTCON_USB, &otg_dev->vbus_nb); return 0; -- cgit v0.10.2 From c662a31be755f5e315945e2c802c335eb8baddb8 Mon Sep 17 00:00:00 2001 From: Michal Nazarewicz Date: Sat, 21 May 2016 20:47:34 +0200 Subject: usb: gadget: f_fs: printk error when excess data is dropped on read Add a pr_err when host sent more data then the size of the buffer user space gave us. This may happen on UDCs which require OUT requests to be aligned to max packet size. The patch includes a description of the situation. Signed-off-by: Michal Nazarewicz Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c index 70ed370..bb3d40a 100644 --- a/drivers/usb/gadget/function/f_fs.c +++ b/drivers/usb/gadget/function/f_fs.c @@ -640,6 +640,44 @@ static void ffs_epfile_io_complete(struct usb_ep *_ep, struct usb_request *req) } } +static ssize_t ffs_copy_to_iter(void *data, int data_len, struct iov_iter *iter) +{ + ssize_t ret = copy_to_iter(data, data_len, iter); + if (likely(ret == data_len)) + return ret; + + if (unlikely(iov_iter_count(iter))) + return -EFAULT; + + /* + * Dear user space developer! + * + * TL;DR: To stop getting below error message in your kernel log, change + * user space code using functionfs to align read buffers to a max + * packet size. + * + * Some UDCs (e.g. dwc3) require request sizes to be a multiple of a max + * packet size. When unaligned buffer is passed to functionfs, it + * internally uses a larger, aligned buffer so that such UDCs are happy. + * + * Unfortunately, this means that host may send more data than was + * requested in read(2) system call. f_fs doesn’t know what to do with + * that excess data so it simply drops it. + * + * Was the buffer aligned in the first place, no such problem would + * happen. + * + * This only affects OUT endpoints, i.e. reading data with a read(2), + * aio_read(2) etc. system calls. Writing data to an IN endpoint is not + * affected. + */ + pr_err("functionfs read size %d > requested size %zd, dropping excess data. " + "Align read buffer size to max packet size to avoid the problem.\n", + data_len, ret); + + return ret; +} + static void ffs_user_copy_worker(struct work_struct *work) { struct ffs_io_data *io_data = container_of(work, struct ffs_io_data, @@ -650,9 +688,7 @@ static void ffs_user_copy_worker(struct work_struct *work) if (io_data->read && ret > 0) { use_mm(io_data->mm); - ret = copy_to_iter(io_data->buf, ret, &io_data->data); - if (ret != io_data->req->actual && iov_iter_count(&io_data->data)) - ret = -EFAULT; + ret = ffs_copy_to_iter(io_data->buf, ret, &io_data->data); unuse_mm(io_data->mm); } @@ -803,18 +839,13 @@ static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data) interrupted = ep->status < 0; } - /* - * XXX We may end up silently droping data here. Since data_len - * (i.e. req->length) may be bigger than len (after being - * rounded up to maxpacketsize), we may end up with more data - * then user space has space for. - */ - ret = interrupted ? -EINTR : ep->status; - if (io_data->read && ret > 0) { - ret = copy_to_iter(data, ret, &io_data->data); - if (!ret) - ret = -EFAULT; - } + if (interrupted) + ret = -EINTR; + else if (io_data->read && ep->status > 0) + ret = ffs_copy_to_iter(data, ep->status, + &io_data->data); + else + ret = ep->status; goto error_mutex; } else if (!(req = usb_ep_alloc_request(ep->ep, GFP_KERNEL))) { ret = -ENOMEM; -- cgit v0.10.2 From 9353afbbfa7b10779a1aa108fcc23e32fd625990 Mon Sep 17 00:00:00 2001 From: Michal Nazarewicz Date: Sat, 21 May 2016 20:47:35 +0200 Subject: =?UTF-8?q?usb:=20gadget:=20f=5Ffs:=20buffer=20data=20from=20?= =?UTF-8?q?=E2=80=98oversized=E2=80=99=20OUT=20requests?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit f_fs rounds up read(2) requests to a multiple of a max packet size which means that host may provide more data than user has space for. So far, the excess data has been silently ignored. This introduces a buffer for a tail of such requests so that they are returned on next read instead of being ignored. Signed-off-by: Michal Nazarewicz Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c index bb3d40a..a91fcb0 100644 --- a/drivers/usb/gadget/function/f_fs.c +++ b/drivers/usb/gadget/function/f_fs.c @@ -130,6 +130,12 @@ struct ffs_epfile { struct dentry *dentry; + /* + * Buffer for holding data from partial reads which may happen since + * we’re rounding user read requests to a multiple of a max packet size. + */ + struct ffs_buffer *read_buffer; /* P: epfile->mutex */ + char name[5]; unsigned char in; /* P: ffs->eps_lock */ @@ -138,6 +144,12 @@ struct ffs_epfile { unsigned char _pad; }; +struct ffs_buffer { + size_t length; + char *data; + char storage[]; +}; + /* ffs_io_data structure ***************************************************/ struct ffs_io_data { @@ -667,6 +679,11 @@ static ssize_t ffs_copy_to_iter(void *data, int data_len, struct iov_iter *iter) * Was the buffer aligned in the first place, no such problem would * happen. * + * Data may be dropped only in AIO reads. Synchronous reads are handled + * by splitting a request into multiple parts. This splitting may still + * be a problem though so it’s likely best to align the buffer + * regardless of it being AIO or not.. + * * This only affects OUT endpoints, i.e. reading data with a read(2), * aio_read(2) etc. system calls. Writing data to an IN endpoint is not * affected. @@ -716,6 +733,56 @@ static void ffs_epfile_async_io_complete(struct usb_ep *_ep, schedule_work(&io_data->work); } +/* Assumes epfile->mutex is held. */ +static ssize_t __ffs_epfile_read_buffered(struct ffs_epfile *epfile, + struct iov_iter *iter) +{ + struct ffs_buffer *buf = epfile->read_buffer; + ssize_t ret; + if (!buf) + return 0; + + ret = copy_to_iter(buf->data, buf->length, iter); + if (buf->length == ret) { + kfree(buf); + epfile->read_buffer = NULL; + } else if (unlikely(iov_iter_count(iter))) { + ret = -EFAULT; + } else { + buf->length -= ret; + buf->data += ret; + } + return ret; +} + +/* Assumes epfile->mutex is held. */ +static ssize_t __ffs_epfile_read_data(struct ffs_epfile *epfile, + void *data, int data_len, + struct iov_iter *iter) +{ + struct ffs_buffer *buf; + + ssize_t ret = copy_to_iter(data, data_len, iter); + if (likely(data_len == ret)) + return ret; + + if (unlikely(iov_iter_count(iter))) + return -EFAULT; + + /* See ffs_copy_to_iter for more context. */ + pr_warn("functionfs read size %d > requested size %zd, splitting request into multiple reads.", + data_len, ret); + + data_len -= ret; + buf = kmalloc(sizeof(*buf) + data_len, GFP_KERNEL); + buf->length = data_len; + buf->data = buf->storage; + memcpy(buf->storage, data + ret, data_len); + epfile->read_buffer = buf; + + return ret; +} + static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data) { struct ffs_epfile *epfile = file->private_data; @@ -745,21 +812,40 @@ static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data) if (halt && epfile->isoc) return -EINVAL; + /* We will be using request and read_buffer */ + ret = ffs_mutex_lock(&epfile->mutex, file->f_flags & O_NONBLOCK); + if (unlikely(ret)) + goto error; + /* Allocate & copy */ if (!halt) { + struct usb_gadget *gadget; + + /* + * Do we have buffered data from previous partial read? Check + * that for synchronous case only because we do not have + * facility to ‘wake up’ a pending asynchronous read and push + * buffered data to it which we would need to make things behave + * consistently. + */ + if (!io_data->aio && io_data->read) { + ret = __ffs_epfile_read_buffered(epfile, &io_data->data); + if (ret) + goto error_mutex; + } + /* * if we _do_ wait above, the epfile->ffs->gadget might be NULL * before the waiting completes, so do not assign to 'gadget' * earlier */ - struct usb_gadget *gadget = epfile->ffs->gadget; - size_t copied; + gadget = epfile->ffs->gadget; spin_lock_irq(&epfile->ffs->eps_lock); /* In the meantime, endpoint got disabled or changed. */ if (epfile->ep != ep) { - spin_unlock_irq(&epfile->ffs->eps_lock); - return -ESHUTDOWN; + ret = -ESHUTDOWN; + goto error_lock; } data_len = iov_iter_count(&io_data->data); /* @@ -771,22 +857,17 @@ static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data) spin_unlock_irq(&epfile->ffs->eps_lock); data = kmalloc(data_len, GFP_KERNEL); - if (unlikely(!data)) - return -ENOMEM; - if (!io_data->read) { - copied = copy_from_iter(data, data_len, &io_data->data); - if (copied != data_len) { - ret = -EFAULT; - goto error; - } + if (unlikely(!data)) { + ret = -ENOMEM; + goto error_mutex; + } + if (!io_data->read && + copy_from_iter(data, data_len, &io_data->data) != data_len) { + ret = -EFAULT; + goto error_mutex; } } - /* We will be using request */ - ret = ffs_mutex_lock(&epfile->mutex, file->f_flags & O_NONBLOCK); - if (unlikely(ret)) - goto error; - spin_lock_irq(&epfile->ffs->eps_lock); if (epfile->ep != ep) { @@ -842,8 +923,8 @@ static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data) if (interrupted) ret = -EINTR; else if (io_data->read && ep->status > 0) - ret = ffs_copy_to_iter(data, ep->status, - &io_data->data); + ret = __ffs_epfile_read_data(epfile, data, ep->status, + &io_data->data); else ret = ep->status; goto error_mutex; @@ -1011,6 +1092,8 @@ ffs_epfile_release(struct inode *inode, struct file *file) ENTER(); + kfree(epfile->read_buffer); + epfile->read_buffer = NULL; ffs_data_closed(epfile->ffs); return 0; @@ -1636,19 +1719,24 @@ static void ffs_func_eps_disable(struct ffs_function *func) unsigned count = func->ffs->eps_count; unsigned long flags; - spin_lock_irqsave(&func->ffs->eps_lock, flags); do { + if (epfile) + mutex_lock(&epfile->mutex); + spin_lock_irqsave(&func->ffs->eps_lock, flags); /* pending requests get nuked */ if (likely(ep->ep)) usb_ep_disable(ep->ep); ++ep; + spin_unlock_irqrestore(&func->ffs->eps_lock, flags); if (epfile) { epfile->ep = NULL; + kfree(epfile->read_buffer); + epfile->read_buffer = NULL; + mutex_unlock(&epfile->mutex); ++epfile; } } while (--count); - spin_unlock_irqrestore(&func->ffs->eps_lock, flags); } static int ffs_func_eps_enable(struct ffs_function *func) -- cgit v0.10.2 From b9b092319be29bf665f1b004679de722b81c9123 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 18 May 2016 23:24:06 +0200 Subject: usb: phy: move msm_hsusb.h into driver As a preparation for another cleanup, this moves the header file for the phy-msm-usb driver into the driver itself. No other file includes it any more, and we don't really want it in the global namespace anyway. Signed-off-by: Arnd Bergmann Signed-off-by: Felipe Balbi diff --git a/drivers/usb/phy/phy-msm-usb.c b/drivers/usb/phy/phy-msm-usb.c index 72b387d..8a34759 100644 --- a/drivers/usb/phy/phy-msm-usb.c +++ b/drivers/usb/phy/phy-msm-usb.c @@ -18,6 +18,7 @@ #include #include +#include #include #include #include @@ -35,6 +36,8 @@ #include #include #include +#include +#include #include #include @@ -42,10 +45,183 @@ #include #include #include -#include #include #include +/** + * OTG control + * + * OTG_NO_CONTROL Id/VBUS notifications not required. Useful in host + * only configuration. + * OTG_PHY_CONTROL Id/VBUS notifications comes form USB PHY. + * OTG_PMIC_CONTROL Id/VBUS notifications comes from PMIC hardware. + * OTG_USER_CONTROL Id/VBUS notifcations comes from User via sysfs. + * + */ +enum otg_control_type { + OTG_NO_CONTROL = 0, + OTG_PHY_CONTROL, + OTG_PMIC_CONTROL, + OTG_USER_CONTROL, +}; + +/** + * PHY used in + * + * INVALID_PHY Unsupported PHY + * CI_45NM_INTEGRATED_PHY Chipidea 45nm integrated PHY + * SNPS_28NM_INTEGRATED_PHY Synopsis 28nm integrated PHY + * + */ +enum msm_usb_phy_type { + INVALID_PHY = 0, + CI_45NM_INTEGRATED_PHY, + SNPS_28NM_INTEGRATED_PHY, +}; + +#define IDEV_CHG_MAX 1500 +#define IUNIT 100 + +/** + * Different states involved in USB charger detection. + * + * USB_CHG_STATE_UNDEFINED USB charger is not connected or detection + * process is not yet started. + * USB_CHG_STATE_WAIT_FOR_DCD Waiting for Data pins contact. + * USB_CHG_STATE_DCD_DONE Data pin contact is detected. + * USB_CHG_STATE_PRIMARY_DONE Primary detection is completed (Detects + * between SDP and DCP/CDP). + * USB_CHG_STATE_SECONDARY_DONE Secondary detection is completed (Detects + * between DCP and CDP). + * USB_CHG_STATE_DETECTED USB charger type is determined. + * + */ +enum usb_chg_state { + USB_CHG_STATE_UNDEFINED = 0, + USB_CHG_STATE_WAIT_FOR_DCD, + USB_CHG_STATE_DCD_DONE, + USB_CHG_STATE_PRIMARY_DONE, + USB_CHG_STATE_SECONDARY_DONE, + USB_CHG_STATE_DETECTED, +}; + +/** + * USB charger types + * + * USB_INVALID_CHARGER Invalid USB charger. + * USB_SDP_CHARGER Standard downstream port. Refers to a downstream port + * on USB2.0 compliant host/hub. + * USB_DCP_CHARGER Dedicated charger port (AC charger/ Wall charger). + * USB_CDP_CHARGER Charging downstream port. Enumeration can happen and + * IDEV_CHG_MAX can be drawn irrespective of USB state. + * + */ +enum usb_chg_type { + USB_INVALID_CHARGER = 0, + USB_SDP_CHARGER, + USB_DCP_CHARGER, + USB_CDP_CHARGER, +}; + +/** + * struct msm_otg_platform_data - platform device data + * for msm_otg driver. + * @phy_init_seq: PHY configuration sequence values. Value of -1 is reserved as + * "do not overwrite default vaule at this address". + * @phy_init_sz: PHY configuration sequence size. + * @vbus_power: VBUS power on/off routine. + * @power_budget: VBUS power budget in mA (0 will be treated as 500mA). + * @mode: Supported mode (OTG/peripheral/host). + * @otg_control: OTG switch controlled by user/Id pin + */ +struct msm_otg_platform_data { + int *phy_init_seq; + int phy_init_sz; + void (*vbus_power)(bool on); + unsigned power_budget; + enum usb_dr_mode mode; + enum otg_control_type otg_control; + enum msm_usb_phy_type phy_type; + void (*setup_gpio)(enum usb_otg_state state); +}; + +/** + * struct msm_usb_cable - structure for exteternal connector cable + * state tracking + * @nb: hold event notification callback + * @conn: used for notification registration + */ +struct msm_usb_cable { + struct notifier_block nb; + struct extcon_dev *extcon; +}; + +/** + * struct msm_otg: OTG driver data. Shared by HCD and DCD. + * @otg: USB OTG Transceiver structure. + * @pdata: otg device platform data. + * @irq: IRQ number assigned for HSUSB controller. + * @clk: clock struct of usb_hs_clk. + * @pclk: clock struct of usb_hs_pclk. + * @core_clk: clock struct of usb_hs_core_clk. + * @regs: ioremapped register base address. + * @inputs: OTG state machine inputs(Id, SessValid etc). + * @sm_work: OTG state machine work. + * @in_lpm: indicates low power mode (LPM) state. + * @async_int: Async interrupt arrived. + * @cur_power: The amount of mA available from downstream port. + * @chg_work: Charger detection work. + * @chg_state: The state of charger detection process. + * @chg_type: The type of charger attached. + * @dcd_retires: The retry count used to track Data contact + * detection process. + * @manual_pullup: true if VBUS is not routed to USB controller/phy + * and controller driver therefore enables pull-up explicitly before + * starting controller using usbcmd run/stop bit. + * @vbus: VBUS signal state trakining, using extcon framework + * @id: ID signal state trakining, using extcon framework + * @switch_gpio: Descriptor for GPIO used to control external Dual + * SPDT USB Switch. + * @reboot: Used to inform the driver to route USB D+/D- line to Device + * connector + */ +struct msm_otg { + struct usb_phy phy; + struct msm_otg_platform_data *pdata; + int irq; + struct clk *clk; + struct clk *pclk; + struct clk *core_clk; + void __iomem *regs; +#define ID 0 +#define B_SESS_VLD 1 + unsigned long inputs; + struct work_struct sm_work; + atomic_t in_lpm; + int async_int; + unsigned cur_power; + int phy_number; + struct delayed_work chg_work; + enum usb_chg_state chg_state; + enum usb_chg_type chg_type; + u8 dcd_retries; + struct regulator *v3p3; + struct regulator *v1p8; + struct regulator *vddcx; + + struct reset_control *phy_rst; + struct reset_control *link_rst; + int vdd_levels[3]; + + bool manual_pullup; + + struct msm_usb_cable vbus; + struct msm_usb_cable id; + + struct gpio_desc *switch_gpio; + struct notifier_block reboot; +}; + #define MSM_USB_BASE (motg->regs) #define DRIVER_NAME "msm_otg" diff --git a/include/linux/usb/msm_hsusb.h b/include/linux/usb/msm_hsusb.h deleted file mode 100644 index 8c8f685..0000000 --- a/include/linux/usb/msm_hsusb.h +++ /dev/null @@ -1,200 +0,0 @@ -/* linux/include/asm-arm/arch-msm/hsusb.h - * - * Copyright (C) 2008 Google, Inc. - * Author: Brian Swetland - * Copyright (c) 2009-2011, Code Aurora Forum. All rights reserved. - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ - -#ifndef __ASM_ARCH_MSM_HSUSB_H -#define __ASM_ARCH_MSM_HSUSB_H - -#include -#include -#include -#include - -/** - * OTG control - * - * OTG_NO_CONTROL Id/VBUS notifications not required. Useful in host - * only configuration. - * OTG_PHY_CONTROL Id/VBUS notifications comes form USB PHY. - * OTG_PMIC_CONTROL Id/VBUS notifications comes from PMIC hardware. - * OTG_USER_CONTROL Id/VBUS notifcations comes from User via sysfs. - * - */ -enum otg_control_type { - OTG_NO_CONTROL = 0, - OTG_PHY_CONTROL, - OTG_PMIC_CONTROL, - OTG_USER_CONTROL, -}; - -/** - * PHY used in - * - * INVALID_PHY Unsupported PHY - * CI_45NM_INTEGRATED_PHY Chipidea 45nm integrated PHY - * SNPS_28NM_INTEGRATED_PHY Synopsis 28nm integrated PHY - * - */ -enum msm_usb_phy_type { - INVALID_PHY = 0, - CI_45NM_INTEGRATED_PHY, - SNPS_28NM_INTEGRATED_PHY, -}; - -#define IDEV_CHG_MAX 1500 -#define IUNIT 100 - -/** - * Different states involved in USB charger detection. - * - * USB_CHG_STATE_UNDEFINED USB charger is not connected or detection - * process is not yet started. - * USB_CHG_STATE_WAIT_FOR_DCD Waiting for Data pins contact. - * USB_CHG_STATE_DCD_DONE Data pin contact is detected. - * USB_CHG_STATE_PRIMARY_DONE Primary detection is completed (Detects - * between SDP and DCP/CDP). - * USB_CHG_STATE_SECONDARY_DONE Secondary detection is completed (Detects - * between DCP and CDP). - * USB_CHG_STATE_DETECTED USB charger type is determined. - * - */ -enum usb_chg_state { - USB_CHG_STATE_UNDEFINED = 0, - USB_CHG_STATE_WAIT_FOR_DCD, - USB_CHG_STATE_DCD_DONE, - USB_CHG_STATE_PRIMARY_DONE, - USB_CHG_STATE_SECONDARY_DONE, - USB_CHG_STATE_DETECTED, -}; - -/** - * USB charger types - * - * USB_INVALID_CHARGER Invalid USB charger. - * USB_SDP_CHARGER Standard downstream port. Refers to a downstream port - * on USB2.0 compliant host/hub. - * USB_DCP_CHARGER Dedicated charger port (AC charger/ Wall charger). - * USB_CDP_CHARGER Charging downstream port. Enumeration can happen and - * IDEV_CHG_MAX can be drawn irrespective of USB state. - * - */ -enum usb_chg_type { - USB_INVALID_CHARGER = 0, - USB_SDP_CHARGER, - USB_DCP_CHARGER, - USB_CDP_CHARGER, -}; - -/** - * struct msm_otg_platform_data - platform device data - * for msm_otg driver. - * @phy_init_seq: PHY configuration sequence values. Value of -1 is reserved as - * "do not overwrite default vaule at this address". - * @phy_init_sz: PHY configuration sequence size. - * @vbus_power: VBUS power on/off routine. - * @power_budget: VBUS power budget in mA (0 will be treated as 500mA). - * @mode: Supported mode (OTG/peripheral/host). - * @otg_control: OTG switch controlled by user/Id pin - */ -struct msm_otg_platform_data { - int *phy_init_seq; - int phy_init_sz; - void (*vbus_power)(bool on); - unsigned power_budget; - enum usb_dr_mode mode; - enum otg_control_type otg_control; - enum msm_usb_phy_type phy_type; - void (*setup_gpio)(enum usb_otg_state state); -}; - -/** - * struct msm_usb_cable - structure for exteternal connector cable - * state tracking - * @nb: hold event notification callback - * @conn: used for notification registration - */ -struct msm_usb_cable { - struct notifier_block nb; - struct extcon_dev *extcon; -}; - -/** - * struct msm_otg: OTG driver data. Shared by HCD and DCD. - * @otg: USB OTG Transceiver structure. - * @pdata: otg device platform data. - * @irq: IRQ number assigned for HSUSB controller. - * @clk: clock struct of usb_hs_clk. - * @pclk: clock struct of usb_hs_pclk. - * @core_clk: clock struct of usb_hs_core_clk. - * @regs: ioremapped register base address. - * @inputs: OTG state machine inputs(Id, SessValid etc). - * @sm_work: OTG state machine work. - * @in_lpm: indicates low power mode (LPM) state. - * @async_int: Async interrupt arrived. - * @cur_power: The amount of mA available from downstream port. - * @chg_work: Charger detection work. - * @chg_state: The state of charger detection process. - * @chg_type: The type of charger attached. - * @dcd_retires: The retry count used to track Data contact - * detection process. - * @manual_pullup: true if VBUS is not routed to USB controller/phy - * and controller driver therefore enables pull-up explicitly before - * starting controller using usbcmd run/stop bit. - * @vbus: VBUS signal state trakining, using extcon framework - * @id: ID signal state trakining, using extcon framework - * @switch_gpio: Descriptor for GPIO used to control external Dual - * SPDT USB Switch. - * @reboot: Used to inform the driver to route USB D+/D- line to Device - * connector - */ -struct msm_otg { - struct usb_phy phy; - struct msm_otg_platform_data *pdata; - int irq; - struct clk *clk; - struct clk *pclk; - struct clk *core_clk; - void __iomem *regs; -#define ID 0 -#define B_SESS_VLD 1 - unsigned long inputs; - struct work_struct sm_work; - atomic_t in_lpm; - int async_int; - unsigned cur_power; - int phy_number; - struct delayed_work chg_work; - enum usb_chg_state chg_state; - enum usb_chg_type chg_type; - u8 dcd_retries; - struct regulator *v3p3; - struct regulator *v1p8; - struct regulator *vddcx; - - struct reset_control *phy_rst; - struct reset_control *link_rst; - int vdd_levels[3]; - - bool manual_pullup; - - struct msm_usb_cable vbus; - struct msm_usb_cable id; - - struct gpio_desc *switch_gpio; - struct notifier_block reboot; -}; - -#endif -- cgit v0.10.2 From 72704f876f50b00f08d41d4b13d5a5d11262254f Mon Sep 17 00:00:00 2001 From: Baolin Wang Date: Mon, 16 May 2016 16:43:53 +0800 Subject: dwc3: gadget: Implement the suspend entry event handler It had changed to be suspend event for BIT6 in DEVT register from version 2.30a and above. Thus this patch introduces one suspend event handler to handle the suspend event. Signed-off-by: Baolin Wang Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index f209753..8f8c215 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -2695,6 +2695,17 @@ static void dwc3_gadget_linksts_change_interrupt(struct dwc3 *dwc, dwc->link_state = next; } +static void dwc3_gadget_suspend_interrupt(struct dwc3 *dwc, + unsigned int evtinfo) +{ + enum dwc3_link_state next = evtinfo & DWC3_LINK_STATE_MASK; + + if (dwc->link_state != next && next == DWC3_LINK_STATE_U3) + dwc3_suspend_gadget(dwc); + + dwc->link_state = next; +} + static void dwc3_gadget_hibernation_interrupt(struct dwc3 *dwc, unsigned int evtinfo) { @@ -2746,7 +2757,20 @@ static void dwc3_gadget_interrupt(struct dwc3 *dwc, dwc3_gadget_linksts_change_interrupt(dwc, event->event_info); break; case DWC3_DEVICE_EVENT_EOPF: - dwc3_trace(trace_dwc3_gadget, "End of Periodic Frame"); + /* It changed to be suspend event for version 2.30a and above */ + if (dwc->revision < DWC3_REVISION_230A) { + dwc3_trace(trace_dwc3_gadget, "End of Periodic Frame"); + } else { + dwc3_trace(trace_dwc3_gadget, "U3/L1-L2 Suspend Event"); + + /* + * Ignore suspend event until the gadget enters into + * USB_STATE_CONFIGURED state. + */ + if (dwc->gadget.state >= USB_STATE_CONFIGURED) + dwc3_gadget_suspend_interrupt(dwc, + event->event_info); + } break; case DWC3_DEVICE_EVENT_SOF: dwc3_trace(trace_dwc3_gadget, "Start of Periodic Frame"); -- cgit v0.10.2 From 43202800010102a857ffb119429d7dc5b41b7096 Mon Sep 17 00:00:00 2001 From: Sandhya Bankar Date: Wed, 4 May 2016 12:23:14 +0530 Subject: usb: Use (foo *) instead of (foo*). Use (foo *) instead of (foo*). Signed-off-by: Sandhya Bankar Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/config.c b/drivers/usb/gadget/config.c index e6c0542..17a6077 100644 --- a/drivers/usb/gadget/config.c +++ b/drivers/usb/gadget/config.c @@ -93,7 +93,7 @@ int usb_gadget_config_buf( *cp = *config; /* then interface/endpoint/class/vendor/... */ - len = usb_descriptor_fillbuf(USB_DT_CONFIG_SIZE + (u8*)buf, + len = usb_descriptor_fillbuf(USB_DT_CONFIG_SIZE + (u8 *)buf, length - USB_DT_CONFIG_SIZE, desc); if (len < 0) return len; -- cgit v0.10.2 From 1d23d16a88e6c8143b07339435ba061b131ebb8c Mon Sep 17 00:00:00 2001 From: Iago Abal Date: Tue, 21 Jun 2016 12:01:11 +0200 Subject: usb: gadget: pch_udc: reorder spin_[un]lock to avoid deadlock The above commit reordered spin_lock/unlock and now `&dev->lock' is acquired (rather than released) before calling `dev->driver->disconnect', `dev->driver->setup', `dev->driver->suspend', `usb_gadget_giveback_request', and `usb_gadget_udc_reset'. But this *may* not be the right way to fix the problem pointed by d3cb25a12138. Note that the other usb/gadget/udc drivers do release the lock before calling these functions. There are also inconsistencies within pch_udc.c, where `dev->driver->disconnect' is called while holding `&dev->lock' in lines 613 and 1184, but not in line 2739. Finally, commit d3cb25a12138 may have introduced several potential deadlocks. For instance, EBA (https://github.com/models-team/eba) reports: Double lock in drivers/usb/gadget/udc/pch_udc.c first at 2791: spin_lock(& dev->lock); [pch_udc_isr] second at 2694: spin_lock(& dev->lock); [pch_udc_svc_cfg_interrupt] after calling from 2793: pch_udc_dev_isr(dev, dev_intr); after calling from 2724: pch_udc_svc_cfg_interrupt(dev); Similarly, other potential deadlocks are 2791 -> 2793 -> 2721 -> 2657; and 2791 -> 2793 -> 2711 -> 2573 -> 1499 -> 1480. Fixes: d3cb25a12138 ("usb: gadget: udc: fix spin_lock in pch_udc") Signed-off-by: Iago Abal Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/udc/pch_udc.c b/drivers/usb/gadget/udc/pch_udc.c index 8ad847a..a97da64 100644 --- a/drivers/usb/gadget/udc/pch_udc.c +++ b/drivers/usb/gadget/udc/pch_udc.c @@ -1477,11 +1477,11 @@ static void complete_req(struct pch_udc_ep *ep, struct pch_udc_request *req, req->dma_mapped = 0; } ep->halted = 1; - spin_lock(&dev->lock); + spin_unlock(&dev->lock); if (!ep->in) pch_udc_ep_clear_rrdy(ep); usb_gadget_giveback_request(&ep->ep, &req->req); - spin_unlock(&dev->lock); + spin_lock(&dev->lock); ep->halted = halted; } @@ -2567,9 +2567,9 @@ static void pch_udc_svc_ur_interrupt(struct pch_udc_dev *dev) empty_req_queue(ep); } if (dev->driver) { - spin_lock(&dev->lock); - usb_gadget_udc_reset(&dev->gadget, dev->driver); spin_unlock(&dev->lock); + usb_gadget_udc_reset(&dev->gadget, dev->driver); + spin_lock(&dev->lock); } } @@ -2648,9 +2648,9 @@ static void pch_udc_svc_intf_interrupt(struct pch_udc_dev *dev) dev->ep[i].halted = 0; } dev->stall = 0; - spin_lock(&dev->lock); - dev->driver->setup(&dev->gadget, &dev->setup_data); spin_unlock(&dev->lock); + dev->driver->setup(&dev->gadget, &dev->setup_data); + spin_lock(&dev->lock); } /** @@ -2685,9 +2685,9 @@ static void pch_udc_svc_cfg_interrupt(struct pch_udc_dev *dev) dev->stall = 0; /* call gadget zero with setup data received */ - spin_lock(&dev->lock); - dev->driver->setup(&dev->gadget, &dev->setup_data); spin_unlock(&dev->lock); + dev->driver->setup(&dev->gadget, &dev->setup_data); + spin_lock(&dev->lock); } /** -- cgit v0.10.2 From b573d8028ee6125b353861bd1869a004d9820603 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Thu, 16 Jun 2016 10:54:20 +0200 Subject: kbuild: List libelf-devel as an alternative On openSUSE, the libelf development files are in package libelf-devel. Signed-off-by: Jean Delvare Acked-by: Josh Poimboeuf Cc: Jiri Olsa Cc: Michal Marek Cc: Peter Zijlstra Cc: linux-kbuild@vger.kernel.org Link: http://lkml.kernel.org/n/tip-s8nyk3pyy2927sd7qp7u42oi@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo diff --git a/Makefile b/Makefile index b409076..4a1fe88 100644 --- a/Makefile +++ b/Makefile @@ -1038,7 +1038,7 @@ ifdef CONFIG_STACK_VALIDATION ifeq ($(has_libelf),1) objtool_target := tools/objtool FORCE else - $(warning "Cannot use CONFIG_STACK_VALIDATION, please install libelf-dev or elfutils-libelf-devel") + $(warning "Cannot use CONFIG_STACK_VALIDATION, please install libelf-dev, libelf-devel or elfutils-libelf-devel") SKIP_STACK_VALIDATION := 1 export SKIP_STACK_VALIDATION endif diff --git a/tools/perf/config/Makefile b/tools/perf/config/Makefile index 80018fe..534c811 100644 --- a/tools/perf/config/Makefile +++ b/tools/perf/config/Makefile @@ -257,7 +257,7 @@ else LIBC_SUPPORT := 1 endif ifeq ($(LIBC_SUPPORT),1) - msg := $(warning No libelf found, disables 'probe' tool and BPF support in 'perf record', please install elfutils-libelf-devel/libelf-dev); + msg := $(warning No libelf found, disables 'probe' tool and BPF support in 'perf record', please install libelf-dev, libelf-devel or elfutils-libelf-devel); NO_LIBELF := 1 NO_DWARF := 1 -- cgit v0.10.2 From cbb0bba9f3526f23832385f9a47cf2a45fff7c05 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Thu, 16 Jun 2016 16:51:26 -0300 Subject: perf script: Fix documentation of '-f' when it should be '-F' The documentation for perf script mixes up '-f' and '-F'. Fix it. Signed-off-by: Adrian Hunter Cc: Andi Kleen Cc: Jiri Olsa Link: http://lkml.kernel.org/r/None Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/Documentation/perf-script.txt b/tools/perf/Documentation/perf-script.txt index 4fc44c7..4f34379 100644 --- a/tools/perf/Documentation/perf-script.txt +++ b/tools/perf/Documentation/perf-script.txt @@ -119,13 +119,13 @@ OPTIONS srcline, period, iregs, brstack, brstacksym, flags. Field list can be prepended with the type, trace, sw or hw, to indicate to which event type the field list applies. - e.g., -f sw:comm,tid,time,ip,sym and -f trace:time,cpu,trace + e.g., -F sw:comm,tid,time,ip,sym and -F trace:time,cpu,trace - perf script -f + perf script -F is equivalent to: - perf script -f trace: -f sw: -f hw: + perf script -F trace: -F sw: -F hw: i.e., the specified fields apply to all event types if the type string is not given. @@ -133,9 +133,9 @@ OPTIONS The arguments are processed in the order received. A later usage can reset a prior request. e.g.: - -f trace: -f comm,tid,time,ip,sym + -F trace: -F comm,tid,time,ip,sym - The first -f suppresses trace events (field list is ""), but then the + The first -F suppresses trace events (field list is ""), but then the second invocation sets the fields to comm,tid,time,ip,sym. In this case a warning is given to the user: @@ -143,9 +143,9 @@ OPTIONS Alternatively, consider the order: - -f comm,tid,time,ip,sym -f trace: + -F comm,tid,time,ip,sym -F trace: - The first -f sets the fields for all events and the second -f + The first -F sets the fields for all events and the second -F suppresses trace events. The user is given a warning message about the override, and the result of the above is that only S/W and H/W events are displayed with the given fields. @@ -154,14 +154,14 @@ OPTIONS event type, a message is displayed to the user that the option is ignored for that type. For example: - $ perf script -f comm,tid,trace + $ perf script -F comm,tid,trace 'trace' not valid for hardware events. Ignoring. 'trace' not valid for software events. Ignoring. Alternatively, if the type is given an invalid field is specified it is an error. For example: - perf script -v -f sw:comm,tid,trace + perf script -v -F sw:comm,tid,trace 'trace' not valid for software events. At this point usage is displayed, and perf-script exits. @@ -173,7 +173,7 @@ OPTIONS respectively. Finally, a user may not set fields to none for all event types. - i.e., -f "" is not allowed. + i.e., -F "" is not allowed. The brstack output includes branch related information with raw addresses using the /v/v/v/v/ syntax in the following order: -- cgit v0.10.2 From 0102ef3ec940e8a68aa94125cd4b40569b24e6be Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Tue, 14 Jun 2016 20:19:21 +0200 Subject: perf hists: Rename __hists__add_entry to hists__add_entry There's no reason we should suffer the '__' prefix for the base global function. Signed-off-by: Jiri Olsa Cc: David Ahern Cc: Namhyung Kim Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1465928361-2442-12-git-send-email-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c index 25c8173..a2324e1 100644 --- a/tools/perf/builtin-annotate.c +++ b/tools/perf/builtin-annotate.c @@ -75,7 +75,7 @@ static int perf_evsel__add_sample(struct perf_evsel *evsel, sample->period = 1; sample->weight = 1; - he = __hists__add_entry(hists, al, NULL, NULL, NULL, sample, true); + he = hists__add_entry(hists, al, NULL, NULL, NULL, sample, true); if (he == NULL) return -ENOMEM; diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c index 7f628f9..8b6735f 100644 --- a/tools/perf/builtin-diff.c +++ b/tools/perf/builtin-diff.c @@ -310,16 +310,6 @@ static int formula_fprintf(struct hist_entry *he, struct hist_entry *pair, return -1; } -static int hists__add_entry(struct hists *hists, - struct addr_location *al, - struct perf_sample *sample) -{ - if (__hists__add_entry(hists, al, NULL, NULL, NULL, - sample, true) != NULL) - return 0; - return -ENOMEM; -} - static int diff__process_sample_event(struct perf_tool *tool __maybe_unused, union perf_event *event, struct perf_sample *sample, @@ -336,7 +326,7 @@ static int diff__process_sample_event(struct perf_tool *tool __maybe_unused, return -1; } - if (hists__add_entry(hists, &al, sample)) { + if (!hists__add_entry(hists, &al, NULL, NULL, NULL, sample, true)) { pr_warning("problem incrementing symbol period, skipping event\n"); goto out_put; } diff --git a/tools/perf/tests/hists_link.c b/tools/perf/tests/hists_link.c index acf5a13..6f96ca4 100644 --- a/tools/perf/tests/hists_link.c +++ b/tools/perf/tests/hists_link.c @@ -84,7 +84,7 @@ static int add_hist_entries(struct perf_evlist *evlist, struct machine *machine) if (machine__resolve(machine, &al, &sample) < 0) goto out; - he = __hists__add_entry(hists, &al, NULL, + he = hists__add_entry(hists, &al, NULL, NULL, NULL, &sample, true); if (he == NULL) { addr_location__put(&al); @@ -103,7 +103,7 @@ static int add_hist_entries(struct perf_evlist *evlist, struct machine *machine) if (machine__resolve(machine, &al, &sample) < 0) goto out; - he = __hists__add_entry(hists, &al, NULL, + he = hists__add_entry(hists, &al, NULL, NULL, NULL, &sample, true); if (he == NULL) { addr_location__put(&al); diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c index 2515cfd..d2647b1 100644 --- a/tools/perf/util/hist.c +++ b/tools/perf/util/hist.c @@ -531,13 +531,13 @@ out: return he; } -struct hist_entry *__hists__add_entry(struct hists *hists, - struct addr_location *al, - struct symbol *sym_parent, - struct branch_info *bi, - struct mem_info *mi, - struct perf_sample *sample, - bool sample_self) +struct hist_entry *hists__add_entry(struct hists *hists, + struct addr_location *al, + struct symbol *sym_parent, + struct branch_info *bi, + struct mem_info *mi, + struct perf_sample *sample, + bool sample_self) { struct hist_entry entry = { .thread = al->thread, @@ -622,8 +622,8 @@ iter_add_single_mem_entry(struct hist_entry_iter *iter, struct addr_location *al */ sample->period = cost; - he = __hists__add_entry(hists, al, iter->parent, NULL, mi, - sample, true); + he = hists__add_entry(hists, al, iter->parent, NULL, mi, + sample, true); if (!he) return -ENOMEM; @@ -727,8 +727,8 @@ iter_add_next_branch_entry(struct hist_entry_iter *iter, struct addr_location *a sample->period = 1; sample->weight = bi->flags.cycles ? bi->flags.cycles : 1; - he = __hists__add_entry(hists, al, iter->parent, &bi[i], NULL, - sample, true); + he = hists__add_entry(hists, al, iter->parent, &bi[i], NULL, + sample, true); if (he == NULL) return -ENOMEM; @@ -764,8 +764,8 @@ iter_add_single_normal_entry(struct hist_entry_iter *iter, struct addr_location struct perf_sample *sample = iter->sample; struct hist_entry *he; - he = __hists__add_entry(evsel__hists(evsel), al, iter->parent, NULL, NULL, - sample, true); + he = hists__add_entry(evsel__hists(evsel), al, iter->parent, NULL, NULL, + sample, true); if (he == NULL) return -ENOMEM; @@ -825,8 +825,8 @@ iter_add_single_cumulative_entry(struct hist_entry_iter *iter, struct hist_entry *he; int err = 0; - he = __hists__add_entry(hists, al, iter->parent, NULL, NULL, - sample, true); + he = hists__add_entry(hists, al, iter->parent, NULL, NULL, + sample, true); if (he == NULL) return -ENOMEM; @@ -900,8 +900,8 @@ iter_add_next_cumulative_entry(struct hist_entry_iter *iter, } } - he = __hists__add_entry(evsel__hists(evsel), al, iter->parent, NULL, NULL, - sample, false); + he = hists__add_entry(evsel__hists(evsel), al, iter->parent, NULL, NULL, + sample, false); if (he == NULL) return -ENOMEM; diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h index a191128..0a03e08 100644 --- a/tools/perf/util/hist.h +++ b/tools/perf/util/hist.h @@ -120,13 +120,13 @@ extern const struct hist_iter_ops hist_iter_branch; extern const struct hist_iter_ops hist_iter_mem; extern const struct hist_iter_ops hist_iter_cumulative; -struct hist_entry *__hists__add_entry(struct hists *hists, - struct addr_location *al, - struct symbol *parent, - struct branch_info *bi, - struct mem_info *mi, - struct perf_sample *sample, - bool sample_self); +struct hist_entry *hists__add_entry(struct hists *hists, + struct addr_location *al, + struct symbol *parent, + struct branch_info *bi, + struct mem_info *mi, + struct perf_sample *sample, + bool sample_self); int hist_entry_iter__add(struct hist_entry_iter *iter, struct addr_location *al, int max_stack_depth, void *arg); -- cgit v0.10.2 From 814b3f5127248db90e5d9983668a44eec7b45c02 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 16 Jun 2016 17:10:46 -0300 Subject: perf tools: Remove some unused functions Probably are there since the beginning, taken from git but never used. Cc: Adrian Hunter Cc: David Ahern Cc: Jiri Olsa Cc: Namhyung Kim Cc: Wang Nan Link: http://lkml.kernel.org/n/tip-lr65jeefffjeaywoapps9a6i@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/util/cache.h b/tools/perf/util/cache.h index 0d814bb..f260040 100644 --- a/tools/perf/util/cache.h +++ b/tools/perf/util/cache.h @@ -32,7 +32,6 @@ int perf_config_int(const char *, const char *); u64 perf_config_u64(const char *, const char *); int perf_config_bool(const char *, const char *); int config_error_nonbool(const char *); -const char *perf_config_dirname(const char *, const char *); const char *perf_etc_perfconfig(void); char *alias_lookup(const char *alias); @@ -45,9 +44,6 @@ static inline int is_absolute_path(const char *path) return path[0] == '/'; } -char *strip_path_suffix(const char *path, const char *suffix); - char *mkpath(const char *fmt, ...) __attribute__((format (printf, 1, 2))); -char *perf_path(const char *fmt, ...) __attribute__((format (printf, 1, 2))); #endif /* __PERF_CACHE_H */ diff --git a/tools/perf/util/config.c b/tools/perf/util/config.c index 31e09a4..d15c592 100644 --- a/tools/perf/util/config.c +++ b/tools/perf/util/config.c @@ -372,7 +372,7 @@ int perf_config_bool(const char *name, const char *value) return !!perf_config_bool_or_int(name, value, &discard); } -const char *perf_config_dirname(const char *name, const char *value) +static const char *perf_config_dirname(const char *name, const char *value) { if (!name) return NULL; diff --git a/tools/perf/util/path.c b/tools/perf/util/path.c index 3bf6bf8..cff8bf0 100644 --- a/tools/perf/util/path.c +++ b/tools/perf/util/path.c @@ -14,14 +14,8 @@ static char bad_path[] = "/bad-path/"; /* - * Two hacks: + * One hack: */ - -static const char *get_perf_dir(void) -{ - return "."; -} - static char *get_pathname(void) { static char pathname_array[4][PATH_MAX]; @@ -54,60 +48,3 @@ char *mkpath(const char *fmt, ...) return bad_path; return cleanup_path(pathname); } - -char *perf_path(const char *fmt, ...) -{ - const char *perf_dir = get_perf_dir(); - char *pathname = get_pathname(); - va_list args; - unsigned len; - - len = strlen(perf_dir); - if (len > PATH_MAX-100) - return bad_path; - memcpy(pathname, perf_dir, len); - if (len && perf_dir[len-1] != '/') - pathname[len++] = '/'; - va_start(args, fmt); - len += vsnprintf(pathname + len, PATH_MAX - len, fmt, args); - va_end(args); - if (len >= PATH_MAX) - return bad_path; - return cleanup_path(pathname); -} - -/* strip arbitrary amount of directory separators at end of path */ -static inline int chomp_trailing_dir_sep(const char *path, int len) -{ - while (len && is_dir_sep(path[len - 1])) - len--; - return len; -} - -/* - * If path ends with suffix (complete path components), returns the - * part before suffix (sans trailing directory separators). - * Otherwise returns NULL. - */ -char *strip_path_suffix(const char *path, const char *suffix) -{ - int path_len = strlen(path), suffix_len = strlen(suffix); - - while (suffix_len) { - if (!path_len) - return NULL; - - if (is_dir_sep(path[path_len - 1])) { - if (!is_dir_sep(suffix[suffix_len - 1])) - return NULL; - path_len = chomp_trailing_dir_sep(path, path_len); - suffix_len = chomp_trailing_dir_sep(suffix, suffix_len); - } - else if (path[--path_len] != suffix[--suffix_len]) - return NULL; - } - - if (path_len && !is_dir_sep(path[path_len - 1])) - return NULL; - return strndup(path, chomp_trailing_dir_sep(path, path_len)); -} -- cgit v0.10.2 From e861964a26b786d349add4db4825597ec65b5780 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 16 Jun 2016 17:36:22 -0300 Subject: perf tools: Remove --perf-dir and --work-dir Completely unused in perf, carried along all this time from the initial copy of git infrastructure, ditch'em. Cc: Adrian Hunter Cc: David Ahern Cc: Jiri Olsa Cc: Namhyung Kim Cc: Wang Nan Link: http://lkml.kernel.org/n/tip-wtiln26gyqndprmkl0kdswvi@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/perf.c b/tools/perf/perf.c index 15982ce..634bf7c 100644 --- a/tools/perf/perf.c +++ b/tools/perf/perf.c @@ -139,8 +139,6 @@ struct option options[] = { OPT_ARGUMENT("html-path", "html-path"), OPT_ARGUMENT("paginate", "paginate"), OPT_ARGUMENT("no-pager", "no-pager"), - OPT_ARGUMENT("perf-dir", "perf-dir"), - OPT_ARGUMENT("work-tree", "work-tree"), OPT_ARGUMENT("debugfs-dir", "debugfs-dir"), OPT_ARGUMENT("buildid-dir", "buildid-dir"), OPT_ARGUMENT("list-cmds", "list-cmds"), @@ -200,35 +198,6 @@ static int handle_options(const char ***argv, int *argc, int *envchanged) use_pager = 0; if (envchanged) *envchanged = 1; - } else if (!strcmp(cmd, "--perf-dir")) { - if (*argc < 2) { - fprintf(stderr, "No directory given for --perf-dir.\n"); - usage(perf_usage_string); - } - setenv(PERF_DIR_ENVIRONMENT, (*argv)[1], 1); - if (envchanged) - *envchanged = 1; - (*argv)++; - (*argc)--; - handled++; - } else if (!prefixcmp(cmd, CMD_PERF_DIR)) { - setenv(PERF_DIR_ENVIRONMENT, cmd + strlen(CMD_PERF_DIR), 1); - if (envchanged) - *envchanged = 1; - } else if (!strcmp(cmd, "--work-tree")) { - if (*argc < 2) { - fprintf(stderr, "No directory given for --work-tree.\n"); - usage(perf_usage_string); - } - setenv(PERF_WORK_TREE_ENVIRONMENT, (*argv)[1], 1); - if (envchanged) - *envchanged = 1; - (*argv)++; - (*argc)--; - } else if (!prefixcmp(cmd, CMD_WORK_TREE)) { - setenv(PERF_WORK_TREE_ENVIRONMENT, cmd + strlen(CMD_WORK_TREE), 1); - if (envchanged) - *envchanged = 1; } else if (!strcmp(cmd, "--debugfs-dir")) { if (*argc < 2) { fprintf(stderr, "No directory given for --debugfs-dir.\n"); @@ -363,11 +332,6 @@ const char perf_version_string[] = PERF_VERSION; #define RUN_SETUP (1<<0) #define USE_PAGER (1<<1) -/* - * require working tree to be present -- anything uses this needs - * RUN_SETUP for reading from the configuration file. - */ -#define NEED_WORK_TREE (1<<2) static int run_builtin(struct cmd_struct *p, int argc, const char **argv) { diff --git a/tools/perf/util/cache.h b/tools/perf/util/cache.h index f260040..369f382 100644 --- a/tools/perf/util/cache.h +++ b/tools/perf/util/cache.h @@ -11,14 +11,9 @@ #include #define CMD_EXEC_PATH "--exec-path" -#define CMD_PERF_DIR "--perf-dir=" -#define CMD_WORK_TREE "--work-tree=" #define CMD_DEBUGFS_DIR "--debugfs-dir=" -#define PERF_DIR_ENVIRONMENT "PERF_DIR" -#define PERF_WORK_TREE_ENVIRONMENT "PERF_WORK_TREE" #define EXEC_PATH_ENVIRONMENT "PERF_EXEC_PATH" -#define DEFAULT_PERF_DIR_ENVIRONMENT ".perf" #define PERF_DEBUGFS_ENVIRONMENT "PERF_DEBUGFS_DIR" #define PERF_TRACEFS_ENVIRONMENT "PERF_TRACEFS_DIR" #define PERF_PAGER_ENVIRONMENT "PERF_PAGER" -- cgit v0.10.2 From f078464925f5b5c977c1196c67cae49cd82f40ff Mon Sep 17 00:00:00 2001 From: Wang Nan Date: Thu, 16 Jun 2016 08:02:40 +0000 Subject: perf llvm: Allow dump llvm output object file using llvm.dump-obj Add a 'llvm.dump-obj' config option to enable perf dump BPF object files compiled by LLVM. This option is useful when using BPF objects in embedded platforms. LLVM compiler won't be deployed in these platforms, and currently we don't support dynamic compiling library. Before this patch users have to explicitly issue llvm commands to compile BPF scripts, and can't use helpers (like include path detection and default macros) in perf. With this option, user is allowed to use perf to compile their BPF objects then copy them into their embedded platforms. Committer notice: Testing it: # cat ~/.perfconfig [llvm] dump-obj = true # # ls -la filter.o ls: cannot access filter.o: No such file or directory # cat filter.c #include #define SEC(NAME) __attribute__((section(NAME), used)) SEC("func=hrtimer_nanosleep rqtp->tv_nsec") int func(void *ctx, int err, long nsec) { return nsec > 1000; } char _license[] SEC("license") = "GPL"; int _version SEC("version") = LINUX_VERSION_CODE; # trace -e nanosleep --event filter.c usleep 6 LLVM: dumping filter.o 0.007 ( 0.007 ms): usleep/13976 nanosleep(rqtp: 0x7ffc5847f640 ) ... 0.007 ( ): perf_bpf_probe:func:(ffffffff811137d0) tv_nsec=6000) 0.070 ( 0.070 ms): usleep/13976 ... [continued]: nanosleep()) = 0 # ls -la filter.o -rw-r--r--. 1 root root 776 Jun 20 17:01 filter.o # readelf -SW filter.o There are 7 section headers, starting at offset 0x148: Section Headers: [Nr] Name Type Address Off Size ES Flg Lk Inf Al [ 0] NULL 0000000000000000 000000 000000 00 0 0 0 [ 1] .strtab STRTAB 0000000000000000 0000e8 00005a 00 0 0 1 [ 2] .text PROGBITS 0000000000000000 000040 000000 00 AX 0 0 4 [ 3] func=hrtimer_nanosleep rqtp->tv_nsec PROGBITS 0000000000000000 000040 000028 00 AX 0 0 8 [ 4] license PROGBITS 0000000000000000 000068 000004 00 WA 0 0 1 [ 5] version PROGBITS 0000000000000000 00006c 000004 00 WA 0 0 4 [ 6] .symtab SYMTAB 0000000000000000 000070 000078 18 1 2 8 Key to Flags: W (write), A (alloc), X (execute), M (merge), S (strings) I (info), L (link order), G (group), T (TLS), E (exclude), x (unknown) O (extra OS processing required) o (OS specific), p (processor specific) # Signed-off-by: Wang Nan Cc: Alexei Starovoitov Cc: Jiri Olsa Cc: pi3orama@163.com Link: http://lkml.kernel.org/r/1466064161-48553-2-git-send-email-wangnan0@huawei.com [ s/dumpping/dumping/g ] Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/util/llvm-utils.c b/tools/perf/util/llvm-utils.c index 33071d6..878a566 100644 --- a/tools/perf/util/llvm-utils.c +++ b/tools/perf/util/llvm-utils.c @@ -42,6 +42,8 @@ int perf_llvm_config(const char *var, const char *value) llvm_param.kbuild_dir = strdup(value); else if (!strcmp(var, "kbuild-opts")) llvm_param.kbuild_opts = strdup(value); + else if (!strcmp(var, "dump-obj")) + llvm_param.dump_obj = !!perf_config_bool(var, value); else return -1; llvm_param.user_set_param = true; @@ -326,6 +328,42 @@ get_kbuild_opts(char **kbuild_dir, char **kbuild_include_opts) pr_debug("include option is set to %s\n", *kbuild_include_opts); } +static void +dump_obj(const char *path, void *obj_buf, size_t size) +{ + char *obj_path = strdup(path); + FILE *fp; + char *p; + + if (!obj_path) { + pr_warning("WARNING: No enough memory, skip object dumping\n"); + return; + } + + p = strrchr(obj_path, '.'); + if (!p || (strcmp(p, ".c") != 0)) { + pr_warning("WARNING: invalid llvm source path: '%s', skip object dumping\n", + obj_path); + goto out; + } + + p[1] = 'o'; + fp = fopen(obj_path, "wb"); + if (!fp) { + pr_warning("WARNING: failed to open '%s': %s, skip object dumping\n", + obj_path, strerror(errno)); + goto out; + } + + pr_info("LLVM: dumping %s\n", obj_path); + if (fwrite(obj_buf, size, 1, fp) != 1) + pr_warning("WARNING: failed to write to file '%s': %s, skip object dumping\n", + obj_path, strerror(errno)); + fclose(fp); +out: + free(obj_path); +} + int llvm__compile_bpf(const char *path, void **p_obj_buf, size_t *p_obj_buf_sz) { @@ -411,6 +449,10 @@ int llvm__compile_bpf(const char *path, void **p_obj_buf, free(kbuild_dir); free(kbuild_include_opts); + + if (llvm_param.dump_obj) + dump_obj(path, obj_buf, obj_buf_sz); + if (!p_obj_buf) free(obj_buf); else diff --git a/tools/perf/util/llvm-utils.h b/tools/perf/util/llvm-utils.h index 23b9a74..9f501ce 100644 --- a/tools/perf/util/llvm-utils.h +++ b/tools/perf/util/llvm-utils.h @@ -30,6 +30,11 @@ struct llvm_param { */ const char *kbuild_opts; /* + * Default is false. If set to true, write compiling result + * to object file. + */ + bool dump_obj; + /* * Default is false. If one of the above fields is set by user * explicitly then user_set_llvm is set to true. This is used * for perf test. If user doesn't set anything in .perfconfig -- cgit v0.10.2 From 0aab21363ffa66d6e7340bc50cc5bfae865fd1a6 Mon Sep 17 00:00:00 2001 From: Wang Nan Date: Thu, 16 Jun 2016 08:02:41 +0000 Subject: perf record: Add --dry-run option to check cmdline options With '--dry-run', 'perf record' doesn't do reall recording. Combine with llvm.dump-obj option, --dry-run can be used to help compile BPF objects for embedded platform. Signed-off-by: Wang Nan Cc: Alexei Starovoitov Cc: Jiri Olsa Cc: pi3orama@163.com Link: http://lkml.kernel.org/r/1466064161-48553-3-git-send-email-wangnan0@huawei.com Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/Documentation/perf-record.txt b/tools/perf/Documentation/perf-record.txt index 8dbee83..5b46b1d 100644 --- a/tools/perf/Documentation/perf-record.txt +++ b/tools/perf/Documentation/perf-record.txt @@ -360,6 +360,13 @@ particular perf.data snapshot should be kept or not. Implies --timestamp-filename, --no-buildid and --no-buildid-cache. +--dry-run:: +Parse options then exit. --dry-run can be used to detect errors in cmdline +options. + +'perf record --dry-run -e' can act as a BPF script compiler if llvm.dump-obj +in config file is set to true. + SEE ALSO -------- linkperf:perf-stat[1], linkperf:perf-list[1] diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index d4cf1b0..b1304eb 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -1274,6 +1274,8 @@ static struct record record = { const char record_callchain_help[] = CALLCHAIN_RECORD_HELP "\n\t\t\t\tDefault: fp"; +static bool dry_run; + /* * XXX Will stay a global variable till we fix builtin-script.c to stop messing * with it and switch to use the library functions in perf_evlist that came @@ -1393,6 +1395,8 @@ struct option __record_options[] = { "append timestamp to output filename"), OPT_BOOLEAN(0, "switch-output", &record.switch_output, "Switch output when receive SIGUSR2"), + OPT_BOOLEAN(0, "dry-run", &dry_run, + "Parse options then exit"), OPT_END() }; @@ -1462,6 +1466,9 @@ int cmd_record(int argc, const char **argv, const char *prefix __maybe_unused) if (err) return err; + if (dry_run) + return 0; + err = bpf__setup_stdout(rec->evlist); if (err) { bpf__strerror_setup_stdout(rec->evlist, err, errbuf, sizeof(errbuf)); -- cgit v0.10.2 From 7da36e94e7fad768ca8640b61ed1f49b284e1dc5 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Mon, 20 Jun 2016 10:47:18 +0000 Subject: perf evsel: Fix write_backwards fallback Commit b90dc17a5d14 "perf evsel: Add overwrite attribute and check write_backward" misunderstood the 'order' should be obeyed in __perf_evsel__open. But the way this was done for attr.write_backwards was buggy, as we need to check features in the inverse order of their introduction to the kernel, so that a newer tool checks first the newest perf_event_attr fields, detecting that the older kernel doesn't have support for them. Also, we can avoid calling sys_perf_event_open() if we have already detected the missing of write_backward. Cc: He Kuang Cc: Jiri Olsa Cc: Masami Hiramatsu Cc: Namhyung Kim Cc: Zefan Li Cc: pi3orama@163.com Fixes: b90dc17a5d14 ("perf evsel: Add overwrite attribute and check write_backward") Link: http://lkml.kernel.org/r/1466419645-75551-2-git-send-email-wangnan0@huawei.com Link: http://lkml.kernel.org/r/20160616214724.GI13337@kernel.org Signed-off-by: Wang Nan Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index 9b2e3e6..1d8f2bb 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c @@ -1389,8 +1389,11 @@ fallback_missing_features: if (perf_missing_features.lbr_flags) evsel->attr.branch_sample_type &= ~(PERF_SAMPLE_BRANCH_NO_FLAGS | PERF_SAMPLE_BRANCH_NO_CYCLES); - if (perf_missing_features.write_backward) + if (perf_missing_features.write_backward) { + if (evsel->overwrite) + return -EINVAL; evsel->attr.write_backward = false; + } retry_sample_id: if (perf_missing_features.sample_id_all) evsel->attr.sample_id_all = 0; @@ -1453,12 +1456,6 @@ retry_open: err = -EINVAL; goto out_close; } - - if (evsel->overwrite && - perf_missing_features.write_backward) { - err = -EINVAL; - goto out_close; - } } } @@ -1496,7 +1493,10 @@ try_fallback: * Must probe features in the order they were added to the * perf_event_attr interface. */ - if (!perf_missing_features.clockid_wrong && evsel->attr.use_clockid) { + if (!perf_missing_features.write_backward && evsel->attr.write_backward) { + perf_missing_features.write_backward = true; + goto fallback_missing_features; + } else if (!perf_missing_features.clockid_wrong && evsel->attr.use_clockid) { perf_missing_features.clockid_wrong = true; goto fallback_missing_features; } else if (!perf_missing_features.clockid && evsel->attr.use_clockid) { @@ -1521,12 +1521,7 @@ try_fallback: PERF_SAMPLE_BRANCH_NO_FLAGS))) { perf_missing_features.lbr_flags = true; goto fallback_missing_features; - } else if (!perf_missing_features.write_backward && - evsel->attr.write_backward) { - perf_missing_features.write_backward = true; - goto fallback_missing_features; } - out_close: do { while (--thread >= 0) { @@ -2409,6 +2404,8 @@ int perf_evsel__open_strerror(struct perf_evsel *evsel, struct target *target, "We found oprofile daemon running, please stop it and try again."); break; case EINVAL: + if (evsel->overwrite && perf_missing_features.write_backward) + return scnprintf(msg, size, "Reading from overwrite event is not supported by this kernel."); if (perf_missing_features.clockid) return scnprintf(msg, size, "clockid feature not supported."); if (perf_missing_features.clockid_wrong) -- cgit v0.10.2 From 6745d8ea825966b0956c691cf7fccc13debedc39 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Tue, 12 Apr 2016 15:26:13 +0200 Subject: perf script: Add stackcollapse.py script Add stackcollapse.py script as an example of parsing call chains, and also of using optparse to access command line options. The flame graph tools include a set of scripts that parse output from various tools (including "perf script"), remove the offsets in the function and collapse each stack to a single line. The website also says "perf report could have a report style [...] that output folded stacks directly, obviating the need for stackcollapse-perf.pl", so here it is. This script is a Python rewrite of stackcollapse-perf.pl, using the perf scripting interface to access the perf data directly from Python. Signed-off-by: Paolo Bonzini Acked-by: Jiri Olsa Cc: Brendan Gregg Link: http://lkml.kernel.org/r/1460467573-22989-1-git-send-email-pbonzini@redhat.com Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/scripts/python/bin/stackcollapse-record b/tools/perf/scripts/python/bin/stackcollapse-record new file mode 100755 index 0000000..9d8f9f0 --- /dev/null +++ b/tools/perf/scripts/python/bin/stackcollapse-record @@ -0,0 +1,8 @@ +#!/bin/sh + +# +# stackcollapse.py can cover all type of perf samples including +# the tracepoints, so no special record requirements, just record what +# you want to analyze. +# +perf record "$@" diff --git a/tools/perf/scripts/python/bin/stackcollapse-report b/tools/perf/scripts/python/bin/stackcollapse-report new file mode 100755 index 0000000..356b965 --- /dev/null +++ b/tools/perf/scripts/python/bin/stackcollapse-report @@ -0,0 +1,3 @@ +#!/bin/sh +# description: produce callgraphs in short form for scripting use +perf script -s "$PERF_EXEC_PATH"/scripts/python/stackcollapse.py -- "$@" diff --git a/tools/perf/scripts/python/stackcollapse.py b/tools/perf/scripts/python/stackcollapse.py new file mode 100755 index 0000000..a2dfcda --- /dev/null +++ b/tools/perf/scripts/python/stackcollapse.py @@ -0,0 +1,127 @@ +#!/usr/bin/perl -w +# +# stackcollapse.py - format perf samples with one line per distinct call stack +# +# This script's output has two space-separated fields. The first is a semicolon +# separated stack including the program name (from the "comm" field) and the +# function names from the call stack. The second is a count: +# +# swapper;start_kernel;rest_init;cpu_idle;default_idle;native_safe_halt 2 +# +# The file is sorted according to the first field. +# +# Input may be created and processed using: +# +# perf record -a -g -F 99 sleep 60 +# perf script report stackcollapse > out.stacks-folded +# +# (perf script record stackcollapse works too). +# +# Written by Paolo Bonzini +# Based on Brendan Gregg's stackcollapse-perf.pl script. + +import os +import sys +from collections import defaultdict +from optparse import OptionParser, make_option + +sys.path.append(os.environ['PERF_EXEC_PATH'] + \ + '/scripts/python/Perf-Trace-Util/lib/Perf/Trace') + +from perf_trace_context import * +from Core import * +from EventClass import * + +# command line parsing + +option_list = [ + # formatting options for the bottom entry of the stack + make_option("--include-tid", dest="include_tid", + action="store_true", default=False, + help="include thread id in stack"), + make_option("--include-pid", dest="include_pid", + action="store_true", default=False, + help="include process id in stack"), + make_option("--no-comm", dest="include_comm", + action="store_false", default=True, + help="do not separate stacks according to comm"), + make_option("--tidy-java", dest="tidy_java", + action="store_true", default=False, + help="beautify Java signatures"), + make_option("--kernel", dest="annotate_kernel", + action="store_true", default=False, + help="annotate kernel functions with _[k]") +] + +parser = OptionParser(option_list=option_list) +(opts, args) = parser.parse_args() + +if len(args) != 0: + parser.error("unexpected command line argument") +if opts.include_tid and not opts.include_comm: + parser.error("requesting tid but not comm is invalid") +if opts.include_pid and not opts.include_comm: + parser.error("requesting pid but not comm is invalid") + +# event handlers + +lines = defaultdict(lambda: 0) + +def process_event(param_dict): + def tidy_function_name(sym, dso): + if sym is None: + sym = '[unknown]' + + sym = sym.replace(';', ':') + if opts.tidy_java: + # the original stackcollapse-perf.pl script gives the + # example of converting this: + # Lorg/mozilla/javascript/MemberBox;.(Ljava/lang/reflect/Method;)V + # to this: + # org/mozilla/javascript/MemberBox:.init + sym = sym.replace('<', '') + sym = sym.replace('>', '') + if sym[0] == 'L' and sym.find('/'): + sym = sym[1:] + try: + sym = sym[:sym.index('(')] + except ValueError: + pass + + if opts.annotate_kernel and dso == '[kernel.kallsyms]': + return sym + '_[k]' + else: + return sym + + stack = list() + if 'callchain' in param_dict: + for entry in param_dict['callchain']: + entry.setdefault('sym', dict()) + entry['sym'].setdefault('name', None) + entry.setdefault('dso', None) + stack.append(tidy_function_name(entry['sym']['name'], + entry['dso'])) + else: + param_dict.setdefault('symbol', None) + param_dict.setdefault('dso', None) + stack.append(tidy_function_name(param_dict['symbol'], + param_dict['dso'])) + + if opts.include_comm: + comm = param_dict["comm"].replace(' ', '_') + sep = "-" + if opts.include_pid: + comm = comm + sep + str(param_dict['sample']['pid']) + sep = "/" + if opts.include_tid: + comm = comm + sep + str(param_dict['sample']['tid']) + stack.append(comm) + + stack_string = ';'.join(reversed(stack)) + lines[stack_string] = lines[stack_string] + 1 + +def trace_end(): + list = lines.keys() + list.sort() + for stack in list: + print "%s %d" % (stack, lines[stack]) -- cgit v0.10.2 From 70992588193617511e1b50bf7adee2fd371a476b Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Tue, 21 Jun 2016 18:52:54 +0100 Subject: usb: renesas_usbhs: make usbhs_write32() static The usbhs_write32 function is not used outside of the rcar3.c file, so fix the following sparse warning by making it static: drivers/usb/renesas_usbhs/rcar3.c:26:6: warning: symbol 'usbhs_write32' was not declared. Should it be static? Signed-off-by: Ben Dooks Signed-off-by: Felipe Balbi diff --git a/drivers/usb/renesas_usbhs/rcar3.c b/drivers/usb/renesas_usbhs/rcar3.c index 38b01f2..1d70add 100644 --- a/drivers/usb/renesas_usbhs/rcar3.c +++ b/drivers/usb/renesas_usbhs/rcar3.c @@ -23,7 +23,7 @@ #define UGCTRL2_RESERVED_3 0x00000001 /* bit[3:0] should be B'0001 */ #define UGCTRL2_USB0SEL_OTG 0x00000030 -void usbhs_write32(struct usbhs_priv *priv, u32 reg, u32 data) +static void usbhs_write32(struct usbhs_priv *priv, u32 reg, u32 data) { iowrite32(data, priv->base + reg); } -- cgit v0.10.2 From b3b630b26ae87a54e2f396b459aab0cd2286fc77 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Mon, 20 Jun 2016 22:57:22 +0200 Subject: ARM: dts: sunxi: Add pll3 to simplefb nodes clocks lists Now that we've a clock node describing pll3 we must add it to the simplefb nodes clocks lists to avoid it getting turned off when simplefb is used. This fixes the screen going black when using simplefb. Signed-off-by: Hans de Goede Signed-off-by: Maxime Ripard diff --git a/arch/arm/boot/dts/sun4i-a10.dtsi b/arch/arm/boot/dts/sun4i-a10.dtsi index a03e56f..ca58eb2 100644 --- a/arch/arm/boot/dts/sun4i-a10.dtsi +++ b/arch/arm/boot/dts/sun4i-a10.dtsi @@ -65,8 +65,9 @@ compatible = "allwinner,simple-framebuffer", "simple-framebuffer"; allwinner,pipeline = "de_be0-lcd0-hdmi"; - clocks = <&pll5 1>, <&ahb_gates 36>, <&ahb_gates 43>, - <&ahb_gates 44>, <&dram_gates 26>; + clocks = <&pll3>, <&pll5 1>, <&ahb_gates 36>, + <&ahb_gates 43>, <&ahb_gates 44>, + <&dram_gates 26>; status = "disabled"; }; @@ -74,8 +75,9 @@ compatible = "allwinner,simple-framebuffer", "simple-framebuffer"; allwinner,pipeline = "de_fe0-de_be0-lcd0-hdmi"; - clocks = <&pll5 1>, <&ahb_gates 36>, <&ahb_gates 43>, - <&ahb_gates 44>, <&ahb_gates 46>, + clocks = <&pll3>, <&pll5 1>, <&ahb_gates 36>, + <&ahb_gates 43>, <&ahb_gates 44>, + <&ahb_gates 46>, <&dram_gates 25>, <&dram_gates 26>; status = "disabled"; }; @@ -84,9 +86,9 @@ compatible = "allwinner,simple-framebuffer", "simple-framebuffer"; allwinner,pipeline = "de_fe0-de_be0-lcd0"; - clocks = <&pll5 1>, <&ahb_gates 36>, <&ahb_gates 44>, - <&ahb_gates 46>, <&dram_gates 25>, - <&dram_gates 26>; + clocks = <&pll3>, <&pll5 1>, <&ahb_gates 36>, + <&ahb_gates 44>, <&ahb_gates 46>, + <&dram_gates 25>, <&dram_gates 26>; status = "disabled"; }; @@ -94,8 +96,9 @@ compatible = "allwinner,simple-framebuffer", "simple-framebuffer"; allwinner,pipeline = "de_fe0-de_be0-lcd0-tve0"; - clocks = <&pll5 1>, <&ahb_gates 34>, <&ahb_gates 36>, - <&ahb_gates 44>, <&ahb_gates 46>, + clocks = <&pll3>, <&pll5 1>, <&ahb_gates 34>, + <&ahb_gates 36>, <&ahb_gates 44>, + <&ahb_gates 46>, <&dram_gates 5>, <&dram_gates 25>, <&dram_gates 26>; status = "disabled"; }; diff --git a/arch/arm/boot/dts/sun5i-a10s.dtsi b/arch/arm/boot/dts/sun5i-a10s.dtsi index bddd0de..367f330 100644 --- a/arch/arm/boot/dts/sun5i-a10s.dtsi +++ b/arch/arm/boot/dts/sun5i-a10s.dtsi @@ -65,8 +65,8 @@ compatible = "allwinner,simple-framebuffer", "simple-framebuffer"; allwinner,pipeline = "de_be0-lcd0-hdmi"; - clocks = <&pll5 1>, <&ahb_gates 36>, <&ahb_gates 43>, - <&ahb_gates 44>; + clocks = <&pll3>, <&pll5 1>, <&ahb_gates 36>, + <&ahb_gates 43>, <&ahb_gates 44>; status = "disabled"; }; @@ -74,7 +74,8 @@ compatible = "allwinner,simple-framebuffer", "simple-framebuffer"; allwinner,pipeline = "de_be0-lcd0"; - clocks = <&pll5 1>, <&ahb_gates 36>, <&ahb_gates 44>; + clocks = <&pll3>, <&pll5 1>, <&ahb_gates 36>, + <&ahb_gates 44>; status = "disabled"; }; @@ -82,8 +83,8 @@ compatible = "allwinner,simple-framebuffer", "simple-framebuffer"; allwinner,pipeline = "de_be0-lcd0-tve0"; - clocks = <&pll5 1>, <&ahb_gates 34>, <&ahb_gates 36>, - <&ahb_gates 44>; + clocks = <&pll3>, <&pll5 1>, <&ahb_gates 34>, + <&ahb_gates 36>, <&ahb_gates 44>; status = "disabled"; }; }; diff --git a/arch/arm/boot/dts/sun7i-a20.dtsi b/arch/arm/boot/dts/sun7i-a20.dtsi index febdf4c..f480051 100644 --- a/arch/arm/boot/dts/sun7i-a20.dtsi +++ b/arch/arm/boot/dts/sun7i-a20.dtsi @@ -67,8 +67,9 @@ compatible = "allwinner,simple-framebuffer", "simple-framebuffer"; allwinner,pipeline = "de_be0-lcd0-hdmi"; - clocks = <&pll5 1>, <&ahb_gates 36>, <&ahb_gates 43>, - <&ahb_gates 44>, <&dram_gates 26>; + clocks = <&pll3>, <&pll5 1>, <&ahb_gates 36>, + <&ahb_gates 43>, <&ahb_gates 44>, + <&dram_gates 26>; status = "disabled"; }; @@ -76,8 +77,8 @@ compatible = "allwinner,simple-framebuffer", "simple-framebuffer"; allwinner,pipeline = "de_be0-lcd0"; - clocks = <&pll5 1>, <&ahb_gates 36>, <&ahb_gates 44>, - <&dram_gates 26>; + clocks = <&pll3>, <&pll5 1>, <&ahb_gates 36>, + <&ahb_gates 44>, <&dram_gates 26>; status = "disabled"; }; @@ -85,7 +86,7 @@ compatible = "allwinner,simple-framebuffer", "simple-framebuffer"; allwinner,pipeline = "de_be0-lcd0-tve0"; - clocks = <&pll5 1>, + clocks = <&pll3>, <&pll5 1>, <&ahb_gates 34>, <&ahb_gates 36>, <&ahb_gates 44>, <&dram_gates 5>, <&dram_gates 26>; status = "disabled"; -- cgit v0.10.2 From dd4629d46c3121b82e6a552c94cda6dcccfc38c6 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 21 Jun 2016 17:33:20 -0300 Subject: perf script stackcollapse: Remove reference to the perl interpreter It is ignored and this is actually a python script, not a perl one. Reported-by: Brendan Gregg Cc: Jiri Olsa Cc: Milian Wolff Cc: Namhyung Kim Cc: Paolo Bonzini Link: http://lkml.kernel.org/n/tip-0w4bpbqd79v3sl34jvpr11v0@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/scripts/python/stackcollapse.py b/tools/perf/scripts/python/stackcollapse.py index a2dfcda..5a605f7 100755 --- a/tools/perf/scripts/python/stackcollapse.py +++ b/tools/perf/scripts/python/stackcollapse.py @@ -1,5 +1,3 @@ -#!/usr/bin/perl -w -# # stackcollapse.py - format perf samples with one line per distinct call stack # # This script's output has two space-separated fields. The first is a semicolon -- cgit v0.10.2 From f758990f25d159c067f31ded52b298a4f15cb08e Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Mon, 20 Jun 2016 23:58:13 +0200 Subject: perf hists browser: Move hist_browser into header file This way we can use it outside of ui/browsers/hists.c and extend it in following patches. Signed-off-by: Jiri Olsa Cc: David Ahern Cc: Namhyung Kim Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1466459899-1166-3-git-send-email-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c index b1b6054..cc8dece 100644 --- a/tools/perf/ui/browsers/hists.c +++ b/tools/perf/ui/browsers/hists.c @@ -12,30 +12,13 @@ #include "../../util/top.h" #include "../../arch/common.h" -#include "../browser.h" +#include "../browsers/hists.h" #include "../helpline.h" #include "../util.h" #include "../ui.h" #include "map.h" #include "annotate.h" -struct hist_browser { - struct ui_browser b; - struct hists *hists; - struct hist_entry *he_selection; - struct map_symbol *selection; - struct hist_browser_timer *hbt; - struct pstack *pstack; - struct perf_env *env; - int print_seq; - bool show_dso; - bool show_headers; - float min_pcnt; - u64 nr_non_filtered_entries; - u64 nr_hierarchy_entries; - u64 nr_callchain_rows; -}; - extern void hist_browser__init_hpp(void); static int hists__browser_title(struct hists *hists, diff --git a/tools/perf/ui/browsers/hists.h b/tools/perf/ui/browsers/hists.h new file mode 100644 index 0000000..9b6785c --- /dev/null +++ b/tools/perf/ui/browsers/hists.h @@ -0,0 +1,23 @@ +#ifndef _PERF_UI_BROWSER_HISTS_H_ +#define _PERF_UI_BROWSER_HISTS_H_ 1 + +#include "ui/browser.h" + +struct hist_browser { + struct ui_browser b; + struct hists *hists; + struct hist_entry *he_selection; + struct map_symbol *selection; + struct hist_browser_timer *hbt; + struct pstack *pstack; + struct perf_env *env; + int print_seq; + bool show_dso; + bool show_headers; + float min_pcnt; + u64 nr_non_filtered_entries; + u64 nr_hierarchy_entries; + u64 nr_callchain_rows; +}; + +#endif /* _PERF_UI_BROWSER_HISTS_H_ */ -- cgit v0.10.2 From dabd201239b5a521c3a5406c86dd273f47f37f1a Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Mon, 20 Jun 2016 23:58:14 +0200 Subject: perf hists browser: Make (new|delete|run) public This way we can use it outside of ui/browsers/hists.c and extend it in following patches. Signed-off-by: Jiri Olsa Cc: David Ahern Cc: Namhyung Kim Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1466459899-1166-4-git-send-email-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c index cc8dece..539b690 100644 --- a/tools/perf/ui/browsers/hists.c +++ b/tools/perf/ui/browsers/hists.c @@ -568,7 +568,7 @@ static void ui_browser__warn_lost_events(struct ui_browser *browser) "Or reduce the sampling frequency."); } -static int hist_browser__run(struct hist_browser *browser, const char *help) +int hist_browser__run(struct hist_browser *browser, const char *help) { int key; char title[160]; @@ -2039,9 +2039,9 @@ static int hist_browser__dump(struct hist_browser *browser) return 0; } -static struct hist_browser *hist_browser__new(struct hists *hists, - struct hist_browser_timer *hbt, - struct perf_env *env) +struct hist_browser *hist_browser__new(struct hists *hists, + struct hist_browser_timer *hbt, + struct perf_env *env) { struct hist_browser *browser = zalloc(sizeof(*browser)); @@ -2059,7 +2059,7 @@ static struct hist_browser *hist_browser__new(struct hists *hists, return browser; } -static void hist_browser__delete(struct hist_browser *browser) +void hist_browser__delete(struct hist_browser *browser) { free(browser); } diff --git a/tools/perf/ui/browsers/hists.h b/tools/perf/ui/browsers/hists.h index 9b6785c..57b7764 100644 --- a/tools/perf/ui/browsers/hists.h +++ b/tools/perf/ui/browsers/hists.h @@ -20,4 +20,9 @@ struct hist_browser { u64 nr_callchain_rows; }; +struct hist_browser *hist_browser__new(struct hists *hists, + struct hist_browser_timer *hbt, + struct perf_env *env); +void hist_browser__delete(struct hist_browser *browser); +int hist_browser__run(struct hist_browser *browser, const char *help); #endif /* _PERF_UI_BROWSER_HISTS_H_ */ -- cgit v0.10.2 From 5b91a86f47669898d6f2fe625844ab65cf258c34 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Mon, 20 Jun 2016 23:58:15 +0200 Subject: perf hists browser: Introduce struct hist_browser title callback We can now setup title callback for hist_browser, which will be useful in following changes to create customized hist_browsers. This also separates struct perf_evsel dependency out of hist_browser basic code. Signed-off-by: Jiri Olsa Cc: David Ahern Cc: Namhyung Kim Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1466459899-1166-5-git-send-email-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c index 539b690..a74cbd3 100644 --- a/tools/perf/ui/browsers/hists.c +++ b/tools/perf/ui/browsers/hists.c @@ -21,9 +21,8 @@ extern void hist_browser__init_hpp(void); -static int hists__browser_title(struct hists *hists, - struct hist_browser_timer *hbt, - char *bf, size_t size); +static int perf_evsel_browser_title(struct hist_browser *browser, + char *bf, size_t size); static void hist_browser__update_nr_entries(struct hist_browser *hb); static struct rb_node *hists__filter_entries(struct rb_node *nd, @@ -568,6 +567,11 @@ static void ui_browser__warn_lost_events(struct ui_browser *browser) "Or reduce the sampling frequency."); } +static int hist_browser__title(struct hist_browser *browser, char *bf, size_t size) +{ + return browser->title ? browser->title(browser, bf, size) : 0; +} + int hist_browser__run(struct hist_browser *browser, const char *help) { int key; @@ -578,7 +582,7 @@ int hist_browser__run(struct hist_browser *browser, const char *help) browser->b.entries = &browser->hists->entries; browser->b.nr_entries = hist_browser__nr_entries(browser); - hists__browser_title(browser->hists, hbt, title, sizeof(title)); + hist_browser__title(browser, title, sizeof(title)); if (ui_browser__show(&browser->b, title, "%s", help) < 0) return -1; @@ -604,8 +608,7 @@ int hist_browser__run(struct hist_browser *browser, const char *help) ui_browser__warn_lost_events(&browser->b); } - hists__browser_title(browser->hists, - hbt, title, sizeof(title)); + hist_browser__title(browser, title, sizeof(title)); ui_browser__show_title(&browser->b, title); continue; } @@ -2054,6 +2057,7 @@ struct hist_browser *hist_browser__new(struct hists *hists, browser->show_headers = symbol_conf.show_hist_headers; browser->hbt = hbt; browser->env = env; + browser->title = perf_evsel_browser_title; } return browser; @@ -2080,10 +2084,11 @@ static inline bool is_report_browser(void *timer) return timer == NULL; } -static int hists__browser_title(struct hists *hists, - struct hist_browser_timer *hbt, +static int perf_evsel_browser_title(struct hist_browser *browser, char *bf, size_t size) { + struct hist_browser_timer *hbt = browser->hbt; + struct hists *hists = browser->hists; char unit; int printed; const struct dso *dso = hists->dso_filter; diff --git a/tools/perf/ui/browsers/hists.h b/tools/perf/ui/browsers/hists.h index 57b7764..cf9d049 100644 --- a/tools/perf/ui/browsers/hists.h +++ b/tools/perf/ui/browsers/hists.h @@ -18,6 +18,10 @@ struct hist_browser { u64 nr_non_filtered_entries; u64 nr_hierarchy_entries; u64 nr_callchain_rows; + + /* Get title string. */ + int (*title)(struct hist_browser *browser, + char *bf, size_t size); }; struct hist_browser *hist_browser__new(struct hists *hists, -- cgit v0.10.2 From b1c7a8f7a1dad1aa46ec26cdfa487598634c5267 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Mon, 20 Jun 2016 23:58:16 +0200 Subject: perf hists browser: Move horizontal scroll init to new() Moving horizontal scroll init to initialization function as already intended. Signed-off-by: Jiri Olsa Cc: David Ahern Cc: Namhyung Kim Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1466459899-1166-6-git-send-email-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c index a74cbd3..ccb9ed6 100644 --- a/tools/perf/ui/browsers/hists.c +++ b/tools/perf/ui/browsers/hists.c @@ -2049,6 +2049,8 @@ struct hist_browser *hist_browser__new(struct hists *hists, struct hist_browser *browser = zalloc(sizeof(*browser)); if (browser) { + struct perf_hpp_fmt *fmt; + browser->hists = hists; browser->b.refresh = hist_browser__refresh; browser->b.refresh_dimensions = hist_browser__refresh_dimensions; @@ -2058,6 +2060,11 @@ struct hist_browser *hist_browser__new(struct hists *hists, browser->hbt = hbt; browser->env = env; browser->title = perf_evsel_browser_title; + + hists__for_each_format(hists, fmt) { + perf_hpp__reset_width(fmt, hists); + ++browser->b.columns; + } } return browser; @@ -2654,7 +2661,6 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, int key = -1; char buf[64]; int delay_secs = hbt ? hbt->refresh : 0; - struct perf_hpp_fmt *fmt; #define HIST_BROWSER_HELP_COMMON \ "h/?/F1 Show this window\n" \ @@ -2713,18 +2719,6 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, memset(options, 0, sizeof(options)); memset(actions, 0, sizeof(actions)); - hists__for_each_format(browser->hists, fmt) { - perf_hpp__reset_width(fmt, hists); - /* - * This is done just once, and activates the horizontal scrolling - * code in the ui_browser code, it would be better to have a the - * counter in the perf_hpp code, but I couldn't find doing it here - * works, FIXME by setting this in hist_browser__new, for now, be - * clever 8-) - */ - ++browser->b.columns; - } - if (symbol_conf.col_width_list_str) perf_hpp__set_user_width(symbol_conf.col_width_list_str); -- cgit v0.10.2 From a6ec894dea730bdc5568289898d27311e4031da0 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Mon, 20 Jun 2016 23:58:17 +0200 Subject: perf hists browser: Introduce perf_evsel_browser constructor So we could use hist_browser__new for generic hist browser in following patches. Signed-off-by: Jiri Olsa Cc: David Ahern Cc: Namhyung Kim Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1466459899-1166-7-git-send-email-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c index ccb9ed6..a81b298b 100644 --- a/tools/perf/ui/browsers/hists.c +++ b/tools/perf/ui/browsers/hists.c @@ -2042,9 +2042,7 @@ static int hist_browser__dump(struct hist_browser *browser) return 0; } -struct hist_browser *hist_browser__new(struct hists *hists, - struct hist_browser_timer *hbt, - struct perf_env *env) +struct hist_browser *hist_browser__new(struct hists *hists) { struct hist_browser *browser = zalloc(sizeof(*browser)); @@ -2057,9 +2055,6 @@ struct hist_browser *hist_browser__new(struct hists *hists, browser->b.seek = ui_browser__hists_seek; browser->b.use_navkeypressed = true; browser->show_headers = symbol_conf.show_hist_headers; - browser->hbt = hbt; - browser->env = env; - browser->title = perf_evsel_browser_title; hists__for_each_format(hists, fmt) { perf_hpp__reset_width(fmt, hists); @@ -2070,6 +2065,21 @@ struct hist_browser *hist_browser__new(struct hists *hists, return browser; } +static struct hist_browser * +perf_evsel_browser__new(struct perf_evsel *evsel, + struct hist_browser_timer *hbt, + struct perf_env *env) +{ + struct hist_browser *browser = hist_browser__new(evsel__hists(evsel)); + + if (browser) { + browser->hbt = hbt; + browser->env = env; + browser->title = perf_evsel_browser_title; + } + return browser; +} + void hist_browser__delete(struct hist_browser *browser) { free(browser); @@ -2652,7 +2662,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, struct perf_env *env) { struct hists *hists = evsel__hists(evsel); - struct hist_browser *browser = hist_browser__new(hists, hbt, env); + struct hist_browser *browser = perf_evsel_browser__new(evsel, hbt, env); struct branch_info *bi; #define MAX_OPTIONS 16 char *options[MAX_OPTIONS]; diff --git a/tools/perf/ui/browsers/hists.h b/tools/perf/ui/browsers/hists.h index cf9d049..ec55a51 100644 --- a/tools/perf/ui/browsers/hists.h +++ b/tools/perf/ui/browsers/hists.h @@ -24,9 +24,7 @@ struct hist_browser { char *bf, size_t size); }; -struct hist_browser *hist_browser__new(struct hists *hists, - struct hist_browser_timer *hbt, - struct perf_env *env); +struct hist_browser *hist_browser__new(struct hists *hists); void hist_browser__delete(struct hist_browser *browser); int hist_browser__run(struct hist_browser *browser, const char *help); #endif /* _PERF_UI_BROWSER_HISTS_H_ */ -- cgit v0.10.2 From fcd864265028b65bf154f35fe5a17591ffd49cb9 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Mon, 20 Jun 2016 23:58:18 +0200 Subject: perf hists browser: Introduce init() Factoring out the hist_browser initialization code, so it could be used from other parts in following patches. Signed-off-by: Jiri Olsa Cc: David Ahern Cc: Namhyung Kim Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1466459899-1166-8-git-send-email-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c index a81b298b..9d74435 100644 --- a/tools/perf/ui/browsers/hists.c +++ b/tools/perf/ui/browsers/hists.c @@ -2042,25 +2042,30 @@ static int hist_browser__dump(struct hist_browser *browser) return 0; } +void hist_browser__init(struct hist_browser *browser, + struct hists *hists) +{ + struct perf_hpp_fmt *fmt; + + browser->hists = hists; + browser->b.refresh = hist_browser__refresh; + browser->b.refresh_dimensions = hist_browser__refresh_dimensions; + browser->b.seek = ui_browser__hists_seek; + browser->b.use_navkeypressed = true; + browser->show_headers = symbol_conf.show_hist_headers; + + hists__for_each_format(hists, fmt) { + perf_hpp__reset_width(fmt, hists); + ++browser->b.columns; + } +} + struct hist_browser *hist_browser__new(struct hists *hists) { struct hist_browser *browser = zalloc(sizeof(*browser)); - if (browser) { - struct perf_hpp_fmt *fmt; - - browser->hists = hists; - browser->b.refresh = hist_browser__refresh; - browser->b.refresh_dimensions = hist_browser__refresh_dimensions; - browser->b.seek = ui_browser__hists_seek; - browser->b.use_navkeypressed = true; - browser->show_headers = symbol_conf.show_hist_headers; - - hists__for_each_format(hists, fmt) { - perf_hpp__reset_width(fmt, hists); - ++browser->b.columns; - } - } + if (browser) + hist_browser__init(browser, hists); return browser; } diff --git a/tools/perf/ui/browsers/hists.h b/tools/perf/ui/browsers/hists.h index ec55a51..39bd0f2 100644 --- a/tools/perf/ui/browsers/hists.h +++ b/tools/perf/ui/browsers/hists.h @@ -27,4 +27,6 @@ struct hist_browser { struct hist_browser *hist_browser__new(struct hists *hists); void hist_browser__delete(struct hist_browser *browser); int hist_browser__run(struct hist_browser *browser, const char *help); +void hist_browser__init(struct hist_browser *browser, + struct hists *hists); #endif /* _PERF_UI_BROWSER_HISTS_H_ */ -- cgit v0.10.2 From 89c7cb2cad5e5e3675df3ba1c12fe2f64dc691d6 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Mon, 20 Jun 2016 23:58:19 +0200 Subject: perf hists: Enlarge pid sort entry size The pid sort entry currently aligns pids with 5 digits, which is not enough for current 4 million pids limit. This leads to unaligned ':' header-data output when we display 7 digits pid: # Children Self Symbol Pid:Command # ........ ........ ...................... ..................... # 0.12% 0.12% [.] 0x0000000000147e0f 2052894:krava ... Adding 2 more digit to properly align the pid limit: # Children Self Symbol Pid:Command # ........ ........ ...................... ....................... # 0.12% 0.12% [.] 0x0000000000147e0f 2052894:krava Signed-off-by: Jiri Olsa Cc: David Ahern Cc: Namhyung Kim Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1466459899-1166-9-git-send-email-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c index d2647b1..d9826cc 100644 --- a/tools/perf/util/hist.c +++ b/tools/perf/util/hist.c @@ -79,7 +79,7 @@ void hists__calc_col_len(struct hists *hists, struct hist_entry *h) len = thread__comm_len(h->thread); if (hists__new_col_len(hists, HISTC_COMM, len)) - hists__set_col_len(hists, HISTC_THREAD, len + 6); + hists__set_col_len(hists, HISTC_THREAD, len + 8); if (h->ms.map) { len = dso__name_len(h->ms.map->dso); diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c index 896d34eb..a764139 100644 --- a/tools/perf/util/sort.c +++ b/tools/perf/util/sort.c @@ -79,8 +79,8 @@ static int hist_entry__thread_snprintf(struct hist_entry *he, char *bf, { const char *comm = thread__comm_str(he->thread); - width = max(7U, width) - 6; - return repsep_snprintf(bf, size, "%5d:%-*.*s", he->thread->tid, + width = max(7U, width) - 8; + return repsep_snprintf(bf, size, "%7d:%-*.*s", he->thread->tid, width, width, comm ?: ""); } @@ -95,7 +95,7 @@ static int hist_entry__thread_filter(struct hist_entry *he, int type, const void } struct sort_entry sort_thread = { - .se_header = " Pid:Command", + .se_header = " Pid:Command", .se_cmp = sort__thread_cmp, .se_snprintf = hist_entry__thread_snprintf, .se_filter = hist_entry__thread_filter, -- cgit v0.10.2 From 0b04b3dcdfb9aeb0e83c8ca322bf0830ee51ce38 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 21 Jun 2016 18:15:45 -0300 Subject: perf evlist: Destructors should accept NULL And do nothing, just like free(), to avoid having to test it in callers, usually in error paths. Cc: Adrian Hunter Cc: David Ahern Cc: Jiri Olsa Cc: Masami Hiramatsu Cc: Namhyung Kim Cc: Wang Nan Link: http://lkml.kernel.org/n/tip-mexbavy0ft387j5w89t365eu@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/builtin-kvm.c b/tools/perf/builtin-kvm.c index 6487c06..ad46e91 100644 --- a/tools/perf/builtin-kvm.c +++ b/tools/perf/builtin-kvm.c @@ -1429,8 +1429,7 @@ out: if (kvm->session) perf_session__delete(kvm->session); kvm->session = NULL; - if (kvm->evlist) - perf_evlist__delete(kvm->evlist); + perf_evlist__delete(kvm->evlist); return err; } diff --git a/tools/perf/tests/event-times.c b/tools/perf/tests/event-times.c index 95fb744..9f5698a 100644 --- a/tools/perf/tests/event-times.c +++ b/tools/perf/tests/event-times.c @@ -200,8 +200,7 @@ static int test_times(int (attach)(struct perf_evlist *), count.ena, count.run); out_err: - if (evlist) - perf_evlist__delete(evlist); + perf_evlist__delete(evlist); return !err ? TEST_OK : TEST_FAIL; } diff --git a/tools/perf/tests/parse-no-sample-id-all.c b/tools/perf/tests/parse-no-sample-id-all.c index 294c76b..81c6eea 100644 --- a/tools/perf/tests/parse-no-sample-id-all.c +++ b/tools/perf/tests/parse-no-sample-id-all.c @@ -44,8 +44,7 @@ static int process_events(union perf_event **events, size_t count) for (i = 0; i < count && !err; i++) err = process_event(&evlist, events[i]); - if (evlist) - perf_evlist__delete(evlist); + perf_evlist__delete(evlist); return err; } diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index 1b918aa..fcb8f1f 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c @@ -127,6 +127,9 @@ void perf_evlist__exit(struct perf_evlist *evlist) void perf_evlist__delete(struct perf_evlist *evlist) { + if (evlist == NULL) + return; + perf_evlist__munmap(evlist); perf_evlist__close(evlist); cpu_map__put(evlist->cpus); -- cgit v0.10.2 From e1446551e60a7773c3acf3c55bb9449d70127882 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Wed, 22 Jun 2016 10:02:16 -0300 Subject: perf session: Destructors should accept NULL And do nothing, just like free(), to avoid having to test it in callers, usually in error paths. Cc: Adrian Hunter Cc: David Ahern Cc: Jiri Olsa Cc: Masami Hiramatsu Cc: Namhyung Kim Cc: Wang Nan Link: http://lkml.kernel.org/n/tip-dyuupcj0hnoyt96vma8b3anv@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/builtin-buildid-cache.c b/tools/perf/builtin-buildid-cache.c index d75bded..2cbec65 100644 --- a/tools/perf/builtin-buildid-cache.c +++ b/tools/perf/builtin-buildid-cache.c @@ -419,8 +419,7 @@ int cmd_buildid_cache(int argc, const char **argv, pr_warning("Couldn't add %s\n", kcore_filename); out: - if (session) - perf_session__delete(session); + perf_session__delete(session); return ret; } diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c index 8b6735f..eac0b11 100644 --- a/tools/perf/builtin-diff.c +++ b/tools/perf/builtin-diff.c @@ -756,9 +756,7 @@ static int __cmd_diff(void) out_delete: data__for_each_file(i, d) { - if (d->session) - perf_session__delete(d->session); - + perf_session__delete(d->session); data__free(d); } diff --git a/tools/perf/builtin-kvm.c b/tools/perf/builtin-kvm.c index ad46e91..8f8f90e 100644 --- a/tools/perf/builtin-kvm.c +++ b/tools/perf/builtin-kvm.c @@ -1426,8 +1426,7 @@ static int kvm_events_live(struct perf_kvm_stat *kvm, err = kvm_events_live_report(kvm); out: - if (kvm->session) - perf_session__delete(kvm->session); + perf_session__delete(kvm->session); kvm->session = NULL; perf_evlist__delete(kvm->evlist); diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index dfedf09..43be0c5 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c @@ -178,6 +178,8 @@ static void perf_session__delete_threads(struct perf_session *session) void perf_session__delete(struct perf_session *session) { + if (session == NULL) + return; auxtrace__free(session); auxtrace_index__free(&session->auxtrace_index); perf_session__destroy_kernel_maps(session); -- cgit v0.10.2 From 61b3f66a3f99bb8a6a5145b1c2bd7eb98bf64748 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Wed, 22 Jun 2016 10:10:52 -0300 Subject: perf tests time-to-tsc: No need to disable an event before deleting it Because at the destructor we will call close() and that will do the disable. And we destructors can accept NULL, just like free(), so no need to check it. Cc: Adrian Hunter Cc: Peter Zijlstra Cc: Jiri Olsa Link: http://lkml.kernel.org/n/tip-i98mcyfkkjh5qp62dle27ac1@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/arch/x86/tests/perf-time-to-tsc.c b/tools/perf/arch/x86/tests/perf-time-to-tsc.c index d4aa567..5c76cc8 100644 --- a/tools/perf/arch/x86/tests/perf-time-to-tsc.c +++ b/tools/perf/arch/x86/tests/perf-time-to-tsc.c @@ -154,10 +154,6 @@ next_event: err = 0; out_err: - if (evlist) { - perf_evlist__disable(evlist); - perf_evlist__delete(evlist); - } - + perf_evlist__delete(evlist); return err; } -- cgit v0.10.2 From 32ca678dcd250f05183cf0c8a9e516545c6068bc Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Wed, 22 Jun 2016 10:19:11 -0300 Subject: perf machine: Destructors should accept NULL And do nothing, just like free(), to avoid having to test it in callers, usually in error paths. Cc: Adrian Hunter Cc: David Ahern Cc: Jiri Olsa Cc: Masami Hiramatsu Cc: Namhyung Kim Cc: Wang Nan Link: http://lkml.kernel.org/n/tip-q42gj3b3znhho9z1mrbo4jce@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c index a0c186a..bc2cdbd 100644 --- a/tools/perf/util/machine.c +++ b/tools/perf/util/machine.c @@ -138,8 +138,10 @@ void machine__exit(struct machine *machine) void machine__delete(struct machine *machine) { - machine__exit(machine); - free(machine); + if (machine) { + machine__exit(machine); + free(machine); + } } void machines__init(struct machines *machines) diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c index 084756c..caad19d 100644 --- a/tools/perf/util/probe-event.c +++ b/tools/perf/util/probe-event.c @@ -102,10 +102,8 @@ out: void exit_probe_symbol_maps(void) { - if (host_machine) { - machine__delete(host_machine); - host_machine = NULL; - } + machine__delete(host_machine); + host_machine = NULL; symbol__exit(); } -- cgit v0.10.2 From 50ad77db41fe3a08aeeae04088869142a1d9d007 Mon Sep 17 00:00:00 2001 From: Joel Stanley Date: Fri, 13 May 2016 00:13:12 +0930 Subject: doc/devicetree: Add Aspeed VIC bindings Signed-off-by: Joel Stanley Link: https://lkml.kernel.org/r/1463064193-2178-2-git-send-email-joel@jms.id.au Signed-off-by: Jason Cooper diff --git a/Documentation/devicetree/bindings/interrupt-controller/aspeed,ast2400-vic.txt b/Documentation/devicetree/bindings/interrupt-controller/aspeed,ast2400-vic.txt new file mode 100644 index 0000000..6c6e853 --- /dev/null +++ b/Documentation/devicetree/bindings/interrupt-controller/aspeed,ast2400-vic.txt @@ -0,0 +1,22 @@ +Aspeed Vectored Interrupt Controller + +These bindings are for the Aspeed AST2400 interrupt controller register layout. +The SoC has an legacy register layout, but this driver does not support that +mode of operation. + +Required properties: + +- compatible : should be "aspeed,ast2400-vic". + +- interrupt-controller : Identifies the node as an interrupt controller +- #interrupt-cells : Specifies the number of cells needed to encode an + interrupt source. The value shall be 1. + +Example: + + vic: interrupt-controller@1e6c0080 { + compatible = "aspeed,ast2400-vic"; + interrupt-controller; + #interrupt-cells = <1>; + reg = <0x1e6c0080 0x80>; + }; -- cgit v0.10.2 From 5952884258e52ad695e281d7b8181d51384ee97c Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Fri, 13 May 2016 00:13:13 +0930 Subject: irqchip/aspeed-vic: Add irq controller for Aspeed Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Joel Stanley Link: https://lkml.kernel.org/r/1463064193-2178-3-git-send-email-joel@jms.id.au Signed-off-by: Jason Cooper diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile index 38853a1..bb5dc3d 100644 --- a/drivers/irqchip/Makefile +++ b/drivers/irqchip/Makefile @@ -69,3 +69,4 @@ obj-$(CONFIG_PIC32_EVIC) += irq-pic32-evic.o obj-$(CONFIG_MVEBU_ODMI) += irq-mvebu-odmi.o obj-$(CONFIG_LS_SCFG_MSI) += irq-ls-scfg-msi.o obj-$(CONFIG_EZNPS_GIC) += irq-eznps.o +obj-$(CONFIG_ARCH_ASPEED) += irq-aspeed-vic.o diff --git a/drivers/irqchip/irq-aspeed-vic.c b/drivers/irqchip/irq-aspeed-vic.c new file mode 100644 index 0000000..d24451d --- /dev/null +++ b/drivers/irqchip/irq-aspeed-vic.c @@ -0,0 +1,230 @@ +/* + * Copyright (C) 2015 - Ben Herrenschmidt, IBM Corp. + * + * Driver for Aspeed "new" VIC as found in SoC generation 3 and later + * + * Based on irq-vic.c: + * + * Copyright (C) 1999 - 2003 ARM Limited + * Copyright (C) 2000 Deep Blue Solutions Ltd + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +/* These definitions correspond to the "new mapping" of the + * register set that interleaves "high" and "low". The offsets + * below are for the "low" register, add 4 to get to the high one + */ +#define AVIC_IRQ_STATUS 0x00 +#define AVIC_FIQ_STATUS 0x08 +#define AVIC_RAW_STATUS 0x10 +#define AVIC_INT_SELECT 0x18 +#define AVIC_INT_ENABLE 0x20 +#define AVIC_INT_ENABLE_CLR 0x28 +#define AVIC_INT_TRIGGER 0x30 +#define AVIC_INT_TRIGGER_CLR 0x38 +#define AVIC_INT_SENSE 0x40 +#define AVIC_INT_DUAL_EDGE 0x48 +#define AVIC_INT_EVENT 0x50 +#define AVIC_EDGE_CLR 0x58 +#define AVIC_EDGE_STATUS 0x60 + +#define NUM_IRQS 64 + +struct aspeed_vic { + void __iomem *base; + u32 edge_sources[2]; + struct irq_domain *dom; +}; +static struct aspeed_vic *system_avic; + +static void vic_init_hw(struct aspeed_vic *vic) +{ + u32 sense; + + /* Disable all interrupts */ + writel(0xffffffff, vic->base + AVIC_INT_ENABLE_CLR); + writel(0xffffffff, vic->base + AVIC_INT_ENABLE_CLR + 4); + + /* Make sure no soft trigger is on */ + writel(0xffffffff, vic->base + AVIC_INT_TRIGGER_CLR); + writel(0xffffffff, vic->base + AVIC_INT_TRIGGER_CLR + 4); + + /* Set everything to be IRQ */ + writel(0, vic->base + AVIC_INT_SELECT); + writel(0, vic->base + AVIC_INT_SELECT + 4); + + /* Some interrupts have a programable high/low level trigger + * (4 GPIO direct inputs), for now we assume this was configured + * by firmware. We read which ones are edge now. + */ + sense = readl(vic->base + AVIC_INT_SENSE); + vic->edge_sources[0] = ~sense; + sense = readl(vic->base + AVIC_INT_SENSE + 4); + vic->edge_sources[1] = ~sense; + + /* Clear edge detection latches */ + writel(0xffffffff, vic->base + AVIC_EDGE_CLR); + writel(0xffffffff, vic->base + AVIC_EDGE_CLR + 4); +} + +static void __exception_irq_entry avic_handle_irq(struct pt_regs *regs) +{ + struct aspeed_vic *vic = system_avic; + u32 stat, irq; + + for (;;) { + irq = 0; + stat = readl_relaxed(vic->base + AVIC_IRQ_STATUS); + if (!stat) { + stat = readl_relaxed(vic->base + AVIC_IRQ_STATUS + 4); + irq = 32; + } + if (stat == 0) + break; + irq += ffs(stat) - 1; + handle_domain_irq(vic->dom, irq, regs); + } +} + +static void avic_ack_irq(struct irq_data *d) +{ + struct aspeed_vic *vic = irq_data_get_irq_chip_data(d); + unsigned int sidx = d->hwirq >> 5; + unsigned int sbit = 1u << (d->hwirq & 0x1f); + + /* Clear edge latch for edge interrupts, nop for level */ + if (vic->edge_sources[sidx] & sbit) + writel(sbit, vic->base + AVIC_EDGE_CLR + sidx * 4); +} + +static void avic_mask_irq(struct irq_data *d) +{ + struct aspeed_vic *vic = irq_data_get_irq_chip_data(d); + unsigned int sidx = d->hwirq >> 5; + unsigned int sbit = 1u << (d->hwirq & 0x1f); + + writel(sbit, vic->base + AVIC_INT_ENABLE_CLR + sidx * 4); +} + +static void avic_unmask_irq(struct irq_data *d) +{ + struct aspeed_vic *vic = irq_data_get_irq_chip_data(d); + unsigned int sidx = d->hwirq >> 5; + unsigned int sbit = 1u << (d->hwirq & 0x1f); + + writel(sbit, vic->base + AVIC_INT_ENABLE + sidx * 4); +} + +/* For level irq, faster than going through a nop "ack" and mask */ +static void avic_mask_ack_irq(struct irq_data *d) +{ + struct aspeed_vic *vic = irq_data_get_irq_chip_data(d); + unsigned int sidx = d->hwirq >> 5; + unsigned int sbit = 1u << (d->hwirq & 0x1f); + + /* First mask */ + writel(sbit, vic->base + AVIC_INT_ENABLE_CLR + sidx * 4); + + /* Then clear edge latch for edge interrupts */ + if (vic->edge_sources[sidx] & sbit) + writel(sbit, vic->base + AVIC_EDGE_CLR + sidx * 4); +} + +static struct irq_chip avic_chip = { + .name = "AVIC", + .irq_ack = avic_ack_irq, + .irq_mask = avic_mask_irq, + .irq_unmask = avic_unmask_irq, + .irq_mask_ack = avic_mask_ack_irq, +}; + +static int avic_map(struct irq_domain *d, unsigned int irq, + irq_hw_number_t hwirq) +{ + struct aspeed_vic *vic = d->host_data; + unsigned int sidx = hwirq >> 5; + unsigned int sbit = 1u << (hwirq & 0x1f); + + /* Check if interrupt exists */ + if (sidx > 1) + return -EPERM; + + if (vic->edge_sources[sidx] & sbit) + irq_set_chip_and_handler(irq, &avic_chip, handle_edge_irq); + else + irq_set_chip_and_handler(irq, &avic_chip, handle_level_irq); + irq_set_chip_data(irq, vic); + irq_set_probe(irq); + return 0; +} + +static struct irq_domain_ops avic_dom_ops = { + .map = avic_map, + .xlate = irq_domain_xlate_onetwocell, +}; + +static int __init avic_of_init(struct device_node *node, + struct device_node *parent) +{ + void __iomem *regs; + struct aspeed_vic *vic; + + if (WARN(parent, "non-root Aspeed VIC not supported")) + return -EINVAL; + if (WARN(system_avic, "duplicate Aspeed VIC not supported")) + return -EINVAL; + + regs = of_iomap(node, 0); + if (WARN_ON(!regs)) + return -EIO; + + vic = kzalloc(sizeof(struct aspeed_vic), GFP_KERNEL); + if (WARN_ON(!vic)) { + iounmap(regs); + return -ENOMEM; + } + vic->base = regs; + + /* Initialize soures, all masked */ + vic_init_hw(vic); + + /* Ready to receive interrupts */ + system_avic = vic; + set_handle_irq(avic_handle_irq); + + /* Register our domain */ + vic->dom = irq_domain_add_simple(node, NUM_IRQS, 0, + &avic_dom_ops, vic); + + return 0; +} + +IRQCHIP_DECLARE(aspeed_new_vic, "aspeed,ast2400-vic", avic_of_init); -- cgit v0.10.2 From 48d8d5db4ac454e590ef7d440f456743d6cbaa94 Mon Sep 17 00:00:00 2001 From: He Kuang Date: Wed, 22 Jun 2016 06:57:05 +0000 Subject: perf tools: Let python use correct gcc for build_ext MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently, python uses host gcc instead of cross-compile gcc in the last step of compiling build_ext(remove '--quiet' to show verbose): cross-gcc ... cross-gcc ... creating ~/out/python_ext_build/lib gcc -pthread -shared -Wl,-z ... This is wrong but may not cause any errors unless the features detected by cross-compiler do not match those for host compiler, and causes the following errors: /usr/lib64/gcc/bin/ld: cannot find -lunwind-x86 collect2: error: ld returned 1 exit status error: command 'gcc' failed with exit status 1 cp: cannot stat ‘~/out/python_ext_build/lib/perf.so’: No such file or directory Makefile.perf:257: recipe for target '~/out/python/perf.so' failed make[1]: *** [~/out/python/perf.so] Error 1 Makefile:68: recipe for target 'all' failed make: *** [all] Error 2 This issue is also reported and anwsered on stackoverflow. Link: http://stackoverflow.com/questions/5986256/python-distutils-gcc-path Signed-off-by: He Kuang Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Andi Kleen Cc: David Ahern Cc: Ekaterina Tumanova Cc: Jiri Olsa Cc: Josh Poimboeuf Cc: Kan Liang Cc: Masami Hiramatsu Cc: Namhyung Kim Cc: Pekka Enberg Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Sukadev Bhattiprolu Cc: Wang Nan Link: http://lkml.kernel.org/r/1466578626-92406-5-git-send-email-hekuang@huawei.com Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf index bde8cba..d0a2cb1 100644 --- a/tools/perf/Makefile.perf +++ b/tools/perf/Makefile.perf @@ -254,7 +254,8 @@ PYTHON_EXT_SRCS := $(shell grep -v ^\# util/python-ext-sources) PYTHON_EXT_DEPS := util/python-ext-sources util/setup.py $(LIBTRACEEVENT) $(LIBAPI) $(OUTPUT)python/perf.so: $(PYTHON_EXT_SRCS) $(PYTHON_EXT_DEPS) $(LIBTRACEEVENT_DYNAMIC_LIST) - $(QUIET_GEN)CFLAGS='$(CFLAGS)' LDFLAGS='$(LDFLAGS) $(LIBTRACEEVENT_DYNAMIC_LIST_LDFLAGS)' \ + $(QUIET_GEN)LDSHARED="$(CC) -pthread -shared" \ + CFLAGS='$(CFLAGS)' LDFLAGS='$(LDFLAGS) $(LIBTRACEEVENT_DYNAMIC_LIST_LDFLAGS)' \ $(PYTHON_WORD) util/setup.py \ --quiet build_ext; \ mkdir -p $(OUTPUT)python && \ -- cgit v0.10.2 From d16dcd3d18759eb955e0325572d07457f93494f5 Mon Sep 17 00:00:00 2001 From: Jon Hunter Date: Tue, 21 Jun 2016 10:23:22 +0100 Subject: irqdomain: Fix disposal of mappings for interrupt hierarchies The function irq_create_of_mapping() is used to create an interrupt mapping. However, depending on whether the irqdomain, to which the interrupt belongs, is part of a hierarchy, determines whether the mapping is created via calling irq_domain_alloc_irqs() or irq_create_mapping(). To dispose of the interrupt mapping, drivers call irq_dispose_mapping(). However, this function does not check to see if the irqdomain is part of a hierarchy or not and simply assumes that it was mapped via calling irq_create_mapping() so calls irq_domain_disassociate() to unmap the interrupt. Fix this by checking to see if the irqdomain is part of a hierarchy and if so call irq_domain_free_irqs() to free/unmap the interrupt. Signed-off-by: Jon Hunter Cc: Marc Zyngier Cc: Jiang Liu Link: http://lkml.kernel.org/r/1466501002-16368-1-git-send-email-jonathanh@nvidia.com Signed-off-by: Thomas Gleixner diff --git a/kernel/irq/irqdomain.c b/kernel/irq/irqdomain.c index caa6a63..5d89d72 100644 --- a/kernel/irq/irqdomain.c +++ b/kernel/irq/irqdomain.c @@ -680,8 +680,12 @@ void irq_dispose_mapping(unsigned int virq) if (WARN_ON(domain == NULL)) return; - irq_domain_disassociate(domain, virq); - irq_free_desc(virq); + if (irq_domain_is_hierarchy(domain)) { + irq_domain_free_irqs(virq, 1); + } else { + irq_domain_disassociate(domain, virq); + irq_free_desc(virq); + } } EXPORT_SYMBOL_GPL(irq_dispose_mapping); -- cgit v0.10.2 From a05f44c89ee1151b0da3ddd43d9e57d8f15b2f20 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Thu, 23 Jun 2016 19:34:30 +0900 Subject: extcon: Check for incorrect connection type in notifier register If we call extcon_register_notifier() with the wrong cable type, it blows up with an oops instead of returning an error code. Let's be nice and fail gracefully given that the consumer might not know if the cable is supported by the extcon provider. Signed-off-by: Stephen Boyd Signed-off-by: Chanwoo Choi diff --git a/drivers/extcon/extcon.c b/drivers/extcon/extcon.c index 4fef9ab..b6408f0 100644 --- a/drivers/extcon/extcon.c +++ b/drivers/extcon/extcon.c @@ -415,6 +415,8 @@ int extcon_register_notifier(struct extcon_dev *edev, unsigned int id, if (edev) { idx = find_cable_index_by_id(edev, id); + if (idx < 0) + return idx; spin_lock_irqsave(&edev->lock, flags); ret = raw_notifier_chain_register(&edev->nh[idx], nb); @@ -458,6 +460,8 @@ int extcon_unregister_notifier(struct extcon_dev *edev, unsigned int id, return -EINVAL; idx = find_cable_index_by_id(edev, id); + if (idx < 0) + return idx; spin_lock_irqsave(&edev->lock, flags); ret = raw_notifier_chain_unregister(&edev->nh[idx], nb); -- cgit v0.10.2 From 41840d211c518e6af6e327b03e09323824e563bf Mon Sep 17 00:00:00 2001 From: Taeung Song Date: Thu, 23 Jun 2016 17:55:17 +0900 Subject: perf config: Move config declarations from util/cache.h to util/config.h Lately util/config.h has been added but util/cache.h has declarations of functions and a global variable for config features. To manage codes about configuration at one spot, move them to util/config.h and let source files that need config features include config.h And if the source files that included previous cache.h need only config.h, remove including cache.h. Signed-off-by: Taeung Song Cc: Alexander Shishkin Cc: Jiri Olsa Cc: Masami Hiramatsu Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Wang Nan Link: http://lkml.kernel.org/r/1466672119-4852-2-git-send-email-treeze.taeung@gmail.com Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/builtin-help.c b/tools/perf/builtin-help.c index f9830c9..268ab73 100644 --- a/tools/perf/builtin-help.c +++ b/tools/perf/builtin-help.c @@ -4,7 +4,7 @@ * Builtin help command */ #include "perf.h" -#include "util/cache.h" +#include "util/config.h" #include "builtin.h" #include #include "common-cmds.h" diff --git a/tools/perf/builtin-kmem.c b/tools/perf/builtin-kmem.c index 58adfee..4defe44 100644 --- a/tools/perf/builtin-kmem.c +++ b/tools/perf/builtin-kmem.c @@ -4,7 +4,7 @@ #include "util/evlist.h" #include "util/evsel.h" #include "util/util.h" -#include "util/cache.h" +#include "util/config.h" #include "util/symbol.h" #include "util/thread.h" #include "util/header.h" diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index b1304eb..c97b2b69 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -13,6 +13,7 @@ #include "util/util.h" #include #include "util/parse-events.h" +#include "util/config.h" #include "util/callchain.h" #include "util/cgroup.h" diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index 9f36b23..bcb49ff 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c @@ -8,7 +8,7 @@ #include "builtin.h" #include "util/util.h" -#include "util/cache.h" +#include "util/config.h" #include "util/annotate.h" #include "util/color.h" diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 81dba80..ec4cba6 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -22,7 +22,7 @@ #include "perf.h" #include "util/annotate.h" -#include "util/cache.h" +#include "util/config.h" #include "util/color.h" #include "util/evlist.h" #include "util/evsel.h" diff --git a/tools/perf/perf.c b/tools/perf/perf.c index 634bf7c..66772da 100644 --- a/tools/perf/perf.c +++ b/tools/perf/perf.c @@ -10,7 +10,7 @@ #include "util/env.h" #include -#include "util/cache.h" +#include "util/config.h" #include "util/quote.h" #include #include "util/parse-events.h" diff --git a/tools/perf/ui/browser.c b/tools/perf/ui/browser.c index af68a9d..3eb3edb 100644 --- a/tools/perf/ui/browser.c +++ b/tools/perf/ui/browser.c @@ -1,5 +1,5 @@ #include "../util.h" -#include "../cache.h" +#include "../config.h" #include "../../perf.h" #include "libslang.h" #include "ui.h" diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c index 4fc208e..0e106bb 100644 --- a/tools/perf/ui/browsers/annotate.c +++ b/tools/perf/ui/browsers/annotate.c @@ -8,6 +8,7 @@ #include "../../util/sort.h" #include "../../util/symbol.h" #include "../../util/evsel.h" +#include "../../util/config.h" #include struct disasm_line_samples { diff --git a/tools/perf/util/alias.c b/tools/perf/util/alias.c index c0b43ee..6c80f83 100644 --- a/tools/perf/util/alias.c +++ b/tools/perf/util/alias.c @@ -1,4 +1,5 @@ #include "cache.h" +#include "config.h" static const char *alias_key; static char *alias_val; diff --git a/tools/perf/util/cache.h b/tools/perf/util/cache.h index 369f382..9f90e36 100644 --- a/tools/perf/util/cache.h +++ b/tools/perf/util/cache.h @@ -18,17 +18,6 @@ #define PERF_TRACEFS_ENVIRONMENT "PERF_TRACEFS_DIR" #define PERF_PAGER_ENVIRONMENT "PERF_PAGER" -extern const char *config_exclusive_filename; - -typedef int (*config_fn_t)(const char *, const char *, void *); -int perf_default_config(const char *, const char *, void *); -int perf_config(config_fn_t fn, void *); -int perf_config_int(const char *, const char *); -u64 perf_config_u64(const char *, const char *); -int perf_config_bool(const char *, const char *); -int config_error_nonbool(const char *); -const char *perf_etc_perfconfig(void); - char *alias_lookup(const char *alias); int split_cmdline(char *cmdline, const char ***argv); diff --git a/tools/perf/util/color.c b/tools/perf/util/color.c index 43e84aa..1210ba5 100644 --- a/tools/perf/util/color.c +++ b/tools/perf/util/color.c @@ -1,5 +1,6 @@ #include #include "cache.h" +#include "config.h" #include "color.h" #include diff --git a/tools/perf/util/config.h b/tools/perf/util/config.h index 22ec626..155a441 100644 --- a/tools/perf/util/config.h +++ b/tools/perf/util/config.h @@ -20,6 +20,17 @@ struct perf_config_set { struct list_head sections; }; +extern const char *config_exclusive_filename; + +typedef int (*config_fn_t)(const char *, const char *, void *); +int perf_default_config(const char *, const char *, void *); +int perf_config(config_fn_t fn, void *); +int perf_config_int(const char *, const char *); +u64 perf_config_u64(const char *, const char *); +int perf_config_bool(const char *, const char *); +int config_error_nonbool(const char *); +const char *perf_etc_perfconfig(void); + struct perf_config_set *perf_config_set__new(void); void perf_config_set__delete(struct perf_config_set *set); diff --git a/tools/perf/util/help-unknown-cmd.c b/tools/perf/util/help-unknown-cmd.c index d62ccae..776e285 100644 --- a/tools/perf/util/help-unknown-cmd.c +++ b/tools/perf/util/help-unknown-cmd.c @@ -1,4 +1,5 @@ #include "cache.h" +#include "config.h" #include #include "../builtin.h" #include "levenshtein.h" diff --git a/tools/perf/util/intel-pt.c b/tools/perf/util/intel-pt.c index 1371969..a2fe3a2 100644 --- a/tools/perf/util/intel-pt.c +++ b/tools/perf/util/intel-pt.c @@ -39,6 +39,7 @@ #include "auxtrace.h" #include "tsc.h" #include "intel-pt.h" +#include "config.h" #include "intel-pt-decoder/intel-pt-log.h" #include "intel-pt-decoder/intel-pt-decoder.h" diff --git a/tools/perf/util/llvm-utils.c b/tools/perf/util/llvm-utils.c index 878a566..40b6f72 100644 --- a/tools/perf/util/llvm-utils.c +++ b/tools/perf/util/llvm-utils.c @@ -8,6 +8,7 @@ #include #include "debug.h" #include "llvm-utils.h" +#include "config.h" #define CLANG_BPF_CMD_DEFAULT_TEMPLATE \ "$CLANG_EXEC -D__KERNEL__ -D__NR_CPUS__=$NR_CPUS "\ -- cgit v0.10.2 From 6cafaf4764a32597c2195aa5411b87728e1fde8a Mon Sep 17 00:00:00 2001 From: Liping Zhang Date: Mon, 20 Jun 2016 21:11:45 +0800 Subject: netfilter: nf_tables: fix memory leak if expr init fails If expr init fails then we need to free it. So when the user add a nft rule as follows: # nft add rule filter input tcp dport 22 flow table ssh \ { ip saddr limit rate 0/second } memory leak will happen. Signed-off-by: Liping Zhang Signed-off-by: Pablo Neira Ayuso diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c index 2c88187..cf7c745 100644 --- a/net/netfilter/nf_tables_api.c +++ b/net/netfilter/nf_tables_api.c @@ -1724,9 +1724,11 @@ struct nft_expr *nft_expr_init(const struct nft_ctx *ctx, err = nf_tables_newexpr(ctx, &info, expr); if (err < 0) - goto err2; + goto err3; return expr; +err3: + kfree(expr); err2: module_put(info.ops->type->owner); err1: -- cgit v0.10.2 From 62131e5d735226074cba53095545d76b491e5003 Mon Sep 17 00:00:00 2001 From: Liping Zhang Date: Wed, 8 Jun 2016 20:20:10 +0800 Subject: netfilter: nft_meta: set skb->nf_trace appropriately When user add a nft rule to set nftrace to zero, for example: # nft add rule ip filter input nftrace set 0 We should set nf_trace to zero also. Signed-off-by: Liping Zhang Signed-off-by: Pablo Neira Ayuso diff --git a/net/netfilter/nft_meta.c b/net/netfilter/nft_meta.c index 16c50b0..f4bad9d 100644 --- a/net/netfilter/nft_meta.c +++ b/net/netfilter/nft_meta.c @@ -227,7 +227,7 @@ void nft_meta_set_eval(const struct nft_expr *expr, skb->pkt_type = value; break; case NFT_META_NFTRACE: - skb->nf_trace = 1; + skb->nf_trace = !!value; break; default: WARN_ON(1); -- cgit v0.10.2 From 76c588f1f6b560c510953b390bc0a26c27cbfbd0 Mon Sep 17 00:00:00 2001 From: He Kuang Date: Tue, 17 May 2016 09:04:54 +0000 Subject: perf tools: Find right DSO taking into account if binary is 32 or 64-bit There's a problem in machine__findnew_vdso(), vdso buildid generated by a 32-bit machine stores it with the name 'vdso', but when processing buildid on a 64-bit machine with the same 'perf.data', perf will search for vdso named as 'vdso32' and get failed. This patch tries to find the existing dsos in machine->dsos by thread dso_type. 64-bit thread tries to find vdso with name 'vdso', because all 64-bit vdso is named as that. 32-bit thread first tries to find vdso with name 'vdso32' if this thread was run on 64-bit machine, if failed, then it tries 'vdso' which indicates that the thread was run on 32-bit machine when recording. Committer note: Additional explanation by Adrian Hunter: We match maps to builds ids using the file name - consider machine__findnew_[v]dso() called in map__new(). So in the context of a perf data file, we consider the file name to be unique. A vdso map does not have a file name - all we know is that it is vdso. We look at the thread to tell if it is 32-bit, 64-bit or x32. Then we need to get the build id which has been recorded using short name "[vdso]" or "[vdso32]" or "[vdsox32]". The problem is that on a 32-bit machine, we use the name "[vdso]". If you take a 32-bit perf data file to a 64-bit machine, it gets hard to figure out if "[vdso]" is 32-bit or 64-bit. This patch solves that problem. ---- This also merges a followup patch fixing a problem introduced by the original submission of this patch, that would crash 'perf record' when recording samples for a 32-bit app on a 64-bit system. Signed-off-by: He Kuang Acked-by: Adrian Hunter Tested-by: Arnaldo Carvalho de Melo Cc: Alexander Shishkin Cc: Andi Kleen Cc: David Ahern Cc: Ekaterina Tumanova Cc: Jiri Olsa Cc: Josh Poimboeuf Cc: Kan Liang Cc: Masami Hiramatsu Cc: Namhyung Kim Cc: Pekka Enberg Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Sukadev Bhattiprolu Cc: Wang Nan Link: http://lkml.kernel.org/r/1463475894-163531-1-git-send-email-hekuang@huawei.com Link: http://lkml.kernel.org/r/1466578626-92406-6-git-send-email-hekuang@huawei.com Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/util/vdso.c b/tools/perf/util/vdso.c index 44d440d..7bdcad4 100644 --- a/tools/perf/util/vdso.c +++ b/tools/perf/util/vdso.c @@ -134,8 +134,6 @@ static struct dso *__machine__addnew_vdso(struct machine *machine, const char *s return dso; } -#if BITS_PER_LONG == 64 - static enum dso_type machine__thread_dso_type(struct machine *machine, struct thread *thread) { @@ -156,6 +154,8 @@ static enum dso_type machine__thread_dso_type(struct machine *machine, return dso_type; } +#if BITS_PER_LONG == 64 + static int vdso__do_copy_compat(FILE *f, int fd) { char buf[4096]; @@ -283,8 +283,38 @@ static int __machine__findnew_vdso_compat(struct machine *machine, #endif +static struct dso *machine__find_vdso(struct machine *machine, + struct thread *thread) +{ + struct dso *dso = NULL; + enum dso_type dso_type; + + dso_type = machine__thread_dso_type(machine, thread); + switch (dso_type) { + case DSO__TYPE_32BIT: + dso = __dsos__find(&machine->dsos, DSO__NAME_VDSO32, true); + if (!dso) { + dso = __dsos__find(&machine->dsos, DSO__NAME_VDSO, + true); + if (dso && dso_type != dso__type(dso, machine)) + dso = NULL; + } + break; + case DSO__TYPE_X32BIT: + dso = __dsos__find(&machine->dsos, DSO__NAME_VDSOX32, true); + break; + case DSO__TYPE_64BIT: + case DSO__TYPE_UNKNOWN: + default: + dso = __dsos__find(&machine->dsos, DSO__NAME_VDSO, true); + break; + } + + return dso; +} + struct dso *machine__findnew_vdso(struct machine *machine, - struct thread *thread __maybe_unused) + struct thread *thread) { struct vdso_info *vdso_info; struct dso *dso = NULL; @@ -297,6 +327,10 @@ struct dso *machine__findnew_vdso(struct machine *machine, if (!vdso_info) goto out_unlock; + dso = machine__find_vdso(machine, thread); + if (dso) + goto out_unlock; + #if BITS_PER_LONG == 64 if (__machine__findnew_vdso_compat(machine, thread, vdso_info, &dso)) goto out_unlock; -- cgit v0.10.2 From 78ff1d6d8bf6bb3ee2b3781bbd88355a322435a4 Mon Sep 17 00:00:00 2001 From: He Kuang Date: Wed, 22 Jun 2016 06:57:02 +0000 Subject: perf unwind: Change macro names of perf register Use macro name prefixed with "LIBUNWIND_ARCH" for better understanding that the regs used by callbacks of libunwind are arch specific. The real regs used should be defined in the wrapper file of "unwind-libunwind-local.c" for each supported arch. Signed-off-by: He Kuang Acked-by: Jiri Olsa Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Andi Kleen Cc: David Ahern Cc: Ekaterina Tumanova Cc: Josh Poimboeuf Cc: Kan Liang Cc: Masami Hiramatsu Cc: Namhyung Kim Cc: Pekka Enberg Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Sukadev Bhattiprolu Cc: Wang Nan Link: http://lkml.kernel.org/r/1466578626-92406-2-git-send-email-hekuang@huawei.com Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/util/unwind-libunwind-local.c b/tools/perf/util/unwind-libunwind-local.c index 01c2e86..97c0f8f 100644 --- a/tools/perf/util/unwind-libunwind-local.c +++ b/tools/perf/util/unwind-libunwind-local.c @@ -462,7 +462,8 @@ static int access_mem(unw_addr_space_t __maybe_unused as, return 0; } - ret = perf_reg_value(&start, &ui->sample->user_regs, PERF_REG_SP); + ret = perf_reg_value(&start, &ui->sample->user_regs, + LIBUNWIND__ARCH_REG_SP); if (ret) return ret; @@ -621,7 +622,8 @@ static int get_entries(struct unwind_info *ui, unwind_entry_cb_t cb, unw_cursor_t c; int ret, i = 0; - ret = perf_reg_value(&val, &ui->sample->user_regs, PERF_REG_IP); + ret = perf_reg_value(&val, &ui->sample->user_regs, + LIBUNWIND__ARCH_REG_IP); if (ret) return ret; diff --git a/tools/perf/util/unwind.h b/tools/perf/util/unwind.h index b074662..84c6d44 100644 --- a/tools/perf/util/unwind.h +++ b/tools/perf/util/unwind.h @@ -32,6 +32,15 @@ int unwind__get_entries(unwind_entry_cb_t cb, void *arg, #ifndef LIBUNWIND__ARCH_REG_ID #define LIBUNWIND__ARCH_REG_ID(regnum) libunwind__arch_reg_id(regnum) #endif + +#ifndef LIBUNWIND__ARCH_REG_SP +#define LIBUNWIND__ARCH_REG_SP PERF_REG_SP +#endif + +#ifndef LIBUNWIND__ARCH_REG_IP +#define LIBUNWIND__ARCH_REG_IP PERF_REG_IP +#endif + int LIBUNWIND__ARCH_REG_ID(int regnum); int unwind__prepare_access(struct thread *thread, struct map *map); void unwind__flush_access(struct thread *thread); -- cgit v0.10.2 From 5dafea097ac65bd01cc86801c399ae41dce79756 Mon Sep 17 00:00:00 2001 From: He Kuang Date: Wed, 22 Jun 2016 06:57:03 +0000 Subject: perf unwind: Fix wrongly used regs for x86_32 unwind By default, "unwind-libunwind-local.c" gets SP/IP register number according to the host platform, for remote unwind, we should use register number for target platform. Fix this by define LIBUNWIND_ARCH_REG_SP/IP in the wrapper file of x86_32 platform. Signed-off-by: He Kuang Acked-by: Jiri Olsa Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Andi Kleen Cc: David Ahern Cc: Ekaterina Tumanova Cc: Josh Poimboeuf Cc: Kan Liang Cc: Masami Hiramatsu Cc: Namhyung Kim Cc: Pekka Enberg Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Sukadev Bhattiprolu Cc: Wang Nan Link: http://lkml.kernel.org/r/1466578626-92406-3-git-send-email-hekuang@huawei.com Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/util/libunwind/x86_32.c b/tools/perf/util/libunwind/x86_32.c index d98c17e..957ffff 100644 --- a/tools/perf/util/libunwind/x86_32.c +++ b/tools/perf/util/libunwind/x86_32.c @@ -12,7 +12,13 @@ */ #define REMOTE_UNWIND_LIBUNWIND + +/* Define arch specific functions & regs for libunwind, should be + * defined before including "unwind.h" + */ #define LIBUNWIND__ARCH_REG_ID(regnum) libunwind__x86_reg_id(regnum) +#define LIBUNWIND__ARCH_REG_IP PERF_REG_X86_IP +#define LIBUNWIND__ARCH_REG_SP PERF_REG_X86_SP #include "unwind.h" #include "debug.h" -- cgit v0.10.2 From 3bd03c9583bfb22cb82eeb09d8445bb79d27ae78 Mon Sep 17 00:00:00 2001 From: He Kuang Date: Wed, 22 Jun 2016 06:57:04 +0000 Subject: perf unwind: Fix wrongly used regs for aarch64 unwind By default, "unwind-libunwind-local.c" gets SP/IP register number according to the host platform, for remote unwind, we should use register number for target platform. Fix this by define LIBUNWIND_ARCH_REG_SP/IP in the wrapper file of aarch64 platform. Signed-off-by: He Kuang Acked-by: Jiri Olsa Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Andi Kleen Cc: David Ahern Cc: Ekaterina Tumanova Cc: Josh Poimboeuf Cc: Kan Liang Cc: Masami Hiramatsu Cc: Namhyung Kim Cc: Pekka Enberg Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Sukadev Bhattiprolu Cc: Wang Nan Link: http://lkml.kernel.org/r/1466578626-92406-4-git-send-email-hekuang@huawei.com Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/util/libunwind/arm64.c b/tools/perf/util/libunwind/arm64.c index 4fb5395..6559bc5 100644 --- a/tools/perf/util/libunwind/arm64.c +++ b/tools/perf/util/libunwind/arm64.c @@ -13,7 +13,12 @@ #define REMOTE_UNWIND_LIBUNWIND +/* Define arch specific functions & regs for libunwind, should be + * defined before including "unwind.h" + */ #define LIBUNWIND__ARCH_REG_ID(regnum) libunwind__arm64_reg_id(regnum) +#define LIBUNWIND__ARCH_REG_IP PERF_REG_ARM64_PC +#define LIBUNWIND__ARCH_REG_SP PERF_REG_ARM64_SP #include "unwind.h" #include "debug.h" -- cgit v0.10.2 From e5cadb93d0839d268a7c4199e0fdef0f94722117 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 23 Jun 2016 11:26:15 -0300 Subject: perf evlist: Rename for_each() macros to for_each_entry() To match the semantics for list.h in the kernel, that are used to implement those macros. Cc: Adrian Hunter Cc: David Ahern Cc: Jiri Olsa Cc: Milian Wolff Cc: Namhyung Kim Cc: Taeung Song Cc: Wang Nan Link: http://lkml.kernel.org/n/tip-qbcjlgj0ffxquxscahbpddi3@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/arch/x86/util/auxtrace.c b/tools/perf/arch/x86/util/auxtrace.c index 7a78055..cc1d865 100644 --- a/tools/perf/arch/x86/util/auxtrace.c +++ b/tools/perf/arch/x86/util/auxtrace.c @@ -37,7 +37,7 @@ struct auxtrace_record *auxtrace_record__init_intel(struct perf_evlist *evlist, intel_bts_pmu = perf_pmu__find(INTEL_BTS_PMU_NAME); if (evlist) { - evlist__for_each(evlist, evsel) { + evlist__for_each_entry(evlist, evsel) { if (intel_pt_pmu && evsel->attr.type == intel_pt_pmu->type) found_pt = true; diff --git a/tools/perf/arch/x86/util/intel-bts.c b/tools/perf/arch/x86/util/intel-bts.c index 7dc3063..5132775 100644 --- a/tools/perf/arch/x86/util/intel-bts.c +++ b/tools/perf/arch/x86/util/intel-bts.c @@ -124,7 +124,7 @@ static int intel_bts_recording_options(struct auxtrace_record *itr, btsr->evlist = evlist; btsr->snapshot_mode = opts->auxtrace_snapshot_mode; - evlist__for_each(evlist, evsel) { + evlist__for_each_entry(evlist, evsel) { if (evsel->attr.type == intel_bts_pmu->type) { if (intel_bts_evsel) { pr_err("There may be only one " INTEL_BTS_PMU_NAME " event\n"); @@ -327,7 +327,7 @@ static int intel_bts_snapshot_start(struct auxtrace_record *itr) container_of(itr, struct intel_bts_recording, itr); struct perf_evsel *evsel; - evlist__for_each(btsr->evlist, evsel) { + evlist__for_each_entry(btsr->evlist, evsel) { if (evsel->attr.type == btsr->intel_bts_pmu->type) return perf_evsel__disable(evsel); } @@ -340,7 +340,7 @@ static int intel_bts_snapshot_finish(struct auxtrace_record *itr) container_of(itr, struct intel_bts_recording, itr); struct perf_evsel *evsel; - evlist__for_each(btsr->evlist, evsel) { + evlist__for_each_entry(btsr->evlist, evsel) { if (evsel->attr.type == btsr->intel_bts_pmu->type) return perf_evsel__enable(evsel); } @@ -422,7 +422,7 @@ static int intel_bts_read_finish(struct auxtrace_record *itr, int idx) container_of(itr, struct intel_bts_recording, itr); struct perf_evsel *evsel; - evlist__for_each(btsr->evlist, evsel) { + evlist__for_each_entry(btsr->evlist, evsel) { if (evsel->attr.type == btsr->intel_bts_pmu->type) return perf_evlist__enable_event_idx(btsr->evlist, evsel, idx); diff --git a/tools/perf/arch/x86/util/intel-pt.c b/tools/perf/arch/x86/util/intel-pt.c index a07b960..fb51457 100644 --- a/tools/perf/arch/x86/util/intel-pt.c +++ b/tools/perf/arch/x86/util/intel-pt.c @@ -131,7 +131,7 @@ static int intel_pt_read_config(struct perf_pmu *intel_pt_pmu, const char *str, if (!mask) return -EINVAL; - evlist__for_each(evlist, evsel) { + evlist__for_each_entry(evlist, evsel) { if (evsel->attr.type == intel_pt_pmu->type) { *res = intel_pt_masked_bits(mask, evsel->attr.config); return 0; @@ -511,7 +511,7 @@ static int intel_pt_recording_options(struct auxtrace_record *itr, ptr->evlist = evlist; ptr->snapshot_mode = opts->auxtrace_snapshot_mode; - evlist__for_each(evlist, evsel) { + evlist__for_each_entry(evlist, evsel) { if (evsel->attr.type == intel_pt_pmu->type) { if (intel_pt_evsel) { pr_err("There may be only one " INTEL_PT_PMU_NAME " event\n"); @@ -725,7 +725,7 @@ static int intel_pt_snapshot_start(struct auxtrace_record *itr) container_of(itr, struct intel_pt_recording, itr); struct perf_evsel *evsel; - evlist__for_each(ptr->evlist, evsel) { + evlist__for_each_entry(ptr->evlist, evsel) { if (evsel->attr.type == ptr->intel_pt_pmu->type) return perf_evsel__disable(evsel); } @@ -738,7 +738,7 @@ static int intel_pt_snapshot_finish(struct auxtrace_record *itr) container_of(itr, struct intel_pt_recording, itr); struct perf_evsel *evsel; - evlist__for_each(ptr->evlist, evsel) { + evlist__for_each_entry(ptr->evlist, evsel) { if (evsel->attr.type == ptr->intel_pt_pmu->type) return perf_evsel__enable(evsel); } @@ -1011,7 +1011,7 @@ static int intel_pt_read_finish(struct auxtrace_record *itr, int idx) container_of(itr, struct intel_pt_recording, itr); struct perf_evsel *evsel; - evlist__for_each(ptr->evlist, evsel) { + evlist__for_each_entry(ptr->evlist, evsel) { if (evsel->attr.type == ptr->intel_pt_pmu->type) return perf_evlist__enable_event_idx(ptr->evlist, evsel, idx); diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c index a2324e1..b15e768 100644 --- a/tools/perf/builtin-annotate.c +++ b/tools/perf/builtin-annotate.c @@ -236,7 +236,7 @@ static int __cmd_annotate(struct perf_annotate *ann) perf_session__fprintf_dsos(session, stdout); total_nr_samples = 0; - evlist__for_each(session->evlist, pos) { + evlist__for_each_entry(session->evlist, pos) { struct hists *hists = evsel__hists(pos); u32 nr_samples = hists->stats.nr_events[PERF_RECORD_SAMPLE]; diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c index eac0b11..21ee753 100644 --- a/tools/perf/builtin-diff.c +++ b/tools/perf/builtin-diff.c @@ -363,7 +363,7 @@ static struct perf_evsel *evsel_match(struct perf_evsel *evsel, { struct perf_evsel *e; - evlist__for_each(evlist, e) { + evlist__for_each_entry(evlist, e) { if (perf_evsel__match2(evsel, e)) return e; } @@ -375,7 +375,7 @@ static void perf_evlist__collapse_resort(struct perf_evlist *evlist) { struct perf_evsel *evsel; - evlist__for_each(evlist, evsel) { + evlist__for_each_entry(evlist, evsel) { struct hists *hists = evsel__hists(evsel); hists__collapse_resort(hists, NULL); @@ -681,7 +681,7 @@ static void data_process(void) struct perf_evsel *evsel_base; bool first = true; - evlist__for_each(evlist_base, evsel_base) { + evlist__for_each_entry(evlist_base, evsel_base) { struct hists *hists_base = evsel__hists(evsel_base); struct data__file *d; int i; diff --git a/tools/perf/builtin-evlist.c b/tools/perf/builtin-evlist.c index 8a31f51..e09c428 100644 --- a/tools/perf/builtin-evlist.c +++ b/tools/perf/builtin-evlist.c @@ -32,7 +32,7 @@ static int __cmd_evlist(const char *file_name, struct perf_attr_details *details if (session == NULL) return -1; - evlist__for_each(session->evlist, pos) { + evlist__for_each_entry(session->evlist, pos) { perf_evsel__fprintf(pos, details, stdout); if (pos->attr.type == PERF_TYPE_TRACEPOINT) diff --git a/tools/perf/builtin-inject.c b/tools/perf/builtin-inject.c index e5afa8f..73c1c4c 100644 --- a/tools/perf/builtin-inject.c +++ b/tools/perf/builtin-inject.c @@ -562,7 +562,7 @@ static void strip_init(struct perf_inject *inject) inject->tool.context_switch = perf_event__drop; - evlist__for_each(evlist, evsel) + evlist__for_each_entry(evlist, evsel) evsel->handler = drop_sample; } @@ -590,7 +590,7 @@ static bool ok_to_remove(struct perf_evlist *evlist, if (!has_tracking(evsel_to_remove)) return true; - evlist__for_each(evlist, evsel) { + evlist__for_each_entry(evlist, evsel) { if (evsel->handler != drop_sample) { cnt += 1; if ((evsel->attr.sample_type & COMPAT_MASK) == @@ -608,7 +608,7 @@ static void strip_fini(struct perf_inject *inject) struct perf_evsel *evsel, *tmp; /* Remove non-synthesized evsels if possible */ - evlist__for_each_safe(evlist, tmp, evsel) { + evlist__for_each_entry_safe(evlist, tmp, evsel) { if (evsel->handler == drop_sample && ok_to_remove(evlist, evsel)) { pr_debug("Deleting %s\n", perf_evsel__name(evsel)); @@ -643,7 +643,7 @@ static int __cmd_inject(struct perf_inject *inject) } else if (inject->sched_stat) { struct perf_evsel *evsel; - evlist__for_each(session->evlist, evsel) { + evlist__for_each_entry(session->evlist, evsel) { const char *name = perf_evsel__name(evsel); if (!strcmp(name, "sched:sched_switch")) { diff --git a/tools/perf/builtin-kmem.c b/tools/perf/builtin-kmem.c index 4defe44..b1d491c 100644 --- a/tools/perf/builtin-kmem.c +++ b/tools/perf/builtin-kmem.c @@ -1354,7 +1354,7 @@ static int __cmd_kmem(struct perf_session *session) goto out; } - evlist__for_each(session->evlist, evsel) { + evlist__for_each_entry(session->evlist, evsel) { if (!strcmp(perf_evsel__name(evsel), "kmem:mm_page_alloc") && perf_evsel__field(evsel, "pfn")) { use_pfn = true; diff --git a/tools/perf/builtin-kvm.c b/tools/perf/builtin-kvm.c index 8f8f90e..f4efef9 100644 --- a/tools/perf/builtin-kvm.c +++ b/tools/perf/builtin-kvm.c @@ -988,7 +988,7 @@ static int kvm_live_open_events(struct perf_kvm_stat *kvm) * Note: exclude_{guest,host} do not apply here. * This command processes KVM tracepoints from host only */ - evlist__for_each(evlist, pos) { + evlist__for_each_entry(evlist, pos) { struct perf_event_attr *attr = &pos->attr; /* make sure these *are* set */ diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index c97b2b69..81411b1 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -353,7 +353,7 @@ static int record__open(struct record *rec) perf_evlist__config(evlist, opts, &callchain_param); - evlist__for_each(evlist, pos) { + evlist__for_each_entry(evlist, pos) { try_again: if (perf_evsel__open(pos, pos->cpus, pos->threads) < 0) { if (perf_evsel__fallback(pos, errno, msg, sizeof(msg))) { diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index bcb49ff..f6cb35798 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c @@ -361,7 +361,7 @@ static int perf_evlist__tty_browse_hists(struct perf_evlist *evlist, struct perf_evsel *pos; fprintf(stdout, "#\n# Total Lost Samples: %" PRIu64 "\n#\n", evlist->stats.total_lost_samples); - evlist__for_each(evlist, pos) { + evlist__for_each_entry(evlist, pos) { struct hists *hists = evsel__hists(pos); const char *evname = perf_evsel__name(pos); @@ -478,7 +478,7 @@ static int report__collapse_hists(struct report *rep) ui_progress__init(&prog, rep->nr_entries, "Merging related events..."); - evlist__for_each(rep->session->evlist, pos) { + evlist__for_each_entry(rep->session->evlist, pos) { struct hists *hists = evsel__hists(pos); if (pos->idx == 0) @@ -511,7 +511,7 @@ static void report__output_resort(struct report *rep) ui_progress__init(&prog, rep->nr_entries, "Sorting events for output..."); - evlist__for_each(rep->session->evlist, pos) + evlist__for_each_entry(rep->session->evlist, pos) perf_evsel__output_resort(pos, &prog); ui_progress__finish(); @@ -552,7 +552,7 @@ static int __cmd_report(struct report *rep) report__warn_kptr_restrict(rep); - evlist__for_each(session->evlist, pos) + evlist__for_each_entry(session->evlist, pos) rep->nr_entries += evsel__hists(pos)->nr_entries; if (use_browser == 0) { @@ -583,7 +583,7 @@ static int __cmd_report(struct report *rep) * might be changed during the collapse phase. */ rep->nr_entries = 0; - evlist__for_each(session->evlist, pos) + evlist__for_each_entry(session->evlist, pos) rep->nr_entries += evsel__hists(pos)->nr_entries; if (rep->nr_entries == 0) { diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c index 4601123..0e18e06 100644 --- a/tools/perf/builtin-script.c +++ b/tools/perf/builtin-script.c @@ -369,7 +369,7 @@ static int perf_session__check_output_opt(struct perf_session *session) if (!no_callchain) { bool use_callchain = false; - evlist__for_each(session->evlist, evsel) { + evlist__for_each_entry(session->evlist, evsel) { if (evsel->attr.sample_type & PERF_SAMPLE_CALLCHAIN) { use_callchain = true; break; @@ -389,7 +389,7 @@ static int perf_session__check_output_opt(struct perf_session *session) j = PERF_TYPE_TRACEPOINT; - evlist__for_each(session->evlist, evsel) { + evlist__for_each_entry(session->evlist, evsel) { if (evsel->attr.type != j) continue; @@ -720,7 +720,7 @@ static int perf_evlist__max_name_len(struct perf_evlist *evlist) struct perf_evsel *evsel; int max = 0; - evlist__for_each(evlist, evsel) { + evlist__for_each_entry(evlist, evsel) { int len = strlen(perf_evsel__name(evsel)); max = MAX(len, max); @@ -945,7 +945,7 @@ static int process_attr(struct perf_tool *tool, union perf_event *event, if (evsel->attr.type >= PERF_TYPE_MAX) return 0; - evlist__for_each(evlist, pos) { + evlist__for_each_entry(evlist, pos) { if (pos->attr.type == evsel->attr.type && pos != evsel) return 0; } @@ -1671,7 +1671,7 @@ static int check_ev_match(char *dir_name, char *scriptname, snprintf(evname, len + 1, "%s", p); match = 0; - evlist__for_each(session->evlist, pos) { + evlist__for_each_entry(session->evlist, pos) { if (!strcmp(perf_evsel__name(pos), evname)) { match = 1; break; @@ -1873,7 +1873,7 @@ static int process_stat_round_event(struct perf_tool *tool __maybe_unused, struct stat_round_event *round = &event->stat_round; struct perf_evsel *counter; - evlist__for_each(session->evlist, counter) { + evlist__for_each_entry(session->evlist, counter) { perf_stat_process_counter(&stat_config, counter); process_stat(counter, round->time); } diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index dff6373..c367a43 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c @@ -331,7 +331,7 @@ static void read_counters(bool close_counters) { struct perf_evsel *counter; - evlist__for_each(evsel_list, counter) { + evlist__for_each_entry(evsel_list, counter) { if (read_counter(counter)) pr_debug("failed to read counter %s\n", counter->name); @@ -417,7 +417,7 @@ static int perf_stat_synthesize_config(bool is_pipe) * Synthesize other events stuff not carried within * attr event - unit, scale, name */ - evlist__for_each(evsel_list, counter) { + evlist__for_each_entry(evsel_list, counter) { if (!counter->supported) continue; @@ -550,7 +550,7 @@ static int __run_perf_stat(int argc, const char **argv) if (group) perf_evlist__set_leader(evsel_list); - evlist__for_each(evsel_list, counter) { + evlist__for_each_entry(evsel_list, counter) { try_again: if (create_perf_stat_counter(counter) < 0) { /* @@ -1134,7 +1134,7 @@ static void aggr_update_shadow(void) for (s = 0; s < aggr_map->nr; s++) { id = aggr_map->map[s]; - evlist__for_each(evsel_list, counter) { + evlist__for_each_entry(evsel_list, counter) { val = 0; for (cpu = 0; cpu < perf_evsel__nr_cpus(counter); cpu++) { s2 = aggr_get_id(evsel_list->cpus, cpu); @@ -1173,7 +1173,7 @@ static void print_aggr(char *prefix) id = aggr_map->map[s]; first = true; - evlist__for_each(evsel_list, counter) { + evlist__for_each_entry(evsel_list, counter) { val = ena = run = 0; nr = 0; for (cpu = 0; cpu < perf_evsel__nr_cpus(counter); cpu++) { @@ -1292,7 +1292,7 @@ static void print_no_aggr_metric(char *prefix) if (prefix) fputs(prefix, stat_config.output); - evlist__for_each(evsel_list, counter) { + evlist__for_each_entry(evsel_list, counter) { if (first) { aggr_printout(counter, cpu, 0); first = false; @@ -1346,7 +1346,7 @@ static void print_metric_headers(const char *prefix, bool no_indent) } /* Print metrics headers only */ - evlist__for_each(evsel_list, counter) { + evlist__for_each_entry(evsel_list, counter) { os.evsel = counter; out.ctx = &os; out.print_metric = print_metric_header; @@ -1482,11 +1482,11 @@ static void print_counters(struct timespec *ts, int argc, const char **argv) print_aggr(prefix); break; case AGGR_THREAD: - evlist__for_each(evsel_list, counter) + evlist__for_each_entry(evsel_list, counter) print_aggr_thread(counter, prefix); break; case AGGR_GLOBAL: - evlist__for_each(evsel_list, counter) + evlist__for_each_entry(evsel_list, counter) print_counter_aggr(counter, prefix); if (metric_only) fputc('\n', stat_config.output); @@ -1495,7 +1495,7 @@ static void print_counters(struct timespec *ts, int argc, const char **argv) if (metric_only) print_no_aggr_metric(prefix); else { - evlist__for_each(evsel_list, counter) + evlist__for_each_entry(evsel_list, counter) print_counter(counter, prefix); } break; @@ -2149,7 +2149,7 @@ static int process_stat_round_event(struct perf_tool *tool __maybe_unused, const char **argv = session->header.env.cmdline_argv; int argc = session->header.env.nr_cmdline; - evlist__for_each(evsel_list, counter) + evlist__for_each_entry(evsel_list, counter) perf_stat_process_counter(&stat_config, counter); if (stat_round->type == PERF_STAT_ROUND_TYPE__FINAL) diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index ec4cba6..07fc792 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -479,7 +479,7 @@ static bool perf_top__handle_keypress(struct perf_top *top, int c) fprintf(stderr, "\nAvailable events:"); - evlist__for_each(top->evlist, top->sym_evsel) + evlist__for_each_entry(top->evlist, top->sym_evsel) fprintf(stderr, "\n\t%d %s", top->sym_evsel->idx, perf_evsel__name(top->sym_evsel)); prompt_integer(&counter, "Enter details event counter"); @@ -490,7 +490,7 @@ static bool perf_top__handle_keypress(struct perf_top *top, int c) sleep(1); break; } - evlist__for_each(top->evlist, top->sym_evsel) + evlist__for_each_entry(top->evlist, top->sym_evsel) if (top->sym_evsel->idx == counter) break; } else @@ -583,7 +583,7 @@ static void *display_thread_tui(void *arg) * Zooming in/out UIDs. For now juse use whatever the user passed * via --uid. */ - evlist__for_each(top->evlist, pos) { + evlist__for_each_entry(top->evlist, pos) { struct hists *hists = evsel__hists(pos); hists->uid_filter_str = top->record_opts.target.uid_str; } @@ -888,7 +888,7 @@ static int perf_top__start_counters(struct perf_top *top) perf_evlist__config(evlist, opts, &callchain_param); - evlist__for_each(evlist, counter) { + evlist__for_each_entry(evlist, counter) { try_again: if (perf_evsel__open(counter, top->evlist->cpus, top->evlist->threads) < 0) { diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c index 5c50fe7..1ecadfc 100644 --- a/tools/perf/builtin-trace.c +++ b/tools/perf/builtin-trace.c @@ -2483,7 +2483,7 @@ static int trace__replay(struct trace *trace) goto out; } - evlist__for_each(session->evlist, evsel) { + evlist__for_each_entry(session->evlist, evsel) { if (evsel->attr.type == PERF_TYPE_SOFTWARE && (evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ || evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MIN || @@ -2714,7 +2714,7 @@ static void evlist__set_evsel_handler(struct perf_evlist *evlist, void *handler) { struct perf_evsel *evsel; - evlist__for_each(evlist, evsel) + evlist__for_each_entry(evlist, evsel) evsel->handler = handler; } diff --git a/tools/perf/tests/backward-ring-buffer.c b/tools/perf/tests/backward-ring-buffer.c index d9ba991..e70313f 100644 --- a/tools/perf/tests/backward-ring-buffer.c +++ b/tools/perf/tests/backward-ring-buffer.c @@ -118,7 +118,7 @@ int test__backward_ring_buffer(int subtest __maybe_unused) perf_evlist__config(evlist, &opts, NULL); /* Set backward bit, ring buffer should be writing from end */ - evlist__for_each(evlist, evsel) + evlist__for_each_entry(evlist, evsel) evsel->attr.write_backward = 1; err = perf_evlist__open(evlist); diff --git a/tools/perf/tests/evsel-roundtrip-name.c b/tools/perf/tests/evsel-roundtrip-name.c index 2de4a4f..60926a1 100644 --- a/tools/perf/tests/evsel-roundtrip-name.c +++ b/tools/perf/tests/evsel-roundtrip-name.c @@ -80,7 +80,7 @@ static int __perf_evsel__name_array_test(const char *names[], int nr_names) } err = 0; - evlist__for_each(evlist, evsel) { + evlist__for_each_entry(evlist, evsel) { if (strcmp(perf_evsel__name(evsel), names[evsel->idx])) { --err; pr_debug("%s != %s\n", perf_evsel__name(evsel), names[evsel->idx]); diff --git a/tools/perf/tests/hists_filter.c b/tools/perf/tests/hists_filter.c index e846f8c..62efb14 100644 --- a/tools/perf/tests/hists_filter.c +++ b/tools/perf/tests/hists_filter.c @@ -56,7 +56,7 @@ static int add_hist_entries(struct perf_evlist *evlist, * (perf [perf] main) will be collapsed to an existing entry * so total 9 entries will be in the tree. */ - evlist__for_each(evlist, evsel) { + evlist__for_each_entry(evlist, evsel) { for (i = 0; i < ARRAY_SIZE(fake_samples); i++) { struct hist_entry_iter iter = { .evsel = evsel, @@ -136,7 +136,7 @@ int test__hists_filter(int subtest __maybe_unused) if (err < 0) goto out; - evlist__for_each(evlist, evsel) { + evlist__for_each_entry(evlist, evsel) { struct hists *hists = evsel__hists(evsel); hists__collapse_resort(hists, NULL); diff --git a/tools/perf/tests/hists_link.c b/tools/perf/tests/hists_link.c index 6f96ca4..eddc740 100644 --- a/tools/perf/tests/hists_link.c +++ b/tools/perf/tests/hists_link.c @@ -72,7 +72,7 @@ static int add_hist_entries(struct perf_evlist *evlist, struct machine *machine) * However the second evsel also has a collapsed entry for * "bash [libc] malloc" so total 9 entries will be in the tree. */ - evlist__for_each(evlist, evsel) { + evlist__for_each_entry(evlist, evsel) { struct hists *hists = evsel__hists(evsel); for (k = 0; k < ARRAY_SIZE(fake_common_samples); k++) { @@ -301,7 +301,7 @@ int test__hists_link(int subtest __maybe_unused) if (err < 0) goto out; - evlist__for_each(evlist, evsel) { + evlist__for_each_entry(evlist, evsel) { hists = evsel__hists(evsel); hists__collapse_resort(hists, NULL); diff --git a/tools/perf/tests/mmap-basic.c b/tools/perf/tests/mmap-basic.c index 359e98f..aea33f5 100644 --- a/tools/perf/tests/mmap-basic.c +++ b/tools/perf/tests/mmap-basic.c @@ -126,7 +126,7 @@ int test__basic_mmap(int subtest __maybe_unused) } err = 0; - evlist__for_each(evlist, evsel) { + evlist__for_each_entry(evlist, evsel) { if (nr_events[evsel->idx] != expected_nr_events[evsel->idx]) { pr_debug("expected %d %s events, got %d\n", expected_nr_events[evsel->idx], diff --git a/tools/perf/tests/parse-events.c b/tools/perf/tests/parse-events.c index b2a2c74..20c2e64 100644 --- a/tools/perf/tests/parse-events.c +++ b/tools/perf/tests/parse-events.c @@ -32,7 +32,7 @@ static int test__checkevent_tracepoint_multi(struct perf_evlist *evlist) TEST_ASSERT_VAL("wrong number of entries", evlist->nr_entries > 1); TEST_ASSERT_VAL("wrong number of groups", 0 == evlist->nr_groups); - evlist__for_each(evlist, evsel) { + evlist__for_each_entry(evlist, evsel) { TEST_ASSERT_VAL("wrong type", PERF_TYPE_TRACEPOINT == evsel->attr.type); TEST_ASSERT_VAL("wrong sample_type", @@ -207,7 +207,7 @@ test__checkevent_tracepoint_multi_modifier(struct perf_evlist *evlist) TEST_ASSERT_VAL("wrong number of entries", evlist->nr_entries > 1); - evlist__for_each(evlist, evsel) { + evlist__for_each_entry(evlist, evsel) { TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user); TEST_ASSERT_VAL("wrong exclude_kernel", diff --git a/tools/perf/tests/switch-tracking.c b/tools/perf/tests/switch-tracking.c index 39a689b..7ddbe26 100644 --- a/tools/perf/tests/switch-tracking.c +++ b/tools/perf/tests/switch-tracking.c @@ -432,7 +432,7 @@ int test__switch_tracking(int subtest __maybe_unused) } /* Check non-tracking events are not tracking */ - evlist__for_each(evlist, evsel) { + evlist__for_each_entry(evlist, evsel) { if (evsel != tracking_evsel) { if (evsel->attr.mmap || evsel->attr.comm) { pr_debug("Non-tracking event is tracking\n"); diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c index 9d74435..e08b8f7 100644 --- a/tools/perf/ui/browsers/hists.c +++ b/tools/perf/ui/browsers/hists.c @@ -3199,7 +3199,7 @@ static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist, ui_helpline__push("Press ESC to exit"); - evlist__for_each(evlist, pos) { + evlist__for_each_entry(evlist, pos) { const char *ev_name = perf_evsel__name(pos); size_t line_len = strlen(ev_name) + 7; @@ -3230,7 +3230,7 @@ single_entry: struct perf_evsel *pos; nr_entries = 0; - evlist__for_each(evlist, pos) { + evlist__for_each_entry(evlist, pos) { if (perf_evsel__is_group_leader(pos)) nr_entries++; } diff --git a/tools/perf/ui/gtk/hists.c b/tools/perf/ui/gtk/hists.c index e5c1325..c5f3677 100644 --- a/tools/perf/ui/gtk/hists.c +++ b/tools/perf/ui/gtk/hists.c @@ -627,7 +627,7 @@ int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist, gtk_container_add(GTK_CONTAINER(window), vbox); - evlist__for_each(evlist, pos) { + evlist__for_each_entry(evlist, pos) { struct hists *hists = evsel__hists(pos); const char *evname = perf_evsel__name(pos); GtkWidget *scrolled_window; diff --git a/tools/perf/ui/hist.c b/tools/perf/ui/hist.c index 6940745..4274969 100644 --- a/tools/perf/ui/hist.c +++ b/tools/perf/ui/hist.c @@ -766,7 +766,7 @@ int perf_hpp__setup_hists_formats(struct perf_hpp_list *list, if (!symbol_conf.report_hierarchy) return 0; - evlist__for_each(evlist, evsel) { + evlist__for_each_entry(evlist, evsel) { hists = evsel__hists(evsel); perf_hpp_list__for_each_sort_list(list, fmt) { diff --git a/tools/perf/util/cgroup.c b/tools/perf/util/cgroup.c index 90aa1b4..8fdee24 100644 --- a/tools/perf/util/cgroup.c +++ b/tools/perf/util/cgroup.c @@ -81,7 +81,7 @@ static int add_cgroup(struct perf_evlist *evlist, char *str) /* * check if cgrp is already defined, if so we reuse it */ - evlist__for_each(evlist, counter) { + evlist__for_each_entry(evlist, counter) { cgrp = counter->cgrp; if (!cgrp) continue; @@ -110,7 +110,7 @@ static int add_cgroup(struct perf_evlist *evlist, char *str) * if add cgroup N, then need to find event N */ n = 0; - evlist__for_each(evlist, counter) { + evlist__for_each_entry(evlist, counter) { if (n == nr_cgroups) goto found; n++; diff --git a/tools/perf/util/data-convert-bt.c b/tools/perf/util/data-convert-bt.c index 9f53020..4b59879 100644 --- a/tools/perf/util/data-convert-bt.c +++ b/tools/perf/util/data-convert-bt.c @@ -997,7 +997,7 @@ static int setup_events(struct ctf_writer *cw, struct perf_session *session) struct perf_evsel *evsel; int ret; - evlist__for_each(evlist, evsel) { + evlist__for_each_entry(evlist, evsel) { ret = add_event(cw, evsel); if (ret) return ret; @@ -1010,7 +1010,7 @@ static void cleanup_events(struct perf_session *session) struct perf_evlist *evlist = session->evlist; struct perf_evsel *evsel; - evlist__for_each(evlist, evsel) { + evlist__for_each_entry(evlist, evsel) { struct evsel_priv *priv; priv = evsel->priv; diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index fcb8f1f..1135077 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c @@ -100,7 +100,7 @@ static void perf_evlist__update_id_pos(struct perf_evlist *evlist) { struct perf_evsel *evsel; - evlist__for_each(evlist, evsel) + evlist__for_each_entry(evlist, evsel) perf_evsel__calc_id_pos(evsel); perf_evlist__set_id_pos(evlist); @@ -110,7 +110,7 @@ static void perf_evlist__purge(struct perf_evlist *evlist) { struct perf_evsel *pos, *n; - evlist__for_each_safe(evlist, n, pos) { + evlist__for_each_entry_safe(evlist, n, pos) { list_del_init(&pos->node); pos->evlist = NULL; perf_evsel__delete(pos); @@ -164,7 +164,7 @@ static void perf_evlist__propagate_maps(struct perf_evlist *evlist) { struct perf_evsel *evsel; - evlist__for_each(evlist, evsel) + evlist__for_each_entry(evlist, evsel) __perf_evlist__propagate_maps(evlist, evsel); } @@ -193,7 +193,7 @@ void perf_evlist__splice_list_tail(struct perf_evlist *evlist, { struct perf_evsel *evsel, *temp; - __evlist__for_each_safe(list, temp, evsel) { + __evlist__for_each_entry_safe(list, temp, evsel) { list_del_init(&evsel->node); perf_evlist__add(evlist, evsel); } @@ -208,7 +208,7 @@ void __perf_evlist__set_leader(struct list_head *list) leader->nr_members = evsel->idx - leader->idx + 1; - __evlist__for_each(list, evsel) { + __evlist__for_each_entry(list, evsel) { evsel->leader = leader; } } @@ -299,7 +299,7 @@ static int perf_evlist__add_attrs(struct perf_evlist *evlist, return 0; out_delete_partial_list: - __evlist__for_each_safe(&head, n, evsel) + __evlist__for_each_entry_safe(&head, n, evsel) perf_evsel__delete(evsel); return -1; } @@ -320,7 +320,7 @@ perf_evlist__find_tracepoint_by_id(struct perf_evlist *evlist, int id) { struct perf_evsel *evsel; - evlist__for_each(evlist, evsel) { + evlist__for_each_entry(evlist, evsel) { if (evsel->attr.type == PERF_TYPE_TRACEPOINT && (int)evsel->attr.config == id) return evsel; @@ -335,7 +335,7 @@ perf_evlist__find_tracepoint_by_name(struct perf_evlist *evlist, { struct perf_evsel *evsel; - evlist__for_each(evlist, evsel) { + evlist__for_each_entry(evlist, evsel) { if ((evsel->attr.type == PERF_TYPE_TRACEPOINT) && (strcmp(evsel->name, name) == 0)) return evsel; @@ -370,7 +370,7 @@ void perf_evlist__disable(struct perf_evlist *evlist) { struct perf_evsel *pos; - evlist__for_each(evlist, pos) { + evlist__for_each_entry(evlist, pos) { if (!perf_evsel__is_group_leader(pos) || !pos->fd) continue; perf_evsel__disable(pos); @@ -383,7 +383,7 @@ void perf_evlist__enable(struct perf_evlist *evlist) { struct perf_evsel *pos; - evlist__for_each(evlist, pos) { + evlist__for_each_entry(evlist, pos) { if (!perf_evsel__is_group_leader(pos) || !pos->fd) continue; perf_evsel__enable(pos); @@ -451,7 +451,7 @@ int perf_evlist__alloc_pollfd(struct perf_evlist *evlist) int nfds = 0; struct perf_evsel *evsel; - evlist__for_each(evlist, evsel) { + evlist__for_each_entry(evlist, evsel) { if (evsel->system_wide) nfds += nr_cpus; else @@ -1015,7 +1015,7 @@ static int perf_evlist__mmap_per_evsel(struct perf_evlist *evlist, int idx, struct perf_evsel *evsel; int revent; - evlist__for_each(evlist, evsel) { + evlist__for_each_entry(evlist, evsel) { int fd; if (evsel->overwrite != (evlist->overwrite && evlist->backward)) @@ -1262,7 +1262,7 @@ int perf_evlist__mmap_ex(struct perf_evlist *evlist, unsigned int pages, auxtrace_mmap_params__init(&mp.auxtrace_mp, evlist->mmap_len, auxtrace_pages, auxtrace_overwrite); - evlist__for_each(evlist, evsel) { + evlist__for_each_entry(evlist, evsel) { if ((evsel->attr.read_format & PERF_FORMAT_ID) && evsel->sample_id == NULL && perf_evsel__alloc_id(evsel, cpu_map__nr(cpus), threads->nr) < 0) @@ -1338,7 +1338,7 @@ void __perf_evlist__set_sample_bit(struct perf_evlist *evlist, { struct perf_evsel *evsel; - evlist__for_each(evlist, evsel) + evlist__for_each_entry(evlist, evsel) __perf_evsel__set_sample_bit(evsel, bit); } @@ -1347,7 +1347,7 @@ void __perf_evlist__reset_sample_bit(struct perf_evlist *evlist, { struct perf_evsel *evsel; - evlist__for_each(evlist, evsel) + evlist__for_each_entry(evlist, evsel) __perf_evsel__reset_sample_bit(evsel, bit); } @@ -1358,7 +1358,7 @@ int perf_evlist__apply_filters(struct perf_evlist *evlist, struct perf_evsel **e const int ncpus = cpu_map__nr(evlist->cpus), nthreads = thread_map__nr(evlist->threads); - evlist__for_each(evlist, evsel) { + evlist__for_each_entry(evlist, evsel) { if (evsel->filter == NULL) continue; @@ -1381,7 +1381,7 @@ int perf_evlist__set_filter(struct perf_evlist *evlist, const char *filter) struct perf_evsel *evsel; int err = 0; - evlist__for_each(evlist, evsel) { + evlist__for_each_entry(evlist, evsel) { if (evsel->attr.type != PERF_TYPE_TRACEPOINT) continue; @@ -1435,7 +1435,7 @@ bool perf_evlist__valid_sample_type(struct perf_evlist *evlist) if (evlist->id_pos < 0 || evlist->is_pos < 0) return false; - evlist__for_each(evlist, pos) { + evlist__for_each_entry(evlist, pos) { if (pos->id_pos != evlist->id_pos || pos->is_pos != evlist->is_pos) return false; @@ -1451,7 +1451,7 @@ u64 __perf_evlist__combined_sample_type(struct perf_evlist *evlist) if (evlist->combined_sample_type) return evlist->combined_sample_type; - evlist__for_each(evlist, evsel) + evlist__for_each_entry(evlist, evsel) evlist->combined_sample_type |= evsel->attr.sample_type; return evlist->combined_sample_type; @@ -1468,7 +1468,7 @@ u64 perf_evlist__combined_branch_type(struct perf_evlist *evlist) struct perf_evsel *evsel; u64 branch_type = 0; - evlist__for_each(evlist, evsel) + evlist__for_each_entry(evlist, evsel) branch_type |= evsel->attr.branch_sample_type; return branch_type; } @@ -1479,7 +1479,7 @@ bool perf_evlist__valid_read_format(struct perf_evlist *evlist) u64 read_format = first->attr.read_format; u64 sample_type = first->attr.sample_type; - evlist__for_each(evlist, pos) { + evlist__for_each_entry(evlist, pos) { if (read_format != pos->attr.read_format) return false; } @@ -1536,7 +1536,7 @@ bool perf_evlist__valid_sample_id_all(struct perf_evlist *evlist) { struct perf_evsel *first = perf_evlist__first(evlist), *pos = first; - evlist__for_each_continue(evlist, pos) { + evlist__for_each_entry_continue(evlist, pos) { if (first->attr.sample_id_all != pos->attr.sample_id_all) return false; } @@ -1563,7 +1563,7 @@ void perf_evlist__close(struct perf_evlist *evlist) int nthreads = thread_map__nr(evlist->threads); int n; - evlist__for_each_reverse(evlist, evsel) { + evlist__for_each_entry_reverse(evlist, evsel) { n = evsel->cpus ? evsel->cpus->nr : ncpus; perf_evsel__close(evsel, n, nthreads); } @@ -1617,7 +1617,7 @@ int perf_evlist__open(struct perf_evlist *evlist) perf_evlist__update_id_pos(evlist); - evlist__for_each(evlist, evsel) { + evlist__for_each_entry(evlist, evsel) { err = perf_evsel__open(evsel, evsel->cpus, evsel->threads); if (err < 0) goto out_err; @@ -1778,7 +1778,7 @@ size_t perf_evlist__fprintf(struct perf_evlist *evlist, FILE *fp) struct perf_evsel *evsel; size_t printed = 0; - evlist__for_each(evlist, evsel) { + evlist__for_each_entry(evlist, evsel) { printed += fprintf(fp, "%s%s", evsel->idx ? ", " : "", perf_evsel__name(evsel)); } @@ -1880,7 +1880,7 @@ void perf_evlist__to_front(struct perf_evlist *evlist, if (move_evsel == perf_evlist__first(evlist)) return; - evlist__for_each_safe(evlist, n, evsel) { + evlist__for_each_entry_safe(evlist, n, evsel) { if (evsel->leader == move_evsel->leader) list_move_tail(&evsel->node, &move); } @@ -1896,7 +1896,7 @@ void perf_evlist__set_tracking_event(struct perf_evlist *evlist, if (tracking_evsel->tracking) return; - evlist__for_each(evlist, evsel) { + evlist__for_each_entry(evlist, evsel) { if (evsel != tracking_evsel) evsel->tracking = false; } @@ -1910,7 +1910,7 @@ perf_evlist__find_evsel_by_str(struct perf_evlist *evlist, { struct perf_evsel *evsel; - evlist__for_each(evlist, evsel) { + evlist__for_each_entry(evlist, evsel) { if (!evsel->name) continue; if (strcmp(str, evsel->name) == 0) diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h index 68cb136..872912b 100644 --- a/tools/perf/util/evlist.h +++ b/tools/perf/util/evlist.h @@ -251,70 +251,70 @@ void perf_evlist__to_front(struct perf_evlist *evlist, struct perf_evsel *move_evsel); /** - * __evlist__for_each - iterate thru all the evsels + * __evlist__for_each_entry - iterate thru all the evsels * @list: list_head instance to iterate * @evsel: struct evsel iterator */ -#define __evlist__for_each(list, evsel) \ +#define __evlist__for_each_entry(list, evsel) \ list_for_each_entry(evsel, list, node) /** - * evlist__for_each - iterate thru all the evsels + * evlist__for_each_entry - iterate thru all the evsels * @evlist: evlist instance to iterate * @evsel: struct evsel iterator */ -#define evlist__for_each(evlist, evsel) \ - __evlist__for_each(&(evlist)->entries, evsel) +#define evlist__for_each_entry(evlist, evsel) \ + __evlist__for_each_entry(&(evlist)->entries, evsel) /** - * __evlist__for_each_continue - continue iteration thru all the evsels + * __evlist__for_each_entry_continue - continue iteration thru all the evsels * @list: list_head instance to iterate * @evsel: struct evsel iterator */ -#define __evlist__for_each_continue(list, evsel) \ +#define __evlist__for_each_entry_continue(list, evsel) \ list_for_each_entry_continue(evsel, list, node) /** - * evlist__for_each_continue - continue iteration thru all the evsels + * evlist__for_each_entry_continue - continue iteration thru all the evsels * @evlist: evlist instance to iterate * @evsel: struct evsel iterator */ -#define evlist__for_each_continue(evlist, evsel) \ - __evlist__for_each_continue(&(evlist)->entries, evsel) +#define evlist__for_each_entry_continue(evlist, evsel) \ + __evlist__for_each_entry_continue(&(evlist)->entries, evsel) /** - * __evlist__for_each_reverse - iterate thru all the evsels in reverse order + * __evlist__for_each_entry_reverse - iterate thru all the evsels in reverse order * @list: list_head instance to iterate * @evsel: struct evsel iterator */ -#define __evlist__for_each_reverse(list, evsel) \ +#define __evlist__for_each_entry_reverse(list, evsel) \ list_for_each_entry_reverse(evsel, list, node) /** - * evlist__for_each_reverse - iterate thru all the evsels in reverse order + * evlist__for_each_entry_reverse - iterate thru all the evsels in reverse order * @evlist: evlist instance to iterate * @evsel: struct evsel iterator */ -#define evlist__for_each_reverse(evlist, evsel) \ - __evlist__for_each_reverse(&(evlist)->entries, evsel) +#define evlist__for_each_entry_reverse(evlist, evsel) \ + __evlist__for_each_entry_reverse(&(evlist)->entries, evsel) /** - * __evlist__for_each_safe - safely iterate thru all the evsels + * __evlist__for_each_entry_safe - safely iterate thru all the evsels * @list: list_head instance to iterate * @tmp: struct evsel temp iterator * @evsel: struct evsel iterator */ -#define __evlist__for_each_safe(list, tmp, evsel) \ +#define __evlist__for_each_entry_safe(list, tmp, evsel) \ list_for_each_entry_safe(evsel, tmp, list, node) /** - * evlist__for_each_safe - safely iterate thru all the evsels + * evlist__for_each_entry_safe - safely iterate thru all the evsels * @evlist: evlist instance to iterate * @evsel: struct evsel iterator * @tmp: struct evsel temp iterator */ -#define evlist__for_each_safe(evlist, tmp, evsel) \ - __evlist__for_each_safe(&(evlist)->entries, tmp, evsel) +#define evlist__for_each_entry_safe(evlist, tmp, evsel) \ + __evlist__for_each_entry_safe(&(evlist)->entries, tmp, evsel) void perf_evlist__set_tracking_event(struct perf_evlist *evlist, struct perf_evsel *tracking_evsel); diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index 08852dd..c5cd269 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c @@ -336,7 +336,7 @@ static int write_event_desc(int fd, struct perf_header *h __maybe_unused, if (ret < 0) return ret; - evlist__for_each(evlist, evsel) { + evlist__for_each_entry(evlist, evsel) { ret = do_write(fd, &evsel->attr, sz); if (ret < 0) return ret; @@ -801,7 +801,7 @@ static int write_group_desc(int fd, struct perf_header *h __maybe_unused, if (ret < 0) return ret; - evlist__for_each(evlist, evsel) { + evlist__for_each_entry(evlist, evsel) { if (perf_evsel__is_group_leader(evsel) && evsel->nr_members > 1) { const char *name = evsel->group_name ?: "{anon_group}"; @@ -1425,7 +1425,7 @@ static void print_group_desc(struct perf_header *ph, int fd __maybe_unused, session = container_of(ph, struct perf_session, header); - evlist__for_each(session->evlist, evsel) { + evlist__for_each_entry(session->evlist, evsel) { if (perf_evsel__is_group_leader(evsel) && evsel->nr_members > 1) { fprintf(fp, "# group: %s{%s", evsel->group_name ?: "", @@ -1703,7 +1703,7 @@ perf_evlist__find_by_index(struct perf_evlist *evlist, int idx) { struct perf_evsel *evsel; - evlist__for_each(evlist, evsel) { + evlist__for_each_entry(evlist, evsel) { if (evsel->idx == idx) return evsel; } @@ -2075,7 +2075,7 @@ static int process_group_desc(struct perf_file_section *section __maybe_unused, session->evlist->nr_groups = nr_groups; i = nr = 0; - evlist__for_each(session->evlist, evsel) { + evlist__for_each_entry(session->evlist, evsel) { if (evsel->idx == (int) desc[i].leader_idx) { evsel->leader = evsel; /* {anon_group} is a dummy name */ @@ -2383,7 +2383,7 @@ int perf_session__write_header(struct perf_session *session, lseek(fd, sizeof(f_header), SEEK_SET); - evlist__for_each(session->evlist, evsel) { + evlist__for_each_entry(session->evlist, evsel) { evsel->id_offset = lseek(fd, 0, SEEK_CUR); err = do_write(fd, evsel->id, evsel->ids * sizeof(u64)); if (err < 0) { @@ -2394,7 +2394,7 @@ int perf_session__write_header(struct perf_session *session, attr_offset = lseek(fd, 0, SEEK_CUR); - evlist__for_each(evlist, evsel) { + evlist__for_each_entry(evlist, evsel) { f_attr = (struct perf_file_attr){ .attr = evsel->attr, .ids = { @@ -2828,7 +2828,7 @@ static int perf_evlist__prepare_tracepoint_events(struct perf_evlist *evlist, { struct perf_evsel *pos; - evlist__for_each(evlist, pos) { + evlist__for_each_entry(evlist, pos) { if (pos->attr.type == PERF_TYPE_TRACEPOINT && perf_evsel__prepare_tracepoint_event(pos, pevent)) return -1; @@ -3127,7 +3127,7 @@ int perf_event__synthesize_attrs(struct perf_tool *tool, struct perf_evsel *evsel; int err = 0; - evlist__for_each(session->evlist, evsel) { + evlist__for_each_entry(session->evlist, evsel) { err = perf_event__synthesize_attr(tool, &evsel->attr, evsel->ids, evsel->id, process); if (err) { diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c index d9826cc..e1fcc8d 100644 --- a/tools/perf/util/hist.c +++ b/tools/perf/util/hist.c @@ -2199,7 +2199,7 @@ size_t perf_evlist__fprintf_nr_events(struct perf_evlist *evlist, FILE *fp) struct perf_evsel *pos; size_t ret = 0; - evlist__for_each(evlist, pos) { + evlist__for_each_entry(evlist, pos) { ret += fprintf(fp, "%s stats:\n", perf_evsel__name(pos)); ret += events_stats__fprintf(&evsel__hists(pos)->stats, fp); } diff --git a/tools/perf/util/intel-bts.c b/tools/perf/util/intel-bts.c index 9df9960..ecec73f 100644 --- a/tools/perf/util/intel-bts.c +++ b/tools/perf/util/intel-bts.c @@ -777,7 +777,7 @@ static int intel_bts_synth_events(struct intel_bts *bts, u64 id; int err; - evlist__for_each(evlist, evsel) { + evlist__for_each_entry(evlist, evsel) { if (evsel->attr.type == bts->pmu_type && evsel->ids) { found = true; break; diff --git a/tools/perf/util/intel-pt.c b/tools/perf/util/intel-pt.c index a2fe3a2..dc243b1 100644 --- a/tools/perf/util/intel-pt.c +++ b/tools/perf/util/intel-pt.c @@ -557,7 +557,7 @@ static bool intel_pt_exclude_kernel(struct intel_pt *pt) { struct perf_evsel *evsel; - evlist__for_each(pt->session->evlist, evsel) { + evlist__for_each_entry(pt->session->evlist, evsel) { if (intel_pt_get_config(pt, &evsel->attr, NULL) && !evsel->attr.exclude_kernel) return false; @@ -573,7 +573,7 @@ static bool intel_pt_return_compression(struct intel_pt *pt) if (!pt->noretcomp_bit) return true; - evlist__for_each(pt->session->evlist, evsel) { + evlist__for_each_entry(pt->session->evlist, evsel) { if (intel_pt_get_config(pt, &evsel->attr, &config) && (config & pt->noretcomp_bit)) return false; @@ -593,7 +593,7 @@ static unsigned int intel_pt_mtc_period(struct intel_pt *pt) for (shift = 0, config = pt->mtc_freq_bits; !(config & 1); shift++) config >>= 1; - evlist__for_each(pt->session->evlist, evsel) { + evlist__for_each_entry(pt->session->evlist, evsel) { if (intel_pt_get_config(pt, &evsel->attr, &config)) return (config & pt->mtc_freq_bits) >> shift; } @@ -609,7 +609,7 @@ static bool intel_pt_timeless_decoding(struct intel_pt *pt) if (!pt->tsc_bit || !pt->cap_user_time_zero) return true; - evlist__for_each(pt->session->evlist, evsel) { + evlist__for_each_entry(pt->session->evlist, evsel) { if (!(evsel->attr.sample_type & PERF_SAMPLE_TIME)) return true; if (intel_pt_get_config(pt, &evsel->attr, &config)) { @@ -626,7 +626,7 @@ static bool intel_pt_tracing_kernel(struct intel_pt *pt) { struct perf_evsel *evsel; - evlist__for_each(pt->session->evlist, evsel) { + evlist__for_each_entry(pt->session->evlist, evsel) { if (intel_pt_get_config(pt, &evsel->attr, NULL) && !evsel->attr.exclude_kernel) return true; @@ -643,7 +643,7 @@ static bool intel_pt_have_tsc(struct intel_pt *pt) if (!pt->tsc_bit) return false; - evlist__for_each(pt->session->evlist, evsel) { + evlist__for_each_entry(pt->session->evlist, evsel) { if (intel_pt_get_config(pt, &evsel->attr, &config)) { if (config & pt->tsc_bit) have_tsc = true; @@ -1851,7 +1851,7 @@ static int intel_pt_synth_events(struct intel_pt *pt, u64 id; int err; - evlist__for_each(evlist, evsel) { + evlist__for_each_entry(evlist, evsel) { if (evsel->attr.type == pt->pmu_type && evsel->ids) { found = true; break; @@ -1931,7 +1931,7 @@ static int intel_pt_synth_events(struct intel_pt *pt, pt->sample_transactions = true; pt->transactions_id = id; id += 1; - evlist__for_each(evlist, evsel) { + evlist__for_each_entry(evlist, evsel) { if (evsel->id && evsel->id[0] == pt->transactions_id) { if (evsel->name) zfree(&evsel->name); @@ -1969,7 +1969,7 @@ static struct perf_evsel *intel_pt_find_sched_switch(struct perf_evlist *evlist) { struct perf_evsel *evsel; - evlist__for_each_reverse(evlist, evsel) { + evlist__for_each_entry_reverse(evlist, evsel) { const char *name = perf_evsel__name(evsel); if (!strcmp(name, "sched:sched_switch")) @@ -1983,7 +1983,7 @@ static bool intel_pt_find_switch(struct perf_evlist *evlist) { struct perf_evsel *evsel; - evlist__for_each(evlist, evsel) { + evlist__for_each_entry(evlist, evsel) { if (evsel->attr.context_switch) return true; } diff --git a/tools/perf/util/jitdump.c b/tools/perf/util/jitdump.c index 86afe96..9f3305f 100644 --- a/tools/perf/util/jitdump.c +++ b/tools/perf/util/jitdump.c @@ -108,7 +108,7 @@ jit_validate_events(struct perf_session *session) /* * check that all events use CLOCK_MONOTONIC */ - evlist__for_each(session->evlist, evsel) { + evlist__for_each_entry(session->evlist, evsel) { if (evsel->attr.use_clockid == 0 || evsel->attr.clockid != CLOCK_MONOTONIC) return -1; } diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index d15e335..ebd87b7 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -1396,7 +1396,7 @@ int parse_events__modifier_event(struct list_head *list, char *str, bool add) if (!add && get_event_modifier(&mod, str, NULL)) return -EINVAL; - __evlist__for_each(list, evsel) { + __evlist__for_each_entry(list, evsel) { if (add && get_event_modifier(&mod, str, evsel)) return -EINVAL; @@ -1422,7 +1422,7 @@ int parse_events_name(struct list_head *list, char *name) { struct perf_evsel *evsel; - __evlist__for_each(list, evsel) { + __evlist__for_each_entry(list, evsel) { if (!evsel->name) evsel->name = strdup(name); } diff --git a/tools/perf/util/python.c b/tools/perf/util/python.c index 98f127a..65c6c73 100644 --- a/tools/perf/util/python.c +++ b/tools/perf/util/python.c @@ -957,7 +957,7 @@ static PyObject *pyrf_evlist__item(PyObject *obj, Py_ssize_t i) if (i >= pevlist->evlist.nr_entries) return NULL; - evlist__for_each(&pevlist->evlist, pos) { + evlist__for_each_entry(&pevlist->evlist, pos) { if (i-- == 0) break; } diff --git a/tools/perf/util/record.c b/tools/perf/util/record.c index 481792c..98bf584 100644 --- a/tools/perf/util/record.c +++ b/tools/perf/util/record.c @@ -148,7 +148,7 @@ void perf_evlist__config(struct perf_evlist *evlist, struct record_opts *opts, use_comm_exec = perf_can_comm_exec(); - evlist__for_each(evlist, evsel) { + evlist__for_each_entry(evlist, evsel) { perf_evsel__config(evsel, opts, callchain); if (evsel->tracking && use_comm_exec) evsel->attr.comm_exec = 1; @@ -161,18 +161,18 @@ void perf_evlist__config(struct perf_evlist *evlist, struct record_opts *opts, * match the id. */ use_sample_identifier = perf_can_sample_identifier(); - evlist__for_each(evlist, evsel) + evlist__for_each_entry(evlist, evsel) perf_evsel__set_sample_id(evsel, use_sample_identifier); } else if (evlist->nr_entries > 1) { struct perf_evsel *first = perf_evlist__first(evlist); - evlist__for_each(evlist, evsel) { + evlist__for_each_entry(evlist, evsel) { if (evsel->attr.sample_type == first->attr.sample_type) continue; use_sample_identifier = perf_can_sample_identifier(); break; } - evlist__for_each(evlist, evsel) + evlist__for_each_entry(evlist, evsel) perf_evsel__set_sample_id(evsel, use_sample_identifier); } diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index 43be0c5..078d496 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c @@ -83,7 +83,7 @@ static bool perf_session__has_comm_exec(struct perf_session *session) { struct perf_evsel *evsel; - evlist__for_each(session->evlist, evsel) { + evlist__for_each_entry(session->evlist, evsel) { if (evsel->attr.comm_exec) return true; } @@ -1872,7 +1872,7 @@ bool perf_session__has_traces(struct perf_session *session, const char *msg) { struct perf_evsel *evsel; - evlist__for_each(session->evlist, evsel) { + evlist__for_each_entry(session->evlist, evsel) { if (evsel->attr.type == PERF_TYPE_TRACEPOINT) return true; } @@ -1954,7 +1954,7 @@ struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session, { struct perf_evsel *pos; - evlist__for_each(session->evlist, pos) { + evlist__for_each_entry(session->evlist, pos) { if (pos->attr.type == type) return pos; } @@ -2109,7 +2109,7 @@ int perf_event__synthesize_id_index(struct perf_tool *tool, max_nr = (UINT16_MAX - sizeof(struct id_index_event)) / sizeof(struct id_index_entry); - evlist__for_each(evlist, evsel) + evlist__for_each_entry(evlist, evsel) nr += evsel->ids; n = nr > max_nr ? max_nr : nr; @@ -2122,7 +2122,7 @@ int perf_event__synthesize_id_index(struct perf_tool *tool, ev->id_index.header.size = sz; ev->id_index.nr = n; - evlist__for_each(evlist, evsel) { + evlist__for_each_entry(evlist, evsel) { u32 j; for (j = 0; j < evsel->ids; j++) { diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c index a764139..5854b46 100644 --- a/tools/perf/util/sort.c +++ b/tools/perf/util/sort.c @@ -2069,7 +2069,7 @@ static struct perf_evsel *find_evsel(struct perf_evlist *evlist, char *event_nam } full_name = !!strchr(event_name, ':'); - evlist__for_each(evlist, pos) { + evlist__for_each_entry(evlist, pos) { /* case 2 */ if (full_name && !strcmp(pos->name, event_name)) return pos; @@ -2125,7 +2125,7 @@ static int add_all_dynamic_fields(struct perf_evlist *evlist, bool raw_trace, int ret; struct perf_evsel *evsel; - evlist__for_each(evlist, evsel) { + evlist__for_each_entry(evlist, evsel) { if (evsel->attr.type != PERF_TYPE_TRACEPOINT) continue; @@ -2143,7 +2143,7 @@ static int add_all_matching_fields(struct perf_evlist *evlist, struct perf_evsel *evsel; struct format_field *field; - evlist__for_each(evlist, evsel) { + evlist__for_each_entry(evlist, evsel) { if (evsel->attr.type != PERF_TYPE_TRACEPOINT) continue; @@ -2456,7 +2456,7 @@ static const char *get_default_sort_order(struct perf_evlist *evlist) if (evlist == NULL) goto out_no_evlist; - evlist__for_each(evlist, evsel) { + evlist__for_each_entry(evlist, evsel) { if (evsel->attr.type != PERF_TYPE_TRACEPOINT) { use_trace = false; break; diff --git a/tools/perf/util/stat.c b/tools/perf/util/stat.c index c1ba255..39345c2d 100644 --- a/tools/perf/util/stat.c +++ b/tools/perf/util/stat.c @@ -162,7 +162,7 @@ int perf_evlist__alloc_stats(struct perf_evlist *evlist, bool alloc_raw) { struct perf_evsel *evsel; - evlist__for_each(evlist, evsel) { + evlist__for_each_entry(evlist, evsel) { if (perf_evsel__alloc_stats(evsel, alloc_raw)) goto out_free; } @@ -178,7 +178,7 @@ void perf_evlist__free_stats(struct perf_evlist *evlist) { struct perf_evsel *evsel; - evlist__for_each(evlist, evsel) { + evlist__for_each_entry(evlist, evsel) { perf_evsel__free_stat_priv(evsel); perf_evsel__free_counts(evsel); perf_evsel__free_prev_raw_counts(evsel); @@ -189,7 +189,7 @@ void perf_evlist__reset_stats(struct perf_evlist *evlist) { struct perf_evsel *evsel; - evlist__for_each(evlist, evsel) { + evlist__for_each_entry(evlist, evsel) { perf_evsel__reset_stat_priv(evsel); perf_evsel__reset_counts(evsel); } -- cgit v0.10.2 From 602a1f4daa5d107e890fd4f5f558dedf6a0874f3 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 23 Jun 2016 11:31:20 -0300 Subject: perf tools: Rename strlist_for_each() macros to for_each_entry() To match the semantics for list.h in the kernel, that are the interface we use in them. Cc: Adrian Hunter Cc: David Ahern Cc: Jiri Olsa Cc: Milian Wolff Cc: Namhyung Kim Cc: Taeung Song Cc: Wang Nan Link: http://lkml.kernel.org/n/tip-0b5i2ki9c3di6706fxpticsb@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/builtin-buildid-cache.c b/tools/perf/builtin-buildid-cache.c index 2cbec65..76a4d03 100644 --- a/tools/perf/builtin-buildid-cache.c +++ b/tools/perf/builtin-buildid-cache.c @@ -209,7 +209,7 @@ static int build_id_cache__purge_path(const char *pathname) if (err) goto out; - strlist__for_each(pos, list) { + strlist__for_each_entry(pos, list) { err = build_id_cache__remove_s(pos->s); pr_debug("Removing %s %s: %s\n", pos->s, pathname, err ? "FAIL" : "Ok"); @@ -343,7 +343,7 @@ int cmd_buildid_cache(int argc, const char **argv, if (add_name_list_str) { list = strlist__new(add_name_list_str, NULL); if (list) { - strlist__for_each(pos, list) + strlist__for_each_entry(pos, list) if (build_id_cache__add_file(pos->s)) { if (errno == EEXIST) { pr_debug("%s already in the cache\n", @@ -361,7 +361,7 @@ int cmd_buildid_cache(int argc, const char **argv, if (remove_name_list_str) { list = strlist__new(remove_name_list_str, NULL); if (list) { - strlist__for_each(pos, list) + strlist__for_each_entry(pos, list) if (build_id_cache__remove_file(pos->s)) { if (errno == ENOENT) { pr_debug("%s wasn't in the cache\n", @@ -379,7 +379,7 @@ int cmd_buildid_cache(int argc, const char **argv, if (purge_name_list_str) { list = strlist__new(purge_name_list_str, NULL); if (list) { - strlist__for_each(pos, list) + strlist__for_each_entry(pos, list) if (build_id_cache__purge_path(pos->s)) { if (errno == ENOENT) { pr_debug("%s wasn't in the cache\n", @@ -400,7 +400,7 @@ int cmd_buildid_cache(int argc, const char **argv, if (update_name_list_str) { list = strlist__new(update_name_list_str, NULL); if (list) { - strlist__for_each(pos, list) + strlist__for_each_entry(pos, list) if (build_id_cache__update_file(pos->s)) { if (errno == ENOENT) { pr_debug("%s wasn't in the cache\n", diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c index 6d7ab431..3426232 100644 --- a/tools/perf/builtin-probe.c +++ b/tools/perf/builtin-probe.c @@ -389,7 +389,7 @@ static int perf_del_probe_events(struct strfilter *filter) ret = probe_file__get_events(kfd, filter, klist); if (ret == 0) { - strlist__for_each(ent, klist) + strlist__for_each_entry(ent, klist) pr_info("Removed event: %s\n", ent->s); ret = probe_file__del_strlist(kfd, klist); @@ -399,7 +399,7 @@ static int perf_del_probe_events(struct strfilter *filter) ret2 = probe_file__get_events(ufd, filter, ulist); if (ret2 == 0) { - strlist__for_each(ent, ulist) + strlist__for_each_entry(ent, ulist) pr_info("Removed event: %s\n", ent->s); ret2 = probe_file__del_strlist(ufd, ulist); diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c index 1ecadfc..1ba1341 100644 --- a/tools/perf/builtin-trace.c +++ b/tools/perf/builtin-trace.c @@ -1247,7 +1247,7 @@ static int trace__validate_ev_qualifier(struct trace *trace) i = 0; - strlist__for_each(pos, trace->ev_qualifier) { + strlist__for_each_entry(pos, trace->ev_qualifier) { const char *sc = pos->s; int id = syscalltbl__id(trace->sctbl, sc); diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c index caad19d..4f7b3e5 100644 --- a/tools/perf/util/probe-event.c +++ b/tools/perf/util/probe-event.c @@ -980,7 +980,7 @@ static int show_available_vars_at(struct debuginfo *dinfo, zfree(&vl->point.symbol); nvars = 0; if (vl->vars) { - strlist__for_each(node, vl->vars) { + strlist__for_each_entry(node, vl->vars) { var = strchr(node->s, '\t') + 1; if (strfilter__compare(_filter, var)) { fprintf(stdout, "\t\t%s\n", node->s); @@ -2333,7 +2333,7 @@ static int __show_perf_probe_events(int fd, bool is_kprobe, if (!rawlist) return -ENOMEM; - strlist__for_each(ent, rawlist) { + strlist__for_each_entry(ent, rawlist) { ret = parse_probe_trace_command(ent->s, &tev); if (ret >= 0) { if (!filter_probe_trace_event(&tev, filter)) diff --git a/tools/perf/util/probe-file.c b/tools/perf/util/probe-file.c index 25a4042..1c12c1a 100644 --- a/tools/perf/util/probe-file.c +++ b/tools/perf/util/probe-file.c @@ -178,7 +178,7 @@ static struct strlist *__probe_file__get_namelist(int fd, bool include_group) if (!rawlist) return NULL; sl = strlist__new(NULL, NULL); - strlist__for_each(ent, rawlist) { + strlist__for_each_entry(ent, rawlist) { ret = parse_probe_trace_command(ent->s, &tev); if (ret < 0) break; @@ -281,7 +281,7 @@ int probe_file__get_events(int fd, struct strfilter *filter, if (!namelist) return -ENOENT; - strlist__for_each(ent, namelist) { + strlist__for_each_entry(ent, namelist) { p = strchr(ent->s, ':'); if ((p && strfilter__compare(filter, p + 1)) || strfilter__compare(filter, ent->s)) { @@ -299,7 +299,7 @@ int probe_file__del_strlist(int fd, struct strlist *namelist) int ret = 0; struct str_node *ent; - strlist__for_each(ent, namelist) { + strlist__for_each_entry(ent, namelist) { ret = __del_trace_probe_event(fd, ent); if (ret < 0) break; @@ -612,7 +612,7 @@ static int probe_cache_entry__write(struct probe_cache_entry *entry, int fd) if (ret < (int)iov[1].iov_len + 2) goto rollback; - strlist__for_each(snode, entry->tevlist) { + strlist__for_each_entry(snode, entry->tevlist) { iov[0].iov_base = (void *)snode->s; iov[0].iov_len = strlen(snode->s); iov[1].iov_base = (void *)"\n"; iov[1].iov_len = 1; diff --git a/tools/perf/util/strlist.h b/tools/perf/util/strlist.h index ca99002..19207e5 100644 --- a/tools/perf/util/strlist.h +++ b/tools/perf/util/strlist.h @@ -73,7 +73,7 @@ static inline struct str_node *strlist__next(struct str_node *sn) * @pos: the &struct str_node to use as a loop cursor. * @slist: the &struct strlist for loop. */ -#define strlist__for_each(pos, slist) \ +#define strlist__for_each_entry(pos, slist) \ for (pos = strlist__first(slist); pos; pos = strlist__next(pos)) /** @@ -83,7 +83,7 @@ static inline struct str_node *strlist__next(struct str_node *sn) * @n: another &struct str_node to use as temporary storage. * @slist: the &struct strlist for loop. */ -#define strlist__for_each_safe(pos, n, slist) \ +#define strlist__for_each_entry_safe(pos, n, slist) \ for (pos = strlist__first(slist), n = strlist__next(pos); pos;\ pos = n, n = strlist__next(n)) #endif /* __PERF_STRLIST_H */ diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index 09c5c34..b044f1a 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c @@ -1626,7 +1626,7 @@ static int find_matching_kcore(struct map *map, char *dir, size_t dir_sz) if (!dirs) return -1; - strlist__for_each(nd, dirs) { + strlist__for_each_entry(nd, dirs) { scnprintf(kallsyms_filename, sizeof(kallsyms_filename), "%s/%s/kallsyms", dir, nd->s); if (!validate_kcore_addresses(kallsyms_filename, map)) { diff --git a/tools/perf/util/thread_map.c b/tools/perf/util/thread_map.c index 5654fe1..40585f5 100644 --- a/tools/perf/util/thread_map.c +++ b/tools/perf/util/thread_map.c @@ -202,7 +202,7 @@ static struct thread_map *thread_map__new_by_pid_str(const char *pid_str) if (!slist) return NULL; - strlist__for_each(pos, slist) { + strlist__for_each_entry(pos, slist) { pid = strtol(pos->s, &end_ptr, 10); if (pid == INT_MIN || pid == INT_MAX || @@ -278,7 +278,7 @@ struct thread_map *thread_map__new_by_tid_str(const char *tid_str) if (!slist) return NULL; - strlist__for_each(pos, slist) { + strlist__for_each_entry(pos, slist) { tid = strtol(pos->s, &end_ptr, 10); if (tid == INT_MIN || tid == INT_MAX || -- cgit v0.10.2 From 98a91837dd1751e730f8265129b376450f41dcfd Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 23 Jun 2016 11:34:10 -0300 Subject: perf rb_resort: Rename for_each() macros to for_each_entry() To match the semantics for list.h in the kernel, that are the interface we use in them. Cc: Adrian Hunter Cc: David Ahern Cc: Jiri Olsa Cc: Milian Wolff Cc: Namhyung Kim Cc: Taeung Song Cc: Wang Nan Link: http://lkml.kernel.org/n/tip-iaxuq2yu43mtb504j96q0axs@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c index 1ba1341..cf90de8 100644 --- a/tools/perf/builtin-trace.c +++ b/tools/perf/builtin-trace.c @@ -2550,7 +2550,7 @@ static size_t thread__dump_stats(struct thread_trace *ttrace, printed += fprintf(fp, " (msec) (msec) (msec) (msec) (%%)\n"); printed += fprintf(fp, " --------------- -------- --------- --------- --------- --------- ------\n"); - resort_rb__for_each(nd, syscall_stats) { + resort_rb__for_each_entry(nd, syscall_stats) { struct stats *stats = syscall_stats_entry->stats; if (stats) { double min = (double)(stats->min) / NSEC_PER_MSEC; @@ -2627,7 +2627,7 @@ static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp) return 0; } - resort_rb__for_each(nd, threads) + resort_rb__for_each_entry(nd, threads) printed += trace__fprintf_thread(fp, threads_entry->thread, trace); resort_rb__delete(threads); diff --git a/tools/perf/util/rb_resort.h b/tools/perf/util/rb_resort.h index abc76e3..808cc45 100644 --- a/tools/perf/util/rb_resort.h +++ b/tools/perf/util/rb_resort.h @@ -35,7 +35,7 @@ DEFINE_RB_RESORT_RB(threads, strcmp(a->thread->shortname, struct rb_node *nd; - resort_rb__for_each(nd, threads) { + resort_rb__for_each_entry(nd, threads) { struct thread *t = threads_entry; printf("%s: %d\n", t->shortname, t->tid); } @@ -123,7 +123,7 @@ static void __name##_sorted__init_entry(struct rb_node *nd, \ struct __name##_sorted_entry *__name##_entry; \ struct __name##_sorted *__name = __name##_sorted__new -#define resort_rb__for_each(__nd, __name) \ +#define resort_rb__for_each_entry(__nd, __name) \ for (__nd = rb_first(&__name->entries); \ __name##_entry = rb_entry(__nd, struct __name##_sorted_entry, \ rb_node), __nd; \ -- cgit v0.10.2 From 10daf4d01bad77c6ae862367ad2148a8340d94e6 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 23 Jun 2016 11:39:19 -0300 Subject: perf intlist: Rename for_each() macros to for_each_entry() To match the semantics for list.h in the kernel, that are the interface we use in them. Cc: Adrian Hunter Cc: David Ahern Cc: Jiri Olsa Cc: Milian Wolff Cc: Namhyung Kim Cc: Taeung Song Cc: Wang Nan Link: http://lkml.kernel.org/n/tip-mdp1heu9xjjc12zebh91232l@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/util/intlist.h b/tools/perf/util/intlist.h index aa6877d..020b9ca 100644 --- a/tools/perf/util/intlist.h +++ b/tools/perf/util/intlist.h @@ -57,21 +57,21 @@ static inline struct int_node *intlist__next(struct int_node *in) } /** - * intlist_for_each - iterate over a intlist + * intlist__for_each_entry - iterate over a intlist * @pos: the &struct int_node to use as a loop cursor. * @ilist: the &struct intlist for loop. */ -#define intlist__for_each(pos, ilist) \ +#define intlist__for_each_entry(pos, ilist) \ for (pos = intlist__first(ilist); pos; pos = intlist__next(pos)) /** - * intlist_for_each_safe - iterate over a intlist safe against removal of + * intlist__for_each_entry_safe - iterate over a intlist safe against removal of * int_node * @pos: the &struct int_node to use as a loop cursor. * @n: another &struct int_node to use as temporary storage. * @ilist: the &struct intlist for loop. */ -#define intlist__for_each_safe(pos, n, ilist) \ +#define intlist__for_each_entry_safe(pos, n, ilist) \ for (pos = intlist__first(ilist), n = intlist__next(pos); pos;\ pos = n, n = intlist__next(n)) #endif /* __PERF_INTLIST_H */ diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c index 4f7b3e5..55f41d5 100644 --- a/tools/perf/util/probe-event.c +++ b/tools/perf/util/probe-event.c @@ -896,7 +896,7 @@ static int __show_line_range(struct line_range *lr, const char *module, goto end; } - intlist__for_each(ln, lr->line_list) { + intlist__for_each_entry(ln, lr->line_list) { for (; ln->i > l; l++) { ret = show_one_line(fp, l - lr->offset); if (ret < 0) -- cgit v0.10.2 From 2a4fe14bc8da0af53076fa90ac34738c7b55fc3b Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Tue, 21 Jun 2016 11:20:29 +0100 Subject: irqchip/exynos-combiner: Fix usage of __raw IO Fix the use of __raw IO accessors when the readl/writel_relaxed are better. This should fix issues if the kernel is running as big endian. Signed-off-by: Ben Dooks [jac: reformat subject line, fix commit message typo] Link: https://lkml.kernel.org/r/1466504432-24187-9-git-send-email-ben.dooks@codethink.co.uk Signed-off-by: Jason Cooper diff --git a/drivers/irqchip/exynos-combiner.c b/drivers/irqchip/exynos-combiner.c index ead15be..b78a169 100644 --- a/drivers/irqchip/exynos-combiner.c +++ b/drivers/irqchip/exynos-combiner.c @@ -55,14 +55,14 @@ static void combiner_mask_irq(struct irq_data *data) { u32 mask = 1 << (data->hwirq % 32); - __raw_writel(mask, combiner_base(data) + COMBINER_ENABLE_CLEAR); + writel_relaxed(mask, combiner_base(data) + COMBINER_ENABLE_CLEAR); } static void combiner_unmask_irq(struct irq_data *data) { u32 mask = 1 << (data->hwirq % 32); - __raw_writel(mask, combiner_base(data) + COMBINER_ENABLE_SET); + writel_relaxed(mask, combiner_base(data) + COMBINER_ENABLE_SET); } static void combiner_handle_cascade_irq(struct irq_desc *desc) @@ -75,7 +75,7 @@ static void combiner_handle_cascade_irq(struct irq_desc *desc) chained_irq_enter(chip, desc); spin_lock(&irq_controller_lock); - status = __raw_readl(chip_data->base + COMBINER_INT_STATUS); + status = readl_relaxed(chip_data->base + COMBINER_INT_STATUS); spin_unlock(&irq_controller_lock); status &= chip_data->irq_mask; @@ -135,7 +135,7 @@ static void __init combiner_init_one(struct combiner_chip_data *combiner_data, combiner_data->parent_irq = irq; /* Disable all interrupts */ - __raw_writel(combiner_data->irq_mask, base + COMBINER_ENABLE_CLEAR); + writel_relaxed(combiner_data->irq_mask, base + COMBINER_ENABLE_CLEAR); } static int combiner_irq_domain_xlate(struct irq_domain *d, @@ -218,7 +218,7 @@ static int combiner_suspend(void) for (i = 0; i < max_nr; i++) combiner_data[i].pm_save = - __raw_readl(combiner_data[i].base + COMBINER_ENABLE_SET); + readl_relaxed(combiner_data[i].base + COMBINER_ENABLE_SET); return 0; } @@ -235,9 +235,9 @@ static void combiner_resume(void) int i; for (i = 0; i < max_nr; i++) { - __raw_writel(combiner_data[i].irq_mask, + writel_relaxed(combiner_data[i].irq_mask, combiner_data[i].base + COMBINER_ENABLE_CLEAR); - __raw_writel(combiner_data[i].pm_save, + writel_relaxed(combiner_data[i].pm_save, combiner_data[i].base + COMBINER_ENABLE_SET); } } -- cgit v0.10.2 From 353332855eef20dc5ae8cd42aaafb4750748f90b Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Tue, 21 Jun 2016 11:20:30 +0100 Subject: irqchip/s3c24xx: Fixup IO accessors for big endian Instead of using the __raw accessors, use the _relaxed versions to deal with any issues due to endian-ness of the CPU. Signed-off-by: Ben Dooks [jac: reformat subject line, fix commit message typo] Link: https://lkml.kernel.org/r/1466504432-24187-10-git-send-email-ben.dooks@codethink.co.uk Signed-off-by: Jason Cooper diff --git a/drivers/irqchip/irq-s3c24xx.c b/drivers/irqchip/irq-s3c24xx.c index 5dc5a76..c25ce5a 100644 --- a/drivers/irqchip/irq-s3c24xx.c +++ b/drivers/irqchip/irq-s3c24xx.c @@ -92,9 +92,9 @@ static void s3c_irq_mask(struct irq_data *data) unsigned long mask; unsigned int irqno; - mask = __raw_readl(intc->reg_mask); + mask = readl_relaxed(intc->reg_mask); mask |= (1UL << irq_data->offset); - __raw_writel(mask, intc->reg_mask); + writel_relaxed(mask, intc->reg_mask); if (parent_intc) { parent_data = &parent_intc->irqs[irq_data->parent_irq]; @@ -119,9 +119,9 @@ static void s3c_irq_unmask(struct irq_data *data) unsigned long mask; unsigned int irqno; - mask = __raw_readl(intc->reg_mask); + mask = readl_relaxed(intc->reg_mask); mask &= ~(1UL << irq_data->offset); - __raw_writel(mask, intc->reg_mask); + writel_relaxed(mask, intc->reg_mask); if (parent_intc) { irqno = irq_find_mapping(parent_intc->domain, @@ -136,9 +136,9 @@ static inline void s3c_irq_ack(struct irq_data *data) struct s3c_irq_intc *intc = irq_data->intc; unsigned long bitval = 1UL << irq_data->offset; - __raw_writel(bitval, intc->reg_pending); + writel_relaxed(bitval, intc->reg_pending); if (intc->reg_intpnd) - __raw_writel(bitval, intc->reg_intpnd); + writel_relaxed(bitval, intc->reg_intpnd); } static int s3c_irq_type(struct irq_data *data, unsigned int type) @@ -172,9 +172,9 @@ static int s3c_irqext_type_set(void __iomem *gpcon_reg, unsigned long newvalue = 0, value; /* Set the GPIO to external interrupt mode */ - value = __raw_readl(gpcon_reg); + value = readl_relaxed(gpcon_reg); value = (value & ~(3 << gpcon_offset)) | (0x02 << gpcon_offset); - __raw_writel(value, gpcon_reg); + writel_relaxed(value, gpcon_reg); /* Set the external interrupt to pointed trigger type */ switch (type) @@ -208,9 +208,9 @@ static int s3c_irqext_type_set(void __iomem *gpcon_reg, return -EINVAL; } - value = __raw_readl(extint_reg); + value = readl_relaxed(extint_reg); value = (value & ~(7 << extint_offset)) | (newvalue << extint_offset); - __raw_writel(value, extint_reg); + writel_relaxed(value, extint_reg); return 0; } @@ -315,8 +315,8 @@ static void s3c_irq_demux(struct irq_desc *desc) chained_irq_enter(chip, desc); - src = __raw_readl(sub_intc->reg_pending); - msk = __raw_readl(sub_intc->reg_mask); + src = readl_relaxed(sub_intc->reg_pending); + msk = readl_relaxed(sub_intc->reg_mask); src &= ~msk; src &= irq_data->sub_bits; @@ -337,7 +337,7 @@ static inline int s3c24xx_handle_intc(struct s3c_irq_intc *intc, int pnd; int offset; - pnd = __raw_readl(intc->reg_intpnd); + pnd = readl_relaxed(intc->reg_intpnd); if (!pnd) return false; @@ -352,7 +352,7 @@ static inline int s3c24xx_handle_intc(struct s3c_irq_intc *intc, * * Thanks to Klaus, Shannon, et al for helping to debug this problem */ - offset = __raw_readl(intc->reg_intpnd + 4); + offset = readl_relaxed(intc->reg_intpnd + 4); /* Find the bit manually, when the offset is wrong. * The pending register only ever contains the one bit of the next @@ -406,7 +406,7 @@ int s3c24xx_set_fiq(unsigned int irq, bool on) intmod = 0; } - __raw_writel(intmod, S3C2410_INTMOD); + writel_relaxed(intmod, S3C2410_INTMOD); return 0; } @@ -508,14 +508,14 @@ static void s3c24xx_clear_intc(struct s3c_irq_intc *intc) last = 0; for (i = 0; i < 4; i++) { - pend = __raw_readl(reg_source); + pend = readl_relaxed(reg_source); if (pend == 0 || pend == last) break; - __raw_writel(pend, intc->reg_pending); + writel_relaxed(pend, intc->reg_pending); if (intc->reg_intpnd) - __raw_writel(pend, intc->reg_intpnd); + writel_relaxed(pend, intc->reg_intpnd); pr_info("irq: clearing pending status %08x\n", (int)pend); last = pend; -- cgit v0.10.2 From 055cd33d93ac310ce68e8b1ebcf88f829426adf5 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Thu, 23 Jun 2016 16:40:56 +0300 Subject: perf script: Print sample flags more nicely The flags field is synthesized and may have a value when Instruction Trace decoding. The flags are "bcrosyiABEx" which stand for branch, call, return, conditional, system, asynchronous, interrupt, transaction abort, trace begin, trace end, and in transaction, respectively. Change the display so that known combinations of flags are printed more nicely e.g.: "call" for "bc", "return" for "br", "jcc" for "bo", "jmp" for "b", "int" for "bci", "iret" for "bri", "syscall" for "bcs", "sysret" for "brs", "async" for "by", "hw int" for "bcyi", "tx abrt" for "bA", "tr strt" for "bB", "tr end" for "bE". However the "x" flag will be displayed separately in those cases e.g. "jcc (x)" for a condition branch within a transaction. Example: perf record -e intel_pt//u ls perf script --ns -F comm,cpu,pid,tid,time,ip,addr,sym,dso,symoff,flags ... ls 3689/3689 [001] 2062.020965237: jcc 7f06a958847a _dl_sysdep_start+0xfa (/lib/x86_64-linux-gnu/ld-2.19.so) => 7f06a9588450 _dl_sysdep_start+0xd0 (/lib/x86_64-linux-gnu/ld-2.19.so) ls 3689/3689 [001] 2062.020965237: jmp 7f06a9588461 _dl_sysdep_start+0xe1 (/lib/x86_64-linux-gnu/ld-2.19.so) => 7f06a95885a0 _dl_sysdep_start+0x220 (/lib/x86_64-linux-gnu/ld-2.19.so) ls 3689/3689 [001] 2062.020965237: jmp 7f06a95885a4 _dl_sysdep_start+0x224 (/lib/x86_64-linux-gnu/ld-2.19.so) => 7f06a9588470 _dl_sysdep_start+0xf0 (/lib/x86_64-linux-gnu/ld-2.19.so) ls 3689/3689 [001] 2062.020965904: call 7f06a95884c3 _dl_sysdep_start+0x143 (/lib/x86_64-linux-gnu/ld-2.19.so) => 7f06a9589140 brk+0x0 (/lib/x86_64-linux-gnu/ld-2.19.so) ls 3689/3689 [001] 2062.020965904: syscall 7f06a958914a brk+0xa (/lib/x86_64-linux-gnu/ld-2.19.so) => 0 [unknown] ([unknown]) ls 3689/3689 [001] 2062.020966237: tr strt 0 [unknown] ([unknown]) => 7f06a958914c brk+0xc (/lib/x86_64-linux-gnu/ld-2.19.so) ls 3689/3689 [001] 2062.020966237: return 7f06a9589165 brk+0x25 (/lib/x86_64-linux-gnu/ld-2.19.so) => 7f06a95884c8 _dl_sysdep_start+0x148 (/lib/x86_64-linux-gnu/ld-2.19.so) ls 3689/3689 [001] 2062.020966237: jcc 7f06a95884d7 _dl_sysdep_start+0x157 (/lib/x86_64-linux-gnu/ld-2.19.so) => 7f06a95885f0 _dl_sysdep_start+0x270 (/lib/x86_64-linux-gnu/ld-2.19.so) ls 3689/3689 [001] 2062.020966237: call 7f06a95885f0 _dl_sysdep_start+0x270 (/lib/x86_64-linux-gnu/ld-2.19.so) => 7f06a958ac50 strlen+0x0 (/lib/x86_64-linux-gnu/ld-2.19.so) ls 3689/3689 [001] 2062.020966237: jcc 7f06a958ac6e strlen+0x1e (/lib/x86_64-linux-gnu/ld-2.19.so) => 7f06a958ac60 strlen+0x10 (/lib/x86_64-linux-gnu/ld-2.19.so) ... Signed-off-by: Adrian Hunter Acked-by: Andi Kleen Tested-by: Arnaldo Carvalho de Melo Cc: Jiri Olsa Link: http://lkml.kernel.org/r/1466689258-28493-2-git-send-email-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/Documentation/perf-script.txt b/tools/perf/Documentation/perf-script.txt index 4f34379..a46030d 100644 --- a/tools/perf/Documentation/perf-script.txt +++ b/tools/perf/Documentation/perf-script.txt @@ -170,7 +170,12 @@ OPTIONS Trace decoding. The flags are "bcrosyiABEx" which stand for branch, call, return, conditional, system, asynchronous, interrupt, transaction abort, trace begin, trace end, and in transaction, - respectively. + respectively. Known combinations of flags are printed more nicely e.g. + "call" for "bc", "return" for "br", "jcc" for "bo", "jmp" for "b", + "int" for "bci", "iret" for "bri", "syscall" for "bcs", "sysret" for "brs", + "async" for "by", "hw int" for "bcyi", "tx abrt" for "bA", "tr strt" for "bB", + "tr end" for "bE". However the "x" flag will be display separately in those + cases e.g. "jcc (x)" for a condition branch within a transaction. Finally, a user may not set fields to none for all event types. i.e., -F "" is not allowed. diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c index 0e18e06..56b2fb8 100644 --- a/tools/perf/builtin-script.c +++ b/tools/perf/builtin-script.c @@ -606,13 +606,42 @@ static void print_sample_bts(struct perf_sample *sample, printf("\n"); } +static struct { + u32 flags; + const char *name; +} sample_flags[] = { + {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_CALL, "call"}, + {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_RETURN, "return"}, + {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_CONDITIONAL, "jcc"}, + {PERF_IP_FLAG_BRANCH, "jmp"}, + {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_CALL | PERF_IP_FLAG_INTERRUPT, "int"}, + {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_RETURN | PERF_IP_FLAG_INTERRUPT, "iret"}, + {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_CALL | PERF_IP_FLAG_SYSCALLRET, "syscall"}, + {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_RETURN | PERF_IP_FLAG_SYSCALLRET, "sysret"}, + {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_ASYNC, "async"}, + {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_CALL | PERF_IP_FLAG_ASYNC | PERF_IP_FLAG_INTERRUPT, "hw int"}, + {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_TX_ABORT, "tx abrt"}, + {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_TRACE_BEGIN, "tr strt"}, + {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_TRACE_END, "tr end"}, + {0, NULL} +}; + static void print_sample_flags(u32 flags) { const char *chars = PERF_IP_FLAG_CHARS; const int n = strlen(PERF_IP_FLAG_CHARS); + bool in_tx = flags & PERF_IP_FLAG_IN_TX; + const char *name = NULL; char str[33]; int i, pos = 0; + for (i = 0; sample_flags[i].name ; i++) { + if (sample_flags[i].flags == (flags & ~PERF_IP_FLAG_IN_TX)) { + name = sample_flags[i].name; + break; + } + } + for (i = 0; i < n; i++, flags >>= 1) { if (flags & 1) str[pos++] = chars[i]; @@ -622,7 +651,11 @@ static void print_sample_flags(u32 flags) str[pos++] = '?'; } str[pos] = 0; - printf(" %-4s ", str); + + if (name) + printf(" %-7s%4s ", name, in_tx ? "(x)" : ""); + else + printf(" %-11s ", str); } struct printer_data { -- cgit v0.10.2 From 50f736372d5ea0ce97ede698f957c9b141aa569e Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Thu, 23 Jun 2016 16:40:57 +0300 Subject: perf auxtrace: Add option to feed branches to the thread stack In preparation for using the thread stack to print an indent representing the stack depth in perf script, add an option to tell decoders to feed branches to the thread stack. Add support for that option to Intel PT and Intel BTS. The advantage of using the decoder to feed the thread stack is that it happens before branch filtering and so can be used with different itrace options (e.g. it still works when only showing calls, even though the thread stack needs to see calls and returns). Also it does not conflict with using the thread stack to get callchains. Signed-off-by: Adrian Hunter Acked-by: Andi Kleen Cc: Jiri Olsa Link: http://lkml.kernel.org/r/1466689258-28493-3-git-send-email-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/util/auxtrace.h b/tools/perf/util/auxtrace.h index 767989e..ac5f0d7 100644 --- a/tools/perf/util/auxtrace.h +++ b/tools/perf/util/auxtrace.h @@ -63,6 +63,7 @@ enum itrace_period_type { * @calls: limit branch samples to calls (can be combined with @returns) * @returns: limit branch samples to returns (can be combined with @calls) * @callchain: add callchain to 'instructions' events + * @thread_stack: feed branches to the thread_stack * @last_branch: add branch context to 'instruction' events * @callchain_sz: maximum callchain size * @last_branch_sz: branch context size @@ -82,6 +83,7 @@ struct itrace_synth_opts { bool calls; bool returns; bool callchain; + bool thread_stack; bool last_branch; unsigned int callchain_sz; unsigned int last_branch_sz; diff --git a/tools/perf/util/intel-bts.c b/tools/perf/util/intel-bts.c index ecec73f..749e6f2 100644 --- a/tools/perf/util/intel-bts.c +++ b/tools/perf/util/intel-bts.c @@ -422,7 +422,8 @@ static int intel_bts_get_branch_type(struct intel_bts_queue *btsq, } static int intel_bts_process_buffer(struct intel_bts_queue *btsq, - struct auxtrace_buffer *buffer) + struct auxtrace_buffer *buffer, + struct thread *thread) { struct branch *branch; size_t sz, bsz = sizeof(struct branch); @@ -444,6 +445,12 @@ static int intel_bts_process_buffer(struct intel_bts_queue *btsq, if (!branch->from && !branch->to) continue; intel_bts_get_branch_type(btsq, branch); + if (btsq->bts->synth_opts.thread_stack) + thread_stack__event(thread, btsq->sample_flags, + le64_to_cpu(branch->from), + le64_to_cpu(branch->to), + btsq->intel_pt_insn.length, + buffer->buffer_nr + 1); if (filter && !(filter & btsq->sample_flags)) continue; err = intel_bts_synth_branch_sample(btsq, branch); @@ -507,12 +514,13 @@ static int intel_bts_process_queue(struct intel_bts_queue *btsq, u64 *timestamp) goto out_put; } - if (!btsq->bts->synth_opts.callchain && thread && + if (!btsq->bts->synth_opts.callchain && + !btsq->bts->synth_opts.thread_stack && thread && (!old_buffer || btsq->bts->sampling_mode || (btsq->bts->snapshot_mode && !buffer->consecutive))) thread_stack__set_trace_nr(thread, buffer->buffer_nr + 1); - err = intel_bts_process_buffer(btsq, buffer); + err = intel_bts_process_buffer(btsq, buffer, thread); auxtrace_buffer__drop_data(buffer); @@ -905,10 +913,14 @@ int intel_bts_process_auxtrace_info(union perf_event *event, if (dump_trace) return 0; - if (session->itrace_synth_opts && session->itrace_synth_opts->set) + if (session->itrace_synth_opts && session->itrace_synth_opts->set) { bts->synth_opts = *session->itrace_synth_opts; - else + } else { itrace_synth_opts__set_default(&bts->synth_opts); + if (session->itrace_synth_opts) + bts->synth_opts.thread_stack = + session->itrace_synth_opts->thread_stack; + } if (bts->synth_opts.calls) bts->branches_filter |= PERF_IP_FLAG_CALL | PERF_IP_FLAG_ASYNC | diff --git a/tools/perf/util/intel-pt.c b/tools/perf/util/intel-pt.c index dc243b1..551ff6f 100644 --- a/tools/perf/util/intel-pt.c +++ b/tools/perf/util/intel-pt.c @@ -1234,7 +1234,7 @@ static int intel_pt_sample(struct intel_pt_queue *ptq) if (!(state->type & INTEL_PT_BRANCH)) return 0; - if (pt->synth_opts.callchain) + if (pt->synth_opts.callchain || pt->synth_opts.thread_stack) thread_stack__event(ptq->thread, ptq->flags, state->from_ip, state->to_ip, ptq->insn_len, state->trace_nr); @@ -2137,6 +2137,9 @@ int intel_pt_process_auxtrace_info(union perf_event *event, pt->synth_opts.branches = false; pt->synth_opts.callchain = true; } + if (session->itrace_synth_opts) + pt->synth_opts.thread_stack = + session->itrace_synth_opts->thread_stack; } if (pt->synth_opts.log) -- cgit v0.10.2 From e216708d982a1c262f411fee2fcac2bd9ec93a32 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Thu, 23 Jun 2016 16:40:58 +0300 Subject: perf script: Add callindent option Based on patches from Andi Kleen. When printing PT instruction traces with perf script it is rather useful to see some indentation for the call tree. This patch adds a new callindent field to perf script that prints spaces for the function call stack depth. We already have code to track the function call stack for PT, that we can reuse with minor modifications. The resulting output is not quite as nice as ftrace yet, but a lot better than what was there before. Note there are some corner cases when the thread stack gets code confused and prints incorrect indentation. Even with that it is fairly useful. When displaying kernel code traces it is recommended to run as root, as otherwise perf doesn't understand the kernel addresses properly, and may not reset the call stack correctly on kernel boundaries. Example output: sudo perf-with-kcore record eg2 -a -e intel_pt// -- sleep 1 sudo perf-with-kcore script eg2 --ns -F callindent,time,comm,pid,sym,ip,addr,flags,cpu --itrace=cre | less ... swapper 0 [000] 5830.389116586: call irq_exit ffffffff8104d620 smp_call_function_single_interrupt+0x30 => ffffffff8107e720 irq_exit swapper 0 [000] 5830.389116586: call idle_cpu ffffffff8107e769 irq_exit+0x49 => ffffffff810a3970 idle_cpu swapper 0 [000] 5830.389116586: return idle_cpu ffffffff810a39b7 idle_cpu+0x47 => ffffffff8107e76e irq_exit swapper 0 [000] 5830.389116586: call tick_nohz_irq_exit ffffffff8107e7bd irq_exit+0x9d => ffffffff810f2fc0 tick_nohz_irq_exit swapper 0 [000] 5830.389116919: call __tick_nohz_idle_enter ffffffff810f2fe0 tick_nohz_irq_exit+0x20 => ffffffff810f28d0 __tick_nohz_idle_enter swapper 0 [000] 5830.389116919: call ktime_get ffffffff810f28f1 __tick_nohz_idle_enter+0x21 => ffffffff810e9ec0 ktime_get swapper 0 [000] 5830.389116919: call read_tsc ffffffff810e9ef6 ktime_get+0x36 => ffffffff81035070 read_tsc swapper 0 [000] 5830.389116919: return read_tsc ffffffff81035084 read_tsc+0x14 => ffffffff810e9efc ktime_get swapper 0 [000] 5830.389116919: return ktime_get ffffffff810e9f46 ktime_get+0x86 => ffffffff810f28f6 __tick_nohz_idle_enter swapper 0 [000] 5830.389116919: call sched_clock_idle_sleep_event ffffffff810f290b __tick_nohz_idle_enter+0x3b => ffffffff810a7380 sched_clock_idle_sleep_event swapper 0 [000] 5830.389116919: call sched_clock_cpu ffffffff810a738b sched_clock_idle_sleep_event+0xb => ffffffff810a72e0 sched_clock_cpu swapper 0 [000] 5830.389116919: call sched_clock ffffffff810a734d sched_clock_cpu+0x6d => ffffffff81035750 sched_clock swapper 0 [000] 5830.389116919: call native_sched_clock ffffffff81035754 sched_clock+0x4 => ffffffff81035640 native_sched_clock swapper 0 [000] 5830.389116919: return native_sched_clock ffffffff8103568c native_sched_clock+0x4c => ffffffff81035759 sched_clock swapper 0 [000] 5830.389116919: return sched_clock ffffffff8103575c sched_clock+0xc => ffffffff810a7352 sched_clock_cpu swapper 0 [000] 5830.389116919: return sched_clock_cpu ffffffff810a7356 sched_clock_cpu+0x76 => ffffffff810a7390 sched_clock_idle_sleep_event swapper 0 [000] 5830.389116919: return sched_clock_idle_sleep_event ffffffff810a7391 sched_clock_idle_sleep_event+0x11 => ffffffff810f2910 __tick_nohz_idle_enter ... Signed-off-by: Adrian Hunter Acked-by: Andi Kleen Tested-by: Arnaldo Carvalho de Melo Cc: Jiri Olsa Link: http://lkml.kernel.org/r/1466689258-28493-4-git-send-email-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/Documentation/perf-script.txt b/tools/perf/Documentation/perf-script.txt index a46030d..1f6c705 100644 --- a/tools/perf/Documentation/perf-script.txt +++ b/tools/perf/Documentation/perf-script.txt @@ -177,6 +177,10 @@ OPTIONS "tr end" for "bE". However the "x" flag will be display separately in those cases e.g. "jcc (x)" for a condition branch within a transaction. + The callindent field is synthesized and may have a value when + Instruction Trace decoding. For calls and returns, it will display the + name of the symbol indented with spaces to reflect the stack depth. + Finally, a user may not set fields to none for all event types. i.e., -F "" is not allowed. diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c index 56b2fb8..971ff91 100644 --- a/tools/perf/builtin-script.c +++ b/tools/perf/builtin-script.c @@ -21,6 +21,7 @@ #include "util/cpumap.h" #include "util/thread_map.h" #include "util/stat.h" +#include "util/thread-stack.h" #include #include #include "asm/bug.h" @@ -63,6 +64,7 @@ enum perf_output_field { PERF_OUTPUT_DATA_SRC = 1U << 17, PERF_OUTPUT_WEIGHT = 1U << 18, PERF_OUTPUT_BPF_OUTPUT = 1U << 19, + PERF_OUTPUT_CALLINDENT = 1U << 20, }; struct output_option { @@ -89,6 +91,7 @@ struct output_option { {.str = "data_src", .field = PERF_OUTPUT_DATA_SRC}, {.str = "weight", .field = PERF_OUTPUT_WEIGHT}, {.str = "bpf-output", .field = PERF_OUTPUT_BPF_OUTPUT}, + {.str = "callindent", .field = PERF_OUTPUT_CALLINDENT}, }; /* default set to maintain compatibility with current format */ @@ -562,6 +565,62 @@ static void print_sample_addr(struct perf_sample *sample, } } +static void print_sample_callindent(struct perf_sample *sample, + struct perf_evsel *evsel, + struct thread *thread, + struct addr_location *al) +{ + struct perf_event_attr *attr = &evsel->attr; + size_t depth = thread_stack__depth(thread); + struct addr_location addr_al; + const char *name = NULL; + static int spacing; + int len = 0; + u64 ip = 0; + + /* + * The 'return' has already been popped off the stack so the depth has + * to be adjusted to match the 'call'. + */ + if (thread->ts && sample->flags & PERF_IP_FLAG_RETURN) + depth += 1; + + if (sample->flags & (PERF_IP_FLAG_CALL | PERF_IP_FLAG_TRACE_BEGIN)) { + if (sample_addr_correlates_sym(attr)) { + thread__resolve(thread, &addr_al, sample); + if (addr_al.sym) + name = addr_al.sym->name; + else + ip = sample->addr; + } else { + ip = sample->addr; + } + } else if (sample->flags & (PERF_IP_FLAG_RETURN | PERF_IP_FLAG_TRACE_END)) { + if (al->sym) + name = al->sym->name; + else + ip = sample->ip; + } + + if (name) + len = printf("%*s%s", (int)depth * 4, "", name); + else if (ip) + len = printf("%*s%16" PRIx64, (int)depth * 4, "", ip); + + if (len < 0) + return; + + /* + * Try to keep the output length from changing frequently so that the + * output lines up more nicely. + */ + if (len > spacing || (len && len < spacing - 52)) + spacing = round_up(len + 4, 32); + + if (len < spacing) + printf("%*s", spacing - len, ""); +} + static void print_sample_bts(struct perf_sample *sample, struct perf_evsel *evsel, struct thread *thread, @@ -570,6 +629,9 @@ static void print_sample_bts(struct perf_sample *sample, struct perf_event_attr *attr = &evsel->attr; bool print_srcline_last = false; + if (PRINT_FIELD(CALLINDENT)) + print_sample_callindent(sample, evsel, thread, al); + /* print branch_from information */ if (PRINT_FIELD(IP)) { unsigned int print_opts = output[attr->type].print_ip_opts; @@ -2053,7 +2115,8 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused) "comma separated output fields prepend with 'type:'. " "Valid types: hw,sw,trace,raw. " "Fields: comm,tid,pid,time,cpu,event,trace,ip,sym,dso," - "addr,symoff,period,iregs,brstack,brstacksym,flags", parse_output_fields), + "addr,symoff,period,iregs,brstack,brstacksym,flags," + "callindent", parse_output_fields), OPT_BOOLEAN('a', "all-cpus", &system_wide, "system-wide collection from all CPUs"), OPT_STRING('S', "symbols", &symbol_conf.sym_list_str, "symbol[,symbol...]", @@ -2292,6 +2355,9 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused) script.session = session; script__setup_sample_type(&script); + if (output[PERF_TYPE_HARDWARE].fields & PERF_OUTPUT_CALLINDENT) + itrace_synth_opts.thread_stack = true; + session->itrace_synth_opts = &itrace_synth_opts; if (cpu_list) { diff --git a/tools/perf/util/thread-stack.c b/tools/perf/util/thread-stack.c index 825086a..d330152 100644 --- a/tools/perf/util/thread-stack.c +++ b/tools/perf/util/thread-stack.c @@ -616,3 +616,10 @@ int thread_stack__process(struct thread *thread, struct comm *comm, return err; } + +size_t thread_stack__depth(struct thread *thread) +{ + if (!thread->ts) + return 0; + return thread->ts->cnt; +} diff --git a/tools/perf/util/thread-stack.h b/tools/perf/util/thread-stack.h index ad44c79..b7e41c4 100644 --- a/tools/perf/util/thread-stack.h +++ b/tools/perf/util/thread-stack.h @@ -87,6 +87,7 @@ void thread_stack__sample(struct thread *thread, struct ip_callchain *chain, size_t sz, u64 ip); int thread_stack__flush(struct thread *thread); void thread_stack__free(struct thread *thread); +size_t thread_stack__depth(struct thread *thread); struct call_return_processor * call_return_processor__new(int (*process)(struct call_return *cr, void *data), -- cgit v0.10.2 From 8a0a9c7e9146781defc96f6743e7ee14ccc9ab23 Mon Sep 17 00:00:00 2001 From: Taeung Song Date: Thu, 23 Jun 2016 23:14:31 +0900 Subject: perf config: Introduce new init() and exit() Many sub-commands use perf_config() but everytime perf_config() is called, perf_config() always read config files. (i.e. user config '~/.perfconfig' and system config '$(sysconfdir)/perfconfig') But it is better to use the config set that already contains all config key-value pairs to avoid this repetitive work reading the config files in perf_config(). (the config set mean a static variable 'config_set') In other words, if new perf_config__init() is called, only first time 'config_set' is initialized collecting all configs from the config files. And then we could use new perf_config() like old perf_config(). When a sub-command finished, free the config set by perf_config__exit() at run_builtin(). If we do, 'config_set' can be reused wherever perf_config() is called and a feature of old perf_config() is the same as new perf_config() work without the repetitive work that read the config files. In summary, in order to use features about configuration, we can call the functions at perf.c and other source files as below. # initialize a config set perf_config__init() # configure actual variables from a config set perf_config() # eliminate allocated config set perf_config__exit() # destroy existing config set and initialize a new config set. perf_config__refresh() Signed-off-by: Taeung Song Cc: Alexander Shishkin Cc: Jiri Olsa Cc: Masami Hiramatsu Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Wang Nan Link: http://lkml.kernel.org/r/1466691272-24117-3-git-send-email-treeze.taeung@gmail.com [ 'init' counterpart is 'exit', not 'finish' ] Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/builtin-config.c b/tools/perf/builtin-config.c index fe1b77f..cfd1036 100644 --- a/tools/perf/builtin-config.c +++ b/tools/perf/builtin-config.c @@ -80,6 +80,10 @@ int cmd_config(int argc, const char **argv, const char *prefix __maybe_unused) else if (use_user_config) config_exclusive_filename = user_config; + /* + * At only 'config' sub-command, individually use the config set + * because of reinitializing with options config file location. + */ set = perf_config_set__new(); if (!set) { ret = -1; diff --git a/tools/perf/perf.c b/tools/perf/perf.c index 66772da..8f21922 100644 --- a/tools/perf/perf.c +++ b/tools/perf/perf.c @@ -355,6 +355,7 @@ static int run_builtin(struct cmd_struct *p, int argc, const char **argv) perf_env__set_cmdline(&perf_env, argc, argv); status = p->fn(argc, argv, prefix); + perf_config__exit(); exit_browser(status); perf_env__exit(&perf_env); bpf__clear(); @@ -522,6 +523,7 @@ int main(int argc, const char **argv) srandom(time(NULL)); + perf_config__init(); perf_config(perf_default_config, NULL); set_buildid_dir(NULL); diff --git a/tools/perf/util/config.c b/tools/perf/util/config.c index d15c592..18dae74 100644 --- a/tools/perf/util/config.c +++ b/tools/perf/util/config.c @@ -26,6 +26,7 @@ static FILE *config_file; static const char *config_file_name; static int config_linenr; static int config_file_eof; +static struct perf_config_set *config_set; const char *config_exclusive_filename; @@ -478,51 +479,6 @@ static int perf_config_global(void) return !perf_env_bool("PERF_CONFIG_NOGLOBAL", 0); } -int perf_config(config_fn_t fn, void *data) -{ - int ret = -1; - const char *home = NULL; - - /* Setting $PERF_CONFIG makes perf read _only_ the given config file. */ - if (config_exclusive_filename) - return perf_config_from_file(fn, config_exclusive_filename, data); - if (perf_config_system() && !access(perf_etc_perfconfig(), R_OK)) { - if (perf_config_from_file(fn, perf_etc_perfconfig(), data) < 0) - goto out; - } - - home = getenv("HOME"); - if (perf_config_global() && home) { - char *user_config = strdup(mkpath("%s/.perfconfig", home)); - struct stat st; - - if (user_config == NULL) { - warning("Not enough memory to process %s/.perfconfig, " - "ignoring it.", home); - goto out; - } - - if (stat(user_config, &st) < 0) - goto out_free; - - if (st.st_uid && (st.st_uid != geteuid())) { - warning("File %s not owned by current user or root, " - "ignoring it.", user_config); - goto out_free; - } - - if (!st.st_size) - goto out_free; - - ret = perf_config_from_file(fn, user_config, data); - -out_free: - free(user_config); - } -out: - return ret; -} - static struct perf_config_section *find_section(struct list_head *sections, const char *section_name) { @@ -706,6 +662,52 @@ struct perf_config_set *perf_config_set__new(void) return set; } +int perf_config(config_fn_t fn, void *data) +{ + int ret = 0; + char key[BUFSIZ]; + struct perf_config_section *section; + struct perf_config_item *item; + + if (config_set == NULL) + return -1; + + perf_config_set__for_each_entry(config_set, section, item) { + char *value = item->value; + + if (value) { + scnprintf(key, sizeof(key), "%s.%s", + section->name, item->name); + ret = fn(key, value, data); + if (ret < 0) { + pr_err("Error: wrong config key-value pair %s=%s\n", + key, value); + break; + } + } + } + + return ret; +} + +void perf_config__init(void) +{ + if (config_set == NULL) + config_set = perf_config_set__new(); +} + +void perf_config__exit(void) +{ + perf_config_set__delete(config_set); + config_set = NULL; +} + +void perf_config__refresh(void) +{ + perf_config__exit(); + perf_config__init(); +} + static void perf_config_item__delete(struct perf_config_item *item) { zfree(&item->name); diff --git a/tools/perf/util/config.h b/tools/perf/util/config.h index 155a441..6f813d4 100644 --- a/tools/perf/util/config.h +++ b/tools/perf/util/config.h @@ -33,5 +33,34 @@ const char *perf_etc_perfconfig(void); struct perf_config_set *perf_config_set__new(void); void perf_config_set__delete(struct perf_config_set *set); +void perf_config__init(void); +void perf_config__exit(void); +void perf_config__refresh(void); + +/** + * perf_config_sections__for_each - iterate thru all the sections + * @list: list_head instance to iterate + * @section: struct perf_config_section iterator + */ +#define perf_config_sections__for_each_entry(list, section) \ + list_for_each_entry(section, list, node) + +/** + * perf_config_items__for_each - iterate thru all the items + * @list: list_head instance to iterate + * @item: struct perf_config_item iterator + */ +#define perf_config_items__for_each_entry(list, item) \ + list_for_each_entry(item, list, node) + +/** + * perf_config_set__for_each - iterate thru all the config section-item pairs + * @set: evlist instance to iterate + * @section: struct perf_config_section iterator + * @item: struct perf_config_item iterator + */ +#define perf_config_set__for_each_entry(set, section, item) \ + perf_config_sections__for_each_entry(&set->sections, section) \ + perf_config_items__for_each_entry(§ion->items, item) #endif /* __PERF_CONFIG_H */ -- cgit v0.10.2 From 4a35b3497c413de8b409f9d75700eeb4772b21b8 Mon Sep 17 00:00:00 2001 From: Taeung Song Date: Thu, 23 Jun 2016 23:14:32 +0900 Subject: perf config: Reimplement show_config() using config_set__for_each Recently config_set__for_each got added. In order to let show_config() be short and clear, rewrite this function using it. Signed-off-by: Taeung Song Cc: Alexander Shishkin Cc: Jiri Olsa Cc: Masami Hiramatsu Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Wang Nan Link: http://lkml.kernel.org/r/1466691272-24117-4-git-send-email-treeze.taeung@gmail.com Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/builtin-config.c b/tools/perf/builtin-config.c index cfd1036..e4207a2 100644 --- a/tools/perf/builtin-config.c +++ b/tools/perf/builtin-config.c @@ -37,23 +37,16 @@ static int show_config(struct perf_config_set *set) { struct perf_config_section *section; struct perf_config_item *item; - struct list_head *sections; if (set == NULL) return -1; - sections = &set->sections; - if (list_empty(sections)) - return -1; - - list_for_each_entry(section, sections, node) { - list_for_each_entry(item, §ion->items, node) { - char *value = item->value; + perf_config_set__for_each_entry(set, section, item) { + char *value = item->value; - if (value) - printf("%s.%s=%s\n", section->name, - item->name, value); - } + if (value) + printf("%s.%s=%s\n", section->name, + item->name, value); } return 0; -- cgit v0.10.2 From b7271b9f3e18181559b96a610f4e42bdb04b07f5 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Wed, 22 Jun 2016 11:16:49 +0200 Subject: locking/atomic, arch/tile: Fix tilepro build The tilepro change wasn't ever compiled it seems (the 0day built bot also doesn't have a toolchain for it). Make it work. The thing that makes the patch bigger than desired is namespace collision with the C11 __atomic builtin functions. So rename the tilepro functions to __atomic32. Reported-by: Sudip Mukherjee Signed-off-by: Peter Zijlstra (Intel) Acked-by: Chris Metcalf Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Stephen Rothwell Cc: Thomas Gleixner Fixes: 1af5de9af138 ("locking/atomic, arch/tile: Implement atomic{,64}_fetch_{add,sub,and,or,xor}()") Link: http://lkml.kernel.org/r/20160622091649.GB30154@twins.programming.kicks-ass.net Signed-off-by: Ingo Molnar diff --git a/arch/tile/include/asm/atomic_32.h b/arch/tile/include/asm/atomic_32.h index da8eb4e..a937742 100644 --- a/arch/tile/include/asm/atomic_32.h +++ b/arch/tile/include/asm/atomic_32.h @@ -143,15 +143,15 @@ static inline void atomic64_##op(long long i, atomic64_t *v) \ { \ _atomic64_fetch_##op(&v->counter, i); \ } \ -static inline void atomic64_##op(long long i, atomic64_t *v) \ +static inline long long atomic64_fetch_##op(long long i, atomic64_t *v) \ { \ smp_mb(); \ return _atomic64_fetch_##op(&v->counter, i); \ } -ATOMIC64_OP(and) -ATOMIC64_OP(or) -ATOMIC64_OP(xor) +ATOMIC64_OPS(and) +ATOMIC64_OPS(or) +ATOMIC64_OPS(xor) #undef ATOMIC64_OPS @@ -266,16 +266,16 @@ struct __get_user { unsigned long val; int err; }; -extern struct __get_user __atomic_cmpxchg(volatile int *p, +extern struct __get_user __atomic32_cmpxchg(volatile int *p, int *lock, int o, int n); -extern struct __get_user __atomic_xchg(volatile int *p, int *lock, int n); -extern struct __get_user __atomic_xchg_add(volatile int *p, int *lock, int n); -extern struct __get_user __atomic_xchg_add_unless(volatile int *p, +extern struct __get_user __atomic32_xchg(volatile int *p, int *lock, int n); +extern struct __get_user __atomic32_xchg_add(volatile int *p, int *lock, int n); +extern struct __get_user __atomic32_xchg_add_unless(volatile int *p, int *lock, int o, int n); -extern struct __get_user __atomic_fetch_or(volatile int *p, int *lock, int n); -extern struct __get_user __atomic_fetch_and(volatile int *p, int *lock, int n); -extern struct __get_user __atomic_fetch_andn(volatile int *p, int *lock, int n); -extern struct __get_user __atomic_fetch_xor(volatile int *p, int *lock, int n); +extern struct __get_user __atomic32_fetch_or(volatile int *p, int *lock, int n); +extern struct __get_user __atomic32_fetch_and(volatile int *p, int *lock, int n); +extern struct __get_user __atomic32_fetch_andn(volatile int *p, int *lock, int n); +extern struct __get_user __atomic32_fetch_xor(volatile int *p, int *lock, int n); extern long long __atomic64_cmpxchg(volatile long long *p, int *lock, long long o, long long n); extern long long __atomic64_xchg(volatile long long *p, int *lock, long long n); diff --git a/arch/tile/include/asm/futex.h b/arch/tile/include/asm/futex.h index 1a6ef1b..e64a1b7 100644 --- a/arch/tile/include/asm/futex.h +++ b/arch/tile/include/asm/futex.h @@ -80,16 +80,16 @@ ret = gu.err; \ } -#define __futex_set() __futex_call(__atomic_xchg) -#define __futex_add() __futex_call(__atomic_xchg_add) -#define __futex_or() __futex_call(__atomic_or) -#define __futex_andn() __futex_call(__atomic_andn) -#define __futex_xor() __futex_call(__atomic_xor) +#define __futex_set() __futex_call(__atomic32_xchg) +#define __futex_add() __futex_call(__atomic32_xchg_add) +#define __futex_or() __futex_call(__atomic32_fetch_or) +#define __futex_andn() __futex_call(__atomic32_fetch_andn) +#define __futex_xor() __futex_call(__atomic32_fetch_xor) #define __futex_cmpxchg() \ { \ - struct __get_user gu = __atomic_cmpxchg((u32 __force *)uaddr, \ - lock, oldval, oparg); \ + struct __get_user gu = __atomic32_cmpxchg((u32 __force *)uaddr, \ + lock, oldval, oparg); \ val = gu.val; \ ret = gu.err; \ } diff --git a/arch/tile/lib/atomic_32.c b/arch/tile/lib/atomic_32.c index 5b6bd93..f812880 100644 --- a/arch/tile/lib/atomic_32.c +++ b/arch/tile/lib/atomic_32.c @@ -61,13 +61,13 @@ static inline int *__atomic_setup(volatile void *v) int _atomic_xchg(int *v, int n) { - return __atomic_xchg(v, __atomic_setup(v), n).val; + return __atomic32_xchg(v, __atomic_setup(v), n).val; } EXPORT_SYMBOL(_atomic_xchg); int _atomic_xchg_add(int *v, int i) { - return __atomic_xchg_add(v, __atomic_setup(v), i).val; + return __atomic32_xchg_add(v, __atomic_setup(v), i).val; } EXPORT_SYMBOL(_atomic_xchg_add); @@ -78,37 +78,37 @@ int _atomic_xchg_add_unless(int *v, int a, int u) * to use the first argument consistently as the "old value" * in the assembly, as is done for _atomic_cmpxchg(). */ - return __atomic_xchg_add_unless(v, __atomic_setup(v), u, a).val; + return __atomic32_xchg_add_unless(v, __atomic_setup(v), u, a).val; } EXPORT_SYMBOL(_atomic_xchg_add_unless); int _atomic_cmpxchg(int *v, int o, int n) { - return __atomic_cmpxchg(v, __atomic_setup(v), o, n).val; + return __atomic32_cmpxchg(v, __atomic_setup(v), o, n).val; } EXPORT_SYMBOL(_atomic_cmpxchg); unsigned long _atomic_fetch_or(volatile unsigned long *p, unsigned long mask) { - return __atomic_fetch_or((int *)p, __atomic_setup(p), mask).val; + return __atomic32_fetch_or((int *)p, __atomic_setup(p), mask).val; } EXPORT_SYMBOL(_atomic_fetch_or); unsigned long _atomic_fetch_and(volatile unsigned long *p, unsigned long mask) { - return __atomic_fetch_and((int *)p, __atomic_setup(p), mask).val; + return __atomic32_fetch_and((int *)p, __atomic_setup(p), mask).val; } EXPORT_SYMBOL(_atomic_fetch_and); unsigned long _atomic_fetch_andn(volatile unsigned long *p, unsigned long mask) { - return __atomic_fetch_andn((int *)p, __atomic_setup(p), mask).val; + return __atomic32_fetch_andn((int *)p, __atomic_setup(p), mask).val; } EXPORT_SYMBOL(_atomic_fetch_andn); unsigned long _atomic_fetch_xor(volatile unsigned long *p, unsigned long mask) { - return __atomic_fetch_xor((int *)p, __atomic_setup(p), mask).val; + return __atomic32_fetch_xor((int *)p, __atomic_setup(p), mask).val; } EXPORT_SYMBOL(_atomic_fetch_xor); diff --git a/arch/tile/lib/atomic_asm_32.S b/arch/tile/lib/atomic_asm_32.S index 507abdd..1a70e6c 100644 --- a/arch/tile/lib/atomic_asm_32.S +++ b/arch/tile/lib/atomic_asm_32.S @@ -172,15 +172,20 @@ STD_ENTRY_SECTION(__atomic\name, .text.atomic) .endif .endm -atomic_op _cmpxchg, 32, "seq r26, r22, r2; { bbns r26, 3f; move r24, r3 }" -atomic_op _xchg, 32, "move r24, r2" -atomic_op _xchg_add, 32, "add r24, r22, r2" -atomic_op _xchg_add_unless, 32, \ + +/* + * Use __atomic32 prefix to avoid collisions with GCC builtin __atomic functions. + */ + +atomic_op 32_cmpxchg, 32, "seq r26, r22, r2; { bbns r26, 3f; move r24, r3 }" +atomic_op 32_xchg, 32, "move r24, r2" +atomic_op 32_xchg_add, 32, "add r24, r22, r2" +atomic_op 32_xchg_add_unless, 32, \ "sne r26, r22, r2; { bbns r26, 3f; add r24, r22, r3 }" -atomic_op _fetch_or, 32, "or r24, r22, r2" -atomic_op _fetch_and, 32, "and r24, r22, r2" -atomic_op _fetch_andn, 32, "nor r2, r2, zero; and r24, r22, r2" -atomic_op _fetch_xor, 32, "xor r24, r22, r2" +atomic_op 32_fetch_or, 32, "or r24, r22, r2" +atomic_op 32_fetch_and, 32, "and r24, r22, r2" +atomic_op 32_fetch_andn, 32, "nor r2, r2, zero; and r24, r22, r2" +atomic_op 32_fetch_xor, 32, "xor r24, r22, r2" atomic_op 64_cmpxchg, 64, "{ seq r26, r22, r2; seq r27, r23, r3 }; \ { bbns r26, 3f; move r24, r4 }; { bbns r27, 3f; move r25, r5 }" -- cgit v0.10.2 From ba360fd040e3417ed1d90e89d681698f82002207 Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Mon, 2 May 2016 19:36:13 +0100 Subject: nvmem: mtk-efuse: remove nvmem regmap dependency Regmap raw accessors are bus specific implementations, using regmap raw apis in nvmem breaks nvmem providers based on regmap mmio. This patch moves to nvmem support in the driver to use callback instead of regmap, which is what the nvmem core supports now. Signed-off-by: Srinivas Kandagatla Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/nvmem/Kconfig b/drivers/nvmem/Kconfig index 3041d48..5ff2189 100644 --- a/drivers/nvmem/Kconfig +++ b/drivers/nvmem/Kconfig @@ -50,7 +50,6 @@ config MTK_EFUSE tristate "Mediatek SoCs EFUSE support" depends on ARCH_MEDIATEK || COMPILE_TEST depends on HAS_IOMEM - select REGMAP_MMIO help This is a driver to access hardware related data like sensor calibration, HDMI impedance etc. diff --git a/drivers/nvmem/mtk-efuse.c b/drivers/nvmem/mtk-efuse.c index 9c49369..32fd572 100644 --- a/drivers/nvmem/mtk-efuse.c +++ b/drivers/nvmem/mtk-efuse.c @@ -14,15 +14,35 @@ #include #include +#include #include #include -#include -static struct regmap_config mtk_regmap_config = { - .reg_bits = 32, - .val_bits = 32, - .reg_stride = 4, -}; +static int mtk_reg_read(void *context, + unsigned int reg, void *_val, size_t bytes) +{ + void __iomem *base = context; + u32 *val = _val; + int i = 0, words = bytes / 4; + + while (words--) + *val++ = readl(base + reg + (i++ * 4)); + + return 0; +} + +static int mtk_reg_write(void *context, + unsigned int reg, void *_val, size_t bytes) +{ + void __iomem *base = context; + u32 *val = _val; + int i = 0, words = bytes / 4; + + while (words--) + writel(*val++, base + reg + (i++ * 4)); + + return 0; +} static int mtk_efuse_probe(struct platform_device *pdev) { @@ -30,7 +50,6 @@ static int mtk_efuse_probe(struct platform_device *pdev) struct resource *res; struct nvmem_device *nvmem; struct nvmem_config *econfig; - struct regmap *regmap; void __iomem *base; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); @@ -42,14 +61,12 @@ static int mtk_efuse_probe(struct platform_device *pdev) if (!econfig) return -ENOMEM; - mtk_regmap_config.max_register = resource_size(res) - 1; - - regmap = devm_regmap_init_mmio(dev, base, &mtk_regmap_config); - if (IS_ERR(regmap)) { - dev_err(dev, "regmap init failed\n"); - return PTR_ERR(regmap); - } - + econfig->stride = 4; + econfig->word_size = 4; + econfig->reg_read = mtk_reg_read; + econfig->reg_write = mtk_reg_write; + econfig->size = resource_size(res); + econfig->priv = base; econfig->dev = dev; econfig->owner = THIS_MODULE; nvmem = nvmem_register(econfig); -- cgit v0.10.2 From 7d8867d71fba7604e5d6417e5cbd68a6ffd85bb4 Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Mon, 2 May 2016 19:36:14 +0100 Subject: nvmem: mxs-ocotp: remove nvmem regmap dependency Regmap raw accessors are bus specific implementations, using regmap raw apis in nvmem breaks nvmem providers based on regmap mmio. This patch moves to nvmem support in the driver to use callback instead of regmap, which is what the nvmem core supports now. Signed-off-by: Srinivas Kandagatla Acked-by: Stefan Wahren Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/nvmem/mxs-ocotp.c b/drivers/nvmem/mxs-ocotp.c index 2bb3c57..d26dd03 100644 --- a/drivers/nvmem/mxs-ocotp.c +++ b/drivers/nvmem/mxs-ocotp.c @@ -25,7 +25,6 @@ #include #include #include -#include #include #include @@ -66,11 +65,10 @@ static int mxs_ocotp_wait(struct mxs_ocotp *otp) return 0; } -static int mxs_ocotp_read(void *context, const void *reg, size_t reg_size, - void *val, size_t val_size) +static int mxs_ocotp_read(void *context, unsigned int offset, + void *val, size_t bytes) { struct mxs_ocotp *otp = context; - unsigned int offset = *(u32 *)reg; u32 *buf = val; int ret; @@ -94,17 +92,16 @@ static int mxs_ocotp_read(void *context, const void *reg, size_t reg_size, if (ret) goto close_banks; - while (val_size >= reg_size) { + while (bytes) { if ((offset < OCOTP_DATA_OFFSET) || (offset % 16)) { /* fill up non-data register */ - *buf = 0; + *buf++ = 0; } else { - *buf = readl(otp->base + offset); + *buf++ = readl(otp->base + offset); } - buf++; - val_size -= reg_size; - offset += reg_size; + bytes -= 4; + offset += 4; } close_banks: @@ -117,57 +114,29 @@ disable_clk: return ret; } -static int mxs_ocotp_write(void *context, const void *data, size_t count) -{ - /* We don't want to support writing */ - return 0; -} - -static bool mxs_ocotp_writeable_reg(struct device *dev, unsigned int reg) -{ - return false; -} - static struct nvmem_config ocotp_config = { .name = "mxs-ocotp", + .stride = 16, + .word_size = 4, .owner = THIS_MODULE, + .reg_read = mxs_ocotp_read, }; -static const struct regmap_range imx23_ranges[] = { - regmap_reg_range(OCOTP_DATA_OFFSET, 0x210), -}; - -static const struct regmap_access_table imx23_access = { - .yes_ranges = imx23_ranges, - .n_yes_ranges = ARRAY_SIZE(imx23_ranges), -}; - -static const struct regmap_range imx28_ranges[] = { - regmap_reg_range(OCOTP_DATA_OFFSET, 0x290), -}; - -static const struct regmap_access_table imx28_access = { - .yes_ranges = imx28_ranges, - .n_yes_ranges = ARRAY_SIZE(imx28_ranges), +struct mxs_data { + int size; }; -static struct regmap_bus mxs_ocotp_bus = { - .read = mxs_ocotp_read, - .write = mxs_ocotp_write, /* make regmap_init() happy */ - .reg_format_endian_default = REGMAP_ENDIAN_NATIVE, - .val_format_endian_default = REGMAP_ENDIAN_NATIVE, +static const struct mxs_data imx23_data = { + .size = 0x220, }; -static struct regmap_config mxs_ocotp_config = { - .reg_bits = 32, - .val_bits = 32, - .reg_stride = 16, - .writeable_reg = mxs_ocotp_writeable_reg, +static const struct mxs_data imx28_data = { + .size = 0x2a0, }; static const struct of_device_id mxs_ocotp_match[] = { - { .compatible = "fsl,imx23-ocotp", .data = &imx23_access }, - { .compatible = "fsl,imx28-ocotp", .data = &imx28_access }, + { .compatible = "fsl,imx23-ocotp", .data = &imx23_data }, + { .compatible = "fsl,imx28-ocotp", .data = &imx28_data }, { /* sentinel */}, }; MODULE_DEVICE_TABLE(of, mxs_ocotp_match); @@ -175,11 +144,10 @@ MODULE_DEVICE_TABLE(of, mxs_ocotp_match); static int mxs_ocotp_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; + const struct mxs_data *data; struct mxs_ocotp *otp; struct resource *res; const struct of_device_id *match; - struct regmap *regmap; - const struct regmap_access_table *access; int ret; match = of_match_device(dev->driver->of_match_table, dev); @@ -205,17 +173,10 @@ static int mxs_ocotp_probe(struct platform_device *pdev) return ret; } - access = match->data; - mxs_ocotp_config.rd_table = access; - mxs_ocotp_config.max_register = access->yes_ranges[0].range_max; - - regmap = devm_regmap_init(dev, &mxs_ocotp_bus, otp, &mxs_ocotp_config); - if (IS_ERR(regmap)) { - dev_err(dev, "regmap init failed\n"); - ret = PTR_ERR(regmap); - goto err_clk; - } + data = match->data; + ocotp_config.size = data->size; + ocotp_config.priv = otp; ocotp_config.dev = dev; otp->nvmem = nvmem_register(&ocotp_config); if (IS_ERR(otp->nvmem)) { -- cgit v0.10.2 From deb319705e7eb60a870e24f75ff8d6452372e350 Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Thu, 2 Jun 2016 12:05:11 +0100 Subject: nvmem: imx-ocotp: handling clock Before access ocotp nvmem area, the clock should be enabled. Or, `hexdump nvmem` will hang the system. So, use such flow: " 1. clock_enable_prepare 2. read nvmem ocotp area 3. clock_disable_unprepare " Signed-off-by: Peng Fan Cc: Srinivas Kandagatla Cc: Maxime Ripard Cc: Shawn Guo Signed-off-by: Srinivas Kandagatla Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/nvmem/imx-ocotp.c b/drivers/nvmem/imx-ocotp.c index 75e66ef..a340390 100644 --- a/drivers/nvmem/imx-ocotp.c +++ b/drivers/nvmem/imx-ocotp.c @@ -15,6 +15,7 @@ * http://www.gnu.org/copyleft/gpl.html */ +#include #include #include #include @@ -26,6 +27,7 @@ struct ocotp_priv { struct device *dev; + struct clk *clk; void __iomem *base; unsigned int nregs; }; @@ -36,7 +38,7 @@ static int imx_ocotp_read(void *context, unsigned int offset, struct ocotp_priv *priv = context; unsigned int count; u32 *buf = val; - int i; + int i, ret; u32 index; index = offset >> 2; @@ -45,9 +47,16 @@ static int imx_ocotp_read(void *context, unsigned int offset, if (count > (priv->nregs - index)) count = priv->nregs - index; + ret = clk_prepare_enable(priv->clk); + if (ret < 0) { + dev_err(priv->dev, "failed to prepare/enable ocotp clk\n"); + return ret; + } for (i = index; i < (index + count); i++) *buf++ = readl(priv->base + 0x400 + i * 0x10); + clk_disable_unprepare(priv->clk); + return 0; } @@ -85,6 +94,10 @@ static int imx_ocotp_probe(struct platform_device *pdev) if (IS_ERR(priv->base)) return PTR_ERR(priv->base); + priv->clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(priv->clk)) + return PTR_ERR(priv->clk); + of_id = of_match_device(imx_ocotp_dt_ids, dev); priv->nregs = (unsigned int)of_id->data; imx_ocotp_nvmem_config.size = 4 * priv->nregs; -- cgit v0.10.2 From a6c50912508d80164a5e607993b617be85a46d73 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Thu, 2 Jun 2016 12:05:12 +0100 Subject: nvmem: Declare nvmem_cell_read() consistently nvmem_cell_read() is declared as void * if CONFIG_NVMEM is enabled, and as char * otherwise. This can result in a build warning if CONFIG_NVMEM is not enabled and a caller asigns the result to a type other than char * without using a typecast. Use a consistent declaration to avoid the problem. Fixes: e2a5402ec7c6 ("nvmem: Add nvmem_device based consumer apis.") Cc: Srinivas Kandagatla Signed-off-by: Guenter Roeck Signed-off-by: Srinivas Kandagatla Signed-off-by: Greg Kroah-Hartman diff --git a/include/linux/nvmem-consumer.h b/include/linux/nvmem-consumer.h index 9bb77d3..c2256d7 100644 --- a/include/linux/nvmem-consumer.h +++ b/include/linux/nvmem-consumer.h @@ -74,7 +74,7 @@ static inline void nvmem_cell_put(struct nvmem_cell *cell) { } -static inline char *nvmem_cell_read(struct nvmem_cell *cell, size_t *len) +static inline void *nvmem_cell_read(struct nvmem_cell *cell, size_t *len) { return ERR_PTR(-ENOSYS); } -- cgit v0.10.2 From 63c0c076e590ed83050c80ada2e82adeac9de126 Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Thu, 2 Jun 2016 12:19:43 +0100 Subject: nvmem: imx-ocotp: add COMPILE_TEST for proper test coverage This patch add COMPILE_TEST to imx-ocotp driver so that it can be compile tested on other platforms with zero day testing. Also adds HAS_IOMEM dependancy as the users of devm_ioremap_resource() which are compile-testable should depend on HAS_IOMEM. Signed-off-by: Srinivas Kandagatla Acked-by: Philipp Zabel Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/nvmem/Kconfig b/drivers/nvmem/Kconfig index 5ff2189..f550c45 100644 --- a/drivers/nvmem/Kconfig +++ b/drivers/nvmem/Kconfig @@ -15,7 +15,8 @@ if NVMEM config NVMEM_IMX_OCOTP tristate "i.MX6 On-Chip OTP Controller support" - depends on SOC_IMX6 + depends on SOC_IMX6 || COMPILE_TEST + depends on HAS_IOMEM help This is a driver for the On-Chip OTP Controller (OCOTP) available on i.MX6 SoCs, providing access to 4 Kbits of one-time programmable -- cgit v0.10.2 From e2402b1d214e5d50e807773563d590115a161f45 Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Thu, 2 Jun 2016 12:19:44 +0100 Subject: nvmem: imx-ocotp: Fix assignment warning. This patch fixes below error if the driver is compiled with 64 bit machine configuration. "drivers/nvmem/imx-ocotp.c:102:14: warning: assignment makes integer from pointer without a cast" Signed-off-by: Srinivas Kandagatla Acked-by: Philipp Zabel Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/nvmem/imx-ocotp.c b/drivers/nvmem/imx-ocotp.c index a340390..ac27b9b 100644 --- a/drivers/nvmem/imx-ocotp.c +++ b/drivers/nvmem/imx-ocotp.c @@ -99,7 +99,7 @@ static int imx_ocotp_probe(struct platform_device *pdev) return PTR_ERR(priv->clk); of_id = of_match_device(imx_ocotp_dt_ids, dev); - priv->nregs = (unsigned int)of_id->data; + priv->nregs = (unsigned long)of_id->data; imx_ocotp_nvmem_config.size = 4 * priv->nregs; imx_ocotp_nvmem_config.dev = dev; imx_ocotp_nvmem_config.priv = priv; -- cgit v0.10.2 From fec4daecadcf3b73facf6b48ed03453c96c7f2dd Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 9 May 2016 09:11:53 +0200 Subject: tty: ipwireless, cleanup TIOCGSERIAL In ipwireless_get_serial_info, struct serial_struct is memset to 0 and then some members set to 0 explicitly. Remove the latter as it is obviously superfluous. And remove the retinfo check against NULL. copy_to_user will take care of that. Part of hub6 cleanup series. Signed-off-by: Jiri Slaby Cc: Jiri Kosina Acked-by: David Sterba Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/ipwireless/tty.c b/drivers/tty/ipwireless/tty.c index 345cebb..2685d59 100644 --- a/drivers/tty/ipwireless/tty.c +++ b/drivers/tty/ipwireless/tty.c @@ -252,20 +252,11 @@ static int ipwireless_get_serial_info(struct ipw_tty *tty, { struct serial_struct tmp; - if (!retinfo) - return (-EFAULT); - memset(&tmp, 0, sizeof(tmp)); tmp.type = PORT_UNKNOWN; tmp.line = tty->index; - tmp.port = 0; - tmp.irq = 0; - tmp.flags = 0; tmp.baud_base = 115200; - tmp.close_delay = 0; - tmp.closing_wait = 0; - tmp.custom_divisor = 0; - tmp.hub6 = 0; + if (copy_to_user(retinfo, &tmp, sizeof(*retinfo))) return -EFAULT; -- cgit v0.10.2 From a2a5f1a2d23b453e2f11c10928c54b282fbe6147 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 9 May 2016 09:11:54 +0200 Subject: net: ircomm, cleanup TIOCGSERIAL In ircomm_tty_get_serial_info, struct serial_struct is memset to 0 and then some members set to 0 explicitly. Remove the latter as it is obviously superfluous. And remove the retinfo check against NULL. copy_to_user will take care of that. Part of hub6 cleanup series. Signed-off-by: Jiri Slaby Cc: Samuel Ortiz Acked-by: David S. Miller Signed-off-by: Greg Kroah-Hartman diff --git a/net/irda/ircomm/ircomm_tty_ioctl.c b/net/irda/ircomm/ircomm_tty_ioctl.c index d4fdf8f..8f5678c 100644 --- a/net/irda/ircomm/ircomm_tty_ioctl.c +++ b/net/irda/ircomm/ircomm_tty_ioctl.c @@ -246,9 +246,6 @@ static int ircomm_tty_get_serial_info(struct ircomm_tty_cb *self, { struct serial_struct info; - if (!retinfo) - return -EFAULT; - memset(&info, 0, sizeof(info)); info.line = self->line; info.flags = self->port.flags; @@ -258,11 +255,6 @@ static int ircomm_tty_get_serial_info(struct ircomm_tty_cb *self, /* For compatibility */ info.type = PORT_16550A; - info.port = 0; - info.irq = 0; - info.xmit_fifo_size = 0; - info.hub6 = 0; - info.custom_divisor = 0; if (copy_to_user(retinfo, &info, sizeof(*retinfo))) return -EFAULT; -- cgit v0.10.2 From 322b7d6d3efd34c7da858b27d7a410b84a9ed6db Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 9 May 2016 09:11:55 +0200 Subject: tty: cyclades+mxser, do not initialize to zero Do not initialize members of initialized structures to zero. They are zeroed automatically. Part of hub6 cleanup series. Signed-off-by: Jiri Slaby Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/cyclades.c b/drivers/tty/cyclades.c index 3840d6b..fcc4962 100644 --- a/drivers/tty/cyclades.c +++ b/drivers/tty/cyclades.c @@ -2288,7 +2288,6 @@ static int cy_get_serial_info(struct cyclades_port *info, .closing_wait = info->port.closing_wait, .baud_base = info->baud, .custom_divisor = info->custom_divisor, - .hub6 = 0, /*!!! */ }; return copy_to_user(retinfo, &tmp, sizeof(*retinfo)) ? -EFAULT : 0; } diff --git a/drivers/tty/mxser.c b/drivers/tty/mxser.c index 98d2bd1..69294ae 100644 --- a/drivers/tty/mxser.c +++ b/drivers/tty/mxser.c @@ -1219,7 +1219,6 @@ static int mxser_get_serial_info(struct tty_struct *tty, .close_delay = info->port.close_delay, .closing_wait = info->port.closing_wait, .custom_divisor = info->custom_divisor, - .hub6 = 0 }; if (copy_to_user(retinfo, &tmp, sizeof(*retinfo))) return -EFAULT; -- cgit v0.10.2 From 5691e03593cb9f7abfee93f4581de8933f1d6630 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 9 May 2016 09:11:56 +0200 Subject: tty: frv, remove unused serial macros STD_COM_FLAGS needs not be defined as it is not used anywhere on frv. SERIAL_PORT_DFNS is defined to be empty. 8250 is aware of empty SERIAL_PORT_DFNS and does: #ifndef SERIAL_PORT_DFNS #define SERIAL_PORT_DFNS #endif So no need to define it on frv. Signed-off-by: Jiri Slaby Cc: David Howells Signed-off-by: Greg Kroah-Hartman diff --git a/arch/frv/include/asm/serial.h b/arch/frv/include/asm/serial.h index bce0d0d..614c6d7 100644 --- a/arch/frv/include/asm/serial.h +++ b/arch/frv/include/asm/serial.h @@ -12,7 +12,3 @@ * the base baud is derived from the clock speed and so is variable */ #define BASE_BAUD 0 - -#define STD_COM_FLAGS UPF_BOOT_AUTOCONF - -#define SERIAL_PORT_DFNS -- cgit v0.10.2 From 6137b7a62978915d76db69e17e25e8e0b1057254 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 9 May 2016 09:11:57 +0200 Subject: tty: stop defining STD_COM_FLAGS in drivers STD_COM_FLAGS is mostly a bad name for what the drivers thinks it is. Stop using it and pass the flags directly. cyclades defines it as 0, so we do not assign anything to freshly tty_port_init'ed structure. Signed-off-by: Jiri Slaby Signed-off-by: Greg Kroah-Hartman diff --git a/arch/xtensa/platforms/xt2000/setup.c b/arch/xtensa/platforms/xt2000/setup.c index 5f4bd71..4904c5c 100644 --- a/arch/xtensa/platforms/xt2000/setup.c +++ b/arch/xtensa/platforms/xt2000/setup.c @@ -113,7 +113,6 @@ void platform_heartbeat(void) } //#define RS_TABLE_SIZE 2 -//#define STD_COM_FLAGS (UPF_BOOT_AUTOCONF|UPF_SKIP_TEST) #define _SERIAL_PORT(_base,_irq) \ { \ diff --git a/drivers/tty/cyclades.c b/drivers/tty/cyclades.c index fcc4962..5e4fa92 100644 --- a/drivers/tty/cyclades.c +++ b/drivers/tty/cyclades.c @@ -93,8 +93,6 @@ static void cy_send_xchar(struct tty_struct *tty, char ch); #define SERIAL_XMIT_SIZE (min(PAGE_SIZE, 4096)) #endif -#define STD_COM_FLAGS (0) - /* firmware stuff */ #define ZL_MAX_BLOCKS 16 #define DRIVER_VERSION 0x02010203 @@ -3083,7 +3081,6 @@ static int cy_init_card(struct cyclades_card *cinfo) info->port.closing_wait = CLOSING_WAIT_DELAY; info->port.close_delay = 5 * HZ / 10; - info->port.flags = STD_COM_FLAGS; init_completion(&info->shutdown_wait); if (cy_is_Z(cinfo)) { diff --git a/drivers/tty/serial/m32r_sio.c b/drivers/tty/serial/m32r_sio.c index 68765f7..1b01504c 100644 --- a/drivers/tty/serial/m32r_sio.c +++ b/drivers/tty/serial/m32r_sio.c @@ -51,9 +51,6 @@ #define PASS_LIMIT 256 -/* Standard COM flags */ -#define STD_COM_FLAGS (UPF_BOOT_AUTOCONF | UPF_SKIP_TEST) - static const struct { unsigned int port; unsigned int irq; @@ -892,7 +889,7 @@ static void __init m32r_sio_init_ports(void) up->port.iobase = old_serial_port[i].port; up->port.irq = irq_canonicalize(old_serial_port[i].irq); up->port.uartclk = BAUD_RATE * 16; - up->port.flags = STD_COM_FLAGS; + up->port.flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST; up->port.membase = 0; up->port.iotype = 0; up->port.regshift = 0; -- cgit v0.10.2 From b0f8aed2cdabb01225b85087d7ea1a88bd22e079 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 9 May 2016 09:11:58 +0200 Subject: tty: 8250, drop unused members from struct old_serial_port hub6 and irqflags from struct old_serial_port are nowhere set. Drop them from the structure and replace the reads by zeros. Signed-off-by: Jiri Slaby Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/8250/8250.h b/drivers/tty/serial/8250/8250.h index 215a992..563ccbe 100644 --- a/drivers/tty/serial/8250/8250.h +++ b/drivers/tty/serial/8250/8250.h @@ -53,11 +53,9 @@ struct old_serial_port { unsigned int port; unsigned int irq; upf_t flags; - unsigned char hub6; unsigned char io_type; unsigned char __iomem *iomem_base; unsigned short iomem_reg_shift; - unsigned long irqflags; }; struct serial8250_config { diff --git a/drivers/tty/serial/8250/8250_core.c b/drivers/tty/serial/8250/8250_core.c index 0fbd7c0..e938ac9 100644 --- a/drivers/tty/serial/8250/8250_core.c +++ b/drivers/tty/serial/8250/8250_core.c @@ -546,10 +546,10 @@ static void __init serial8250_isa_init_ports(void) port->iobase = old_serial_port[i].port; port->irq = irq_canonicalize(old_serial_port[i].irq); - port->irqflags = old_serial_port[i].irqflags; + port->irqflags = 0; port->uartclk = old_serial_port[i].baud_base * 16; port->flags = old_serial_port[i].flags; - port->hub6 = old_serial_port[i].hub6; + port->hub6 = 0; port->membase = old_serial_port[i].iomem_base; port->iotype = old_serial_port[i].io_type; port->regshift = old_serial_port[i].iomem_reg_shift; -- cgit v0.10.2 From 934014d5220616dc6ea62da6685b79855b164643 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 9 May 2016 09:11:59 +0200 Subject: tty: 8250, kill DEBUG_INTR Convert DEBUG_INTR to pr_debug: * defined semantics (DEBUG, DYNAMIC_DEBUG) * KERN_DEBUG level instead of KERN_DEFAULT * emit __func__ and \n * verified 'fmt' even when !DEBUG I wonder if anybody ever used that or whether we should just drop the lines. Signed-off-by: Jiri Slaby Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/8250/8250.h b/drivers/tty/serial/8250/8250.h index 563ccbe..31b3d55 100644 --- a/drivers/tty/serial/8250/8250.h +++ b/drivers/tty/serial/8250/8250.h @@ -235,9 +235,3 @@ static inline int serial_index(struct uart_port *port) { return port->minor - 64; } - -#if 0 -#define DEBUG_INTR(fmt...) printk(fmt) -#else -#define DEBUG_INTR(fmt...) do { } while (0) -#endif diff --git a/drivers/tty/serial/8250/8250_core.c b/drivers/tty/serial/8250/8250_core.c index e938ac9..fa823a5 100644 --- a/drivers/tty/serial/8250/8250_core.c +++ b/drivers/tty/serial/8250/8250_core.c @@ -114,7 +114,7 @@ static irqreturn_t serial8250_interrupt(int irq, void *dev_id) struct list_head *l, *end = NULL; int pass_counter = 0, handled = 0; - DEBUG_INTR("serial8250_interrupt(%d)...", irq); + pr_debug("%s(%d): start\n", __func__, irq); spin_lock(&i->lock); @@ -144,7 +144,7 @@ static irqreturn_t serial8250_interrupt(int irq, void *dev_id) spin_unlock(&i->lock); - DEBUG_INTR("end.\n"); + pr_debug("%s(%d): end\n", __func__, irq); return IRQ_RETVAL(handled); } diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c index d403603..b10d05f 100644 --- a/drivers/tty/serial/8250/8250_port.c +++ b/drivers/tty/serial/8250/8250_port.c @@ -1686,7 +1686,7 @@ static void serial8250_read_char(struct uart_8250_port *up, unsigned char lsr) lsr &= port->read_status_mask; if (lsr & UART_LSR_BI) { - DEBUG_INTR("handling break...."); + pr_debug("%s: handling break\n", __func__); flag = TTY_BREAK; } else if (lsr & UART_LSR_PE) flag = TTY_PARITY; @@ -1757,7 +1757,7 @@ void serial8250_tx_chars(struct uart_8250_port *up) if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) uart_write_wakeup(port); - DEBUG_INTR("THRE..."); + pr_debug("%s: THRE\n", __func__); /* * With RPM enabled, we have to wait until the FIFO is empty before the @@ -1823,7 +1823,7 @@ int serial8250_handle_irq(struct uart_port *port, unsigned int iir) status = serial_port_in(port, UART_LSR); - DEBUG_INTR("status = %x...", status); + pr_debug("%s: status = %x\n", __func__, status); if (status & (UART_LSR_DR | UART_LSR_BI)) { if (!up->dma || handle_rx_dma(up, iir)) -- cgit v0.10.2 From 394a9e2ca2b6326c939c90453184cbc65542cfa1 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 9 May 2016 09:23:35 +0200 Subject: TTY: serial, handle platform_get_irq retval properly MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit platform_get_irq can fail, so we should handle negative value when returned. [v2] platform_get_irq can actually return zero on some platforms. So do not remove checks for irq == 0 there. Signed-off-by: Jiri Slaby Cc: Russell King Cc: "Uwe Kleine-König" Cc: Russell King Cc: Benjamin Herrenschmidt Cc: Paul Mackerras Cc: Michael Ellerman Cc: Laxman Dewangan Cc: Stephen Warren Cc: Thierry Reding Cc: Alexandre Courbot Cc: linux-serial@vger.kernel.org Cc: linux-kernel@vger.kernel.org Cc: linuxppc-dev@lists.ozlabs.org Cc: linux-tegra@vger.kernel.org Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c index 1b7331e..8a9e213 100644 --- a/drivers/tty/serial/amba-pl011.c +++ b/drivers/tty/serial/amba-pl011.c @@ -2553,11 +2553,17 @@ static int sbsa_uart_probe(struct platform_device *pdev) if (!uap) return -ENOMEM; + ret = platform_get_irq(pdev, 0); + if (ret < 0) { + dev_err(&pdev->dev, "cannot obtain irq\n"); + return ret; + } + uap->port.irq = ret; + uap->reg_offset = vendor_sbsa.reg_offset; uap->vendor = &vendor_sbsa; uap->fifosize = 32; uap->port.iotype = vendor_sbsa.access_32b ? UPIO_MEM32 : UPIO_MEM; - uap->port.irq = platform_get_irq(pdev, 0); uap->port.ops = &sbsa_uart_pops; uap->fixed_baud = baudrate; diff --git a/drivers/tty/serial/fsl_lpuart.c b/drivers/tty/serial/fsl_lpuart.c index 3d79003..7f95f78 100644 --- a/drivers/tty/serial/fsl_lpuart.c +++ b/drivers/tty/serial/fsl_lpuart.c @@ -1830,7 +1830,13 @@ static int lpuart_probe(struct platform_device *pdev) sport->port.dev = &pdev->dev; sport->port.type = PORT_LPUART; sport->port.iotype = UPIO_MEM; - sport->port.irq = platform_get_irq(pdev, 0); + ret = platform_get_irq(pdev, 0); + if (ret < 0) { + dev_err(&pdev->dev, "cannot obtain irq\n"); + return ret; + } + sport->port.irq = ret; + if (sport->lpuart32) sport->port.ops = &lpuart32_pops; else diff --git a/drivers/tty/serial/pmac_zilog.c b/drivers/tty/serial/pmac_zilog.c index e156e39..b24b055 100644 --- a/drivers/tty/serial/pmac_zilog.c +++ b/drivers/tty/serial/pmac_zilog.c @@ -1720,7 +1720,7 @@ static int __init pmz_init_port(struct uart_pmac_port *uap) r_ports = platform_get_resource(uap->pdev, IORESOURCE_MEM, 0); irq = platform_get_irq(uap->pdev, 0); - if (!r_ports || !irq) + if (!r_ports || irq <= 0) return -ENODEV; uap->port.mapbase = r_ports->start; diff --git a/drivers/tty/serial/serial-tegra.c b/drivers/tty/serial/serial-tegra.c index 1dba671..731ac35 100644 --- a/drivers/tty/serial/serial-tegra.c +++ b/drivers/tty/serial/serial-tegra.c @@ -1317,7 +1317,12 @@ static int tegra_uart_probe(struct platform_device *pdev) } u->iotype = UPIO_MEM32; - u->irq = platform_get_irq(pdev, 0); + ret = platform_get_irq(pdev, 0); + if (ret < 0) { + dev_err(&pdev->dev, "Couldn't get IRQ\n"); + return ret; + } + u->irq = ret; u->regshift = 2; ret = uart_add_one_port(&tegra_uart_driver, u); if (ret < 0) { -- cgit v0.10.2 From 17b2720b114cc95b2b7c8c0f5cfa20e44e1f5912 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Thu, 23 Jun 2016 13:34:22 +0200 Subject: tty: 8250, remove shadow and unused variables MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The compiler complains about variables that are set, but never used: * intX variables in exar_handle_irq drivers/tty/serial/8250/8250_port.c:1864:34: warning: variable ‘int3’ set but not used [-Wunused-but-set-variable] * val variable in pci_quatech_wqopr drivers/tty/serial/8250/8250_pci.c:1139:10: warning: variable ‘val’ set but not used [-Wunused-but-set-variable] And about a shadow variable: * tmout in wait_for_xmitr is defined twice with the same type. Both of them are also initialized before use. Remove all of them. Signed-off-by: Jiri Slaby Cc: Matt Schulte Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c index 8dd250f..3d6287a 100644 --- a/drivers/tty/serial/8250/8250_pci.c +++ b/drivers/tty/serial/8250/8250_pci.c @@ -1136,11 +1136,11 @@ static int pci_quatech_rqopr(struct uart_8250_port *port) static void pci_quatech_wqopr(struct uart_8250_port *port, u8 qopr) { unsigned long base = port->port.iobase; - u8 LCR, val; + u8 LCR; LCR = inb(base + UART_LCR); outb(0xBF, base + UART_LCR); - val = inb(base + UART_SCR); + inb(base + UART_SCR); outb(qopr, base + UART_SCR); outb(LCR, base + UART_LCR); } diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c index b10d05f..c8d8d24 100644 --- a/drivers/tty/serial/8250/8250_port.c +++ b/drivers/tty/serial/8250/8250_port.c @@ -1861,7 +1861,6 @@ static int serial8250_default_handle_irq(struct uart_port *port) */ static int exar_handle_irq(struct uart_port *port) { - unsigned char int0, int1, int2, int3; unsigned int iir = serial_port_in(port, UART_IIR); int ret; @@ -1869,10 +1868,10 @@ static int exar_handle_irq(struct uart_port *port) if ((port->type == PORT_XR17V35X) || (port->type == PORT_XR17D15X)) { - int0 = serial_port_in(port, 0x80); - int1 = serial_port_in(port, 0x81); - int2 = serial_port_in(port, 0x82); - int3 = serial_port_in(port, 0x83); + serial_port_in(port, 0x80); + serial_port_in(port, 0x81); + serial_port_in(port, 0x82); + serial_port_in(port, 0x83); } return ret; @@ -1994,8 +1993,6 @@ static void wait_for_xmitr(struct uart_8250_port *up, int bits) /* Wait up to 1s for flow control if necessary */ if (up->port.flags & UPF_CONS_FLOW) { - unsigned int tmout; - for (tmout = 1000000; tmout; tmout--) { unsigned int msr = serial_in(up, UART_MSR); up->msr_saved_flags |= msr & MSR_SAVE_FLAGS; -- cgit v0.10.2 From 1b0ec88ac1cb0413a717bc3cefea72d6f2533672 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Thu, 23 Jun 2016 13:34:23 +0200 Subject: vt: remove lines parameter from scrollback It is always called with 0, so remove the parameter and pass the default down to scrolldelta without checking. Signed-off-by: Jiri Slaby Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/vt/keyboard.c b/drivers/tty/vt/keyboard.c index f973bfc..cd08c10 100644 --- a/drivers/tty/vt/keyboard.c +++ b/drivers/tty/vt/keyboard.c @@ -579,7 +579,7 @@ static void fn_scroll_forw(struct vc_data *vc) static void fn_scroll_back(struct vc_data *vc) { - scrollback(vc, 0); + scrollback(vc); } static void fn_show_mem(struct vc_data *vc) diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index dc12532..abc79ae1 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -1102,11 +1102,9 @@ static void gotoxay(struct vc_data *vc, int new_x, int new_y) gotoxy(vc, new_x, vc->vc_decom ? (vc->vc_top + new_y) : new_y); } -void scrollback(struct vc_data *vc, int lines) +void scrollback(struct vc_data *vc) { - if (!lines) - lines = vc->vc_rows / 2; - scrolldelta(-lines); + scrolldelta(-(vc->vc_rows / 2)); } void scrollfront(struct vc_data *vc, int lines) diff --git a/include/linux/vt_kern.h b/include/linux/vt_kern.h index 8d76342..160f81f 100644 --- a/include/linux/vt_kern.h +++ b/include/linux/vt_kern.h @@ -45,7 +45,7 @@ void poke_blanked_console(void); int con_font_op(struct vc_data *vc, struct console_font_op *op); int con_set_cmap(unsigned char __user *cmap); int con_get_cmap(unsigned char __user *cmap); -void scrollback(struct vc_data *vc, int lines); +void scrollback(struct vc_data *vc); void scrollfront(struct vc_data *vc, int lines); void clear_buffer_attributes(struct vc_data *vc); void update_region(struct vc_data *vc, unsigned long start, int count); -- cgit v0.10.2 From a4bedd019ec9690c1e5c7105509a2ef52c5ae3e0 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Thu, 23 Jun 2016 13:34:24 +0200 Subject: vt: document vc_data by example All those members of vc_data are each explained in short. But it needs an example for one to understand the whole picture. So add an ascii art depicting the most important vc_data members. Signed-off-by: Jiri Slaby Signed-off-by: Greg Kroah-Hartman diff --git a/include/linux/console_struct.h b/include/linux/console_struct.h index e329ee2..5fa605c 100644 --- a/include/linux/console_struct.h +++ b/include/linux/console_struct.h @@ -21,6 +21,38 @@ struct uni_pagedir; #define NPAR 16 +/* + * Example: vc_data of a console that was scrolled 3 lines down. + * + * Console buffer + * vc_screenbuf ---------> +----------------------+-. + * | initializing W | \ + * | initializing X | | + * | initializing Y | > scroll-back area + * | initializing Z | | + * | | / + * vc_visible_origin ---> ^+----------------------+-: + * (changes by scroll) || Welcome to linux | \ + * || | | + * vc_rows --->< | login: root | | visible on console + * || password: | > (vc_screenbuf_size is + * vc_origin -----------> || | | vc_size_row * vc_rows) + * (start when no scroll) || Last login: 12:28 | / + * v+----------------------+-: + * | Have a lot of fun... | \ + * vc_pos -----------------|--------v | > scroll-front area + * | ~ # cat_ | / + * vc_scr_end -----------> +----------------------+-: + * (vc_origin + | | \ EMPTY, to be filled by + * vc_screenbuf_size) | | / vc_video_erase_char + * +----------------------+-' + * <---- 2 * vc_cols -----> + * <---- vc_size_row -----> + * + * Note that every character in the console buffer is accompanied with an + * attribute in the buffer right after the character. This is not depicted + * in the figure. + */ struct vc_data { struct tty_port port; /* Upper level data */ -- cgit v0.10.2 From 3cc5be7739295ce00f5658c6f45c5c453412f708 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Thu, 23 Jun 2016 13:34:25 +0200 Subject: sisusb: remove dummy variables bytes_written parameter of sisusb_copy_memory and sisusb_read_memory is an out parameter, but its value is never used. So remove it and pass a dummy variable down to sisusb_read_mem_bulk. Signed-off-by: Jiri Slaby Cc: Thomas Winischhofer Cc: linux-usb@vger.kernel.org Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/misc/sisusbvga/sisusb.c b/drivers/usb/misc/sisusbvga/sisusb.c index 15666ad..02abfcd 100644 --- a/drivers/usb/misc/sisusbvga/sisusb.c +++ b/drivers/usb/misc/sisusbvga/sisusb.c @@ -1285,18 +1285,22 @@ int sisusb_readb(struct sisusb_usb_data *sisusb, u32 adr, u8 *data) } int sisusb_copy_memory(struct sisusb_usb_data *sisusb, char *src, - u32 dest, int length, size_t *bytes_written) + u32 dest, int length) { + size_t dummy; + return sisusb_write_mem_bulk(sisusb, dest, src, length, - NULL, 0, bytes_written); + NULL, 0, &dummy); } #ifdef SISUSBENDIANTEST -int sisusb_read_memory(struct sisusb_usb_data *sisusb, char *dest, - u32 src, int length, size_t *bytes_written) +static int sisusb_read_memory(struct sisusb_usb_data *sisusb, char *dest, + u32 src, int length) { + size_t dummy; + return sisusb_read_mem_bulk(sisusb, src, dest, length, - NULL, bytes_written); + NULL, &dummy); } #endif #endif @@ -1306,16 +1310,14 @@ static void sisusb_testreadwrite(struct sisusb_usb_data *sisusb) { static char srcbuffer[] = { 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77 }; char destbuffer[10]; - size_t dummy; int i, j; - sisusb_copy_memory(sisusb, srcbuffer, sisusb->vrambase, 7, &dummy); + sisusb_copy_memory(sisusb, srcbuffer, sisusb->vrambase, 7); for (i = 1; i <= 7; i++) { dev_dbg(&sisusb->sisusb_dev->dev, "sisusb: rwtest %d bytes\n", i); - sisusb_read_memory(sisusb, destbuffer, sisusb->vrambase, - i, &dummy); + sisusb_read_memory(sisusb, destbuffer, sisusb->vrambase, i); for (j = 0; j < i; j++) { dev_dbg(&sisusb->sisusb_dev->dev, "rwtest read[%d] = %x\n", @@ -2276,7 +2278,6 @@ int sisusb_reset_text_mode(struct sisusb_usb_data *sisusb, int init) const struct font_desc *myfont; u8 *tempbuf; u16 *tempbufb; - size_t written; static const char bootstring[] = "SiSUSB VGA text console, (C) 2005 Thomas Winischhofer."; static const char bootlogo[] = "(o_ //\\ V_/_"; @@ -2343,18 +2344,15 @@ int sisusb_reset_text_mode(struct sisusb_usb_data *sisusb, int init) *(tempbufb++) = 0x0700 | bootstring[i++]; ret |= sisusb_copy_memory(sisusb, tempbuf, - sisusb->vrambase, 8192, &written); + sisusb->vrambase, 8192); vfree(tempbuf); } } else if (sisusb->scrbuf) { - ret |= sisusb_copy_memory(sisusb, (char *)sisusb->scrbuf, - sisusb->vrambase, sisusb->scrbuf_size, - &written); - + sisusb->vrambase, sisusb->scrbuf_size); } if (sisusb->sisusb_cursor_size_from >= 0 && diff --git a/drivers/usb/misc/sisusbvga/sisusb_con.c b/drivers/usb/misc/sisusbvga/sisusb_con.c index afa8532..0ebbf49 100644 --- a/drivers/usb/misc/sisusbvga/sisusb_con.c +++ b/drivers/usb/misc/sisusbvga/sisusb_con.c @@ -370,7 +370,6 @@ static void sisusbcon_putc(struct vc_data *c, int ch, int y, int x) { struct sisusb_usb_data *sisusb; - ssize_t written; sisusb = sisusb_get_sisusb_lock_and_check(c->vc_num); if (!sisusb) @@ -384,7 +383,7 @@ sisusbcon_putc(struct vc_data *c, int ch, int y, int x) sisusb_copy_memory(sisusb, (char *)SISUSB_VADDR(x, y), - (long)SISUSB_HADDR(x, y), 2, &written); + (long)SISUSB_HADDR(x, y), 2); mutex_unlock(&sisusb->lock); } @@ -395,7 +394,6 @@ sisusbcon_putcs(struct vc_data *c, const unsigned short *s, int count, int y, int x) { struct sisusb_usb_data *sisusb; - ssize_t written; u16 *dest; int i; @@ -420,7 +418,7 @@ sisusbcon_putcs(struct vc_data *c, const unsigned short *s, } sisusb_copy_memory(sisusb, (char *)SISUSB_VADDR(x, y), - (long)SISUSB_HADDR(x, y), count * 2, &written); + (long)SISUSB_HADDR(x, y), count * 2); mutex_unlock(&sisusb->lock); } @@ -431,7 +429,6 @@ sisusbcon_clear(struct vc_data *c, int y, int x, int height, int width) { struct sisusb_usb_data *sisusb; u16 eattr = c->vc_video_erase_char; - ssize_t written; int i, length, cols; u16 *dest; @@ -475,7 +472,7 @@ sisusbcon_clear(struct vc_data *c, int y, int x, int height, int width) sisusb_copy_memory(sisusb, (unsigned char *)SISUSB_VADDR(x, y), - (long)SISUSB_HADDR(x, y), length, &written); + (long)SISUSB_HADDR(x, y), length); mutex_unlock(&sisusb->lock); } @@ -486,7 +483,6 @@ sisusbcon_bmove(struct vc_data *c, int sy, int sx, int dy, int dx, int height, int width) { struct sisusb_usb_data *sisusb; - ssize_t written; int cols, length; if (width <= 0 || height <= 0) @@ -509,7 +505,7 @@ sisusbcon_bmove(struct vc_data *c, int sy, int sx, sisusb_copy_memory(sisusb, (unsigned char *)SISUSB_VADDR(dx, dy), - (long)SISUSB_HADDR(dx, dy), length, &written); + (long)SISUSB_HADDR(dx, dy), length); mutex_unlock(&sisusb->lock); } @@ -519,7 +515,6 @@ static int sisusbcon_switch(struct vc_data *c) { struct sisusb_usb_data *sisusb; - ssize_t written; int length; /* Returnvalue 0 means we have fully restored screen, @@ -559,7 +554,7 @@ sisusbcon_switch(struct vc_data *c) sisusb_copy_memory(sisusb, (unsigned char *)c->vc_origin, (long)SISUSB_HADDR(0, 0), - length, &written); + length); mutex_unlock(&sisusb->lock); @@ -644,7 +639,6 @@ sisusbcon_blank(struct vc_data *c, int blank, int mode_switch) { struct sisusb_usb_data *sisusb; u8 sr1, cr17, pmreg, cr63; - ssize_t written; int ret = 0; sisusb = sisusb_get_sisusb_lock_and_check(c->vc_num); @@ -672,7 +666,7 @@ sisusbcon_blank(struct vc_data *c, int blank, int mode_switch) (unsigned char *)c->vc_origin, (u32)(sisusb->vrambase + (c->vc_origin - sisusb->scrbuf)), - c->vc_screenbuf_size, &written); + c->vc_screenbuf_size); sisusb->con_blanked = 1; ret = 1; break; @@ -860,7 +854,6 @@ sisusbcon_scroll_area(struct vc_data *c, struct sisusb_usb_data *sisusb, int cols = sisusb->sisusb_num_columns; int length = ((b - t) * cols) * 2; u16 eattr = c->vc_video_erase_char; - ssize_t written; /* sisusb->lock is down */ @@ -890,7 +883,7 @@ sisusbcon_scroll_area(struct vc_data *c, struct sisusb_usb_data *sisusb, } sisusb_copy_memory(sisusb, (char *)SISUSB_VADDR(0, t), - (long)SISUSB_HADDR(0, t), length, &written); + (long)SISUSB_HADDR(0, t), length); mutex_unlock(&sisusb->lock); @@ -903,7 +896,6 @@ sisusbcon_scroll(struct vc_data *c, int t, int b, int dir, int lines) { struct sisusb_usb_data *sisusb; u16 eattr = c->vc_video_erase_char; - ssize_t written; int copyall = 0; unsigned long oldorigin; unsigned int delta = lines * c->vc_size_row; @@ -996,18 +988,18 @@ sisusbcon_scroll(struct vc_data *c, int t, int b, int dir, int lines) sisusb_copy_memory(sisusb, (char *)c->vc_origin, (u32)(sisusb->vrambase + originoffset), - c->vc_screenbuf_size, &written); + c->vc_screenbuf_size); else if (dir == SM_UP) sisusb_copy_memory(sisusb, (char *)c->vc_origin + c->vc_screenbuf_size - delta, (u32)sisusb->vrambase + originoffset + c->vc_screenbuf_size - delta, - delta, &written); + delta); else sisusb_copy_memory(sisusb, (char *)c->vc_origin, (u32)(sisusb->vrambase + originoffset), - delta, &written); + delta); c->vc_scr_end = c->vc_origin + c->vc_screenbuf_size; c->vc_visible_origin = c->vc_origin; diff --git a/drivers/usb/misc/sisusbvga/sisusb_init.h b/drivers/usb/misc/sisusbvga/sisusb_init.h index c46ce42..e79a616 100644 --- a/drivers/usb/misc/sisusbvga/sisusb_init.h +++ b/drivers/usb/misc/sisusbvga/sisusb_init.h @@ -828,7 +828,7 @@ void sisusb_delete(struct kref *kref); int sisusb_writeb(struct sisusb_usb_data *sisusb, u32 adr, u8 data); int sisusb_readb(struct sisusb_usb_data *sisusb, u32 adr, u8 * data); int sisusb_copy_memory(struct sisusb_usb_data *sisusb, char *src, - u32 dest, int length, size_t * bytes_written); + u32 dest, int length); int sisusb_reset_text_mode(struct sisusb_usb_data *sisusb, int init); int sisusbcon_do_font_op(struct sisusb_usb_data *sisusb, int set, int slot, u8 * arg, int cmapsz, int ch512, int dorecalc, -- cgit v0.10.2 From 97293de977365fe672daec2523e66ef457104921 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Thu, 23 Jun 2016 13:34:26 +0200 Subject: tty: vt, consw->con_scrolldelta cleanup * allow NULL consw->con_scrolldelta (some consoles define an empty hook) * => remove empty hooks now * return value of consw->con_scrolldelta is never checked => make the function void * document consw->con_scrolldelta a bit Signed-off-by: Jiri Slaby Cc: Thomas Winischhofer Cc: linux-usb@vger.kernel.org Cc: Jean-Christophe Plagniol-Villard Cc: Tomi Valkeinen Cc: "James E.J. Bottomley" Cc: Helge Deller Cc: linux-fbdev@vger.kernel.org Cc: linux-parisc@vger.kernel.org Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index abc79ae1..365a91d 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -2468,7 +2468,7 @@ static void console_callback(struct work_struct *ignored) if (scrollback_delta) { struct vc_data *vc = vc_cons[fg_console].d; clear_selection(); - if (vc->vc_mode == KD_TEXT) + if (vc->vc_mode == KD_TEXT && vc->vc_sw->con_scrolldelta) vc->vc_sw->con_scrolldelta(vc, scrollback_delta); scrollback_delta = 0; } diff --git a/drivers/usb/misc/sisusbvga/sisusb_con.c b/drivers/usb/misc/sisusbvga/sisusb_con.c index 0ebbf49..a8244eb 100644 --- a/drivers/usb/misc/sisusbvga/sisusb_con.c +++ b/drivers/usb/misc/sisusbvga/sisusb_con.c @@ -717,24 +717,22 @@ sisusbcon_blank(struct vc_data *c, int blank, int mode_switch) } /* interface routine */ -static int +static void sisusbcon_scrolldelta(struct vc_data *c, int lines) { struct sisusb_usb_data *sisusb; int margin = c->vc_size_row * 4; int ul, we, p, st; - /* The return value does not seem to be used */ - sisusb = sisusb_get_sisusb_lock_and_check(c->vc_num); if (!sisusb) - return 0; + return; /* sisusb->lock is down */ if (sisusb_is_inactive(c, sisusb)) { mutex_unlock(&sisusb->lock); - return 0; + return; } if (!lines) /* Turn scrollback off */ @@ -774,8 +772,6 @@ sisusbcon_scrolldelta(struct vc_data *c, int lines) sisusbcon_set_start_address(sisusb, c); mutex_unlock(&sisusb->lock); - - return 1; } /* Interface routine */ @@ -1433,7 +1429,6 @@ static const struct consw sisusb_dummy_con = { .con_font_default = SISUSBCONDUMMY, .con_font_copy = SISUSBCONDUMMY, .con_set_palette = SISUSBCONDUMMY, - .con_scrolldelta = SISUSBCONDUMMY, }; int diff --git a/drivers/video/console/dummycon.c b/drivers/video/console/dummycon.c index 0efc52f..9ce03b9 100644 --- a/drivers/video/console/dummycon.c +++ b/drivers/video/console/dummycon.c @@ -72,6 +72,5 @@ const struct consw dummy_con = { .con_font_default = DUMMY, .con_font_copy = DUMMY, .con_set_palette = DUMMY, - .con_scrolldelta = DUMMY, }; EXPORT_SYMBOL_GPL(dummy_con); diff --git a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c index afd3301..eadc7bf 100644 --- a/drivers/video/console/fbcon.c +++ b/drivers/video/console/fbcon.c @@ -171,7 +171,6 @@ static void fbcon_bmove(struct vc_data *vc, int sy, int sx, int dy, int dx, static int fbcon_switch(struct vc_data *vc); static int fbcon_blank(struct vc_data *vc, int blank, int mode_switch); static int fbcon_set_palette(struct vc_data *vc, const unsigned char *table); -static int fbcon_scrolldelta(struct vc_data *vc, int lines); /* * Internal routines @@ -2765,7 +2764,7 @@ static void fbcon_invert_region(struct vc_data *vc, u16 * p, int cnt) } } -static int fbcon_scrolldelta(struct vc_data *vc, int lines) +static void fbcon_scrolldelta(struct vc_data *vc, int lines) { struct fb_info *info = registered_fb[con2fb_map[fg_console]]; struct fbcon_ops *ops = info->fbcon_par; @@ -2774,9 +2773,9 @@ static int fbcon_scrolldelta(struct vc_data *vc, int lines) if (softback_top) { if (vc->vc_num != fg_console) - return 0; + return; if (vc->vc_mode != KD_TEXT || !lines) - return 0; + return; if (logo_shown >= 0) { struct vc_data *conp2 = vc_cons[logo_shown].d; @@ -2809,11 +2808,11 @@ static int fbcon_scrolldelta(struct vc_data *vc, int lines) fbcon_cursor(vc, CM_ERASE | CM_SOFTBACK); fbcon_redraw_softback(vc, disp, lines); fbcon_cursor(vc, CM_DRAW | CM_SOFTBACK); - return 0; + return; } if (!scrollback_phys_max) - return -ENOSYS; + return; scrollback_old = scrollback_current; scrollback_current -= lines; @@ -2822,10 +2821,10 @@ static int fbcon_scrolldelta(struct vc_data *vc, int lines) else if (scrollback_current > scrollback_max) scrollback_current = scrollback_max; if (scrollback_current == scrollback_old) - return 0; + return; if (fbcon_is_inactive(vc, info)) - return 0; + return; fbcon_cursor(vc, CM_ERASE); @@ -2852,7 +2851,6 @@ static int fbcon_scrolldelta(struct vc_data *vc, int lines) if (!scrollback_current) fbcon_cursor(vc, CM_DRAW); - return 0; } static int fbcon_set_origin(struct vc_data *vc) diff --git a/drivers/video/console/mdacon.c b/drivers/video/console/mdacon.c index 8edc062..234af26b 100644 --- a/drivers/video/console/mdacon.c +++ b/drivers/video/console/mdacon.c @@ -505,11 +505,6 @@ static int mdacon_blank(struct vc_data *c, int blank, int mode_switch) } } -static int mdacon_scrolldelta(struct vc_data *c, int lines) -{ - return 0; -} - static void mdacon_cursor(struct vc_data *c, int mode) { if (mode == CM_ERASE) { @@ -578,7 +573,6 @@ static const struct consw mda_con = { .con_switch = mdacon_switch, .con_blank = mdacon_blank, .con_set_palette = mdacon_set_palette, - .con_scrolldelta = mdacon_scrolldelta, .con_build_attr = mdacon_build_attr, .con_invert_region = mdacon_invert_region, }; diff --git a/drivers/video/console/newport_con.c b/drivers/video/console/newport_con.c index 0553dfe..eb3d4ce 100644 --- a/drivers/video/console/newport_con.c +++ b/drivers/video/console/newport_con.c @@ -579,12 +579,6 @@ static int newport_set_palette(struct vc_data *vc, const unsigned char *table) return -EINVAL; } -static int newport_scrolldelta(struct vc_data *vc, int lines) -{ - /* there is (nearly) no off-screen memory, so we can't scroll back */ - return 0; -} - static int newport_scroll(struct vc_data *vc, int t, int b, int dir, int lines) { @@ -735,7 +729,6 @@ const struct consw newport_con = { .con_font_set = newport_font_set, .con_font_default = newport_font_default, .con_set_palette = newport_set_palette, - .con_scrolldelta = newport_scrolldelta, .con_set_origin = DUMMY, .con_save_screen = DUMMY }; diff --git a/drivers/video/console/sticon.c b/drivers/video/console/sticon.c index e440c2d..20f6a2f 100644 --- a/drivers/video/console/sticon.c +++ b/drivers/video/console/sticon.c @@ -256,11 +256,6 @@ static int sticon_blank(struct vc_data *c, int blank, int mode_switch) return 1; } -static int sticon_scrolldelta(struct vc_data *conp, int lines) -{ - return 0; -} - static u16 *sticon_screen_pos(struct vc_data *conp, int offset) { int line; @@ -359,7 +354,6 @@ static const struct consw sti_con = { .con_switch = sticon_switch, .con_blank = sticon_blank, .con_set_palette = sticon_set_palette, - .con_scrolldelta = sticon_scrolldelta, .con_set_origin = sticon_set_origin, .con_save_screen = sticon_save_screen, .con_build_attr = sticon_build_attr, diff --git a/drivers/video/console/vgacon.c b/drivers/video/console/vgacon.c index 8bf9110..f447d69 100644 --- a/drivers/video/console/vgacon.c +++ b/drivers/video/console/vgacon.c @@ -80,7 +80,7 @@ static void vgacon_deinit(struct vc_data *c); static void vgacon_cursor(struct vc_data *c, int mode); static int vgacon_switch(struct vc_data *c); static int vgacon_blank(struct vc_data *c, int blank, int mode_switch); -static int vgacon_scrolldelta(struct vc_data *c, int lines); +static void vgacon_scrolldelta(struct vc_data *c, int lines); static int vgacon_set_origin(struct vc_data *c); static void vgacon_save_screen(struct vc_data *c); static int vgacon_scroll(struct vc_data *c, int t, int b, int dir, @@ -248,18 +248,18 @@ static void vgacon_restore_screen(struct vc_data *c) } } -static int vgacon_scrolldelta(struct vc_data *c, int lines) +static void vgacon_scrolldelta(struct vc_data *c, int lines) { int start, end, count, soff; if (!lines) { c->vc_visible_origin = c->vc_origin; vga_set_mem_top(c); - return 1; + return; } if (!vgacon_scrollback) - return 1; + return; if (!vgacon_scrollback_save) { vgacon_cursor(c, CM_ERASE); @@ -320,8 +320,6 @@ static int vgacon_scrolldelta(struct vc_data *c, int lines) scr_memcpyw(d, s, diff * c->vc_size_row); } else vgacon_cursor(c, CM_MOVE); - - return 1; } #else #define vgacon_scrollback_startup(...) do { } while (0) @@ -334,7 +332,7 @@ static void vgacon_restore_screen(struct vc_data *c) vgacon_scrolldelta(c, 0); } -static int vgacon_scrolldelta(struct vc_data *c, int lines) +static void vgacon_scrolldelta(struct vc_data *c, int lines) { if (!lines) /* Turn scrollback off */ c->vc_visible_origin = c->vc_origin; @@ -362,7 +360,6 @@ static int vgacon_scrolldelta(struct vc_data *c, int lines) c->vc_visible_origin = vga_vram_base + (p + ul) % we; } vga_set_mem_top(c); - return 1; } #endif /* CONFIG_VGACON_SOFT_SCROLLBACK */ diff --git a/include/linux/console.h b/include/linux/console.h index 98c8615..d175de8 100644 --- a/include/linux/console.h +++ b/include/linux/console.h @@ -28,6 +28,12 @@ struct tty_struct; #define VT100ID "\033[?1;2c" #define VT102ID "\033[?6c" +/** + * struct consw - callbacks for consoles + * + * @con_scrolldelta: the contents of the console should be scrolled by @lines. + * Invoked by user. (optional) + */ struct consw { struct module *owner; const char *(*con_startup)(void); @@ -48,7 +54,7 @@ struct consw { int (*con_resize)(struct vc_data *, unsigned int, unsigned int, unsigned int); int (*con_set_palette)(struct vc_data *, const unsigned char *); - int (*con_scrolldelta)(struct vc_data *, int); + void (*con_scrolldelta)(struct vc_data *, int lines); int (*con_set_origin)(struct vc_data *); void (*con_save_screen)(struct vc_data *); u8 (*con_build_attr)(struct vc_data *, u8, u8, u8, u8, u8, u8); -- cgit v0.10.2 From 709280da6238629c3b488b7be87c6d9185f4d03e Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Thu, 23 Jun 2016 13:34:27 +0200 Subject: tty: vt, consw->con_set_palette cleanup * allow NULL consw->con_set_palette (some consoles define an empty hook) * => remove empty hooks now * return value of consw->con_set_palette is never checked => make the function void * document consw->con_set_palette a bit Signed-off-by: Jiri Slaby Cc: Thomas Winischhofer Cc: linux-usb@vger.kernel.org Cc: Jean-Christophe Plagniol-Villard Cc: Tomi Valkeinen Cc: "James E.J. Bottomley" Cc: Helge Deller Cc: linux-fbdev@vger.kernel.org Cc: linux-parisc@vger.kernel.org Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index 365a91d..d5d9060 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -3978,7 +3978,7 @@ static void set_palette(struct vc_data *vc) { WARN_CONSOLE_UNLOCKED(); - if (vc->vc_mode != KD_GRAPHICS) + if (vc->vc_mode != KD_GRAPHICS && vc->vc_sw->con_set_palette) vc->vc_sw->con_set_palette(vc, color_table); } diff --git a/drivers/usb/misc/sisusbvga/sisusb_con.c b/drivers/usb/misc/sisusbvga/sisusb_con.c index a8244eb..4112835 100644 --- a/drivers/usb/misc/sisusbvga/sisusb_con.c +++ b/drivers/usb/misc/sisusbvga/sisusb_con.c @@ -595,7 +595,7 @@ sisusbcon_save_screen(struct vc_data *c) } /* interface routine */ -static int +static void sisusbcon_set_palette(struct vc_data *c, const unsigned char *table) { struct sisusb_usb_data *sisusb; @@ -604,17 +604,17 @@ sisusbcon_set_palette(struct vc_data *c, const unsigned char *table) /* Return value not used by vt */ if (!CON_IS_VISIBLE(c)) - return -EINVAL; + return; sisusb = sisusb_get_sisusb_lock_and_check(c->vc_num); if (!sisusb) - return -EINVAL; + return; /* sisusb->lock is down */ if (sisusb_is_inactive(c, sisusb)) { mutex_unlock(&sisusb->lock); - return -EINVAL; + return; } for (i = j = 0; i < 16; i++) { @@ -629,8 +629,6 @@ sisusbcon_set_palette(struct vc_data *c, const unsigned char *table) } mutex_unlock(&sisusb->lock); - - return 0; } /* interface routine */ @@ -1428,7 +1426,6 @@ static const struct consw sisusb_dummy_con = { .con_font_get = SISUSBCONDUMMY, .con_font_default = SISUSBCONDUMMY, .con_font_copy = SISUSBCONDUMMY, - .con_set_palette = SISUSBCONDUMMY, }; int diff --git a/drivers/video/console/dummycon.c b/drivers/video/console/dummycon.c index 9ce03b9..0ef544e 100644 --- a/drivers/video/console/dummycon.c +++ b/drivers/video/console/dummycon.c @@ -71,6 +71,5 @@ const struct consw dummy_con = { .con_font_get = DUMMY, .con_font_default = DUMMY, .con_font_copy = DUMMY, - .con_set_palette = DUMMY, }; EXPORT_SYMBOL_GPL(dummy_con); diff --git a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c index eadc7bf..9359b06 100644 --- a/drivers/video/console/fbcon.c +++ b/drivers/video/console/fbcon.c @@ -170,7 +170,7 @@ static void fbcon_bmove(struct vc_data *vc, int sy, int sx, int dy, int dx, int height, int width); static int fbcon_switch(struct vc_data *vc); static int fbcon_blank(struct vc_data *vc, int blank, int mode_switch); -static int fbcon_set_palette(struct vc_data *vc, const unsigned char *table); +static void fbcon_set_palette(struct vc_data *vc, const unsigned char *table); /* * Internal routines @@ -2651,17 +2651,17 @@ static struct fb_cmap palette_cmap = { 0, 16, palette_red, palette_green, palette_blue, NULL }; -static int fbcon_set_palette(struct vc_data *vc, const unsigned char *table) +static void fbcon_set_palette(struct vc_data *vc, const unsigned char *table) { struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; int i, j, k, depth; u8 val; if (fbcon_is_inactive(vc, info)) - return -EINVAL; + return; if (!CON_IS_VISIBLE(vc)) - return 0; + return; depth = fb_get_color_depth(&info->var, &info->fix); if (depth > 3) { @@ -2683,7 +2683,7 @@ static int fbcon_set_palette(struct vc_data *vc, const unsigned char *table) } else fb_copy_cmap(fb_default_cmap(1 << depth), &palette_cmap); - return fb_set_cmap(&palette_cmap, info); + fb_set_cmap(&palette_cmap, info); } static u16 *fbcon_screen_pos(struct vc_data *vc, int offset) diff --git a/drivers/video/console/mdacon.c b/drivers/video/console/mdacon.c index 234af26b..1fe5245 100644 --- a/drivers/video/console/mdacon.c +++ b/drivers/video/console/mdacon.c @@ -481,11 +481,6 @@ static int mdacon_switch(struct vc_data *c) return 1; /* redrawing needed */ } -static int mdacon_set_palette(struct vc_data *c, const unsigned char *table) -{ - return -EINVAL; -} - static int mdacon_blank(struct vc_data *c, int blank, int mode_switch) { if (mda_type == TYPE_MDA) { @@ -572,7 +567,6 @@ static const struct consw mda_con = { .con_bmove = mdacon_bmove, .con_switch = mdacon_switch, .con_blank = mdacon_blank, - .con_set_palette = mdacon_set_palette, .con_build_attr = mdacon_build_attr, .con_invert_region = mdacon_invert_region, }; diff --git a/drivers/video/console/newport_con.c b/drivers/video/console/newport_con.c index eb3d4ce..a436930 100644 --- a/drivers/video/console/newport_con.c +++ b/drivers/video/console/newport_con.c @@ -574,11 +574,6 @@ static int newport_font_set(struct vc_data *vc, struct console_font *font, unsig return newport_set_font(vc->vc_num, font); } -static int newport_set_palette(struct vc_data *vc, const unsigned char *table) -{ - return -EINVAL; -} - static int newport_scroll(struct vc_data *vc, int t, int b, int dir, int lines) { @@ -728,7 +723,6 @@ const struct consw newport_con = { .con_blank = newport_blank, .con_font_set = newport_font_set, .con_font_default = newport_font_default, - .con_set_palette = newport_set_palette, .con_set_origin = DUMMY, .con_save_screen = DUMMY }; diff --git a/drivers/video/console/sticon.c b/drivers/video/console/sticon.c index 20f6a2f..fe7c4db 100644 --- a/drivers/video/console/sticon.c +++ b/drivers/video/console/sticon.c @@ -79,11 +79,6 @@ static const char *sticon_startup(void) return "STI console"; } -static int sticon_set_palette(struct vc_data *c, const unsigned char *table) -{ - return -EINVAL; -} - static void sticon_putc(struct vc_data *conp, int c, int ypos, int xpos) { int redraw_cursor = 0; @@ -353,7 +348,6 @@ static const struct consw sti_con = { .con_bmove = sticon_bmove, .con_switch = sticon_switch, .con_blank = sticon_blank, - .con_set_palette = sticon_set_palette, .con_set_origin = sticon_set_origin, .con_save_screen = sticon_save_screen, .con_build_attr = sticon_build_attr, diff --git a/drivers/video/console/vgacon.c b/drivers/video/console/vgacon.c index f447d69..aaae9bd 100644 --- a/drivers/video/console/vgacon.c +++ b/drivers/video/console/vgacon.c @@ -856,16 +856,13 @@ static void vga_set_palette(struct vc_data *vc, const unsigned char *table) } } -static int vgacon_set_palette(struct vc_data *vc, const unsigned char *table) +static void vgacon_set_palette(struct vc_data *vc, const unsigned char *table) { #ifdef CAN_LOAD_PALETTE if (vga_video_type != VIDEO_TYPE_VGAC || vga_palette_blanked || !CON_IS_VISIBLE(vc)) - return -EINVAL; + return; vga_set_palette(vc, table); - return 0; -#else - return -EINVAL; #endif } diff --git a/include/linux/console.h b/include/linux/console.h index d175de8..382a527 100644 --- a/include/linux/console.h +++ b/include/linux/console.h @@ -31,6 +31,7 @@ struct tty_struct; /** * struct consw - callbacks for consoles * + * @con_set_palette: sets the palette of the console to @table (optional) * @con_scrolldelta: the contents of the console should be scrolled by @lines. * Invoked by user. (optional) */ @@ -53,7 +54,8 @@ struct consw { int (*con_font_copy)(struct vc_data *, int); int (*con_resize)(struct vc_data *, unsigned int, unsigned int, unsigned int); - int (*con_set_palette)(struct vc_data *, const unsigned char *); + void (*con_set_palette)(struct vc_data *, + const unsigned char *table); void (*con_scrolldelta)(struct vc_data *, int lines); int (*con_set_origin)(struct vc_data *); void (*con_save_screen)(struct vc_data *); -- cgit v0.10.2 From 52ad1f38b4f6e2f2133668247036ad64ef7ae18a Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Thu, 23 Jun 2016 13:34:28 +0200 Subject: tty: vt, remove consw->con_bmove It is never called since commit 81732c3b2fede (tty vt: Fix line garbage in virtual console on command line edition) in 3.7. So remove all the callbacks. Signed-off-by: Jiri Slaby Cc: Thomas Winischhofer Cc: linux-usb@vger.kernel.org Cc: Jean-Christophe Plagniol-Villard Cc: Tomi Valkeinen Cc: "James E.J. Bottomley" Cc: Helge Deller Cc: linux-fbdev@vger.kernel.org Cc: linux-parisc@vger.kernel.org Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/misc/sisusbvga/sisusb_con.c b/drivers/usb/misc/sisusbvga/sisusb_con.c index 4112835..52a6da9 100644 --- a/drivers/usb/misc/sisusbvga/sisusb_con.c +++ b/drivers/usb/misc/sisusbvga/sisusb_con.c @@ -477,39 +477,6 @@ sisusbcon_clear(struct vc_data *c, int y, int x, int height, int width) mutex_unlock(&sisusb->lock); } -/* Interface routine */ -static void -sisusbcon_bmove(struct vc_data *c, int sy, int sx, - int dy, int dx, int height, int width) -{ - struct sisusb_usb_data *sisusb; - int cols, length; - - if (width <= 0 || height <= 0) - return; - - sisusb = sisusb_get_sisusb_lock_and_check(c->vc_num); - if (!sisusb) - return; - - /* sisusb->lock is down */ - - cols = sisusb->sisusb_num_columns; - - if (sisusb_is_inactive(c, sisusb)) { - mutex_unlock(&sisusb->lock); - return; - } - - length = ((height * cols) - dx - (cols - width - dx)) * 2; - - - sisusb_copy_memory(sisusb, (unsigned char *)SISUSB_VADDR(dx, dy), - (long)SISUSB_HADDR(dx, dy), length); - - mutex_unlock(&sisusb->lock); -} - /* interface routine */ static int sisusbcon_switch(struct vc_data *c) @@ -1371,7 +1338,6 @@ static const struct consw sisusb_con = { .con_putcs = sisusbcon_putcs, .con_cursor = sisusbcon_cursor, .con_scroll = sisusbcon_scroll, - .con_bmove = sisusbcon_bmove, .con_switch = sisusbcon_switch, .con_blank = sisusbcon_blank, .con_font_set = sisusbcon_font_set, @@ -1419,7 +1385,6 @@ static const struct consw sisusb_dummy_con = { .con_putcs = SISUSBCONDUMMY, .con_cursor = SISUSBCONDUMMY, .con_scroll = SISUSBCONDUMMY, - .con_bmove = SISUSBCONDUMMY, .con_switch = SISUSBCONDUMMY, .con_blank = SISUSBCONDUMMY, .con_font_set = SISUSBCONDUMMY, diff --git a/drivers/video/console/dummycon.c b/drivers/video/console/dummycon.c index 0ef544e..9269d56 100644 --- a/drivers/video/console/dummycon.c +++ b/drivers/video/console/dummycon.c @@ -64,7 +64,6 @@ const struct consw dummy_con = { .con_putcs = DUMMY, .con_cursor = DUMMY, .con_scroll = DUMMY, - .con_bmove = DUMMY, .con_switch = DUMMY, .con_blank = DUMMY, .con_font_set = DUMMY, diff --git a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c index 9359b06..eef8a8b 100644 --- a/drivers/video/console/fbcon.c +++ b/drivers/video/console/fbcon.c @@ -3334,7 +3334,6 @@ static const struct consw fb_con = { .con_putcs = fbcon_putcs, .con_cursor = fbcon_cursor, .con_scroll = fbcon_scroll, - .con_bmove = fbcon_bmove, .con_switch = fbcon_switch, .con_blank = fbcon_blank, .con_font_set = fbcon_set_font, diff --git a/drivers/video/console/mdacon.c b/drivers/video/console/mdacon.c index 1fe5245..bacbb04 100644 --- a/drivers/video/console/mdacon.c +++ b/drivers/video/console/mdacon.c @@ -444,38 +444,6 @@ static void mdacon_clear(struct vc_data *c, int y, int x, } } -static void mdacon_bmove(struct vc_data *c, int sy, int sx, - int dy, int dx, int height, int width) -{ - u16 *src, *dest; - - if (width <= 0 || height <= 0) - return; - - if (sx==0 && dx==0 && width==mda_num_columns) { - scr_memmovew(MDA_ADDR(0,dy), MDA_ADDR(0,sy), height*width*2); - - } else if (dy < sy || (dy == sy && dx < sx)) { - src = MDA_ADDR(sx, sy); - dest = MDA_ADDR(dx, dy); - - for (; height > 0; height--) { - scr_memmovew(dest, src, width*2); - src += mda_num_columns; - dest += mda_num_columns; - } - } else { - src = MDA_ADDR(sx, sy+height-1); - dest = MDA_ADDR(dx, dy+height-1); - - for (; height > 0; height--) { - scr_memmovew(dest, src, width*2); - src -= mda_num_columns; - dest -= mda_num_columns; - } - } -} - static int mdacon_switch(struct vc_data *c) { return 1; /* redrawing needed */ @@ -564,7 +532,6 @@ static const struct consw mda_con = { .con_putcs = mdacon_putcs, .con_cursor = mdacon_cursor, .con_scroll = mdacon_scroll, - .con_bmove = mdacon_bmove, .con_switch = mdacon_switch, .con_blank = mdacon_blank, .con_build_attr = mdacon_build_attr, diff --git a/drivers/video/console/newport_con.c b/drivers/video/console/newport_con.c index a436930..e3b9521 100644 --- a/drivers/video/console/newport_con.c +++ b/drivers/video/console/newport_con.c @@ -673,34 +673,6 @@ static int newport_scroll(struct vc_data *vc, int t, int b, int dir, return 1; } -static void newport_bmove(struct vc_data *vc, int sy, int sx, int dy, - int dx, int h, int w) -{ - short xs, ys, xe, ye, xoffs, yoffs; - - xs = sx << 3; - xe = ((sx + w) << 3) - 1; - /* - * as bmove is only used to move stuff around in the same line - * (h == 1), we don't care about wrap arounds caused by topscan != 0 - */ - ys = ((sy << 4) + topscan) & 0x3ff; - ye = (((sy + h) << 4) - 1 + topscan) & 0x3ff; - xoffs = (dx - sx) << 3; - yoffs = (dy - sy) << 4; - if (xoffs > 0) { - /* move to the right, exchange starting points */ - swap(xe, xs); - } - newport_wait(npregs); - npregs->set.drawmode0 = (NPORT_DMODE0_S2S | NPORT_DMODE0_BLOCK | - NPORT_DMODE0_DOSETUP | NPORT_DMODE0_STOPX - | NPORT_DMODE0_STOPY); - npregs->set.xystarti = (xs << 16) | ys; - npregs->set.xyendi = (xe << 16) | ye; - npregs->go.xymove = (xoffs << 16) | yoffs; -} - static int newport_dummy(struct vc_data *c) { return 0; @@ -718,7 +690,6 @@ const struct consw newport_con = { .con_putcs = newport_putcs, .con_cursor = newport_cursor, .con_scroll = newport_scroll, - .con_bmove = newport_bmove, .con_switch = newport_switch, .con_blank = newport_blank, .con_font_set = newport_font_set, diff --git a/drivers/video/console/sticon.c b/drivers/video/console/sticon.c index fe7c4db..3a10ac1 100644 --- a/drivers/video/console/sticon.c +++ b/drivers/video/console/sticon.c @@ -177,22 +177,6 @@ static int sticon_scroll(struct vc_data *conp, int t, int b, int dir, int count) return 0; } -static void sticon_bmove(struct vc_data *conp, int sy, int sx, - int dy, int dx, int height, int width) -{ - if (!width || !height) - return; -#if 0 - if (((sy <= p->cursor_y) && (p->cursor_y < sy+height) && - (sx <= p->cursor_x) && (p->cursor_x < sx+width)) || - ((dy <= p->cursor_y) && (p->cursor_y < dy+height) && - (dx <= p->cursor_x) && (p->cursor_x < dx+width))) - sticon_cursor(p, CM_ERASE /*|CM_SOFTBACK*/); -#endif - - sti_bmove(sticon_sti, sy, sx, dy, dx, height, width); -} - static void sticon_init(struct vc_data *c, int init) { struct sti_struct *sti = sticon_sti; @@ -345,7 +329,6 @@ static const struct consw sti_con = { .con_putcs = sticon_putcs, .con_cursor = sticon_cursor, .con_scroll = sticon_scroll, - .con_bmove = sticon_bmove, .con_switch = sticon_switch, .con_blank = sticon_blank, .con_set_origin = sticon_set_origin, diff --git a/drivers/video/console/vgacon.c b/drivers/video/console/vgacon.c index aaae9bd..e280b3c 100644 --- a/drivers/video/console/vgacon.c +++ b/drivers/video/console/vgacon.c @@ -1421,7 +1421,6 @@ const struct consw vga_con = { .con_putcs = DUMMY, .con_cursor = vgacon_cursor, .con_scroll = vgacon_scroll, - .con_bmove = DUMMY, .con_switch = vgacon_switch, .con_blank = vgacon_blank, .con_font_set = vgacon_font_set, diff --git a/include/linux/console.h b/include/linux/console.h index 382a527..d530c46 100644 --- a/include/linux/console.h +++ b/include/linux/console.h @@ -45,7 +45,6 @@ struct consw { void (*con_putcs)(struct vc_data *, const unsigned short *, int, int, int); void (*con_cursor)(struct vc_data *, int); int (*con_scroll)(struct vc_data *, int, int, int, int); - void (*con_bmove)(struct vc_data *, int, int, int, int, int, int); int (*con_switch)(struct vc_data *); int (*con_blank)(struct vc_data *, int, int); int (*con_font_set)(struct vc_data *, struct console_font *, unsigned); -- cgit v0.10.2 From 6af39ed30264691994647daba07a416830f674b2 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Thu, 23 Jun 2016 13:34:29 +0200 Subject: tty: vt, drop VT_BUF_VRAM_ONLY It is never defined. And I spent quite some time looking into the history and cannot find how this was ever used. Given it was not used in the history, I doubt it currently works as expected after the years of changes all over the code. So kill it. Signed-off-by: Jiri Slaby Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index d5d9060..600c3bb 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -278,12 +278,7 @@ static void notify_update(struct vc_data *vc) */ #define IS_FG(vc) ((vc)->vc_num == fg_console) - -#ifdef VT_BUF_VRAM_ONLY -#define DO_UPDATE(vc) 0 -#else #define DO_UPDATE(vc) (CON_IS_VISIBLE(vc) && !console_blanked) -#endif static inline unsigned short *screenpos(struct vc_data *vc, int offset, int viewed) { @@ -349,7 +344,6 @@ static void scrdown(struct vc_data *vc, unsigned int t, unsigned int b, int nr) static void do_update_region(struct vc_data *vc, unsigned long start, int count) { -#ifndef VT_BUF_VRAM_ONLY unsigned int xx, yy, offset; u16 *p; @@ -390,7 +384,6 @@ static void do_update_region(struct vc_data *vc, unsigned long start, int count) start = vc->vc_sw->con_getxy(vc, start, NULL, NULL); } } -#endif } void update_region(struct vc_data *vc, unsigned long start, int count) @@ -413,7 +406,6 @@ static u8 build_attr(struct vc_data *vc, u8 _color, u8 _intensity, u8 _blink, return vc->vc_sw->con_build_attr(vc, _color, _intensity, _blink, _underline, _reverse, _italic); -#ifndef VT_BUF_VRAM_ONLY /* * ++roman: I completely changed the attribute format for monochrome * mode (!can_do_color). The formerly used MDA (monochrome display @@ -448,9 +440,6 @@ static u8 build_attr(struct vc_data *vc, u8 _color, u8 _intensity, u8 _blink, a <<= 1; return a; } -#else - return 0; -#endif } static void update_attr(struct vc_data *vc) @@ -470,10 +459,9 @@ void invert_screen(struct vc_data *vc, int offset, int count, int viewed) count /= 2; p = screenpos(vc, offset, viewed); - if (vc->vc_sw->con_invert_region) + if (vc->vc_sw->con_invert_region) { vc->vc_sw->con_invert_region(vc, p, count); -#ifndef VT_BUF_VRAM_ONLY - else { + } else { u16 *q = p; int cnt = count; u16 a; @@ -501,7 +489,7 @@ void invert_screen(struct vc_data *vc, int offset, int count, int viewed) } } } -#endif + if (DO_UPDATE(vc)) do_update_region(vc, (unsigned long) p, count); notify_update(vc); @@ -2178,14 +2166,10 @@ static int is_double_width(uint32_t ucs) /* acquires console_lock */ static int do_con_write(struct tty_struct *tty, const unsigned char *buf, int count) { -#ifdef VT_BUF_VRAM_ONLY -#define FLUSH do { } while(0); -#else #define FLUSH if (draw_x >= 0) { \ vc->vc_sw->con_putcs(vc, (u16 *)draw_from, (u16 *)draw_to - (u16 *)draw_from, vc->vc_y, draw_x); \ draw_x = -1; \ } -#endif int c, tc, ok, n = 0, draw_x = -1; unsigned int currcons; -- cgit v0.10.2 From d711ea8f762eec3bc057bc92423c6ec804523a40 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Thu, 23 Jun 2016 13:34:30 +0200 Subject: tty: vt, get rid of ugly FLUSH macro It's a macro accessing and changing some local variables. And the code uses it without appending semicolon which confuses everybody too. Switch from this bad guy to a sane standard function. Signed-off-by: Jiri Slaby Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index 600c3bb..6e12d9c 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -2163,14 +2163,20 @@ static int is_double_width(uint32_t ucs) return bisearch(ucs, double_width, ARRAY_SIZE(double_width) - 1); } +static void con_flush(struct vc_data *vc, unsigned long draw_from, + unsigned long draw_to, int *draw_x) +{ + if (*draw_x < 0) + return; + + vc->vc_sw->con_putcs(vc, (u16 *)draw_from, + (u16 *)draw_to - (u16 *)draw_from, vc->vc_y, *draw_x); + *draw_x = -1; +} + /* acquires console_lock */ static int do_con_write(struct tty_struct *tty, const unsigned char *buf, int count) { -#define FLUSH if (draw_x >= 0) { \ - vc->vc_sw->con_putcs(vc, (u16 *)draw_from, (u16 *)draw_to - (u16 *)draw_from, vc->vc_y, draw_x); \ - draw_x = -1; \ - } - int c, tc, ok, n = 0, draw_x = -1; unsigned int currcons; unsigned long draw_from = 0, draw_to = 0; @@ -2362,12 +2368,13 @@ rescan_last_byte: } else { vc_attr = ((vc->vc_attr) & 0x88) | (((vc->vc_attr) & 0x70) >> 4) | (((vc->vc_attr) & 0x07) << 4); } - FLUSH + con_flush(vc, draw_from, draw_to, &draw_x); } while (1) { if (vc->vc_need_wrap || vc->vc_decim) - FLUSH + con_flush(vc, draw_from, draw_to, + &draw_x); if (vc->vc_need_wrap) { cr(vc); lf(vc); @@ -2397,9 +2404,8 @@ rescan_last_byte: } notify_write(vc, c); - if (inverse) { - FLUSH - } + if (inverse) + con_flush(vc, draw_from, draw_to, &draw_x); if (rescan) { rescan = 0; @@ -2410,15 +2416,14 @@ rescan_last_byte: } continue; } - FLUSH + con_flush(vc, draw_from, draw_to, &draw_x); do_con_trol(tty, vc, orig); } - FLUSH + con_flush(vc, draw_from, draw_to, &draw_x); console_conditional_schedule(); console_unlock(); notify_update(vc); return n; -#undef FLUSH } /* -- cgit v0.10.2 From e05ab238e30572abbac0cc4aba051553928de949 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Thu, 23 Jun 2016 13:34:31 +0200 Subject: tty: vt, separate T.416 high colors handler The code with T.416 high colors handling is flushed to the right and hard to read. Move the code to a separate function and remove code duplication for foreground & background colors. Signed-off-by: Jiri Slaby Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index 6e12d9c..da49f5c 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -1284,6 +1284,40 @@ static void rgb_background(struct vc_data *vc, struct rgb c) | (c.r&0x80) >> 1 | (c.g&0x80) >> 2 | (c.b&0x80) >> 3; } +/* + * ITU T.416 Higher colour modes. They break the usual properties of SGR codes + * and thus need to be detected and ignored by hand. Strictly speaking, that + * standard also wants : rather than ; as separators, contrary to ECMA-48, but + * no one produces such codes and almost no one accepts them. + * + * Subcommands 3 (CMY) and 4 (CMYK) are so insane there's no point in + * supporting them. + */ +static int vc_t416_color(struct vc_data *vc, int i, + void(*set_color)(struct vc_data *vc, struct rgb c)) +{ + i++; + if (i > vc->vc_npar) + return i; + + if (vc->vc_par[i] == 5 && i < vc->vc_npar) { + /* 256 colours -- ubiquitous */ + i++; + set_color(vc, rgb_from_256(vc->vc_par[i])); + } else if (vc->vc_par[i] == 2 && i <= vc->vc_npar + 3) { + /* 24 bit -- extremely rare */ + struct rgb c = { + .r = vc->vc_par[i + 1], + .g = vc->vc_par[i + 2], + .b = vc->vc_par[i + 3], + }; + set_color(vc, c); + i += 3; + } + + return i; +} + /* console_lock is held */ static void csi_m(struct vc_data *vc) { @@ -1355,56 +1389,11 @@ static void csi_m(struct vc_data *vc) case 27: vc->vc_reverse = 0; break; - case 38: /* ITU T.416 - * Higher colour modes. - * They break the usual properties of SGR codes - * and thus need to be detected and ignored by - * hand. Strictly speaking, that standard also - * wants : rather than ; as separators, contrary - * to ECMA-48, but no one produces such codes - * and almost no one accepts them. - */ - i++; - if (i > vc->vc_npar) - break; - if (vc->vc_par[i] == 5 && /* 256 colours */ - i < vc->vc_npar) { /* ubiquitous */ - i++; - rgb_foreground(vc, - rgb_from_256(vc->vc_par[i])); - } else if (vc->vc_par[i] == 2 && /* 24 bit */ - i <= vc->vc_npar + 3) {/* extremely rare */ - struct rgb c = { - .r = vc->vc_par[i + 1], - .g = vc->vc_par[i + 2], - .b = vc->vc_par[i + 3], - }; - rgb_foreground(vc, c); - i += 3; - } - /* Subcommands 3 (CMY) and 4 (CMYK) are so insane - * there's no point in supporting them. - */ + case 38: + i = vc_t416_color(vc, i, rgb_foreground); break; case 48: - i++; - if (i > vc->vc_npar) - break; - if (vc->vc_par[i] == 5 && /* 256 colours */ - i < vc->vc_npar) { - i++; - rgb_background(vc, - rgb_from_256(vc->vc_par[i])); - } else if (vc->vc_par[i] == 2 && /* 24 bit */ - i <= vc->vc_npar + 3) { - struct rgb c = { - .r = vc->vc_par[i + 1], - .g = vc->vc_par[i + 2], - .b = vc->vc_par[i + 3], - }; - rgb_background(vc, c); - i += 3; - } + i = vc_t416_color(vc, i, rgb_background); break; case 39: vc->vc_color = (vc->vc_def_color & 0x0f) | (vc->vc_color & 0xf0); -- cgit v0.10.2 From 0f91e14264cb04c90987206f30d97385eef121c9 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Thu, 23 Jun 2016 13:34:32 +0200 Subject: tty: vt, do not pass structure over stack The compiler noticed passing structure over stack. Even though rgb is a small structure, let us define one and pass that over all the functions wherever needed. Signed-off-by: Jiri Slaby Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index da49f5c..6397233 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -1240,36 +1240,34 @@ static void default_attr(struct vc_data *vc) struct rgb { u8 r; u8 g; u8 b; }; -static struct rgb rgb_from_256(int i) +static void rgb_from_256(int i, struct rgb *c) { - struct rgb c; if (i < 8) { /* Standard colours. */ - c.r = i&1 ? 0xaa : 0x00; - c.g = i&2 ? 0xaa : 0x00; - c.b = i&4 ? 0xaa : 0x00; + c->r = i&1 ? 0xaa : 0x00; + c->g = i&2 ? 0xaa : 0x00; + c->b = i&4 ? 0xaa : 0x00; } else if (i < 16) { - c.r = i&1 ? 0xff : 0x55; - c.g = i&2 ? 0xff : 0x55; - c.b = i&4 ? 0xff : 0x55; + c->r = i&1 ? 0xff : 0x55; + c->g = i&2 ? 0xff : 0x55; + c->b = i&4 ? 0xff : 0x55; } else if (i < 232) { /* 6x6x6 colour cube. */ - c.r = (i - 16) / 36 * 85 / 2; - c.g = (i - 16) / 6 % 6 * 85 / 2; - c.b = (i - 16) % 6 * 85 / 2; + c->r = (i - 16) / 36 * 85 / 2; + c->g = (i - 16) / 6 % 6 * 85 / 2; + c->b = (i - 16) % 6 * 85 / 2; } else /* Grayscale ramp. */ - c.r = c.g = c.b = i * 10 - 2312; - return c; + c->r = c->g = c->b = i * 10 - 2312; } -static void rgb_foreground(struct vc_data *vc, struct rgb c) +static void rgb_foreground(struct vc_data *vc, const struct rgb *c) { - u8 hue, max = c.r; - if (c.g > max) - max = c.g; - if (c.b > max) - max = c.b; - hue = (c.r > max/2 ? 4 : 0) - | (c.g > max/2 ? 2 : 0) - | (c.b > max/2 ? 1 : 0); + u8 hue, max = c->r; + if (c->g > max) + max = c->g; + if (c->b > max) + max = c->b; + hue = (c->r > max/2 ? 4 : 0) + | (c->g > max/2 ? 2 : 0) + | (c->b > max/2 ? 1 : 0); if (hue == 7 && max <= 0x55) hue = 0, vc->vc_intensity = 2; else @@ -1277,11 +1275,11 @@ static void rgb_foreground(struct vc_data *vc, struct rgb c) vc->vc_color = (vc->vc_color & 0xf0) | hue; } -static void rgb_background(struct vc_data *vc, struct rgb c) +static void rgb_background(struct vc_data *vc, const struct rgb *c) { /* For backgrounds, err on the dark side. */ vc->vc_color = (vc->vc_color & 0x0f) - | (c.r&0x80) >> 1 | (c.g&0x80) >> 2 | (c.b&0x80) >> 3; + | (c->r&0x80) >> 1 | (c->g&0x80) >> 2 | (c->b&0x80) >> 3; } /* @@ -1294,8 +1292,10 @@ static void rgb_background(struct vc_data *vc, struct rgb c) * supporting them. */ static int vc_t416_color(struct vc_data *vc, int i, - void(*set_color)(struct vc_data *vc, struct rgb c)) + void(*set_color)(struct vc_data *vc, const struct rgb *c)) { + struct rgb c; + i++; if (i > vc->vc_npar) return i; @@ -1303,17 +1303,17 @@ static int vc_t416_color(struct vc_data *vc, int i, if (vc->vc_par[i] == 5 && i < vc->vc_npar) { /* 256 colours -- ubiquitous */ i++; - set_color(vc, rgb_from_256(vc->vc_par[i])); + rgb_from_256(vc->vc_par[i], &c); } else if (vc->vc_par[i] == 2 && i <= vc->vc_npar + 3) { /* 24 bit -- extremely rare */ - struct rgb c = { - .r = vc->vc_par[i + 1], - .g = vc->vc_par[i + 2], - .b = vc->vc_par[i + 3], - }; - set_color(vc, c); + c.r = vc->vc_par[i + 1]; + c.g = vc->vc_par[i + 2]; + c.b = vc->vc_par[i + 3]; i += 3; - } + } else + return i; + + set_color(vc, &c); return i; } -- cgit v0.10.2 From 193df0227964a0620267bb0236dfd6463a0ccea0 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Thu, 23 Jun 2016 13:34:33 +0200 Subject: tty: vt, too many commands per line in rgb_foreground Do not opencode max3, use the macro. Separate commands. Until now, I have not noticed the comma. Make it one line, one command. And make the code obvious. Signed-off-by: Jiri Slaby Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index 6397233..acecd66 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -1260,18 +1260,23 @@ static void rgb_from_256(int i, struct rgb *c) static void rgb_foreground(struct vc_data *vc, const struct rgb *c) { - u8 hue, max = c->r; - if (c->g > max) - max = c->g; - if (c->b > max) - max = c->b; - hue = (c->r > max/2 ? 4 : 0) - | (c->g > max/2 ? 2 : 0) - | (c->b > max/2 ? 1 : 0); - if (hue == 7 && max <= 0x55) - hue = 0, vc->vc_intensity = 2; + u8 hue = 0, max = max3(c->r, c->g, c->b); + + if (c->r > max / 2) + hue |= 4; + if (c->g > max / 2) + hue |= 2; + if (c->b > max / 2) + hue |= 1; + + if (hue == 7 && max <= 0x55) { + hue = 0; + vc->vc_intensity = 2; + } else if (max > 0xaa) + vc->vc_intensity = 2; else - vc->vc_intensity = (max > 0xaa) + 1; + vc->vc_intensity = 1; + vc->vc_color = (vc->vc_color & 0xf0) | hue; } -- cgit v0.10.2 From aada0a344182e3aec7bfb0cc611f272e6297c3e3 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Thu, 23 Jun 2016 13:34:34 +0200 Subject: tty: vt, whitespace cleanup in csi_m Flush the switch cases to be aligned with the switch. Mostly everything can now fit to the 80-chars terminal. Signed-off-by: Jiri Slaby Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index acecd66..8ceabfd 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -1330,90 +1330,91 @@ static void csi_m(struct vc_data *vc) for (i = 0; i <= vc->vc_npar; i++) switch (vc->vc_par[i]) { - case 0: /* all attributes off */ - default_attr(vc); - break; - case 1: - vc->vc_intensity = 2; - break; - case 2: - vc->vc_intensity = 0; - break; - case 3: - vc->vc_italic = 1; - break; - case 4: - vc->vc_underline = 1; - break; - case 5: - vc->vc_blink = 1; - break; - case 7: - vc->vc_reverse = 1; - break; - case 10: /* ANSI X3.64-1979 (SCO-ish?) - * Select primary font, don't display - * control chars if defined, don't set - * bit 8 on output. - */ - vc->vc_translate = set_translate(vc->vc_charset == 0 - ? vc->vc_G0_charset - : vc->vc_G1_charset, vc); - vc->vc_disp_ctrl = 0; - vc->vc_toggle_meta = 0; - break; - case 11: /* ANSI X3.64-1979 (SCO-ish?) - * Select first alternate font, lets - * chars < 32 be displayed as ROM chars. - */ - vc->vc_translate = set_translate(IBMPC_MAP, vc); - vc->vc_disp_ctrl = 1; - vc->vc_toggle_meta = 0; - break; - case 12: /* ANSI X3.64-1979 (SCO-ish?) - * Select second alternate font, toggle - * high bit before displaying as ROM char. - */ - vc->vc_translate = set_translate(IBMPC_MAP, vc); - vc->vc_disp_ctrl = 1; - vc->vc_toggle_meta = 1; - break; - case 21: - case 22: - vc->vc_intensity = 1; - break; - case 23: - vc->vc_italic = 0; - break; - case 24: - vc->vc_underline = 0; - break; - case 25: - vc->vc_blink = 0; - break; - case 27: - vc->vc_reverse = 0; - break; - case 38: - i = vc_t416_color(vc, i, rgb_foreground); - break; - case 48: - i = vc_t416_color(vc, i, rgb_background); - break; - case 39: - vc->vc_color = (vc->vc_def_color & 0x0f) | (vc->vc_color & 0xf0); - break; - case 49: - vc->vc_color = (vc->vc_def_color & 0xf0) | (vc->vc_color & 0x0f); - break; - default: - if (vc->vc_par[i] >= 30 && vc->vc_par[i] <= 37) - vc->vc_color = color_table[vc->vc_par[i] - 30] - | (vc->vc_color & 0xf0); - else if (vc->vc_par[i] >= 40 && vc->vc_par[i] <= 47) - vc->vc_color = (color_table[vc->vc_par[i] - 40] << 4) - | (vc->vc_color & 0x0f); - break; + case 0: /* all attributes off */ + default_attr(vc); + break; + case 1: + vc->vc_intensity = 2; + break; + case 2: + vc->vc_intensity = 0; + break; + case 3: + vc->vc_italic = 1; + break; + case 4: + vc->vc_underline = 1; + break; + case 5: + vc->vc_blink = 1; + break; + case 7: + vc->vc_reverse = 1; + break; + case 10: /* ANSI X3.64-1979 (SCO-ish?) + * Select primary font, don't display control chars if + * defined, don't set bit 8 on output. + */ + vc->vc_translate = set_translate(vc->vc_charset == 0 + ? vc->vc_G0_charset + : vc->vc_G1_charset, vc); + vc->vc_disp_ctrl = 0; + vc->vc_toggle_meta = 0; + break; + case 11: /* ANSI X3.64-1979 (SCO-ish?) + * Select first alternate font, lets chars < 32 be + * displayed as ROM chars. + */ + vc->vc_translate = set_translate(IBMPC_MAP, vc); + vc->vc_disp_ctrl = 1; + vc->vc_toggle_meta = 0; + break; + case 12: /* ANSI X3.64-1979 (SCO-ish?) + * Select second alternate font, toggle high bit + * before displaying as ROM char. + */ + vc->vc_translate = set_translate(IBMPC_MAP, vc); + vc->vc_disp_ctrl = 1; + vc->vc_toggle_meta = 1; + break; + case 21: + case 22: + vc->vc_intensity = 1; + break; + case 23: + vc->vc_italic = 0; + break; + case 24: + vc->vc_underline = 0; + break; + case 25: + vc->vc_blink = 0; + break; + case 27: + vc->vc_reverse = 0; + break; + case 38: + i = vc_t416_color(vc, i, rgb_foreground); + break; + case 48: + i = vc_t416_color(vc, i, rgb_background); + break; + case 39: + vc->vc_color = (vc->vc_def_color & 0x0f) | + (vc->vc_color & 0xf0); + break; + case 49: + vc->vc_color = (vc->vc_def_color & 0xf0) | + (vc->vc_color & 0x0f); + break; + default: + if (vc->vc_par[i] >= 30 && vc->vc_par[i] <= 37) + vc->vc_color = color_table[vc->vc_par[i] - 30] + | (vc->vc_color & 0xf0); + else if (vc->vc_par[i] >= 40 && vc->vc_par[i] <= 47) + vc->vc_color = (color_table[vc->vc_par[i] - 40] << 4) + | (vc->vc_color & 0x0f); + break; } update_attr(vc); } -- cgit v0.10.2 From 6ca8dfd78187d8238abc5b2996848a0c8f07948d Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Thu, 23 Jun 2016 13:34:35 +0200 Subject: tty: vt, convert more macros to functions Namely convert: * IS_FG -> con_is_fg * DO_UPDATE -> con_should_update * CON_IS_VISIBLE -> con_is_visible DO_UPDATE was a weird name for a yes/no answer, so the new name is con_should_update. Signed-off-by: Jiri Slaby Cc: Thomas Winischhofer Cc: Jean-Christophe Plagniol-Villard Cc: linux-usb@vger.kernel.org Cc: linux-fbdev@vger.kernel.org Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index 8ceabfd..26de5c0 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -277,8 +277,15 @@ static void notify_update(struct vc_data *vc) * Low-Level Functions */ -#define IS_FG(vc) ((vc)->vc_num == fg_console) -#define DO_UPDATE(vc) (CON_IS_VISIBLE(vc) && !console_blanked) +static inline bool con_is_fg(const struct vc_data *vc) +{ + return vc->vc_num == fg_console; +} + +static inline bool con_should_update(const struct vc_data *vc) +{ + return con_is_visible(vc) && !console_blanked; +} static inline unsigned short *screenpos(struct vc_data *vc, int offset, int viewed) { @@ -316,7 +323,7 @@ static void scrup(struct vc_data *vc, unsigned int t, unsigned int b, int nr) nr = b - t - 1; if (b > vc->vc_rows || t >= b || nr < 1) return; - if (CON_IS_VISIBLE(vc) && vc->vc_sw->con_scroll(vc, t, b, SM_UP, nr)) + if (con_is_visible(vc) && vc->vc_sw->con_scroll(vc, t, b, SM_UP, nr)) return; d = (unsigned short *)(vc->vc_origin + vc->vc_size_row * t); s = (unsigned short *)(vc->vc_origin + vc->vc_size_row * (t + nr)); @@ -334,7 +341,7 @@ static void scrdown(struct vc_data *vc, unsigned int t, unsigned int b, int nr) nr = b - t - 1; if (b > vc->vc_rows || t >= b || nr < 1) return; - if (CON_IS_VISIBLE(vc) && vc->vc_sw->con_scroll(vc, t, b, SM_DOWN, nr)) + if (con_is_visible(vc) && vc->vc_sw->con_scroll(vc, t, b, SM_DOWN, nr)) return; s = (unsigned short *)(vc->vc_origin + vc->vc_size_row * t); step = vc->vc_cols * nr; @@ -390,7 +397,7 @@ void update_region(struct vc_data *vc, unsigned long start, int count) { WARN_CONSOLE_UNLOCKED(); - if (DO_UPDATE(vc)) { + if (con_should_update(vc)) { hide_cursor(vc); do_update_region(vc, start, count); set_cursor(vc); @@ -490,7 +497,7 @@ void invert_screen(struct vc_data *vc, int offset, int count, int viewed) } } - if (DO_UPDATE(vc)) + if (con_should_update(vc)) do_update_region(vc, (unsigned long) p, count); notify_update(vc); } @@ -507,7 +514,7 @@ void complement_pos(struct vc_data *vc, int offset) if (old_offset != -1 && old_offset >= 0 && old_offset < vc->vc_screenbuf_size) { scr_writew(old, screenpos(vc, old_offset, 1)); - if (DO_UPDATE(vc)) + if (con_should_update(vc)) vc->vc_sw->con_putc(vc, old, oldy, oldx); notify_update(vc); } @@ -522,7 +529,7 @@ void complement_pos(struct vc_data *vc, int offset) old = scr_readw(p); new = old ^ vc->vc_complement_mask; scr_writew(new, p); - if (DO_UPDATE(vc)) { + if (con_should_update(vc)) { oldx = (offset >> 1) % vc->vc_cols; oldy = (offset >> 1) / vc->vc_cols; vc->vc_sw->con_putc(vc, new, oldy, oldx); @@ -538,7 +545,7 @@ static void insert_char(struct vc_data *vc, unsigned int nr) scr_memmovew(p + nr, p, (vc->vc_cols - vc->vc_x - nr) * 2); scr_memsetw(p, vc->vc_video_erase_char, nr * 2); vc->vc_need_wrap = 0; - if (DO_UPDATE(vc)) + if (con_should_update(vc)) do_update_region(vc, (unsigned long) p, vc->vc_cols - vc->vc_x); } @@ -551,7 +558,7 @@ static void delete_char(struct vc_data *vc, unsigned int nr) scr_memsetw(p + vc->vc_cols - vc->vc_x - nr, vc->vc_video_erase_char, nr * 2); vc->vc_need_wrap = 0; - if (DO_UPDATE(vc)) + if (con_should_update(vc)) do_update_region(vc, (unsigned long) p, vc->vc_cols - vc->vc_x); } @@ -571,7 +578,7 @@ static void add_softcursor(struct vc_data *vc) if ((type & 0x20) && ((softcursor_original & 0x7000) == (i & 0x7000))) i ^= 0x7000; if ((type & 0x40) && ((i & 0x700) == ((i & 0x7000) >> 4))) i ^= 0x0700; scr_writew(i, (u16 *) vc->vc_pos); - if (DO_UPDATE(vc)) + if (con_should_update(vc)) vc->vc_sw->con_putc(vc, i, vc->vc_y, vc->vc_x); } @@ -579,7 +586,7 @@ static void hide_softcursor(struct vc_data *vc) { if (softcursor_original != -1) { scr_writew(softcursor_original, (u16 *)vc->vc_pos); - if (DO_UPDATE(vc)) + if (con_should_update(vc)) vc->vc_sw->con_putc(vc, softcursor_original, vc->vc_y, vc->vc_x); softcursor_original = -1; @@ -596,8 +603,7 @@ static void hide_cursor(struct vc_data *vc) static void set_cursor(struct vc_data *vc) { - if (!IS_FG(vc) || console_blanked || - vc->vc_mode == KD_GRAPHICS) + if (!con_is_fg(vc) || console_blanked || vc->vc_mode == KD_GRAPHICS) return; if (vc->vc_deccm) { if (vc == sel_cons) @@ -613,7 +619,7 @@ static void set_origin(struct vc_data *vc) { WARN_CONSOLE_UNLOCKED(); - if (!CON_IS_VISIBLE(vc) || + if (!con_is_visible(vc) || !vc->vc_sw->con_set_origin || !vc->vc_sw->con_set_origin(vc)) vc->vc_origin = (unsigned long)vc->vc_screenbuf; @@ -661,12 +667,12 @@ void redraw_screen(struct vc_data *vc, int is_switch) struct vc_data *old_vc = vc_cons[fg_console].d; if (old_vc == vc) return; - if (!CON_IS_VISIBLE(vc)) + if (!con_is_visible(vc)) redraw = 1; *vc->vc_display_fg = vc; fg_console = vc->vc_num; hide_cursor(old_vc); - if (!CON_IS_VISIBLE(old_vc)) { + if (!con_is_visible(old_vc)) { save_screen(old_vc); set_origin(old_vc); } @@ -941,7 +947,7 @@ static int vc_do_resize(struct tty_struct *tty, struct vc_data *vc, tty_do_resize(tty, &ws); } - if (CON_IS_VISIBLE(vc)) + if (con_is_visible(vc)) update_screen(vc); vt_event_post(VT_EVENT_RESIZE, vc->vc_num, vc->vc_num); return err; @@ -1171,7 +1177,7 @@ static void csi_J(struct vc_data *vc, int vpar) scr_memsetw(vc->vc_screenbuf, vc->vc_video_erase_char, vc->vc_screenbuf_size >> 1); set_origin(vc); - if (CON_IS_VISIBLE(vc)) + if (con_is_visible(vc)) update_screen(vc); /* fall through */ case 2: /* erase whole display */ @@ -1182,7 +1188,7 @@ static void csi_J(struct vc_data *vc, int vpar) return; } scr_memsetw(start, vc->vc_video_erase_char, 2 * count); - if (DO_UPDATE(vc)) + if (con_should_update(vc)) do_update_region(vc, (unsigned long) start, count); vc->vc_need_wrap = 0; } @@ -1210,7 +1216,7 @@ static void csi_K(struct vc_data *vc, int vpar) } scr_memsetw(start, vc->vc_video_erase_char, 2 * count); vc->vc_need_wrap = 0; - if (DO_UPDATE(vc)) + if (con_should_update(vc)) do_update_region(vc, (unsigned long) start, count); } @@ -1223,7 +1229,7 @@ static void csi_X(struct vc_data *vc, int vpar) /* erase the following vpar posi count = (vpar > vc->vc_cols - vc->vc_x) ? (vc->vc_cols - vc->vc_x) : vpar; scr_memsetw((unsigned short *)vc->vc_pos, vc->vc_video_erase_char, 2 * count); - if (DO_UPDATE(vc)) + if (con_should_update(vc)) vc->vc_sw->con_clear(vc, vc->vc_y, vc->vc_x, 1, count); vc->vc_need_wrap = 0; } @@ -2208,7 +2214,7 @@ static int do_con_write(struct tty_struct *tty, const unsigned char *buf, int co charmask = himask ? 0x1ff : 0xff; /* undraw cursor first */ - if (IS_FG(vc)) + if (con_is_fg(vc)) hide_cursor(vc); param.vc = vc; @@ -2380,7 +2386,7 @@ rescan_last_byte: ((vc_attr << 8) & ~himask) + ((tc & 0x100) ? himask : 0) + (tc & 0xff) : (vc_attr << 8) + tc, (u16 *) vc->vc_pos); - if (DO_UPDATE(vc) && draw_x < 0) { + if (con_should_update(vc) && draw_x < 0) { draw_x = vc->vc_x; draw_from = vc->vc_pos; } @@ -2564,7 +2570,7 @@ static void vt_console_print(struct console *co, const char *b, unsigned count) goto quit; /* undraw cursor first */ - if (IS_FG(vc)) + if (con_is_fg(vc)) hide_cursor(vc); start = (ushort *)vc->vc_pos; @@ -2575,7 +2581,7 @@ static void vt_console_print(struct console *co, const char *b, unsigned count) c = *b++; if (c == 10 || c == 13 || c == 8 || vc->vc_need_wrap) { if (cnt > 0) { - if (CON_IS_VISIBLE(vc)) + if (con_is_visible(vc)) vc->vc_sw->con_putcs(vc, start, cnt, vc->vc_y, vc->vc_x); vc->vc_x += cnt; if (vc->vc_need_wrap) @@ -2607,7 +2613,7 @@ static void vt_console_print(struct console *co, const char *b, unsigned count) myx++; } if (cnt > 0) { - if (CON_IS_VISIBLE(vc)) + if (con_is_visible(vc)) vc->vc_sw->con_putcs(vc, start, cnt, vc->vc_y, vc->vc_x); vc->vc_x += cnt; if (vc->vc_x == vc->vc_cols) { @@ -3154,7 +3160,7 @@ static int do_bind_con_driver(const struct consw *csw, int first, int last, j = i; - if (CON_IS_VISIBLE(vc)) { + if (con_is_visible(vc)) { k = i; save_screen(vc); } diff --git a/drivers/usb/misc/sisusbvga/sisusb_con.c b/drivers/usb/misc/sisusbvga/sisusb_con.c index 52a6da9..460cebf 100644 --- a/drivers/usb/misc/sisusbvga/sisusb_con.c +++ b/drivers/usb/misc/sisusbvga/sisusb_con.c @@ -570,7 +570,7 @@ sisusbcon_set_palette(struct vc_data *c, const unsigned char *table) /* Return value not used by vt */ - if (!CON_IS_VISIBLE(c)) + if (!con_is_visible(c)) return; sisusb = sisusb_get_sisusb_lock_and_check(c->vc_num); @@ -1226,7 +1226,7 @@ sisusbcon_do_font_op(struct sisusb_usb_data *sisusb, int set, int slot, struct vc_data *vc = vc_cons[i].d; if (vc && vc->vc_sw == &sisusb_con) { - if (CON_IS_VISIBLE(vc)) { + if (con_is_visible(vc)) { vc->vc_sw->con_cursor(vc, CM_DRAW); } vc->vc_font.height = fh; diff --git a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c index eef8a8b..b87f5cf 100644 --- a/drivers/video/console/fbcon.c +++ b/drivers/video/console/fbcon.c @@ -380,7 +380,7 @@ static void fb_flashcursor(struct work_struct *work) if (ops && ops->currcon != -1) vc = vc_cons[ops->currcon].d; - if (!vc || !CON_IS_VISIBLE(vc) || + if (!vc || !con_is_visible(vc) || registered_fb[con2fb_map[vc->vc_num]] != info || vc->vc_deccm != 1) { console_unlock(); @@ -618,7 +618,7 @@ static void fbcon_prepare_logo(struct vc_data *vc, struct fb_info *info, erase, vc->vc_size_row * logo_lines); - if (CON_IS_VISIBLE(vc) && vc->vc_mode == KD_TEXT) { + if (con_is_visible(vc) && vc->vc_mode == KD_TEXT) { fbcon_clear_margins(vc, 0); update_screen(vc); } @@ -1112,7 +1112,7 @@ static void fbcon_init(struct vc_data *vc, int init) * * We need to do it in fbcon_init() to prevent screen corruption. */ - if (CON_IS_VISIBLE(vc) && vc->vc_mode == KD_TEXT) { + if (con_is_visible(vc) && vc->vc_mode == KD_TEXT) { if (info->fbops->fb_set_par && !(ops->flags & FBCON_FLAGS_INIT)) { ret = info->fbops->fb_set_par(info); @@ -1192,7 +1192,7 @@ static void fbcon_deinit(struct vc_data *vc) if (!ops) goto finished; - if (CON_IS_VISIBLE(vc)) + if (con_is_visible(vc)) fbcon_del_cursor_timer(info); ops->flags &= ~FBCON_FLAGS_INIT; @@ -1397,7 +1397,7 @@ static void fbcon_set_disp(struct fb_info *info, struct fb_var_screeninfo *var, rows /= vc->vc_font.height; vc_resize(vc, cols, rows); - if (CON_IS_VISIBLE(vc)) { + if (con_is_visible(vc)) { update_screen(vc); if (softback_buf) fbcon_update_softback(vc); @@ -2145,7 +2145,7 @@ static int fbcon_resize(struct vc_data *vc, unsigned int width, return -EINVAL; DPRINTK("resize now %ix%i\n", var.xres, var.yres); - if (CON_IS_VISIBLE(vc)) { + if (con_is_visible(vc)) { var.activate = FB_ACTIVATE_NOW | FB_ACTIVATE_FORCE; fb_set_var(info, &var); @@ -2448,7 +2448,7 @@ static int fbcon_do_set_font(struct vc_data *vc, int w, int h, int cnt; char *old_data = NULL; - if (CON_IS_VISIBLE(vc) && softback_lines) + if (con_is_visible(vc) && softback_lines) fbcon_set_origin(vc); resize = (w != vc->vc_font.width) || (h != vc->vc_font.height); @@ -2529,9 +2529,9 @@ static int fbcon_do_set_font(struct vc_data *vc, int w, int h, cols /= w; rows /= h; vc_resize(vc, cols, rows); - if (CON_IS_VISIBLE(vc) && softback_buf) + if (con_is_visible(vc) && softback_buf) fbcon_update_softback(vc); - } else if (CON_IS_VISIBLE(vc) + } else if (con_is_visible(vc) && vc->vc_mode == KD_TEXT) { fbcon_clear_margins(vc, 0); update_screen(vc); @@ -2660,7 +2660,7 @@ static void fbcon_set_palette(struct vc_data *vc, const unsigned char *table) if (fbcon_is_inactive(vc, info)) return; - if (!CON_IS_VISIBLE(vc)) + if (!con_is_visible(vc)) return; depth = fb_get_color_depth(&info->var, &info->fix); @@ -2902,7 +2902,7 @@ static void fbcon_modechanged(struct fb_info *info) p = &fb_display[vc->vc_num]; set_blitting_type(vc, info); - if (CON_IS_VISIBLE(vc)) { + if (con_is_visible(vc)) { var_to_display(p, &info->var, info); cols = FBCON_SWAP(ops->rotate, info->var.xres, info->var.yres); rows = FBCON_SWAP(ops->rotate, info->var.yres, info->var.xres); @@ -2941,7 +2941,7 @@ static void fbcon_set_all_vcs(struct fb_info *info) registered_fb[con2fb_map[i]] != info) continue; - if (CON_IS_VISIBLE(vc)) { + if (con_is_visible(vc)) { fg = i; continue; } @@ -3180,7 +3180,7 @@ static void fbcon_fb_blanked(struct fb_info *info, int blank) registered_fb[con2fb_map[ops->currcon]] != info) return; - if (CON_IS_VISIBLE(vc)) { + if (con_is_visible(vc)) { if (blank) do_blank_screen(0); else diff --git a/drivers/video/console/vgacon.c b/drivers/video/console/vgacon.c index e280b3c..1157661 100644 --- a/drivers/video/console/vgacon.c +++ b/drivers/video/console/vgacon.c @@ -589,7 +589,7 @@ static void vgacon_init(struct vc_data *c, int init) static void vgacon_deinit(struct vc_data *c) { /* When closing the active console, reset video origin */ - if (CON_IS_VISIBLE(c)) { + if (con_is_visible(c)) { c->vc_visible_origin = vga_vram_base; vga_set_mem_top(c); } @@ -860,7 +860,7 @@ static void vgacon_set_palette(struct vc_data *vc, const unsigned char *table) { #ifdef CAN_LOAD_PALETTE if (vga_video_type != VIDEO_TYPE_VGAC || vga_palette_blanked - || !CON_IS_VISIBLE(vc)) + || !con_is_visible(vc)) return; vga_set_palette(vc, table); #endif @@ -1248,7 +1248,7 @@ static int vgacon_adjust_height(struct vc_data *vc, unsigned fontheight) struct vc_data *c = vc_cons[i].d; if (c && c->vc_sw == &vga_con) { - if (CON_IS_VISIBLE(c)) { + if (con_is_visible(c)) { /* void size to cause regs to be rewritten */ cursor_size_lastfrom = 0; cursor_size_lastto = 0; @@ -1312,7 +1312,7 @@ static int vgacon_resize(struct vc_data *c, unsigned int width, return success */ return (user) ? 0 : -EINVAL; - if (CON_IS_VISIBLE(c) && !vga_is_gfx) /* who knows */ + if (con_is_visible(c) && !vga_is_gfx) /* who knows */ vgacon_doresize(c, width, height); return 0; } diff --git a/include/linux/console_struct.h b/include/linux/console_struct.h index 5fa605c..a12d3f2 100644 --- a/include/linux/console_struct.h +++ b/include/linux/console_struct.h @@ -168,6 +168,9 @@ extern void vc_SAK(struct work_struct *work); #define CUR_DEFAULT CUR_UNDERLINE -#define CON_IS_VISIBLE(conp) (*conp->vc_display_fg == conp) +static inline bool con_is_visible(const struct vc_data *vc) +{ + return *vc->vc_display_fg == vc; +} #endif /* _LINUX_CONSOLE_STRUCT_H */ -- cgit v0.10.2 From f8b0c2e688f086d22157afc734755ed370e288dc Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Thu, 23 Jun 2016 13:34:36 +0200 Subject: tty: vt, ignore PIO_UNIMAPCLR param We do not do hashtables for unicode fonts since 1995 (1.3.28). So it is time to remove the second parameter of con_clear_unimap and ignore the advice from userspace completely. Signed-off-by: Jiri Slaby Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/vt/consolemap.c b/drivers/tty/vt/consolemap.c index c8c91f0..9d7ab7b 100644 --- a/drivers/tty/vt/consolemap.c +++ b/drivers/tty/vt/consolemap.c @@ -499,9 +499,8 @@ con_insert_unipair(struct uni_pagedir *p, u_short unicode, u_short fontpos) return 0; } -/* ui is a leftover from using a hashtable, but might be used again - Caller must hold the lock */ -static int con_do_clear_unimap(struct vc_data *vc, struct unimapinit *ui) +/* Caller must hold the lock */ +static int con_do_clear_unimap(struct vc_data *vc) { struct uni_pagedir *p, *q; @@ -524,11 +523,11 @@ static int con_do_clear_unimap(struct vc_data *vc, struct unimapinit *ui) return 0; } -int con_clear_unimap(struct vc_data *vc, struct unimapinit *ui) +int con_clear_unimap(struct vc_data *vc) { int ret; console_lock(); - ret = con_do_clear_unimap(vc, ui); + ret = con_do_clear_unimap(vc); console_unlock(); return ret; } @@ -556,7 +555,7 @@ int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list) int j, k; u16 **p1, *p2, l; - err1 = con_do_clear_unimap(vc, NULL); + err1 = con_do_clear_unimap(vc); if (err1) { console_unlock(); return err1; @@ -677,7 +676,7 @@ int con_set_default_unimap(struct vc_data *vc) /* The default font is always 256 characters */ - err = con_do_clear_unimap(vc, NULL); + err = con_do_clear_unimap(vc); if (err) return err; diff --git a/drivers/tty/vt/vt_ioctl.c b/drivers/tty/vt/vt_ioctl.c index 97d5a74..f62c598 100644 --- a/drivers/tty/vt/vt_ioctl.c +++ b/drivers/tty/vt/vt_ioctl.c @@ -1006,16 +1006,10 @@ int vt_ioctl(struct tty_struct *tty, break; case PIO_UNIMAPCLR: - { struct unimapinit ui; if (!perm) return -EPERM; - ret = copy_from_user(&ui, up, sizeof(struct unimapinit)); - if (ret) - ret = -EFAULT; - else - con_clear_unimap(vc, &ui); + con_clear_unimap(vc); break; - } case PIO_UNIMAP: case GIO_UNIMAP: diff --git a/include/linux/vt_kern.h b/include/linux/vt_kern.h index 160f81f..6abd24f 100644 --- a/include/linux/vt_kern.h +++ b/include/linux/vt_kern.h @@ -59,14 +59,13 @@ int tioclinux(struct tty_struct *tty, unsigned long arg); #ifdef CONFIG_CONSOLE_TRANSLATIONS /* consolemap.c */ -struct unimapinit; struct unipair; int con_set_trans_old(unsigned char __user * table); int con_get_trans_old(unsigned char __user * table); int con_set_trans_new(unsigned short __user * table); int con_get_trans_new(unsigned short __user * table); -int con_clear_unimap(struct vc_data *vc, struct unimapinit *ui); +int con_clear_unimap(struct vc_data *vc); int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list); int con_get_unimap(struct vc_data *vc, ushort ct, ushort __user *uct, struct unipair __user *list); int con_set_default_unimap(struct vc_data *vc); @@ -92,7 +91,7 @@ static inline int con_get_trans_new(unsigned short __user *table) { return -EINVAL; } -static inline int con_clear_unimap(struct vc_data *vc, struct unimapinit *ui) +static inline int con_clear_unimap(struct vc_data *vc) { return 0; } -- cgit v0.10.2 From abd530de2a55c1a74271e27d6e8c71c74c25e222 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Thu, 23 Jun 2016 13:34:37 +0200 Subject: tty: vt, remove unused vc_deccolm vc_deccolm is only set and never read, remove the member from vc_data. Signed-off-by: Jiri Slaby Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index 26de5c0..213ce24 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -1482,7 +1482,6 @@ static void set_mode(struct vc_data *vc, int on_off) clr_kbd(vc, decckm); break; case 3: /* 80/132 mode switch unimplemented */ - vc->vc_deccolm = on_off; #if 0 vc_resize(deccolm ? 132 : 80, vc->vc_rows); /* this alone does not suffice; some user mode diff --git a/include/linux/console_struct.h b/include/linux/console_struct.h index a12d3f2..6fd3c90 100644 --- a/include/linux/console_struct.h +++ b/include/linux/console_struct.h @@ -106,7 +106,6 @@ struct vc_data { unsigned int vc_decawm : 1; /* Autowrap Mode */ unsigned int vc_deccm : 1; /* Cursor Visible */ unsigned int vc_decim : 1; /* Insert Mode */ - unsigned int vc_deccolm : 1; /* 80/132 Column Mode */ /* attribute flags */ unsigned int vc_intensity : 2; /* 0=half-bright, 1=normal, 2=bold */ unsigned int vc_italic:1; -- cgit v0.10.2 From 0c529b3fc6c66e618088aa3a998d760d1ad05272 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 3 Jun 2016 12:00:01 +0200 Subject: serial: sh-sci: Update DT binding documentation for GPIO modem lines Amend the DT bindings for the Renesas SCI driver to allow describing optional GPIO-controlled modem lines, which can be used where dedicated modem lines are not available. The property naming is dictated by the Generic Serial DT Bindings. Signed-off-by: Geert Uytterhoeven Acked-by: Rob Herring Cc: devicetree@vger.kernel.org Signed-off-by: Greg Kroah-Hartman diff --git a/Documentation/devicetree/bindings/serial/renesas,sci-serial.txt b/Documentation/devicetree/bindings/serial/renesas,sci-serial.txt index 528c3b9..997baea 100644 --- a/Documentation/devicetree/bindings/serial/renesas,sci-serial.txt +++ b/Documentation/devicetree/bindings/serial/renesas,sci-serial.txt @@ -76,6 +76,8 @@ Optional properties: - dmas: Must contain a list of two references to DMA specifiers, one for transmission, and one for reception. - dma-names: Must contain a list of two DMA names, "tx" and "rx". + - {cts,dsr,dcd,rng,rts,dtr}-gpios: Specify GPIOs for modem lines, cfr. the + generic serial DT bindings in serial.txt. Example: aliases { -- cgit v0.10.2 From b0405dc998e425bbb1f64488b6fda781b627056b Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 3 Jun 2016 12:00:02 +0200 Subject: serial: sh-sci: Update DT binding documentation for dedicated RTS/CTS Some Renesas SCIF UARTs have dedicated lines for RTS/CTS hardware flow control. Whether these lines exist depends on SoC and UART instance inside the SoC. Whether these lines can be used for hardware flow control depends on board wiring. Amend the DT bindings with an optional property to indicate that RTS/CTS hardware flow control lines exist, and can be used as such, according to the Generic Serial DT Bindings. Signed-off-by: Geert Uytterhoeven Acked-by: Rob Herring Cc: devicetree@vger.kernel.org Signed-off-by: Greg Kroah-Hartman diff --git a/Documentation/devicetree/bindings/serial/renesas,sci-serial.txt b/Documentation/devicetree/bindings/serial/renesas,sci-serial.txt index 997baea..7a0e150 100644 --- a/Documentation/devicetree/bindings/serial/renesas,sci-serial.txt +++ b/Documentation/devicetree/bindings/serial/renesas,sci-serial.txt @@ -78,6 +78,8 @@ Optional properties: - dma-names: Must contain a list of two DMA names, "tx" and "rx". - {cts,dsr,dcd,rng,rts,dtr}-gpios: Specify GPIOs for modem lines, cfr. the generic serial DT bindings in serial.txt. + - uart-has-rtscts: Indicates dedicated lines for RTS/CTS hardware flow + control, cfr. the generic serial DT bindings in serial.txt. Example: aliases { -- cgit v0.10.2 From 71e98e0e2aede08d6e0a0f3d94ea28b591ef4306 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 3 Jun 2016 12:00:03 +0200 Subject: serial: sh-sci: Always set TIOCM_CTS in .get_mctrl() callback Documentation/serial/driver clearly states: If the port does not support CTS, DCD or DSR, the driver should indicate that the signal is permanently active. Hence always set TIOCM_CTS, as we currently don't look at the CTS hardware line state at all. FWIW, this fixes the transmit path when hardware-assisted flow control is enabled, and userspace enables CRTSCTS. The receive path is still broken, as RTS is never asserted. Signed-off-by: Geert Uytterhoeven Reviewed-by: Peter Hurley Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c index 0130feb..135f836 100644 --- a/drivers/tty/serial/sh-sci.c +++ b/drivers/tty/serial/sh-sci.c @@ -1835,9 +1835,9 @@ static unsigned int sci_get_mctrl(struct uart_port *port) { /* * CTS/RTS is handled in hardware when supported, while nothing - * else is wired up. Keep it simple and simply assert DSR/CAR. + * else is wired up. Keep it simple and simply assert CTS/DSR/CAR. */ - return TIOCM_DSR | TIOCM_CAR; + return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR; } static void sci_break_ctl(struct uart_port *port, int break_state) -- cgit v0.10.2 From f907c9ea88355ac9fe065ffbd6acc914408b4232 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 3 Jun 2016 12:00:04 +0200 Subject: serial: sh-sci: Add support for GPIO-controlled modem lines Enhance the Renesas SCI UART driver to add support for GPIO-controlled modem lines (CTS, DSR, DCD, RNG, RTS, DTR), using the serial_mctrl_gpio helpers. GPIO-controlled modem lines can be used when dedicated modem lines are not available. Invalid configurations specifying both GPIO RTS/CTS and dedicated RTS/CTS are rejected. Signed-off-by: Geert Uytterhoeven Reviewed-by: Peter Hurley Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig index 7e3a58c..b5c8ad1 100644 --- a/drivers/tty/serial/Kconfig +++ b/drivers/tty/serial/Kconfig @@ -736,6 +736,7 @@ config SERIAL_SH_SCI tristate "SuperH SCI(F) serial port support" depends on SUPERH || ARCH_RENESAS || H8300 || COMPILE_TEST select SERIAL_CORE + select SERIAL_MCTRL_GPIO if GPIOLIB config SERIAL_SH_SCI_NR_UARTS int "Maximum number of SCI(F) serial ports" diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c index 135f836..bf3780a 100644 --- a/drivers/tty/serial/sh-sci.c +++ b/drivers/tty/serial/sh-sci.c @@ -57,6 +57,7 @@ #include #endif +#include "serial_mctrl_gpio.h" #include "sh-sci.h" /* Offsets into the sci_port->irqs array */ @@ -111,6 +112,7 @@ struct sci_port { unsigned int error_clear; unsigned int sampling_rate_mask; resource_size_t reg_size; + struct mctrl_gpios *gpios; /* Break timer */ struct timer_list break_timer; @@ -1817,6 +1819,8 @@ static unsigned int sci_tx_empty(struct uart_port *port) */ static void sci_set_mctrl(struct uart_port *port, unsigned int mctrl) { + struct sci_port *s = to_sci_port(port); + if (mctrl & TIOCM_LOOP) { const struct plat_sci_reg *reg; @@ -1829,15 +1833,35 @@ static void sci_set_mctrl(struct uart_port *port, unsigned int mctrl) serial_port_in(port, SCFCR) | SCFCR_LOOP); } + + mctrl_gpio_set(s->gpios, mctrl); } static unsigned int sci_get_mctrl(struct uart_port *port) { + struct sci_port *s = to_sci_port(port); + struct mctrl_gpios *gpios = s->gpios; + unsigned int mctrl = 0; + + mctrl_gpio_get(gpios, &mctrl); + /* * CTS/RTS is handled in hardware when supported, while nothing * else is wired up. Keep it simple and simply assert CTS/DSR/CAR. */ - return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR; + if (IS_ERR_OR_NULL(mctrl_gpio_to_gpiod(gpios, UART_GPIO_CTS))) + mctrl |= TIOCM_CTS; + if (IS_ERR_OR_NULL(mctrl_gpio_to_gpiod(gpios, UART_GPIO_DSR))) + mctrl |= TIOCM_DSR; + if (IS_ERR_OR_NULL(mctrl_gpio_to_gpiod(gpios, UART_GPIO_DCD))) + mctrl |= TIOCM_CAR; + + return mctrl; +} + +static void sci_enable_ms(struct uart_port *port) +{ + mctrl_gpio_enable_ms(to_sci_port(port)->gpios); } static void sci_break_ctl(struct uart_port *port, int break_state) @@ -1899,6 +1923,8 @@ static void sci_shutdown(struct uart_port *port) dev_dbg(port->dev, "%s(%d)\n", __func__, port->line); + mctrl_gpio_disable_ms(to_sci_port(port)->gpios); + spin_lock_irqsave(&port->lock, flags); sci_stop_rx(port); sci_stop_tx(port); @@ -2300,6 +2326,9 @@ done: sci_start_rx(port); sci_port_disable(s); + + if (UART_ENABLE_MS(port, termios->c_cflag)) + sci_enable_ms(port); } static void sci_pm(struct uart_port *port, unsigned int state, @@ -2425,6 +2454,7 @@ static struct uart_ops sci_uart_ops = { .start_tx = sci_start_tx, .stop_tx = sci_stop_tx, .stop_rx = sci_stop_rx, + .enable_ms = sci_enable_ms, .break_ctl = sci_break_ctl, .startup = sci_startup, .shutdown = sci_shutdown, @@ -2912,6 +2942,20 @@ static int sci_probe_single(struct platform_device *dev, if (ret) return ret; + sciport->gpios = mctrl_gpio_init(&sciport->port, 0); + if (IS_ERR(sciport->gpios) && PTR_ERR(sciport->gpios) != -ENOSYS) + return PTR_ERR(sciport->gpios); + + if (p->capabilities & SCIx_HAVE_RTSCTS) { + if (!IS_ERR_OR_NULL(mctrl_gpio_to_gpiod(sciport->gpios, + UART_GPIO_CTS)) || + !IS_ERR_OR_NULL(mctrl_gpio_to_gpiod(sciport->gpios, + UART_GPIO_RTS))) { + dev_err(&dev->dev, "Conflicting RTS/CTS config\n"); + return -EINVAL; + } + } + ret = uart_add_one_port(&sci_uart_driver, &sciport->port); if (ret) { sci_cleanup_single(sciport); -- cgit v0.10.2 From abbf121fb6dae6657388a32feac346e5e1debdbd Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 3 Jun 2016 12:00:05 +0200 Subject: serial: sh-sci: Do not open-code sci_getreg() Replace open-coded variants of sci_getreg() by function calls, and drop intermediate variables where appropriate. Signed-off-by: Geert Uytterhoeven Reviewed-by: Peter Hurley Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c index bf3780a..ce7bd16 100644 --- a/drivers/tty/serial/sh-sci.c +++ b/drivers/tty/serial/sh-sci.c @@ -703,7 +703,6 @@ static void sci_poll_put_char(struct uart_port *port, unsigned char c) static void sci_init_pins(struct uart_port *port, unsigned int cflag) { struct sci_port *s = to_sci_port(port); - const struct plat_sci_reg *reg = sci_regmap[s->cfg->regtype] + SCSPTR; /* * Use port-specific handler if provided. @@ -717,7 +716,7 @@ static void sci_init_pins(struct uart_port *port, unsigned int cflag) * For the generic path SCSPTR is necessary. Bail out if that's * unavailable, too. */ - if (!reg->size) + if (!sci_getreg(port, SCSPTR)->size) return; if ((s->cfg->capabilities & SCIx_HAVE_RTSCTS) && @@ -1866,12 +1865,10 @@ static void sci_enable_ms(struct uart_port *port) static void sci_break_ctl(struct uart_port *port, int break_state) { - struct sci_port *s = to_sci_port(port); - const struct plat_sci_reg *reg = sci_regmap[s->cfg->regtype] + SCSPTR; unsigned short scscr, scsptr; /* check wheter the port has SCSPTR */ - if (!reg->size) { + if (!sci_getreg(port, SCSPTR)->size) { /* * Not supported by hardware. Most parts couple break and rx * interrupts together, with break detection always enabled. -- cgit v0.10.2 From ef5e90e8ccb7b715c0a1509339f730b2bf9698a2 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 3 Jun 2016 12:00:06 +0200 Subject: serial: sh-sci: Add more Serial Port Register documentation Improve documentation for the (H)SCIF Serial Port Register: - Make it clear the RTS and CTS lines are active-low, - Document the bits related to the serial port's clock pin. Signed-off-by: Geert Uytterhoeven Reviewed-by: Peter Hurley Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/sh-sci.h b/drivers/tty/serial/sh-sci.h index 7a4fa18..85a2b81 100644 --- a/drivers/tty/serial/sh-sci.h +++ b/drivers/tty/serial/sh-sci.h @@ -108,10 +108,12 @@ enum { #define SCLSR_ORER BIT(0) /* Overrun Error */ /* SCSPTR (Serial Port Register), optional */ -#define SCSPTR_RTSIO BIT(7) /* Serial Port RTS Pin Input/Output */ -#define SCSPTR_RTSDT BIT(6) /* Serial Port RTS Pin Data */ -#define SCSPTR_CTSIO BIT(5) /* Serial Port CTS Pin Input/Output */ -#define SCSPTR_CTSDT BIT(4) /* Serial Port CTS Pin Data */ +#define SCSPTR_RTSIO BIT(7) /* Serial Port RTS# Pin Input/Output */ +#define SCSPTR_RTSDT BIT(6) /* Serial Port RTS# Pin Data */ +#define SCSPTR_CTSIO BIT(5) /* Serial Port CTS# Pin Input/Output */ +#define SCSPTR_CTSDT BIT(4) /* Serial Port CTS# Pin Data */ +#define SCSPTR_SCKIO BIT(3) /* Serial Port Clock Pin Input/Output */ +#define SCSPTR_SCKDT BIT(2) /* Serial Port Clock Pin Data */ #define SCSPTR_SPB2IO BIT(1) /* Serial Port Break Input/Output */ #define SCSPTR_SPB2DT BIT(0) /* Serial Port Break Data */ -- cgit v0.10.2 From 4780c09f7a0926674c96c0a40dfeb7469f759c8e Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 3 Jun 2016 12:00:07 +0200 Subject: serial: sh-sci: Add more Serial Port Control/Data Register documentation Improve documentation for the SCIFA/SCIFB Serial Port Control and Data Registers: - State clearly that the RTS and CTS lines are active-low, - Document the bits related to the serial port's SCK, RXD, and TXD pins. Signed-off-by: Geert Uytterhoeven Reviewed-by: Peter Hurley Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/sh-sci.h b/drivers/tty/serial/sh-sci.h index 85a2b81..e7d2bc6 100644 --- a/drivers/tty/serial/sh-sci.h +++ b/drivers/tty/serial/sh-sci.h @@ -121,12 +121,18 @@ enum { #define HSCIF_SRE BIT(15) /* Sampling Rate Register Enable */ /* SCPCR (Serial Port Control Register), SCIFA/SCIFB only */ -#define SCPCR_RTSC BIT(4) /* Serial Port RTS Pin / Output Pin */ -#define SCPCR_CTSC BIT(3) /* Serial Port CTS Pin / Input Pin */ +#define SCPCR_RTSC BIT(4) /* Serial Port RTS# Pin / Output Pin */ +#define SCPCR_CTSC BIT(3) /* Serial Port CTS# Pin / Input Pin */ +#define SCPCR_SCKC BIT(2) /* Serial Port SCK Pin / Output Pin */ +#define SCPCR_RXDC BIT(1) /* Serial Port RXD Pin / Input Pin */ +#define SCPCR_TXDC BIT(0) /* Serial Port TXD Pin / Output Pin */ /* SCPDR (Serial Port Data Register), SCIFA/SCIFB only */ -#define SCPDR_RTSD BIT(4) /* Serial Port RTS Output Pin Data */ -#define SCPDR_CTSD BIT(3) /* Serial Port CTS Input Pin Data */ +#define SCPDR_RTSD BIT(4) /* Serial Port RTS# Output Pin Data */ +#define SCPDR_CTSD BIT(3) /* Serial Port CTS# Input Pin Data */ +#define SCPDR_SCKD BIT(2) /* Serial Port SCK Output Pin Data */ +#define SCPDR_RXDD BIT(1) /* Serial Port RXD Input Pin Data */ +#define SCPDR_TXDD BIT(0) /* Serial Port TXD Output Pin Data */ /* * BRG Clock Select Register (Some SCIF and HSCIF) -- cgit v0.10.2 From d2b9775d795ec05fb42504c0f47dd06ba5fd709e Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 3 Jun 2016 12:00:08 +0200 Subject: serial: sh-sci: Correct pin initialization on (H)SCIF Correct pin initialization on (H)SCIF: - RTS must be deasserted (it's active low), - SCK must be an input, as it may be used as the optional external clock input. Initial pin configuration must always be done: - Regardless of the presence of dedicated RTS and CTS pins: if the register exists, the RTS/CTS bits exist, too, - Regardless of hardware flow control being enabled or not: RTS must be deasserted. Signed-off-by: Geert Uytterhoeven Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c index ce7bd16..c46999f 100644 --- a/drivers/tty/serial/sh-sci.c +++ b/drivers/tty/serial/sh-sci.c @@ -712,21 +712,14 @@ static void sci_init_pins(struct uart_port *port, unsigned int cflag) return; } - /* - * For the generic path SCSPTR is necessary. Bail out if that's - * unavailable, too. - */ - if (!sci_getreg(port, SCSPTR)->size) - return; - - if ((s->cfg->capabilities & SCIx_HAVE_RTSCTS) && - ((!(cflag & CRTSCTS)))) { - unsigned short status; - - status = serial_port_in(port, SCSPTR); - status &= ~SCSPTR_CTSIO; - status |= SCSPTR_RTSIO; - serial_port_out(port, SCSPTR, status); /* Set RTS = 1 */ + if (sci_getreg(port, SCSPTR)->size) { + u16 status = serial_port_in(port, SCSPTR); + + /* RTS# is output, driven 1 */ + status |= SCSPTR_RTSIO | SCSPTR_RTSDT; + /* CTS# and SCK are inputs */ + status &= ~(SCSPTR_CTSIO | SCSPTR_SCKIO); + serial_port_out(port, SCSPTR, status); } } -- cgit v0.10.2 From e9d7a45a039913497a57887d85f5decfda4679f0 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 3 Jun 2016 12:00:09 +0200 Subject: serial: sh-sci: Add pin initialization for SCIFA/SCIFB Before, the driver relied on initialization by the boot loader, or by implicit reset state. Note that unlike on (H)SCIF, the RTS/CTS bits exist only if dedicated RTS/CTS pins are available, which depends on the SoC and UART instance. Signed-off-by: Geert Uytterhoeven Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c index c46999f..b9d027a 100644 --- a/drivers/tty/serial/sh-sci.c +++ b/drivers/tty/serial/sh-sci.c @@ -712,7 +712,21 @@ static void sci_init_pins(struct uart_port *port, unsigned int cflag) return; } - if (sci_getreg(port, SCSPTR)->size) { + if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) { + u16 ctrl = serial_port_in(port, SCPCR); + + /* Enable RXD and TXD pin functions */ + ctrl &= ~(SCPCR_RXDC | SCPCR_TXDC); + if (to_sci_port(port)->cfg->capabilities & SCIx_HAVE_RTSCTS) { + /* RTS# is output, driven 1 */ + ctrl |= SCPCR_RTSC; + serial_port_out(port, SCPDR, + serial_port_in(port, SCPDR) | SCPDR_RTSD); + /* Enable CTS# pin function */ + ctrl &= ~SCPCR_CTSC; + } + serial_port_out(port, SCPCR, ctrl); + } else if (sci_getreg(port, SCSPTR)->size) { u16 status = serial_port_in(port, SCSPTR); /* RTS# is output, driven 1 */ -- cgit v0.10.2 From 33f50ffc253854cf6cd556786ae893c7454a1a67 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 3 Jun 2016 12:00:10 +0200 Subject: serial: sh-sci: Fix support for hardware-assisted RTS/CTS The existing support for hardware-assisted RTS/CTS is rudimentary and doesn't work. Add support for hardware-assisted RTS/CTS hardware flow control for the (H)SCIF, SCIFA, and SCIFB variants. Signed-off-by: Geert Uytterhoeven Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c index b9d027a..02b240a 100644 --- a/drivers/tty/serial/sh-sci.c +++ b/drivers/tty/serial/sh-sci.c @@ -141,6 +141,8 @@ struct sci_port { struct timer_list rx_timer; unsigned int rx_timeout; #endif + + bool autorts; }; #define SCI_NPORTS CONFIG_SERIAL_SH_SCI_NR_UARTS @@ -1811,6 +1813,46 @@ static unsigned int sci_tx_empty(struct uart_port *port) return (status & SCxSR_TEND(port)) && !in_tx_fifo ? TIOCSER_TEMT : 0; } +static void sci_set_rts(struct uart_port *port, bool state) +{ + if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) { + u16 data = serial_port_in(port, SCPDR); + + /* Active low */ + if (state) + data &= ~SCPDR_RTSD; + else + data |= SCPDR_RTSD; + serial_port_out(port, SCPDR, data); + + /* RTS# is output */ + serial_port_out(port, SCPCR, + serial_port_in(port, SCPCR) | SCPCR_RTSC); + } else if (sci_getreg(port, SCSPTR)->size) { + u16 ctrl = serial_port_in(port, SCSPTR); + + /* Active low */ + if (state) + ctrl &= ~SCSPTR_RTSDT; + else + ctrl |= SCSPTR_RTSDT; + serial_port_out(port, SCSPTR, ctrl); + } +} + +static bool sci_get_cts(struct uart_port *port) +{ + if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) { + /* Active low */ + return !(serial_port_in(port, SCPDR) & SCPDR_CTSD); + } else if (sci_getreg(port, SCSPTR)->size) { + /* Active low */ + return !(serial_port_in(port, SCSPTR) & SCSPTR_CTSDT); + } + + return true; +} + /* * Modem control is a bit of a mixed bag for SCI(F) ports. Generally * CTS/RTS is supported in hardware by at least one port and controlled @@ -1841,6 +1883,31 @@ static void sci_set_mctrl(struct uart_port *port, unsigned int mctrl) } mctrl_gpio_set(s->gpios, mctrl); + + if (!(s->cfg->capabilities & SCIx_HAVE_RTSCTS)) + return; + + if (!(mctrl & TIOCM_RTS)) { + /* Disable Auto RTS */ + serial_port_out(port, SCFCR, + serial_port_in(port, SCFCR) & ~SCFCR_MCE); + + /* Clear RTS */ + sci_set_rts(port, 0); + } else if (s->autorts) { + if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) { + /* Enable RTS# pin function */ + serial_port_out(port, SCPCR, + serial_port_in(port, SCPCR) & ~SCPCR_RTSC); + } + + /* Enable Auto RTS */ + serial_port_out(port, SCFCR, + serial_port_in(port, SCFCR) | SCFCR_MCE); + } else { + /* Set RTS */ + sci_set_rts(port, 1); + } } static unsigned int sci_get_mctrl(struct uart_port *port) @@ -1853,10 +1920,14 @@ static unsigned int sci_get_mctrl(struct uart_port *port) /* * CTS/RTS is handled in hardware when supported, while nothing - * else is wired up. Keep it simple and simply assert CTS/DSR/CAR. + * else is wired up. */ - if (IS_ERR_OR_NULL(mctrl_gpio_to_gpiod(gpios, UART_GPIO_CTS))) + if (s->autorts) { + if (sci_get_cts(port)) + mctrl |= TIOCM_CTS; + } else if (IS_ERR_OR_NULL(mctrl_gpio_to_gpiod(gpios, UART_GPIO_CTS))) { mctrl |= TIOCM_CTS; + } if (IS_ERR_OR_NULL(mctrl_gpio_to_gpiod(gpios, UART_GPIO_DSR))) mctrl |= TIOCM_DSR; if (IS_ERR_OR_NULL(mctrl_gpio_to_gpiod(gpios, UART_GPIO_DCD))) @@ -1927,6 +1998,7 @@ static void sci_shutdown(struct uart_port *port) dev_dbg(port->dev, "%s(%d)\n", __func__, port->line); + s->autorts = false; mctrl_gpio_disable_ms(to_sci_port(port)->gpios); spin_lock_irqsave(&port->lock, flags); @@ -2248,15 +2320,18 @@ done: sci_init_pins(port, termios->c_cflag); + port->status &= ~UPSTAT_AUTOCTS; + s->autorts = false; reg = sci_getreg(port, SCFCR); if (reg->size) { unsigned short ctrl = serial_port_in(port, SCFCR); - if (s->cfg->capabilities & SCIx_HAVE_RTSCTS) { - if (termios->c_cflag & CRTSCTS) - ctrl |= SCFCR_MCE; - else - ctrl &= ~SCFCR_MCE; + if ((port->flags & UPF_HARD_FLOW) && + (termios->c_cflag & CRTSCTS)) { + /* There is no CTS interrupt to restart the hardware */ + port->status |= UPSTAT_AUTOCTS; + /* MCE is enabled when RTS is raised */ + s->autorts = true; } /* @@ -2958,6 +3033,7 @@ static int sci_probe_single(struct platform_device *dev, dev_err(&dev->dev, "Conflicting RTS/CTS config\n"); return -EINVAL; } + sciport->port.flags |= UPF_HARD_FLOW; } ret = uart_add_one_port(&sci_uart_driver, &sciport->port); -- cgit v0.10.2 From 861a70abb483645d4474a6bc006471c2db59a78d Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 3 Jun 2016 12:00:11 +0200 Subject: serial: sh-sci: Add DT support for dedicated RTS/CTS Add support for indicating the availability of dedicated lines for RTS/CTS hardware flow control, using the standard "uart-has-rtscts" DT property. Signed-off-by: Geert Uytterhoeven Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c index 02b240a..d9cb0d7 100644 --- a/drivers/tty/serial/sh-sci.c +++ b/drivers/tty/serial/sh-sci.c @@ -2999,6 +2999,9 @@ sci_parse_dt(struct platform_device *pdev, unsigned int *dev_id) p->regtype = SCI_OF_REGTYPE(match->data); p->scscr = SCSCR_RE | SCSCR_TE; + if (of_find_property(np, "uart-has-rtscts", NULL)) + p->capabilities |= SCIx_HAVE_RTSCTS; + return p; } -- cgit v0.10.2 From ac8305cd16ea2c35084ceb5cdf36f5a90c275c3a Mon Sep 17 00:00:00 2001 From: Hiromitsu Yamasaki Date: Thu, 12 May 2016 15:33:58 +0900 Subject: serial: sh-sci: Document SoC specific bindings for r8a7796 Signed-off-by: Hiromitsu Yamasaki Signed-off-by: Simon Horman Acked-by: Geert Uytterhoeven Signed-off-by: Greg Kroah-Hartman diff --git a/Documentation/devicetree/bindings/serial/renesas,sci-serial.txt b/Documentation/devicetree/bindings/serial/renesas,sci-serial.txt index 7a0e150..1e4000d 100644 --- a/Documentation/devicetree/bindings/serial/renesas,sci-serial.txt +++ b/Documentation/devicetree/bindings/serial/renesas,sci-serial.txt @@ -31,6 +31,8 @@ Required properties: - "renesas,hscif-r8a7794" for R8A7794 (R-Car E2) HSCIF compatible UART. - "renesas,scif-r8a7795" for R8A7795 (R-Car H3) SCIF compatible UART. - "renesas,hscif-r8a7795" for R8A7795 (R-Car H3) HSCIF compatible UART. + - "renesas,scif-r8a7796" for R8A7796 (R-Car M3-W) SCIF compatible UART. + - "renesas,hscif-r8a7796" for R8A7796 (R-Car M3-W) HSCIF compatible UART. - "renesas,scifa-sh73a0" for SH73A0 (SH-Mobile AG5) SCIFA compatible UART. - "renesas,scifb-sh73a0" for SH73A0 (SH-Mobile AG5) SCIFB compatible UART. - "renesas,rcar-gen1-scif" for R-Car Gen1 SCIF compatible UART, -- cgit v0.10.2 From 44763d3d301a13523186731b4797b181c78fe8b4 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 24 Jun 2016 16:59:13 +0200 Subject: serial: sh-sci: Do not start transfers from sci_startup() FIFO reset is done in sci_reset(), called from sci_set_termios(), while sci_start_tx() and sci_start_rx() are called before, from sci_startup(). However, starting transfers before the UART's FIFOs have been reset may cause reading of stale data. Remove the calls to sci_start_tx() and sci_start_rx() from sci_startup() to fix this. Transfers are still started when needed: - sci_start_rx() is called from sci_set_termios() after FIFO reset, if the CREAD flag is set, - sci_start_tx() is called from uart_change_speed() immediately thereafter, if transmission is enabled. Signed-off-by: Geert Uytterhoeven Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c index d9cb0d7..d88c84cd 100644 --- a/drivers/tty/serial/sh-sci.c +++ b/drivers/tty/serial/sh-sci.c @@ -1972,7 +1972,6 @@ static void sci_break_ctl(struct uart_port *port, int break_state) static int sci_startup(struct uart_port *port) { struct sci_port *s = to_sci_port(port); - unsigned long flags; int ret; dev_dbg(port->dev, "%s(%d)\n", __func__, port->line); @@ -1983,11 +1982,6 @@ static int sci_startup(struct uart_port *port) sci_request_dma(port); - spin_lock_irqsave(&port->lock, flags); - sci_start_tx(port); - sci_start_rx(port); - spin_unlock_irqrestore(&port->lock, flags); - return 0; } -- cgit v0.10.2 From 2768cf42874ae04bdbc33a9c9db96181dc0bbb8d Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 24 Jun 2016 16:59:15 +0200 Subject: serial: sh-sci: Clear RX, error, and break flags during reset Setting the FIFO reset bits is not sufficient to reset the RX FIFO. After this the status register's RDF flag bit may still be set, causing the reception of one stale byte of data. To fix this, clear all status flag bits related to reception, error, and break handling, cfr. the initialization flowchart in the datasheet. Signed-off-by: Geert Uytterhoeven Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c index d88c84cd..408f706 100644 --- a/drivers/tty/serial/sh-sci.c +++ b/drivers/tty/serial/sh-sci.c @@ -2152,6 +2152,10 @@ static void sci_reset(struct uart_port *port) reg = sci_getreg(port, SCFCR); if (reg->size) serial_port_out(port, SCFCR, SCFCR_RFRST | SCFCR_TFRST); + + sci_clear_SCxSR(port, + SCxSR_RDxF_CLEAR(port) & SCxSR_ERROR_CLEAR(port) & + SCxSR_BREAK_CLEAR(port)); } static void sci_set_termios(struct uart_port *port, struct ktermios *termios, -- cgit v0.10.2 From fc2af3348a4acea0c28db89a8c84660d0baed4aa Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 24 Jun 2016 16:59:16 +0200 Subject: serial: sh-sci: Clear (H)SCIF timeout and overrun during reset Add the missing timeout bit definition for (H)SCIF. Clear the timeout and overrun flag bits during UART reset, cfr. the initialization flowchart in the datasheet. Signed-off-by: Geert Uytterhoeven Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c index 408f706..432d9ac 100644 --- a/drivers/tty/serial/sh-sci.c +++ b/drivers/tty/serial/sh-sci.c @@ -2156,6 +2156,11 @@ static void sci_reset(struct uart_port *port) sci_clear_SCxSR(port, SCxSR_RDxF_CLEAR(port) & SCxSR_ERROR_CLEAR(port) & SCxSR_BREAK_CLEAR(port)); + if (sci_getreg(port, SCLSR)->size) { + status = serial_port_in(port, SCLSR); + status &= ~(SCLSR_TO | SCLSR_ORER); + serial_port_out(port, SCLSR, status); + } } static void sci_set_termios(struct uart_port *port, struct ktermios *termios, diff --git a/drivers/tty/serial/sh-sci.h b/drivers/tty/serial/sh-sci.h index e7d2bc6..ffa6d68 100644 --- a/drivers/tty/serial/sh-sci.h +++ b/drivers/tty/serial/sh-sci.h @@ -105,6 +105,7 @@ enum { #define SCFCR_LOOP BIT(0) /* Loopback Test */ /* SCLSR (Line Status Register) on (H)SCIF */ +#define SCLSR_TO BIT(2) /* Timeout */ #define SCLSR_ORER BIT(0) /* Overrun Error */ /* SCSPTR (Serial Port Register), optional */ -- cgit v0.10.2 From 01e4d273559715ee6a8b1cfbe07ceda6c8e1a515 Mon Sep 17 00:00:00 2001 From: Kefeng Wang Date: Wed, 11 May 2016 14:06:01 +0800 Subject: serial: 8250_early: Add earlycon support for Synopsys DesignWare ABP UART Some board like Hisilicon D02 uses Synopsys DesignWare ABP UART, declare an OF early console for it, so early console device can be enabled with comand line "earlycon"(without option) via the "stdout-path" property in device-tree. Signed-off-by: Kefeng Wang Tested-by: Jon Mason Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/8250/8250_early.c b/drivers/tty/serial/8250/8250_early.c index 8d08ff5..85a12f0 100644 --- a/drivers/tty/serial/8250/8250_early.c +++ b/drivers/tty/serial/8250/8250_early.c @@ -150,6 +150,7 @@ EARLYCON_DECLARE(uart, early_serial8250_setup); OF_EARLYCON_DECLARE(ns16550, "ns16550", early_serial8250_setup); OF_EARLYCON_DECLARE(ns16550a, "ns16550a", early_serial8250_setup); OF_EARLYCON_DECLARE(uart, "nvidia,tegra20-uart", early_serial8250_setup); +OF_EARLYCON_DECLARE(uart, "snps,dw-apb-uart", early_serial8250_setup); #ifdef CONFIG_SERIAL_8250_OMAP -- cgit v0.10.2 From 321737416c72dc3d3dd8753c3684c6eb86d0ea6c Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Wed, 11 May 2016 18:02:26 -0700 Subject: tty: serial: msm: Move header file into driver This header file is only used by the driver, so let's merge the two together to reduce files and make it easier to see the whole driver without flipping through two files. This also makes it easier to use the structures defined in msm_serial.c in the functions that are defined in msm_serial.h by placing them in the proper locations. Signed-off-by: Stephen Boyd Acked-by: Andy Gross Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/msm_serial.c b/drivers/tty/serial/msm_serial.c index b7d80bd..28b8ac4 100644 --- a/drivers/tty/serial/msm_serial.c +++ b/drivers/tty/serial/msm_serial.c @@ -40,12 +40,126 @@ #include #include -#include "msm_serial.h" - -#define UARTDM_BURST_SIZE 16 /* in bytes */ -#define UARTDM_TX_AIGN(x) ((x) & ~0x3) /* valid for > 1p3 */ -#define UARTDM_TX_MAX 256 /* in bytes, valid for <= 1p3 */ -#define UARTDM_RX_SIZE (UART_XMIT_SIZE / 4) +#define UART_MR1 0x0000 + +#define UART_MR1_AUTO_RFR_LEVEL0 0x3F +#define UART_MR1_AUTO_RFR_LEVEL1 0x3FF00 +#define UART_DM_MR1_AUTO_RFR_LEVEL1 0xFFFFFF00 +#define UART_MR1_RX_RDY_CTL BIT(7) +#define UART_MR1_CTS_CTL BIT(6) + +#define UART_MR2 0x0004 +#define UART_MR2_ERROR_MODE BIT(6) +#define UART_MR2_BITS_PER_CHAR 0x30 +#define UART_MR2_BITS_PER_CHAR_5 (0x0 << 4) +#define UART_MR2_BITS_PER_CHAR_6 (0x1 << 4) +#define UART_MR2_BITS_PER_CHAR_7 (0x2 << 4) +#define UART_MR2_BITS_PER_CHAR_8 (0x3 << 4) +#define UART_MR2_STOP_BIT_LEN_ONE (0x1 << 2) +#define UART_MR2_STOP_BIT_LEN_TWO (0x3 << 2) +#define UART_MR2_PARITY_MODE_NONE 0x0 +#define UART_MR2_PARITY_MODE_ODD 0x1 +#define UART_MR2_PARITY_MODE_EVEN 0x2 +#define UART_MR2_PARITY_MODE_SPACE 0x3 +#define UART_MR2_PARITY_MODE 0x3 + +#define UART_CSR 0x0008 + +#define UART_TF 0x000C +#define UARTDM_TF 0x0070 + +#define UART_CR 0x0010 +#define UART_CR_CMD_NULL (0 << 4) +#define UART_CR_CMD_RESET_RX (1 << 4) +#define UART_CR_CMD_RESET_TX (2 << 4) +#define UART_CR_CMD_RESET_ERR (3 << 4) +#define UART_CR_CMD_RESET_BREAK_INT (4 << 4) +#define UART_CR_CMD_START_BREAK (5 << 4) +#define UART_CR_CMD_STOP_BREAK (6 << 4) +#define UART_CR_CMD_RESET_CTS (7 << 4) +#define UART_CR_CMD_RESET_STALE_INT (8 << 4) +#define UART_CR_CMD_PACKET_MODE (9 << 4) +#define UART_CR_CMD_MODE_RESET (12 << 4) +#define UART_CR_CMD_SET_RFR (13 << 4) +#define UART_CR_CMD_RESET_RFR (14 << 4) +#define UART_CR_CMD_PROTECTION_EN (16 << 4) +#define UART_CR_CMD_STALE_EVENT_DISABLE (6 << 8) +#define UART_CR_CMD_STALE_EVENT_ENABLE (80 << 4) +#define UART_CR_CMD_FORCE_STALE (4 << 8) +#define UART_CR_CMD_RESET_TX_READY (3 << 8) +#define UART_CR_TX_DISABLE BIT(3) +#define UART_CR_TX_ENABLE BIT(2) +#define UART_CR_RX_DISABLE BIT(1) +#define UART_CR_RX_ENABLE BIT(0) +#define UART_CR_CMD_RESET_RXBREAK_START ((1 << 11) | (2 << 4)) + +#define UART_IMR 0x0014 +#define UART_IMR_TXLEV BIT(0) +#define UART_IMR_RXSTALE BIT(3) +#define UART_IMR_RXLEV BIT(4) +#define UART_IMR_DELTA_CTS BIT(5) +#define UART_IMR_CURRENT_CTS BIT(6) +#define UART_IMR_RXBREAK_START BIT(10) + +#define UART_IPR_RXSTALE_LAST 0x20 +#define UART_IPR_STALE_LSB 0x1F +#define UART_IPR_STALE_TIMEOUT_MSB 0x3FF80 +#define UART_DM_IPR_STALE_TIMEOUT_MSB 0xFFFFFF80 + +#define UART_IPR 0x0018 +#define UART_TFWR 0x001C +#define UART_RFWR 0x0020 +#define UART_HCR 0x0024 + +#define UART_MREG 0x0028 +#define UART_NREG 0x002C +#define UART_DREG 0x0030 +#define UART_MNDREG 0x0034 +#define UART_IRDA 0x0038 +#define UART_MISR_MODE 0x0040 +#define UART_MISR_RESET 0x0044 +#define UART_MISR_EXPORT 0x0048 +#define UART_MISR_VAL 0x004C +#define UART_TEST_CTRL 0x0050 + +#define UART_SR 0x0008 +#define UART_SR_HUNT_CHAR BIT(7) +#define UART_SR_RX_BREAK BIT(6) +#define UART_SR_PAR_FRAME_ERR BIT(5) +#define UART_SR_OVERRUN BIT(4) +#define UART_SR_TX_EMPTY BIT(3) +#define UART_SR_TX_READY BIT(2) +#define UART_SR_RX_FULL BIT(1) +#define UART_SR_RX_READY BIT(0) + +#define UART_RF 0x000C +#define UARTDM_RF 0x0070 +#define UART_MISR 0x0010 +#define UART_ISR 0x0014 +#define UART_ISR_TX_READY BIT(7) + +#define UARTDM_RXFS 0x50 +#define UARTDM_RXFS_BUF_SHIFT 0x7 +#define UARTDM_RXFS_BUF_MASK 0x7 + +#define UARTDM_DMEN 0x3C +#define UARTDM_DMEN_RX_SC_ENABLE BIT(5) +#define UARTDM_DMEN_TX_SC_ENABLE BIT(4) + +#define UARTDM_DMEN_TX_BAM_ENABLE BIT(2) /* UARTDM_1P4 */ +#define UARTDM_DMEN_TX_DM_ENABLE BIT(0) /* < UARTDM_1P4 */ + +#define UARTDM_DMEN_RX_BAM_ENABLE BIT(3) /* UARTDM_1P4 */ +#define UARTDM_DMEN_RX_DM_ENABLE BIT(1) /* < UARTDM_1P4 */ + +#define UARTDM_DMRX 0x34 +#define UARTDM_NCF_TX 0x40 +#define UARTDM_RX_TOTAL_SNAP 0x38 + +#define UARTDM_BURST_SIZE 16 /* in bytes */ +#define UARTDM_TX_AIGN(x) ((x) & ~0x3) /* valid for > 1p3 */ +#define UARTDM_TX_MAX 256 /* in bytes, valid for <= 1p3 */ +#define UARTDM_RX_SIZE (UART_XMIT_SIZE / 4) enum { UARTDM_1P1 = 1, @@ -78,6 +192,52 @@ struct msm_port { struct msm_dma rx_dma; }; +#define UART_TO_MSM(uart_port) container_of(uart_port, struct msm_port, uart) + +static +void msm_write(struct uart_port *port, unsigned int val, unsigned int off) +{ + writel_relaxed(val, port->membase + off); +} + +static +unsigned int msm_read(struct uart_port *port, unsigned int off) +{ + return readl_relaxed(port->membase + off); +} + +/* + * Setup the MND registers to use the TCXO clock. + */ +static void msm_serial_set_mnd_regs_tcxo(struct uart_port *port) +{ + msm_write(port, 0x06, UART_MREG); + msm_write(port, 0xF1, UART_NREG); + msm_write(port, 0x0F, UART_DREG); + msm_write(port, 0x1A, UART_MNDREG); + port->uartclk = 1843200; +} + +/* + * Setup the MND registers to use the TCXO clock divided by 4. + */ +static void msm_serial_set_mnd_regs_tcxoby4(struct uart_port *port) +{ + msm_write(port, 0x18, UART_MREG); + msm_write(port, 0xF6, UART_NREG); + msm_write(port, 0x0F, UART_DREG); + msm_write(port, 0x0A, UART_MNDREG); + port->uartclk = 1843200; +} + +static void msm_serial_set_mnd_regs(struct uart_port *port) +{ + if (port->uartclk == 19200000) + msm_serial_set_mnd_regs_tcxo(port); + else if (port->uartclk == 4800000) + msm_serial_set_mnd_regs_tcxoby4(port); +} + static void msm_handle_tx(struct uart_port *port); static void msm_start_rx_dma(struct msm_port *msm_port); diff --git a/drivers/tty/serial/msm_serial.h b/drivers/tty/serial/msm_serial.h deleted file mode 100644 index 1786458..0000000 --- a/drivers/tty/serial/msm_serial.h +++ /dev/null @@ -1,184 +0,0 @@ -/* - * Copyright (C) 2007 Google, Inc. - * Author: Robert Love - * Copyright (c) 2011, Code Aurora Forum. All rights reserved. - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#ifndef __DRIVERS_SERIAL_MSM_SERIAL_H -#define __DRIVERS_SERIAL_MSM_SERIAL_H - -#define UART_MR1 0x0000 - -#define UART_MR1_AUTO_RFR_LEVEL0 0x3F -#define UART_MR1_AUTO_RFR_LEVEL1 0x3FF00 -#define UART_DM_MR1_AUTO_RFR_LEVEL1 0xFFFFFF00 -#define UART_MR1_RX_RDY_CTL BIT(7) -#define UART_MR1_CTS_CTL BIT(6) - -#define UART_MR2 0x0004 -#define UART_MR2_ERROR_MODE BIT(6) -#define UART_MR2_BITS_PER_CHAR 0x30 -#define UART_MR2_BITS_PER_CHAR_5 (0x0 << 4) -#define UART_MR2_BITS_PER_CHAR_6 (0x1 << 4) -#define UART_MR2_BITS_PER_CHAR_7 (0x2 << 4) -#define UART_MR2_BITS_PER_CHAR_8 (0x3 << 4) -#define UART_MR2_STOP_BIT_LEN_ONE (0x1 << 2) -#define UART_MR2_STOP_BIT_LEN_TWO (0x3 << 2) -#define UART_MR2_PARITY_MODE_NONE 0x0 -#define UART_MR2_PARITY_MODE_ODD 0x1 -#define UART_MR2_PARITY_MODE_EVEN 0x2 -#define UART_MR2_PARITY_MODE_SPACE 0x3 -#define UART_MR2_PARITY_MODE 0x3 - -#define UART_CSR 0x0008 - -#define UART_TF 0x000C -#define UARTDM_TF 0x0070 - -#define UART_CR 0x0010 -#define UART_CR_CMD_NULL (0 << 4) -#define UART_CR_CMD_RESET_RX (1 << 4) -#define UART_CR_CMD_RESET_TX (2 << 4) -#define UART_CR_CMD_RESET_ERR (3 << 4) -#define UART_CR_CMD_RESET_BREAK_INT (4 << 4) -#define UART_CR_CMD_START_BREAK (5 << 4) -#define UART_CR_CMD_STOP_BREAK (6 << 4) -#define UART_CR_CMD_RESET_CTS (7 << 4) -#define UART_CR_CMD_RESET_STALE_INT (8 << 4) -#define UART_CR_CMD_PACKET_MODE (9 << 4) -#define UART_CR_CMD_MODE_RESET (12 << 4) -#define UART_CR_CMD_SET_RFR (13 << 4) -#define UART_CR_CMD_RESET_RFR (14 << 4) -#define UART_CR_CMD_PROTECTION_EN (16 << 4) -#define UART_CR_CMD_STALE_EVENT_DISABLE (6 << 8) -#define UART_CR_CMD_STALE_EVENT_ENABLE (80 << 4) -#define UART_CR_CMD_FORCE_STALE (4 << 8) -#define UART_CR_CMD_RESET_TX_READY (3 << 8) -#define UART_CR_TX_DISABLE BIT(3) -#define UART_CR_TX_ENABLE BIT(2) -#define UART_CR_RX_DISABLE BIT(1) -#define UART_CR_RX_ENABLE BIT(0) -#define UART_CR_CMD_RESET_RXBREAK_START ((1 << 11) | (2 << 4)) - -#define UART_IMR 0x0014 -#define UART_IMR_TXLEV BIT(0) -#define UART_IMR_RXSTALE BIT(3) -#define UART_IMR_RXLEV BIT(4) -#define UART_IMR_DELTA_CTS BIT(5) -#define UART_IMR_CURRENT_CTS BIT(6) -#define UART_IMR_RXBREAK_START BIT(10) - -#define UART_IPR_RXSTALE_LAST 0x20 -#define UART_IPR_STALE_LSB 0x1F -#define UART_IPR_STALE_TIMEOUT_MSB 0x3FF80 -#define UART_DM_IPR_STALE_TIMEOUT_MSB 0xFFFFFF80 - -#define UART_IPR 0x0018 -#define UART_TFWR 0x001C -#define UART_RFWR 0x0020 -#define UART_HCR 0x0024 - -#define UART_MREG 0x0028 -#define UART_NREG 0x002C -#define UART_DREG 0x0030 -#define UART_MNDREG 0x0034 -#define UART_IRDA 0x0038 -#define UART_MISR_MODE 0x0040 -#define UART_MISR_RESET 0x0044 -#define UART_MISR_EXPORT 0x0048 -#define UART_MISR_VAL 0x004C -#define UART_TEST_CTRL 0x0050 - -#define UART_SR 0x0008 -#define UART_SR_HUNT_CHAR BIT(7) -#define UART_SR_RX_BREAK BIT(6) -#define UART_SR_PAR_FRAME_ERR BIT(5) -#define UART_SR_OVERRUN BIT(4) -#define UART_SR_TX_EMPTY BIT(3) -#define UART_SR_TX_READY BIT(2) -#define UART_SR_RX_FULL BIT(1) -#define UART_SR_RX_READY BIT(0) - -#define UART_RF 0x000C -#define UARTDM_RF 0x0070 -#define UART_MISR 0x0010 -#define UART_ISR 0x0014 -#define UART_ISR_TX_READY BIT(7) - -#define UARTDM_RXFS 0x50 -#define UARTDM_RXFS_BUF_SHIFT 0x7 -#define UARTDM_RXFS_BUF_MASK 0x7 - -#define UARTDM_DMEN 0x3C -#define UARTDM_DMEN_RX_SC_ENABLE BIT(5) -#define UARTDM_DMEN_TX_SC_ENABLE BIT(4) - -#define UARTDM_DMEN_TX_BAM_ENABLE BIT(2) /* UARTDM_1P4 */ -#define UARTDM_DMEN_TX_DM_ENABLE BIT(0) /* < UARTDM_1P4 */ - -#define UARTDM_DMEN_RX_BAM_ENABLE BIT(3) /* UARTDM_1P4 */ -#define UARTDM_DMEN_RX_DM_ENABLE BIT(1) /* < UARTDM_1P4 */ - -#define UARTDM_DMRX 0x34 -#define UARTDM_NCF_TX 0x40 -#define UARTDM_RX_TOTAL_SNAP 0x38 - -#define UART_TO_MSM(uart_port) ((struct msm_port *) uart_port) - -static inline -void msm_write(struct uart_port *port, unsigned int val, unsigned int off) -{ - writel_relaxed(val, port->membase + off); -} - -static inline -unsigned int msm_read(struct uart_port *port, unsigned int off) -{ - return readl_relaxed(port->membase + off); -} - -/* - * Setup the MND registers to use the TCXO clock. - */ -static inline void msm_serial_set_mnd_regs_tcxo(struct uart_port *port) -{ - msm_write(port, 0x06, UART_MREG); - msm_write(port, 0xF1, UART_NREG); - msm_write(port, 0x0F, UART_DREG); - msm_write(port, 0x1A, UART_MNDREG); - port->uartclk = 1843200; -} - -/* - * Setup the MND registers to use the TCXO clock divided by 4. - */ -static inline void msm_serial_set_mnd_regs_tcxoby4(struct uart_port *port) -{ - msm_write(port, 0x18, UART_MREG); - msm_write(port, 0xF6, UART_NREG); - msm_write(port, 0x0F, UART_DREG); - msm_write(port, 0x0A, UART_MNDREG); - port->uartclk = 1843200; -} - -static inline -void msm_serial_set_mnd_regs_from_uartclk(struct uart_port *port) -{ - if (port->uartclk == 19200000) - msm_serial_set_mnd_regs_tcxo(port); - else if (port->uartclk == 4800000) - msm_serial_set_mnd_regs_tcxoby4(port); -} - -#define msm_serial_set_mnd_regs msm_serial_set_mnd_regs_from_uartclk - -#endif /* __DRIVERS_SERIAL_MSM_SERIAL_H */ -- cgit v0.10.2 From 2a31f094553125e0353b9f7e7b6e9aeea752fed3 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Wed, 11 May 2016 18:02:27 -0700 Subject: tty: serial: msm: Only configure MND registers on hw that has it The registers that msm_serial_set_mnd_regs() writes only exist on the non-uartdm hardware, so let's return early here if this function is called on uartdm hardware. This also prevents us from messing up the uartclk variable if the uartclk rate happens to be 19.2 or 4.8 MHz. Signed-off-by: Stephen Boyd Acked-by: Andy Gross Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/msm_serial.c b/drivers/tty/serial/msm_serial.c index 28b8ac4..a051dc5 100644 --- a/drivers/tty/serial/msm_serial.c +++ b/drivers/tty/serial/msm_serial.c @@ -232,6 +232,15 @@ static void msm_serial_set_mnd_regs_tcxoby4(struct uart_port *port) static void msm_serial_set_mnd_regs(struct uart_port *port) { + struct msm_port *msm_port = UART_TO_MSM(port); + + /* + * These registers don't exist so we change the clk input rate + * on uartdm hardware instead + */ + if (msm_port->is_uartdm) + return; + if (port->uartclk == 19200000) msm_serial_set_mnd_regs_tcxo(port); else if (port->uartclk == 4800000) -- cgit v0.10.2 From e4276ff8a08116f22589b4f52974cf82cd3207db Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Wed, 11 May 2016 18:02:28 -0700 Subject: tty: serial: msm: Cleanup include usage The hrtimer include isn't used and neither is serial. Drop those ones. The irq.h header really should be interrupt.h because this is an interrupt user and not an interrupt chip. Finally add wait.h for the wake_up*() usage in this driver and kernel.h for container_of(). Signed-off-by: Stephen Boyd Acked-by: Andy Gross Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/msm_serial.c b/drivers/tty/serial/msm_serial.c index a051dc5..88af5a3 100644 --- a/drivers/tty/serial/msm_serial.c +++ b/drivers/tty/serial/msm_serial.c @@ -19,26 +19,26 @@ # define SUPPORT_SYSRQ #endif +#include #include #include #include -#include #include #include #include -#include +#include #include #include #include #include #include -#include #include #include #include #include #include #include +#include #define UART_MR1 0x0000 -- cgit v0.10.2 From 002eb41f303e007011aecba25ea6de25a4ed475f Mon Sep 17 00:00:00 2001 From: Charanya Venkatraman Date: Tue, 7 Jun 2016 15:58:41 +0530 Subject: tty:serial:msm:Do not restore Rx interrupts in DMA Avoid data corruption issues that result in CRC errors during file transfers over serial ports at higher baud rates. The current msm_serial driver masks the FIFO Rx interrupts in msm_start_rx_dma() since Rx FIFO interrupts are not required in DMA mode. However, msm_complete_rx_dma() re-enables the Rx FIFO interrupts which could cause RXSTALE event to be processed when a TXLEV interrupt occurs. The following is the sequence of events that could occur resulting in data corruption. msm_start_rx_dma -> msm_complete_rx_dma --> spin_unlock_irqrestore(&port->lock) --> msm_uart_irq()(For TXLEV interrupt) --> msm_handle_rx_dm() (Read from FIFO resulting in data corruption) The patch fixes the issue by not restoring the RXLEV and RXSTALE interrupts in msm_complete_rx_dma(). These interrupts are required only in FIFO mode. Signed-off-by: Charanya Venkatraman Acked-by: Andy Gross Reviewed-by: Stephen Boyd Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/msm_serial.c b/drivers/tty/serial/msm_serial.c index 88af5a3..d0384d4 100644 --- a/drivers/tty/serial/msm_serial.c +++ b/drivers/tty/serial/msm_serial.c @@ -557,10 +557,6 @@ static void msm_complete_rx_dma(void *args) val &= ~dma->enable_bit; msm_write(port, val, UARTDM_DMEN); - /* Restore interrupts */ - msm_port->imr |= UART_IMR_RXLEV | UART_IMR_RXSTALE; - msm_write(port, msm_port->imr, UART_IMR); - if (msm_read(port, UART_SR) & UART_SR_OVERRUN) { port->icount.overrun++; tty_insert_flip_char(tport, 0, TTY_OVERRUN); -- cgit v0.10.2 From 30acf549ca1e81859a67590ab9ecfce3d1050a0b Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Thu, 2 Jun 2016 17:48:28 -0700 Subject: tty: serial: msm: Don't read off end of tx fifo For dm uarts in pio mode tx data is transferred to the fifo register 4 bytes at a time, but care is not taken when these 4 bytes spans the end of the xmit buffer so the loop might read up to 3 bytes past the buffer and then skip the actual data at the beginning of the buffer. Fix this by, analogous to the DMA case, make sure the chunk doesn't wrap the xmit buffer. Fixes: 3a878c430fd6 ("tty: serial: msm: Add TX DMA support") Cc: Ivan Ivanov Cc: stable@vger.kernel.org Reported-by: Frank Rowand Reported-by: Nicolas Dechesne Signed-off-by: Bjorn Andersson Acked-by: Andy Gross Tested-by: Frank Rowand Reviewed-by: Stephen Boyd Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/msm_serial.c b/drivers/tty/serial/msm_serial.c index d0384d4..2c30aae 100644 --- a/drivers/tty/serial/msm_serial.c +++ b/drivers/tty/serial/msm_serial.c @@ -891,7 +891,7 @@ static void msm_handle_tx(struct uart_port *port) return; } - pio_count = CIRC_CNT(xmit->head, xmit->tail, UART_XMIT_SIZE); + pio_count = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE); dma_count = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE); dma_min = 1; /* Always DMA */ -- cgit v0.10.2 From 9a3f5bf275e68b6651a2bc935beaac938cf27adc Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Tue, 7 Jun 2016 19:11:52 +0100 Subject: tty: serial: msm: fix definition of msm_stop_dma The msm_stop_dma() is not exported from the driver, so make it static to stop the following warning: drivers/tty/serial/msm_serial.c:84:6: warning: symbol 'msm_stop_dma' was not declared. Should it be static? Signed-off-by: Ben Dooks Acked-by: Andy Gross Reviewed-by: Bjorn Andersson Reviewed-by: Stephen Boyd Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/msm_serial.c b/drivers/tty/serial/msm_serial.c index 2c30aae..7312e7e 100644 --- a/drivers/tty/serial/msm_serial.c +++ b/drivers/tty/serial/msm_serial.c @@ -250,7 +250,7 @@ static void msm_serial_set_mnd_regs(struct uart_port *port) static void msm_handle_tx(struct uart_port *port); static void msm_start_rx_dma(struct msm_port *msm_port); -void msm_stop_dma(struct uart_port *port, struct msm_dma *dma) +static void msm_stop_dma(struct uart_port *port, struct msm_dma *dma) { struct device *dev = port->dev; unsigned int mapped; -- cgit v0.10.2 From 3e5af8e04a3b104b6a8ccca4ff33644b5bcc21f0 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 10 May 2016 20:56:10 +0200 Subject: serial: Make SERIAL_MPS2_UART depend on ARCH_MPS2 Enabling support for the UART on the ARM MPS2 platform only make sense when compiling for the ARM MPS2 platform, unless compile-testing. Signed-off-by: Geert Uytterhoeven Reviewed-by: Vladimir Murzin Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig index b5c8ad1..518db24a 100644 --- a/drivers/tty/serial/Kconfig +++ b/drivers/tty/serial/Kconfig @@ -1478,7 +1478,7 @@ config SERIAL_MPS2_UART_CONSOLE config SERIAL_MPS2_UART bool "MPS2 UART port" - depends on ARM || COMPILE_TEST + depends on ARCH_MPS2 || COMPILE_TEST select SERIAL_CORE help This driver support the UART ports on ARM MPS2. -- cgit v0.10.2 From a7cfaf165ed0f0b1e5e8636f9f28843b2b90139a Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Fri, 20 May 2016 01:59:54 -0300 Subject: serial: serial_core: Perform NULL checks for release/request_port ops Doing the following UART bind/unbind sequence on a i.mx platform causes a kernel crash due to NULL pointer dereference: echo 21f4000.serial > /sys/bus/platform/drivers/imx-uart/bind echo 21f4000.serial > /sys/bus/platform/drivers/imx-uart/unbind Fix this problem by adding NULL checks prior to calling release/request_port ops. Reported-by: Fugang Duan Signed-off-by: Fabio Estevam Tested-by: Fugang Duan Acked-by: Fugang Duan Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index a333c59..9fc1533 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -887,7 +887,7 @@ static int uart_set_info(struct tty_struct *tty, struct tty_port *port, /* * Free and release old regions */ - if (old_type != PORT_UNKNOWN) + if (old_type != PORT_UNKNOWN && uport->ops->release_port) uport->ops->release_port(uport); uport->iobase = new_port; @@ -900,7 +900,7 @@ static int uart_set_info(struct tty_struct *tty, struct tty_port *port, /* * Claim and map the new regions */ - if (uport->type != PORT_UNKNOWN) { + if (uport->type != PORT_UNKNOWN && uport->ops->request_port) { retval = uport->ops->request_port(uport); } else { /* Always success - Jean II */ @@ -1125,7 +1125,7 @@ static int uart_do_autoconfig(struct tty_struct *tty,struct uart_state *state) * If we already have a port type configured, * we must release its resources. */ - if (uport->type != PORT_UNKNOWN) + if (uport->type != PORT_UNKNOWN && uport->ops->release_port) uport->ops->release_port(uport); flags = UART_CONFIG_TYPE; @@ -2897,7 +2897,7 @@ int uart_remove_one_port(struct uart_driver *drv, struct uart_port *uport) /* * Free the port IO and memory resources, if any. */ - if (uport->type != PORT_UNKNOWN) + if (uport->type != PORT_UNKNOWN && uport->ops->release_port) uport->ops->release_port(uport); kfree(uport->tty_groups); -- cgit v0.10.2 From 9b6519009dbe2b361a73284ea0fd2e9b86aeef4d Mon Sep 17 00:00:00 2001 From: Muhammad Falak R Wani Date: Fri, 20 May 2016 17:53:28 +0530 Subject: tty/vt/keyboard: use memdup_user(). Use memdup_user to duplicate a memory region from user-space to kernel-space, instead of open coding using kmalloc & copy_from_user. Signed-off-by: Muhammad Falak R Wani Reviewed-by: Samuel Thibault Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/vt/keyboard.c b/drivers/tty/vt/keyboard.c index cd08c10..89a7ab0 100644 --- a/drivers/tty/vt/keyboard.c +++ b/drivers/tty/vt/keyboard.c @@ -1745,16 +1745,10 @@ int vt_do_diacrit(unsigned int cmd, void __user *udp, int perm) return -EINVAL; if (ct) { - buf = kmalloc(ct * sizeof(struct kbdiacruc), - GFP_KERNEL); - if (buf == NULL) - return -ENOMEM; - - if (copy_from_user(buf, a->kbdiacruc, - ct * sizeof(struct kbdiacruc))) { - kfree(buf); - return -EFAULT; - } + buf = memdup_user(a->kbdiacruc, + ct * sizeof(struct kbdiacruc)); + if (IS_ERR(buf)) + return PTR_ERR(buf); } spin_lock_irqsave(&kbd_event_lock, flags); if (ct) -- cgit v0.10.2 From 9205218e491d70bf45f4527cd3bcb5cd3734ae17 Mon Sep 17 00:00:00 2001 From: Nicolas Ferre Date: Fri, 17 Jun 2016 12:05:46 +0200 Subject: tty/serial: atmel: re-integrate status check in irq handler The IRQ status check and related actions was done in the tasklet without benefit. So, move it back to the IRQ context to simplify IRQ handling and having the possibility to split the tasklet in two separated ones for receive and transmit actions. Signed-off-by: Nicolas Ferre Signed-off-by: Ludovic Desroches Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c index 954941d..8854ac6 100644 --- a/drivers/tty/serial/atmel_serial.c +++ b/drivers/tty/serial/atmel_serial.c @@ -146,9 +146,7 @@ struct atmel_uart_port { struct scatterlist sg_tx; struct scatterlist sg_rx; struct tasklet_struct tasklet; - unsigned int irq_status; unsigned int irq_status_prev; - unsigned int status_change; unsigned int tx_len; struct circ_buf rx_ring; @@ -1237,14 +1235,27 @@ atmel_handle_status(struct uart_port *port, unsigned int pending, unsigned int status) { struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); + unsigned int status_change; if (pending & (ATMEL_US_RIIC | ATMEL_US_DSRIC | ATMEL_US_DCDIC | ATMEL_US_CTSIC)) { - atmel_port->irq_status = status; - atmel_port->status_change = atmel_port->irq_status ^ - atmel_port->irq_status_prev; + status_change = status ^ atmel_port->irq_status_prev; atmel_port->irq_status_prev = status; - tasklet_schedule(&atmel_port->tasklet); + + if (status_change & (ATMEL_US_RI | ATMEL_US_DSR + | ATMEL_US_DCD | ATMEL_US_CTS)) { + /* TODO: All reads to CSR will clear these interrupts! */ + if (status_change & ATMEL_US_RI) + port->icount.rng++; + if (status_change & ATMEL_US_DSR) + port->icount.dsr++; + if (status_change & ATMEL_US_DCD) + uart_handle_dcd_change(port, !(status & ATMEL_US_DCD)); + if (status_change & ATMEL_US_CTS) + uart_handle_cts_change(port, !(status & ATMEL_US_CTS)); + + wake_up_interruptible(&port->state->port.delta_msr_wait); + } } } @@ -1575,31 +1586,12 @@ static void atmel_tasklet_func(unsigned long data) { struct uart_port *port = (struct uart_port *)data; struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); - unsigned int status = atmel_port->irq_status; - unsigned int status_change = atmel_port->status_change; /* The interrupt handler does not take the lock */ spin_lock(&port->lock); atmel_port->schedule_tx(port); - if (status_change & (ATMEL_US_RI | ATMEL_US_DSR - | ATMEL_US_DCD | ATMEL_US_CTS)) { - /* TODO: All reads to CSR will clear these interrupts! */ - if (status_change & ATMEL_US_RI) - port->icount.rng++; - if (status_change & ATMEL_US_DSR) - port->icount.dsr++; - if (status_change & ATMEL_US_DCD) - uart_handle_dcd_change(port, !(status & ATMEL_US_DCD)); - if (status_change & ATMEL_US_CTS) - uart_handle_cts_change(port, !(status & ATMEL_US_CTS)); - - wake_up_interruptible(&port->state->port.delta_msr_wait); - - atmel_port->status_change = 0; - } - atmel_port->schedule_rx(port); spin_unlock(&port->lock); @@ -1833,7 +1825,6 @@ static int atmel_startup(struct uart_port *port) /* Save current CSR for comparison in atmel_tasklet_func() */ atmel_port->irq_status_prev = atmel_get_lines_status(port); - atmel_port->irq_status = atmel_port->irq_status_prev; /* * Finally, enable the serial port -- cgit v0.10.2 From 00e8e65870cc581a0a8496e95480ea1b39aec58b Mon Sep 17 00:00:00 2001 From: Nicolas Ferre Date: Fri, 17 Jun 2016 12:05:47 +0200 Subject: tty/serial: atmel: split tx and rx paths Split TX and RX paths to not schedule RX tasklet on TX events and vice versa. Signed-off-by: Nicolas Ferre Signed-off-by: Ludovic Desroches Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c index 8854ac6..6c1ec7d 100644 --- a/drivers/tty/serial/atmel_serial.c +++ b/drivers/tty/serial/atmel_serial.c @@ -145,7 +145,8 @@ struct atmel_uart_port { dma_cookie_t cookie_rx; struct scatterlist sg_tx; struct scatterlist sg_rx; - struct tasklet_struct tasklet; + struct tasklet_struct tasklet_rx; + struct tasklet_struct tasklet_tx; unsigned int irq_status_prev; unsigned int tx_len; @@ -708,7 +709,7 @@ static void atmel_rx_chars(struct uart_port *port) status = atmel_uart_readl(port, ATMEL_US_CSR); } - tasklet_schedule(&atmel_port->tasklet); + tasklet_schedule(&atmel_port->tasklet_rx); } /* @@ -779,7 +780,7 @@ static void atmel_complete_tx_dma(void *arg) * remaining data from the beginning of xmit->buf to xmit->head. */ if (!uart_circ_empty(xmit)) - tasklet_schedule(&atmel_port->tasklet); + tasklet_schedule(&atmel_port->tasklet_tx); spin_unlock_irqrestore(&port->lock, flags); } @@ -964,7 +965,7 @@ static void atmel_complete_rx_dma(void *arg) struct uart_port *port = arg; struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); - tasklet_schedule(&atmel_port->tasklet); + tasklet_schedule(&atmel_port->tasklet_rx); } static void atmel_release_rx_dma(struct uart_port *port) @@ -1004,7 +1005,7 @@ static void atmel_rx_from_dma(struct uart_port *port) if (dmastat == DMA_ERROR) { dev_dbg(port->dev, "Get residue error, restart tasklet\n"); atmel_uart_writel(port, ATMEL_US_IER, ATMEL_US_TIMEOUT); - tasklet_schedule(&atmel_port->tasklet); + tasklet_schedule(&atmel_port->tasklet_rx); return; } @@ -1158,7 +1159,7 @@ static void atmel_uart_timer_callback(unsigned long data) struct uart_port *port = (void *)data; struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); - tasklet_schedule(&atmel_port->tasklet); + tasklet_schedule(&atmel_port->tasklet_rx); mod_timer(&atmel_port->uart_timer, jiffies + uart_poll_timeout(port)); } @@ -1181,7 +1182,7 @@ atmel_handle_receive(struct uart_port *port, unsigned int pending) if (pending & (ATMEL_US_ENDRX | ATMEL_US_TIMEOUT)) { atmel_uart_writel(port, ATMEL_US_IDR, (ATMEL_US_ENDRX | ATMEL_US_TIMEOUT)); - tasklet_schedule(&atmel_port->tasklet); + tasklet_schedule(&atmel_port->tasklet_rx); } if (pending & (ATMEL_US_RXBRK | ATMEL_US_OVRE | @@ -1193,7 +1194,7 @@ atmel_handle_receive(struct uart_port *port, unsigned int pending) if (pending & ATMEL_US_TIMEOUT) { atmel_uart_writel(port, ATMEL_US_IDR, ATMEL_US_TIMEOUT); - tasklet_schedule(&atmel_port->tasklet); + tasklet_schedule(&atmel_port->tasklet_rx); } } @@ -1223,7 +1224,7 @@ atmel_handle_transmit(struct uart_port *port, unsigned int pending) /* Either PDC or interrupt transmission */ atmel_uart_writel(port, ATMEL_US_IDR, atmel_port->tx_done_mask); - tasklet_schedule(&atmel_port->tasklet); + tasklet_schedule(&atmel_port->tasklet_tx); } } @@ -1582,18 +1583,25 @@ static int atmel_prepare_rx_pdc(struct uart_port *port) /* * tasklet handling tty stuff outside the interrupt handler. */ -static void atmel_tasklet_func(unsigned long data) +static void atmel_tasklet_rx_func(unsigned long data) { struct uart_port *port = (struct uart_port *)data; struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); /* The interrupt handler does not take the lock */ spin_lock(&port->lock); - - atmel_port->schedule_tx(port); - atmel_port->schedule_rx(port); + spin_unlock(&port->lock); +} +static void atmel_tasklet_tx_func(unsigned long data) +{ + struct uart_port *port = (struct uart_port *)data; + struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); + + /* The interrupt handler does not take the lock */ + spin_lock(&port->lock); + atmel_port->schedule_tx(port); spin_unlock(&port->lock); } @@ -1777,7 +1785,8 @@ static int atmel_startup(struct uart_port *port) return retval; } - tasklet_enable(&atmel_port->tasklet); + tasklet_enable(&atmel_port->tasklet_rx); + tasklet_enable(&atmel_port->tasklet_tx); /* * Initialize DMA (if necessary) @@ -1906,8 +1915,10 @@ static void atmel_shutdown(struct uart_port *port) * Clear out any scheduled tasklets before * we destroy the buffers */ - tasklet_disable(&atmel_port->tasklet); - tasklet_kill(&atmel_port->tasklet); + tasklet_disable(&atmel_port->tasklet_rx); + tasklet_disable(&atmel_port->tasklet_tx); + tasklet_kill(&atmel_port->tasklet_rx); + tasklet_kill(&atmel_port->tasklet_tx); /* * Ensure everything is stopped and @@ -2302,9 +2313,12 @@ static int atmel_init_port(struct atmel_uart_port *atmel_port, port->irq = pdev->resource[1].start; port->rs485_config = atmel_config_rs485; - tasklet_init(&atmel_port->tasklet, atmel_tasklet_func, + tasklet_init(&atmel_port->tasklet_rx, atmel_tasklet_rx_func, + (unsigned long)port); + tasklet_init(&atmel_port->tasklet_tx, atmel_tasklet_tx_func, (unsigned long)port); - tasklet_disable(&atmel_port->tasklet); + tasklet_disable(&atmel_port->tasklet_rx); + tasklet_disable(&atmel_port->tasklet_tx); memset(&atmel_port->rx_ring, 0, sizeof(atmel_port->rx_ring)); @@ -2786,7 +2800,8 @@ static int atmel_serial_remove(struct platform_device *pdev) struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); int ret = 0; - tasklet_kill(&atmel_port->tasklet); + tasklet_kill(&atmel_port->tasklet_rx); + tasklet_kill(&atmel_port->tasklet_tx); device_init_wakeup(&pdev->dev, 0); -- cgit v0.10.2 From 637ba54f6051903e1f0011b75ee36b2a29696c6d Mon Sep 17 00:00:00 2001 From: Ludovic Desroches Date: Fri, 17 Jun 2016 12:05:48 +0200 Subject: tty/serial: atmel: add comment for the ring buffer size macro There is a macro named ATMEL_SERIAL_RINGSIZE which suggesting that it corresponds to the real size of the ring buffer. Let warn people that there is a factor of four since allocation size is sizeof(struct atmel_uart_char) * ATMEL_SERIAL_RINGSIZE. Signed-off-by: Ludovic Desroches Signed-off-by: Nicolas Ferre Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c index 6c1ec7d..8570163 100644 --- a/drivers/tty/serial/atmel_serial.c +++ b/drivers/tty/serial/atmel_serial.c @@ -108,6 +108,12 @@ struct atmel_uart_char { u16 ch; }; +/* + * Be careful, the real size of the ring buffer is + * sizeof(atmel_uart_char) * ATMEL_SERIAL_RINGSIZE. It means that ring buffer + * can contain up to 1024 characters in PIO mode and up to 4096 characters in + * DMA mode. + */ #define ATMEL_SERIAL_RINGSIZE 1024 /* -- cgit v0.10.2 From 0058f0871efe7b01c6f2b3046c68196ab73e96da Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Sat, 28 May 2016 00:54:08 +0200 Subject: tty/serial: atmel: fix RS485 half duplex with DMA When using DMA, half duplex doesn't work properly because rx is not stopped before starting tx. Ensure we call atmel_stop_rx() in the DMA case. Signed-off-by: Alexandre Belloni Acked-by: Nicolas Ferre Cc: stable Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c index 8570163..f887c1d 100644 --- a/drivers/tty/serial/atmel_serial.c +++ b/drivers/tty/serial/atmel_serial.c @@ -487,19 +487,21 @@ static void atmel_start_tx(struct uart_port *port) { struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); - if (atmel_use_pdc_tx(port)) { - if (atmel_uart_readl(port, ATMEL_PDC_PTSR) & ATMEL_PDC_TXTEN) - /* The transmitter is already running. Yes, we - really need this.*/ - return; + if (atmel_use_pdc_tx(port) && (atmel_uart_readl(port, ATMEL_PDC_PTSR) + & ATMEL_PDC_TXTEN)) + /* The transmitter is already running. Yes, we + really need this.*/ + return; + if (atmel_use_pdc_tx(port) || atmel_use_dma_tx(port)) if ((port->rs485.flags & SER_RS485_ENABLED) && !(port->rs485.flags & SER_RS485_RX_DURING_TX)) atmel_stop_rx(port); + if (atmel_use_pdc_tx(port)) /* re-enable PDC transmit */ atmel_uart_writel(port, ATMEL_PDC_PTCR, ATMEL_PDC_TXTEN); - } + /* Enable interrupts */ atmel_uart_writel(port, ATMEL_US_IER, atmel_port->tx_done_mask); } -- cgit v0.10.2 From 210417ce836aa3f0ededcc8f541f5e4a05d2e880 Mon Sep 17 00:00:00 2001 From: Shubhrajyoti Datta Date: Fri, 27 May 2016 15:05:19 +0530 Subject: tty: xuartps: disable clocks when not used Currently the clocks are enabled at probe and disabled at remove. Instead enable the clocks when used. Signed-off-by: Shubhrajyoti Datta Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/xilinx_uartps.c b/drivers/tty/serial/xilinx_uartps.c index cd46e64..9ca1a4d 100644 --- a/drivers/tty/serial/xilinx_uartps.c +++ b/drivers/tty/serial/xilinx_uartps.c @@ -976,6 +976,23 @@ static void cdns_uart_poll_put_char(struct uart_port *port, unsigned char c) } #endif +static void cdns_uart_pm(struct uart_port *port, unsigned int state, + unsigned int oldstate) +{ + struct cdns_uart *cdns_uart = port->private_data; + + switch (state) { + case UART_PM_STATE_OFF: + clk_disable(cdns_uart->uartclk); + clk_disable(cdns_uart->pclk); + break; + default: + clk_enable(cdns_uart->pclk); + clk_enable(cdns_uart->uartclk); + break; + } +} + static struct uart_ops cdns_uart_ops = { .set_mctrl = cdns_uart_set_mctrl, .get_mctrl = cdns_uart_get_mctrl, @@ -987,6 +1004,7 @@ static struct uart_ops cdns_uart_ops = { .set_termios = cdns_uart_set_termios, .startup = cdns_uart_startup, .shutdown = cdns_uart_shutdown, + .pm = cdns_uart_pm, .type = cdns_uart_type, .verify_port = cdns_uart_verify_port, .request_port = cdns_uart_request_port, @@ -1350,12 +1368,12 @@ static int cdns_uart_probe(struct platform_device *pdev) return PTR_ERR(cdns_uart_data->uartclk); } - rc = clk_prepare_enable(cdns_uart_data->pclk); + rc = clk_prepare(cdns_uart_data->pclk); if (rc) { dev_err(&pdev->dev, "Unable to enable pclk clock.\n"); return rc; } - rc = clk_prepare_enable(cdns_uart_data->uartclk); + rc = clk_prepare(cdns_uart_data->uartclk); if (rc) { dev_err(&pdev->dev, "Unable to enable device clock.\n"); goto err_out_clk_dis_pclk; @@ -1422,9 +1440,9 @@ err_out_notif_unreg: &cdns_uart_data->clk_rate_change_nb); #endif err_out_clk_disable: - clk_disable_unprepare(cdns_uart_data->uartclk); + clk_unprepare(cdns_uart_data->uartclk); err_out_clk_dis_pclk: - clk_disable_unprepare(cdns_uart_data->pclk); + clk_unprepare(cdns_uart_data->pclk); return rc; } @@ -1448,8 +1466,8 @@ static int cdns_uart_remove(struct platform_device *pdev) #endif rc = uart_remove_one_port(&cdns_uart_uart_driver, port); port->mapbase = 0; - clk_disable_unprepare(cdns_uart_data->uartclk); - clk_disable_unprepare(cdns_uart_data->pclk); + clk_unprepare(cdns_uart_data->uartclk); + clk_unprepare(cdns_uart_data->pclk); return rc; } -- cgit v0.10.2 From 24a6a3037e0b47168f9b3bb9db7ad60c89dad7ba Mon Sep 17 00:00:00 2001 From: Purna Chandra Mandal Date: Tue, 17 May 2016 10:35:54 +0530 Subject: serial: pic32_uart: Fix double free of 'sport->irq_fault_name'. Allocated memory for 'sport->irq_fault_name' is freed twice, first in error check of 'if(!sport->irq_rx_name)' and other in fallback handler. Signed-off-by: Purna Chandra Mandal Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/pic32_uart.c b/drivers/tty/serial/pic32_uart.c index 62a43bf..7f8e99b 100644 --- a/drivers/tty/serial/pic32_uart.c +++ b/drivers/tty/serial/pic32_uart.c @@ -445,7 +445,6 @@ static int pic32_uart_startup(struct uart_port *port) sport->idx); if (!sport->irq_rx_name) { dev_err(port->dev, "%s: kasprintf err!", __func__); - kfree(sport->irq_fault_name); ret = -ENOMEM; goto out_f; } -- cgit v0.10.2 From 30743257f04d8ffa1d58aa5f68f2be84f4607103 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Sun, 22 May 2016 11:06:25 +0200 Subject: MAINTAINERS: Add file patterns for serial device tree bindings Submitters of device tree binding documentation may forget to CC the subsystem maintainer if this is missing. Signed-off-by: Geert Uytterhoeven Cc: Greg Kroah-Hartman Cc: linux-serial@vger.kernel.org Signed-off-by: Greg Kroah-Hartman diff --git a/MAINTAINERS b/MAINTAINERS index e1b090f..51447a5 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -9996,6 +9996,7 @@ SERIAL DRIVERS M: Greg Kroah-Hartman L: linux-serial@vger.kernel.org S: Maintained +F: Documentation/devicetree/bindings/serial/ F: drivers/tty/serial/ SYNOPSYS DESIGNWARE DMAC DRIVER -- cgit v0.10.2 From 4da22f1418cb6f09e974499794db2f5e59fe8090 Mon Sep 17 00:00:00 2001 From: "Ji-Ze Hong (Peter Hong)" Date: Fri, 27 May 2016 10:02:51 +0800 Subject: serial: 8250_fintek: fix the mismatched IRQ mode MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Some BIOS only use _OSI("Linux") to distinguish between Linux & Windows. Apply Level/Low to UART trigger mode if Windows, Edge/High mode otherwise. But since 2.6.23 the mainline kernel no longer returns true for _OSI(“Linux”). The default IRQ0~15 trigger mode in Linux is Edge/High mode without ACPI MADT override. It mismatches IRQ mode and makes UART malfunctional on such motherboard. This patch will check the current IRQ mode and apply correct mode to UART. The following link is F81216AD spec PDF: http://html.alldatasheet.com/html-pdf/257956/FINTEK/F81216AD/5569/ 25/F81216AD.html LDN0~3 70h: IRQ channel & Mode register Bit 6~5 : 00 : Active low level mode 01 : Active high edge mode Bit 4 : Sharing Flag (0: not share/1: share) Bit 3~0 : IRQ channel Signed-off-by: Ji-Ze Hong (Peter Hong) Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/8250/8250_fintek.c b/drivers/tty/serial/8250/8250_fintek.c index 870981d..737b4b3 100644 --- a/drivers/tty/serial/8250/8250_fintek.c +++ b/drivers/tty/serial/8250/8250_fintek.c @@ -13,6 +13,7 @@ #include #include #include +#include #include "8250.h" #define ADDR_PORT 0 @@ -30,6 +31,12 @@ #define IO_ADDR2 0x60 #define LDN 0x7 +#define IRQ_MODE 0x70 +#define IRQ_SHARE BIT(4) +#define IRQ_MODE_MASK (BIT(6) | BIT(5)) +#define IRQ_LEVEL_LOW 0 +#define IRQ_EDGE_HIGH BIT(5) + #define RS485 0xF0 #define RTS_INVERT BIT(5) #define RS485_URA BIT(4) @@ -176,10 +183,37 @@ static int find_base_port(struct fintek_8250 *pdata, u16 io_address) return -ENODEV; } +static int fintek_8250_set_irq_mode(struct fintek_8250 *pdata, bool level_mode) +{ + int status; + u8 tmp; + + status = fintek_8250_enter_key(pdata->base_port, pdata->key); + if (status) + return status; + + outb(LDN, pdata->base_port + ADDR_PORT); + outb(pdata->index, pdata->base_port + DATA_PORT); + + outb(IRQ_MODE, pdata->base_port + ADDR_PORT); + tmp = inb(pdata->base_port + DATA_PORT); + + tmp &= ~IRQ_MODE_MASK; + tmp |= IRQ_SHARE; + if (!level_mode) + tmp |= IRQ_EDGE_HIGH; + + outb(tmp, pdata->base_port + DATA_PORT); + fintek_8250_exit_key(pdata->base_port); + return 0; +} + int fintek_8250_probe(struct uart_8250_port *uart) { struct fintek_8250 *pdata; struct fintek_8250 probe_data; + struct irq_data *irq_data = irq_get_irq_data(uart->port.irq); + bool level_mode = irqd_is_level_type(irq_data); if (find_base_port(&probe_data, uart->port.iobase)) return -ENODEV; @@ -192,5 +226,5 @@ int fintek_8250_probe(struct uart_8250_port *uart) uart->port.rs485_config = fintek_8250_rs485_config; uart->port.private_data = pdata; - return 0; + return fintek_8250_set_irq_mode(pdata, level_mode); } -- cgit v0.10.2 From e51e4d8a185de90424b03f30181b35f29c46a25a Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Thu, 16 Jun 2016 08:27:35 +0200 Subject: serial: samsung: Fix ERR pointer dereference on deferred probe When the clk_get() of "uart" clock returns EPROBE_DEFER, the next re-probe finishes with success but uses invalid (ERR_PTR) values. This leads to dereferencing of ERR_PTR stored under ourport->clk: 12c30000.serial: Controller clock not found (...) 12c30000.serial: ttySAC3 at MMIO 0x12c30000 (irq = 61, base_baud = 0) is a S3C6400/10 Unable to handle kernel paging request at virtual address fffffdfb (clk_prepare) from [] (s3c24xx_serial_pm+0x20/0x128) (s3c24xx_serial_pm) from [] (uart_change_pm+0x38/0x40) (uart_change_pm) from [] (uart_add_one_port+0x31c/0x44c) (uart_add_one_port) from [] (s3c24xx_serial_probe+0x2a8/0x418) (s3c24xx_serial_probe) from [] (platform_drv_probe+0x50/0xb0) (platform_drv_probe) from [] (driver_probe_device+0x1f4/0x2b0) (driver_probe_device) from [] (bus_for_each_drv+0x44/0x8c) (bus_for_each_drv) from [] (__device_attach+0x9c/0x100) (__device_attach) from [] (bus_probe_device+0x84/0x8c) (bus_probe_device) from [] (deferred_probe_work_func+0x60/0x8c) (deferred_probe_work_func) from [] (process_one_work+0x120/0x328) (process_one_work) from [] (worker_thread+0x2c/0x4ac) (worker_thread) from [] (kthread+0xd8/0xf4) (kthread) from [] (ret_from_fork+0x14/0x3c) The first unsuccessful clk_get() causes s3c24xx_serial_init_port() to exit with failure but the s3c24xx_uart_port is left half-configured (e.g. port->mapbase is set, clk contains ERR_PTR). On next re-probe, the function s3c24xx_serial_init_port() will exit early with success because of configured port->mapbase and driver will use old values, including the ERR_PTR as clock. Fix this by cleaning the port->mapbase on error path so each re-probe will initialize all of the port settings. Fixes: 60e93575476f ("serial: samsung: enable clock before clearing pending interrupts during init") Cc: Signed-off-by: Krzysztof Kozlowski Reviewed-by: Javier Martinez Canillas Tested-by: Javier Martinez Canillas Tested-by: Kevin Hilman Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/samsung.c b/drivers/tty/serial/samsung.c index 99bb231..f0bd2ec 100644 --- a/drivers/tty/serial/samsung.c +++ b/drivers/tty/serial/samsung.c @@ -1684,7 +1684,7 @@ static int s3c24xx_serial_init_port(struct s3c24xx_uart_port *ourport, return -ENODEV; if (port->mapbase != 0) - return 0; + return -EINVAL; /* setup info for port */ port->dev = &platdev->dev; @@ -1738,22 +1738,25 @@ static int s3c24xx_serial_init_port(struct s3c24xx_uart_port *ourport, ourport->dma = devm_kzalloc(port->dev, sizeof(*ourport->dma), GFP_KERNEL); - if (!ourport->dma) - return -ENOMEM; + if (!ourport->dma) { + ret = -ENOMEM; + goto err; + } } ourport->clk = clk_get(&platdev->dev, "uart"); if (IS_ERR(ourport->clk)) { pr_err("%s: Controller clock not found\n", dev_name(&platdev->dev)); - return PTR_ERR(ourport->clk); + ret = PTR_ERR(ourport->clk); + goto err; } ret = clk_prepare_enable(ourport->clk); if (ret) { pr_err("uart: clock failed to prepare+enable: %d\n", ret); clk_put(ourport->clk); - return ret; + goto err; } /* Keep all interrupts masked and cleared */ @@ -1769,7 +1772,12 @@ static int s3c24xx_serial_init_port(struct s3c24xx_uart_port *ourport, /* reset the fifos (and setup the uart) */ s3c24xx_serial_resetport(port, cfg); + return 0; + +err: + port->mapbase = 0; + return ret; } /* Device driver serial port probe */ -- cgit v0.10.2 From 926b7b5122c96e1f18cd20e85a286c7ec8d18c97 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Thu, 16 Jun 2016 08:27:36 +0200 Subject: serial: samsung: Fix possible out of bounds access on non-DT platform On non-DeviceTree platforms, the index of serial device is a static variable incremented on each probe. It is incremented even if deferred probe happens when getting the clock in s3c24xx_serial_init_port(). This index is used for referencing elements of statically allocated s3c24xx_serial_ports array. In case of re-probe, the index will point outside of this array leading to memory corruption. Increment the index only on successful probe. Reported-by: Bartlomiej Zolnierkiewicz Fixes: b497549a035c ("[ARM] S3C24XX: Split serial driver into core and per-cpu drivers") Signed-off-by: Krzysztof Kozlowski Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/samsung.c b/drivers/tty/serial/samsung.c index f0bd2ec..4d2924f 100644 --- a/drivers/tty/serial/samsung.c +++ b/drivers/tty/serial/samsung.c @@ -1844,8 +1844,6 @@ static int s3c24xx_serial_probe(struct platform_device *pdev) ourport->min_dma_size = max_t(int, ourport->port.fifosize, dma_get_cache_alignment()); - probe_index++; - dbg("%s: initialising port %p...\n", __func__, ourport); ret = s3c24xx_serial_init_port(ourport, pdev); @@ -1875,6 +1873,8 @@ static int s3c24xx_serial_probe(struct platform_device *pdev) if (ret < 0) dev_err(&pdev->dev, "failed to add cpufreq notifier\n"); + probe_index++; + return 0; } -- cgit v0.10.2 From 55c368cb760f08ba1f15718086696754e593504a Mon Sep 17 00:00:00 2001 From: Alexandr Petrenko Date: Mon, 23 May 2016 10:04:54 +0300 Subject: 8250_pci: Adds support for the WCH CH355 4S card Adds support for the WCH CH355 4S card in the 8250 serial driver. Signed-off-by: Alexandr Petrenko Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c index 3d6287a..20ebaea 100644 --- a/drivers/tty/serial/8250/8250_pci.c +++ b/drivers/tty/serial/8250/8250_pci.c @@ -1865,6 +1865,16 @@ pci_wch_ch353_setup(struct serial_private *priv, } static int +pci_wch_ch355_setup(struct serial_private *priv, + const struct pciserial_board *board, + struct uart_8250_port *port, int idx) +{ + port->port.flags |= UPF_FIXED_TYPE; + port->port.type = PORT_16550A; + return pci_default_setup(priv, board, port, idx); +} + +static int pci_wch_ch38x_setup(struct serial_private *priv, const struct pciserial_board *board, struct uart_8250_port *port, int idx) @@ -1915,6 +1925,7 @@ pci_wch_ch38x_setup(struct serial_private *priv, #define PCI_DEVICE_ID_WCH_CH353_2S1PF 0x5046 #define PCI_DEVICE_ID_WCH_CH353_1S1P 0x5053 #define PCI_DEVICE_ID_WCH_CH353_2S1P 0x7053 +#define PCI_DEVICE_ID_WCH_CH355_4S 0x7173 #define PCI_VENDOR_ID_AGESTAR 0x5372 #define PCI_DEVICE_ID_AGESTAR_9375 0x6872 #define PCI_VENDOR_ID_ASIX 0x9710 @@ -2618,6 +2629,14 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = { .subdevice = PCI_ANY_ID, .setup = pci_wch_ch353_setup, }, + /* WCH CH355 4S card (16550 clone) */ + { + .vendor = PCI_VENDOR_ID_WCH, + .device = PCI_DEVICE_ID_WCH_CH355_4S, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .setup = pci_wch_ch355_setup, + }, /* WCH CH382 2S card (16850 clone) */ { .vendor = PCIE_VENDOR_ID_WCH, @@ -3812,6 +3831,7 @@ static const struct pci_device_id blacklist[] = { /* multi-io cards handled by parport_serial */ { PCI_DEVICE(0x4348, 0x7053), }, /* WCH CH353 2S1P */ { PCI_DEVICE(0x4348, 0x5053), }, /* WCH CH353 1S1P */ + { PCI_DEVICE(0x4348, 0x7173), }, /* WCH CH355 4S */ { PCI_DEVICE(0x1c00, 0x3250), }, /* WCH CH382 2S1P */ { PCI_DEVICE(0x1c00, 0x3470), }, /* WCH CH384 4S */ @@ -5567,6 +5587,10 @@ static struct pci_device_id serial_pci_tbl[] = { PCI_ANY_ID, PCI_ANY_ID, 0, 0, pbn_b0_bt_2_115200 }, + { PCI_VENDOR_ID_WCH, PCI_DEVICE_ID_WCH_CH355_4S, + PCI_ANY_ID, PCI_ANY_ID, + 0, 0, pbn_b0_bt_4_115200 }, + { PCIE_VENDOR_ID_WCH, PCIE_DEVICE_ID_WCH_CH382_2S, PCI_ANY_ID, PCI_ANY_ID, 0, 0, pbn_wch382_2 }, -- cgit v0.10.2 From 5bdb48b501e8366d5fd361cd402816aa3e525895 Mon Sep 17 00:00:00 2001 From: Alexander Shiyan Date: Tue, 7 Jun 2016 18:59:21 +0300 Subject: serial: max310x: Fix RS485 handling RS485 IOCTLs uses spinlocks, so move regmap functions into a separate work queue. Signed-off-by: Alexander Shiyan Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c index 3f6e0ab..bf6e3e0 100644 --- a/drivers/tty/serial/max310x.c +++ b/drivers/tty/serial/max310x.c @@ -262,6 +262,7 @@ struct max310x_one { struct uart_port port; struct work_struct tx_work; struct work_struct md_work; + struct work_struct rs_work; }; struct max310x_port { @@ -877,36 +878,45 @@ static void max310x_set_termios(struct uart_port *port, uart_update_timeout(port, termios->c_cflag, baud); } -static int max310x_rs485_config(struct uart_port *port, - struct serial_rs485 *rs485) +static void max310x_rs_proc(struct work_struct *ws) { + struct max310x_one *one = container_of(ws, struct max310x_one, rs_work); unsigned int val; - if (rs485->delay_rts_before_send > 0x0f || - rs485->delay_rts_after_send > 0x0f) - return -ERANGE; + val = (one->port.rs485.delay_rts_before_send << 4) | + one->port.rs485.delay_rts_after_send; + max310x_port_write(&one->port, MAX310X_HDPIXDELAY_REG, val); - val = (rs485->delay_rts_before_send << 4) | - rs485->delay_rts_after_send; - max310x_port_write(port, MAX310X_HDPIXDELAY_REG, val); - if (rs485->flags & SER_RS485_ENABLED) { - max310x_port_update(port, MAX310X_MODE1_REG, + if (one->port.rs485.flags & SER_RS485_ENABLED) { + max310x_port_update(&one->port, MAX310X_MODE1_REG, MAX310X_MODE1_TRNSCVCTRL_BIT, MAX310X_MODE1_TRNSCVCTRL_BIT); - max310x_port_update(port, MAX310X_MODE2_REG, + max310x_port_update(&one->port, MAX310X_MODE2_REG, MAX310X_MODE2_ECHOSUPR_BIT, MAX310X_MODE2_ECHOSUPR_BIT); } else { - max310x_port_update(port, MAX310X_MODE1_REG, + max310x_port_update(&one->port, MAX310X_MODE1_REG, MAX310X_MODE1_TRNSCVCTRL_BIT, 0); - max310x_port_update(port, MAX310X_MODE2_REG, + max310x_port_update(&one->port, MAX310X_MODE2_REG, MAX310X_MODE2_ECHOSUPR_BIT, 0); } +} + +static int max310x_rs485_config(struct uart_port *port, + struct serial_rs485 *rs485) +{ + struct max310x_one *one = container_of(port, struct max310x_one, port); + + if ((rs485->delay_rts_before_send > 0x0f) || + (rs485->delay_rts_after_send > 0x0f)) + return -ERANGE; rs485->flags &= SER_RS485_RTS_ON_SEND | SER_RS485_ENABLED; memset(rs485->padding, 0, sizeof(rs485->padding)); port->rs485 = *rs485; + schedule_work(&one->rs_work); + return 0; } @@ -1214,8 +1224,10 @@ static int max310x_probe(struct device *dev, struct max310x_devtype *devtype, MAX310X_MODE1_IRQSEL_BIT); /* Initialize queue for start TX */ INIT_WORK(&s->p[i].tx_work, max310x_wq_proc); - /* Initialize queue for changing mode */ + /* Initialize queue for changing LOOPBACK mode */ INIT_WORK(&s->p[i].md_work, max310x_md_proc); + /* Initialize queue for changing RS485 mode */ + INIT_WORK(&s->p[i].rs_work, max310x_rs_proc); /* Register port */ uart_add_one_port(&s->uart, &s->p[i].port); /* Go to suspend mode */ @@ -1257,6 +1269,7 @@ static int max310x_remove(struct device *dev) for (i = 0; i < s->uart.nr; i++) { cancel_work_sync(&s->p[i].tx_work); cancel_work_sync(&s->p[i].md_work); + cancel_work_sync(&s->p[i].rs_work); uart_remove_one_port(&s->uart, &s->p[i].port); s->devtype->power(&s->p[i].port, 0); } -- cgit v0.10.2 From 0e8cc7c2ea025b96b4ed57b52c61f2d982a95ddb Mon Sep 17 00:00:00 2001 From: Alexander Shiyan Date: Tue, 7 Jun 2016 18:59:23 +0300 Subject: serial: max310x: Using resource-managed function for GPIO Use resource managed functions devm_gpiochip_add_data() to make error & exit path a bit simpler. Signed-off-by: Alexander Shiyan Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c index bf6e3e0..6e2edbb 100644 --- a/drivers/tty/serial/max310x.c +++ b/drivers/tty/serial/max310x.c @@ -1193,9 +1193,11 @@ static int max310x_probe(struct device *dev, struct max310x_devtype *devtype, s->gpio.base = -1; s->gpio.ngpio = devtype->nr * 4; s->gpio.can_sleep = 1; - ret = gpiochip_add_data(&s->gpio, s); - if (ret) - goto out_uart; + ret = devm_gpiochip_add_data(dev, &s->gpio, s); + if (ret) { + uart_unregister_driver(&s->uart); + goto out_clk; + } #endif mutex_init(&s->mutex); @@ -1244,11 +1246,6 @@ static int max310x_probe(struct device *dev, struct max310x_devtype *devtype, mutex_destroy(&s->mutex); -#ifdef CONFIG_GPIOLIB - gpiochip_remove(&s->gpio); - -out_uart: -#endif uart_unregister_driver(&s->uart); out_clk: @@ -1262,10 +1259,6 @@ static int max310x_remove(struct device *dev) struct max310x_port *s = dev_get_drvdata(dev); int i; -#ifdef CONFIG_GPIOLIB - gpiochip_remove(&s->gpio); -#endif - for (i = 0; i < s->uart.nr; i++) { cancel_work_sync(&s->p[i].tx_work); cancel_work_sync(&s->p[i].md_work); -- cgit v0.10.2 From 6286767ad3afc886ec6473409aa02191cb54f97b Mon Sep 17 00:00:00 2001 From: Alexander Shiyan Date: Tue, 7 Jun 2016 18:59:24 +0300 Subject: serial: max310x: Register UART driver at module_init This patch moves UART registration at module_init initcall, so this should helps to add multiple chip support in the future. Signed-off-by: Alexander Shiyan Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c index 6e2edbb..66dd3e2 100644 --- a/drivers/tty/serial/max310x.c +++ b/drivers/tty/serial/max310x.c @@ -1,7 +1,7 @@ /* * Maxim (Dallas) MAX3107/8/9, MAX14830 serial driver * - * Copyright (C) 2012-2014 Alexander Shiyan + * Copyright (C) 2012-2016 Alexander Shiyan * * Based on max3100.c, by Christian Pellegrin * Based on max3110.c, by Feng Tang @@ -32,6 +32,7 @@ #define MAX310X_NAME "max310x" #define MAX310X_MAJOR 204 #define MAX310X_MINOR 209 +#define MAX310X_UART_NR 4 /* MAX310X register definitions */ #define MAX310X_RHR_REG (0x00) /* RX FIFO */ @@ -266,7 +267,6 @@ struct max310x_one { }; struct max310x_port { - struct uart_driver uart; struct max310x_devtype *devtype; struct regmap *regmap; struct mutex mutex; @@ -277,6 +277,15 @@ struct max310x_port { struct max310x_one p[0]; }; +static struct uart_driver max310x_uart = { + .owner = THIS_MODULE, + .driver_name = MAX310X_NAME, + .dev_name = "ttyMAX", + .major = MAX310X_MAJOR, + .minor = MAX310X_MINOR, + .nr = MAX310X_UART_NR, +}; + static u8 max310x_port_read(struct uart_port *port, u8 reg) { struct max310x_port *s = dev_get_drvdata(port->dev); @@ -716,13 +725,13 @@ static irqreturn_t max310x_ist(int irq, void *dev_id) { struct max310x_port *s = (struct max310x_port *)dev_id; - if (s->uart.nr > 1) { + if (s->devtype->nr > 1) { do { unsigned int val = ~0; WARN_ON_ONCE(regmap_read(s->regmap, MAX310X_GLOBALIRQ_REG, &val)); - val = ((1 << s->uart.nr) - 1) & ~val; + val = ((1 << s->devtype->nr) - 1) & ~val; if (!val) break; max310x_port_irq(s, fls(val) - 1); @@ -1019,8 +1028,8 @@ static int __maybe_unused max310x_suspend(struct device *dev) struct max310x_port *s = dev_get_drvdata(dev); int i; - for (i = 0; i < s->uart.nr; i++) { - uart_suspend_port(&s->uart, &s->p[i].port); + for (i = 0; i < s->devtype->nr; i++) { + uart_suspend_port(&max310x_uart, &s->p[i].port); s->devtype->power(&s->p[i].port, 0); } @@ -1032,9 +1041,9 @@ static int __maybe_unused max310x_resume(struct device *dev) struct max310x_port *s = dev_get_drvdata(dev); int i; - for (i = 0; i < s->uart.nr; i++) { + for (i = 0; i < s->devtype->nr; i++) { s->devtype->power(&s->p[i].port, 1); - uart_resume_port(&s->uart, &s->p[i].port); + uart_resume_port(&max310x_uart, &s->p[i].port); } return 0; @@ -1169,18 +1178,6 @@ static int max310x_probe(struct device *dev, struct max310x_devtype *devtype, uartclk = max310x_set_ref_clk(s, freq, xtal); dev_dbg(dev, "Reference clock set to %i Hz\n", uartclk); - /* Register UART driver */ - s->uart.owner = THIS_MODULE; - s->uart.dev_name = "ttyMAX"; - s->uart.major = MAX310X_MAJOR; - s->uart.minor = MAX310X_MINOR; - s->uart.nr = devtype->nr; - ret = uart_register_driver(&s->uart); - if (ret) { - dev_err(dev, "Registering UART driver failed\n"); - goto out_clk; - } - #ifdef CONFIG_GPIOLIB /* Setup GPIO cotroller */ s->gpio.owner = THIS_MODULE; @@ -1194,10 +1191,8 @@ static int max310x_probe(struct device *dev, struct max310x_devtype *devtype, s->gpio.ngpio = devtype->nr * 4; s->gpio.can_sleep = 1; ret = devm_gpiochip_add_data(dev, &s->gpio, s); - if (ret) { - uart_unregister_driver(&s->uart); + if (ret) goto out_clk; - } #endif mutex_init(&s->mutex); @@ -1231,7 +1226,7 @@ static int max310x_probe(struct device *dev, struct max310x_devtype *devtype, /* Initialize queue for changing RS485 mode */ INIT_WORK(&s->p[i].rs_work, max310x_rs_proc); /* Register port */ - uart_add_one_port(&s->uart, &s->p[i].port); + uart_add_one_port(&max310x_uart, &s->p[i].port); /* Go to suspend mode */ devtype->power(&s->p[i].port, 0); } @@ -1246,8 +1241,6 @@ static int max310x_probe(struct device *dev, struct max310x_devtype *devtype, mutex_destroy(&s->mutex); - uart_unregister_driver(&s->uart); - out_clk: clk_disable_unprepare(s->clk); @@ -1259,16 +1252,15 @@ static int max310x_remove(struct device *dev) struct max310x_port *s = dev_get_drvdata(dev); int i; - for (i = 0; i < s->uart.nr; i++) { + for (i = 0; i < s->devtype->nr; i++) { cancel_work_sync(&s->p[i].tx_work); cancel_work_sync(&s->p[i].md_work); cancel_work_sync(&s->p[i].rs_work); - uart_remove_one_port(&s->uart, &s->p[i].port); + uart_remove_one_port(&max310x_uart, &s->p[i].port); s->devtype->power(&s->p[i].port, 0); } mutex_destroy(&s->mutex); - uart_unregister_driver(&s->uart); clk_disable_unprepare(s->clk); return 0; @@ -1341,7 +1333,7 @@ static const struct spi_device_id max310x_id_table[] = { }; MODULE_DEVICE_TABLE(spi, max310x_id_table); -static struct spi_driver max310x_uart_driver = { +static struct spi_driver max310x_spi_driver = { .driver = { .name = MAX310X_NAME, .of_match_table = of_match_ptr(max310x_dt_ids), @@ -1351,9 +1343,34 @@ static struct spi_driver max310x_uart_driver = { .remove = max310x_spi_remove, .id_table = max310x_id_table, }; -module_spi_driver(max310x_uart_driver); #endif +static int __init max310x_uart_init(void) +{ + int ret; + + ret = uart_register_driver(&max310x_uart); + if (ret) + return ret; + +#ifdef CONFIG_SPI_MASTER + spi_register_driver(&max310x_spi_driver); +#endif + + return 0; +} +module_init(max310x_uart_init); + +static void __exit max310x_uart_exit(void) +{ +#ifdef CONFIG_SPI_MASTER + spi_unregister_driver(&max310x_spi_driver); +#endif + + uart_unregister_driver(&max310x_uart); +} +module_exit(max310x_uart_exit); + MODULE_LICENSE("GPL"); MODULE_AUTHOR("Alexander Shiyan "); MODULE_DESCRIPTION("MAX310X serial driver"); -- cgit v0.10.2 From e940e817a701dcaf0d218571c251af0cb6d1bbfb Mon Sep 17 00:00:00 2001 From: Alexander Shiyan Date: Tue, 7 Jun 2016 18:59:25 +0300 Subject: serial: max310x: Remove duplicate bits definition Signed-off-by: Alexander Shiyan Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c index 66dd3e2..e73ae6e 100644 --- a/drivers/tty/serial/max310x.c +++ b/drivers/tty/serial/max310x.c @@ -156,10 +156,6 @@ #define MAX310X_LCR_FORCEPARITY_BIT (1 << 5) /* 9-bit multidrop parity */ #define MAX310X_LCR_TXBREAK_BIT (1 << 6) /* TX break enable */ #define MAX310X_LCR_RTS_BIT (1 << 7) /* RTS pin control */ -#define MAX310X_LCR_WORD_LEN_5 (0x00) -#define MAX310X_LCR_WORD_LEN_6 (0x01) -#define MAX310X_LCR_WORD_LEN_7 (0x02) -#define MAX310X_LCR_WORD_LEN_8 (0x03) /* IRDA register bits */ #define MAX310X_IRDA_IRDAEN_BIT (1 << 0) /* IRDA mode enable */ @@ -806,7 +802,7 @@ static void max310x_set_termios(struct uart_port *port, struct ktermios *termios, struct ktermios *old) { - unsigned int lcr, flow = 0; + unsigned int lcr = 0, flow = 0; int baud; /* Mask termios capabilities we don't support */ @@ -815,17 +811,16 @@ static void max310x_set_termios(struct uart_port *port, /* Word size */ switch (termios->c_cflag & CSIZE) { case CS5: - lcr = MAX310X_LCR_WORD_LEN_5; break; case CS6: - lcr = MAX310X_LCR_WORD_LEN_6; + lcr = MAX310X_LCR_LENGTH0_BIT; break; case CS7: - lcr = MAX310X_LCR_WORD_LEN_7; + lcr = MAX310X_LCR_LENGTH1_BIT; break; case CS8: default: - lcr = MAX310X_LCR_WORD_LEN_8; + lcr = MAX310X_LCR_LENGTH1_BIT | MAX310X_LCR_LENGTH0_BIT; break; } -- cgit v0.10.2 From c8246fefe2c995e128345614fb98b5ed5014318b Mon Sep 17 00:00:00 2001 From: Alexander Shiyan Date: Tue, 7 Jun 2016 18:59:26 +0300 Subject: serial: max310x: Unregister UARTs on error Add uart_remove_one_port() for error path. Signed-off-by: Alexander Shiyan Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c index e73ae6e..347f6e8 100644 --- a/drivers/tty/serial/max310x.c +++ b/drivers/tty/serial/max310x.c @@ -1234,6 +1234,9 @@ static int max310x_probe(struct device *dev, struct max310x_devtype *devtype, dev_err(dev, "Unable to reguest IRQ %i\n", irq); + for (i = 0; i < devtype->nr; i++) + uart_remove_one_port(&max310x_uart, &s->p[i].port); + mutex_destroy(&s->mutex); out_clk: -- cgit v0.10.2 From 78adccac1ff9f485ccf427f337982799ce68738e Mon Sep 17 00:00:00 2001 From: Alexander Shiyan Date: Tue, 7 Jun 2016 18:59:27 +0300 Subject: serial: max310x: Assign port line automatically This patch makes assignment of port line automatically, so now user allow to use several MAX310X chips. Signed-off-by: Alexander Shiyan Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c index 347f6e8..9360801 100644 --- a/drivers/tty/serial/max310x.c +++ b/drivers/tty/serial/max310x.c @@ -32,7 +32,7 @@ #define MAX310X_NAME "max310x" #define MAX310X_MAJOR 204 #define MAX310X_MINOR 209 -#define MAX310X_UART_NR 4 +#define MAX310X_UART_NRMAX 16 /* MAX310X register definitions */ #define MAX310X_RHR_REG (0x00) /* RX FIFO */ @@ -279,9 +279,11 @@ static struct uart_driver max310x_uart = { .dev_name = "ttyMAX", .major = MAX310X_MAJOR, .minor = MAX310X_MINOR, - .nr = MAX310X_UART_NR, + .nr = MAX310X_UART_NRMAX, }; +static DECLARE_BITMAP(max310x_lines, MAX310X_UART_NRMAX); + static u8 max310x_port_read(struct uart_port *port, u8 reg) { struct max310x_port *s = dev_get_drvdata(port->dev); @@ -600,9 +602,7 @@ static void max310x_handle_rx(struct uart_port *port, unsigned int rxlen) unsigned int sts, ch, flag; if (unlikely(rxlen >= port->fifosize)) { - dev_warn_ratelimited(port->dev, - "Port %i: Possible RX FIFO overrun\n", - port->line); + dev_warn_ratelimited(port->dev, "Possible RX FIFO overrun\n"); port->icount.buf_overrun++; /* Ensure sanity of RX level */ rxlen = port->fifosize; @@ -1193,8 +1193,16 @@ static int max310x_probe(struct device *dev, struct max310x_devtype *devtype, mutex_init(&s->mutex); for (i = 0; i < devtype->nr; i++) { + unsigned int line; + + line = find_first_zero_bit(max310x_lines, MAX310X_UART_NRMAX); + if (line == MAX310X_UART_NRMAX) { + ret = -ERANGE; + goto out_uart; + } + /* Initialize port data */ - s->p[i].port.line = i; + s->p[i].port.line = line; s->p[i].port.dev = dev; s->p[i].port.irq = irq; s->p[i].port.type = PORT_MAX310X; @@ -1220,8 +1228,15 @@ static int max310x_probe(struct device *dev, struct max310x_devtype *devtype, INIT_WORK(&s->p[i].md_work, max310x_md_proc); /* Initialize queue for changing RS485 mode */ INIT_WORK(&s->p[i].rs_work, max310x_rs_proc); + /* Register port */ - uart_add_one_port(&max310x_uart, &s->p[i].port); + ret = uart_add_one_port(&max310x_uart, &s->p[i].port); + if (ret) { + s->p[i].port.dev = NULL; + goto out_uart; + } + set_bit(line, max310x_lines); + /* Go to suspend mode */ devtype->power(&s->p[i].port, 0); } @@ -1234,8 +1249,13 @@ static int max310x_probe(struct device *dev, struct max310x_devtype *devtype, dev_err(dev, "Unable to reguest IRQ %i\n", irq); - for (i = 0; i < devtype->nr; i++) - uart_remove_one_port(&max310x_uart, &s->p[i].port); +out_uart: + for (i = 0; i < devtype->nr; i++) { + if (s->p[i].port.dev) { + uart_remove_one_port(&max310x_uart, &s->p[i].port); + clear_bit(s->p[i].port.line, max310x_lines); + } + } mutex_destroy(&s->mutex); @@ -1255,6 +1275,7 @@ static int max310x_remove(struct device *dev) cancel_work_sync(&s->p[i].md_work); cancel_work_sync(&s->p[i].rs_work); uart_remove_one_port(&max310x_uart, &s->p[i].port); + clear_bit(s->p[i].port.line, max310x_lines); s->devtype->power(&s->p[i].port, 0); } @@ -1347,6 +1368,8 @@ static int __init max310x_uart_init(void) { int ret; + bitmap_zero(max310x_lines, MAX310X_UART_NRMAX); + ret = uart_register_driver(&max310x_uart); if (ret) return ret; -- cgit v0.10.2 From 8d6d544cfb52a28d5c75d17552fa3d3f1cfe4a8c Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Mon, 6 Jun 2016 13:30:25 +0900 Subject: serial: 8250_uniphier: add COMPILE_TEST option Add COMPILE_TEST for the compilation test coverage. Signed-off-by: Masahiro Yamada Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/8250/Kconfig b/drivers/tty/serial/8250/Kconfig index e46761d..b5a0f2e 100644 --- a/drivers/tty/serial/8250/Kconfig +++ b/drivers/tty/serial/8250/Kconfig @@ -387,7 +387,8 @@ config SERIAL_8250_MT6577 config SERIAL_8250_UNIPHIER tristate "Support for UniPhier on-chip UART" - depends on SERIAL_8250 && ARCH_UNIPHIER + depends on SERIAL_8250 + depends on ARCH_UNIPHIER || COMPILE_TEST help If you have a UniPhier based board and want to use the on-chip serial ports, say Y to this option. If unsure, say N. -- cgit v0.10.2 From ca16c5a300c33fd9d0cda48ef08166f32b35a56d Mon Sep 17 00:00:00 2001 From: Paul Gortmaker Date: Mon, 20 Jun 2016 18:55:03 -0400 Subject: serial: pxa: make it explicitly non-modular The Kconfig currently controlling compilation of this code is: drivers/tty/serial/Kconfig:config SERIAL_PXA drivers/tty/serial/Kconfig: bool "PXA serial port support" ...meaning that it currently is not being built as a module by anyone. Lets remove the modular code that is essentially orphaned, so that when reading the driver there is no doubt it is builtin-only. We explicitly disallow a driver unbind, since that doesn't have a sensible use case anyway, and it allows us to drop the ".remove" code for non-modular drivers. Since module_init translates to device_initcall in the non-modular case, the init ordering remains unchanged with this commit. Also note that MODULE_DEVICE_TABLE and MODULE_ALIAS are both a no-op for non-modular builds. We also delete the MODULE_LICENSE tag since that information is already contained at the top of the file in the comments. Cc: Greg Kroah-Hartman Cc: Jiri Slaby Cc: linux-serial@vger.kernel.org Signed-off-by: Paul Gortmaker Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/pxa.c b/drivers/tty/serial/pxa.c index 41eab75..cd9d9e8 100644 --- a/drivers/tty/serial/pxa.c +++ b/drivers/tty/serial/pxa.c @@ -27,7 +27,6 @@ #define SUPPORT_SYSRQ #endif -#include #include #include #include @@ -829,7 +828,6 @@ static const struct of_device_id serial_pxa_dt_ids[] = { { .compatible = "mrvl,mmp-uart", }, {} }; -MODULE_DEVICE_TABLE(of, serial_pxa_dt_ids); static int serial_pxa_probe_dt(struct platform_device *pdev, struct uart_pxa_port *sport) @@ -914,28 +912,15 @@ static int serial_pxa_probe(struct platform_device *dev) return ret; } -static int serial_pxa_remove(struct platform_device *dev) -{ - struct uart_pxa_port *sport = platform_get_drvdata(dev); - - uart_remove_one_port(&serial_pxa_reg, &sport->port); - - clk_unprepare(sport->clk); - clk_put(sport->clk); - kfree(sport); - - return 0; -} - static struct platform_driver serial_pxa_driver = { .probe = serial_pxa_probe, - .remove = serial_pxa_remove, .driver = { .name = "pxa2xx-uart", #ifdef CONFIG_PM .pm = &serial_pxa_pm_ops, #endif + .suppress_bind_attrs = true, .of_match_table = serial_pxa_dt_ids, }, }; @@ -954,15 +939,4 @@ static int __init serial_pxa_init(void) return ret; } - -static void __exit serial_pxa_exit(void) -{ - platform_driver_unregister(&serial_pxa_driver); - uart_unregister_driver(&serial_pxa_reg); -} - -module_init(serial_pxa_init); -module_exit(serial_pxa_exit); - -MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:pxa2xx-uart"); +device_initcall(serial_pxa_init); -- cgit v0.10.2 From 03ba5d5187b009e01215b3f74e508d986b912efb Mon Sep 17 00:00:00 2001 From: Paul Gortmaker Date: Mon, 20 Jun 2016 18:55:04 -0400 Subject: serial: vt8500_serial: make it explicitly non-modular The Kconfig currently controlling compilation of this code is: drivers/tty/serial/Kconfig:config SERIAL_VT8500 drivers/tty/serial/Kconfig: bool "VIA VT8500 on-chip serial port support" ...meaning that it currently is not being built as a module by anyone. Lets remove the modular code that is essentially orphaned, so that when reading the driver there is no doubt it is builtin-only. We explicitly disallow a driver unbind, since that doesn't have a sensible use case anyway, and it allows us to drop the ".remove" code for non-modular drivers. Since module_init translates to device_initcall in the non-modular case, the init ordering remains unchanged with this commit. We don't replace module.h with init.h since the file already has that. We also delete the MODULE_LICENSE tag etc. since all that information is already contained at the top of the file in the comments. Cc: Tony Prisk Cc: Greg Kroah-Hartman Cc: Jiri Slaby Cc: Alexey Charkov Cc: linux-serial@vger.kernel.org Signed-off-by: Paul Gortmaker Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/vt8500_serial.c b/drivers/tty/serial/vt8500_serial.c index b384060..23cfc5e 100644 --- a/drivers/tty/serial/vt8500_serial.c +++ b/drivers/tty/serial/vt8500_serial.c @@ -21,7 +21,6 @@ #include #include -#include #include #include #include @@ -730,22 +729,12 @@ static int vt8500_serial_probe(struct platform_device *pdev) return 0; } -static int vt8500_serial_remove(struct platform_device *pdev) -{ - struct vt8500_port *vt8500_port = platform_get_drvdata(pdev); - - clk_disable_unprepare(vt8500_port->clk); - uart_remove_one_port(&vt8500_uart_driver, &vt8500_port->uart); - - return 0; -} - static struct platform_driver vt8500_platform_driver = { .probe = vt8500_serial_probe, - .remove = vt8500_serial_remove, .driver = { .name = "vt8500_serial", .of_match_table = wmt_dt_ids, + .suppress_bind_attrs = true, }, }; @@ -764,19 +753,4 @@ static int __init vt8500_serial_init(void) return ret; } - -static void __exit vt8500_serial_exit(void) -{ -#ifdef CONFIG_SERIAL_VT8500_CONSOLE - unregister_console(&vt8500_console); -#endif - platform_driver_unregister(&vt8500_platform_driver); - uart_unregister_driver(&vt8500_uart_driver); -} - -module_init(vt8500_serial_init); -module_exit(vt8500_serial_exit); - -MODULE_AUTHOR("Alexey Charkov "); -MODULE_DESCRIPTION("Driver for vt8500 serial device"); -MODULE_LICENSE("GPL v2"); +device_initcall(vt8500_serial_init); -- cgit v0.10.2 From a10aebe2cd8dfeebc83a0d1790a429d0fe789fd5 Mon Sep 17 00:00:00 2001 From: Paul Gortmaker Date: Mon, 20 Jun 2016 18:55:05 -0400 Subject: serial: m32r_sio: make it explicitly non-modular The Kconfig currently controlling compilation of this code is: drivers/tty/serial/Kconfig:config SERIAL_M32R_SIO drivers/tty/serial/Kconfig: bool "M32R SIO I/F" ...meaning that it currently is not being built as a module by anyone. Lets remove the modular code that is essentially orphaned, so that when reading the driver there is no doubt it is builtin-only. Since module_init translates to device_initcall in the non-modular case, the init ordering remains unchanged with this commit. We also delete the MODULE_LICENSE tag etc. since all that information is already contained at the top of the file in the comments. We don't replace module.h with init.h since the file already has that. Cc: Greg Kroah-Hartman Cc: Jiri Slaby Cc: linux-serial@vger.kernel.org Signed-off-by: Paul Gortmaker Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/m32r_sio.c b/drivers/tty/serial/m32r_sio.c index 1b01504c..218b711 100644 --- a/drivers/tty/serial/m32r_sio.c +++ b/drivers/tty/serial/m32r_sio.c @@ -30,7 +30,6 @@ #define SUPPORT_SYSRQ #endif -#include #include #include #include @@ -1057,19 +1056,4 @@ static int __init m32r_sio_init(void) return ret; } - -static void __exit m32r_sio_exit(void) -{ - int i; - - for (i = 0; i < UART_NR; i++) - uart_remove_one_port(&m32r_sio_reg, &m32r_sio_ports[i].port); - - uart_unregister_driver(&m32r_sio_reg); -} - -module_init(m32r_sio_init); -module_exit(m32r_sio_exit); - -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("Generic M32R SIO serial driver"); +device_initcall(m32r_sio_init); -- cgit v0.10.2 From a59388668d0ce19dadea909e09f4eb905a27b1ce Mon Sep 17 00:00:00 2001 From: Jonas Gorski Date: Wed, 8 Jun 2016 12:08:43 +0200 Subject: serial/bcm63xx_uart: use correct alias naming The bcm63xx_uart driver uses the of alias for determing its id. Recent changes in dts files changed the expected 'uartX' to the recommended 'serialX', breaking serial output. Fix this by checking for a 'serialX' alias as well. Fixes: e3b992d028f8 ("MIPS: BMIPS: Improve BCM6328 device tree") Fixes: 2d52ee82b475 ("MIPS: BMIPS: Improve BCM6368 device tree") Fixes: 7537d273e2f3 ("MIPS: BMIPS: Add device tree example for BCM6358") Signed-off-by: Jonas Gorski Acked-by: Florian Fainelli Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/bcm63xx_uart.c b/drivers/tty/serial/bcm63xx_uart.c index c28e5c24..5108fab 100644 --- a/drivers/tty/serial/bcm63xx_uart.c +++ b/drivers/tty/serial/bcm63xx_uart.c @@ -813,8 +813,12 @@ static int bcm_uart_probe(struct platform_device *pdev) struct clk *clk; int ret; - if (pdev->dev.of_node) - pdev->id = of_alias_get_id(pdev->dev.of_node, "uart"); + if (pdev->dev.of_node) { + pdev->id = of_alias_get_id(pdev->dev.of_node, "serial"); + + if (pdev->id < 0) + pdev->id = of_alias_get_id(pdev->dev.of_node, "uart"); + } if (pdev->id < 0 || pdev->id >= BCM63XX_NR_UARTS) return -EINVAL; -- cgit v0.10.2 From c2c1659b4f8f9e19fe82a4fd06cca4b3d59090ce Mon Sep 17 00:00:00 2001 From: Thomas Petazzoni Date: Thu, 16 Jun 2016 16:48:52 +0200 Subject: serial: mvebu-uart: free the IRQ in ->shutdown() As suggested by the serial port infrastructure documentation, the IRQ is requested in ->startup(). However, it is never freed in the ->shutdown() hook. With simple systems that open the serial port once for all and always have at least one process that keep the serial port opened, there was no problem. But with a more complicated system (*cough* systemd *cough*), the serial port is opened/closed many times, which at some point no processes having the serial port open at all. Due to this ->startup() gets called again, tries to request_irq() again, which fails. Fixes: 30530791a7a0 ("serial: mvebu-uart: initial support for Armada-3700 serial port") Cc: Cc: Ofer Heifetz Signed-off-by: Thomas Petazzoni Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/mvebu-uart.c b/drivers/tty/serial/mvebu-uart.c index ce362bd..45b57c2 100644 --- a/drivers/tty/serial/mvebu-uart.c +++ b/drivers/tty/serial/mvebu-uart.c @@ -300,6 +300,8 @@ static int mvebu_uart_startup(struct uart_port *port) static void mvebu_uart_shutdown(struct uart_port *port) { writel(0, port->membase + UART_CTRL); + + free_irq(port->irq, port); } static void mvebu_uart_set_termios(struct uart_port *port, -- cgit v0.10.2 From ce87122911f8db59d3c2bc355c694c7a38940804 Mon Sep 17 00:00:00 2001 From: Vladimir Murzin Date: Tue, 7 Jun 2016 16:02:37 +0100 Subject: serial: mps2-uart: make driver explicitly non-modular The Kconfig currently controlling compilation of mps2-uart is: config SERIAL_MPS2_UART bool "MPS2 UART port" depends on ARM || COMPILE_TEST ...meaning that it currently is not being built as a module by anyone. Follow commit 89ebc2742769 ("drivers/tty: make serial/mvebu-uart.c explicitly non-modular") as an example of moving modular code to non-modular: - remove the modular code that is essentially orphaned, so that when reading the driver there is no doubt it is builtin-only. - explicitly disallow a driver unbind, since that doesn't have a sensible use case anyway, and it allows us to drop the ".remove" code for non-modular drivers. - use arch_initcall instead of module_init and remove module_exit. Also note that MODULE_DEVICE_TABLE is a no-op for non-modular code. We also delete the MODULE_LICENSE tag etc. since all that information was (or is now) contained at the top of the file in the comments. Reported-by: Paul Gortmaker Signed-off-by: Vladimir Murzin Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/mps2-uart.c b/drivers/tty/serial/mps2-uart.c index da9e27d..492ec4b 100644 --- a/drivers/tty/serial/mps2-uart.c +++ b/drivers/tty/serial/mps2-uart.c @@ -1,4 +1,6 @@ /* + * MPS2 UART driver + * * Copyright (C) 2015 ARM Limited * * Author: Vladimir Murzin @@ -17,7 +19,6 @@ #include #include #include -#include #include #include #include @@ -569,30 +570,20 @@ static int mps2_serial_probe(struct platform_device *pdev) return 0; } -static int mps2_serial_remove(struct platform_device *pdev) -{ - struct mps2_uart_port *mps_port = platform_get_drvdata(pdev); - - uart_remove_one_port(&mps2_uart_driver, &mps_port->port); - - return 0; -} - #ifdef CONFIG_OF static const struct of_device_id mps2_match[] = { { .compatible = "arm,mps2-uart", }, {}, }; -MODULE_DEVICE_TABLE(of, mps2_match); #endif static struct platform_driver mps2_serial_driver = { .probe = mps2_serial_probe, - .remove = mps2_serial_remove, .driver = { .name = DRIVER_NAME, .of_match_table = of_match_ptr(mps2_match), + .suppress_bind_attrs = true, }, }; @@ -610,16 +601,4 @@ static int __init mps2_uart_init(void) return ret; } -module_init(mps2_uart_init); - -static void __exit mps2_uart_exit(void) -{ - platform_driver_unregister(&mps2_serial_driver); - uart_unregister_driver(&mps2_uart_driver); -} -module_exit(mps2_uart_exit); - -MODULE_AUTHOR("Vladimir Murzin "); -MODULE_DESCRIPTION("MPS2 UART driver"); -MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("platform:" DRIVER_NAME); +arch_initcall(mps2_uart_init); -- cgit v0.10.2 From 3548e45c71881eb6c9d324f04ae32b28ce7439e9 Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Tue, 7 Jun 2016 19:06:11 +0100 Subject: serial: sirf: make fifo functions static The fifo mask functions should be static as they are not used outside of the driver. Fix the following warnings by making them static: drivers/tty/serial/sirfsoc_uart.h:109:5: warning: symbol 'uart_usp_ff_full_mask' was not declared. Should it be static? drivers/tty/serial/sirfsoc_uart.h:117:5: warning: symbol 'uart_usp_ff_empty_mask' was not declared. Should it be static? Signed-off-by: Ben Dooks Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/sirfsoc_uart.h b/drivers/tty/serial/sirfsoc_uart.h index c3a885b..43756bd 100644 --- a/drivers/tty/serial/sirfsoc_uart.h +++ b/drivers/tty/serial/sirfsoc_uart.h @@ -106,7 +106,7 @@ struct sirfsoc_uart_register { enum sirfsoc_uart_type uart_type; }; -u32 uart_usp_ff_full_mask(struct uart_port *port) +static u32 uart_usp_ff_full_mask(struct uart_port *port) { u32 full_bit; @@ -114,7 +114,7 @@ u32 uart_usp_ff_full_mask(struct uart_port *port) return (1 << full_bit); } -u32 uart_usp_ff_empty_mask(struct uart_port *port) +static u32 uart_usp_ff_empty_mask(struct uart_port *port) { u32 empty_bit; -- cgit v0.10.2 From e37697b3f75464dbf86ecb0f480eb11581cc75d2 Mon Sep 17 00:00:00 2001 From: Matthew Leach Date: Wed, 22 Jun 2016 17:57:02 +0100 Subject: tty: serial: samsung: fixup accessors for endian Fix the serial access code to deal with kernels built for big endian operation. Signed-off-by: Matthew Leach Acked-by: Ben Dooks Reviewed-by: Krzysztof Kozlowski Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/samsung.h b/drivers/tty/serial/samsung.h index fc5deaa..8f96b71 100644 --- a/drivers/tty/serial/samsung.h +++ b/drivers/tty/serial/samsung.h @@ -117,10 +117,10 @@ struct s3c24xx_uart_port { #define portaddrl(port, reg) \ ((unsigned long *)(unsigned long)((port)->membase + (reg))) -#define rd_regb(port, reg) (__raw_readb(portaddr(port, reg))) -#define rd_regl(port, reg) (__raw_readl(portaddr(port, reg))) +#define rd_regb(port, reg) (readb_relaxed(portaddr(port, reg))) +#define rd_regl(port, reg) (readl_relaxed(portaddr(port, reg))) -#define wr_regb(port, reg, val) __raw_writeb(val, portaddr(port, reg)) -#define wr_regl(port, reg, val) __raw_writel(val, portaddr(port, reg)) +#define wr_regb(port, reg, val) writeb_relaxed(val, portaddr(port, reg)) +#define wr_regl(port, reg, val) writel_relaxed(val, portaddr(port, reg)) #endif -- cgit v0.10.2 From bbb5ff91225dfbf3e5c27619552e41661048ed61 Mon Sep 17 00:00:00 2001 From: Matthew Leach Date: Wed, 22 Jun 2016 17:57:03 +0100 Subject: tty: serial: samsung: add byte-order aware bit functions This driver makes use of the __set_bit() and __clear_bit() functions. When running under big-endian, these functions don't convert the bit indexes when working with peripheral registers, leading to the incorrect bits being set and cleared when running big-endian. Add two new driver functions for setting and clearing bits that are byte-order aware. Signed-off-by: Matthew Leach Reviewed-by: Krzysztof Kozlowski Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/samsung.c b/drivers/tty/serial/samsung.c index 4d2924f..ae2095a 100644 --- a/drivers/tty/serial/samsung.c +++ b/drivers/tty/serial/samsung.c @@ -169,8 +169,7 @@ static void s3c24xx_serial_stop_tx(struct uart_port *port) return; if (s3c24xx_serial_has_interrupt_mask(port)) - __set_bit(S3C64XX_UINTM_TXD, - portaddrl(port, S3C64XX_UINTM)); + s3c24xx_set_bit(port, S3C64XX_UINTM_TXD, S3C64XX_UINTM); else disable_irq_nosync(ourport->tx_irq); @@ -235,8 +234,7 @@ static void enable_tx_dma(struct s3c24xx_uart_port *ourport) /* Mask Tx interrupt */ if (s3c24xx_serial_has_interrupt_mask(port)) - __set_bit(S3C64XX_UINTM_TXD, - portaddrl(port, S3C64XX_UINTM)); + s3c24xx_set_bit(port, S3C64XX_UINTM_TXD, S3C64XX_UINTM); else disable_irq_nosync(ourport->tx_irq); @@ -269,8 +267,8 @@ static void enable_tx_pio(struct s3c24xx_uart_port *ourport) /* Unmask Tx interrupt */ if (s3c24xx_serial_has_interrupt_mask(port)) - __clear_bit(S3C64XX_UINTM_TXD, - portaddrl(port, S3C64XX_UINTM)); + s3c24xx_clear_bit(port, S3C64XX_UINTM_TXD, + S3C64XX_UINTM); else enable_irq(ourport->tx_irq); @@ -397,8 +395,8 @@ static void s3c24xx_serial_stop_rx(struct uart_port *port) if (rx_enabled(port)) { dbg("s3c24xx_serial_stop_rx: port=%p\n", port); if (s3c24xx_serial_has_interrupt_mask(port)) - __set_bit(S3C64XX_UINTM_RXD, - portaddrl(port, S3C64XX_UINTM)); + s3c24xx_set_bit(port, S3C64XX_UINTM_RXD, + S3C64XX_UINTM); else disable_irq_nosync(ourport->rx_irq); rx_enabled(port) = 0; @@ -1069,7 +1067,7 @@ static int s3c64xx_serial_startup(struct uart_port *port) spin_unlock_irqrestore(&port->lock, flags); /* Enable Rx Interrupt */ - __clear_bit(S3C64XX_UINTM_RXD, portaddrl(port, S3C64XX_UINTM)); + s3c24xx_clear_bit(port, S3C64XX_UINTM_RXD, S3C64XX_UINTM); dbg("s3c64xx_serial_startup ok\n"); return ret; diff --git a/drivers/tty/serial/samsung.h b/drivers/tty/serial/samsung.h index 8f96b71..2ae4fce 100644 --- a/drivers/tty/serial/samsung.h +++ b/drivers/tty/serial/samsung.h @@ -123,4 +123,32 @@ struct s3c24xx_uart_port { #define wr_regb(port, reg, val) writeb_relaxed(val, portaddr(port, reg)) #define wr_regl(port, reg, val) writel_relaxed(val, portaddr(port, reg)) +/* Byte-order aware bit setting/clearing functions. */ + +static inline void s3c24xx_set_bit(struct uart_port *port, int idx, + unsigned int reg) +{ + unsigned long flags; + u32 val; + + local_irq_save(flags); + val = rd_regl(port, reg); + val |= (1 << idx); + wr_regl(port, reg, val); + local_irq_restore(flags); +} + +static inline void s3c24xx_clear_bit(struct uart_port *port, int idx, + unsigned int reg) +{ + unsigned long flags; + u32 val; + + local_irq_save(flags); + val = rd_regl(port, reg); + val &= ~(1 << idx); + wr_regl(port, reg, val); + local_irq_restore(flags); +} + #endif -- cgit v0.10.2 From d03516df837587368fc6e75591f6329c072b9eb5 Mon Sep 17 00:00:00 2001 From: Matthew Leach Date: Tue, 21 Jun 2016 16:19:49 +0100 Subject: tty: serial: 8250: add CON_CONSDEV to flags When using the 8250 as a boot console and the main console results in messages being printed twice. The console framework will only unregister boot consoles if a new console is registered with the CON_CONSDEV flag set. Set this flag for the univ8250 console to prevent double-registration. Signed-off-by: Matthew Leach Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/8250/8250_core.c b/drivers/tty/serial/8250/8250_core.c index fa823a5..dcf43f6 100644 --- a/drivers/tty/serial/8250/8250_core.c +++ b/drivers/tty/serial/8250/8250_core.c @@ -675,7 +675,7 @@ static struct console univ8250_console = { .device = uart_console_device, .setup = univ8250_console_setup, .match = univ8250_console_match, - .flags = CON_PRINTBUFFER | CON_ANYTIME, + .flags = CON_PRINTBUFFER | CON_ANYTIME | CON_CONSDEV, .index = -1, .data = &serial8250_reg, }; -- cgit v0.10.2 From c6f82787a5a193a5c4c49ddaeb362d320efa5fba Mon Sep 17 00:00:00 2001 From: "Chuah, Kim Tatt" Date: Wed, 15 Jun 2016 13:44:11 +0800 Subject: dmaengine: hsu: Export hsu_dma_get_status() To allow other code to safely read DMA Channel Status Register (where the register attribute for Channel Error, Descriptor Time Out & Descriptor Done fields are read-clear), export hsu_dma_get_status(). hsu_dma_irq() is renamed to hsu_dma_do_irq() and requires Status Register value to be passed in. Signed-off-by: Chuah, Kim Tatt Acked-by: Andy Shevchenko Reviewed-by: Heikki Krogerus Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/dma/hsu/hsu.c b/drivers/dma/hsu/hsu.c index f8c5cd5..c5f21ef 100644 --- a/drivers/dma/hsu/hsu.c +++ b/drivers/dma/hsu/hsu.c @@ -126,28 +126,33 @@ static void hsu_dma_start_transfer(struct hsu_dma_chan *hsuc) hsu_dma_start_channel(hsuc); } -static u32 hsu_dma_chan_get_sr(struct hsu_dma_chan *hsuc) -{ - unsigned long flags; - u32 sr; - - spin_lock_irqsave(&hsuc->vchan.lock, flags); - sr = hsu_chan_readl(hsuc, HSU_CH_SR); - spin_unlock_irqrestore(&hsuc->vchan.lock, flags); - - return sr & ~(HSU_CH_SR_DESCE_ANY | HSU_CH_SR_CDESC_ANY); -} - -irqreturn_t hsu_dma_irq(struct hsu_dma_chip *chip, unsigned short nr) +/* + * hsu_dma_get_status() - get DMA channel status + * @chip: HSUART DMA chip + * @nr: DMA channel number + * @status: pointer for DMA Channel Status Register value + * + * Description: + * The function reads and clears the DMA Channel Status Register, checks + * if it was a timeout interrupt and returns a corresponding value. + * + * Caller should provide a valid pointer for the DMA Channel Status + * Register value that will be returned in @status. + * + * Return: + * 1 for DMA timeout status, 0 for other DMA status, or error code for + * invalid parameters or no interrupt pending. + */ +int hsu_dma_get_status(struct hsu_dma_chip *chip, unsigned short nr, + u32 *status) { struct hsu_dma_chan *hsuc; - struct hsu_dma_desc *desc; unsigned long flags; u32 sr; /* Sanity check */ if (nr >= chip->hsu->nr_channels) - return IRQ_NONE; + return -EINVAL; hsuc = &chip->hsu->chan[nr]; @@ -155,22 +160,65 @@ irqreturn_t hsu_dma_irq(struct hsu_dma_chip *chip, unsigned short nr) * No matter what situation, need read clear the IRQ status * There is a bug, see Errata 5, HSD 2900918 */ - sr = hsu_dma_chan_get_sr(hsuc); + spin_lock_irqsave(&hsuc->vchan.lock, flags); + sr = hsu_chan_readl(hsuc, HSU_CH_SR); + spin_unlock_irqrestore(&hsuc->vchan.lock, flags); + + /* Check if any interrupt is pending */ + sr &= ~(HSU_CH_SR_DESCE_ANY | HSU_CH_SR_CDESC_ANY); if (!sr) - return IRQ_NONE; + return -EIO; /* Timeout IRQ, need wait some time, see Errata 2 */ if (sr & HSU_CH_SR_DESCTO_ANY) udelay(2); + /* + * At this point, at least one of Descriptor Time Out, Channel Error + * or Descriptor Done bits must be set. Clear the Descriptor Time Out + * bits and if sr is still non-zero, it must be channel error or + * descriptor done which are higher priority than timeout and handled + * in hsu_dma_do_irq(). Else, it must be a timeout. + */ sr &= ~HSU_CH_SR_DESCTO_ANY; - if (!sr) - return IRQ_HANDLED; + + *status = sr; + + return sr ? 0 : 1; +} +EXPORT_SYMBOL_GPL(hsu_dma_get_status); + +/* + * hsu_dma_do_irq() - DMA interrupt handler + * @chip: HSUART DMA chip + * @nr: DMA channel number + * @status: Channel Status Register value + * + * Description: + * This function handles Channel Error and Descriptor Done interrupts. + * This function should be called after determining that the DMA interrupt + * is not a normal timeout interrupt, ie. hsu_dma_get_status() returned 0. + * + * Return: + * IRQ_NONE for invalid channel number, IRQ_HANDLED otherwise. + */ +irqreturn_t hsu_dma_do_irq(struct hsu_dma_chip *chip, unsigned short nr, + u32 status) +{ + struct hsu_dma_chan *hsuc; + struct hsu_dma_desc *desc; + unsigned long flags; + + /* Sanity check */ + if (nr >= chip->hsu->nr_channels) + return IRQ_NONE; + + hsuc = &chip->hsu->chan[nr]; spin_lock_irqsave(&hsuc->vchan.lock, flags); desc = hsuc->desc; if (desc) { - if (sr & HSU_CH_SR_CHE) { + if (status & HSU_CH_SR_CHE) { desc->status = DMA_ERROR; } else if (desc->active < desc->nents) { hsu_dma_start_channel(hsuc); @@ -184,7 +232,7 @@ irqreturn_t hsu_dma_irq(struct hsu_dma_chip *chip, unsigned short nr) return IRQ_HANDLED; } -EXPORT_SYMBOL_GPL(hsu_dma_irq); +EXPORT_SYMBOL_GPL(hsu_dma_do_irq); static struct hsu_dma_desc *hsu_dma_alloc_desc(unsigned int nents) { diff --git a/drivers/dma/hsu/pci.c b/drivers/dma/hsu/pci.c index e2db76b..9916058 100644 --- a/drivers/dma/hsu/pci.c +++ b/drivers/dma/hsu/pci.c @@ -27,13 +27,20 @@ static irqreturn_t hsu_pci_irq(int irq, void *dev) { struct hsu_dma_chip *chip = dev; u32 dmaisr; + u32 status; unsigned short i; irqreturn_t ret = IRQ_NONE; + int err; dmaisr = readl(chip->regs + HSU_PCI_DMAISR); for (i = 0; i < chip->hsu->nr_channels; i++) { - if (dmaisr & 0x1) - ret |= hsu_dma_irq(chip, i); + if (dmaisr & 0x1) { + err = hsu_dma_get_status(chip, i, &status); + if (err > 0) + ret |= IRQ_HANDLED; + else if (err == 0) + ret |= hsu_dma_do_irq(chip, i, status); + } dmaisr >>= 1; } diff --git a/drivers/tty/serial/8250/8250_mid.c b/drivers/tty/serial/8250/8250_mid.c index 86379a7..b218ff5 100644 --- a/drivers/tty/serial/8250/8250_mid.c +++ b/drivers/tty/serial/8250/8250_mid.c @@ -97,12 +97,24 @@ static int dnv_handle_irq(struct uart_port *p) { struct mid8250 *mid = p->private_data; unsigned int fisr = serial_port_in(p, INTEL_MID_UART_DNV_FISR); + u32 status; int ret = IRQ_NONE; - - if (fisr & BIT(2)) - ret |= hsu_dma_irq(&mid->dma_chip, 1); - if (fisr & BIT(1)) - ret |= hsu_dma_irq(&mid->dma_chip, 0); + int err; + + if (fisr & BIT(2)) { + err = hsu_dma_get_status(&mid->dma_chip, 1, &status); + if (err > 0) + ret |= IRQ_HANDLED; + else if (err == 0) + ret |= hsu_dma_do_irq(&mid->dma_chip, 1, status); + } + if (fisr & BIT(1)) { + err = hsu_dma_get_status(&mid->dma_chip, 0, &status); + if (err > 0) + ret |= IRQ_HANDLED; + else if (err == 0) + ret |= hsu_dma_do_irq(&mid->dma_chip, 0, status); + } if (fisr & BIT(0)) ret |= serial8250_handle_irq(p, serial_port_in(p, UART_IIR)); return ret; diff --git a/include/linux/dma/hsu.h b/include/linux/dma/hsu.h index 79df69d..aaff68e 100644 --- a/include/linux/dma/hsu.h +++ b/include/linux/dma/hsu.h @@ -39,14 +39,22 @@ struct hsu_dma_chip { #if IS_ENABLED(CONFIG_HSU_DMA) /* Export to the internal users */ -irqreturn_t hsu_dma_irq(struct hsu_dma_chip *chip, unsigned short nr); +int hsu_dma_get_status(struct hsu_dma_chip *chip, unsigned short nr, + u32 *status); +irqreturn_t hsu_dma_do_irq(struct hsu_dma_chip *chip, unsigned short nr, + u32 status); /* Export to the platform drivers */ int hsu_dma_probe(struct hsu_dma_chip *chip); int hsu_dma_remove(struct hsu_dma_chip *chip); #else -static inline irqreturn_t hsu_dma_irq(struct hsu_dma_chip *chip, - unsigned short nr) +static inline int hsu_dma_get_status(struct hsu_dma_chip *chip, + unsigned short nr, u32 *status) +{ + return 0; +} +static inline irqreturn_t hsu_dma_do_irq(struct hsu_dma_chip *chip, + unsigned short nr, u32 status) { return IRQ_NONE; } -- cgit v0.10.2 From fd9e516d83108ad82d2c0c30097a6143c779f9c0 Mon Sep 17 00:00:00 2001 From: "Chuah, Kim Tatt" Date: Wed, 15 Jun 2016 13:44:12 +0800 Subject: serial: 8250_dma: Export serial8250_rx_dma_flush() Export serial8250_rx_dma_flush() for use by SOC UART drivers. Signed-off-by: Chuah, Kim Tatt Acked-by: Andy Shevchenko Reviewed-by: Heikki Krogerus Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/8250/8250_dma.c b/drivers/tty/serial/8250/8250_dma.c index 7f33d1c..3590d01 100644 --- a/drivers/tty/serial/8250/8250_dma.c +++ b/drivers/tty/serial/8250/8250_dma.c @@ -145,6 +145,7 @@ void serial8250_rx_dma_flush(struct uart_8250_port *p) dmaengine_terminate_all(dma->rxchan); } } +EXPORT_SYMBOL_GPL(serial8250_rx_dma_flush); int serial8250_request_dma(struct uart_8250_port *p) { -- cgit v0.10.2 From 692aa1905679bd72f84115986235d214f6096a98 Mon Sep 17 00:00:00 2001 From: "Chuah, Kim Tatt" Date: Wed, 15 Jun 2016 13:44:13 +0800 Subject: serial: 8250_mid: Read RX buffer on RX DMA timeout for DNV In DNV, when RX DMA is used and number of bytes received is less than transfer size, only RX DMA timeout interrupt is sent. When this happens, read the RX buffer. Signed-off-by: Chuah, Kim Tatt Acked-by: Andy Shevchenko Reviewed-by: Heikki Krogerus Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/8250/8250_mid.c b/drivers/tty/serial/8250/8250_mid.c index b218ff5..339de9c 100644 --- a/drivers/tty/serial/8250/8250_mid.c +++ b/drivers/tty/serial/8250/8250_mid.c @@ -96,6 +96,7 @@ static int tng_setup(struct mid8250 *mid, struct uart_port *p) static int dnv_handle_irq(struct uart_port *p) { struct mid8250 *mid = p->private_data; + struct uart_8250_port *up = up_to_u8250p(p); unsigned int fisr = serial_port_in(p, INTEL_MID_UART_DNV_FISR); u32 status; int ret = IRQ_NONE; @@ -103,9 +104,10 @@ static int dnv_handle_irq(struct uart_port *p) if (fisr & BIT(2)) { err = hsu_dma_get_status(&mid->dma_chip, 1, &status); - if (err > 0) + if (err > 0) { + serial8250_rx_dma_flush(up); ret |= IRQ_HANDLED; - else if (err == 0) + } else if (err == 0) ret |= hsu_dma_do_irq(&mid->dma_chip, 1, status); } if (fisr & BIT(1)) { -- cgit v0.10.2 From 36fd95b17e9c1c41836632d95f2be5cff93b3df8 Mon Sep 17 00:00:00 2001 From: Yegor Yefremov Date: Tue, 31 May 2016 10:59:15 +0200 Subject: tty/serial/8250: make UART_MCR register access consistent Introduce serial8250_out_MCR() and serial8250_in_MCR() routines, that replace following calls: serial_out(port, UART_MCR, val) serial_port_out(up, UART_MCR, val) serial_in(port, UART_MCR) This patch is needed in order to integrate reading/writing of MCR signals via SERIAL_MCTRL_GPIO infrastructure later. Reviewed-by: Peter Hurley Signed-off-by: Yegor Yefremov Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/8250/8250.h b/drivers/tty/serial/8250/8250.h index 31b3d55..1a16fea 100644 --- a/drivers/tty/serial/8250/8250.h +++ b/drivers/tty/serial/8250/8250.h @@ -129,6 +129,16 @@ void serial8250_rpm_put(struct uart_8250_port *p); int serial8250_em485_init(struct uart_8250_port *p); void serial8250_em485_destroy(struct uart_8250_port *p); +static inline void serial8250_out_MCR(struct uart_8250_port *up, int value) +{ + serial_out(up, UART_MCR, value); +} + +static inline int serial8250_in_MCR(struct uart_8250_port *up) +{ + return serial_in(up, UART_MCR); +} + #if defined(__alpha__) && !defined(CONFIG_PCI) /* * Digital did something really horribly wrong with the OUT1 and OUT2 diff --git a/drivers/tty/serial/8250/8250_omap.c b/drivers/tty/serial/8250/8250_omap.c index 2c44c79..61ad6c3 100644 --- a/drivers/tty/serial/8250/8250_omap.c +++ b/drivers/tty/serial/8250/8250_omap.c @@ -280,7 +280,7 @@ static void omap8250_restore_regs(struct uart_8250_port *up) serial_out(up, UART_EFR, UART_EFR_ECB); serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A); - serial_out(up, UART_MCR, UART_MCR_TCRTLR); + serial8250_out_MCR(up, UART_MCR_TCRTLR); serial_out(up, UART_FCR, up->fcr); omap8250_update_scr(up, priv); @@ -296,7 +296,7 @@ static void omap8250_restore_regs(struct uart_8250_port *up) serial_out(up, UART_LCR, 0); /* drop TCR + TLR access, we setup XON/XOFF later */ - serial_out(up, UART_MCR, up->mcr); + serial8250_out_MCR(up, up->mcr); serial_out(up, UART_IER, up->ier); serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c index c8d8d24..bdfa659 100644 --- a/drivers/tty/serial/8250/8250_port.c +++ b/drivers/tty/serial/8250/8250_port.c @@ -527,13 +527,13 @@ static void serial8250_clear_fifos(struct uart_8250_port *p) static inline void serial8250_em485_rts_after_send(struct uart_8250_port *p) { - unsigned char mcr = serial_in(p, UART_MCR); + unsigned char mcr = serial8250_in_MCR(p); if (p->port.rs485.flags & SER_RS485_RTS_AFTER_SEND) mcr |= UART_MCR_RTS; else mcr &= ~UART_MCR_RTS; - serial_out(p, UART_MCR, mcr); + serial8250_out_MCR(p, mcr); } static void serial8250_em485_handle_start_tx(unsigned long arg); @@ -785,10 +785,10 @@ static int size_fifo(struct uart_8250_port *up) old_lcr = serial_in(up, UART_LCR); serial_out(up, UART_LCR, 0); old_fcr = serial_in(up, UART_FCR); - old_mcr = serial_in(up, UART_MCR); + old_mcr = serial8250_in_MCR(up); serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT); - serial_out(up, UART_MCR, UART_MCR_LOOP); + serial8250_out_MCR(up, UART_MCR_LOOP); serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A); old_dl = serial_dl_read(up); serial_dl_write(up, 0x0001); @@ -800,7 +800,7 @@ static int size_fifo(struct uart_8250_port *up) (count < 256); count++) serial_in(up, UART_RX); serial_out(up, UART_FCR, old_fcr); - serial_out(up, UART_MCR, old_mcr); + serial8250_out_MCR(up, old_mcr); serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A); serial_dl_write(up, old_dl); serial_out(up, UART_LCR, old_lcr); @@ -1040,17 +1040,17 @@ static void autoconfig_16550a(struct uart_8250_port *up) * it's changed. If so, set baud_base in EXCR2 to 921600. -- dwmw2 */ serial_out(up, UART_LCR, 0); - status1 = serial_in(up, UART_MCR); + status1 = serial8250_in_MCR(up); serial_out(up, UART_LCR, 0xE0); status2 = serial_in(up, 0x02); /* EXCR1 */ if (!((status2 ^ status1) & UART_MCR_LOOP)) { serial_out(up, UART_LCR, 0); - serial_out(up, UART_MCR, status1 ^ UART_MCR_LOOP); + serial8250_out_MCR(up, status1 ^ UART_MCR_LOOP); serial_out(up, UART_LCR, 0xE0); status2 = serial_in(up, 0x02); /* EXCR1 */ serial_out(up, UART_LCR, 0); - serial_out(up, UART_MCR, status1); + serial8250_out_MCR(up, status1); if ((status2 ^ status1) & UART_MCR_LOOP) { unsigned short quot; @@ -1224,7 +1224,7 @@ static void autoconfig(struct uart_8250_port *up) } } - save_mcr = serial_in(up, UART_MCR); + save_mcr = serial8250_in_MCR(up); save_lcr = serial_in(up, UART_LCR); /* @@ -1237,9 +1237,9 @@ static void autoconfig(struct uart_8250_port *up) * that conflicts with COM 1-4 --- we hope! */ if (!(port->flags & UPF_SKIP_TEST)) { - serial_out(up, UART_MCR, UART_MCR_LOOP | 0x0A); + serial8250_out_MCR(up, UART_MCR_LOOP | 0x0A); status1 = serial_in(up, UART_MSR) & 0xF0; - serial_out(up, UART_MCR, save_mcr); + serial8250_out_MCR(up, save_mcr); if (status1 != 0x90) { spin_unlock_irqrestore(&port->lock, flags); DEBUG_AUTOCONF("LOOP test failed (%02x) ", @@ -1305,7 +1305,7 @@ static void autoconfig(struct uart_8250_port *up) if (port->type == PORT_RSA) serial_out(up, UART_RSA_FRR, 0); #endif - serial_out(up, UART_MCR, save_mcr); + serial8250_out_MCR(up, save_mcr); serial8250_clear_fifos(up); serial_in(up, UART_RX); if (up->capabilities & UART_CAP_UUE) @@ -1353,19 +1353,18 @@ static void autoconfig_irq(struct uart_8250_port *up) /* forget possible initially masked and pending IRQ */ probe_irq_off(probe_irq_on()); - save_mcr = serial_in(up, UART_MCR); + save_mcr = serial8250_in_MCR(up); save_ier = serial_in(up, UART_IER); - serial_out(up, UART_MCR, UART_MCR_OUT1 | UART_MCR_OUT2); + serial8250_out_MCR(up, UART_MCR_OUT1 | UART_MCR_OUT2); irqs = probe_irq_on(); - serial_out(up, UART_MCR, 0); + serial8250_out_MCR(up, 0); udelay(10); if (port->flags & UPF_FOURPORT) { - serial_out(up, UART_MCR, - UART_MCR_DTR | UART_MCR_RTS); + serial8250_out_MCR(up, UART_MCR_DTR | UART_MCR_RTS); } else { - serial_out(up, UART_MCR, - UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2); + serial8250_out_MCR(up, + UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2); } serial_out(up, UART_IER, 0x0f); /* enable all intrs */ serial_in(up, UART_LSR); @@ -1376,7 +1375,7 @@ static void autoconfig_irq(struct uart_8250_port *up) udelay(20); irq = probe_irq_off(irqs); - serial_out(up, UART_MCR, save_mcr); + serial8250_out_MCR(up, save_mcr); serial_out(up, UART_IER, save_ier); if (port->flags & UPF_FOURPORT) @@ -1549,14 +1548,14 @@ static inline void start_tx_rs485(struct uart_port *port) del_timer(&em485->stop_tx_timer); em485->active_timer = NULL; - mcr = serial_in(up, UART_MCR); + mcr = serial8250_in_MCR(up); if (!!(up->port.rs485.flags & SER_RS485_RTS_ON_SEND) != !!(mcr & UART_MCR_RTS)) { if (up->port.rs485.flags & SER_RS485_RTS_ON_SEND) mcr |= UART_MCR_RTS; else mcr &= ~UART_MCR_RTS; - serial_out(up, UART_MCR, mcr); + serial8250_out_MCR(up, mcr); if (up->port.rs485.delay_rts_before_send > 0) { em485->active_timer = &em485->start_tx_timer; @@ -1943,7 +1942,7 @@ void serial8250_do_set_mctrl(struct uart_port *port, unsigned int mctrl) mcr = (mcr & up->mcr_mask) | up->mcr_force | up->mcr; - serial_port_out(port, UART_MCR, mcr); + serial8250_out_MCR(up, mcr); } EXPORT_SYMBOL_GPL(serial8250_do_set_mctrl); @@ -3090,7 +3089,7 @@ static void serial8250_console_restore(struct uart_8250_port *up) serial8250_set_divisor(port, baud, quot, frac); serial_port_out(port, UART_LCR, up->lcr); - serial_port_out(port, UART_MCR, UART_MCR_DTR | UART_MCR_RTS); + serial8250_out_MCR(up, UART_MCR_DTR | UART_MCR_RTS); } /* -- cgit v0.10.2 From bf5cee681e57babde5358a71e59b75151eb02c1a Mon Sep 17 00:00:00 2001 From: Yegor Yefremov Date: Tue, 31 May 2016 10:59:16 +0200 Subject: serial: mctrl_gpio: add modem control read routine mctrl_gpio_get_outputs() returns the state of following signals: RTS, DTR While defining the routine for reading outputs, fix the comment for mctrl_gpio_get() routine as it returns only the state of the input signals. Signed-off-by: Yegor Yefremov Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/serial_mctrl_gpio.c b/drivers/tty/serial/serial_mctrl_gpio.c index e8dd509..a868595 100644 --- a/drivers/tty/serial/serial_mctrl_gpio.c +++ b/drivers/tty/serial/serial_mctrl_gpio.c @@ -86,6 +86,24 @@ unsigned int mctrl_gpio_get(struct mctrl_gpios *gpios, unsigned int *mctrl) } EXPORT_SYMBOL_GPL(mctrl_gpio_get); +unsigned int +mctrl_gpio_get_outputs(struct mctrl_gpios *gpios, unsigned int *mctrl) +{ + enum mctrl_gpio_idx i; + + for (i = 0; i < UART_GPIO_MAX; i++) { + if (gpios->gpio[i] && mctrl_gpios_desc[i].dir_out) { + if (gpiod_get_value(gpios->gpio[i])) + *mctrl |= mctrl_gpios_desc[i].mctrl; + else + *mctrl &= ~mctrl_gpios_desc[i].mctrl; + } + } + + return *mctrl; +} +EXPORT_SYMBOL_GPL(mctrl_gpio_get_outputs); + struct mctrl_gpios *mctrl_gpio_init_noauto(struct device *dev, unsigned int idx) { struct mctrl_gpios *gpios; diff --git a/drivers/tty/serial/serial_mctrl_gpio.h b/drivers/tty/serial/serial_mctrl_gpio.h index 332a33a..fa000bc 100644 --- a/drivers/tty/serial/serial_mctrl_gpio.h +++ b/drivers/tty/serial/serial_mctrl_gpio.h @@ -48,12 +48,19 @@ struct mctrl_gpios; void mctrl_gpio_set(struct mctrl_gpios *gpios, unsigned int mctrl); /* - * Get state of the modem control output lines from GPIOs. + * Get state of the modem control input lines from GPIOs. * The mctrl flags are updated and returned. */ unsigned int mctrl_gpio_get(struct mctrl_gpios *gpios, unsigned int *mctrl); /* + * Get state of the modem control output lines from GPIOs. + * The mctrl flags are updated and returned. + */ +unsigned int +mctrl_gpio_get_outputs(struct mctrl_gpios *gpios, unsigned int *mctrl); + +/* * Returns the associated struct gpio_desc to the modem line gidx */ struct gpio_desc *mctrl_gpio_to_gpiod(struct mctrl_gpios *gpios, @@ -107,6 +114,12 @@ unsigned int mctrl_gpio_get(struct mctrl_gpios *gpios, unsigned int *mctrl) return *mctrl; } +static inline unsigned int +mctrl_gpio_get_outputs(struct mctrl_gpios *gpios, unsigned int *mctrl) +{ + return *mctrl; +} + static inline struct gpio_desc *mctrl_gpio_to_gpiod(struct mctrl_gpios *gpios, enum mctrl_gpio_idx gidx) -- cgit v0.10.2 From 434be0ae7aa746f481c3a22139e472dbc3f4f817 Mon Sep 17 00:00:00 2001 From: Yegor Yefremov Date: Tue, 31 May 2016 10:59:17 +0200 Subject: serial: mctrl_gpio: enable API usage only for initialized mctrl_gpios struct This workaround is needed for the cases, where mctrl_gpio API is used before mctrl_gpio_init() was invoked. This happens in 8250 during console initialization, as the driver sets DTR signal. Signed-off-by: Yegor Yefremov Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/serial_mctrl_gpio.c b/drivers/tty/serial/serial_mctrl_gpio.c index a868595..d2da6aa 100644 --- a/drivers/tty/serial/serial_mctrl_gpio.c +++ b/drivers/tty/serial/serial_mctrl_gpio.c @@ -52,6 +52,9 @@ void mctrl_gpio_set(struct mctrl_gpios *gpios, unsigned int mctrl) int value_array[UART_GPIO_MAX]; unsigned int count = 0; + if (gpios == NULL) + return; + for (i = 0; i < UART_GPIO_MAX; i++) if (gpios->gpio[i] && mctrl_gpios_desc[i].dir_out) { desc_array[count] = gpios->gpio[i]; @@ -73,6 +76,9 @@ unsigned int mctrl_gpio_get(struct mctrl_gpios *gpios, unsigned int *mctrl) { enum mctrl_gpio_idx i; + if (gpios == NULL) + return *mctrl; + for (i = 0; i < UART_GPIO_MAX; i++) { if (gpios->gpio[i] && !mctrl_gpios_desc[i].dir_out) { if (gpiod_get_value(gpios->gpio[i])) @@ -91,6 +97,9 @@ mctrl_gpio_get_outputs(struct mctrl_gpios *gpios, unsigned int *mctrl) { enum mctrl_gpio_idx i; + if (gpios == NULL) + return *mctrl; + for (i = 0; i < UART_GPIO_MAX; i++) { if (gpios->gpio[i] && mctrl_gpios_desc[i].dir_out) { if (gpiod_get_value(gpios->gpio[i])) @@ -221,6 +230,9 @@ void mctrl_gpio_free(struct device *dev, struct mctrl_gpios *gpios) { enum mctrl_gpio_idx i; + if (gpios == NULL) + return; + for (i = 0; i < UART_GPIO_MAX; i++) { if (gpios->irq[i]) devm_free_irq(gpios->port->dev, gpios->irq[i], gpios); @@ -236,6 +248,9 @@ void mctrl_gpio_enable_ms(struct mctrl_gpios *gpios) { enum mctrl_gpio_idx i; + if (gpios == NULL) + return; + /* .enable_ms may be called multiple times */ if (gpios->mctrl_on) return; @@ -258,6 +273,9 @@ void mctrl_gpio_disable_ms(struct mctrl_gpios *gpios) { enum mctrl_gpio_idx i; + if (gpios == NULL) + return; + if (!gpios->mctrl_on) return; -- cgit v0.10.2 From 4ef03d328769eddbfeca1f1c958fdb181a69c341 Mon Sep 17 00:00:00 2001 From: Yegor Yefremov Date: Tue, 31 May 2016 10:59:18 +0200 Subject: tty/serial/8250: use mctrl_gpio helpers This patch permits the usage for GPIOs to control the CTS/RTS/DTR/DSR/DCD/RI signals. Signed-off-by: Yegor Yefremov Signed-off-by: Greg Kroah-Hartman diff --git a/Documentation/devicetree/bindings/serial/8250.txt b/Documentation/devicetree/bindings/serial/8250.txt index 936ab5b..f5561ac 100644 --- a/Documentation/devicetree/bindings/serial/8250.txt +++ b/Documentation/devicetree/bindings/serial/8250.txt @@ -42,6 +42,9 @@ Optional properties: - auto-flow-control: one way to enable automatic flow control support. The driver is allowed to detect support for the capability even without this property. +- {rts,cts,dtr,dsr,rng,dcd}-gpios: specify a GPIO for RTS/CTS/DTR/DSR/RI/DCD + line respectively. It will use specified GPIO instead of the peripheral + function pin for the UART feature. If unsure, don't specify this property. Note: * fsl,ns16550: @@ -63,3 +66,19 @@ Example: interrupts = <10>; reg-shift = <2>; }; + +Example for OMAP UART using GPIO-based modem control signals: + + uart4: serial@49042000 { + compatible = "ti,omap3-uart"; + reg = <0x49042000 0x400>; + interrupts = <80>; + ti,hwmods = "uart4"; + clock-frequency = <48000000>; + cts-gpios = <&gpio3 5 GPIO_ACTIVE_LOW>; + rts-gpios = <&gpio3 6 GPIO_ACTIVE_LOW>; + dtr-gpios = <&gpio1 12 GPIO_ACTIVE_LOW>; + dsr-gpios = <&gpio1 13 GPIO_ACTIVE_LOW>; + dcd-gpios = <&gpio1 14 GPIO_ACTIVE_LOW>; + rng-gpios = <&gpio1 15 GPIO_ACTIVE_LOW>; + }; diff --git a/drivers/tty/serial/8250/8250.h b/drivers/tty/serial/8250/8250.h index 1a16fea..122e0e4 100644 --- a/drivers/tty/serial/8250/8250.h +++ b/drivers/tty/serial/8250/8250.h @@ -15,6 +15,8 @@ #include #include +#include "../serial_mctrl_gpio.h" + struct uart_8250_dma { int (*tx_dma)(struct uart_8250_port *p); int (*rx_dma)(struct uart_8250_port *p); @@ -131,12 +133,43 @@ void serial8250_em485_destroy(struct uart_8250_port *p); static inline void serial8250_out_MCR(struct uart_8250_port *up, int value) { + int mctrl_gpio = 0; + serial_out(up, UART_MCR, value); + + if (value & UART_MCR_RTS) + mctrl_gpio |= TIOCM_RTS; + if (value & UART_MCR_DTR) + mctrl_gpio |= TIOCM_DTR; + + mctrl_gpio_set(up->gpios, mctrl_gpio); } static inline int serial8250_in_MCR(struct uart_8250_port *up) { - return serial_in(up, UART_MCR); + int mctrl, mctrl_gpio = 0; + + mctrl = serial_in(up, UART_MCR); + + /* save current MCR values */ + if (mctrl & UART_MCR_RTS) + mctrl_gpio |= TIOCM_RTS; + if (mctrl & UART_MCR_DTR) + mctrl_gpio |= TIOCM_DTR; + + mctrl_gpio = mctrl_gpio_get_outputs(up->gpios, &mctrl_gpio); + + if (mctrl_gpio & TIOCM_RTS) + mctrl |= UART_MCR_RTS; + else + mctrl &= ~UART_MCR_RTS; + + if (mctrl_gpio & TIOCM_DTR) + mctrl |= UART_MCR_DTR; + else + mctrl &= ~UART_MCR_DTR; + + return mctrl; } #if defined(__alpha__) && !defined(CONFIG_PCI) diff --git a/drivers/tty/serial/8250/8250_core.c b/drivers/tty/serial/8250/8250_core.c index dcf43f6..13ad5c3 100644 --- a/drivers/tty/serial/8250/8250_core.c +++ b/drivers/tty/serial/8250/8250_core.c @@ -974,6 +974,8 @@ int serial8250_register_8250_port(struct uart_8250_port *up) uart = serial8250_find_match_or_unused(&up->port); if (uart && uart->port.type != PORT_8250_CIR) { + struct mctrl_gpios *gpios; + if (uart->port.dev) uart_remove_one_port(&serial8250_reg, &uart->port); @@ -1011,6 +1013,13 @@ int serial8250_register_8250_port(struct uart_8250_port *up) if (up->port.flags & UPF_FIXED_TYPE) uart->port.type = up->port.type; + gpios = mctrl_gpio_init(&uart->port, 0); + if (IS_ERR(gpios)) { + if (PTR_ERR(gpios) != -ENOSYS) + return PTR_ERR(gpios); + } else + uart->gpios = gpios; + serial8250_set_defaults(uart); /* Possibly override default I/O functions. */ diff --git a/drivers/tty/serial/8250/8250_omap.c b/drivers/tty/serial/8250/8250_omap.c index 61ad6c3..e14982f 100644 --- a/drivers/tty/serial/8250/8250_omap.c +++ b/drivers/tty/serial/8250/8250_omap.c @@ -134,18 +134,21 @@ static void omap8250_set_mctrl(struct uart_port *port, unsigned int mctrl) serial8250_do_set_mctrl(port, mctrl); - /* - * Turn off autoRTS if RTS is lowered and restore autoRTS setting - * if RTS is raised - */ - lcr = serial_in(up, UART_LCR); - serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); - if ((mctrl & TIOCM_RTS) && (port->status & UPSTAT_AUTORTS)) - priv->efr |= UART_EFR_RTS; - else - priv->efr &= ~UART_EFR_RTS; - serial_out(up, UART_EFR, priv->efr); - serial_out(up, UART_LCR, lcr); + if (IS_ERR_OR_NULL(mctrl_gpio_to_gpiod(up->gpios, + UART_GPIO_RTS))) { + /* + * Turn off autoRTS if RTS is lowered and restore autoRTS + * setting if RTS is raised + */ + lcr = serial_in(up, UART_LCR); + serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); + if ((mctrl & TIOCM_RTS) && (port->status & UPSTAT_AUTORTS)) + priv->efr |= UART_EFR_RTS; + else + priv->efr &= ~UART_EFR_RTS; + serial_out(up, UART_EFR, priv->efr); + serial_out(up, UART_LCR, lcr); + } } /* @@ -446,7 +449,9 @@ static void omap_8250_set_termios(struct uart_port *port, priv->efr = 0; up->port.status &= ~(UPSTAT_AUTOCTS | UPSTAT_AUTORTS | UPSTAT_AUTOXOFF); - if (termios->c_cflag & CRTSCTS && up->port.flags & UPF_HARD_FLOW) { + if (termios->c_cflag & CRTSCTS && up->port.flags & UPF_HARD_FLOW + && IS_ERR_OR_NULL(mctrl_gpio_to_gpiod(up->gpios, + UART_GPIO_RTS))) { /* Enable AUTOCTS (autoRTS is enabled when RTS is raised) */ up->port.status |= UPSTAT_AUTOCTS | UPSTAT_AUTORTS; priv->efr |= UART_EFR_CTS; diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c index bdfa659..7481b95 100644 --- a/drivers/tty/serial/8250/8250_port.c +++ b/drivers/tty/serial/8250/8250_port.c @@ -1618,6 +1618,8 @@ static void serial8250_disable_ms(struct uart_port *port) if (up->bugs & UART_BUG_NOMSR) return; + mctrl_gpio_disable_ms(up->gpios); + up->ier &= ~UART_IER_MSI; serial_port_out(port, UART_IER, up->ier); } @@ -1630,6 +1632,8 @@ static void serial8250_enable_ms(struct uart_port *port) if (up->bugs & UART_BUG_NOMSR) return; + mctrl_gpio_enable_ms(up->gpios); + up->ier |= UART_IER_MSI; serial8250_rpm_get(up); @@ -1913,7 +1917,8 @@ unsigned int serial8250_do_get_mctrl(struct uart_port *port) ret |= TIOCM_DSR; if (status & UART_MSR_CTS) ret |= TIOCM_CTS; - return ret; + + return mctrl_gpio_get(up->gpios, &ret); } EXPORT_SYMBOL_GPL(serial8250_do_get_mctrl); diff --git a/drivers/tty/serial/8250/Kconfig b/drivers/tty/serial/8250/Kconfig index b5a0f2e..b1c73de 100644 --- a/drivers/tty/serial/8250/Kconfig +++ b/drivers/tty/serial/8250/Kconfig @@ -6,6 +6,7 @@ config SERIAL_8250 tristate "8250/16550 and compatible serial support" select SERIAL_CORE + select SERIAL_MCTRL_GPIO if GPIOLIB ---help--- This selects whether you want to include the driver for the standard serial ports. The standard answer is Y. People who might say N diff --git a/include/linux/serial_8250.h b/include/linux/serial_8250.h index 48ec765..923266c 100644 --- a/include/linux/serial_8250.h +++ b/include/linux/serial_8250.h @@ -111,6 +111,7 @@ struct uart_8250_port { * if no_console_suspend */ unsigned char probe; + struct mctrl_gpios *gpios; #define UART_PROBE_RSA (1 << 0) /* -- cgit v0.10.2 From f8ba3647f30ab22daeb5110453e2dad8a2c1d841 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Mon, 6 Jun 2016 18:41:00 +0900 Subject: earlycon: mark earlycon code as __used iif the caller is built-in Keep earlycon related symbols only when CONFIG_SERIAL_EARLYCON is enabled and the driver is built-in. This will be helpful to clean up ifdefs surrounding earlycon code in serial drivers. Signed-off-by: Masahiro Yamada Acked-by: Arnd Bergmann Signed-off-by: Greg Kroah-Hartman diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h index a3d7c0d..2f44e20 100644 --- a/include/linux/serial_core.h +++ b/include/linux/serial_core.h @@ -352,9 +352,15 @@ struct earlycon_id { extern const struct earlycon_id __earlycon_table[]; extern const struct earlycon_id __earlycon_table_end[]; +#if defined(CONFIG_SERIAL_EARLYCON) && !defined(MODULE) +#define EARLYCON_USED_OR_UNUSED __used +#else +#define EARLYCON_USED_OR_UNUSED __maybe_unused +#endif + #define OF_EARLYCON_DECLARE(_name, compat, fn) \ static const struct earlycon_id __UNIQUE_ID(__earlycon_##_name) \ - __used __section(__earlycon_table) \ + EARLYCON_USED_OR_UNUSED __section(__earlycon_table) \ = { .name = __stringify(_name), \ .compatible = compat, \ .setup = fn } -- cgit v0.10.2 From 68b780598d75fb2be80d70034ec7b46e4fe712da Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Mon, 6 Jun 2016 18:41:01 +0900 Subject: serial: 8250_uniphier: drop !defined(MODULE) conditional The !defined(MODULE) conditional has been added to the OF_EARLYCON_DECLARE() define. Now we can revert commit a2d3ea2f2399 ("serial: 8250/uniphier: fix modular build"). Signed-off-by: Masahiro Yamada Acked-by: Arnd Bergmann Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/8250/8250_uniphier.c b/drivers/tty/serial/8250/8250_uniphier.c index efd1f9c..b8d9c8c 100644 --- a/drivers/tty/serial/8250/8250_uniphier.c +++ b/drivers/tty/serial/8250/8250_uniphier.c @@ -35,7 +35,7 @@ struct uniphier8250_priv { spinlock_t atomic_write_lock; }; -#if defined(CONFIG_SERIAL_8250_CONSOLE) && !defined(MODULE) +#ifdef CONFIG_SERIAL_8250_CONSOLE static int __init uniphier_early_console_setup(struct earlycon_device *device, const char *options) { -- cgit v0.10.2 From ae73975f193547cf50e61480b92781b199574b83 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Mon, 6 Jun 2016 18:41:02 +0900 Subject: serial: 8250_mtk: drop !defined(MODULE) conditional The !defined(MODULE) conditional has been added to the OF_EARLYCON_DECLARE() define. This commit partially reverts commit 3f5921a60f74 ("serial: 8250/mediatek: fix building with SERIAL_8250=m"). Signed-off-by: Masahiro Yamada Acked-by: Matthias Brugger Acked-by: Arnd Bergmann Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/8250/8250_mtk.c b/drivers/tty/serial/8250/8250_mtk.c index 3489fbc..3611ec9 100644 --- a/drivers/tty/serial/8250/8250_mtk.c +++ b/drivers/tty/serial/8250/8250_mtk.c @@ -301,7 +301,7 @@ static struct platform_driver mtk8250_platform_driver = { }; module_platform_driver(mtk8250_platform_driver); -#if defined(CONFIG_SERIAL_8250_CONSOLE) && !defined(MODULE) +#ifdef CONFIG_SERIAL_8250_CONSOLE static int __init early_mtk8250_setup(struct earlycon_device *device, const char *options) { -- cgit v0.10.2 From 755dd8aa12d162e40f3c5bd0031ad2f29ce6bc68 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Mon, 6 Jun 2016 18:41:03 +0900 Subject: serial: 8250_ingenic: drop #if conditional surrounding earlycon code The #if defined(CONFIG_SERIAL_EARLYCON) && !defined(MODULE) conditional has been added to the OF_EARLYCON_DECLARE() define. The same conditional can be dropped from 8250_ingenic.c because the unused symbols will be marked as __maybe_unsed. Also, the Kconfig dependency can become much simpler. Signed-off-by: Masahiro Yamada Acked-by: Arnd Bergmann Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/8250/8250_ingenic.c b/drivers/tty/serial/8250/8250_ingenic.c index b0677f61..4d9dc10 100644 --- a/drivers/tty/serial/8250/8250_ingenic.c +++ b/drivers/tty/serial/8250/8250_ingenic.c @@ -48,7 +48,6 @@ static const struct of_device_id of_match[]; #define UART_MCR_MDCE BIT(7) #define UART_MCR_FCM BIT(6) -#if defined(CONFIG_SERIAL_EARLYCON) && !defined(MODULE) static struct earlycon_device *early_device; static uint8_t __init early_in(struct uart_port *port, int offset) @@ -141,7 +140,6 @@ OF_EARLYCON_DECLARE(jz4775_uart, "ingenic,jz4775-uart", EARLYCON_DECLARE(jz4780_uart, ingenic_early_console_setup); OF_EARLYCON_DECLARE(jz4780_uart, "ingenic,jz4780-uart", ingenic_early_console_setup); -#endif /* CONFIG_SERIAL_EARLYCON */ static void ingenic_uart_serial_out(struct uart_port *p, int offset, int value) { diff --git a/drivers/tty/serial/8250/Kconfig b/drivers/tty/serial/8250/Kconfig index b1c73de..c9ec839 100644 --- a/drivers/tty/serial/8250/Kconfig +++ b/drivers/tty/serial/8250/Kconfig @@ -397,7 +397,7 @@ config SERIAL_8250_UNIPHIER config SERIAL_8250_INGENIC tristate "Support for Ingenic SoC serial ports" depends on SERIAL_8250 - depends on (OF_FLATTREE && SERIAL_8250_CONSOLE) || !SERIAL_EARLYCON + depends on OF_FLATTREE depends on MIPS || COMPILE_TEST help If you have a system using an Ingenic SoC and wish to make use of -- cgit v0.10.2 From fbc976c1eb540ae06b4201dd9707ddace77d15eb Mon Sep 17 00:00:00 2001 From: Chaehyun Lim Date: Mon, 13 Jun 2016 08:28:10 +0900 Subject: staging: wilc1000: change handle_cfg_param's return type to void When handle_cfg_param is called in hostIFthread that is a kernel thread, it is not checked return type of this function. This patch changes return type to void. Signed-off-by: Chaehyun Lim Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/wilc1000/host_interface.c b/drivers/staging/wilc1000/host_interface.c index 9535842..aeb355e 100644 --- a/drivers/staging/wilc1000/host_interface.c +++ b/drivers/staging/wilc1000/host_interface.c @@ -417,8 +417,8 @@ static void handle_get_mac_address(struct wilc_vif *vif, complete(&hif_wait_response); } -static s32 handle_cfg_param(struct wilc_vif *vif, - struct cfg_param_attr *cfg_param_attr) +static void handle_cfg_param(struct wilc_vif *vif, + struct cfg_param_attr *cfg_param_attr) { s32 result = 0; struct wid wid_list[32]; @@ -436,7 +436,6 @@ static s32 handle_cfg_param(struct wilc_vif *vif, hif_drv->cfg_values.bss_type = (u8)cfg_param_attr->bss_type; } else { netdev_err(vif->ndev, "check value 6 over\n"); - result = -EINVAL; goto unlock; } i++; @@ -452,7 +451,6 @@ static s32 handle_cfg_param(struct wilc_vif *vif, hif_drv->cfg_values.auth_type = (u8)cfg_param_attr->auth_type; } else { netdev_err(vif->ndev, "Impossible value\n"); - result = -EINVAL; goto unlock; } i++; @@ -467,7 +465,6 @@ static s32 handle_cfg_param(struct wilc_vif *vif, hif_drv->cfg_values.auth_timeout = cfg_param_attr->auth_timeout; } else { netdev_err(vif->ndev, "Range(1 ~ 65535) over\n"); - result = -EINVAL; goto unlock; } i++; @@ -481,7 +478,6 @@ static s32 handle_cfg_param(struct wilc_vif *vif, hif_drv->cfg_values.power_mgmt_mode = (u8)cfg_param_attr->power_mgmt_mode; } else { netdev_err(vif->ndev, "Invalid power mode\n"); - result = -EINVAL; goto unlock; } i++; @@ -496,7 +492,6 @@ static s32 handle_cfg_param(struct wilc_vif *vif, hif_drv->cfg_values.short_retry_limit = cfg_param_attr->short_retry_limit; } else { netdev_err(vif->ndev, "Range(1~256) over\n"); - result = -EINVAL; goto unlock; } i++; @@ -511,7 +506,6 @@ static s32 handle_cfg_param(struct wilc_vif *vif, hif_drv->cfg_values.long_retry_limit = cfg_param_attr->long_retry_limit; } else { netdev_err(vif->ndev, "Range(1~256) over\n"); - result = -EINVAL; goto unlock; } i++; @@ -526,7 +520,6 @@ static s32 handle_cfg_param(struct wilc_vif *vif, hif_drv->cfg_values.frag_threshold = cfg_param_attr->frag_threshold; } else { netdev_err(vif->ndev, "Threshold Range fail\n"); - result = -EINVAL; goto unlock; } i++; @@ -541,7 +534,6 @@ static s32 handle_cfg_param(struct wilc_vif *vif, hif_drv->cfg_values.rts_threshold = cfg_param_attr->rts_threshold; } else { netdev_err(vif->ndev, "Threshold Range fail\n"); - result = -EINVAL; goto unlock; } i++; @@ -555,7 +547,6 @@ static s32 handle_cfg_param(struct wilc_vif *vif, hif_drv->cfg_values.preamble_type = cfg_param_attr->preamble_type; } else { netdev_err(vif->ndev, "Preamle Range(0~2) over\n"); - result = -EINVAL; goto unlock; } i++; @@ -569,7 +560,6 @@ static s32 handle_cfg_param(struct wilc_vif *vif, hif_drv->cfg_values.short_slot_allowed = (u8)cfg_param_attr->short_slot_allowed; } else { netdev_err(vif->ndev, "Short slot(2) over\n"); - result = -EINVAL; goto unlock; } i++; @@ -583,7 +573,6 @@ static s32 handle_cfg_param(struct wilc_vif *vif, hif_drv->cfg_values.txop_prot_disabled = (u8)cfg_param_attr->txop_prot_disabled; } else { netdev_err(vif->ndev, "TXOP prot disable\n"); - result = -EINVAL; goto unlock; } i++; @@ -598,7 +587,6 @@ static s32 handle_cfg_param(struct wilc_vif *vif, hif_drv->cfg_values.beacon_interval = cfg_param_attr->beacon_interval; } else { netdev_err(vif->ndev, "Beacon interval(1~65535)fail\n"); - result = -EINVAL; goto unlock; } i++; @@ -613,7 +601,6 @@ static s32 handle_cfg_param(struct wilc_vif *vif, hif_drv->cfg_values.dtim_period = cfg_param_attr->dtim_period; } else { netdev_err(vif->ndev, "DTIM range(1~255) fail\n"); - result = -EINVAL; goto unlock; } i++; @@ -627,7 +614,6 @@ static s32 handle_cfg_param(struct wilc_vif *vif, hif_drv->cfg_values.site_survey_enabled = (u8)cfg_param_attr->site_survey_enabled; } else { netdev_err(vif->ndev, "Site survey disable\n"); - result = -EINVAL; goto unlock; } i++; @@ -642,7 +628,6 @@ static s32 handle_cfg_param(struct wilc_vif *vif, hif_drv->cfg_values.site_survey_scan_time = cfg_param_attr->site_survey_scan_time; } else { netdev_err(vif->ndev, "Site scan time(1~65535) over\n"); - result = -EINVAL; goto unlock; } i++; @@ -657,7 +642,6 @@ static s32 handle_cfg_param(struct wilc_vif *vif, hif_drv->cfg_values.active_scan_time = cfg_param_attr->active_scan_time; } else { netdev_err(vif->ndev, "Active time(1~65535) over\n"); - result = -EINVAL; goto unlock; } i++; @@ -672,7 +656,6 @@ static s32 handle_cfg_param(struct wilc_vif *vif, hif_drv->cfg_values.passive_scan_time = cfg_param_attr->passive_scan_time; } else { netdev_err(vif->ndev, "Passive time(1~65535) over\n"); - result = -EINVAL; goto unlock; } i++; @@ -694,7 +677,6 @@ static s32 handle_cfg_param(struct wilc_vif *vif, hif_drv->cfg_values.curr_tx_rate = (u8)curr_tx_rate; } else { netdev_err(vif->ndev, "out of TX rate\n"); - result = -EINVAL; goto unlock; } i++; @@ -708,7 +690,6 @@ static s32 handle_cfg_param(struct wilc_vif *vif, unlock: mutex_unlock(&hif_drv->cfg_values_lock); - return result; } static s32 handle_scan(struct wilc_vif *vif, struct scan_attr *scan_info) -- cgit v0.10.2 From eebb4df136a8b60b2fddda3886aaf20c8f3a644f Mon Sep 17 00:00:00 2001 From: Chaehyun Lim Date: Mon, 13 Jun 2016 08:28:11 +0900 Subject: staging: wilc1000: change data type of result in handle_cfg_param This patch changes data type of result variable from s32 to int. result is used to get return value from wilc_send_config_pkt that has return type of int. Signed-off-by: Chaehyun Lim Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/wilc1000/host_interface.c b/drivers/staging/wilc1000/host_interface.c index aeb355e..0220045 100644 --- a/drivers/staging/wilc1000/host_interface.c +++ b/drivers/staging/wilc1000/host_interface.c @@ -420,7 +420,7 @@ static void handle_get_mac_address(struct wilc_vif *vif, static void handle_cfg_param(struct wilc_vif *vif, struct cfg_param_attr *cfg_param_attr) { - s32 result = 0; + int result = 0; struct wid wid_list[32]; struct host_if_drv *hif_drv = vif->hif_drv; int i = 0; -- cgit v0.10.2 From a1e7df48832c28e8f65c489b1e312717f52218ab Mon Sep 17 00:00:00 2001 From: Chaehyun Lim Date: Mon, 13 Jun 2016 08:28:12 +0900 Subject: staging: wilc1000: rename result in handle_cfg_param This patch renames result to ret that is used to get return value from wilc_send_config_pkt. Some handle_*() functions are used as result, others are used as ret. It will be changed as ret in all handle_*() functions to match variable name. Signed-off-by: Chaehyun Lim Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/wilc1000/host_interface.c b/drivers/staging/wilc1000/host_interface.c index 0220045..ea5cb2d 100644 --- a/drivers/staging/wilc1000/host_interface.c +++ b/drivers/staging/wilc1000/host_interface.c @@ -420,7 +420,7 @@ static void handle_get_mac_address(struct wilc_vif *vif, static void handle_cfg_param(struct wilc_vif *vif, struct cfg_param_attr *cfg_param_attr) { - int result = 0; + int ret = 0; struct wid wid_list[32]; struct host_if_drv *hif_drv = vif->hif_drv; int i = 0; @@ -682,10 +682,10 @@ static void handle_cfg_param(struct wilc_vif *vif, i++; } - result = wilc_send_config_pkt(vif, SET_CFG, wid_list, - i, wilc_get_vif_idx(vif)); + ret = wilc_send_config_pkt(vif, SET_CFG, wid_list, + i, wilc_get_vif_idx(vif)); - if (result) + if (ret) netdev_err(vif->ndev, "Error in setting CFG params\n"); unlock: -- cgit v0.10.2 From 783fa6431eb05c81640d0d2bb05cb878b924c50a Mon Sep 17 00:00:00 2001 From: Chaehyun Lim Date: Mon, 13 Jun 2016 08:28:13 +0900 Subject: staging: wilc1000: remove unused struct set_mac_addr struct set_mac_addr is not used anymore, so just remove it. Signed-off-by: Chaehyun Lim Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/wilc1000/host_interface.c b/drivers/staging/wilc1000/host_interface.c index ea5cb2d..96821f6 100644 --- a/drivers/staging/wilc1000/host_interface.c +++ b/drivers/staging/wilc1000/host_interface.c @@ -181,7 +181,6 @@ union message_body { struct drv_handler drv; struct set_multicast multicast_info; struct op_mode mode; - struct set_mac_addr set_mac_info; struct get_mac_addr get_mac_info; struct ba_session_info session_info; struct remain_ch remain_on_ch; diff --git a/drivers/staging/wilc1000/host_interface.h b/drivers/staging/wilc1000/host_interface.h index 8d2dd0d..ddfea29 100644 --- a/drivers/staging/wilc1000/host_interface.h +++ b/drivers/staging/wilc1000/host_interface.h @@ -224,10 +224,6 @@ struct op_mode { u32 mode; }; -struct set_mac_addr { - u8 mac_addr[ETH_ALEN]; -}; - struct get_mac_addr { u8 *mac_addr; }; -- cgit v0.10.2 From 0cb7a5742d6d6ea094107ba0a3c7e3768483538c Mon Sep 17 00:00:00 2001 From: Chaehyun Lim Date: Mon, 13 Jun 2016 08:28:14 +0900 Subject: staging: wilc1000: add bss_type to remove line over 80 characters A local bss_type variable is added to remove checkpatch warning of line over 80 characters. Signed-off-by: Chaehyun Lim Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/wilc1000/host_interface.c b/drivers/staging/wilc1000/host_interface.c index 96821f6..828efff 100644 --- a/drivers/staging/wilc1000/host_interface.c +++ b/drivers/staging/wilc1000/host_interface.c @@ -427,12 +427,14 @@ static void handle_cfg_param(struct wilc_vif *vif, mutex_lock(&hif_drv->cfg_values_lock); if (cfg_param_attr->flag & BSS_TYPE) { - if (cfg_param_attr->bss_type < 6) { + u8 bss_type = cfg_param_attr->bss_type; + + if (bss_type < 6) { wid_list[i].id = WID_BSS_TYPE; - wid_list[i].val = (s8 *)&cfg_param_attr->bss_type; + wid_list[i].val = (s8 *)&bss_type; wid_list[i].type = WID_CHAR; wid_list[i].size = sizeof(char); - hif_drv->cfg_values.bss_type = (u8)cfg_param_attr->bss_type; + hif_drv->cfg_values.bss_type = (u8)bss_type; } else { netdev_err(vif->ndev, "check value 6 over\n"); goto unlock; -- cgit v0.10.2 From 2938f208420d7f9c695d637ca92495c33bdfae5c Mon Sep 17 00:00:00 2001 From: Chaehyun Lim Date: Mon, 13 Jun 2016 08:28:15 +0900 Subject: staging: wilc1000: remove unnecesary type cast of bss_type There is no need to use type cast of bss_type because hif_drv->cfg_values.bss_type is u8. Signed-off-by: Chaehyun Lim Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/wilc1000/host_interface.c b/drivers/staging/wilc1000/host_interface.c index 828efff..5b2278b 100644 --- a/drivers/staging/wilc1000/host_interface.c +++ b/drivers/staging/wilc1000/host_interface.c @@ -434,7 +434,7 @@ static void handle_cfg_param(struct wilc_vif *vif, wid_list[i].val = (s8 *)&bss_type; wid_list[i].type = WID_CHAR; wid_list[i].size = sizeof(char); - hif_drv->cfg_values.bss_type = (u8)bss_type; + hif_drv->cfg_values.bss_type = bss_type; } else { netdev_err(vif->ndev, "check value 6 over\n"); goto unlock; -- cgit v0.10.2 From 95b8cb8917e358cdf8489b1101e3559ef868ff13 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Thu, 23 Jun 2016 14:14:07 +0100 Subject: staging: wilc1000: fix spelling mistake: "interupts" -> "interrupts" trivial fix to spelling mistake in dev_err messages Signed-off-by: Colin Ian King Reviewed-by: Julian Calaby Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/wilc1000/wilc_sdio.c b/drivers/staging/wilc1000/wilc_sdio.c index a839a79..39b73fb2 100644 --- a/drivers/staging/wilc1000/wilc_sdio.c +++ b/drivers/staging/wilc1000/wilc_sdio.c @@ -1006,7 +1006,7 @@ static int sdio_sync_ext(struct wilc *wilc, int nint) u32 reg; if (nint > MAX_NUM_INT) { - dev_err(&func->dev, "Too many interupts (%d)...\n", nint); + dev_err(&func->dev, "Too many interrupts (%d)...\n", nint); return 0; } if (nint > MAX_NUN_INT_THRPT_ENH2) { diff --git a/drivers/staging/wilc1000/wilc_spi.c b/drivers/staging/wilc1000/wilc_spi.c index 4268e2f..22cf4b7 100644 --- a/drivers/staging/wilc1000/wilc_spi.c +++ b/drivers/staging/wilc1000/wilc_spi.c @@ -1082,7 +1082,7 @@ static int wilc_spi_sync_ext(struct wilc *wilc, int nint) int ret, i; if (nint > MAX_NUM_INT) { - dev_err(&spi->dev, "Too many interupts (%d)...\n", nint); + dev_err(&spi->dev, "Too many interrupts (%d)...\n", nint); return 0; } -- cgit v0.10.2 From b9811891a9f60ca9c314dcab3244c65930c4cf37 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Tue, 17 May 2016 16:38:43 +0200 Subject: staging: wilc1000: fix typo firmare -> firmware Signed-off-by: Julia Lawall Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/wilc1000/linux_wlan.c b/drivers/staging/wilc1000/linux_wlan.c index 4f93c11..274c390 100644 --- a/drivers/staging/wilc1000/linux_wlan.c +++ b/drivers/staging/wilc1000/linux_wlan.c @@ -362,7 +362,7 @@ int wilc_wlan_get_firmware(struct net_device *dev) goto _fail_; if (request_firmware(&wilc_firmware, firmware, wilc->dev) != 0) { - netdev_err(dev, "%s - firmare not available\n", firmware); + netdev_err(dev, "%s - firmware not available\n", firmware); ret = -1; goto _fail_; } -- cgit v0.10.2 From b27a6d5e636ac80b223a18ca2b3c892f1caef9e3 Mon Sep 17 00:00:00 2001 From: Binoy Jayan Date: Wed, 15 Jun 2016 11:00:34 +0530 Subject: staging: wilc1000: Replace semaphore txq_event with completion The semaphore 'txq_event' is used as completion, so convert it to a struct completion type. Signed-off-by: Binoy Jayan Reviewed-by: Arnd Bergmann Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/wilc1000/linux_wlan.c b/drivers/staging/wilc1000/linux_wlan.c index 274c390..baf9326 100644 --- a/drivers/staging/wilc1000/linux_wlan.c +++ b/drivers/staging/wilc1000/linux_wlan.c @@ -316,7 +316,7 @@ static int linux_wlan_txq_task(void *vp) complete(&wl->txq_thread_started); while (1) { - down(&wl->txq_event); + wait_for_completion(&wl->txq_event); if (wl->close) { complete(&wl->txq_thread_started); @@ -650,7 +650,7 @@ void wilc1000_wlan_deinit(struct net_device *dev) mutex_unlock(&wl->hif_cs); } if (&wl->txq_event) - up(&wl->txq_event); + wait_for_completion(&wl->txq_event); wlan_deinitialize_threads(dev); deinit_irq(dev); @@ -681,7 +681,7 @@ static int wlan_init_locks(struct net_device *dev) spin_lock_init(&wl->txq_spinlock); sema_init(&wl->txq_add_to_head_cs, 1); - sema_init(&wl->txq_event, 0); + init_completion(&wl->txq_event); sema_init(&wl->cfg_event, 0); sema_init(&wl->sync_event, 0); @@ -738,7 +738,7 @@ static void wlan_deinitialize_threads(struct net_device *dev) wl->close = 1; if (&wl->txq_event) - up(&wl->txq_event); + complete(&wl->txq_event); if (wl->txq_thread) { kthread_stop(wl->txq_thread); diff --git a/drivers/staging/wilc1000/wilc_wfi_netdevice.h b/drivers/staging/wilc1000/wilc_wfi_netdevice.h index 3a561df6..12d7c7b 100644 --- a/drivers/staging/wilc1000/wilc_wfi_netdevice.h +++ b/drivers/staging/wilc1000/wilc_wfi_netdevice.h @@ -42,6 +42,7 @@ #include "host_interface.h" #include "wilc_wlan.h" #include +#include #define FLOW_CONTROL_LOWER_THRESHOLD 128 #define FLOW_CONTROL_UPPER_THRESHOLD 256 @@ -178,7 +179,7 @@ struct wilc { struct semaphore cfg_event; struct semaphore sync_event; - struct semaphore txq_event; + struct completion txq_event; struct completion txq_thread_started; struct task_struct *txq_thread; diff --git a/drivers/staging/wilc1000/wilc_wlan.c b/drivers/staging/wilc1000/wilc_wlan.c index 11e16d5..1a57135 100644 --- a/drivers/staging/wilc1000/wilc_wlan.c +++ b/drivers/staging/wilc1000/wilc_wlan.c @@ -1,3 +1,4 @@ +#include #include "wilc_wlan_if.h" #include "wilc_wlan.h" #include "wilc_wfi_netdevice.h" @@ -89,7 +90,7 @@ static void wilc_wlan_txq_add_to_tail(struct net_device *dev, spin_unlock_irqrestore(&wilc->txq_spinlock, flags); - up(&wilc->txq_event); + complete(&wilc->txq_event); } static int wilc_wlan_txq_add_to_head(struct wilc_vif *vif, @@ -119,7 +120,7 @@ static int wilc_wlan_txq_add_to_head(struct wilc_vif *vif, spin_unlock_irqrestore(&wilc->txq_spinlock, flags); up(&wilc->txq_add_to_head_cs); - up(&wilc->txq_event); + complete(&wilc->txq_event); return 0; } @@ -287,7 +288,8 @@ static int wilc_wlan_txq_filter_dup_tcp_ack(struct net_device *dev) spin_unlock_irqrestore(&wilc->txq_spinlock, wilc->txq_spinlock_flags); while (dropped > 0) { - wilc_lock_timeout(wilc, &wilc->txq_event, 1); + wait_for_completion_timeout(&wilc->txq_event, + msecs_to_jiffies(1)); dropped--; } -- cgit v0.10.2 From 334bed089d3d74e64a34b0ebee52b146b6778a6b Mon Sep 17 00:00:00 2001 From: Binoy Jayan Date: Wed, 15 Jun 2016 11:00:35 +0530 Subject: staging: wilc1000: Replace semaphore txq_add_to_head_cs with mutex The semaphore 'txq_add_to_head_cs' is a simple mutex, so it should be written as one. Semaphores are going away in the future. Also, removing the timeout scenario as the error handling code does not propagate the timeout properly. Signed-off-by: Binoy Jayan Reviewed-by: Arnd Bergmann Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/wilc1000/linux_wlan.c b/drivers/staging/wilc1000/linux_wlan.c index baf9326..5dc645c 100644 --- a/drivers/staging/wilc1000/linux_wlan.c +++ b/drivers/staging/wilc1000/linux_wlan.c @@ -20,7 +20,7 @@ #include #include #include - +#include #include #include @@ -679,7 +679,7 @@ static int wlan_init_locks(struct net_device *dev) mutex_init(&wl->rxq_cs); spin_lock_init(&wl->txq_spinlock); - sema_init(&wl->txq_add_to_head_cs, 1); + mutex_init(&wl->txq_add_to_head_cs); init_completion(&wl->txq_event); diff --git a/drivers/staging/wilc1000/wilc_wfi_netdevice.h b/drivers/staging/wilc1000/wilc_wfi_netdevice.h index 12d7c7b..239cd43 100644 --- a/drivers/staging/wilc1000/wilc_wfi_netdevice.h +++ b/drivers/staging/wilc1000/wilc_wfi_netdevice.h @@ -43,6 +43,7 @@ #include "wilc_wlan.h" #include #include +#include #define FLOW_CONTROL_LOWER_THRESHOLD 128 #define FLOW_CONTROL_UPPER_THRESHOLD 256 @@ -171,7 +172,7 @@ struct wilc { struct wilc_vif *vif[NUM_CONCURRENT_IFC]; u8 open_ifcs; - struct semaphore txq_add_to_head_cs; + struct mutex txq_add_to_head_cs; spinlock_t txq_spinlock; struct mutex rxq_cs; diff --git a/drivers/staging/wilc1000/wilc_wlan.c b/drivers/staging/wilc1000/wilc_wlan.c index 1a57135..9afbe8d 100644 --- a/drivers/staging/wilc1000/wilc_wlan.c +++ b/drivers/staging/wilc1000/wilc_wlan.c @@ -99,9 +99,7 @@ static int wilc_wlan_txq_add_to_head(struct wilc_vif *vif, unsigned long flags; struct wilc *wilc = vif->wilc; - if (wilc_lock_timeout(wilc, &wilc->txq_add_to_head_cs, - CFG_PKTS_TIMEOUT)) - return -1; + mutex_lock(&wilc->txq_add_to_head_cs); spin_lock_irqsave(&wilc->txq_spinlock, flags); @@ -119,7 +117,7 @@ static int wilc_wlan_txq_add_to_head(struct wilc_vif *vif, wilc->txq_entries += 1; spin_unlock_irqrestore(&wilc->txq_spinlock, flags); - up(&wilc->txq_add_to_head_cs); + mutex_unlock(&wilc->txq_add_to_head_cs); complete(&wilc->txq_event); return 0; @@ -573,8 +571,7 @@ int wilc_wlan_handle_txq(struct net_device *dev, u32 *txq_count) if (wilc->quit) break; - wilc_lock_timeout(wilc, &wilc->txq_add_to_head_cs, - CFG_PKTS_TIMEOUT); + mutex_lock(&wilc->txq_add_to_head_cs); wilc_wlan_txq_filter_dup_tcp_ack(dev); tqe = wilc_wlan_txq_get_first(wilc); i = 0; @@ -755,7 +752,7 @@ _end_: if (ret != 1) break; } while (0); - up(&wilc->txq_add_to_head_cs); + mutex_unlock(&wilc->txq_add_to_head_cs); wilc->txq_exit = 1; *txq_count = wilc->txq_entries; -- cgit v0.10.2 From fa6596982f00e7c341c95174de2275062f14e3fa Mon Sep 17 00:00:00 2001 From: Binoy Jayan Date: Wed, 15 Jun 2016 11:00:36 +0530 Subject: staging: wilc1000: Replace semaphore cfg_event with completion The semaphore 'cfg_event' is used as completion, so convert it to a struct completion type. Signed-off-by: Binoy Jayan Reviewed-by: Arnd Bergmann Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/wilc1000/linux_wlan.c b/drivers/staging/wilc1000/linux_wlan.c index 5dc645c..5c5e8ad 100644 --- a/drivers/staging/wilc1000/linux_wlan.c +++ b/drivers/staging/wilc1000/linux_wlan.c @@ -683,7 +683,7 @@ static int wlan_init_locks(struct net_device *dev) init_completion(&wl->txq_event); - sema_init(&wl->cfg_event, 0); + init_completion(&wl->cfg_event); sema_init(&wl->sync_event, 0); init_completion(&wl->txq_thread_started); diff --git a/drivers/staging/wilc1000/wilc_wfi_netdevice.h b/drivers/staging/wilc1000/wilc_wfi_netdevice.h index 239cd43..5fbc07c 100644 --- a/drivers/staging/wilc1000/wilc_wfi_netdevice.h +++ b/drivers/staging/wilc1000/wilc_wfi_netdevice.h @@ -178,7 +178,7 @@ struct wilc { struct mutex rxq_cs; struct mutex hif_cs; - struct semaphore cfg_event; + struct completion cfg_event; struct semaphore sync_event; struct completion txq_event; struct completion txq_thread_started; diff --git a/drivers/staging/wilc1000/wilc_wlan.c b/drivers/staging/wilc1000/wilc_wlan.c index 9afbe8d..19a5809 100644 --- a/drivers/staging/wilc1000/wilc_wlan.c +++ b/drivers/staging/wilc1000/wilc_wlan.c @@ -310,7 +310,7 @@ static int wilc_wlan_txq_add_cfg_pkt(struct wilc_vif *vif, u8 *buffer, netdev_dbg(vif->ndev, "Adding config packet ...\n"); if (wilc->quit) { netdev_dbg(vif->ndev, "Return due to clear function\n"); - up(&wilc->cfg_event); + complete(&wilc->cfg_event); return 0; } @@ -769,7 +769,7 @@ static void wilc_wlan_handle_rxq(struct wilc *wilc) do { if (wilc->quit) { - up(&wilc->cfg_event); + complete(&wilc->cfg_event); break; } rqe = wilc_wlan_rxq_remove(wilc); @@ -820,7 +820,7 @@ static void wilc_wlan_handle_rxq(struct wilc *wilc) wilc_wlan_cfg_indicate_rx(wilc, &buffer[pkt_offset + offset], pkt_len, &rsp); if (rsp.type == WILC_CFG_RSP) { if (wilc->cfg_seq_no == rsp.seq_no) - up(&wilc->cfg_event); + complete(&wilc->cfg_event); } else if (rsp.type == WILC_CFG_RSP_STATUS) { wilc_mac_indicate(wilc, WILC_MAC_INDICATE_STATUS); @@ -1228,11 +1228,12 @@ int wilc_wlan_cfg_set(struct wilc_vif *vif, int start, u16 wid, u8 *buffer, if (wilc_wlan_cfg_commit(vif, WILC_CFG_SET, drv_handler)) ret_size = 0; - if (wilc_lock_timeout(wilc, &wilc->cfg_event, - CFG_PKTS_TIMEOUT)) { + if (!wait_for_completion_timeout(&wilc->cfg_event, + msecs_to_jiffies(CFG_PKTS_TIMEOUT))) { netdev_dbg(vif->ndev, "Set Timed Out\n"); ret_size = 0; } + wilc->cfg_frame_in_use = 0; wilc->cfg_frame_offset = 0; wilc->cfg_seq_no += 1; @@ -1265,8 +1266,8 @@ int wilc_wlan_cfg_get(struct wilc_vif *vif, int start, u16 wid, int commit, if (wilc_wlan_cfg_commit(vif, WILC_CFG_QUERY, drv_handler)) ret_size = 0; - if (wilc_lock_timeout(wilc, &wilc->cfg_event, - CFG_PKTS_TIMEOUT)) { + if (!wait_for_completion_timeout(&wilc->cfg_event, + msecs_to_jiffies(CFG_PKTS_TIMEOUT))) { netdev_dbg(vif->ndev, "Get Timed Out\n"); ret_size = 0; } -- cgit v0.10.2 From 04247e7d65c9ce80a7d19aae2fd7cdf64ce80800 Mon Sep 17 00:00:00 2001 From: Binoy Jayan Date: Wed, 15 Jun 2016 11:00:37 +0530 Subject: staging: wilc1000: Replace semaphore sync_event with completion The semaphore 'sync_event' is used as completion, so convert it to a struct completion type. Also, return -ETIME if the return value of wait_for_completion_timeout is 0. Signed-off-by: Binoy Jayan Reviewed-by: Arnd Bergmann Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/wilc1000/linux_wlan.c b/drivers/staging/wilc1000/linux_wlan.c index 5c5e8ad..e0890f5 100644 --- a/drivers/staging/wilc1000/linux_wlan.c +++ b/drivers/staging/wilc1000/linux_wlan.c @@ -241,7 +241,7 @@ void wilc_mac_indicate(struct wilc *wilc, int flag) (unsigned char *)&status, 4); if (wilc->mac_status == WILC_MAC_STATUS_INIT) { wilc->mac_status = status; - up(&wilc->sync_event); + complete(&wilc->sync_event); } else { wilc->mac_status = status; } @@ -386,9 +386,9 @@ static int linux_wlan_start_firmware(struct net_device *dev) if (ret < 0) return ret; - ret = wilc_lock_timeout(wilc, &wilc->sync_event, 5000); - if (ret) - return ret; + if (!wait_for_completion_timeout(&wilc->sync_event, + msecs_to_jiffies(5000))) + return -ETIME; return 0; } @@ -684,7 +684,7 @@ static int wlan_init_locks(struct net_device *dev) init_completion(&wl->txq_event); init_completion(&wl->cfg_event); - sema_init(&wl->sync_event, 0); + init_completion(&wl->sync_event); init_completion(&wl->txq_thread_started); return 0; diff --git a/drivers/staging/wilc1000/wilc_wfi_netdevice.h b/drivers/staging/wilc1000/wilc_wfi_netdevice.h index 5fbc07c..5cc6a82 100644 --- a/drivers/staging/wilc1000/wilc_wfi_netdevice.h +++ b/drivers/staging/wilc1000/wilc_wfi_netdevice.h @@ -179,7 +179,7 @@ struct wilc { struct mutex hif_cs; struct completion cfg_event; - struct semaphore sync_event; + struct completion sync_event; struct completion txq_event; struct completion txq_thread_started; -- cgit v0.10.2 From 77eebe82eb114605c0ade45f1b4587c530660f4f Mon Sep 17 00:00:00 2001 From: Binoy Jayan Date: Wed, 15 Jun 2016 11:00:38 +0530 Subject: staging: wilc1000: Remove semaphore close_exit_sync The semaphore 'close_exit_sync' does not serve any purpose other than delaying the deregistration of the device which it is trying to protect from shared access. 'up' is called only when a subdevice is closed and not when it is opened. So, the semaphore count only goes up when the device is used. Signed-off-by: Binoy Jayan Reviewed-by: Arnd Bergmann Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/wilc1000/linux_wlan.c b/drivers/staging/wilc1000/linux_wlan.c index e0890f5..2ce9df5 100644 --- a/drivers/staging/wilc1000/linux_wlan.c +++ b/drivers/staging/wilc1000/linux_wlan.c @@ -31,8 +31,6 @@ static struct notifier_block g_dev_notifier = { .notifier_call = dev_state_ev_handler }; -static struct semaphore close_exit_sync; - static int wlan_deinit_locks(struct net_device *dev); static void wlan_deinitialize_threads(struct net_device *dev); @@ -1088,7 +1086,6 @@ int wilc_mac_close(struct net_device *ndev) WILC_WFI_deinit_mon_interface(); } - up(&close_exit_sync); vif->mac_opened = 0; return 0; @@ -1232,8 +1229,6 @@ void wilc_netdev_cleanup(struct wilc *wilc) } if (wilc && (wilc->vif[0]->ndev || wilc->vif[1]->ndev)) { - wilc_lock_timeout(wilc, &close_exit_sync, 5 * 1000); - for (i = 0; i < NUM_CONCURRENT_IFC; i++) if (wilc->vif[i]->ndev) if (vif[i]->mac_opened) @@ -1258,8 +1253,6 @@ int wilc_netdev_init(struct wilc **wilc, struct device *dev, int io_type, struct net_device *ndev; struct wilc *wl; - sema_init(&close_exit_sync, 0); - wl = kzalloc(sizeof(*wl), GFP_KERNEL); if (!wl) return -ENOMEM; -- cgit v0.10.2 From c6bb38a5e82a26c6556e05d2140c3a1b4176c2ab Mon Sep 17 00:00:00 2001 From: Binoy Jayan Date: Thu, 23 Jun 2016 11:11:50 +0530 Subject: staging: wilc1000: message_queue: Move code to host interface Move the contents of wilc_msgqueue.c and wilc_msgqueue.h into host_interface.c, remove 'wilc_msgqueue.c' and 'wilc_msgqueue.h'. This is done so as to restructure the implementation of the kthread 'hostIFthread' using a work queue. Signed-off-by: Binoy Jayan Reviewed-by: Arnd Bergmann Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/wilc1000/Makefile b/drivers/staging/wilc1000/Makefile index acc3f3e..d226283 100644 --- a/drivers/staging/wilc1000/Makefile +++ b/drivers/staging/wilc1000/Makefile @@ -6,7 +6,6 @@ ccflags-y += -DFIRMWARE_1002=\"atmel/wilc1002_firmware.bin\" \ ccflags-y += -I$(src)/ -DWILC_ASIC_A0 -DWILC_DEBUGFS wilc1000-objs := wilc_wfi_cfgoperations.o linux_wlan.o linux_mon.o \ - wilc_msgqueue.o \ coreconfigurator.o host_interface.o \ wilc_wlan_cfg.o wilc_debugfs.o \ wilc_wlan.o diff --git a/drivers/staging/wilc1000/host_interface.c b/drivers/staging/wilc1000/host_interface.c index 5b2278b..a34a1bb 100644 --- a/drivers/staging/wilc1000/host_interface.c +++ b/drivers/staging/wilc1000/host_interface.c @@ -3,11 +3,13 @@ #include #include #include +#include #include "host_interface.h" +#include +#include #include "coreconfigurator.h" #include "wilc_wlan.h" #include "wilc_wlan_if.h" -#include "wilc_msgqueue.h" #include #include "wilc_wfi_netdevice.h" @@ -57,6 +59,20 @@ #define TCP_ACK_FILTER_LINK_SPEED_THRESH 54 #define DEFAULT_LINK_SPEED 72 +struct message { + void *buf; + u32 len; + struct list_head list; +}; + +struct message_queue { + struct semaphore sem; + spinlock_t lock; + bool exiting; + u32 recv_count; + struct list_head msg_list; +}; + struct host_if_wpa_attr { u8 *key; const u8 *mac_addr; @@ -263,6 +279,151 @@ static struct wilc_vif *join_req_vif; static void *host_int_ParseJoinBssParam(struct network_info *ptstrNetworkInfo); static int host_int_get_ipaddress(struct wilc_vif *vif, u8 *ip_addr, u8 idx); static s32 Handle_ScanDone(struct wilc_vif *vif, enum scan_event enuEvent); +static int wilc_mq_create(struct message_queue *mq); +static int wilc_mq_send(struct message_queue *mq, + const void *send_buf, u32 send_buf_size); +static int wilc_mq_recv(struct message_queue *mq, + void *recv_buf, u32 recv_buf_size, u32 *recv_len); +static int wilc_mq_destroy(struct message_queue *mq); + +/*! + * @author syounan + * @date 1 Sep 2010 + * @note copied from FLO glue implementatuion + * @version 1.0 + */ +static int wilc_mq_create(struct message_queue *mq) +{ + spin_lock_init(&mq->lock); + sema_init(&mq->sem, 0); + INIT_LIST_HEAD(&mq->msg_list); + mq->recv_count = 0; + mq->exiting = false; + return 0; +} + +/*! + * @author syounan + * @date 1 Sep 2010 + * @note copied from FLO glue implementatuion + * @version 1.0 + */ +static int wilc_mq_destroy(struct message_queue *mq) +{ + struct message *msg; + + mq->exiting = true; + + /* Release any waiting receiver thread. */ + while (mq->recv_count > 0) { + up(&mq->sem); + mq->recv_count--; + } + + while (!list_empty(&mq->msg_list)) { + msg = list_first_entry(&mq->msg_list, struct message, list); + list_del(&msg->list); + kfree(msg->buf); + } + + return 0; +} + +/*! + * @author syounan + * @date 1 Sep 2010 + * @note copied from FLO glue implementatuion + * @version 1.0 + */ +static int wilc_mq_send(struct message_queue *mq, + const void *send_buf, u32 send_buf_size) +{ + unsigned long flags; + struct message *new_msg = NULL; + + if (!mq || (send_buf_size == 0) || !send_buf) + return -EINVAL; + + if (mq->exiting) + return -EFAULT; + + /* construct a new message */ + new_msg = kmalloc(sizeof(*new_msg), GFP_ATOMIC); + if (!new_msg) + return -ENOMEM; + + new_msg->len = send_buf_size; + INIT_LIST_HEAD(&new_msg->list); + new_msg->buf = kmemdup(send_buf, send_buf_size, GFP_ATOMIC); + if (!new_msg->buf) { + kfree(new_msg); + return -ENOMEM; + } + + spin_lock_irqsave(&mq->lock, flags); + + /* add it to the message queue */ + list_add_tail(&new_msg->list, &mq->msg_list); + + spin_unlock_irqrestore(&mq->lock, flags); + + up(&mq->sem); + + return 0; +} + +/*! + * @author syounan + * @date 1 Sep 2010 + * @note copied from FLO glue implementatuion + * @version 1.0 + */ +static int wilc_mq_recv(struct message_queue *mq, + void *recv_buf, u32 recv_buf_size, u32 *recv_len) +{ + struct message *msg; + unsigned long flags; + + if (!mq || (recv_buf_size == 0) || !recv_buf || !recv_len) + return -EINVAL; + + if (mq->exiting) + return -EFAULT; + + spin_lock_irqsave(&mq->lock, flags); + mq->recv_count++; + spin_unlock_irqrestore(&mq->lock, flags); + + down(&mq->sem); + spin_lock_irqsave(&mq->lock, flags); + + if (list_empty(&mq->msg_list)) { + spin_unlock_irqrestore(&mq->lock, flags); + up(&mq->sem); + return -EFAULT; + } + /* check buffer size */ + msg = list_first_entry(&mq->msg_list, struct message, list); + if (recv_buf_size < msg->len) { + spin_unlock_irqrestore(&mq->lock, flags); + up(&mq->sem); + return -EOVERFLOW; + } + + /* consume the message */ + mq->recv_count--; + memcpy(recv_buf, msg->buf, msg->len); + *recv_len = msg->len; + + list_del(&msg->list); + + kfree(msg->buf); + kfree(msg); + + spin_unlock_irqrestore(&mq->lock, flags); + + return 0; +} /* The u8IfIdx starts from 0 to NUM_CONCURRENT_IFC -1, but 0 index used as * special purpose in wilc device, so we add 1 to the index to starts from 1. diff --git a/drivers/staging/wilc1000/wilc_msgqueue.c b/drivers/staging/wilc1000/wilc_msgqueue.c deleted file mode 100644 index 6cb894e..0000000 --- a/drivers/staging/wilc1000/wilc_msgqueue.c +++ /dev/null @@ -1,144 +0,0 @@ - -#include "wilc_msgqueue.h" -#include -#include -#include - -/*! - * @author syounan - * @date 1 Sep 2010 - * @note copied from FLO glue implementatuion - * @version 1.0 - */ -int wilc_mq_create(struct message_queue *mq) -{ - spin_lock_init(&mq->lock); - sema_init(&mq->sem, 0); - INIT_LIST_HEAD(&mq->msg_list); - mq->recv_count = 0; - mq->exiting = false; - return 0; -} - -/*! - * @author syounan - * @date 1 Sep 2010 - * @note copied from FLO glue implementatuion - * @version 1.0 - */ -int wilc_mq_destroy(struct message_queue *mq) -{ - struct message *msg; - - mq->exiting = true; - - /* Release any waiting receiver thread. */ - while (mq->recv_count > 0) { - up(&mq->sem); - mq->recv_count--; - } - - while (!list_empty(&mq->msg_list)) { - msg = list_first_entry(&mq->msg_list, struct message, list); - list_del(&msg->list); - kfree(msg->buf); - } - - return 0; -} - -/*! - * @author syounan - * @date 1 Sep 2010 - * @note copied from FLO glue implementatuion - * @version 1.0 - */ -int wilc_mq_send(struct message_queue *mq, - const void *send_buf, u32 send_buf_size) -{ - unsigned long flags; - struct message *new_msg = NULL; - - if (!mq || (send_buf_size == 0) || !send_buf) - return -EINVAL; - - if (mq->exiting) - return -EFAULT; - - /* construct a new message */ - new_msg = kmalloc(sizeof(*new_msg), GFP_ATOMIC); - if (!new_msg) - return -ENOMEM; - - new_msg->len = send_buf_size; - INIT_LIST_HEAD(&new_msg->list); - new_msg->buf = kmemdup(send_buf, send_buf_size, GFP_ATOMIC); - if (!new_msg->buf) { - kfree(new_msg); - return -ENOMEM; - } - - spin_lock_irqsave(&mq->lock, flags); - - /* add it to the message queue */ - list_add_tail(&new_msg->list, &mq->msg_list); - - spin_unlock_irqrestore(&mq->lock, flags); - - up(&mq->sem); - - return 0; -} - -/*! - * @author syounan - * @date 1 Sep 2010 - * @note copied from FLO glue implementatuion - * @version 1.0 - */ -int wilc_mq_recv(struct message_queue *mq, - void *recv_buf, u32 recv_buf_size, u32 *recv_len) -{ - struct message *msg; - unsigned long flags; - - if (!mq || (recv_buf_size == 0) || !recv_buf || !recv_len) - return -EINVAL; - - if (mq->exiting) - return -EFAULT; - - spin_lock_irqsave(&mq->lock, flags); - mq->recv_count++; - spin_unlock_irqrestore(&mq->lock, flags); - - down(&mq->sem); - spin_lock_irqsave(&mq->lock, flags); - - if (list_empty(&mq->msg_list)) { - spin_unlock_irqrestore(&mq->lock, flags); - up(&mq->sem); - return -EFAULT; - } - /* check buffer size */ - msg = list_first_entry(&mq->msg_list, struct message, list); - if (recv_buf_size < msg->len) { - spin_unlock_irqrestore(&mq->lock, flags); - up(&mq->sem); - return -EOVERFLOW; - } - - /* consume the message */ - mq->recv_count--; - memcpy(recv_buf, msg->buf, msg->len); - *recv_len = msg->len; - - list_del(&msg->list); - - kfree(msg->buf); - kfree(msg); - - spin_unlock_irqrestore(&mq->lock, flags); - - return 0; -} diff --git a/drivers/staging/wilc1000/wilc_msgqueue.h b/drivers/staging/wilc1000/wilc_msgqueue.h deleted file mode 100644 index 846a484..0000000 --- a/drivers/staging/wilc1000/wilc_msgqueue.h +++ /dev/null @@ -1,28 +0,0 @@ -#ifndef __WILC_MSG_QUEUE_H__ -#define __WILC_MSG_QUEUE_H__ - -#include -#include - -struct message { - void *buf; - u32 len; - struct list_head list; -}; - -struct message_queue { - struct semaphore sem; - spinlock_t lock; - bool exiting; - u32 recv_count; - struct list_head msg_list; -}; - -int wilc_mq_create(struct message_queue *mq); -int wilc_mq_send(struct message_queue *mq, - const void *send_buf, u32 send_buf_size); -int wilc_mq_recv(struct message_queue *mq, - void *recv_buf, u32 recv_buf_size, u32 *recv_len); -int wilc_mq_destroy(struct message_queue *mq); - -#endif -- cgit v0.10.2 From 2518ac59eb27ed003c5a97e8f9588adafdfe4a8a Mon Sep 17 00:00:00 2001 From: Binoy Jayan Date: Thu, 23 Jun 2016 11:11:51 +0530 Subject: staging: wilc1000: Replace kthread with workqueue for host interface Deconstruct the kthread / message_queue logic, replacing it with create_singlethread_workqueue() / queue_work() setup, by adding a 'struct work_struct' to 'struct host_if_msg'. The current kthread hostIFthread() is converted to a work queue helper with the name 'host_if_work'. Signed-off-by: Binoy Jayan Reviewed-by: Arnd Bergmann Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/wilc1000/TODO b/drivers/staging/wilc1000/TODO index 95199d8..ec93b2e 100644 --- a/drivers/staging/wilc1000/TODO +++ b/drivers/staging/wilc1000/TODO @@ -4,6 +4,11 @@ TODO: - remove custom debug and tracing functions - rework comments and function headers(also coding style) - replace all semaphores with mutexes or completions +- Move handling for each individual members of 'union message_body' out + into a separate 'struct work_struct' and completely remove the multiplexer + that is currently part of host_if_work(), allowing movement of the + implementation of each message handler into the callsite of the function + that currently queues the 'host_if_msg'. - make spi and sdio components coexist in one build - turn compile-time platform configuration (BEAGLE_BOARD, PANDA_BOARD, PLAT_WMS8304, PLAT_RKXXXX, CUSTOMER_PLATFORM, ...) diff --git a/drivers/staging/wilc1000/host_interface.c b/drivers/staging/wilc1000/host_interface.c index a34a1bb..98b9e7d 100644 --- a/drivers/staging/wilc1000/host_interface.c +++ b/drivers/staging/wilc1000/host_interface.c @@ -4,6 +4,7 @@ #include #include #include +#include #include "host_interface.h" #include #include @@ -210,6 +211,7 @@ struct host_if_msg { u16 id; union message_body body; struct wilc_vif *vif; + struct work_struct work; }; struct join_bss_param { @@ -244,7 +246,7 @@ struct join_bss_param { static struct host_if_drv *terminated_handle; bool wilc_optaining_ip; static u8 P2P_LISTEN_STATE; -static struct task_struct *hif_thread_handler; +static struct workqueue_struct *hif_workqueue; static struct message_queue hif_msg_q; static struct completion hif_thread_comp; static struct completion hif_driver_comp; @@ -279,55 +281,7 @@ static struct wilc_vif *join_req_vif; static void *host_int_ParseJoinBssParam(struct network_info *ptstrNetworkInfo); static int host_int_get_ipaddress(struct wilc_vif *vif, u8 *ip_addr, u8 idx); static s32 Handle_ScanDone(struct wilc_vif *vif, enum scan_event enuEvent); -static int wilc_mq_create(struct message_queue *mq); -static int wilc_mq_send(struct message_queue *mq, - const void *send_buf, u32 send_buf_size); -static int wilc_mq_recv(struct message_queue *mq, - void *recv_buf, u32 recv_buf_size, u32 *recv_len); -static int wilc_mq_destroy(struct message_queue *mq); - -/*! - * @author syounan - * @date 1 Sep 2010 - * @note copied from FLO glue implementatuion - * @version 1.0 - */ -static int wilc_mq_create(struct message_queue *mq) -{ - spin_lock_init(&mq->lock); - sema_init(&mq->sem, 0); - INIT_LIST_HEAD(&mq->msg_list); - mq->recv_count = 0; - mq->exiting = false; - return 0; -} - -/*! - * @author syounan - * @date 1 Sep 2010 - * @note copied from FLO glue implementatuion - * @version 1.0 - */ -static int wilc_mq_destroy(struct message_queue *mq) -{ - struct message *msg; - - mq->exiting = true; - - /* Release any waiting receiver thread. */ - while (mq->recv_count > 0) { - up(&mq->sem); - mq->recv_count--; - } - - while (!list_empty(&mq->msg_list)) { - msg = list_first_entry(&mq->msg_list, struct message, list); - list_del(&msg->list); - kfree(msg->buf); - } - - return 0; -} +static void host_if_work(struct work_struct *work); /*! * @author syounan @@ -338,92 +292,17 @@ static int wilc_mq_destroy(struct message_queue *mq) static int wilc_mq_send(struct message_queue *mq, const void *send_buf, u32 send_buf_size) { - unsigned long flags; - struct message *new_msg = NULL; + struct host_if_msg *new_msg; - if (!mq || (send_buf_size == 0) || !send_buf) - return -EINVAL; - - if (mq->exiting) - return -EFAULT; - - /* construct a new message */ - new_msg = kmalloc(sizeof(*new_msg), GFP_ATOMIC); + new_msg = kmemdup(send_buf, sizeof(*new_msg), GFP_ATOMIC); if (!new_msg) return -ENOMEM; - new_msg->len = send_buf_size; - INIT_LIST_HEAD(&new_msg->list); - new_msg->buf = kmemdup(send_buf, send_buf_size, GFP_ATOMIC); - if (!new_msg->buf) { - kfree(new_msg); - return -ENOMEM; - } - - spin_lock_irqsave(&mq->lock, flags); - - /* add it to the message queue */ - list_add_tail(&new_msg->list, &mq->msg_list); - - spin_unlock_irqrestore(&mq->lock, flags); - - up(&mq->sem); - + INIT_WORK(&new_msg->work, host_if_work); + queue_work(hif_workqueue, &new_msg->work); return 0; } -/*! - * @author syounan - * @date 1 Sep 2010 - * @note copied from FLO glue implementatuion - * @version 1.0 - */ -static int wilc_mq_recv(struct message_queue *mq, - void *recv_buf, u32 recv_buf_size, u32 *recv_len) -{ - struct message *msg; - unsigned long flags; - - if (!mq || (recv_buf_size == 0) || !recv_buf || !recv_len) - return -EINVAL; - - if (mq->exiting) - return -EFAULT; - - spin_lock_irqsave(&mq->lock, flags); - mq->recv_count++; - spin_unlock_irqrestore(&mq->lock, flags); - - down(&mq->sem); - spin_lock_irqsave(&mq->lock, flags); - - if (list_empty(&mq->msg_list)) { - spin_unlock_irqrestore(&mq->lock, flags); - up(&mq->sem); - return -EFAULT; - } - /* check buffer size */ - msg = list_first_entry(&mq->msg_list, struct message, list); - if (recv_buf_size < msg->len) { - spin_unlock_irqrestore(&mq->lock, flags); - up(&mq->sem); - return -EOVERFLOW; - } - - /* consume the message */ - mq->recv_count--; - memcpy(recv_buf, msg->buf, msg->len); - *recv_len = msg->len; - - list_del(&msg->list); - - kfree(msg->buf); - kfree(msg); - - spin_unlock_irqrestore(&mq->lock, flags); - - return 0; -} /* The u8IfIdx starts from 0 to NUM_CONCURRENT_IFC -1, but 0 index used as * special purpose in wilc device, so we add 1 to the index to starts from 1. @@ -2607,187 +2486,172 @@ static void handle_get_tx_pwr(struct wilc_vif *vif, u8 *tx_pwr) complete(&hif_wait_response); } -static int hostIFthread(void *pvArg) +static void host_if_work(struct work_struct *work) { - u32 u32Ret; - struct host_if_msg msg; - struct wilc *wilc = pvArg; - struct wilc_vif *vif; - - memset(&msg, 0, sizeof(struct host_if_msg)); + struct host_if_msg *msg; + struct wilc *wilc; - while (1) { - wilc_mq_recv(&hif_msg_q, &msg, sizeof(struct host_if_msg), &u32Ret); - vif = msg.vif; - if (msg.id == HOST_IF_MSG_EXIT) - break; + msg = container_of(work, struct host_if_msg, work); + wilc = msg->vif->wilc; - if ((!wilc_initialized)) { - usleep_range(200 * 1000, 200 * 1000); - wilc_mq_send(&hif_msg_q, &msg, sizeof(struct host_if_msg)); - continue; - } - - if (msg.id == HOST_IF_MSG_CONNECT && - vif->hif_drv->usr_scan_req.scan_result) { - wilc_mq_send(&hif_msg_q, &msg, sizeof(struct host_if_msg)); - usleep_range(2 * 1000, 2 * 1000); - continue; - } + if (msg->id == HOST_IF_MSG_CONNECT && + msg->vif->hif_drv->usr_scan_req.scan_result) { + wilc_mq_send(&hif_msg_q, msg, sizeof(struct host_if_msg)); + usleep_range(2 * 1000, 2 * 1000); + } else { - switch (msg.id) { + switch (msg->id) { case HOST_IF_MSG_SCAN: - handle_scan(msg.vif, &msg.body.scan_info); + handle_scan(msg->vif, &msg->body.scan_info); break; case HOST_IF_MSG_CONNECT: - Handle_Connect(msg.vif, &msg.body.con_info); + Handle_Connect(msg->vif, &msg->body.con_info); break; case HOST_IF_MSG_RCVD_NTWRK_INFO: - Handle_RcvdNtwrkInfo(msg.vif, &msg.body.net_info); + Handle_RcvdNtwrkInfo(msg->vif, &msg->body.net_info); break; case HOST_IF_MSG_RCVD_GNRL_ASYNC_INFO: - Handle_RcvdGnrlAsyncInfo(vif, - &msg.body.async_info); + Handle_RcvdGnrlAsyncInfo(msg->vif, + &msg->body.async_info); break; case HOST_IF_MSG_KEY: - Handle_Key(msg.vif, &msg.body.key_info); + Handle_Key(msg->vif, &msg->body.key_info); break; case HOST_IF_MSG_CFG_PARAMS: - handle_cfg_param(msg.vif, &msg.body.cfg_info); + handle_cfg_param(msg->vif, &msg->body.cfg_info); break; case HOST_IF_MSG_SET_CHANNEL: - handle_set_channel(msg.vif, &msg.body.channel_info); + handle_set_channel(msg->vif, &msg->body.channel_info); break; case HOST_IF_MSG_DISCONNECT: - Handle_Disconnect(msg.vif); + Handle_Disconnect(msg->vif); break; case HOST_IF_MSG_RCVD_SCAN_COMPLETE: - del_timer(&vif->hif_drv->scan_timer); + del_timer(&msg->vif->hif_drv->scan_timer); if (!wilc_wlan_get_num_conn_ifcs(wilc)) wilc_chip_sleep_manually(wilc); - Handle_ScanDone(msg.vif, SCAN_EVENT_DONE); + Handle_ScanDone(msg->vif, SCAN_EVENT_DONE); - if (vif->hif_drv->remain_on_ch_pending) - Handle_RemainOnChan(msg.vif, - &msg.body.remain_on_ch); + if (msg->vif->hif_drv->remain_on_ch_pending) + Handle_RemainOnChan(msg->vif, + &msg->body.remain_on_ch); break; case HOST_IF_MSG_GET_RSSI: - Handle_GetRssi(msg.vif); + Handle_GetRssi(msg->vif); break; case HOST_IF_MSG_GET_STATISTICS: - Handle_GetStatistics(msg.vif, - (struct rf_info *)msg.body.data); + Handle_GetStatistics(msg->vif, + (struct rf_info *)msg->body.data); break; case HOST_IF_MSG_ADD_BEACON: - Handle_AddBeacon(msg.vif, &msg.body.beacon_info); + Handle_AddBeacon(msg->vif, &msg->body.beacon_info); break; case HOST_IF_MSG_DEL_BEACON: - Handle_DelBeacon(msg.vif); + Handle_DelBeacon(msg->vif); break; case HOST_IF_MSG_ADD_STATION: - Handle_AddStation(msg.vif, &msg.body.add_sta_info); + Handle_AddStation(msg->vif, &msg->body.add_sta_info); break; case HOST_IF_MSG_DEL_STATION: - Handle_DelStation(msg.vif, &msg.body.del_sta_info); + Handle_DelStation(msg->vif, &msg->body.del_sta_info); break; case HOST_IF_MSG_EDIT_STATION: - Handle_EditStation(msg.vif, &msg.body.edit_sta_info); + Handle_EditStation(msg->vif, &msg->body.edit_sta_info); break; case HOST_IF_MSG_GET_INACTIVETIME: - Handle_Get_InActiveTime(msg.vif, &msg.body.mac_info); + Handle_Get_InActiveTime(msg->vif, &msg->body.mac_info); break; case HOST_IF_MSG_SCAN_TIMER_FIRED: - Handle_ScanDone(msg.vif, SCAN_EVENT_ABORTED); + Handle_ScanDone(msg->vif, SCAN_EVENT_ABORTED); break; case HOST_IF_MSG_CONNECT_TIMER_FIRED: - Handle_ConnectTimeout(msg.vif); + Handle_ConnectTimeout(msg->vif); break; case HOST_IF_MSG_POWER_MGMT: - Handle_PowerManagement(msg.vif, - &msg.body.pwr_mgmt_info); + Handle_PowerManagement(msg->vif, + &msg->body.pwr_mgmt_info); break; case HOST_IF_MSG_SET_WFIDRV_HANDLER: - handle_set_wfi_drv_handler(msg.vif, &msg.body.drv); + handle_set_wfi_drv_handler(msg->vif, &msg->body.drv); break; case HOST_IF_MSG_SET_OPERATION_MODE: - handle_set_operation_mode(msg.vif, &msg.body.mode); + handle_set_operation_mode(msg->vif, &msg->body.mode); break; case HOST_IF_MSG_SET_IPADDRESS: - handle_set_ip_address(vif, - msg.body.ip_info.ip_addr, - msg.body.ip_info.idx); + handle_set_ip_address(msg->vif, + msg->body.ip_info.ip_addr, + msg->body.ip_info.idx); break; case HOST_IF_MSG_GET_IPADDRESS: - handle_get_ip_address(vif, msg.body.ip_info.idx); + handle_get_ip_address(msg->vif, msg->body.ip_info.idx); break; case HOST_IF_MSG_GET_MAC_ADDRESS: - handle_get_mac_address(msg.vif, - &msg.body.get_mac_info); + handle_get_mac_address(msg->vif, + &msg->body.get_mac_info); break; case HOST_IF_MSG_REMAIN_ON_CHAN: - Handle_RemainOnChan(msg.vif, &msg.body.remain_on_ch); + Handle_RemainOnChan(msg->vif, &msg->body.remain_on_ch); break; case HOST_IF_MSG_REGISTER_FRAME: - Handle_RegisterFrame(msg.vif, &msg.body.reg_frame); + Handle_RegisterFrame(msg->vif, &msg->body.reg_frame); break; case HOST_IF_MSG_LISTEN_TIMER_FIRED: - Handle_ListenStateExpired(msg.vif, &msg.body.remain_on_ch); + Handle_ListenStateExpired(msg->vif, &msg->body.remain_on_ch); break; case HOST_IF_MSG_SET_MULTICAST_FILTER: - Handle_SetMulticastFilter(msg.vif, &msg.body.multicast_info); + Handle_SetMulticastFilter(msg->vif, &msg->body.multicast_info); break; case HOST_IF_MSG_DEL_ALL_STA: - Handle_DelAllSta(msg.vif, &msg.body.del_all_sta_info); + Handle_DelAllSta(msg->vif, &msg->body.del_all_sta_info); break; case HOST_IF_MSG_SET_TX_POWER: - handle_set_tx_pwr(msg.vif, msg.body.tx_power.tx_pwr); + handle_set_tx_pwr(msg->vif, msg->body.tx_power.tx_pwr); break; case HOST_IF_MSG_GET_TX_POWER: - handle_get_tx_pwr(msg.vif, &msg.body.tx_power.tx_pwr); + handle_get_tx_pwr(msg->vif, &msg->body.tx_power.tx_pwr); break; default: - netdev_err(vif->ndev, "[Host Interface] undefined\n"); + netdev_err(msg->vif->ndev, "[Host Interface] undefined\n"); break; } } - + kfree(msg); complete(&hif_thread_comp); - return 0; } static void TimerCB_Scan(unsigned long arg) @@ -3514,21 +3378,17 @@ int wilc_init(struct net_device *dev, struct host_if_drv **hif_drv_handler) init_completion(&hif_drv->comp_inactive_time); if (clients_count == 0) { - result = wilc_mq_create(&hif_msg_q); - if (result < 0) { netdev_err(vif->ndev, "Failed to creat MQ\n"); goto _fail_; } - - hif_thread_handler = kthread_run(hostIFthread, wilc, - "WILC_kthread"); - - if (IS_ERR(hif_thread_handler)) { - netdev_err(vif->ndev, "Failed to creat Thread\n"); - result = -EFAULT; + hif_workqueue = create_singlethread_workqueue("WILC_wq"); + if (!hif_workqueue) { + netdev_err(vif->ndev, "Failed to create workqueue\n"); + result = -ENOMEM; goto _fail_mq_; } + setup_timer(&periodic_rssi, GetPeriodicRSSI, (unsigned long)vif); mod_timer(&periodic_rssi, jiffies + msecs_to_jiffies(5000)); @@ -3554,10 +3414,8 @@ int wilc_init(struct net_device *dev, struct host_if_drv **hif_drv_handler) clients_count++; - return result; - _fail_mq_: - wilc_mq_destroy(&hif_msg_q); + destroy_workqueue(hif_workqueue); _fail_: return result; } @@ -3607,7 +3465,7 @@ int wilc_deinit(struct wilc_vif *vif) else wait_for_completion(&hif_thread_comp); - wilc_mq_destroy(&hif_msg_q); + destroy_workqueue(hif_workqueue); } kfree(hif_drv); -- cgit v0.10.2 From a5c84b2f67259e06d78e0dbf5ce55a9fdb77c084 Mon Sep 17 00:00:00 2001 From: Binoy Jayan Date: Thu, 23 Jun 2016 11:11:52 +0530 Subject: staging: wilc1000: Change interface wilc_mq_send to wilc_enqueue_cmd Replace the interface 'wilc_mq_send' with 'wilc_enqueue_cmd' and remove the now unused structures 'message' and 'message_queue'. Restructure switch statement in the work queue helper function host_if_work and remove unwanted indentation. Signed-off-by: Binoy Jayan Reviewed-by: Arnd Bergmann Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/wilc1000/host_interface.c b/drivers/staging/wilc1000/host_interface.c index 98b9e7d..bee693a 100644 --- a/drivers/staging/wilc1000/host_interface.c +++ b/drivers/staging/wilc1000/host_interface.c @@ -60,20 +60,6 @@ #define TCP_ACK_FILTER_LINK_SPEED_THRESH 54 #define DEFAULT_LINK_SPEED 72 -struct message { - void *buf; - u32 len; - struct list_head list; -}; - -struct message_queue { - struct semaphore sem; - spinlock_t lock; - bool exiting; - u32 recv_count; - struct list_head msg_list; -}; - struct host_if_wpa_attr { u8 *key; const u8 *mac_addr; @@ -247,7 +233,6 @@ static struct host_if_drv *terminated_handle; bool wilc_optaining_ip; static u8 P2P_LISTEN_STATE; static struct workqueue_struct *hif_workqueue; -static struct message_queue hif_msg_q; static struct completion hif_thread_comp; static struct completion hif_driver_comp; static struct completion hif_wait_response; @@ -289,12 +274,11 @@ static void host_if_work(struct work_struct *work); * @note copied from FLO glue implementatuion * @version 1.0 */ -static int wilc_mq_send(struct message_queue *mq, - const void *send_buf, u32 send_buf_size) +static int wilc_enqueue_cmd(struct host_if_msg *msg) { struct host_if_msg *new_msg; - new_msg = kmemdup(send_buf, sizeof(*new_msg), GFP_ATOMIC); + new_msg = kmemdup(msg, sizeof(*new_msg), GFP_ATOMIC); if (!new_msg) return -ENOMEM; @@ -2386,7 +2370,7 @@ static void ListenTimerCB(unsigned long arg) msg.vif = vif; msg.body.remain_on_ch.id = vif->hif_drv->remain_on_ch.id; - result = wilc_mq_send(&hif_msg_q, &msg, sizeof(struct host_if_msg)); + result = wilc_enqueue_cmd(&msg); if (result) netdev_err(vif->ndev, "wilc_mq_send fail\n"); } @@ -2496,160 +2480,159 @@ static void host_if_work(struct work_struct *work) if (msg->id == HOST_IF_MSG_CONNECT && msg->vif->hif_drv->usr_scan_req.scan_result) { - wilc_mq_send(&hif_msg_q, msg, sizeof(struct host_if_msg)); + wilc_enqueue_cmd(msg); usleep_range(2 * 1000, 2 * 1000); - } else { - - switch (msg->id) { - case HOST_IF_MSG_SCAN: - handle_scan(msg->vif, &msg->body.scan_info); - break; - - case HOST_IF_MSG_CONNECT: - Handle_Connect(msg->vif, &msg->body.con_info); - break; + goto free_msg; + } + switch (msg->id) { + case HOST_IF_MSG_SCAN: + handle_scan(msg->vif, &msg->body.scan_info); + break; - case HOST_IF_MSG_RCVD_NTWRK_INFO: - Handle_RcvdNtwrkInfo(msg->vif, &msg->body.net_info); - break; + case HOST_IF_MSG_CONNECT: + Handle_Connect(msg->vif, &msg->body.con_info); + break; - case HOST_IF_MSG_RCVD_GNRL_ASYNC_INFO: - Handle_RcvdGnrlAsyncInfo(msg->vif, - &msg->body.async_info); - break; + case HOST_IF_MSG_RCVD_NTWRK_INFO: + Handle_RcvdNtwrkInfo(msg->vif, &msg->body.net_info); + break; - case HOST_IF_MSG_KEY: - Handle_Key(msg->vif, &msg->body.key_info); - break; + case HOST_IF_MSG_RCVD_GNRL_ASYNC_INFO: + Handle_RcvdGnrlAsyncInfo(msg->vif, + &msg->body.async_info); + break; - case HOST_IF_MSG_CFG_PARAMS: - handle_cfg_param(msg->vif, &msg->body.cfg_info); - break; + case HOST_IF_MSG_KEY: + Handle_Key(msg->vif, &msg->body.key_info); + break; - case HOST_IF_MSG_SET_CHANNEL: - handle_set_channel(msg->vif, &msg->body.channel_info); - break; + case HOST_IF_MSG_CFG_PARAMS: + handle_cfg_param(msg->vif, &msg->body.cfg_info); + break; - case HOST_IF_MSG_DISCONNECT: - Handle_Disconnect(msg->vif); - break; + case HOST_IF_MSG_SET_CHANNEL: + handle_set_channel(msg->vif, &msg->body.channel_info); + break; - case HOST_IF_MSG_RCVD_SCAN_COMPLETE: - del_timer(&msg->vif->hif_drv->scan_timer); + case HOST_IF_MSG_DISCONNECT: + Handle_Disconnect(msg->vif); + break; - if (!wilc_wlan_get_num_conn_ifcs(wilc)) - wilc_chip_sleep_manually(wilc); + case HOST_IF_MSG_RCVD_SCAN_COMPLETE: + del_timer(&msg->vif->hif_drv->scan_timer); - Handle_ScanDone(msg->vif, SCAN_EVENT_DONE); + if (!wilc_wlan_get_num_conn_ifcs(wilc)) + wilc_chip_sleep_manually(wilc); - if (msg->vif->hif_drv->remain_on_ch_pending) - Handle_RemainOnChan(msg->vif, - &msg->body.remain_on_ch); + Handle_ScanDone(msg->vif, SCAN_EVENT_DONE); - break; + if (msg->vif->hif_drv->remain_on_ch_pending) + Handle_RemainOnChan(msg->vif, + &msg->body.remain_on_ch); - case HOST_IF_MSG_GET_RSSI: - Handle_GetRssi(msg->vif); - break; + break; - case HOST_IF_MSG_GET_STATISTICS: - Handle_GetStatistics(msg->vif, - (struct rf_info *)msg->body.data); - break; + case HOST_IF_MSG_GET_RSSI: + Handle_GetRssi(msg->vif); + break; - case HOST_IF_MSG_ADD_BEACON: - Handle_AddBeacon(msg->vif, &msg->body.beacon_info); - break; + case HOST_IF_MSG_GET_STATISTICS: + Handle_GetStatistics(msg->vif, + (struct rf_info *)msg->body.data); + break; - case HOST_IF_MSG_DEL_BEACON: - Handle_DelBeacon(msg->vif); - break; + case HOST_IF_MSG_ADD_BEACON: + Handle_AddBeacon(msg->vif, &msg->body.beacon_info); + break; - case HOST_IF_MSG_ADD_STATION: - Handle_AddStation(msg->vif, &msg->body.add_sta_info); - break; + case HOST_IF_MSG_DEL_BEACON: + Handle_DelBeacon(msg->vif); + break; - case HOST_IF_MSG_DEL_STATION: - Handle_DelStation(msg->vif, &msg->body.del_sta_info); - break; + case HOST_IF_MSG_ADD_STATION: + Handle_AddStation(msg->vif, &msg->body.add_sta_info); + break; - case HOST_IF_MSG_EDIT_STATION: - Handle_EditStation(msg->vif, &msg->body.edit_sta_info); - break; + case HOST_IF_MSG_DEL_STATION: + Handle_DelStation(msg->vif, &msg->body.del_sta_info); + break; - case HOST_IF_MSG_GET_INACTIVETIME: - Handle_Get_InActiveTime(msg->vif, &msg->body.mac_info); - break; + case HOST_IF_MSG_EDIT_STATION: + Handle_EditStation(msg->vif, &msg->body.edit_sta_info); + break; - case HOST_IF_MSG_SCAN_TIMER_FIRED: + case HOST_IF_MSG_GET_INACTIVETIME: + Handle_Get_InActiveTime(msg->vif, &msg->body.mac_info); + break; - Handle_ScanDone(msg->vif, SCAN_EVENT_ABORTED); - break; + case HOST_IF_MSG_SCAN_TIMER_FIRED: + Handle_ScanDone(msg->vif, SCAN_EVENT_ABORTED); + break; - case HOST_IF_MSG_CONNECT_TIMER_FIRED: - Handle_ConnectTimeout(msg->vif); - break; + case HOST_IF_MSG_CONNECT_TIMER_FIRED: + Handle_ConnectTimeout(msg->vif); + break; - case HOST_IF_MSG_POWER_MGMT: - Handle_PowerManagement(msg->vif, - &msg->body.pwr_mgmt_info); - break; + case HOST_IF_MSG_POWER_MGMT: + Handle_PowerManagement(msg->vif, + &msg->body.pwr_mgmt_info); + break; - case HOST_IF_MSG_SET_WFIDRV_HANDLER: - handle_set_wfi_drv_handler(msg->vif, &msg->body.drv); - break; + case HOST_IF_MSG_SET_WFIDRV_HANDLER: + handle_set_wfi_drv_handler(msg->vif, &msg->body.drv); + break; - case HOST_IF_MSG_SET_OPERATION_MODE: - handle_set_operation_mode(msg->vif, &msg->body.mode); - break; + case HOST_IF_MSG_SET_OPERATION_MODE: + handle_set_operation_mode(msg->vif, &msg->body.mode); + break; - case HOST_IF_MSG_SET_IPADDRESS: - handle_set_ip_address(msg->vif, - msg->body.ip_info.ip_addr, - msg->body.ip_info.idx); - break; + case HOST_IF_MSG_SET_IPADDRESS: + handle_set_ip_address(msg->vif, + msg->body.ip_info.ip_addr, + msg->body.ip_info.idx); + break; - case HOST_IF_MSG_GET_IPADDRESS: - handle_get_ip_address(msg->vif, msg->body.ip_info.idx); - break; + case HOST_IF_MSG_GET_IPADDRESS: + handle_get_ip_address(msg->vif, msg->body.ip_info.idx); + break; - case HOST_IF_MSG_GET_MAC_ADDRESS: - handle_get_mac_address(msg->vif, - &msg->body.get_mac_info); - break; + case HOST_IF_MSG_GET_MAC_ADDRESS: + handle_get_mac_address(msg->vif, + &msg->body.get_mac_info); + break; - case HOST_IF_MSG_REMAIN_ON_CHAN: - Handle_RemainOnChan(msg->vif, &msg->body.remain_on_ch); - break; + case HOST_IF_MSG_REMAIN_ON_CHAN: + Handle_RemainOnChan(msg->vif, &msg->body.remain_on_ch); + break; - case HOST_IF_MSG_REGISTER_FRAME: - Handle_RegisterFrame(msg->vif, &msg->body.reg_frame); - break; + case HOST_IF_MSG_REGISTER_FRAME: + Handle_RegisterFrame(msg->vif, &msg->body.reg_frame); + break; - case HOST_IF_MSG_LISTEN_TIMER_FIRED: - Handle_ListenStateExpired(msg->vif, &msg->body.remain_on_ch); - break; + case HOST_IF_MSG_LISTEN_TIMER_FIRED: + Handle_ListenStateExpired(msg->vif, &msg->body.remain_on_ch); + break; - case HOST_IF_MSG_SET_MULTICAST_FILTER: - Handle_SetMulticastFilter(msg->vif, &msg->body.multicast_info); - break; + case HOST_IF_MSG_SET_MULTICAST_FILTER: + Handle_SetMulticastFilter(msg->vif, &msg->body.multicast_info); + break; - case HOST_IF_MSG_DEL_ALL_STA: - Handle_DelAllSta(msg->vif, &msg->body.del_all_sta_info); - break; + case HOST_IF_MSG_DEL_ALL_STA: + Handle_DelAllSta(msg->vif, &msg->body.del_all_sta_info); + break; - case HOST_IF_MSG_SET_TX_POWER: - handle_set_tx_pwr(msg->vif, msg->body.tx_power.tx_pwr); - break; + case HOST_IF_MSG_SET_TX_POWER: + handle_set_tx_pwr(msg->vif, msg->body.tx_power.tx_pwr); + break; - case HOST_IF_MSG_GET_TX_POWER: - handle_get_tx_pwr(msg->vif, &msg->body.tx_power.tx_pwr); - break; - default: - netdev_err(msg->vif->ndev, "[Host Interface] undefined\n"); - break; - } + case HOST_IF_MSG_GET_TX_POWER: + handle_get_tx_pwr(msg->vif, &msg->body.tx_power.tx_pwr); + break; + default: + netdev_err(msg->vif->ndev, "[Host Interface] undefined\n"); + break; } +free_msg: kfree(msg); complete(&hif_thread_comp); } @@ -2663,7 +2646,7 @@ static void TimerCB_Scan(unsigned long arg) msg.vif = vif; msg.id = HOST_IF_MSG_SCAN_TIMER_FIRED; - wilc_mq_send(&hif_msg_q, &msg, sizeof(struct host_if_msg)); + wilc_enqueue_cmd(&msg); } static void TimerCB_Connect(unsigned long arg) @@ -2675,7 +2658,7 @@ static void TimerCB_Connect(unsigned long arg) msg.vif = vif; msg.id = HOST_IF_MSG_CONNECT_TIMER_FIRED; - wilc_mq_send(&hif_msg_q, &msg, sizeof(struct host_if_msg)); + wilc_enqueue_cmd(&msg); } s32 wilc_remove_key(struct host_if_drv *hif_drv, const u8 *pu8StaAddress) @@ -2710,7 +2693,7 @@ int wilc_remove_wep_key(struct wilc_vif *vif, u8 index) msg.vif = vif; msg.body.key_info.attr.wep.index = index; - result = wilc_mq_send(&hif_msg_q, &msg, sizeof(struct host_if_msg)); + result = wilc_enqueue_cmd(&msg); if (result) netdev_err(vif->ndev, "Request to remove WEP key\n"); else @@ -2739,7 +2722,7 @@ int wilc_set_wep_default_keyid(struct wilc_vif *vif, u8 index) msg.vif = vif; msg.body.key_info.attr.wep.index = index; - result = wilc_mq_send(&hif_msg_q, &msg, sizeof(struct host_if_msg)); + result = wilc_enqueue_cmd(&msg); if (result) netdev_err(vif->ndev, "Default key index\n"); else @@ -2773,7 +2756,7 @@ int wilc_add_wep_key_bss_sta(struct wilc_vif *vif, const u8 *key, u8 len, msg.body.key_info.attr.wep.key_len = len; msg.body.key_info.attr.wep.index = index; - result = wilc_mq_send(&hif_msg_q, &msg, sizeof(struct host_if_msg)); + result = wilc_enqueue_cmd(&msg); if (result) netdev_err(vif->ndev, "STA - WEP Key\n"); wait_for_completion(&hif_drv->comp_test_key_block); @@ -2808,7 +2791,7 @@ int wilc_add_wep_key_bss_ap(struct wilc_vif *vif, const u8 *key, u8 len, msg.body.key_info.attr.wep.mode = mode; msg.body.key_info.attr.wep.auth_type = auth_type; - result = wilc_mq_send(&hif_msg_q, &msg, sizeof(struct host_if_msg)); + result = wilc_enqueue_cmd(&msg); if (result) netdev_err(vif->ndev, "AP - WEP Key\n"); @@ -2864,7 +2847,7 @@ int wilc_add_ptk(struct wilc_vif *vif, const u8 *ptk, u8 ptk_key_len, msg.body.key_info.attr.wpa.mode = cipher_mode; msg.vif = vif; - result = wilc_mq_send(&hif_msg_q, &msg, sizeof(struct host_if_msg)); + result = wilc_enqueue_cmd(&msg); if (result) netdev_err(vif->ndev, "PTK Key\n"); @@ -2933,7 +2916,7 @@ int wilc_add_rx_gtk(struct wilc_vif *vif, const u8 *rx_gtk, u8 gtk_key_len, msg.body.key_info.attr.wpa.key_len = key_len; msg.body.key_info.attr.wpa.seq_len = key_rsc_len; - result = wilc_mq_send(&hif_msg_q, &msg, sizeof(struct host_if_msg)); + result = wilc_enqueue_cmd(&msg); if (result) netdev_err(vif->ndev, "RX GTK\n"); else @@ -2963,7 +2946,7 @@ int wilc_set_pmkid_info(struct wilc_vif *vif, &pmkid->pmkidlist[i].pmkid, PMKID_LEN); } - result = wilc_mq_send(&hif_msg_q, &msg, sizeof(struct host_if_msg)); + result = wilc_enqueue_cmd(&msg); if (result) netdev_err(vif->ndev, "PMKID Info\n"); @@ -2981,7 +2964,7 @@ int wilc_get_mac_address(struct wilc_vif *vif, u8 *mac_addr) msg.body.get_mac_info.mac_addr = mac_addr; msg.vif = vif; - result = wilc_mq_send(&hif_msg_q, &msg, sizeof(struct host_if_msg)); + result = wilc_enqueue_cmd(&msg); if (result) { netdev_err(vif->ndev, "Failed to send get mac address\n"); return -EFAULT; @@ -3045,7 +3028,7 @@ int wilc_set_join_req(struct wilc_vif *vif, u8 *bssid, const u8 *ssid, if (hif_drv->hif_state < HOST_IF_CONNECTING) hif_drv->hif_state = HOST_IF_CONNECTING; - result = wilc_mq_send(&hif_msg_q, &msg, sizeof(struct host_if_msg)); + result = wilc_enqueue_cmd(&msg); if (result) { netdev_err(vif->ndev, "send message: Set join request\n"); return -EFAULT; @@ -3074,7 +3057,7 @@ int wilc_disconnect(struct wilc_vif *vif, u16 reason_code) msg.id = HOST_IF_MSG_DISCONNECT; msg.vif = vif; - result = wilc_mq_send(&hif_msg_q, &msg, sizeof(struct host_if_msg)); + result = wilc_enqueue_cmd(&msg); if (result) netdev_err(vif->ndev, "Failed to send message: disconnect\n"); else @@ -3118,7 +3101,7 @@ int wilc_set_mac_chnl_num(struct wilc_vif *vif, u8 channel) msg.body.channel_info.set_ch = channel; msg.vif = vif; - result = wilc_mq_send(&hif_msg_q, &msg, sizeof(struct host_if_msg)); + result = wilc_enqueue_cmd(&msg); if (result) { netdev_err(vif->ndev, "wilc mq send fail\n"); return -EINVAL; @@ -3138,7 +3121,7 @@ int wilc_set_wfi_drv_handler(struct wilc_vif *vif, int index, u8 mac_idx) msg.body.drv.mac_idx = mac_idx; msg.vif = vif; - result = wilc_mq_send(&hif_msg_q, &msg, sizeof(struct host_if_msg)); + result = wilc_enqueue_cmd(&msg); if (result) { netdev_err(vif->ndev, "wilc mq send fail\n"); result = -EINVAL; @@ -3157,7 +3140,7 @@ int wilc_set_operation_mode(struct wilc_vif *vif, u32 mode) msg.body.mode.mode = mode; msg.vif = vif; - result = wilc_mq_send(&hif_msg_q, &msg, sizeof(struct host_if_msg)); + result = wilc_enqueue_cmd(&msg); if (result) { netdev_err(vif->ndev, "wilc mq send fail\n"); result = -EINVAL; @@ -3184,7 +3167,7 @@ s32 wilc_get_inactive_time(struct wilc_vif *vif, const u8 *mac, msg.id = HOST_IF_MSG_GET_INACTIVETIME; msg.vif = vif; - result = wilc_mq_send(&hif_msg_q, &msg, sizeof(struct host_if_msg)); + result = wilc_enqueue_cmd(&msg); if (result) netdev_err(vif->ndev, "Failed to send get host ch param\n"); else @@ -3205,7 +3188,7 @@ int wilc_get_rssi(struct wilc_vif *vif, s8 *rssi_level) msg.id = HOST_IF_MSG_GET_RSSI; msg.vif = vif; - result = wilc_mq_send(&hif_msg_q, &msg, sizeof(struct host_if_msg)); + result = wilc_enqueue_cmd(&msg); if (result) { netdev_err(vif->ndev, "Failed to send get host ch param\n"); return -EFAULT; @@ -3233,7 +3216,7 @@ int wilc_get_statistics(struct wilc_vif *vif, struct rf_info *stats) msg.body.data = (char *)stats; msg.vif = vif; - result = wilc_mq_send(&hif_msg_q, &msg, sizeof(struct host_if_msg)); + result = wilc_enqueue_cmd(&msg); if (result) { netdev_err(vif->ndev, "Failed to send get host channel\n"); return -EFAULT; @@ -3286,7 +3269,7 @@ int wilc_scan(struct wilc_vif *vif, u8 scan_source, u8 scan_type, if (!scan_info->ies) return -ENOMEM; - result = wilc_mq_send(&hif_msg_q, &msg, sizeof(struct host_if_msg)); + result = wilc_enqueue_cmd(&msg); if (result) { netdev_err(vif->ndev, "Error in sending message queue\n"); return -EINVAL; @@ -3316,7 +3299,7 @@ int wilc_hif_set_cfg(struct wilc_vif *vif, msg.body.cfg_info = *cfg_param; msg.vif = vif; - result = wilc_mq_send(&hif_msg_q, &msg, sizeof(struct host_if_msg)); + result = wilc_enqueue_cmd(&msg); return result; } @@ -3459,7 +3442,7 @@ int wilc_deinit(struct wilc_vif *vif) msg.id = HOST_IF_MSG_EXIT; msg.vif = vif; - result = wilc_mq_send(&hif_msg_q, &msg, sizeof(struct host_if_msg)); + result = wilc_enqueue_cmd(&msg); if (result != 0) netdev_err(vif->ndev, "deinit : Error(%d)\n", result); else @@ -3505,7 +3488,7 @@ void wilc_network_info_received(struct wilc *wilc, u8 *pu8Buffer, msg.body.net_info.buffer = kmalloc(u32Length, GFP_KERNEL); memcpy(msg.body.net_info.buffer, pu8Buffer, u32Length); - result = wilc_mq_send(&hif_msg_q, &msg, sizeof(struct host_if_msg)); + result = wilc_enqueue_cmd(&msg); if (result) netdev_err(vif->ndev, "message parameters (%d)\n", result); } @@ -3550,7 +3533,7 @@ void wilc_gnrl_async_info_received(struct wilc *wilc, u8 *pu8Buffer, msg.body.async_info.buffer = kmalloc(u32Length, GFP_KERNEL); memcpy(msg.body.async_info.buffer, pu8Buffer, u32Length); - result = wilc_mq_send(&hif_msg_q, &msg, sizeof(struct host_if_msg)); + result = wilc_enqueue_cmd(&msg); if (result) netdev_err(vif->ndev, "synchronous info (%d)\n", result); @@ -3581,7 +3564,7 @@ void wilc_scan_complete_received(struct wilc *wilc, u8 *pu8Buffer, msg.id = HOST_IF_MSG_RCVD_SCAN_COMPLETE; msg.vif = vif; - result = wilc_mq_send(&hif_msg_q, &msg, sizeof(struct host_if_msg)); + result = wilc_enqueue_cmd(&msg); if (result) netdev_err(vif->ndev, "complete param (%d)\n", result); } @@ -3607,7 +3590,7 @@ int wilc_remain_on_channel(struct wilc_vif *vif, u32 session_id, msg.body.remain_on_ch.id = session_id; msg.vif = vif; - result = wilc_mq_send(&hif_msg_q, &msg, sizeof(struct host_if_msg)); + result = wilc_enqueue_cmd(&msg); if (result) netdev_err(vif->ndev, "wilc mq send fail\n"); @@ -3632,7 +3615,7 @@ int wilc_listen_state_expired(struct wilc_vif *vif, u32 session_id) msg.vif = vif; msg.body.remain_on_ch.id = session_id; - result = wilc_mq_send(&hif_msg_q, &msg, sizeof(struct host_if_msg)); + result = wilc_enqueue_cmd(&msg); if (result) netdev_err(vif->ndev, "wilc mq send fail\n"); @@ -3663,7 +3646,7 @@ int wilc_frame_register(struct wilc_vif *vif, u16 frame_type, bool reg) msg.body.reg_frame.reg = reg; msg.vif = vif; - result = wilc_mq_send(&hif_msg_q, &msg, sizeof(struct host_if_msg)); + result = wilc_enqueue_cmd(&msg); if (result) netdev_err(vif->ndev, "wilc mq send fail\n"); @@ -3701,7 +3684,7 @@ int wilc_add_beacon(struct wilc_vif *vif, u32 interval, u32 dtim_period, beacon_info->tail = NULL; } - result = wilc_mq_send(&hif_msg_q, &msg, sizeof(struct host_if_msg)); + result = wilc_enqueue_cmd(&msg); if (result) netdev_err(vif->ndev, "wilc mq send fail\n"); @@ -3723,7 +3706,7 @@ int wilc_del_beacon(struct wilc_vif *vif) msg.id = HOST_IF_MSG_DEL_BEACON; msg.vif = vif; - result = wilc_mq_send(&hif_msg_q, &msg, sizeof(struct host_if_msg)); + result = wilc_enqueue_cmd(&msg); if (result) netdev_err(vif->ndev, "wilc_mq_send fail\n"); @@ -3750,7 +3733,7 @@ int wilc_add_station(struct wilc_vif *vif, struct add_sta_param *sta_param) return -ENOMEM; } - result = wilc_mq_send(&hif_msg_q, &msg, sizeof(struct host_if_msg)); + result = wilc_enqueue_cmd(&msg); if (result) netdev_err(vif->ndev, "wilc_mq_send fail\n"); return result; @@ -3772,7 +3755,7 @@ int wilc_del_station(struct wilc_vif *vif, const u8 *mac_addr) else memcpy(del_sta_info->mac_addr, mac_addr, ETH_ALEN); - result = wilc_mq_send(&hif_msg_q, &msg, sizeof(struct host_if_msg)); + result = wilc_enqueue_cmd(&msg); if (result) netdev_err(vif->ndev, "wilc_mq_send fail\n"); return result; @@ -3802,7 +3785,7 @@ int wilc_del_allstation(struct wilc_vif *vif, u8 mac_addr[][ETH_ALEN]) return result; del_all_sta_info->assoc_sta = assoc_sta; - result = wilc_mq_send(&hif_msg_q, &msg, sizeof(struct host_if_msg)); + result = wilc_enqueue_cmd(&msg); if (result) netdev_err(vif->ndev, "wilc_mq_send fail\n"); @@ -3833,7 +3816,7 @@ int wilc_edit_station(struct wilc_vif *vif, return -ENOMEM; } - result = wilc_mq_send(&hif_msg_q, &msg, sizeof(struct host_if_msg)); + result = wilc_enqueue_cmd(&msg); if (result) netdev_err(vif->ndev, "wilc_mq_send fail\n"); @@ -3857,7 +3840,7 @@ int wilc_set_power_mgmt(struct wilc_vif *vif, bool enabled, u32 timeout) pwr_mgmt_info->enabled = enabled; pwr_mgmt_info->timeout = timeout; - result = wilc_mq_send(&hif_msg_q, &msg, sizeof(struct host_if_msg)); + result = wilc_enqueue_cmd(&msg); if (result) netdev_err(vif->ndev, "wilc_mq_send fail\n"); return result; @@ -3878,7 +3861,7 @@ int wilc_setup_multicast_filter(struct wilc_vif *vif, bool enabled, multicast_filter_param->enabled = enabled; multicast_filter_param->cnt = count; - result = wilc_mq_send(&hif_msg_q, &msg, sizeof(struct host_if_msg)); + result = wilc_enqueue_cmd(&msg); if (result) netdev_err(vif->ndev, "wilc_mq_send fail\n"); return result; @@ -4051,7 +4034,7 @@ int wilc_setup_ipaddress(struct wilc_vif *vif, u8 *ip_addr, u8 idx) msg.vif = vif; msg.body.ip_info.idx = idx; - result = wilc_mq_send(&hif_msg_q, &msg, sizeof(struct host_if_msg)); + result = wilc_enqueue_cmd(&msg); if (result) netdev_err(vif->ndev, "wilc_mq_send fail\n"); @@ -4071,7 +4054,7 @@ static int host_int_get_ipaddress(struct wilc_vif *vif, u8 *ip_addr, u8 idx) msg.vif = vif; msg.body.ip_info.idx = idx; - result = wilc_mq_send(&hif_msg_q, &msg, sizeof(struct host_if_msg)); + result = wilc_enqueue_cmd(&msg); if (result) netdev_err(vif->ndev, "wilc_mq_send fail\n"); @@ -4089,7 +4072,7 @@ int wilc_set_tx_power(struct wilc_vif *vif, u8 tx_power) msg.body.tx_power.tx_pwr = tx_power; msg.vif = vif; - ret = wilc_mq_send(&hif_msg_q, &msg, sizeof(struct host_if_msg)); + ret = wilc_enqueue_cmd(&msg); if (ret) netdev_err(vif->ndev, "wilc_mq_send fail\n"); @@ -4106,7 +4089,7 @@ int wilc_get_tx_power(struct wilc_vif *vif, u8 *tx_power) msg.id = HOST_IF_MSG_GET_TX_POWER; msg.vif = vif; - ret = wilc_mq_send(&hif_msg_q, &msg, sizeof(struct host_if_msg)); + ret = wilc_enqueue_cmd(&msg); if (ret) netdev_err(vif->ndev, "Failed to get TX PWR\n"); -- cgit v0.10.2 From 4562d224edbe62e5620abbf49ffa8ceae2b73762 Mon Sep 17 00:00:00 2001 From: Luis de Bethencourt Date: Thu, 23 Jun 2016 18:57:09 +0100 Subject: staging: wilc1000: arrays can't be NULL hif_drv->usr_scan_req.net.net_info[i] contains found_net_info structs which have the following element: u8 bssid[6]; pstrNetworkInfo, of type network_info, also contains an u8 array named bssid. request->ssids is an array of cfg80211_ssid structs. Making ssid: u8 ssid[IEEE80211_MAX_SSID_LEN]; In these 3 cases the arrays are being checked against NULL, which can't happen. Removing the checks since they will always be true. Found with smatch: drivers/staging/wilc1000/host_interface.c:1234 Handle_RcvdNtwrkInfo() warn: this array is probably non-NULL. 'hif_drv->usr_scan_req.net_info[i].bssid' drivers/staging/wilc1000/host_interface.c:1235 Handle_RcvdNtwrkInfo() warn: this array is probably non-NULL. 'pstrNetworkInfo->bssid' drivers/staging/wilc1000/host_interface.c:1253 Handle_RcvdNtwrkInfo() warn: this array is probably non-NULL. 'hif_drv->usr_scan_req.net_info[hif_drv->usr_scan_req.rcvd_ch_cnt].bssid' drivers/staging/wilc1000/host_interface.c:1254 Handle_RcvdNtwrkInfo() warn: this array is probably non-NULL. 'pstrNetworkInfo->bssid' Signed-off-by: Luis de Bethencourt Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/wilc1000/host_interface.c b/drivers/staging/wilc1000/host_interface.c index bee693a..0b1760c 100644 --- a/drivers/staging/wilc1000/host_interface.c +++ b/drivers/staging/wilc1000/host_interface.c @@ -1237,17 +1237,14 @@ static s32 Handle_RcvdNtwrkInfo(struct wilc_vif *vif, } for (i = 0; i < hif_drv->usr_scan_req.rcvd_ch_cnt; i++) { - if ((hif_drv->usr_scan_req.net_info[i].bssid) && - (pstrNetworkInfo->bssid)) { - if (memcmp(hif_drv->usr_scan_req.net_info[i].bssid, - pstrNetworkInfo->bssid, 6) == 0) { - if (pstrNetworkInfo->rssi <= hif_drv->usr_scan_req.net_info[i].rssi) { - goto done; - } else { - hif_drv->usr_scan_req.net_info[i].rssi = pstrNetworkInfo->rssi; - bNewNtwrkFound = false; - break; - } + if (memcmp(hif_drv->usr_scan_req.net_info[i].bssid, + pstrNetworkInfo->bssid, 6) == 0) { + if (pstrNetworkInfo->rssi <= hif_drv->usr_scan_req.net_info[i].rssi) { + goto done; + } else { + hif_drv->usr_scan_req.net_info[i].rssi = pstrNetworkInfo->rssi; + bNewNtwrkFound = false; + break; } } } @@ -1256,20 +1253,17 @@ static s32 Handle_RcvdNtwrkInfo(struct wilc_vif *vif, if (hif_drv->usr_scan_req.rcvd_ch_cnt < MAX_NUM_SCANNED_NETWORKS) { hif_drv->usr_scan_req.net_info[hif_drv->usr_scan_req.rcvd_ch_cnt].rssi = pstrNetworkInfo->rssi; - if (hif_drv->usr_scan_req.net_info[hif_drv->usr_scan_req.rcvd_ch_cnt].bssid && - pstrNetworkInfo->bssid) { - memcpy(hif_drv->usr_scan_req.net_info[hif_drv->usr_scan_req.rcvd_ch_cnt].bssid, - pstrNetworkInfo->bssid, 6); + memcpy(hif_drv->usr_scan_req.net_info[hif_drv->usr_scan_req.rcvd_ch_cnt].bssid, + pstrNetworkInfo->bssid, 6); - hif_drv->usr_scan_req.rcvd_ch_cnt++; + hif_drv->usr_scan_req.rcvd_ch_cnt++; - pstrNetworkInfo->new_network = true; - pJoinParams = host_int_ParseJoinBssParam(pstrNetworkInfo); + pstrNetworkInfo->new_network = true; + pJoinParams = host_int_ParseJoinBssParam(pstrNetworkInfo); - hif_drv->usr_scan_req.scan_result(SCAN_EVENT_NETWORK_FOUND, pstrNetworkInfo, - hif_drv->usr_scan_req.arg, - pJoinParams); - } + hif_drv->usr_scan_req.scan_result(SCAN_EVENT_NETWORK_FOUND, pstrNetworkInfo, + hif_drv->usr_scan_req.arg, + pJoinParams); } } else { pstrNetworkInfo->new_network = false; diff --git a/drivers/staging/wilc1000/wilc_wfi_cfgoperations.c b/drivers/staging/wilc1000/wilc_wfi_cfgoperations.c index 51aff4f..3ddfa4a 100644 --- a/drivers/staging/wilc1000/wilc_wfi_cfgoperations.c +++ b/drivers/staging/wilc1000/wilc_wfi_cfgoperations.c @@ -625,8 +625,7 @@ static int scan(struct wiphy *wiphy, struct cfg80211_scan_request *request) for (i = 0; i < request->n_ssids; i++) { - if (request->ssids[i].ssid && - request->ssids[i].ssid_len != 0) { + if (request->ssids[i].ssid_len != 0) { strHiddenNetwork.net_info[i].ssid = kmalloc(request->ssids[i].ssid_len, GFP_KERNEL); memcpy(strHiddenNetwork.net_info[i].ssid, request->ssids[i].ssid, request->ssids[i].ssid_len); strHiddenNetwork.net_info[i].ssid_len = request->ssids[i].ssid_len; -- cgit v0.10.2 From b3e6916d6edfdf12505efbfb4a019e8a96f2c674 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Fri, 17 Jun 2016 17:34:17 +0000 Subject: staging: wilc1000: fix return value check in wlan_initialize_threads() In case of error, the function kthread_run() returns ERR_PTR() and never returns NULL. The NULL test in the return value check should be replaced with IS_ERR(). Signed-off-by: Wei Yongjun Reviewed-by: Julian Calaby Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/wilc1000/linux_wlan.c b/drivers/staging/wilc1000/linux_wlan.c index 2ce9df5..3a66255 100644 --- a/drivers/staging/wilc1000/linux_wlan.c +++ b/drivers/staging/wilc1000/linux_wlan.c @@ -715,10 +715,10 @@ static int wlan_initialize_threads(struct net_device *dev) wilc->txq_thread = kthread_run(linux_wlan_txq_task, (void *)dev, "K_TXQ_TASK"); - if (!wilc->txq_thread) { + if (IS_ERR(wilc->txq_thread)) { netdev_err(dev, "couldn't create TXQ thread\n"); wilc->close = 0; - return -ENOBUFS; + return PTR_ERR(wilc->txq_thread); } wait_for_completion(&wilc->txq_thread_started); -- cgit v0.10.2 From 81e43960dce1c8e58e682fb3ec26c1d8f83a9afc Mon Sep 17 00:00:00 2001 From: Bob Copeland Date: Sat, 25 Jun 2016 07:58:45 -0400 Subject: ALSA: hda - fix read before array start UBSAN reports the following warning from accessing path->path[-1] in set_path_power(): [ 16.078040] ================================================================================ [ 16.078124] UBSAN: Undefined behaviour in sound/pci/hda/hda_generic.c:3981:17 [ 16.078198] index -1 is out of range for type 'hda_nid_t [10]' [ 16.078270] CPU: 2 PID: 1738 Comm: modprobe Not tainted 4.7.0-rc1-wt+ #47 [ 16.078274] Hardware name: LENOVO 3443CTO/3443CTO, BIOS G6ET23WW (1.02 ) 08/14/2012 [ 16.078278] ffff8800cb246000 ffff8800cb3638b8 ffffffff815c4fe3 0000000000000032 [ 16.078286] ffff8800cb3638e0 ffffffffffffffff ffff8800cb3638d0 ffffffff8162443d [ 16.078294] ffffffffa0894200 ffff8800cb363920 ffffffff81624af7 0000000000000292 [ 16.078302] Call Trace: [ 16.078311] [] dump_stack+0x86/0xd3 [ 16.078317] [] ubsan_epilogue+0xd/0x40 [ 16.078324] [] __ubsan_handle_out_of_bounds+0x67/0x70 [ 16.078335] [] set_path_power+0x1bf/0x230 [snd_hda_codec_generic] [ 16.078344] [] add_pin_power_ctls+0x8d/0xc0 [snd_hda_codec_generic] [ 16.078352] [] ? pin_power_down_callback+0x20/0x20 [snd_hda_codec_generic] [ 16.078360] [] add_all_pin_power_ctls+0x107/0x150 [snd_hda_codec_generic] [ 16.078370] [] snd_hda_gen_parse_auto_config+0x2d73/0x49e0 [snd_hda_codec_generic] [ 16.078376] [] ? trace_hardirqs_on_caller+0x1b0/0x2c0 [ 16.078390] [] alc_parse_auto_config+0x147/0x310 [snd_hda_codec_realtek] [ 16.078402] [] patch_alc269+0x23a/0x560 [snd_hda_codec_realtek] [ 16.078417] [] hda_codec_driver_probe+0xa4/0x1a0 [snd_hda_codec] [ 16.078424] [] driver_probe_device+0x101/0x380 [ 16.078430] [] __driver_attach+0xb9/0x100 [ 16.078438] [] ? driver_probe_device+0x380/0x380 [ 16.078444] [] bus_for_each_dev+0x70/0xc0 [ 16.078449] [] driver_attach+0x27/0x50 [ 16.078454] [] bus_add_driver+0x166/0x2c0 [ 16.078460] [] ? 0xffffffffa0369000 [ 16.078465] [] driver_register+0x7d/0x130 [ 16.078477] [] __hda_codec_driver_register+0x6f/0x90 [snd_hda_codec] [ 16.078488] [] realtek_driver_init+0x1e/0x1000 [snd_hda_codec_realtek] [ 16.078493] [] do_one_initcall+0x4e/0x1d0 [ 16.078499] [] ? rcu_read_lock_sched_held+0x6d/0x80 [ 16.078504] [] ? kmem_cache_alloc_trace+0x391/0x560 [ 16.078510] [] ? do_init_module+0x28/0x273 [ 16.078515] [] do_init_module+0x9b/0x273 [ 16.078522] [] load_module+0x20b2/0x3410 [ 16.078527] [] ? m_show+0x210/0x210 [ 16.078533] [] ? kernel_read+0x66/0xe0 [ 16.078541] [] SYSC_finit_module+0xba/0xc0 [ 16.078547] [] SyS_finit_module+0xe/0x10 [ 16.078552] [] entry_SYSCALL_64_fastpath+0x1f/0xbd [ 16.078556] ================================================================================ Fix by checking path->depth before use. Signed-off-by: Bob Copeland Cc: Signed-off-by: Takashi Iwai diff --git a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c index 320445f..79c7b34 100644 --- a/sound/pci/hda/hda_generic.c +++ b/sound/pci/hda/hda_generic.c @@ -3977,6 +3977,8 @@ static hda_nid_t set_path_power(struct hda_codec *codec, hda_nid_t nid, for (n = 0; n < spec->paths.used; n++) { path = snd_array_elem(&spec->paths, n); + if (!path->depth) + continue; if (path->path[0] == nid || path->path[path->depth - 1] == nid) { bool pin_old = path->pin_enabled; -- cgit v0.10.2 From 65fe935dd2387a4faf15314c73f5e6d31ef0217e Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Mon, 13 Jun 2016 15:10:02 -0700 Subject: x86/KASLR, x86/power: Remove x86 hibernation restrictions With the following fix: 70595b479ce1 ("x86/power/64: Fix crash whan the hibernation code passes control to the image kernel") ... there is no longer a problem with hibernation resuming a KASLR-booted kernel image, so remove the restriction. Signed-off-by: Kees Cook Cc: Andy Lutomirski Cc: Baoquan He Cc: Borislav Petkov Cc: Brian Gerst Cc: Denys Vlasenko Cc: H. Peter Anvin Cc: Jonathan Corbet Cc: Len Brown Cc: Linus Torvalds Cc: Linux PM list Cc: Logan Gunthorpe Cc: Pavel Machek Cc: Peter Zijlstra Cc: Stephen Smalley Cc: Thomas Gleixner Cc: Yinghai Lu Cc: linux-doc@vger.kernel.org Link: http://lkml.kernel.org/r/20160613221002.GA29719@www.outflux.net Signed-off-by: Ingo Molnar diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index 82b42c9..fa8c6d4 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -1803,12 +1803,10 @@ bytes respectively. Such letter suffixes can also be entirely omitted. js= [HW,JOY] Analog joystick See Documentation/input/joystick.txt. - kaslr/nokaslr [X86] - Enable/disable kernel and module base offset ASLR - (Address Space Layout Randomization) if built into - the kernel. When CONFIG_HIBERNATION is selected, - kASLR is disabled by default. When kASLR is enabled, - hibernation will be disabled. + nokaslr [KNL] + When CONFIG_RANDOMIZE_BASE is set, this disables + kernel and module base offset ASLR (Address Space + Layout Randomization). keepinitrd [HW,ARM] diff --git a/arch/x86/boot/compressed/kaslr.c b/arch/x86/boot/compressed/kaslr.c index cfeb025..dff4217 100644 --- a/arch/x86/boot/compressed/kaslr.c +++ b/arch/x86/boot/compressed/kaslr.c @@ -471,17 +471,10 @@ unsigned char *choose_random_location(unsigned long input, unsigned long choice = output; unsigned long random_addr; -#ifdef CONFIG_HIBERNATION - if (!cmdline_find_option_bool("kaslr")) { - warn("KASLR disabled: 'kaslr' not on cmdline (hibernation selected)."); - goto out; - } -#else if (cmdline_find_option_bool("nokaslr")) { warn("KASLR disabled: 'nokaslr' on cmdline."); goto out; } -#endif boot_params->hdr.loadflags |= KASLR_FLAG; diff --git a/kernel/power/hibernate.c b/kernel/power/hibernate.c index fca9254..9021387 100644 --- a/kernel/power/hibernate.c +++ b/kernel/power/hibernate.c @@ -1154,11 +1154,6 @@ static int __init nohibernate_setup(char *str) return 1; } -static int __init kaslr_nohibernate_setup(char *str) -{ - return nohibernate_setup(str); -} - static int __init page_poison_nohibernate_setup(char *str) { #ifdef CONFIG_PAGE_POISONING_ZERO @@ -1182,5 +1177,4 @@ __setup("hibernate=", hibernate_setup); __setup("resumewait", resumewait_setup); __setup("resumedelay=", resumedelay_setup); __setup("nohibernate", nohibernate_setup); -__setup("kaslr", kaslr_nohibernate_setup); __setup("page_poison=", page_poison_nohibernate_setup); -- cgit v0.10.2 From 98f78525371b55ccd1c480207ce10296c72fa340 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Wed, 25 May 2016 15:45:30 -0700 Subject: x86/boot: Refuse to build with data relocations The compressed kernel is built with -fPIC/-fPIE so that it can run in any location a bootloader happens to put it. However, since ELF relocation processing is not happening (and all the relocation information has already been stripped at link time), none of the code can use data relocations (e.g. static assignments of pointers). This is already noted in a warning comment at the top of misc.c, but this adds an explicit check for the condition during the linking stage to block any such bugs from appearing. If this was in place with the earlier bug in pagetable.c, the build would fail like this: ... CC arch/x86/boot/compressed/pagetable.o DATAREL arch/x86/boot/compressed/vmlinux error: arch/x86/boot/compressed/pagetable.o has data relocations! make[2]: *** [arch/x86/boot/compressed/vmlinux] Error 1 ... A clean build shows: ... CC arch/x86/boot/compressed/pagetable.o DATAREL arch/x86/boot/compressed/vmlinux LD arch/x86/boot/compressed/vmlinux ... Suggested-by: Ingo Molnar Signed-off-by: Kees Cook Cc: Andrew Morton Cc: Andrey Ryabinin Cc: Andy Lutomirski Cc: Baoquan He Cc: Borislav Petkov Cc: Brian Gerst Cc: Denys Vlasenko Cc: Dmitry Vyukov Cc: H. Peter Anvin Cc: H.J. Lu Cc: Josh Poimboeuf Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: Yinghai Lu Link: http://lkml.kernel.org/r/1464216334-17200-2-git-send-email-keescook@chromium.org Signed-off-by: Ingo Molnar diff --git a/arch/x86/boot/compressed/Makefile b/arch/x86/boot/compressed/Makefile index f135688..536ccfc 100644 --- a/arch/x86/boot/compressed/Makefile +++ b/arch/x86/boot/compressed/Makefile @@ -85,7 +85,25 @@ vmlinux-objs-$(CONFIG_EFI_STUB) += $(obj)/eboot.o $(obj)/efi_stub_$(BITS).o \ $(objtree)/drivers/firmware/efi/libstub/lib.a vmlinux-objs-$(CONFIG_EFI_MIXED) += $(obj)/efi_thunk_$(BITS).o +# The compressed kernel is built with -fPIC/-fPIE so that a boot loader +# can place it anywhere in memory and it will still run. However, since +# it is executed as-is without any ELF relocation processing performed +# (and has already had all relocation sections stripped from the binary), +# none of the code can use data relocations (e.g. static assignments of +# pointer values), since they will be meaningless at runtime. This check +# will refuse to link the vmlinux if any of these relocations are found. +quiet_cmd_check_data_rel = DATAREL $@ +define cmd_check_data_rel + for obj in $(filter %.o,$^); do \ + readelf -S $$obj | grep -qF .rel.local && { \ + echo "error: $$obj has data relocations!" >&2; \ + exit 1; \ + } || true; \ + done +endef + $(obj)/vmlinux: $(vmlinux-objs-y) FORCE + $(call if_changed,check_data_rel) $(call if_changed,ld) OBJCOPYFLAGS_vmlinux.bin := -R .comment -S -- cgit v0.10.2 From 11fdf97a3cd1a5a27625f820ceb74e1caba4fd26 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Wed, 25 May 2016 15:45:31 -0700 Subject: x86/KASLR: Clarify identity map interface This extracts the call to prepare_level4() into a top-level function that the user of the pagetable.c interface must call to initialize the new page tables. For clarity and to match the "finalize" function, it has been renamed to initialize_identity_maps(). This function also gains the initialization of mapping_info so we don't have to do it each time in add_identity_map(). Additionally add copyright notice to the top, to make it clear that the bulk of the pagetable.c code was written by Yinghai, and that I just added bugs later. :) Signed-off-by: Kees Cook Cc: Andrew Morton Cc: Andrey Ryabinin Cc: Andy Lutomirski Cc: Baoquan He Cc: Borislav Petkov Cc: Brian Gerst Cc: Denys Vlasenko Cc: Dmitry Vyukov Cc: H. Peter Anvin Cc: H.J. Lu Cc: Josh Poimboeuf Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: Yinghai Lu Link: http://lkml.kernel.org/r/1464216334-17200-3-git-send-email-keescook@chromium.org Signed-off-by: Ingo Molnar diff --git a/arch/x86/boot/compressed/kaslr.c b/arch/x86/boot/compressed/kaslr.c index dff4217..54037c9 100644 --- a/arch/x86/boot/compressed/kaslr.c +++ b/arch/x86/boot/compressed/kaslr.c @@ -478,6 +478,9 @@ unsigned char *choose_random_location(unsigned long input, boot_params->hdr.loadflags |= KASLR_FLAG; + /* Prepare to add new identity pagetables on demand. */ + initialize_identity_maps(); + /* Record the various known unsafe memory ranges. */ mem_avoid_init(input, input_size, output); diff --git a/arch/x86/boot/compressed/misc.h b/arch/x86/boot/compressed/misc.h index b6fec1f..09c4ddd 100644 --- a/arch/x86/boot/compressed/misc.h +++ b/arch/x86/boot/compressed/misc.h @@ -85,10 +85,13 @@ unsigned char *choose_random_location(unsigned long input_ptr, #endif #ifdef CONFIG_X86_64 +void initialize_identity_maps(void); void add_identity_map(unsigned long start, unsigned long size); void finalize_identity_maps(void); extern unsigned char _pgtable[]; #else +static inline void initialize_identity_maps(void) +{ } static inline void add_identity_map(unsigned long start, unsigned long size) { } static inline void finalize_identity_maps(void) diff --git a/arch/x86/boot/compressed/pagetable.c b/arch/x86/boot/compressed/pagetable.c index 34b95df..6e31a6a 100644 --- a/arch/x86/boot/compressed/pagetable.c +++ b/arch/x86/boot/compressed/pagetable.c @@ -2,6 +2,9 @@ * This code is used on x86_64 to create page table identity mappings on * demand by building up a new set of page tables (or appending to the * existing ones), and then switching over to them when ready. + * + * Copyright (C) 2015-2016 Yinghai Lu + * Copyright (C) 2016 Kees Cook */ /* @@ -59,9 +62,21 @@ static struct alloc_pgt_data pgt_data; /* The top level page table entry pointer. */ static unsigned long level4p; +/* + * Mapping information structure passed to kernel_ident_mapping_init(). + * Due to relocation, pointers must be assigned at run time not build time. + */ +static struct x86_mapping_info mapping_info = { + .pmd_flag = __PAGE_KERNEL_LARGE_EXEC, +}; + /* Locates and clears a region for a new top level page table. */ -static void prepare_level4(void) +void initialize_identity_maps(void) { + /* Init mapping_info with run-time function/buffer pointers. */ + mapping_info.alloc_pgt_page = alloc_pgt_page; + mapping_info.context = &pgt_data; + /* * It should be impossible for this not to already be true, * but since calling this a second time would rewind the other @@ -96,17 +111,8 @@ static void prepare_level4(void) */ void add_identity_map(unsigned long start, unsigned long size) { - struct x86_mapping_info mapping_info = { - .alloc_pgt_page = alloc_pgt_page, - .context = &pgt_data, - .pmd_flag = __PAGE_KERNEL_LARGE_EXEC, - }; unsigned long end = start + size; - /* Make sure we have a top level page table ready to use. */ - if (!level4p) - prepare_level4(); - /* Align boundary to 2M. */ start = round_down(start, PMD_SIZE); end = round_up(end, PMD_SIZE); -- cgit v0.10.2 From 8391c73c96f28d4e8c40fd401fd0c9c04391b44a Mon Sep 17 00:00:00 2001 From: Baoquan He Date: Wed, 25 May 2016 15:45:32 -0700 Subject: x86/KASLR: Randomize virtual address separately The current KASLR implementation randomizes the physical and virtual addresses of the kernel together (both are offset by the same amount). It calculates the delta of the physical address where vmlinux was linked to load and where it is finally loaded. If the delta is not equal to 0 (i.e. the kernel was relocated), relocation handling needs be done. On 64-bit, this patch randomizes both the physical address where kernel is decompressed and the virtual address where kernel text is mapped and will execute from. We now have two values being chosen, so the function arguments are reorganized to pass by pointer so they can be directly updated. Since relocation handling only depends on the virtual address, we must check the virtual delta, not the physical delta for processing kernel relocations. This also populates the page table for the new virtual address range. 32-bit does not support a separate virtual address, so it continues to use the physical offset for its virtual offset. Additionally updates the sanity checks done on the resulting kernel addresses since they are potentially separate now. [kees: rewrote changelog, limited virtual split to 64-bit only, update checks] [kees: fix CONFIG_RANDOMIZE_BASE=n boot failure] Signed-off-by: Baoquan He Signed-off-by: Kees Cook Cc: Andrew Morton Cc: Andrey Ryabinin Cc: Andy Lutomirski Cc: Borislav Petkov Cc: Brian Gerst Cc: Denys Vlasenko Cc: Dmitry Vyukov Cc: H. Peter Anvin Cc: H.J. Lu Cc: Josh Poimboeuf Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: Yinghai Lu Link: http://lkml.kernel.org/r/1464216334-17200-4-git-send-email-keescook@chromium.org Signed-off-by: Ingo Molnar diff --git a/arch/x86/boot/compressed/kaslr.c b/arch/x86/boot/compressed/kaslr.c index 54037c9..5550546 100644 --- a/arch/x86/boot/compressed/kaslr.c +++ b/arch/x86/boot/compressed/kaslr.c @@ -463,17 +463,20 @@ static unsigned long find_random_virt_addr(unsigned long minimum, * Since this function examines addresses much more numerically, * it takes the input and output pointers as 'unsigned long'. */ -unsigned char *choose_random_location(unsigned long input, - unsigned long input_size, - unsigned long output, - unsigned long output_size) +void choose_random_location(unsigned long input, + unsigned long input_size, + unsigned long *output, + unsigned long output_size, + unsigned long *virt_addr) { - unsigned long choice = output; unsigned long random_addr; + /* By default, keep output position unchanged. */ + *virt_addr = *output; + if (cmdline_find_option_bool("nokaslr")) { warn("KASLR disabled: 'nokaslr' on cmdline."); - goto out; + return; } boot_params->hdr.loadflags |= KASLR_FLAG; @@ -482,25 +485,25 @@ unsigned char *choose_random_location(unsigned long input, initialize_identity_maps(); /* Record the various known unsafe memory ranges. */ - mem_avoid_init(input, input_size, output); + mem_avoid_init(input, input_size, *output); /* Walk e820 and find a random address. */ - random_addr = find_random_phys_addr(output, output_size); + random_addr = find_random_phys_addr(*output, output_size); if (!random_addr) { warn("KASLR disabled: could not find suitable E820 region!"); - goto out; + } else { + /* Update the new physical address location. */ + if (*output != random_addr) { + add_identity_map(random_addr, output_size); + *output = random_addr; + } } - /* Always enforce the minimum. */ - if (random_addr < choice) - goto out; - - choice = random_addr; - - add_identity_map(choice, output_size); - /* This actually loads the identity pagetable on x86_64. */ finalize_identity_maps(); -out: - return (unsigned char *)choice; + + /* Pick random virtual address starting from LOAD_PHYSICAL_ADDR. */ + if (IS_ENABLED(CONFIG_X86_64)) + random_addr = find_random_virt_addr(LOAD_PHYSICAL_ADDR, output_size); + *virt_addr = random_addr; } diff --git a/arch/x86/boot/compressed/misc.c b/arch/x86/boot/compressed/misc.c index f14db4e..b3c5a5f0 100644 --- a/arch/x86/boot/compressed/misc.c +++ b/arch/x86/boot/compressed/misc.c @@ -170,7 +170,8 @@ void __puthex(unsigned long value) } #if CONFIG_X86_NEED_RELOCS -static void handle_relocations(void *output, unsigned long output_len) +static void handle_relocations(void *output, unsigned long output_len, + unsigned long virt_addr) { int *reloc; unsigned long delta, map, ptr; @@ -182,11 +183,6 @@ static void handle_relocations(void *output, unsigned long output_len) * and where it was actually loaded. */ delta = min_addr - LOAD_PHYSICAL_ADDR; - if (!delta) { - debug_putstr("No relocation needed... "); - return; - } - debug_putstr("Performing relocations... "); /* * The kernel contains a table of relocation addresses. Those @@ -198,6 +194,20 @@ static void handle_relocations(void *output, unsigned long output_len) map = delta - __START_KERNEL_map; /* + * 32-bit always performs relocations. 64-bit relocations are only + * needed if KASLR has chosen a different starting address offset + * from __START_KERNEL_map. + */ + if (IS_ENABLED(CONFIG_X86_64)) + delta = virt_addr - LOAD_PHYSICAL_ADDR; + + if (!delta) { + debug_putstr("No relocation needed... "); + return; + } + debug_putstr("Performing relocations... "); + + /* * Process relocations: 32 bit relocations first then 64 bit after. * Three sets of binary relocations are added to the end of the kernel * before compression. Each relocation table entry is the kernel @@ -250,7 +260,8 @@ static void handle_relocations(void *output, unsigned long output_len) #endif } #else -static inline void handle_relocations(void *output, unsigned long output_len) +static inline void handle_relocations(void *output, unsigned long output_len, + unsigned long virt_addr) { } #endif @@ -327,7 +338,7 @@ asmlinkage __visible void *extract_kernel(void *rmode, memptr heap, unsigned long output_len) { const unsigned long kernel_total_size = VO__end - VO__text; - unsigned char *output_orig = output; + unsigned long virt_addr = (unsigned long)output; /* Retain x86 boot parameters pointer passed from startup_32/64. */ boot_params = rmode; @@ -366,13 +377,16 @@ asmlinkage __visible void *extract_kernel(void *rmode, memptr heap, * the entire decompressed kernel plus relocation table, or the * entire decompressed kernel plus .bss and .brk sections. */ - output = choose_random_location((unsigned long)input_data, input_len, - (unsigned long)output, - max(output_len, kernel_total_size)); + choose_random_location((unsigned long)input_data, input_len, + (unsigned long *)&output, + max(output_len, kernel_total_size), + &virt_addr); /* Validate memory location choices. */ if ((unsigned long)output & (MIN_KERNEL_ALIGN - 1)) - error("Destination address inappropriately aligned"); + error("Destination physical address inappropriately aligned"); + if (virt_addr & (MIN_KERNEL_ALIGN - 1)) + error("Destination virtual address inappropriately aligned"); #ifdef CONFIG_X86_64 if (heap > 0x3fffffffffffUL) error("Destination address too large"); @@ -382,19 +396,16 @@ asmlinkage __visible void *extract_kernel(void *rmode, memptr heap, #endif #ifndef CONFIG_RELOCATABLE if ((unsigned long)output != LOAD_PHYSICAL_ADDR) - error("Wrong destination address"); + error("Destination address does not match LOAD_PHYSICAL_ADDR"); + if ((unsigned long)output != virt_addr) + error("Destination virtual address changed when not relocatable"); #endif debug_putstr("\nDecompressing Linux... "); __decompress(input_data, input_len, NULL, NULL, output, output_len, NULL, error); parse_elf(output); - /* - * 32-bit always performs relocations. 64-bit relocations are only - * needed if kASLR has chosen a different load address. - */ - if (!IS_ENABLED(CONFIG_X86_64) || output != output_orig) - handle_relocations(output, output_len); + handle_relocations(output, output_len, virt_addr); debug_putstr("done.\nBooting the kernel.\n"); return output; } diff --git a/arch/x86/boot/compressed/misc.h b/arch/x86/boot/compressed/misc.h index 09c4ddd..1c8355e 100644 --- a/arch/x86/boot/compressed/misc.h +++ b/arch/x86/boot/compressed/misc.h @@ -67,20 +67,22 @@ int cmdline_find_option_bool(const char *option); #if CONFIG_RANDOMIZE_BASE /* kaslr.c */ -unsigned char *choose_random_location(unsigned long input_ptr, - unsigned long input_size, - unsigned long output_ptr, - unsigned long output_size); +void choose_random_location(unsigned long input, + unsigned long input_size, + unsigned long *output, + unsigned long output_size, + unsigned long *virt_addr); /* cpuflags.c */ bool has_cpuflag(int flag); #else -static inline -unsigned char *choose_random_location(unsigned long input_ptr, - unsigned long input_size, - unsigned long output_ptr, - unsigned long output_size) +static inline void choose_random_location(unsigned long input, + unsigned long input_size, + unsigned long *output, + unsigned long output_size, + unsigned long *virt_addr) { - return (unsigned char *)output_ptr; + /* No change from existing output location. */ + *virt_addr = *output; } #endif -- cgit v0.10.2 From ed9f007ee68478f6a50ec9971ade25a0129a5c0e Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Wed, 25 May 2016 15:45:33 -0700 Subject: x86/KASLR: Extend kernel image physical address randomization to addresses larger than 4G We want the physical address to be randomized anywhere between 16MB and the top of physical memory (up to 64TB). This patch exchanges the prior slots[] array for the new slot_areas[] array, and lifts the limitation of KERNEL_IMAGE_SIZE on the physical address offset for 64-bit. As before, process_e820_entry() walks memory and populates slot_areas[], splitting on any detected mem_avoid collisions. Finally, since the slots[] array and its associated functions are not needed any more, so they are removed. Based on earlier patches by Baoquan He. Originally-from: Baoquan He Signed-off-by: Kees Cook Cc: Andrew Morton Cc: Andrey Ryabinin Cc: Andy Lutomirski Cc: Baoquan He Cc: Borislav Petkov Cc: Brian Gerst Cc: Denys Vlasenko Cc: Dmitry Vyukov Cc: H. Peter Anvin Cc: H.J. Lu Cc: Josh Poimboeuf Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: Yinghai Lu Link: http://lkml.kernel.org/r/1464216334-17200-5-git-send-email-keescook@chromium.org Signed-off-by: Ingo Molnar diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 0a7b885..770ae52 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -1934,21 +1934,26 @@ config RANDOMIZE_BASE attempts relying on knowledge of the location of kernel code internals. - The kernel physical and virtual address can be randomized - from 16MB up to 1GB on 64-bit and 512MB on 32-bit. (Note that - using RANDOMIZE_BASE reduces the memory space available to - kernel modules from 1.5GB to 1GB.) + On 64-bit, the kernel physical and virtual addresses are + randomized separately. The physical address will be anywhere + between 16MB and the top of physical memory (up to 64TB). The + virtual address will be randomized from 16MB up to 1GB (9 bits + of entropy). Note that this also reduces the memory space + available to kernel modules from 1.5GB to 1GB. + + On 32-bit, the kernel physical and virtual addresses are + randomized together. They will be randomized from 16MB up to + 512MB (8 bits of entropy). Entropy is generated using the RDRAND instruction if it is supported. If RDTSC is supported, its value is mixed into the entropy pool as well. If neither RDRAND nor RDTSC are - supported, then entropy is read from the i8254 timer. - - Since the kernel is built using 2GB addressing, and - PHYSICAL_ALIGN must be at a minimum of 2MB, only 10 bits of - entropy is theoretically possible. Currently, with the - default value for PHYSICAL_ALIGN and due to page table - layouts, 64-bit uses 9 bits of entropy and 32-bit uses 8 bits. + supported, then entropy is read from the i8254 timer. The + usable entropy is limited by the kernel being built using + 2GB addressing, and that PHYSICAL_ALIGN must be at a + minimum of 2MB. As a result, only 10 bits of entropy are + theoretically possible, but the implementations are further + limited due to memory layouts. If CONFIG_HIBERNATE is also enabled, KASLR is disabled at boot time. To enable it, boot with "kaslr" on the kernel command diff --git a/arch/x86/boot/compressed/kaslr.c b/arch/x86/boot/compressed/kaslr.c index 5550546..36e2811 100644 --- a/arch/x86/boot/compressed/kaslr.c +++ b/arch/x86/boot/compressed/kaslr.c @@ -132,17 +132,6 @@ enum mem_avoid_index { static struct mem_vector mem_avoid[MEM_AVOID_MAX]; -static bool mem_contains(struct mem_vector *region, struct mem_vector *item) -{ - /* Item at least partially before region. */ - if (item->start < region->start) - return false; - /* Item at least partially after region. */ - if (item->start + item->size > region->start + region->size) - return false; - return true; -} - static bool mem_overlaps(struct mem_vector *one, struct mem_vector *two) { /* Item one is entirely before item two. */ @@ -319,8 +308,6 @@ static bool mem_avoid_overlap(struct mem_vector *img, return is_overlapping; } -static unsigned long slots[KERNEL_IMAGE_SIZE / CONFIG_PHYSICAL_ALIGN]; - struct slot_area { unsigned long addr; int num; @@ -351,36 +338,44 @@ static void store_slot_info(struct mem_vector *region, unsigned long image_size) } } -static void slots_append(unsigned long addr) -{ - /* Overflowing the slots list should be impossible. */ - if (slot_max >= KERNEL_IMAGE_SIZE / CONFIG_PHYSICAL_ALIGN) - return; - - slots[slot_max++] = addr; -} - static unsigned long slots_fetch_random(void) { + unsigned long slot; + int i; + /* Handle case of no slots stored. */ if (slot_max == 0) return 0; - return slots[get_random_long("Physical") % slot_max]; + slot = get_random_long("Physical") % slot_max; + + for (i = 0; i < slot_area_index; i++) { + if (slot >= slot_areas[i].num) { + slot -= slot_areas[i].num; + continue; + } + return slot_areas[i].addr + slot * CONFIG_PHYSICAL_ALIGN; + } + + if (i == slot_area_index) + debug_putstr("slots_fetch_random() failed!?\n"); + return 0; } static void process_e820_entry(struct e820entry *entry, unsigned long minimum, unsigned long image_size) { - struct mem_vector region, img, overlap; + struct mem_vector region, overlap; + struct slot_area slot_area; + unsigned long start_orig; /* Skip non-RAM entries. */ if (entry->type != E820_RAM) return; - /* Ignore entries entirely above our maximum. */ - if (entry->addr >= KERNEL_IMAGE_SIZE) + /* On 32-bit, ignore entries entirely above our maximum. */ + if (IS_ENABLED(CONFIG_X86_32) && entry->addr >= KERNEL_IMAGE_SIZE) return; /* Ignore entries entirely below our minimum. */ @@ -390,31 +385,55 @@ static void process_e820_entry(struct e820entry *entry, region.start = entry->addr; region.size = entry->size; - /* Potentially raise address to minimum location. */ - if (region.start < minimum) - region.start = minimum; + /* Give up if slot area array is full. */ + while (slot_area_index < MAX_SLOT_AREA) { + start_orig = region.start; - /* Potentially raise address to meet alignment requirements. */ - region.start = ALIGN(region.start, CONFIG_PHYSICAL_ALIGN); + /* Potentially raise address to minimum location. */ + if (region.start < minimum) + region.start = minimum; - /* Did we raise the address above the bounds of this e820 region? */ - if (region.start > entry->addr + entry->size) - return; + /* Potentially raise address to meet alignment needs. */ + region.start = ALIGN(region.start, CONFIG_PHYSICAL_ALIGN); - /* Reduce size by any delta from the original address. */ - region.size -= region.start - entry->addr; + /* Did we raise the address above this e820 region? */ + if (region.start > entry->addr + entry->size) + return; - /* Reduce maximum size to fit end of image within maximum limit. */ - if (region.start + region.size > KERNEL_IMAGE_SIZE) - region.size = KERNEL_IMAGE_SIZE - region.start; + /* Reduce size by any delta from the original address. */ + region.size -= region.start - start_orig; - /* Walk each aligned slot and check for avoided areas. */ - for (img.start = region.start, img.size = image_size ; - mem_contains(®ion, &img) ; - img.start += CONFIG_PHYSICAL_ALIGN) { - if (mem_avoid_overlap(&img, &overlap)) - continue; - slots_append(img.start); + /* On 32-bit, reduce region size to fit within max size. */ + if (IS_ENABLED(CONFIG_X86_32) && + region.start + region.size > KERNEL_IMAGE_SIZE) + region.size = KERNEL_IMAGE_SIZE - region.start; + + /* Return if region can't contain decompressed kernel */ + if (region.size < image_size) + return; + + /* If nothing overlaps, store the region and return. */ + if (!mem_avoid_overlap(®ion, &overlap)) { + store_slot_info(®ion, image_size); + return; + } + + /* Store beginning of region if holds at least image_size. */ + if (overlap.start > region.start + image_size) { + struct mem_vector beginning; + + beginning.start = region.start; + beginning.size = overlap.start - region.start; + store_slot_info(&beginning, image_size); + } + + /* Return if overlap extends to or past end of region. */ + if (overlap.start + overlap.size >= region.start + region.size) + return; + + /* Clip off the overlapping region and start over. */ + region.size -= overlap.start - region.start + overlap.size; + region.start = overlap.start + overlap.size; } } @@ -431,6 +450,10 @@ static unsigned long find_random_phys_addr(unsigned long minimum, for (i = 0; i < boot_params->e820_entries; i++) { process_e820_entry(&boot_params->e820_map[i], minimum, image_size); + if (slot_area_index == MAX_SLOT_AREA) { + debug_putstr("Aborted e820 scan (slot_areas full)!\n"); + break; + } } return slots_fetch_random(); -- cgit v0.10.2 From e066cc47776a89bbdaf4184c0e75f7d389f9ab48 Mon Sep 17 00:00:00 2001 From: Yinghai Lu Date: Wed, 25 May 2016 15:45:34 -0700 Subject: x86/KASLR: Allow randomization below the load address Currently the kernel image physical address randomization's lower boundary is the original kernel load address. For bootloaders that load kernels into very high memory (e.g. kexec), this means randomization takes place in a very small window at the top of memory, ignoring the large region of physical memory below the load address. Since mem_avoid[] is already correctly tracking the regions that must be avoided, this patch changes the minimum address to whatever is less: 512M (to conservatively avoid unknown things in lower memory) or the load address. Now, for example, if the kernel is loaded at 8G, [512M, 8G) will be added to the list of possible physical memory positions. Signed-off-by: Yinghai Lu [ Rewrote the changelog, refactored the code to use min(). ] Signed-off-by: Kees Cook Cc: Andrew Morton Cc: Andrey Ryabinin Cc: Andy Lutomirski Cc: Baoquan He Cc: Borislav Petkov Cc: Brian Gerst Cc: Denys Vlasenko Cc: Dmitry Vyukov Cc: H. Peter Anvin Cc: H.J. Lu Cc: Josh Poimboeuf Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/1464216334-17200-6-git-send-email-keescook@chromium.org [ Edited the changelog some more, plus the code comment as well. ] Signed-off-by: Ingo Molnar diff --git a/arch/x86/boot/compressed/kaslr.c b/arch/x86/boot/compressed/kaslr.c index 36e2811..749c9e0 100644 --- a/arch/x86/boot/compressed/kaslr.c +++ b/arch/x86/boot/compressed/kaslr.c @@ -492,7 +492,7 @@ void choose_random_location(unsigned long input, unsigned long output_size, unsigned long *virt_addr) { - unsigned long random_addr; + unsigned long random_addr, min_addr; /* By default, keep output position unchanged. */ *virt_addr = *output; @@ -510,8 +510,15 @@ void choose_random_location(unsigned long input, /* Record the various known unsafe memory ranges. */ mem_avoid_init(input, input_size, *output); + /* + * Low end of the randomization range should be the + * smaller of 512M or the initial kernel image + * location: + */ + min_addr = min(*output, 512UL << 20); + /* Walk e820 and find a random address. */ - random_addr = find_random_phys_addr(*output, output_size); + random_addr = find_random_phys_addr(min_addr, output_size); if (!random_addr) { warn("KASLR disabled: could not find suitable E820 region!"); } else { -- cgit v0.10.2 From 18f5839932e5c8c019f394d433dc5efcd6ae737a Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Thu, 23 Jun 2016 22:07:03 +0530 Subject: ASoC: Intel: atom: fix missing breaks that would cause the wrong operation to execute Now we correctly error an attempt to execute an unsupported operation. Signed-off-by: Alan Cox Signed-off-by: Vinod Koul Signed-off-by: Mark Brown diff --git a/sound/soc/intel/atom/sst-mfld-platform-compress.c b/sound/soc/intel/atom/sst-mfld-platform-compress.c index 3951689..1bead81 100644 --- a/sound/soc/intel/atom/sst-mfld-platform-compress.c +++ b/sound/soc/intel/atom/sst-mfld-platform-compress.c @@ -182,24 +182,29 @@ static int sst_platform_compr_trigger(struct snd_compr_stream *cstream, int cmd) case SNDRV_PCM_TRIGGER_START: if (stream->compr_ops->stream_start) return stream->compr_ops->stream_start(sst->dev, stream->id); + break; case SNDRV_PCM_TRIGGER_STOP: if (stream->compr_ops->stream_drop) return stream->compr_ops->stream_drop(sst->dev, stream->id); + break; case SND_COMPR_TRIGGER_DRAIN: if (stream->compr_ops->stream_drain) return stream->compr_ops->stream_drain(sst->dev, stream->id); + break; case SND_COMPR_TRIGGER_PARTIAL_DRAIN: if (stream->compr_ops->stream_partial_drain) return stream->compr_ops->stream_partial_drain(sst->dev, stream->id); + break; case SNDRV_PCM_TRIGGER_PAUSE_PUSH: if (stream->compr_ops->stream_pause) return stream->compr_ops->stream_pause(sst->dev, stream->id); + break; case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: if (stream->compr_ops->stream_pause_release) return stream->compr_ops->stream_pause_release(sst->dev, stream->id); - default: - return -EINVAL; + break; } + return -EINVAL; } static int sst_platform_compr_pointer(struct snd_compr_stream *cstream, -- cgit v0.10.2 From 5fd2b6ee7a319e0955acff96948fae57321b1f5a Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Sun, 26 Jun 2016 11:20:21 +0200 Subject: serial: sh-sci: Stop transfers in sci_shutdown() Make sure the transmitter and receiver are stopped when shutting down the port, and related interrupts are disabled. Without this: - New input data may be received into the RX FIFO, possibly triggering a new RX DMA completion, - Transfers will still be enabled on a subsequent startup of the UART, before the UART's FIFOs have been reset, causing reading of stale data. Inspired by a patch in the BSP by Koji Matsuoka . Signed-off-by: Geert Uytterhoeven Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c index 432d9ac..d86eee3 100644 --- a/drivers/tty/serial/sh-sci.c +++ b/drivers/tty/serial/sh-sci.c @@ -1989,6 +1989,7 @@ static void sci_shutdown(struct uart_port *port) { struct sci_port *s = to_sci_port(port); unsigned long flags; + u16 scr; dev_dbg(port->dev, "%s(%d)\n", __func__, port->line); @@ -1998,6 +1999,9 @@ static void sci_shutdown(struct uart_port *port) spin_lock_irqsave(&port->lock, flags); sci_stop_rx(port); sci_stop_tx(port); + /* Stop RX and TX, disable related interrupts, keep clock source */ + scr = serial_port_in(port, SCSCR); + serial_port_out(port, SCSCR, scr & (SCSCR_CKE1 | SCSCR_CKE0)); spin_unlock_irqrestore(&port->lock, flags); #ifdef CONFIG_SERIAL_SH_SCI_DMA -- cgit v0.10.2 From 98f2082c3ac4042189723c120553310700b583bb Mon Sep 17 00:00:00 2001 From: Nicolas Ferre Date: Sun, 26 Jun 2016 09:44:49 +0200 Subject: tty/serial: atmel: enforce tasklet init and termination sequences As some race conditions are identified in the termination process of tasklets, enforce the atmel_shutdown() sequence. This way we make sure that no new tasklets or software timer are scheduled during shutdown process. An atomic flag is positioned to give this information throughout the code. We also remove tasklet_disable() calls that were leading to deadlocks while stopping the driver. A simpler init/kill sequence is used. Signed-off-by: Nicolas Ferre Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c index f887c1d..2eaa18d 100644 --- a/drivers/tty/serial/atmel_serial.c +++ b/drivers/tty/serial/atmel_serial.c @@ -153,6 +153,7 @@ struct atmel_uart_port { struct scatterlist sg_rx; struct tasklet_struct tasklet_rx; struct tasklet_struct tasklet_tx; + atomic_t tasklet_shutdown; unsigned int irq_status_prev; unsigned int tx_len; @@ -286,6 +287,13 @@ static bool atmel_use_fifo(struct uart_port *port) return atmel_port->fifo_size; } +static void atmel_tasklet_schedule(struct atmel_uart_port *atmel_port, + struct tasklet_struct *t) +{ + if (!atomic_read(&atmel_port->tasklet_shutdown)) + tasklet_schedule(t); +} + static unsigned int atmel_get_lines_status(struct uart_port *port) { struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); @@ -717,7 +725,7 @@ static void atmel_rx_chars(struct uart_port *port) status = atmel_uart_readl(port, ATMEL_US_CSR); } - tasklet_schedule(&atmel_port->tasklet_rx); + atmel_tasklet_schedule(atmel_port, &atmel_port->tasklet_rx); } /* @@ -788,7 +796,7 @@ static void atmel_complete_tx_dma(void *arg) * remaining data from the beginning of xmit->buf to xmit->head. */ if (!uart_circ_empty(xmit)) - tasklet_schedule(&atmel_port->tasklet_tx); + atmel_tasklet_schedule(atmel_port, &atmel_port->tasklet_tx); spin_unlock_irqrestore(&port->lock, flags); } @@ -973,7 +981,7 @@ static void atmel_complete_rx_dma(void *arg) struct uart_port *port = arg; struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); - tasklet_schedule(&atmel_port->tasklet_rx); + atmel_tasklet_schedule(atmel_port, &atmel_port->tasklet_rx); } static void atmel_release_rx_dma(struct uart_port *port) @@ -1013,7 +1021,7 @@ static void atmel_rx_from_dma(struct uart_port *port) if (dmastat == DMA_ERROR) { dev_dbg(port->dev, "Get residue error, restart tasklet\n"); atmel_uart_writel(port, ATMEL_US_IER, ATMEL_US_TIMEOUT); - tasklet_schedule(&atmel_port->tasklet_rx); + atmel_tasklet_schedule(atmel_port, &atmel_port->tasklet_rx); return; } @@ -1167,8 +1175,11 @@ static void atmel_uart_timer_callback(unsigned long data) struct uart_port *port = (void *)data; struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); - tasklet_schedule(&atmel_port->tasklet_rx); - mod_timer(&atmel_port->uart_timer, jiffies + uart_poll_timeout(port)); + if (!atomic_read(&atmel_port->tasklet_shutdown)) { + tasklet_schedule(&atmel_port->tasklet_rx); + mod_timer(&atmel_port->uart_timer, + jiffies + uart_poll_timeout(port)); + } } /* @@ -1190,7 +1201,8 @@ atmel_handle_receive(struct uart_port *port, unsigned int pending) if (pending & (ATMEL_US_ENDRX | ATMEL_US_TIMEOUT)) { atmel_uart_writel(port, ATMEL_US_IDR, (ATMEL_US_ENDRX | ATMEL_US_TIMEOUT)); - tasklet_schedule(&atmel_port->tasklet_rx); + atmel_tasklet_schedule(atmel_port, + &atmel_port->tasklet_rx); } if (pending & (ATMEL_US_RXBRK | ATMEL_US_OVRE | @@ -1202,7 +1214,8 @@ atmel_handle_receive(struct uart_port *port, unsigned int pending) if (pending & ATMEL_US_TIMEOUT) { atmel_uart_writel(port, ATMEL_US_IDR, ATMEL_US_TIMEOUT); - tasklet_schedule(&atmel_port->tasklet_rx); + atmel_tasklet_schedule(atmel_port, + &atmel_port->tasklet_rx); } } @@ -1232,7 +1245,7 @@ atmel_handle_transmit(struct uart_port *port, unsigned int pending) /* Either PDC or interrupt transmission */ atmel_uart_writel(port, ATMEL_US_IDR, atmel_port->tx_done_mask); - tasklet_schedule(&atmel_port->tasklet_tx); + atmel_tasklet_schedule(atmel_port, &atmel_port->tasklet_tx); } } @@ -1793,8 +1806,11 @@ static int atmel_startup(struct uart_port *port) return retval; } - tasklet_enable(&atmel_port->tasklet_rx); - tasklet_enable(&atmel_port->tasklet_tx); + atomic_set(&atmel_port->tasklet_shutdown, 0); + tasklet_init(&atmel_port->tasklet_rx, atmel_tasklet_rx_func, + (unsigned long)port); + tasklet_init(&atmel_port->tasklet_tx, atmel_tasklet_tx_func, + (unsigned long)port); /* * Initialize DMA (if necessary) @@ -1913,31 +1929,36 @@ static void atmel_shutdown(struct uart_port *port) { struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); + /* Disable interrupts at device level */ + atmel_uart_writel(port, ATMEL_US_IDR, -1); + + /* Prevent spurious interrupts from scheduling the tasklet */ + atomic_inc(&atmel_port->tasklet_shutdown); + /* * Prevent any tasklets being scheduled during * cleanup */ del_timer_sync(&atmel_port->uart_timer); + /* Make sure that no interrupt is on the fly */ + synchronize_irq(port->irq); + /* * Clear out any scheduled tasklets before * we destroy the buffers */ - tasklet_disable(&atmel_port->tasklet_rx); - tasklet_disable(&atmel_port->tasklet_tx); tasklet_kill(&atmel_port->tasklet_rx); tasklet_kill(&atmel_port->tasklet_tx); /* * Ensure everything is stopped and - * disable all interrupts, port and break condition. + * disable port and break condition. */ atmel_stop_rx(port); atmel_stop_tx(port); atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_RSTSTA); - atmel_uart_writel(port, ATMEL_US_IDR, -1); - /* * Shut-down the DMA. @@ -2321,13 +2342,6 @@ static int atmel_init_port(struct atmel_uart_port *atmel_port, port->irq = pdev->resource[1].start; port->rs485_config = atmel_config_rs485; - tasklet_init(&atmel_port->tasklet_rx, atmel_tasklet_rx_func, - (unsigned long)port); - tasklet_init(&atmel_port->tasklet_tx, atmel_tasklet_tx_func, - (unsigned long)port); - tasklet_disable(&atmel_port->tasklet_rx); - tasklet_disable(&atmel_port->tasklet_tx); - memset(&atmel_port->rx_ring, 0, sizeof(atmel_port->rx_ring)); if (pdata && pdata->regs) { @@ -2712,6 +2726,7 @@ static int atmel_serial_probe(struct platform_device *pdev) atmel_port->uart.line = ret; atmel_serial_probe_fifos(atmel_port, pdev); + atomic_set(&atmel_port->tasklet_shutdown, 0); spin_lock_init(&atmel_port->lock_suspended); ret = atmel_init_port(atmel_port, pdev); -- cgit v0.10.2 From 5a5a0b1ae54c9467594e75957240b25863d7e997 Mon Sep 17 00:00:00 2001 From: Mathias Nyman Date: Tue, 21 Jun 2016 10:57:57 +0300 Subject: =?UTF-8?q?xhci:=20rename=20ep=5Fring=20variable=20in=20queue=5Fbu?= =?UTF-8?q?lk=5Ftx(),=20no=20functional=C2=A0change?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Tiny change, a bit more readable. The real reason for this change is that the coming td fragment work had several over 80 lines character lines split just because of a few extra characters in variable names. no functional changes Signed-off-by: Mathias Nyman Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index d7d5025..e62427d 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -3120,7 +3120,7 @@ static u32 xhci_td_remainder(struct xhci_hcd *xhci, int transferred, int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags, struct urb *urb, int slot_id, unsigned int ep_index) { - struct xhci_ring *ep_ring; + struct xhci_ring *ring; struct urb_priv *urb_priv; struct xhci_td *td; struct xhci_generic_trb *start_trb; @@ -3129,14 +3129,13 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags, bool zero_length_needed; unsigned int num_trbs, last_trb_num, i; unsigned int start_cycle, num_sgs = 0; - unsigned int running_total, block_len, trb_buff_len; - unsigned int full_len; + unsigned int running_total, block_len, trb_buff_len, full_len; int ret; u32 field, length_field, remainder; u64 addr; - ep_ring = xhci_urb_to_transfer_ring(xhci, urb); - if (!ep_ring) + ring = xhci_urb_to_transfer_ring(xhci, urb); + if (!ring) return -EINVAL; /* If we have scatter/gather list, we use it. */ @@ -3177,8 +3176,8 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags, * until we've finished creating all the other TRBs. The ring's cycle * state may change as we enqueue the other TRBs, so save it too. */ - start_trb = &ep_ring->enqueue->generic; - start_cycle = ep_ring->cycle_state; + start_trb = &ring->enqueue->generic; + start_cycle = ring->cycle_state; full_len = urb->transfer_buffer_length; running_total = 0; @@ -3217,7 +3216,7 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags, if (start_cycle == 0) field |= TRB_CYCLE; } else - field |= ep_ring->cycle_state; + field |= ring->cycle_state; /* Chain all the TRBs together; clear the chain bit in the last * TRB to indicate it's the last TRB in the chain. @@ -3227,10 +3226,10 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags, } else { field |= TRB_IOC; if (i == last_trb_num) - td->last_trb = ep_ring->enqueue; + td->last_trb = ring->enqueue; else if (zero_length_needed) { trb_buff_len = 0; - urb_priv->td[1]->last_trb = ep_ring->enqueue; + urb_priv->td[1]->last_trb = ring->enqueue; } } @@ -3251,7 +3250,7 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags, more_trbs_coming = true; else more_trbs_coming = false; - queue_trb(xhci, ep_ring, more_trbs_coming, + queue_trb(xhci, ring, more_trbs_coming, lower_32_bits(addr), upper_32_bits(addr), length_field, -- cgit v0.10.2 From 5a83f04a7961bbbbae9f9ff389aef0e2c1b0d843 Mon Sep 17 00:00:00 2001 From: Mathias Nyman Date: Tue, 21 Jun 2016 10:57:58 +0300 Subject: xhci: properly prepare zero packet TD after normal bulk TD. If a zero-length packet is needed after a bulk transfer, then an additional zero length TD was prepared before enqueueing the bulk transfer This set up the zero packet TD structure with incorrect td->start_seg and td->first_trb pointers. Prepare the zero packet TD after the data bulk TD is enqueued instead. It sets these pointers correctly. This change also simplifies unnecessary complexity related to keeping track of the last trb when enqueuing trbs. Signed-off-by: Mathias Nyman Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index e62427d..71cae79 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -3125,8 +3125,8 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags, struct xhci_td *td; struct xhci_generic_trb *start_trb; struct scatterlist *sg = NULL; - bool more_trbs_coming; - bool zero_length_needed; + bool more_trbs_coming = true; + bool need_zero_pkt = false; unsigned int num_trbs, last_trb_num, i; unsigned int start_cycle, num_sgs = 0; unsigned int running_total, block_len, trb_buff_len, full_len; @@ -3157,17 +3157,8 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags, last_trb_num = num_trbs - 1; /* Deal with URB_ZERO_PACKET - need one more td/trb */ - zero_length_needed = urb->transfer_flags & URB_ZERO_PACKET && - urb_priv->length == 2; - if (zero_length_needed) { - num_trbs++; - xhci_dbg(xhci, "Creating zero length td.\n"); - ret = prepare_transfer(xhci, xhci->devs[slot_id], - ep_index, urb->stream_id, - 1, urb, 1, mem_flags); - if (unlikely(ret < 0)) - return ret; - } + if (urb->transfer_flags & URB_ZERO_PACKET && urb_priv->length > 1) + need_zero_pkt = true; td = urb_priv->td[0]; @@ -3225,12 +3216,8 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags, field |= TRB_CHAIN; } else { field |= TRB_IOC; - if (i == last_trb_num) - td->last_trb = ring->enqueue; - else if (zero_length_needed) { - trb_buff_len = 0; - urb_priv->td[1]->last_trb = ring->enqueue; - } + more_trbs_coming = need_zero_pkt; + td->last_trb = ring->enqueue; } /* Only set interrupt on short packet for IN endpoints */ @@ -3246,10 +3233,6 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags, TRB_TD_SIZE(remainder) | TRB_INTR_TARGET(0); - if (i < num_trbs - 1) - more_trbs_coming = true; - else - more_trbs_coming = false; queue_trb(xhci, ring, more_trbs_coming, lower_32_bits(addr), upper_32_bits(addr), @@ -3271,6 +3254,15 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags, } } + if (need_zero_pkt) { + ret = prepare_transfer(xhci, xhci->devs[slot_id], + ep_index, urb->stream_id, + 1, urb, 1, mem_flags); + urb_priv->td[1]->last_trb = ring->enqueue; + field = TRB_TYPE(TRB_NORMAL) | ring->cycle_state | TRB_IOC; + queue_trb(xhci, ring, 0, 0, 0, TRB_INTR_TARGET(0), field); + } + check_trb_math(urb, running_total); giveback_first_trb(xhci, slot_id, ep_index, urb->stream_id, start_cycle, start_trb); -- cgit v0.10.2 From 124c39371114f43df34882685db3682a91dea10c Mon Sep 17 00:00:00 2001 From: Mathias Nyman Date: Tue, 21 Jun 2016 10:57:59 +0300 Subject: xhci: use boolean to indicate last trb in td remainder calculation We only need to know if we are queuing the last trb for a TD when calculating the td remainder field. The total number of trbs left is not used. We won't be able to trust the pre-calculated number of trbs used if we need to align trb data by splitting or merging trbs in order to satisfy comply with data alignment requirements in xhci specs section 4.11.7.1. Signed-off-by: Mathias Nyman Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index 71cae79..4637da6 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -3092,7 +3092,7 @@ int xhci_queue_intr_tx(struct xhci_hcd *xhci, gfp_t mem_flags, */ static u32 xhci_td_remainder(struct xhci_hcd *xhci, int transferred, int trb_buff_len, unsigned int td_total_len, - struct urb *urb, unsigned int num_trbs_left) + struct urb *urb, bool more_trbs_coming) { u32 maxp, total_packet_count; @@ -3101,7 +3101,7 @@ static u32 xhci_td_remainder(struct xhci_hcd *xhci, int transferred, return ((td_total_len - transferred) >> 10); /* One TRB with a zero-length data packet. */ - if (num_trbs_left == 0 || (transferred == 0 && trb_buff_len == 0) || + if (!more_trbs_coming || (transferred == 0 && trb_buff_len == 0) || trb_buff_len == td_total_len) return 0; @@ -3216,7 +3216,7 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags, field |= TRB_CHAIN; } else { field |= TRB_IOC; - more_trbs_coming = need_zero_pkt; + more_trbs_coming = false; td->last_trb = ring->enqueue; } @@ -3227,13 +3227,12 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags, /* Set the TRB length, TD size, and interrupter fields. */ remainder = xhci_td_remainder(xhci, running_total, trb_buff_len, full_len, - urb, num_trbs - i - 1); - + urb, more_trbs_coming); length_field = TRB_LEN(trb_buff_len) | TRB_TD_SIZE(remainder) | TRB_INTR_TARGET(0); - queue_trb(xhci, ring, more_trbs_coming, + queue_trb(xhci, ring, more_trbs_coming | need_zero_pkt, lower_32_bits(addr), upper_32_bits(addr), length_field, @@ -3657,7 +3656,7 @@ static int xhci_queue_isoc_tx(struct xhci_hcd *xhci, gfp_t mem_flags, /* Set the TRB length, TD size, & interrupter fields. */ remainder = xhci_td_remainder(xhci, running_total, trb_buff_len, td_len, - urb, trbs_per_td - j - 1); + urb, more_trbs_coming); length_field = TRB_LEN(trb_buff_len) | TRB_INTR_TARGET(0); -- cgit v0.10.2 From 86065c2719a5685cef36945f09def3f0658c7860 Mon Sep 17 00:00:00 2001 From: Mathias Nyman Date: Tue, 21 Jun 2016 10:58:00 +0300 Subject: xhci: don't rely on precalculated value of needed trbs in the enqueue loop Queue trbs until all payload data in the urb is tranferred. The actual number of trbs might need to change from the pre-calculated number when the packet alignment restrictions for td fragments in xhci 4.11.7.1 are taken into account. Long term plan is to get rid of calculating the needed trbs in advance all together. It's an unnecessary extra walk through the scatterlist. This change also allows some bulk queue function simplifications Signed-off-by: Mathias Nyman Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index 4637da6..519dc14 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -3127,9 +3127,10 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags, struct scatterlist *sg = NULL; bool more_trbs_coming = true; bool need_zero_pkt = false; - unsigned int num_trbs, last_trb_num, i; + bool first_trb = true; + unsigned int num_trbs; unsigned int start_cycle, num_sgs = 0; - unsigned int running_total, block_len, trb_buff_len, full_len; + unsigned int enqd_len, block_len, trb_buff_len, full_len; int ret; u32 field, length_field, remainder; u64 addr; @@ -3138,14 +3139,19 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags, if (!ring) return -EINVAL; + full_len = urb->transfer_buffer_length; /* If we have scatter/gather list, we use it. */ if (urb->num_sgs) { num_sgs = urb->num_mapped_sgs; sg = urb->sg; + addr = (u64) sg_dma_address(sg); + block_len = sg_dma_len(sg); num_trbs = count_sg_trbs_needed(urb); - } else + } else { num_trbs = count_trbs_needed(urb); - + addr = (u64) urb->transfer_dma; + block_len = full_len; + } ret = prepare_transfer(xhci, xhci->devs[slot_id], ep_index, urb->stream_id, num_trbs, urb, 0, mem_flags); @@ -3154,8 +3160,6 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags, urb_priv = urb->hcpriv; - last_trb_num = num_trbs - 1; - /* Deal with URB_ZERO_PACKET - need one more td/trb */ if (urb->transfer_flags & URB_ZERO_PACKET && urb_priv->length > 1) need_zero_pkt = true; @@ -3170,40 +3174,20 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags, start_trb = &ring->enqueue->generic; start_cycle = ring->cycle_state; - full_len = urb->transfer_buffer_length; - running_total = 0; - block_len = 0; - /* Queue the TRBs, even if they are zero-length */ - for (i = 0; i < num_trbs; i++) { + for (enqd_len = 0; enqd_len < full_len; enqd_len += trb_buff_len) { field = TRB_TYPE(TRB_NORMAL); - if (block_len == 0) { - /* A new contiguous block. */ - if (sg) { - addr = (u64) sg_dma_address(sg); - block_len = sg_dma_len(sg); - } else { - addr = (u64) urb->transfer_dma; - block_len = full_len; - } - /* TRB buffer should not cross 64KB boundaries */ - trb_buff_len = TRB_BUFF_LEN_UP_TO_BOUNDARY(addr); - trb_buff_len = min_t(unsigned int, - trb_buff_len, - block_len); - } else { - /* Further through the contiguous block. */ - trb_buff_len = block_len; - if (trb_buff_len > TRB_MAX_BUFF_SIZE) - trb_buff_len = TRB_MAX_BUFF_SIZE; - } + /* TRB buffer should not cross 64KB boundaries */ + trb_buff_len = TRB_BUFF_LEN_UP_TO_BOUNDARY(addr); + trb_buff_len = min_t(unsigned int, trb_buff_len, block_len); - if (running_total + trb_buff_len > full_len) - trb_buff_len = full_len - running_total; + if (enqd_len + trb_buff_len > full_len) + trb_buff_len = full_len - enqd_len; /* Don't change the cycle bit of the first TRB until later */ - if (i == 0) { + if (first_trb) { + first_trb = false; if (start_cycle == 0) field |= TRB_CYCLE; } else @@ -3212,7 +3196,7 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags, /* Chain all the TRBs together; clear the chain bit in the last * TRB to indicate it's the last TRB in the chain. */ - if (i < last_trb_num) { + if (enqd_len + trb_buff_len < full_len) { field |= TRB_CHAIN; } else { field |= TRB_IOC; @@ -3225,9 +3209,9 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags, field |= TRB_ISP; /* Set the TRB length, TD size, and interrupter fields. */ - remainder = xhci_td_remainder(xhci, running_total, - trb_buff_len, full_len, - urb, more_trbs_coming); + remainder = xhci_td_remainder(xhci, enqd_len, trb_buff_len, + full_len, urb, more_trbs_coming); + length_field = TRB_LEN(trb_buff_len) | TRB_TD_SIZE(remainder) | TRB_INTR_TARGET(0); @@ -3238,17 +3222,16 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags, length_field, field); - running_total += trb_buff_len; addr += trb_buff_len; block_len -= trb_buff_len; - if (sg) { - if (block_len == 0) { - /* New sg entry */ - --num_sgs; - if (num_sgs == 0) - break; + if (sg && block_len == 0) { + /* New sg entry */ + --num_sgs; + if (num_sgs != 0) { sg = sg_next(sg); + block_len = sg_dma_len(sg); + addr = (u64) sg_dma_address(sg); } } } @@ -3262,7 +3245,7 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags, queue_trb(xhci, ring, 0, 0, 0, TRB_INTR_TARGET(0), field); } - check_trb_math(urb, running_total); + check_trb_math(urb, enqd_len); giveback_first_trb(xhci, slot_id, ep_index, urb->stream_id, start_cycle, start_trb); return 0; -- cgit v0.10.2 From 474ed23a6257b552ab48585c1511eac98653b4e8 Mon Sep 17 00:00:00 2001 From: Mathias Nyman Date: Tue, 21 Jun 2016 10:58:01 +0300 Subject: xhci: align the last trb before link if it is easily splittable. TD fragments section 4.11.7.1 in xhci specs have additional requirements on how trbs in TDs must be organized. TD fragments shall not span transfer ring segments and TD fragments must be packet aligned. Normally we don't care about TD fragments, on TD is one big fragment, but if a TD spans ring segments it will be treated as two fragments, and we need to comply with the alignment requirements. For us this means that the payload data must be packet aligned in the last trb before a link trb. In most mass storage bulk tranfers we are lucky as the block size aligns nicely with packet size, and there are no issues. However, usb network adapters using scatterlists can hit this alignment issue, and usbtest in kernel triggers this in minutes. This patch is a partial solution, it solves the easy case when the last trb before the link trb contains a packet boundary. If that is the case then just split the trb at the boundary. If not, then just print a debug message and continue as we have always done, hoping for the best Signed-off-by: Mathias Nyman Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index 519dc14..81bb8bf 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -3116,6 +3116,27 @@ static u32 xhci_td_remainder(struct xhci_hcd *xhci, int transferred, return (total_packet_count - ((transferred + trb_buff_len) / maxp)); } +static int xhci_align_td(struct xhci_hcd *xhci, struct urb *urb, u32 enqd_len, + u32 *trb_buff_len) +{ + unsigned int unalign; + unsigned int max_pkt; + + max_pkt = GET_MAX_PACKET(usb_endpoint_maxp(&urb->ep->desc)); + unalign = (enqd_len + *trb_buff_len) % max_pkt; + + /* we got lucky, last normal TRB data on segment is packet aligned */ + if (unalign == 0) + return 0; + + /* is the last nornal TRB alignable by splitting it */ + if (*trb_buff_len > unalign) { + *trb_buff_len -= unalign; + return 0; + } + return 1; +} + /* This is very similar to what ehci-q.c qtd_fill() does */ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags, struct urb *urb, int slot_id, unsigned int ep_index) @@ -3198,6 +3219,12 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags, */ if (enqd_len + trb_buff_len < full_len) { field |= TRB_CHAIN; + if (last_trb(xhci, ring, ring->enq_seg, + ring->enqueue + 1)) { + if (xhci_align_td(xhci, urb, enqd_len, + &trb_buff_len)) + xhci_dbg(xhci, "TRB align fail\n"); + } } else { field |= TRB_IOC; more_trbs_coming = false; -- cgit v0.10.2 From f9c589e142d04b8a19eb382162f804d17102b5ed Mon Sep 17 00:00:00 2001 From: Mathias Nyman Date: Tue, 21 Jun 2016 10:58:02 +0300 Subject: xhci: TD-fragment, align the unsplittable case with a bounce buffer If the last trb before a link is not packet size aligned, and is not splittable then use a bounce buffer for that chunk of max packet size unalignable data. Allocate a max packet size bounce buffer for every segment of a bulk endpoint ring at the same time as allocating the ring. If we need to align the data before the link trb in that segment then copy the data to the segment bounce buffer, dma map it, and enqueue it. Once the td finishes, or is cancelled, unmap it. For in transfers we need to first map the bounce buffer, then queue it, after it finishes, copy the bounce buffer to the original sg list, and finally unmap it Signed-off-by: Mathias Nyman Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c index bad0d1f..6afe323 100644 --- a/drivers/usb/host/xhci-mem.c +++ b/drivers/usb/host/xhci-mem.c @@ -37,7 +37,9 @@ * "All components of all Command and Transfer TRBs shall be initialized to '0'" */ static struct xhci_segment *xhci_segment_alloc(struct xhci_hcd *xhci, - unsigned int cycle_state, gfp_t flags) + unsigned int cycle_state, + unsigned int max_packet, + gfp_t flags) { struct xhci_segment *seg; dma_addr_t dma; @@ -53,6 +55,14 @@ static struct xhci_segment *xhci_segment_alloc(struct xhci_hcd *xhci, return NULL; } + if (max_packet) { + seg->bounce_buf = kzalloc(max_packet, flags | GFP_DMA); + if (!seg->bounce_buf) { + dma_pool_free(xhci->segment_pool, seg->trbs, dma); + kfree(seg); + return NULL; + } + } /* If the cycle state is 0, set the cycle bit to 1 for all the TRBs */ if (cycle_state == 0) { for (i = 0; i < TRBS_PER_SEGMENT; i++) @@ -70,6 +80,7 @@ static void xhci_segment_free(struct xhci_hcd *xhci, struct xhci_segment *seg) dma_pool_free(xhci->segment_pool, seg->trbs, seg->dma); seg->trbs = NULL; } + kfree(seg->bounce_buf); kfree(seg); } @@ -317,11 +328,11 @@ static void xhci_initialize_ring_info(struct xhci_ring *ring, static int xhci_alloc_segments_for_ring(struct xhci_hcd *xhci, struct xhci_segment **first, struct xhci_segment **last, unsigned int num_segs, unsigned int cycle_state, - enum xhci_ring_type type, gfp_t flags) + enum xhci_ring_type type, unsigned int max_packet, gfp_t flags) { struct xhci_segment *prev; - prev = xhci_segment_alloc(xhci, cycle_state, flags); + prev = xhci_segment_alloc(xhci, cycle_state, max_packet, flags); if (!prev) return -ENOMEM; num_segs--; @@ -330,7 +341,7 @@ static int xhci_alloc_segments_for_ring(struct xhci_hcd *xhci, while (num_segs > 0) { struct xhci_segment *next; - next = xhci_segment_alloc(xhci, cycle_state, flags); + next = xhci_segment_alloc(xhci, cycle_state, max_packet, flags); if (!next) { prev = *first; while (prev) { @@ -360,7 +371,7 @@ static int xhci_alloc_segments_for_ring(struct xhci_hcd *xhci, */ static struct xhci_ring *xhci_ring_alloc(struct xhci_hcd *xhci, unsigned int num_segs, unsigned int cycle_state, - enum xhci_ring_type type, gfp_t flags) + enum xhci_ring_type type, unsigned int max_packet, gfp_t flags) { struct xhci_ring *ring; int ret; @@ -370,13 +381,15 @@ static struct xhci_ring *xhci_ring_alloc(struct xhci_hcd *xhci, return NULL; ring->num_segs = num_segs; + ring->bounce_buf_len = max_packet; INIT_LIST_HEAD(&ring->td_list); ring->type = type; if (num_segs == 0) return ring; ret = xhci_alloc_segments_for_ring(xhci, &ring->first_seg, - &ring->last_seg, num_segs, cycle_state, type, flags); + &ring->last_seg, num_segs, cycle_state, type, + max_packet, flags); if (ret) goto fail; @@ -470,7 +483,8 @@ int xhci_ring_expansion(struct xhci_hcd *xhci, struct xhci_ring *ring, ring->num_segs : num_segs_needed; ret = xhci_alloc_segments_for_ring(xhci, &first, &last, - num_segs, ring->cycle_state, ring->type, flags); + num_segs, ring->cycle_state, ring->type, + ring->bounce_buf_len, flags); if (ret) return -ENOMEM; @@ -652,7 +666,8 @@ struct xhci_ring *xhci_stream_id_to_ring( */ struct xhci_stream_info *xhci_alloc_stream_info(struct xhci_hcd *xhci, unsigned int num_stream_ctxs, - unsigned int num_streams, gfp_t mem_flags) + unsigned int num_streams, + unsigned int max_packet, gfp_t mem_flags) { struct xhci_stream_info *stream_info; u32 cur_stream; @@ -704,9 +719,11 @@ struct xhci_stream_info *xhci_alloc_stream_info(struct xhci_hcd *xhci, * and add their segment DMA addresses to the radix tree. * Stream 0 is reserved. */ + for (cur_stream = 1; cur_stream < num_streams; cur_stream++) { stream_info->stream_rings[cur_stream] = - xhci_ring_alloc(xhci, 2, 1, TYPE_STREAM, mem_flags); + xhci_ring_alloc(xhci, 2, 1, TYPE_STREAM, max_packet, + mem_flags); cur_ring = stream_info->stream_rings[cur_stream]; if (!cur_ring) goto cleanup_rings; @@ -1003,7 +1020,7 @@ int xhci_alloc_virt_device(struct xhci_hcd *xhci, int slot_id, } /* Allocate endpoint 0 ring */ - dev->eps[0].ring = xhci_ring_alloc(xhci, 2, 1, TYPE_CTRL, flags); + dev->eps[0].ring = xhci_ring_alloc(xhci, 2, 1, TYPE_CTRL, 0, flags); if (!dev->eps[0].ring) goto fail; @@ -1434,22 +1451,6 @@ int xhci_endpoint_init(struct xhci_hcd *xhci, return -EINVAL; ring_type = usb_endpoint_type(&ep->desc); - /* Set up the endpoint ring */ - virt_dev->eps[ep_index].new_ring = - xhci_ring_alloc(xhci, 2, 1, ring_type, mem_flags); - if (!virt_dev->eps[ep_index].new_ring) { - /* Attempt to use the ring cache */ - if (virt_dev->num_rings_cached == 0) - return -ENOMEM; - virt_dev->num_rings_cached--; - virt_dev->eps[ep_index].new_ring = - virt_dev->ring_cache[virt_dev->num_rings_cached]; - virt_dev->ring_cache[virt_dev->num_rings_cached] = NULL; - xhci_reinit_cached_ring(xhci, virt_dev->eps[ep_index].new_ring, - 1, ring_type); - } - virt_dev->eps[ep_index].skip = false; - ep_ring = virt_dev->eps[ep_index].new_ring; /* * Get values to fill the endpoint context, mostly from ep descriptor. @@ -1479,6 +1480,23 @@ int xhci_endpoint_init(struct xhci_hcd *xhci, if ((xhci->hci_version > 0x100) && HCC2_LEC(xhci->hcc_params2)) mult = 0; + /* Set up the endpoint ring */ + virt_dev->eps[ep_index].new_ring = + xhci_ring_alloc(xhci, 2, 1, ring_type, max_packet, mem_flags); + if (!virt_dev->eps[ep_index].new_ring) { + /* Attempt to use the ring cache */ + if (virt_dev->num_rings_cached == 0) + return -ENOMEM; + virt_dev->num_rings_cached--; + virt_dev->eps[ep_index].new_ring = + virt_dev->ring_cache[virt_dev->num_rings_cached]; + virt_dev->ring_cache[virt_dev->num_rings_cached] = NULL; + xhci_reinit_cached_ring(xhci, virt_dev->eps[ep_index].new_ring, + 1, ring_type); + } + virt_dev->eps[ep_index].skip = false; + ep_ring = virt_dev->eps[ep_index].new_ring; + /* Fill the endpoint context */ ep_ctx->ep_info = cpu_to_le32(EP_MAX_ESIT_PAYLOAD_HI(max_esit_payload) | EP_INTERVAL(interval) | @@ -2409,7 +2427,7 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags) goto fail; /* Set up the command ring to have one segments for now. */ - xhci->cmd_ring = xhci_ring_alloc(xhci, 1, 1, TYPE_COMMAND, flags); + xhci->cmd_ring = xhci_ring_alloc(xhci, 1, 1, TYPE_COMMAND, 0, flags); if (!xhci->cmd_ring) goto fail; xhci_dbg_trace(xhci, trace_xhci_dbg_init, @@ -2454,7 +2472,7 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags) */ xhci_dbg_trace(xhci, trace_xhci_dbg_init, "// Allocating event ring"); xhci->event_ring = xhci_ring_alloc(xhci, ERST_NUM_SEGS, 1, TYPE_EVENT, - flags); + 0, flags); if (!xhci->event_ring) goto fail; if (xhci_check_trb_in_td_math(xhci) < 0) diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index 81bb8bf..b2c861e 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -66,6 +66,7 @@ #include #include +#include #include "xhci.h" #include "xhci-trace.h" #include "xhci-mtk.h" @@ -626,6 +627,31 @@ static void xhci_giveback_urb_in_irq(struct xhci_hcd *xhci, } } +void xhci_unmap_td_bounce_buffer(struct xhci_hcd *xhci, struct xhci_ring *ring, + struct xhci_td *td) +{ + struct device *dev = xhci_to_hcd(xhci)->self.controller; + struct xhci_segment *seg = td->bounce_seg; + struct urb *urb = td->urb; + + if (!seg || !urb) + return; + + if (usb_urb_dir_out(urb)) { + dma_unmap_single(dev, seg->bounce_dma, ring->bounce_buf_len, + DMA_TO_DEVICE); + return; + } + + /* for in tranfers we need to copy the data from bounce to sg */ + sg_pcopy_from_buffer(urb->sg, urb->num_mapped_sgs, seg->bounce_buf, + seg->bounce_len, seg->bounce_offs); + dma_unmap_single(dev, seg->bounce_dma, ring->bounce_buf_len, + DMA_FROM_DEVICE); + seg->bounce_len = 0; + seg->bounce_offs = 0; +} + /* * When we get a command completion for a Stop Endpoint Command, we need to * unlink any cancelled TDs from the ring. There are two ways to do that: @@ -745,6 +771,8 @@ remove_finished_td: /* Doesn't matter what we pass for status, since the core will * just overwrite it (because the URB has been unlinked). */ + if (ep_ring && cur_td->bounce_seg) + xhci_unmap_td_bounce_buffer(xhci, ep_ring, cur_td); xhci_giveback_urb_in_irq(xhci, cur_td, 0); /* Stop processing the cancelled list if the watchdog timer is @@ -767,6 +795,9 @@ static void xhci_kill_ring_urbs(struct xhci_hcd *xhci, struct xhci_ring *ring) list_del_init(&cur_td->td_list); if (!list_empty(&cur_td->cancelled_td_list)) list_del_init(&cur_td->cancelled_td_list); + + if (cur_td->bounce_seg) + xhci_unmap_td_bounce_buffer(xhci, ring, cur_td); xhci_giveback_urb_in_irq(xhci, cur_td, -ESHUTDOWN); } } @@ -1865,6 +1896,10 @@ td_cleanup: urb = td->urb; urb_priv = urb->hcpriv; + /* if a bounce buffer was used to align this td then unmap it */ + if (td->bounce_seg) + xhci_unmap_td_bounce_buffer(xhci, ep_ring, td); + /* Do one last check of the actual transfer length. * If the host controller said we transferred more data than the buffer * length, urb->actual_length will be a very big number (since it's @@ -3116,11 +3151,14 @@ static u32 xhci_td_remainder(struct xhci_hcd *xhci, int transferred, return (total_packet_count - ((transferred + trb_buff_len) / maxp)); } + static int xhci_align_td(struct xhci_hcd *xhci, struct urb *urb, u32 enqd_len, - u32 *trb_buff_len) + u32 *trb_buff_len, struct xhci_segment *seg) { + struct device *dev = xhci_to_hcd(xhci)->self.controller; unsigned int unalign; unsigned int max_pkt; + u32 new_buff_len; max_pkt = GET_MAX_PACKET(usb_endpoint_maxp(&urb->ep->desc)); unalign = (enqd_len + *trb_buff_len) % max_pkt; @@ -3129,11 +3167,48 @@ static int xhci_align_td(struct xhci_hcd *xhci, struct urb *urb, u32 enqd_len, if (unalign == 0) return 0; + xhci_dbg(xhci, "Unaligned %d bytes, buff len %d\n", + unalign, *trb_buff_len); + /* is the last nornal TRB alignable by splitting it */ if (*trb_buff_len > unalign) { *trb_buff_len -= unalign; + xhci_dbg(xhci, "split align, new buff len %d\n", *trb_buff_len); return 0; } + + /* + * We want enqd_len + trb_buff_len to sum up to a number aligned to + * number which is divisible by the endpoint's wMaxPacketSize. IOW: + * (size of currently enqueued TRBs + remainder) % wMaxPacketSize == 0. + */ + new_buff_len = max_pkt - (enqd_len % max_pkt); + + if (new_buff_len > (urb->transfer_buffer_length - enqd_len)) + new_buff_len = (urb->transfer_buffer_length - enqd_len); + + /* create a max max_pkt sized bounce buffer pointed to by last trb */ + if (usb_urb_dir_out(urb)) { + sg_pcopy_to_buffer(urb->sg, urb->num_mapped_sgs, + seg->bounce_buf, new_buff_len, enqd_len); + seg->bounce_dma = dma_map_single(dev, seg->bounce_buf, + max_pkt, DMA_TO_DEVICE); + } else { + seg->bounce_dma = dma_map_single(dev, seg->bounce_buf, + max_pkt, DMA_FROM_DEVICE); + } + + if (dma_mapping_error(dev, seg->bounce_dma)) { + /* try without aligning. Some host controllers survive */ + xhci_warn(xhci, "Failed mapping bounce buffer, not aligning\n"); + return 0; + } + *trb_buff_len = new_buff_len; + seg->bounce_len = new_buff_len; + seg->bounce_offs = enqd_len; + + xhci_dbg(xhci, "Bounce align, new buff len %d\n", *trb_buff_len); + return 1; } @@ -3152,9 +3227,9 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags, unsigned int num_trbs; unsigned int start_cycle, num_sgs = 0; unsigned int enqd_len, block_len, trb_buff_len, full_len; - int ret; + int sent_len, ret; u32 field, length_field, remainder; - u64 addr; + u64 addr, send_addr; ring = xhci_urb_to_transfer_ring(xhci, urb); if (!ring) @@ -3194,6 +3269,7 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags, */ start_trb = &ring->enqueue->generic; start_cycle = ring->cycle_state; + send_addr = addr; /* Queue the TRBs, even if they are zero-length */ for (enqd_len = 0; enqd_len < full_len; enqd_len += trb_buff_len) { @@ -3222,10 +3298,16 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags, if (last_trb(xhci, ring, ring->enq_seg, ring->enqueue + 1)) { if (xhci_align_td(xhci, urb, enqd_len, - &trb_buff_len)) - xhci_dbg(xhci, "TRB align fail\n"); + &trb_buff_len, + ring->enq_seg)) { + send_addr = ring->enq_seg->bounce_dma; + /* assuming TD won't span 2 segs */ + td->bounce_seg = ring->enq_seg; + } } - } else { + } + if (enqd_len + trb_buff_len >= full_len) { + field &= ~TRB_CHAIN; field |= TRB_IOC; more_trbs_coming = false; td->last_trb = ring->enqueue; @@ -3244,23 +3326,27 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags, TRB_INTR_TARGET(0); queue_trb(xhci, ring, more_trbs_coming | need_zero_pkt, - lower_32_bits(addr), - upper_32_bits(addr), + lower_32_bits(send_addr), + upper_32_bits(send_addr), length_field, field); addr += trb_buff_len; - block_len -= trb_buff_len; + sent_len = trb_buff_len; - if (sg && block_len == 0) { + while (sg && sent_len >= block_len) { /* New sg entry */ --num_sgs; + sent_len -= block_len; if (num_sgs != 0) { sg = sg_next(sg); block_len = sg_dma_len(sg); addr = (u64) sg_dma_address(sg); + addr += sent_len; } } + block_len -= sent_len; + send_addr = addr; } if (need_zero_pkt) { diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index f2f9518..9da9832 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -3139,6 +3139,7 @@ int xhci_alloc_streams(struct usb_hcd *hcd, struct usb_device *udev, struct xhci_input_control_ctx *ctrl_ctx; unsigned int ep_index; unsigned int num_stream_ctxs; + unsigned int max_packet; unsigned long flags; u32 changed_ep_bitmask = 0; @@ -3212,9 +3213,11 @@ int xhci_alloc_streams(struct usb_hcd *hcd, struct usb_device *udev, for (i = 0; i < num_eps; i++) { ep_index = xhci_get_endpoint_index(&eps[i]->desc); + max_packet = GET_MAX_PACKET(usb_endpoint_maxp(&eps[i]->desc)); vdev->eps[ep_index].stream_info = xhci_alloc_stream_info(xhci, num_stream_ctxs, - num_streams, mem_flags); + num_streams, + max_packet, mem_flags); if (!vdev->eps[ep_index].stream_info) goto cleanup; /* Set maxPstreams in endpoint context and update deq ptr to diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index b0b8d0f..b2c1dc5 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -1347,6 +1347,11 @@ struct xhci_segment { /* private to HCD */ struct xhci_segment *next; dma_addr_t dma; + /* Max packet sized bounce buffer for td-fragmant alignment */ + dma_addr_t bounce_dma; + void *bounce_buf; + unsigned int bounce_offs; + unsigned int bounce_len; }; struct xhci_td { @@ -1356,6 +1361,7 @@ struct xhci_td { struct xhci_segment *start_seg; union xhci_trb *first_trb; union xhci_trb *last_trb; + struct xhci_segment *bounce_seg; /* actual_length of the URB has already been set */ bool urb_length_set; }; @@ -1405,6 +1411,7 @@ struct xhci_ring { unsigned int num_segs; unsigned int num_trbs_free; unsigned int num_trbs_free_temp; + unsigned int bounce_buf_len; enum xhci_ring_type type; bool last_td_was_short; struct radix_tree_root *trb_address_map; @@ -1807,7 +1814,8 @@ void xhci_free_or_cache_endpoint_ring(struct xhci_hcd *xhci, unsigned int ep_index); struct xhci_stream_info *xhci_alloc_stream_info(struct xhci_hcd *xhci, unsigned int num_stream_ctxs, - unsigned int num_streams, gfp_t flags); + unsigned int num_streams, + unsigned int max_packet, gfp_t flags); void xhci_free_stream_info(struct xhci_hcd *xhci, struct xhci_stream_info *stream_info); void xhci_setup_streams_ep_input_ctx(struct xhci_hcd *xhci, -- cgit v0.10.2 From 2251198bef4252c9b64fadd271f03da46cf802e8 Mon Sep 17 00:00:00 2001 From: Mathias Nyman Date: Tue, 21 Jun 2016 10:58:03 +0300 Subject: xhci: clean up event ring checks from inc_enq() Remove the event ring related checks in inc_enq() Host hardware is the producer of events on the event ring, driver will not queue anything, or call inc_enq() for the event ring. Signed-off-by: Mathias Nyman Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index b2c861e..34fd641 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -199,50 +199,42 @@ static void inc_enq(struct xhci_hcd *xhci, struct xhci_ring *ring, chain = le32_to_cpu(ring->enqueue->generic.field[3]) & TRB_CHAIN; /* If this is not event ring, there is one less usable TRB */ - if (ring->type != TYPE_EVENT && - !last_trb(xhci, ring, ring->enq_seg, ring->enqueue)) + if (!last_trb(xhci, ring, ring->enq_seg, ring->enqueue)) ring->num_trbs_free--; next = ++(ring->enqueue); ring->enq_updates++; - /* Update the dequeue pointer further if that was a link TRB or we're at - * the end of an event ring segment (which doesn't have link TRBS) - */ + /* Update the dequeue pointer further if that was a link TRB */ while (last_trb(xhci, ring, ring->enq_seg, next)) { - if (ring->type != TYPE_EVENT) { - /* - * If the caller doesn't plan on enqueueing more - * TDs before ringing the doorbell, then we - * don't want to give the link TRB to the - * hardware just yet. We'll give the link TRB - * back in prepare_ring() just before we enqueue - * the TD at the top of the ring. - */ - if (!chain && !more_trbs_coming) - break; - /* If we're not dealing with 0.95 hardware or - * isoc rings on AMD 0.96 host, - * carry over the chain bit of the previous TRB - * (which may mean the chain bit is cleared). - */ - if (!(ring->type == TYPE_ISOC && - (xhci->quirks & XHCI_AMD_0x96_HOST)) - && !xhci_link_trb_quirk(xhci)) { - next->link.control &= - cpu_to_le32(~TRB_CHAIN); - next->link.control |= - cpu_to_le32(chain); - } - /* Give this link TRB to the hardware */ - wmb(); - next->link.control ^= cpu_to_le32(TRB_CYCLE); + /* + * If the caller doesn't plan on enqueueing more TDs before + * ringing the doorbell, then we don't want to give the link TRB + * to the hardware just yet. We'll give the link TRB back in + * prepare_ring() just before we enqueue the TD at the top of + * the ring. + */ + if (!chain && !more_trbs_coming) + break; - /* Toggle the cycle bit after the last ring segment. */ - if (last_trb_on_last_seg(xhci, ring, ring->enq_seg, next)) { - ring->cycle_state ^= 1; - } + /* If we're not dealing with 0.95 hardware or isoc rings on + * AMD 0.96 host, carry over the chain bit of the previous TRB + * (which may mean the chain bit is cleared). + */ + if (!(ring->type == TYPE_ISOC && + (xhci->quirks & XHCI_AMD_0x96_HOST)) && + !xhci_link_trb_quirk(xhci)) { + next->link.control &= cpu_to_le32(~TRB_CHAIN); + next->link.control |= cpu_to_le32(chain); } + /* Give this link TRB to the hardware */ + wmb(); + next->link.control ^= cpu_to_le32(TRB_CYCLE); + + /* Toggle the cycle bit after the last ring segment. */ + if (last_trb_on_last_seg(xhci, ring, ring->enq_seg, next)) + ring->cycle_state ^= 1; + ring->enq_seg = ring->enq_seg->next; ring->enqueue = ring->enq_seg->trbs; next = ring->enqueue; -- cgit v0.10.2 From 2d98ef406f17ec3cfc196dc65c0e53d7fab8671b Mon Sep 17 00:00:00 2001 From: Mathias Nyman Date: Tue, 21 Jun 2016 10:58:04 +0300 Subject: xhci: use and add separate function for checking for link trbs Add a new is_link_trb() function that only checks for link trbs. We want to split generic last_trb() function which is used for both event rings without link trbs, and endpoint and command rings with links. This will allow us to easier check for link trbs added mid segments. Signed-off-by: Mathias Nyman Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index 34fd641..eaa3822 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -115,6 +115,11 @@ static int last_trb(struct xhci_hcd *xhci, struct xhci_ring *ring, return TRB_TYPE_LINK_LE32(trb->link.control); } +static bool trb_is_link(union xhci_trb *trb) +{ + return TRB_TYPE_LINK_LE32(trb->link.control); +} + static int enqueue_is_link_trb(struct xhci_ring *ring) { struct xhci_link_trb *link = &ring->enqueue->link; @@ -130,7 +135,7 @@ static void next_trb(struct xhci_hcd *xhci, struct xhci_segment **seg, union xhci_trb **trb) { - if (last_trb(xhci, ring, *seg, *trb)) { + if (trb_is_link(*trb)) { *seg = (*seg)->next; *trb = ((*seg)->trbs); } else { @@ -150,8 +155,7 @@ static void inc_deq(struct xhci_hcd *xhci, struct xhci_ring *ring) * If this is not event ring, and the dequeue pointer * is not on a link TRB, there is one more usable TRB */ - if (ring->type != TYPE_EVENT && - !last_trb(xhci, ring, ring->deq_seg, ring->dequeue)) + if (ring->type != TYPE_EVENT && !trb_is_link(ring->dequeue)) ring->num_trbs_free++; do { @@ -199,13 +203,13 @@ static void inc_enq(struct xhci_hcd *xhci, struct xhci_ring *ring, chain = le32_to_cpu(ring->enqueue->generic.field[3]) & TRB_CHAIN; /* If this is not event ring, there is one less usable TRB */ - if (!last_trb(xhci, ring, ring->enq_seg, ring->enqueue)) + if (!trb_is_link(ring->enqueue)) ring->num_trbs_free--; next = ++(ring->enqueue); ring->enq_updates++; /* Update the dequeue pointer further if that was a link TRB */ - while (last_trb(xhci, ring, ring->enq_seg, next)) { + while (trb_is_link(next)) { /* * If the caller doesn't plan on enqueueing more TDs before @@ -940,7 +944,7 @@ static void update_ring_for_set_deq_completion(struct xhci_hcd *xhci, * the dequeue pointer one segment further, or we'll jump off * the segment into la-la-land. */ - if (last_trb(xhci, ep_ring, ep_ring->deq_seg, ep_ring->dequeue)) { + if (trb_is_link(ep_ring->dequeue)) { ep_ring->deq_seg = ep_ring->deq_seg->next; ep_ring->dequeue = ep_ring->deq_seg->trbs; } @@ -949,8 +953,7 @@ static void update_ring_for_set_deq_completion(struct xhci_hcd *xhci, /* We have more usable TRBs */ ep_ring->num_trbs_free++; ep_ring->dequeue++; - if (last_trb(xhci, ep_ring, ep_ring->deq_seg, - ep_ring->dequeue)) { + if (trb_is_link(ep_ring->dequeue)) { if (ep_ring->dequeue == dev->eps[ep_index].queued_deq_ptr) break; @@ -2898,7 +2901,7 @@ static int prepare_ring(struct xhci_hcd *xhci, struct xhci_ring *ep_ring, next = ring->enqueue; - while (last_trb(xhci, ring, ring->enq_seg, next)) { + while (trb_is_link(next)) { /* If we're not dealing with 0.95 hardware or isoc rings * on AMD 0.96 host, clear the chain bit. */ @@ -3287,8 +3290,7 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags, */ if (enqd_len + trb_buff_len < full_len) { field |= TRB_CHAIN; - if (last_trb(xhci, ring, ring->enq_seg, - ring->enqueue + 1)) { + if (trb_is_link(ring->enqueue + 1)) { if (xhci_align_td(xhci, urb, enqd_len, &trb_buff_len, ring->enq_seg)) { -- cgit v0.10.2 From bd5e67f59a2e26d8c342590df2d0936c237d8f1a Mon Sep 17 00:00:00 2001 From: Mathias Nyman Date: Tue, 21 Jun 2016 10:58:05 +0300 Subject: xhci: rework inc_deq() and fix off by one error. inc_deq() is called both for rings with link trbs and the event ring without link trbs. The last_trb() check in inc_deq() has a off by one error, going beyond allocated array when checking if trb == [TRBS_PER_SEGMENT], and the whole inc_deq() depend on this. Rewrite the inc_deq() funciton, remove the faulty last_trb() helper, add new last_trb_on_seg() and last_trb_on_ring() helpers Signed-off-by: Mathias Nyman Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index eaa3822..89ce94c 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -102,19 +102,6 @@ static bool last_trb_on_last_seg(struct xhci_hcd *xhci, struct xhci_ring *ring, return le32_to_cpu(trb->link.control) & LINK_TOGGLE; } -/* Is this TRB a link TRB or was the last TRB the last TRB in this event ring - * segment? I.e. would the updated event TRB pointer step off the end of the - * event seg? - */ -static int last_trb(struct xhci_hcd *xhci, struct xhci_ring *ring, - struct xhci_segment *seg, union xhci_trb *trb) -{ - if (ring == xhci->event_ring) - return trb == &seg->trbs[TRBS_PER_SEGMENT]; - else - return TRB_TYPE_LINK_LE32(trb->link.control); -} - static bool trb_is_link(union xhci_trb *trb) { return TRB_TYPE_LINK_LE32(trb->link.control); @@ -126,6 +113,17 @@ static int enqueue_is_link_trb(struct xhci_ring *ring) return TRB_TYPE_LINK_LE32(link->control); } +static bool last_trb_on_seg(struct xhci_segment *seg, union xhci_trb *trb) +{ + return trb == &seg->trbs[TRBS_PER_SEGMENT - 1]; +} + +static bool last_trb_on_ring(struct xhci_ring *ring, + struct xhci_segment *seg, union xhci_trb *trb) +{ + return last_trb_on_seg(seg, trb) && (seg->next == ring->first_seg); +} + /* Updates trb to point to the next TRB in the ring, and updates seg if the next * TRB is in a new segment. This does not skip over link TRBs, and it does not * effect the ring dequeue or enqueue pointers. @@ -151,31 +149,29 @@ static void inc_deq(struct xhci_hcd *xhci, struct xhci_ring *ring) { ring->deq_updates++; - /* - * If this is not event ring, and the dequeue pointer - * is not on a link TRB, there is one more usable TRB - */ - if (ring->type != TYPE_EVENT && !trb_is_link(ring->dequeue)) - ring->num_trbs_free++; - - do { - /* - * Update the dequeue pointer further if that was a link TRB or - * we're at the end of an event ring segment (which doesn't have - * link TRBS) - */ - if (last_trb(xhci, ring, ring->deq_seg, ring->dequeue)) { - if (ring->type == TYPE_EVENT && - last_trb_on_last_seg(xhci, ring, - ring->deq_seg, ring->dequeue)) { - ring->cycle_state ^= 1; - } - ring->deq_seg = ring->deq_seg->next; - ring->dequeue = ring->deq_seg->trbs; - } else { + /* event ring doesn't have link trbs, check for last trb */ + if (ring->type == TYPE_EVENT) { + if (!last_trb_on_seg(ring->deq_seg, ring->dequeue)) { ring->dequeue++; + return; } - } while (last_trb(xhci, ring, ring->deq_seg, ring->dequeue)); + if (last_trb_on_ring(ring, ring->deq_seg, ring->dequeue)) + ring->cycle_state ^= 1; + ring->deq_seg = ring->deq_seg->next; + ring->dequeue = ring->deq_seg->trbs; + return; + } + + /* All other rings have link trbs */ + if (!trb_is_link(ring->dequeue)) { + ring->dequeue++; + ring->num_trbs_free++; + } + while (trb_is_link(ring->dequeue)) { + ring->deq_seg = ring->deq_seg->next; + ring->dequeue = ring->deq_seg->trbs; + } + return; } /* -- cgit v0.10.2 From 549310ab5d72158b84c80995894eb1ade5453ef1 Mon Sep 17 00:00:00 2001 From: Mathias Nyman Date: Tue, 21 Jun 2016 10:58:06 +0300 Subject: xhci: remove enqueue_is_link() helper Only used in one place, replace with trb_is_link() helper Signed-off-by: Mathias Nyman Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index 89ce94c..64e24d2 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -107,12 +107,6 @@ static bool trb_is_link(union xhci_trb *trb) return TRB_TYPE_LINK_LE32(trb->link.control); } -static int enqueue_is_link_trb(struct xhci_ring *ring) -{ - struct xhci_link_trb *link = &ring->enqueue->link; - return TRB_TYPE_LINK_LE32(link->control); -} - static bool last_trb_on_seg(struct xhci_segment *seg, union xhci_trb *trb) { return trb == &seg->trbs[TRBS_PER_SEGMENT - 1]; @@ -2891,7 +2885,7 @@ static int prepare_ring(struct xhci_hcd *xhci, struct xhci_ring *ep_ring, } } - if (enqueue_is_link_trb(ep_ring)) { + if (trb_is_link(ep_ring->enqueue)) { struct xhci_ring *ring = ep_ring; union xhci_trb *next; -- cgit v0.10.2 From d0c77d84b497965dcdedb2a755cc5e45b9320aea Mon Sep 17 00:00:00 2001 From: Mathias Nyman Date: Tue, 21 Jun 2016 10:58:07 +0300 Subject: xhci: rename and simplify last_trb_on_last_seg() helper It's only used with rings that have link trbs Signed-off-by: Mathias Nyman Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index 64e24d2..21e1dd6 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -89,19 +89,6 @@ dma_addr_t xhci_trb_virt_to_dma(struct xhci_segment *seg, return seg->dma + (segment_offset * sizeof(*trb)); } -/* Does this link TRB point to the first segment in a ring, - * or was the previous TRB the last TRB on the last segment in the ERST? - */ -static bool last_trb_on_last_seg(struct xhci_hcd *xhci, struct xhci_ring *ring, - struct xhci_segment *seg, union xhci_trb *trb) -{ - if (ring == xhci->event_ring) - return (trb == &seg->trbs[TRBS_PER_SEGMENT]) && - (seg->next == xhci->event_ring->first_seg); - else - return le32_to_cpu(trb->link.control) & LINK_TOGGLE; -} - static bool trb_is_link(union xhci_trb *trb) { return TRB_TYPE_LINK_LE32(trb->link.control); @@ -118,6 +105,11 @@ static bool last_trb_on_ring(struct xhci_ring *ring, return last_trb_on_seg(seg, trb) && (seg->next == ring->first_seg); } +static bool link_trb_toggles_cycle(union xhci_trb *trb) +{ + return le32_to_cpu(trb->link.control) & LINK_TOGGLE; +} + /* Updates trb to point to the next TRB in the ring, and updates seg if the next * TRB is in a new segment. This does not skip over link TRBs, and it does not * effect the ring dequeue or enqueue pointers. @@ -226,7 +218,7 @@ static void inc_enq(struct xhci_hcd *xhci, struct xhci_ring *ring, next->link.control ^= cpu_to_le32(TRB_CYCLE); /* Toggle the cycle bit after the last ring segment. */ - if (last_trb_on_last_seg(xhci, ring, ring->enq_seg, next)) + if (link_trb_toggles_cycle(next)) ring->cycle_state ^= 1; ring->enq_seg = ring->enq_seg->next; @@ -2885,36 +2877,29 @@ static int prepare_ring(struct xhci_hcd *xhci, struct xhci_ring *ep_ring, } } - if (trb_is_link(ep_ring->enqueue)) { - struct xhci_ring *ring = ep_ring; - union xhci_trb *next; - - next = ring->enqueue; + while (trb_is_link(ep_ring->enqueue)) { + /* If we're not dealing with 0.95 hardware or isoc rings + * on AMD 0.96 host, clear the chain bit. + */ + if (!xhci_link_trb_quirk(xhci) && + !(ep_ring->type == TYPE_ISOC && + (xhci->quirks & XHCI_AMD_0x96_HOST))) + ep_ring->enqueue->link.control &= + cpu_to_le32(~TRB_CHAIN); + else + ep_ring->enqueue->link.control |= + cpu_to_le32(TRB_CHAIN); - while (trb_is_link(next)) { - /* If we're not dealing with 0.95 hardware or isoc rings - * on AMD 0.96 host, clear the chain bit. - */ - if (!xhci_link_trb_quirk(xhci) && - !(ring->type == TYPE_ISOC && - (xhci->quirks & XHCI_AMD_0x96_HOST))) - next->link.control &= cpu_to_le32(~TRB_CHAIN); - else - next->link.control |= cpu_to_le32(TRB_CHAIN); + wmb(); + ep_ring->enqueue->link.control ^= cpu_to_le32(TRB_CYCLE); - wmb(); - next->link.control ^= cpu_to_le32(TRB_CYCLE); + /* Toggle the cycle bit after the last ring segment. */ + if (link_trb_toggles_cycle(ep_ring->enqueue)) + ep_ring->cycle_state ^= 1; - /* Toggle the cycle bit after the last ring segment. */ - if (last_trb_on_last_seg(xhci, ring, ring->enq_seg, next)) { - ring->cycle_state ^= 1; - } - ring->enq_seg = ring->enq_seg->next; - ring->enqueue = ring->enq_seg->trbs; - next = ring->enqueue; - } + ep_ring->enq_seg = ep_ring->enq_seg->next; + ep_ring->enqueue = ep_ring->enq_seg->trbs; } - return 0; } -- cgit v0.10.2 From 76f9502fe7616a10a471f2599eee783dbd2674e5 Mon Sep 17 00:00:00 2001 From: Heikki Krogerus Date: Tue, 21 Jun 2016 10:58:08 +0300 Subject: xhci: plat: adapt to unified device property interface Requesting the only property that the driver needs using the unified device property interface so it will be available for all types of platforms, not just the ones using DT. Signed-off-by: Heikki Krogerus Signed-off-by: Mathias Nyman Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/host/xhci-plat.c b/drivers/usb/host/xhci-plat.c index 1f3f981..d1db8bb 100644 --- a/drivers/usb/host/xhci-plat.c +++ b/drivers/usb/host/xhci-plat.c @@ -138,7 +138,6 @@ MODULE_DEVICE_TABLE(of, usb_xhci_of_match); static int xhci_plat_probe(struct platform_device *pdev) { - struct device_node *node = pdev->dev.of_node; struct usb_xhci_pdata *pdata = dev_get_platdata(&pdev->dev); const struct of_device_id *match; const struct hc_driver *driver; @@ -202,7 +201,7 @@ static int xhci_plat_probe(struct platform_device *pdev) } xhci = hcd_to_xhci(hcd); - match = of_match_node(usb_xhci_of_match, node); + match = of_match_node(usb_xhci_of_match, pdev->dev.of_node); if (match) { const struct xhci_plat_priv *priv_match = match->data; struct xhci_plat_priv *priv = hcd_to_xhci_priv(hcd); @@ -223,7 +222,7 @@ static int xhci_plat_probe(struct platform_device *pdev) goto disable_clk; } - if ((node && of_property_read_bool(node, "usb3-lpm-capable")) || + if (device_property_read_bool(&pdev->dev, "usb3-lpm-capable") || (pdata && pdata->usb3_lpm_capable)) xhci->quirks |= XHCI_LPM_SUPPORT; -- cgit v0.10.2 From 95b57df45062d7005ff01ed956b69166b6b3481e Mon Sep 17 00:00:00 2001 From: Heikki Krogerus Date: Tue, 21 Jun 2016 10:58:09 +0300 Subject: usb: dwc3: host: use build-in property instead of platform data This should allow xhci to remove handling of platform data. Signed-off-by: Heikki Krogerus Signed-off-by: Mathias Nyman Acked-by: Felipe Balbi Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/dwc3/host.c b/drivers/usb/dwc3/host.c index c679f63..67f90d7 100644 --- a/drivers/usb/dwc3/host.c +++ b/drivers/usb/dwc3/host.c @@ -16,14 +16,13 @@ */ #include -#include #include "core.h" int dwc3_host_init(struct dwc3 *dwc) { + struct property_entry props[2]; struct platform_device *xhci; - struct usb_xhci_pdata pdata; int ret; xhci = platform_device_alloc("xhci-hcd", PLATFORM_DEVID_AUTO); @@ -47,14 +46,15 @@ int dwc3_host_init(struct dwc3 *dwc) goto err1; } - memset(&pdata, 0, sizeof(pdata)); + memset(props, 0, sizeof(struct property_entry) * ARRAY_SIZE(props)); - pdata.usb3_lpm_capable = dwc->usb3_lpm_capable; - - ret = platform_device_add_data(xhci, &pdata, sizeof(pdata)); - if (ret) { - dev_err(dwc->dev, "couldn't add platform data to xHCI device\n"); - goto err1; + if (dwc->usb3_lpm_capable) { + props[0].name = "usb3-lpm-capable"; + ret = platform_device_add_properties(xhci, props); + if (ret) { + dev_err(dwc->dev, "failed to add properties to xHCI\n"); + goto err1; + } } phy_create_lookup(dwc->usb2_generic_phy, "usb2-phy", -- cgit v0.10.2 From a3aef37930713447b45b1f0f9f8841be44f7db45 Mon Sep 17 00:00:00 2001 From: Heikki Krogerus Date: Tue, 21 Jun 2016 10:58:10 +0300 Subject: xhci: get rid of platform data No more users for it. Signed-off-by: Heikki Krogerus Signed-off-by: Mathias Nyman Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/host/xhci-plat.c b/drivers/usb/host/xhci-plat.c index d1db8bb..ed56bf9 100644 --- a/drivers/usb/host/xhci-plat.c +++ b/drivers/usb/host/xhci-plat.c @@ -18,7 +18,6 @@ #include #include #include -#include #include #include "xhci.h" @@ -138,7 +137,6 @@ MODULE_DEVICE_TABLE(of, usb_xhci_of_match); static int xhci_plat_probe(struct platform_device *pdev) { - struct usb_xhci_pdata *pdata = dev_get_platdata(&pdev->dev); const struct of_device_id *match; const struct hc_driver *driver; struct xhci_hcd *xhci; @@ -222,8 +220,7 @@ static int xhci_plat_probe(struct platform_device *pdev) goto disable_clk; } - if (device_property_read_bool(&pdev->dev, "usb3-lpm-capable") || - (pdata && pdata->usb3_lpm_capable)) + if (device_property_read_bool(&pdev->dev, "usb3-lpm-capable")) xhci->quirks |= XHCI_LPM_SUPPORT; if (HCC_MAX_PSA(xhci->hcc_params) >= 4) diff --git a/include/linux/usb/xhci_pdriver.h b/include/linux/usb/xhci_pdriver.h deleted file mode 100644 index 376654b..0000000 --- a/include/linux/usb/xhci_pdriver.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - */ - -#ifndef __USB_CORE_XHCI_PDRIVER_H -#define __USB_CORE_XHCI_PDRIVER_H - -/** - * struct usb_xhci_pdata - platform_data for generic xhci platform driver - * - * @usb3_lpm_capable: determines if this xhci platform supports USB3 - * LPM capability - * - */ -struct usb_xhci_pdata { - unsigned usb3_lpm_capable:1; -}; - -#endif /* __USB_CORE_XHCI_PDRIVER_H */ -- cgit v0.10.2 From 4e84e22195910b315b36eca149febd0a6b02f7c4 Mon Sep 17 00:00:00 2001 From: Paul Gortmaker Date: Wed, 15 Jun 2016 17:52:14 -0400 Subject: usb: early/ehci-dbgp: make it explicitly non-modular The Kconfig currently controlling compilation of this code is: arch/x86/Kconfig.debug:config EARLY_PRINTK_DBGP arch/x86/Kconfig.debug: bool "Early printk via EHCI debug port" ...meaning that it currently is not being built as a module by anyone. Lets remove the couple traces of modularity so that when reading the driver there is no doubt it is builtin-only. Since module_init translates to device_initcall in the non-modular case, the init ordering remains unchanged with this commit. Cc: Greg Kroah-Hartman Cc: linux-usb@vger.kernel.org Signed-off-by: Paul Gortmaker Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/early/ehci-dbgp.c b/drivers/usb/early/ehci-dbgp.c index 8cfc319..12731e6 100644 --- a/drivers/usb/early/ehci-dbgp.c +++ b/drivers/usb/early/ehci-dbgp.c @@ -13,7 +13,7 @@ #include #include -#include +#include #include #include #include @@ -1093,5 +1093,5 @@ static int __init kgdbdbgp_start_thread(void) return 0; } -module_init(kgdbdbgp_start_thread); +device_initcall(kgdbdbgp_start_thread); #endif /* CONFIG_KGDB */ -- cgit v0.10.2 From 107a4b535b7d1da4203a26949775d67173e96e04 Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Tue, 21 Jun 2016 18:52:54 +0100 Subject: usb: renesas_usbhs: make usbhs_write32() static The usbhs_write32 function is not used outside of the rcar3.c file, so fix the following sparse warning by making it static: drivers/usb/renesas_usbhs/rcar3.c:26:6: warning: symbol 'usbhs_write32' was not declared. Should it be static? Signed-off-by: Ben Dooks Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/renesas_usbhs/rcar3.c b/drivers/usb/renesas_usbhs/rcar3.c index 38b01f2..1d70add 100644 --- a/drivers/usb/renesas_usbhs/rcar3.c +++ b/drivers/usb/renesas_usbhs/rcar3.c @@ -23,7 +23,7 @@ #define UGCTRL2_RESERVED_3 0x00000001 /* bit[3:0] should be B'0001 */ #define UGCTRL2_USB0SEL_OTG 0x00000030 -void usbhs_write32(struct usbhs_priv *priv, u32 reg, u32 data) +static void usbhs_write32(struct usbhs_priv *priv, u32 reg, u32 data) { iowrite32(data, priv->base + reg); } -- cgit v0.10.2 From 3d579c350842c7a46da2da76b3461f7cfa3f6df9 Mon Sep 17 00:00:00 2001 From: Stuart Yoder Date: Wed, 22 Jun 2016 16:40:42 -0500 Subject: staging: fsl-mc: add support for the modalias sysfs attribute In order to support uevent based module loading implement modalias support for the fsl-mc bus driver. Aliases are based on vendor and object/device id and are of the form "fsl-mc:vNdN". Signed-off-by: Stuart Yoder Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/fsl-mc/bus/mc-bus.c b/drivers/staging/fsl-mc/bus/mc-bus.c index 4053643..d8776dd 100644 --- a/drivers/staging/fsl-mc/bus/mc-bus.c +++ b/drivers/staging/fsl-mc/bus/mc-bus.c @@ -82,10 +82,35 @@ static int fsl_mc_bus_uevent(struct device *dev, struct kobj_uevent_env *env) return 0; } +static ssize_t modalias_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct fsl_mc_device *mc_dev = to_fsl_mc_device(dev); + + return sprintf(buf, "fsl-mc:v%08Xd%s\n", mc_dev->obj_desc.vendor, + mc_dev->obj_desc.type); +} +static DEVICE_ATTR_RO(modalias); + +static struct attribute *fsl_mc_dev_attrs[] = { + &dev_attr_modalias.attr, + NULL, +}; + +static const struct attribute_group fsl_mc_dev_group = { + .attrs = fsl_mc_dev_attrs, +}; + +static const struct attribute_group *fsl_mc_dev_groups[] = { + &fsl_mc_dev_group, + NULL, +}; + struct bus_type fsl_mc_bus_type = { .name = "fsl-mc", .match = fsl_mc_bus_match, .uevent = fsl_mc_bus_uevent, + .dev_groups = fsl_mc_dev_groups, }; EXPORT_SYMBOL_GPL(fsl_mc_bus_type); -- cgit v0.10.2 From d568b7679f03aca820e61a758a8b034cff8ccb40 Mon Sep 17 00:00:00 2001 From: Stuart Yoder Date: Wed, 22 Jun 2016 16:40:43 -0500 Subject: staging: fsl-mc: implement uevent callback and set the modalias Replace placeholder code in the uevent callback to properly set the MODALIAS env variable. Signed-off-by: Stuart Yoder Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/fsl-mc/bus/mc-bus.c b/drivers/staging/fsl-mc/bus/mc-bus.c index d8776dd..cf92a1c 100644 --- a/drivers/staging/fsl-mc/bus/mc-bus.c +++ b/drivers/staging/fsl-mc/bus/mc-bus.c @@ -78,7 +78,13 @@ out: */ static int fsl_mc_bus_uevent(struct device *dev, struct kobj_uevent_env *env) { - pr_debug("%s invoked\n", __func__); + struct fsl_mc_device *mc_dev = to_fsl_mc_device(dev); + + if (add_uevent_var(env, "MODALIAS=fsl-mc:v%08Xd%s", + mc_dev->obj_desc.vendor, + mc_dev->obj_desc.type)) + return -ENOMEM; + return 0; } -- cgit v0.10.2 From 57538afb42e492eb6984f89663361bcfd80d9745 Mon Sep 17 00:00:00 2001 From: Stuart Yoder Date: Wed, 22 Jun 2016 16:40:44 -0500 Subject: staging: fsl-mc: clean up the device id struct -rename the struct used for fsl-mc device ids to be more consistent with other busses -remove the now obsolete and unused version fields Signed-off-by: Stuart Yoder Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/fsl-mc/bus/dprc-driver.c b/drivers/staging/fsl-mc/bus/dprc-driver.c index 7fc4717..f865d18 100644 --- a/drivers/staging/fsl-mc/bus/dprc-driver.c +++ b/drivers/staging/fsl-mc/bus/dprc-driver.c @@ -805,7 +805,7 @@ static int dprc_remove(struct fsl_mc_device *mc_dev) return 0; } -static const struct fsl_mc_device_match_id match_id_table[] = { +static const struct fsl_mc_device_id match_id_table[] = { { .vendor = FSL_MC_VENDOR_FREESCALE, .obj_type = "dprc"}, diff --git a/drivers/staging/fsl-mc/bus/mc-allocator.c b/drivers/staging/fsl-mc/bus/mc-allocator.c index fb08f22..e59d850 100644 --- a/drivers/staging/fsl-mc/bus/mc-allocator.c +++ b/drivers/staging/fsl-mc/bus/mc-allocator.c @@ -717,7 +717,7 @@ static int fsl_mc_allocator_remove(struct fsl_mc_device *mc_dev) return 0; } -static const struct fsl_mc_device_match_id match_id_table[] = { +static const struct fsl_mc_device_id match_id_table[] = { { .vendor = FSL_MC_VENDOR_FREESCALE, .obj_type = "dpbp", diff --git a/drivers/staging/fsl-mc/bus/mc-bus.c b/drivers/staging/fsl-mc/bus/mc-bus.c index cf92a1c..e975adc 100644 --- a/drivers/staging/fsl-mc/bus/mc-bus.c +++ b/drivers/staging/fsl-mc/bus/mc-bus.c @@ -36,7 +36,7 @@ static bool fsl_mc_is_root_dprc(struct device *dev); */ static int fsl_mc_bus_match(struct device *dev, struct device_driver *drv) { - const struct fsl_mc_device_match_id *id; + const struct fsl_mc_device_id *id; struct fsl_mc_device *mc_dev = to_fsl_mc_device(dev); struct fsl_mc_driver *mc_drv = to_fsl_mc_driver(drv); bool found = false; diff --git a/drivers/staging/fsl-mc/include/mc.h b/drivers/staging/fsl-mc/include/mc.h index ac7c1ce..bc0d45c 100644 --- a/drivers/staging/fsl-mc/include/mc.h +++ b/drivers/staging/fsl-mc/include/mc.h @@ -39,7 +39,7 @@ struct fsl_mc_bus; */ struct fsl_mc_driver { struct device_driver driver; - const struct fsl_mc_device_match_id *match_id_table; + const struct fsl_mc_device_id *match_id_table; int (*probe)(struct fsl_mc_device *dev); int (*remove)(struct fsl_mc_device *dev); void (*shutdown)(struct fsl_mc_device *dev); @@ -51,20 +51,16 @@ struct fsl_mc_driver { container_of(_drv, struct fsl_mc_driver, driver) /** - * struct fsl_mc_device_match_id - MC object device Id entry for driver matching + * struct fsl_mc_device_id - MC object device Id entry for driver matching * @vendor: vendor ID * @obj_type: MC object type - * @ver_major: MC object version major number - * @ver_minor: MC object version minor number * * Type of entries in the "device Id" table for MC object devices supported by * a MC object device driver. The last entry of the table has vendor set to 0x0 */ -struct fsl_mc_device_match_id { +struct fsl_mc_device_id { u16 vendor; const char obj_type[16]; - u32 ver_major; - u32 ver_minor; }; /** -- cgit v0.10.2 From 0afef45654ae908536278ecb143ded5bbc713391 Mon Sep 17 00:00:00 2001 From: Stuart Yoder Date: Wed, 22 Jun 2016 16:40:45 -0500 Subject: staging: fsl-mc: add support for device table matching Move the definition of fsl_mc_device_id to its proper location in mod_devicetable.h, and add fsl-mc bus support to devicetable-offsets.c and file2alias.c to enable device table matching. With this patch udev based module loading of fsl-mc drivers is supported. Signed-off-by: Stuart Yoder Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/fsl-mc/include/mc.h b/drivers/staging/fsl-mc/include/mc.h index bc0d45c..a9a9d23 100644 --- a/drivers/staging/fsl-mc/include/mc.h +++ b/drivers/staging/fsl-mc/include/mc.h @@ -51,19 +51,6 @@ struct fsl_mc_driver { container_of(_drv, struct fsl_mc_driver, driver) /** - * struct fsl_mc_device_id - MC object device Id entry for driver matching - * @vendor: vendor ID - * @obj_type: MC object type - * - * Type of entries in the "device Id" table for MC object devices supported by - * a MC object device driver. The last entry of the table has vendor set to 0x0 - */ -struct fsl_mc_device_id { - u16 vendor; - const char obj_type[16]; -}; - -/** * enum fsl_mc_pool_type - Types of allocatable MC bus resources * * Entries in these enum are used as indices in the array of resource diff --git a/include/linux/mod_devicetable.h b/include/linux/mod_devicetable.h index 6e4c645..ed84c07 100644 --- a/include/linux/mod_devicetable.h +++ b/include/linux/mod_devicetable.h @@ -657,4 +657,20 @@ struct ulpi_device_id { kernel_ulong_t driver_data; }; +/** + * struct fsl_mc_device_id - MC object device identifier + * @vendor: vendor ID + * @obj_type: MC object type + * @ver_major: MC object version major number + * @ver_minor: MC object version minor number + * + * Type of entries in the "device Id" table for MC object devices supported by + * a MC object device driver. The last entry of the table has vendor set to 0x0 + */ +struct fsl_mc_device_id { + __u16 vendor; + const char obj_type[16]; +}; + + #endif /* LINUX_MOD_DEVICETABLE_H */ diff --git a/scripts/mod/devicetable-offsets.c b/scripts/mod/devicetable-offsets.c index 840b973..e4d90e5 100644 --- a/scripts/mod/devicetable-offsets.c +++ b/scripts/mod/devicetable-offsets.c @@ -202,5 +202,9 @@ int main(void) DEVID_FIELD(hda_device_id, rev_id); DEVID_FIELD(hda_device_id, api_version); + DEVID(fsl_mc_device_id); + DEVID_FIELD(fsl_mc_device_id, vendor); + DEVID_FIELD(fsl_mc_device_id, obj_type); + return 0; } diff --git a/scripts/mod/file2alias.c b/scripts/mod/file2alias.c index fec7578..29d6699 100644 --- a/scripts/mod/file2alias.c +++ b/scripts/mod/file2alias.c @@ -1289,6 +1289,18 @@ static int do_hda_entry(const char *filename, void *symval, char *alias) } ADD_TO_DEVTABLE("hdaudio", hda_device_id, do_hda_entry); +/* Looks like: fsl-mc:vNdN */ +static int do_fsl_mc_entry(const char *filename, void *symval, + char *alias) +{ + DEF_FIELD(symval, fsl_mc_device_id, vendor); + DEF_FIELD_ADDR(symval, fsl_mc_device_id, obj_type); + + sprintf(alias, "fsl-mc:v%08Xd%s", vendor, *obj_type); + return 1; +} +ADD_TO_DEVTABLE("fslmc", fsl_mc_device_id, do_fsl_mc_entry); + /* Does namelen bytes of name exactly match the symbol? */ static bool sym_is(const char *name, unsigned namelen, const char *symbol) { -- cgit v0.10.2 From ec8d35d430922273a6cc68cfafaeadc5eb767c12 Mon Sep 17 00:00:00 2001 From: Stuart Yoder Date: Wed, 22 Jun 2016 16:40:46 -0500 Subject: staging: fsl-mc: export mc_get_version some drivers (built as modules) rely on mc_get_version() Signed-off-by: Stuart Yoder Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/fsl-mc/bus/dpmng.c b/drivers/staging/fsl-mc/bus/dpmng.c index f633fcd..a31fa9b 100644 --- a/drivers/staging/fsl-mc/bus/dpmng.c +++ b/drivers/staging/fsl-mc/bus/dpmng.c @@ -67,6 +67,7 @@ int mc_get_version(struct fsl_mc_io *mc_io, return 0; } +EXPORT_SYMBOL(mc_get_version); /** * dpmng_get_container_id() - Get container ID associated with a given portal. -- cgit v0.10.2 From fde867d308f39dfd4744c8da1695547b20e002b1 Mon Sep 17 00:00:00 2001 From: Stuart Yoder Date: Wed, 22 Jun 2016 16:40:47 -0500 Subject: staging: fsl-mc: make fsl_mc_is_root_dprc() global make fsl_mc_is_root_dprc() global so that the dprc driver can use it Signed-off-by: Stuart Yoder Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/fsl-mc/bus/mc-bus.c b/drivers/staging/fsl-mc/bus/mc-bus.c index e975adc..a49186e 100644 --- a/drivers/staging/fsl-mc/bus/mc-bus.c +++ b/drivers/staging/fsl-mc/bus/mc-bus.c @@ -24,8 +24,6 @@ static struct kmem_cache *mc_dev_cache; -static bool fsl_mc_is_root_dprc(struct device *dev); - /** * fsl_mc_bus_match - device to driver matching callback * @dev: the MC object device structure to match against @@ -247,19 +245,6 @@ static void fsl_mc_get_root_dprc(struct device *dev, } } -/** - * fsl_mc_is_root_dprc - function to check if a given device is a root dprc - */ -static bool fsl_mc_is_root_dprc(struct device *dev) -{ - struct device *root_dprc_dev; - - fsl_mc_get_root_dprc(dev, &root_dprc_dev); - if (!root_dprc_dev) - return false; - return dev == root_dprc_dev; -} - static int get_dprc_attr(struct fsl_mc_io *mc_io, int container_id, struct dprc_attributes *attr) { @@ -424,6 +409,19 @@ error_cleanup_regions: } /** + * fsl_mc_is_root_dprc - function to check if a given device is a root dprc + */ +bool fsl_mc_is_root_dprc(struct device *dev) +{ + struct device *root_dprc_dev; + + fsl_mc_get_root_dprc(dev, &root_dprc_dev); + if (!root_dprc_dev) + return false; + return dev == root_dprc_dev; +} + +/** * Add a newly discovered MC object device to be visible in Linux */ int fsl_mc_device_add(struct dprc_obj_desc *obj_desc, diff --git a/drivers/staging/fsl-mc/include/mc.h b/drivers/staging/fsl-mc/include/mc.h index a9a9d23..853cbf3 100644 --- a/drivers/staging/fsl-mc/include/mc.h +++ b/drivers/staging/fsl-mc/include/mc.h @@ -207,6 +207,8 @@ int __must_check fsl_mc_allocate_irqs(struct fsl_mc_device *mc_dev); void fsl_mc_free_irqs(struct fsl_mc_device *mc_dev); +bool fsl_mc_is_root_dprc(struct device *dev); + extern struct bus_type fsl_mc_bus_type; #endif /* _FSL_MC_H_ */ -- cgit v0.10.2 From f93627146f0e371093966ed3d44c065aa077cfb1 Mon Sep 17 00:00:00 2001 From: Bharat Bhushan Date: Wed, 22 Jun 2016 16:40:48 -0500 Subject: staging: fsl-mc: fix asymmetry in destroy of mc_io An mc_io represents a mapped MC portal. Previously, an mc_io was created for the root dprc in fsl_mc_bus_probe() and for child dprcs in dprc_probe(). But the free of that data structure happened in the general bus remove callback. This asymmetry resulted in some bugs due to unwanted destroys of mc_io object in some scenarios (e.g. vfio). Fix this bug by making things symmetric-- mc_io created in fsl_mc_bus_probe() is freed in fsl_mc_bus_remove(). The mc_io created in dprc_probe() is freed in dprc_remove(). Signed-off-by: Bharat Bhushan [Stuart: added check for root dprc and reworded commit message] Signed-off-by: Stuart Yoder Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/fsl-mc/bus/dprc-driver.c b/drivers/staging/fsl-mc/bus/dprc-driver.c index f865d18..1a6bcc4 100644 --- a/drivers/staging/fsl-mc/bus/dprc-driver.c +++ b/drivers/staging/fsl-mc/bus/dprc-driver.c @@ -801,6 +801,11 @@ static int dprc_remove(struct fsl_mc_device *mc_dev) dev_set_msi_domain(&mc_dev->dev, NULL); } + if (!fsl_mc_is_root_dprc(&mc_dev->dev)) { + fsl_destroy_mc_io(mc_dev->mc_io); + mc_dev->mc_io = NULL; + } + dev_info(&mc_dev->dev, "DPRC device unbound from driver"); return 0; } diff --git a/drivers/staging/fsl-mc/bus/mc-bus.c b/drivers/staging/fsl-mc/bus/mc-bus.c index a49186e..db3afdb 100644 --- a/drivers/staging/fsl-mc/bus/mc-bus.c +++ b/drivers/staging/fsl-mc/bus/mc-bus.c @@ -579,10 +579,6 @@ void fsl_mc_device_remove(struct fsl_mc_device *mc_dev) if (strcmp(mc_dev->obj_desc.type, "dprc") == 0) { mc_bus = to_fsl_mc_bus(mc_dev); - if (mc_dev->mc_io) { - fsl_destroy_mc_io(mc_dev->mc_io); - mc_dev->mc_io = NULL; - } if (fsl_mc_is_root_dprc(&mc_dev->dev)) { if (atomic_read(&root_dprc_count) > 0) @@ -810,6 +806,10 @@ static int fsl_mc_bus_remove(struct platform_device *pdev) return -EINVAL; fsl_mc_device_remove(mc->root_mc_bus_dev); + + fsl_destroy_mc_io(mc->root_mc_bus_dev->mc_io); + mc->root_mc_bus_dev->mc_io = NULL; + dev_info(&pdev->dev, "Root MC bus device removed"); return 0; } -- cgit v0.10.2 From ae34934f9c8c504df6c0b412352e2850dcba495e Mon Sep 17 00:00:00 2001 From: Stuart Yoder Date: Wed, 22 Jun 2016 16:40:49 -0500 Subject: staging: fsl-mc: dprc: add missing irq free add missing free of the Linux irq when tearing down interrupts Signed-off-by: Stuart Yoder Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/fsl-mc/bus/dprc-driver.c b/drivers/staging/fsl-mc/bus/dprc-driver.c index 1a6bcc4..96ee1b7 100644 --- a/drivers/staging/fsl-mc/bus/dprc-driver.c +++ b/drivers/staging/fsl-mc/bus/dprc-driver.c @@ -760,7 +760,12 @@ error_cleanup_msi_domain: */ static void dprc_teardown_irq(struct fsl_mc_device *mc_dev) { + struct fsl_mc_device_irq *irq = mc_dev->irqs[0]; + (void)disable_dprc_irq(mc_dev); + + devm_free_irq(&mc_dev->dev, irq->msi_desc->irq, &mc_dev->dev); + fsl_mc_free_irqs(mc_dev); } -- cgit v0.10.2 From a137fc805838a444fa934bfd918eba30396f933c Mon Sep 17 00:00:00 2001 From: Stuart Yoder Date: Wed, 22 Jun 2016 16:40:50 -0500 Subject: staging: fsl-mc: dprc: fix ordering problem freeing resources in remove of dprc When unbinding a dprc from the dprc driver the cleanup of the resource pools must happen after irq pool cleanup is done. Signed-off-by: Stuart Yoder Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/fsl-mc/bus/dprc-driver.c b/drivers/staging/fsl-mc/bus/dprc-driver.c index 96ee1b7..d2a71f1 100644 --- a/drivers/staging/fsl-mc/bus/dprc-driver.c +++ b/drivers/staging/fsl-mc/bus/dprc-driver.c @@ -796,16 +796,18 @@ static int dprc_remove(struct fsl_mc_device *mc_dev) dprc_teardown_irq(mc_dev); device_for_each_child(&mc_dev->dev, NULL, __fsl_mc_device_remove); - dprc_cleanup_all_resource_pools(mc_dev); - error = dprc_close(mc_dev->mc_io, 0, mc_dev->mc_handle); - if (error < 0) - dev_err(&mc_dev->dev, "dprc_close() failed: %d\n", error); if (dev_get_msi_domain(&mc_dev->dev)) { fsl_mc_cleanup_irq_pool(mc_bus); dev_set_msi_domain(&mc_dev->dev, NULL); } + dprc_cleanup_all_resource_pools(mc_dev); + + error = dprc_close(mc_dev->mc_io, 0, mc_dev->mc_handle); + if (error < 0) + dev_err(&mc_dev->dev, "dprc_close() failed: %d\n", error); + if (!fsl_mc_is_root_dprc(&mc_dev->dev)) { fsl_destroy_mc_io(mc_dev->mc_io); mc_dev->mc_io = NULL; -- cgit v0.10.2 From adf72b5ba372ca9006f8cdcf9c0b902579f7da9f Mon Sep 17 00:00:00 2001 From: Stuart Yoder Date: Wed, 22 Jun 2016 16:40:51 -0500 Subject: staging: fsl-mc: properly set hwirq in msi set_desc For an MSI domain the hwirq is an arbitrary but unique id to identify an interrupt. Previously the hwirq was set to the MSI index of the interrupt, but that only works if there is one DPRC. Additional DPRCs require an expanded namespace. Use both the ICID (which is unique per DPRC) and the MSI index to compose a hwirq value. Signed-off-by: Stuart Yoder Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/fsl-mc/bus/mc-msi.c b/drivers/staging/fsl-mc/bus/mc-msi.c index e202b2b..c7be156 100644 --- a/drivers/staging/fsl-mc/bus/mc-msi.c +++ b/drivers/staging/fsl-mc/bus/mc-msi.c @@ -20,11 +20,26 @@ #include "../include/mc-sys.h" #include "dprc-cmd.h" +/* + * Generate a unique ID identifying the interrupt (only used within the MSI + * irqdomain. Combine the icid with the interrupt index. + */ +static irq_hw_number_t fsl_mc_domain_calc_hwirq(struct fsl_mc_device *dev, + struct msi_desc *desc) +{ + /* + * Make the base hwirq value for ICID*10000 so it is readable + * as a decimal value in /proc/interrupts. + */ + return (irq_hw_number_t)(desc->fsl_mc.msi_index + (dev->icid * 10000)); +} + static void fsl_mc_msi_set_desc(msi_alloc_info_t *arg, struct msi_desc *desc) { arg->desc = desc; - arg->hwirq = (irq_hw_number_t)desc->fsl_mc.msi_index; + arg->hwirq = fsl_mc_domain_calc_hwirq(to_fsl_mc_device(desc->dev), + desc); } static void fsl_mc_msi_update_dom_ops(struct msi_domain_info *info) -- cgit v0.10.2 From 9989b59961a8ad55d92df4588b556f0c6c838ec7 Mon Sep 17 00:00:00 2001 From: Ioana Radulescu Date: Wed, 22 Jun 2016 16:40:52 -0500 Subject: staging: fsl-mc: convert mc command build/parse to use C structs The layer abstracting the building of commands and extracting responses is currently based on macros that shift and mask the command fields and requires exposing offset/size values as macro parameters and makes the code harder to read. For clarity and maintainability, instead use an implementation based on mapping the MC command definitions to C structures. These structures contain the hardware command fields (which are naturally-aligned) and individual fields are little-endian ordering (the byte ordering of the hardware). As such, there is no need to perform the conversion between core and hardware (LE) endianness in mc_send_command(), but instead each individual field in a command will be converted separately if needed by the function building the command or extracting the response. This patch does not introduce functional changes, both the hardware ABIs and the APIs exposed for the DPAA2 objects remain the same. Signed-off-by: Ioana Radulescu Signed-off-by: Stuart Yoder Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/fsl-mc/bus/dpbp.c b/drivers/staging/fsl-mc/bus/dpbp.c index c31fe1b..fe271fb 100644 --- a/drivers/staging/fsl-mc/bus/dpbp.c +++ b/drivers/staging/fsl-mc/bus/dpbp.c @@ -1,4 +1,4 @@ -/* Copyright 2013-2014 Freescale Semiconductor Inc. +/* Copyright 2013-2016 Freescale Semiconductor Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -57,12 +57,14 @@ int dpbp_open(struct fsl_mc_io *mc_io, u16 *token) { struct mc_command cmd = { 0 }; + struct dpbp_cmd_open *cmd_params; int err; /* prepare command */ cmd.header = mc_encode_cmd_header(DPBP_CMDID_OPEN, cmd_flags, 0); - cmd.params[0] |= mc_enc(0, 32, dpbp_id); + cmd_params = (struct dpbp_cmd_open *)cmd.params; + cmd_params->dpbp_id = cpu_to_le32(dpbp_id); /* send command to mc*/ err = mc_send_command(mc_io, &cmd); @@ -70,7 +72,7 @@ int dpbp_open(struct fsl_mc_io *mc_io, return err; /* retrieve response parameters */ - *token = MC_CMD_HDR_READ_TOKEN(cmd.header); + *token = mc_cmd_hdr_read_token(&cmd); return err; } @@ -143,7 +145,7 @@ int dpbp_create(struct fsl_mc_io *mc_io, return err; /* retrieve response parameters */ - *token = MC_CMD_HDR_READ_TOKEN(cmd.header); + *token = mc_cmd_hdr_read_token(&cmd); return 0; } @@ -231,6 +233,7 @@ int dpbp_is_enabled(struct fsl_mc_io *mc_io, int *en) { struct mc_command cmd = { 0 }; + struct dpbp_rsp_is_enabled *rsp_params; int err; /* prepare command */ cmd.header = mc_encode_cmd_header(DPBP_CMDID_IS_ENABLED, cmd_flags, @@ -242,7 +245,8 @@ int dpbp_is_enabled(struct fsl_mc_io *mc_io, return err; /* retrieve response parameters */ - *en = (int)mc_dec(cmd.params[0], 0, 1); + rsp_params = (struct dpbp_rsp_is_enabled *)cmd.params; + *en = rsp_params->enabled & DPBP_ENABLE; return 0; } @@ -286,14 +290,16 @@ int dpbp_set_irq(struct fsl_mc_io *mc_io, struct dpbp_irq_cfg *irq_cfg) { struct mc_command cmd = { 0 }; + struct dpbp_cmd_set_irq *cmd_params; /* prepare command */ cmd.header = mc_encode_cmd_header(DPBP_CMDID_SET_IRQ, cmd_flags, token); - cmd.params[0] |= mc_enc(0, 8, irq_index); - cmd.params[0] |= mc_enc(32, 32, irq_cfg->val); - cmd.params[1] |= mc_enc(0, 64, irq_cfg->addr); - cmd.params[2] |= mc_enc(0, 32, irq_cfg->irq_num); + cmd_params = (struct dpbp_cmd_set_irq *)cmd.params; + cmd_params->irq_index = irq_index; + cmd_params->irq_val = cpu_to_le32(irq_cfg->val); + cmd_params->irq_addr = cpu_to_le64(irq_cfg->addr); + cmd_params->irq_num = cpu_to_le32(irq_cfg->irq_num); /* send command to mc*/ return mc_send_command(mc_io, &cmd); @@ -319,12 +325,15 @@ int dpbp_get_irq(struct fsl_mc_io *mc_io, struct dpbp_irq_cfg *irq_cfg) { struct mc_command cmd = { 0 }; + struct dpbp_cmd_get_irq *cmd_params; + struct dpbp_rsp_get_irq *rsp_params; int err; /* prepare command */ cmd.header = mc_encode_cmd_header(DPBP_CMDID_GET_IRQ, cmd_flags, token); - cmd.params[0] |= mc_enc(32, 8, irq_index); + cmd_params = (struct dpbp_cmd_get_irq *)cmd.params; + cmd_params->irq_index = irq_index; /* send command to mc*/ err = mc_send_command(mc_io, &cmd); @@ -332,10 +341,12 @@ int dpbp_get_irq(struct fsl_mc_io *mc_io, return err; /* retrieve response parameters */ - irq_cfg->val = (u32)mc_dec(cmd.params[0], 0, 32); - irq_cfg->addr = (u64)mc_dec(cmd.params[1], 0, 64); - irq_cfg->irq_num = (int)mc_dec(cmd.params[2], 0, 32); - *type = (int)mc_dec(cmd.params[2], 32, 32); + rsp_params = (struct dpbp_rsp_get_irq *)cmd.params; + irq_cfg->val = le32_to_cpu(rsp_params->irq_val); + irq_cfg->addr = le64_to_cpu(rsp_params->irq_addr); + irq_cfg->irq_num = le32_to_cpu(rsp_params->irq_num); + *type = le32_to_cpu(rsp_params->type); + return 0; } @@ -361,12 +372,14 @@ int dpbp_set_irq_enable(struct fsl_mc_io *mc_io, u8 en) { struct mc_command cmd = { 0 }; + struct dpbp_cmd_set_irq_enable *cmd_params; /* prepare command */ cmd.header = mc_encode_cmd_header(DPBP_CMDID_SET_IRQ_ENABLE, cmd_flags, token); - cmd.params[0] |= mc_enc(0, 8, en); - cmd.params[0] |= mc_enc(32, 8, irq_index); + cmd_params = (struct dpbp_cmd_set_irq_enable *)cmd.params; + cmd_params->enable = en & DPBP_ENABLE; + cmd_params->irq_index = irq_index; /* send command to mc*/ return mc_send_command(mc_io, &cmd); @@ -389,12 +402,15 @@ int dpbp_get_irq_enable(struct fsl_mc_io *mc_io, u8 *en) { struct mc_command cmd = { 0 }; + struct dpbp_cmd_get_irq_enable *cmd_params; + struct dpbp_rsp_get_irq_enable *rsp_params; int err; /* prepare command */ cmd.header = mc_encode_cmd_header(DPBP_CMDID_GET_IRQ_ENABLE, cmd_flags, token); - cmd.params[0] |= mc_enc(32, 8, irq_index); + cmd_params = (struct dpbp_cmd_get_irq_enable *)cmd.params; + cmd_params->irq_index = irq_index; /* send command to mc*/ err = mc_send_command(mc_io, &cmd); @@ -402,7 +418,8 @@ int dpbp_get_irq_enable(struct fsl_mc_io *mc_io, return err; /* retrieve response parameters */ - *en = (u8)mc_dec(cmd.params[0], 0, 8); + rsp_params = (struct dpbp_rsp_get_irq_enable *)cmd.params; + *en = rsp_params->enabled & DPBP_ENABLE; return 0; } @@ -429,12 +446,14 @@ int dpbp_set_irq_mask(struct fsl_mc_io *mc_io, u32 mask) { struct mc_command cmd = { 0 }; + struct dpbp_cmd_set_irq_mask *cmd_params; /* prepare command */ cmd.header = mc_encode_cmd_header(DPBP_CMDID_SET_IRQ_MASK, cmd_flags, token); - cmd.params[0] |= mc_enc(0, 32, mask); - cmd.params[0] |= mc_enc(32, 8, irq_index); + cmd_params = (struct dpbp_cmd_set_irq_mask *)cmd.params; + cmd_params->mask = cpu_to_le32(mask); + cmd_params->irq_index = irq_index; /* send command to mc*/ return mc_send_command(mc_io, &cmd); @@ -460,12 +479,15 @@ int dpbp_get_irq_mask(struct fsl_mc_io *mc_io, u32 *mask) { struct mc_command cmd = { 0 }; + struct dpbp_cmd_get_irq_mask *cmd_params; + struct dpbp_rsp_get_irq_mask *rsp_params; int err; /* prepare command */ cmd.header = mc_encode_cmd_header(DPBP_CMDID_GET_IRQ_MASK, cmd_flags, token); - cmd.params[0] |= mc_enc(32, 8, irq_index); + cmd_params = (struct dpbp_cmd_get_irq_mask *)cmd.params; + cmd_params->irq_index = irq_index; /* send command to mc*/ err = mc_send_command(mc_io, &cmd); @@ -473,7 +495,9 @@ int dpbp_get_irq_mask(struct fsl_mc_io *mc_io, return err; /* retrieve response parameters */ - *mask = (u32)mc_dec(cmd.params[0], 0, 32); + rsp_params = (struct dpbp_rsp_get_irq_mask *)cmd.params; + *mask = le32_to_cpu(rsp_params->mask); + return 0; } @@ -497,13 +521,16 @@ int dpbp_get_irq_status(struct fsl_mc_io *mc_io, u32 *status) { struct mc_command cmd = { 0 }; + struct dpbp_cmd_get_irq_status *cmd_params; + struct dpbp_rsp_get_irq_status *rsp_params; int err; /* prepare command */ cmd.header = mc_encode_cmd_header(DPBP_CMDID_GET_IRQ_STATUS, cmd_flags, token); - cmd.params[0] |= mc_enc(0, 32, *status); - cmd.params[0] |= mc_enc(32, 8, irq_index); + cmd_params = (struct dpbp_cmd_get_irq_status *)cmd.params; + cmd_params->status = cpu_to_le32(*status); + cmd_params->irq_index = irq_index; /* send command to mc*/ err = mc_send_command(mc_io, &cmd); @@ -511,7 +538,9 @@ int dpbp_get_irq_status(struct fsl_mc_io *mc_io, return err; /* retrieve response parameters */ - *status = (u32)mc_dec(cmd.params[0], 0, 32); + rsp_params = (struct dpbp_rsp_get_irq_status *)cmd.params; + *status = le32_to_cpu(rsp_params->status); + return 0; } @@ -535,12 +564,14 @@ int dpbp_clear_irq_status(struct fsl_mc_io *mc_io, u32 status) { struct mc_command cmd = { 0 }; + struct dpbp_cmd_clear_irq_status *cmd_params; /* prepare command */ cmd.header = mc_encode_cmd_header(DPBP_CMDID_CLEAR_IRQ_STATUS, cmd_flags, token); - cmd.params[0] |= mc_enc(0, 32, status); - cmd.params[0] |= mc_enc(32, 8, irq_index); + cmd_params = (struct dpbp_cmd_clear_irq_status *)cmd.params; + cmd_params->status = cpu_to_le32(status); + cmd_params->irq_index = irq_index; /* send command to mc*/ return mc_send_command(mc_io, &cmd); @@ -562,6 +593,7 @@ int dpbp_get_attributes(struct fsl_mc_io *mc_io, struct dpbp_attr *attr) { struct mc_command cmd = { 0 }; + struct dpbp_rsp_get_attributes *rsp_params; int err; /* prepare command */ @@ -574,10 +606,12 @@ int dpbp_get_attributes(struct fsl_mc_io *mc_io, return err; /* retrieve response parameters */ - attr->bpid = (u16)mc_dec(cmd.params[0], 16, 16); - attr->id = (int)mc_dec(cmd.params[0], 32, 32); - attr->version.major = (u16)mc_dec(cmd.params[1], 0, 16); - attr->version.minor = (u16)mc_dec(cmd.params[1], 16, 16); + rsp_params = (struct dpbp_rsp_get_attributes *)cmd.params; + attr->bpid = le16_to_cpu(rsp_params->bpid); + attr->id = le32_to_cpu(rsp_params->id); + attr->version.major = le16_to_cpu(rsp_params->version_major); + attr->version.minor = le16_to_cpu(rsp_params->version_minor); + return 0; } EXPORT_SYMBOL(dpbp_get_attributes); @@ -597,19 +631,19 @@ int dpbp_set_notifications(struct fsl_mc_io *mc_io, struct dpbp_notification_cfg *cfg) { struct mc_command cmd = { 0 }; + struct dpbp_cmd_set_notifications *cmd_params; /* prepare command */ cmd.header = mc_encode_cmd_header(DPBP_CMDID_SET_NOTIFICATIONS, - cmd_flags, - token); - - cmd.params[0] |= mc_enc(0, 32, cfg->depletion_entry); - cmd.params[0] |= mc_enc(32, 32, cfg->depletion_exit); - cmd.params[1] |= mc_enc(0, 32, cfg->surplus_entry); - cmd.params[1] |= mc_enc(32, 32, cfg->surplus_exit); - cmd.params[2] |= mc_enc(0, 16, cfg->options); - cmd.params[3] |= mc_enc(0, 64, cfg->message_ctx); - cmd.params[4] |= mc_enc(0, 64, cfg->message_iova); + cmd_flags, token); + cmd_params = (struct dpbp_cmd_set_notifications *)cmd.params; + cmd_params->depletion_entry = cpu_to_le32(cfg->depletion_entry); + cmd_params->depletion_exit = cpu_to_le32(cfg->depletion_exit); + cmd_params->surplus_entry = cpu_to_le32(cfg->surplus_entry); + cmd_params->surplus_exit = cpu_to_le32(cfg->surplus_exit); + cmd_params->options = cpu_to_le16(cfg->options); + cmd_params->message_ctx = cpu_to_le64(cfg->message_ctx); + cmd_params->message_iova = cpu_to_le64(cfg->message_iova); /* send command to mc*/ return mc_send_command(mc_io, &cmd); @@ -630,6 +664,7 @@ int dpbp_get_notifications(struct fsl_mc_io *mc_io, struct dpbp_notification_cfg *cfg) { struct mc_command cmd = { 0 }; + struct dpbp_rsp_get_notifications *rsp_params; int err; /* prepare command */ @@ -643,13 +678,14 @@ int dpbp_get_notifications(struct fsl_mc_io *mc_io, return err; /* retrieve response parameters */ - cfg->depletion_entry = (u32)mc_dec(cmd.params[0], 0, 32); - cfg->depletion_exit = (u32)mc_dec(cmd.params[0], 32, 32); - cfg->surplus_entry = (u32)mc_dec(cmd.params[1], 0, 32); - cfg->surplus_exit = (u32)mc_dec(cmd.params[1], 32, 32); - cfg->options = (u16)mc_dec(cmd.params[2], 0, 16); - cfg->message_ctx = (u64)mc_dec(cmd.params[3], 0, 64); - cfg->message_iova = (u64)mc_dec(cmd.params[4], 0, 64); + rsp_params = (struct dpbp_rsp_get_notifications *)cmd.params; + cfg->depletion_entry = le32_to_cpu(rsp_params->depletion_entry); + cfg->depletion_exit = le32_to_cpu(rsp_params->depletion_exit); + cfg->surplus_entry = le32_to_cpu(rsp_params->surplus_entry); + cfg->surplus_exit = le32_to_cpu(rsp_params->surplus_exit); + cfg->options = le16_to_cpu(rsp_params->options); + cfg->message_ctx = le64_to_cpu(rsp_params->message_ctx); + cfg->message_iova = le64_to_cpu(rsp_params->message_iova); return 0; } diff --git a/drivers/staging/fsl-mc/bus/dpmcp-cmd.h b/drivers/staging/fsl-mc/bus/dpmcp-cmd.h index c9b52dd..d098a6d 100644 --- a/drivers/staging/fsl-mc/bus/dpmcp-cmd.h +++ b/drivers/staging/fsl-mc/bus/dpmcp-cmd.h @@ -1,4 +1,4 @@ -/* Copyright 2013-2015 Freescale Semiconductor Inc. +/* Copyright 2013-2016 Freescale Semiconductor Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -53,4 +53,88 @@ #define DPMCP_CMDID_GET_IRQ_MASK 0x015 #define DPMCP_CMDID_GET_IRQ_STATUS 0x016 +struct dpmcp_cmd_open { + __le32 dpmcp_id; +}; + +struct dpmcp_cmd_create { + __le32 portal_id; +}; + +struct dpmcp_cmd_set_irq { + /* cmd word 0 */ + u8 irq_index; + u8 pad[3]; + __le32 irq_val; + /* cmd word 1 */ + __le64 irq_addr; + /* cmd word 2 */ + __le32 irq_num; +}; + +struct dpmcp_cmd_get_irq { + __le32 pad; + u8 irq_index; +}; + +struct dpmcp_rsp_get_irq { + /* cmd word 0 */ + __le32 irq_val; + __le32 pad; + /* cmd word 1 */ + __le64 irq_paddr; + /* cmd word 2 */ + __le32 irq_num; + __le32 type; +}; + +#define DPMCP_ENABLE 0x1 + +struct dpmcp_cmd_set_irq_enable { + u8 enable; + u8 pad[3]; + u8 irq_index; +}; + +struct dpmcp_cmd_get_irq_enable { + __le32 pad; + u8 irq_index; +}; + +struct dpmcp_rsp_get_irq_enable { + u8 enabled; +}; + +struct dpmcp_cmd_set_irq_mask { + __le32 mask; + u8 irq_index; +}; + +struct dpmcp_cmd_get_irq_mask { + __le32 pad; + u8 irq_index; +}; + +struct dpmcp_rsp_get_irq_mask { + __le32 mask; +}; + +struct dpmcp_cmd_get_irq_status { + __le32 status; + u8 irq_index; +}; + +struct dpmcp_rsp_get_irq_status { + __le32 status; +}; + +struct dpmcp_rsp_get_attributes { + /* response word 0 */ + __le32 pad; + __le32 id; + /* response word 1 */ + __le16 version_major; + __le16 version_minor; +}; + #endif /* _FSL_DPMCP_CMD_H */ diff --git a/drivers/staging/fsl-mc/bus/dpmcp.c b/drivers/staging/fsl-mc/bus/dpmcp.c index fd6dd4e..0644017 100644 --- a/drivers/staging/fsl-mc/bus/dpmcp.c +++ b/drivers/staging/fsl-mc/bus/dpmcp.c @@ -1,4 +1,4 @@ -/* Copyright 2013-2015 Freescale Semiconductor Inc. +/* Copyright 2013-2016 Freescale Semiconductor Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -57,12 +57,14 @@ int dpmcp_open(struct fsl_mc_io *mc_io, u16 *token) { struct mc_command cmd = { 0 }; + struct dpmcp_cmd_open *cmd_params; int err; /* prepare command */ cmd.header = mc_encode_cmd_header(DPMCP_CMDID_OPEN, cmd_flags, 0); - cmd.params[0] |= mc_enc(0, 32, dpmcp_id); + cmd_params = (struct dpmcp_cmd_open *)cmd.params; + cmd_params->dpmcp_id = cpu_to_le32(dpmcp_id); /* send command to mc*/ err = mc_send_command(mc_io, &cmd); @@ -70,7 +72,7 @@ int dpmcp_open(struct fsl_mc_io *mc_io, return err; /* retrieve response parameters */ - *token = MC_CMD_HDR_READ_TOKEN(cmd.header); + *token = mc_cmd_hdr_read_token(&cmd); return err; } @@ -127,12 +129,15 @@ int dpmcp_create(struct fsl_mc_io *mc_io, u16 *token) { struct mc_command cmd = { 0 }; + struct dpmcp_cmd_create *cmd_params; + int err; /* prepare command */ cmd.header = mc_encode_cmd_header(DPMCP_CMDID_CREATE, cmd_flags, 0); - cmd.params[0] |= mc_enc(0, 32, cfg->portal_id); + cmd_params = (struct dpmcp_cmd_create *)cmd.params; + cmd_params->portal_id = cpu_to_le32(cfg->portal_id); /* send command to mc*/ err = mc_send_command(mc_io, &cmd); @@ -140,7 +145,7 @@ int dpmcp_create(struct fsl_mc_io *mc_io, return err; /* retrieve response parameters */ - *token = MC_CMD_HDR_READ_TOKEN(cmd.header); + *token = mc_cmd_hdr_read_token(&cmd); return 0; } @@ -206,14 +211,16 @@ int dpmcp_set_irq(struct fsl_mc_io *mc_io, struct dpmcp_irq_cfg *irq_cfg) { struct mc_command cmd = { 0 }; + struct dpmcp_cmd_set_irq *cmd_params; /* prepare command */ cmd.header = mc_encode_cmd_header(DPMCP_CMDID_SET_IRQ, cmd_flags, token); - cmd.params[0] |= mc_enc(0, 8, irq_index); - cmd.params[0] |= mc_enc(32, 32, irq_cfg->val); - cmd.params[1] |= mc_enc(0, 64, irq_cfg->paddr); - cmd.params[2] |= mc_enc(0, 32, irq_cfg->irq_num); + cmd_params = (struct dpmcp_cmd_set_irq *)cmd.params; + cmd_params->irq_index = irq_index; + cmd_params->irq_val = cpu_to_le32(irq_cfg->val); + cmd_params->irq_addr = cpu_to_le64(irq_cfg->paddr); + cmd_params->irq_num = cpu_to_le32(irq_cfg->irq_num); /* send command to mc*/ return mc_send_command(mc_io, &cmd); @@ -239,12 +246,15 @@ int dpmcp_get_irq(struct fsl_mc_io *mc_io, struct dpmcp_irq_cfg *irq_cfg) { struct mc_command cmd = { 0 }; + struct dpmcp_cmd_get_irq *cmd_params; + struct dpmcp_rsp_get_irq *rsp_params; int err; /* prepare command */ cmd.header = mc_encode_cmd_header(DPMCP_CMDID_GET_IRQ, cmd_flags, token); - cmd.params[0] |= mc_enc(32, 8, irq_index); + cmd_params = (struct dpmcp_cmd_get_irq *)cmd.params; + cmd_params->irq_index = irq_index; /* send command to mc*/ err = mc_send_command(mc_io, &cmd); @@ -252,10 +262,11 @@ int dpmcp_get_irq(struct fsl_mc_io *mc_io, return err; /* retrieve response parameters */ - irq_cfg->val = (u32)mc_dec(cmd.params[0], 0, 32); - irq_cfg->paddr = (u64)mc_dec(cmd.params[1], 0, 64); - irq_cfg->irq_num = (int)mc_dec(cmd.params[2], 0, 32); - *type = (int)mc_dec(cmd.params[2], 32, 32); + rsp_params = (struct dpmcp_rsp_get_irq *)cmd.params; + irq_cfg->val = le32_to_cpu(rsp_params->irq_val); + irq_cfg->paddr = le64_to_cpu(rsp_params->irq_paddr); + irq_cfg->irq_num = le32_to_cpu(rsp_params->irq_num); + *type = le32_to_cpu(rsp_params->type); return 0; } @@ -281,12 +292,14 @@ int dpmcp_set_irq_enable(struct fsl_mc_io *mc_io, u8 en) { struct mc_command cmd = { 0 }; + struct dpmcp_cmd_set_irq_enable *cmd_params; /* prepare command */ cmd.header = mc_encode_cmd_header(DPMCP_CMDID_SET_IRQ_ENABLE, cmd_flags, token); - cmd.params[0] |= mc_enc(0, 8, en); - cmd.params[0] |= mc_enc(32, 8, irq_index); + cmd_params = (struct dpmcp_cmd_set_irq_enable *)cmd.params; + cmd_params->enable = en & DPMCP_ENABLE; + cmd_params->irq_index = irq_index; /* send command to mc*/ return mc_send_command(mc_io, &cmd); @@ -309,12 +322,15 @@ int dpmcp_get_irq_enable(struct fsl_mc_io *mc_io, u8 *en) { struct mc_command cmd = { 0 }; + struct dpmcp_cmd_get_irq_enable *cmd_params; + struct dpmcp_rsp_get_irq_enable *rsp_params; int err; /* prepare command */ cmd.header = mc_encode_cmd_header(DPMCP_CMDID_GET_IRQ_ENABLE, cmd_flags, token); - cmd.params[0] |= mc_enc(32, 8, irq_index); + cmd_params = (struct dpmcp_cmd_get_irq_enable *)cmd.params; + cmd_params->irq_index = irq_index; /* send command to mc*/ err = mc_send_command(mc_io, &cmd); @@ -322,7 +338,8 @@ int dpmcp_get_irq_enable(struct fsl_mc_io *mc_io, return err; /* retrieve response parameters */ - *en = (u8)mc_dec(cmd.params[0], 0, 8); + rsp_params = (struct dpmcp_rsp_get_irq_enable *)cmd.params; + *en = rsp_params->enabled & DPMCP_ENABLE; return 0; } @@ -349,12 +366,15 @@ int dpmcp_set_irq_mask(struct fsl_mc_io *mc_io, u32 mask) { struct mc_command cmd = { 0 }; + struct dpmcp_cmd_set_irq_mask *cmd_params; + /* prepare command */ cmd.header = mc_encode_cmd_header(DPMCP_CMDID_SET_IRQ_MASK, cmd_flags, token); - cmd.params[0] |= mc_enc(0, 32, mask); - cmd.params[0] |= mc_enc(32, 8, irq_index); + cmd_params = (struct dpmcp_cmd_set_irq_mask *)cmd.params; + cmd_params->mask = cpu_to_le32(mask); + cmd_params->irq_index = irq_index; /* send command to mc*/ return mc_send_command(mc_io, &cmd); @@ -380,12 +400,16 @@ int dpmcp_get_irq_mask(struct fsl_mc_io *mc_io, u32 *mask) { struct mc_command cmd = { 0 }; + struct dpmcp_cmd_get_irq_mask *cmd_params; + struct dpmcp_rsp_get_irq_mask *rsp_params; + int err; /* prepare command */ cmd.header = mc_encode_cmd_header(DPMCP_CMDID_GET_IRQ_MASK, cmd_flags, token); - cmd.params[0] |= mc_enc(32, 8, irq_index); + cmd_params = (struct dpmcp_cmd_get_irq_mask *)cmd.params; + cmd_params->irq_index = irq_index; /* send command to mc*/ err = mc_send_command(mc_io, &cmd); @@ -393,7 +417,9 @@ int dpmcp_get_irq_mask(struct fsl_mc_io *mc_io, return err; /* retrieve response parameters */ - *mask = (u32)mc_dec(cmd.params[0], 0, 32); + rsp_params = (struct dpmcp_rsp_get_irq_mask *)cmd.params; + *mask = le32_to_cpu(rsp_params->mask); + return 0; } @@ -417,12 +443,16 @@ int dpmcp_get_irq_status(struct fsl_mc_io *mc_io, u32 *status) { struct mc_command cmd = { 0 }; + struct dpmcp_cmd_get_irq_status *cmd_params; + struct dpmcp_rsp_get_irq_status *rsp_params; int err; /* prepare command */ cmd.header = mc_encode_cmd_header(DPMCP_CMDID_GET_IRQ_STATUS, cmd_flags, token); - cmd.params[0] |= mc_enc(32, 8, irq_index); + cmd_params = (struct dpmcp_cmd_get_irq_status *)cmd.params; + cmd_params->status = cpu_to_le32(*status); + cmd_params->irq_index = irq_index; /* send command to mc*/ err = mc_send_command(mc_io, &cmd); @@ -430,7 +460,9 @@ int dpmcp_get_irq_status(struct fsl_mc_io *mc_io, return err; /* retrieve response parameters */ - *status = (u32)mc_dec(cmd.params[0], 0, 32); + rsp_params = (struct dpmcp_rsp_get_irq_status *)cmd.params; + *status = le32_to_cpu(rsp_params->status); + return 0; } @@ -450,6 +482,7 @@ int dpmcp_get_attributes(struct fsl_mc_io *mc_io, struct dpmcp_attr *attr) { struct mc_command cmd = { 0 }; + struct dpmcp_rsp_get_attributes *rsp_params; int err; /* prepare command */ @@ -462,8 +495,10 @@ int dpmcp_get_attributes(struct fsl_mc_io *mc_io, return err; /* retrieve response parameters */ - attr->id = (int)mc_dec(cmd.params[0], 32, 32); - attr->version.major = (u16)mc_dec(cmd.params[1], 0, 16); - attr->version.minor = (u16)mc_dec(cmd.params[1], 16, 16); + rsp_params = (struct dpmcp_rsp_get_attributes *)cmd.params; + attr->id = le32_to_cpu(rsp_params->id); + attr->version.major = le16_to_cpu(rsp_params->version_major); + attr->version.minor = le16_to_cpu(rsp_params->version_minor); + return 0; } diff --git a/drivers/staging/fsl-mc/bus/dpmng-cmd.h b/drivers/staging/fsl-mc/bus/dpmng-cmd.h index ba8cfa9..779bf9c 100644 --- a/drivers/staging/fsl-mc/bus/dpmng-cmd.h +++ b/drivers/staging/fsl-mc/bus/dpmng-cmd.h @@ -1,4 +1,4 @@ -/* Copyright 2013-2014 Freescale Semiconductor Inc. +/* Copyright 2013-2016 Freescale Semiconductor Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -44,4 +44,14 @@ #define DPMNG_CMDID_GET_CONT_ID 0x830 #define DPMNG_CMDID_GET_VERSION 0x831 +struct dpmng_rsp_get_container_id { + __le32 container_id; +}; + +struct dpmng_rsp_get_version { + __le32 revision; + __le32 version_major; + __le32 version_minor; +}; + #endif /* __FSL_DPMNG_CMD_H */ diff --git a/drivers/staging/fsl-mc/bus/dpmng.c b/drivers/staging/fsl-mc/bus/dpmng.c index a31fa9b..660bbe7 100644 --- a/drivers/staging/fsl-mc/bus/dpmng.c +++ b/drivers/staging/fsl-mc/bus/dpmng.c @@ -1,4 +1,4 @@ -/* Copyright 2013-2014 Freescale Semiconductor Inc. +/* Copyright 2013-2016 Freescale Semiconductor Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -48,6 +48,7 @@ int mc_get_version(struct fsl_mc_io *mc_io, struct mc_version *mc_ver_info) { struct mc_command cmd = { 0 }; + struct dpmng_rsp_get_version *rsp_params; int err; /* prepare command */ @@ -61,9 +62,10 @@ int mc_get_version(struct fsl_mc_io *mc_io, return err; /* retrieve response parameters */ - mc_ver_info->revision = mc_dec(cmd.params[0], 0, 32); - mc_ver_info->major = mc_dec(cmd.params[0], 32, 32); - mc_ver_info->minor = mc_dec(cmd.params[1], 0, 32); + rsp_params = (struct dpmng_rsp_get_version *)cmd.params; + mc_ver_info->revision = le32_to_cpu(rsp_params->revision); + mc_ver_info->major = le32_to_cpu(rsp_params->version_major); + mc_ver_info->minor = le32_to_cpu(rsp_params->version_minor); return 0; } @@ -82,6 +84,7 @@ int dpmng_get_container_id(struct fsl_mc_io *mc_io, int *container_id) { struct mc_command cmd = { 0 }; + struct dpmng_rsp_get_container_id *rsp_params; int err; /* prepare command */ @@ -95,7 +98,8 @@ int dpmng_get_container_id(struct fsl_mc_io *mc_io, return err; /* retrieve response parameters */ - *container_id = mc_dec(cmd.params[0], 0, 32); + rsp_params = (struct dpmng_rsp_get_container_id *)cmd.params; + *container_id = le32_to_cpu(rsp_params->container_id); return 0; } diff --git a/drivers/staging/fsl-mc/bus/dprc-cmd.h b/drivers/staging/fsl-mc/bus/dprc-cmd.h index 9b854fa..bb127f4 100644 --- a/drivers/staging/fsl-mc/bus/dprc-cmd.h +++ b/drivers/staging/fsl-mc/bus/dprc-cmd.h @@ -1,4 +1,4 @@ -/* Copyright 2013-2014 Freescale Semiconductor Inc. +/* Copyright 2013-2016 Freescale Semiconductor Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -84,4 +84,381 @@ #define DPRC_CMDID_GET_CONNECTION 0x16C +struct dprc_cmd_open { + __le32 container_id; +}; + +struct dprc_cmd_create_container { + /* cmd word 0 */ + __le32 options; + __le16 icid; + __le16 pad0; + /* cmd word 1 */ + __le32 pad1; + __le32 portal_id; + /* cmd words 2-3 */ + u8 label[16]; +}; + +struct dprc_rsp_create_container { + /* response word 0 */ + __le64 pad0; + /* response word 1 */ + __le32 child_container_id; + __le32 pad1; + /* response word 2 */ + __le64 child_portal_addr; +}; + +struct dprc_cmd_destroy_container { + __le32 child_container_id; +}; + +struct dprc_cmd_reset_container { + __le32 child_container_id; +}; + +struct dprc_cmd_set_irq { + /* cmd word 0 */ + __le32 irq_val; + u8 irq_index; + u8 pad[3]; + /* cmd word 1 */ + __le64 irq_addr; + /* cmd word 2 */ + __le32 irq_num; +}; + +struct dprc_cmd_get_irq { + __le32 pad; + u8 irq_index; +}; + +struct dprc_rsp_get_irq { + /* response word 0 */ + __le32 irq_val; + __le32 pad; + /* response word 1 */ + __le64 irq_addr; + /* response word 2 */ + __le32 irq_num; + __le32 type; +}; + +#define DPRC_ENABLE 0x1 + +struct dprc_cmd_set_irq_enable { + u8 enable; + u8 pad[3]; + u8 irq_index; +}; + +struct dprc_cmd_get_irq_enable { + __le32 pad; + u8 irq_index; +}; + +struct dprc_rsp_get_irq_enable { + u8 enabled; +}; + +struct dprc_cmd_set_irq_mask { + __le32 mask; + u8 irq_index; +}; + +struct dprc_cmd_get_irq_mask { + __le32 pad; + u8 irq_index; +}; + +struct dprc_rsp_get_irq_mask { + __le32 mask; +}; + +struct dprc_cmd_get_irq_status { + __le32 status; + u8 irq_index; +}; + +struct dprc_rsp_get_irq_status { + __le32 status; +}; + +struct dprc_cmd_clear_irq_status { + __le32 status; + u8 irq_index; +}; + +struct dprc_rsp_get_attributes { + /* response word 0 */ + __le32 container_id; + __le16 icid; + __le16 pad; + /* response word 1 */ + __le32 options; + __le32 portal_id; + /* response word 2 */ + __le16 version_major; + __le16 version_minor; +}; + +struct dprc_cmd_set_res_quota { + /* cmd word 0 */ + __le32 child_container_id; + __le16 quota; + __le16 pad; + /* cmd words 1-2 */ + u8 type[16]; +}; + +struct dprc_cmd_get_res_quota { + /* cmd word 0 */ + __le32 child_container_id; + __le32 pad; + /* cmd word 1-2 */ + u8 type[16]; +}; + +struct dprc_rsp_get_res_quota { + __le32 pad; + __le16 quota; +}; + +struct dprc_cmd_assign { + /* cmd word 0 */ + __le32 container_id; + __le32 options; + /* cmd word 1 */ + __le32 num; + __le32 id_base_align; + /* cmd word 2-3 */ + u8 type[16]; +}; + +struct dprc_cmd_unassign { + /* cmd word 0 */ + __le32 child_container_id; + __le32 options; + /* cmd word 1 */ + __le32 num; + __le32 id_base_align; + /* cmd word 2-3 */ + u8 type[16]; +}; + +struct dprc_rsp_get_pool_count { + __le32 pool_count; +}; + +struct dprc_cmd_get_pool { + __le32 pool_index; +}; + +struct dprc_rsp_get_pool { + /* response word 0 */ + __le64 pad; + /* response word 1-2 */ + u8 type[16]; +}; + +struct dprc_rsp_get_obj_count { + __le32 pad; + __le32 obj_count; +}; + +struct dprc_cmd_get_obj { + __le32 obj_index; +}; + +struct dprc_rsp_get_obj { + /* response word 0 */ + __le32 pad0; + __le32 id; + /* response word 1 */ + __le16 vendor; + u8 irq_count; + u8 region_count; + __le32 state; + /* response word 2 */ + __le16 version_major; + __le16 version_minor; + __le16 flags; + __le16 pad1; + /* response word 3-4 */ + u8 type[16]; + /* response word 5-6 */ + u8 label[16]; +}; + +struct dprc_cmd_get_obj_desc { + /* cmd word 0 */ + __le32 obj_id; + __le32 pad; + /* cmd word 1-2 */ + u8 type[16]; +}; + +struct dprc_rsp_get_obj_desc { + /* response word 0 */ + __le32 pad0; + __le32 id; + /* response word 1 */ + __le16 vendor; + u8 irq_count; + u8 region_count; + __le32 state; + /* response word 2 */ + __le16 version_major; + __le16 version_minor; + __le16 flags; + __le16 pad1; + /* response word 3-4 */ + u8 type[16]; + /* response word 5-6 */ + u8 label[16]; +}; + +struct dprc_cmd_get_res_count { + /* cmd word 0 */ + __le64 pad; + /* cmd word 1-2 */ + u8 type[16]; +}; + +struct dprc_rsp_get_res_count { + __le32 res_count; +}; + +struct dprc_cmd_get_res_ids { + /* cmd word 0 */ + u8 pad0[5]; + u8 iter_status; + __le16 pad1; + /* cmd word 1 */ + __le32 base_id; + __le32 last_id; + /* cmd word 2-3 */ + u8 type[16]; +}; + +struct dprc_rsp_get_res_ids { + /* response word 0 */ + u8 pad0[5]; + u8 iter_status; + __le16 pad1; + /* response word 1 */ + __le32 base_id; + __le32 last_id; +}; + +struct dprc_cmd_get_obj_region { + /* cmd word 0 */ + __le32 obj_id; + __le16 pad0; + u8 region_index; + u8 pad1; + /* cmd word 1-2 */ + __le64 pad2[2]; + /* cmd word 3-4 */ + u8 obj_type[16]; +}; + +struct dprc_rsp_get_obj_region { + /* response word 0 */ + __le64 pad; + /* response word 1 */ + __le64 base_addr; + /* response word 2 */ + __le32 size; +}; + +struct dprc_cmd_set_obj_label { + /* cmd word 0 */ + __le32 obj_id; + __le32 pad; + /* cmd word 1-2 */ + u8 label[16]; + /* cmd word 3-4 */ + u8 obj_type[16]; +}; + +struct dprc_cmd_set_obj_irq { + /* cmd word 0 */ + __le32 irq_val; + u8 irq_index; + u8 pad[3]; + /* cmd word 1 */ + __le64 irq_addr; + /* cmd word 2 */ + __le32 irq_num; + __le32 obj_id; + /* cmd word 3-4 */ + u8 obj_type[16]; +}; + +struct dprc_cmd_get_obj_irq { + /* cmd word 0 */ + __le32 obj_id; + u8 irq_index; + u8 pad[3]; + /* cmd word 1-2 */ + u8 obj_type[16]; +}; + +struct dprc_rsp_get_obj_irq { + /* response word 0 */ + __le32 irq_val; + __le32 pad; + /* response word 1 */ + __le64 irq_addr; + /* response word 2 */ + __le32 irq_num; + __le32 type; +}; + +struct dprc_cmd_connect { + /* cmd word 0 */ + __le32 ep1_id; + __le32 ep1_interface_id; + /* cmd word 1 */ + __le32 ep2_id; + __le32 ep2_interface_id; + /* cmd word 2-3 */ + u8 ep1_type[16]; + /* cmd word 4 */ + __le32 max_rate; + __le32 committed_rate; + /* cmd word 5-6 */ + u8 ep2_type[16]; +}; + +struct dprc_cmd_disconnect { + /* cmd word 0 */ + __le32 id; + __le32 interface_id; + /* cmd word 1-2 */ + u8 type[16]; +}; + +struct dprc_cmd_get_connection { + /* cmd word 0 */ + __le32 ep1_id; + __le32 ep1_interface_id; + /* cmd word 1-2 */ + u8 ep1_type[16]; +}; + +struct dprc_rsp_get_connection { + /* response word 0-2 */ + __le64 pad[3]; + /* response word 3 */ + __le32 ep2_id; + __le32 ep2_interface_id; + /* response word 4-5 */ + u8 ep2_type[16]; + /* response word 6 */ + __le32 state; +}; + #endif /* _FSL_DPRC_CMD_H */ diff --git a/drivers/staging/fsl-mc/bus/dprc.c b/drivers/staging/fsl-mc/bus/dprc.c index a2c4737..c260549 100644 --- a/drivers/staging/fsl-mc/bus/dprc.c +++ b/drivers/staging/fsl-mc/bus/dprc.c @@ -1,4 +1,4 @@ -/* Copyright 2013-2014 Freescale Semiconductor Inc. +/* Copyright 2013-2016 Freescale Semiconductor Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -51,12 +51,14 @@ int dprc_open(struct fsl_mc_io *mc_io, u16 *token) { struct mc_command cmd = { 0 }; + struct dprc_cmd_open *cmd_params; int err; /* prepare command */ cmd.header = mc_encode_cmd_header(DPRC_CMDID_OPEN, cmd_flags, 0); - cmd.params[0] |= mc_enc(0, 32, container_id); + cmd_params = (struct dprc_cmd_open *)cmd.params; + cmd_params->container_id = cpu_to_le32(container_id); /* send command to mc*/ err = mc_send_command(mc_io, &cmd); @@ -64,7 +66,7 @@ int dprc_open(struct fsl_mc_io *mc_io, return err; /* retrieve response parameters */ - *token = MC_CMD_HDR_READ_TOKEN(cmd.header); + *token = mc_cmd_hdr_read_token(&cmd); return 0; } @@ -115,28 +117,17 @@ int dprc_create_container(struct fsl_mc_io *mc_io, u64 *child_portal_offset) { struct mc_command cmd = { 0 }; + struct dprc_cmd_create_container *cmd_params; + struct dprc_rsp_create_container *rsp_params; int err; /* prepare command */ - cmd.params[0] |= mc_enc(32, 16, cfg->icid); - cmd.params[0] |= mc_enc(0, 32, cfg->options); - cmd.params[1] |= mc_enc(32, 32, cfg->portal_id); - cmd.params[2] |= mc_enc(0, 8, cfg->label[0]); - cmd.params[2] |= mc_enc(8, 8, cfg->label[1]); - cmd.params[2] |= mc_enc(16, 8, cfg->label[2]); - cmd.params[2] |= mc_enc(24, 8, cfg->label[3]); - cmd.params[2] |= mc_enc(32, 8, cfg->label[4]); - cmd.params[2] |= mc_enc(40, 8, cfg->label[5]); - cmd.params[2] |= mc_enc(48, 8, cfg->label[6]); - cmd.params[2] |= mc_enc(56, 8, cfg->label[7]); - cmd.params[3] |= mc_enc(0, 8, cfg->label[8]); - cmd.params[3] |= mc_enc(8, 8, cfg->label[9]); - cmd.params[3] |= mc_enc(16, 8, cfg->label[10]); - cmd.params[3] |= mc_enc(24, 8, cfg->label[11]); - cmd.params[3] |= mc_enc(32, 8, cfg->label[12]); - cmd.params[3] |= mc_enc(40, 8, cfg->label[13]); - cmd.params[3] |= mc_enc(48, 8, cfg->label[14]); - cmd.params[3] |= mc_enc(56, 8, cfg->label[15]); + cmd_params = (struct dprc_cmd_create_container *)cmd.params; + cmd_params->options = cpu_to_le32(cfg->options); + cmd_params->icid = cpu_to_le16(cfg->icid); + cmd_params->portal_id = cpu_to_le32(cfg->portal_id); + strncpy(cmd_params->label, cfg->label, 16); + cmd_params->label[15] = '\0'; cmd.header = mc_encode_cmd_header(DPRC_CMDID_CREATE_CONT, cmd_flags, token); @@ -147,8 +138,9 @@ int dprc_create_container(struct fsl_mc_io *mc_io, return err; /* retrieve response parameters */ - *child_container_id = mc_dec(cmd.params[1], 0, 32); - *child_portal_offset = mc_dec(cmd.params[2], 0, 64); + rsp_params = (struct dprc_rsp_create_container *)cmd.params; + *child_container_id = le32_to_cpu(rsp_params->child_container_id); + *child_portal_offset = le64_to_cpu(rsp_params->child_portal_addr); return 0; } @@ -181,11 +173,13 @@ int dprc_destroy_container(struct fsl_mc_io *mc_io, int child_container_id) { struct mc_command cmd = { 0 }; + struct dprc_cmd_destroy_container *cmd_params; /* prepare command */ cmd.header = mc_encode_cmd_header(DPRC_CMDID_DESTROY_CONT, cmd_flags, token); - cmd.params[0] |= mc_enc(0, 32, child_container_id); + cmd_params = (struct dprc_cmd_destroy_container *)cmd.params; + cmd_params->child_container_id = cpu_to_le32(child_container_id); /* send command to mc*/ return mc_send_command(mc_io, &cmd); @@ -219,11 +213,13 @@ int dprc_reset_container(struct fsl_mc_io *mc_io, int child_container_id) { struct mc_command cmd = { 0 }; + struct dprc_cmd_reset_container *cmd_params; /* prepare command */ cmd.header = mc_encode_cmd_header(DPRC_CMDID_RESET_CONT, cmd_flags, token); - cmd.params[0] |= mc_enc(0, 32, child_container_id); + cmd_params = (struct dprc_cmd_reset_container *)cmd.params; + cmd_params->child_container_id = cpu_to_le32(child_container_id); /* send command to mc*/ return mc_send_command(mc_io, &cmd); @@ -249,13 +245,16 @@ int dprc_get_irq(struct fsl_mc_io *mc_io, struct dprc_irq_cfg *irq_cfg) { struct mc_command cmd = { 0 }; + struct dprc_cmd_get_irq *cmd_params; + struct dprc_rsp_get_irq *rsp_params; int err; /* prepare command */ cmd.header = mc_encode_cmd_header(DPRC_CMDID_GET_IRQ, cmd_flags, token); - cmd.params[0] |= mc_enc(32, 8, irq_index); + cmd_params = (struct dprc_cmd_get_irq *)cmd.params; + cmd_params->irq_index = irq_index; /* send command to mc*/ err = mc_send_command(mc_io, &cmd); @@ -263,10 +262,11 @@ int dprc_get_irq(struct fsl_mc_io *mc_io, return err; /* retrieve response parameters */ - irq_cfg->val = mc_dec(cmd.params[0], 0, 32); - irq_cfg->paddr = mc_dec(cmd.params[1], 0, 64); - irq_cfg->irq_num = mc_dec(cmd.params[2], 0, 32); - *type = mc_dec(cmd.params[2], 32, 32); + rsp_params = (struct dprc_rsp_get_irq *)cmd.params; + irq_cfg->val = le32_to_cpu(rsp_params->irq_val); + irq_cfg->paddr = le64_to_cpu(rsp_params->irq_addr); + irq_cfg->irq_num = le32_to_cpu(rsp_params->irq_num); + *type = le32_to_cpu(rsp_params->type); return 0; } @@ -288,15 +288,17 @@ int dprc_set_irq(struct fsl_mc_io *mc_io, struct dprc_irq_cfg *irq_cfg) { struct mc_command cmd = { 0 }; + struct dprc_cmd_set_irq *cmd_params; /* prepare command */ cmd.header = mc_encode_cmd_header(DPRC_CMDID_SET_IRQ, cmd_flags, token); - cmd.params[0] |= mc_enc(32, 8, irq_index); - cmd.params[0] |= mc_enc(0, 32, irq_cfg->val); - cmd.params[1] |= mc_enc(0, 64, irq_cfg->paddr); - cmd.params[2] |= mc_enc(0, 32, irq_cfg->irq_num); + cmd_params = (struct dprc_cmd_set_irq *)cmd.params; + cmd_params->irq_val = cpu_to_le32(irq_cfg->val); + cmd_params->irq_index = irq_index; + cmd_params->irq_addr = cpu_to_le64(irq_cfg->paddr); + cmd_params->irq_num = cpu_to_le32(irq_cfg->irq_num); /* send command to mc*/ return mc_send_command(mc_io, &cmd); @@ -319,12 +321,15 @@ int dprc_get_irq_enable(struct fsl_mc_io *mc_io, u8 *en) { struct mc_command cmd = { 0 }; + struct dprc_cmd_get_irq_enable *cmd_params; + struct dprc_rsp_get_irq_enable *rsp_params; int err; /* prepare command */ cmd.header = mc_encode_cmd_header(DPRC_CMDID_GET_IRQ_ENABLE, cmd_flags, token); - cmd.params[0] |= mc_enc(32, 8, irq_index); + cmd_params = (struct dprc_cmd_get_irq_enable *)cmd.params; + cmd_params->irq_index = irq_index; /* send command to mc*/ err = mc_send_command(mc_io, &cmd); @@ -332,7 +337,8 @@ int dprc_get_irq_enable(struct fsl_mc_io *mc_io, return err; /* retrieve response parameters */ - *en = mc_dec(cmd.params[0], 0, 8); + rsp_params = (struct dprc_rsp_get_irq_enable *)cmd.params; + *en = rsp_params->enabled & DPRC_ENABLE; return 0; } @@ -359,12 +365,14 @@ int dprc_set_irq_enable(struct fsl_mc_io *mc_io, u8 en) { struct mc_command cmd = { 0 }; + struct dprc_cmd_set_irq_enable *cmd_params; /* prepare command */ cmd.header = mc_encode_cmd_header(DPRC_CMDID_SET_IRQ_ENABLE, cmd_flags, token); - cmd.params[0] |= mc_enc(0, 8, en); - cmd.params[0] |= mc_enc(32, 8, irq_index); + cmd_params = (struct dprc_cmd_set_irq_enable *)cmd.params; + cmd_params->enable = en & DPRC_ENABLE; + cmd_params->irq_index = irq_index; /* send command to mc*/ return mc_send_command(mc_io, &cmd); @@ -390,12 +398,15 @@ int dprc_get_irq_mask(struct fsl_mc_io *mc_io, u32 *mask) { struct mc_command cmd = { 0 }; + struct dprc_cmd_get_irq_mask *cmd_params; + struct dprc_rsp_get_irq_mask *rsp_params; int err; /* prepare command */ cmd.header = mc_encode_cmd_header(DPRC_CMDID_GET_IRQ_MASK, cmd_flags, token); - cmd.params[0] |= mc_enc(32, 8, irq_index); + cmd_params = (struct dprc_cmd_get_irq_mask *)cmd.params; + cmd_params->irq_index = irq_index; /* send command to mc*/ err = mc_send_command(mc_io, &cmd); @@ -403,7 +414,8 @@ int dprc_get_irq_mask(struct fsl_mc_io *mc_io, return err; /* retrieve response parameters */ - *mask = mc_dec(cmd.params[0], 0, 32); + rsp_params = (struct dprc_rsp_get_irq_mask *)cmd.params; + *mask = le32_to_cpu(rsp_params->mask); return 0; } @@ -431,12 +443,14 @@ int dprc_set_irq_mask(struct fsl_mc_io *mc_io, u32 mask) { struct mc_command cmd = { 0 }; + struct dprc_cmd_set_irq_mask *cmd_params; /* prepare command */ cmd.header = mc_encode_cmd_header(DPRC_CMDID_SET_IRQ_MASK, cmd_flags, token); - cmd.params[0] |= mc_enc(0, 32, mask); - cmd.params[0] |= mc_enc(32, 8, irq_index); + cmd_params = (struct dprc_cmd_set_irq_mask *)cmd.params; + cmd_params->mask = cpu_to_le32(mask); + cmd_params->irq_index = irq_index; /* send command to mc*/ return mc_send_command(mc_io, &cmd); @@ -461,13 +475,16 @@ int dprc_get_irq_status(struct fsl_mc_io *mc_io, u32 *status) { struct mc_command cmd = { 0 }; + struct dprc_cmd_get_irq_status *cmd_params; + struct dprc_rsp_get_irq_status *rsp_params; int err; /* prepare command */ cmd.header = mc_encode_cmd_header(DPRC_CMDID_GET_IRQ_STATUS, cmd_flags, token); - cmd.params[0] |= mc_enc(0, 32, *status); - cmd.params[0] |= mc_enc(32, 8, irq_index); + cmd_params = (struct dprc_cmd_get_irq_status *)cmd.params; + cmd_params->status = cpu_to_le32(*status); + cmd_params->irq_index = irq_index; /* send command to mc*/ err = mc_send_command(mc_io, &cmd); @@ -475,7 +492,8 @@ int dprc_get_irq_status(struct fsl_mc_io *mc_io, return err; /* retrieve response parameters */ - *status = mc_dec(cmd.params[0], 0, 32); + rsp_params = (struct dprc_rsp_get_irq_status *)cmd.params; + *status = le32_to_cpu(rsp_params->status); return 0; } @@ -499,12 +517,14 @@ int dprc_clear_irq_status(struct fsl_mc_io *mc_io, u32 status) { struct mc_command cmd = { 0 }; + struct dprc_cmd_clear_irq_status *cmd_params; /* prepare command */ cmd.header = mc_encode_cmd_header(DPRC_CMDID_CLEAR_IRQ_STATUS, cmd_flags, token); - cmd.params[0] |= mc_enc(0, 32, status); - cmd.params[0] |= mc_enc(32, 8, irq_index); + cmd_params = (struct dprc_cmd_clear_irq_status *)cmd.params; + cmd_params->status = cpu_to_le32(status); + cmd_params->irq_index = irq_index; /* send command to mc*/ return mc_send_command(mc_io, &cmd); @@ -525,6 +545,7 @@ int dprc_get_attributes(struct fsl_mc_io *mc_io, struct dprc_attributes *attr) { struct mc_command cmd = { 0 }; + struct dprc_rsp_get_attributes *rsp_params; int err; /* prepare command */ @@ -538,12 +559,13 @@ int dprc_get_attributes(struct fsl_mc_io *mc_io, return err; /* retrieve response parameters */ - attr->container_id = mc_dec(cmd.params[0], 0, 32); - attr->icid = mc_dec(cmd.params[0], 32, 16); - attr->options = mc_dec(cmd.params[1], 0, 32); - attr->portal_id = mc_dec(cmd.params[1], 32, 32); - attr->version.major = mc_dec(cmd.params[2], 0, 16); - attr->version.minor = mc_dec(cmd.params[2], 16, 16); + rsp_params = (struct dprc_rsp_get_attributes *)cmd.params; + attr->container_id = le32_to_cpu(rsp_params->container_id); + attr->icid = le16_to_cpu(rsp_params->icid); + attr->options = le32_to_cpu(rsp_params->options); + attr->portal_id = le32_to_cpu(rsp_params->portal_id); + attr->version.major = le16_to_cpu(rsp_params->version_major); + attr->version.minor = le16_to_cpu(rsp_params->version_minor); return 0; } @@ -581,28 +603,16 @@ int dprc_set_res_quota(struct fsl_mc_io *mc_io, u16 quota) { struct mc_command cmd = { 0 }; + struct dprc_cmd_set_res_quota *cmd_params; /* prepare command */ cmd.header = mc_encode_cmd_header(DPRC_CMDID_SET_RES_QUOTA, cmd_flags, token); - cmd.params[0] |= mc_enc(0, 32, child_container_id); - cmd.params[0] |= mc_enc(32, 16, quota); - cmd.params[1] |= mc_enc(0, 8, type[0]); - cmd.params[1] |= mc_enc(8, 8, type[1]); - cmd.params[1] |= mc_enc(16, 8, type[2]); - cmd.params[1] |= mc_enc(24, 8, type[3]); - cmd.params[1] |= mc_enc(32, 8, type[4]); - cmd.params[1] |= mc_enc(40, 8, type[5]); - cmd.params[1] |= mc_enc(48, 8, type[6]); - cmd.params[1] |= mc_enc(56, 8, type[7]); - cmd.params[2] |= mc_enc(0, 8, type[8]); - cmd.params[2] |= mc_enc(8, 8, type[9]); - cmd.params[2] |= mc_enc(16, 8, type[10]); - cmd.params[2] |= mc_enc(24, 8, type[11]); - cmd.params[2] |= mc_enc(32, 8, type[12]); - cmd.params[2] |= mc_enc(40, 8, type[13]); - cmd.params[2] |= mc_enc(48, 8, type[14]); - cmd.params[2] |= mc_enc(56, 8, '\0'); + cmd_params = (struct dprc_cmd_set_res_quota *)cmd.params; + cmd_params->child_container_id = cpu_to_le32(child_container_id); + cmd_params->quota = cpu_to_le16(quota); + strncpy(cmd_params->type, type, 16); + cmd_params->type[15] = '\0'; /* send command to mc*/ return mc_send_command(mc_io, &cmd); @@ -631,28 +641,17 @@ int dprc_get_res_quota(struct fsl_mc_io *mc_io, u16 *quota) { struct mc_command cmd = { 0 }; + struct dprc_cmd_get_res_quota *cmd_params; + struct dprc_rsp_get_res_quota *rsp_params; int err; /* prepare command */ cmd.header = mc_encode_cmd_header(DPRC_CMDID_GET_RES_QUOTA, cmd_flags, token); - cmd.params[0] |= mc_enc(0, 32, child_container_id); - cmd.params[1] |= mc_enc(0, 8, type[0]); - cmd.params[1] |= mc_enc(8, 8, type[1]); - cmd.params[1] |= mc_enc(16, 8, type[2]); - cmd.params[1] |= mc_enc(24, 8, type[3]); - cmd.params[1] |= mc_enc(32, 8, type[4]); - cmd.params[1] |= mc_enc(40, 8, type[5]); - cmd.params[1] |= mc_enc(48, 8, type[6]); - cmd.params[1] |= mc_enc(56, 8, type[7]); - cmd.params[2] |= mc_enc(0, 8, type[8]); - cmd.params[2] |= mc_enc(8, 8, type[9]); - cmd.params[2] |= mc_enc(16, 8, type[10]); - cmd.params[2] |= mc_enc(24, 8, type[11]); - cmd.params[2] |= mc_enc(32, 8, type[12]); - cmd.params[2] |= mc_enc(40, 8, type[13]); - cmd.params[2] |= mc_enc(48, 8, type[14]); - cmd.params[2] |= mc_enc(56, 8, '\0'); + cmd_params = (struct dprc_cmd_get_res_quota *)cmd.params; + cmd_params->child_container_id = cpu_to_le32(child_container_id); + strncpy(cmd_params->type, type, 16); + cmd_params->type[15] = '\0'; /* send command to mc*/ err = mc_send_command(mc_io, &cmd); @@ -660,7 +659,8 @@ int dprc_get_res_quota(struct fsl_mc_io *mc_io, return err; /* retrieve response parameters */ - *quota = mc_dec(cmd.params[0], 32, 16); + rsp_params = (struct dprc_rsp_get_res_quota *)cmd.params; + *quota = le16_to_cpu(rsp_params->quota); return 0; } @@ -704,30 +704,18 @@ int dprc_assign(struct fsl_mc_io *mc_io, struct dprc_res_req *res_req) { struct mc_command cmd = { 0 }; + struct dprc_cmd_assign *cmd_params; /* prepare command */ cmd.header = mc_encode_cmd_header(DPRC_CMDID_ASSIGN, cmd_flags, token); - cmd.params[0] |= mc_enc(0, 32, container_id); - cmd.params[0] |= mc_enc(32, 32, res_req->options); - cmd.params[1] |= mc_enc(0, 32, res_req->num); - cmd.params[1] |= mc_enc(32, 32, res_req->id_base_align); - cmd.params[2] |= mc_enc(0, 8, res_req->type[0]); - cmd.params[2] |= mc_enc(8, 8, res_req->type[1]); - cmd.params[2] |= mc_enc(16, 8, res_req->type[2]); - cmd.params[2] |= mc_enc(24, 8, res_req->type[3]); - cmd.params[2] |= mc_enc(32, 8, res_req->type[4]); - cmd.params[2] |= mc_enc(40, 8, res_req->type[5]); - cmd.params[2] |= mc_enc(48, 8, res_req->type[6]); - cmd.params[2] |= mc_enc(56, 8, res_req->type[7]); - cmd.params[3] |= mc_enc(0, 8, res_req->type[8]); - cmd.params[3] |= mc_enc(8, 8, res_req->type[9]); - cmd.params[3] |= mc_enc(16, 8, res_req->type[10]); - cmd.params[3] |= mc_enc(24, 8, res_req->type[11]); - cmd.params[3] |= mc_enc(32, 8, res_req->type[12]); - cmd.params[3] |= mc_enc(40, 8, res_req->type[13]); - cmd.params[3] |= mc_enc(48, 8, res_req->type[14]); - cmd.params[3] |= mc_enc(56, 8, res_req->type[15]); + cmd_params = (struct dprc_cmd_assign *)cmd.params; + cmd_params->container_id = cpu_to_le32(container_id); + cmd_params->options = cpu_to_le32(res_req->options); + cmd_params->num = cpu_to_le32(res_req->num); + cmd_params->id_base_align = cpu_to_le32(res_req->id_base_align); + strncpy(cmd_params->type, res_req->type, 16); + cmd_params->type[15] = '\0'; /* send command to mc*/ return mc_send_command(mc_io, &cmd); @@ -755,31 +743,19 @@ int dprc_unassign(struct fsl_mc_io *mc_io, struct dprc_res_req *res_req) { struct mc_command cmd = { 0 }; + struct dprc_cmd_unassign *cmd_params; /* prepare command */ cmd.header = mc_encode_cmd_header(DPRC_CMDID_UNASSIGN, cmd_flags, token); - cmd.params[0] |= mc_enc(0, 32, child_container_id); - cmd.params[0] |= mc_enc(32, 32, res_req->options); - cmd.params[1] |= mc_enc(0, 32, res_req->num); - cmd.params[1] |= mc_enc(32, 32, res_req->id_base_align); - cmd.params[2] |= mc_enc(0, 8, res_req->type[0]); - cmd.params[2] |= mc_enc(8, 8, res_req->type[1]); - cmd.params[2] |= mc_enc(16, 8, res_req->type[2]); - cmd.params[2] |= mc_enc(24, 8, res_req->type[3]); - cmd.params[2] |= mc_enc(32, 8, res_req->type[4]); - cmd.params[2] |= mc_enc(40, 8, res_req->type[5]); - cmd.params[2] |= mc_enc(48, 8, res_req->type[6]); - cmd.params[2] |= mc_enc(56, 8, res_req->type[7]); - cmd.params[3] |= mc_enc(0, 8, res_req->type[8]); - cmd.params[3] |= mc_enc(8, 8, res_req->type[9]); - cmd.params[3] |= mc_enc(16, 8, res_req->type[10]); - cmd.params[3] |= mc_enc(24, 8, res_req->type[11]); - cmd.params[3] |= mc_enc(32, 8, res_req->type[12]); - cmd.params[3] |= mc_enc(40, 8, res_req->type[13]); - cmd.params[3] |= mc_enc(48, 8, res_req->type[14]); - cmd.params[3] |= mc_enc(56, 8, res_req->type[15]); + cmd_params = (struct dprc_cmd_unassign *)cmd.params; + cmd_params->child_container_id = cpu_to_le32(child_container_id); + cmd_params->options = cpu_to_le32(res_req->options); + cmd_params->num = cpu_to_le32(res_req->num); + cmd_params->id_base_align = cpu_to_le32(res_req->id_base_align); + strncpy(cmd_params->type, res_req->type, 16); + cmd_params->type[15] = '\0'; /* send command to mc*/ return mc_send_command(mc_io, &cmd); @@ -800,6 +776,7 @@ int dprc_get_pool_count(struct fsl_mc_io *mc_io, int *pool_count) { struct mc_command cmd = { 0 }; + struct dprc_rsp_get_pool_count *rsp_params; int err; /* prepare command */ @@ -812,7 +789,8 @@ int dprc_get_pool_count(struct fsl_mc_io *mc_io, return err; /* retrieve response parameters */ - *pool_count = mc_dec(cmd.params[0], 0, 32); + rsp_params = (struct dprc_rsp_get_pool_count *)cmd.params; + *pool_count = le32_to_cpu(rsp_params->pool_count); return 0; } @@ -839,13 +817,16 @@ int dprc_get_pool(struct fsl_mc_io *mc_io, char *type) { struct mc_command cmd = { 0 }; + struct dprc_cmd_get_pool *cmd_params; + struct dprc_rsp_get_pool *rsp_params; int err; /* prepare command */ cmd.header = mc_encode_cmd_header(DPRC_CMDID_GET_POOL, cmd_flags, token); - cmd.params[0] |= mc_enc(0, 32, pool_index); + cmd_params = (struct dprc_cmd_get_pool *)cmd.params; + cmd_params->pool_index = cpu_to_le32(pool_index); /* send command to mc*/ err = mc_send_command(mc_io, &cmd); @@ -853,21 +834,8 @@ int dprc_get_pool(struct fsl_mc_io *mc_io, return err; /* retrieve response parameters */ - type[0] = mc_dec(cmd.params[1], 0, 8); - type[1] = mc_dec(cmd.params[1], 8, 8); - type[2] = mc_dec(cmd.params[1], 16, 8); - type[3] = mc_dec(cmd.params[1], 24, 8); - type[4] = mc_dec(cmd.params[1], 32, 8); - type[5] = mc_dec(cmd.params[1], 40, 8); - type[6] = mc_dec(cmd.params[1], 48, 8); - type[7] = mc_dec(cmd.params[1], 56, 8); - type[8] = mc_dec(cmd.params[2], 0, 8); - type[9] = mc_dec(cmd.params[2], 8, 8); - type[10] = mc_dec(cmd.params[2], 16, 8); - type[11] = mc_dec(cmd.params[2], 24, 8); - type[12] = mc_dec(cmd.params[2], 32, 8); - type[13] = mc_dec(cmd.params[2], 40, 8); - type[14] = mc_dec(cmd.params[2], 48, 8); + rsp_params = (struct dprc_rsp_get_pool *)cmd.params; + strncpy(type, rsp_params->type, 16); type[15] = '\0'; return 0; @@ -888,6 +856,7 @@ int dprc_get_obj_count(struct fsl_mc_io *mc_io, int *obj_count) { struct mc_command cmd = { 0 }; + struct dprc_rsp_get_obj_count *rsp_params; int err; /* prepare command */ @@ -900,7 +869,8 @@ int dprc_get_obj_count(struct fsl_mc_io *mc_io, return err; /* retrieve response parameters */ - *obj_count = mc_dec(cmd.params[0], 32, 32); + rsp_params = (struct dprc_rsp_get_obj_count *)cmd.params; + *obj_count = le32_to_cpu(rsp_params->obj_count); return 0; } @@ -928,13 +898,16 @@ int dprc_get_obj(struct fsl_mc_io *mc_io, struct dprc_obj_desc *obj_desc) { struct mc_command cmd = { 0 }; + struct dprc_cmd_get_obj *cmd_params; + struct dprc_rsp_get_obj *rsp_params; int err; /* prepare command */ cmd.header = mc_encode_cmd_header(DPRC_CMDID_GET_OBJ, cmd_flags, token); - cmd.params[0] |= mc_enc(0, 32, obj_index); + cmd_params = (struct dprc_cmd_get_obj *)cmd.params; + cmd_params->obj_index = cpu_to_le32(obj_index); /* send command to mc*/ err = mc_send_command(mc_io, &cmd); @@ -942,45 +915,18 @@ int dprc_get_obj(struct fsl_mc_io *mc_io, return err; /* retrieve response parameters */ - obj_desc->id = mc_dec(cmd.params[0], 32, 32); - obj_desc->vendor = mc_dec(cmd.params[1], 0, 16); - obj_desc->irq_count = mc_dec(cmd.params[1], 16, 8); - obj_desc->region_count = mc_dec(cmd.params[1], 24, 8); - obj_desc->state = mc_dec(cmd.params[1], 32, 32); - obj_desc->ver_major = mc_dec(cmd.params[2], 0, 16); - obj_desc->ver_minor = mc_dec(cmd.params[2], 16, 16); - obj_desc->flags = mc_dec(cmd.params[2], 32, 16); - obj_desc->type[0] = mc_dec(cmd.params[3], 0, 8); - obj_desc->type[1] = mc_dec(cmd.params[3], 8, 8); - obj_desc->type[2] = mc_dec(cmd.params[3], 16, 8); - obj_desc->type[3] = mc_dec(cmd.params[3], 24, 8); - obj_desc->type[4] = mc_dec(cmd.params[3], 32, 8); - obj_desc->type[5] = mc_dec(cmd.params[3], 40, 8); - obj_desc->type[6] = mc_dec(cmd.params[3], 48, 8); - obj_desc->type[7] = mc_dec(cmd.params[3], 56, 8); - obj_desc->type[8] = mc_dec(cmd.params[4], 0, 8); - obj_desc->type[9] = mc_dec(cmd.params[4], 8, 8); - obj_desc->type[10] = mc_dec(cmd.params[4], 16, 8); - obj_desc->type[11] = mc_dec(cmd.params[4], 24, 8); - obj_desc->type[12] = mc_dec(cmd.params[4], 32, 8); - obj_desc->type[13] = mc_dec(cmd.params[4], 40, 8); - obj_desc->type[14] = mc_dec(cmd.params[4], 48, 8); + rsp_params = (struct dprc_rsp_get_obj *)cmd.params; + obj_desc->id = le32_to_cpu(rsp_params->id); + obj_desc->vendor = le16_to_cpu(rsp_params->vendor); + obj_desc->irq_count = rsp_params->irq_count; + obj_desc->region_count = rsp_params->region_count; + obj_desc->state = le32_to_cpu(rsp_params->state); + obj_desc->ver_major = le16_to_cpu(rsp_params->version_major); + obj_desc->ver_minor = le16_to_cpu(rsp_params->version_minor); + obj_desc->flags = le16_to_cpu(rsp_params->flags); + strncpy(obj_desc->type, rsp_params->type, 16); obj_desc->type[15] = '\0'; - obj_desc->label[0] = mc_dec(cmd.params[5], 0, 8); - obj_desc->label[1] = mc_dec(cmd.params[5], 8, 8); - obj_desc->label[2] = mc_dec(cmd.params[5], 16, 8); - obj_desc->label[3] = mc_dec(cmd.params[5], 24, 8); - obj_desc->label[4] = mc_dec(cmd.params[5], 32, 8); - obj_desc->label[5] = mc_dec(cmd.params[5], 40, 8); - obj_desc->label[6] = mc_dec(cmd.params[5], 48, 8); - obj_desc->label[7] = mc_dec(cmd.params[5], 56, 8); - obj_desc->label[8] = mc_dec(cmd.params[6], 0, 8); - obj_desc->label[9] = mc_dec(cmd.params[6], 8, 8); - obj_desc->label[10] = mc_dec(cmd.params[6], 16, 8); - obj_desc->label[11] = mc_dec(cmd.params[6], 24, 8); - obj_desc->label[12] = mc_dec(cmd.params[6], 32, 8); - obj_desc->label[13] = mc_dec(cmd.params[6], 40, 8); - obj_desc->label[14] = mc_dec(cmd.params[6], 48, 8); + strncpy(obj_desc->label, rsp_params->label, 16); obj_desc->label[15] = '\0'; return 0; } @@ -1007,29 +953,18 @@ int dprc_get_obj_desc(struct fsl_mc_io *mc_io, struct dprc_obj_desc *obj_desc) { struct mc_command cmd = { 0 }; + struct dprc_cmd_get_obj_desc *cmd_params; + struct dprc_rsp_get_obj_desc *rsp_params; int err; /* prepare command */ cmd.header = mc_encode_cmd_header(DPRC_CMDID_GET_OBJ_DESC, cmd_flags, token); - cmd.params[0] |= mc_enc(0, 32, obj_id); - cmd.params[1] |= mc_enc(0, 8, obj_type[0]); - cmd.params[1] |= mc_enc(8, 8, obj_type[1]); - cmd.params[1] |= mc_enc(16, 8, obj_type[2]); - cmd.params[1] |= mc_enc(24, 8, obj_type[3]); - cmd.params[1] |= mc_enc(32, 8, obj_type[4]); - cmd.params[1] |= mc_enc(40, 8, obj_type[5]); - cmd.params[1] |= mc_enc(48, 8, obj_type[6]); - cmd.params[1] |= mc_enc(56, 8, obj_type[7]); - cmd.params[2] |= mc_enc(0, 8, obj_type[8]); - cmd.params[2] |= mc_enc(8, 8, obj_type[9]); - cmd.params[2] |= mc_enc(16, 8, obj_type[10]); - cmd.params[2] |= mc_enc(24, 8, obj_type[11]); - cmd.params[2] |= mc_enc(32, 8, obj_type[12]); - cmd.params[2] |= mc_enc(40, 8, obj_type[13]); - cmd.params[2] |= mc_enc(48, 8, obj_type[14]); - cmd.params[2] |= mc_enc(56, 8, obj_type[15]); + cmd_params = (struct dprc_cmd_get_obj_desc *)cmd.params; + cmd_params->obj_id = cpu_to_le32(obj_id); + strncpy(cmd_params->type, obj_type, 16); + cmd_params->type[15] = '\0'; /* send command to mc*/ err = mc_send_command(mc_io, &cmd); @@ -1037,46 +972,19 @@ int dprc_get_obj_desc(struct fsl_mc_io *mc_io, return err; /* retrieve response parameters */ - obj_desc->id = (int)mc_dec(cmd.params[0], 32, 32); - obj_desc->vendor = (u16)mc_dec(cmd.params[1], 0, 16); - obj_desc->vendor = (u8)mc_dec(cmd.params[1], 16, 8); - obj_desc->region_count = (u8)mc_dec(cmd.params[1], 24, 8); - obj_desc->state = (u32)mc_dec(cmd.params[1], 32, 32); - obj_desc->ver_major = (u16)mc_dec(cmd.params[2], 0, 16); - obj_desc->ver_minor = (u16)mc_dec(cmd.params[2], 16, 16); - obj_desc->flags = mc_dec(cmd.params[2], 32, 16); - obj_desc->type[0] = (char)mc_dec(cmd.params[3], 0, 8); - obj_desc->type[1] = (char)mc_dec(cmd.params[3], 8, 8); - obj_desc->type[2] = (char)mc_dec(cmd.params[3], 16, 8); - obj_desc->type[3] = (char)mc_dec(cmd.params[3], 24, 8); - obj_desc->type[4] = (char)mc_dec(cmd.params[3], 32, 8); - obj_desc->type[5] = (char)mc_dec(cmd.params[3], 40, 8); - obj_desc->type[6] = (char)mc_dec(cmd.params[3], 48, 8); - obj_desc->type[7] = (char)mc_dec(cmd.params[3], 56, 8); - obj_desc->type[8] = (char)mc_dec(cmd.params[4], 0, 8); - obj_desc->type[9] = (char)mc_dec(cmd.params[4], 8, 8); - obj_desc->type[10] = (char)mc_dec(cmd.params[4], 16, 8); - obj_desc->type[11] = (char)mc_dec(cmd.params[4], 24, 8); - obj_desc->type[12] = (char)mc_dec(cmd.params[4], 32, 8); - obj_desc->type[13] = (char)mc_dec(cmd.params[4], 40, 8); - obj_desc->type[14] = (char)mc_dec(cmd.params[4], 48, 8); - obj_desc->type[15] = (char)mc_dec(cmd.params[4], 56, 8); - obj_desc->label[0] = (char)mc_dec(cmd.params[5], 0, 8); - obj_desc->label[1] = (char)mc_dec(cmd.params[5], 8, 8); - obj_desc->label[2] = (char)mc_dec(cmd.params[5], 16, 8); - obj_desc->label[3] = (char)mc_dec(cmd.params[5], 24, 8); - obj_desc->label[4] = (char)mc_dec(cmd.params[5], 32, 8); - obj_desc->label[5] = (char)mc_dec(cmd.params[5], 40, 8); - obj_desc->label[6] = (char)mc_dec(cmd.params[5], 48, 8); - obj_desc->label[7] = (char)mc_dec(cmd.params[5], 56, 8); - obj_desc->label[8] = (char)mc_dec(cmd.params[6], 0, 8); - obj_desc->label[9] = (char)mc_dec(cmd.params[6], 8, 8); - obj_desc->label[10] = (char)mc_dec(cmd.params[6], 16, 8); - obj_desc->label[11] = (char)mc_dec(cmd.params[6], 24, 8); - obj_desc->label[12] = (char)mc_dec(cmd.params[6], 32, 8); - obj_desc->label[13] = (char)mc_dec(cmd.params[6], 40, 8); - obj_desc->label[14] = (char)mc_dec(cmd.params[6], 48, 8); - obj_desc->label[15] = (char)mc_dec(cmd.params[6], 56, 8); + rsp_params = (struct dprc_rsp_get_obj_desc *)cmd.params; + obj_desc->id = le32_to_cpu(rsp_params->id); + obj_desc->vendor = le16_to_cpu(rsp_params->vendor); + obj_desc->irq_count = rsp_params->irq_count; + obj_desc->region_count = rsp_params->region_count; + obj_desc->state = le32_to_cpu(rsp_params->state); + obj_desc->ver_major = le16_to_cpu(rsp_params->version_major); + obj_desc->ver_minor = le16_to_cpu(rsp_params->version_minor); + obj_desc->flags = le16_to_cpu(rsp_params->flags); + strncpy(obj_desc->type, rsp_params->type, 16); + obj_desc->type[15] = '\0'; + strncpy(obj_desc->label, rsp_params->label, 16); + obj_desc->label[15] = '\0'; return 0; } @@ -1103,32 +1011,20 @@ int dprc_set_obj_irq(struct fsl_mc_io *mc_io, struct dprc_irq_cfg *irq_cfg) { struct mc_command cmd = { 0 }; + struct dprc_cmd_set_obj_irq *cmd_params; /* prepare command */ cmd.header = mc_encode_cmd_header(DPRC_CMDID_SET_OBJ_IRQ, cmd_flags, token); - cmd.params[0] |= mc_enc(32, 8, irq_index); - cmd.params[0] |= mc_enc(0, 32, irq_cfg->val); - cmd.params[1] |= mc_enc(0, 64, irq_cfg->paddr); - cmd.params[2] |= mc_enc(0, 32, irq_cfg->irq_num); - cmd.params[2] |= mc_enc(32, 32, obj_id); - cmd.params[3] |= mc_enc(0, 8, obj_type[0]); - cmd.params[3] |= mc_enc(8, 8, obj_type[1]); - cmd.params[3] |= mc_enc(16, 8, obj_type[2]); - cmd.params[3] |= mc_enc(24, 8, obj_type[3]); - cmd.params[3] |= mc_enc(32, 8, obj_type[4]); - cmd.params[3] |= mc_enc(40, 8, obj_type[5]); - cmd.params[3] |= mc_enc(48, 8, obj_type[6]); - cmd.params[3] |= mc_enc(56, 8, obj_type[7]); - cmd.params[4] |= mc_enc(0, 8, obj_type[8]); - cmd.params[4] |= mc_enc(8, 8, obj_type[9]); - cmd.params[4] |= mc_enc(16, 8, obj_type[10]); - cmd.params[4] |= mc_enc(24, 8, obj_type[11]); - cmd.params[4] |= mc_enc(32, 8, obj_type[12]); - cmd.params[4] |= mc_enc(40, 8, obj_type[13]); - cmd.params[4] |= mc_enc(48, 8, obj_type[14]); - cmd.params[4] |= mc_enc(56, 8, obj_type[15]); + cmd_params = (struct dprc_cmd_set_obj_irq *)cmd.params; + cmd_params->irq_val = cpu_to_le32(irq_cfg->val); + cmd_params->irq_index = irq_index; + cmd_params->irq_addr = cpu_to_le64(irq_cfg->paddr); + cmd_params->irq_num = cpu_to_le32(irq_cfg->irq_num); + cmd_params->obj_id = cpu_to_le32(obj_id); + strncpy(cmd_params->obj_type, obj_type, 16); + cmd_params->obj_type[15] = '\0'; /* send command to mc*/ return mc_send_command(mc_io, &cmd); @@ -1159,30 +1055,19 @@ int dprc_get_obj_irq(struct fsl_mc_io *mc_io, struct dprc_irq_cfg *irq_cfg) { struct mc_command cmd = { 0 }; + struct dprc_cmd_get_obj_irq *cmd_params; + struct dprc_rsp_get_obj_irq *rsp_params; int err; /* prepare command */ cmd.header = mc_encode_cmd_header(DPRC_CMDID_GET_OBJ_IRQ, cmd_flags, token); - cmd.params[0] |= mc_enc(0, 32, obj_id); - cmd.params[0] |= mc_enc(32, 8, irq_index); - cmd.params[1] |= mc_enc(0, 8, obj_type[0]); - cmd.params[1] |= mc_enc(8, 8, obj_type[1]); - cmd.params[1] |= mc_enc(16, 8, obj_type[2]); - cmd.params[1] |= mc_enc(24, 8, obj_type[3]); - cmd.params[1] |= mc_enc(32, 8, obj_type[4]); - cmd.params[1] |= mc_enc(40, 8, obj_type[5]); - cmd.params[1] |= mc_enc(48, 8, obj_type[6]); - cmd.params[1] |= mc_enc(56, 8, obj_type[7]); - cmd.params[2] |= mc_enc(0, 8, obj_type[8]); - cmd.params[2] |= mc_enc(8, 8, obj_type[9]); - cmd.params[2] |= mc_enc(16, 8, obj_type[10]); - cmd.params[2] |= mc_enc(24, 8, obj_type[11]); - cmd.params[2] |= mc_enc(32, 8, obj_type[12]); - cmd.params[2] |= mc_enc(40, 8, obj_type[13]); - cmd.params[2] |= mc_enc(48, 8, obj_type[14]); - cmd.params[2] |= mc_enc(56, 8, obj_type[15]); + cmd_params = (struct dprc_cmd_get_obj_irq *)cmd.params; + cmd_params->obj_id = cpu_to_le32(obj_id); + cmd_params->irq_index = irq_index; + strncpy(cmd_params->obj_type, obj_type, 16); + cmd_params->obj_type[15] = '\0'; /* send command to mc*/ err = mc_send_command(mc_io, &cmd); @@ -1190,10 +1075,11 @@ int dprc_get_obj_irq(struct fsl_mc_io *mc_io, return err; /* retrieve response parameters */ - irq_cfg->val = (u32)mc_dec(cmd.params[0], 0, 32); - irq_cfg->paddr = (u64)mc_dec(cmd.params[1], 0, 64); - irq_cfg->irq_num = (int)mc_dec(cmd.params[2], 0, 32); - *type = (int)mc_dec(cmd.params[2], 32, 32); + rsp_params = (struct dprc_rsp_get_obj_irq *)cmd.params; + irq_cfg->val = le32_to_cpu(rsp_params->irq_val); + irq_cfg->paddr = le64_to_cpu(rsp_params->irq_addr); + irq_cfg->irq_num = le32_to_cpu(rsp_params->irq_num); + *type = le32_to_cpu(rsp_params->type); return 0; } @@ -1218,29 +1104,16 @@ int dprc_get_res_count(struct fsl_mc_io *mc_io, int *res_count) { struct mc_command cmd = { 0 }; + struct dprc_cmd_get_res_count *cmd_params; + struct dprc_rsp_get_res_count *rsp_params; int err; - *res_count = 0; - /* prepare command */ cmd.header = mc_encode_cmd_header(DPRC_CMDID_GET_RES_COUNT, cmd_flags, token); - cmd.params[1] |= mc_enc(0, 8, type[0]); - cmd.params[1] |= mc_enc(8, 8, type[1]); - cmd.params[1] |= mc_enc(16, 8, type[2]); - cmd.params[1] |= mc_enc(24, 8, type[3]); - cmd.params[1] |= mc_enc(32, 8, type[4]); - cmd.params[1] |= mc_enc(40, 8, type[5]); - cmd.params[1] |= mc_enc(48, 8, type[6]); - cmd.params[1] |= mc_enc(56, 8, type[7]); - cmd.params[2] |= mc_enc(0, 8, type[8]); - cmd.params[2] |= mc_enc(8, 8, type[9]); - cmd.params[2] |= mc_enc(16, 8, type[10]); - cmd.params[2] |= mc_enc(24, 8, type[11]); - cmd.params[2] |= mc_enc(32, 8, type[12]); - cmd.params[2] |= mc_enc(40, 8, type[13]); - cmd.params[2] |= mc_enc(48, 8, type[14]); - cmd.params[2] |= mc_enc(56, 8, '\0'); + cmd_params = (struct dprc_cmd_get_res_count *)cmd.params; + strncpy(cmd_params->type, type, 16); + cmd_params->type[15] = '\0'; /* send command to mc*/ err = mc_send_command(mc_io, &cmd); @@ -1248,7 +1121,8 @@ int dprc_get_res_count(struct fsl_mc_io *mc_io, return err; /* retrieve response parameters */ - *res_count = mc_dec(cmd.params[0], 0, 32); + rsp_params = (struct dprc_rsp_get_res_count *)cmd.params; + *res_count = le32_to_cpu(rsp_params->res_count); return 0; } @@ -1271,30 +1145,19 @@ int dprc_get_res_ids(struct fsl_mc_io *mc_io, struct dprc_res_ids_range_desc *range_desc) { struct mc_command cmd = { 0 }; + struct dprc_cmd_get_res_ids *cmd_params; + struct dprc_rsp_get_res_ids *rsp_params; int err; /* prepare command */ cmd.header = mc_encode_cmd_header(DPRC_CMDID_GET_RES_IDS, cmd_flags, token); - cmd.params[0] |= mc_enc(42, 7, range_desc->iter_status); - cmd.params[1] |= mc_enc(0, 32, range_desc->base_id); - cmd.params[1] |= mc_enc(32, 32, range_desc->last_id); - cmd.params[2] |= mc_enc(0, 8, type[0]); - cmd.params[2] |= mc_enc(8, 8, type[1]); - cmd.params[2] |= mc_enc(16, 8, type[2]); - cmd.params[2] |= mc_enc(24, 8, type[3]); - cmd.params[2] |= mc_enc(32, 8, type[4]); - cmd.params[2] |= mc_enc(40, 8, type[5]); - cmd.params[2] |= mc_enc(48, 8, type[6]); - cmd.params[2] |= mc_enc(56, 8, type[7]); - cmd.params[3] |= mc_enc(0, 8, type[8]); - cmd.params[3] |= mc_enc(8, 8, type[9]); - cmd.params[3] |= mc_enc(16, 8, type[10]); - cmd.params[3] |= mc_enc(24, 8, type[11]); - cmd.params[3] |= mc_enc(32, 8, type[12]); - cmd.params[3] |= mc_enc(40, 8, type[13]); - cmd.params[3] |= mc_enc(48, 8, type[14]); - cmd.params[3] |= mc_enc(56, 8, '\0'); + cmd_params = (struct dprc_cmd_get_res_ids *)cmd.params; + cmd_params->iter_status = range_desc->iter_status; + cmd_params->base_id = cpu_to_le32(range_desc->base_id); + cmd_params->last_id = cpu_to_le32(range_desc->last_id); + strncpy(cmd_params->type, type, 16); + cmd_params->type[15] = '\0'; /* send command to mc*/ err = mc_send_command(mc_io, &cmd); @@ -1302,9 +1165,10 @@ int dprc_get_res_ids(struct fsl_mc_io *mc_io, return err; /* retrieve response parameters */ - range_desc->iter_status = mc_dec(cmd.params[0], 42, 7); - range_desc->base_id = mc_dec(cmd.params[1], 0, 32); - range_desc->last_id = mc_dec(cmd.params[1], 32, 32); + rsp_params = (struct dprc_rsp_get_res_ids *)cmd.params; + range_desc->iter_status = rsp_params->iter_status; + range_desc->base_id = le32_to_cpu(rsp_params->base_id); + range_desc->last_id = le32_to_cpu(rsp_params->last_id); return 0; } @@ -1331,29 +1195,18 @@ int dprc_get_obj_region(struct fsl_mc_io *mc_io, struct dprc_region_desc *region_desc) { struct mc_command cmd = { 0 }; + struct dprc_cmd_get_obj_region *cmd_params; + struct dprc_rsp_get_obj_region *rsp_params; int err; /* prepare command */ cmd.header = mc_encode_cmd_header(DPRC_CMDID_GET_OBJ_REG, cmd_flags, token); - cmd.params[0] |= mc_enc(0, 32, obj_id); - cmd.params[0] |= mc_enc(48, 8, region_index); - cmd.params[3] |= mc_enc(0, 8, obj_type[0]); - cmd.params[3] |= mc_enc(8, 8, obj_type[1]); - cmd.params[3] |= mc_enc(16, 8, obj_type[2]); - cmd.params[3] |= mc_enc(24, 8, obj_type[3]); - cmd.params[3] |= mc_enc(32, 8, obj_type[4]); - cmd.params[3] |= mc_enc(40, 8, obj_type[5]); - cmd.params[3] |= mc_enc(48, 8, obj_type[6]); - cmd.params[3] |= mc_enc(56, 8, obj_type[7]); - cmd.params[4] |= mc_enc(0, 8, obj_type[8]); - cmd.params[4] |= mc_enc(8, 8, obj_type[9]); - cmd.params[4] |= mc_enc(16, 8, obj_type[10]); - cmd.params[4] |= mc_enc(24, 8, obj_type[11]); - cmd.params[4] |= mc_enc(32, 8, obj_type[12]); - cmd.params[4] |= mc_enc(40, 8, obj_type[13]); - cmd.params[4] |= mc_enc(48, 8, obj_type[14]); - cmd.params[4] |= mc_enc(56, 8, '\0'); + cmd_params = (struct dprc_cmd_get_obj_region *)cmd.params; + cmd_params->obj_id = cpu_to_le32(obj_id); + cmd_params->region_index = region_index; + strncpy(cmd_params->obj_type, obj_type, 16); + cmd_params->obj_type[15] = '\0'; /* send command to mc*/ err = mc_send_command(mc_io, &cmd); @@ -1361,8 +1214,9 @@ int dprc_get_obj_region(struct fsl_mc_io *mc_io, return err; /* retrieve response parameters */ - region_desc->base_offset = mc_dec(cmd.params[1], 0, 64); - region_desc->size = mc_dec(cmd.params[2], 0, 32); + rsp_params = (struct dprc_rsp_get_obj_region *)cmd.params; + region_desc->base_offset = le64_to_cpu(rsp_params->base_addr); + region_desc->size = le32_to_cpu(rsp_params->size); return 0; } @@ -1387,45 +1241,18 @@ int dprc_set_obj_label(struct fsl_mc_io *mc_io, char *label) { struct mc_command cmd = { 0 }; + struct dprc_cmd_set_obj_label *cmd_params; /* prepare command */ cmd.header = mc_encode_cmd_header(DPRC_CMDID_SET_OBJ_LABEL, cmd_flags, token); - - cmd.params[0] |= mc_enc(0, 32, obj_id); - cmd.params[1] |= mc_enc(0, 8, label[0]); - cmd.params[1] |= mc_enc(8, 8, label[1]); - cmd.params[1] |= mc_enc(16, 8, label[2]); - cmd.params[1] |= mc_enc(24, 8, label[3]); - cmd.params[1] |= mc_enc(32, 8, label[4]); - cmd.params[1] |= mc_enc(40, 8, label[5]); - cmd.params[1] |= mc_enc(48, 8, label[6]); - cmd.params[1] |= mc_enc(56, 8, label[7]); - cmd.params[2] |= mc_enc(0, 8, label[8]); - cmd.params[2] |= mc_enc(8, 8, label[9]); - cmd.params[2] |= mc_enc(16, 8, label[10]); - cmd.params[2] |= mc_enc(24, 8, label[11]); - cmd.params[2] |= mc_enc(32, 8, label[12]); - cmd.params[2] |= mc_enc(40, 8, label[13]); - cmd.params[2] |= mc_enc(48, 8, label[14]); - cmd.params[2] |= mc_enc(56, 8, label[15]); - cmd.params[3] |= mc_enc(0, 8, obj_type[0]); - cmd.params[3] |= mc_enc(8, 8, obj_type[1]); - cmd.params[3] |= mc_enc(16, 8, obj_type[2]); - cmd.params[3] |= mc_enc(24, 8, obj_type[3]); - cmd.params[3] |= mc_enc(32, 8, obj_type[4]); - cmd.params[3] |= mc_enc(40, 8, obj_type[5]); - cmd.params[3] |= mc_enc(48, 8, obj_type[6]); - cmd.params[3] |= mc_enc(56, 8, obj_type[7]); - cmd.params[4] |= mc_enc(0, 8, obj_type[8]); - cmd.params[4] |= mc_enc(8, 8, obj_type[9]); - cmd.params[4] |= mc_enc(16, 8, obj_type[10]); - cmd.params[4] |= mc_enc(24, 8, obj_type[11]); - cmd.params[4] |= mc_enc(32, 8, obj_type[12]); - cmd.params[4] |= mc_enc(40, 8, obj_type[13]); - cmd.params[4] |= mc_enc(48, 8, obj_type[14]); - cmd.params[4] |= mc_enc(56, 8, obj_type[15]); + cmd_params = (struct dprc_cmd_set_obj_label *)cmd.params; + cmd_params->obj_id = cpu_to_le32(obj_id); + strncpy(cmd_params->label, label, 16); + cmd_params->label[15] = '\0'; + strncpy(cmd_params->obj_type, obj_type, 16); + cmd_params->obj_type[15] = '\0'; /* send command to mc*/ return mc_send_command(mc_io, &cmd); @@ -1453,49 +1280,23 @@ int dprc_connect(struct fsl_mc_io *mc_io, const struct dprc_connection_cfg *cfg) { struct mc_command cmd = { 0 }; + struct dprc_cmd_connect *cmd_params; /* prepare command */ cmd.header = mc_encode_cmd_header(DPRC_CMDID_CONNECT, cmd_flags, token); - cmd.params[0] |= mc_enc(0, 32, endpoint1->id); - cmd.params[0] |= mc_enc(32, 32, endpoint1->if_id); - cmd.params[1] |= mc_enc(0, 32, endpoint2->id); - cmd.params[1] |= mc_enc(32, 32, endpoint2->if_id); - cmd.params[2] |= mc_enc(0, 8, endpoint1->type[0]); - cmd.params[2] |= mc_enc(8, 8, endpoint1->type[1]); - cmd.params[2] |= mc_enc(16, 8, endpoint1->type[2]); - cmd.params[2] |= mc_enc(24, 8, endpoint1->type[3]); - cmd.params[2] |= mc_enc(32, 8, endpoint1->type[4]); - cmd.params[2] |= mc_enc(40, 8, endpoint1->type[5]); - cmd.params[2] |= mc_enc(48, 8, endpoint1->type[6]); - cmd.params[2] |= mc_enc(56, 8, endpoint1->type[7]); - cmd.params[3] |= mc_enc(0, 8, endpoint1->type[8]); - cmd.params[3] |= mc_enc(8, 8, endpoint1->type[9]); - cmd.params[3] |= mc_enc(16, 8, endpoint1->type[10]); - cmd.params[3] |= mc_enc(24, 8, endpoint1->type[11]); - cmd.params[3] |= mc_enc(32, 8, endpoint1->type[12]); - cmd.params[3] |= mc_enc(40, 8, endpoint1->type[13]); - cmd.params[3] |= mc_enc(48, 8, endpoint1->type[14]); - cmd.params[3] |= mc_enc(56, 8, endpoint1->type[15]); - cmd.params[4] |= mc_enc(0, 32, cfg->max_rate); - cmd.params[4] |= mc_enc(32, 32, cfg->committed_rate); - cmd.params[5] |= mc_enc(0, 8, endpoint2->type[0]); - cmd.params[5] |= mc_enc(8, 8, endpoint2->type[1]); - cmd.params[5] |= mc_enc(16, 8, endpoint2->type[2]); - cmd.params[5] |= mc_enc(24, 8, endpoint2->type[3]); - cmd.params[5] |= mc_enc(32, 8, endpoint2->type[4]); - cmd.params[5] |= mc_enc(40, 8, endpoint2->type[5]); - cmd.params[5] |= mc_enc(48, 8, endpoint2->type[6]); - cmd.params[5] |= mc_enc(56, 8, endpoint2->type[7]); - cmd.params[6] |= mc_enc(0, 8, endpoint2->type[8]); - cmd.params[6] |= mc_enc(8, 8, endpoint2->type[9]); - cmd.params[6] |= mc_enc(16, 8, endpoint2->type[10]); - cmd.params[6] |= mc_enc(24, 8, endpoint2->type[11]); - cmd.params[6] |= mc_enc(32, 8, endpoint2->type[12]); - cmd.params[6] |= mc_enc(40, 8, endpoint2->type[13]); - cmd.params[6] |= mc_enc(48, 8, endpoint2->type[14]); - cmd.params[6] |= mc_enc(56, 8, endpoint2->type[15]); + cmd_params = (struct dprc_cmd_connect *)cmd.params; + cmd_params->ep1_id = cpu_to_le32(endpoint1->id); + cmd_params->ep1_interface_id = cpu_to_le32(endpoint1->if_id); + cmd_params->ep2_id = cpu_to_le32(endpoint2->id); + cmd_params->ep2_interface_id = cpu_to_le32(endpoint2->if_id); + strncpy(cmd_params->ep1_type, endpoint1->type, 16); + cmd_params->ep1_type[15] = '\0'; + cmd_params->max_rate = cpu_to_le32(cfg->max_rate); + cmd_params->committed_rate = cpu_to_le32(cfg->committed_rate); + strncpy(cmd_params->ep2_type, endpoint2->type, 16); + cmd_params->ep2_type[15] = '\0'; /* send command to mc*/ return mc_send_command(mc_io, &cmd); @@ -1516,29 +1317,17 @@ int dprc_disconnect(struct fsl_mc_io *mc_io, const struct dprc_endpoint *endpoint) { struct mc_command cmd = { 0 }; + struct dprc_cmd_disconnect *cmd_params; /* prepare command */ cmd.header = mc_encode_cmd_header(DPRC_CMDID_DISCONNECT, cmd_flags, token); - cmd.params[0] |= mc_enc(0, 32, endpoint->id); - cmd.params[0] |= mc_enc(32, 32, endpoint->if_id); - cmd.params[1] |= mc_enc(0, 8, endpoint->type[0]); - cmd.params[1] |= mc_enc(8, 8, endpoint->type[1]); - cmd.params[1] |= mc_enc(16, 8, endpoint->type[2]); - cmd.params[1] |= mc_enc(24, 8, endpoint->type[3]); - cmd.params[1] |= mc_enc(32, 8, endpoint->type[4]); - cmd.params[1] |= mc_enc(40, 8, endpoint->type[5]); - cmd.params[1] |= mc_enc(48, 8, endpoint->type[6]); - cmd.params[1] |= mc_enc(56, 8, endpoint->type[7]); - cmd.params[2] |= mc_enc(0, 8, endpoint->type[8]); - cmd.params[2] |= mc_enc(8, 8, endpoint->type[9]); - cmd.params[2] |= mc_enc(16, 8, endpoint->type[10]); - cmd.params[2] |= mc_enc(24, 8, endpoint->type[11]); - cmd.params[2] |= mc_enc(32, 8, endpoint->type[12]); - cmd.params[2] |= mc_enc(40, 8, endpoint->type[13]); - cmd.params[2] |= mc_enc(48, 8, endpoint->type[14]); - cmd.params[2] |= mc_enc(56, 8, endpoint->type[15]); + cmd_params = (struct dprc_cmd_disconnect *)cmd.params; + cmd_params->id = cpu_to_le32(endpoint->id); + cmd_params->interface_id = cpu_to_le32(endpoint->if_id); + strncpy(cmd_params->type, endpoint->type, 16); + cmd_params->type[15] = '\0'; /* send command to mc*/ return mc_send_command(mc_io, &cmd); @@ -1567,30 +1356,19 @@ int dprc_get_connection(struct fsl_mc_io *mc_io, int *state) { struct mc_command cmd = { 0 }; + struct dprc_cmd_get_connection *cmd_params; + struct dprc_rsp_get_connection *rsp_params; int err; /* prepare command */ cmd.header = mc_encode_cmd_header(DPRC_CMDID_GET_CONNECTION, cmd_flags, token); - cmd.params[0] |= mc_enc(0, 32, endpoint1->id); - cmd.params[0] |= mc_enc(32, 32, endpoint1->if_id); - cmd.params[1] |= mc_enc(0, 8, endpoint1->type[0]); - cmd.params[1] |= mc_enc(8, 8, endpoint1->type[1]); - cmd.params[1] |= mc_enc(16, 8, endpoint1->type[2]); - cmd.params[1] |= mc_enc(24, 8, endpoint1->type[3]); - cmd.params[1] |= mc_enc(32, 8, endpoint1->type[4]); - cmd.params[1] |= mc_enc(40, 8, endpoint1->type[5]); - cmd.params[1] |= mc_enc(48, 8, endpoint1->type[6]); - cmd.params[1] |= mc_enc(56, 8, endpoint1->type[7]); - cmd.params[2] |= mc_enc(0, 8, endpoint1->type[8]); - cmd.params[2] |= mc_enc(8, 8, endpoint1->type[9]); - cmd.params[2] |= mc_enc(16, 8, endpoint1->type[10]); - cmd.params[2] |= mc_enc(24, 8, endpoint1->type[11]); - cmd.params[2] |= mc_enc(32, 8, endpoint1->type[12]); - cmd.params[2] |= mc_enc(40, 8, endpoint1->type[13]); - cmd.params[2] |= mc_enc(48, 8, endpoint1->type[14]); - cmd.params[2] |= mc_enc(56, 8, endpoint1->type[15]); + cmd_params = (struct dprc_cmd_get_connection *)cmd.params; + cmd_params->ep1_id = cpu_to_le32(endpoint1->id); + cmd_params->ep1_interface_id = cpu_to_le32(endpoint1->if_id); + strncpy(cmd_params->ep1_type, endpoint1->type, 16); + cmd_params->ep1_type[15] = '\0'; /* send command to mc*/ err = mc_send_command(mc_io, &cmd); @@ -1598,25 +1376,12 @@ int dprc_get_connection(struct fsl_mc_io *mc_io, return err; /* retrieve response parameters */ - endpoint2->id = mc_dec(cmd.params[3], 0, 32); - endpoint2->if_id = mc_dec(cmd.params[3], 32, 32); - endpoint2->type[0] = mc_dec(cmd.params[4], 0, 8); - endpoint2->type[1] = mc_dec(cmd.params[4], 8, 8); - endpoint2->type[2] = mc_dec(cmd.params[4], 16, 8); - endpoint2->type[3] = mc_dec(cmd.params[4], 24, 8); - endpoint2->type[4] = mc_dec(cmd.params[4], 32, 8); - endpoint2->type[5] = mc_dec(cmd.params[4], 40, 8); - endpoint2->type[6] = mc_dec(cmd.params[4], 48, 8); - endpoint2->type[7] = mc_dec(cmd.params[4], 56, 8); - endpoint2->type[8] = mc_dec(cmd.params[5], 0, 8); - endpoint2->type[9] = mc_dec(cmd.params[5], 8, 8); - endpoint2->type[10] = mc_dec(cmd.params[5], 16, 8); - endpoint2->type[11] = mc_dec(cmd.params[5], 24, 8); - endpoint2->type[12] = mc_dec(cmd.params[5], 32, 8); - endpoint2->type[13] = mc_dec(cmd.params[5], 40, 8); - endpoint2->type[14] = mc_dec(cmd.params[5], 48, 8); - endpoint2->type[15] = mc_dec(cmd.params[5], 56, 8); - *state = mc_dec(cmd.params[6], 0, 32); + rsp_params = (struct dprc_rsp_get_connection *)cmd.params; + endpoint2->id = le32_to_cpu(rsp_params->ep2_id); + endpoint2->if_id = le32_to_cpu(rsp_params->ep2_interface_id); + strncpy(endpoint2->type, rsp_params->ep2_type, 16); + endpoint2->type[15] = '\0'; + *state = le32_to_cpu(rsp_params->state); return 0; } diff --git a/drivers/staging/fsl-mc/bus/mc-sys.c b/drivers/staging/fsl-mc/bus/mc-sys.c index 810a611..0c185ab 100644 --- a/drivers/staging/fsl-mc/bus/mc-sys.c +++ b/drivers/staging/fsl-mc/bus/mc-sys.c @@ -53,8 +53,20 @@ #define MC_CMD_COMPLETION_POLLING_MIN_SLEEP_USECS 10 #define MC_CMD_COMPLETION_POLLING_MAX_SLEEP_USECS 500 -#define MC_CMD_HDR_READ_CMDID(_hdr) \ - ((u16)mc_dec((_hdr), MC_CMD_HDR_CMDID_O, MC_CMD_HDR_CMDID_S)) +static enum mc_cmd_status mc_cmd_hdr_read_status(struct mc_command *cmd) +{ + struct mc_cmd_header *hdr = (struct mc_cmd_header *)&cmd->header; + + return (enum mc_cmd_status)hdr->status; +} + +static u16 mc_cmd_hdr_read_cmdid(struct mc_command *cmd) +{ + struct mc_cmd_header *hdr = (struct mc_cmd_header *)&cmd->header; + u16 cmd_id = le16_to_cpu(hdr->cmd_id); + + return (cmd_id & MC_CMD_HDR_CMDID_MASK) >> MC_CMD_HDR_CMDID_SHIFT; +} /** * Creates an MC I/O object @@ -261,10 +273,11 @@ static inline void mc_write_command(struct mc_command __iomem *portal, /* copy command parameters into the portal */ for (i = 0; i < MC_CMD_NUM_OF_PARAMS; i++) - writeq(cmd->params[i], &portal->params[i]); + __raw_writeq(cmd->params[i], &portal->params[i]); + __iowmb(); /* submit the command by writing the header */ - writeq(cmd->header, &portal->header); + __raw_writeq(cmd->header, &portal->header); } /** @@ -284,14 +297,17 @@ static inline enum mc_cmd_status mc_read_response(struct mc_command __iomem * enum mc_cmd_status status; /* Copy command response header from MC portal: */ - resp->header = readq(&portal->header); - status = MC_CMD_HDR_READ_STATUS(resp->header); + __iormb(); + resp->header = __raw_readq(&portal->header); + __iormb(); + status = mc_cmd_hdr_read_status(resp); if (status != MC_CMD_STATUS_OK) return status; /* Copy command response data from MC portal: */ for (i = 0; i < MC_CMD_NUM_OF_PARAMS; i++) - resp->params[i] = readq(&portal->params[i]); + resp->params[i] = __raw_readq(&portal->params[i]); + __iormb(); return status; } @@ -331,10 +347,8 @@ static int mc_polling_wait_preemptible(struct fsl_mc_io *mc_io, dev_dbg(mc_io->dev, "MC command timed out (portal: %#llx, obj handle: %#x, command: %#x)\n", mc_io->portal_phys_addr, - (unsigned int) - MC_CMD_HDR_READ_TOKEN(cmd->header), - (unsigned int) - MC_CMD_HDR_READ_CMDID(cmd->header)); + (unsigned int)mc_cmd_hdr_read_token(cmd), + (unsigned int)mc_cmd_hdr_read_cmdid(cmd)); return -ETIMEDOUT; } @@ -373,10 +387,8 @@ static int mc_polling_wait_atomic(struct fsl_mc_io *mc_io, dev_dbg(mc_io->dev, "MC command timed out (portal: %#llx, obj handle: %#x, command: %#x)\n", mc_io->portal_phys_addr, - (unsigned int) - MC_CMD_HDR_READ_TOKEN(cmd->header), - (unsigned int) - MC_CMD_HDR_READ_CMDID(cmd->header)); + (unsigned int)mc_cmd_hdr_read_token(cmd), + (unsigned int)mc_cmd_hdr_read_cmdid(cmd)); return -ETIMEDOUT; } @@ -429,8 +441,8 @@ int mc_send_command(struct fsl_mc_io *mc_io, struct mc_command *cmd) dev_dbg(mc_io->dev, "MC command failed: portal: %#llx, obj handle: %#x, command: %#x, status: %s (%#x)\n", mc_io->portal_phys_addr, - (unsigned int)MC_CMD_HDR_READ_TOKEN(cmd->header), - (unsigned int)MC_CMD_HDR_READ_CMDID(cmd->header), + (unsigned int)mc_cmd_hdr_read_token(cmd), + (unsigned int)mc_cmd_hdr_read_cmdid(cmd), mc_status_to_string(status), (unsigned int)status); diff --git a/drivers/staging/fsl-mc/include/dpbp-cmd.h b/drivers/staging/fsl-mc/include/dpbp-cmd.h index c57b454..4828ccd 100644 --- a/drivers/staging/fsl-mc/include/dpbp-cmd.h +++ b/drivers/staging/fsl-mc/include/dpbp-cmd.h @@ -1,4 +1,4 @@ -/* Copyright 2013-2014 Freescale Semiconductor Inc. +/* Copyright 2013-2016 Freescale Semiconductor Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -59,4 +59,127 @@ #define DPBP_CMDID_SET_NOTIFICATIONS 0x01b0 #define DPBP_CMDID_GET_NOTIFICATIONS 0x01b1 + +struct dpbp_cmd_open { + __le32 dpbp_id; +}; + +#define DPBP_ENABLE 0x1 + +struct dpbp_rsp_is_enabled { + u8 enabled; +}; + +struct dpbp_cmd_set_irq { + /* cmd word 0 */ + u8 irq_index; + u8 pad[3]; + __le32 irq_val; + /* cmd word 1 */ + __le64 irq_addr; + /* cmd word 2 */ + __le32 irq_num; +}; + +struct dpbp_cmd_get_irq { + __le32 pad; + u8 irq_index; +}; + +struct dpbp_rsp_get_irq { + /* response word 0 */ + __le32 irq_val; + __le32 pad; + /* response word 1 */ + __le64 irq_addr; + /* response word 2 */ + __le32 irq_num; + __le32 type; +}; + +struct dpbp_cmd_set_irq_enable { + u8 enable; + u8 pad[3]; + u8 irq_index; +}; + +struct dpbp_cmd_get_irq_enable { + __le32 pad; + u8 irq_index; +}; + +struct dpbp_rsp_get_irq_enable { + u8 enabled; +}; + +struct dpbp_cmd_set_irq_mask { + __le32 mask; + u8 irq_index; +}; + +struct dpbp_cmd_get_irq_mask { + __le32 pad; + u8 irq_index; +}; + +struct dpbp_rsp_get_irq_mask { + __le32 mask; +}; + +struct dpbp_cmd_get_irq_status { + __le32 status; + u8 irq_index; +}; + +struct dpbp_rsp_get_irq_status { + __le32 status; +}; + +struct dpbp_cmd_clear_irq_status { + __le32 status; + u8 irq_index; +}; + +struct dpbp_rsp_get_attributes { + /* response word 0 */ + __le16 pad; + __le16 bpid; + __le32 id; + /* response word 1 */ + __le16 version_major; + __le16 version_minor; +}; + +struct dpbp_cmd_set_notifications { + /* cmd word 0 */ + __le32 depletion_entry; + __le32 depletion_exit; + /* cmd word 1 */ + __le32 surplus_entry; + __le32 surplus_exit; + /* cmd word 2 */ + __le16 options; + __le16 pad[3]; + /* cmd word 3 */ + __le64 message_ctx; + /* cmd word 4 */ + __le64 message_iova; +}; + +struct dpbp_rsp_get_notifications { + /* response word 0 */ + __le32 depletion_entry; + __le32 depletion_exit; + /* response word 1 */ + __le32 surplus_entry; + __le32 surplus_exit; + /* response word 2 */ + __le16 options; + __le16 pad[3]; + /* response word 3 */ + __le64 message_ctx; + /* response word 4 */ + __le64 message_iova; +}; + #endif /* _FSL_DPBP_CMD_H */ diff --git a/drivers/staging/fsl-mc/include/mc-cmd.h b/drivers/staging/fsl-mc/include/mc-cmd.h index 65277e3..5decb98 100644 --- a/drivers/staging/fsl-mc/include/mc-cmd.h +++ b/drivers/staging/fsl-mc/include/mc-cmd.h @@ -34,18 +34,14 @@ #define MC_CMD_NUM_OF_PARAMS 7 -#define MAKE_UMASK64(_width) \ - ((u64)((_width) < 64 ? ((u64)1 << (_width)) - 1 : -1)) - -static inline u64 mc_enc(int lsoffset, int width, u64 val) -{ - return (u64)(((u64)val & MAKE_UMASK64(width)) << lsoffset); -} - -static inline u64 mc_dec(u64 val, int lsoffset, int width) -{ - return (u64)((val >> lsoffset) & MAKE_UMASK64(width)); -} +struct mc_cmd_header { + u8 src_id; + u8 flags_hw; + u8 status; + u8 flags_sw; + __le16 token; + __le16 cmd_id; +}; struct mc_command { u64 header; @@ -72,60 +68,41 @@ enum mc_cmd_status { */ /* High priority flag */ -#define MC_CMD_FLAG_PRI 0x00008000 +#define MC_CMD_FLAG_PRI 0x80 /* Command completion flag */ -#define MC_CMD_FLAG_INTR_DIS 0x01000000 - -/* - * TODO Remove following two defines after completion of flib 8.0.0 - * integration - */ -#define MC_CMD_PRI_LOW 0 /*!< Low Priority command indication */ -#define MC_CMD_PRI_HIGH 1 /*!< High Priority command indication */ - -#define MC_CMD_HDR_CMDID_O 52 /* Command ID field offset */ -#define MC_CMD_HDR_CMDID_S 12 /* Command ID field size */ -#define MC_CMD_HDR_TOKEN_O 38 /* Token field offset */ -#define MC_CMD_HDR_TOKEN_S 10 /* Token field size */ -#define MC_CMD_HDR_STATUS_O 16 /* Status field offset */ -#define MC_CMD_HDR_STATUS_S 8 /* Status field size*/ -#define MC_CMD_HDR_FLAGS_O 0 /* Flags field offset */ -#define MC_CMD_HDR_FLAGS_S 32 /* Flags field size*/ -#define MC_CMD_HDR_FLAGS_MASK 0xFF00FF00 /* Command flags mask */ - -#define MC_CMD_HDR_READ_STATUS(_hdr) \ - ((enum mc_cmd_status)mc_dec((_hdr), \ - MC_CMD_HDR_STATUS_O, MC_CMD_HDR_STATUS_S)) - -#define MC_CMD_HDR_READ_TOKEN(_hdr) \ - ((u16)mc_dec((_hdr), MC_CMD_HDR_TOKEN_O, MC_CMD_HDR_TOKEN_S)) - -#define MC_CMD_HDR_READ_FLAGS(_hdr) \ - ((u32)mc_dec((_hdr), MC_CMD_HDR_FLAGS_O, MC_CMD_HDR_FLAGS_S)) +#define MC_CMD_FLAG_INTR_DIS 0x01 -#define MC_EXT_OP(_ext, _param, _offset, _width, _type, _arg) \ - ((_ext)[_param] |= mc_enc((_offset), (_width), _arg)) - -#define MC_CMD_OP(_cmd, _param, _offset, _width, _type, _arg) \ - ((_cmd).params[_param] |= mc_enc((_offset), (_width), _arg)) - -#define MC_RSP_OP(_cmd, _param, _offset, _width, _type, _arg) \ - (_arg = (_type)mc_dec(_cmd.params[_param], (_offset), (_width))) +#define MC_CMD_HDR_CMDID_MASK 0xFFF0 +#define MC_CMD_HDR_CMDID_SHIFT 4 +#define MC_CMD_HDR_TOKEN_MASK 0xFFC0 +#define MC_CMD_HDR_TOKEN_SHIFT 6 static inline u64 mc_encode_cmd_header(u16 cmd_id, u32 cmd_flags, u16 token) { - u64 hdr; + u64 header = 0; + struct mc_cmd_header *hdr = (struct mc_cmd_header *)&header; + + hdr->cmd_id = cpu_to_le16((cmd_id << MC_CMD_HDR_CMDID_SHIFT) & + MC_CMD_HDR_CMDID_MASK); + hdr->token = cpu_to_le16((token << MC_CMD_HDR_TOKEN_SHIFT) & + MC_CMD_HDR_TOKEN_MASK); + hdr->status = MC_CMD_STATUS_READY; + if (cmd_flags & MC_CMD_FLAG_PRI) + hdr->flags_hw = MC_CMD_FLAG_PRI; + if (cmd_flags & MC_CMD_FLAG_INTR_DIS) + hdr->flags_sw = MC_CMD_FLAG_INTR_DIS; + + return header; +} - hdr = mc_enc(MC_CMD_HDR_CMDID_O, MC_CMD_HDR_CMDID_S, cmd_id); - hdr |= mc_enc(MC_CMD_HDR_FLAGS_O, MC_CMD_HDR_FLAGS_S, - (cmd_flags & MC_CMD_HDR_FLAGS_MASK)); - hdr |= mc_enc(MC_CMD_HDR_TOKEN_O, MC_CMD_HDR_TOKEN_S, token); - hdr |= mc_enc(MC_CMD_HDR_STATUS_O, MC_CMD_HDR_STATUS_S, - MC_CMD_STATUS_READY); +static inline u16 mc_cmd_hdr_read_token(struct mc_command *cmd) +{ + struct mc_cmd_header *hdr = (struct mc_cmd_header *)&cmd->header; + u16 token = le16_to_cpu(hdr->token); - return hdr; + return (token & MC_CMD_HDR_TOKEN_MASK) >> MC_CMD_HDR_TOKEN_SHIFT; } #endif /* __FSL_MC_CMD_H */ -- cgit v0.10.2 From 7dd4912594daf769a46744848b05bd5bc6d62469 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Fri, 24 Jun 2016 15:53:54 +0200 Subject: sched/fair: Fix effective_load() to consistently use smoothed load Starting with the following commit: fde7d22e01aa ("sched/fair: Fix overly small weight for interactive group entities") calc_tg_weight() doesn't compute the right value as expected by effective_load(). The difference is in the 'correction' term. In order to ensure \Sum rw_j >= rw_i we cannot use tg->load_avg directly, since that might be lagging a correction on the current cfs_rq->avg.load_avg value. Therefore we use tg->load_avg - cfs_rq->tg_load_avg_contrib + cfs_rq->avg.load_avg. Now, per the referenced commit, calc_tg_weight() doesn't use cfs_rq->avg.load_avg, as is later used in @w, but uses cfs_rq->load.weight instead. So stop using calc_tg_weight() and do it explicitly. The effects of this bug are wake_affine() making randomly poor choices in cgroup-intense workloads. Signed-off-by: Peter Zijlstra (Intel) Cc: # v4.3+ Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Fixes: fde7d22e01aa ("sched/fair: Fix overly small weight for interactive group entities") Signed-off-by: Ingo Molnar diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c index bdcbeea..cc48bef 100644 --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c @@ -735,8 +735,6 @@ void post_init_entity_util_avg(struct sched_entity *se) } } -static inline unsigned long cfs_rq_runnable_load_avg(struct cfs_rq *cfs_rq); -static inline unsigned long cfs_rq_load_avg(struct cfs_rq *cfs_rq); #else void init_entity_runnable_average(struct sched_entity *se) { @@ -4946,19 +4944,24 @@ static long effective_load(struct task_group *tg, int cpu, long wl, long wg) return wl; for_each_sched_entity(se) { - long w, W; + struct cfs_rq *cfs_rq = se->my_q; + long W, w = cfs_rq_load_avg(cfs_rq); - tg = se->my_q->tg; + tg = cfs_rq->tg; /* * W = @wg + \Sum rw_j */ - W = wg + calc_tg_weight(tg, se->my_q); + W = wg + atomic_long_read(&tg->load_avg); + + /* Ensure \Sum rw_j >= rw_i */ + W -= cfs_rq->tg_load_avg_contrib; + W += w; /* * w = rw_i + @wl */ - w = cfs_rq_load_avg(se->my_q) + wl; + w += wl; /* * wl = S * s'_i; see (2) -- cgit v0.10.2 From ea1dc6fc6242f991656e35e2ed3d90ec1cd13418 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Fri, 24 Jun 2016 16:11:02 +0200 Subject: sched/fair: Fix calc_cfs_shares() fixed point arithmetics width confusion Commit: fde7d22e01aa ("sched/fair: Fix overly small weight for interactive group entities") did something non-obvious but also did it buggy yet latent. The problem was exposed for real by a later commit in the v4.7 merge window: 2159197d6677 ("sched/core: Enable increased load resolution on 64-bit kernels") ... after which tg->load_avg and cfs_rq->load.weight had different units (10 bit fixed point and 20 bit fixed point resp.). Add a comment to explain the use of cfs_rq->load.weight over the 'natural' cfs_rq->avg.load_avg and add scale_load_down() to correct for the difference in unit. Since this is (now, as per a previous commit) the only user of calc_tg_weight(), collapse it. The effects of this bug should be randomly inconsistent SMP-balancing of cgroups workloads. Reported-by: Jirka Hladky Signed-off-by: Peter Zijlstra (Intel) Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Fixes: 2159197d6677 ("sched/core: Enable increased load resolution on 64-bit kernels") Fixes: fde7d22e01aa ("sched/fair: Fix overly small weight for interactive group entities") Signed-off-by: Ingo Molnar diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c index cc48bef..c8c5d2d 100644 --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c @@ -2497,28 +2497,22 @@ account_entity_dequeue(struct cfs_rq *cfs_rq, struct sched_entity *se) #ifdef CONFIG_FAIR_GROUP_SCHED # ifdef CONFIG_SMP -static inline long calc_tg_weight(struct task_group *tg, struct cfs_rq *cfs_rq) +static long calc_cfs_shares(struct cfs_rq *cfs_rq, struct task_group *tg) { - long tg_weight; + long tg_weight, load, shares; /* - * Use this CPU's real-time load instead of the last load contribution - * as the updating of the contribution is delayed, and we will use the - * the real-time load to calc the share. See update_tg_load_avg(). + * This really should be: cfs_rq->avg.load_avg, but instead we use + * cfs_rq->load.weight, which is its upper bound. This helps ramp up + * the shares for small weight interactive tasks. */ - tg_weight = atomic_long_read(&tg->load_avg); - tg_weight -= cfs_rq->tg_load_avg_contrib; - tg_weight += cfs_rq->load.weight; - - return tg_weight; -} + load = scale_load_down(cfs_rq->load.weight); -static long calc_cfs_shares(struct cfs_rq *cfs_rq, struct task_group *tg) -{ - long tg_weight, load, shares; + tg_weight = atomic_long_read(&tg->load_avg); - tg_weight = calc_tg_weight(tg, cfs_rq); - load = cfs_rq->load.weight; + /* Ensure tg_weight >= load */ + tg_weight -= cfs_rq->tg_load_avg_contrib; + tg_weight += load; shares = (tg->shares * load); if (tg_weight) @@ -2537,6 +2531,7 @@ static inline long calc_cfs_shares(struct cfs_rq *cfs_rq, struct task_group *tg) return tg->shares; } # endif /* CONFIG_SMP */ + static void reweight_entity(struct cfs_rq *cfs_rq, struct sched_entity *se, unsigned long weight) { -- cgit v0.10.2 From f09509b9398b23ca53360ca57106555698ec2e93 Mon Sep 17 00:00:00 2001 From: David Carrillo-Cisneros Date: Tue, 21 Jun 2016 11:31:10 -0700 Subject: perf/x86/intel: Print LBR support statement after validation The following commit: 338b522ca43c ("perf/x86/intel: Protect LBR and extra_regs against KVM lying") added an additional test to LBR support detection that is performed after printing the LBR support statement to dmesg. Move the LBR support output after the very last test, to make sure we print the true status of LBR support. Signed-off-by: David Carrillo-Cisneros Signed-off-by: Peter Zijlstra (Intel) Reviewed-by: Stephane Eranian Reviewed-by: Andi Kleen Cc: Alexander Shishkin Cc: Arnaldo Carvalho de Melo Cc: Jiri Olsa Cc: Kan Liang Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: Vince Weaver Link: http://lkml.kernel.org/r/1466533874-52003-2-git-send-email-davidcc@google.com Signed-off-by: Ingo Molnar diff --git a/arch/x86/events/intel/core.c b/arch/x86/events/intel/core.c index 3ed528c..61a027b 100644 --- a/arch/x86/events/intel/core.c +++ b/arch/x86/events/intel/core.c @@ -3958,6 +3958,8 @@ __init int intel_pmu_init(void) x86_pmu.lbr_nr = 0; } + if (x86_pmu.lbr_nr) + pr_cont("%d-deep LBR, ", x86_pmu.lbr_nr); /* * Access extra MSR may cause #GP under certain circumstances. * E.g. KVM doesn't support offcore event diff --git a/arch/x86/events/intel/lbr.c b/arch/x86/events/intel/lbr.c index 9e2b40c..2dca66c 100644 --- a/arch/x86/events/intel/lbr.c +++ b/arch/x86/events/intel/lbr.c @@ -956,7 +956,6 @@ void __init intel_pmu_lbr_init_core(void) * SW branch filter usage: * - compensate for lack of HW filter */ - pr_cont("4-deep LBR, "); } /* nehalem/westmere */ @@ -977,7 +976,6 @@ void __init intel_pmu_lbr_init_nhm(void) * That requires LBR_FAR but that means far * jmp need to be filtered out */ - pr_cont("16-deep LBR, "); } /* sandy bridge */ @@ -997,7 +995,6 @@ void __init intel_pmu_lbr_init_snb(void) * That requires LBR_FAR but that means far * jmp need to be filtered out */ - pr_cont("16-deep LBR, "); } /* haswell */ @@ -1010,8 +1007,6 @@ void intel_pmu_lbr_init_hsw(void) x86_pmu.lbr_sel_mask = LBR_SEL_MASK; x86_pmu.lbr_sel_map = hsw_lbr_sel_map; - - pr_cont("16-deep LBR, "); } /* skylake */ @@ -1031,7 +1026,6 @@ __init void intel_pmu_lbr_init_skl(void) * That requires LBR_FAR but that means far * jmp need to be filtered out */ - pr_cont("32-deep LBR, "); } /* atom */ @@ -1057,7 +1051,6 @@ void __init intel_pmu_lbr_init_atom(void) * SW branch filter usage: * - compensate for lack of HW filter */ - pr_cont("8-deep LBR, "); } /* slm */ @@ -1088,6 +1081,4 @@ void intel_pmu_lbr_init_knl(void) x86_pmu.lbr_sel_mask = LBR_SEL_MASK; x86_pmu.lbr_sel_map = snb_lbr_sel_map; - - pr_cont("8-deep LBR, "); } -- cgit v0.10.2 From 19fc9ddd61e059cc45464bdf6e8fa304bb94080f Mon Sep 17 00:00:00 2001 From: David Carrillo-Cisneros Date: Tue, 21 Jun 2016 11:31:11 -0700 Subject: perf/x86/intel: Fix MSR_LAST_BRANCH_FROM_x bug when no TSX Intel's SDM states that bits 61:62 in MSR_LAST_BRANCH_FROM_x are the TSX flags for formats with LBR_TSX flags (i.e. LBR_FORMAT_EIP_EFLAGS2). However, when the CPU has TSX support deactivated, bits 61:62 actually behave as follows: - For wrmsr(), bits 61:62 are considered part of the sign extension. - When capturing branches, the LBR hw will always clear bits 61:62. regardless of the sign extension. Therefore, if: 1) LBR has TSX format. 2) CPU has no TSX support enabled. ... then any value passed to wrmsr() must be sign extended to 63 bits and any value from rdmsr() must be converted to have a sign extension of 61 bits, ignoring the values at TSX flags. This bug was masked by the work-around to the Intel's CPU bug: BJ94. "LBR May Contain Incorrect Information When Using FREEZE_LBRS_ON_PMI" in Document Number: 324643-037US. The aforementioned work-around uses hw flags to filter out all kernel branches, limiting LBR callstack to user level execution only. Since user addresses are not sign extended, they do not trigger the wrmsr() bug in MSR_LAST_BRANCH_FROM_x when saved/restored at context switch. To verify the hw bug: $ perf record -b -e cycles sleep 1 $ rdmsr -p 0 0x680 0x1fffffffb0b9b0cc $ wrmsr -p 0 0x680 0x1fffffffb0b9b0cc write(): Input/output error The quirk for LBR_FROM_ MSRs is required before calls to wrmsrl() and after rdmsrl(). This patch introduces it for wrmsrl()'s done for testing LBR support. Future patch in series adds the quirk for context switch, that would be required if LBR callstack is to be enabled for ring 0. Signed-off-by: David Carrillo-Cisneros Signed-off-by: Peter Zijlstra (Intel) Reviewed-by: Stephane Eranian Reviewed-by: Andi Kleen Cc: Alexander Shishkin Cc: Arnaldo Carvalho de Melo Cc: Jiri Olsa Cc: Kan Liang Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: Vince Weaver Link: http://lkml.kernel.org/r/1466533874-52003-3-git-send-email-davidcc@google.com Signed-off-by: Ingo Molnar diff --git a/arch/x86/events/intel/core.c b/arch/x86/events/intel/core.c index 61a027b..3eccc42 100644 --- a/arch/x86/events/intel/core.c +++ b/arch/x86/events/intel/core.c @@ -3361,6 +3361,13 @@ static void intel_snb_check_microcode(void) } } +static bool is_lbr_from(unsigned long msr) +{ + unsigned long lbr_from_nr = x86_pmu.lbr_from + x86_pmu.lbr_nr; + + return x86_pmu.lbr_from <= msr && msr < lbr_from_nr; +} + /* * Under certain circumstances, access certain MSR may cause #GP. * The function tests if the input MSR can be safely accessed. @@ -3381,13 +3388,24 @@ static bool check_msr(unsigned long msr, u64 mask) * Only change the bits which can be updated by wrmsrl. */ val_tmp = val_old ^ mask; + + if (is_lbr_from(msr)) + val_tmp = lbr_from_signext_quirk_wr(val_tmp); + if (wrmsrl_safe(msr, val_tmp) || rdmsrl_safe(msr, &val_new)) return false; + /* + * Quirk only affects validation in wrmsr(), so wrmsrl()'s value + * should equal rdmsrl()'s even with the quirk. + */ if (val_new != val_tmp) return false; + if (is_lbr_from(msr)) + val_old = lbr_from_signext_quirk_wr(val_old); + /* Here it's sure that the MSR can be safely accessed. * Restore the old value and return. */ diff --git a/arch/x86/events/intel/lbr.c b/arch/x86/events/intel/lbr.c index 2dca66c..88093e0 100644 --- a/arch/x86/events/intel/lbr.c +++ b/arch/x86/events/intel/lbr.c @@ -81,6 +81,8 @@ static enum { #define LBR_FROM_FLAG_IN_TX (1ULL << 62) #define LBR_FROM_FLAG_ABORT (1ULL << 61) +#define LBR_FROM_SIGNEXT_2MSB (BIT_ULL(60) | BIT_ULL(59)) + /* * x86control flow change classification * x86control flow changes include branches, interrupts, traps, faults @@ -235,6 +237,53 @@ enum { LBR_VALID, }; +/* + * For formats with LBR_TSX flags (e.g. LBR_FORMAT_EIP_FLAGS2), bits 61:62 in + * MSR_LAST_BRANCH_FROM_x are the TSX flags when TSX is supported, but when + * TSX is not supported they have no consistent behavior: + * + * - For wrmsr(), bits 61:62 are considered part of the sign extension. + * - For HW updates (branch captures) bits 61:62 are always OFF and are not + * part of the sign extension. + * + * Therefore, if: + * + * 1) LBR has TSX format + * 2) CPU has no TSX support enabled + * + * ... then any value passed to wrmsr() must be sign extended to 63 bits and any + * value from rdmsr() must be converted to have a 61 bits sign extension, + * ignoring the TSX flags. + */ +static inline bool lbr_from_signext_quirk_needed(void) +{ + int lbr_format = x86_pmu.intel_cap.lbr_format; + bool tsx_support = boot_cpu_has(X86_FEATURE_HLE) || + boot_cpu_has(X86_FEATURE_RTM); + + return !tsx_support && (lbr_desc[lbr_format] & LBR_TSX); +} + +DEFINE_STATIC_KEY_FALSE(lbr_from_quirk_key); + +/* If quirk is enabled, ensure sign extension is 63 bits: */ +inline u64 lbr_from_signext_quirk_wr(u64 val) +{ + if (static_branch_unlikely(&lbr_from_quirk_key)) { + /* + * Sign extend into bits 61:62 while preserving bit 63. + * + * Quirk is enabled when TSX is disabled. Therefore TSX bits + * in val are always OFF and must be changed to be sign + * extension bits. Since bits 59:60 are guaranteed to be + * part of the sign extension bits, we can just copy them + * to 61:62. + */ + val |= (LBR_FROM_SIGNEXT_2MSB & val) << 2; + } + return val; +} + static void __intel_pmu_lbr_restore(struct x86_perf_task_context *task_ctx) { int i; @@ -1007,6 +1056,9 @@ void intel_pmu_lbr_init_hsw(void) x86_pmu.lbr_sel_mask = LBR_SEL_MASK; x86_pmu.lbr_sel_map = hsw_lbr_sel_map; + + if (lbr_from_signext_quirk_needed()) + static_branch_enable(&lbr_from_quirk_key); } /* skylake */ diff --git a/arch/x86/events/perf_event.h b/arch/x86/events/perf_event.h index e2d7285..8c4a477 100644 --- a/arch/x86/events/perf_event.h +++ b/arch/x86/events/perf_event.h @@ -902,6 +902,8 @@ void intel_ds_init(void); void intel_pmu_lbr_sched_task(struct perf_event_context *ctx, bool sched_in); +u64 lbr_from_signext_quirk_wr(u64 val); + void intel_pmu_lbr_reset(void); void intel_pmu_lbr_enable(struct perf_event *event); -- cgit v0.10.2 From 3812bba84f3d721ff7dc3bb90360bc5ed6771994 Mon Sep 17 00:00:00 2001 From: David Carrillo-Cisneros Date: Tue, 21 Jun 2016 11:31:12 -0700 Subject: perf/x86/intel: Fix trivial formatting and style bug Replace spaces by tabs in LBR_FROM_* constants to align with newly defined constant. Use BIT_ULL. Signed-off-by: David Carrillo-Cisneros Signed-off-by: Peter Zijlstra (Intel) Reviewed-by: Stephane Eranian Reviewed-by: Andi Kleen Cc: Alexander Shishkin Cc: Arnaldo Carvalho de Melo Cc: Jiri Olsa Cc: Kan Liang Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: Vince Weaver Link: http://lkml.kernel.org/r/1466533874-52003-4-git-send-email-davidcc@google.com Signed-off-by: Ingo Molnar diff --git a/arch/x86/events/intel/lbr.c b/arch/x86/events/intel/lbr.c index 88093e0..0da0eb0 100644 --- a/arch/x86/events/intel/lbr.c +++ b/arch/x86/events/intel/lbr.c @@ -77,9 +77,9 @@ static enum { LBR_IND_JMP |\ LBR_FAR) -#define LBR_FROM_FLAG_MISPRED (1ULL << 63) -#define LBR_FROM_FLAG_IN_TX (1ULL << 62) -#define LBR_FROM_FLAG_ABORT (1ULL << 61) +#define LBR_FROM_FLAG_MISPRED BIT_ULL(63) +#define LBR_FROM_FLAG_IN_TX BIT_ULL(62) +#define LBR_FROM_FLAG_ABORT BIT_ULL(61) #define LBR_FROM_SIGNEXT_2MSB (BIT_ULL(60) | BIT_ULL(59)) -- cgit v0.10.2 From 71adae99ed187de9fcf988cc8873ee2c3af3385f Mon Sep 17 00:00:00 2001 From: David Carrillo-Cisneros Date: Tue, 21 Jun 2016 11:31:13 -0700 Subject: perf/x86/intel: Add MSR_LAST_BRANCH_FROM_x quirk for ctx switch Add quirk for context switch to save/restore the value of MSR_LAST_BRANCH_FROM_x when LBR is enabled and there is potential for kernel addresses to be in the lbr_from register. To test this patch, use a perf tool and kernel with the patch next in this series. That patch removes the work around that masked the hw bug: $ ./lbr_perf record --call-graph lbr -e cycles:k sleep 1 where lbr_perf is the patched perf tool, that allows to specify :k on lbr mode. The above command will trigger a #GPF : WARNING: CPU: 28 PID: 14096 at arch/x86/mm/extable.c:65 ex_handler_wrmsr_unsafe+0x70/0x80 unchecked MSR access error: WRMSR to 0x681 (tried to write 0x1fffffff81010794) ... Call Trace: [] dump_stack+0x4d/0x63 [] __warn+0xe5/0x100 [] warn_slowpath_fmt+0x49/0x50 [] ex_handler_wrmsr_unsafe+0x70/0x80 [] fixup_exception+0x42/0x50 [] do_general_protection+0x8a/0x160 [] general_protection+0x22/0x30 [] ? intel_pmu_lbr_sched_task+0xc9/0x380 [] intel_pmu_sched_task+0x3c/0x60 [] x86_pmu_sched_task+0x1b/0x20 [] perf_pmu_sched_task+0x6b/0xb0 [] __perf_event_task_sched_in+0x7d/0x150 [] finish_task_switch+0x15c/0x200 [] __schedule+0x274/0x6cc [] schedule+0x39/0x90 [] exit_to_usermode_loop+0x39/0x89 [] prepare_exit_to_usermode+0x2e/0x30 [] retint_user+0x8/0x10 Signed-off-by: David Carrillo-Cisneros Signed-off-by: Peter Zijlstra (Intel) Reviewed-by: Stephane Eranian Reviewed-by: Andi Kleen Cc: Alexander Shishkin Cc: Arnaldo Carvalho de Melo Cc: Jiri Olsa Cc: Kan Liang Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: Vince Weaver Link: http://lkml.kernel.org/r/1466533874-52003-5-git-send-email-davidcc@google.com Signed-off-by: Ingo Molnar diff --git a/arch/x86/events/intel/lbr.c b/arch/x86/events/intel/lbr.c index 0da0eb0..52bef15 100644 --- a/arch/x86/events/intel/lbr.c +++ b/arch/x86/events/intel/lbr.c @@ -284,6 +284,20 @@ inline u64 lbr_from_signext_quirk_wr(u64 val) return val; } +/* + * If quirk is needed, ensure sign extension is 61 bits: + */ +u64 lbr_from_signext_quirk_rd(u64 val) +{ + if (static_branch_unlikely(&lbr_from_quirk_key)) + /* + * Quirk is on when TSX is not enabled. Therefore TSX + * flags must be read as OFF. + */ + val &= ~(LBR_FROM_FLAG_IN_TX | LBR_FROM_FLAG_ABORT); + return val; +} + static void __intel_pmu_lbr_restore(struct x86_perf_task_context *task_ctx) { int i; @@ -300,7 +314,8 @@ static void __intel_pmu_lbr_restore(struct x86_perf_task_context *task_ctx) tos = task_ctx->tos; for (i = 0; i < tos; i++) { lbr_idx = (tos - i) & mask; - wrmsrl(x86_pmu.lbr_from + lbr_idx, task_ctx->lbr_from[i]); + wrmsrl(x86_pmu.lbr_from + lbr_idx, + lbr_from_signext_quirk_wr(task_ctx->lbr_from[i])); wrmsrl(x86_pmu.lbr_to + lbr_idx, task_ctx->lbr_to[i]); if (x86_pmu.intel_cap.lbr_format == LBR_FORMAT_INFO) wrmsrl(MSR_LBR_INFO_0 + lbr_idx, task_ctx->lbr_info[i]); @@ -313,7 +328,7 @@ static void __intel_pmu_lbr_save(struct x86_perf_task_context *task_ctx) { int i; unsigned lbr_idx, mask; - u64 tos; + u64 tos, val; if (task_ctx->lbr_callstack_users == 0) { task_ctx->lbr_stack_state = LBR_NONE; @@ -324,7 +339,8 @@ static void __intel_pmu_lbr_save(struct x86_perf_task_context *task_ctx) tos = intel_pmu_lbr_tos(); for (i = 0; i < tos; i++) { lbr_idx = (tos - i) & mask; - rdmsrl(x86_pmu.lbr_from + lbr_idx, task_ctx->lbr_from[i]); + rdmsrl(x86_pmu.lbr_from + lbr_idx, val); + task_ctx->lbr_from[i] = lbr_from_signext_quirk_rd(val); rdmsrl(x86_pmu.lbr_to + lbr_idx, task_ctx->lbr_to[i]); if (x86_pmu.intel_cap.lbr_format == LBR_FORMAT_INFO) rdmsrl(MSR_LBR_INFO_0 + lbr_idx, task_ctx->lbr_info[i]); @@ -502,6 +518,8 @@ static void intel_pmu_lbr_read_64(struct cpu_hw_events *cpuc) int lbr_flags = lbr_desc[lbr_format]; rdmsrl(x86_pmu.lbr_from + lbr_idx, from); + from = lbr_from_signext_quirk_rd(from); + rdmsrl(x86_pmu.lbr_to + lbr_idx, to); if (lbr_format == LBR_FORMAT_INFO && need_info) { -- cgit v0.10.2 From d4cf1949f9689314aef962eea95df84a8288d097 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Thu, 23 Jun 2016 10:44:49 +0200 Subject: perf/x86/intel: Add {rd,wr}lbr_{to,from} wrappers The whole rdmsr()/wrmsr() for lbr_from got a little unweildy with the sign extension quirk, provide a few simple wrappers to clean things up. Signed-off-by: Peter Zijlstra (Intel) Cc: Alexander Shishkin Cc: Arnaldo Carvalho de Melo Cc: David Carrillo-Cisneros Cc: Jiri Olsa Cc: Kan Liang Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Thomas Gleixner Cc: Vince Weaver Signed-off-by: Ingo Molnar diff --git a/arch/x86/events/intel/lbr.c b/arch/x86/events/intel/lbr.c index 52bef15..cc4555a 100644 --- a/arch/x86/events/intel/lbr.c +++ b/arch/x86/events/intel/lbr.c @@ -289,12 +289,42 @@ inline u64 lbr_from_signext_quirk_wr(u64 val) */ u64 lbr_from_signext_quirk_rd(u64 val) { - if (static_branch_unlikely(&lbr_from_quirk_key)) + if (static_branch_unlikely(&lbr_from_quirk_key)) { /* * Quirk is on when TSX is not enabled. Therefore TSX * flags must be read as OFF. */ val &= ~(LBR_FROM_FLAG_IN_TX | LBR_FROM_FLAG_ABORT); + } + return val; +} + +static inline void wrlbr_from(unsigned int idx, u64 val) +{ + val = lbr_from_signext_quirk_wr(val); + wrmsrl(x86_pmu.lbr_from + idx, val); +} + +static inline void wrlbr_to(unsigned int idx, u64 val) +{ + wrmsrl(x86_pmu.lbr_to + idx, val); +} + +static inline u64 rdlbr_from(unsigned int idx) +{ + u64 val; + + rdmsrl(x86_pmu.lbr_from + idx, val); + + return lbr_from_signext_quirk_rd(val); +} + +static inline u64 rdlbr_to(unsigned int idx) +{ + u64 val; + + rdmsrl(x86_pmu.lbr_from + idx, val); + return val; } @@ -314,9 +344,9 @@ static void __intel_pmu_lbr_restore(struct x86_perf_task_context *task_ctx) tos = task_ctx->tos; for (i = 0; i < tos; i++) { lbr_idx = (tos - i) & mask; - wrmsrl(x86_pmu.lbr_from + lbr_idx, - lbr_from_signext_quirk_wr(task_ctx->lbr_from[i])); - wrmsrl(x86_pmu.lbr_to + lbr_idx, task_ctx->lbr_to[i]); + wrlbr_from(lbr_idx, task_ctx->lbr_from[i]); + wrlbr_to (lbr_idx, task_ctx->lbr_to[i]); + if (x86_pmu.intel_cap.lbr_format == LBR_FORMAT_INFO) wrmsrl(MSR_LBR_INFO_0 + lbr_idx, task_ctx->lbr_info[i]); } @@ -326,9 +356,9 @@ static void __intel_pmu_lbr_restore(struct x86_perf_task_context *task_ctx) static void __intel_pmu_lbr_save(struct x86_perf_task_context *task_ctx) { - int i; unsigned lbr_idx, mask; - u64 tos, val; + u64 tos; + int i; if (task_ctx->lbr_callstack_users == 0) { task_ctx->lbr_stack_state = LBR_NONE; @@ -339,9 +369,8 @@ static void __intel_pmu_lbr_save(struct x86_perf_task_context *task_ctx) tos = intel_pmu_lbr_tos(); for (i = 0; i < tos; i++) { lbr_idx = (tos - i) & mask; - rdmsrl(x86_pmu.lbr_from + lbr_idx, val); - task_ctx->lbr_from[i] = lbr_from_signext_quirk_rd(val); - rdmsrl(x86_pmu.lbr_to + lbr_idx, task_ctx->lbr_to[i]); + task_ctx->lbr_from[i] = rdlbr_from(lbr_idx); + task_ctx->lbr_to[i] = rdlbr_to(lbr_idx); if (x86_pmu.intel_cap.lbr_format == LBR_FORMAT_INFO) rdmsrl(MSR_LBR_INFO_0 + lbr_idx, task_ctx->lbr_info[i]); } @@ -517,10 +546,8 @@ static void intel_pmu_lbr_read_64(struct cpu_hw_events *cpuc) u16 cycles = 0; int lbr_flags = lbr_desc[lbr_format]; - rdmsrl(x86_pmu.lbr_from + lbr_idx, from); - from = lbr_from_signext_quirk_rd(from); - - rdmsrl(x86_pmu.lbr_to + lbr_idx, to); + from = rdlbr_from(lbr_idx); + to = rdlbr_to(lbr_idx); if (lbr_format == LBR_FORMAT_INFO && need_info) { u64 info; -- cgit v0.10.2 From 0dceeaf599e6d9b8bd908ba4bd3dfee84aa26be2 Mon Sep 17 00:00:00 2001 From: Pan Xinhui Date: Tue, 14 Jun 2016 14:37:27 +0800 Subject: locking/qspinlock: Use __this_cpu_dec() instead of full-blown this_cpu_dec() queued_spin_lock_slowpath() should not worry about another queued_spin_lock_slowpath() running in interrupt context and changing node->count by accident, because node->count keeps the same value every time we enter/leave queued_spin_lock_slowpath(). On some architectures this_cpu_dec() will save/restore irq flags, which has high overhead. Use the much cheaper __this_cpu_dec() instead. Signed-off-by: Pan Xinhui Signed-off-by: Peter Zijlstra (Intel) Cc: Linus Torvalds Cc: Mike Galbraith Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: Waiman.Long@hpe.com Link: http://lkml.kernel.org/r/1465886247-3773-1-git-send-email-xinhui.pan@linux.vnet.ibm.com [ Rewrote changelog. ] Signed-off-by: Ingo Molnar diff --git a/kernel/locking/qspinlock.c b/kernel/locking/qspinlock.c index 7306555..b2caec7 100644 --- a/kernel/locking/qspinlock.c +++ b/kernel/locking/qspinlock.c @@ -619,7 +619,7 @@ release: /* * release the node */ - this_cpu_dec(mcs_nodes[0].count); + __this_cpu_dec(mcs_nodes[0].count); } EXPORT_SYMBOL(queued_spin_lock_slowpath); -- cgit v0.10.2 From e210bffd39d01b649c94b820c28ff112673266dd Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Thu, 16 Jun 2016 18:51:48 +0200 Subject: sched/fair: Fix and optimize the fork() path The task_fork_fair() callback already calls __set_task_cpu() and takes rq->lock. If we move the sched_class::task_fork callback in sched_fork() under the existing p->pi_lock, right after its set_task_cpu() call, we can avoid doing two such calls and omit the IRQ disabling on the rq->lock. Change to __set_task_cpu() to skip the migration bits, this is a new task, not a migration. Similarly, make wake_up_new_task() use __set_task_cpu() for the same reason, the task hasn't actually migrated as it hasn't ever ran. This cures the problem of calling migrate_task_rq_fair(), which does remove_entity_from_load_avg() on tasks that have never been added to the load avg to begin with. This bug would result in transiently messed up load_avg values, averaged out after a few dozen milliseconds. This is probably the reason why this bug was not found for such a long time. Reported-by: Vincent Guittot Signed-off-by: Peter Zijlstra (Intel) Cc: Linus Torvalds Cc: Mike Galbraith Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: linux-kernel@vger.kernel.org Signed-off-by: Ingo Molnar diff --git a/kernel/sched/core.c b/kernel/sched/core.c index e406ba0..fa3434df 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c @@ -2383,9 +2383,6 @@ int sched_fork(unsigned long clone_flags, struct task_struct *p) p->sched_class = &fair_sched_class; } - if (p->sched_class->task_fork) - p->sched_class->task_fork(p); - /* * The child is not yet in the pid-hash so no cgroup attach races, * and the cgroup is pinned to this child due to cgroup_fork() @@ -2394,7 +2391,13 @@ int sched_fork(unsigned long clone_flags, struct task_struct *p) * Silence PROVE_RCU. */ raw_spin_lock_irqsave(&p->pi_lock, flags); - set_task_cpu(p, cpu); + /* + * We're setting the cpu for the first time, we don't migrate, + * so use __set_task_cpu(). + */ + __set_task_cpu(p, cpu); + if (p->sched_class->task_fork) + p->sched_class->task_fork(p); raw_spin_unlock_irqrestore(&p->pi_lock, flags); #ifdef CONFIG_SCHED_INFO @@ -2534,8 +2537,11 @@ void wake_up_new_task(struct task_struct *p) * Fork balancing, do it here and not earlier because: * - cpus_allowed can change in the fork path * - any previously selected cpu might disappear through hotplug + * + * Use __set_task_cpu() to avoid calling sched_class::migrate_task_rq, + * as we're not fully set-up yet. */ - set_task_cpu(p, select_task_rq(p, task_cpu(p), SD_BALANCE_FORK, 0)); + __set_task_cpu(p, select_task_rq(p, task_cpu(p), SD_BALANCE_FORK, 0)); #endif rq = __task_rq_lock(p, &rf); post_init_entity_util_avg(&p->se); diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c index 7306356..994f549 100644 --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c @@ -4448,7 +4448,7 @@ enqueue_task_fair(struct rq *rq, struct task_struct *p, int flags) * * note: in the case of encountering a throttled cfs_rq we will * post the final h_nr_running increment below. - */ + */ if (cfs_rq_throttled(cfs_rq)) break; cfs_rq->h_nr_running++; @@ -8289,31 +8289,17 @@ static void task_fork_fair(struct task_struct *p) { struct cfs_rq *cfs_rq; struct sched_entity *se = &p->se, *curr; - int this_cpu = smp_processor_id(); struct rq *rq = this_rq(); - unsigned long flags; - - raw_spin_lock_irqsave(&rq->lock, flags); + raw_spin_lock(&rq->lock); update_rq_clock(rq); cfs_rq = task_cfs_rq(current); curr = cfs_rq->curr; - - /* - * Not only the cpu but also the task_group of the parent might have - * been changed after parent->se.parent,cfs_rq were copied to - * child->se.parent,cfs_rq. So call __set_task_cpu() to make those - * of child point to valid ones. - */ - rcu_read_lock(); - __set_task_cpu(p, this_cpu); - rcu_read_unlock(); - - update_curr(cfs_rq); - - if (curr) + if (curr) { + update_curr(cfs_rq); se->vruntime = curr->vruntime; + } place_entity(cfs_rq, se, 1); if (sysctl_sched_child_runs_first && curr && entity_before(curr, se)) { @@ -8326,8 +8312,7 @@ static void task_fork_fair(struct task_struct *p) } se->vruntime -= cfs_rq->min_vruntime; - - raw_spin_unlock_irqrestore(&rq->lock, flags); + raw_spin_unlock(&rq->lock); } /* -- cgit v0.10.2 From 010114739d294c474764c94196d32fb92e233657 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Fri, 17 Jun 2016 11:20:46 +0200 Subject: sched/fair: Fix PELT integrity for new groups Vincent reported that when a new task is moved into a new cgroup it gets attached twice to the load tracking: sched_move_task() task_move_group_fair() detach_task_cfs_rq() set_task_rq() attach_task_cfs_rq() attach_entity_load_avg() se->avg.last_load_update = cfs_rq->avg.last_load_update // == 0 enqueue_entity() enqueue_entity_load_avg() update_cfs_rq_load_avg() now = clock() __update_load_avg(&cfs_rq->avg) cfs_rq->avg.last_load_update = now // ages load/util for: now - 0, load/util -> 0 if (migrated) attach_entity_load_avg() se->avg.last_load_update = cfs_rq->avg.last_load_update; // now != 0 The problem is that we don't update cfs_rq load_avg before all entity attach/detach operations. Only enqueue_task() and migrate_task() do this. By fixing this, the above will not happen, because the sched_move_task() attach will have updated cfs_rq's last_load_update time before attach, and in turn the attach will have set the entity's last_load_update stamp. Note that there is a further problem with sched_move_task() calling detach on a task that hasn't yet been attached; this will be taken care of in a subsequent patch. Reported-by: Vincent Guittot Tested-by: Vincent Guittot Signed-off-by: Peter Zijlstra (Intel) Cc: Linus Torvalds Cc: Mike Galbraith Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: Yuyang Du Cc: linux-kernel@vger.kernel.org Signed-off-by: Ingo Molnar diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c index 994f549..dda0ccb 100644 --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c @@ -3083,6 +3083,12 @@ static int idle_balance(struct rq *this_rq); #else /* CONFIG_SMP */ +static inline int +update_cfs_rq_load_avg(u64 now, struct cfs_rq *cfs_rq, bool update_freq) +{ + return 0; +} + static inline void update_load_avg(struct sched_entity *se, int not_used) { struct cfs_rq *cfs_rq = cfs_rq_of(se); @@ -8368,6 +8374,7 @@ static void detach_task_cfs_rq(struct task_struct *p) { struct sched_entity *se = &p->se; struct cfs_rq *cfs_rq = cfs_rq_of(se); + u64 now = cfs_rq_clock_task(cfs_rq); if (!vruntime_normalized(p)) { /* @@ -8379,6 +8386,7 @@ static void detach_task_cfs_rq(struct task_struct *p) } /* Catch up with the cfs_rq and remove our load when we leave */ + update_cfs_rq_load_avg(now, cfs_rq, false); detach_entity_load_avg(cfs_rq, se); } @@ -8386,6 +8394,7 @@ static void attach_task_cfs_rq(struct task_struct *p) { struct sched_entity *se = &p->se; struct cfs_rq *cfs_rq = cfs_rq_of(se); + u64 now = cfs_rq_clock_task(cfs_rq); #ifdef CONFIG_FAIR_GROUP_SCHED /* @@ -8396,6 +8405,7 @@ static void attach_task_cfs_rq(struct task_struct *p) #endif /* Synchronize task with its cfs_rq */ + update_cfs_rq_load_avg(now, cfs_rq, false); attach_entity_load_avg(cfs_rq, se); if (!vruntime_normalized(p)) -- cgit v0.10.2 From ea86cb4b7621e1298a37197005bf0abcc86348d4 Mon Sep 17 00:00:00 2001 From: Vincent Guittot Date: Fri, 17 Jun 2016 13:38:55 +0200 Subject: sched/cgroup: Fix cpu_cgroup_fork() handling A new fair task is detached and attached from/to task_group with: cgroup_post_fork() ss->fork(child) := cpu_cgroup_fork() sched_move_task() task_move_group_fair() Which is wrong, because at this point in fork() the task isn't fully initialized and it cannot 'move' to another group, because its not attached to any group as yet. In fact, cpu_cgroup_fork() needs a small part of sched_move_task() so we can just call this small part directly instead sched_move_task(). And the task doesn't really migrate because it is not yet attached so we need the following sequence: do_fork() sched_fork() __set_task_cpu() cgroup_post_fork() set_task_rq() # set task group and runqueue wake_up_new_task() select_task_rq() can select a new cpu __set_task_cpu post_init_entity_util_avg attach_task_cfs_rq() activate_task enqueue_task This patch makes that happen. Signed-off-by: Vincent Guittot [ Added TASK_SET_GROUP to set depth properly. ] Signed-off-by: Peter Zijlstra (Intel) Cc: Linus Torvalds Cc: Mike Galbraith Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: linux-kernel@vger.kernel.org Signed-off-by: Ingo Molnar diff --git a/kernel/sched/core.c b/kernel/sched/core.c index fa3434df..3d856c4 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c @@ -7744,27 +7744,9 @@ void sched_offline_group(struct task_group *tg) spin_unlock_irqrestore(&task_group_lock, flags); } -/* change task's runqueue when it moves between groups. - * The caller of this function should have put the task in its new group - * by now. This function just updates tsk->se.cfs_rq and tsk->se.parent to - * reflect its new group. - */ -void sched_move_task(struct task_struct *tsk) +static void sched_change_group(struct task_struct *tsk, int type) { struct task_group *tg; - int queued, running; - struct rq_flags rf; - struct rq *rq; - - rq = task_rq_lock(tsk, &rf); - - running = task_current(rq, tsk); - queued = task_on_rq_queued(tsk); - - if (queued) - dequeue_task(rq, tsk, DEQUEUE_SAVE | DEQUEUE_MOVE); - if (unlikely(running)) - put_prev_task(rq, tsk); /* * All callers are synchronized by task_rq_lock(); we do not use RCU @@ -7777,11 +7759,37 @@ void sched_move_task(struct task_struct *tsk) tsk->sched_task_group = tg; #ifdef CONFIG_FAIR_GROUP_SCHED - if (tsk->sched_class->task_move_group) - tsk->sched_class->task_move_group(tsk); + if (tsk->sched_class->task_change_group) + tsk->sched_class->task_change_group(tsk, type); else #endif set_task_rq(tsk, task_cpu(tsk)); +} + +/* + * Change task's runqueue when it moves between groups. + * + * The caller of this function should have put the task in its new group by + * now. This function just updates tsk->se.cfs_rq and tsk->se.parent to reflect + * its new group. + */ +void sched_move_task(struct task_struct *tsk) +{ + int queued, running; + struct rq_flags rf; + struct rq *rq; + + rq = task_rq_lock(tsk, &rf); + + running = task_current(rq, tsk); + queued = task_on_rq_queued(tsk); + + if (queued) + dequeue_task(rq, tsk, DEQUEUE_SAVE | DEQUEUE_MOVE); + if (unlikely(running)) + put_prev_task(rq, tsk); + + sched_change_group(tsk, TASK_MOVE_GROUP); if (unlikely(running)) tsk->sched_class->set_curr_task(rq); @@ -8209,9 +8217,20 @@ static void cpu_cgroup_css_free(struct cgroup_subsys_state *css) sched_free_group(tg); } +/* + * This is called before wake_up_new_task(), therefore we really only + * have to set its group bits, all the other stuff does not apply. + */ static void cpu_cgroup_fork(struct task_struct *task) { - sched_move_task(task); + struct rq_flags rf; + struct rq *rq; + + rq = task_rq_lock(task, &rf); + + sched_change_group(task, TASK_SET_GROUP); + + task_rq_unlock(rq, task, &rf); } static int cpu_cgroup_can_attach(struct cgroup_taskset *tset) diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c index dda0ccb..64f26bc 100644 --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c @@ -8466,6 +8466,14 @@ void init_cfs_rq(struct cfs_rq *cfs_rq) } #ifdef CONFIG_FAIR_GROUP_SCHED +static void task_set_group_fair(struct task_struct *p) +{ + struct sched_entity *se = &p->se; + + set_task_rq(p, task_cpu(p)); + se->depth = se->parent ? se->parent->depth + 1 : 0; +} + static void task_move_group_fair(struct task_struct *p) { detach_task_cfs_rq(p); @@ -8478,6 +8486,19 @@ static void task_move_group_fair(struct task_struct *p) attach_task_cfs_rq(p); } +static void task_change_group_fair(struct task_struct *p, int type) +{ + switch (type) { + case TASK_SET_GROUP: + task_set_group_fair(p); + break; + + case TASK_MOVE_GROUP: + task_move_group_fair(p); + break; + } +} + void free_fair_sched_group(struct task_group *tg) { int i; @@ -8706,7 +8727,7 @@ const struct sched_class fair_sched_class = { .update_curr = update_curr_fair, #ifdef CONFIG_FAIR_GROUP_SCHED - .task_move_group = task_move_group_fair, + .task_change_group = task_change_group_fair, #endif }; diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h index 71ce986..307bd04 100644 --- a/kernel/sched/sched.h +++ b/kernel/sched/sched.h @@ -1246,8 +1246,11 @@ struct sched_class { void (*update_curr) (struct rq *rq); +#define TASK_SET_GROUP 0 +#define TASK_MOVE_GROUP 1 + #ifdef CONFIG_FAIR_GROUP_SCHED - void (*task_move_group) (struct task_struct *p); + void (*task_change_group) (struct task_struct *p, int type); #endif }; -- cgit v0.10.2 From 7dc603c9028ea5d4354e0e317e8481df99b06d7e Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Thu, 16 Jun 2016 13:29:28 +0200 Subject: sched/fair: Fix PELT integrity for new tasks Vincent and Yuyang found another few scenarios in which entity tracking goes wobbly. The scenarios are basically due to the fact that new tasks are not immediately attached and thereby differ from the normal situation -- a task is always attached to a cfs_rq load average (such that it includes its blocked contribution) and are explicitly detached/attached on migration to another cfs_rq. Scenario 1: switch to fair class p->sched_class = fair_class; if (queued) enqueue_task(p); ... enqueue_entity() enqueue_entity_load_avg() migrated = !sa->last_update_time (true) if (migrated) attach_entity_load_avg() check_class_changed() switched_from() (!fair) switched_to() (fair) switched_to_fair() attach_entity_load_avg() If @p is a new task that hasn't been fair before, it will have !last_update_time and, per the above, end up in attach_entity_load_avg() _twice_. Scenario 2: change between cgroups sched_move_group(p) if (queued) dequeue_task() task_move_group_fair() detach_task_cfs_rq() detach_entity_load_avg() set_task_rq() attach_task_cfs_rq() attach_entity_load_avg() if (queued) enqueue_task(); ... enqueue_entity() enqueue_entity_load_avg() migrated = !sa->last_update_time (true) if (migrated) attach_entity_load_avg() Similar as with scenario 1, if @p is a new task, it will have !load_update_time and we'll end up in attach_entity_load_avg() _twice_. Furthermore, notice how we do a detach_entity_load_avg() on something that wasn't attached to begin with. As stated above; the problem is that the new task isn't yet attached to the load tracking and thereby violates the invariant assumption. This patch remedies this by ensuring a new task is indeed properly attached to the load tracking on creation, through post_init_entity_util_avg(). Of course, this isn't entirely as straightforward as one might think, since the task is hashed before we call wake_up_new_task() and thus can be poked at. We avoid this by adding TASK_NEW and teaching cpu_cgroup_can_attach() to refuse such tasks. Reported-by: Yuyang Du Reported-by: Vincent Guittot Signed-off-by: Peter Zijlstra (Intel) Cc: Linus Torvalds Cc: Mike Galbraith Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: linux-kernel@vger.kernel.org Signed-off-by: Ingo Molnar diff --git a/include/linux/sched.h b/include/linux/sched.h index b45acfd..d99218a 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -219,9 +219,10 @@ extern void proc_sched_set_task(struct task_struct *p); #define TASK_WAKING 256 #define TASK_PARKED 512 #define TASK_NOLOAD 1024 -#define TASK_STATE_MAX 2048 +#define TASK_NEW 2048 +#define TASK_STATE_MAX 4096 -#define TASK_STATE_TO_CHAR_STR "RSDTtXZxKWPN" +#define TASK_STATE_TO_CHAR_STR "RSDTtXZxKWPNn" extern char ___assert_task_state[1 - 2*!!( sizeof(TASK_STATE_TO_CHAR_STR)-1 != ilog2(TASK_STATE_MAX)+1)]; diff --git a/kernel/sched/core.c b/kernel/sched/core.c index 3d856c4..14afa51 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c @@ -2342,11 +2342,11 @@ int sched_fork(unsigned long clone_flags, struct task_struct *p) __sched_fork(clone_flags, p); /* - * We mark the process as running here. This guarantees that + * We mark the process as NEW here. This guarantees that * nobody will actually run it, and a signal or other external * event cannot wake it up and insert it on the runqueue either. */ - p->state = TASK_RUNNING; + p->state = TASK_NEW; /* * Make sure we do not leak PI boosting priority to the child. @@ -2383,6 +2383,8 @@ int sched_fork(unsigned long clone_flags, struct task_struct *p) p->sched_class = &fair_sched_class; } + init_entity_runnable_average(&p->se); + /* * The child is not yet in the pid-hash so no cgroup attach races, * and the cgroup is pinned to this child due to cgroup_fork() @@ -2529,9 +2531,8 @@ void wake_up_new_task(struct task_struct *p) struct rq_flags rf; struct rq *rq; - /* Initialize new task's runnable average */ - init_entity_runnable_average(&p->se); raw_spin_lock_irqsave(&p->pi_lock, rf.flags); + p->state = TASK_RUNNING; #ifdef CONFIG_SMP /* * Fork balancing, do it here and not earlier because: @@ -8237,6 +8238,7 @@ static int cpu_cgroup_can_attach(struct cgroup_taskset *tset) { struct task_struct *task; struct cgroup_subsys_state *css; + int ret = 0; cgroup_taskset_for_each(task, css, tset) { #ifdef CONFIG_RT_GROUP_SCHED @@ -8247,8 +8249,24 @@ static int cpu_cgroup_can_attach(struct cgroup_taskset *tset) if (task->sched_class != &fair_sched_class) return -EINVAL; #endif + /* + * Serialize against wake_up_new_task() such that if its + * running, we're sure to observe its full state. + */ + raw_spin_lock_irq(&task->pi_lock); + /* + * Avoid calling sched_move_task() before wake_up_new_task() + * has happened. This would lead to problems with PELT, due to + * move wanting to detach+attach while we're not attached yet. + */ + if (task->state == TASK_NEW) + ret = -EINVAL; + raw_spin_unlock_irq(&task->pi_lock); + + if (ret) + break; } - return 0; + return ret; } static void cpu_cgroup_attach(struct cgroup_taskset *tset) diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c index 64f26bc..0c21a12 100644 --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c @@ -690,6 +690,10 @@ void init_entity_runnable_average(struct sched_entity *se) /* when this task enqueue'ed, it will contribute to its cfs_rq's load_avg */ } +static inline u64 cfs_rq_clock_task(struct cfs_rq *cfs_rq); +static int update_cfs_rq_load_avg(u64 now, struct cfs_rq *cfs_rq, bool update_freq); +static void attach_entity_load_avg(struct cfs_rq *cfs_rq, struct sched_entity *se); + /* * With new tasks being created, their initial util_avgs are extrapolated * based on the cfs_rq's current util_avg: @@ -720,6 +724,7 @@ void post_init_entity_util_avg(struct sched_entity *se) struct cfs_rq *cfs_rq = cfs_rq_of(se); struct sched_avg *sa = &se->avg; long cap = (long)(SCHED_CAPACITY_SCALE - cfs_rq->avg.util_avg) / 2; + u64 now = cfs_rq_clock_task(cfs_rq); if (cap > 0) { if (cfs_rq->avg.util_avg != 0) { @@ -733,16 +738,37 @@ void post_init_entity_util_avg(struct sched_entity *se) } sa->util_sum = sa->util_avg * LOAD_AVG_MAX; } + + if (entity_is_task(se)) { + struct task_struct *p = task_of(se); + if (p->sched_class != &fair_sched_class) { + /* + * For !fair tasks do: + * + update_cfs_rq_load_avg(now, cfs_rq, false); + attach_entity_load_avg(cfs_rq, se); + switched_from_fair(rq, p); + * + * such that the next switched_to_fair() has the + * expected state. + */ + se->avg.last_update_time = now; + return; + } + } + + update_cfs_rq_load_avg(now, cfs_rq, false); + attach_entity_load_avg(cfs_rq, se); } -#else +#else /* !CONFIG_SMP */ void init_entity_runnable_average(struct sched_entity *se) { } void post_init_entity_util_avg(struct sched_entity *se) { } -#endif +#endif /* CONFIG_SMP */ /* * Update the current task's runtime statistics. @@ -2840,8 +2866,6 @@ void set_task_rq_fair(struct sched_entity *se, static inline void update_tg_load_avg(struct cfs_rq *cfs_rq, int force) {} #endif /* CONFIG_FAIR_GROUP_SCHED */ -static inline u64 cfs_rq_clock_task(struct cfs_rq *cfs_rq); - static inline void cfs_rq_util_change(struct cfs_rq *cfs_rq) { struct rq *rq = rq_of(cfs_rq); @@ -2951,6 +2975,8 @@ static void attach_entity_load_avg(struct cfs_rq *cfs_rq, struct sched_entity *s /* * If we got migrated (either between CPUs or between cgroups) we'll * have aged the average right before clearing @last_update_time. + * + * Or we're fresh through post_init_entity_util_avg(). */ if (se->avg.last_update_time) { __update_load_avg(cfs_rq->avg.last_update_time, cpu_of(rq_of(cfs_rq)), @@ -3056,11 +3082,14 @@ void remove_entity_load_avg(struct sched_entity *se) u64 last_update_time; /* - * Newly created task or never used group entity should not be removed - * from its (source) cfs_rq + * tasks cannot exit without having gone through wake_up_new_task() -> + * post_init_entity_util_avg() which will have added things to the + * cfs_rq, so we can remove unconditionally. + * + * Similarly for groups, they will have passed through + * post_init_entity_util_avg() before unregister_sched_fair_group() + * calls this. */ - if (se->avg.last_update_time == 0) - return; last_update_time = cfs_rq_last_update_time(cfs_rq); -- cgit v0.10.2 From 3d30544f02120b884bba2a9466c87dba980e3be5 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Tue, 21 Jun 2016 14:27:50 +0200 Subject: sched/fair: Apply more PELT fixes One additional 'rule' for using update_cfs_rq_load_avg() is that one should call update_tg_load_avg() if it returns true. Add a bunch of comments to hopefully clarify some of the rules: o You need to update cfs_rq _before_ any entity attach/detach, this is important, because while for mathmatical consisency this isn't strictly needed, it is required for the physical interpretation of the model, you attach/detach _now_. o When you modify the cfs_rq avg, you have to then call update_tg_load_avg() in order to propagate changes upwards. o (Fair) entities are always attached, switched_{to,from}_fair() deal with !fair. This directly follows from the definition of the cfs_rq averages, namely that they are a direct sum of all (runnable or blocked) entities on that rq. It is the second rule that this patch enforces, but it adds comments pertaining to all of them. Signed-off-by: Peter Zijlstra (Intel) Cc: Linus Torvalds Cc: Mike Galbraith Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: linux-kernel@vger.kernel.org Signed-off-by: Ingo Molnar diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c index 0c21a12..781788d 100644 --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c @@ -692,6 +692,7 @@ void init_entity_runnable_average(struct sched_entity *se) static inline u64 cfs_rq_clock_task(struct cfs_rq *cfs_rq); static int update_cfs_rq_load_avg(u64 now, struct cfs_rq *cfs_rq, bool update_freq); +static void update_tg_load_avg(struct cfs_rq *cfs_rq, int force); static void attach_entity_load_avg(struct cfs_rq *cfs_rq, struct sched_entity *se); /* @@ -725,6 +726,7 @@ void post_init_entity_util_avg(struct sched_entity *se) struct sched_avg *sa = &se->avg; long cap = (long)(SCHED_CAPACITY_SCALE - cfs_rq->avg.util_avg) / 2; u64 now = cfs_rq_clock_task(cfs_rq); + int tg_update; if (cap > 0) { if (cfs_rq->avg.util_avg != 0) { @@ -757,8 +759,10 @@ void post_init_entity_util_avg(struct sched_entity *se) } } - update_cfs_rq_load_avg(now, cfs_rq, false); + tg_update = update_cfs_rq_load_avg(now, cfs_rq, false); attach_entity_load_avg(cfs_rq, se); + if (tg_update) + update_tg_load_avg(cfs_rq, false); } #else /* !CONFIG_SMP */ @@ -768,6 +772,9 @@ void init_entity_runnable_average(struct sched_entity *se) void post_init_entity_util_avg(struct sched_entity *se) { } +static void update_tg_load_avg(struct cfs_rq *cfs_rq, int force) +{ +} #endif /* CONFIG_SMP */ /* @@ -2912,7 +2919,23 @@ static inline void cfs_rq_util_change(struct cfs_rq *cfs_rq) WRITE_ONCE(*ptr, res); \ } while (0) -/* Group cfs_rq's load_avg is used for task_h_load and update_cfs_share */ +/** + * update_cfs_rq_load_avg - update the cfs_rq's load/util averages + * @now: current time, as per cfs_rq_clock_task() + * @cfs_rq: cfs_rq to update + * @update_freq: should we call cfs_rq_util_change() or will the call do so + * + * The cfs_rq avg is the direct sum of all its entities (blocked and runnable) + * avg. The immediate corollary is that all (fair) tasks must be attached, see + * post_init_entity_util_avg(). + * + * cfs_rq->avg is used for task_h_load() and update_cfs_share() for example. + * + * Returns true if the load decayed or we removed utilization. It is expected + * that one calls update_tg_load_avg() on this condition, but after you've + * modified the cfs_rq avg (attach/detach), such that we propagate the new + * avg up. + */ static inline int update_cfs_rq_load_avg(u64 now, struct cfs_rq *cfs_rq, bool update_freq) { @@ -2967,6 +2990,14 @@ static inline void update_load_avg(struct sched_entity *se, int update_tg) update_tg_load_avg(cfs_rq, 0); } +/** + * attach_entity_load_avg - attach this entity to its cfs_rq load avg + * @cfs_rq: cfs_rq to attach to + * @se: sched_entity to attach + * + * Must call update_cfs_rq_load_avg() before this, since we rely on + * cfs_rq->avg.last_update_time being current. + */ static void attach_entity_load_avg(struct cfs_rq *cfs_rq, struct sched_entity *se) { if (!sched_feat(ATTACH_AGE_LOAD)) @@ -2998,6 +3029,14 @@ skip_aging: cfs_rq_util_change(cfs_rq); } +/** + * detach_entity_load_avg - detach this entity from its cfs_rq load avg + * @cfs_rq: cfs_rq to detach from + * @se: sched_entity to detach + * + * Must call update_cfs_rq_load_avg() before this, since we rely on + * cfs_rq->avg.last_update_time being current. + */ static void detach_entity_load_avg(struct cfs_rq *cfs_rq, struct sched_entity *se) { __update_load_avg(cfs_rq->avg.last_update_time, cpu_of(rq_of(cfs_rq)), @@ -8404,6 +8443,7 @@ static void detach_task_cfs_rq(struct task_struct *p) struct sched_entity *se = &p->se; struct cfs_rq *cfs_rq = cfs_rq_of(se); u64 now = cfs_rq_clock_task(cfs_rq); + int tg_update; if (!vruntime_normalized(p)) { /* @@ -8415,8 +8455,10 @@ static void detach_task_cfs_rq(struct task_struct *p) } /* Catch up with the cfs_rq and remove our load when we leave */ - update_cfs_rq_load_avg(now, cfs_rq, false); + tg_update = update_cfs_rq_load_avg(now, cfs_rq, false); detach_entity_load_avg(cfs_rq, se); + if (tg_update) + update_tg_load_avg(cfs_rq, false); } static void attach_task_cfs_rq(struct task_struct *p) @@ -8424,6 +8466,7 @@ static void attach_task_cfs_rq(struct task_struct *p) struct sched_entity *se = &p->se; struct cfs_rq *cfs_rq = cfs_rq_of(se); u64 now = cfs_rq_clock_task(cfs_rq); + int tg_update; #ifdef CONFIG_FAIR_GROUP_SCHED /* @@ -8434,8 +8477,10 @@ static void attach_task_cfs_rq(struct task_struct *p) #endif /* Synchronize task with its cfs_rq */ - update_cfs_rq_load_avg(now, cfs_rq, false); + tg_update = update_cfs_rq_load_avg(now, cfs_rq, false); attach_entity_load_avg(cfs_rq, se); + if (tg_update) + update_tg_load_avg(cfs_rq, false); if (!vruntime_normalized(p)) se->vruntime += cfs_rq->min_vruntime; -- cgit v0.10.2 From 8663e24d56dc1f093232783c23ea17f2a6f61c03 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Wed, 22 Jun 2016 14:58:02 +0200 Subject: sched/fair: Reorder cgroup creation code A future patch needs rq->lock held _after_ we link the task_group into the hierarchy. In order to avoid taking every rq->lock twice, reorder things a little and create online_fair_sched_group() to be called after we link the task_group. All this code is still ran from css_alloc() so css_online() isn't in fact used for this. Signed-off-by: Peter Zijlstra (Intel) Cc: Konstantin Khlebnikov Cc: Linus Torvalds Cc: Mike Galbraith Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: bsegall@google.com Cc: linux-kernel@vger.kernel.org Signed-off-by: Ingo Molnar diff --git a/kernel/sched/core.c b/kernel/sched/core.c index 14afa51..4ede4fc 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c @@ -7717,6 +7717,8 @@ void sched_online_group(struct task_group *tg, struct task_group *parent) INIT_LIST_HEAD(&tg->children); list_add_rcu(&tg->siblings, &parent->children); spin_unlock_irqrestore(&task_group_lock, flags); + + online_fair_sched_group(tg); } /* rcu callback to free various structures associated with a task group */ diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c index 781788d..62d5e7d 100644 --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c @@ -8624,10 +8624,6 @@ int alloc_fair_sched_group(struct task_group *tg, struct task_group *parent) init_cfs_rq(cfs_rq); init_tg_cfs_entry(tg, cfs_rq, se, i, parent->se[i]); init_entity_runnable_average(se); - - raw_spin_lock_irq(&rq->lock); - post_init_entity_util_avg(se); - raw_spin_unlock_irq(&rq->lock); } return 1; @@ -8638,6 +8634,22 @@ err: return 0; } +void online_fair_sched_group(struct task_group *tg) +{ + struct sched_entity *se; + struct rq *rq; + int i; + + for_each_possible_cpu(i) { + rq = cpu_rq(i); + se = tg->se[i]; + + raw_spin_lock_irq(&rq->lock); + post_init_entity_util_avg(se); + raw_spin_unlock_irq(&rq->lock); + } +} + void unregister_fair_sched_group(struct task_group *tg) { unsigned long flags; @@ -8742,6 +8754,8 @@ int alloc_fair_sched_group(struct task_group *tg, struct task_group *parent) return 1; } +void online_fair_sched_group(struct task_group *tg) { } + void unregister_fair_sched_group(struct task_group *tg) { } #endif /* CONFIG_FAIR_GROUP_SCHED */ diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h index 307bd04..28c42b7 100644 --- a/kernel/sched/sched.h +++ b/kernel/sched/sched.h @@ -321,6 +321,7 @@ extern int tg_nop(struct task_group *tg, void *data); extern void free_fair_sched_group(struct task_group *tg); extern int alloc_fair_sched_group(struct task_group *tg, struct task_group *parent); +extern void online_fair_sched_group(struct task_group *tg); extern void unregister_fair_sched_group(struct task_group *tg); extern void init_tg_cfs_entry(struct task_group *tg, struct cfs_rq *cfs_rq, struct sched_entity *se, int cpu, -- cgit v0.10.2 From dbf984d825935f61965bcfacfd8e8dfdaf3e8051 Mon Sep 17 00:00:00 2001 From: Borislav Petkov Date: Sat, 25 Jun 2016 13:24:57 +0200 Subject: x86/boot/64: Add forgotten end of function marker Add secondary_startup_64()'s ENDPROC() marker. No functionality change. Signed-off-by: Borislav Petkov Cc: Andy Lutomirski Cc: Borislav Petkov Cc: Brian Gerst Cc: Denys Vlasenko Cc: H. Peter Anvin Cc: Josh Poimboeuf Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: linux-kernel@vger.kernel.org Link: http://lkml.kernel.org/r/20160625112457.16930-1-bp@alien8.de Signed-off-by: Ingo Molnar diff --git a/arch/x86/kernel/head_64.S b/arch/x86/kernel/head_64.S index 5df831e..c7920ba 100644 --- a/arch/x86/kernel/head_64.S +++ b/arch/x86/kernel/head_64.S @@ -299,6 +299,7 @@ ENTRY(secondary_startup_64) pushq $__KERNEL_CS # set correct cs pushq %rax # target address in negative space lretq +ENDPROC(secondary_startup_64) #include "verify_cpu.S" -- cgit v0.10.2 From 599b4840b0ea453c7d11e1798dcc8f494dcfd58a Mon Sep 17 00:00:00 2001 From: Zev Weiss Date: Sun, 26 Jun 2016 16:13:23 -0500 Subject: sched/core: Fix sched_getaffinity() return value kerneldoc comment Previous version was probably written referencing the man page for glibc's wrapper, but the wrapper's behavior differs from that of the syscall itself in this case. Signed-off-by: Zev Weiss Signed-off-by: Peter Zijlstra (Intel) Cc: Linus Torvalds Cc: Mike Galbraith Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: linux-kernel@vger.kernel.org Link: http://lkml.kernel.org/r/1466975603-25408-1-git-send-email-zev@bewilderbeest.net Signed-off-by: Ingo Molnar diff --git a/kernel/sched/core.c b/kernel/sched/core.c index 4ede4fc..28da50a 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c @@ -4759,7 +4759,8 @@ out_unlock: * @len: length in bytes of the bitmask pointed to by user_mask_ptr * @user_mask_ptr: user-space pointer to hold the current cpu mask * - * Return: 0 on success. An error code otherwise. + * Return: size of CPU mask copied to user_mask_ptr on success. An + * error code otherwise. */ SYSCALL_DEFINE3(sched_getaffinity, pid_t, pid, unsigned int, len, unsigned long __user *, user_mask_ptr) -- cgit v0.10.2 From 55e16d30bd99510900caec913c90f53bc2b35cba Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Wed, 22 Jun 2016 15:14:26 +0200 Subject: sched/fair: Rework throttle_count sync Since we already take rq->lock when creating a cgroup, use it to also sync the throttle_count and avoid the extra state and enqueue path branch. Signed-off-by: Peter Zijlstra (Intel) Cc: Konstantin Khlebnikov Cc: Linus Torvalds Cc: Mike Galbraith Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: bsegall@google.com Cc: linux-kernel@vger.kernel.org [ Fixed build warning. ] Signed-off-by: Ingo Molnar diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c index 62d5e7d..4088eed 100644 --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c @@ -4241,26 +4241,6 @@ static void check_enqueue_throttle(struct cfs_rq *cfs_rq) if (!cfs_bandwidth_used()) return; - /* Synchronize hierarchical throttle counter: */ - if (unlikely(!cfs_rq->throttle_uptodate)) { - struct rq *rq = rq_of(cfs_rq); - struct cfs_rq *pcfs_rq; - struct task_group *tg; - - cfs_rq->throttle_uptodate = 1; - - /* Get closest up-to-date node, because leaves go first: */ - for (tg = cfs_rq->tg->parent; tg; tg = tg->parent) { - pcfs_rq = tg->cfs_rq[cpu_of(rq)]; - if (pcfs_rq->throttle_uptodate) - break; - } - if (tg) { - cfs_rq->throttle_count = pcfs_rq->throttle_count; - cfs_rq->throttled_clock_task = rq_clock_task(rq); - } - } - /* an active group must be handled by the update_curr()->put() path */ if (!cfs_rq->runtime_enabled || cfs_rq->curr) return; @@ -4275,6 +4255,23 @@ static void check_enqueue_throttle(struct cfs_rq *cfs_rq) throttle_cfs_rq(cfs_rq); } +static void sync_throttle(struct task_group *tg, int cpu) +{ + struct cfs_rq *pcfs_rq, *cfs_rq; + + if (!cfs_bandwidth_used()) + return; + + if (!tg->parent) + return; + + cfs_rq = tg->cfs_rq[cpu]; + pcfs_rq = tg->parent->cfs_rq[cpu]; + + cfs_rq->throttle_count = pcfs_rq->throttle_count; + pcfs_rq->throttled_clock_task = rq_clock_task(cpu_rq(cpu)); +} + /* conditionally throttle active cfs_rq's from put_prev_entity() */ static bool check_cfs_rq_runtime(struct cfs_rq *cfs_rq) { @@ -4414,6 +4411,7 @@ static inline u64 cfs_rq_clock_task(struct cfs_rq *cfs_rq) static void account_cfs_rq_runtime(struct cfs_rq *cfs_rq, u64 delta_exec) {} static bool check_cfs_rq_runtime(struct cfs_rq *cfs_rq) { return false; } static void check_enqueue_throttle(struct cfs_rq *cfs_rq) {} +static inline void sync_throttle(struct task_group *tg, int cpu) {} static __always_inline void return_cfs_rq_runtime(struct cfs_rq *cfs_rq) {} static inline int cfs_rq_throttled(struct cfs_rq *cfs_rq) @@ -8646,6 +8644,7 @@ void online_fair_sched_group(struct task_group *tg) raw_spin_lock_irq(&rq->lock); post_init_entity_util_avg(se); + sync_throttle(tg, i); raw_spin_unlock_irq(&rq->lock); } } diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h index 28c42b7..f44da95 100644 --- a/kernel/sched/sched.h +++ b/kernel/sched/sched.h @@ -438,7 +438,7 @@ struct cfs_rq { u64 throttled_clock, throttled_clock_task; u64 throttled_clock_task_time; - int throttled, throttle_count, throttle_uptodate; + int throttled, throttle_count; struct list_head throttled_list; #endif /* CONFIG_CFS_BANDWIDTH */ #endif /* CONFIG_FAIR_GROUP_SCHED */ -- cgit v0.10.2 From 5356c32742bd51c8c57065d2389a2c4bc036adcd Mon Sep 17 00:00:00 2001 From: "Compostella, Jeremy" Date: Sat, 25 Jun 2016 08:20:24 +0100 Subject: efibc: Report more information in the error messages Report the name of the EFI variable if the value size is too large, or if efibc_set_variable() fails to allocate the 'struct efivar_entry' object. If efibc_set_variable() fails because the 'size' value is too large, it also reports this value in the error message. Reported-by: Robert Elliott Signed-off-by: Jeremy Compostella Signed-off-by: Matt Fleming Cc: Ard Biesheuvel Cc: Arnd Bergmann Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: linux-efi@vger.kernel.org Link: http://lkml.kernel.org/r/1466839230-12781-2-git-send-email-matt@codeblueprint.co.uk [ Minor readability edits. ] Signed-off-by: Ingo Molnar diff --git a/drivers/firmware/efi/efibc.c b/drivers/firmware/efi/efibc.c index 8dd0c70..503bbe2 100644 --- a/drivers/firmware/efi/efibc.c +++ b/drivers/firmware/efi/efibc.c @@ -37,13 +37,13 @@ static int efibc_set_variable(const char *name, const char *value) size_t size = (strlen(value) + 1) * sizeof(efi_char16_t); if (size > sizeof(entry->var.Data)) { - pr_err("value is too large"); + pr_err("value is too large (%zu bytes) for '%s' EFI variable\n", size, name); return -EINVAL; } entry = kmalloc(sizeof(*entry), GFP_KERNEL); if (!entry) { - pr_err("failed to allocate efivar entry"); + pr_err("failed to allocate efivar entry for '%s' EFI variable\n", name); return -ENOMEM; } -- cgit v0.10.2 From 54fd11fee59e7d05287bc4eebccc8ec9742f2745 Mon Sep 17 00:00:00 2001 From: Peter Jones Date: Sat, 25 Jun 2016 08:20:25 +0100 Subject: efi: Document #define FOO_PROTOCOL_GUID layout Add a comment documenting why EFI GUIDs are laid out like they are. Ideally I'd like to change all the ", " to "," too, but right now the format is such that checkpatch won't complain with new ones, and staring at checkpatch didn't get me anywhere towards making that work. Signed-off-by: Peter Jones Signed-off-by: Matt Fleming Cc: Ard Biesheuvel Cc: Joe Perches Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: linux-efi@vger.kernel.org Link: http://lkml.kernel.org/r/1466839230-12781-3-git-send-email-matt@codeblueprint.co.uk Signed-off-by: Ingo Molnar diff --git a/include/linux/efi.h b/include/linux/efi.h index f196dd0..0300969 100644 --- a/include/linux/efi.h +++ b/include/linux/efi.h @@ -536,7 +536,22 @@ typedef efi_status_t efi_query_variable_store_t(u32 attributes, void efi_native_runtime_setup(void); /* - * EFI Configuration Table and GUID definitions + * EFI Configuration Table and GUID definitions + * + * These should be formatted roughly like the ones in the UEFI SPEC has + * them. It makes them easier to grep for, and they look the same when + * you're staring at them. Here's the guide: + * + * GUID: 12345678-1234-1234-1234-123456789012 + * Spec: + * #define EFI_SOME_PROTOCOL_GUID \ + * {0x12345678,0x1234,0x1234,\ + * {0x12,0x34,0x12,0x34,0x56,0x78,0x90,0x12}} + * Here: + * #define SOME_PROTOCOL_GUID \ + * EFI_GUID(0x12345678, 0x1234, 0x1234, \ + * 0x12, 0x34, 0x12, 0x34, 0x56, 0x78, 0x90, 0x12) + * ^ tab ^tab ^ space */ #define NULL_GUID \ EFI_GUID(0x00000000, 0x0000, 0x0000, \ -- cgit v0.10.2 From f6d1747f898cfe1fe52e3d18f5c77e5bd21fed9a Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Sat, 25 Jun 2016 08:20:26 +0100 Subject: x86/efi: Remove unused variable 'efi' Remove unused variable 'efi', it is never used. This fixes the following clang build warning: arch/x86/boot/compressed/eboot.c:803:2: warning: Value stored to 'efi' is never read Signed-off-by: Colin Ian King Signed-off-by: Matt Fleming Cc: Ard Biesheuvel Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: linux-efi@vger.kernel.org Link: http://lkml.kernel.org/r/1466839230-12781-4-git-send-email-matt@codeblueprint.co.uk Signed-off-by: Ingo Molnar diff --git a/arch/x86/boot/compressed/eboot.c b/arch/x86/boot/compressed/eboot.c index 52fef60..ff574da 100644 --- a/arch/x86/boot/compressed/eboot.c +++ b/arch/x86/boot/compressed/eboot.c @@ -757,7 +757,6 @@ struct boot_params *make_boot_params(struct efi_config *c) struct boot_params *boot_params; struct apm_bios_info *bi; struct setup_header *hdr; - struct efi_info *efi; efi_loaded_image_t *image; void *options, *handle; efi_guid_t proto = LOADED_IMAGE_PROTOCOL_GUID; @@ -800,7 +799,6 @@ struct boot_params *make_boot_params(struct efi_config *c) memset(boot_params, 0x0, 0x4000); hdr = &boot_params->hdr; - efi = &boot_params->efi_info; bi = &boot_params->apm_bios_info; /* Copy the second sector to boot_params */ -- cgit v0.10.2 From 80e75596079f0a41f905836ad0ccaac68ba33612 Mon Sep 17 00:00:00 2001 From: Alex Thorlton Date: Sat, 25 Jun 2016 08:20:27 +0100 Subject: efi: Convert efi_call_virt() to efi_call_virt_pointer() This commit makes a few slight modifications to the efi_call_virt() macro to get it to work with function pointers that are stored in locations other than efi.systab->runtime, and renames the macro to efi_call_virt_pointer(). The majority of the changes here are to pull these macros up into header files so that they can be accessed from outside of drivers/firmware/efi/runtime-wrappers.c. The most significant change not directly related to the code move is to add an extra "p" argument into the appropriate efi_call macros, and use that new argument in place of the, formerly hard-coded, efi.systab->runtime pointer. The last piece of the puzzle was to add an efi_call_virt() macro back into drivers/firmware/efi/runtime-wrappers.c to wrap around the new efi_call_virt_pointer() macro - this was mainly to keep the code from looking too cluttered by adding a bunch of extra references to efi.systab->runtime everywhere. Note that I also broke up the code in the efi_call_virt_pointer() macro a bit in the process of moving it. Signed-off-by: Alex Thorlton Signed-off-by: Matt Fleming Cc: Ard Biesheuvel Cc: Catalin Marinas Cc: Dimitri Sivanich Cc: Linus Torvalds Cc: Mark Rutland Cc: Peter Zijlstra Cc: Roy Franz Cc: Russ Anderson Cc: Russell King Cc: Thomas Gleixner Cc: Will Deacon Cc: linux-arm-kernel@lists.infradead.org Cc: linux-efi@vger.kernel.org Link: http://lkml.kernel.org/r/1466839230-12781-5-git-send-email-matt@codeblueprint.co.uk Signed-off-by: Ingo Molnar diff --git a/arch/arm/include/asm/efi.h b/arch/arm/include/asm/efi.h index a708fa1..766bf9b 100644 --- a/arch/arm/include/asm/efi.h +++ b/arch/arm/include/asm/efi.h @@ -28,10 +28,10 @@ int efi_set_mapping_permissions(struct mm_struct *mm, efi_memory_desc_t *md); #define arch_efi_call_virt_setup() efi_virtmap_load() #define arch_efi_call_virt_teardown() efi_virtmap_unload() -#define arch_efi_call_virt(f, args...) \ +#define arch_efi_call_virt(p, f, args...) \ ({ \ efi_##f##_t *__f; \ - __f = efi.systab->runtime->f; \ + __f = p->f; \ __f(args); \ }) diff --git a/arch/arm64/include/asm/efi.h b/arch/arm64/include/asm/efi.h index 622db3c..bd88766 100644 --- a/arch/arm64/include/asm/efi.h +++ b/arch/arm64/include/asm/efi.h @@ -23,10 +23,10 @@ int efi_create_mapping(struct mm_struct *mm, efi_memory_desc_t *md); efi_virtmap_load(); \ }) -#define arch_efi_call_virt(f, args...) \ +#define arch_efi_call_virt(p, f, args...) \ ({ \ efi_##f##_t *__f; \ - __f = efi.systab->runtime->f; \ + __f = p->f; \ __f(args); \ }) diff --git a/arch/x86/include/asm/efi.h b/arch/x86/include/asm/efi.h index 78d1e74..55b4596 100644 --- a/arch/x86/include/asm/efi.h +++ b/arch/x86/include/asm/efi.h @@ -41,10 +41,9 @@ extern unsigned long asmlinkage efi_call_phys(void *, ...); /* * Wrap all the virtual calls in a way that forces the parameters on the stack. */ -#define arch_efi_call_virt(f, args...) \ +#define arch_efi_call_virt(p, f, args...) \ ({ \ - ((efi_##f##_t __attribute__((regparm(0)))*) \ - efi.systab->runtime->f)(args); \ + ((efi_##f##_t __attribute__((regparm(0)))*) p->f)(args); \ }) #define efi_ioremap(addr, size, type, attr) ioremap_cache(addr, size) @@ -81,8 +80,8 @@ struct efi_scratch { } \ }) -#define arch_efi_call_virt(f, args...) \ - efi_call((void *)efi.systab->runtime->f, args) \ +#define arch_efi_call_virt(p, f, args...) \ + efi_call((void *)p->f, args) \ #define arch_efi_call_virt_teardown() \ ({ \ diff --git a/drivers/firmware/efi/runtime-wrappers.c b/drivers/firmware/efi/runtime-wrappers.c index 23bef6b..4195877 100644 --- a/drivers/firmware/efi/runtime-wrappers.c +++ b/drivers/firmware/efi/runtime-wrappers.c @@ -22,7 +22,16 @@ #include #include -static void efi_call_virt_check_flags(unsigned long flags, const char *call) +/* + * Wrap around the new efi_call_virt_generic() macros so that the + * code doesn't get too cluttered: + */ +#define efi_call_virt(f, args...) \ + efi_call_virt_pointer(efi.systab->runtime, f, args) +#define __efi_call_virt(f, args...) \ + __efi_call_virt_pointer(efi.systab->runtime, f, args) + +void efi_call_virt_check_flags(unsigned long flags, const char *call) { unsigned long cur_flags, mismatch; @@ -39,48 +48,6 @@ static void efi_call_virt_check_flags(unsigned long flags, const char *call) } /* - * Arch code can implement the following three template macros, avoiding - * reptition for the void/non-void return cases of {__,}efi_call_virt: - * - * * arch_efi_call_virt_setup - * - * Sets up the environment for the call (e.g. switching page tables, - * allowing kernel-mode use of floating point, if required). - * - * * arch_efi_call_virt - * - * Performs the call. The last expression in the macro must be the call - * itself, allowing the logic to be shared by the void and non-void - * cases. - * - * * arch_efi_call_virt_teardown - * - * Restores the usual kernel environment once the call has returned. - */ - -#define efi_call_virt(f, args...) \ -({ \ - efi_status_t __s; \ - unsigned long flags; \ - arch_efi_call_virt_setup(); \ - local_save_flags(flags); \ - __s = arch_efi_call_virt(f, args); \ - efi_call_virt_check_flags(flags, __stringify(f)); \ - arch_efi_call_virt_teardown(); \ - __s; \ -}) - -#define __efi_call_virt(f, args...) \ -({ \ - unsigned long flags; \ - arch_efi_call_virt_setup(); \ - local_save_flags(flags); \ - arch_efi_call_virt(f, args); \ - efi_call_virt_check_flags(flags, __stringify(f)); \ - arch_efi_call_virt_teardown(); \ -}) - -/* * According to section 7.1 of the UEFI spec, Runtime Services are not fully * reentrant, and there are particular combinations of calls that need to be * serialized. (source: UEFI Specification v2.4A) diff --git a/include/linux/efi.h b/include/linux/efi.h index 0300969..75d148d 100644 --- a/include/linux/efi.h +++ b/include/linux/efi.h @@ -1480,4 +1480,55 @@ efi_status_t efi_setup_gop(efi_system_table_t *sys_table_arg, unsigned long size); bool efi_runtime_disabled(void); +extern void efi_call_virt_check_flags(unsigned long flags, const char *call); + +/* + * Arch code can implement the following three template macros, avoiding + * reptition for the void/non-void return cases of {__,}efi_call_virt(): + * + * * arch_efi_call_virt_setup() + * + * Sets up the environment for the call (e.g. switching page tables, + * allowing kernel-mode use of floating point, if required). + * + * * arch_efi_call_virt() + * + * Performs the call. The last expression in the macro must be the call + * itself, allowing the logic to be shared by the void and non-void + * cases. + * + * * arch_efi_call_virt_teardown() + * + * Restores the usual kernel environment once the call has returned. + */ + +#define efi_call_virt_pointer(p, f, args...) \ +({ \ + efi_status_t __s; \ + unsigned long __flags; \ + \ + arch_efi_call_virt_setup(); \ + \ + local_save_flags(__flags); \ + __s = arch_efi_call_virt(p, f, args); \ + efi_call_virt_check_flags(__flags, __stringify(f)); \ + \ + arch_efi_call_virt_teardown(); \ + \ + __s; \ +}) + +#define __efi_call_virt_pointer(p, f, args...) \ +({ \ + unsigned long __flags; \ + \ + arch_efi_call_virt_setup(); \ + \ + local_save_flags(__flags); \ + arch_efi_call_virt(p, f, args); \ + efi_call_virt_check_flags(__flags, __stringify(f)); \ + \ + arch_efi_call_virt_teardown(); \ +}) + #endif /* _LINUX_EFI_H */ -- cgit v0.10.2 From d1be84a232e359ca9456c63e72cb0082d68311b6 Mon Sep 17 00:00:00 2001 From: Alex Thorlton Date: Sat, 25 Jun 2016 08:20:28 +0100 Subject: x86/uv: Update uv_bios_call() to use efi_call_virt_pointer() Now that the efi_call_virt() macro has been generalized to be able to use EFI system tables besides efi.systab, we are able to convert our uv_bios_call() wrapper to use this standard EFI callback mechanism. This simple change is part of a much larger effort to recover from some issues with the way we were mapping in some of our MMRs, and the way that we were doing our BIOS callbacks, which were uncovered by commit 67a9108ed431 ("x86/efi: Build our own page table structures"). The first issue that this uncovered was that we were relying on the EFI memory mapping mechanism to map in our MMR space for us, which, while reliable, was technically a bug, as it relied on "undefined" behavior in the mapping code. The reason we were able to piggyback on the EFI memory mapping code to map in our MMRs was because, previously, EFI code used the trampoline_pgd, which shares a few entries with the main kernel pgd. It just so happened, that the memory range containing our MMRs was inside one of those shared regions, which kept our code working without issue for quite a while. Anyways, once we discovered this problem, we brought back our original code to map in the MMRs with commit: 08914f436bdd ("x86/platform/UV: Bring back the call to map_low_mmrs in uv_system_init") This got our systems a little further along, but we were still running into trouble with our EFI callbacks, which prevented us from booting all the way up. Our first step towards fixing the BIOS callbacks was to get our uv_bios_call() wrapper updated to use efi_call_virt() instead of the plain efi_call(). The previous patch took care of the effort needed to make that possible. Along the way, we hit a major issue with some confusion about how to properly pull arguments higher than number 6 off the stack in the efi_call() code, which resulted in the following commit from Linus: 683ad8092cd2 ("x86/efi: Fix 7-parameter efi_call()s") Now that all of those issues are out of the way, we're able to make this simple change to use the new efi_call_virt_pointer() in uv_bios_call() which gets our machines booting, running properly, and able to execute our callbacks with 6+ arguments. Note that, since we are now using the EFI page table when we make our function call, we are no longer able to make the call using the __va() of our function pointer, since the memory range containing that address isn't mapped into the EFI page table. For now, we will use the physical address of the function directly, since that is mapped into the EFI page table. In the near future, we're going to get some code added in to properly update our function pointer to its virtual address during SetVirtualAddressMap. Signed-off-by: Alex Thorlton Signed-off-by: Matt Fleming Cc: Ard Biesheuvel Cc: Catalin Marinas Cc: Dimitri Sivanich Cc: Linus Torvalds Cc: Mark Rutland Cc: Peter Zijlstra Cc: Roy Franz Cc: Russ Anderson Cc: Russell King Cc: Thomas Gleixner Cc: Will Deacon Cc: linux-arm-kernel@lists.infradead.org Cc: linux-efi@vger.kernel.org Link: http://lkml.kernel.org/r/1466839230-12781-6-git-send-email-matt@codeblueprint.co.uk Signed-off-by: Ingo Molnar diff --git a/arch/x86/platform/uv/bios_uv.c b/arch/x86/platform/uv/bios_uv.c index 815fec6..66b2166 100644 --- a/arch/x86/platform/uv/bios_uv.c +++ b/arch/x86/platform/uv/bios_uv.c @@ -40,8 +40,7 @@ s64 uv_bios_call(enum uv_bios_cmd which, u64 a1, u64 a2, u64 a3, u64 a4, u64 a5) */ return BIOS_STATUS_UNIMPLEMENTED; - ret = efi_call((void *)__va(tab->function), (u64)which, - a1, a2, a3, a4, a5); + ret = efi_call_virt_pointer(tab, function, (u64)which, a1, a2, a3, a4, a5); return ret; } EXPORT_SYMBOL_GPL(uv_bios_call); -- cgit v0.10.2 From 21f866257c7027f8f49bfde83f559f9e58f9ee93 Mon Sep 17 00:00:00 2001 From: Alex Thorlton Date: Sat, 25 Jun 2016 08:20:29 +0100 Subject: x86/efi: Update efi_thunk() to use the the arch_efi_call_virt*() macros Currently, the efi_thunk macro has some semi-duplicated code in it that can be replaced with the arch_efi_call_virt_setup/teardown macros. This commit simply replaces the duplicated code with those macros. Suggested-by: Matt Fleming Signed-off-by: Alex Thorlton Signed-off-by: Matt Fleming Cc: Ard Biesheuvel Cc: Catalin Marinas Cc: Dimitri Sivanich Cc: Linus Torvalds Cc: Mark Rutland Cc: Peter Zijlstra Cc: Roy Franz Cc: Russ Anderson Cc: Russell King Cc: Thomas Gleixner Cc: Will Deacon Cc: linux-arm-kernel@lists.infradead.org Cc: linux-efi@vger.kernel.org Link: http://lkml.kernel.org/r/1466839230-12781-7-git-send-email-matt@codeblueprint.co.uk [ Renamed variables to the standard __ prefix. ] Signed-off-by: Ingo Molnar diff --git a/arch/x86/platform/efi/efi_64.c b/arch/x86/platform/efi/efi_64.c index b226b3f..5cb4301 100644 --- a/arch/x86/platform/efi/efi_64.c +++ b/arch/x86/platform/efi/efi_64.c @@ -466,22 +466,17 @@ extern efi_status_t efi64_thunk(u32, ...); #define efi_thunk(f, ...) \ ({ \ efi_status_t __s; \ - unsigned long flags; \ - u32 func; \ + unsigned long __flags; \ + u32 __func; \ \ - efi_sync_low_kernel_mappings(); \ - local_irq_save(flags); \ + local_irq_save(__flags); \ + arch_efi_call_virt_setup(); \ \ - efi_scratch.prev_cr3 = read_cr3(); \ - write_cr3((unsigned long)efi_scratch.efi_pgt); \ - __flush_tlb_all(); \ + __func = runtime_service32(f); \ + __s = efi64_thunk(__func, __VA_ARGS__); \ \ - func = runtime_service32(f); \ - __s = efi64_thunk(func, __VA_ARGS__); \ - \ - write_cr3(efi_scratch.prev_cr3); \ - __flush_tlb_all(); \ - local_irq_restore(flags); \ + arch_efi_call_virt_teardown(); \ + local_irq_restore(__flags); \ \ __s; \ }) -- cgit v0.10.2 From b684e9bc750b6349ff59f1b1ab4397cae255765f Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Sat, 25 Jun 2016 08:20:30 +0100 Subject: x86/efi: Remove the unused efi_get_time() function Nothing calls the efi_get_time() function on x86, but it does suffer from the 32-bit time_t overflow in 2038. This removes the function, we can always put it back in case we need it later. Signed-off-by: Arnd Bergmann Signed-off-by: Matt Fleming Acked-by: Ard Biesheuvel Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: linux-efi@vger.kernel.org Link: http://lkml.kernel.org/r/1466839230-12781-8-git-send-email-matt@codeblueprint.co.uk Signed-off-by: Ingo Molnar diff --git a/arch/x86/platform/efi/efi.c b/arch/x86/platform/efi/efi.c index f93545e..d898b33 100644 --- a/arch/x86/platform/efi/efi.c +++ b/arch/x86/platform/efi/efi.c @@ -98,21 +98,6 @@ static efi_status_t __init phys_efi_set_virtual_address_map( return status; } -void efi_get_time(struct timespec *now) -{ - efi_status_t status; - efi_time_t eft; - efi_time_cap_t cap; - - status = efi.get_time(&eft, &cap); - if (status != EFI_SUCCESS) - pr_err("Oops: efitime: can't read time!\n"); - - now->tv_sec = mktime(eft.year, eft.month, eft.day, eft.hour, - eft.minute, eft.second); - now->tv_nsec = 0; -} - void __init efi_find_mirror(void) { efi_memory_desc_t *md; diff --git a/include/linux/efi.h b/include/linux/efi.h index 75d148d..0174f28 100644 --- a/include/linux/efi.h +++ b/include/linux/efi.h @@ -990,7 +990,6 @@ extern u64 efi_mem_desc_end(efi_memory_desc_t *md); extern int efi_mem_desc_lookup(u64 phys_addr, efi_memory_desc_t *out_md); extern void efi_initialize_iomem_resources(struct resource *code_resource, struct resource *data_resource, struct resource *bss_resource); -extern void efi_get_time(struct timespec *now); extern void efi_reserve_boot_services(void); extern int efi_get_fdt_params(struct efi_fdt_params *params); extern struct kobject *efi_kobj; -- cgit v0.10.2 From 20f7b53dfc24e0caa984087691af82e442229680 Mon Sep 17 00:00:00 2001 From: Chanwoo Choi Date: Mon, 27 Jun 2016 19:17:06 +0900 Subject: extcon: Move struct extcon_cable from header file to core This patch moves the struct extcon_cable because that should be only handled by extcon core. There are no reason to publish the internal structure. Signed-off-by: Chanwoo Choi diff --git a/drivers/extcon/extcon.c b/drivers/extcon/extcon.c index b6408f0..b5fdb5d 100644 --- a/drivers/extcon/extcon.c +++ b/drivers/extcon/extcon.c @@ -77,6 +77,26 @@ static const char *extcon_name[] = { NULL, }; +/** + * struct extcon_cable - An internal data for each cable of extcon device. + * @edev: The extcon device + * @cable_index: Index of this cable in the edev + * @attr_g: Attribute group for the cable + * @attr_name: "name" sysfs entry + * @attr_state: "state" sysfs entry + * @attrs: Array pointing to attr_name and attr_state for attr_g + */ +struct extcon_cable { + struct extcon_dev *edev; + int cable_index; + + struct attribute_group attr_g; + struct device_attribute attr_name; + struct device_attribute attr_state; + + struct attribute *attrs[3]; /* to be fed to attr_g.attrs */ +}; + static struct class *extcon_class; #if defined(CONFIG_ANDROID) static struct class_compat *switch_class; diff --git a/include/linux/extcon.h b/include/linux/extcon.h index cec5c54..1b2c8b6 100644 --- a/include/linux/extcon.h +++ b/include/linux/extcon.h @@ -126,26 +126,6 @@ struct extcon_dev { struct device_attribute *d_attrs_muex; }; -/** - * struct extcon_cable - An internal data for each cable of extcon device. - * @edev: The extcon device - * @cable_index: Index of this cable in the edev - * @attr_g: Attribute group for the cable - * @attr_name: "name" sysfs entry - * @attr_state: "state" sysfs entry - * @attrs: Array pointing to attr_name and attr_state for attr_g - */ -struct extcon_cable { - struct extcon_dev *edev; - int cable_index; - - struct attribute_group attr_g; - struct device_attribute attr_name; - struct device_attribute attr_state; - - struct attribute *attrs[3]; /* to be fed to attr_g.attrs */ -}; - #if IS_ENABLED(CONFIG_EXTCON) /* -- cgit v0.10.2 From b225d00f3ad2d996f914790a0f6324a4efd18768 Mon Sep 17 00:00:00 2001 From: Chanwoo Choi Date: Mon, 27 Jun 2016 19:28:04 +0900 Subject: extcon: Split out the resource-managed functions from extcon core This patch split out the resource-managed related functions from extcon core driver. Signed-off-by: Chanwoo Choi diff --git a/drivers/extcon/Makefile b/drivers/extcon/Makefile index 2a0e4f4..423ebc8 100644 --- a/drivers/extcon/Makefile +++ b/drivers/extcon/Makefile @@ -2,7 +2,7 @@ # Makefile for external connector class (extcon) devices # -obj-$(CONFIG_EXTCON) += extcon.o +obj-$(CONFIG_EXTCON) += extcon.o devres.o obj-$(CONFIG_EXTCON_ADC_JACK) += extcon-adc-jack.o obj-$(CONFIG_EXTCON_ARIZONA) += extcon-arizona.o obj-$(CONFIG_EXTCON_AXP288) += extcon-axp288.o diff --git a/drivers/extcon/devres.c b/drivers/extcon/devres.c new file mode 100644 index 0000000..694ca85 --- /dev/null +++ b/drivers/extcon/devres.c @@ -0,0 +1,143 @@ +/* + * drivers/extcon/devres.c - EXTCON device's resource management + * + * Copyright (C) 2016 Samsung Electronics + * Author: Chanwoo Choi + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include + +static int devm_extcon_dev_match(struct device *dev, void *res, void *data) +{ + struct extcon_dev **r = res; + + if (WARN_ON(!r || !*r)) + return 0; + + return *r == data; +} + +static void devm_extcon_dev_release(struct device *dev, void *res) +{ + extcon_dev_free(*(struct extcon_dev **)res); +} + + +static void devm_extcon_dev_unreg(struct device *dev, void *res) +{ + extcon_dev_unregister(*(struct extcon_dev **)res); +} + +/** + * devm_extcon_dev_allocate - Allocate managed extcon device + * @dev: device owning the extcon device being created + * @supported_cable: Array of supported extcon ending with EXTCON_NONE. + * If supported_cable is NULL, cable name related APIs + * are disabled. + * + * This function manages automatically the memory of extcon device using device + * resource management and simplify the control of freeing the memory of extcon + * device. + * + * Returns the pointer memory of allocated extcon_dev if success + * or ERR_PTR(err) if fail + */ +struct extcon_dev *devm_extcon_dev_allocate(struct device *dev, + const unsigned int *supported_cable) +{ + struct extcon_dev **ptr, *edev; + + ptr = devres_alloc(devm_extcon_dev_release, sizeof(*ptr), GFP_KERNEL); + if (!ptr) + return ERR_PTR(-ENOMEM); + + edev = extcon_dev_allocate(supported_cable); + if (IS_ERR(edev)) { + devres_free(ptr); + return edev; + } + + edev->dev.parent = dev; + + *ptr = edev; + devres_add(dev, ptr); + + return edev; +} +EXPORT_SYMBOL_GPL(devm_extcon_dev_allocate); + +/** + * devm_extcon_dev_free() - Resource-managed extcon_dev_unregister() + * @dev: device the extcon belongs to + * @edev: the extcon device to unregister + * + * Free the memory that is allocated with devm_extcon_dev_allocate() + * function. + */ +void devm_extcon_dev_free(struct device *dev, struct extcon_dev *edev) +{ + WARN_ON(devres_release(dev, devm_extcon_dev_release, + devm_extcon_dev_match, edev)); +} +EXPORT_SYMBOL_GPL(devm_extcon_dev_free); + +/** + * devm_extcon_dev_register() - Resource-managed extcon_dev_register() + * @dev: device to allocate extcon device + * @edev: the new extcon device to register + * + * Managed extcon_dev_register() function. If extcon device is attached with + * this function, that extcon device is automatically unregistered on driver + * detach. Internally this function calls extcon_dev_register() function. + * To get more information, refer that function. + * + * If extcon device is registered with this function and the device needs to be + * unregistered separately, devm_extcon_dev_unregister() should be used. + * + * Returns 0 if success or negaive error number if failure. + */ +int devm_extcon_dev_register(struct device *dev, struct extcon_dev *edev) +{ + struct extcon_dev **ptr; + int ret; + + ptr = devres_alloc(devm_extcon_dev_unreg, sizeof(*ptr), GFP_KERNEL); + if (!ptr) + return -ENOMEM; + + ret = extcon_dev_register(edev); + if (ret) { + devres_free(ptr); + return ret; + } + + *ptr = edev; + devres_add(dev, ptr); + + return 0; +} +EXPORT_SYMBOL_GPL(devm_extcon_dev_register); + +/** + * devm_extcon_dev_unregister() - Resource-managed extcon_dev_unregister() + * @dev: device the extcon belongs to + * @edev: the extcon device to unregister + * + * Unregister extcon device that is registered with devm_extcon_dev_register() + * function. + */ +void devm_extcon_dev_unregister(struct device *dev, struct extcon_dev *edev) +{ + WARN_ON(devres_release(dev, devm_extcon_dev_unreg, + devm_extcon_dev_match, edev)); +} +EXPORT_SYMBOL_GPL(devm_extcon_dev_unregister); diff --git a/drivers/extcon/extcon.c b/drivers/extcon/extcon.c index b5fdb5d..862334e 100644 --- a/drivers/extcon/extcon.c +++ b/drivers/extcon/extcon.c @@ -564,66 +564,6 @@ void extcon_dev_free(struct extcon_dev *edev) } EXPORT_SYMBOL_GPL(extcon_dev_free); -static int devm_extcon_dev_match(struct device *dev, void *res, void *data) -{ - struct extcon_dev **r = res; - - if (WARN_ON(!r || !*r)) - return 0; - - return *r == data; -} - -static void devm_extcon_dev_release(struct device *dev, void *res) -{ - extcon_dev_free(*(struct extcon_dev **)res); -} - -/** - * devm_extcon_dev_allocate - Allocate managed extcon device - * @dev: device owning the extcon device being created - * @supported_cable: Array of supported extcon ending with EXTCON_NONE. - * If supported_cable is NULL, cable name related APIs - * are disabled. - * - * This function manages automatically the memory of extcon device using device - * resource management and simplify the control of freeing the memory of extcon - * device. - * - * Returns the pointer memory of allocated extcon_dev if success - * or ERR_PTR(err) if fail - */ -struct extcon_dev *devm_extcon_dev_allocate(struct device *dev, - const unsigned int *supported_cable) -{ - struct extcon_dev **ptr, *edev; - - ptr = devres_alloc(devm_extcon_dev_release, sizeof(*ptr), GFP_KERNEL); - if (!ptr) - return ERR_PTR(-ENOMEM); - - edev = extcon_dev_allocate(supported_cable); - if (IS_ERR(edev)) { - devres_free(ptr); - return edev; - } - - edev->dev.parent = dev; - - *ptr = edev; - devres_add(dev, ptr); - - return edev; -} -EXPORT_SYMBOL_GPL(devm_extcon_dev_allocate); - -void devm_extcon_dev_free(struct device *dev, struct extcon_dev *edev) -{ - WARN_ON(devres_release(dev, devm_extcon_dev_release, - devm_extcon_dev_match, edev)); -} -EXPORT_SYMBOL_GPL(devm_extcon_dev_free); - /** * extcon_dev_register() - Register a new extcon device * @edev : the new extcon device (should be allocated before calling) @@ -889,63 +829,6 @@ void extcon_dev_unregister(struct extcon_dev *edev) } EXPORT_SYMBOL_GPL(extcon_dev_unregister); -static void devm_extcon_dev_unreg(struct device *dev, void *res) -{ - extcon_dev_unregister(*(struct extcon_dev **)res); -} - -/** - * devm_extcon_dev_register() - Resource-managed extcon_dev_register() - * @dev: device to allocate extcon device - * @edev: the new extcon device to register - * - * Managed extcon_dev_register() function. If extcon device is attached with - * this function, that extcon device is automatically unregistered on driver - * detach. Internally this function calls extcon_dev_register() function. - * To get more information, refer that function. - * - * If extcon device is registered with this function and the device needs to be - * unregistered separately, devm_extcon_dev_unregister() should be used. - * - * Returns 0 if success or negaive error number if failure. - */ -int devm_extcon_dev_register(struct device *dev, struct extcon_dev *edev) -{ - struct extcon_dev **ptr; - int ret; - - ptr = devres_alloc(devm_extcon_dev_unreg, sizeof(*ptr), GFP_KERNEL); - if (!ptr) - return -ENOMEM; - - ret = extcon_dev_register(edev); - if (ret) { - devres_free(ptr); - return ret; - } - - *ptr = edev; - devres_add(dev, ptr); - - return 0; -} -EXPORT_SYMBOL_GPL(devm_extcon_dev_register); - -/** - * devm_extcon_dev_unregister() - Resource-managed extcon_dev_unregister() - * @dev: device the extcon belongs to - * @edev: the extcon device to unregister - * - * Unregister extcon device that is registered with devm_extcon_dev_register() - * function. - */ -void devm_extcon_dev_unregister(struct device *dev, struct extcon_dev *edev) -{ - WARN_ON(devres_release(dev, devm_extcon_dev_unreg, - devm_extcon_dev_match, edev)); -} -EXPORT_SYMBOL_GPL(devm_extcon_dev_unregister); - #ifdef CONFIG_OF /* * extcon_get_edev_by_phandle - Get the extcon device from devicetree -- cgit v0.10.2 From 58f386560a68dd98bd6744a28fc853eef11faebe Mon Sep 17 00:00:00 2001 From: Chanwoo Choi Date: Mon, 27 Jun 2016 20:03:39 +0900 Subject: extcon: Add resource-managed functions to register extcon notifier This patch adds the resource-managed functions for register/unregister the extcon notifier with the id of each external connector. This function will make it easy to handle the extcon notifier. - int devm_extcon_register_notifier(struct device *dev, struct extcon_dev *edev, unsigned int id, struct notifier_block *nb); - void devm_extcon_unregister_notifier(struct device *dev, struct extcon_dev *edev, unsigned int id, struct notifier_block *nb); Signed-off-by: Chanwoo Choi diff --git a/drivers/extcon/devres.c b/drivers/extcon/devres.c index 694ca85..e686acd 100644 --- a/drivers/extcon/devres.c +++ b/drivers/extcon/devres.c @@ -37,6 +37,19 @@ static void devm_extcon_dev_unreg(struct device *dev, void *res) extcon_dev_unregister(*(struct extcon_dev **)res); } +struct extcon_dev_notifier_devres { + struct extcon_dev *edev; + unsigned int id; + struct notifier_block *nb; +}; + +static void devm_extcon_dev_notifier_unreg(struct device *dev, void *res) +{ + struct extcon_dev_notifier_devres *this = res; + + extcon_unregister_notifier(this->edev, this->id, this->nb); +} + /** * devm_extcon_dev_allocate - Allocate managed extcon device * @dev: device owning the extcon device being created @@ -141,3 +154,63 @@ void devm_extcon_dev_unregister(struct device *dev, struct extcon_dev *edev) devm_extcon_dev_match, edev)); } EXPORT_SYMBOL_GPL(devm_extcon_dev_unregister); + +/** + * devm_extcon_register_notifier() - Resource-managed extcon_register_notifier() + * @dev: device to allocate extcon device + * @edev: the extcon device that has the external connecotr. + * @id: the unique id of each external connector in extcon enumeration. + * @nb: a notifier block to be registered. + * + * This function manages automatically the notifier of extcon device using + * device resource management and simplify the control of unregistering + * the notifier of extcon device. + * + * Note that the second parameter given to the callback of nb (val) is + * "old_state", not the current state. The current state can be retrieved + * by looking at the third pameter (edev pointer)'s state value. + * + * Returns 0 if success or negaive error number if failure. + */ +int devm_extcon_register_notifier(struct device *dev, struct extcon_dev *edev, + unsigned int id, struct notifier_block *nb) +{ + struct extcon_dev_notifier_devres *ptr; + int ret; + + ptr = devres_alloc(devm_extcon_dev_notifier_unreg, sizeof(*ptr), + GFP_KERNEL); + if (!ptr) + return -ENOMEM; + + ret = extcon_register_notifier(edev, id, nb); + if (ret) { + devres_free(ptr); + return ret; + } + + ptr->edev = edev; + ptr->id = id; + ptr->nb = nb; + devres_add(dev, ptr); + + return 0; +} +EXPORT_SYMBOL(devm_extcon_register_notifier); + +/** + * devm_extcon_unregister_notifier() + - Resource-managed extcon_unregister_notifier() + * @dev: device to allocate extcon device + * @edev: the extcon device that has the external connecotr. + * @id: the unique id of each external connector in extcon enumeration. + * @nb: a notifier block to be registered. + */ +void devm_extcon_unregister_notifier(struct device *dev, + struct extcon_dev *edev, unsigned int id, + struct notifier_block *nb) +{ + WARN_ON(devres_release(dev, devm_extcon_dev_notifier_unreg, + devm_extcon_dev_match, edev)); +} +EXPORT_SYMBOL(devm_extcon_unregister_notifier); diff --git a/include/linux/extcon.h b/include/linux/extcon.h index 1b2c8b6..7bf530f 100644 --- a/include/linux/extcon.h +++ b/include/linux/extcon.h @@ -182,6 +182,12 @@ extern int extcon_register_notifier(struct extcon_dev *edev, unsigned int id, struct notifier_block *nb); extern int extcon_unregister_notifier(struct extcon_dev *edev, unsigned int id, struct notifier_block *nb); +extern int devm_extcon_register_notifier(struct device *dev, + struct extcon_dev *edev, unsigned int id, + struct notifier_block *nb); +extern void devm_extcon_unregister_notifier(struct device *dev, + struct extcon_dev *edev, unsigned int id, + struct notifier_block *nb); /* * Following API get the extcon device from devicetree. @@ -273,6 +279,17 @@ static inline int extcon_unregister_notifier(struct extcon_dev *edev, return 0; } +static inline int devm_extcon_register_notifier(struct device *dev, + struct extcon_dev *edev, unsigned int id, + struct notifier_block *nb) +{ + return -ENOSYS; +} + +static inline void devm_extcon_unregister_notifier(struct device *dev, + struct extcon_dev *edev, unsigned int id, + struct notifier_block *nb) { } + static inline struct extcon_dev *extcon_get_edev_by_phandle(struct device *dev, int index) { -- cgit v0.10.2 From f2f4fe4410ac6de96f8561aefeadbb680e5ddc99 Mon Sep 17 00:00:00 2001 From: Ravi Bangoria Date: Fri, 24 Jun 2016 17:23:55 +0530 Subject: perf annotate: Remove unused hist_entry__annotate function hist_entry__annotate looks part of API but I don't find any caller of this function. Removing it. Signed-off-by: Ravi Bangoria Cc: Ananth N Mavinakayanahalli Cc: Anton Blanchard Cc: Daniel Axtens Cc: Michael Ellerman Link: http://lkml.kernel.org/r/1466769240-12376-2-git-send-email-ravi.bangoria@linux.vnet.ibm.com Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index 7e5a1e8..b2c7ae4 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -1676,11 +1676,6 @@ int symbol__tty_annotate(struct symbol *sym, struct map *map, return 0; } -int hist_entry__annotate(struct hist_entry *he, size_t privsize) -{ - return symbol__annotate(he->ms.sym, he->ms.map, privsize); -} - bool ui__has_annotation(void) { return use_browser == 1 && perf_hpp_list.sym; diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h index 9241f8c..82f3781 100644 --- a/tools/perf/util/annotate.h +++ b/tools/perf/util/annotate.h @@ -156,8 +156,6 @@ void symbol__annotate_zero_histograms(struct symbol *sym); int symbol__annotate(struct symbol *sym, struct map *map, size_t privsize); -int hist_entry__annotate(struct hist_entry *he, size_t privsize); - int symbol__annotate_init(struct map *map, struct symbol *sym); int symbol__annotate_printf(struct symbol *sym, struct map *map, struct perf_evsel *evsel, bool full_paths, -- cgit v0.10.2 From 3ce37b2cb4917674fa5b776e857dcea94c0e0835 Mon Sep 17 00:00:00 2001 From: Andreas Gruenbacher Date: Tue, 14 Jun 2016 12:22:27 -0500 Subject: gfs2: Fix gfs2_lookup_by_inum lock inversion The current gfs2_lookup_by_inum takes the glock of a presumed inode identified by block number, verifies that the block is indeed an inode, and then instantiates and reads the new inode via gfs2_inode_lookup. However, instantiating a new inode may block on freeing a previous instance of that inode (__wait_on_freeing_inode), and freeing an inode requires to take the glock already held, leading to lock inversion and deadlock. Fix this by first instantiating the new inode, then verifying that the block is an inode (if required), and then reading in the new inode, all in gfs2_inode_lookup. If the block we are looking for is not an inode, we discard the new inode via iget_failed, which marks inodes as bad and unhashes them. Other tasks waiting on that inode will get back a bad inode back from ilookup or iget_locked; in that case, retry the lookup. Signed-off-by: Andreas Gruenbacher Signed-off-by: Bob Peterson diff --git a/fs/gfs2/dir.c b/fs/gfs2/dir.c index 4a01f30..1b02665 100644 --- a/fs/gfs2/dir.c +++ b/fs/gfs2/dir.c @@ -1660,7 +1660,8 @@ struct inode *gfs2_dir_search(struct inode *dir, const struct qstr *name, brelse(bh); if (fail_on_exist) return ERR_PTR(-EEXIST); - inode = gfs2_inode_lookup(dir->i_sb, dtype, addr, formal_ino); + inode = gfs2_inode_lookup(dir->i_sb, dtype, addr, formal_ino, + GFS2_BLKST_FREE /* ignore */); if (!IS_ERR(inode)) GFS2_I(inode)->i_rahead = rahead; return inode; diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c index 706fd93..ce46375 100644 --- a/fs/gfs2/glock.c +++ b/fs/gfs2/glock.c @@ -576,7 +576,7 @@ static void delete_work_func(struct work_struct *work) struct gfs2_glock *gl = container_of(work, struct gfs2_glock, gl_delete); struct gfs2_sbd *sdp = gl->gl_name.ln_sbd; struct gfs2_inode *ip; - struct inode *inode; + struct inode *inode = NULL; u64 no_addr = gl->gl_name.ln_number; /* If someone's using this glock to create a new dinode, the block must @@ -590,7 +590,7 @@ static void delete_work_func(struct work_struct *work) if (ip) inode = gfs2_ilookup(sdp->sd_vfs, no_addr); - else + if (IS_ERR_OR_NULL(inode)) inode = gfs2_lookup_by_inum(sdp, no_addr, NULL, GFS2_BLKST_UNLINKED); if (inode && !IS_ERR(inode)) { d_prune_aliases(inode); diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c index 21dc784..6d5c6bb 100644 --- a/fs/gfs2/inode.c +++ b/fs/gfs2/inode.c @@ -39,7 +39,33 @@ struct inode *gfs2_ilookup(struct super_block *sb, u64 no_addr) { - return ilookup(sb, (unsigned long)no_addr); + struct inode *inode; + +repeat: + inode = ilookup(sb, no_addr); + if (!inode) + return inode; + if (is_bad_inode(inode)) { + iput(inode); + goto repeat; + } + return inode; +} + +static struct inode *gfs2_iget(struct super_block *sb, u64 no_addr) +{ + struct inode *inode; + +repeat: + inode = iget_locked(sb, no_addr); + if (!inode) + return inode; + if (is_bad_inode(inode)) { + iput(inode); + goto repeat; + } + GFS2_I(inode)->i_no_addr = no_addr; + return inode; } /** @@ -78,26 +104,37 @@ static void gfs2_set_iop(struct inode *inode) /** * gfs2_inode_lookup - Lookup an inode * @sb: The super block - * @no_addr: The inode number * @type: The type of the inode + * @no_addr: The inode number + * @no_formal_ino: The inode generation number + * @blktype: Requested block type (GFS2_BLKST_DINODE or GFS2_BLKST_UNLINKED; + * GFS2_BLKST_FREE do indicate not to verify) + * + * If @type is DT_UNKNOWN, the inode type is fetched from disk. + * + * If @blktype is anything other than GFS2_BLKST_FREE (which is used as a + * placeholder because it doesn't otherwise make sense), the on-disk block type + * is verified to be @blktype. * * Returns: A VFS inode, or an error */ struct inode *gfs2_inode_lookup(struct super_block *sb, unsigned int type, - u64 no_addr, u64 no_formal_ino) + u64 no_addr, u64 no_formal_ino, + unsigned int blktype) { struct inode *inode; struct gfs2_inode *ip; struct gfs2_glock *io_gl = NULL; + struct gfs2_holder i_gh; + bool unlock = false; int error; - inode = iget_locked(sb, (unsigned long)no_addr); + inode = gfs2_iget(sb, no_addr); if (!inode) return ERR_PTR(-ENOMEM); ip = GFS2_I(inode); - ip->i_no_addr = no_addr; if (inode->i_state & I_NEW) { struct gfs2_sbd *sdp = GFS2_SB(inode); @@ -112,10 +149,30 @@ struct inode *gfs2_inode_lookup(struct super_block *sb, unsigned int type, if (unlikely(error)) goto fail_put; + if (type == DT_UNKNOWN || blktype != GFS2_BLKST_FREE) { + /* + * The GL_SKIP flag indicates to skip reading the inode + * block. We read the inode with gfs2_inode_refresh + * after possibly checking the block type. + */ + error = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, + GL_SKIP, &i_gh); + if (error) + goto fail_put; + unlock = true; + + if (blktype != GFS2_BLKST_FREE) { + error = gfs2_check_blk_type(sdp, no_addr, + blktype); + if (error) + goto fail_put; + } + } + set_bit(GIF_INVALID, &ip->i_flags); error = gfs2_glock_nq_init(io_gl, LM_ST_SHARED, GL_EXACT, &ip->i_iopen_gh); if (unlikely(error)) - goto fail_iopen; + goto fail_put; ip->i_iopen_gh.gh_gl->gl_object = ip; gfs2_glock_put(io_gl); @@ -134,6 +191,8 @@ struct inode *gfs2_inode_lookup(struct super_block *sb, unsigned int type, unlock_new_inode(inode); } + if (unlock) + gfs2_glock_dq_uninit(&i_gh); return inode; fail_refresh: @@ -141,10 +200,11 @@ fail_refresh: ip->i_iopen_gh.gh_gl->gl_object = NULL; gfs2_glock_dq_wait(&ip->i_iopen_gh); gfs2_holder_uninit(&ip->i_iopen_gh); -fail_iopen: +fail_put: if (io_gl) gfs2_glock_put(io_gl); -fail_put: + if (unlock) + gfs2_glock_dq_uninit(&i_gh); ip->i_gl->gl_object = NULL; fail: iget_failed(inode); @@ -155,23 +215,12 @@ struct inode *gfs2_lookup_by_inum(struct gfs2_sbd *sdp, u64 no_addr, u64 *no_formal_ino, unsigned int blktype) { struct super_block *sb = sdp->sd_vfs; - struct gfs2_holder i_gh; - struct inode *inode = NULL; + struct inode *inode; int error; - /* Must not read in block until block type is verified */ - error = gfs2_glock_nq_num(sdp, no_addr, &gfs2_inode_glops, - LM_ST_EXCLUSIVE, GL_SKIP, &i_gh); - if (error) - return ERR_PTR(error); - - error = gfs2_check_blk_type(sdp, no_addr, blktype); - if (error) - goto fail; - - inode = gfs2_inode_lookup(sb, DT_UNKNOWN, no_addr, 0); + inode = gfs2_inode_lookup(sb, DT_UNKNOWN, no_addr, 0, blktype); if (IS_ERR(inode)) - goto fail; + return inode; /* Two extra checks for NFS only */ if (no_formal_ino) { @@ -182,16 +231,12 @@ struct inode *gfs2_lookup_by_inum(struct gfs2_sbd *sdp, u64 no_addr, error = -EIO; if (GFS2_I(inode)->i_diskflags & GFS2_DIF_SYSTEM) goto fail_iput; - - error = 0; } + return inode; -fail: - gfs2_glock_dq_uninit(&i_gh); - return error ? ERR_PTR(error) : inode; fail_iput: iput(inode); - goto fail; + return ERR_PTR(error); } diff --git a/fs/gfs2/inode.h b/fs/gfs2/inode.h index e1af0d4..443b46c 100644 --- a/fs/gfs2/inode.h +++ b/fs/gfs2/inode.h @@ -94,7 +94,8 @@ err: } extern struct inode *gfs2_inode_lookup(struct super_block *sb, unsigned type, - u64 no_addr, u64 no_formal_ino); + u64 no_addr, u64 no_formal_ino, + unsigned int blktype); extern struct inode *gfs2_lookup_by_inum(struct gfs2_sbd *sdp, u64 no_addr, u64 *no_formal_ino, unsigned int blktype); diff --git a/fs/gfs2/ops_fstype.c b/fs/gfs2/ops_fstype.c index 4546360..b8f6fc9 100644 --- a/fs/gfs2/ops_fstype.c +++ b/fs/gfs2/ops_fstype.c @@ -454,7 +454,8 @@ static int gfs2_lookup_root(struct super_block *sb, struct dentry **dptr, struct dentry *dentry; struct inode *inode; - inode = gfs2_inode_lookup(sb, DT_DIR, no_addr, 0); + inode = gfs2_inode_lookup(sb, DT_DIR, no_addr, 0, + GFS2_BLKST_FREE /* ignore */); if (IS_ERR(inode)) { fs_err(sdp, "can't read in %s inode: %ld\n", name, PTR_ERR(inode)); return PTR_ERR(inode); -- cgit v0.10.2 From ec5ec66ba48bd3163110599359797858ac38e79b Mon Sep 17 00:00:00 2001 From: Andreas Gruenbacher Date: Tue, 14 Jun 2016 12:23:59 -0500 Subject: gfs2: Get rid of gfs2_ilookup Now that gfs2_lookup_by_inum only takes the inode glock for new inodes (and not for cached inodes anymore), there no longer is a need to optimize the cached-inode case in gfs2_get_dentry or delete_work_func, and gfs2_ilookup can be removed. In addition, gfs2_get_dentry wasn't checking the GFS2_DIF_SYSTEM flag in i_diskflags in the gfs2_ilookup case (see gfs2_lookup_by_inum); this inconsistency goes away as well. Signed-off-by: Andreas Gruenbacher Signed-off-by: Bob Peterson diff --git a/fs/gfs2/export.c b/fs/gfs2/export.c index d5bda85..a332f3c 100644 --- a/fs/gfs2/export.c +++ b/fs/gfs2/export.c @@ -137,21 +137,10 @@ static struct dentry *gfs2_get_dentry(struct super_block *sb, struct gfs2_sbd *sdp = sb->s_fs_info; struct inode *inode; - inode = gfs2_ilookup(sb, inum->no_addr); - if (inode) { - if (GFS2_I(inode)->i_no_formal_ino != inum->no_formal_ino) { - iput(inode); - return ERR_PTR(-ESTALE); - } - goto out_inode; - } - inode = gfs2_lookup_by_inum(sdp, inum->no_addr, &inum->no_formal_ino, GFS2_BLKST_DINODE); if (IS_ERR(inode)) return ERR_CAST(inode); - -out_inode: return d_obtain_alias(inode); } diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c index ce46375..1138a61 100644 --- a/fs/gfs2/glock.c +++ b/fs/gfs2/glock.c @@ -575,8 +575,7 @@ static void delete_work_func(struct work_struct *work) { struct gfs2_glock *gl = container_of(work, struct gfs2_glock, gl_delete); struct gfs2_sbd *sdp = gl->gl_name.ln_sbd; - struct gfs2_inode *ip; - struct inode *inode = NULL; + struct inode *inode; u64 no_addr = gl->gl_name.ln_number; /* If someone's using this glock to create a new dinode, the block must @@ -585,13 +584,7 @@ static void delete_work_func(struct work_struct *work) if (test_bit(GLF_INODE_CREATING, &gl->gl_flags)) goto out; - ip = gl->gl_object; - /* Note: Unsafe to dereference ip as we don't hold right refs/locks */ - - if (ip) - inode = gfs2_ilookup(sdp->sd_vfs, no_addr); - if (IS_ERR_OR_NULL(inode)) - inode = gfs2_lookup_by_inum(sdp, no_addr, NULL, GFS2_BLKST_UNLINKED); + inode = gfs2_lookup_by_inum(sdp, no_addr, NULL, GFS2_BLKST_UNLINKED); if (inode && !IS_ERR(inode)) { d_prune_aliases(inode); iput(inode); diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c index 6d5c6bb..ebff26e 100644 --- a/fs/gfs2/inode.c +++ b/fs/gfs2/inode.c @@ -37,21 +37,6 @@ #include "super.h" #include "glops.h" -struct inode *gfs2_ilookup(struct super_block *sb, u64 no_addr) -{ - struct inode *inode; - -repeat: - inode = ilookup(sb, no_addr); - if (!inode) - return inode; - if (is_bad_inode(inode)) { - iput(inode); - goto repeat; - } - return inode; -} - static struct inode *gfs2_iget(struct super_block *sb, u64 no_addr) { struct inode *inode; diff --git a/fs/gfs2/inode.h b/fs/gfs2/inode.h index 443b46c..7710dfd 100644 --- a/fs/gfs2/inode.h +++ b/fs/gfs2/inode.h @@ -99,7 +99,6 @@ extern struct inode *gfs2_inode_lookup(struct super_block *sb, unsigned type, extern struct inode *gfs2_lookup_by_inum(struct gfs2_sbd *sdp, u64 no_addr, u64 *no_formal_ino, unsigned int blktype); -extern struct inode *gfs2_ilookup(struct super_block *sb, u64 no_addr); extern int gfs2_inode_refresh(struct gfs2_inode *ip); -- cgit v0.10.2 From cda9dd4207aeb29d0aa2298085cc2d1ebcb87e04 Mon Sep 17 00:00:00 2001 From: Andreas Gruenbacher Date: Tue, 14 Jun 2016 12:24:50 -0500 Subject: gfs2: Large-filesystem fix for 32-bit systems Commit ff34245d switched from iget5_locked to iget_locked among other things, but iget_locked doesn't work for filesystems larger than 2^32 blocks on 32-bit systems. Switch back to iget5_locked. Filesystems larger than 2^32 blocks are unrealistic to work well on 32-bit systems, so this is mostly a code cleanliness fix. Signed-off-by: Andreas Gruenbacher Signed-off-by: Bob Peterson diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c index ebff26e..481b649 100644 --- a/fs/gfs2/inode.c +++ b/fs/gfs2/inode.c @@ -37,19 +37,34 @@ #include "super.h" #include "glops.h" +static int iget_test(struct inode *inode, void *opaque) +{ + u64 no_addr = *(u64 *)opaque; + + return GFS2_I(inode)->i_no_addr == no_addr; +} + +static int iget_set(struct inode *inode, void *opaque) +{ + u64 no_addr = *(u64 *)opaque; + + GFS2_I(inode)->i_no_addr = no_addr; + inode->i_ino = no_addr; + return 0; +} + static struct inode *gfs2_iget(struct super_block *sb, u64 no_addr) { struct inode *inode; repeat: - inode = iget_locked(sb, no_addr); + inode = iget5_locked(sb, no_addr, iget_test, iget_set, &no_addr); if (!inode) return inode; if (is_bad_inode(inode)) { iput(inode); goto repeat; } - GFS2_I(inode)->i_no_addr = no_addr; return inode; } -- cgit v0.10.2 From 6df9f9a253c7dc9f8ed18bf89d762de350a31813 Mon Sep 17 00:00:00 2001 From: Andreas Gruenbacher Date: Fri, 17 Jun 2016 07:31:27 -0500 Subject: gfs2: Lock holder cleanup Make the code more readable by cleaning up the different ways of initializing lock holders and checking for initialized lock holders: mark lock holders as uninitialized by setting the holder's glock to NULL (gfs2_holder_mark_uninitialized) instead of zeroing out the entire object or using a separate flag. Recognize initialized holders by their non-NULL glock (gfs2_holder_initialized). Don't zero out holder objects which are immeditiately initialized via gfs2_holder_init or gfs2_glock_nq_init. Signed-off-by: Andreas Gruenbacher Signed-off-by: Bob Peterson diff --git a/fs/gfs2/dentry.c b/fs/gfs2/dentry.c index 30822b1..5173b98 100644 --- a/fs/gfs2/dentry.c +++ b/fs/gfs2/dentry.c @@ -117,7 +117,7 @@ static int gfs2_dentry_delete(const struct dentry *dentry) return 0; ginode = GFS2_I(d_inode(dentry)); - if (!ginode->i_iopen_gh.gh_gl) + if (!gfs2_holder_initialized(&ginode->i_iopen_gh)) return 0; if (test_bit(GLF_DEMOTE, &ginode->i_iopen_gh.gh_gl->gl_flags)) diff --git a/fs/gfs2/file.c b/fs/gfs2/file.c index e0f98e4..320e65e 100644 --- a/fs/gfs2/file.c +++ b/fs/gfs2/file.c @@ -1098,7 +1098,7 @@ static void do_unflock(struct file *file, struct file_lock *fl) mutex_lock(&fp->f_fl_mutex); locks_lock_file_wait(file, fl); - if (fl_gh->gh_gl) { + if (gfs2_holder_initialized(fl_gh)) { gfs2_glock_dq(fl_gh); gfs2_holder_uninit(fl_gh); } diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c index 1138a61..3a90b2b 100644 --- a/fs/gfs2/glock.c +++ b/fs/gfs2/glock.c @@ -801,7 +801,7 @@ void gfs2_holder_uninit(struct gfs2_holder *gh) { put_pid(gh->gh_owner_pid); gfs2_glock_put(gh->gh_gl); - gh->gh_gl = NULL; + gfs2_holder_mark_uninitialized(gh); gh->gh_ip = 0; } diff --git a/fs/gfs2/glock.h b/fs/gfs2/glock.h index 46ab67f..ab1ef32 100644 --- a/fs/gfs2/glock.h +++ b/fs/gfs2/glock.h @@ -247,4 +247,14 @@ extern void gfs2_unregister_debugfs(void); extern const struct lm_lockops gfs2_dlm_ops; +static inline void gfs2_holder_mark_uninitialized(struct gfs2_holder *gh) +{ + gh->gh_gl = NULL; +} + +static inline bool gfs2_holder_initialized(struct gfs2_holder *gh) +{ + return gh->gh_gl; +} + #endif /* __GLOCK_DOT_H__ */ diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c index 481b649..de54d60 100644 --- a/fs/gfs2/inode.c +++ b/fs/gfs2/inode.c @@ -127,9 +127,9 @@ struct inode *gfs2_inode_lookup(struct super_block *sb, unsigned int type, struct gfs2_inode *ip; struct gfs2_glock *io_gl = NULL; struct gfs2_holder i_gh; - bool unlock = false; int error; + gfs2_holder_mark_uninitialized(&i_gh); inode = gfs2_iget(sb, no_addr); if (!inode) return ERR_PTR(-ENOMEM); @@ -159,7 +159,6 @@ struct inode *gfs2_inode_lookup(struct super_block *sb, unsigned int type, GL_SKIP, &i_gh); if (error) goto fail_put; - unlock = true; if (blktype != GFS2_BLKST_FREE) { error = gfs2_check_blk_type(sdp, no_addr, @@ -191,7 +190,7 @@ struct inode *gfs2_inode_lookup(struct super_block *sb, unsigned int type, unlock_new_inode(inode); } - if (unlock) + if (gfs2_holder_initialized(&i_gh)) gfs2_glock_dq_uninit(&i_gh); return inode; @@ -203,7 +202,7 @@ fail_refresh: fail_put: if (io_gl) gfs2_glock_put(io_gl); - if (unlock) + if (gfs2_holder_initialized(&i_gh)) gfs2_glock_dq_uninit(&i_gh); ip->i_gl->gl_object = NULL; fail: @@ -281,8 +280,8 @@ struct inode *gfs2_lookupi(struct inode *dir, const struct qstr *name, struct gfs2_holder d_gh; int error = 0; struct inode *inode = NULL; - int unlock = 0; + gfs2_holder_mark_uninitialized(&d_gh); if (!name->len || name->len > GFS2_FNAMESIZE) return ERR_PTR(-ENAMETOOLONG); @@ -297,7 +296,6 @@ struct inode *gfs2_lookupi(struct inode *dir, const struct qstr *name, error = gfs2_glock_nq_init(dip->i_gl, LM_ST_SHARED, 0, &d_gh); if (error) return ERR_PTR(error); - unlock = 1; } if (!is_root) { @@ -310,7 +308,7 @@ struct inode *gfs2_lookupi(struct inode *dir, const struct qstr *name, if (IS_ERR(inode)) error = PTR_ERR(inode); out: - if (unlock) + if (gfs2_holder_initialized(&d_gh)) gfs2_glock_dq_uninit(&d_gh); if (error == -ENOENT) return NULL; @@ -1354,7 +1352,7 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry, struct gfs2_inode *ip = GFS2_I(d_inode(odentry)); struct gfs2_inode *nip = NULL; struct gfs2_sbd *sdp = GFS2_SB(odir); - struct gfs2_holder ghs[5], r_gh = { .gh_gl = NULL, }; + struct gfs2_holder ghs[5], r_gh; struct gfs2_rgrpd *nrgd; unsigned int num_gh; int dir_rename = 0; @@ -1362,6 +1360,7 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry, unsigned int x; int error; + gfs2_holder_mark_uninitialized(&r_gh); if (d_really_is_positive(ndentry)) { nip = GFS2_I(d_inode(ndentry)); if (ip == nip) @@ -1551,7 +1550,7 @@ out_gunlock: gfs2_holder_uninit(ghs + x); } out_gunlock_r: - if (r_gh.gh_gl) + if (gfs2_holder_initialized(&r_gh)) gfs2_glock_dq_uninit(&r_gh); out: return error; @@ -1577,13 +1576,14 @@ static int gfs2_exchange(struct inode *odir, struct dentry *odentry, struct gfs2_inode *oip = GFS2_I(odentry->d_inode); struct gfs2_inode *nip = GFS2_I(ndentry->d_inode); struct gfs2_sbd *sdp = GFS2_SB(odir); - struct gfs2_holder ghs[5], r_gh = { .gh_gl = NULL, }; + struct gfs2_holder ghs[5], r_gh; unsigned int num_gh; unsigned int x; umode_t old_mode = oip->i_inode.i_mode; umode_t new_mode = nip->i_inode.i_mode; int error; + gfs2_holder_mark_uninitialized(&r_gh); error = gfs2_rindex_update(sdp); if (error) return error; @@ -1691,7 +1691,7 @@ out_gunlock: gfs2_holder_uninit(ghs + x); } out_gunlock_r: - if (r_gh.gh_gl) + if (gfs2_holder_initialized(&r_gh)) gfs2_glock_dq_uninit(&r_gh); out: return error; @@ -1788,9 +1788,8 @@ int gfs2_permission(struct inode *inode, int mask) struct gfs2_inode *ip; struct gfs2_holder i_gh; int error; - int unlock = 0; - + gfs2_holder_mark_uninitialized(&i_gh); ip = GFS2_I(inode); if (gfs2_glock_is_locked_by_me(ip->i_gl) == NULL) { if (mask & MAY_NOT_BLOCK) @@ -1798,14 +1797,13 @@ int gfs2_permission(struct inode *inode, int mask) error = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, LM_FLAG_ANY, &i_gh); if (error) return error; - unlock = 1; } if ((mask & MAY_WRITE) && IS_IMMUTABLE(inode)) error = -EACCES; else error = generic_permission(inode, mask); - if (unlock) + if (gfs2_holder_initialized(&i_gh)) gfs2_glock_dq_uninit(&i_gh); return error; @@ -1977,17 +1975,16 @@ static int gfs2_getattr(struct vfsmount *mnt, struct dentry *dentry, struct gfs2_inode *ip = GFS2_I(inode); struct gfs2_holder gh; int error; - int unlock = 0; + gfs2_holder_mark_uninitialized(&gh); if (gfs2_glock_is_locked_by_me(ip->i_gl) == NULL) { error = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, LM_FLAG_ANY, &gh); if (error) return error; - unlock = 1; } generic_fillattr(inode, stat); - if (unlock) + if (gfs2_holder_initialized(&gh)) gfs2_glock_dq_uninit(&gh); return 0; diff --git a/fs/gfs2/main.c b/fs/gfs2/main.c index 615f675..74fd013 100644 --- a/fs/gfs2/main.c +++ b/fs/gfs2/main.c @@ -45,7 +45,7 @@ static void gfs2_init_inode_once(void *foo) memset(&ip->i_res, 0, sizeof(ip->i_res)); RB_CLEAR_NODE(&ip->i_res.rs_node); ip->i_hash_cache = NULL; - ip->i_iopen_gh.gh_gl = NULL; + gfs2_holder_mark_uninitialized(&ip->i_iopen_gh); } static void gfs2_init_glock_once(void *foo) diff --git a/fs/gfs2/quota.c b/fs/gfs2/quota.c index ce7d69a..6c657b2 100644 --- a/fs/gfs2/quota.c +++ b/fs/gfs2/quota.c @@ -883,7 +883,7 @@ static int do_sync(unsigned int num_qd, struct gfs2_quota_data **qda) gfs2_write_calc_reserv(ip, sizeof(struct gfs2_quota), &data_blocks, &ind_blocks); - ghs = kcalloc(num_qd, sizeof(struct gfs2_holder), GFP_NOFS); + ghs = kmalloc(num_qd * sizeof(struct gfs2_holder), GFP_NOFS); if (!ghs) return -ENOMEM; diff --git a/fs/gfs2/rgrp.c b/fs/gfs2/rgrp.c index 960aaf4..fba38ca 100644 --- a/fs/gfs2/rgrp.c +++ b/fs/gfs2/rgrp.c @@ -2100,7 +2100,7 @@ void gfs2_inplace_release(struct gfs2_inode *ip) { struct gfs2_blkreserv *rs = &ip->i_res; - if (rs->rs_rgd_gh.gh_gl) + if (gfs2_holder_initialized(&rs->rs_rgd_gh)) gfs2_glock_dq_uninit(&rs->rs_rgd_gh); } @@ -2600,7 +2600,7 @@ void gfs2_rlist_alloc(struct gfs2_rgrp_list *rlist, unsigned int state) { unsigned int x; - rlist->rl_ghs = kcalloc(rlist->rl_rgrps, sizeof(struct gfs2_holder), + rlist->rl_ghs = kmalloc(rlist->rl_rgrps * sizeof(struct gfs2_holder), GFP_NOFS | __GFP_NOFAIL); for (x = 0; x < rlist->rl_rgrps; x++) gfs2_holder_init(rlist->rl_rgd[x]->rd_gl, diff --git a/fs/gfs2/super.c b/fs/gfs2/super.c index 9b2ff353..3a7e60b 100644 --- a/fs/gfs2/super.c +++ b/fs/gfs2/super.c @@ -855,7 +855,7 @@ static int gfs2_make_fs_ro(struct gfs2_sbd *sdp) wait_event(sdp->sd_reserving_log_wait, atomic_read(&sdp->sd_reserving_log) == 0); gfs2_assert_warn(sdp, atomic_read(&sdp->sd_log_blks_free) == sdp->sd_jdesc->jd_blocks); - if (freeze_gh.gh_gl) + if (gfs2_holder_initialized(&freeze_gh)) gfs2_glock_dq_uninit(&freeze_gh); gfs2_quota_cleanup(sdp); @@ -1033,7 +1033,7 @@ static int gfs2_unfreeze(struct super_block *sb) mutex_lock(&sdp->sd_freeze_mutex); if (atomic_read(&sdp->sd_freeze_state) != SFS_FROZEN || - sdp->sd_freeze_gh.gh_gl == NULL) { + !gfs2_holder_initialized(&sdp->sd_freeze_gh)) { mutex_unlock(&sdp->sd_freeze_mutex); return 0; } @@ -1084,9 +1084,11 @@ static int gfs2_statfs_slow(struct gfs2_sbd *sdp, struct gfs2_statfs_change_host int error = 0, err; memset(sc, 0, sizeof(struct gfs2_statfs_change_host)); - gha = kcalloc(slots, sizeof(struct gfs2_holder), GFP_KERNEL); + gha = kmalloc(slots * sizeof(struct gfs2_holder), GFP_KERNEL); if (!gha) return -ENOMEM; + for (x = 0; x < slots; x++) + gfs2_holder_mark_uninitialized(gha + x); rgd_next = gfs2_rgrpd_get_first(sdp); @@ -1096,7 +1098,7 @@ static int gfs2_statfs_slow(struct gfs2_sbd *sdp, struct gfs2_statfs_change_host for (x = 0; x < slots; x++) { gh = gha + x; - if (gh->gh_gl && gfs2_glock_poll(gh)) { + if (gfs2_holder_initialized(gh) && gfs2_glock_poll(gh)) { err = gfs2_glock_wait(gh); if (err) { gfs2_holder_uninit(gh); @@ -1109,7 +1111,7 @@ static int gfs2_statfs_slow(struct gfs2_sbd *sdp, struct gfs2_statfs_change_host } } - if (gh->gh_gl) + if (gfs2_holder_initialized(gh)) done = 0; else if (rgd_next && !error) { error = gfs2_glock_nq_init(rgd_next->rd_gl, @@ -1304,9 +1306,11 @@ static int gfs2_drop_inode(struct inode *inode) { struct gfs2_inode *ip = GFS2_I(inode); - if (!test_bit(GIF_FREE_VFS_INODE, &ip->i_flags) && inode->i_nlink) { + if (!test_bit(GIF_FREE_VFS_INODE, &ip->i_flags) && + inode->i_nlink && + gfs2_holder_initialized(&ip->i_iopen_gh)) { struct gfs2_glock *gl = ip->i_iopen_gh.gh_gl; - if (gl && test_bit(GLF_DEMOTE, &gl->gl_flags)) + if (test_bit(GLF_DEMOTE, &gl->gl_flags)) clear_nlink(inode); } return generic_drop_inode(inode); @@ -1551,7 +1555,7 @@ static void gfs2_evict_inode(struct inode *inode) goto out_truncate; } - if (ip->i_iopen_gh.gh_gl && + if (gfs2_holder_initialized(&ip->i_iopen_gh) && test_bit(HIF_HOLDER, &ip->i_iopen_gh.gh_iflags)) { ip->i_iopen_gh.gh_flags |= GL_NOCACHE; gfs2_glock_dq_wait(&ip->i_iopen_gh); @@ -1610,7 +1614,7 @@ out_unlock: if (gfs2_rs_active(&ip->i_res)) gfs2_rs_deltree(&ip->i_res); - if (ip->i_iopen_gh.gh_gl) { + if (gfs2_holder_initialized(&ip->i_iopen_gh)) { if (test_bit(HIF_HOLDER, &ip->i_iopen_gh.gh_iflags)) { ip->i_iopen_gh.gh_flags |= GL_NOCACHE; gfs2_glock_dq_wait(&ip->i_iopen_gh); @@ -1632,7 +1636,7 @@ out: gfs2_glock_add_to_lru(ip->i_gl); gfs2_glock_put(ip->i_gl); ip->i_gl = NULL; - if (ip->i_iopen_gh.gh_gl) { + if (gfs2_holder_initialized(&ip->i_iopen_gh)) { ip->i_iopen_gh.gh_gl->gl_object = NULL; ip->i_iopen_gh.gh_flags |= GL_NOCACHE; gfs2_glock_dq_wait(&ip->i_iopen_gh); -- cgit v0.10.2 From b4bba38909c21689de21355e84259cb7b38f25ac Mon Sep 17 00:00:00 2001 From: Benjamin Marzinski Date: Mon, 27 Jun 2016 09:58:40 -0500 Subject: fs: export __block_write_full_page gfs2 needs to be able to skip the check to see if a page is outside of the file size when writing it out. gfs2 can get into a situation where it needs to flush its in-memory log to disk while a truncate is in progress. If the file being trucated has data journaling enabled, it is possible that there are data blocks in the log that are past the end of the file. gfs can't finish the log flush without either writing these blocks out or revoking them. Otherwise, if the node crashed, it could overwrite subsequent changes made by other nodes in the cluster when it's journal was replayed. Unfortunately, there is no way to add log entries to the log during a flush. So gfs2 simply writes out the page instead. This situation can only occur when the truncate code still has the file locked exclusively, and hasn't marked this block as free in the metadata (which happens later in truc_dealloc). After gfs2 writes this page out, the truncation code will shortly invalidate it and write out any revokes if necessary. In order to make this work, gfs2 needs to be able to skip the check for writes outside the file size. Since the check exists in block_write_full_page, this patch exports __block_write_full_page, which doesn't have the check. Signed-off-by: Benjamin Marzinski Signed-off-by: Bob Peterson diff --git a/fs/buffer.c b/fs/buffer.c index 754813a..6c15012 100644 --- a/fs/buffer.c +++ b/fs/buffer.c @@ -1687,7 +1687,7 @@ static struct buffer_head *create_page_buffers(struct page *page, struct inode * * WB_SYNC_ALL, the writes are posted using WRITE_SYNC; this * causes the writes to be flagged as synchronous writes. */ -static int __block_write_full_page(struct inode *inode, struct page *page, +int __block_write_full_page(struct inode *inode, struct page *page, get_block_t *get_block, struct writeback_control *wbc, bh_end_io_t *handler) { @@ -1848,6 +1848,7 @@ recover: unlock_page(page); goto done; } +EXPORT_SYMBOL(__block_write_full_page); /* * If a page has any new buffers, zero them out here, and mark them uptodate diff --git a/include/linux/buffer_head.h b/include/linux/buffer_head.h index d48daa3..7e14e54 100644 --- a/include/linux/buffer_head.h +++ b/include/linux/buffer_head.h @@ -208,6 +208,9 @@ void block_invalidatepage(struct page *page, unsigned int offset, unsigned int length); int block_write_full_page(struct page *page, get_block_t *get_block, struct writeback_control *wbc); +int __block_write_full_page(struct inode *inode, struct page *page, + get_block_t *get_block, struct writeback_control *wbc, + bh_end_io_t *handler); int block_read_full_page(struct page*, get_block_t*); int block_is_partially_uptodate(struct page *page, unsigned long from, unsigned long count); -- cgit v0.10.2 From fd4c5748b8d3f7420e8932ed0bde3d53cc8acc9d Mon Sep 17 00:00:00 2001 From: Benjamin Marzinski Date: Mon, 27 Jun 2016 10:01:06 -0500 Subject: gfs2: writeout truncated pages When gfs2 attempts to write a page to a file that is being truncated, and notices that the page is completely outside of the file size, it tries to invalidate it. However, this may require a transaction for journaled data files to revoke any buffers from the page on the active items list. Unfortunately, this can happen inside a log flush, where a transaction cannot be started. Also, gfs2 may need to be able to remove the buffer from the ail1 list before it can finish the log flush. To deal with this, when writing a page of a file with data journalling enabled gfs2 now skips the check to see if the write is outside the file size, and simply writes it anyway. This situation can only occur when the truncate code still has the file locked exclusively, and hasn't marked this block as free in the metadata (which happens later in truc_dealloc). After gfs2 writes this page out, the truncation code will shortly invalidate it and write out any revokes if necessary. To do this, gfs2 now implements its own version of block_write_full_page without the check, and calls the newly exported __block_write_full_page. It also no longer calls gfs2_writepage_common from gfs2_jdata_writepage. Signed-off-by: Benjamin Marzinski Signed-off-by: Bob Peterson diff --git a/fs/gfs2/aops.c b/fs/gfs2/aops.c index 37b7bc1..82df368 100644 --- a/fs/gfs2/aops.c +++ b/fs/gfs2/aops.c @@ -140,6 +140,32 @@ static int gfs2_writepage(struct page *page, struct writeback_control *wbc) return nobh_writepage(page, gfs2_get_block_noalloc, wbc); } +/* This is the same as calling block_write_full_page, but it also + * writes pages outside of i_size + */ +int gfs2_write_full_page(struct page *page, get_block_t *get_block, + struct writeback_control *wbc) +{ + struct inode * const inode = page->mapping->host; + loff_t i_size = i_size_read(inode); + const pgoff_t end_index = i_size >> PAGE_SHIFT; + unsigned offset; + + /* + * The page straddles i_size. It must be zeroed out on each and every + * writepage invocation because it may be mmapped. "A file is mapped + * in multiples of the page size. For a file that is not a multiple of + * the page size, the remaining memory is zeroed when mapped, and + * writes to that region are not written out to the file." + */ + offset = i_size & (PAGE_SIZE-1); + if (page->index == end_index && offset) + zero_user_segment(page, offset, PAGE_SIZE); + + return __block_write_full_page(inode, page, get_block, wbc, + end_buffer_async_write); +} + /** * __gfs2_jdata_writepage - The core of jdata writepage * @page: The page to write @@ -165,7 +191,7 @@ static int __gfs2_jdata_writepage(struct page *page, struct writeback_control *w } gfs2_page_add_databufs(ip, page, 0, sdp->sd_vfs->s_blocksize-1); } - return block_write_full_page(page, gfs2_get_block_noalloc, wbc); + return gfs2_write_full_page(page, gfs2_get_block_noalloc, wbc); } /** @@ -180,27 +206,20 @@ static int __gfs2_jdata_writepage(struct page *page, struct writeback_control *w static int gfs2_jdata_writepage(struct page *page, struct writeback_control *wbc) { struct inode *inode = page->mapping->host; + struct gfs2_inode *ip = GFS2_I(inode); struct gfs2_sbd *sdp = GFS2_SB(inode); int ret; - int done_trans = 0; - if (PageChecked(page)) { - if (wbc->sync_mode != WB_SYNC_ALL) - goto out_ignore; - ret = gfs2_trans_begin(sdp, RES_DINODE + 1, 0); - if (ret) - goto out_ignore; - done_trans = 1; - } - ret = gfs2_writepage_common(page, wbc); - if (ret > 0) - ret = __gfs2_jdata_writepage(page, wbc); - if (done_trans) - gfs2_trans_end(sdp); + if (gfs2_assert_withdraw(sdp, gfs2_glock_is_held_excl(ip->i_gl))) + goto out; + if (PageChecked(page) || current->journal_info) + goto out_ignore; + ret = __gfs2_jdata_writepage(page, wbc); return ret; out_ignore: redirty_page_for_writepage(wbc, page); +out: unlock_page(page); return 0; } -- cgit v0.10.2 From 9f776ba11c8be311a5c23777bc9f3b96498cc6cc Mon Sep 17 00:00:00 2001 From: Neeraj Badlani Date: Mon, 27 Jun 2016 06:59:57 -0700 Subject: perf tools: Update makefile message for installing slang devel package In case of missing library (libslang), give hint to install library (libslang2-dev), since libslang-dev is not provided by Ubuntu. Signed-off-by: Neeraj Badlani Link: http://lkml.kernel.org/r/1467035997-9100-1-git-send-email-neerajbadlani@gmail.com [ removed excessive 'or' usage ] Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/config/Makefile b/tools/perf/config/Makefile index 534c811..bf1a0a0 100644 --- a/tools/perf/config/Makefile +++ b/tools/perf/config/Makefile @@ -482,7 +482,7 @@ endif ifndef NO_SLANG ifneq ($(feature-libslang), 1) - msg := $(warning slang not found, disables TUI support. Please install slang-devel or libslang-dev); + msg := $(warning slang not found, disables TUI support. Please install slang-devel, libslang-dev or libslang2-dev); NO_SLANG := 1 else # Fedora has /usr/include/slang/slang.h, but ubuntu /usr/include/slang.h -- cgit v0.10.2 From 6ef9492915b09816c75bb41e7e37b2e507d2f70f Mon Sep 17 00:00:00 2001 From: "Naveen N. Rao" Date: Fri, 24 Jun 2016 17:23:58 +0530 Subject: perf annotate: Generalize handling of 'ret' instructions Introduce helper to detect 'ret' instructions and use the same in the TUI. A helper is needed since some architectures such as powerpc have more than one return instruction. Signed-off-by: Naveen N. Rao Cc: Ananth N Mavinakayanahalli Cc: Anton Blanchard Cc: Daniel Axtens Cc: Michael Ellerman Link: http://lkml.kernel.org/r/1466769240-12376-5-git-send-email-ravi.bangoria@linux.vnet.ibm.com Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c index 0e106bb..29dc6d2 100644 --- a/tools/perf/ui/browsers/annotate.c +++ b/tools/perf/ui/browsers/annotate.c @@ -223,16 +223,14 @@ static void annotate_browser__write(struct ui_browser *browser, void *entry, int } else if (ins__is_call(dl->ins)) { ui_browser__write_graph(browser, SLSMG_RARROW_CHAR); SLsmg_write_char(' '); + } else if (ins__is_ret(dl->ins)) { + ui_browser__write_graph(browser, SLSMG_LARROW_CHAR); + SLsmg_write_char(' '); } else { ui_browser__write_nstring(browser, " ", 2); } } else { - if (strcmp(dl->name, "retq")) { - ui_browser__write_nstring(browser, " ", 2); - } else { - ui_browser__write_graph(browser, SLSMG_LARROW_CHAR); - SLsmg_write_char(' '); - } + ui_browser__write_nstring(browser, " ", 2); } disasm_line__scnprintf(dl, bf, sizeof(bf), !annotate_browser__opts.use_offset); @@ -843,14 +841,14 @@ show_help: ui_helpline__puts("Huh? No selection. Report to linux-kernel@vger.kernel.org"); else if (browser->selection->offset == -1) ui_helpline__puts("Actions are only available for assembly lines."); - else if (!browser->selection->ins) { - if (strcmp(browser->selection->name, "retq")) - goto show_sup_ins; + else if (!browser->selection->ins) + goto show_sup_ins; + else if (ins__is_ret(browser->selection->ins)) goto out; - } else if (!(annotate_browser__jump(browser) || + else if (!(annotate_browser__jump(browser) || annotate_browser__callq(browser, evsel, hbt))) { show_sup_ins: - ui_helpline__puts("Actions are only available for 'callq', 'retq' & jump instructions."); + ui_helpline__puts("Actions are only available for function call/return & jump/branch instructions."); } continue; case 't': diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index b2c7ae4..c385fec 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -354,6 +354,15 @@ static struct ins_ops nop_ops = { .scnprintf = nop__scnprintf, }; +static struct ins_ops ret_ops = { + .scnprintf = ins__raw_scnprintf, +}; + +bool ins__is_ret(const struct ins *ins) +{ + return ins->ops == &ret_ops; +} + static struct ins instructions[] = { { .name = "add", .ops = &mov_ops, }, { .name = "addl", .ops = &mov_ops, }, @@ -444,6 +453,7 @@ static struct ins instructions[] = { { .name = "xadd", .ops = &mov_ops, }, { .name = "xbeginl", .ops = &jump_ops, }, { .name = "xbeginq", .ops = &jump_ops, }, + { .name = "retq", .ops = &ret_ops, }, }; static int ins__key_cmp(const void *name, const void *insp) diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h index 82f3781..a23084f 100644 --- a/tools/perf/util/annotate.h +++ b/tools/perf/util/annotate.h @@ -48,6 +48,7 @@ struct ins { bool ins__is_jump(const struct ins *ins); bool ins__is_call(const struct ins *ins); +bool ins__is_ret(const struct ins *ins); int ins__scnprintf(struct ins *ins, char *bf, size_t size, struct ins_operands *ops); struct annotation; -- cgit v0.10.2 From 78f69b5865dbb7cc87fe18fb98212e23b10b5cbd Mon Sep 17 00:00:00 2001 From: Ravi Bangoria Date: Fri, 24 Jun 2016 17:24:00 +0530 Subject: perf tools: Add more toolchain triplets Add few more triplets based on Fedora and Ubuntu binutils (cross tools). Before applying patch on x86: ( Install binutils-powerpc64-linux-gnu.x86_64 ) $ perf report -i perf.data.powerpc --vmlinux vmlinux.powerpc \ --objdump powerpc64-linux-gnu-objdump After applying patch on x86: $ perf report -i perf.data.powerpc --vmlinux vmlinux.powerpc I.e. it will find the right objdump from the environment data recorded in the perf.data file + these triplets. Signed-off-by: Ravi Bangoria Cc: Ananth N Mavinakayanahalli Cc: Anton Blanchard Cc: Daniel Axtens Cc: Michael Ellerman Link: http://lkml.kernel.org/r/1466769240-12376-7-git-send-email-ravi.bangoria@linux.vnet.ibm.com Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/arch/common.c b/tools/perf/arch/common.c index fa090a9..ee69668 100644 --- a/tools/perf/arch/common.c +++ b/tools/perf/arch/common.c @@ -9,34 +9,44 @@ const char *const arm_triplets[] = { "arm-unknown-linux-", "arm-unknown-linux-gnu-", "arm-unknown-linux-gnueabi-", + "arm-linux-gnu-", + "arm-linux-gnueabihf-", + "arm-none-eabi-", NULL }; const char *const arm64_triplets[] = { "aarch64-linux-android-", + "aarch64-linux-gnu-", NULL }; const char *const powerpc_triplets[] = { "powerpc-unknown-linux-gnu-", "powerpc64-unknown-linux-gnu-", + "powerpc64-linux-gnu-", + "powerpc64le-linux-gnu-", NULL }; const char *const s390_triplets[] = { "s390-ibm-linux-", + "s390x-linux-gnu-", NULL }; const char *const sh_triplets[] = { "sh-unknown-linux-gnu-", "sh64-unknown-linux-gnu-", + "sh-linux-gnu-", + "sh64-linux-gnu-", NULL }; const char *const sparc_triplets[] = { "sparc-unknown-linux-gnu-", "sparc64-unknown-linux-gnu-", + "sparc64-linux-gnu-", NULL }; @@ -49,12 +59,19 @@ const char *const x86_triplets[] = { "i386-pc-linux-gnu-", "i686-linux-android-", "i686-android-linux-", + "x86_64-linux-gnu-", + "i586-linux-gnu-", NULL }; const char *const mips_triplets[] = { "mips-unknown-linux-gnu-", "mipsel-linux-android-", + "mips-linux-gnu-", + "mips64-linux-gnu-", + "mips64el-linux-gnuabi64-", + "mips64-linux-gnuabi64-", + "mipsel-linux-gnu-", NULL }; -- cgit v0.10.2 From 3b8e73ec822cecf62e68e12c5320cf329d69923a Mon Sep 17 00:00:00 2001 From: Crestez Dan Leonard Date: Mon, 23 May 2016 21:40:01 +0300 Subject: iio: Refuse to register triggers with duplicate names The trigger name is documented as unique but drivers are currently allowed to register triggers with duplicate names. This should be considered a bug since it makes the 'current_trigger' interface unusable. Signed-off-by: Crestez Dan Leonard Signed-off-by: Jonathan Cameron diff --git a/drivers/iio/industrialio-trigger.c b/drivers/iio/industrialio-trigger.c index 6729112..b3ca308 100644 --- a/drivers/iio/industrialio-trigger.c +++ b/drivers/iio/industrialio-trigger.c @@ -64,6 +64,8 @@ static struct attribute *iio_trig_dev_attrs[] = { }; ATTRIBUTE_GROUPS(iio_trig_dev); +static struct iio_trigger *__iio_trigger_find_by_name(const char *name); + int iio_trigger_register(struct iio_trigger *trig_info) { int ret; @@ -86,11 +88,19 @@ int iio_trigger_register(struct iio_trigger *trig_info) /* Add to list of available triggers held by the IIO core */ mutex_lock(&iio_trigger_list_lock); + if (__iio_trigger_find_by_name(trig_info->name)) { + pr_err("Duplicate trigger name '%s'\n", trig_info->name); + ret = -EEXIST; + goto error_device_del; + } list_add_tail(&trig_info->list, &iio_trigger_list); mutex_unlock(&iio_trigger_list_lock); return 0; +error_device_del: + mutex_unlock(&iio_trigger_list_lock); + device_del(&trig_info->dev); error_unregister_id: ida_simple_remove(&iio_trigger_ida, trig_info->id); return ret; @@ -109,6 +119,18 @@ void iio_trigger_unregister(struct iio_trigger *trig_info) } EXPORT_SYMBOL(iio_trigger_unregister); +/* Search for trigger by name, assuming iio_trigger_list_lock held */ +static struct iio_trigger *__iio_trigger_find_by_name(const char *name) +{ + struct iio_trigger *iter; + + list_for_each_entry(iter, &iio_trigger_list, list) + if (!strcmp(iter->name, name)) + return iter; + + return NULL; +} + static struct iio_trigger *iio_trigger_find_by_name(const char *name, size_t len) { -- cgit v0.10.2 From 7feae871b263b509625b3bf946d4f1d72bb77c70 Mon Sep 17 00:00:00 2001 From: Dan O'Donovan Date: Fri, 27 May 2016 18:37:30 +0100 Subject: iio: adc: ti-adc081c: add ACPI device ID matching Add ACPI device ID matching for TI ADC081C/ADC101C/ADC121C ADCs. Signed-off-by: Dan O'Donovan Signed-off-by: Jonathan Cameron diff --git a/drivers/iio/adc/ti-adc081c.c b/drivers/iio/adc/ti-adc081c.c index 9fd032d..f8807ad 100644 --- a/drivers/iio/adc/ti-adc081c.c +++ b/drivers/iio/adc/ti-adc081c.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include @@ -149,12 +150,24 @@ static int adc081c_probe(struct i2c_client *client, { struct iio_dev *iio; struct adc081c *adc; - struct adcxx1c_model *model = &adcxx1c_models[id->driver_data]; + struct adcxx1c_model *model; int err; if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WORD_DATA)) return -EOPNOTSUPP; + if (ACPI_COMPANION(&client->dev)) { + const struct acpi_device_id *ad_id; + + ad_id = acpi_match_device(client->dev.driver->acpi_match_table, + &client->dev); + if (!ad_id) + return -ENODEV; + model = &adcxx1c_models[ad_id->driver_data]; + } else { + model = &adcxx1c_models[id->driver_data]; + } + iio = devm_iio_device_alloc(&client->dev, sizeof(*adc)); if (!iio) return -ENOMEM; @@ -231,10 +244,21 @@ static const struct of_device_id adc081c_of_match[] = { MODULE_DEVICE_TABLE(of, adc081c_of_match); #endif +#ifdef CONFIG_ACPI +static const struct acpi_device_id adc081c_acpi_match[] = { + { "ADC081C", ADC081C }, + { "ADC101C", ADC101C }, + { "ADC121C", ADC121C }, + { } +}; +MODULE_DEVICE_TABLE(acpi, adc081c_acpi_match); +#endif + static struct i2c_driver adc081c_driver = { .driver = { .name = "adc081c", .of_match_table = of_match_ptr(adc081c_of_match), + .acpi_match_table = ACPI_PTR(adc081c_acpi_match), }, .probe = adc081c_probe, .remove = adc081c_remove, -- cgit v0.10.2 From aea7b1dc2bb7405f2d7827b202788fbee3912c1a Mon Sep 17 00:00:00 2001 From: Luis de Bethencourt Date: Wed, 22 Jun 2016 20:43:31 +0100 Subject: staging: iio: accel: add error check Go to error_ret if sca3000_read_ctrl_reg() failed. Signed-off-by: Luis de Bethencourt Signed-off-by: Jonathan Cameron diff --git a/drivers/staging/iio/accel/sca3000_core.c b/drivers/staging/iio/accel/sca3000_core.c index a8f533a..53c5425 100644 --- a/drivers/staging/iio/accel/sca3000_core.c +++ b/drivers/staging/iio/accel/sca3000_core.c @@ -1046,6 +1046,8 @@ static int sca3000_clean_setup(struct sca3000_state *st) /* Disable ring buffer */ ret = sca3000_read_ctrl_reg(st, SCA3000_REG_CTRL_SEL_OUT_CTRL); + if (ret < 0) + goto error_ret; ret = sca3000_write_ctrl_reg(st, SCA3000_REG_CTRL_SEL_OUT_CTRL, (ret & SCA3000_OUT_CTRL_PROT_MASK) | SCA3000_OUT_CTRL_BUF_X_EN -- cgit v0.10.2 From 22ed1a1c1cceebff380b3f6f84d520a0b398509a Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Mon, 30 May 2016 16:52:04 +0200 Subject: iio: as3935: improve error reporting in as3935_event_work MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit gcc warns about a potentially uninitialized variable use in as3935_event_work: drivers/iio/proximity/as3935.c: In function ‘as3935_event_work’: drivers/iio/proximity/as3935.c:231:6: error: ‘val’ may be used uninitialized in this function [-Werror=maybe-uninitialized] This case specifically happens when spi_w8r8() fails with a negative return code. We check all other users of this function except this one. As the error is rather unlikely to happen after the device has already been initialized, this just adds a dev_warn(). Another warning already exists in the same function, but is missing a trailing '\n' character, so I'm fixing that too. Signed-off-by: Arnd Bergmann Reviewed-by: Matt Ranostay Signed-off-by: Jonathan Cameron diff --git a/drivers/iio/proximity/as3935.c b/drivers/iio/proximity/as3935.c index c12fde2..a9d5847 100644 --- a/drivers/iio/proximity/as3935.c +++ b/drivers/iio/proximity/as3935.c @@ -224,10 +224,16 @@ static void as3935_event_work(struct work_struct *work) { struct as3935_state *st; int val; + int ret; st = container_of(work, struct as3935_state, work.work); - as3935_read(st, AS3935_INT, &val); + ret = as3935_read(st, AS3935_INT, &val); + if (ret) { + dev_warn(&st->spi->dev, "read error\n"); + return; + } + val &= AS3935_INT_MASK; switch (val) { @@ -235,7 +241,7 @@ static void as3935_event_work(struct work_struct *work) iio_trigger_poll(st->trig); break; case AS3935_NOISE_INT: - dev_warn(&st->spi->dev, "noise level is too high"); + dev_warn(&st->spi->dev, "noise level is too high\n"); break; } } -- cgit v0.10.2 From 765550e4d98d8f5931a3863781acb7c6b995161c Mon Sep 17 00:00:00 2001 From: William Breathitt Gray Date: Mon, 13 Jun 2016 09:06:48 -0400 Subject: iio: stx104: Add GPIO support for the Apex Embedded Systems STX104 The Apex Embedded Systems STX104 device features eight lines of digital I/O (four digital inputs and four digital outputs). This patch adds GPIO support for these eight lines of digital I/O via GPIOLIB. Cc: Alexandre Courbot Signed-off-by: William Breathitt Gray Reviewed-by: Linus Walleij Signed-off-by: Jonathan Cameron diff --git a/drivers/iio/dac/Kconfig b/drivers/iio/dac/Kconfig index 61d5008..b3feb0bf 100644 --- a/drivers/iio/dac/Kconfig +++ b/drivers/iio/dac/Kconfig @@ -246,13 +246,14 @@ config MCP4922 will be called mcp4922. config STX104 - tristate "Apex Embedded Systems STX104 DAC driver" + tristate "Apex Embedded Systems STX104 driver" depends on ISA + select GPIOLIB help - Say yes here to build support for the 2-channel DAC on the Apex - Embedded Systems STX104 integrated analog PC/104 card. The base port - addresses for the devices may be configured via the "base" module - parameter array. + Say yes here to build support for the 2-channel DAC and GPIO on the + Apex Embedded Systems STX104 integrated analog PC/104 card. The base + port addresses for the devices may be configured via the base array + module parameter. config VF610_DAC tristate "Vybrid vf610 DAC driver" diff --git a/drivers/iio/dac/stx104.c b/drivers/iio/dac/stx104.c index 174f4b7..e0f31a1 100644 --- a/drivers/iio/dac/stx104.c +++ b/drivers/iio/dac/stx104.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -21,6 +22,7 @@ #include #include #include +#include #define STX104_NUM_CHAN 2 @@ -56,6 +58,20 @@ struct stx104_iio { unsigned base; }; +/** + * struct stx104_gpio - GPIO device private data structure + * @chip: instance of the gpio_chip + * @lock: synchronization lock to prevent I/O race conditions + * @base: base port address of the GPIO device + * @out_state: output bits state + */ +struct stx104_gpio { + struct gpio_chip chip; + spinlock_t lock; + unsigned int base; + unsigned int out_state; +}; + static int stx104_read_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int *val, int *val2, long mask) { @@ -95,15 +111,81 @@ static const struct iio_chan_spec stx104_channels[STX104_NUM_CHAN] = { STX104_CHAN(1) }; +static int stx104_gpio_get_direction(struct gpio_chip *chip, + unsigned int offset) +{ + if (offset < 4) + return 1; + + return 0; +} + +static int stx104_gpio_direction_input(struct gpio_chip *chip, + unsigned int offset) +{ + if (offset >= 4) + return -EINVAL; + + return 0; +} + +static int stx104_gpio_direction_output(struct gpio_chip *chip, + unsigned int offset, int value) +{ + if (offset < 4) + return -EINVAL; + + chip->set(chip, offset, value); + return 0; +} + +static int stx104_gpio_get(struct gpio_chip *chip, unsigned int offset) +{ + struct stx104_gpio *const stx104gpio = gpiochip_get_data(chip); + + if (offset >= 4) + return -EINVAL; + + return !!(inb(stx104gpio->base) & BIT(offset)); +} + +static void stx104_gpio_set(struct gpio_chip *chip, unsigned int offset, + int value) +{ + struct stx104_gpio *const stx104gpio = gpiochip_get_data(chip); + const unsigned int mask = BIT(offset) >> 4; + unsigned long flags; + + if (offset < 4) + return; + + spin_lock_irqsave(&stx104gpio->lock, flags); + + if (value) + stx104gpio->out_state |= mask; + else + stx104gpio->out_state &= ~mask; + + outb(stx104gpio->out_state, stx104gpio->base); + + spin_unlock_irqrestore(&stx104gpio->lock, flags); +} + static int stx104_probe(struct device *dev, unsigned int id) { struct iio_dev *indio_dev; struct stx104_iio *priv; + struct stx104_gpio *stx104gpio; + int err; indio_dev = devm_iio_device_alloc(dev, sizeof(*priv)); if (!indio_dev) return -ENOMEM; + stx104gpio = devm_kzalloc(dev, sizeof(*stx104gpio), GFP_KERNEL); + if (!stx104gpio) + return -ENOMEM; + if (!devm_request_region(dev, base[id], STX104_EXTENT, dev_name(dev))) { dev_err(dev, "Unable to lock port addresses (0x%X-0x%X)\n", @@ -124,14 +206,53 @@ static int stx104_probe(struct device *dev, unsigned int id) outw(0, base[id] + 4); outw(0, base[id] + 6); - return devm_iio_device_register(dev, indio_dev); + err = devm_iio_device_register(dev, indio_dev); + if (err) { + dev_err(dev, "IIO device registering failed (%d)\n", err); + return err; + } + + stx104gpio->chip.label = dev_name(dev); + stx104gpio->chip.parent = dev; + stx104gpio->chip.owner = THIS_MODULE; + stx104gpio->chip.base = -1; + stx104gpio->chip.ngpio = 8; + stx104gpio->chip.get_direction = stx104_gpio_get_direction; + stx104gpio->chip.direction_input = stx104_gpio_direction_input; + stx104gpio->chip.direction_output = stx104_gpio_direction_output; + stx104gpio->chip.get = stx104_gpio_get; + stx104gpio->chip.set = stx104_gpio_set; + stx104gpio->base = base[id] + 3; + stx104gpio->out_state = 0x0; + + spin_lock_init(&stx104gpio->lock); + + dev_set_drvdata(dev, stx104gpio); + + err = gpiochip_add_data(&stx104gpio->chip, stx104gpio); + if (err) { + dev_err(dev, "GPIO registering failed (%d)\n", err); + return err; + } + + return 0; +} + +static int stx104_remove(struct device *dev, unsigned int id) +{ + struct stx104_gpio *const stx104gpio = dev_get_drvdata(dev); + + gpiochip_remove(&stx104gpio->chip); + + return 0; } static struct isa_driver stx104_driver = { .probe = stx104_probe, .driver = { .name = "stx104" - } + }, + .remove = stx104_remove }; static void __exit stx104_exit(void) -- cgit v0.10.2 From 4d462b85e727d482e6fa95252b909f3fce6851e0 Mon Sep 17 00:00:00 2001 From: Matt Ranostay Date: Wed, 15 Jun 2016 18:47:02 -0700 Subject: iio: proximity: as3935: remove redundant zeroing of tune_cap This is redundant as the containing stucture is allocated as part of iio_device_alloc using kzalloc and hence is already 0. Signed-off-by: Matt Ranostay Signed-off-by: Jonathan Cameron diff --git a/drivers/iio/proximity/as3935.c b/drivers/iio/proximity/as3935.c index a9d5847..0566cb4 100644 --- a/drivers/iio/proximity/as3935.c +++ b/drivers/iio/proximity/as3935.c @@ -345,7 +345,6 @@ static int as3935_probe(struct spi_device *spi) st = iio_priv(indio_dev); st->spi = spi; - st->tune_cap = 0; spi_set_drvdata(spi, indio_dev); mutex_init(&st->lock); -- cgit v0.10.2 From c48c7b2e470ede9bfae2bff3ab8ba1fe5e832f64 Mon Sep 17 00:00:00 2001 From: Florian Vaussard Date: Tue, 21 Jun 2016 09:09:27 +0200 Subject: iio: adc: max1363: Fix missing i2c_device_id for MAX1164x parts The driver supports MAX11644, MAX11645, MAX11646 and MAX11647 parts. But the corresponding i2c_device_id are missing. Add them! Signed-off-by: Florian Vaussard Signed-off-by: Jonathan Cameron diff --git a/drivers/iio/adc/max1363.c b/drivers/iio/adc/max1363.c index 929508e..b5d28c0 100644 --- a/drivers/iio/adc/max1363.c +++ b/drivers/iio/adc/max1363.c @@ -1680,6 +1680,10 @@ static const struct i2c_device_id max1363_id[] = { { "max11615", max11615 }, { "max11616", max11616 }, { "max11617", max11617 }, + { "max11644", max11644 }, + { "max11645", max11645 }, + { "max11646", max11646 }, + { "max11647", max11647 }, {} }; -- cgit v0.10.2 From 29e3e06d893105febb9c9ccaff856fcdcbe3f712 Mon Sep 17 00:00:00 2001 From: Phil Reid Date: Mon, 27 Jun 2016 11:17:56 +0800 Subject: iio: buffer-dma: Use ARRAY_SIZE in for loop range Use the ARRAY_SIZE macro in the for loops that access queue->fileio.blocks. Macro is already used in a couple of places where this access occurs, but range was hardcoded in these locations. Signed-off-by: Phil Reid Acked-by: Lars-Peter Clausen Signed-off-by: Jonathan Cameron diff --git a/drivers/iio/buffer/industrialio-buffer-dma.c b/drivers/iio/buffer/industrialio-buffer-dma.c index 212cbed..dd99d27 100644 --- a/drivers/iio/buffer/industrialio-buffer-dma.c +++ b/drivers/iio/buffer/industrialio-buffer-dma.c @@ -305,7 +305,7 @@ int iio_dma_buffer_request_update(struct iio_buffer *buffer) queue->fileio.active_block = NULL; spin_lock_irq(&queue->list_lock); - for (i = 0; i < 2; i++) { + for (i = 0; i < ARRAY_SIZE(queue->fileio.blocks); i++) { block = queue->fileio.blocks[i]; /* If we can't re-use it free it */ @@ -323,7 +323,7 @@ int iio_dma_buffer_request_update(struct iio_buffer *buffer) INIT_LIST_HEAD(&queue->incoming); - for (i = 0; i < 2; i++) { + for (i = 0; i < ARRAY_SIZE(queue->fileio.blocks); i++) { if (queue->fileio.blocks[i]) { block = queue->fileio.blocks[i]; if (block->state == IIO_BLOCK_STATE_DEAD) { -- cgit v0.10.2 From c947459979c6c9c8aff9c9b5027b31dbf8055106 Mon Sep 17 00:00:00 2001 From: Sean Nyekjaer Date: Mon, 27 Jun 2016 10:27:17 +0200 Subject: iio: ad5755: add support for dt bindings Devicetree can provide platform data Signed-off-by: Sean Nyekjaer Signed-off-by: Jonathan Cameron diff --git a/drivers/iio/dac/ad5755.c b/drivers/iio/dac/ad5755.c index bfb350a..0fde593 100644 --- a/drivers/iio/dac/ad5755.c +++ b/drivers/iio/dac/ad5755.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -109,6 +110,51 @@ enum ad5755_type { ID_AD5737, }; +#ifdef CONFIG_OF +static const int ad5755_dcdc_freq_table[][2] = { + { 250000, AD5755_DC_DC_FREQ_250kHZ }, + { 410000, AD5755_DC_DC_FREQ_410kHZ }, + { 650000, AD5755_DC_DC_FREQ_650kHZ } +}; + +static const int ad5755_dcdc_maxv_table[][2] = { + { 23000000, AD5755_DC_DC_MAXV_23V }, + { 24500000, AD5755_DC_DC_MAXV_24V5 }, + { 27000000, AD5755_DC_DC_MAXV_27V }, + { 29500000, AD5755_DC_DC_MAXV_29V5 }, +}; + +static const int ad5755_slew_rate_table[][2] = { + { 64000, AD5755_SLEW_RATE_64k }, + { 32000, AD5755_SLEW_RATE_32k }, + { 16000, AD5755_SLEW_RATE_16k }, + { 8000, AD5755_SLEW_RATE_8k }, + { 4000, AD5755_SLEW_RATE_4k }, + { 2000, AD5755_SLEW_RATE_2k }, + { 1000, AD5755_SLEW_RATE_1k }, + { 500, AD5755_SLEW_RATE_500 }, + { 250, AD5755_SLEW_RATE_250 }, + { 125, AD5755_SLEW_RATE_125 }, + { 64, AD5755_SLEW_RATE_64 }, + { 32, AD5755_SLEW_RATE_32 }, + { 16, AD5755_SLEW_RATE_16 }, + { 8, AD5755_SLEW_RATE_8 }, + { 4, AD5755_SLEW_RATE_4 }, + { 0, AD5755_SLEW_RATE_0_5 }, +}; + +static const int ad5755_slew_step_table[][2] = { + { 256, AD5755_SLEW_STEP_SIZE_256 }, + { 128, AD5755_SLEW_STEP_SIZE_128 }, + { 64, AD5755_SLEW_STEP_SIZE_64 }, + { 32, AD5755_SLEW_STEP_SIZE_32 }, + { 16, AD5755_SLEW_STEP_SIZE_16 }, + { 4, AD5755_SLEW_STEP_SIZE_4 }, + { 2, AD5755_SLEW_STEP_SIZE_2 }, + { 1, AD5755_SLEW_STEP_SIZE_1 }, +}; +#endif + static int ad5755_write_unlocked(struct iio_dev *indio_dev, unsigned int reg, unsigned int val) { @@ -556,6 +602,129 @@ static const struct ad5755_platform_data ad5755_default_pdata = { }, }; +#ifdef CONFIG_OF +static struct ad5755_platform_data *ad5755_parse_dt(struct device *dev) +{ + struct device_node *np = dev->of_node; + struct device_node *pp; + struct ad5755_platform_data *pdata; + unsigned int tmp; + unsigned int tmparray[3]; + int devnr, i; + + pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); + if (!pdata) + return NULL; + + pdata->ext_dc_dc_compenstation_resistor = + of_property_read_bool(np, "adi,ext-dc-dc-compenstation-resistor"); + + if (!of_property_read_u32(np, "adi,dc-dc-phase", &tmp)) + pdata->dc_dc_phase = tmp; + else + pdata->dc_dc_phase = AD5755_DC_DC_PHASE_ALL_SAME_EDGE; + + pdata->dc_dc_freq = AD5755_DC_DC_FREQ_410kHZ; + if (!of_property_read_u32(np, "adi,dc-dc-freq-hz", &tmp)) { + for (i = 0; i < ARRAY_SIZE(ad5755_dcdc_freq_table); i++) { + if (tmp == ad5755_dcdc_freq_table[i][0]) { + pdata->dc_dc_freq = ad5755_dcdc_freq_table[i][1]; + break; + } + } + + if (i == ARRAY_SIZE(ad5755_dcdc_freq_table)) { + dev_err(dev, + "adi,dc-dc-freq out of range selecting 410kHz"); + } + } + + pdata->dc_dc_maxv = AD5755_DC_DC_MAXV_23V; + if (!of_property_read_u32(np, "adi,dc-dc-max-microvolt", &tmp)) { + for (i = 0; i < ARRAY_SIZE(ad5755_dcdc_maxv_table); i++) { + if (tmp == ad5755_dcdc_maxv_table[i][0]) { + pdata->dc_dc_maxv = ad5755_dcdc_maxv_table[i][1]; + break; + } + } + if (i == ARRAY_SIZE(ad5755_dcdc_maxv_table)) { + dev_err(dev, + "adi,dc-dc-maxv out of range selecting 23V"); + } + } + + devnr = 0; + for_each_child_of_node(np, pp) { + if (devnr > AD5755_NUM_CHANNELS) { + dev_err(dev, + "There is to many channels defined in DT\n"); + goto error_out; + } + + if (!of_property_read_u32(pp, "adi,mode", &tmp)) + pdata->dac[devnr].mode = tmp; + else + pdata->dac[devnr].mode = AD5755_MODE_CURRENT_4mA_20mA; + + pdata->dac[devnr].ext_current_sense_resistor = + of_property_read_bool(pp, "adi,ext-current-sense-resistor"); + + pdata->dac[devnr].enable_voltage_overrange = + of_property_read_bool(pp, "adi,enable-voltage-overrange"); + + if (!of_property_read_u32_array(pp, "adi,slew", tmparray, 3)) { + pdata->dac[devnr].slew.enable = tmparray[0]; + + pdata->dac[devnr].slew.rate = AD5755_SLEW_RATE_64k; + for (i = 0; i < ARRAY_SIZE(ad5755_slew_rate_table); i++) { + if (tmparray[1] == ad5755_slew_rate_table[i][0]) { + pdata->dac[devnr].slew.rate = + ad5755_slew_rate_table[i][1]; + break; + } + } + if (i == ARRAY_SIZE(ad5755_slew_rate_table)) { + dev_err(dev, + "channel %d slew rate out of range selecting 64kHz", + devnr); + } + + pdata->dac[devnr].slew.step_size = AD5755_SLEW_STEP_SIZE_1; + for (i = 0; i < ARRAY_SIZE(ad5755_slew_step_table); i++) { + if (tmparray[2] == ad5755_slew_step_table[i][0]) { + pdata->dac[devnr].slew.step_size = + ad5755_slew_step_table[i][1]; + break; + } + } + if (i == ARRAY_SIZE(ad5755_slew_step_table)) { + dev_err(dev, + "channel %d slew step size out of range selecting 1 LSB", + devnr); + } + } else { + pdata->dac[devnr].slew.enable = false; + pdata->dac[devnr].slew.rate = AD5755_SLEW_RATE_64k; + pdata->dac[devnr].slew.step_size = + AD5755_SLEW_STEP_SIZE_1; + } + devnr++; + } + + return pdata; + + error_out: + devm_kfree(dev, pdata); + return NULL; +} +#else +static +struct ad5755_platform_data *ad5755_parse_dt(struct device *dev) +{ + return NULL; +} +#endif + static int ad5755_probe(struct spi_device *spi) { enum ad5755_type type = spi_get_device_id(spi)->driver_data; @@ -583,8 +752,15 @@ static int ad5755_probe(struct spi_device *spi) indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->num_channels = AD5755_NUM_CHANNELS; - if (!pdata) + if (spi->dev.of_node) + pdata = ad5755_parse_dt(&spi->dev); + else + pdata = spi->dev.platform_data; + + if (!pdata) { + dev_warn(&spi->dev, "no platform data? using default\n"); pdata = &ad5755_default_pdata; + } ret = ad5755_init_channels(indio_dev, pdata); if (ret) @@ -607,6 +783,16 @@ static const struct spi_device_id ad5755_id[] = { }; MODULE_DEVICE_TABLE(spi, ad5755_id); +static const struct of_device_id ad5755_of_match[] = { + { .compatible = "adi,ad5755" }, + { .compatible = "adi,ad5755-1" }, + { .compatible = "adi,ad5757" }, + { .compatible = "adi,ad5735" }, + { .compatible = "adi,ad5737" }, + { } +}; +MODULE_DEVICE_TABLE(of, ad5755_of_match); + static struct spi_driver ad5755_driver = { .driver = { .name = "ad5755", -- cgit v0.10.2 From 67626cc1a0f7bd6700b6f2f547244382247f5bb3 Mon Sep 17 00:00:00 2001 From: Sean Nyekjaer Date: Mon, 27 Jun 2016 10:27:18 +0200 Subject: iio: ad5755: Add DT binding documentation Signed-off-by: Sean Nyekjaer Acked-by: Rob Herring Signed-off-by: Jonathan Cameron diff --git a/Documentation/devicetree/bindings/iio/dac/ad5755.txt b/Documentation/devicetree/bindings/iio/dac/ad5755.txt new file mode 100644 index 0000000..f0bbd7e --- /dev/null +++ b/Documentation/devicetree/bindings/iio/dac/ad5755.txt @@ -0,0 +1,124 @@ +* Analog Device AD5755 IIO Multi-Channel DAC Linux Driver + +Required properties: + - compatible: Has to contain one of the following: + adi,ad5755 + adi,ad5755-1 + adi,ad5757 + adi,ad5735 + adi,ad5737 + + - reg: spi chip select number for the device + - spi-cpha or spi-cpol: is the only modes that is supported + +Recommended properties: + - spi-max-frequency: Definition as per + Documentation/devicetree/bindings/spi/spi-bus.txt + +Optional properties: +See include/dt-bindings/iio/ad5755.h + - adi,ext-dc-dc-compenstation-resistor: boolean set if the hardware have an + external resistor and thereby bypasses + the internal compensation resistor. + - adi,dc-dc-phase: + Valid values for DC DC Phase control is: + 0: All dc-to-dc converters clock on the same edge. + 1: Channel A and Channel B clock on the same edge, + Channel C and Channel D clock on opposite edges. + 2: Channel A and Channel C clock on the same edge, + Channel B and Channel D clock on opposite edges. + 3: Channel A, Channel B, Channel C, and Channel D + clock 90 degrees out of phase from each other. + - adi,dc-dc-freq-hz: + Valid values for DC DC frequency is [Hz]: + 250000 + 410000 + 650000 + - adi,dc-dc-max-microvolt: + Valid values for the maximum allowed Vboost voltage supplied by + the dc-to-dc converter is: + 23000000 + 24500000 + 27000000 + 29500000 + +Optional for every channel: + - adi,mode: + Valid values for DAC modes is: + 0: 0 V to 5 V voltage range. + 1: 0 V to 10 V voltage range. + 2: Plus minus 5 V voltage range. + 3: Plus minus 10 V voltage range. + 4: 4 mA to 20 mA current range. + 5: 0 mA to 20 mA current range. + 6: 0 mA to 24 mA current range. + - adi,ext-current-sense-resistor: boolean set if the hardware a external + current sense resistor. + - adi,enable-voltage-overrange: boolean enable voltage overrange + - adi,slew: Array of slewrate settings should contain 3 fields: + 1: Should be either 0 or 1 in order to enable or disable slewrate. + 2: Slew rate settings: + Valid values for the slew rate update frequency: + 64000 + 32000 + 16000 + 8000 + 4000 + 2000 + 1000 + 500 + 250 + 125 + 64 + 32 + 16 + 8 + 4 + 0 + 3: Slew step size: + Valid values for the step size LSBs: + 1 + 2 + 4 + 16 + 32 + 64 + 128 + 256 + +Example: +dac@0 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "adi,ad5755"; + reg = <0>; + spi-max-frequency = <1000000>; + spi-cpha; + adi,dc-dc-phase = <0>; + adi,dc-dc-freq-hz = <410000>; + adi,dc-dc-max-microvolt = <23000000>; + channel@0 { + reg = <0>; + adi,mode = <4>; + adi,ext-current-sense-resistor; + adi,slew = <0 64000 1>; + }; + channel@1 { + reg = <1>; + adi,mode = <4>; + adi,ext-current-sense-resistor; + adi,slew = <0 64000 1>; + }; + channel@2 { + reg = <2>; + adi,mode = <4>; + adi,ext-current-sense-resistor; + adi,slew = <0 64000 1>; + }; + channel@3 { + reg = <3>; + adi,mode = <4>; + adi,ext-current-sense-resistor; + adi,slew = <0 64000 1>; + }; +}; -- cgit v0.10.2 From 9c6795a9b3cbb56a9fbfaf43909c5c22999ba317 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Mon, 27 Jun 2016 21:06:51 +0200 Subject: ALSA: echoaudio: Fix memory allocation 'commpage_bak' is allocated with 'sizeof(struct echoaudio)' bytes. We then copy 'sizeof(struct comm_page)' bytes in it. On my system, smatch complains because one is 2960 and the other is 3072. This would result in memory corruption or a oops. Signed-off-by: Christophe JAILLET Cc: Signed-off-by: Takashi Iwai diff --git a/sound/pci/echoaudio/echoaudio.c b/sound/pci/echoaudio/echoaudio.c index 1cb85ae..286f5e3 100644 --- a/sound/pci/echoaudio/echoaudio.c +++ b/sound/pci/echoaudio/echoaudio.c @@ -2200,11 +2200,11 @@ static int snd_echo_resume(struct device *dev) u32 pipe_alloc_mask; int err; - commpage_bak = kmalloc(sizeof(struct echoaudio), GFP_KERNEL); + commpage_bak = kmalloc(sizeof(*commpage), GFP_KERNEL); if (commpage_bak == NULL) return -ENOMEM; commpage = chip->comm_page; - memcpy(commpage_bak, commpage, sizeof(struct comm_page)); + memcpy(commpage_bak, commpage, sizeof(*commpage)); err = init_hw(chip, chip->pci->device, chip->pci->subsystem_device); if (err < 0) { -- cgit v0.10.2 From b6757042200f8c876be99213712f4a101334e203 Mon Sep 17 00:00:00 2001 From: Andrea Gelmini Date: Sat, 21 May 2016 13:41:00 +0200 Subject: hwmon: (abituguru) Fix typos in documentation Signed-off-by: Andrea Gelmini [groeck: Updated subject] Signed-off-by: Guenter Roeck diff --git a/Documentation/hwmon/abituguru b/Documentation/hwmon/abituguru index f1d4fe4..44013d2 100644 --- a/Documentation/hwmon/abituguru +++ b/Documentation/hwmon/abituguru @@ -24,7 +24,7 @@ Supported chips: AW9D-MAX) (2) 1) For revisions 2 and 3 uGuru's the driver can autodetect the sensortype (Volt or Temp) for bank1 sensors, for revision 1 uGuru's - this doesnot always work. For these uGuru's the autodection can + this does not always work. For these uGuru's the autodetection can be overridden with the bank1_types module param. For all 3 known revison 1 motherboards the correct use of this param is: bank1_types=1,1,0,0,0,0,0,2,0,0,0,0,2,0,0,1 -- cgit v0.10.2 From 76b5808e8cb9d8be214a1bbf613e19b6e3ebb3fb Mon Sep 17 00:00:00 2001 From: Andrea Gelmini Date: Sat, 21 May 2016 13:41:07 +0200 Subject: hwmon: (max1668) Fix typo in documentation Signed-off-by: Andrea Gelmini [groeck: Updated subject] Signed-off-by: Guenter Roeck diff --git a/Documentation/hwmon/max1668 b/Documentation/hwmon/max1668 index 0616ed9..8f9d570 100644 --- a/Documentation/hwmon/max1668 +++ b/Documentation/hwmon/max1668 @@ -17,7 +17,7 @@ This driver implements support for the Maxim MAX1668, MAX1805 and MAX1989 chips. The three devices are very similar, but the MAX1805 has a reduced feature -set; only two remote temperature inputs vs the four avaible on the other +set; only two remote temperature inputs vs the four available on the other two ICs. The driver is able to distinguish between the devices and creates sysfs -- cgit v0.10.2 From 7c84f7f80d6fcea36246b793d06c3555ca53ddcd Mon Sep 17 00:00:00 2001 From: David Frey Date: Thu, 2 Jun 2016 09:59:11 +0200 Subject: hwmon: add support for Sensirion SHT3x sensors This driver implements support for the Sensirion SHT3x-DIS chip, a humidity and temperature sensor. Temperature is measured in degrees celsius, relative humidity is expressed as a percentage. In the sysfs interface, all values are scaled by 1000, i.e. the value for 31.5 degrees celsius is 31500. Signed-off-by: Pascal Sachs [groeck: Fixed 'Variable length array is used' gcc warning] Signed-off-by: Guenter Roeck diff --git a/Documentation/hwmon/sht3x b/Documentation/hwmon/sht3x new file mode 100644 index 0000000..f5aa633 --- /dev/null +++ b/Documentation/hwmon/sht3x @@ -0,0 +1,72 @@ +Kernel driver sht3x +=================== + +Supported chips: + * Sensirion SHT3x-DIS + Prefix: 'sht3x' + Addresses scanned: none + Datasheet: http://www.sensirion.com/fileadmin/user_upload/customers/sensirion/Dokumente/Humidity/Sensirion_Humidity_Datasheet_SHT3x_DIS.pdf + +Author: + David Frey + Pascal Sachs + +Description +----------- + +This driver implements support for the Sensirion SHT3x-DIS chip, a humidity +and temperature sensor. Temperature is measured in degrees celsius, relative +humidity is expressed as a percentage. In the sysfs interface, all values are +scaled by 1000, i.e. the value for 31.5 degrees celsius is 31500. + +The device communicates with the I2C protocol. Sensors can have the I2C +addresses 0x44 or 0x45, depending on the wiring. See +Documentation/i2c/instantiating-devices for methods to instantiate the device. + +There are two options configurable by means of sht3x_platform_data: +1. blocking (pull the I2C clock line down while performing the measurement) or + non-blocking mode. Blocking mode will guarantee the fastest result but + the I2C bus will be busy during that time. By default, non-blocking mode + is used. Make sure clock-stretching works properly on your device if you + want to use blocking mode. +2. high or low accuracy. High accuracy is used by default and using it is + strongly recommended. + +The sht3x sensor supports a single shot mode as well as 5 periodic measure +modes, which can be controlled with the update_interval sysfs interface. +The allowed update_interval in milliseconds are as follows: + * 0 single shot mode + * 2000 0.5 Hz periodic measurement + * 1000 1 Hz periodic measurement + * 500 2 Hz periodic measurement + * 250 4 Hz periodic measurement + * 100 10 Hz periodic measurement + +In the periodic measure mode, the sensor automatically triggers a measurement +with the configured update interval on the chip. When a temperature or humidity +reading exceeds the configured limits, the alert attribute is set to 1 and +the alert pin on the sensor is set to high. +When the temperature and humidity readings move back between the hysteresis +values, the alert bit is set to 0 and the alert pin on the sensor is set to +low. + +sysfs-Interface +--------------- + +temp1_input: temperature input +humidity1_input: humidity input +temp1_max: temperature max value +temp1_max_hyst: temperature hysteresis value for max limit +humidity1_max: humidity max value +humidity1_max_hyst: humidity hysteresis value for max limit +temp1_min: temperature min value +temp1_min_hyst: temperature hysteresis value for min limit +humidity1_min: humidity min value +humidity1_min_hyst: humidity hysteresis value for min limit +temp1_alarm: alarm flag is set to 1 if the temperature is outside the + configured limits. Alarm only works in periodic measure mode +humidity1_alarm: alarm flag is set to 1 if the humidity is outside the + configured limits. Alarm only works in periodic measure mode +update_interval: update interval, 0 for single shot, interval in msec + for periodic measurement. If the interval is not supported + by the sensor, the next faster interval is chosen diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index ff94007..e0be99a 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -1265,6 +1265,17 @@ config SENSORS_SHT21 This driver can also be built as a module. If so, the module will be called sht21. +config SENSORS_SHT3x + tristate "Sensiron humidity and temperature sensors. SHT3x and compat." + depends on I2C + select CRC8 + help + If you say yes here you get support for the Sensiron SHT30 and SHT31 + humidity and temperature sensors. + + This driver can also be built as a module. If so, the module + will be called sht3x. + config SENSORS_SHTC1 tristate "Sensiron humidity and temperature sensors. SHTC1 and compat." depends on I2C diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile index 2ef5b7c..406b18b 100644 --- a/drivers/hwmon/Makefile +++ b/drivers/hwmon/Makefile @@ -138,6 +138,7 @@ obj-$(CONFIG_SENSORS_SCH5627) += sch5627.o obj-$(CONFIG_SENSORS_SCH5636) += sch5636.o obj-$(CONFIG_SENSORS_SHT15) += sht15.o obj-$(CONFIG_SENSORS_SHT21) += sht21.o +obj-$(CONFIG_SENSORS_SHT3x) += sht3x.o obj-$(CONFIG_SENSORS_SHTC1) += shtc1.o obj-$(CONFIG_SENSORS_SIS5595) += sis5595.o obj-$(CONFIG_SENSORS_SMM665) += smm665.o diff --git a/drivers/hwmon/sht3x.c b/drivers/hwmon/sht3x.c new file mode 100644 index 0000000..707a3f8 --- /dev/null +++ b/drivers/hwmon/sht3x.c @@ -0,0 +1,725 @@ +/* Sensirion SHT3x-DIS humidity and temperature sensor driver. + * The SHT3x comes in many different versions, this driver is for the + * I2C version only. + * + * Copyright (C) 2016 Sensirion AG, Switzerland + * Author: David Frey + * Author: Pascal Sachs + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* commands (high precision mode) */ +static const unsigned char sht3x_cmd_measure_blocking_hpm[] = { 0x2c, 0x06 }; +static const unsigned char sht3x_cmd_measure_nonblocking_hpm[] = { 0x24, 0x00 }; + +/* commands (low power mode) */ +static const unsigned char sht3x_cmd_measure_blocking_lpm[] = { 0x2c, 0x10 }; +static const unsigned char sht3x_cmd_measure_nonblocking_lpm[] = { 0x24, 0x16 }; + +/* commands for periodic mode */ +static const unsigned char sht3x_cmd_measure_periodic_mode[] = { 0xe0, 0x00 }; +static const unsigned char sht3x_cmd_break[] = { 0x30, 0x93 }; + +/* other commands */ +static const unsigned char sht3x_cmd_read_status_reg[] = { 0xf3, 0x2d }; +static const unsigned char sht3x_cmd_clear_status_reg[] = { 0x30, 0x41 }; + +/* delays for non-blocking i2c commands, both in us */ +#define SHT3X_NONBLOCKING_WAIT_TIME_HPM 15000 +#define SHT3X_NONBLOCKING_WAIT_TIME_LPM 4000 + +#define SHT3X_WORD_LEN 2 +#define SHT3X_CMD_LENGTH 2 +#define SHT3X_CRC8_LEN 1 +#define SHT3X_RESPONSE_LENGTH 6 +#define SHT3X_CRC8_POLYNOMIAL 0x31 +#define SHT3X_CRC8_INIT 0xFF +#define SHT3X_MIN_TEMPERATURE -45000 +#define SHT3X_MAX_TEMPERATURE 130000 +#define SHT3X_MIN_HUMIDITY 0 +#define SHT3X_MAX_HUMIDITY 100000 + +enum sht3x_chips { + sht3x, + sts3x, +}; + +enum sht3x_limits { + limit_max = 0, + limit_max_hyst, + limit_min, + limit_min_hyst, +}; + +DECLARE_CRC8_TABLE(sht3x_crc8_table); + +/* periodic measure commands (high precision mode) */ +static const char periodic_measure_commands_hpm[][SHT3X_CMD_LENGTH] = { + /* 0.5 measurements per second */ + {0x20, 0x32}, + /* 1 measurements per second */ + {0x21, 0x30}, + /* 2 measurements per second */ + {0x22, 0x36}, + /* 4 measurements per second */ + {0x23, 0x34}, + /* 10 measurements per second */ + {0x27, 0x37}, +}; + +/* periodic measure commands (low power mode) */ +static const char periodic_measure_commands_lpm[][SHT3X_CMD_LENGTH] = { + /* 0.5 measurements per second */ + {0x20, 0x2f}, + /* 1 measurements per second */ + {0x21, 0x2d}, + /* 2 measurements per second */ + {0x22, 0x2b}, + /* 4 measurements per second */ + {0x23, 0x29}, + /* 10 measurements per second */ + {0x27, 0x2a}, +}; + +struct sht3x_limit_commands { + const char read_command[SHT3X_CMD_LENGTH]; + const char write_command[SHT3X_CMD_LENGTH]; +}; + +static const struct sht3x_limit_commands limit_commands[] = { + /* temp1_max, humidity1_max */ + [limit_max] = { {0xe1, 0x1f}, {0x61, 0x1d} }, + /* temp_1_max_hyst, humidity1_max_hyst */ + [limit_max_hyst] = { {0xe1, 0x14}, {0x61, 0x16} }, + /* temp1_min, humidity1_min */ + [limit_min] = { {0xe1, 0x02}, {0x61, 0x00} }, + /* temp_1_min_hyst, humidity1_min_hyst */ + [limit_min_hyst] = { {0xe1, 0x09}, {0x61, 0x0B} }, +}; + +#define SHT3X_NUM_LIMIT_CMD ARRAY_SIZE(limit_commands) + +static const u16 mode_to_update_interval[] = { + 0, + 2000, + 1000, + 500, + 250, + 100, +}; + +struct sht3x_data { + struct i2c_client *client; + struct mutex i2c_lock; /* lock for sending i2c commands */ + struct mutex data_lock; /* lock for updating driver data */ + + u8 mode; + const unsigned char *command; + u32 wait_time; /* in us*/ + unsigned long last_update; /* last update in periodic mode*/ + + struct sht3x_platform_data setup; + + /* + * cached values for temperature and humidity and limits + * the limits arrays have the following order: + * max, max_hyst, min, min_hyst + */ + int temperature; + int temperature_limits[SHT3X_NUM_LIMIT_CMD]; + u32 humidity; + u32 humidity_limits[SHT3X_NUM_LIMIT_CMD]; +}; + +static u8 get_mode_from_update_interval(u16 value) +{ + size_t index; + u8 number_of_modes = ARRAY_SIZE(mode_to_update_interval); + + if (value == 0) + return 0; + + /* find next faster update interval */ + for (index = 1; index < number_of_modes; index++) { + if (mode_to_update_interval[index] <= value) + return index; + } + + return number_of_modes - 1; +} + +static int sht3x_read_from_command(struct i2c_client *client, + struct sht3x_data *data, + const char *command, + char *buf, int length, u32 wait_time) +{ + int ret; + + mutex_lock(&data->i2c_lock); + ret = i2c_master_send(client, command, SHT3X_CMD_LENGTH); + + if (ret != SHT3X_CMD_LENGTH) { + ret = ret < 0 ? ret : -EIO; + goto out; + } + + if (wait_time) + usleep_range(wait_time, wait_time + 1000); + + ret = i2c_master_recv(client, buf, length); + if (ret != length) { + ret = ret < 0 ? ret : -EIO; + goto out; + } + + ret = 0; +out: + mutex_unlock(&data->i2c_lock); + return ret; +} + +static int sht3x_extract_temperature(u16 raw) +{ + /* + * From datasheet: + * T = -45 + 175 * ST / 2^16 + * Adapted for integer fixed point (3 digit) arithmetic. + */ + return ((21875 * (int)raw) >> 13) - 45000; +} + +static u32 sht3x_extract_humidity(u16 raw) +{ + /* + * From datasheet: + * RH = 100 * SRH / 2^16 + * Adapted for integer fixed point (3 digit) arithmetic. + */ + return (12500 * (u32)raw) >> 13; +} + +static struct sht3x_data *sht3x_update_client(struct device *dev) +{ + struct sht3x_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; + u16 interval_ms = mode_to_update_interval[data->mode]; + unsigned long interval_jiffies = msecs_to_jiffies(interval_ms); + unsigned char buf[SHT3X_RESPONSE_LENGTH]; + u16 val; + int ret = 0; + + mutex_lock(&data->data_lock); + /* + * Only update cached readings once per update interval in periodic + * mode. In single shot mode the sensor measures values on demand, so + * every time the sysfs interface is called, a measurement is triggered. + * In periodic mode however, the measurement process is handled + * internally by the sensor and reading out sensor values only makes + * sense if a new reading is available. + */ + if (time_after(jiffies, data->last_update + interval_jiffies)) { + ret = sht3x_read_from_command(client, data, data->command, buf, + sizeof(buf), data->wait_time); + if (ret) + goto out; + + val = be16_to_cpup((__be16 *)buf); + data->temperature = sht3x_extract_temperature(val); + val = be16_to_cpup((__be16 *)(buf + 3)); + data->humidity = sht3x_extract_humidity(val); + data->last_update = jiffies; + } + +out: + mutex_unlock(&data->data_lock); + if (ret) + return ERR_PTR(ret); + + return data; +} + +/* sysfs attributes */ +static ssize_t temp1_input_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct sht3x_data *data = sht3x_update_client(dev); + + if (IS_ERR(data)) + return PTR_ERR(data); + + return sprintf(buf, "%d\n", data->temperature); +} + +static ssize_t humidity1_input_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct sht3x_data *data = sht3x_update_client(dev); + + if (IS_ERR(data)) + return PTR_ERR(data); + + return sprintf(buf, "%u\n", data->humidity); +} + +/* + * limits_update must only be called from probe or with data_lock held + */ +static int limits_update(struct sht3x_data *data) +{ + int ret; + u8 index; + int temperature; + u32 humidity; + u16 raw; + char buffer[SHT3X_RESPONSE_LENGTH]; + const struct sht3x_limit_commands *commands; + struct i2c_client *client = data->client; + + for (index = 0; index < SHT3X_NUM_LIMIT_CMD; index++) { + commands = &limit_commands[index]; + ret = sht3x_read_from_command(client, data, + commands->read_command, buffer, + SHT3X_RESPONSE_LENGTH, 0); + + if (ret) + return ret; + + raw = be16_to_cpup((__be16 *)buffer); + temperature = sht3x_extract_temperature((raw & 0x01ff) << 7); + humidity = sht3x_extract_humidity(raw & 0xfe00); + data->temperature_limits[index] = temperature; + data->humidity_limits[index] = humidity; + } + + return ret; +} + +static ssize_t temp1_limit_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct sht3x_data *data = dev_get_drvdata(dev); + u8 index = to_sensor_dev_attr(attr)->index; + int temperature_limit = data->temperature_limits[index]; + + return scnprintf(buf, PAGE_SIZE, "%d\n", temperature_limit); +} + +static ssize_t humidity1_limit_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct sht3x_data *data = dev_get_drvdata(dev); + u8 index = to_sensor_dev_attr(attr)->index; + u32 humidity_limit = data->humidity_limits[index]; + + return scnprintf(buf, PAGE_SIZE, "%u\n", humidity_limit); +} + +/* + * limit_store must only be called with data_lock held + */ +static size_t limit_store(struct device *dev, + size_t count, + u8 index, + int temperature, + u32 humidity) +{ + char buffer[SHT3X_CMD_LENGTH + SHT3X_WORD_LEN + SHT3X_CRC8_LEN]; + char *position = buffer; + int ret; + u16 raw; + struct sht3x_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; + const struct sht3x_limit_commands *commands; + + commands = &limit_commands[index]; + + memcpy(position, commands->write_command, SHT3X_CMD_LENGTH); + position += SHT3X_CMD_LENGTH; + /* + * ST = (T + 45) / 175 * 2^16 + * SRH = RH / 100 * 2^16 + * adapted for fixed point arithmetic and packed the same as + * in limit_show() + */ + raw = ((u32)(temperature + 45000) * 24543) >> (16 + 7); + raw |= ((humidity * 42950) >> 16) & 0xfe00; + + *((__be16 *)position) = cpu_to_be16(raw); + position += SHT3X_WORD_LEN; + *position = crc8(sht3x_crc8_table, + position - SHT3X_WORD_LEN, + SHT3X_WORD_LEN, + SHT3X_CRC8_INIT); + + mutex_lock(&data->i2c_lock); + ret = i2c_master_send(client, buffer, sizeof(buffer)); + mutex_unlock(&data->i2c_lock); + + if (ret != sizeof(buffer)) + return ret < 0 ? ret : -EIO; + + data->temperature_limits[index] = temperature; + data->humidity_limits[index] = humidity; + return count; +} + +static ssize_t temp1_limit_store(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t count) +{ + int temperature; + int ret; + struct sht3x_data *data = dev_get_drvdata(dev); + u8 index = to_sensor_dev_attr(attr)->index; + + ret = kstrtoint(buf, 0, &temperature); + if (ret) + return ret; + + temperature = clamp_val(temperature, SHT3X_MIN_TEMPERATURE, + SHT3X_MAX_TEMPERATURE); + mutex_lock(&data->data_lock); + ret = limit_store(dev, count, index, temperature, + data->humidity_limits[index]); + mutex_unlock(&data->data_lock); + + return ret; +} + +static ssize_t humidity1_limit_store(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t count) +{ + u32 humidity; + int ret; + struct sht3x_data *data = dev_get_drvdata(dev); + u8 index = to_sensor_dev_attr(attr)->index; + + ret = kstrtou32(buf, 0, &humidity); + if (ret) + return ret; + + humidity = clamp_val(humidity, SHT3X_MIN_HUMIDITY, SHT3X_MAX_HUMIDITY); + mutex_lock(&data->data_lock); + ret = limit_store(dev, count, index, data->temperature_limits[index], + humidity); + mutex_unlock(&data->data_lock); + + return ret; +} + +static void sht3x_select_command(struct sht3x_data *data) +{ + /* + * In blocking mode (clock stretching mode) the I2C bus + * is blocked for other traffic, thus the call to i2c_master_recv() + * will wait until the data is ready. For non blocking mode, we + * have to wait ourselves. + */ + if (data->mode > 0) { + data->command = sht3x_cmd_measure_periodic_mode; + data->wait_time = 0; + } else if (data->setup.blocking_io) { + data->command = data->setup.high_precision ? + sht3x_cmd_measure_blocking_hpm : + sht3x_cmd_measure_blocking_lpm; + data->wait_time = 0; + } else { + if (data->setup.high_precision) { + data->command = sht3x_cmd_measure_nonblocking_hpm; + data->wait_time = SHT3X_NONBLOCKING_WAIT_TIME_HPM; + } else { + data->command = sht3x_cmd_measure_nonblocking_lpm; + data->wait_time = SHT3X_NONBLOCKING_WAIT_TIME_LPM; + } + } +} + +static int status_register_read(struct device *dev, + struct device_attribute *attr, + char *buffer, int length) +{ + int ret; + struct sht3x_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; + + ret = sht3x_read_from_command(client, data, sht3x_cmd_read_status_reg, + buffer, length, 0); + + return ret; +} + +static ssize_t temp1_alarm_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + char buffer[SHT3X_WORD_LEN + SHT3X_CRC8_LEN]; + int ret; + + ret = status_register_read(dev, attr, buffer, + SHT3X_WORD_LEN + SHT3X_CRC8_LEN); + if (ret) + return ret; + + return scnprintf(buf, PAGE_SIZE, "%d\n", !!(buffer[0] & 0x04)); +} + +static ssize_t humidity1_alarm_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + char buffer[SHT3X_WORD_LEN + SHT3X_CRC8_LEN]; + int ret; + + ret = status_register_read(dev, attr, buffer, + SHT3X_WORD_LEN + SHT3X_CRC8_LEN); + if (ret) + return ret; + + return scnprintf(buf, PAGE_SIZE, "%d\n", !!(buffer[0] & 0x08)); +} + +static ssize_t update_interval_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct sht3x_data *data = dev_get_drvdata(dev); + + return scnprintf(buf, PAGE_SIZE, "%u\n", + mode_to_update_interval[data->mode]); +} + +static ssize_t update_interval_store(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t count) +{ + u16 update_interval; + u8 mode; + int ret; + const char *command; + struct sht3x_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; + + ret = kstrtou16(buf, 0, &update_interval); + if (ret) + return ret; + + mode = get_mode_from_update_interval(update_interval); + + mutex_lock(&data->data_lock); + /* mode did not change */ + if (mode == data->mode) { + mutex_unlock(&data->data_lock); + return count; + } + + mutex_lock(&data->i2c_lock); + /* + * Abort periodic measure mode. + * To do any changes to the configuration while in periodic mode, we + * have to send a break command to the sensor, which then falls back + * to single shot (mode = 0). + */ + if (data->mode > 0) { + ret = i2c_master_send(client, sht3x_cmd_break, + SHT3X_CMD_LENGTH); + if (ret != SHT3X_CMD_LENGTH) + goto out; + data->mode = 0; + } + + if (mode > 0) { + if (data->setup.high_precision) + command = periodic_measure_commands_hpm[mode - 1]; + else + command = periodic_measure_commands_lpm[mode - 1]; + + /* select mode */ + ret = i2c_master_send(client, command, SHT3X_CMD_LENGTH); + if (ret != SHT3X_CMD_LENGTH) + goto out; + } + + /* select mode and command */ + data->mode = mode; + sht3x_select_command(data); + +out: + mutex_unlock(&data->i2c_lock); + mutex_unlock(&data->data_lock); + if (ret != SHT3X_CMD_LENGTH) + return ret < 0 ? ret : -EIO; + + return count; +} + +static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, temp1_input_show, NULL, 0); +static SENSOR_DEVICE_ATTR(humidity1_input, S_IRUGO, humidity1_input_show, + NULL, 0); +static SENSOR_DEVICE_ATTR(temp1_max, S_IRUGO | S_IWUSR, + temp1_limit_show, temp1_limit_store, + limit_max); +static SENSOR_DEVICE_ATTR(humidity1_max, S_IRUGO | S_IWUSR, + humidity1_limit_show, humidity1_limit_store, + limit_max); +static SENSOR_DEVICE_ATTR(temp1_max_hyst, S_IRUGO | S_IWUSR, + temp1_limit_show, temp1_limit_store, + limit_max_hyst); +static SENSOR_DEVICE_ATTR(humidity1_max_hyst, S_IRUGO | S_IWUSR, + humidity1_limit_show, humidity1_limit_store, + limit_max_hyst); +static SENSOR_DEVICE_ATTR(temp1_min, S_IRUGO | S_IWUSR, + temp1_limit_show, temp1_limit_store, + limit_min); +static SENSOR_DEVICE_ATTR(humidity1_min, S_IRUGO | S_IWUSR, + humidity1_limit_show, humidity1_limit_store, + limit_min); +static SENSOR_DEVICE_ATTR(temp1_min_hyst, S_IRUGO | S_IWUSR, + temp1_limit_show, temp1_limit_store, + limit_min_hyst); +static SENSOR_DEVICE_ATTR(humidity1_min_hyst, S_IRUGO | S_IWUSR, + humidity1_limit_show, humidity1_limit_store, + limit_min_hyst); +static SENSOR_DEVICE_ATTR(temp1_alarm, S_IRUGO, temp1_alarm_show, NULL, 0); +static SENSOR_DEVICE_ATTR(humidity1_alarm, S_IRUGO, humidity1_alarm_show, + NULL, 0); +static SENSOR_DEVICE_ATTR(update_interval, S_IRUGO | S_IWUSR, + update_interval_show, update_interval_store, 0); + +static struct attribute *sht3x_attrs[] = { + &sensor_dev_attr_temp1_input.dev_attr.attr, + &sensor_dev_attr_humidity1_input.dev_attr.attr, + &sensor_dev_attr_temp1_max.dev_attr.attr, + &sensor_dev_attr_temp1_max_hyst.dev_attr.attr, + &sensor_dev_attr_humidity1_max.dev_attr.attr, + &sensor_dev_attr_humidity1_max_hyst.dev_attr.attr, + &sensor_dev_attr_temp1_min.dev_attr.attr, + &sensor_dev_attr_temp1_min_hyst.dev_attr.attr, + &sensor_dev_attr_humidity1_min.dev_attr.attr, + &sensor_dev_attr_humidity1_min_hyst.dev_attr.attr, + &sensor_dev_attr_temp1_alarm.dev_attr.attr, + &sensor_dev_attr_humidity1_alarm.dev_attr.attr, + &sensor_dev_attr_update_interval.dev_attr.attr, + NULL +}; + +static struct attribute *sts3x_attrs[] = { + &sensor_dev_attr_temp1_input.dev_attr.attr, + NULL +}; + +ATTRIBUTE_GROUPS(sht3x); +ATTRIBUTE_GROUPS(sts3x); + +static int sht3x_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + int ret; + struct sht3x_data *data; + struct device *hwmon_dev; + struct i2c_adapter *adap = client->adapter; + struct device *dev = &client->dev; + const struct attribute_group **attribute_groups; + + /* + * we require full i2c support since the sht3x uses multi-byte read and + * writes as well as multi-byte commands which are not supported by + * the smbus protocol + */ + if (!i2c_check_functionality(adap, I2C_FUNC_I2C)) + return -ENODEV; + + ret = i2c_master_send(client, sht3x_cmd_clear_status_reg, + SHT3X_CMD_LENGTH); + if (ret != SHT3X_CMD_LENGTH) + return ret < 0 ? ret : -ENODEV; + + data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + data->setup.blocking_io = false; + data->setup.high_precision = true; + data->mode = 0; + data->last_update = 0; + data->client = client; + crc8_populate_msb(sht3x_crc8_table, SHT3X_CRC8_POLYNOMIAL); + + if (client->dev.platform_data) + data->setup = *(struct sht3x_platform_data *)dev->platform_data; + + sht3x_select_command(data); + + mutex_init(&data->i2c_lock); + mutex_init(&data->data_lock); + + ret = limits_update(data); + if (ret) + return ret; + + if (id->driver_data == sts3x) + attribute_groups = sts3x_groups; + else + attribute_groups = sht3x_groups; + + hwmon_dev = devm_hwmon_device_register_with_groups(dev, + client->name, + data, + attribute_groups); + + if (IS_ERR(hwmon_dev)) + dev_dbg(dev, "unable to register hwmon device\n"); + + return PTR_ERR_OR_ZERO(hwmon_dev); +} + +/* device ID table */ +static const struct i2c_device_id sht3x_ids[] = { + {"sht3x", sht3x}, + {"sts3x", sts3x}, + {} +}; + +MODULE_DEVICE_TABLE(i2c, sht3x_ids); + +static struct i2c_driver sht3x_i2c_driver = { + .driver.name = "sht3x", + .probe = sht3x_probe, + .id_table = sht3x_ids, +}; + +module_i2c_driver(sht3x_i2c_driver); + +MODULE_AUTHOR("David Frey "); +MODULE_AUTHOR("Pascal Sachs "); +MODULE_DESCRIPTION("Sensirion SHT3x humidity and temperature sensor driver"); +MODULE_LICENSE("GPL"); diff --git a/include/linux/platform_data/sht3x.h b/include/linux/platform_data/sht3x.h new file mode 100644 index 0000000..2e5eea3 --- /dev/null +++ b/include/linux/platform_data/sht3x.h @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2016 Sensirion AG, Switzerland + * Author: David Frey + * Author: Pascal Sachs + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef __SHT3X_H_ +#define __SHT3X_H_ + +struct sht3x_platform_data { + bool blocking_io; + bool high_precision; +}; +#endif /* __SHT3X_H_ */ -- cgit v0.10.2 From c0a68601804dcb4ee8a141e42e1e6893b6b0610c Mon Sep 17 00:00:00 2001 From: "Andrew F. Davis" Date: Wed, 8 Jun 2016 12:00:54 -0500 Subject: hwmon: (tmp401) Add support for TI TMP461 Signed-off-by: Andrew F. Davis Signed-off-by: Guenter Roeck diff --git a/Documentation/hwmon/tmp401 b/Documentation/hwmon/tmp401 index 711f75e..2d9ca42 100644 --- a/Documentation/hwmon/tmp401 +++ b/Documentation/hwmon/tmp401 @@ -22,6 +22,9 @@ Supported chips: Prefix: 'tmp435' Addresses scanned: I2C 0x48 - 0x4f Datasheet: http://focus.ti.com/docs/prod/folders/print/tmp435.html + * Texas Instruments TMP461 + Prefix: 'tmp461' + Datasheet: http://www.ti.com/product/tmp461 Authors: Hans de Goede @@ -31,8 +34,8 @@ Description ----------- This driver implements support for Texas Instruments TMP401, TMP411, -TMP431, TMP432 and TMP435 chips. These chips implement one or two remote -and one local temperature sensors. Temperature is measured in degrees +TMP431, TMP432, TMP435, and TMP461 chips. These chips implement one or two +remote and one local temperature sensors. Temperature is measured in degrees Celsius. Resolution of the remote sensor is 0.0625 degree. Local sensor resolution can be set to 0.5, 0.25, 0.125 or 0.0625 degree (not supported by the driver so far, so using the default resolution of 0.5 @@ -55,3 +58,10 @@ some additional features. TMP432 is compatible with TMP401 and TMP431. It supports two external temperature sensors. + +TMP461 is compatible with TMP401. It supports offset correction +that is applied to the remote sensor. + +* Sensor offset values are temperature values + + Exported via sysfs attribute tempX_offset diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index e0be99a..be63b14 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -1572,7 +1572,7 @@ config SENSORS_TMP401 depends on I2C help If you say yes here you get support for Texas Instruments TMP401, - TMP411, TMP431, TMP432 and TMP435 temperature sensor chips. + TMP411, TMP431, TMP432, TMP435, and TMP461 temperature sensor chips. This driver can also be built as a module. If so, the module will be called tmp401. diff --git a/drivers/hwmon/tmp401.c b/drivers/hwmon/tmp401.c index ccf4cff..eeeed2c 100644 --- a/drivers/hwmon/tmp401.c +++ b/drivers/hwmon/tmp401.c @@ -47,7 +47,7 @@ static const unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4c, 0x4d, 0x4e, 0x4f, I2C_CLIENT_END }; -enum chips { tmp401, tmp411, tmp431, tmp432, tmp435 }; +enum chips { tmp401, tmp411, tmp431, tmp432, tmp435, tmp461 }; /* * The TMP401 registers, note some registers have different addresses for @@ -62,31 +62,34 @@ enum chips { tmp401, tmp411, tmp431, tmp432, tmp435 }; #define TMP401_MANUFACTURER_ID_REG 0xFE #define TMP401_DEVICE_ID_REG 0xFF -static const u8 TMP401_TEMP_MSB_READ[6][2] = { +static const u8 TMP401_TEMP_MSB_READ[7][2] = { { 0x00, 0x01 }, /* temp */ { 0x06, 0x08 }, /* low limit */ { 0x05, 0x07 }, /* high limit */ { 0x20, 0x19 }, /* therm (crit) limit */ { 0x30, 0x34 }, /* lowest */ { 0x32, 0x36 }, /* highest */ + { 0, 0x11 }, /* offset */ }; -static const u8 TMP401_TEMP_MSB_WRITE[6][2] = { +static const u8 TMP401_TEMP_MSB_WRITE[7][2] = { { 0, 0 }, /* temp (unused) */ { 0x0C, 0x0E }, /* low limit */ { 0x0B, 0x0D }, /* high limit */ { 0x20, 0x19 }, /* therm (crit) limit */ { 0x30, 0x34 }, /* lowest */ { 0x32, 0x36 }, /* highest */ + { 0, 0x11 }, /* offset */ }; -static const u8 TMP401_TEMP_LSB[6][2] = { +static const u8 TMP401_TEMP_LSB[7][2] = { { 0x15, 0x10 }, /* temp */ { 0x17, 0x14 }, /* low limit */ { 0x16, 0x13 }, /* high limit */ { 0, 0 }, /* therm (crit) limit (unused) */ { 0x31, 0x35 }, /* lowest */ { 0x33, 0x37 }, /* highest */ + { 0, 0x12 }, /* offset */ }; static const u8 TMP432_TEMP_MSB_READ[4][3] = { @@ -149,6 +152,7 @@ static const struct i2c_device_id tmp401_id[] = { { "tmp431", tmp431 }, { "tmp432", tmp432 }, { "tmp435", tmp435 }, + { "tmp461", tmp461 }, { } }; MODULE_DEVICE_TABLE(i2c, tmp401_id); @@ -170,7 +174,7 @@ struct tmp401_data { /* register values */ u8 status[4]; u8 config; - u16 temp[6][3]; + u16 temp[7][3]; u8 temp_crit_hyst; }; @@ -613,6 +617,22 @@ static const struct attribute_group tmp432_group = { }; /* + * Additional features of the TMP461 chip. + * The TMP461 temperature offset for the remote channel. + */ +static SENSOR_DEVICE_ATTR_2(temp2_offset, S_IWUSR | S_IRUGO, show_temp, + store_temp, 6, 1); + +static struct attribute *tmp461_attributes[] = { + &sensor_dev_attr_temp2_offset.dev_attr.attr, + NULL +}; + +static const struct attribute_group tmp461_group = { + .attrs = tmp461_attributes, +}; + +/* * Begin non sysfs callback code (aka Real code) */ @@ -714,7 +734,7 @@ static int tmp401_probe(struct i2c_client *client, const struct i2c_device_id *id) { static const char * const names[] = { - "TMP401", "TMP411", "TMP431", "TMP432", "TMP435" + "TMP401", "TMP411", "TMP431", "TMP432", "TMP435", "TMP461" }; struct device *dev = &client->dev; struct device *hwmon_dev; @@ -745,6 +765,9 @@ static int tmp401_probe(struct i2c_client *client, if (data->kind == tmp432) data->groups[groups++] = &tmp432_group; + if (data->kind == tmp461) + data->groups[groups++] = &tmp461_group; + hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name, data, data->groups); if (IS_ERR(hwmon_dev)) -- cgit v0.10.2 From 7cb6dcff1956ec9e338abfa2f298d2971cfbab79 Mon Sep 17 00:00:00 2001 From: "Andrew F. Davis" Date: Fri, 10 Jun 2016 10:32:33 -0500 Subject: hwmon: Add support for INA3221 Triple Current/Voltage Monitors Add support for the the INA3221 26v capable, Triple channel, Bi-Directional, Zero-Drift, Low-/High-Side, Current/Voltage Monitor with I2C interface. Signed-off-by: Andrew F. Davis Signed-off-by: Guenter Roeck diff --git a/Documentation/hwmon/ina3221 b/Documentation/hwmon/ina3221 new file mode 100644 index 0000000..0ff7485 --- /dev/null +++ b/Documentation/hwmon/ina3221 @@ -0,0 +1,35 @@ +Kernel driver ina3221 +===================== + +Supported chips: + * Texas Instruments INA3221 + Prefix: 'ina3221' + Addresses: I2C 0x40 - 0x43 + Datasheet: Publicly available at the Texas Instruments website + http://www.ti.com/ + +Author: Andrew F. Davis + +Description +----------- + +The Texas Instruments INA3221 monitors voltage, current, and power on the high +side of up to three D.C. power supplies. The INA3221 monitors both shunt drop +and supply voltage, with programmable conversion times and averaging, current +and power are calculated host-side from these. + +Sysfs entries +------------- + +in[123]_input Bus voltage(mV) channels +curr[123]_input Current(mA) measurement channels +shunt[123]_resistor Shunt resistance(uOhm) channels +curr[123]_crit Critical alert current(mA) setting, activates the + corresponding alarm when the respective current + is above this value +curr[123]_crit_alarm Critical alert current limit exceeded +curr[123]_max Warning alert current(mA) setting, activates the + corresponding alarm when the respective current + average is above this value. +curr[123]_max_alarm Warning alert current limit exceeded +in[456]_input Shunt voltage(uV) for channels 1, 2, and 3 respectively diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index be63b14..b2aa13b 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -1525,6 +1525,17 @@ config SENSORS_INA2XX This driver can also be built as a module. If so, the module will be called ina2xx. +config SENSORS_INA3221 + tristate "Texas Instruments INA3221 Triple Power Monitor" + depends on I2C + select REGMAP_I2C + help + If you say yes here you get support for the TI INA3221 Triple Power + Monitor. + + This driver can also be built as a module. If so, the module + will be called ina3221. + config SENSORS_TC74 tristate "Microchip TC74" depends on I2C diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile index 406b18b..446a4e7 100644 --- a/drivers/hwmon/Makefile +++ b/drivers/hwmon/Makefile @@ -77,6 +77,7 @@ obj-$(CONFIG_SENSORS_IBMPOWERNV)+= ibmpowernv.o obj-$(CONFIG_SENSORS_IIO_HWMON) += iio_hwmon.o obj-$(CONFIG_SENSORS_INA209) += ina209.o obj-$(CONFIG_SENSORS_INA2XX) += ina2xx.o +obj-$(CONFIG_SENSORS_INA3221) += ina3221.o obj-$(CONFIG_SENSORS_IT87) += it87.o obj-$(CONFIG_SENSORS_JC42) += jc42.o obj-$(CONFIG_SENSORS_JZ4740) += jz4740-hwmon.o diff --git a/drivers/hwmon/ina3221.c b/drivers/hwmon/ina3221.c new file mode 100644 index 0000000..d055b6a --- /dev/null +++ b/drivers/hwmon/ina3221.c @@ -0,0 +1,446 @@ +/* + * INA3221 Triple Current/Voltage Monitor + * + * Copyright (C) 2016 Texas Instruments Incorporated - http://www.ti.com/ + * Andrew F. Davis + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include + +#define INA3221_DRIVER_NAME "ina3221" + +#define INA3221_CONFIG 0x00 +#define INA3221_SHUNT1 0x01 +#define INA3221_BUS1 0x02 +#define INA3221_SHUNT2 0x03 +#define INA3221_BUS2 0x04 +#define INA3221_SHUNT3 0x05 +#define INA3221_BUS3 0x06 +#define INA3221_CRIT1 0x07 +#define INA3221_WARN1 0x08 +#define INA3221_CRIT2 0x09 +#define INA3221_WARN2 0x0a +#define INA3221_CRIT3 0x0b +#define INA3221_WARN3 0x0c +#define INA3221_MASK_ENABLE 0x0f + +#define INA3221_CONFIG_MODE_SHUNT BIT(1) +#define INA3221_CONFIG_MODE_BUS BIT(2) +#define INA3221_CONFIG_MODE_CONTINUOUS BIT(3) + +#define INA3221_RSHUNT_DEFAULT 10000 + +enum ina3221_fields { + /* Configuration */ + F_RST, + + /* Alert Flags */ + F_WF3, F_WF2, F_WF1, + F_CF3, F_CF2, F_CF1, + + /* sentinel */ + F_MAX_FIELDS +}; + +static const struct reg_field ina3221_reg_fields[] = { + [F_RST] = REG_FIELD(INA3221_CONFIG, 15, 15), + + [F_WF3] = REG_FIELD(INA3221_MASK_ENABLE, 3, 3), + [F_WF2] = REG_FIELD(INA3221_MASK_ENABLE, 4, 4), + [F_WF1] = REG_FIELD(INA3221_MASK_ENABLE, 5, 5), + [F_CF3] = REG_FIELD(INA3221_MASK_ENABLE, 7, 7), + [F_CF2] = REG_FIELD(INA3221_MASK_ENABLE, 8, 8), + [F_CF1] = REG_FIELD(INA3221_MASK_ENABLE, 9, 9), +}; + +enum ina3221_channels { + INA3221_CHANNEL1, + INA3221_CHANNEL2, + INA3221_CHANNEL3, + INA3221_NUM_CHANNELS +}; + +static const unsigned int register_channel[] = { + [INA3221_SHUNT1] = INA3221_CHANNEL1, + [INA3221_SHUNT2] = INA3221_CHANNEL2, + [INA3221_SHUNT3] = INA3221_CHANNEL3, + [INA3221_CRIT1] = INA3221_CHANNEL1, + [INA3221_CRIT2] = INA3221_CHANNEL2, + [INA3221_CRIT3] = INA3221_CHANNEL3, + [INA3221_WARN1] = INA3221_CHANNEL1, + [INA3221_WARN2] = INA3221_CHANNEL2, + [INA3221_WARN3] = INA3221_CHANNEL3, +}; + +/** + * struct ina3221_data - device specific information + * @regmap: Register map of the device + * @fields: Register fields of the device + * @shunt_resistors: Array of resistor values per channel + */ +struct ina3221_data { + struct regmap *regmap; + struct regmap_field *fields[F_MAX_FIELDS]; + unsigned int shunt_resistors[INA3221_NUM_CHANNELS]; +}; + +static int ina3221_read_value(struct ina3221_data *ina, unsigned int reg, + int *val) +{ + unsigned int regval; + int ret; + + ret = regmap_read(ina->regmap, reg, ®val); + if (ret) + return ret; + + *val = sign_extend32(regval >> 3, 12); + + return 0; +} + +static ssize_t ina3221_show_bus_voltage(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct sensor_device_attribute *sd_attr = to_sensor_dev_attr(attr); + struct ina3221_data *ina = dev_get_drvdata(dev); + unsigned int reg = sd_attr->index; + int val, voltage_mv, ret; + + ret = ina3221_read_value(ina, reg, &val); + if (ret) + return ret; + + voltage_mv = val * 8; + + return snprintf(buf, PAGE_SIZE, "%d\n", voltage_mv); +} + +static ssize_t ina3221_show_shunt_voltage(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct sensor_device_attribute *sd_attr = to_sensor_dev_attr(attr); + struct ina3221_data *ina = dev_get_drvdata(dev); + unsigned int reg = sd_attr->index; + int val, voltage_uv, ret; + + ret = ina3221_read_value(ina, reg, &val); + if (ret) + return ret; + voltage_uv = val * 40; + + return snprintf(buf, PAGE_SIZE, "%d\n", voltage_uv); +} + +static ssize_t ina3221_show_current(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct sensor_device_attribute *sd_attr = to_sensor_dev_attr(attr); + struct ina3221_data *ina = dev_get_drvdata(dev); + unsigned int reg = sd_attr->index; + unsigned int channel = register_channel[reg]; + unsigned int resistance_uo = ina->shunt_resistors[channel]; + int val, current_ma, voltage_nv, ret; + + ret = ina3221_read_value(ina, reg, &val); + if (ret) + return ret; + voltage_nv = val * 40000; + + current_ma = DIV_ROUND_CLOSEST(voltage_nv, resistance_uo); + + return snprintf(buf, PAGE_SIZE, "%d\n", current_ma); +} + +static ssize_t ina3221_set_current(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct sensor_device_attribute *sd_attr = to_sensor_dev_attr(attr); + struct ina3221_data *ina = dev_get_drvdata(dev); + unsigned int reg = sd_attr->index; + unsigned int channel = register_channel[reg]; + unsigned int resistance_uo = ina->shunt_resistors[channel]; + int val, current_ma, voltage_uv, ret; + + ret = kstrtoint(buf, 0, ¤t_ma); + if (ret) + return ret; + + /* clamp current */ + current_ma = clamp_val(current_ma, + INT_MIN / resistance_uo, + INT_MAX / resistance_uo); + + voltage_uv = DIV_ROUND_CLOSEST(current_ma * resistance_uo, 1000); + + /* clamp voltage */ + voltage_uv = clamp_val(voltage_uv, -163800, 163800); + + /* 1 / 40uV(scale) << 3(register shift) = 5 */ + val = DIV_ROUND_CLOSEST(voltage_uv, 5) & 0xfff8; + + ret = regmap_write(ina->regmap, reg, val); + if (ret) + return ret; + + return count; +} + +static ssize_t ina3221_show_shunt(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct sensor_device_attribute *sd_attr = to_sensor_dev_attr(attr); + struct ina3221_data *ina = dev_get_drvdata(dev); + unsigned int channel = sd_attr->index; + unsigned int resistance_uo; + + resistance_uo = ina->shunt_resistors[channel]; + + return snprintf(buf, PAGE_SIZE, "%d\n", resistance_uo); +} + +static ssize_t ina3221_set_shunt(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct sensor_device_attribute *sd_attr = to_sensor_dev_attr(attr); + struct ina3221_data *ina = dev_get_drvdata(dev); + unsigned int channel = sd_attr->index; + unsigned int val; + int ret; + + ret = kstrtouint(buf, 0, &val); + if (ret) + return ret; + + if (val == 0) + return -EINVAL; + + ina->shunt_resistors[channel] = val; + + return count; +} + +static ssize_t ina3221_show_alert(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct sensor_device_attribute *sd_attr = to_sensor_dev_attr(attr); + struct ina3221_data *ina = dev_get_drvdata(dev); + unsigned int field = sd_attr->index; + unsigned int regval; + int ret; + + ret = regmap_field_read(ina->fields[field], ®val); + if (ret) + return ret; + + return snprintf(buf, PAGE_SIZE, "%d\n", regval); +} + +/* bus voltage */ +static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, + ina3221_show_bus_voltage, NULL, INA3221_BUS1); +static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, + ina3221_show_bus_voltage, NULL, INA3221_BUS2); +static SENSOR_DEVICE_ATTR(in3_input, S_IRUGO, + ina3221_show_bus_voltage, NULL, INA3221_BUS3); + +/* calculated current */ +static SENSOR_DEVICE_ATTR(curr1_input, S_IRUGO, + ina3221_show_current, NULL, INA3221_SHUNT1); +static SENSOR_DEVICE_ATTR(curr2_input, S_IRUGO, + ina3221_show_current, NULL, INA3221_SHUNT2); +static SENSOR_DEVICE_ATTR(curr3_input, S_IRUGO, + ina3221_show_current, NULL, INA3221_SHUNT3); + +/* shunt resistance */ +static SENSOR_DEVICE_ATTR(shunt1_resistor, S_IRUGO | S_IWUSR, + ina3221_show_shunt, ina3221_set_shunt, INA3221_CHANNEL1); +static SENSOR_DEVICE_ATTR(shunt2_resistor, S_IRUGO | S_IWUSR, + ina3221_show_shunt, ina3221_set_shunt, INA3221_CHANNEL2); +static SENSOR_DEVICE_ATTR(shunt3_resistor, S_IRUGO | S_IWUSR, + ina3221_show_shunt, ina3221_set_shunt, INA3221_CHANNEL3); + +/* critical current */ +static SENSOR_DEVICE_ATTR(curr1_crit, S_IRUGO | S_IWUSR, + ina3221_show_current, ina3221_set_current, INA3221_CRIT1); +static SENSOR_DEVICE_ATTR(curr2_crit, S_IRUGO | S_IWUSR, + ina3221_show_current, ina3221_set_current, INA3221_CRIT2); +static SENSOR_DEVICE_ATTR(curr3_crit, S_IRUGO | S_IWUSR, + ina3221_show_current, ina3221_set_current, INA3221_CRIT3); + +/* critical current alert */ +static SENSOR_DEVICE_ATTR(curr1_crit_alarm, S_IRUGO, + ina3221_show_alert, NULL, F_CF1); +static SENSOR_DEVICE_ATTR(curr2_crit_alarm, S_IRUGO, + ina3221_show_alert, NULL, F_CF2); +static SENSOR_DEVICE_ATTR(curr3_crit_alarm, S_IRUGO, + ina3221_show_alert, NULL, F_CF3); + +/* warning current */ +static SENSOR_DEVICE_ATTR(curr1_max, S_IRUGO | S_IWUSR, + ina3221_show_current, ina3221_set_current, INA3221_WARN1); +static SENSOR_DEVICE_ATTR(curr2_max, S_IRUGO | S_IWUSR, + ina3221_show_current, ina3221_set_current, INA3221_WARN2); +static SENSOR_DEVICE_ATTR(curr3_max, S_IRUGO | S_IWUSR, + ina3221_show_current, ina3221_set_current, INA3221_WARN3); + +/* warning current alert */ +static SENSOR_DEVICE_ATTR(curr1_max_alarm, S_IRUGO, + ina3221_show_alert, NULL, F_WF1); +static SENSOR_DEVICE_ATTR(curr2_max_alarm, S_IRUGO, + ina3221_show_alert, NULL, F_WF2); +static SENSOR_DEVICE_ATTR(curr3_max_alarm, S_IRUGO, + ina3221_show_alert, NULL, F_WF3); + +/* shunt voltage */ +static SENSOR_DEVICE_ATTR(in4_input, S_IRUGO, + ina3221_show_shunt_voltage, NULL, INA3221_SHUNT1); +static SENSOR_DEVICE_ATTR(in5_input, S_IRUGO, + ina3221_show_shunt_voltage, NULL, INA3221_SHUNT2); +static SENSOR_DEVICE_ATTR(in6_input, S_IRUGO, + ina3221_show_shunt_voltage, NULL, INA3221_SHUNT3); + +static struct attribute *ina3221_attrs[] = { + /* channel 1 */ + &sensor_dev_attr_in1_input.dev_attr.attr, + &sensor_dev_attr_curr1_input.dev_attr.attr, + &sensor_dev_attr_shunt1_resistor.dev_attr.attr, + &sensor_dev_attr_curr1_crit.dev_attr.attr, + &sensor_dev_attr_curr1_crit_alarm.dev_attr.attr, + &sensor_dev_attr_curr1_max.dev_attr.attr, + &sensor_dev_attr_curr1_max_alarm.dev_attr.attr, + &sensor_dev_attr_in4_input.dev_attr.attr, + + /* channel 2 */ + &sensor_dev_attr_in2_input.dev_attr.attr, + &sensor_dev_attr_curr2_input.dev_attr.attr, + &sensor_dev_attr_shunt2_resistor.dev_attr.attr, + &sensor_dev_attr_curr2_crit.dev_attr.attr, + &sensor_dev_attr_curr2_crit_alarm.dev_attr.attr, + &sensor_dev_attr_curr2_max.dev_attr.attr, + &sensor_dev_attr_curr2_max_alarm.dev_attr.attr, + &sensor_dev_attr_in5_input.dev_attr.attr, + + /* channel 3 */ + &sensor_dev_attr_in3_input.dev_attr.attr, + &sensor_dev_attr_curr3_input.dev_attr.attr, + &sensor_dev_attr_shunt3_resistor.dev_attr.attr, + &sensor_dev_attr_curr3_crit.dev_attr.attr, + &sensor_dev_attr_curr3_crit_alarm.dev_attr.attr, + &sensor_dev_attr_curr3_max.dev_attr.attr, + &sensor_dev_attr_curr3_max_alarm.dev_attr.attr, + &sensor_dev_attr_in6_input.dev_attr.attr, + + NULL, +}; +ATTRIBUTE_GROUPS(ina3221); + +static const struct regmap_range ina3221_yes_ranges[] = { + regmap_reg_range(INA3221_SHUNT1, INA3221_BUS3), + regmap_reg_range(INA3221_MASK_ENABLE, INA3221_MASK_ENABLE), +}; + +static const struct regmap_access_table ina3221_volatile_table = { + .yes_ranges = ina3221_yes_ranges, + .n_yes_ranges = ARRAY_SIZE(ina3221_yes_ranges), +}; + +static const struct regmap_config ina3221_regmap_config = { + .reg_bits = 8, + .val_bits = 16, + + .cache_type = REGCACHE_RBTREE, + .volatile_table = &ina3221_volatile_table, +}; + +static int ina3221_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct device *dev = &client->dev; + struct ina3221_data *ina; + struct device *hwmon_dev; + int i, ret; + + ina = devm_kzalloc(dev, sizeof(*ina), GFP_KERNEL); + if (!ina) + return -ENOMEM; + + ina->regmap = devm_regmap_init_i2c(client, &ina3221_regmap_config); + if (IS_ERR(ina->regmap)) { + dev_err(dev, "Unable to allocate register map\n"); + return PTR_ERR(ina->regmap); + } + + for (i = 0; i < F_MAX_FIELDS; i++) { + ina->fields[i] = devm_regmap_field_alloc(dev, + ina->regmap, + ina3221_reg_fields[i]); + if (IS_ERR(ina->fields[i])) { + dev_err(dev, "Unable to allocate regmap fields\n"); + return PTR_ERR(ina->fields[i]); + } + } + + for (i = 0; i < INA3221_NUM_CHANNELS; i++) + ina->shunt_resistors[i] = INA3221_RSHUNT_DEFAULT; + + ret = regmap_field_write(ina->fields[F_RST], true); + if (ret) { + dev_err(dev, "Unable to reset device\n"); + return ret; + } + + hwmon_dev = devm_hwmon_device_register_with_groups(dev, + client->name, + ina, ina3221_groups); + if (IS_ERR(hwmon_dev)) { + dev_err(dev, "Unable to register hwmon device\n"); + return PTR_ERR(hwmon_dev); + } + + return 0; +} + +static const struct of_device_id ina3221_of_match_table[] = { + { .compatible = "ti,ina3221", }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, ina3221_of_match_table); + +static const struct i2c_device_id ina3221_ids[] = { + { "ina3221", 0 }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(i2c, ina3221_ids); + +static struct i2c_driver ina3221_i2c_driver = { + .probe = ina3221_probe, + .driver = { + .name = INA3221_DRIVER_NAME, + .of_match_table = ina3221_of_match_table, + }, + .id_table = ina3221_ids, +}; +module_i2c_driver(ina3221_i2c_driver); + +MODULE_AUTHOR("Andrew F. Davis "); +MODULE_DESCRIPTION("Texas Instruments INA3221 HWMon Driver"); +MODULE_LICENSE("GPL v2"); -- cgit v0.10.2 From 165720d9ff3e33f626802da6cef3118ebfc6940c Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Fri, 10 Jun 2016 21:01:28 -0700 Subject: hwmon: Update guildelines for submitting patches Add more details to the guidelines for submitting patches. Signed-off-by: Guenter Roeck diff --git a/Documentation/hwmon/submitting-patches b/Documentation/hwmon/submitting-patches index d201828..57f6030 100644 --- a/Documentation/hwmon/submitting-patches +++ b/Documentation/hwmon/submitting-patches @@ -15,10 +15,15 @@ increase the chances of your change being accepted. Documentation/SubmittingPatches Documentation/CodingStyle -* If your patch generates checkpatch warnings, please refrain from explanations - such as "I don't like that coding style". Keep in mind that each unnecessary - warning helps hiding a real problem. If you don't like the kernel coding - style, don't write kernel drivers. +* Please run your patch through 'checkpatch --strict'. There should be no + errors, no warnings, and few if any check messages. If there are any + messages, please be prepared to explain. + +* If your patch generates checkpatch errors, warnings, or check messages, + please refrain from explanations such as "I prefer that coding style". + Keep in mind that each unnecessary message helps hiding a real problem, + and a consistent coding style makes it easier for others to understand + and review the code. * Please test your patch thoroughly. We are not your test group. Sometimes a patch can not or not completely be tested because of missing @@ -61,15 +66,30 @@ increase the chances of your change being accepted. * Make sure that all dependencies are listed in Kconfig. +* Please list include files in alphabetic order. + +* Please align continuation lines with '(' on the previous line. + * Avoid forward declarations if you can. Rearrange the code if necessary. +* Avoid macros to generate groups of sensor attributes. It not only confuses + checkpatch, but also makes it more difficult to review the code. + * Avoid calculations in macros and macro-generated functions. While such macros may save a line or so in the source, it obfuscates the code and makes code review more difficult. It may also result in code which is more complicated than necessary. Use inline functions or just regular functions instead. +* Limit the number of kernel log messages. In general, your driver should not + generate an error message just because a runtime operation failed. Report + errors to user space instead, using an appropriate error code. Keep in mind + that kernel error log messages not only fill up the kernel log, but also are + printed synchronously, most likely with interrupt disabled, often to a serial + console. Excessive logging can seriously affect system performance. + * Use devres functions whenever possible to allocate resources. For rationale and supported functions, please see Documentation/driver-model/devres.txt. + If a function is not supported by devres, consider using devm_add_action(). * If the driver has a detect function, make sure it is silent. Debug messages and messages printed after a successful detection are acceptable, but it @@ -96,8 +116,16 @@ increase the chances of your change being accepted. writing to it might cause a bad misconfiguration. * Make sure there are no race conditions in the probe function. Specifically, - completely initialize your chip first, then create sysfs entries and register - with the hwmon subsystem. + completely initialize your chip and your driver first, then register with + the hwmon subsystem. + +* Use devm_hwmon_device_register_with_groups() or, if your driver needs a remove + function, hwmon_device_register_with_groups() to register your driver with the + hwmon subsystem. Try using devm_add_action() instead of a remove function if + possible. Do not use hwmon_device_register(). + +* Your driver should be buildable as module. If not, please be prepared to + explain why it has to be built into the kernel. * Do not provide support for deprecated sysfs attributes. -- cgit v0.10.2 From 157926c013b39561fd1e3b93f8df96fb0ed17648 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Tue, 1 Jul 2014 22:29:28 +0800 Subject: hwmon: (ad7314) Convert to devm_hwmon_device_register_with_groups Use ATTRIBUTE_GROUPS macro and devm_hwmon_device_register_with_groups() to simplify the code a bit. Signed-off-by: Axel Lin Signed-off-by: Guenter Roeck diff --git a/drivers/hwmon/ad7314.c b/drivers/hwmon/ad7314.c index 202c1fbb..8ea3593 100644 --- a/drivers/hwmon/ad7314.c +++ b/drivers/hwmon/ad7314.c @@ -37,7 +37,6 @@ enum ad7314_variant { struct ad7314_data { struct spi_device *spi_dev; - struct device *hwmon_dev; u16 rx ____cacheline_aligned; }; @@ -88,62 +87,30 @@ static ssize_t ad7314_show_temperature(struct device *dev, } } -static ssize_t ad7314_show_name(struct device *dev, - struct device_attribute *devattr, char *buf) -{ - return sprintf(buf, "%s\n", to_spi_device(dev)->modalias); -} - -static DEVICE_ATTR(name, S_IRUGO, ad7314_show_name, NULL); static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, ad7314_show_temperature, NULL, 0); -static struct attribute *ad7314_attributes[] = { - &dev_attr_name.attr, +static struct attribute *ad7314_attrs[] = { &sensor_dev_attr_temp1_input.dev_attr.attr, NULL, }; -static const struct attribute_group ad7314_group = { - .attrs = ad7314_attributes, -}; +ATTRIBUTE_GROUPS(ad7314); static int ad7314_probe(struct spi_device *spi_dev) { - int ret; struct ad7314_data *chip; + struct device *hwmon_dev; chip = devm_kzalloc(&spi_dev->dev, sizeof(*chip), GFP_KERNEL); if (chip == NULL) return -ENOMEM; - spi_set_drvdata(spi_dev, chip); - - ret = sysfs_create_group(&spi_dev->dev.kobj, &ad7314_group); - if (ret < 0) - return ret; - - chip->hwmon_dev = hwmon_device_register(&spi_dev->dev); - if (IS_ERR(chip->hwmon_dev)) { - ret = PTR_ERR(chip->hwmon_dev); - goto error_remove_group; - } chip->spi_dev = spi_dev; - - return 0; -error_remove_group: - sysfs_remove_group(&spi_dev->dev.kobj, &ad7314_group); - return ret; -} - -static int ad7314_remove(struct spi_device *spi_dev) -{ - struct ad7314_data *chip = spi_get_drvdata(spi_dev); - - hwmon_device_unregister(chip->hwmon_dev); - sysfs_remove_group(&spi_dev->dev.kobj, &ad7314_group); - - return 0; + hwmon_dev = devm_hwmon_device_register_with_groups(&spi_dev->dev, + spi_dev->modalias, + chip, ad7314_groups); + return PTR_ERR_OR_ZERO(hwmon_dev); } static const struct spi_device_id ad7314_id[] = { @@ -159,7 +126,6 @@ static struct spi_driver ad7314_driver = { .name = "ad7314", }, .probe = ad7314_probe, - .remove = ad7314_remove, .id_table = ad7314_id, }; -- cgit v0.10.2 From 699f279d998cf95809babc987abd4a409eada5b2 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Sun, 29 Jun 2014 21:39:11 +0800 Subject: hwmon: (jz4740) Convert to devm_hwmon_device_register_with_groups Use ATTRIBUTE_GROUPS macro and devm_hwmon_device_register_with_groups() to simplify the code a bit. Signed-off-by: Axel Lin Signed-off-by: Guenter Roeck diff --git a/drivers/hwmon/jz4740-hwmon.c b/drivers/hwmon/jz4740-hwmon.c index df9b344..0621ee1 100644 --- a/drivers/hwmon/jz4740-hwmon.c +++ b/drivers/hwmon/jz4740-hwmon.c @@ -29,23 +29,13 @@ struct jz4740_hwmon { void __iomem *base; - int irq; - const struct mfd_cell *cell; - struct device *hwmon; - + struct platform_device *pdev; struct completion read_completion; - struct mutex lock; }; -static ssize_t jz4740_hwmon_show_name(struct device *dev, - struct device_attribute *dev_attr, char *buf) -{ - return sprintf(buf, "jz4740\n"); -} - static irqreturn_t jz4740_hwmon_irq(int irq, void *data) { struct jz4740_hwmon *hwmon = data; @@ -58,6 +48,7 @@ static ssize_t jz4740_hwmon_read_adcin(struct device *dev, struct device_attribute *dev_attr, char *buf) { struct jz4740_hwmon *hwmon = dev_get_drvdata(dev); + struct platform_device *pdev = hwmon->pdev; struct completion *completion = &hwmon->read_completion; long t; unsigned long val; @@ -68,7 +59,7 @@ static ssize_t jz4740_hwmon_read_adcin(struct device *dev, reinit_completion(completion); enable_irq(hwmon->irq); - hwmon->cell->enable(to_platform_device(dev)); + hwmon->cell->enable(pdev); t = wait_for_completion_interruptible_timeout(completion, HZ); @@ -80,7 +71,7 @@ static ssize_t jz4740_hwmon_read_adcin(struct device *dev, ret = t ? t : -ETIMEDOUT; } - hwmon->cell->disable(to_platform_device(dev)); + hwmon->cell->disable(pdev); disable_irq(hwmon->irq); mutex_unlock(&hwmon->lock); @@ -88,26 +79,24 @@ static ssize_t jz4740_hwmon_read_adcin(struct device *dev, return ret; } -static DEVICE_ATTR(name, S_IRUGO, jz4740_hwmon_show_name, NULL); static DEVICE_ATTR(in0_input, S_IRUGO, jz4740_hwmon_read_adcin, NULL); -static struct attribute *jz4740_hwmon_attributes[] = { - &dev_attr_name.attr, +static struct attribute *jz4740_attrs[] = { &dev_attr_in0_input.attr, NULL }; -static const struct attribute_group jz4740_hwmon_attr_group = { - .attrs = jz4740_hwmon_attributes, -}; +ATTRIBUTE_GROUPS(jz4740); static int jz4740_hwmon_probe(struct platform_device *pdev) { int ret; + struct device *dev = &pdev->dev; struct jz4740_hwmon *hwmon; + struct device *hwmon_dev; struct resource *mem; - hwmon = devm_kzalloc(&pdev->dev, sizeof(*hwmon), GFP_KERNEL); + hwmon = devm_kzalloc(dev, sizeof(*hwmon), GFP_KERNEL); if (!hwmon) return -ENOMEM; @@ -125,12 +114,11 @@ static int jz4740_hwmon_probe(struct platform_device *pdev) if (IS_ERR(hwmon->base)) return PTR_ERR(hwmon->base); + hwmon->pdev = pdev; init_completion(&hwmon->read_completion); mutex_init(&hwmon->lock); - platform_set_drvdata(pdev, hwmon); - - ret = devm_request_irq(&pdev->dev, hwmon->irq, jz4740_hwmon_irq, 0, + ret = devm_request_irq(dev, hwmon->irq, jz4740_hwmon_irq, 0, pdev->name, hwmon); if (ret) { dev_err(&pdev->dev, "Failed to request irq: %d\n", ret); @@ -138,38 +126,13 @@ static int jz4740_hwmon_probe(struct platform_device *pdev) } disable_irq(hwmon->irq); - ret = sysfs_create_group(&pdev->dev.kobj, &jz4740_hwmon_attr_group); - if (ret) { - dev_err(&pdev->dev, "Failed to create sysfs group: %d\n", ret); - return ret; - } - - hwmon->hwmon = hwmon_device_register(&pdev->dev); - if (IS_ERR(hwmon->hwmon)) { - ret = PTR_ERR(hwmon->hwmon); - goto err_remove_file; - } - - return 0; - -err_remove_file: - sysfs_remove_group(&pdev->dev.kobj, &jz4740_hwmon_attr_group); - return ret; -} - -static int jz4740_hwmon_remove(struct platform_device *pdev) -{ - struct jz4740_hwmon *hwmon = platform_get_drvdata(pdev); - - hwmon_device_unregister(hwmon->hwmon); - sysfs_remove_group(&pdev->dev.kobj, &jz4740_hwmon_attr_group); - - return 0; + hwmon_dev = devm_hwmon_device_register_with_groups(dev, "jz4740", hwmon, + jz4740_groups); + return PTR_ERR_OR_ZERO(hwmon_dev); } static struct platform_driver jz4740_hwmon_driver = { .probe = jz4740_hwmon_probe, - .remove = jz4740_hwmon_remove, .driver = { .name = "jz4740-hwmon", }, -- cgit v0.10.2 From 68f86c75ca1eaf790907eb43c68f9f2996474116 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Wed, 2 Jul 2014 20:31:21 +0800 Subject: hwmon: (ads7871) Convert to devm_hwmon_device_register_with_groups Use ATTRIBUTE_GROUPS macro and devm_hwmon_device_register_with_groups() to simplify the code a bit. The update_lock mutex is not used, so remove it. Signed-off-by: Axel Lin Signed-off-by: Guenter Roeck diff --git a/drivers/hwmon/ads7871.c b/drivers/hwmon/ads7871.c index 4fd9e4d..59bd7b9 100644 --- a/drivers/hwmon/ads7871.c +++ b/drivers/hwmon/ads7871.c @@ -66,14 +66,12 @@ #include #include #include -#include #include #define DEVICE_NAME "ads7871" struct ads7871_data { - struct device *hwmon_dev; - struct mutex update_lock; + struct spi_device *spi; }; static int ads7871_read_reg8(struct spi_device *spi, int reg) @@ -101,7 +99,8 @@ static int ads7871_write_reg8(struct spi_device *spi, int reg, u8 val) static ssize_t show_voltage(struct device *dev, struct device_attribute *da, char *buf) { - struct spi_device *spi = to_spi_device(dev); + struct ads7871_data *pdata = dev_get_drvdata(dev); + struct spi_device *spi = pdata->spi; struct sensor_device_attribute *attr = to_sensor_dev_attr(da); int ret, val, i = 0; uint8_t channel, mux_cnv; @@ -139,12 +138,6 @@ static ssize_t show_voltage(struct device *dev, } } -static ssize_t ads7871_show_name(struct device *dev, - struct device_attribute *devattr, char *buf) -{ - return sprintf(buf, "%s\n", to_spi_device(dev)->modalias); -} - static SENSOR_DEVICE_ATTR(in0_input, S_IRUGO, show_voltage, NULL, 0); static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, show_voltage, NULL, 1); static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, show_voltage, NULL, 2); @@ -154,9 +147,7 @@ static SENSOR_DEVICE_ATTR(in5_input, S_IRUGO, show_voltage, NULL, 5); static SENSOR_DEVICE_ATTR(in6_input, S_IRUGO, show_voltage, NULL, 6); static SENSOR_DEVICE_ATTR(in7_input, S_IRUGO, show_voltage, NULL, 7); -static DEVICE_ATTR(name, S_IRUGO, ads7871_show_name, NULL); - -static struct attribute *ads7871_attributes[] = { +static struct attribute *ads7871_attrs[] = { &sensor_dev_attr_in0_input.dev_attr.attr, &sensor_dev_attr_in1_input.dev_attr.attr, &sensor_dev_attr_in2_input.dev_attr.attr, @@ -165,21 +156,18 @@ static struct attribute *ads7871_attributes[] = { &sensor_dev_attr_in5_input.dev_attr.attr, &sensor_dev_attr_in6_input.dev_attr.attr, &sensor_dev_attr_in7_input.dev_attr.attr, - &dev_attr_name.attr, NULL }; -static const struct attribute_group ads7871_group = { - .attrs = ads7871_attributes, -}; +ATTRIBUTE_GROUPS(ads7871); static int ads7871_probe(struct spi_device *spi) { - int ret, err; + struct device *dev = &spi->dev; + int ret; uint8_t val; struct ads7871_data *pdata; - - dev_dbg(&spi->dev, "probe\n"); + struct device *hwmon_dev; /* Configure the SPI bus */ spi->mode = (SPI_MODE_0); @@ -193,7 +181,7 @@ static int ads7871_probe(struct spi_device *spi) ads7871_write_reg8(spi, REG_OSC_CONTROL, val); ret = ads7871_read_reg8(spi, REG_OSC_CONTROL); - dev_dbg(&spi->dev, "REG_OSC_CONTROL write:%x, read:%x\n", val, ret); + dev_dbg(dev, "REG_OSC_CONTROL write:%x, read:%x\n", val, ret); /* * because there is no other error checking on an SPI bus * we need to make sure we really have a chip @@ -201,46 +189,23 @@ static int ads7871_probe(struct spi_device *spi) if (val != ret) return -ENODEV; - pdata = devm_kzalloc(&spi->dev, sizeof(struct ads7871_data), - GFP_KERNEL); + pdata = devm_kzalloc(dev, sizeof(struct ads7871_data), GFP_KERNEL); if (!pdata) return -ENOMEM; - err = sysfs_create_group(&spi->dev.kobj, &ads7871_group); - if (err < 0) - return err; - - spi_set_drvdata(spi, pdata); + pdata->spi = spi; - pdata->hwmon_dev = hwmon_device_register(&spi->dev); - if (IS_ERR(pdata->hwmon_dev)) { - err = PTR_ERR(pdata->hwmon_dev); - goto error_remove; - } - - return 0; - -error_remove: - sysfs_remove_group(&spi->dev.kobj, &ads7871_group); - return err; -} - -static int ads7871_remove(struct spi_device *spi) -{ - struct ads7871_data *pdata = spi_get_drvdata(spi); - - hwmon_device_unregister(pdata->hwmon_dev); - sysfs_remove_group(&spi->dev.kobj, &ads7871_group); - return 0; + hwmon_dev = devm_hwmon_device_register_with_groups(dev, spi->modalias, + pdata, + ads7871_groups); + return PTR_ERR_OR_ZERO(hwmon_dev); } static struct spi_driver ads7871_driver = { .driver = { .name = DEVICE_NAME, }, - .probe = ads7871_probe, - .remove = ads7871_remove, }; module_spi_driver(ads7871_driver); -- cgit v0.10.2 From 747bc8b063ae6b66447918280922253721cb1d9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pali=20Roh=C3=A1r?= Date: Sat, 18 Jun 2016 00:54:48 +0200 Subject: hwmon: (dell-smm) Detect fan with index=2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Some Dell machines (e.g. Dell Precision M3800) have two fans, first with index=0 and second with index=2. So export also attributes for third fan device with index=2. Reported-by: Tolga Cakir Signed-off-by: Pali Rohár Tested-by: Tolga Cakir Signed-off-by: Guenter Roeck diff --git a/drivers/hwmon/dell-smm-hwmon.c b/drivers/hwmon/dell-smm-hwmon.c index 2ac87d5..571d498 100644 --- a/drivers/hwmon/dell-smm-hwmon.c +++ b/drivers/hwmon/dell-smm-hwmon.c @@ -81,6 +81,7 @@ static bool disallow_fan_type_call; #define I8K_HWMON_HAVE_TEMP4 (1 << 3) #define I8K_HWMON_HAVE_FAN1 (1 << 4) #define I8K_HWMON_HAVE_FAN2 (1 << 5) +#define I8K_HWMON_HAVE_FAN3 (1 << 6) MODULE_AUTHOR("Massimo Dal Zotto (dz@debian.org)"); MODULE_AUTHOR("Pali Rohár "); @@ -252,7 +253,7 @@ static int _i8k_get_fan_type(int fan) static int i8k_get_fan_type(int fan) { /* I8K_SMM_GET_FAN_TYPE SMM call is expensive, so cache values */ - static int types[2] = { INT_MIN, INT_MIN }; + static int types[3] = { INT_MIN, INT_MIN, INT_MIN }; if (types[fan] == INT_MIN) types[fan] = _i8k_get_fan_type(fan); @@ -719,6 +720,12 @@ static SENSOR_DEVICE_ATTR(fan2_label, S_IRUGO, i8k_hwmon_show_fan_label, NULL, 1); static SENSOR_DEVICE_ATTR(pwm2, S_IRUGO | S_IWUSR, i8k_hwmon_show_pwm, i8k_hwmon_set_pwm, 1); +static SENSOR_DEVICE_ATTR(fan3_input, S_IRUGO, i8k_hwmon_show_fan, NULL, + 2); +static SENSOR_DEVICE_ATTR(fan3_label, S_IRUGO, i8k_hwmon_show_fan_label, NULL, + 2); +static SENSOR_DEVICE_ATTR(pwm3, S_IRUGO | S_IWUSR, i8k_hwmon_show_pwm, + i8k_hwmon_set_pwm, 2); static struct attribute *i8k_attrs[] = { &sensor_dev_attr_temp1_input.dev_attr.attr, /* 0 */ @@ -735,6 +742,9 @@ static struct attribute *i8k_attrs[] = { &sensor_dev_attr_fan2_input.dev_attr.attr, /* 11 */ &sensor_dev_attr_fan2_label.dev_attr.attr, /* 12 */ &sensor_dev_attr_pwm2.dev_attr.attr, /* 13 */ + &sensor_dev_attr_fan3_input.dev_attr.attr, /* 14 */ + &sensor_dev_attr_fan3_label.dev_attr.attr, /* 15 */ + &sensor_dev_attr_pwm3.dev_attr.attr, /* 16 */ NULL }; @@ -742,7 +752,7 @@ static umode_t i8k_is_visible(struct kobject *kobj, struct attribute *attr, int index) { if (disallow_fan_type_call && - (index == 9 || index == 12)) + (index == 9 || index == 12 || index == 15)) return 0; if (index >= 0 && index <= 1 && !(i8k_hwmon_flags & I8K_HWMON_HAVE_TEMP1)) @@ -762,6 +772,9 @@ static umode_t i8k_is_visible(struct kobject *kobj, struct attribute *attr, if (index >= 11 && index <= 13 && !(i8k_hwmon_flags & I8K_HWMON_HAVE_FAN2)) return 0; + if (index >= 14 && index <= 16 && + !(i8k_hwmon_flags & I8K_HWMON_HAVE_FAN3)) + return 0; return attr->mode; } @@ -807,6 +820,13 @@ static int __init i8k_init_hwmon(void) if (err >= 0) i8k_hwmon_flags |= I8K_HWMON_HAVE_FAN2; + /* Third fan attributes, if fan status or type is OK */ + err = i8k_get_fan_status(2); + if (err < 0) + err = i8k_get_fan_type(2); + if (err >= 0) + i8k_hwmon_flags |= I8K_HWMON_HAVE_FAN3; + i8k_hwmon_dev = hwmon_device_register_with_groups(NULL, "dell_smm", NULL, i8k_groups); if (IS_ERR(i8k_hwmon_dev)) { -- cgit v0.10.2 From 9d58bec0966bfc87948244b81056137e6d214e04 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pali=20Roh=C3=A1r?= Date: Sat, 18 Jun 2016 00:54:49 +0200 Subject: hwmon: (dell-smm) In debug mode log duration of SMM calls MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This allow us to debug how long take each SMM call and how long is system frozen in SMM handler. Signed-off-by: Pali Rohár Signed-off-by: Guenter Roeck diff --git a/drivers/hwmon/dell-smm-hwmon.c b/drivers/hwmon/dell-smm-hwmon.c index 571d498..acf9c03 100644 --- a/drivers/hwmon/dell-smm-hwmon.c +++ b/drivers/hwmon/dell-smm-hwmon.c @@ -140,6 +140,14 @@ static int i8k_smm(struct smm_regs *regs) int eax = regs->eax; cpumask_var_t old_mask; +#ifdef DEBUG + int ebx = regs->ebx; + unsigned long duration; + ktime_t calltime, delta, rettime; + + calltime = ktime_get(); +#endif + /* SMM requires CPU 0 */ if (!alloc_cpumask_var(&old_mask, GFP_KERNEL)) return -ENOMEM; @@ -211,6 +219,15 @@ static int i8k_smm(struct smm_regs *regs) out: set_cpus_allowed_ptr(current, old_mask); free_cpumask_var(old_mask); + +#ifdef DEBUG + rettime = ktime_get(); + delta = ktime_sub(rettime, calltime); + duration = ktime_to_ns(delta) >> 10; + pr_debug("smm(0x%.4x 0x%.4x) = 0x%.4x (took %7lu usecs)\n", eax, ebx, + (rc ? 0xffff : regs->eax & 0xffff), duration); +#endif + return rc; } -- cgit v0.10.2 From 51b8c2cd92f1b59657a13339dffcca79c76126d1 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Fri, 24 Jun 2016 18:31:32 +0100 Subject: hwmon: (emc6w201): trivial fix of spelling mistake "Unknwown" -> "Unknown" trivial fix to spelling mistake in dev_dbg message Signed-off-by: Colin Ian King Signed-off-by: Guenter Roeck diff --git a/drivers/hwmon/emc6w201.c b/drivers/hwmon/emc6w201.c index ada9071..f37fe201 100644 --- a/drivers/hwmon/emc6w201.c +++ b/drivers/hwmon/emc6w201.c @@ -464,7 +464,7 @@ static int emc6w201_detect(struct i2c_client *client, if (verstep < 0 || (verstep & 0xF0) != 0xB0) return -ENODEV; if ((verstep & 0x0F) > 2) { - dev_dbg(&client->dev, "Unknwown EMC6W201 stepping %d\n", + dev_dbg(&client->dev, "Unknown EMC6W201 stepping %d\n", verstep & 0x0F); return -ENODEV; } -- cgit v0.10.2 From 9ad0df1adac20d694fbb8e7cb7bac04e0645a927 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Fri, 24 Jun 2016 19:41:57 -0700 Subject: hwmon: (ina3221) Fix negative limits The result of an integer divide by an unsigned is undefined. This causes unexpected results when writing negative values into the limit registers. Maintain the shunt_resistors variables as signed integer to avoid the problem. Also, for simplicity and ease of use, clamp shunt resistor value on writes instead of rejecting bad values. Cc: Andrew F. Davis Acked-by: Andrew F. Davis Signed-off-by: Guenter Roeck diff --git a/drivers/hwmon/ina3221.c b/drivers/hwmon/ina3221.c index d055b6a..e6b4950 100644 --- a/drivers/hwmon/ina3221.c +++ b/drivers/hwmon/ina3221.c @@ -95,7 +95,7 @@ static const unsigned int register_channel[] = { struct ina3221_data { struct regmap *regmap; struct regmap_field *fields[F_MAX_FIELDS]; - unsigned int shunt_resistors[INA3221_NUM_CHANNELS]; + int shunt_resistors[INA3221_NUM_CHANNELS]; }; static int ina3221_read_value(struct ina3221_data *ina, unsigned int reg, @@ -155,7 +155,7 @@ static ssize_t ina3221_show_current(struct device *dev, struct ina3221_data *ina = dev_get_drvdata(dev); unsigned int reg = sd_attr->index; unsigned int channel = register_channel[reg]; - unsigned int resistance_uo = ina->shunt_resistors[channel]; + int resistance_uo = ina->shunt_resistors[channel]; int val, current_ma, voltage_nv, ret; ret = ina3221_read_value(ina, reg, &val); @@ -176,7 +176,7 @@ static ssize_t ina3221_set_current(struct device *dev, struct ina3221_data *ina = dev_get_drvdata(dev); unsigned int reg = sd_attr->index; unsigned int channel = register_channel[reg]; - unsigned int resistance_uo = ina->shunt_resistors[channel]; + int resistance_uo = ina->shunt_resistors[channel]; int val, current_ma, voltage_uv, ret; ret = kstrtoint(buf, 0, ¤t_ma); @@ -223,15 +223,14 @@ static ssize_t ina3221_set_shunt(struct device *dev, struct sensor_device_attribute *sd_attr = to_sensor_dev_attr(attr); struct ina3221_data *ina = dev_get_drvdata(dev); unsigned int channel = sd_attr->index; - unsigned int val; + int val; int ret; - ret = kstrtouint(buf, 0, &val); + ret = kstrtoint(buf, 0, &val); if (ret) return ret; - if (val == 0) - return -EINVAL; + val = clamp_val(val, 1, INT_MAX); ina->shunt_resistors[channel] = val; -- cgit v0.10.2 From a31887dc9be1a65cde2562ed10e7fbf5c82581a2 Mon Sep 17 00:00:00 2001 From: Alison Schofield Date: Mon, 27 Jun 2016 17:23:27 -0700 Subject: hwmon: (jc42) Add support for Microchip MCP9808 temperature sensor MCP9808 is not officially compliant to JC-42, similar to MCP9804, but its registers are compatible to JC-42. Signed-off-by: Alison Schofield Cc: Daniel Baluta Signed-off-by: Guenter Roeck diff --git a/Documentation/hwmon/jc42 b/Documentation/hwmon/jc42 index f7f1830a..b4b671f 100644 --- a/Documentation/hwmon/jc42 +++ b/Documentation/hwmon/jc42 @@ -18,10 +18,11 @@ Supported chips: * Maxim MAX6604 Datasheets: http://datasheets.maxim-ic.com/en/ds/MAX6604.pdf - * Microchip MCP9804, MCP9805, MCP98242, MCP98243, MCP98244, MCP9843 + * Microchip MCP9804, MCP9805, MCP9808, MCP98242, MCP98243, MCP98244, MCP9843 Datasheets: http://ww1.microchip.com/downloads/en/DeviceDoc/22203C.pdf http://ww1.microchip.com/downloads/en/DeviceDoc/21977b.pdf + http://ww1.microchip.com/downloads/en/DeviceDoc/25095A.pdf http://ww1.microchip.com/downloads/en/DeviceDoc/21996a.pdf http://ww1.microchip.com/downloads/en/DeviceDoc/22153c.pdf http://ww1.microchip.com/downloads/en/DeviceDoc/22327A.pdf diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index b2aa13b..91f145e 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -645,8 +645,8 @@ config SENSORS_JC42 temperature sensors, which are used on many DDR3 memory modules for mobile devices and servers. Support will include, but not be limited to, ADT7408, AT30TS00, CAT34TS02, CAT6095, MAX6604, MCP9804, MCP9805, - MCP98242, MCP98243, MCP98244, MCP9843, SE97, SE98, STTS424(E), - STTS2002, STTS3000, TSE2002, TSE2004, TS3000, and TS3001. + MCP9808, MCP98242, MCP98243, MCP98244, MCP9843, SE97, SE98, + STTS424(E), STTS2002, STTS3000, TSE2002, TSE2004, TS3000, and TS3001. This driver can also be built as a module. If so, the module will be called jc42. diff --git a/drivers/hwmon/jc42.c b/drivers/hwmon/jc42.c index 9887d32..f67c1bb 100644 --- a/drivers/hwmon/jc42.c +++ b/drivers/hwmon/jc42.c @@ -104,6 +104,9 @@ static const unsigned short normal_i2c[] = { #define MCP9804_DEVID 0x0200 #define MCP9804_DEVID_MASK 0xfffc +#define MCP9808_DEVID 0x0400 +#define MCP9808_DEVID_MASK 0xfffc + #define MCP98242_DEVID 0x2000 #define MCP98242_DEVID_MASK 0xfffc @@ -160,6 +163,7 @@ static struct jc42_chips jc42_chips[] = { { IDT_MANID, TS3001_DEVID, TS3001_DEVID_MASK }, { MAX_MANID, MAX6604_DEVID, MAX6604_DEVID_MASK }, { MCP_MANID, MCP9804_DEVID, MCP9804_DEVID_MASK }, + { MCP_MANID, MCP9808_DEVID, MCP9808_DEVID_MASK }, { MCP_MANID, MCP98242_DEVID, MCP98242_DEVID_MASK }, { MCP_MANID, MCP98243_DEVID, MCP98243_DEVID_MASK }, { MCP_MANID, MCP98244_DEVID, MCP98244_DEVID_MASK }, -- cgit v0.10.2 From b17ea1ca1da115050959d24353e58ccae8aacb58 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Sun, 19 Jun 2016 20:09:54 -0700 Subject: hwmon: (tmp102) Use devm_add_action to register cleanup function By registering a cleanup function with devm_add_action(), we can simplify the error path in the probe function and drop the remove function entirely. Acked-by: Nishanth Menon Signed-off-by: Guenter Roeck diff --git a/drivers/hwmon/tmp102.c b/drivers/hwmon/tmp102.c index f1e96fd..befd06b 100644 --- a/drivers/hwmon/tmp102.c +++ b/drivers/hwmon/tmp102.c @@ -52,7 +52,6 @@ struct tmp102 { struct i2c_client *client; - struct device *hwmon_dev; struct mutex lock; u16 config_orig; unsigned long last_update; @@ -173,6 +172,15 @@ static const struct thermal_zone_of_device_ops tmp102_of_thermal_ops = { .get_temp = tmp102_read_temp, }; +static void tmp102_restore_config(void *data) +{ + struct tmp102 *tmp102 = data; + struct i2c_client *client = tmp102->client; + + i2c_smbus_write_word_swapped(client, TMP102_CONF_REG, + tmp102->config_orig); +} + static int tmp102_probe(struct i2c_client *client, const struct i2c_device_id *id) { @@ -201,66 +209,43 @@ static int tmp102_probe(struct i2c_client *client, return status; } tmp102->config_orig = status; + + devm_add_action(dev, tmp102_restore_config, tmp102); + status = i2c_smbus_write_word_swapped(client, TMP102_CONF_REG, TMP102_CONFIG); if (status < 0) { dev_err(dev, "error writing config register\n"); - goto fail_restore_config; + return status; } status = i2c_smbus_read_word_swapped(client, TMP102_CONF_REG); if (status < 0) { dev_err(dev, "error reading config register\n"); - goto fail_restore_config; + return status; } status &= ~TMP102_CONFIG_RD_ONLY; if (status != TMP102_CONFIG) { dev_err(dev, "config settings did not stick\n"); - status = -ENODEV; - goto fail_restore_config; + return -ENODEV; } tmp102->last_update = jiffies; /* Mark that we are not ready with data until conversion is complete */ tmp102->first_time = true; mutex_init(&tmp102->lock); - hwmon_dev = hwmon_device_register_with_groups(dev, client->name, - tmp102, tmp102_groups); + hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name, + tmp102, + tmp102_groups); if (IS_ERR(hwmon_dev)) { dev_dbg(dev, "unable to register hwmon device\n"); - status = PTR_ERR(hwmon_dev); - goto fail_restore_config; + return PTR_ERR(hwmon_dev); } - tmp102->hwmon_dev = hwmon_dev; devm_thermal_zone_of_sensor_register(hwmon_dev, 0, hwmon_dev, &tmp102_of_thermal_ops); dev_info(dev, "initialized\n"); return 0; - -fail_restore_config: - i2c_smbus_write_word_swapped(client, TMP102_CONF_REG, - tmp102->config_orig); - return status; -} - -static int tmp102_remove(struct i2c_client *client) -{ - struct tmp102 *tmp102 = i2c_get_clientdata(client); - - hwmon_device_unregister(tmp102->hwmon_dev); - - /* Stop monitoring if device was stopped originally */ - if (tmp102->config_orig & TMP102_CONF_SD) { - int config; - - config = i2c_smbus_read_word_swapped(client, TMP102_CONF_REG); - if (config >= 0) - i2c_smbus_write_word_swapped(client, TMP102_CONF_REG, - config | TMP102_CONF_SD); - } - - return 0; } #ifdef CONFIG_PM_SLEEP @@ -303,7 +288,6 @@ static struct i2c_driver tmp102_driver = { .driver.name = DRIVER_NAME, .driver.pm = &tmp102_dev_pm_ops, .probe = tmp102_probe, - .remove = tmp102_remove, .id_table = tmp102_id, }; -- cgit v0.10.2 From 4e6163e859cd572acb4bc2525e00714f6c1905c8 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Wed, 22 Jun 2016 10:40:07 -0700 Subject: hwmon: (tmp102) Drop FSF address The FSF address can change, so drop it from the driver. Acked-by: Nishanth Menon Signed-off-by: Guenter Roeck diff --git a/drivers/hwmon/tmp102.c b/drivers/hwmon/tmp102.c index befd06b..5bdf262 100644 --- a/drivers/hwmon/tmp102.c +++ b/drivers/hwmon/tmp102.c @@ -11,10 +11,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA */ #include -- cgit v0.10.2 From 2c436e46fabd9f34d0127f7ff3e3678ef826b55e Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Thu, 16 Jun 2016 15:47:49 +0200 Subject: clocksource/drivers/armada-370-xp: Make syscore_ops static The driver does not export armada_370_xp_timer_syscore_ops so make it static to fix the following warning: drivers/clocksource/time-armada-370-xp.c:249:20: warning: symbol 'armada_370_xp_timer_syscore_ops' was not declared. Should it be static? Signed-off-by: Ben Dooks Signed-off-by: Daniel Lezcano Acked-by: Gregory CLEMENT diff --git a/drivers/clocksource/time-armada-370-xp.c b/drivers/clocksource/time-armada-370-xp.c index d93ec3c..601dbf74 100644 --- a/drivers/clocksource/time-armada-370-xp.c +++ b/drivers/clocksource/time-armada-370-xp.c @@ -246,7 +246,7 @@ static void armada_370_xp_timer_resume(void) writel(timer0_local_ctrl_reg, local_base + TIMER_CTRL_OFF); } -struct syscore_ops armada_370_xp_timer_syscore_ops = { +static struct syscore_ops armada_370_xp_timer_syscore_ops = { .suspend = armada_370_xp_timer_suspend, .resume = armada_370_xp_timer_resume, }; -- cgit v0.10.2 From 48419b1bf04d185bd4e8950f938d89be552876d0 Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Thu, 16 Jun 2016 15:49:23 +0200 Subject: clocksource/drivers/digicolor: Fix warning of non-static function Change the dc_timer function to be static as it is not used outside this driver. This fixes the following warning: drivers/clocksource/timer-digicolor.c:66:24: warning: symbol 'dc_timer' was not declared. Should it be static? Signed-off-by: Ben Dooks Signed-off-by: Daniel Lezcano Acked-by: Baruch Siach diff --git a/drivers/clocksource/timer-digicolor.c b/drivers/clocksource/timer-digicolor.c index a536eeb..96bb222 100644 --- a/drivers/clocksource/timer-digicolor.c +++ b/drivers/clocksource/timer-digicolor.c @@ -63,7 +63,7 @@ struct digicolor_timer { int timer_id; /* one of TIMER_* */ }; -struct digicolor_timer *dc_timer(struct clock_event_device *ce) +static struct digicolor_timer *dc_timer(struct clock_event_device *ce) { return container_of(ce, struct digicolor_timer, ce); } -- cgit v0.10.2 From 7cc061797be91ca02a95f4d01f0275831c588671 Mon Sep 17 00:00:00 2001 From: Matthew Leach Date: Thu, 16 Jun 2016 15:51:29 +0200 Subject: clocksource/drivers/samsung_pwm_timer: Fix endian accessors Fix the Samsung pwm timer access code to deal with kernels built for big endian operation. Signed-off-by: Matthew Leach Signed-off-by: Daniel Lezcano Reviewed-by: Krzysztof Kozlowski diff --git a/drivers/clocksource/samsung_pwm_timer.c b/drivers/clocksource/samsung_pwm_timer.c index 9502bc4..47e0515 100644 --- a/drivers/clocksource/samsung_pwm_timer.c +++ b/drivers/clocksource/samsung_pwm_timer.c @@ -130,9 +130,9 @@ static void samsung_time_stop(unsigned int channel) spin_lock_irqsave(&samsung_pwm_lock, flags); - tcon = __raw_readl(pwm.base + REG_TCON); + tcon = readl_relaxed(pwm.base + REG_TCON); tcon &= ~TCON_START(channel); - __raw_writel(tcon, pwm.base + REG_TCON); + writel_relaxed(tcon, pwm.base + REG_TCON); spin_unlock_irqrestore(&samsung_pwm_lock, flags); } @@ -148,14 +148,14 @@ static void samsung_time_setup(unsigned int channel, unsigned long tcnt) spin_lock_irqsave(&samsung_pwm_lock, flags); - tcon = __raw_readl(pwm.base + REG_TCON); + tcon = readl_relaxed(pwm.base + REG_TCON); tcon &= ~(TCON_START(tcon_chan) | TCON_AUTORELOAD(tcon_chan)); tcon |= TCON_MANUALUPDATE(tcon_chan); - __raw_writel(tcnt, pwm.base + REG_TCNTB(channel)); - __raw_writel(tcnt, pwm.base + REG_TCMPB(channel)); - __raw_writel(tcon, pwm.base + REG_TCON); + writel_relaxed(tcnt, pwm.base + REG_TCNTB(channel)); + writel_relaxed(tcnt, pwm.base + REG_TCMPB(channel)); + writel_relaxed(tcon, pwm.base + REG_TCON); spin_unlock_irqrestore(&samsung_pwm_lock, flags); } @@ -170,7 +170,7 @@ static void samsung_time_start(unsigned int channel, bool periodic) spin_lock_irqsave(&samsung_pwm_lock, flags); - tcon = __raw_readl(pwm.base + REG_TCON); + tcon = readl_relaxed(pwm.base + REG_TCON); tcon &= ~TCON_MANUALUPDATE(channel); tcon |= TCON_START(channel); @@ -180,7 +180,7 @@ static void samsung_time_start(unsigned int channel, bool periodic) else tcon &= ~TCON_AUTORELOAD(channel); - __raw_writel(tcon, pwm.base + REG_TCON); + writel_relaxed(tcon, pwm.base + REG_TCON); spin_unlock_irqrestore(&samsung_pwm_lock, flags); } -- cgit v0.10.2 From de37b0b569cf89ac7e27141c9305509007cba2d6 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Thu, 16 Jun 2016 15:53:18 +0200 Subject: clocksource/drivers/samsung_pwm: Fix typo in Kconfig Correct the typo in "driver" word in the option description. Signed-off-by: Alexandre Belloni Signed-off-by: Daniel Lezcano diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig index 47352d2..6bbd3d8 100644 --- a/drivers/clocksource/Kconfig +++ b/drivers/clocksource/Kconfig @@ -270,7 +270,7 @@ config CLKSRC_EXYNOS_MCT Support for Multi Core Timer controller on Exynos SoCs. config CLKSRC_SAMSUNG_PWM - bool "PWM timer drvier for Samsung S3C, S5P" if COMPILE_TEST + bool "PWM timer driver for Samsung S3C, S5P" if COMPILE_TEST depends on GENERIC_CLOCKEVENTS depends on HAS_IOMEM help -- cgit v0.10.2 From 85889876ca37d67c20d14e444b111c0b81744b3e Mon Sep 17 00:00:00 2001 From: Huang Tao Date: Thu, 16 Jun 2016 15:54:27 +0200 Subject: dt-bindings: Document rk3399 rk-timer bindings Add a compatible string for rk3399 SoC because the timer is slightly different from the older SoCs. So rename the file name from rockchip,rk3288-timer.txt to rockchip,rk-timer.txt and clarify rockchip,rk3288-timer supported SoCs. Signed-off-by: Huang Tao Cc: Rob Herring Cc: Daniel Lezcano Cc: Thomas Gleixner Cc: Heiko Stuebner Signed-off-by: Caesar Wang Acked-by: Rob Herring Signed-off-by: Daniel Lezcano diff --git a/Documentation/devicetree/bindings/timer/rockchip,rk-timer.txt b/Documentation/devicetree/bindings/timer/rockchip,rk-timer.txt new file mode 100644 index 0000000..a41b184 --- /dev/null +++ b/Documentation/devicetree/bindings/timer/rockchip,rk-timer.txt @@ -0,0 +1,20 @@ +Rockchip rk timer + +Required properties: +- compatible: shall be one of: + "rockchip,rk3288-timer" - for rk3066, rk3036, rk3188, rk322x, rk3288, rk3368 + "rockchip,rk3399-timer" - for rk3399 +- reg: base address of the timer register starting with TIMERS CONTROL register +- interrupts: should contain the interrupts for Timer0 +- clocks : must contain an entry for each entry in clock-names +- clock-names : must include the following entries: + "timer", "pclk" + +Example: + timer: timer@ff810000 { + compatible = "rockchip,rk3288-timer"; + reg = <0xff810000 0x20>; + interrupts = ; + clocks = <&xin24m>, <&cru PCLK_TIMER>; + clock-names = "timer", "pclk"; + }; diff --git a/Documentation/devicetree/bindings/timer/rockchip,rk3288-timer.txt b/Documentation/devicetree/bindings/timer/rockchip,rk3288-timer.txt deleted file mode 100644 index 87f0b00..0000000 --- a/Documentation/devicetree/bindings/timer/rockchip,rk3288-timer.txt +++ /dev/null @@ -1,18 +0,0 @@ -Rockchip rk3288 timer - -Required properties: -- compatible: shall be "rockchip,rk3288-timer" -- reg: base address of the timer register starting with TIMERS CONTROL register -- interrupts: should contain the interrupts for Timer0 -- clocks : must contain an entry for each entry in clock-names -- clock-names : must include the following entries: - "timer", "pclk" - -Example: - timer: timer@ff810000 { - compatible = "rockchip,rk3288-timer"; - reg = <0xff810000 0x20>; - interrupts = ; - clocks = <&xin24m>, <&cru PCLK_TIMER>; - clock-names = "timer", "pclk"; - }; -- cgit v0.10.2 From 716897d90f2bb1b732c45ddcc1f2f4651a06a9f6 Mon Sep 17 00:00:00 2001 From: "Huang, Tao" Date: Thu, 16 Jun 2016 15:57:53 +0200 Subject: clocksource/drivers/rockchip: Add the dynamic irq flag to the timer The rockchip timer is a broadcast timer. Add the CLOCK_EVT_FEAT_DYNIRQ flag and set the cpumask to all possible cpus to save power by avoiding unnecessary wakeups and IPIs. Signed-off-by: Huang Tao Cc: Daniel Lezcano Cc: Thomas Gleixner Cc: Heiko Stuebner Tested-by: Jianqun Xu Signed-off-by: Caesar Wang Signed-off-by: Daniel Lezcano diff --git a/drivers/clocksource/rockchip_timer.c b/drivers/clocksource/rockchip_timer.c index b991b28..b510863 100644 --- a/drivers/clocksource/rockchip_timer.c +++ b/drivers/clocksource/rockchip_timer.c @@ -150,12 +150,13 @@ static void __init rk_timer_init(struct device_node *np) } ce->name = TIMER_NAME; - ce->features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT; + ce->features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT | + CLOCK_EVT_FEAT_DYNIRQ; ce->set_next_event = rk_timer_set_next_event; ce->set_state_shutdown = rk_timer_shutdown; ce->set_state_periodic = rk_timer_set_periodic; ce->irq = irq; - ce->cpumask = cpumask_of(0); + ce->cpumask = cpu_possible_mask; ce->rating = 250; rk_timer_interrupt_clear(ce); -- cgit v0.10.2 From be6af450bb1b74177f14afc6228458f16f92a6c5 Mon Sep 17 00:00:00 2001 From: "Huang, Tao" Date: Thu, 16 Jun 2016 16:00:08 +0200 Subject: clocksource/drivers/rockchip: Add support for the rk3399 SoC The only difference between the rk3399 SoC and the other ones is the control register offset which is different. Add a new field to store the control register address depending on the SoC and use it instead of the + . Signed-off-by: Huang Tao Cc: Daniel Lezcano Cc: Thomas Gleixner Cc: Heiko Stuebner Tested-by: Jianqun Xu Signed-off-by: Caesar Wang Signed-off-by: Daniel Lezcano diff --git a/drivers/clocksource/rockchip_timer.c b/drivers/clocksource/rockchip_timer.c index b510863..a3f22b0 100644 --- a/drivers/clocksource/rockchip_timer.c +++ b/drivers/clocksource/rockchip_timer.c @@ -19,7 +19,8 @@ #define TIMER_LOAD_COUNT0 0x00 #define TIMER_LOAD_COUNT1 0x04 -#define TIMER_CONTROL_REG 0x10 +#define TIMER_CONTROL_REG3288 0x10 +#define TIMER_CONTROL_REG3399 0x1c #define TIMER_INT_STATUS 0x18 #define TIMER_DISABLE 0x0 @@ -31,6 +32,7 @@ struct bc_timer { struct clock_event_device ce; void __iomem *base; + void __iomem *ctrl; u32 freq; }; @@ -46,15 +48,20 @@ static inline void __iomem *rk_base(struct clock_event_device *ce) return rk_timer(ce)->base; } +static inline void __iomem *rk_ctrl(struct clock_event_device *ce) +{ + return rk_timer(ce)->ctrl; +} + static inline void rk_timer_disable(struct clock_event_device *ce) { - writel_relaxed(TIMER_DISABLE, rk_base(ce) + TIMER_CONTROL_REG); + writel_relaxed(TIMER_DISABLE, rk_ctrl(ce)); } static inline void rk_timer_enable(struct clock_event_device *ce, u32 flags) { writel_relaxed(TIMER_ENABLE | TIMER_INT_UNMASK | flags, - rk_base(ce) + TIMER_CONTROL_REG); + rk_ctrl(ce)); } static void rk_timer_update_counter(unsigned long cycles, @@ -106,7 +113,7 @@ static irqreturn_t rk_timer_interrupt(int irq, void *dev_id) return IRQ_HANDLED; } -static void __init rk_timer_init(struct device_node *np) +static void __init rk_timer_init(struct device_node *np, u32 ctrl_reg) { struct clock_event_device *ce = &bc_timer.ce; struct clk *timer_clk; @@ -118,6 +125,7 @@ static void __init rk_timer_init(struct device_node *np) pr_err("Failed to get base address for '%s'\n", TIMER_NAME); return; } + bc_timer.ctrl = bc_timer.base + ctrl_reg; pclk = of_clk_get_by_name(np, "pclk"); if (IS_ERR(pclk)) { @@ -180,4 +188,17 @@ out_unmap: iounmap(bc_timer.base); } -CLOCKSOURCE_OF_DECLARE(rk_timer, "rockchip,rk3288-timer", rk_timer_init); +static void __init rk3288_timer_init(struct device_node *np) +{ + rk_timer_init(np, TIMER_CONTROL_REG3288); +} + +static void __init rk3399_timer_init(struct device_node *np) +{ + rk_timer_init(np, TIMER_CONTROL_REG3399); +} + +CLOCKSOURCE_OF_DECLARE(rk3288_timer, "rockchip,rk3288-timer", + rk3288_timer_init); +CLOCKSOURCE_OF_DECLARE(rk3399_timer, "rockchip,rk3399-timer", + rk3399_timer_init); -- cgit v0.10.2 From 1e8567d53d3bbefe3f6e0a27685da1b842f4c1fa Mon Sep 17 00:00:00 2001 From: Huang Tao Date: Thu, 16 Jun 2016 16:18:58 +0200 Subject: arm64: dts: rockchip: Add rktimer device node for rk3399 Add a 'rktimer' node in the device treee for the ARM64 rk3399 SoC. Signed-off-by: Huang Tao Cc: Daniel Lezcano Cc: Thomas Gleixner Cc: Heiko Stuebner Tested-by: Jianqun Xu Signed-off-by: Caesar Wang Signed-off-by: Daniel Lezcano diff --git a/arch/arm64/boot/dts/rockchip/rk3399.dtsi b/arch/arm64/boot/dts/rockchip/rk3399.dtsi index 46f325a..f0c0d76 100644 --- a/arch/arm64/boot/dts/rockchip/rk3399.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3399.dtsi @@ -492,6 +492,14 @@ interrupts = ; }; + rktimer: rktimer@ff850000 { + compatible = "rockchip,rk3399-timer"; + reg = <0x0 0xff850000 0x0 0x1000>; + interrupts = ; + clocks = <&cru PCLK_TIMER0>, <&cru SCLK_TIMER00>; + clock-names = "pclk", "timer"; + }; + spdif: spdif@ff870000 { compatible = "rockchip,rk3399-spdif"; reg = <0x0 0xff870000 0x0 0x1000>; -- cgit v0.10.2 From 89355274e1f7f218186bb15a9f0c4b4a026a84d3 Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Wed, 15 Jun 2016 12:13:26 +0200 Subject: clocksource/drivers/oxnas-rps: Add Oxford Semiconductor RPS Dual Timer Add clocksource and clockevent driver from dual RPS timer. The HW provides a dual one-shot or periodic 24bit timers, the drivers set the first one as tick event source and the second as a continuous scheduler clock source. The timer can use 1, 16 or 256 as pre-dividers, thus the clocksource uses 16 by default. CC: Ma Haijun Signed-off-by: Neil Armstrong Signed-off-by: Daniel Lezcano diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig index 6bbd3d8..d4b9e04 100644 --- a/drivers/clocksource/Kconfig +++ b/drivers/clocksource/Kconfig @@ -293,6 +293,14 @@ config VF_PIT_TIMER help Support for Period Interrupt Timer on Freescale Vybrid Family SoCs. +config OXNAS_RPS_TIMER + bool "Oxford Semiconductor OXNAS RPS Timers driver" if COMPILE_TEST + depends on GENERIC_CLOCKEVENTS + select CLKSRC_OF + select CLKSRC_MMIO + help + This enables support for the Oxford Semiconductor OXNAS RPS timers. + config SYS_SUPPORTS_SH_CMT bool diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile index 473974f..bc66981 100644 --- a/drivers/clocksource/Makefile +++ b/drivers/clocksource/Makefile @@ -48,6 +48,7 @@ obj-$(CONFIG_MTK_TIMER) += mtk_timer.o obj-$(CONFIG_CLKSRC_PISTACHIO) += time-pistachio.o obj-$(CONFIG_CLKSRC_TI_32K) += timer-ti-32k.o obj-$(CONFIG_CLKSRC_NPS) += timer-nps.o +obj-$(CONFIG_OXNAS_RPS_TIMER) += timer-oxnas-rps.o obj-$(CONFIG_ARM_ARCH_TIMER) += arm_arch_timer.o obj-$(CONFIG_ARM_GLOBAL_TIMER) += arm_global_timer.o diff --git a/drivers/clocksource/timer-oxnas-rps.c b/drivers/clocksource/timer-oxnas-rps.c new file mode 100644 index 0000000..c002e99 --- /dev/null +++ b/drivers/clocksource/timer-oxnas-rps.c @@ -0,0 +1,290 @@ +/* + * drivers/clocksource/timer-oxnas-rps.c + * + * Copyright (C) 2009 Oxford Semiconductor Ltd + * Copyright (C) 2013 Ma Haijun + * Copyright (C) 2016 Neil Armstrong + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* TIMER1 used as tick + * TIMER2 used as clocksource + */ + +/* Registers definitions */ + +#define TIMER_LOAD_REG 0x0 +#define TIMER_CURR_REG 0x4 +#define TIMER_CTRL_REG 0x8 +#define TIMER_CLRINT_REG 0xC + +#define TIMER_BITS 24 + +#define TIMER_MAX_VAL (BIT(TIMER_BITS) - 1) + +#define TIMER_PERIODIC BIT(6) +#define TIMER_ENABLE BIT(7) + +#define TIMER_DIV1 (0) +#define TIMER_DIV16 (1 << 2) +#define TIMER_DIV256 (2 << 2) + +#define TIMER1_REG_OFFSET 0 +#define TIMER2_REG_OFFSET 0x20 + +/* Clockevent & Clocksource data */ + +struct oxnas_rps_timer { + struct clock_event_device clkevent; + void __iomem *clksrc_base; + void __iomem *clkevt_base; + unsigned long timer_period; + unsigned int timer_prescaler; + struct clk *clk; + int irq; +}; + +static irqreturn_t oxnas_rps_timer_irq(int irq, void *dev_id) +{ + struct oxnas_rps_timer *rps = dev_id; + + writel_relaxed(0, rps->clkevt_base + TIMER_CLRINT_REG); + + rps->clkevent.event_handler(&rps->clkevent); + + return IRQ_HANDLED; +} + +static void oxnas_rps_timer_config(struct oxnas_rps_timer *rps, + unsigned long period, + unsigned int periodic) +{ + uint32_t cfg = rps->timer_prescaler; + + if (period) + cfg |= TIMER_ENABLE; + + if (periodic) + cfg |= TIMER_PERIODIC; + + writel_relaxed(period, rps->clkevt_base + TIMER_LOAD_REG); + writel_relaxed(cfg, rps->clkevt_base + TIMER_CTRL_REG); +} + +static int oxnas_rps_timer_shutdown(struct clock_event_device *evt) +{ + struct oxnas_rps_timer *rps = + container_of(evt, struct oxnas_rps_timer, clkevent); + + oxnas_rps_timer_config(rps, 0, 0); + + return 0; +} + +static int oxnas_rps_timer_set_periodic(struct clock_event_device *evt) +{ + struct oxnas_rps_timer *rps = + container_of(evt, struct oxnas_rps_timer, clkevent); + + oxnas_rps_timer_config(rps, rps->timer_period, 1); + + return 0; +} + +static int oxnas_rps_timer_set_oneshot(struct clock_event_device *evt) +{ + struct oxnas_rps_timer *rps = + container_of(evt, struct oxnas_rps_timer, clkevent); + + oxnas_rps_timer_config(rps, rps->timer_period, 0); + + return 0; +} + +static int oxnas_rps_timer_next_event(unsigned long delta, + struct clock_event_device *evt) +{ + struct oxnas_rps_timer *rps = + container_of(evt, struct oxnas_rps_timer, clkevent); + + oxnas_rps_timer_config(rps, delta, 0); + + return 0; +} + +static int __init oxnas_rps_clockevent_init(struct oxnas_rps_timer *rps) +{ + ulong clk_rate = clk_get_rate(rps->clk); + ulong timer_rate; + + /* Start with prescaler 1 */ + rps->timer_prescaler = TIMER_DIV1; + rps->timer_period = DIV_ROUND_UP(clk_rate, HZ); + timer_rate = clk_rate; + + if (rps->timer_period > TIMER_MAX_VAL) { + rps->timer_prescaler = TIMER_DIV16; + timer_rate = clk_rate / 16; + rps->timer_period = DIV_ROUND_UP(timer_rate, HZ); + } + if (rps->timer_period > TIMER_MAX_VAL) { + rps->timer_prescaler = TIMER_DIV256; + timer_rate = clk_rate / 256; + rps->timer_period = DIV_ROUND_UP(timer_rate, HZ); + } + + rps->clkevent.name = "oxnas-rps"; + rps->clkevent.features = CLOCK_EVT_FEAT_PERIODIC | + CLOCK_EVT_FEAT_ONESHOT | + CLOCK_EVT_FEAT_DYNIRQ; + rps->clkevent.tick_resume = oxnas_rps_timer_shutdown; + rps->clkevent.set_state_shutdown = oxnas_rps_timer_shutdown; + rps->clkevent.set_state_periodic = oxnas_rps_timer_set_periodic; + rps->clkevent.set_state_oneshot = oxnas_rps_timer_set_oneshot; + rps->clkevent.set_next_event = oxnas_rps_timer_next_event; + rps->clkevent.rating = 200; + rps->clkevent.cpumask = cpu_possible_mask; + rps->clkevent.irq = rps->irq; + clockevents_config_and_register(&rps->clkevent, + timer_rate, + 1, + TIMER_MAX_VAL); + + pr_info("Registered clock event rate %luHz prescaler %x period %lu\n", + clk_rate, + rps->timer_prescaler, + rps->timer_period); + + return 0; +} + +/* Clocksource */ + +static void __iomem *timer_sched_base; + +static u64 notrace oxnas_rps_read_sched_clock(void) +{ + return ~readl_relaxed(timer_sched_base); +} + +static int __init oxnas_rps_clocksource_init(struct oxnas_rps_timer *rps) +{ + ulong clk_rate = clk_get_rate(rps->clk); + int ret; + + /* use prescale 16 */ + clk_rate = clk_rate / 16; + + writel_relaxed(TIMER_MAX_VAL, rps->clksrc_base + TIMER_LOAD_REG); + writel_relaxed(TIMER_PERIODIC | TIMER_ENABLE | TIMER_DIV16, + rps->clksrc_base + TIMER_CTRL_REG); + + timer_sched_base = rps->clksrc_base + TIMER_CURR_REG; + sched_clock_register(oxnas_rps_read_sched_clock, + TIMER_BITS, clk_rate); + ret = clocksource_mmio_init(timer_sched_base, + "oxnas_rps_clocksource_timer", + clk_rate, 250, TIMER_BITS, + clocksource_mmio_readl_down); + if (WARN_ON(ret)) { + pr_err("can't register clocksource\n"); + return ret; + } + + pr_info("Registered clocksource rate %luHz\n", clk_rate); + + return 0; +} + +static void __init oxnas_rps_timer_init(struct device_node *np) +{ + struct oxnas_rps_timer *rps; + void __iomem *base; + int ret; + + rps = kzalloc(sizeof(*rps), GFP_KERNEL); + if (!rps) { + pr_err("Failed to allocate rps structure\n"); + return; + } + + rps->clk = of_clk_get(np, 0); + if (WARN_ON(IS_ERR(rps->clk))) + goto err_alloc; + + if (WARN_ON(clk_prepare_enable(rps->clk))) + goto err_clk; + + base = of_iomap(np, 0); + if (WARN_ON(!base)) + goto err_clk_prepare; + + rps->irq = irq_of_parse_and_map(np, 0); + if (WARN_ON(rps->irq < 0)) + goto err_iomap; + + rps->clkevt_base = base + TIMER1_REG_OFFSET; + rps->clksrc_base = base + TIMER2_REG_OFFSET; + + /* Disable timers */ + writel_relaxed(0, rps->clkevt_base + TIMER_CTRL_REG); + writel_relaxed(0, rps->clksrc_base + TIMER_CTRL_REG); + writel_relaxed(0, rps->clkevt_base + TIMER_LOAD_REG); + writel_relaxed(0, rps->clksrc_base + TIMER_LOAD_REG); + writel_relaxed(0, rps->clkevt_base + TIMER_CLRINT_REG); + writel_relaxed(0, rps->clksrc_base + TIMER_CLRINT_REG); + + ret = request_irq(rps->irq, oxnas_rps_timer_irq, + IRQF_TIMER | IRQF_IRQPOLL, + "rps-timer", rps); + if (WARN_ON(ret)) + goto err_iomap; + + ret = oxnas_rps_clocksource_init(rps); + if (ret) + goto err_irqreq; + + ret = oxnas_rps_clockevent_init(rps); + if (ret) + goto err_irqreq; + + return; + +err_irqreq: + free_irq(rps->irq, rps); +err_iomap: + iounmap(base); +err_clk_prepare: + clk_disable_unprepare(rps->clk); +err_clk: + clk_put(rps->clk); +err_alloc: + kfree(rps); +} + +CLOCKSOURCE_OF_DECLARE(ox810se_rps, + "oxsemi,ox810se-rps-timer", oxnas_rps_timer_init); -- cgit v0.10.2 From 43e88c8a73f5896b964183d503d9bf892a551e25 Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Wed, 15 Jun 2016 12:13:27 +0200 Subject: dt-bindings: clocksource: Add Oxford Semiconductor RPS Timer bindings Add DT bindings for the Oxford Semiconductor RPS dual Timer. Signed-off-by: Neil Armstrong Signed-off-by: Daniel Lezcano Acked-by: Rob Herring diff --git a/Documentation/devicetree/bindings/timer/oxsemi,rps-timer.txt b/Documentation/devicetree/bindings/timer/oxsemi,rps-timer.txt new file mode 100644 index 0000000..3ca89cd --- /dev/null +++ b/Documentation/devicetree/bindings/timer/oxsemi,rps-timer.txt @@ -0,0 +1,17 @@ +Oxford Semiconductor OXNAS SoCs Family RPS Timer +================================================ + +Required properties: +- compatible: Should be "oxsemi,ox810se-rps-timer" +- reg : Specifies base physical address and size of the registers. +- interrupts : The interrupts of the two timers +- clocks : The phandle of the timer clock source + +example: + +timer0: timer@200 { + compatible = "oxsemi,ox810se-rps-timer"; + reg = <0x200 0x40>; + clocks = <&rpsclk>; + interrupts = <4 5>; +}; -- cgit v0.10.2 From c35d9292fee0474a1a037f75b0b85af32200c76f Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Mon, 18 Apr 2016 23:06:48 +0200 Subject: of: Add a new macro to declare_of for one parameter function returning a value The macro OF_DECLARE_1 expect a void (*func)(struct device_node *) while the OF_DECLARE_2 expect a int (*func)(struct device_node *, struct device_node *). The second one allows to pass an init function returning a value, which make possible to call the functions in the table and check the return value in order to catch at a higher level the errors and handle them from there instead of doing a panic in each driver (well at least this is the case for the clkevt). Unfortunately the OF_DECLARE_1 does not allow that and that lead to some code duplication and crappyness in the drivers. The OF_DECLARE_1 is used by all the clk drivers and the clocksource/clockevent drivers. It is not possible to do the change in one shot as we have to change all the init functions. The OF_DECLARE_2 specifies an init function prototype with two parameters with the node and its parent. The latter won't be used, ever, in the timer drivers. Introduce a OF_DECLARE_1_RET macro to be used, and hopefully we can smoothly and iteratively change the users of OF_DECLARE_1 to use the new macro instead. Signed-off-by: Daniel Lezcano Acked-by: Rob Herring diff --git a/include/linux/of.h b/include/linux/of.h index c7292e8..552943d 100644 --- a/include/linux/of.h +++ b/include/linux/of.h @@ -1009,10 +1009,13 @@ static inline int of_get_available_child_count(const struct device_node *np) #endif typedef int (*of_init_fn_2)(struct device_node *, struct device_node *); +typedef int (*of_init_fn_1_ret)(struct device_node *); typedef void (*of_init_fn_1)(struct device_node *); #define OF_DECLARE_1(table, name, compat, fn) \ _OF_DECLARE(table, name, compat, fn, of_init_fn_1) +#define OF_DECLARE_1_RET(table, name, compat, fn) \ + _OF_DECLARE(table, name, compat, fn, of_init_fn_1_ret) #define OF_DECLARE_2(table, name, compat, fn) \ _OF_DECLARE(table, name, compat, fn, of_init_fn_2) -- cgit v0.10.2 From b7c4db861683af5fc50ac3cb3751cf847d765211 Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Tue, 31 May 2016 16:25:59 +0200 Subject: clocksource/drivers/clksrc-probe: Introduce init functions with return code Currently, the clksrc-probe is not able to handle any error from the init functions. There are different issues with the current code: - the code is duplicated in the init functions by writing error - every driver tends to panic in its own init function - counting the number of clocksources is not reliable This patch adds another table to store the functions returning an error. The table is temporary while we convert all the drivers to return an error and will disappear. Signed-off-by: Daniel Lezcano diff --git a/drivers/clocksource/clksrc-probe.c b/drivers/clocksource/clksrc-probe.c index 7cb6c92..5fa6a55 100644 --- a/drivers/clocksource/clksrc-probe.c +++ b/drivers/clocksource/clksrc-probe.c @@ -20,16 +20,22 @@ #include extern struct of_device_id __clksrc_of_table[]; +extern struct of_device_id __clksrc_ret_of_table[]; static const struct of_device_id __clksrc_of_table_sentinel __used __section(__clksrc_of_table_end); +static const struct of_device_id __clksrc_ret_of_table_sentinel + __used __section(__clksrc_ret_of_table_end); + void __init clocksource_probe(void) { struct device_node *np; const struct of_device_id *match; of_init_fn_1 init_func; + of_init_fn_1_ret init_func_ret; unsigned clocksources = 0; + int ret; for_each_matching_node_and_match(np, __clksrc_of_table, &match) { if (!of_device_is_available(np)) @@ -40,6 +46,22 @@ void __init clocksource_probe(void) clocksources++; } + for_each_matching_node_and_match(np, __clksrc_ret_of_table, &match) { + if (!of_device_is_available(np)) + continue; + + init_func_ret = match->data; + + ret = init_func_ret(np); + if (ret) { + pr_err("Failed to initialize '%s': %d", + of_node_full_name(np), ret); + continue; + } + + clocksources++; + } + clocksources += acpi_probe_device_table(clksrc); if (!clocksources) diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h index 6a67ab9..8c6c626 100644 --- a/include/asm-generic/vmlinux.lds.h +++ b/include/asm-generic/vmlinux.lds.h @@ -173,6 +173,7 @@ *(__##name##_of_table_end) #define CLKSRC_OF_TABLES() OF_TABLE(CONFIG_CLKSRC_OF, clksrc) +#define CLKSRC_RET_OF_TABLES() OF_TABLE(CONFIG_CLKSRC_OF, clksrc_ret) #define IRQCHIP_OF_MATCH_TABLE() OF_TABLE(CONFIG_IRQCHIP, irqchip) #define CLK_OF_TABLES() OF_TABLE(CONFIG_COMMON_CLK, clk) #define IOMMU_OF_TABLES() OF_TABLE(CONFIG_OF_IOMMU, iommu) @@ -531,6 +532,7 @@ CLK_OF_TABLES() \ RESERVEDMEM_OF_TABLES() \ CLKSRC_OF_TABLES() \ + CLKSRC_RET_OF_TABLES() \ IOMMU_OF_TABLES() \ CPU_METHOD_OF_TABLES() \ CPUIDLE_METHOD_OF_TABLES() \ diff --git a/include/linux/clocksource.h b/include/linux/clocksource.h index 44a1aff..15c3839 100644 --- a/include/linux/clocksource.h +++ b/include/linux/clocksource.h @@ -246,6 +246,9 @@ extern int clocksource_i8253_init(void); #define CLOCKSOURCE_OF_DECLARE(name, compat, fn) \ OF_DECLARE_1(clksrc, name, compat, fn) +#define CLOCKSOURCE_OF_DECLARE_RET(name, compat, fn) \ + OF_DECLARE_1_RET(clksrc_ret, name, compat, fn) + #ifdef CONFIG_CLKSRC_PROBE extern void clocksource_probe(void); #else -- cgit v0.10.2 From 8bdd5a2e7c479dcdb632c614b0d9bb1ac6ed5be7 Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Tue, 31 May 2016 17:28:55 +0200 Subject: clocksource/drivers/rockchip_timer: Convert init function to return error The init functions do not return any error. They behave as the following: - panic, thus leading to a kernel crash while another timer may work and make the system boot up correctly or - print an error and let the caller unaware if the state of the system Change that by converting the init functions to return an error conforming to the CLOCKSOURCE_OF_RET prototype. Proper error handling (rollback, errno value) will be changed later case by case, thus this change just return back an error or success in the init function. Signed-off-by: Daniel Lezcano Reviewed-by: Heiko Stuebner on a rk3399-evb Tested-by: Heiko Stuebner diff --git a/drivers/clocksource/rockchip_timer.c b/drivers/clocksource/rockchip_timer.c index a3f22b0..85aee69 100644 --- a/drivers/clocksource/rockchip_timer.c +++ b/drivers/clocksource/rockchip_timer.c @@ -113,38 +113,42 @@ static irqreturn_t rk_timer_interrupt(int irq, void *dev_id) return IRQ_HANDLED; } -static void __init rk_timer_init(struct device_node *np, u32 ctrl_reg) +static int __init rk_timer_init(struct device_node *np, u32 ctrl_reg) { struct clock_event_device *ce = &bc_timer.ce; struct clk *timer_clk; struct clk *pclk; - int ret, irq; + int ret = -EINVAL, irq; bc_timer.base = of_iomap(np, 0); if (!bc_timer.base) { pr_err("Failed to get base address for '%s'\n", TIMER_NAME); - return; + return -ENXIO; } bc_timer.ctrl = bc_timer.base + ctrl_reg; pclk = of_clk_get_by_name(np, "pclk"); if (IS_ERR(pclk)) { + ret = PTR_ERR(pclk); pr_err("Failed to get pclk for '%s'\n", TIMER_NAME); goto out_unmap; } - if (clk_prepare_enable(pclk)) { + ret = clk_prepare_enable(pclk); + if (ret) { pr_err("Failed to enable pclk for '%s'\n", TIMER_NAME); goto out_unmap; } timer_clk = of_clk_get_by_name(np, "timer"); if (IS_ERR(timer_clk)) { + ret = PTR_ERR(timer_clk); pr_err("Failed to get timer clock for '%s'\n", TIMER_NAME); goto out_timer_clk; } - if (clk_prepare_enable(timer_clk)) { + ret = clk_prepare_enable(timer_clk); + if (ret) { pr_err("Failed to enable timer clock\n"); goto out_timer_clk; } @@ -153,6 +157,7 @@ static void __init rk_timer_init(struct device_node *np, u32 ctrl_reg) irq = irq_of_parse_and_map(np, 0); if (!irq) { + ret = -EINVAL; pr_err("Failed to map interrupts for '%s'\n", TIMER_NAME); goto out_irq; } @@ -178,7 +183,7 @@ static void __init rk_timer_init(struct device_node *np, u32 ctrl_reg) clockevents_config_and_register(ce, bc_timer.freq, 1, UINT_MAX); - return; + return 0; out_irq: clk_disable_unprepare(timer_clk); @@ -186,19 +191,21 @@ out_timer_clk: clk_disable_unprepare(pclk); out_unmap: iounmap(bc_timer.base); + + return ret; } -static void __init rk3288_timer_init(struct device_node *np) +static int __init rk3288_timer_init(struct device_node *np) { - rk_timer_init(np, TIMER_CONTROL_REG3288); + return rk_timer_init(np, TIMER_CONTROL_REG3288); } -static void __init rk3399_timer_init(struct device_node *np) +static int __init rk3399_timer_init(struct device_node *np) { - rk_timer_init(np, TIMER_CONTROL_REG3399); + return rk_timer_init(np, TIMER_CONTROL_REG3399); } -CLOCKSOURCE_OF_DECLARE(rk3288_timer, "rockchip,rk3288-timer", - rk3288_timer_init); -CLOCKSOURCE_OF_DECLARE(rk3399_timer, "rockchip,rk3399-timer", - rk3399_timer_init); +CLOCKSOURCE_OF_DECLARE_RET(rk3288_timer, "rockchip,rk3288-timer", + rk3288_timer_init); +CLOCKSOURCE_OF_DECLARE_RET(rk3399_timer, "rockchip,rk3399-timer", + rk3399_timer_init); -- cgit v0.10.2 From d64e24ce5fdddd7efc31486f187159be986f6c29 Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Tue, 31 May 2016 17:43:47 +0200 Subject: clocksource/drivers/mtk_timer: Convert init function to return error The init functions do not return any error. They behave as the following: - panic, thus leading to a kernel crash while another timer may work and make the system boot up correctly or - print an error and let the caller unaware if the state of the system Change that by converting the init functions to return an error conforming to the CLOCKSOURCE_OF_RET prototype. Proper error handling (rollback, errno value) will be changed later case by case, thus this change just return back an error or success in the init function. Signed-off-by: Daniel Lezcano Acked-by: Matthias Brugger diff --git a/drivers/clocksource/mtk_timer.c b/drivers/clocksource/mtk_timer.c index 7e583f8..432a2c0 100644 --- a/drivers/clocksource/mtk_timer.c +++ b/drivers/clocksource/mtk_timer.c @@ -181,7 +181,7 @@ static void mtk_timer_enable_irq(struct mtk_clock_event_device *evt, u8 timer) evt->gpt_base + GPT_IRQ_EN_REG); } -static void __init mtk_timer_init(struct device_node *node) +static int __init mtk_timer_init(struct device_node *node) { struct mtk_clock_event_device *evt; struct resource res; @@ -190,7 +190,7 @@ static void __init mtk_timer_init(struct device_node *node) evt = kzalloc(sizeof(*evt), GFP_KERNEL); if (!evt) - return; + return -ENOMEM; evt->dev.name = "mtk_tick"; evt->dev.rating = 300; @@ -248,7 +248,7 @@ static void __init mtk_timer_init(struct device_node *node) mtk_timer_enable_irq(evt, GPT_CLK_EVT); - return; + return 0; err_clk_disable: clk_disable_unprepare(clk); @@ -262,5 +262,7 @@ err_mem: release_mem_region(res.start, resource_size(&res)); err_kzalloc: kfree(evt); + + return -EINVAL; } -CLOCKSOURCE_OF_DECLARE(mtk_mt6577, "mediatek,mt6577-timer", mtk_timer_init); +CLOCKSOURCE_OF_DECLARE_RET(mtk_mt6577, "mediatek,mt6577-timer", mtk_timer_init); -- cgit v0.10.2 From 5e558ebd3d88d3492e0fd3b021d071fad7e2e3d2 Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Tue, 31 May 2016 19:26:55 +0200 Subject: clocksource/drivers/exynos_mct: Convert init function to return error The init functions do not return any error. They behave as the following: - panic, thus leading to a kernel crash while another timer may work and make the system boot up correctly or - print an error and let the caller unaware if the state of the system Change that by converting the init functions to return an error conforming to the CLOCKSOURCE_OF_RET prototype. Proper error handling (rollback, errno value) will be changed later case by case, thus this change just return back an error or success in the init function. Signed-off-by: Daniel Lezcano Reviewed-by: Krzysztof Kozlowski diff --git a/drivers/clocksource/exynos_mct.c b/drivers/clocksource/exynos_mct.c index be09bc0..f6caed0 100644 --- a/drivers/clocksource/exynos_mct.c +++ b/drivers/clocksource/exynos_mct.c @@ -232,7 +232,7 @@ static cycles_t exynos4_read_current_timer(void) return exynos4_read_count_32(); } -static void __init exynos4_clocksource_init(void) +static int __init exynos4_clocksource_init(void) { exynos4_mct_frc_start(); @@ -244,6 +244,8 @@ static void __init exynos4_clocksource_init(void) panic("%s: can't register clocksource\n", mct_frc.name); sched_clock_register(exynos4_read_sched_clock, 32, clk_rate); + + return 0; } static void exynos4_mct_comp0_stop(void) @@ -335,12 +337,14 @@ static struct irqaction mct_comp_event_irq = { .dev_id = &mct_comp_device, }; -static void exynos4_clockevent_init(void) +static int exynos4_clockevent_init(void) { mct_comp_device.cpumask = cpumask_of(0); clockevents_config_and_register(&mct_comp_device, clk_rate, 0xf, 0xffffffff); setup_irq(mct_irqs[MCT_G0_IRQ], &mct_comp_event_irq); + + return 0; } static DEFINE_PER_CPU(struct mct_clock_event_device, percpu_mct_tick); @@ -516,7 +520,7 @@ static struct notifier_block exynos4_mct_cpu_nb = { .notifier_call = exynos4_mct_cpu_notify, }; -static void __init exynos4_timer_resources(struct device_node *np, void __iomem *base) +static int __init exynos4_timer_resources(struct device_node *np, void __iomem *base) { int err, cpu; struct mct_clock_event_device *mevt = this_cpu_ptr(&percpu_mct_tick); @@ -572,15 +576,17 @@ static void __init exynos4_timer_resources(struct device_node *np, void __iomem /* Immediately configure the timer on the boot CPU */ exynos4_local_timer_setup(mevt); - return; + return 0; out_irq: free_percpu_irq(mct_irqs[MCT_L0_IRQ], &percpu_mct_tick); + return err; } -static void __init mct_init_dt(struct device_node *np, unsigned int int_type) +static int __init mct_init_dt(struct device_node *np, unsigned int int_type) { u32 nr_irqs, i; + int ret; mct_int_type = int_type; @@ -600,20 +606,26 @@ static void __init mct_init_dt(struct device_node *np, unsigned int int_type) for (i = MCT_L0_IRQ; i < nr_irqs; i++) mct_irqs[i] = irq_of_parse_and_map(np, i); - exynos4_timer_resources(np, of_iomap(np, 0)); - exynos4_clocksource_init(); - exynos4_clockevent_init(); + ret = exynos4_timer_resources(np, of_iomap(np, 0)); + if (ret) + return ret; + + ret = exynos4_clocksource_init(); + if (ret) + return ret; + + return exynos4_clockevent_init(); } -static void __init mct_init_spi(struct device_node *np) +static int __init mct_init_spi(struct device_node *np) { return mct_init_dt(np, MCT_INT_SPI); } -static void __init mct_init_ppi(struct device_node *np) +static int __init mct_init_ppi(struct device_node *np) { return mct_init_dt(np, MCT_INT_PPI); } -CLOCKSOURCE_OF_DECLARE(exynos4210, "samsung,exynos4210-mct", mct_init_spi); -CLOCKSOURCE_OF_DECLARE(exynos4412, "samsung,exynos4412-mct", mct_init_ppi); +CLOCKSOURCE_OF_DECLARE_RET(exynos4210, "samsung,exynos4210-mct", mct_init_spi); +CLOCKSOURCE_OF_DECLARE_RET(exynos4412, "samsung,exynos4412-mct", mct_init_ppi); -- cgit v0.10.2 From be5eb33d5d1bd076d98564ba2fea7a4ed36ca24f Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Tue, 31 May 2016 19:38:30 +0200 Subject: clocksource/drivers/asm9260: Convert init function to return error The init functions do not return any error. They behave as the following: - panic, thus leading to a kernel crash while another timer may work and make the system boot up correctly or - print an error and let the caller unaware if the state of the system Change that by converting the init functions to return an error conforming to the CLOCKSOURCE_OF_RET prototype. Proper error handling (rollback, errno value) will be changed later case by case, thus this change just return back an error or success in the init function. Signed-off-by: Daniel Lezcano diff --git a/drivers/clocksource/asm9260_timer.c b/drivers/clocksource/asm9260_timer.c index 217438d..d113c02 100644 --- a/drivers/clocksource/asm9260_timer.c +++ b/drivers/clocksource/asm9260_timer.c @@ -184,7 +184,7 @@ static irqreturn_t asm9260_timer_interrupt(int irq, void *dev_id) * Timer initialization * --------------------------------------------------------------------------- */ -static void __init asm9260_timer_init(struct device_node *np) +static int __init asm9260_timer_init(struct device_node *np) { int irq; struct clk *clk; @@ -192,20 +192,26 @@ static void __init asm9260_timer_init(struct device_node *np) unsigned long rate; priv.base = of_io_request_and_map(np, 0, np->name); - if (IS_ERR(priv.base)) - panic("%s: unable to map resource", np->name); + if (IS_ERR(priv.base)) { + pr_err("%s: unable to map resource", np->name); + return PTR_ERR(priv.base); + } clk = of_clk_get(np, 0); ret = clk_prepare_enable(clk); - if (ret) - panic("Failed to enable clk!\n"); + if (ret) { + pr_err("Failed to enable clk!\n"); + return ret; + } irq = irq_of_parse_and_map(np, 0); ret = request_irq(irq, asm9260_timer_interrupt, IRQF_TIMER, DRIVER_NAME, &event_dev); - if (ret) - panic("Failed to setup irq!\n"); + if (ret) { + pr_err("Failed to setup irq!\n"); + return ret; + } /* set all timers for count-up */ writel_relaxed(BM_DIR_DEFAULT, priv.base + HW_DIR); @@ -229,6 +235,8 @@ static void __init asm9260_timer_init(struct device_node *np) priv.ticks_per_jiffy = DIV_ROUND_CLOSEST(rate, HZ); event_dev.cpumask = cpumask_of(0); clockevents_config_and_register(&event_dev, rate, 0x2c00, 0xfffffffe); + + return 0; } -CLOCKSOURCE_OF_DECLARE(asm9260_timer, "alphascale,asm9260-timer", +CLOCKSOURCE_OF_DECLARE_RET(asm9260_timer, "alphascale,asm9260-timer", asm9260_timer_init); -- cgit v0.10.2 From 70504f311d4bd5b6a6d494f50c5ab0bd30fdf75c Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Tue, 31 May 2016 19:52:09 +0200 Subject: clocksource/drivers/cadence_ttc: Convert init function to return error MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The init functions do not return any error. They behave as the following: - panic, thus leading to a kernel crash while another timer may work and make the system boot up correctly or - print an error and let the caller unaware if the state of the system Change that by converting the init functions to return an error conforming to the CLOCKSOURCE_OF_RET prototype. Proper error handling (rollback, errno value) will be changed later case by case, thus this change just return back an error or success in the init function. Signed-off-by: Daniel Lezcano Acked-by: Sören Brinkmann diff --git a/drivers/clocksource/cadence_ttc_timer.c b/drivers/clocksource/cadence_ttc_timer.c index 9be6018..e2e7631 100644 --- a/drivers/clocksource/cadence_ttc_timer.c +++ b/drivers/clocksource/cadence_ttc_timer.c @@ -322,22 +322,22 @@ static int ttc_rate_change_clocksource_cb(struct notifier_block *nb, return NOTIFY_DONE; } -static void __init ttc_setup_clocksource(struct clk *clk, void __iomem *base, +static int __init ttc_setup_clocksource(struct clk *clk, void __iomem *base, u32 timer_width) { struct ttc_timer_clocksource *ttccs; int err; ttccs = kzalloc(sizeof(*ttccs), GFP_KERNEL); - if (WARN_ON(!ttccs)) - return; + if (!ttccs) + return -ENOMEM; ttccs->ttc.clk = clk; err = clk_prepare_enable(ttccs->ttc.clk); - if (WARN_ON(err)) { + if (err) { kfree(ttccs); - return; + return err; } ttccs->ttc.freq = clk_get_rate(ttccs->ttc.clk); @@ -345,8 +345,10 @@ static void __init ttc_setup_clocksource(struct clk *clk, void __iomem *base, ttccs->ttc.clk_rate_change_nb.notifier_call = ttc_rate_change_clocksource_cb; ttccs->ttc.clk_rate_change_nb.next = NULL; - if (clk_notifier_register(ttccs->ttc.clk, - &ttccs->ttc.clk_rate_change_nb)) + + err = clk_notifier_register(ttccs->ttc.clk, + &ttccs->ttc.clk_rate_change_nb); + if (err) pr_warn("Unable to register clock notifier.\n"); ttccs->ttc.base_addr = base; @@ -368,14 +370,16 @@ static void __init ttc_setup_clocksource(struct clk *clk, void __iomem *base, ttccs->ttc.base_addr + TTC_CNT_CNTRL_OFFSET); err = clocksource_register_hz(&ttccs->cs, ttccs->ttc.freq / PRESCALE); - if (WARN_ON(err)) { + if (err) { kfree(ttccs); - return; + return err; } ttc_sched_clock_val_reg = base + TTC_COUNT_VAL_OFFSET; sched_clock_register(ttc_sched_clock_read, timer_width, ttccs->ttc.freq / PRESCALE); + + return 0; } static int ttc_rate_change_clockevent_cb(struct notifier_block *nb, @@ -401,30 +405,35 @@ static int ttc_rate_change_clockevent_cb(struct notifier_block *nb, } } -static void __init ttc_setup_clockevent(struct clk *clk, - void __iomem *base, u32 irq) +static int __init ttc_setup_clockevent(struct clk *clk, + void __iomem *base, u32 irq) { struct ttc_timer_clockevent *ttcce; int err; ttcce = kzalloc(sizeof(*ttcce), GFP_KERNEL); - if (WARN_ON(!ttcce)) - return; + if (!ttcce) + return -ENOMEM; ttcce->ttc.clk = clk; err = clk_prepare_enable(ttcce->ttc.clk); - if (WARN_ON(err)) { + if (err) { kfree(ttcce); - return; + return err; } ttcce->ttc.clk_rate_change_nb.notifier_call = ttc_rate_change_clockevent_cb; ttcce->ttc.clk_rate_change_nb.next = NULL; - if (clk_notifier_register(ttcce->ttc.clk, - &ttcce->ttc.clk_rate_change_nb)) + + err = clk_notifier_register(ttcce->ttc.clk, + &ttcce->ttc.clk_rate_change_nb); + if (err) { pr_warn("Unable to register clock notifier.\n"); + return err; + } + ttcce->ttc.freq = clk_get_rate(ttcce->ttc.clk); ttcce->ttc.base_addr = base; @@ -451,13 +460,15 @@ static void __init ttc_setup_clockevent(struct clk *clk, err = request_irq(irq, ttc_clock_event_interrupt, IRQF_TIMER, ttcce->ce.name, ttcce); - if (WARN_ON(err)) { + if (err) { kfree(ttcce); - return; + return err; } clockevents_config_and_register(&ttcce->ce, ttcce->ttc.freq / PRESCALE, 1, 0xfffe); + + return 0; } /** @@ -466,17 +477,17 @@ static void __init ttc_setup_clockevent(struct clk *clk, * Initializes the timer hardware and register the clock source and clock event * timers with Linux kernal timer framework */ -static void __init ttc_timer_init(struct device_node *timer) +static int __init ttc_timer_init(struct device_node *timer) { unsigned int irq; void __iomem *timer_baseaddr; struct clk *clk_cs, *clk_ce; static int initialized; - int clksel; + int clksel, ret; u32 timer_width = 16; if (initialized) - return; + return 0; initialized = 1; @@ -488,13 +499,13 @@ static void __init ttc_timer_init(struct device_node *timer) timer_baseaddr = of_iomap(timer, 0); if (!timer_baseaddr) { pr_err("ERROR: invalid timer base address\n"); - BUG(); + return -ENXIO; } irq = irq_of_parse_and_map(timer, 1); if (irq <= 0) { pr_err("ERROR: invalid interrupt number\n"); - BUG(); + return -EINVAL; } of_property_read_u32(timer, "timer-width", &timer_width); @@ -504,7 +515,7 @@ static void __init ttc_timer_init(struct device_node *timer) clk_cs = of_clk_get(timer, clksel); if (IS_ERR(clk_cs)) { pr_err("ERROR: timer input clock not found\n"); - BUG(); + return PTR_ERR(clk_cs); } clksel = readl_relaxed(timer_baseaddr + 4 + TTC_CLK_CNTRL_OFFSET); @@ -512,13 +523,20 @@ static void __init ttc_timer_init(struct device_node *timer) clk_ce = of_clk_get(timer, clksel); if (IS_ERR(clk_ce)) { pr_err("ERROR: timer input clock not found\n"); - BUG(); + return PTR_ERR(clk_cs); } - ttc_setup_clocksource(clk_cs, timer_baseaddr, timer_width); - ttc_setup_clockevent(clk_ce, timer_baseaddr + 4, irq); + ret = ttc_setup_clocksource(clk_cs, timer_baseaddr, timer_width); + if (ret) + return ret; + + ret = ttc_setup_clockevent(clk_ce, timer_baseaddr + 4, irq); + if (ret) + return ret; pr_info("%s #0 at %p, irq=%d\n", timer->name, timer_baseaddr, irq); + + return 0; } -CLOCKSOURCE_OF_DECLARE(ttc, "cdns,ttc", ttc_timer_init); +CLOCKSOURCE_OF_DECLARE_RET(ttc, "cdns,ttc", ttc_timer_init); -- cgit v0.10.2 From 84309e0abdd76517b7b0d72e2f8373194fcffeb2 Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Wed, 1 Jun 2016 00:34:25 +0200 Subject: clocksource/drivers/st_lpc: Convert init function to return error The init functions do not return any error. They behave as the following: - panic, thus leading to a kernel crash while another timer may work and make the system boot up correctly or - print an error and let the caller unaware if the state of the system Change that by converting the init functions to return an error conforming to the CLOCKSOURCE_OF_RET prototype. Proper error handling (rollback, errno value) will be changed later case by case, thus this change just return back an error or success in the init function. Signed-off-by: Daniel Lezcano Acked-by: Patrice Chotard Acked-by: Maxime Coquelin diff --git a/drivers/clocksource/clksrc_st_lpc.c b/drivers/clocksource/clksrc_st_lpc.c index 65ec467..c9022a9 100644 --- a/drivers/clocksource/clksrc_st_lpc.c +++ b/drivers/clocksource/clksrc_st_lpc.c @@ -92,7 +92,7 @@ static int __init st_clksrc_setup_clk(struct device_node *np) return 0; } -static void __init st_clksrc_of_register(struct device_node *np) +static int __init st_clksrc_of_register(struct device_node *np) { int ret; uint32_t mode; @@ -100,32 +100,36 @@ static void __init st_clksrc_of_register(struct device_node *np) ret = of_property_read_u32(np, "st,lpc-mode", &mode); if (ret) { pr_err("clksrc-st-lpc: An LPC mode must be provided\n"); - return; + return ret; } /* LPC can either run as a Clocksource or in RTC or WDT mode */ if (mode != ST_LPC_MODE_CLKSRC) - return; + return 0; ddata.base = of_iomap(np, 0); if (!ddata.base) { pr_err("clksrc-st-lpc: Unable to map iomem\n"); - return; + return -ENXIO; } - if (st_clksrc_setup_clk(np)) { + ret = st_clksrc_setup_clk(np); + if (ret) { iounmap(ddata.base); - return; + return ret; } - if (st_clksrc_init()) { + ret = st_clksrc_init(); + if (ret) { clk_disable_unprepare(ddata.clk); clk_put(ddata.clk); iounmap(ddata.base); - return; + return ret; } pr_info("clksrc-st-lpc: clocksource initialised - running @ %luHz\n", clk_get_rate(ddata.clk)); + + return ret; } -CLOCKSOURCE_OF_DECLARE(ddata, "st,stih407-lpc", st_clksrc_of_register); +CLOCKSOURCE_OF_DECLARE_RET(ddata, "st,stih407-lpc", st_clksrc_of_register); -- cgit v0.10.2 From 2e1773f8caef47037486814989e689ff9eacc155 Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Wed, 1 Jun 2016 08:55:46 +0200 Subject: clocksource/drivers/dw_apb_timer: Convert init function to return error The init functions do not return any error. They behave as the following: - panic, thus leading to a kernel crash while another timer may work and make the system boot up correctly or - print an error and let the caller unaware if the state of the system Change that by converting the init functions to return an error conforming to the CLOCKSOURCE_OF_RET prototype. Proper error handling (rollback, errno value) will be changed later case by case, thus this change just return back an error or success in the init function. Signed-off-by: Daniel Lezcano diff --git a/drivers/clocksource/dw_apb_timer_of.c b/drivers/clocksource/dw_apb_timer_of.c index 860843c..4985a2c 100644 --- a/drivers/clocksource/dw_apb_timer_of.c +++ b/drivers/clocksource/dw_apb_timer_of.c @@ -143,7 +143,7 @@ static struct delay_timer dw_apb_delay_timer = { #endif static int num_called; -static void __init dw_apb_timer_init(struct device_node *timer) +static int __init dw_apb_timer_init(struct device_node *timer) { switch (num_called) { case 0: @@ -164,8 +164,10 @@ static void __init dw_apb_timer_init(struct device_node *timer) } num_called++; + + return 0; } -CLOCKSOURCE_OF_DECLARE(pc3x2_timer, "picochip,pc3x2-timer", dw_apb_timer_init); -CLOCKSOURCE_OF_DECLARE(apb_timer_osc, "snps,dw-apb-timer-osc", dw_apb_timer_init); -CLOCKSOURCE_OF_DECLARE(apb_timer_sp, "snps,dw-apb-timer-sp", dw_apb_timer_init); -CLOCKSOURCE_OF_DECLARE(apb_timer, "snps,dw-apb-timer", dw_apb_timer_init); +CLOCKSOURCE_OF_DECLARE_RET(pc3x2_timer, "picochip,pc3x2-timer", dw_apb_timer_init); +CLOCKSOURCE_OF_DECLARE_RET(apb_timer_osc, "snps,dw-apb-timer-osc", dw_apb_timer_init); +CLOCKSOURCE_OF_DECLARE_RET(apb_timer_sp, "snps,dw-apb-timer-sp", dw_apb_timer_init); +CLOCKSOURCE_OF_DECLARE_RET(apb_timer, "snps,dw-apb-timer", dw_apb_timer_init); -- cgit v0.10.2 From 04410efbb6bc0d0e4de634b02155d1070b102adf Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Thu, 2 Jun 2016 20:07:35 +0200 Subject: clocksource/drivers/clps711x: Convert init function to return error The init functions do not return any error. They behave as the following: - panic, thus leading to a kernel crash while another timer may work and make the system boot up correctly or - print an error and let the caller unaware if the state of the system Change that by converting the init functions to return an error conforming to the CLOCKSOURCE_OF_RET prototype. Proper error handling (rollback, errno value) will be changed later case by case, thus this change just return back an error or success in the init function. Signed-off-by: Daniel Lezcano diff --git a/drivers/clocksource/clps711x-timer.c b/drivers/clocksource/clps711x-timer.c index cdd86e3..3b66198 100644 --- a/drivers/clocksource/clps711x-timer.c +++ b/drivers/clocksource/clps711x-timer.c @@ -104,7 +104,7 @@ void __init clps711x_clksrc_init(void __iomem *tc1_base, void __iomem *tc2_base, } #ifdef CONFIG_CLKSRC_OF -static void __init clps711x_timer_init(struct device_node *np) +static int __init clps711x_timer_init(struct device_node *np) { unsigned int irq = irq_of_parse_and_map(np, 0); struct clk *clock = of_clk_get(np, 0); @@ -112,14 +112,12 @@ static void __init clps711x_timer_init(struct device_node *np) switch (of_alias_get_id(np, "timer")) { case CLPS711X_CLKSRC_CLOCKSOURCE: - BUG_ON(_clps711x_clksrc_init(clock, base)); - break; + return _clps711x_clksrc_init(clock, base); case CLPS711X_CLKSRC_CLOCKEVENT: - BUG_ON(_clps711x_clkevt_init(clock, base, irq)); - break; + return _clps711x_clkevt_init(clock, base, irq); default: - break; + return -EINVAL; } } -CLOCKSOURCE_OF_DECLARE(clps711x, "cirrus,clps711x-timer", clps711x_timer_init); +CLOCKSOURCE_OF_DECLARE_RET(clps711x, "cirrus,clps711x-timer", clps711x_timer_init); #endif -- cgit v0.10.2 From c77b9d44aceed7b85c9951a12df7c2ad865fba02 Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Thu, 2 Jun 2016 20:20:01 +0200 Subject: clocksource/drivers/digicolor: Convert init function to return error The init functions do not return any error. They behave as the following: - panic, thus leading to a kernel crash while another timer may work and make the system boot up correctly or - print an error and let the caller unaware if the state of the system Change that by converting the init functions to return an error conforming to the CLOCKSOURCE_OF_RET prototype. Proper error handling (rollback, errno value) will be changed later case by case, thus this change just return back an error or success in the init function. Signed-off-by: Daniel Lezcano Acked-by: Baruch Siach diff --git a/drivers/clocksource/timer-digicolor.c b/drivers/clocksource/timer-digicolor.c index 96bb222..b929061 100644 --- a/drivers/clocksource/timer-digicolor.c +++ b/drivers/clocksource/timer-digicolor.c @@ -148,7 +148,7 @@ static u64 notrace digicolor_timer_sched_read(void) return ~readl(dc_timer_dev.base + COUNT(TIMER_B)); } -static void __init digicolor_timer_init(struct device_node *node) +static int __init digicolor_timer_init(struct device_node *node) { unsigned long rate; struct clk *clk; @@ -161,19 +161,19 @@ static void __init digicolor_timer_init(struct device_node *node) dc_timer_dev.base = of_iomap(node, 0); if (!dc_timer_dev.base) { pr_err("Can't map registers"); - return; + return -ENXIO; } irq = irq_of_parse_and_map(node, dc_timer_dev.timer_id); if (irq <= 0) { pr_err("Can't parse IRQ"); - return; + return -EINVAL; } clk = of_clk_get(node, 0); if (IS_ERR(clk)) { pr_err("Can't get timer clock"); - return; + return PTR_ERR(clk); } clk_prepare_enable(clk); rate = clk_get_rate(clk); @@ -190,13 +190,17 @@ static void __init digicolor_timer_init(struct device_node *node) ret = request_irq(irq, digicolor_timer_interrupt, IRQF_TIMER | IRQF_IRQPOLL, "digicolor_timerC", &dc_timer_dev.ce); - if (ret) + if (ret) { pr_warn("request of timer irq %d failed (%d)\n", irq, ret); + return ret; + } dc_timer_dev.ce.cpumask = cpu_possible_mask; dc_timer_dev.ce.irq = irq; clockevents_config_and_register(&dc_timer_dev.ce, rate, 0, 0xffffffff); + + return 0; } -CLOCKSOURCE_OF_DECLARE(conexant_digicolor, "cnxt,cx92755-timer", +CLOCKSOURCE_OF_DECLARE_RET(conexant_digicolor, "cnxt,cx92755-timer", digicolor_timer_init); -- cgit v0.10.2 From 802fa498dbd27d5dea57e624606c8f8ec47d1915 Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Thu, 2 Jun 2016 18:43:42 +0200 Subject: clocksource/drivers/armv7m_systick: Convert init function to return error The init functions do not return any error. They behave as the following: - panic, thus leading to a kernel crash while another timer may work and make the system boot up correctly or - print an error and let the caller unaware if the state of the system Change that by converting the init functions to return an error conforming to the CLOCKSOURCE_OF_RET prototype. Proper error handling (rollback, errno value) will be changed later case by case, thus this change just return back an error or success in the init function. Signed-off-by: Daniel Lezcano Acked-by: Maxime Coquelin diff --git a/drivers/clocksource/armv7m_systick.c b/drivers/clocksource/armv7m_systick.c index addfd2c..2b55410 100644 --- a/drivers/clocksource/armv7m_systick.c +++ b/drivers/clocksource/armv7m_systick.c @@ -21,7 +21,7 @@ #define SYSTICK_LOAD_RELOAD_MASK 0x00FFFFFF -static void __init system_timer_of_register(struct device_node *np) +static int __init system_timer_of_register(struct device_node *np) { struct clk *clk = NULL; void __iomem *base; @@ -31,22 +31,26 @@ static void __init system_timer_of_register(struct device_node *np) base = of_iomap(np, 0); if (!base) { pr_warn("system-timer: invalid base address\n"); - return; + return -ENXIO; } ret = of_property_read_u32(np, "clock-frequency", &rate); if (ret) { clk = of_clk_get(np, 0); - if (IS_ERR(clk)) + if (IS_ERR(clk)) { + ret = PTR_ERR(clk); goto out_unmap; + } ret = clk_prepare_enable(clk); if (ret) goto out_clk_put; rate = clk_get_rate(clk); - if (!rate) + if (!rate) { + ret = -EINVAL; goto out_clk_disable; + } } writel_relaxed(SYSTICK_LOAD_RELOAD_MASK, base + SYST_RVR); @@ -64,7 +68,7 @@ static void __init system_timer_of_register(struct device_node *np) pr_info("ARM System timer initialized as clocksource\n"); - return; + return 0; out_clk_disable: clk_disable_unprepare(clk); @@ -73,7 +77,9 @@ out_clk_put: out_unmap: iounmap(base); pr_warn("ARM System timer register failed (%d)\n", ret); + + return ret; } -CLOCKSOURCE_OF_DECLARE(arm_systick, "arm,armv7m-systick", +CLOCKSOURCE_OF_DECLARE_RET(arm_systick, "arm,armv7m-systick", system_timer_of_register); -- cgit v0.10.2 From 524a7f08983daa756ad355a302fb67bd90713dd0 Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Thu, 2 Jun 2016 18:46:11 +0200 Subject: clocksource/drivers/bcm2835_timer: Convert init function to return error The init functions do not return any error. They behave as the following: - panic, thus leading to a kernel crash while another timer may work and make the system boot up correctly or - print an error and let the caller unaware if the state of the system Change that by converting the init functions to return an error conforming to the CLOCKSOURCE_OF_RET prototype. Proper error handling (rollback, errno value) will be changed later case by case, thus this change just return back an error or success in the init function. Signed-off-by: Daniel Lezcano Acked-by: Eric Anholt diff --git a/drivers/clocksource/bcm2835_timer.c b/drivers/clocksource/bcm2835_timer.c index 6f28229..2dcf896 100644 --- a/drivers/clocksource/bcm2835_timer.c +++ b/drivers/clocksource/bcm2835_timer.c @@ -80,19 +80,24 @@ static irqreturn_t bcm2835_time_interrupt(int irq, void *dev_id) } } -static void __init bcm2835_timer_init(struct device_node *node) +static int __init bcm2835_timer_init(struct device_node *node) { void __iomem *base; u32 freq; - int irq; + int irq, ret; struct bcm2835_timer *timer; base = of_iomap(node, 0); - if (!base) - panic("Can't remap registers"); + if (!base) { + pr_err("Can't remap registers"); + return -ENXIO; + } - if (of_property_read_u32(node, "clock-frequency", &freq)) - panic("Can't read clock-frequency"); + ret = of_property_read_u32(node, "clock-frequency", &freq); + if (ret) { + pr_err("Can't read clock-frequency"); + return ret; + } system_clock = base + REG_COUNTER_LO; sched_clock_register(bcm2835_sched_read, 32, freq); @@ -101,12 +106,16 @@ static void __init bcm2835_timer_init(struct device_node *node) freq, 300, 32, clocksource_mmio_readl_up); irq = irq_of_parse_and_map(node, DEFAULT_TIMER); - if (irq <= 0) - panic("Can't parse IRQ"); + if (irq <= 0) { + pr_err("Can't parse IRQ"); + return -EINVAL; + } timer = kzalloc(sizeof(*timer), GFP_KERNEL); - if (!timer) - panic("Can't allocate timer struct\n"); + if (!timer) { + pr_err("Can't allocate timer struct\n"); + return -ENOMEM; + } timer->control = base + REG_CONTROL; timer->compare = base + REG_COMPARE(DEFAULT_TIMER); @@ -121,12 +130,17 @@ static void __init bcm2835_timer_init(struct device_node *node) timer->act.dev_id = timer; timer->act.handler = bcm2835_time_interrupt; - if (setup_irq(irq, &timer->act)) - panic("Can't set up timer IRQ\n"); + ret = setup_irq(irq, &timer->act); + if (ret) { + pr_err("Can't set up timer IRQ\n"); + return ret; + } clockevents_config_and_register(&timer->evt, freq, 0xf, 0xffffffff); pr_info("bcm2835: system timer (irq = %d)\n", irq); + + return 0; } -CLOCKSOURCE_OF_DECLARE(bcm2835, "brcm,bcm2835-system-timer", +CLOCKSOURCE_OF_DECLARE_RET(bcm2835, "brcm,bcm2835-system-timer", bcm2835_timer_init); -- cgit v0.10.2 From 595197743ee63e4ea0e20cccaf455bf5fd3fd1c9 Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Thu, 2 Jun 2016 19:44:04 +0200 Subject: clocksource/drivers/bcm_kona: Convert init function to return error The init functions do not return any error. They behave as the following: - panic, thus leading to a kernel crash while another timer may work and make the system boot up correctly or - print an error and let the caller unaware if the state of the system Change that by converting the init functions to return an error conforming to the CLOCKSOURCE_OF_RET prototype. Proper error handling (rollback, errno value) will be changed later case by case, thus this change just return back an error or success in the init function. Signed-off-by: Daniel Lezcano Acked-by: Ray Jui diff --git a/drivers/clocksource/bcm_kona_timer.c b/drivers/clocksource/bcm_kona_timer.c index e717e87..c251aa6 100644 --- a/drivers/clocksource/bcm_kona_timer.c +++ b/drivers/clocksource/bcm_kona_timer.c @@ -163,16 +163,11 @@ static struct irqaction kona_timer_irq = { .handler = kona_timer_interrupt, }; -static void __init kona_timer_init(struct device_node *node) +static int __init kona_timer_init(struct device_node *node) { u32 freq; struct clk *external_clk; - if (!of_device_is_available(node)) { - pr_info("Kona Timer v1 marked as disabled in device tree\n"); - return; - } - external_clk = of_clk_get_by_name(node, NULL); if (!IS_ERR(external_clk)) { @@ -182,7 +177,7 @@ static void __init kona_timer_init(struct device_node *node) arch_timer_rate = freq; } else { pr_err("Kona Timer v1 unable to determine clock-frequency"); - return; + return -EINVAL; } /* Setup IRQ numbers */ @@ -196,11 +191,13 @@ static void __init kona_timer_init(struct device_node *node) kona_timer_clockevents_init(); setup_irq(timers.tmr_irq, &kona_timer_irq); kona_timer_set_next_event((arch_timer_rate / HZ), NULL); + + return 0; } -CLOCKSOURCE_OF_DECLARE(brcm_kona, "brcm,kona-timer", kona_timer_init); +CLOCKSOURCE_OF_DECLARE_RET(brcm_kona, "brcm,kona-timer", kona_timer_init); /* * bcm,kona-timer is deprecated by brcm,kona-timer * being kept here for driver compatibility */ -CLOCKSOURCE_OF_DECLARE(bcm_kona, "bcm,kona-timer", kona_timer_init); +CLOCKSOURCE_OF_DECLARE_RET(bcm_kona, "bcm,kona-timer", kona_timer_init); -- cgit v0.10.2 From 108a4ed965b601986d054c0f0cf6f964959e0017 Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Thu, 2 Jun 2016 19:44:34 +0200 Subject: clocksource/drivers/clksrc-dbx500: Convert init function to return error The init functions do not return any error. They behave as the following: - panic, thus leading to a kernel crash while another timer may work and make the system boot up correctly or - print an error and let the caller unaware if the state of the system Change that by converting the init functions to return an error conforming to the CLOCKSOURCE_OF_RET prototype. Proper error handling (rollback, errno value) will be changed later case by case, thus this change just return back an error or success in the init function. Signed-off-by: Daniel Lezcano Acked-by: Linus Walleij diff --git a/drivers/clocksource/clksrc-dbx500-prcmu.c b/drivers/clocksource/clksrc-dbx500-prcmu.c index dfad6eb..5a59d29 100644 --- a/drivers/clocksource/clksrc-dbx500-prcmu.c +++ b/drivers/clocksource/clksrc-dbx500-prcmu.c @@ -64,7 +64,7 @@ static u64 notrace dbx500_prcmu_sched_clock_read(void) #endif -static void __init clksrc_dbx500_prcmu_init(struct device_node *node) +static int __init clksrc_dbx500_prcmu_init(struct device_node *node) { clksrc_dbx500_timer_base = of_iomap(node, 0); @@ -84,7 +84,7 @@ static void __init clksrc_dbx500_prcmu_init(struct device_node *node) #ifdef CONFIG_CLKSRC_DBX500_PRCMU_SCHED_CLOCK sched_clock_register(dbx500_prcmu_sched_clock_read, 32, RATE_32K); #endif - clocksource_register_hz(&clocksource_dbx500_prcmu, RATE_32K); + return clocksource_register_hz(&clocksource_dbx500_prcmu, RATE_32K); } -CLOCKSOURCE_OF_DECLARE(dbx500_prcmu, "stericsson,db8500-prcmu-timer-4", +CLOCKSOURCE_OF_DECLARE_RET(dbx500_prcmu, "stericsson,db8500-prcmu-timer-4", clksrc_dbx500_prcmu_init); -- cgit v0.10.2 From 17c8669d8084bdb69ee56566956c59447763364e Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Fri, 3 Jun 2016 15:45:27 +0200 Subject: clocksource/drivers/fsl_ftm_timer: Convert init function to return error The init functions do not return any error. They behave as the following: - panic, thus leading to a kernel crash while another timer may work and make the system boot up correctly or - print an error and let the caller unaware if the state of the system Change that by converting the init functions to return an error conforming to the CLOCKSOURCE_OF_RET prototype. Proper error handling (rollback, errno value) will be changed later case by case, thus this change just return back an error or success in the init function. Signed-off-by: Daniel Lezcano diff --git a/drivers/clocksource/fsl_ftm_timer.c b/drivers/clocksource/fsl_ftm_timer.c index 517e1c7..9ad4ca3 100644 --- a/drivers/clocksource/fsl_ftm_timer.c +++ b/drivers/clocksource/fsl_ftm_timer.c @@ -316,15 +316,16 @@ static int __init ftm_calc_closest_round_cyc(unsigned long freq) return 0; } -static void __init ftm_timer_init(struct device_node *np) +static int __init ftm_timer_init(struct device_node *np) { unsigned long freq; - int irq; + int ret, irq; priv = kzalloc(sizeof(*priv), GFP_KERNEL); if (!priv) - return; + return -ENOMEM; + ret = -ENXIO; priv->clkevt_base = of_iomap(np, 0); if (!priv->clkevt_base) { pr_err("ftm: unable to map event timer registers\n"); @@ -337,6 +338,7 @@ static void __init ftm_timer_init(struct device_node *np) goto err; } + ret = -EINVAL; irq = irq_of_parse_and_map(np, 0); if (irq <= 0) { pr_err("ftm: unable to get IRQ from DT, %d\n", irq); @@ -349,18 +351,22 @@ static void __init ftm_timer_init(struct device_node *np) if (!freq) goto err; - if (ftm_calc_closest_round_cyc(freq)) + ret = ftm_calc_closest_round_cyc(freq); + if (ret) goto err; - if (ftm_clocksource_init(freq)) + ret = ftm_clocksource_init(freq); + if (ret) goto err; - if (ftm_clockevent_init(freq, irq)) + ret = ftm_clockevent_init(freq, irq); + if (ret) goto err; - return; + return 0; err: kfree(priv); + return ret; } -CLOCKSOURCE_OF_DECLARE(flextimer, "fsl,ftm-timer", ftm_timer_init); +CLOCKSOURCE_OF_DECLARE_RET(flextimer, "fsl,ftm-timer", ftm_timer_init); -- cgit v0.10.2 From 3c0731db1540ef3cd08fc76c66f6e9d9865b96d2 Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Mon, 6 Jun 2016 17:55:40 +0200 Subject: clocksource/drivers/arm_arch_timer: Convert init function to return error The init functions do not return any error. They behave as the following: - panic, thus leading to a kernel crash while another timer may work and make the system boot up correctly or - print an error and let the caller unaware if the state of the system Change that by converting the init functions to return an error conforming to the CLOCKSOURCE_OF_RET prototype. Proper error handling (rollback, errno value) will be changed later case by case, thus this change just return back an error or success in the init function. Signed-off-by: Daniel Lezcano diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c index 4814446..d0cda68 100644 --- a/drivers/clocksource/arm_arch_timer.c +++ b/drivers/clocksource/arm_arch_timer.c @@ -693,25 +693,26 @@ arch_timer_needs_probing(int type, const struct of_device_id *matches) return needs_probing; } -static void __init arch_timer_common_init(void) +static int __init arch_timer_common_init(void) { unsigned mask = ARCH_CP15_TIMER | ARCH_MEM_TIMER; /* Wait until both nodes are probed if we have two timers */ if ((arch_timers_present & mask) != mask) { if (arch_timer_needs_probing(ARCH_MEM_TIMER, arch_timer_mem_of_match)) - return; + return 0; if (arch_timer_needs_probing(ARCH_CP15_TIMER, arch_timer_of_match)) - return; + return 0; } arch_timer_banner(arch_timers_present); arch_counter_register(arch_timers_present); - arch_timer_arch_init(); + return arch_timer_arch_init(); } -static void __init arch_timer_init(void) +static int __init arch_timer_init(void) { + int ret; /* * If HYP mode is available, we know that the physical timer * has been configured to be accessible from PL1. Use it, so @@ -739,23 +740,30 @@ static void __init arch_timer_init(void) if (!has_ppi) { pr_warn("arch_timer: No interrupt available, giving up\n"); - return; + return -EINVAL; } } - arch_timer_register(); - arch_timer_common_init(); + ret = arch_timer_register(); + if (ret) + return ret; + + ret = arch_timer_common_init(); + if (ret) + return ret; arch_timer_kvm_info.virtual_irq = arch_timer_ppi[VIRT_PPI]; + + return 0; } -static void __init arch_timer_of_init(struct device_node *np) +static int __init arch_timer_of_init(struct device_node *np) { int i; if (arch_timers_present & ARCH_CP15_TIMER) { pr_warn("arch_timer: multiple nodes in dt, skipping\n"); - return; + return 0; } arch_timers_present |= ARCH_CP15_TIMER; @@ -774,23 +782,23 @@ static void __init arch_timer_of_init(struct device_node *np) of_property_read_bool(np, "arm,cpu-registers-not-fw-configured")) arch_timer_uses_ppi = PHYS_SECURE_PPI; - arch_timer_init(); + return arch_timer_init(); } -CLOCKSOURCE_OF_DECLARE(armv7_arch_timer, "arm,armv7-timer", arch_timer_of_init); -CLOCKSOURCE_OF_DECLARE(armv8_arch_timer, "arm,armv8-timer", arch_timer_of_init); +CLOCKSOURCE_OF_DECLARE_RET(armv7_arch_timer, "arm,armv7-timer", arch_timer_of_init); +CLOCKSOURCE_OF_DECLARE_RET(armv8_arch_timer, "arm,armv8-timer", arch_timer_of_init); -static void __init arch_timer_mem_init(struct device_node *np) +static int __init arch_timer_mem_init(struct device_node *np) { struct device_node *frame, *best_frame = NULL; void __iomem *cntctlbase, *base; - unsigned int irq; + unsigned int irq, ret = -EINVAL; u32 cnttidr; arch_timers_present |= ARCH_MEM_TIMER; cntctlbase = of_iomap(np, 0); if (!cntctlbase) { pr_err("arch_timer: Can't find CNTCTLBase\n"); - return; + return -ENXIO; } cnttidr = readl_relaxed(cntctlbase + CNTTIDR); @@ -830,6 +838,7 @@ static void __init arch_timer_mem_init(struct device_node *np) best_frame = of_node_get(frame); } + ret= -ENXIO; base = arch_counter_base = of_iomap(best_frame, 0); if (!base) { pr_err("arch_timer: Can't map frame's registers\n"); @@ -841,6 +850,7 @@ static void __init arch_timer_mem_init(struct device_node *np) else irq = irq_of_parse_and_map(best_frame, 0); + ret = -EINVAL; if (!irq) { pr_err("arch_timer: Frame missing %s irq", arch_timer_mem_use_virtual ? "virt" : "phys"); @@ -848,13 +858,17 @@ static void __init arch_timer_mem_init(struct device_node *np) } arch_timer_detect_rate(base, np); - arch_timer_mem_register(base, irq); - arch_timer_common_init(); + ret = arch_timer_mem_register(base, irq); + if (ret) + goto out; + + return arch_timer_common_init(); out: iounmap(cntctlbase); of_node_put(best_frame); + return ret; } -CLOCKSOURCE_OF_DECLARE(armv7_arch_timer_mem, "arm,armv7-timer-mem", +CLOCKSOURCE_OF_DECLARE_RET(armv7_arch_timer_mem, "arm,armv7-timer-mem", arch_timer_mem_init); #ifdef CONFIG_ACPI -- cgit v0.10.2 From 5a54c1873f29411c769f8ebb044980ba0397eb1d Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Mon, 6 Jun 2016 17:56:04 +0200 Subject: clocksource/drivers/arm_global_timer: Convert init function to return error The init functions do not return any error. They behave as the following: - panic, thus leading to a kernel crash while another timer may work and make the system boot up correctly or - print an error and let the caller unaware if the state of the system Change that by converting the init functions to return an error conforming to the CLOCKSOURCE_OF_RET prototype. Proper error handling (rollback, errno value) will be changed later case by case, thus this change just return back an error or success in the init function. Signed-off-by: Daniel Lezcano Acked-by: Maxime Coquelin diff --git a/drivers/clocksource/arm_global_timer.c b/drivers/clocksource/arm_global_timer.c index 9df0d16..40104fc 100644 --- a/drivers/clocksource/arm_global_timer.c +++ b/drivers/clocksource/arm_global_timer.c @@ -238,7 +238,7 @@ static void __init gt_delay_timer_init(void) register_current_timer_delay(>_delay_timer); } -static void __init gt_clocksource_init(void) +static int __init gt_clocksource_init(void) { writel(0, gt_base + GT_CONTROL); writel(0, gt_base + GT_COUNTER0); @@ -249,7 +249,7 @@ static void __init gt_clocksource_init(void) #ifdef CONFIG_CLKSRC_ARM_GLOBAL_TIMER_SCHED_CLOCK sched_clock_register(gt_sched_clock_read, 64, gt_clk_rate); #endif - clocksource_register_hz(>_clocksource, gt_clk_rate); + return clocksource_register_hz(>_clocksource, gt_clk_rate); } static int gt_cpu_notify(struct notifier_block *self, unsigned long action, @@ -270,7 +270,7 @@ static struct notifier_block gt_cpu_nb = { .notifier_call = gt_cpu_notify, }; -static void __init global_timer_of_register(struct device_node *np) +static int __init global_timer_of_register(struct device_node *np) { struct clk *gt_clk; int err = 0; @@ -283,19 +283,19 @@ static void __init global_timer_of_register(struct device_node *np) if (read_cpuid_part() == ARM_CPU_PART_CORTEX_A9 && (read_cpuid_id() & 0xf0000f) < 0x200000) { pr_warn("global-timer: non support for this cpu version.\n"); - return; + return -ENOSYS; } gt_ppi = irq_of_parse_and_map(np, 0); if (!gt_ppi) { pr_warn("global-timer: unable to parse irq\n"); - return; + return -EINVAL; } gt_base = of_iomap(np, 0); if (!gt_base) { pr_warn("global-timer: invalid base address\n"); - return; + return -ENXIO; } gt_clk = of_clk_get(np, 0); @@ -332,11 +332,17 @@ static void __init global_timer_of_register(struct device_node *np) } /* Immediately configure the timer on the boot CPU */ - gt_clocksource_init(); - gt_clockevents_init(this_cpu_ptr(gt_evt)); + err = gt_clocksource_init(); + if (err) + goto out_irq; + + err = gt_clockevents_init(this_cpu_ptr(gt_evt)); + if (err) + goto out_irq; + gt_delay_timer_init(); - return; + return 0; out_irq: free_percpu_irq(gt_ppi, gt_evt); @@ -347,8 +353,10 @@ out_clk: out_unmap: iounmap(gt_base); WARN(err, "ARM Global timer register failed (%d)\n", err); + + return err; } /* Only tested on r2p2 and r3p0 */ -CLOCKSOURCE_OF_DECLARE(arm_gt, "arm,cortex-a9-global-timer", +CLOCKSOURCE_OF_DECLARE_RET(arm_gt, "arm,cortex-a9-global-timer", global_timer_of_register); -- cgit v0.10.2 From eacf209168f7f16cd6adbbe1524b8c2bec85ae46 Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Mon, 6 Jun 2016 17:56:21 +0200 Subject: clocksource/drivers/h8300_timer16: Convert init function to return error The init functions do not return any error. They behave as the following: - panic, thus leading to a kernel crash while another timer may work and make the system boot up correctly or - print an error and let the caller unaware if the state of the system Change that by converting the init functions to return an error conforming to the CLOCKSOURCE_OF_RET prototype. Proper error handling (rollback, errno value) will be changed later case by case, thus this change just return back an error or success in the init function. Signed-off-by: Daniel Lezcano diff --git a/drivers/clocksource/h8300_timer16.c b/drivers/clocksource/h8300_timer16.c index 75c4407..9d99fc8 100644 --- a/drivers/clocksource/h8300_timer16.c +++ b/drivers/clocksource/h8300_timer16.c @@ -126,7 +126,7 @@ static struct timer16_priv timer16_priv = { #define REG_CH 0 #define REG_COMM 1 -static void __init h8300_16timer_init(struct device_node *node) +static int __init h8300_16timer_init(struct device_node *node) { void __iomem *base[2]; int ret, irq; @@ -136,9 +136,10 @@ static void __init h8300_16timer_init(struct device_node *node) clk = of_clk_get(node, 0); if (IS_ERR(clk)) { pr_err("failed to get clock for clocksource\n"); - return; + return PTR_ERR(clk); } + ret = -ENXIO; base[REG_CH] = of_iomap(node, 0); if (!base[REG_CH]) { pr_err("failed to map registers for clocksource\n"); @@ -151,6 +152,7 @@ static void __init h8300_16timer_init(struct device_node *node) goto unmap_ch; } + ret = -EINVAL; irq = irq_of_parse_and_map(node, 0); if (!irq) { pr_err("failed to get irq for clockevent\n"); @@ -174,7 +176,7 @@ static void __init h8300_16timer_init(struct device_node *node) clocksource_register_hz(&timer16_priv.cs, clk_get_rate(clk) / 8); - return; + return 0; unmap_comm: iounmap(base[REG_COMM]); @@ -182,6 +184,8 @@ unmap_ch: iounmap(base[REG_CH]); free_clk: clk_put(clk); + return ret; } -CLOCKSOURCE_OF_DECLARE(h8300_16bit, "renesas,16bit-timer", h8300_16timer_init); +CLOCKSOURCE_OF_DECLARE_RET(h8300_16bit, "renesas,16bit-timer", + h8300_16timer_init); -- cgit v0.10.2 From 691f8f878290f7a94b94fe238e28263982eb52ca Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Mon, 6 Jun 2016 17:56:37 +0200 Subject: clocksource/drivers/h8300_timer8: Convert init function to return error The init functions do not return any error. They behave as the following: - panic, thus leading to a kernel crash while another timer may work and make the system boot up correctly or - print an error and let the caller unaware if the state of the system Change that by converting the init functions to return an error conforming to the CLOCKSOURCE_OF_RET prototype. Proper error handling (rollback, errno value) will be changed later case by case, thus this change just return back an error or success in the init function. Signed-off-by: Daniel Lezcano diff --git a/drivers/clocksource/h8300_timer8.c b/drivers/clocksource/h8300_timer8.c index c151941..0292a19 100644 --- a/drivers/clocksource/h8300_timer8.c +++ b/drivers/clocksource/h8300_timer8.c @@ -164,24 +164,26 @@ static struct timer8_priv timer8_priv = { }, }; -static void __init h8300_8timer_init(struct device_node *node) +static int __init h8300_8timer_init(struct device_node *node) { void __iomem *base; - int irq; + int irq, ret; struct clk *clk; clk = of_clk_get(node, 0); if (IS_ERR(clk)) { pr_err("failed to get clock for clockevent\n"); - return; + return PTR_ERR(clk); } + ret = ENXIO; base = of_iomap(node, 0); if (!base) { pr_err("failed to map registers for clockevent\n"); goto free_clk; } + ret = -EINVAL; irq = irq_of_parse_and_map(node, 0); if (!irq) { pr_err("failed to get irq for clockevent\n"); @@ -205,11 +207,12 @@ static void __init h8300_8timer_init(struct device_node *node) clockevents_config_and_register(&timer8_priv.ced, timer8_priv.rate, 1, 0x0000ffff); - return; + return 0; unmap_reg: iounmap(base); free_clk: clk_put(clk); + return ret; } -CLOCKSOURCE_OF_DECLARE(h8300_8bit, "renesas,8bit-timer", h8300_8timer_init); +CLOCKSOURCE_OF_DECLARE_RET(h8300_8bit, "renesas,8bit-timer", h8300_8timer_init); -- cgit v0.10.2 From f2f9900caa1fbfe55484375818427093d1406c1e Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Mon, 6 Jun 2016 17:56:52 +0200 Subject: clocksource/drivers/h8300_tpu: Convert init function to return error The init functions do not return any error. They behave as the following: - panic, thus leading to a kernel crash while another timer may work and make the system boot up correctly or - print an error and let the caller unaware if the state of the system Change that by converting the init functions to return an error conforming to the CLOCKSOURCE_OF_RET prototype. Proper error handling (rollback, errno value) will be changed later case by case, thus this change just return back an error or success in the init function. Signed-off-by: Daniel Lezcano diff --git a/drivers/clocksource/h8300_tpu.c b/drivers/clocksource/h8300_tpu.c index d4c1a28..4faf718 100644 --- a/drivers/clocksource/h8300_tpu.c +++ b/drivers/clocksource/h8300_tpu.c @@ -119,15 +119,16 @@ static struct tpu_priv tpu_priv = { #define CH_L 0 #define CH_H 1 -static void __init h8300_tpu_init(struct device_node *node) +static int __init h8300_tpu_init(struct device_node *node) { void __iomem *base[2]; struct clk *clk; + int ret = -ENXIO; clk = of_clk_get(node, 0); if (IS_ERR(clk)) { pr_err("failed to get clock for clocksource\n"); - return; + return PTR_ERR(clk); } base[CH_L] = of_iomap(node, CH_L); @@ -144,14 +145,13 @@ static void __init h8300_tpu_init(struct device_node *node) tpu_priv.mapbase1 = base[CH_L]; tpu_priv.mapbase2 = base[CH_H]; - clocksource_register_hz(&tpu_priv.cs, clk_get_rate(clk) / 64); - - return; + return clocksource_register_hz(&tpu_priv.cs, clk_get_rate(clk) / 64); unmap_L: iounmap(base[CH_H]); free_clk: clk_put(clk); + return ret; } -CLOCKSOURCE_OF_DECLARE(h8300_tpu, "renesas,tpu", h8300_tpu_init); +CLOCKSOURCE_OF_DECLARE_RET(h8300_tpu, "renesas,tpu", h8300_tpu_init); -- cgit v0.10.2 From ca46acb981072f084d63d2a94430a5c3190aa32a Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Mon, 6 Jun 2016 17:57:07 +0200 Subject: clocksource/drivers/meson6_timer.c: Convert init function to return error The init functions do not return any error. They behave as the following: - panic, thus leading to a kernel crash while another timer may work and make the system boot up correctly or - print an error and let the caller unaware if the state of the system Change that by converting the init functions to return an error conforming to the CLOCKSOURCE_OF_RET prototype. Proper error handling (rollback, errno value) will be changed later case by case, thus this change just return back an error or success in the init function. Signed-off-by: Daniel Lezcano diff --git a/drivers/clocksource/meson6_timer.c b/drivers/clocksource/meson6_timer.c index 1fa22c4..3a6e78f 100644 --- a/drivers/clocksource/meson6_timer.c +++ b/drivers/clocksource/meson6_timer.c @@ -126,18 +126,22 @@ static struct irqaction meson6_timer_irq = { .dev_id = &meson6_clockevent, }; -static void __init meson6_timer_init(struct device_node *node) +static int __init meson6_timer_init(struct device_node *node) { u32 val; int ret, irq; timer_base = of_io_request_and_map(node, 0, "meson6-timer"); - if (IS_ERR(timer_base)) - panic("Can't map registers"); + if (IS_ERR(timer_base)) { + pr_err("Can't map registers"); + return -ENXIO; + } irq = irq_of_parse_and_map(node, 0); - if (irq <= 0) - panic("Can't parse IRQ"); + if (irq <= 0) { + pr_err("Can't parse IRQ"); + return -EINVAL; + } /* Set 1us for timer E */ val = readl(timer_base + TIMER_ISA_MUX); @@ -158,14 +162,17 @@ static void __init meson6_timer_init(struct device_node *node) meson6_clkevt_time_stop(CED_ID); ret = setup_irq(irq, &meson6_timer_irq); - if (ret) + if (ret) { pr_warn("failed to setup irq %d\n", irq); + return ret; + } meson6_clockevent.cpumask = cpu_possible_mask; meson6_clockevent.irq = irq; clockevents_config_and_register(&meson6_clockevent, USEC_PER_SEC, 1, 0xfffe); + return 0; } -CLOCKSOURCE_OF_DECLARE(meson6, "amlogic,meson6-timer", +CLOCKSOURCE_OF_DECLARE_RET(meson6, "amlogic,meson6-timer", meson6_timer_init); -- cgit v0.10.2 From d8152bf85d2c057fc39c3e20a4d623f524d9f09c Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Mon, 6 Jun 2016 17:57:25 +0200 Subject: clocksource/drivers/mips-gic-timer: Convert init function to return error The init functions do not return any error. They behave as the following: - panic, thus leading to a kernel crash while another timer may work and make the system boot up correctly or - print an error and let the caller unaware if the state of the system Change that by converting the init functions to return an error conforming to the CLOCKSOURCE_OF_RET prototype. Proper error handling (rollback, errno value) will be changed later case by case, thus this change just return back an error or success in the init function. Signed-off-by: Daniel Lezcano diff --git a/drivers/clocksource/mips-gic-timer.c b/drivers/clocksource/mips-gic-timer.c index 89d3e4d..b164b87 100644 --- a/drivers/clocksource/mips-gic-timer.c +++ b/drivers/clocksource/mips-gic-timer.c @@ -146,7 +146,7 @@ static struct clocksource gic_clocksource = { .archdata = { .vdso_clock_mode = VDSO_CLOCK_GIC }, }; -static void __init __gic_clocksource_init(void) +static int __init __gic_clocksource_init(void) { int ret; @@ -159,6 +159,8 @@ static void __init __gic_clocksource_init(void) ret = clocksource_register_hz(&gic_clocksource, gic_frequency); if (ret < 0) pr_warn("GIC: Unable to register clocksource\n"); + + return ret; } void __init gic_clocksource_init(unsigned int frequency) @@ -179,31 +181,35 @@ static void __init gic_clocksource_of_init(struct device_node *node) struct clk *clk; int ret; - if (WARN_ON(!gic_present || !node->parent || - !of_device_is_compatible(node->parent, "mti,gic"))) - return; + if (!gic_present || !node->parent || + !of_device_is_compatible(node->parent, "mti,gic")) { + pr_warn("No DT definition for the mips gic driver"); + return -ENXIO; + } clk = of_clk_get(node, 0); if (!IS_ERR(clk)) { if (clk_prepare_enable(clk) < 0) { pr_err("GIC failed to enable clock\n"); clk_put(clk); - return; + return PTR_ERR(clk); } gic_frequency = clk_get_rate(clk); } else if (of_property_read_u32(node, "clock-frequency", &gic_frequency)) { pr_err("GIC frequency not specified.\n"); - return; + return -EINVAL;; } gic_timer_irq = irq_of_parse_and_map(node, 0); if (!gic_timer_irq) { pr_err("GIC timer IRQ not specified.\n"); - return; + return -EINVAL;; } - __gic_clocksource_init(); + ret = __gic_clocksource_init(); + if (ret) + return ret; ret = gic_clockevent_init(); if (!ret && !IS_ERR(clk)) { @@ -213,6 +219,8 @@ static void __init gic_clocksource_of_init(struct device_node *node) /* And finally start the counter */ gic_start_count(); + + return 0; } -CLOCKSOURCE_OF_DECLARE(mips_gic_timer, "mti,gic-timer", +CLOCKSOURCE_OF_DECLARE_RET(mips_gic_timer, "mti,gic-timer", gic_clocksource_of_init); -- cgit v0.10.2 From b7357e656ca45dd57ef02f2a1be513af2b80579c Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Mon, 6 Jun 2016 17:57:38 +0200 Subject: clocksource/drivers/moxart: Convert init function to return error The init functions do not return any error. They behave as the following: - panic, thus leading to a kernel crash while another timer may work and make the system boot up correctly or - print an error and let the caller unaware if the state of the system Change that by converting the init functions to return an error conforming to the CLOCKSOURCE_OF_RET prototype. Proper error handling (rollback, errno value) will be changed later case by case, thus this change just return back an error or success in the init function. Signed-off-by: Daniel Lezcano diff --git a/drivers/clocksource/moxart_timer.c b/drivers/clocksource/moxart_timer.c index 19857af..b9c30cd 100644 --- a/drivers/clocksource/moxart_timer.c +++ b/drivers/clocksource/moxart_timer.c @@ -119,34 +119,45 @@ static struct irqaction moxart_timer_irq = { .dev_id = &moxart_clockevent, }; -static void __init moxart_timer_init(struct device_node *node) +static int __init moxart_timer_init(struct device_node *node) { int ret, irq; unsigned long pclk; struct clk *clk; base = of_iomap(node, 0); - if (!base) - panic("%s: of_iomap failed\n", node->full_name); + if (!base) { + pr_err("%s: of_iomap failed\n", node->full_name); + return -ENXIO; + } irq = irq_of_parse_and_map(node, 0); - if (irq <= 0) - panic("%s: irq_of_parse_and_map failed\n", node->full_name); + if (irq <= 0) { + pr_err("%s: irq_of_parse_and_map failed\n", node->full_name); + return -EINVAL; + } ret = setup_irq(irq, &moxart_timer_irq); - if (ret) - panic("%s: setup_irq failed\n", node->full_name); + if (ret) { + pr_err("%s: setup_irq failed\n", node->full_name); + return ret; + } clk = of_clk_get(node, 0); - if (IS_ERR(clk)) - panic("%s: of_clk_get failed\n", node->full_name); + if (IS_ERR(clk)) { + pr_err("%s: of_clk_get failed\n", node->full_name); + return PTR_ERR(clk); + } pclk = clk_get_rate(clk); - if (clocksource_mmio_init(base + TIMER2_BASE + REG_COUNT, - "moxart_timer", pclk, 200, 32, - clocksource_mmio_readl_down)) - panic("%s: clocksource_mmio_init failed\n", node->full_name); + ret = clocksource_mmio_init(base + TIMER2_BASE + REG_COUNT, + "moxart_timer", pclk, 200, 32, + clocksource_mmio_readl_down); + if (ret) { + pr_err("%s: clocksource_mmio_init failed\n", node->full_name); + return ret; + } clock_count_per_tick = DIV_ROUND_CLOSEST(pclk, HZ); @@ -164,5 +175,7 @@ static void __init moxart_timer_init(struct device_node *node) */ clockevents_config_and_register(&moxart_clockevent, pclk, 0x4, 0xfffffffe); + + return 0; } -CLOCKSOURCE_OF_DECLARE(moxart, "moxa,moxart-timer", moxart_timer_init); +CLOCKSOURCE_OF_DECLARE_RET(moxart, "moxa,moxart-timer", moxart_timer_init); -- cgit v0.10.2 From 0cc7afc6e0ccd593f4ce86feb83ac45cd6bd9440 Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Mon, 6 Jun 2016 17:57:50 +0200 Subject: clocksource/drivers/mps2-timer: Convert init function to return error The init functions do not return any error. They behave as the following: - panic, thus leading to a kernel crash while another timer may work and make the system boot up correctly or - print an error and let the caller unaware if the state of the system Change that by converting the init functions to return an error conforming to the CLOCKSOURCE_OF_RET prototype. Proper error handling (rollback, errno value) will be changed later case by case, thus this change just return back an error or success in the init function. Signed-off-by: Daniel Lezcano Acked-by: Liviu Dudau diff --git a/drivers/clocksource/mps2-timer.c b/drivers/clocksource/mps2-timer.c index 3d33a5e..c303fa9 100644 --- a/drivers/clocksource/mps2-timer.c +++ b/drivers/clocksource/mps2-timer.c @@ -250,7 +250,7 @@ out: return ret; } -static void __init mps2_timer_init(struct device_node *np) +static int __init mps2_timer_init(struct device_node *np) { static int has_clocksource, has_clockevent; int ret; @@ -259,7 +259,7 @@ static void __init mps2_timer_init(struct device_node *np) ret = mps2_clocksource_init(np); if (!ret) { has_clocksource = 1; - return; + return 0; } } @@ -267,9 +267,11 @@ static void __init mps2_timer_init(struct device_node *np) ret = mps2_clockevent_init(np); if (!ret) { has_clockevent = 1; - return; + return 0; } } + + return 0; } -CLOCKSOURCE_OF_DECLARE(mps2_timer, "arm,mps2-timer", mps2_timer_init); +CLOCKSOURCE_OF_DECLARE_RET(mps2_timer, "arm,mps2-timer", mps2_timer_init); -- cgit v0.10.2 From e1d2b9f024c519788c044ee6a5f694d69973791e Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Mon, 6 Jun 2016 17:58:03 +0200 Subject: clocksource/drivers/mxs: Convert init function to return error The init function does not return any error, it prints a message, returns and lets the caller unaware if the state of the system. Change that by converting the init functions to return an error conforming to the CLOCKSOURCE_OF_RET prototype. Proper error handling (rollback, errno value) will be changed later case by case, thus this change just return back an error or success in the init function. Signed-off-by: Daniel Lezcano diff --git a/drivers/clocksource/mxs_timer.c b/drivers/clocksource/mxs_timer.c index f5ce296..17b9d19 100644 --- a/drivers/clocksource/mxs_timer.c +++ b/drivers/clocksource/mxs_timer.c @@ -226,10 +226,10 @@ static int __init mxs_clocksource_init(struct clk *timer_clk) return 0; } -static void __init mxs_timer_init(struct device_node *np) +static int __init mxs_timer_init(struct device_node *np) { struct clk *timer_clk; - int irq; + int irq, ret; mxs_timrot_base = of_iomap(np, 0); WARN_ON(!mxs_timrot_base); @@ -237,10 +237,12 @@ static void __init mxs_timer_init(struct device_node *np) timer_clk = of_clk_get(np, 0); if (IS_ERR(timer_clk)) { pr_err("%s: failed to get clk\n", __func__); - return; + return PTR_ERR(timer_clk); } - clk_prepare_enable(timer_clk); + ret = clk_prepare_enable(timer_clk); + if (ret) + return ret; /* * Initialize timers to a known state @@ -278,11 +280,19 @@ static void __init mxs_timer_init(struct device_node *np) mxs_timrot_base + HW_TIMROT_FIXED_COUNTn(1)); /* init and register the timer to the framework */ - mxs_clocksource_init(timer_clk); - mxs_clockevent_init(timer_clk); + ret = mxs_clocksource_init(timer_clk); + if (ret) + return ret; + + ret = mxs_clockevent_init(timer_clk); + if (ret) + return ret; /* Make irqs happen */ irq = irq_of_parse_and_map(np, 0); - setup_irq(irq, &mxs_timer_irq); + if (irq <= 0) + return -EINVAL; + + return setup_irq(irq, &mxs_timer_irq); } -CLOCKSOURCE_OF_DECLARE(mxs, "fsl,timrot", mxs_timer_init); +CLOCKSOURCE_OF_DECLARE_RET(mxs, "fsl,timrot", mxs_timer_init); -- cgit v0.10.2 From e46105aff5e53b27844541ebe0de5089268c6692 Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Mon, 6 Jun 2016 17:58:15 +0200 Subject: clocksource/drivers/nomadik-mtu: Convert init function to return error The init functions do not return any error. They behave as the following: - panic, thus leading to a kernel crash while another timer may work and make the system boot up correctly or - print an error and let the caller unaware if the state of the system Change that by converting the init functions to return an error conforming to the CLOCKSOURCE_OF_RET prototype. Proper error handling (rollback, errno value) will be changed later case by case, thus this change just return back an error or success in the init function. Signed-off-by: Daniel Lezcano diff --git a/drivers/clocksource/nomadik-mtu.c b/drivers/clocksource/nomadik-mtu.c index bc8dd44..d2be5b3 100644 --- a/drivers/clocksource/nomadik-mtu.c +++ b/drivers/clocksource/nomadik-mtu.c @@ -193,10 +193,11 @@ static struct irqaction nmdk_timer_irq = { .dev_id = &nmdk_clkevt, }; -static void __init nmdk_timer_init(void __iomem *base, int irq, +static int __init nmdk_timer_init(void __iomem *base, int irq, struct clk *pclk, struct clk *clk) { unsigned long rate; + int ret; mtu_base = base; @@ -226,10 +227,12 @@ static void __init nmdk_timer_init(void __iomem *base, int irq, /* Timer 0 is the free running clocksource */ nmdk_clksrc_reset(); - if (clocksource_mmio_init(mtu_base + MTU_VAL(0), "mtu_0", - rate, 200, 32, clocksource_mmio_readl_down)) - pr_err("timer: failed to initialize clock source %s\n", - "mtu_0"); + ret = clocksource_mmio_init(mtu_base + MTU_VAL(0), "mtu_0", + rate, 200, 32, clocksource_mmio_readl_down); + if (ret) { + pr_err("timer: failed to initialize clock source %s\n", "mtu_0"); + return ret; + } #ifdef CONFIG_CLKSRC_NOMADIK_MTU_SCHED_CLOCK sched_clock_register(nomadik_read_sched_clock, 32, rate); @@ -244,9 +247,11 @@ static void __init nmdk_timer_init(void __iomem *base, int irq, mtu_delay_timer.read_current_timer = &nmdk_timer_read_current_timer; mtu_delay_timer.freq = rate; register_current_timer_delay(&mtu_delay_timer); + + return 0; } -static void __init nmdk_timer_of_init(struct device_node *node) +static int __init nmdk_timer_of_init(struct device_node *node) { struct clk *pclk; struct clk *clk; @@ -254,22 +259,30 @@ static void __init nmdk_timer_of_init(struct device_node *node) int irq; base = of_iomap(node, 0); - if (!base) - panic("Can't remap registers"); + if (!base) { + pr_err("Can't remap registers"); + return -ENXIO; + } pclk = of_clk_get_by_name(node, "apb_pclk"); - if (IS_ERR(pclk)) - panic("could not get apb_pclk"); + if (IS_ERR(pclk)) { + pr_err("could not get apb_pclk"); + return PTR_ERR(pclk); + } clk = of_clk_get_by_name(node, "timclk"); - if (IS_ERR(clk)) - panic("could not get timclk"); + if (IS_ERR(clk)) { + pr_err("could not get timclk"); + return PTR_ERR(clk); + } irq = irq_of_parse_and_map(node, 0); - if (irq <= 0) - panic("Can't parse IRQ"); + if (irq <= 0) { + pr_err("Can't parse IRQ"); + return -EINVAL; + } - nmdk_timer_init(base, irq, pclk, clk); + return nmdk_timer_init(base, irq, pclk, clk); } -CLOCKSOURCE_OF_DECLARE(nomadik_mtu, "st,nomadik-mtu", +CLOCKSOURCE_OF_DECLARE_RET(nomadik_mtu, "st,nomadik-mtu", nmdk_timer_of_init); -- cgit v0.10.2 From be3aff842d646f64c1c82e3ee8a0ba14c0319a30 Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Mon, 6 Jun 2016 17:58:27 +0200 Subject: clocksource/drivers/pxa: Convert init function to return error The init functions do not return any error. They behave as the following: - panic, thus leading to a kernel crash while another timer may work and make the system boot up correctly or - print an error and let the caller unaware if the state of the system Change that by converting the init functions to return an error conforming to the CLOCKSOURCE_OF_RET prototype. Proper error handling (rollback, errno value) will be changed later case by case, thus this change just return back an error or success in the init function. Signed-off-by: Daniel Lezcano diff --git a/drivers/clocksource/pxa_timer.c b/drivers/clocksource/pxa_timer.c index 45b6a49..59af75c 100644 --- a/drivers/clocksource/pxa_timer.c +++ b/drivers/clocksource/pxa_timer.c @@ -150,8 +150,10 @@ static struct irqaction pxa_ost0_irq = { .dev_id = &ckevt_pxa_osmr0, }; -static void __init pxa_timer_common_init(int irq, unsigned long clock_tick_rate) +static int __init pxa_timer_common_init(int irq, unsigned long clock_tick_rate) { + int ret; + timer_writel(0, OIER); timer_writel(OSSR_M0 | OSSR_M1 | OSSR_M2 | OSSR_M3, OSSR); @@ -159,41 +161,59 @@ static void __init pxa_timer_common_init(int irq, unsigned long clock_tick_rate) ckevt_pxa_osmr0.cpumask = cpumask_of(0); - setup_irq(irq, &pxa_ost0_irq); + ret = setup_irq(irq, &pxa_ost0_irq); + if (ret) { + pr_err("Failed to setup irq"); + return ret; + } + + ret = clocksource_mmio_init(timer_base + OSCR, "oscr0", clock_tick_rate, 200, + 32, clocksource_mmio_readl_up); + if (ret) { + pr_err("Failed to init clocksource"); + return ret; + } - clocksource_mmio_init(timer_base + OSCR, "oscr0", clock_tick_rate, 200, - 32, clocksource_mmio_readl_up); clockevents_config_and_register(&ckevt_pxa_osmr0, clock_tick_rate, MIN_OSCR_DELTA * 2, 0x7fffffff); + + return 0; } -static void __init pxa_timer_dt_init(struct device_node *np) +static int __init pxa_timer_dt_init(struct device_node *np) { struct clk *clk; - int irq; + int irq, ret; /* timer registers are shared with watchdog timer */ timer_base = of_iomap(np, 0); - if (!timer_base) - panic("%s: unable to map resource\n", np->name); + if (!timer_base) { + pr_err("%s: unable to map resource\n", np->name); + return -ENXIO; + } clk = of_clk_get(np, 0); if (IS_ERR(clk)) { pr_crit("%s: unable to get clk\n", np->name); - return; + return PTR_ERR(clk); + } + + ret = clk_prepare_enable(clk); + if (ret) { + pr_crit("Failed to prepare clock"); + return ret; } - clk_prepare_enable(clk); /* we are only interested in OS-timer0 irq */ irq = irq_of_parse_and_map(np, 0); if (irq <= 0) { pr_crit("%s: unable to parse OS-timer0 irq\n", np->name); - return; + return -EINVAL; } - pxa_timer_common_init(irq, clk_get_rate(clk)); + return pxa_timer_common_init(irq, clk_get_rate(clk)); } -CLOCKSOURCE_OF_DECLARE(pxa_timer, "marvell,pxa-timer", pxa_timer_dt_init); +CLOCKSOURCE_OF_DECLARE_RET(pxa_timer, "marvell,pxa-timer", pxa_timer_dt_init); /* * Legacy timer init for non device-tree boards. -- cgit v0.10.2 From ab51189ca48520debe92ed7738a49c185b0f57d5 Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Mon, 6 Jun 2016 17:58:43 +0200 Subject: clocksource/drivers/qcom: Convert init function to return error The init functions do not return any error. They behave as the following: - panic, thus leading to a kernel crash while another timer may work and make the system boot up correctly or - print an error and let the caller unaware if the state of the system Change that by converting the init functions to return an error conforming to the CLOCKSOURCE_OF_RET prototype. Proper error handling (rollback, errno value) will be changed later case by case, thus this change just return back an error or success in the init function. Signed-off-by: Daniel Lezcano diff --git a/drivers/clocksource/qcom-timer.c b/drivers/clocksource/qcom-timer.c index f8e09f9..79f73bd 100644 --- a/drivers/clocksource/qcom-timer.c +++ b/drivers/clocksource/qcom-timer.c @@ -178,7 +178,7 @@ static struct delay_timer msm_delay_timer = { .read_current_timer = msm_read_current_timer, }; -static void __init msm_timer_init(u32 dgt_hz, int sched_bits, int irq, +static int __init msm_timer_init(u32 dgt_hz, int sched_bits, int irq, bool percpu) { struct clocksource *cs = &msm_clocksource; @@ -218,12 +218,14 @@ err: sched_clock_register(msm_sched_clock_read, sched_bits, dgt_hz); msm_delay_timer.freq = dgt_hz; register_current_timer_delay(&msm_delay_timer); + + return res; } -static void __init msm_dt_timer_init(struct device_node *np) +static int __init msm_dt_timer_init(struct device_node *np) { u32 freq; - int irq; + int irq, ret; struct resource res; u32 percpu_offset; void __iomem *base; @@ -232,34 +234,35 @@ static void __init msm_dt_timer_init(struct device_node *np) base = of_iomap(np, 0); if (!base) { pr_err("Failed to map event base\n"); - return; + return -ENXIO; } /* We use GPT0 for the clockevent */ irq = irq_of_parse_and_map(np, 1); if (irq <= 0) { pr_err("Can't get irq\n"); - return; + return -EINVAL; } /* We use CPU0's DGT for the clocksource */ if (of_property_read_u32(np, "cpu-offset", &percpu_offset)) percpu_offset = 0; - if (of_address_to_resource(np, 0, &res)) { + ret = of_address_to_resource(np, 0, &res); + if (ret) { pr_err("Failed to parse DGT resource\n"); - return; + return ret; } cpu0_base = ioremap(res.start + percpu_offset, resource_size(&res)); if (!cpu0_base) { pr_err("Failed to map source base\n"); - return; + return -EINVAL; } if (of_property_read_u32(np, "clock-frequency", &freq)) { pr_err("Unknown frequency\n"); - return; + return -EINVAL; } event_base = base + 0x4; @@ -268,7 +271,7 @@ static void __init msm_dt_timer_init(struct device_node *np) freq /= 4; writel_relaxed(DGT_CLK_CTL_DIV_4, source_base + DGT_CLK_CTL); - msm_timer_init(freq, 32, irq, !!percpu_offset); + return msm_timer_init(freq, 32, irq, !!percpu_offset); } -CLOCKSOURCE_OF_DECLARE(kpss_timer, "qcom,kpss-timer", msm_dt_timer_init); -CLOCKSOURCE_OF_DECLARE(scss_timer, "qcom,scss-timer", msm_dt_timer_init); +CLOCKSOURCE_OF_DECLARE_RET(kpss_timer, "qcom,kpss-timer", msm_dt_timer_init); +CLOCKSOURCE_OF_DECLARE_RET(scss_timer, "qcom,scss-timer", msm_dt_timer_init); -- cgit v0.10.2 From 0993f57b020cd6936aa51e675a2eb59e7c063a84 Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Mon, 6 Jun 2016 17:58:56 +0200 Subject: clocksource/drivers/samsung_pwm: Convert init function to return error The init functions do not return any error. They behave as the following: - panic, thus leading to a kernel crash while another timer may work and make the system boot up correctly or - print an error and let the caller unaware if the state of the system Change that by converting the init functions to return an error conforming to the CLOCKSOURCE_OF_RET prototype. Proper error handling (rollback, errno value) will be changed later case by case, thus this change just return back an error or success in the init function. Signed-off-by: Daniel Lezcano diff --git a/drivers/clocksource/samsung_pwm_timer.c b/drivers/clocksource/samsung_pwm_timer.c index 47e0515..27a9797 100644 --- a/drivers/clocksource/samsung_pwm_timer.c +++ b/drivers/clocksource/samsung_pwm_timer.c @@ -333,11 +333,10 @@ static u64 notrace samsung_read_sched_clock(void) return samsung_clocksource_read(NULL); } -static void __init samsung_clocksource_init(void) +static int __init samsung_clocksource_init(void) { unsigned long pclk; unsigned long clock_rate; - int ret; pclk = clk_get_rate(pwm.timerclk); @@ -358,9 +357,7 @@ static void __init samsung_clocksource_init(void) pwm.variant.bits, clock_rate); samsung_clocksource.mask = CLOCKSOURCE_MASK(pwm.variant.bits); - ret = clocksource_register_hz(&samsung_clocksource, clock_rate); - if (ret) - panic("samsung_clocksource_timer: can't register clocksource\n"); + return clocksource_register_hz(&samsung_clocksource, clock_rate); } static void __init samsung_timer_resources(void) @@ -380,26 +377,31 @@ static void __init samsung_timer_resources(void) /* * PWM master driver */ -static void __init _samsung_pwm_clocksource_init(void) +static int __init _samsung_pwm_clocksource_init(void) { u8 mask; int channel; mask = ~pwm.variant.output_mask & ((1 << SAMSUNG_PWM_NUM) - 1); channel = fls(mask) - 1; - if (channel < 0) - panic("failed to find PWM channel for clocksource"); + if (channel < 0) { + pr_crit("failed to find PWM channel for clocksource"); + return -EINVAL; + } pwm.source_id = channel; mask &= ~(1 << channel); channel = fls(mask) - 1; - if (channel < 0) - panic("failed to find PWM channel for clock event"); + if (channel < 0) { + pr_crit("failed to find PWM channel for clock event"); + return -EINVAL; + } pwm.event_id = channel; samsung_timer_resources(); samsung_clockevent_init(); - samsung_clocksource_init(); + + return samsung_clocksource_init(); } void __init samsung_pwm_clocksource_init(void __iomem *base, @@ -417,8 +419,8 @@ void __init samsung_pwm_clocksource_init(void __iomem *base, } #ifdef CONFIG_CLKSRC_OF -static void __init samsung_pwm_alloc(struct device_node *np, - const struct samsung_pwm_variant *variant) +static int __init samsung_pwm_alloc(struct device_node *np, + const struct samsung_pwm_variant *variant) { struct property *prop; const __be32 *cur; @@ -441,14 +443,16 @@ static void __init samsung_pwm_alloc(struct device_node *np, pwm.base = of_iomap(np, 0); if (!pwm.base) { pr_err("%s: failed to map PWM registers\n", __func__); - return; + return -ENXIO; } pwm.timerclk = of_clk_get_by_name(np, "timers"); - if (IS_ERR(pwm.timerclk)) - panic("failed to get timers clock for timer"); + if (IS_ERR(pwm.timerclk)) { + pr_crit("failed to get timers clock for timer"); + return PTR_ERR(pwm.timerclk); + } - _samsung_pwm_clocksource_init(); + return _samsung_pwm_clocksource_init(); } static const struct samsung_pwm_variant s3c24xx_variant = { @@ -458,11 +462,11 @@ static const struct samsung_pwm_variant s3c24xx_variant = { .tclk_mask = (1 << 4), }; -static void __init s3c2410_pwm_clocksource_init(struct device_node *np) +static int __init s3c2410_pwm_clocksource_init(struct device_node *np) { - samsung_pwm_alloc(np, &s3c24xx_variant); + return samsung_pwm_alloc(np, &s3c24xx_variant); } -CLOCKSOURCE_OF_DECLARE(s3c2410_pwm, "samsung,s3c2410-pwm", s3c2410_pwm_clocksource_init); +CLOCKSOURCE_OF_DECLARE_RET(s3c2410_pwm, "samsung,s3c2410-pwm", s3c2410_pwm_clocksource_init); static const struct samsung_pwm_variant s3c64xx_variant = { .bits = 32, @@ -471,11 +475,11 @@ static const struct samsung_pwm_variant s3c64xx_variant = { .tclk_mask = (1 << 7) | (1 << 6) | (1 << 5), }; -static void __init s3c64xx_pwm_clocksource_init(struct device_node *np) +static int __init s3c64xx_pwm_clocksource_init(struct device_node *np) { - samsung_pwm_alloc(np, &s3c64xx_variant); + return samsung_pwm_alloc(np, &s3c64xx_variant); } -CLOCKSOURCE_OF_DECLARE(s3c6400_pwm, "samsung,s3c6400-pwm", s3c64xx_pwm_clocksource_init); +CLOCKSOURCE_OF_DECLARE_RET(s3c6400_pwm, "samsung,s3c6400-pwm", s3c64xx_pwm_clocksource_init); static const struct samsung_pwm_variant s5p64x0_variant = { .bits = 32, @@ -484,11 +488,11 @@ static const struct samsung_pwm_variant s5p64x0_variant = { .tclk_mask = 0, }; -static void __init s5p64x0_pwm_clocksource_init(struct device_node *np) +static int __init s5p64x0_pwm_clocksource_init(struct device_node *np) { - samsung_pwm_alloc(np, &s5p64x0_variant); + return samsung_pwm_alloc(np, &s5p64x0_variant); } -CLOCKSOURCE_OF_DECLARE(s5p6440_pwm, "samsung,s5p6440-pwm", s5p64x0_pwm_clocksource_init); +CLOCKSOURCE_OF_DECLARE_RET(s5p6440_pwm, "samsung,s5p6440-pwm", s5p64x0_pwm_clocksource_init); static const struct samsung_pwm_variant s5p_variant = { .bits = 32, @@ -497,9 +501,9 @@ static const struct samsung_pwm_variant s5p_variant = { .tclk_mask = (1 << 5), }; -static void __init s5p_pwm_clocksource_init(struct device_node *np) +static int __init s5p_pwm_clocksource_init(struct device_node *np) { - samsung_pwm_alloc(np, &s5p_variant); + return samsung_pwm_alloc(np, &s5p_variant); } -CLOCKSOURCE_OF_DECLARE(s5pc100_pwm, "samsung,s5pc100-pwm", s5p_pwm_clocksource_init); +CLOCKSOURCE_OF_DECLARE_RET(s5pc100_pwm, "samsung,s5pc100-pwm", s5p_pwm_clocksource_init); #endif -- cgit v0.10.2 From ce5dc743f6669467c162f480e3c7bf61ec5aaf61 Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Mon, 6 Jun 2016 17:59:09 +0200 Subject: clocksource/drivers/sun4i: Convert init function to return error The init functions do not return any error. They behave as the following: - panic, thus leading to a kernel crash while another timer may work and make the system boot up correctly or - print an error and let the caller unaware if the state of the system Change that by converting the init functions to return an error conforming to the CLOCKSOURCE_OF_RET prototype. Proper error handling (rollback, errno value) will be changed later case by case, thus this change just return back an error or success in the init function. Signed-off-by: Daniel Lezcano diff --git a/drivers/clocksource/sun4i_timer.c b/drivers/clocksource/sun4i_timer.c index 6f3719d..4453730 100644 --- a/drivers/clocksource/sun4i_timer.c +++ b/drivers/clocksource/sun4i_timer.c @@ -146,7 +146,7 @@ static u64 notrace sun4i_timer_sched_read(void) return ~readl(timer_base + TIMER_CNTVAL_REG(1)); } -static void __init sun4i_timer_init(struct device_node *node) +static int __init sun4i_timer_init(struct device_node *node) { unsigned long rate = 0; struct clk *clk; @@ -154,17 +154,28 @@ static void __init sun4i_timer_init(struct device_node *node) u32 val; timer_base = of_iomap(node, 0); - if (!timer_base) - panic("Can't map registers"); + if (!timer_base) { + pr_crit("Can't map registers"); + return -ENXIO; + } irq = irq_of_parse_and_map(node, 0); - if (irq <= 0) - panic("Can't parse IRQ"); + if (irq <= 0) { + pr_crit("Can't parse IRQ"); + return -EINVAL; + } clk = of_clk_get(node, 0); - if (IS_ERR(clk)) - panic("Can't get timer clock"); - clk_prepare_enable(clk); + if (IS_ERR(clk)) { + pr_crit("Can't get timer clock"); + return PTR_ERR(clk); + } + + ret = clk_prepare_enable(clk); + if (ret) { + pr_err("Failed to prepare clock"); + return ret; + } rate = clk_get_rate(clk); @@ -182,8 +193,12 @@ static void __init sun4i_timer_init(struct device_node *node) of_machine_is_compatible("allwinner,sun5i-a10s")) sched_clock_register(sun4i_timer_sched_read, 32, rate); - clocksource_mmio_init(timer_base + TIMER_CNTVAL_REG(1), node->name, - rate, 350, 32, clocksource_mmio_readl_down); + ret = clocksource_mmio_init(timer_base + TIMER_CNTVAL_REG(1), node->name, + rate, 350, 32, clocksource_mmio_readl_down); + if (ret) { + pr_err("Failed to register clocksource"); + return ret; + } ticks_per_jiffy = DIV_ROUND_UP(rate, HZ); @@ -200,12 +215,16 @@ static void __init sun4i_timer_init(struct device_node *node) TIMER_SYNC_TICKS, 0xffffffff); ret = setup_irq(irq, &sun4i_timer_irq); - if (ret) - pr_warn("failed to setup irq %d\n", irq); + if (ret) { + pr_err("failed to setup irq %d\n", irq); + return ret; + } /* Enable timer0 interrupt */ val = readl(timer_base + TIMER_IRQ_EN_REG); writel(val | TIMER_IRQ_EN(0), timer_base + TIMER_IRQ_EN_REG); + + return ret; } -CLOCKSOURCE_OF_DECLARE(sun4i, "allwinner,sun4i-a10-timer", +CLOCKSOURCE_OF_DECLARE_RET(sun4i, "allwinner,sun4i-a10-timer", sun4i_timer_init); -- cgit v0.10.2 From 0683d5035ca92c5646aaea00b493c946bff656d2 Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Mon, 6 Jun 2016 17:59:24 +0200 Subject: clocksource/drivers/tango_xtal: Convert init function to return error The init functions do not return any error. They behave as the following: - panic, thus leading to a kernel crash while another timer may work and make the system boot up correctly or - print an error and leave the caller unaware of the state of the system Change that by converting the init functions to return an error conforming to the CLOCKSOURCE_OF_RET prototype. Proper error handling (rollback, errno value) will be changed later case by case, thus this change just returns an error code from the init function. Signed-off-by: Daniel Lezcano Acked-by: Marc Gonzalez diff --git a/drivers/clocksource/tango_xtal.c b/drivers/clocksource/tango_xtal.c index c407c47..7dc716c 100644 --- a/drivers/clocksource/tango_xtal.c +++ b/drivers/clocksource/tango_xtal.c @@ -19,7 +19,7 @@ static u64 notrace read_sched_clock(void) return read_xtal_counter(); } -static void __init tango_clocksource_init(struct device_node *np) +static int __init tango_clocksource_init(struct device_node *np) { struct clk *clk; int xtal_freq, ret; @@ -27,13 +27,13 @@ static void __init tango_clocksource_init(struct device_node *np) xtal_in_cnt = of_iomap(np, 0); if (xtal_in_cnt == NULL) { pr_err("%s: invalid address\n", np->full_name); - return; + return -ENXIO; } clk = of_clk_get(np, 0); if (IS_ERR(clk)) { pr_err("%s: invalid clock\n", np->full_name); - return; + return PTR_ERR(clk); } xtal_freq = clk_get_rate(clk); @@ -44,11 +44,13 @@ static void __init tango_clocksource_init(struct device_node *np) 32, clocksource_mmio_readl_up); if (ret) { pr_err("%s: registration failed\n", np->full_name); - return; + return ret; } sched_clock_register(read_sched_clock, 32, xtal_freq); register_current_timer_delay(&delay_timer); + + return 0; } -CLOCKSOURCE_OF_DECLARE(tango, "sigma,tick-counter", tango_clocksource_init); +CLOCKSOURCE_OF_DECLARE_RET(tango, "sigma,tick-counter", tango_clocksource_init); -- cgit v0.10.2 From 53978bba61853a85dfddc1980178d488e2efe2eb Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Mon, 6 Jun 2016 17:59:43 +0200 Subject: clocksource/drivers/tegra20: Convert init function to return error The init functions do not return any error. They behave as the following: - panic, thus leading to a kernel crash while another timer may work and make the system boot up correctly or - print an error and let the caller unaware if the state of the system Change that by converting the init functions to return an error conforming to the CLOCKSOURCE_OF_RET prototype. Proper error handling (rollback, errno value) will be changed later case by case, thus this change just return back an error or success in the init function. Signed-off-by: Daniel Lezcano diff --git a/drivers/clocksource/tegra20_timer.c b/drivers/clocksource/tegra20_timer.c index 7b94ad2..543c37e 100644 --- a/drivers/clocksource/tegra20_timer.c +++ b/drivers/clocksource/tegra20_timer.c @@ -165,7 +165,7 @@ static struct irqaction tegra_timer_irq = { .dev_id = &tegra_clockevent, }; -static void __init tegra20_init_timer(struct device_node *np) +static int __init tegra20_init_timer(struct device_node *np) { struct clk *clk; unsigned long rate; @@ -174,13 +174,13 @@ static void __init tegra20_init_timer(struct device_node *np) timer_reg_base = of_iomap(np, 0); if (!timer_reg_base) { pr_err("Can't map timer registers\n"); - BUG(); + return -ENXIO; } tegra_timer_irq.irq = irq_of_parse_and_map(np, 2); if (tegra_timer_irq.irq <= 0) { pr_err("Failed to map timer IRQ\n"); - BUG(); + return -EINVAL; } clk = of_clk_get(np, 0); @@ -211,10 +211,12 @@ static void __init tegra20_init_timer(struct device_node *np) sched_clock_register(tegra_read_sched_clock, 32, 1000000); - if (clocksource_mmio_init(timer_reg_base + TIMERUS_CNTR_1US, - "timer_us", 1000000, 300, 32, clocksource_mmio_readl_up)) { + ret = clocksource_mmio_init(timer_reg_base + TIMERUS_CNTR_1US, + "timer_us", 1000000, 300, 32, + clocksource_mmio_readl_up); + if (ret) { pr_err("Failed to register clocksource\n"); - BUG(); + return ret; } tegra_delay_timer.read_current_timer = @@ -225,24 +227,26 @@ static void __init tegra20_init_timer(struct device_node *np) ret = setup_irq(tegra_timer_irq.irq, &tegra_timer_irq); if (ret) { pr_err("Failed to register timer IRQ: %d\n", ret); - BUG(); + return ret; } tegra_clockevent.cpumask = cpu_all_mask; tegra_clockevent.irq = tegra_timer_irq.irq; clockevents_config_and_register(&tegra_clockevent, 1000000, 0x1, 0x1fffffff); + + return 0; } -CLOCKSOURCE_OF_DECLARE(tegra20_timer, "nvidia,tegra20-timer", tegra20_init_timer); +CLOCKSOURCE_OF_DECLARE_RET(tegra20_timer, "nvidia,tegra20-timer", tegra20_init_timer); -static void __init tegra20_init_rtc(struct device_node *np) +static int __init tegra20_init_rtc(struct device_node *np) { struct clk *clk; rtc_base = of_iomap(np, 0); if (!rtc_base) { pr_err("Can't map RTC registers"); - BUG(); + return -ENXIO; } /* @@ -255,6 +259,6 @@ static void __init tegra20_init_rtc(struct device_node *np) else clk_prepare_enable(clk); - register_persistent_clock(NULL, tegra_read_persistent_clock64); + return register_persistent_clock(NULL, tegra_read_persistent_clock64); } -CLOCKSOURCE_OF_DECLARE(tegra20_rtc, "nvidia,tegra20-rtc", tegra20_init_rtc); +CLOCKSOURCE_OF_DECLARE_RET(tegra20_rtc, "nvidia,tegra20-rtc", tegra20_init_rtc); -- cgit v0.10.2 From 12549e27c63c61d76bb059bfafce0a4ee05c7e90 Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Mon, 6 Jun 2016 18:00:01 +0200 Subject: clocksource/drivers/time-armada-370-xp: Convert init function to return error The init functions do not return any error. They behave as the following: - panic, thus leading to a kernel crash while another timer may work and make the system boot up correctly or - print an error and let the caller unaware if the state of the system Change that by converting the init functions to return an error conforming to the CLOCKSOURCE_OF_RET prototype. Proper error handling (rollback, errno value) will be changed later case by case, thus this change just return back an error or success in the init function. Signed-off-by: Daniel Lezcano diff --git a/drivers/clocksource/time-armada-370-xp.c b/drivers/clocksource/time-armada-370-xp.c index 601dbf74..bc4ab48 100644 --- a/drivers/clocksource/time-armada-370-xp.c +++ b/drivers/clocksource/time-armada-370-xp.c @@ -260,14 +260,22 @@ static struct delay_timer armada_370_delay_timer = { .read_current_timer = armada_370_delay_timer_read, }; -static void __init armada_370_xp_timer_common_init(struct device_node *np) +static int __init armada_370_xp_timer_common_init(struct device_node *np) { u32 clr = 0, set = 0; int res; timer_base = of_iomap(np, 0); - WARN_ON(!timer_base); + if (!timer_base) { + pr_err("Failed to iomap"); + return -ENXIO; + } + local_base = of_iomap(np, 1); + if (!local_base) { + pr_err("Failed to iomap"); + return -ENXIO; + } if (timer25Mhz) { set = TIMER0_25MHZ; @@ -306,14 +314,19 @@ static void __init armada_370_xp_timer_common_init(struct device_node *np) */ sched_clock_register(armada_370_xp_read_sched_clock, 32, timer_clk); - clocksource_mmio_init(timer_base + TIMER0_VAL_OFF, - "armada_370_xp_clocksource", - timer_clk, 300, 32, clocksource_mmio_readl_down); + res = clocksource_mmio_init(timer_base + TIMER0_VAL_OFF, + "armada_370_xp_clocksource", + timer_clk, 300, 32, clocksource_mmio_readl_down); + if (res) { + pr_err("Failed to initialize clocksource mmio"); + return res; + } register_cpu_notifier(&armada_370_xp_timer_cpu_nb); armada_370_xp_evt = alloc_percpu(struct clock_event_device); - + if (!armada_370_xp_evt) + return -ENOMEM; /* * Setup clockevent timer (interrupt-driven). @@ -323,33 +336,54 @@ static void __init armada_370_xp_timer_common_init(struct device_node *np) "armada_370_xp_per_cpu_tick", armada_370_xp_evt); /* Immediately configure the timer on the boot CPU */ - if (!res) - armada_370_xp_timer_setup(this_cpu_ptr(armada_370_xp_evt)); + if (res) { + pr_err("Failed to request percpu irq"); + return res; + } + + res = armada_370_xp_timer_setup(this_cpu_ptr(armada_370_xp_evt)); + if (!res) { + pr_err("Failed to setup timer"); + return res; + } register_syscore_ops(&armada_370_xp_timer_syscore_ops); + + return 0; } -static void __init armada_xp_timer_init(struct device_node *np) +static int __init armada_xp_timer_init(struct device_node *np) { struct clk *clk = of_clk_get_by_name(np, "fixed"); + int ret; + + clk = of_clk_get(np, 0); + if (IS_ERR(clk)) { + pr_err("Failed to get clock"); + return PTR_ERR(clk); + } + + ret = clk_prepare_enable(clk); + if (ret) + return ret; - /* The 25Mhz fixed clock is mandatory, and must always be available */ - BUG_ON(IS_ERR(clk)); - clk_prepare_enable(clk); timer_clk = clk_get_rate(clk); - armada_370_xp_timer_common_init(np); + return armada_370_xp_timer_common_init(np); } -CLOCKSOURCE_OF_DECLARE(armada_xp, "marvell,armada-xp-timer", +CLOCKSOURCE_OF_DECLARE_RET(armada_xp, "marvell,armada-xp-timer", armada_xp_timer_init); -static void __init armada_375_timer_init(struct device_node *np) +static int __init armada_375_timer_init(struct device_node *np) { struct clk *clk; + int ret; clk = of_clk_get_by_name(np, "fixed"); if (!IS_ERR(clk)) { - clk_prepare_enable(clk); + ret = clk_prepare_enable(clk); + if (ret) + return ret; timer_clk = clk_get_rate(clk); } else { @@ -360,27 +394,43 @@ static void __init armada_375_timer_init(struct device_node *np) clk = of_clk_get(np, 0); /* Must have at least a clock */ - BUG_ON(IS_ERR(clk)); - clk_prepare_enable(clk); + if (IS_ERR(clk)) { + pr_err("Failed to get clock"); + return PTR_ERR(clk); + } + + ret = clk_prepare_enable(clk); + if (ret) + return ret; + timer_clk = clk_get_rate(clk) / TIMER_DIVIDER; timer25Mhz = false; } - armada_370_xp_timer_common_init(np); + return armada_370_xp_timer_common_init(np); } -CLOCKSOURCE_OF_DECLARE(armada_375, "marvell,armada-375-timer", +CLOCKSOURCE_OF_DECLARE_RET(armada_375, "marvell,armada-375-timer", armada_375_timer_init); -static void __init armada_370_timer_init(struct device_node *np) +static int __init armada_370_timer_init(struct device_node *np) { - struct clk *clk = of_clk_get(np, 0); + struct clk *clk; + int ret; + + clk = of_clk_get(np, 0); + if (IS_ERR(clk)) { + pr_err("Failed to get clock"); + return PTR_ERR(clk); + } + + ret = clk_prepare_enable(clk); + if (ret) + return ret; - BUG_ON(IS_ERR(clk)); - clk_prepare_enable(clk); timer_clk = clk_get_rate(clk) / TIMER_DIVIDER; timer25Mhz = false; - armada_370_xp_timer_common_init(np); + return armada_370_xp_timer_common_init(np); } -CLOCKSOURCE_OF_DECLARE(armada_370, "marvell,armada-370-timer", +CLOCKSOURCE_OF_DECLARE_RET(armada_370, "marvell,armada-370-timer", armada_370_timer_init); -- cgit v0.10.2 From dc5011131b8c78d1f5040bf0f79b7c38b4211fe6 Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Mon, 6 Jun 2016 18:00:14 +0200 Subject: clocksource/drivers/time-efm32: Convert init function to return error MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The init functions do not return any error and let the caller unaware of the state of the system. Change that by converting the init functions to return an error conforming to the CLOCKSOURCE_OF_RET prototype. Proper error handling (rollback, errno value) will be changed later case by case, thus this change just return back an error or success in the init function. Signed-off-by: Daniel Lezcano Acked-by: Uwe Kleine-König diff --git a/drivers/clocksource/time-efm32.c b/drivers/clocksource/time-efm32.c index b06e4c2..6e2f79f 100644 --- a/drivers/clocksource/time-efm32.c +++ b/drivers/clocksource/time-efm32.c @@ -233,10 +233,15 @@ static int __init efm32_clockevent_init(struct device_node *np) DIV_ROUND_CLOSEST(rate, 1024), 0xf, 0xffff); - setup_irq(irq, &efm32_clock_event_irq); + ret = setup_irq(irq, &efm32_clock_event_irq); + if (ret) { + pr_err("Failed setup irq"); + goto err_setup_irq; + } return 0; +err_setup_irq: err_get_irq: iounmap(base); @@ -255,16 +260,16 @@ err_clk_get: * This function asserts that we have exactly one clocksource and one * clock_event_device in the end. */ -static void __init efm32_timer_init(struct device_node *np) +static int __init efm32_timer_init(struct device_node *np) { static int has_clocksource, has_clockevent; - int ret; + int ret = 0; if (!has_clocksource) { ret = efm32_clocksource_init(np); if (!ret) { has_clocksource = 1; - return; + return 0; } } @@ -272,9 +277,11 @@ static void __init efm32_timer_init(struct device_node *np) ret = efm32_clockevent_init(np); if (!ret) { has_clockevent = 1; - return; + return 0; } } + + return ret; } -CLOCKSOURCE_OF_DECLARE(efm32compat, "efm32,timer", efm32_timer_init); -CLOCKSOURCE_OF_DECLARE(efm32, "energymicro,efm32-timer", efm32_timer_init); +CLOCKSOURCE_OF_DECLARE_RET(efm32compat, "efm32,timer", efm32_timer_init); +CLOCKSOURCE_OF_DECLARE_RET(efm32, "energymicro,efm32-timer", efm32_timer_init); -- cgit v0.10.2 From 4e2afeb9e653d4201039f06c02a37312bc38c3b8 Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Mon, 6 Jun 2016 18:00:27 +0200 Subject: clocksource/drivers/time-lpc32xx: Convert init function to return error The init functions do not return any error. They behave as the following: - panic, thus leading to a kernel crash while another timer may work and make the system boot up correctly or - print an error and let the caller unaware if the state of the system Change that by converting the init functions to return an error conforming to the CLOCKSOURCE_OF_RET prototype. Proper error handling (rollback, errno value) will be changed later case by case, thus this change just return back an error or success in the init function. Signed-off-by: Daniel Lezcano Acked-by: Sylvain Lemieux diff --git a/drivers/clocksource/time-lpc32xx.c b/drivers/clocksource/time-lpc32xx.c index daae61e..cb5b866 100644 --- a/drivers/clocksource/time-lpc32xx.c +++ b/drivers/clocksource/time-lpc32xx.c @@ -288,16 +288,16 @@ err_clk_enable: * This function asserts that we have exactly one clocksource and one * clock_event_device in the end. */ -static void __init lpc32xx_timer_init(struct device_node *np) +static int __init lpc32xx_timer_init(struct device_node *np) { static int has_clocksource, has_clockevent; - int ret; + int ret = 0; if (!has_clocksource) { ret = lpc32xx_clocksource_init(np); if (!ret) { has_clocksource = 1; - return; + return 0; } } @@ -305,8 +305,10 @@ static void __init lpc32xx_timer_init(struct device_node *np) ret = lpc32xx_clockevent_init(np); if (!ret) { has_clockevent = 1; - return; + return 0; } } + + return ret; } -CLOCKSOURCE_OF_DECLARE(lpc32xx_timer, "nxp,lpc3220-timer", lpc32xx_timer_init); +CLOCKSOURCE_OF_DECLARE_RET(lpc32xx_timer, "nxp,lpc3220-timer", lpc32xx_timer_init); -- cgit v0.10.2 From fbe4b3566ddcde4b0708330651cbd982e555f4eb Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Mon, 6 Jun 2016 18:00:38 +0200 Subject: clocksource/drivers/orion: Convert init function to return error The init functions do not return any error. They behave as the following: - panic, thus leading to a kernel crash while another timer may work and make the system boot up correctly or - print an error and let the caller unaware if the state of the system Change that by converting the init functions to return an error conforming to the CLOCKSOURCE_OF_RET prototype. Proper error handling (rollback, errno value) will be changed later case by case, thus this change just return back an error or success in the init function. Signed-off-by: Daniel Lezcano diff --git a/drivers/clocksource/time-orion.c b/drivers/clocksource/time-orion.c index 0ece742..5fdeb5d 100644 --- a/drivers/clocksource/time-orion.c +++ b/drivers/clocksource/time-orion.c @@ -104,25 +104,36 @@ static struct irqaction orion_clkevt_irq = { .handler = orion_clkevt_irq_handler, }; -static void __init orion_timer_init(struct device_node *np) +static int __init orion_timer_init(struct device_node *np) { struct clk *clk; - int irq; + int irq, ret; /* timer registers are shared with watchdog timer */ timer_base = of_iomap(np, 0); - if (!timer_base) - panic("%s: unable to map resource\n", np->name); + if (!timer_base) { + pr_err("%s: unable to map resource\n", np->name); + return -ENXIO; + } clk = of_clk_get(np, 0); - if (IS_ERR(clk)) - panic("%s: unable to get clk\n", np->name); - clk_prepare_enable(clk); + if (IS_ERR(clk)) { + pr_err("%s: unable to get clk\n", np->name); + return PTR_ERR(clk); + } + + ret = clk_prepare_enable(clk); + if (ret) { + pr_err("Failed to prepare clock"); + return ret; + } /* we are only interested in timer1 irq */ irq = irq_of_parse_and_map(np, 1); - if (irq <= 0) - panic("%s: unable to parse timer1 irq\n", np->name); + if (irq <= 0) { + pr_err("%s: unable to parse timer1 irq\n", np->name); + return -EINVAL; + } /* setup timer0 as free-running clocksource */ writel(~0, timer_base + TIMER0_VAL); @@ -130,19 +141,30 @@ static void __init orion_timer_init(struct device_node *np) atomic_io_modify(timer_base + TIMER_CTRL, TIMER0_RELOAD_EN | TIMER0_EN, TIMER0_RELOAD_EN | TIMER0_EN); - clocksource_mmio_init(timer_base + TIMER0_VAL, "orion_clocksource", - clk_get_rate(clk), 300, 32, - clocksource_mmio_readl_down); + + ret = clocksource_mmio_init(timer_base + TIMER0_VAL, "orion_clocksource", + clk_get_rate(clk), 300, 32, + clocksource_mmio_readl_down); + if (ret) { + pr_err("Failed to initialize mmio timer"); + return ret; + } + sched_clock_register(orion_read_sched_clock, 32, clk_get_rate(clk)); /* setup timer1 as clockevent timer */ - if (setup_irq(irq, &orion_clkevt_irq)) - panic("%s: unable to setup irq\n", np->name); + ret = setup_irq(irq, &orion_clkevt_irq); + if (ret) { + pr_err("%s: unable to setup irq\n", np->name); + return ret; + } ticks_per_jiffy = (clk_get_rate(clk) + HZ/2) / HZ; orion_clkevt.cpumask = cpumask_of(0); orion_clkevt.irq = irq; clockevents_config_and_register(&orion_clkevt, clk_get_rate(clk), ORION_ONESHOT_MIN, ORION_ONESHOT_MAX); + + return 0; } -CLOCKSOURCE_OF_DECLARE(orion_timer, "marvell,orion-timer", orion_timer_init); +CLOCKSOURCE_OF_DECLARE_RET(orion_timer, "marvell,orion-timer", orion_timer_init); -- cgit v0.10.2 From 41505a208f5d48671fcc9efe67a71cc8e28df653 Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Mon, 6 Jun 2016 18:00:51 +0200 Subject: clocksource/drivers/pistachio: Convert init function to return error The init functions do not return any error. They behave as the following: - panic, thus leading to a kernel crash while another timer may work and make the system boot up correctly or - print an error and let the caller unaware if the state of the system Change that by converting the init functions to return an error conforming to the CLOCKSOURCE_OF_RET prototype. Proper error handling (rollback, errno value) will be changed later case by case, thus this change just return back an error or success in the init function. Signed-off-by: Daniel Lezcano diff --git a/drivers/clocksource/time-pistachio.c b/drivers/clocksource/time-pistachio.c index 376e59b..adaaec5 100644 --- a/drivers/clocksource/time-pistachio.c +++ b/drivers/clocksource/time-pistachio.c @@ -148,7 +148,7 @@ static struct pistachio_clocksource pcs_gpt = { }, }; -static void __init pistachio_clksrc_of_init(struct device_node *node) +static int __init pistachio_clksrc_of_init(struct device_node *node) { struct clk *sys_clk, *fast_clk; struct regmap *periph_regs; @@ -158,45 +158,45 @@ static void __init pistachio_clksrc_of_init(struct device_node *node) pcs_gpt.base = of_iomap(node, 0); if (!pcs_gpt.base) { pr_err("cannot iomap\n"); - return; + return -ENXIO; } periph_regs = syscon_regmap_lookup_by_phandle(node, "img,cr-periph"); if (IS_ERR(periph_regs)) { pr_err("cannot get peripheral regmap (%ld)\n", PTR_ERR(periph_regs)); - return; + return PTR_ERR(periph_regs); } /* Switch to using the fast counter clock */ ret = regmap_update_bits(periph_regs, PERIP_TIMER_CONTROL, 0xf, 0x0); if (ret) - return; + return ret; sys_clk = of_clk_get_by_name(node, "sys"); if (IS_ERR(sys_clk)) { pr_err("clock get failed (%ld)\n", PTR_ERR(sys_clk)); - return; + return PTR_ERR(sys_clk); } fast_clk = of_clk_get_by_name(node, "fast"); if (IS_ERR(fast_clk)) { pr_err("clock get failed (%lu)\n", PTR_ERR(fast_clk)); - return; + return PTR_ERR(fast_clk); } ret = clk_prepare_enable(sys_clk); if (ret < 0) { pr_err("failed to enable clock (%d)\n", ret); - return; + return ret; } ret = clk_prepare_enable(fast_clk); if (ret < 0) { pr_err("failed to enable clock (%d)\n", ret); clk_disable_unprepare(sys_clk); - return; + return ret; } rate = clk_get_rate(fast_clk); @@ -212,7 +212,7 @@ static void __init pistachio_clksrc_of_init(struct device_node *node) raw_spin_lock_init(&pcs_gpt.lock); sched_clock_register(pistachio_read_sched_clock, 32, rate); - clocksource_register_hz(&pcs_gpt.cs, rate); + return clocksource_register_hz(&pcs_gpt.cs, rate); } -CLOCKSOURCE_OF_DECLARE(pistachio_gptimer, "img,pistachio-gptimer", +CLOCKSOURCE_OF_DECLARE_RET(pistachio_gptimer, "img,pistachio-gptimer", pistachio_clksrc_of_init); -- cgit v0.10.2 From c41c96ddac8eec158f488be2e122dcfc40fd1823 Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Mon, 6 Jun 2016 18:01:09 +0200 Subject: clocksource/drivers/atlas7: Convert init function to return error The init functions do not return any error. They behave as the following: - panic, thus leading to a kernel crash while another timer may work and make the system boot up correctly or - print an error and let the caller unaware if the state of the system Change that by converting the init functions to return an error conforming to the CLOCKSOURCE_OF_RET prototype. Proper error handling (rollback, errno value) will be changed later case by case, thus this change just return back an error or success in the init function. Signed-off-by: Daniel Lezcano diff --git a/drivers/clocksource/timer-atlas7.c b/drivers/clocksource/timer-atlas7.c index 27fa136..7b1a007 100644 --- a/drivers/clocksource/timer-atlas7.c +++ b/drivers/clocksource/timer-atlas7.c @@ -238,7 +238,7 @@ static struct notifier_block sirfsoc_cpu_nb = { .notifier_call = sirfsoc_cpu_notify, }; -static void __init sirfsoc_clockevent_init(void) +static int __init sirfsoc_clockevent_init(void) { sirfsoc_clockevent = alloc_percpu(struct clock_event_device); BUG_ON(!sirfsoc_clockevent); @@ -246,11 +246,11 @@ static void __init sirfsoc_clockevent_init(void) BUG_ON(register_cpu_notifier(&sirfsoc_cpu_nb)); /* Immediately configure the timer on the boot CPU */ - sirfsoc_local_timer_setup(this_cpu_ptr(sirfsoc_clockevent)); + return sirfsoc_local_timer_setup(this_cpu_ptr(sirfsoc_clockevent)); } /* initialize the kernel jiffy timer source */ -static void __init sirfsoc_atlas7_timer_init(struct device_node *np) +static int __init sirfsoc_atlas7_timer_init(struct device_node *np) { struct clk *clk; @@ -279,23 +279,29 @@ static void __init sirfsoc_atlas7_timer_init(struct device_node *np) BUG_ON(clocksource_register_hz(&sirfsoc_clocksource, atlas7_timer_rate)); - sirfsoc_clockevent_init(); + return sirfsoc_clockevent_init(); } -static void __init sirfsoc_of_timer_init(struct device_node *np) +static int __init sirfsoc_of_timer_init(struct device_node *np) { sirfsoc_timer_base = of_iomap(np, 0); - if (!sirfsoc_timer_base) - panic("unable to map timer cpu registers\n"); + if (!sirfsoc_timer_base) { + pr_err("unable to map timer cpu registers\n"); + return -ENXIO; + } sirfsoc_timer_irq.irq = irq_of_parse_and_map(np, 0); - if (!sirfsoc_timer_irq.irq) - panic("No irq passed for timer0 via DT\n"); + if (!sirfsoc_timer_irq.irq) { + pr_err("No irq passed for timer0 via DT\n"); + return -EINVAL; + } sirfsoc_timer1_irq.irq = irq_of_parse_and_map(np, 1); - if (!sirfsoc_timer1_irq.irq) - panic("No irq passed for timer1 via DT\n"); + if (!sirfsoc_timer1_irq.irq) { + pr_err("No irq passed for timer1 via DT\n"); + return -EINVAL; + } - sirfsoc_atlas7_timer_init(np); + return sirfsoc_atlas7_timer_init(np); } -CLOCKSOURCE_OF_DECLARE(sirfsoc_atlas7_timer, "sirf,atlas7-tick", sirfsoc_of_timer_init); +CLOCKSOURCE_OF_DECLARE_RET(sirfsoc_atlas7_timer, "sirf,atlas7-tick", sirfsoc_of_timer_init); -- cgit v0.10.2 From 504f34c9e45cf81731734ea1c80429a5116b23ca Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Mon, 6 Jun 2016 19:10:55 +0200 Subject: clocksource/drivers/atmel-pit: Convert init function to return error The init functions do not return any error. They behave as the following: - panic, thus leading to a kernel crash while another timer may work and make the system boot up correctly or - print an error and let the caller unaware if the state of the system Change that by converting the init functions to return an error conforming to the CLOCKSOURCE_OF_RET prototype. Proper error handling (rollback, errno value) will be changed later case by case, thus this change just return back an error or success in the init function. Signed-off-by: Daniel Lezcano diff --git a/drivers/clocksource/timer-atmel-pit.c b/drivers/clocksource/timer-atmel-pit.c index d911c5d..ffaca7c 100644 --- a/drivers/clocksource/timer-atmel-pit.c +++ b/drivers/clocksource/timer-atmel-pit.c @@ -177,7 +177,7 @@ static irqreturn_t at91sam926x_pit_interrupt(int irq, void *dev_id) /* * Set up both clocksource and clockevent support. */ -static void __init at91sam926x_pit_common_init(struct pit_data *data) +static int __init at91sam926x_pit_common_init(struct pit_data *data) { unsigned long pit_rate; unsigned bits; @@ -204,14 +204,21 @@ static void __init at91sam926x_pit_common_init(struct pit_data *data) data->clksrc.rating = 175; data->clksrc.read = read_pit_clk; data->clksrc.flags = CLOCK_SOURCE_IS_CONTINUOUS; - clocksource_register_hz(&data->clksrc, pit_rate); + + ret = clocksource_register_hz(&data->clksrc, pit_rate); + if (ret) { + pr_err("Failed to register clocksource"); + return ret; + } /* Set up irq handler */ ret = request_irq(data->irq, at91sam926x_pit_interrupt, IRQF_SHARED | IRQF_TIMER | IRQF_IRQPOLL, "at91_tick", data); - if (ret) - panic(pr_fmt("Unable to setup IRQ\n")); + if (ret) { + pr_err("Unable to setup IRQ\n"); + return ret; + } /* Set up and register clockevents */ data->clkevt.name = "pit"; @@ -226,34 +233,42 @@ static void __init at91sam926x_pit_common_init(struct pit_data *data) data->clkevt.resume = at91sam926x_pit_resume; data->clkevt.suspend = at91sam926x_pit_suspend; clockevents_register_device(&data->clkevt); + + return 0; } -static void __init at91sam926x_pit_dt_init(struct device_node *node) +static int __init at91sam926x_pit_dt_init(struct device_node *node) { struct pit_data *data; data = kzalloc(sizeof(*data), GFP_KERNEL); if (!data) - panic(pr_fmt("Unable to allocate memory\n")); + return -ENOMEM; data->base = of_iomap(node, 0); - if (!data->base) - panic(pr_fmt("Could not map PIT address\n")); + if (!data->base) { + pr_err("Could not map PIT address\n"); + return -ENXIO; + } data->mck = of_clk_get(node, 0); if (IS_ERR(data->mck)) /* Fallback on clkdev for !CCF-based boards */ data->mck = clk_get(NULL, "mck"); - if (IS_ERR(data->mck)) - panic(pr_fmt("Unable to get mck clk\n")); + if (IS_ERR(data->mck)) { + pr_err("Unable to get mck clk\n"); + return PTR_ERR(data->mck); + } /* Get the interrupts property */ data->irq = irq_of_parse_and_map(node, 0); - if (!data->irq) - panic(pr_fmt("Unable to get IRQ from DT\n")); + if (!data->irq) { + pr_err("Unable to get IRQ from DT\n"); + return -EINVAL; + } - at91sam926x_pit_common_init(data); + return at91sam926x_pit_common_init(data); } -CLOCKSOURCE_OF_DECLARE(at91sam926x_pit, "atmel,at91sam9260-pit", +CLOCKSOURCE_OF_DECLARE_RET(at91sam926x_pit, "atmel,at91sam9260-pit", at91sam926x_pit_dt_init); -- cgit v0.10.2 From adbaf5254152f322b873d0a9cd0f150dd30c64aa Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Mon, 6 Jun 2016 19:11:12 +0200 Subject: clocksource/drivers/atmel-st: Convert init function to return error The init functions do not return any error. They behave as the following: - panic, thus leading to a kernel crash while another timer may work and make the system boot up correctly or - print an error and let the caller unaware if the state of the system Change that by converting the init functions to return an error conforming to the CLOCKSOURCE_OF_RET prototype. Proper error handling (rollback, errno value) will be changed later case by case, thus this change just return back an error or success in the init function. Signed-off-by: Daniel Lezcano diff --git a/drivers/clocksource/timer-atmel-st.c b/drivers/clocksource/timer-atmel-st.c index 29d21d6..e9331d3 100644 --- a/drivers/clocksource/timer-atmel-st.c +++ b/drivers/clocksource/timer-atmel-st.c @@ -194,15 +194,17 @@ static struct clock_event_device clkevt = { /* * ST (system timer) module supports both clockevents and clocksource. */ -static void __init atmel_st_timer_init(struct device_node *node) +static int __init atmel_st_timer_init(struct device_node *node) { struct clk *sclk; unsigned int sclk_rate, val; int irq, ret; regmap_st = syscon_node_to_regmap(node); - if (IS_ERR(regmap_st)) - panic(pr_fmt("Unable to get regmap\n")); + if (IS_ERR(regmap_st)) { + pr_err("Unable to get regmap\n"); + return PTR_ERR(regmap_st); + } /* Disable all timer interrupts, and clear any pending ones */ regmap_write(regmap_st, AT91_ST_IDR, @@ -211,27 +213,37 @@ static void __init atmel_st_timer_init(struct device_node *node) /* Get the interrupts property */ irq = irq_of_parse_and_map(node, 0); - if (!irq) - panic(pr_fmt("Unable to get IRQ from DT\n")); + if (!irq) { + pr_err("Unable to get IRQ from DT\n"); + return -EINVAL; + } /* Make IRQs happen for the system timer */ ret = request_irq(irq, at91rm9200_timer_interrupt, IRQF_SHARED | IRQF_TIMER | IRQF_IRQPOLL, "at91_tick", regmap_st); - if (ret) - panic(pr_fmt("Unable to setup IRQ\n")); + if (ret) { + pr_err("Unable to setup IRQ\n"); + return ret; + } sclk = of_clk_get(node, 0); - if (IS_ERR(sclk)) - panic(pr_fmt("Unable to get slow clock\n")); + if (IS_ERR(sclk)) { + pr_err("Unable to get slow clock\n"); + return PTR_ERR(sclk); + } - clk_prepare_enable(sclk); - if (ret) - panic(pr_fmt("Could not enable slow clock\n")); + ret = clk_prepare_enable(sclk); + if (ret) { + pr_err("Could not enable slow clock\n"); + return ret; + } sclk_rate = clk_get_rate(sclk); - if (!sclk_rate) - panic(pr_fmt("Invalid slow clock rate\n")); + if (!sclk_rate) { + pr_err("Invalid slow clock rate\n"); + return -EINVAL; + } timer_latch = (sclk_rate + HZ / 2) / HZ; /* The 32KiHz "Slow Clock" (tick every 30517.58 nanoseconds) is used @@ -246,7 +258,7 @@ static void __init atmel_st_timer_init(struct device_node *node) 2, AT91_ST_ALMV); /* register clocksource */ - clocksource_register_hz(&clk32k, sclk_rate); + return clocksource_register_hz(&clk32k, sclk_rate); } -CLOCKSOURCE_OF_DECLARE(atmel_st_timer, "atmel,at91rm9200-st", +CLOCKSOURCE_OF_DECLARE_RET(atmel_st_timer, "atmel,at91rm9200-st", atmel_st_timer_init); -- cgit v0.10.2 From de23484dd50829fb2f2fffbe2a97cfe5d50aa8b7 Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Mon, 6 Jun 2016 23:02:59 +0200 Subject: clocksource/drivers/prima2: Convert init function to return error The init functions do not return any error. They behave as the following: - panic, thus leading to a kernel crash while another timer may work and make the system boot up correctly or - print an error and let the caller unaware if the state of the system Change that by converting the init functions to return an error conforming to the CLOCKSOURCE_OF_RET prototype. Proper error handling (rollback, errno value) will be changed later case by case, thus this change just return back an error or success in the init function. Signed-off-by: Daniel Lezcano diff --git a/drivers/clocksource/timer-prima2.c b/drivers/clocksource/timer-prima2.c index 2854c66..7b1084d 100644 --- a/drivers/clocksource/timer-prima2.c +++ b/drivers/clocksource/timer-prima2.c @@ -189,24 +189,36 @@ static void __init sirfsoc_clockevent_init(void) } /* initialize the kernel jiffy timer source */ -static void __init sirfsoc_prima2_timer_init(struct device_node *np) +static int __init sirfsoc_prima2_timer_init(struct device_node *np) { unsigned long rate; struct clk *clk; + int ret; clk = of_clk_get(np, 0); - BUG_ON(IS_ERR(clk)); + if (IS_ERR(clk)) { + pr_err("Failed to get clock"); + return PTR_ERR(clk); + } - BUG_ON(clk_prepare_enable(clk)); + ret = clk_prepare_enable(clk); + if (ret) { + pr_err("Failed to enable clock"); + return ret; + } rate = clk_get_rate(clk); - BUG_ON(rate < PRIMA2_CLOCK_FREQ); - BUG_ON(rate % PRIMA2_CLOCK_FREQ); + if (rate < PRIMA2_CLOCK_FREQ || rate % PRIMA2_CLOCK_FREQ) { + pr_err("Invalid clock rate"); + return -EINVAL; + } sirfsoc_timer_base = of_iomap(np, 0); - if (!sirfsoc_timer_base) - panic("unable to map timer cpu registers\n"); + if (!sirfsoc_timer_base) { + pr_err("unable to map timer cpu registers\n"); + return -ENXIO; + } sirfsoc_timer_irq.irq = irq_of_parse_and_map(np, 0); @@ -216,14 +228,23 @@ static void __init sirfsoc_prima2_timer_init(struct device_node *np) writel_relaxed(0, sirfsoc_timer_base + SIRFSOC_TIMER_COUNTER_HI); writel_relaxed(BIT(0), sirfsoc_timer_base + SIRFSOC_TIMER_STATUS); - BUG_ON(clocksource_register_hz(&sirfsoc_clocksource, - PRIMA2_CLOCK_FREQ)); + ret = clocksource_register_hz(&sirfsoc_clocksource, PRIMA2_CLOCK_FREQ); + if (ret) { + pr_err("Failed to register clocksource"); + return ret; + } sched_clock_register(sirfsoc_read_sched_clock, 64, PRIMA2_CLOCK_FREQ); - BUG_ON(setup_irq(sirfsoc_timer_irq.irq, &sirfsoc_timer_irq)); + ret = setup_irq(sirfsoc_timer_irq.irq, &sirfsoc_timer_irq); + if (ret) { + pr_err("Failed to setup irq"); + return ret; + } sirfsoc_clockevent_init(); + + return 0; } -CLOCKSOURCE_OF_DECLARE(sirfsoc_prima2_timer, +CLOCKSOURCE_OF_DECLARE_RET(sirfsoc_prima2_timer, "sirf,prima2-tick", sirfsoc_prima2_timer_init); -- cgit v0.10.2 From c11cd416aea9e4f71b58def49e860ba8609a1892 Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Mon, 6 Jun 2016 23:27:05 +0200 Subject: clocksource/drivers/imx-gpt: Convert init function to return error The init functions do not return any error. They behave as the following: - panic, thus leading to a kernel crash while another timer may work and make the system boot up correctly or - print an error and let the caller unaware if the state of the system Change that by converting the init functions to return an error conforming to the CLOCKSOURCE_OF_RET prototype. Proper error handling (rollback, errno value) will be changed later case by case, thus this change just return back an error or success in the init function. Signed-off-by: Daniel Lezcano diff --git a/drivers/clocksource/timer-imx-gpt.c b/drivers/clocksource/timer-imx-gpt.c index 99ec967..d5640a74 100644 --- a/drivers/clocksource/timer-imx-gpt.c +++ b/drivers/clocksource/timer-imx-gpt.c @@ -407,8 +407,10 @@ static const struct imx_gpt_data imx6dl_gpt_data = { .set_next_event = v2_set_next_event, }; -static void __init _mxc_timer_init(struct imx_timer *imxtm) +static int __init _mxc_timer_init(struct imx_timer *imxtm) { + int ret; + switch (imxtm->type) { case GPT_TYPE_IMX1: imxtm->gpt = &imx1_gpt_data; @@ -423,12 +425,12 @@ static void __init _mxc_timer_init(struct imx_timer *imxtm) imxtm->gpt = &imx6dl_gpt_data; break; default: - BUG(); + return -EINVAL; } if (IS_ERR(imxtm->clk_per)) { pr_err("i.MX timer: unable to get clk\n"); - return; + return PTR_ERR(imxtm->clk_per); } if (!IS_ERR(imxtm->clk_ipg)) @@ -446,8 +448,11 @@ static void __init _mxc_timer_init(struct imx_timer *imxtm) imxtm->gpt->gpt_setup_tctl(imxtm); /* init and register the timer to the framework */ - mxc_clocksource_init(imxtm); - mxc_clockevent_init(imxtm); + ret = mxc_clocksource_init(imxtm); + if (ret) + return ret; + + return mxc_clockevent_init(imxtm); } void __init mxc_timer_init(unsigned long pbase, int irq, enum imx_gpt_type type) @@ -469,21 +474,27 @@ void __init mxc_timer_init(unsigned long pbase, int irq, enum imx_gpt_type type) _mxc_timer_init(imxtm); } -static void __init mxc_timer_init_dt(struct device_node *np, enum imx_gpt_type type) +static int __init mxc_timer_init_dt(struct device_node *np, enum imx_gpt_type type) { struct imx_timer *imxtm; static int initialized; + int ret; /* Support one instance only */ if (initialized) - return; + return 0; imxtm = kzalloc(sizeof(*imxtm), GFP_KERNEL); - BUG_ON(!imxtm); + if (!imxtm) + return -ENOMEM; imxtm->base = of_iomap(np, 0); - WARN_ON(!imxtm->base); + if (!imxtm->base) + return -ENXIO; + imxtm->irq = irq_of_parse_and_map(np, 0); + if (imxtm->irq <= 0) + return -EINVAL; imxtm->clk_ipg = of_clk_get_by_name(np, "ipg"); @@ -494,22 +505,26 @@ static void __init mxc_timer_init_dt(struct device_node *np, enum imx_gpt_type imxtm->type = type; - _mxc_timer_init(imxtm); + ret = _mxc_timer_init(imxtm); + if (ret) + return ret; initialized = 1; + + return 0; } -static void __init imx1_timer_init_dt(struct device_node *np) +static int __init imx1_timer_init_dt(struct device_node *np) { - mxc_timer_init_dt(np, GPT_TYPE_IMX1); + return mxc_timer_init_dt(np, GPT_TYPE_IMX1); } -static void __init imx21_timer_init_dt(struct device_node *np) +static int __init imx21_timer_init_dt(struct device_node *np) { - mxc_timer_init_dt(np, GPT_TYPE_IMX21); + return mxc_timer_init_dt(np, GPT_TYPE_IMX21); } -static void __init imx31_timer_init_dt(struct device_node *np) +static int __init imx31_timer_init_dt(struct device_node *np) { enum imx_gpt_type type = GPT_TYPE_IMX31; @@ -522,23 +537,23 @@ static void __init imx31_timer_init_dt(struct device_node *np) if (of_machine_is_compatible("fsl,imx6dl")) type = GPT_TYPE_IMX6DL; - mxc_timer_init_dt(np, type); + return mxc_timer_init_dt(np, type); } -static void __init imx6dl_timer_init_dt(struct device_node *np) +static int __init imx6dl_timer_init_dt(struct device_node *np) { - mxc_timer_init_dt(np, GPT_TYPE_IMX6DL); + return mxc_timer_init_dt(np, GPT_TYPE_IMX6DL); } -CLOCKSOURCE_OF_DECLARE(imx1_timer, "fsl,imx1-gpt", imx1_timer_init_dt); -CLOCKSOURCE_OF_DECLARE(imx21_timer, "fsl,imx21-gpt", imx21_timer_init_dt); -CLOCKSOURCE_OF_DECLARE(imx27_timer, "fsl,imx27-gpt", imx21_timer_init_dt); -CLOCKSOURCE_OF_DECLARE(imx31_timer, "fsl,imx31-gpt", imx31_timer_init_dt); -CLOCKSOURCE_OF_DECLARE(imx25_timer, "fsl,imx25-gpt", imx31_timer_init_dt); -CLOCKSOURCE_OF_DECLARE(imx50_timer, "fsl,imx50-gpt", imx31_timer_init_dt); -CLOCKSOURCE_OF_DECLARE(imx51_timer, "fsl,imx51-gpt", imx31_timer_init_dt); -CLOCKSOURCE_OF_DECLARE(imx53_timer, "fsl,imx53-gpt", imx31_timer_init_dt); -CLOCKSOURCE_OF_DECLARE(imx6q_timer, "fsl,imx6q-gpt", imx31_timer_init_dt); -CLOCKSOURCE_OF_DECLARE(imx6dl_timer, "fsl,imx6dl-gpt", imx6dl_timer_init_dt); -CLOCKSOURCE_OF_DECLARE(imx6sl_timer, "fsl,imx6sl-gpt", imx6dl_timer_init_dt); -CLOCKSOURCE_OF_DECLARE(imx6sx_timer, "fsl,imx6sx-gpt", imx6dl_timer_init_dt); +CLOCKSOURCE_OF_DECLARE_RET(imx1_timer, "fsl,imx1-gpt", imx1_timer_init_dt); +CLOCKSOURCE_OF_DECLARE_RET(imx21_timer, "fsl,imx21-gpt", imx21_timer_init_dt); +CLOCKSOURCE_OF_DECLARE_RET(imx27_timer, "fsl,imx27-gpt", imx21_timer_init_dt); +CLOCKSOURCE_OF_DECLARE_RET(imx31_timer, "fsl,imx31-gpt", imx31_timer_init_dt); +CLOCKSOURCE_OF_DECLARE_RET(imx25_timer, "fsl,imx25-gpt", imx31_timer_init_dt); +CLOCKSOURCE_OF_DECLARE_RET(imx50_timer, "fsl,imx50-gpt", imx31_timer_init_dt); +CLOCKSOURCE_OF_DECLARE_RET(imx51_timer, "fsl,imx51-gpt", imx31_timer_init_dt); +CLOCKSOURCE_OF_DECLARE_RET(imx53_timer, "fsl,imx53-gpt", imx31_timer_init_dt); +CLOCKSOURCE_OF_DECLARE_RET(imx6q_timer, "fsl,imx6q-gpt", imx31_timer_init_dt); +CLOCKSOURCE_OF_DECLARE_RET(imx6dl_timer, "fsl,imx6dl-gpt", imx6dl_timer_init_dt); +CLOCKSOURCE_OF_DECLARE_RET(imx6sl_timer, "fsl,imx6sl-gpt", imx6dl_timer_init_dt); +CLOCKSOURCE_OF_DECLARE_RET(imx6sx_timer, "fsl,imx6sx-gpt", imx6dl_timer_init_dt); -- cgit v0.10.2 From 76804d052316d3562c58934200c932243f312c07 Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Mon, 6 Jun 2016 23:27:24 +0200 Subject: clocksource/drivers/integrator-ap: Convert init function to return error The init functions do not return any error. They behave as the following: - panic, thus leading to a kernel crash while another timer may work and make the system boot up correctly or - print an error and let the caller unaware if the state of the system Change that by converting the init functions to return an error conforming to the CLOCKSOURCE_OF_RET prototype. Proper error handling (rollback, errno value) will be changed later case by case, thus this change just return back an error or success in the init function. Signed-off-by: Daniel Lezcano diff --git a/drivers/clocksource/timer-integrator-ap.c b/drivers/clocksource/timer-integrator-ap.c index 3f59ac2..675face 100644 --- a/drivers/clocksource/timer-integrator-ap.c +++ b/drivers/clocksource/timer-integrator-ap.c @@ -36,11 +36,12 @@ static u64 notrace integrator_read_sched_clock(void) return -readl(sched_clk_base + TIMER_VALUE); } -static void integrator_clocksource_init(unsigned long inrate, - void __iomem *base) +static int integrator_clocksource_init(unsigned long inrate, + void __iomem *base) { u32 ctrl = TIMER_CTRL_ENABLE | TIMER_CTRL_PERIODIC; unsigned long rate = inrate; + int ret; if (rate >= 1500000) { rate /= 16; @@ -50,11 +51,15 @@ static void integrator_clocksource_init(unsigned long inrate, writel(0xffff, base + TIMER_LOAD); writel(ctrl, base + TIMER_CTRL); - clocksource_mmio_init(base + TIMER_VALUE, "timer2", - rate, 200, 16, clocksource_mmio_readl_down); + ret = clocksource_mmio_init(base + TIMER_VALUE, "timer2", + rate, 200, 16, clocksource_mmio_readl_down); + if (ret) + return ret; sched_clk_base = base; sched_clock_register(integrator_read_sched_clock, 16, rate); + + return 0; } static unsigned long timer_reload; @@ -138,11 +143,12 @@ static struct irqaction integrator_timer_irq = { .dev_id = &integrator_clockevent, }; -static void integrator_clockevent_init(unsigned long inrate, - void __iomem *base, int irq) +static int integrator_clockevent_init(unsigned long inrate, + void __iomem *base, int irq) { unsigned long rate = inrate; unsigned int ctrl = 0; + int ret; clkevt_base = base; /* Calculate and program a divisor */ @@ -156,14 +162,18 @@ static void integrator_clockevent_init(unsigned long inrate, timer_reload = rate / HZ; writel(ctrl, clkevt_base + TIMER_CTRL); - setup_irq(irq, &integrator_timer_irq); + ret = setup_irq(irq, &integrator_timer_irq); + if (ret) + return ret; + clockevents_config_and_register(&integrator_clockevent, rate, 1, 0xffffU); + return 0; } -static void __init integrator_ap_timer_init_of(struct device_node *node) +static int __init integrator_ap_timer_init_of(struct device_node *node) { const char *path; void __iomem *base; @@ -176,12 +186,12 @@ static void __init integrator_ap_timer_init_of(struct device_node *node) base = of_io_request_and_map(node, 0, "integrator-timer"); if (IS_ERR(base)) - return; + return PTR_ERR(base); clk = of_clk_get(node, 0); if (IS_ERR(clk)) { pr_err("No clock for %s\n", node->name); - return; + return PTR_ERR(clk); } clk_prepare_enable(clk); rate = clk_get_rate(clk); @@ -189,31 +199,38 @@ static void __init integrator_ap_timer_init_of(struct device_node *node) err = of_property_read_string(of_aliases, "arm,timer-primary", &path); - if (WARN_ON(err)) - return; + if (err) { + pr_warn("Failed to read property"); + return err; + } + pri_node = of_find_node_by_path(path); + err = of_property_read_string(of_aliases, "arm,timer-secondary", &path); - if (WARN_ON(err)) - return; + if (err) { + pr_warn("Failed to read property"); + return err; + } + + sec_node = of_find_node_by_path(path); - if (node == pri_node) { + if (node == pri_node) /* The primary timer lacks IRQ, use as clocksource */ - integrator_clocksource_init(rate, base); - return; - } + return integrator_clocksource_init(rate, base); if (node == sec_node) { /* The secondary timer will drive the clock event */ irq = irq_of_parse_and_map(node, 0); - integrator_clockevent_init(rate, base, irq); - return; + return integrator_clockevent_init(rate, base, irq); } pr_info("Timer @%p unused\n", base); clk_disable_unprepare(clk); + + return 0; } -CLOCKSOURCE_OF_DECLARE(integrator_ap_timer, "arm,integrator-timer", +CLOCKSOURCE_OF_DECLARE_RET(integrator_ap_timer, "arm,integrator-timer", integrator_ap_timer_init_of); -- cgit v0.10.2 From 53186505802c8845d5af4ed40ddb84e221acb92f Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Mon, 6 Jun 2016 23:27:44 +0200 Subject: clocksource/drivers/keystone: Convert init function to return error The init functions do not return any error. They behave as the following: - panic, thus leading to a kernel crash while another timer may work and make the system boot up correctly or - print an error and let the caller unaware if the state of the system Change that by converting the init functions to return an error conforming to the CLOCKSOURCE_OF_RET prototype. Proper error handling (rollback, errno value) will be changed later case by case, thus this change just return back an error or success in the init function. Signed-off-by: Daniel Lezcano Acked-by: Santosh Shilimkar diff --git a/drivers/clocksource/timer-keystone.c b/drivers/clocksource/timer-keystone.c index 1cea08c..4199823 100644 --- a/drivers/clocksource/timer-keystone.c +++ b/drivers/clocksource/timer-keystone.c @@ -144,7 +144,7 @@ static int keystone_set_periodic(struct clock_event_device *evt) return 0; } -static void __init keystone_timer_init(struct device_node *np) +static int __init keystone_timer_init(struct device_node *np) { struct clock_event_device *event_dev = &timer.event_dev; unsigned long rate; @@ -154,20 +154,20 @@ static void __init keystone_timer_init(struct device_node *np) irq = irq_of_parse_and_map(np, 0); if (!irq) { pr_err("%s: failed to map interrupts\n", __func__); - return; + return -EINVAL; } timer.base = of_iomap(np, 0); if (!timer.base) { pr_err("%s: failed to map registers\n", __func__); - return; + return -ENXIO; } clk = of_clk_get(np, 0); if (IS_ERR(clk)) { pr_err("%s: failed to get clock\n", __func__); iounmap(timer.base); - return; + return PTR_ERR(clk); } error = clk_prepare_enable(clk); @@ -219,11 +219,12 @@ static void __init keystone_timer_init(struct device_node *np) clockevents_config_and_register(event_dev, rate, 1, ULONG_MAX); pr_info("keystone timer clock @%lu Hz\n", rate); - return; + return 0; err: clk_put(clk); iounmap(timer.base); + return error; } -CLOCKSOURCE_OF_DECLARE(keystone_timer, "ti,keystone-timer", - keystone_timer_init); +CLOCKSOURCE_OF_DECLARE_RET(keystone_timer, "ti,keystone-timer", + keystone_timer_init); -- cgit v0.10.2 From 2ef2538bc613af45baf9f2a032c9a8259c4c6672 Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Mon, 6 Jun 2016 23:28:01 +0200 Subject: clocksource/drivers/sp804: Convert init function to return error The init functions do not return any error. They behave as the following: - panic, thus leading to a kernel crash while another timer may work and make the system boot up correctly or - print an error and let the caller unaware if the state of the system Change that by converting the init functions to return an error conforming to the CLOCKSOURCE_OF_RET prototype. Proper error handling (rollback, errno value) will be changed later case by case, thus this change just return back an error or success in the init function. Signed-off-by: Daniel Lezcano diff --git a/drivers/clocksource/timer-sp804.c b/drivers/clocksource/timer-sp804.c index 5f45b9a..3dc47ef 100644 --- a/drivers/clocksource/timer-sp804.c +++ b/drivers/clocksource/timer-sp804.c @@ -77,7 +77,7 @@ void __init sp804_timer_disable(void __iomem *base) writel(0, base + TIMER_CTRL); } -void __init __sp804_clocksource_and_sched_clock_init(void __iomem *base, +int __init __sp804_clocksource_and_sched_clock_init(void __iomem *base, const char *name, struct clk *clk, int use_sched_clock) @@ -89,14 +89,13 @@ void __init __sp804_clocksource_and_sched_clock_init(void __iomem *base, if (IS_ERR(clk)) { pr_err("sp804: clock not found: %d\n", (int)PTR_ERR(clk)); - return; + return PTR_ERR(clk); } } rate = sp804_get_clock_rate(clk); - if (rate < 0) - return; + return -EINVAL; /* setup timer 0 as free-running clocksource */ writel(0, base + TIMER_CTRL); @@ -112,6 +111,8 @@ void __init __sp804_clocksource_and_sched_clock_init(void __iomem *base, sched_clock_base = base; sched_clock_register(sp804_read, 32, rate); } + + return 0; } @@ -186,7 +187,7 @@ static struct irqaction sp804_timer_irq = { .dev_id = &sp804_clockevent, }; -void __init __sp804_clockevents_init(void __iomem *base, unsigned int irq, struct clk *clk, const char *name) +int __init __sp804_clockevents_init(void __iomem *base, unsigned int irq, struct clk *clk, const char *name) { struct clock_event_device *evt = &sp804_clockevent; long rate; @@ -196,12 +197,12 @@ void __init __sp804_clockevents_init(void __iomem *base, unsigned int irq, struc if (IS_ERR(clk)) { pr_err("sp804: %s clock not found: %d\n", name, (int)PTR_ERR(clk)); - return; + return PTR_ERR(clk); } rate = sp804_get_clock_rate(clk); if (rate < 0) - return; + return -EINVAL; clkevt_base = base; clkevt_reload = DIV_ROUND_CLOSEST(rate, HZ); @@ -213,27 +214,31 @@ void __init __sp804_clockevents_init(void __iomem *base, unsigned int irq, struc setup_irq(irq, &sp804_timer_irq); clockevents_config_and_register(evt, rate, 0xf, 0xffffffff); + + return 0; } -static void __init sp804_of_init(struct device_node *np) +static int __init sp804_of_init(struct device_node *np) { static bool initialized = false; void __iomem *base; - int irq; + int irq, ret = -EINVAL; u32 irq_num = 0; struct clk *clk1, *clk2; const char *name = of_get_property(np, "compatible", NULL); base = of_iomap(np, 0); - if (WARN_ON(!base)) - return; + if (!base) + return -ENXIO; /* Ensure timers are disabled */ writel(0, base + TIMER_CTRL); writel(0, base + TIMER_2_BASE + TIMER_CTRL); - if (initialized || !of_device_is_available(np)) + if (initialized || !of_device_is_available(np)) { + ret = -EINVAL; goto err; + } clk1 = of_clk_get(np, 0); if (IS_ERR(clk1)) @@ -256,35 +261,53 @@ static void __init sp804_of_init(struct device_node *np) of_property_read_u32(np, "arm,sp804-has-irq", &irq_num); if (irq_num == 2) { - __sp804_clockevents_init(base + TIMER_2_BASE, irq, clk2, name); - __sp804_clocksource_and_sched_clock_init(base, name, clk1, 1); + + ret = __sp804_clockevents_init(base + TIMER_2_BASE, irq, clk2, name); + if (ret) + goto err; + + ret = __sp804_clocksource_and_sched_clock_init(base, name, clk1, 1); + if (ret) + goto err; } else { - __sp804_clockevents_init(base, irq, clk1 , name); - __sp804_clocksource_and_sched_clock_init(base + TIMER_2_BASE, - name, clk2, 1); + + ret = __sp804_clockevents_init(base, irq, clk1 , name); + if (ret) + goto err; + + ret =__sp804_clocksource_and_sched_clock_init(base + TIMER_2_BASE, + name, clk2, 1); + if (ret) + goto err; } initialized = true; - return; + return 0; err: iounmap(base); + return ret; } -CLOCKSOURCE_OF_DECLARE(sp804, "arm,sp804", sp804_of_init); +CLOCKSOURCE_OF_DECLARE_RET(sp804, "arm,sp804", sp804_of_init); -static void __init integrator_cp_of_init(struct device_node *np) +static int __init integrator_cp_of_init(struct device_node *np) { static int init_count = 0; void __iomem *base; - int irq; + int irq, ret = -EINVAL; const char *name = of_get_property(np, "compatible", NULL); struct clk *clk; base = of_iomap(np, 0); - if (WARN_ON(!base)) - return; + if (!base) { + pr_err("Failed to iomap"); + return -ENXIO; + } + clk = of_clk_get(np, 0); - if (WARN_ON(IS_ERR(clk))) - return; + if (IS_ERR(clk)) { + pr_err("Failed to get clock"); + return PTR_ERR(clk); + } /* Ensure timer is disabled */ writel(0, base + TIMER_CTRL); @@ -292,19 +315,24 @@ static void __init integrator_cp_of_init(struct device_node *np) if (init_count == 2 || !of_device_is_available(np)) goto err; - if (!init_count) - __sp804_clocksource_and_sched_clock_init(base, name, clk, 0); - else { + if (!init_count) { + ret = __sp804_clocksource_and_sched_clock_init(base, name, clk, 0); + if (ret) + goto err; + } else { irq = irq_of_parse_and_map(np, 0); if (irq <= 0) goto err; - __sp804_clockevents_init(base, irq, clk, name); + ret = __sp804_clockevents_init(base, irq, clk, name); + if (ret) + goto err; } init_count++; - return; + return 0; err: iounmap(base); + return ret; } -CLOCKSOURCE_OF_DECLARE(intcp, "arm,integrator-cp-timer", integrator_cp_of_init); +CLOCKSOURCE_OF_DECLARE_RET(intcp, "arm,integrator-cp-timer", integrator_cp_of_init); diff --git a/include/clocksource/timer-sp804.h b/include/clocksource/timer-sp804.h index 1f8a1ca..7654d71 100644 --- a/include/clocksource/timer-sp804.h +++ b/include/clocksource/timer-sp804.h @@ -3,10 +3,10 @@ struct clk; -void __sp804_clocksource_and_sched_clock_init(void __iomem *, - const char *, struct clk *, int); -void __sp804_clockevents_init(void __iomem *, unsigned int, - struct clk *, const char *); +int __sp804_clocksource_and_sched_clock_init(void __iomem *, + const char *, struct clk *, int); +int __sp804_clockevents_init(void __iomem *, unsigned int, + struct clk *, const char *); void sp804_timer_disable(void __iomem *); static inline void sp804_clocksource_init(void __iomem *base, const char *name) -- cgit v0.10.2 From 38d94c5ae2dc60d6b54127695df9447e86a7d402 Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Mon, 6 Jun 2016 23:28:17 +0200 Subject: clocksource/drivers/stm32: Convert init function to return error The init functions do not return any error. They behave as the following: - panic, thus leading to a kernel crash while another timer may work and make the system boot up correctly or - print an error and let the caller unaware if the state of the system Change that by converting the init functions to return an error conforming to the CLOCKSOURCE_OF_RET prototype. Proper error handling (rollback, errno value) will be changed later case by case, thus this change just return back an error or success in the init function. Signed-off-by: Daniel Lezcano Acked-by: Maxime Coquelin diff --git a/drivers/clocksource/timer-stm32.c b/drivers/clocksource/timer-stm32.c index f3dcb76..d5bf352 100644 --- a/drivers/clocksource/timer-stm32.c +++ b/drivers/clocksource/timer-stm32.c @@ -98,7 +98,7 @@ static struct stm32_clock_event_ddata clock_event_ddata = { }, }; -static void __init stm32_clockevent_init(struct device_node *np) +static int __init stm32_clockevent_init(struct device_node *np) { struct stm32_clock_event_ddata *data = &clock_event_ddata; struct clk *clk; @@ -130,12 +130,14 @@ static void __init stm32_clockevent_init(struct device_node *np) data->base = of_iomap(np, 0); if (!data->base) { + ret = -ENXIO; pr_err("failed to map registers for clockevent\n"); goto err_iomap; } irq = irq_of_parse_and_map(np, 0); if (!irq) { + ret = -EINVAL; pr_err("%s: failed to get irq.\n", np->full_name); goto err_get_irq; } @@ -173,7 +175,7 @@ static void __init stm32_clockevent_init(struct device_node *np) pr_info("%s: STM32 clockevent driver initialized (%d bits)\n", np->full_name, bits); - return; + return ret; err_get_irq: iounmap(data->base); @@ -182,7 +184,7 @@ err_iomap: err_clk_enable: clk_put(clk); err_clk_get: - return; + return ret; } -CLOCKSOURCE_OF_DECLARE(stm32, "st,stm32-timer", stm32_clockevent_init); +CLOCKSOURCE_OF_DECLARE_RET(stm32, "st,stm32-timer", stm32_clockevent_init); -- cgit v0.10.2 From e4d9f2ee4ef53d4637308921602e5406d5540e0d Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Mon, 6 Jun 2016 23:28:36 +0200 Subject: clocksource/drivers/sun5i: Convert init function to return error The init functions do not return any error. They behave as the following: - panic, thus leading to a kernel crash while another timer may work and make the system boot up correctly or - print an error and let the caller unaware if the state of the system Change that by converting the init functions to return an error conforming to the CLOCKSOURCE_OF_RET prototype. Proper error handling (rollback, errno value) will be changed later case by case, thus this change just return back an error or success in the init function. Signed-off-by: Daniel Lezcano diff --git a/drivers/clocksource/timer-sun5i.c b/drivers/clocksource/timer-sun5i.c index 24c83f9..f0a3ffb 100644 --- a/drivers/clocksource/timer-sun5i.c +++ b/drivers/clocksource/timer-sun5i.c @@ -311,33 +311,42 @@ err_free: return ret; } -static void __init sun5i_timer_init(struct device_node *node) +static int __init sun5i_timer_init(struct device_node *node) { struct reset_control *rstc; void __iomem *timer_base; struct clk *clk; - int irq; + int irq, ret; timer_base = of_io_request_and_map(node, 0, of_node_full_name(node)); - if (IS_ERR(timer_base)) - panic("Can't map registers"); + if (IS_ERR(timer_base)) { + pr_err("Can't map registers"); + return PTR_ERR(timer_base);; + } irq = irq_of_parse_and_map(node, 0); - if (irq <= 0) - panic("Can't parse IRQ"); + if (irq <= 0) { + pr_err("Can't parse IRQ"); + return -EINVAL; + } clk = of_clk_get(node, 0); - if (IS_ERR(clk)) - panic("Can't get timer clock"); + if (IS_ERR(clk)) { + pr_err("Can't get timer clock"); + return PTR_ERR(clk); + } rstc = of_reset_control_get(node, NULL); if (!IS_ERR(rstc)) reset_control_deassert(rstc); - sun5i_setup_clocksource(node, timer_base, clk, irq); - sun5i_setup_clockevent(node, timer_base, clk, irq); + ret = sun5i_setup_clocksource(node, timer_base, clk, irq); + if (ret) + return ret; + + return sun5i_setup_clockevent(node, timer_base, clk, irq); } -CLOCKSOURCE_OF_DECLARE(sun5i_a13, "allwinner,sun5i-a13-hstimer", - sun5i_timer_init); -CLOCKSOURCE_OF_DECLARE(sun7i_a20, "allwinner,sun7i-a20-hstimer", - sun5i_timer_init); +CLOCKSOURCE_OF_DECLARE_RET(sun5i_a13, "allwinner,sun5i-a13-hstimer", + sun5i_timer_init); +CLOCKSOURCE_OF_DECLARE_RET(sun7i_a20, "allwinner,sun7i-a20-hstimer", + sun5i_timer_init); -- cgit v0.10.2 From 0a8e7d49d59ce3910dd341d0d3df419f8defc9fe Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Mon, 6 Jun 2016 23:29:03 +0200 Subject: clocksource/drivers/ti-32k: Convert init function to return error The init functions do not return any error. They behave as the following: - panic, thus leading to a kernel crash while another timer may work and make the system boot up correctly or - print an error and let the caller unaware if the state of the system Change that by converting the init functions to return an error conforming to the CLOCKSOURCE_OF_RET prototype. Proper error handling (rollback, errno value) will be changed later case by case, thus this change just return back an error or success in the init function. Signed-off-by: Daniel Lezcano diff --git a/drivers/clocksource/timer-ti-32k.c b/drivers/clocksource/timer-ti-32k.c index 8518d9d..e4ad3c6e 100644 --- a/drivers/clocksource/timer-ti-32k.c +++ b/drivers/clocksource/timer-ti-32k.c @@ -88,14 +88,14 @@ static u64 notrace omap_32k_read_sched_clock(void) return ti_32k_read_cycles(&ti_32k_timer.cs); } -static void __init ti_32k_timer_init(struct device_node *np) +static int __init ti_32k_timer_init(struct device_node *np) { int ret; ti_32k_timer.base = of_iomap(np, 0); if (!ti_32k_timer.base) { pr_err("Can't ioremap 32k timer base\n"); - return; + return -ENXIO; } ti_32k_timer.counter = ti_32k_timer.base; @@ -116,11 +116,13 @@ static void __init ti_32k_timer_init(struct device_node *np) ret = clocksource_register_hz(&ti_32k_timer.cs, 32768); if (ret) { pr_err("32k_counter: can't register clocksource\n"); - return; + return ret; } sched_clock_register(omap_32k_read_sched_clock, 32, 32768); pr_info("OMAP clocksource: 32k_counter at 32768 Hz\n"); + + return 0; } -CLOCKSOURCE_OF_DECLARE(ti_32k_timer, "ti,omap-counter32k", +CLOCKSOURCE_OF_DECLARE_RET(ti_32k_timer, "ti,omap-counter32k", ti_32k_timer_init); -- cgit v0.10.2 From 1ee078facfd4f26f516becd4c73a7e6a2e520965 Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Mon, 6 Jun 2016 23:29:18 +0200 Subject: clocksource/drivers/u300: Convert init function to return error The init functions do not return any error. They behave as the following: - panic, thus leading to a kernel crash while another timer may work and make the system boot up correctly or - print an error and let the caller unaware if the state of the system Change that by converting the init functions to return an error conforming to the CLOCKSOURCE_OF_RET prototype. Proper error handling (rollback, errno value) will be changed later case by case, thus this change just return back an error or success in the init function. Signed-off-by: Daniel Lezcano Acked-by: Linus Walleij diff --git a/drivers/clocksource/timer-u300.c b/drivers/clocksource/timer-u300.c index 1744b24..a6a0dec 100644 --- a/drivers/clocksource/timer-u300.c +++ b/drivers/clocksource/timer-u300.c @@ -359,27 +359,37 @@ static struct delay_timer u300_delay_timer; /* * This sets up the system timers, clock source and clock event. */ -static void __init u300_timer_init_of(struct device_node *np) +static int __init u300_timer_init_of(struct device_node *np) { unsigned int irq; struct clk *clk; unsigned long rate; + int ret; u300_timer_base = of_iomap(np, 0); - if (!u300_timer_base) - panic("could not ioremap system timer\n"); + if (!u300_timer_base) { + pr_err("could not ioremap system timer\n"); + return -ENXIO; + } /* Get the IRQ for the GP1 timer */ irq = irq_of_parse_and_map(np, 2); - if (!irq) - panic("no IRQ for system timer\n"); + if (!irq) { + pr_err("no IRQ for system timer\n"); + return -EINVAL; + } pr_info("U300 GP1 timer @ base: %p, IRQ: %u\n", u300_timer_base, irq); /* Clock the interrupt controller */ clk = of_clk_get(np, 0); - BUG_ON(IS_ERR(clk)); - clk_prepare_enable(clk); + if (IS_ERR(clk)) + return PTR_ERR(clk); + + ret = clk_prepare_enable(clk); + if (ret) + return ret; + rate = clk_get_rate(clk); u300_clockevent_data.ticks_per_jiffy = DIV_ROUND_CLOSEST(rate, HZ); @@ -410,7 +420,9 @@ static void __init u300_timer_init_of(struct device_node *np) u300_timer_base + U300_TIMER_APP_RGPT1); /* Set up the IRQ handler */ - setup_irq(irq, &u300_timer_irq); + ret = setup_irq(irq, &u300_timer_irq); + if (ret) + return ret; /* Reset the General Purpose timer 2 */ writel(U300_TIMER_APP_RGPT2_TIMER_RESET, @@ -428,9 +440,12 @@ static void __init u300_timer_init_of(struct device_node *np) u300_timer_base + U300_TIMER_APP_EGPT2); /* Use general purpose timer 2 as clock source */ - if (clocksource_mmio_init(u300_timer_base + U300_TIMER_APP_GPT2CC, - "GPT2", rate, 300, 32, clocksource_mmio_readl_up)) + ret = clocksource_mmio_init(u300_timer_base + U300_TIMER_APP_GPT2CC, + "GPT2", rate, 300, 32, clocksource_mmio_readl_up); + if (ret) { pr_err("timer: failed to initialize U300 clock source\n"); + return ret; + } /* Configure and register the clockevent */ clockevents_config_and_register(&u300_clockevent_data.cevd, rate, @@ -440,7 +455,8 @@ static void __init u300_timer_init_of(struct device_node *np) * TODO: init and register the rest of the timers too, they can be * used by hrtimers! */ + return 0; } -CLOCKSOURCE_OF_DECLARE(u300_timer, "stericsson,u300-apptimer", +CLOCKSOURCE_OF_DECLARE_RET(u300_timer, "stericsson,u300-apptimer", u300_timer_init_of); -- cgit v0.10.2 From 86de9628230956aa976fe50f407a25bd268d8a68 Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Mon, 6 Jun 2016 23:29:30 +0200 Subject: clocksource/drivers/versatile: Convert init function to return error The init functions do not return any error. They behave as the following: - panic, thus leading to a kernel crash while another timer may work and make the system boot up correctly or - print an error and let the caller unaware if the state of the system Change that by converting the init functions to return an error conforming to the CLOCKSOURCE_OF_RET prototype. Proper error handling (rollback, errno value) will be changed later case by case, thus this change just return back an error or success in the init function. Signed-off-by: Daniel Lezcano Acked-by: Liviu Dudau diff --git a/drivers/clocksource/versatile.c b/drivers/clocksource/versatile.c index 0a26d3d..8daeffa 100644 --- a/drivers/clocksource/versatile.c +++ b/drivers/clocksource/versatile.c @@ -25,18 +25,20 @@ static u64 notrace versatile_sys_24mhz_read(void) return readl(versatile_sys_24mhz); } -static void __init versatile_sched_clock_init(struct device_node *node) +static int __init versatile_sched_clock_init(struct device_node *node) { void __iomem *base = of_iomap(node, 0); if (!base) - return; + return -ENXIO; versatile_sys_24mhz = base + SYS_24MHZ; sched_clock_register(versatile_sys_24mhz_read, 32, 24000000); + + return 0; } -CLOCKSOURCE_OF_DECLARE(vexpress, "arm,vexpress-sysreg", +CLOCKSOURCE_OF_DECLARE_RET(vexpress, "arm,vexpress-sysreg", versatile_sched_clock_init); -CLOCKSOURCE_OF_DECLARE(versatile, "arm,versatile-sysreg", +CLOCKSOURCE_OF_DECLARE_RET(versatile, "arm,versatile-sysreg", versatile_sched_clock_init); -- cgit v0.10.2 From b71306e62d6a42a00bf8ebb6b77bbd42dec75e6e Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Mon, 6 Jun 2016 23:29:49 +0200 Subject: clocksource/drivers/vf_pit_timer: Convert init function to return error The init functions do not return any error. They behave as the following: - panic, thus leading to a kernel crash while another timer may work and make the system boot up correctly or - print an error and let the caller unaware if the state of the system Change that by converting the init functions to return an error conforming to the CLOCKSOURCE_OF_RET prototype. Proper error handling (rollback, errno value) will be changed later case by case, thus this change just return back an error or success in the init function. Signed-off-by: Daniel Lezcano diff --git a/drivers/clocksource/vf_pit_timer.c b/drivers/clocksource/vf_pit_timer.c index a0e6c68..ca4dff4 100644 --- a/drivers/clocksource/vf_pit_timer.c +++ b/drivers/clocksource/vf_pit_timer.c @@ -156,15 +156,18 @@ static int __init pit_clockevent_init(unsigned long rate, int irq) return 0; } -static void __init pit_timer_init(struct device_node *np) +static int __init pit_timer_init(struct device_node *np) { struct clk *pit_clk; void __iomem *timer_base; unsigned long clk_rate; - int irq; + int irq, ret; timer_base = of_iomap(np, 0); - BUG_ON(!timer_base); + if (!timer_base) { + pr_err("Failed to iomap"); + return -ENXIO; + } /* * PIT0 and PIT1 can be chained to build a 64-bit timer, @@ -175,12 +178,16 @@ static void __init pit_timer_init(struct device_node *np) clkevt_base = timer_base + PITn_OFFSET(3); irq = irq_of_parse_and_map(np, 0); - BUG_ON(irq <= 0); + if (irq <= 0) + return -EINVAL; pit_clk = of_clk_get(np, 0); - BUG_ON(IS_ERR(pit_clk)); + if (IS_ERR(pit_clk)) + return PTR_ERR(pit_clk); - BUG_ON(clk_prepare_enable(pit_clk)); + ret = clk_prepare_enable(pit_clk); + if (ret) + return ret; clk_rate = clk_get_rate(pit_clk); cycle_per_jiffy = clk_rate / (HZ); @@ -188,8 +195,10 @@ static void __init pit_timer_init(struct device_node *np) /* enable the pit module */ __raw_writel(~PITMCR_MDIS, timer_base + PITMCR); - BUG_ON(pit_clocksource_init(clk_rate)); + ret = pit_clocksource_init(clk_rate); + if (ret) + return ret; - pit_clockevent_init(clk_rate, irq); + return pit_clockevent_init(clk_rate, irq); } -CLOCKSOURCE_OF_DECLARE(vf610, "fsl,vf610-pit", pit_timer_init); +CLOCKSOURCE_OF_DECLARE_RET(vf610, "fsl,vf610-pit", pit_timer_init); -- cgit v0.10.2 From 979d7f28ff9914cb02d12c40a2e0fb9b0718e52b Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Mon, 6 Jun 2016 23:30:04 +0200 Subject: clocksource/drivers/vt8500: Convert init function to return error The init functions do not return any error. They behave as the following: - panic, thus leading to a kernel crash while another timer may work and make the system boot up correctly or - print an error and let the caller unaware if the state of the system Change that by converting the init functions to return an error conforming to the CLOCKSOURCE_OF_RET prototype. Proper error handling (rollback, errno value) will be changed later case by case, thus this change just return back an error or success in the init function. Signed-off-by: Daniel Lezcano diff --git a/drivers/clocksource/vt8500_timer.c b/drivers/clocksource/vt8500_timer.c index ddb4092..1bc8707 100644 --- a/drivers/clocksource/vt8500_timer.c +++ b/drivers/clocksource/vt8500_timer.c @@ -121,38 +121,48 @@ static struct irqaction irq = { .dev_id = &clockevent, }; -static void __init vt8500_timer_init(struct device_node *np) +static int __init vt8500_timer_init(struct device_node *np) { - int timer_irq; + int timer_irq, ret; regbase = of_iomap(np, 0); if (!regbase) { pr_err("%s: Missing iobase description in Device Tree\n", __func__); - return; + return -ENXIO; } + timer_irq = irq_of_parse_and_map(np, 0); if (!timer_irq) { pr_err("%s: Missing irq description in Device Tree\n", __func__); - return; + return -EINVAL; } writel(1, regbase + TIMER_CTRL_VAL); writel(0xf, regbase + TIMER_STATUS_VAL); writel(~0, regbase + TIMER_MATCH_VAL); - if (clocksource_register_hz(&clocksource, VT8500_TIMER_HZ)) + ret = clocksource_register_hz(&clocksource, VT8500_TIMER_HZ); + if (ret) { pr_err("%s: vt8500_timer_init: clocksource_register failed for %s\n", - __func__, clocksource.name); + __func__, clocksource.name); + return ret; + } clockevent.cpumask = cpumask_of(0); - if (setup_irq(timer_irq, &irq)) + ret = setup_irq(timer_irq, &irq); + if (ret) { pr_err("%s: setup_irq failed for %s\n", __func__, clockevent.name); + return ret; + } + clockevents_config_and_register(&clockevent, VT8500_TIMER_HZ, MIN_OSCR_DELTA * 2, 0xf0000000); + + return 0; } -CLOCKSOURCE_OF_DECLARE(vt8500, "via,vt8500-timer", vt8500_timer_init); +CLOCKSOURCE_OF_DECLARE_RET(vt8500, "via,vt8500-timer", vt8500_timer_init); -- cgit v0.10.2 From 42452508bd7a6527221fff84f3da2b0197b726ae Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Mon, 6 Jun 2016 23:30:17 +0200 Subject: clocksource/drivers/zevio: Convert init function to return error The init functions do not return any error. They behave as the following: - panic, thus leading to a kernel crash while another timer may work and make the system boot up correctly or - print an error and let the caller unaware if the state of the system Change that by converting the init functions to return an error conforming to the CLOCKSOURCE_OF_RET prototype. Proper error handling (rollback, errno value) will be changed later case by case, thus this change just return back an error or success in the init function. Signed-off-by: Daniel Lezcano diff --git a/drivers/clocksource/zevio-timer.c b/drivers/clocksource/zevio-timer.c index ceaa613..cb4cf05 100644 --- a/drivers/clocksource/zevio-timer.c +++ b/drivers/clocksource/zevio-timer.c @@ -210,9 +210,9 @@ error_free: return ret; } -static void __init zevio_timer_init(struct device_node *node) +static int __init zevio_timer_init(struct device_node *node) { - BUG_ON(zevio_timer_add(node)); + return zevio_timer_add(node); } -CLOCKSOURCE_OF_DECLARE(zevio_timer, "lsi,zevio-timer", zevio_timer_init); +CLOCKSOURCE_OF_DECLARE_RET(zevio_timer, "lsi,zevio-timer", zevio_timer_init); -- cgit v0.10.2 From 0586421746ef2bc33898d2d7f3dbb0eec6b234c3 Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Tue, 7 Jun 2016 00:03:34 +0200 Subject: clocksource/drivers/microblaze: Convert init function to return error The init functions do not return any error. They behave as the following: - panic, thus leading to a kernel crash while another timer may work and make the system boot up correctly or - print an error and let the caller unaware if the state of the system Change that by converting the init functions to return an error conforming to the CLOCKSOURCE_OF_RET prototype. Proper error handling (rollback, errno value) will be changed later case by case, thus this change just return back an error or success in the init function. Signed-off-by: Daniel Lezcano diff --git a/arch/microblaze/kernel/timer.c b/arch/microblaze/kernel/timer.c index 67e2ef4..7f35e7b 100644 --- a/arch/microblaze/kernel/timer.c +++ b/arch/microblaze/kernel/timer.c @@ -170,7 +170,7 @@ static struct irqaction timer_irqaction = { .dev_id = &clockevent_xilinx_timer, }; -static __init void xilinx_clockevent_init(void) +static __init int xilinx_clockevent_init(void) { clockevent_xilinx_timer.mult = div_sc(timer_clock_freq, NSEC_PER_SEC, @@ -181,6 +181,8 @@ static __init void xilinx_clockevent_init(void) clockevent_delta2ns(1, &clockevent_xilinx_timer); clockevent_xilinx_timer.cpumask = cpumask_of(0); clockevents_register_device(&clockevent_xilinx_timer); + + return 0; } static u64 xilinx_clock_read(void) @@ -229,8 +231,14 @@ static struct clocksource clocksource_microblaze = { static int __init xilinx_clocksource_init(void) { - if (clocksource_register_hz(&clocksource_microblaze, timer_clock_freq)) - panic("failed to register clocksource"); + int ret; + + ret = clocksource_register_hz(&clocksource_microblaze, + timer_clock_freq); + if (ret) { + pr_err("failed to register clocksource"); + return ret; + } /* stop timer1 */ write_fn(read_fn(timer_baseaddr + TCSR1) & ~TCSR_ENT, @@ -239,16 +247,16 @@ static int __init xilinx_clocksource_init(void) write_fn(TCSR_TINT|TCSR_ENT|TCSR_ARHT, timer_baseaddr + TCSR1); /* register timecounter - for ftrace support */ - init_xilinx_timecounter(); - return 0; + return init_xilinx_timecounter(); } -static void __init xilinx_timer_init(struct device_node *timer) +static int __init xilinx_timer_init(struct device_node *timer) { struct clk *clk; static int initialized; u32 irq; u32 timer_num = 1; + int ret; if (initialized) return; @@ -258,7 +266,7 @@ static void __init xilinx_timer_init(struct device_node *timer) timer_baseaddr = of_iomap(timer, 0); if (!timer_baseaddr) { pr_err("ERROR: invalid timer base address\n"); - BUG(); + return -ENXIO; } write_fn = timer_write32; @@ -271,11 +279,15 @@ static void __init xilinx_timer_init(struct device_node *timer) } irq = irq_of_parse_and_map(timer, 0); + if (irq <= 0) { + pr_err("Failed to parse and map irq"); + return -EINVAL; + } of_property_read_u32(timer, "xlnx,one-timer-only", &timer_num); if (timer_num) { - pr_emerg("Please enable two timers in HW\n"); - BUG(); + pr_err("Please enable two timers in HW\n"); + return -EINVAL; } pr_info("%s: irq=%d\n", timer->full_name, irq); @@ -297,15 +309,28 @@ static void __init xilinx_timer_init(struct device_node *timer) freq_div_hz = timer_clock_freq / HZ; - setup_irq(irq, &timer_irqaction); + ret = setup_irq(irq, &timer_irqaction); + if (ret) { + pr_err("Failed to setup IRQ"); + return ret; + } + #ifdef CONFIG_HEART_BEAT microblaze_setup_heartbeat(); #endif - xilinx_clocksource_init(); - xilinx_clockevent_init(); + + ret = xilinx_clocksource_init(); + if (ret) + return ret; + + ret = xilinx_clockevent_init(); + if (ret) + return ret; sched_clock_register(xilinx_clock_read, 32, timer_clock_freq); + + return 0; } -CLOCKSOURCE_OF_DECLARE(xilinx_timer, "xlnx,xps-timer-1.00.a", +CLOCKSOURCE_OF_DECLARE_RET(xilinx_timer, "xlnx,xps-timer-1.00.a", xilinx_timer_init); -- cgit v0.10.2 From 2712616fed84ddf60c788269d39bb26eb6779945 Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Tue, 7 Jun 2016 00:03:49 +0200 Subject: clocksource/drivers/ralink: Convert init function to return error The init functions do not return any error. They behave as the following: - panic, thus leading to a kernel crash while another timer may work and make the system boot up correctly or - print an error and let the caller unaware if the state of the system Change that by converting the init functions to return an error conforming to the CLOCKSOURCE_OF_RET prototype. Proper error handling (rollback, errno value) will be changed later case by case, thus this change just return back an error or success in the init function. Signed-off-by: Daniel Lezcano diff --git a/arch/mips/ralink/cevt-rt3352.c b/arch/mips/ralink/cevt-rt3352.c index 3ad0b07..f2d3c79 100644 --- a/arch/mips/ralink/cevt-rt3352.c +++ b/arch/mips/ralink/cevt-rt3352.c @@ -117,11 +117,13 @@ static int systick_set_oneshot(struct clock_event_device *evt) return 0; } -static void __init ralink_systick_init(struct device_node *np) +static int __init ralink_systick_init(struct device_node *np) { + int ret; + systick.membase = of_iomap(np, 0); if (!systick.membase) - return; + return -ENXIO; systick_irqaction.name = np->name; systick.dev.name = np->name; @@ -131,16 +133,21 @@ static void __init ralink_systick_init(struct device_node *np) systick.dev.irq = irq_of_parse_and_map(np, 0); if (!systick.dev.irq) { pr_err("%s: request_irq failed", np->name); - return; + return -EINVAL; } - clocksource_mmio_init(systick.membase + SYSTICK_COUNT, np->name, - SYSTICK_FREQ, 301, 16, clocksource_mmio_readl_up); + ret = clocksource_mmio_init(systick.membase + SYSTICK_COUNT, np->name, + SYSTICK_FREQ, 301, 16, + clocksource_mmio_readl_up); + if (ret) + return ret; clockevents_register_device(&systick.dev); pr_info("%s: running - mult: %d, shift: %d\n", np->name, systick.dev.mult, systick.dev.shift); + + return 0; } -CLOCKSOURCE_OF_DECLARE(systick, "ralink,cevt-systick", ralink_systick_init); +CLOCKSOURCE_OF_DECLARE_RET(systick, "ralink,cevt-systick", ralink_systick_init); -- cgit v0.10.2 From dd1364a7439be4d20f87637a72eb7bd4553827f0 Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Tue, 7 Jun 2016 00:04:02 +0200 Subject: clocksource/drivers/nios2: Convert init function to return error The init functions do not return any error. They behave as the following: - panic, thus leading to a kernel crash while another timer may work and make the system boot up correctly or - print an error and let the caller unaware if the state of the system Change that by converting the init functions to return an error conforming to the CLOCKSOURCE_OF_RET prototype. Proper error handling (rollback, errno value) will be changed later case by case, thus this change just return back an error or success in the init function. Signed-off-by: Daniel Lezcano diff --git a/arch/nios2/kernel/time.c b/arch/nios2/kernel/time.c index e835dda..b75e40e 100644 --- a/arch/nios2/kernel/time.c +++ b/arch/nios2/kernel/time.c @@ -206,15 +206,21 @@ irqreturn_t timer_interrupt(int irq, void *dev_id) return IRQ_HANDLED; } -static void __init nios2_timer_get_base_and_freq(struct device_node *np, +static int __init nios2_timer_get_base_and_freq(struct device_node *np, void __iomem **base, u32 *freq) { *base = of_iomap(np, 0); - if (!*base) - panic("Unable to map reg for %s\n", np->name); + if (!*base) { + pr_crit("Unable to map reg for %s\n", np->name); + return -ENXIO; + } + + if (of_property_read_u32(np, "clock-frequency", freq)) { + pr_crit("Unable to get %s clock frequency\n", np->name); + return -EINVAL; + } - if (of_property_read_u32(np, "clock-frequency", freq)) - panic("Unable to get %s clock frequency\n", np->name); + return 0; } static struct nios2_clockevent_dev nios2_ce = { @@ -231,17 +237,21 @@ static struct nios2_clockevent_dev nios2_ce = { }, }; -static __init void nios2_clockevent_init(struct device_node *timer) +static __init int nios2_clockevent_init(struct device_node *timer) { void __iomem *iobase; u32 freq; - int irq; + int irq, ret; - nios2_timer_get_base_and_freq(timer, &iobase, &freq); + ret = nios2_timer_get_base_and_freq(timer, &iobase, &freq); + if (ret) + return ret; irq = irq_of_parse_and_map(timer, 0); - if (!irq) - panic("Unable to parse timer irq\n"); + if (!irq) { + pr_crit("Unable to parse timer irq\n"); + return -EINVAL; + } nios2_ce.timer.base = iobase; nios2_ce.timer.freq = freq; @@ -253,25 +263,35 @@ static __init void nios2_clockevent_init(struct device_node *timer) /* clear pending interrupt */ timer_writew(&nios2_ce.timer, 0, ALTERA_TIMER_STATUS_REG); - if (request_irq(irq, timer_interrupt, IRQF_TIMER, timer->name, - &nios2_ce.ced)) - panic("Unable to setup timer irq\n"); + ret = request_irq(irq, timer_interrupt, IRQF_TIMER, timer->name, + &nios2_ce.ced); + if (ret) { + pr_crit("Unable to setup timer irq\n"); + return ret; + } clockevents_config_and_register(&nios2_ce.ced, freq, 1, ULONG_MAX); + + return 0; } -static __init void nios2_clocksource_init(struct device_node *timer) +static __init int nios2_clocksource_init(struct device_node *timer) { unsigned int ctrl; void __iomem *iobase; u32 freq; + int ret; - nios2_timer_get_base_and_freq(timer, &iobase, &freq); + ret = nios2_timer_get_base_and_freq(timer, &iobase, &freq); + if (ret) + return ret; nios2_cs.timer.base = iobase; nios2_cs.timer.freq = freq; - clocksource_register_hz(&nios2_cs.cs, freq); + ret = clocksource_register_hz(&nios2_cs.cs, freq); + if (ret) + return ret; timer_writew(&nios2_cs.timer, USHRT_MAX, ALTERA_TIMER_PERIODL_REG); timer_writew(&nios2_cs.timer, USHRT_MAX, ALTERA_TIMER_PERIODH_REG); @@ -282,6 +302,8 @@ static __init void nios2_clocksource_init(struct device_node *timer) /* Calibrate the delay loop directly */ lpj_fine = freq / HZ; + + return 0; } /* @@ -289,22 +311,25 @@ static __init void nios2_clocksource_init(struct device_node *timer) * more instances, the second one gets used as clocksource and all * others are unused. */ -static void __init nios2_time_init(struct device_node *timer) +static int __init nios2_time_init(struct device_node *timer) { static int num_called; + int ret; switch (num_called) { case 0: - nios2_clockevent_init(timer); + ret = nios2_clockevent_init(timer); break; case 1: - nios2_clocksource_init(timer); + ret = nios2_clocksource_init(timer); break; default: break; } num_called++; + + return ret; } void read_persistent_clock(struct timespec *ts) @@ -327,4 +352,4 @@ void __init time_init(void) clocksource_probe(); } -CLOCKSOURCE_OF_DECLARE(nios2_timer, ALTR_TIMER_COMPATIBLE, nios2_time_init); +CLOCKSOURCE_OF_DECLARE_RET(nios2_timer, ALTR_TIMER_COMPATIBLE, nios2_time_init); -- cgit v0.10.2 From dcbc0eddcbbf441fdcf0eb4c2e9c1716ac235972 Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Tue, 7 Jun 2016 00:03:11 +0200 Subject: clocksource/drivers/smp_twd: Convert init function to return error The init functions do not return any error. They behave as the following: - panic, thus leading to a kernel crash while another timer may work and make the system boot up correctly or - print an error and let the caller unaware if the state of the system Change that by converting the init functions to return an error conforming to the CLOCKSOURCE_OF_RET prototype. Proper error handling (rollback, errno value) will be changed later case by case, thus this change just return back an error or success in the init function. Signed-off-by: Daniel Lezcano diff --git a/arch/arm/kernel/smp_twd.c b/arch/arm/kernel/smp_twd.c index 1bfa7a7..2b24be4 100644 --- a/arch/arm/kernel/smp_twd.c +++ b/arch/arm/kernel/smp_twd.c @@ -390,7 +390,7 @@ int __init twd_local_timer_register(struct twd_local_timer *tlt) } #ifdef CONFIG_OF -static void __init twd_local_timer_of_register(struct device_node *np) +static int __init twd_local_timer_of_register(struct device_node *np) { int err; @@ -410,8 +410,9 @@ static void __init twd_local_timer_of_register(struct device_node *np) out: WARN(err, "twd_local_timer_of_register failed (%d)\n", err); + return err; } -CLOCKSOURCE_OF_DECLARE(arm_twd_a9, "arm,cortex-a9-twd-timer", twd_local_timer_of_register); -CLOCKSOURCE_OF_DECLARE(arm_twd_a5, "arm,cortex-a5-twd-timer", twd_local_timer_of_register); -CLOCKSOURCE_OF_DECLARE(arm_twd_11mp, "arm,arm11mp-twd-timer", twd_local_timer_of_register); +CLOCKSOURCE_OF_DECLARE_RET(arm_twd_a9, "arm,cortex-a9-twd-timer", twd_local_timer_of_register); +CLOCKSOURCE_OF_DECLARE_RET(arm_twd_a5, "arm,cortex-a5-twd-timer", twd_local_timer_of_register); +CLOCKSOURCE_OF_DECLARE_RET(arm_twd_11mp, "arm,arm11mp-twd-timer", twd_local_timer_of_register); #endif -- cgit v0.10.2 From 2d9b65061652dcde5200998f3cebe5e736e5d9b3 Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Wed, 15 Jun 2016 14:16:11 +0200 Subject: clocksource/drivers/nps: Convert init function to return error The init functions do not return any error. They behave as the following: - panic, thus leading to a kernel crash while another timer may work and make the system boot up correctly or - print an error and let the caller unaware if the state of the system Change that by converting the init functions to return an error conforming to the CLOCKSOURCE_OF_RET prototype. Proper error handling (rollback, errno value) will be changed later case by case, thus this change just return back an error or success in the init function. Signed-off-by: Daniel Lezcano Signed-off-by: Arnd Bergmann diff --git a/drivers/clocksource/timer-nps.c b/drivers/clocksource/timer-nps.c index d461089..b5c7b2b 100644 --- a/drivers/clocksource/timer-nps.c +++ b/drivers/clocksource/timer-nps.c @@ -55,8 +55,8 @@ static cycle_t nps_clksrc_read(struct clocksource *clksrc) return (cycle_t)ioread32be(nps_msu_reg_low_addr[cluster]); } -static void __init nps_setup_clocksource(struct device_node *node, - struct clk *clk) +static int __init nps_setup_clocksource(struct device_node *node, + struct clk *clk) { int ret, cluster; @@ -68,7 +68,7 @@ static void __init nps_setup_clocksource(struct device_node *node, ret = clk_prepare_enable(clk); if (ret) { pr_err("Couldn't enable parent clock\n"); - return; + return ret; } nps_timer_rate = clk_get_rate(clk); @@ -79,20 +79,22 @@ static void __init nps_setup_clocksource(struct device_node *node, pr_err("Couldn't register clock source.\n"); clk_disable_unprepare(clk); } + + return ret; } -static void __init nps_timer_init(struct device_node *node) +static int __init nps_timer_init(struct device_node *node) { struct clk *clk; clk = of_clk_get(node, 0); if (IS_ERR(clk)) { pr_err("Can't get timer clock.\n"); - return; + return PTR_ERR(clk); } - nps_setup_clocksource(node, clk); + return nps_setup_clocksource(node, clk); } -CLOCKSOURCE_OF_DECLARE(ezchip_nps400_clksrc, "ezchip,nps400-timer", - nps_timer_init); +CLOCKSOURCE_OF_DECLARE_RET(ezchip_nps400_clksrc, "ezchip,nps400-timer", + nps_timer_init); -- cgit v0.10.2 From 43d7560494a264a34e8bb5257ef43b0be6134dac Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Wed, 15 Jun 2016 14:50:12 +0200 Subject: clocksource/drivers/arc: Convert init function to return error The init functions do not return any error. They behave as the following: - panic, thus leading to a kernel crash while another timer may work and make the system boot up correctly or - print an error and let the caller unaware if the state of the system Change that by converting the init functions to return an error conforming to the CLOCKSOURCE_OF_RET prototype. Proper error handling (rollback, errno value) will be changed later case by case, thus this change just return back an error or success in the init function. Signed-off-by: Daniel Lezcano diff --git a/arch/arc/kernel/time.c b/arch/arc/kernel/time.c index 4549ab2..09de669 100644 --- a/arch/arc/kernel/time.c +++ b/arch/arc/kernel/time.c @@ -116,21 +116,21 @@ static struct clocksource arc_counter_gfrc = { .flags = CLOCK_SOURCE_IS_CONTINUOUS, }; -static void __init arc_cs_setup_gfrc(struct device_node *node) +static int __init arc_cs_setup_gfrc(struct device_node *node) { int exists = cpuinfo_arc700[0].extn.gfrc; int ret; if (WARN(!exists, "Global-64-bit-Ctr clocksource not detected")) - return; + return -ENXIO; ret = arc_get_timer_clk(node); if (ret) - return; + return ret; - clocksource_register_hz(&arc_counter_gfrc, arc_timer_freq); + return clocksource_register_hz(&arc_counter_gfrc, arc_timer_freq); } -CLOCKSOURCE_OF_DECLARE(arc_gfrc, "snps,archs-timer-gfrc", arc_cs_setup_gfrc); +CLOCKSOURCE_OF_DECLARE_RET(arc_gfrc, "snps,archs-timer-gfrc", arc_cs_setup_gfrc); #endif @@ -172,27 +172,27 @@ static struct clocksource arc_counter_rtc = { .flags = CLOCK_SOURCE_IS_CONTINUOUS, }; -static void __init arc_cs_setup_rtc(struct device_node *node) +static int __init arc_cs_setup_rtc(struct device_node *node) { int exists = cpuinfo_arc700[smp_processor_id()].extn.rtc; int ret; if (WARN(!exists, "Local-64-bit-Ctr clocksource not detected")) - return; + return -ENXIO; /* Local to CPU hence not usable in SMP */ if (WARN(IS_ENABLED(CONFIG_SMP), "Local-64-bit-Ctr not usable in SMP")) - return; + return -EINVAL; ret = arc_get_timer_clk(node); if (ret) - return; + return ret; write_aux_reg(AUX_RTC_CTRL, 1); - clocksource_register_hz(&arc_counter_rtc, arc_timer_freq); + return clocksource_register_hz(&arc_counter_rtc, arc_timer_freq); } -CLOCKSOURCE_OF_DECLARE(arc_rtc, "snps,archs-timer-rtc", arc_cs_setup_rtc); +CLOCKSOURCE_OF_DECLARE_RET(arc_rtc, "snps,archs-timer-rtc", arc_cs_setup_rtc); #endif @@ -213,23 +213,23 @@ static struct clocksource arc_counter_timer1 = { .flags = CLOCK_SOURCE_IS_CONTINUOUS, }; -static void __init arc_cs_setup_timer1(struct device_node *node) +static int __init arc_cs_setup_timer1(struct device_node *node) { int ret; /* Local to CPU hence not usable in SMP */ if (IS_ENABLED(CONFIG_SMP)) - return; + return -EINVAL; ret = arc_get_timer_clk(node); if (ret) - return; + return ret; write_aux_reg(ARC_REG_TIMER1_LIMIT, ARC_TIMER_MAX); write_aux_reg(ARC_REG_TIMER1_CNT, 0); write_aux_reg(ARC_REG_TIMER1_CTRL, TIMER_CTRL_NH); - clocksource_register_hz(&arc_counter_timer1, arc_timer_freq); + return clocksource_register_hz(&arc_counter_timer1, arc_timer_freq); } /********** Clock Event Device *********/ @@ -324,20 +324,28 @@ static struct notifier_block arc_timer_cpu_nb = { /* * clockevent setup for boot CPU */ -static void __init arc_clockevent_setup(struct device_node *node) +static int __init arc_clockevent_setup(struct device_node *node) { struct clock_event_device *evt = this_cpu_ptr(&arc_clockevent_device); int ret; - register_cpu_notifier(&arc_timer_cpu_nb); + ret = register_cpu_notifier(&arc_timer_cpu_nb); + if (ret) { + pr_err("Failed to register cpu notifier"); + return ret; + } arc_timer_irq = irq_of_parse_and_map(node, 0); - if (arc_timer_irq <= 0) - panic("clockevent: missing irq"); + if (arc_timer_irq <= 0) { + pr_err("clockevent: missing irq"); + return -EINVAL; + } ret = arc_get_timer_clk(node); - if (ret) - panic("clockevent: missing clk"); + if (ret) { + pr_err("clockevent: missing clk"); + return ret; + } evt->irq = arc_timer_irq; evt->cpumask = cpumask_of(smp_processor_id()); @@ -347,24 +355,31 @@ static void __init arc_clockevent_setup(struct device_node *node) /* Needs apriori irq_set_percpu_devid() done in intc map function */ ret = request_percpu_irq(arc_timer_irq, timer_irq_handler, "Timer0 (per-cpu-tick)", evt); - if (ret) - panic("clockevent: unable to request irq\n"); + if (ret) { + pr_err("clockevent: unable to request irq\n"); + return ret; + } enable_percpu_irq(arc_timer_irq, 0); + + return 0; } -static void __init arc_of_timer_init(struct device_node *np) +static int __init arc_of_timer_init(struct device_node *np) { static int init_count = 0; + int ret; if (!init_count) { init_count = 1; - arc_clockevent_setup(np); + ret = arc_clockevent_setup(np); } else { - arc_cs_setup_timer1(np); + ret = arc_cs_setup_timer1(np); } + + return ret; } -CLOCKSOURCE_OF_DECLARE(arc_clkevt, "snps,arc-timer", arc_of_timer_init); +CLOCKSOURCE_OF_DECLARE_RET(arc_clkevt, "snps,arc-timer", arc_of_timer_init); /* * Called from start_kernel() - boot CPU only -- cgit v0.10.2 From 8595b1ba14f763da8c406c8a243510fa13097214 Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Thu, 16 Jun 2016 18:10:58 +0200 Subject: clocksource/drivers/oxnas-rps: Convert init function to return error The init functions do not return any error. They behave as the following: - panic, thus leading to a kernel crash while another timer may work and make the system boot up correctly or - print an error and let the caller unaware if the state of the system Change that by converting the init functions to return an error conforming to the CLOCKSOURCE_OF_RET prototype. Proper error handling (rollback, errno value) will be changed later case by case, thus this change just return back an error or success in the init function. Signed-off-by: Daniel Lezcano Acked-by: Neil Armstrong diff --git a/drivers/clocksource/timer-oxnas-rps.c b/drivers/clocksource/timer-oxnas-rps.c index c002e99..0d99f40 100644 --- a/drivers/clocksource/timer-oxnas-rps.c +++ b/drivers/clocksource/timer-oxnas-rps.c @@ -220,32 +220,37 @@ static int __init oxnas_rps_clocksource_init(struct oxnas_rps_timer *rps) return 0; } -static void __init oxnas_rps_timer_init(struct device_node *np) +static int __init oxnas_rps_timer_init(struct device_node *np) { struct oxnas_rps_timer *rps; void __iomem *base; int ret; rps = kzalloc(sizeof(*rps), GFP_KERNEL); - if (!rps) { - pr_err("Failed to allocate rps structure\n"); - return; - } + if (!rps) + return -ENOMEM; rps->clk = of_clk_get(np, 0); - if (WARN_ON(IS_ERR(rps->clk))) + if (IS_ERR(rps->clk)) { + ret = PTR_ERR(rps->clk); goto err_alloc; + } - if (WARN_ON(clk_prepare_enable(rps->clk))) + ret = clk_prepare_enable(rps->clk); + if (ret) goto err_clk; base = of_iomap(np, 0); - if (WARN_ON(!base)) + if (!base) { + ret = -ENXIO; goto err_clk_prepare; + } rps->irq = irq_of_parse_and_map(np, 0); - if (WARN_ON(rps->irq < 0)) + if (rps->irq < 0) { + ret = -EINVAL; goto err_iomap; + } rps->clkevt_base = base + TIMER1_REG_OFFSET; rps->clksrc_base = base + TIMER2_REG_OFFSET; @@ -261,7 +266,7 @@ static void __init oxnas_rps_timer_init(struct device_node *np) ret = request_irq(rps->irq, oxnas_rps_timer_irq, IRQF_TIMER | IRQF_IRQPOLL, "rps-timer", rps); - if (WARN_ON(ret)) + if (ret) goto err_iomap; ret = oxnas_rps_clocksource_init(rps); @@ -272,7 +277,7 @@ static void __init oxnas_rps_timer_init(struct device_node *np) if (ret) goto err_irqreq; - return; + return 0; err_irqreq: free_irq(rps->irq, rps); @@ -284,7 +289,9 @@ err_clk: clk_put(rps->clk); err_alloc: kfree(rps); + + return ret; } -CLOCKSOURCE_OF_DECLARE(ox810se_rps, - "oxsemi,ox810se-rps-timer", oxnas_rps_timer_init); +CLOCKSOURCE_OF_DECLARE_RET(ox810se_rps, + "oxsemi,ox810se-rps-timer", oxnas_rps_timer_init); -- cgit v0.10.2 From 177cf6e52b0a1a382b9892d3cc9aafd6e7c5943f Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Tue, 7 Jun 2016 00:27:44 +0200 Subject: clocksources: Switch back to the clksrc table All the clocksource drivers's init function are now converted to return an error code. CLOCKSOURCE_OF_DECLARE is no longer used as well as the clksrc-of table. Let's convert back the names: - CLOCKSOURCE_OF_DECLARE_RET => CLOCKSOURCE_OF_DECLARE - clksrc-of-ret => clksrc-of Signed-off-by: Daniel Lezcano For exynos_mct and samsung_pwm_timer: Acked-by: Krzysztof Kozlowski For arch/arc: Acked-by: Vineet Gupta For mediatek driver: Acked-by: Matthias Brugger For the Rockchip-part Acked-by: Heiko Stuebner For STi : Acked-by: Patrice Chotard For the mps2-timer.c and versatile.c changes: Acked-by: Liviu Dudau For the OXNAS part : Acked-by: Neil Armstrong For LPC32xx driver: Acked-by: Sylvain Lemieux For Broadcom Kona timer change: Acked-by: Ray Jui For Sun4i and Sun5i: Acked-by: Chen-Yu Tsai For Meson6: Acked-by: Carlo Caione For Keystone: Acked-by: Santosh Shilimkar For NPS: Acked-by: Noam Camus For bcm2835: Acked-by: Eric Anholt diff --git a/arch/arc/kernel/time.c b/arch/arc/kernel/time.c index 09de669..98f22d2 100644 --- a/arch/arc/kernel/time.c +++ b/arch/arc/kernel/time.c @@ -130,7 +130,7 @@ static int __init arc_cs_setup_gfrc(struct device_node *node) return clocksource_register_hz(&arc_counter_gfrc, arc_timer_freq); } -CLOCKSOURCE_OF_DECLARE_RET(arc_gfrc, "snps,archs-timer-gfrc", arc_cs_setup_gfrc); +CLOCKSOURCE_OF_DECLARE(arc_gfrc, "snps,archs-timer-gfrc", arc_cs_setup_gfrc); #endif @@ -192,7 +192,7 @@ static int __init arc_cs_setup_rtc(struct device_node *node) return clocksource_register_hz(&arc_counter_rtc, arc_timer_freq); } -CLOCKSOURCE_OF_DECLARE_RET(arc_rtc, "snps,archs-timer-rtc", arc_cs_setup_rtc); +CLOCKSOURCE_OF_DECLARE(arc_rtc, "snps,archs-timer-rtc", arc_cs_setup_rtc); #endif @@ -379,7 +379,7 @@ static int __init arc_of_timer_init(struct device_node *np) return ret; } -CLOCKSOURCE_OF_DECLARE_RET(arc_clkevt, "snps,arc-timer", arc_of_timer_init); +CLOCKSOURCE_OF_DECLARE(arc_clkevt, "snps,arc-timer", arc_of_timer_init); /* * Called from start_kernel() - boot CPU only diff --git a/arch/arm/kernel/smp_twd.c b/arch/arm/kernel/smp_twd.c index 2b24be4..b6ec65e 100644 --- a/arch/arm/kernel/smp_twd.c +++ b/arch/arm/kernel/smp_twd.c @@ -412,7 +412,7 @@ out: WARN(err, "twd_local_timer_of_register failed (%d)\n", err); return err; } -CLOCKSOURCE_OF_DECLARE_RET(arm_twd_a9, "arm,cortex-a9-twd-timer", twd_local_timer_of_register); -CLOCKSOURCE_OF_DECLARE_RET(arm_twd_a5, "arm,cortex-a5-twd-timer", twd_local_timer_of_register); -CLOCKSOURCE_OF_DECLARE_RET(arm_twd_11mp, "arm,arm11mp-twd-timer", twd_local_timer_of_register); +CLOCKSOURCE_OF_DECLARE(arm_twd_a9, "arm,cortex-a9-twd-timer", twd_local_timer_of_register); +CLOCKSOURCE_OF_DECLARE(arm_twd_a5, "arm,cortex-a5-twd-timer", twd_local_timer_of_register); +CLOCKSOURCE_OF_DECLARE(arm_twd_11mp, "arm,arm11mp-twd-timer", twd_local_timer_of_register); #endif diff --git a/arch/microblaze/kernel/timer.c b/arch/microblaze/kernel/timer.c index 7f35e7b..5bbf38b 100644 --- a/arch/microblaze/kernel/timer.c +++ b/arch/microblaze/kernel/timer.c @@ -332,5 +332,5 @@ static int __init xilinx_timer_init(struct device_node *timer) return 0; } -CLOCKSOURCE_OF_DECLARE_RET(xilinx_timer, "xlnx,xps-timer-1.00.a", +CLOCKSOURCE_OF_DECLARE(xilinx_timer, "xlnx,xps-timer-1.00.a", xilinx_timer_init); diff --git a/arch/mips/ralink/cevt-rt3352.c b/arch/mips/ralink/cevt-rt3352.c index f2d3c79..f24eee0 100644 --- a/arch/mips/ralink/cevt-rt3352.c +++ b/arch/mips/ralink/cevt-rt3352.c @@ -150,4 +150,4 @@ static int __init ralink_systick_init(struct device_node *np) return 0; } -CLOCKSOURCE_OF_DECLARE_RET(systick, "ralink,cevt-systick", ralink_systick_init); +CLOCKSOURCE_OF_DECLARE(systick, "ralink,cevt-systick", ralink_systick_init); diff --git a/arch/nios2/kernel/time.c b/arch/nios2/kernel/time.c index b75e40e..d9563dd 100644 --- a/arch/nios2/kernel/time.c +++ b/arch/nios2/kernel/time.c @@ -352,4 +352,4 @@ void __init time_init(void) clocksource_probe(); } -CLOCKSOURCE_OF_DECLARE_RET(nios2_timer, ALTR_TIMER_COMPATIBLE, nios2_time_init); +CLOCKSOURCE_OF_DECLARE(nios2_timer, ALTR_TIMER_COMPATIBLE, nios2_time_init); diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c index d0cda68..9e33309 100644 --- a/drivers/clocksource/arm_arch_timer.c +++ b/drivers/clocksource/arm_arch_timer.c @@ -784,8 +784,8 @@ static int __init arch_timer_of_init(struct device_node *np) return arch_timer_init(); } -CLOCKSOURCE_OF_DECLARE_RET(armv7_arch_timer, "arm,armv7-timer", arch_timer_of_init); -CLOCKSOURCE_OF_DECLARE_RET(armv8_arch_timer, "arm,armv8-timer", arch_timer_of_init); +CLOCKSOURCE_OF_DECLARE(armv7_arch_timer, "arm,armv7-timer", arch_timer_of_init); +CLOCKSOURCE_OF_DECLARE(armv8_arch_timer, "arm,armv8-timer", arch_timer_of_init); static int __init arch_timer_mem_init(struct device_node *np) { @@ -868,7 +868,7 @@ out: of_node_put(best_frame); return ret; } -CLOCKSOURCE_OF_DECLARE_RET(armv7_arch_timer_mem, "arm,armv7-timer-mem", +CLOCKSOURCE_OF_DECLARE(armv7_arch_timer_mem, "arm,armv7-timer-mem", arch_timer_mem_init); #ifdef CONFIG_ACPI diff --git a/drivers/clocksource/arm_global_timer.c b/drivers/clocksource/arm_global_timer.c index 40104fc..2a9ceb6 100644 --- a/drivers/clocksource/arm_global_timer.c +++ b/drivers/clocksource/arm_global_timer.c @@ -358,5 +358,5 @@ out_unmap: } /* Only tested on r2p2 and r3p0 */ -CLOCKSOURCE_OF_DECLARE_RET(arm_gt, "arm,cortex-a9-global-timer", +CLOCKSOURCE_OF_DECLARE(arm_gt, "arm,cortex-a9-global-timer", global_timer_of_register); diff --git a/drivers/clocksource/armv7m_systick.c b/drivers/clocksource/armv7m_systick.c index 2b55410..e93af1f 100644 --- a/drivers/clocksource/armv7m_systick.c +++ b/drivers/clocksource/armv7m_systick.c @@ -81,5 +81,5 @@ out_unmap: return ret; } -CLOCKSOURCE_OF_DECLARE_RET(arm_systick, "arm,armv7m-systick", +CLOCKSOURCE_OF_DECLARE(arm_systick, "arm,armv7m-systick", system_timer_of_register); diff --git a/drivers/clocksource/asm9260_timer.c b/drivers/clocksource/asm9260_timer.c index d113c02..1ba871b 100644 --- a/drivers/clocksource/asm9260_timer.c +++ b/drivers/clocksource/asm9260_timer.c @@ -238,5 +238,5 @@ static int __init asm9260_timer_init(struct device_node *np) return 0; } -CLOCKSOURCE_OF_DECLARE_RET(asm9260_timer, "alphascale,asm9260-timer", +CLOCKSOURCE_OF_DECLARE(asm9260_timer, "alphascale,asm9260-timer", asm9260_timer_init); diff --git a/drivers/clocksource/bcm2835_timer.c b/drivers/clocksource/bcm2835_timer.c index 2dcf896..e71acf2 100644 --- a/drivers/clocksource/bcm2835_timer.c +++ b/drivers/clocksource/bcm2835_timer.c @@ -142,5 +142,5 @@ static int __init bcm2835_timer_init(struct device_node *node) return 0; } -CLOCKSOURCE_OF_DECLARE_RET(bcm2835, "brcm,bcm2835-system-timer", +CLOCKSOURCE_OF_DECLARE(bcm2835, "brcm,bcm2835-system-timer", bcm2835_timer_init); diff --git a/drivers/clocksource/bcm_kona_timer.c b/drivers/clocksource/bcm_kona_timer.c index c251aa6..86f87be3d 100644 --- a/drivers/clocksource/bcm_kona_timer.c +++ b/drivers/clocksource/bcm_kona_timer.c @@ -195,9 +195,9 @@ static int __init kona_timer_init(struct device_node *node) return 0; } -CLOCKSOURCE_OF_DECLARE_RET(brcm_kona, "brcm,kona-timer", kona_timer_init); +CLOCKSOURCE_OF_DECLARE(brcm_kona, "brcm,kona-timer", kona_timer_init); /* * bcm,kona-timer is deprecated by brcm,kona-timer * being kept here for driver compatibility */ -CLOCKSOURCE_OF_DECLARE_RET(bcm_kona, "bcm,kona-timer", kona_timer_init); +CLOCKSOURCE_OF_DECLARE(bcm_kona, "bcm,kona-timer", kona_timer_init); diff --git a/drivers/clocksource/cadence_ttc_timer.c b/drivers/clocksource/cadence_ttc_timer.c index e2e7631..388a77b 100644 --- a/drivers/clocksource/cadence_ttc_timer.c +++ b/drivers/clocksource/cadence_ttc_timer.c @@ -539,4 +539,4 @@ static int __init ttc_timer_init(struct device_node *timer) return 0; } -CLOCKSOURCE_OF_DECLARE_RET(ttc, "cdns,ttc", ttc_timer_init); +CLOCKSOURCE_OF_DECLARE(ttc, "cdns,ttc", ttc_timer_init); diff --git a/drivers/clocksource/clksrc-dbx500-prcmu.c b/drivers/clocksource/clksrc-dbx500-prcmu.c index 5a59d29..77a365f 100644 --- a/drivers/clocksource/clksrc-dbx500-prcmu.c +++ b/drivers/clocksource/clksrc-dbx500-prcmu.c @@ -86,5 +86,5 @@ static int __init clksrc_dbx500_prcmu_init(struct device_node *node) #endif return clocksource_register_hz(&clocksource_dbx500_prcmu, RATE_32K); } -CLOCKSOURCE_OF_DECLARE_RET(dbx500_prcmu, "stericsson,db8500-prcmu-timer-4", +CLOCKSOURCE_OF_DECLARE(dbx500_prcmu, "stericsson,db8500-prcmu-timer-4", clksrc_dbx500_prcmu_init); diff --git a/drivers/clocksource/clksrc-probe.c b/drivers/clocksource/clksrc-probe.c index 5fa6a55..bc62be9 100644 --- a/drivers/clocksource/clksrc-probe.c +++ b/drivers/clocksource/clksrc-probe.c @@ -20,19 +20,14 @@ #include extern struct of_device_id __clksrc_of_table[]; -extern struct of_device_id __clksrc_ret_of_table[]; static const struct of_device_id __clksrc_of_table_sentinel __used __section(__clksrc_of_table_end); -static const struct of_device_id __clksrc_ret_of_table_sentinel - __used __section(__clksrc_ret_of_table_end); - void __init clocksource_probe(void) { struct device_node *np; const struct of_device_id *match; - of_init_fn_1 init_func; of_init_fn_1_ret init_func_ret; unsigned clocksources = 0; int ret; @@ -41,15 +36,6 @@ void __init clocksource_probe(void) if (!of_device_is_available(np)) continue; - init_func = match->data; - init_func(np); - clocksources++; - } - - for_each_matching_node_and_match(np, __clksrc_ret_of_table, &match) { - if (!of_device_is_available(np)) - continue; - init_func_ret = match->data; ret = init_func_ret(np); diff --git a/drivers/clocksource/clksrc_st_lpc.c b/drivers/clocksource/clksrc_st_lpc.c index c9022a9..03cc492 100644 --- a/drivers/clocksource/clksrc_st_lpc.c +++ b/drivers/clocksource/clksrc_st_lpc.c @@ -132,4 +132,4 @@ static int __init st_clksrc_of_register(struct device_node *np) return ret; } -CLOCKSOURCE_OF_DECLARE_RET(ddata, "st,stih407-lpc", st_clksrc_of_register); +CLOCKSOURCE_OF_DECLARE(ddata, "st,stih407-lpc", st_clksrc_of_register); diff --git a/drivers/clocksource/clps711x-timer.c b/drivers/clocksource/clps711x-timer.c index 3b66198..84aed78 100644 --- a/drivers/clocksource/clps711x-timer.c +++ b/drivers/clocksource/clps711x-timer.c @@ -119,5 +119,5 @@ static int __init clps711x_timer_init(struct device_node *np) return -EINVAL; } } -CLOCKSOURCE_OF_DECLARE_RET(clps711x, "cirrus,clps711x-timer", clps711x_timer_init); +CLOCKSOURCE_OF_DECLARE(clps711x, "cirrus,clps711x-timer", clps711x_timer_init); #endif diff --git a/drivers/clocksource/dw_apb_timer_of.c b/drivers/clocksource/dw_apb_timer_of.c index 4985a2c..aee6c0d 100644 --- a/drivers/clocksource/dw_apb_timer_of.c +++ b/drivers/clocksource/dw_apb_timer_of.c @@ -167,7 +167,7 @@ static int __init dw_apb_timer_init(struct device_node *timer) return 0; } -CLOCKSOURCE_OF_DECLARE_RET(pc3x2_timer, "picochip,pc3x2-timer", dw_apb_timer_init); -CLOCKSOURCE_OF_DECLARE_RET(apb_timer_osc, "snps,dw-apb-timer-osc", dw_apb_timer_init); -CLOCKSOURCE_OF_DECLARE_RET(apb_timer_sp, "snps,dw-apb-timer-sp", dw_apb_timer_init); -CLOCKSOURCE_OF_DECLARE_RET(apb_timer, "snps,dw-apb-timer", dw_apb_timer_init); +CLOCKSOURCE_OF_DECLARE(pc3x2_timer, "picochip,pc3x2-timer", dw_apb_timer_init); +CLOCKSOURCE_OF_DECLARE(apb_timer_osc, "snps,dw-apb-timer-osc", dw_apb_timer_init); +CLOCKSOURCE_OF_DECLARE(apb_timer_sp, "snps,dw-apb-timer-sp", dw_apb_timer_init); +CLOCKSOURCE_OF_DECLARE(apb_timer, "snps,dw-apb-timer", dw_apb_timer_init); diff --git a/drivers/clocksource/exynos_mct.c b/drivers/clocksource/exynos_mct.c index f6caed0..0d18dd4b 100644 --- a/drivers/clocksource/exynos_mct.c +++ b/drivers/clocksource/exynos_mct.c @@ -627,5 +627,5 @@ static int __init mct_init_ppi(struct device_node *np) { return mct_init_dt(np, MCT_INT_PPI); } -CLOCKSOURCE_OF_DECLARE_RET(exynos4210, "samsung,exynos4210-mct", mct_init_spi); -CLOCKSOURCE_OF_DECLARE_RET(exynos4412, "samsung,exynos4412-mct", mct_init_ppi); +CLOCKSOURCE_OF_DECLARE(exynos4210, "samsung,exynos4210-mct", mct_init_spi); +CLOCKSOURCE_OF_DECLARE(exynos4412, "samsung,exynos4412-mct", mct_init_ppi); diff --git a/drivers/clocksource/fsl_ftm_timer.c b/drivers/clocksource/fsl_ftm_timer.c index 9ad4ca3..738515b 100644 --- a/drivers/clocksource/fsl_ftm_timer.c +++ b/drivers/clocksource/fsl_ftm_timer.c @@ -369,4 +369,4 @@ err: kfree(priv); return ret; } -CLOCKSOURCE_OF_DECLARE_RET(flextimer, "fsl,ftm-timer", ftm_timer_init); +CLOCKSOURCE_OF_DECLARE(flextimer, "fsl,ftm-timer", ftm_timer_init); diff --git a/drivers/clocksource/h8300_timer16.c b/drivers/clocksource/h8300_timer16.c index 9d99fc8..07d9d5b 100644 --- a/drivers/clocksource/h8300_timer16.c +++ b/drivers/clocksource/h8300_timer16.c @@ -187,5 +187,5 @@ free_clk: return ret; } -CLOCKSOURCE_OF_DECLARE_RET(h8300_16bit, "renesas,16bit-timer", +CLOCKSOURCE_OF_DECLARE(h8300_16bit, "renesas,16bit-timer", h8300_16timer_init); diff --git a/drivers/clocksource/h8300_timer8.c b/drivers/clocksource/h8300_timer8.c index 0292a19..546bb18 100644 --- a/drivers/clocksource/h8300_timer8.c +++ b/drivers/clocksource/h8300_timer8.c @@ -215,4 +215,4 @@ free_clk: return ret; } -CLOCKSOURCE_OF_DECLARE_RET(h8300_8bit, "renesas,8bit-timer", h8300_8timer_init); +CLOCKSOURCE_OF_DECLARE(h8300_8bit, "renesas,8bit-timer", h8300_8timer_init); diff --git a/drivers/clocksource/h8300_tpu.c b/drivers/clocksource/h8300_tpu.c index 4faf718..7bdf199 100644 --- a/drivers/clocksource/h8300_tpu.c +++ b/drivers/clocksource/h8300_tpu.c @@ -154,4 +154,4 @@ free_clk: return ret; } -CLOCKSOURCE_OF_DECLARE_RET(h8300_tpu, "renesas,tpu", h8300_tpu_init); +CLOCKSOURCE_OF_DECLARE(h8300_tpu, "renesas,tpu", h8300_tpu_init); diff --git a/drivers/clocksource/meson6_timer.c b/drivers/clocksource/meson6_timer.c index 3a6e78f..52af591 100644 --- a/drivers/clocksource/meson6_timer.c +++ b/drivers/clocksource/meson6_timer.c @@ -174,5 +174,5 @@ static int __init meson6_timer_init(struct device_node *node) 1, 0xfffe); return 0; } -CLOCKSOURCE_OF_DECLARE_RET(meson6, "amlogic,meson6-timer", +CLOCKSOURCE_OF_DECLARE(meson6, "amlogic,meson6-timer", meson6_timer_init); diff --git a/drivers/clocksource/mips-gic-timer.c b/drivers/clocksource/mips-gic-timer.c index b164b87..1572c7a 100644 --- a/drivers/clocksource/mips-gic-timer.c +++ b/drivers/clocksource/mips-gic-timer.c @@ -222,5 +222,5 @@ static void __init gic_clocksource_of_init(struct device_node *node) return 0; } -CLOCKSOURCE_OF_DECLARE_RET(mips_gic_timer, "mti,gic-timer", +CLOCKSOURCE_OF_DECLARE(mips_gic_timer, "mti,gic-timer", gic_clocksource_of_init); diff --git a/drivers/clocksource/moxart_timer.c b/drivers/clocksource/moxart_timer.c index b9c30cd..8414544 100644 --- a/drivers/clocksource/moxart_timer.c +++ b/drivers/clocksource/moxart_timer.c @@ -178,4 +178,4 @@ static int __init moxart_timer_init(struct device_node *node) return 0; } -CLOCKSOURCE_OF_DECLARE_RET(moxart, "moxa,moxart-timer", moxart_timer_init); +CLOCKSOURCE_OF_DECLARE(moxart, "moxa,moxart-timer", moxart_timer_init); diff --git a/drivers/clocksource/mps2-timer.c b/drivers/clocksource/mps2-timer.c index c303fa9..3e4431e 100644 --- a/drivers/clocksource/mps2-timer.c +++ b/drivers/clocksource/mps2-timer.c @@ -274,4 +274,4 @@ static int __init mps2_timer_init(struct device_node *np) return 0; } -CLOCKSOURCE_OF_DECLARE_RET(mps2_timer, "arm,mps2-timer", mps2_timer_init); +CLOCKSOURCE_OF_DECLARE(mps2_timer, "arm,mps2-timer", mps2_timer_init); diff --git a/drivers/clocksource/mtk_timer.c b/drivers/clocksource/mtk_timer.c index 432a2c0..9065949 100644 --- a/drivers/clocksource/mtk_timer.c +++ b/drivers/clocksource/mtk_timer.c @@ -265,4 +265,4 @@ err_kzalloc: return -EINVAL; } -CLOCKSOURCE_OF_DECLARE_RET(mtk_mt6577, "mediatek,mt6577-timer", mtk_timer_init); +CLOCKSOURCE_OF_DECLARE(mtk_mt6577, "mediatek,mt6577-timer", mtk_timer_init); diff --git a/drivers/clocksource/mxs_timer.c b/drivers/clocksource/mxs_timer.c index 17b9d19..630a8d3 100644 --- a/drivers/clocksource/mxs_timer.c +++ b/drivers/clocksource/mxs_timer.c @@ -295,4 +295,4 @@ static int __init mxs_timer_init(struct device_node *np) return setup_irq(irq, &mxs_timer_irq); } -CLOCKSOURCE_OF_DECLARE_RET(mxs, "fsl,timrot", mxs_timer_init); +CLOCKSOURCE_OF_DECLARE(mxs, "fsl,timrot", mxs_timer_init); diff --git a/drivers/clocksource/nomadik-mtu.c b/drivers/clocksource/nomadik-mtu.c index d2be5b3..3c124d1 100644 --- a/drivers/clocksource/nomadik-mtu.c +++ b/drivers/clocksource/nomadik-mtu.c @@ -284,5 +284,5 @@ static int __init nmdk_timer_of_init(struct device_node *node) return nmdk_timer_init(base, irq, pclk, clk); } -CLOCKSOURCE_OF_DECLARE_RET(nomadik_mtu, "st,nomadik-mtu", +CLOCKSOURCE_OF_DECLARE(nomadik_mtu, "st,nomadik-mtu", nmdk_timer_of_init); diff --git a/drivers/clocksource/pxa_timer.c b/drivers/clocksource/pxa_timer.c index 59af75c..937e10b 100644 --- a/drivers/clocksource/pxa_timer.c +++ b/drivers/clocksource/pxa_timer.c @@ -213,7 +213,7 @@ static int __init pxa_timer_dt_init(struct device_node *np) return pxa_timer_common_init(irq, clk_get_rate(clk)); } -CLOCKSOURCE_OF_DECLARE_RET(pxa_timer, "marvell,pxa-timer", pxa_timer_dt_init); +CLOCKSOURCE_OF_DECLARE(pxa_timer, "marvell,pxa-timer", pxa_timer_dt_init); /* * Legacy timer init for non device-tree boards. diff --git a/drivers/clocksource/qcom-timer.c b/drivers/clocksource/qcom-timer.c index 79f73bd..6625763 100644 --- a/drivers/clocksource/qcom-timer.c +++ b/drivers/clocksource/qcom-timer.c @@ -273,5 +273,5 @@ static int __init msm_dt_timer_init(struct device_node *np) return msm_timer_init(freq, 32, irq, !!percpu_offset); } -CLOCKSOURCE_OF_DECLARE_RET(kpss_timer, "qcom,kpss-timer", msm_dt_timer_init); -CLOCKSOURCE_OF_DECLARE_RET(scss_timer, "qcom,scss-timer", msm_dt_timer_init); +CLOCKSOURCE_OF_DECLARE(kpss_timer, "qcom,kpss-timer", msm_dt_timer_init); +CLOCKSOURCE_OF_DECLARE(scss_timer, "qcom,scss-timer", msm_dt_timer_init); diff --git a/drivers/clocksource/rockchip_timer.c b/drivers/clocksource/rockchip_timer.c index 85aee69..23e267a 100644 --- a/drivers/clocksource/rockchip_timer.c +++ b/drivers/clocksource/rockchip_timer.c @@ -205,7 +205,7 @@ static int __init rk3399_timer_init(struct device_node *np) return rk_timer_init(np, TIMER_CONTROL_REG3399); } -CLOCKSOURCE_OF_DECLARE_RET(rk3288_timer, "rockchip,rk3288-timer", - rk3288_timer_init); -CLOCKSOURCE_OF_DECLARE_RET(rk3399_timer, "rockchip,rk3399-timer", - rk3399_timer_init); +CLOCKSOURCE_OF_DECLARE(rk3288_timer, "rockchip,rk3288-timer", + rk3288_timer_init); +CLOCKSOURCE_OF_DECLARE(rk3399_timer, "rockchip,rk3399-timer", + rk3399_timer_init); diff --git a/drivers/clocksource/samsung_pwm_timer.c b/drivers/clocksource/samsung_pwm_timer.c index 27a9797..54565bd 100644 --- a/drivers/clocksource/samsung_pwm_timer.c +++ b/drivers/clocksource/samsung_pwm_timer.c @@ -466,7 +466,7 @@ static int __init s3c2410_pwm_clocksource_init(struct device_node *np) { return samsung_pwm_alloc(np, &s3c24xx_variant); } -CLOCKSOURCE_OF_DECLARE_RET(s3c2410_pwm, "samsung,s3c2410-pwm", s3c2410_pwm_clocksource_init); +CLOCKSOURCE_OF_DECLARE(s3c2410_pwm, "samsung,s3c2410-pwm", s3c2410_pwm_clocksource_init); static const struct samsung_pwm_variant s3c64xx_variant = { .bits = 32, @@ -479,7 +479,7 @@ static int __init s3c64xx_pwm_clocksource_init(struct device_node *np) { return samsung_pwm_alloc(np, &s3c64xx_variant); } -CLOCKSOURCE_OF_DECLARE_RET(s3c6400_pwm, "samsung,s3c6400-pwm", s3c64xx_pwm_clocksource_init); +CLOCKSOURCE_OF_DECLARE(s3c6400_pwm, "samsung,s3c6400-pwm", s3c64xx_pwm_clocksource_init); static const struct samsung_pwm_variant s5p64x0_variant = { .bits = 32, @@ -492,7 +492,7 @@ static int __init s5p64x0_pwm_clocksource_init(struct device_node *np) { return samsung_pwm_alloc(np, &s5p64x0_variant); } -CLOCKSOURCE_OF_DECLARE_RET(s5p6440_pwm, "samsung,s5p6440-pwm", s5p64x0_pwm_clocksource_init); +CLOCKSOURCE_OF_DECLARE(s5p6440_pwm, "samsung,s5p6440-pwm", s5p64x0_pwm_clocksource_init); static const struct samsung_pwm_variant s5p_variant = { .bits = 32, @@ -505,5 +505,5 @@ static int __init s5p_pwm_clocksource_init(struct device_node *np) { return samsung_pwm_alloc(np, &s5p_variant); } -CLOCKSOURCE_OF_DECLARE_RET(s5pc100_pwm, "samsung,s5pc100-pwm", s5p_pwm_clocksource_init); +CLOCKSOURCE_OF_DECLARE(s5pc100_pwm, "samsung,s5pc100-pwm", s5p_pwm_clocksource_init); #endif diff --git a/drivers/clocksource/sun4i_timer.c b/drivers/clocksource/sun4i_timer.c index 4453730..97669ee 100644 --- a/drivers/clocksource/sun4i_timer.c +++ b/drivers/clocksource/sun4i_timer.c @@ -226,5 +226,5 @@ static int __init sun4i_timer_init(struct device_node *node) return ret; } -CLOCKSOURCE_OF_DECLARE_RET(sun4i, "allwinner,sun4i-a10-timer", +CLOCKSOURCE_OF_DECLARE(sun4i, "allwinner,sun4i-a10-timer", sun4i_timer_init); diff --git a/drivers/clocksource/tango_xtal.c b/drivers/clocksource/tango_xtal.c index 7dc716c..12fcef8 100644 --- a/drivers/clocksource/tango_xtal.c +++ b/drivers/clocksource/tango_xtal.c @@ -53,4 +53,4 @@ static int __init tango_clocksource_init(struct device_node *np) return 0; } -CLOCKSOURCE_OF_DECLARE_RET(tango, "sigma,tick-counter", tango_clocksource_init); +CLOCKSOURCE_OF_DECLARE(tango, "sigma,tick-counter", tango_clocksource_init); diff --git a/drivers/clocksource/tegra20_timer.c b/drivers/clocksource/tegra20_timer.c index 543c37e..f960891 100644 --- a/drivers/clocksource/tegra20_timer.c +++ b/drivers/clocksource/tegra20_timer.c @@ -237,7 +237,7 @@ static int __init tegra20_init_timer(struct device_node *np) return 0; } -CLOCKSOURCE_OF_DECLARE_RET(tegra20_timer, "nvidia,tegra20-timer", tegra20_init_timer); +CLOCKSOURCE_OF_DECLARE(tegra20_timer, "nvidia,tegra20-timer", tegra20_init_timer); static int __init tegra20_init_rtc(struct device_node *np) { @@ -261,4 +261,4 @@ static int __init tegra20_init_rtc(struct device_node *np) return register_persistent_clock(NULL, tegra_read_persistent_clock64); } -CLOCKSOURCE_OF_DECLARE_RET(tegra20_rtc, "nvidia,tegra20-rtc", tegra20_init_rtc); +CLOCKSOURCE_OF_DECLARE(tegra20_rtc, "nvidia,tegra20-rtc", tegra20_init_rtc); diff --git a/drivers/clocksource/time-armada-370-xp.c b/drivers/clocksource/time-armada-370-xp.c index bc4ab48..a4e5923 100644 --- a/drivers/clocksource/time-armada-370-xp.c +++ b/drivers/clocksource/time-armada-370-xp.c @@ -371,7 +371,7 @@ static int __init armada_xp_timer_init(struct device_node *np) return armada_370_xp_timer_common_init(np); } -CLOCKSOURCE_OF_DECLARE_RET(armada_xp, "marvell,armada-xp-timer", +CLOCKSOURCE_OF_DECLARE(armada_xp, "marvell,armada-xp-timer", armada_xp_timer_init); static int __init armada_375_timer_init(struct device_node *np) @@ -409,7 +409,7 @@ static int __init armada_375_timer_init(struct device_node *np) return armada_370_xp_timer_common_init(np); } -CLOCKSOURCE_OF_DECLARE_RET(armada_375, "marvell,armada-375-timer", +CLOCKSOURCE_OF_DECLARE(armada_375, "marvell,armada-375-timer", armada_375_timer_init); static int __init armada_370_timer_init(struct device_node *np) @@ -432,5 +432,5 @@ static int __init armada_370_timer_init(struct device_node *np) return armada_370_xp_timer_common_init(np); } -CLOCKSOURCE_OF_DECLARE_RET(armada_370, "marvell,armada-370-timer", +CLOCKSOURCE_OF_DECLARE(armada_370, "marvell,armada-370-timer", armada_370_timer_init); diff --git a/drivers/clocksource/time-efm32.c b/drivers/clocksource/time-efm32.c index 6e2f79f..5ac344b 100644 --- a/drivers/clocksource/time-efm32.c +++ b/drivers/clocksource/time-efm32.c @@ -283,5 +283,5 @@ static int __init efm32_timer_init(struct device_node *np) return ret; } -CLOCKSOURCE_OF_DECLARE_RET(efm32compat, "efm32,timer", efm32_timer_init); -CLOCKSOURCE_OF_DECLARE_RET(efm32, "energymicro,efm32-timer", efm32_timer_init); +CLOCKSOURCE_OF_DECLARE(efm32compat, "efm32,timer", efm32_timer_init); +CLOCKSOURCE_OF_DECLARE(efm32, "energymicro,efm32-timer", efm32_timer_init); diff --git a/drivers/clocksource/time-lpc32xx.c b/drivers/clocksource/time-lpc32xx.c index cb5b866..9649cfd 100644 --- a/drivers/clocksource/time-lpc32xx.c +++ b/drivers/clocksource/time-lpc32xx.c @@ -311,4 +311,4 @@ static int __init lpc32xx_timer_init(struct device_node *np) return ret; } -CLOCKSOURCE_OF_DECLARE_RET(lpc32xx_timer, "nxp,lpc3220-timer", lpc32xx_timer_init); +CLOCKSOURCE_OF_DECLARE(lpc32xx_timer, "nxp,lpc3220-timer", lpc32xx_timer_init); diff --git a/drivers/clocksource/time-orion.c b/drivers/clocksource/time-orion.c index 5fdeb5d..a28f496 100644 --- a/drivers/clocksource/time-orion.c +++ b/drivers/clocksource/time-orion.c @@ -167,4 +167,4 @@ static int __init orion_timer_init(struct device_node *np) return 0; } -CLOCKSOURCE_OF_DECLARE_RET(orion_timer, "marvell,orion-timer", orion_timer_init); +CLOCKSOURCE_OF_DECLARE(orion_timer, "marvell,orion-timer", orion_timer_init); diff --git a/drivers/clocksource/time-pistachio.c b/drivers/clocksource/time-pistachio.c index adaaec5..a7d9a08 100644 --- a/drivers/clocksource/time-pistachio.c +++ b/drivers/clocksource/time-pistachio.c @@ -214,5 +214,5 @@ static int __init pistachio_clksrc_of_init(struct device_node *node) sched_clock_register(pistachio_read_sched_clock, 32, rate); return clocksource_register_hz(&pcs_gpt.cs, rate); } -CLOCKSOURCE_OF_DECLARE_RET(pistachio_gptimer, "img,pistachio-gptimer", +CLOCKSOURCE_OF_DECLARE(pistachio_gptimer, "img,pistachio-gptimer", pistachio_clksrc_of_init); diff --git a/drivers/clocksource/timer-atlas7.c b/drivers/clocksource/timer-atlas7.c index 7b1a007..90f8fbc 100644 --- a/drivers/clocksource/timer-atlas7.c +++ b/drivers/clocksource/timer-atlas7.c @@ -304,4 +304,4 @@ static int __init sirfsoc_of_timer_init(struct device_node *np) return sirfsoc_atlas7_timer_init(np); } -CLOCKSOURCE_OF_DECLARE_RET(sirfsoc_atlas7_timer, "sirf,atlas7-tick", sirfsoc_of_timer_init); +CLOCKSOURCE_OF_DECLARE(sirfsoc_atlas7_timer, "sirf,atlas7-tick", sirfsoc_of_timer_init); diff --git a/drivers/clocksource/timer-atmel-pit.c b/drivers/clocksource/timer-atmel-pit.c index ffaca7c..1ffac0c 100644 --- a/drivers/clocksource/timer-atmel-pit.c +++ b/drivers/clocksource/timer-atmel-pit.c @@ -270,5 +270,5 @@ static int __init at91sam926x_pit_dt_init(struct device_node *node) return at91sam926x_pit_common_init(data); } -CLOCKSOURCE_OF_DECLARE_RET(at91sam926x_pit, "atmel,at91sam9260-pit", +CLOCKSOURCE_OF_DECLARE(at91sam926x_pit, "atmel,at91sam9260-pit", at91sam926x_pit_dt_init); diff --git a/drivers/clocksource/timer-atmel-st.c b/drivers/clocksource/timer-atmel-st.c index e9331d3..e90ab5b 100644 --- a/drivers/clocksource/timer-atmel-st.c +++ b/drivers/clocksource/timer-atmel-st.c @@ -260,5 +260,5 @@ static int __init atmel_st_timer_init(struct device_node *node) /* register clocksource */ return clocksource_register_hz(&clk32k, sclk_rate); } -CLOCKSOURCE_OF_DECLARE_RET(atmel_st_timer, "atmel,at91rm9200-st", +CLOCKSOURCE_OF_DECLARE(atmel_st_timer, "atmel,at91rm9200-st", atmel_st_timer_init); diff --git a/drivers/clocksource/timer-digicolor.c b/drivers/clocksource/timer-digicolor.c index b929061..10318cc 100644 --- a/drivers/clocksource/timer-digicolor.c +++ b/drivers/clocksource/timer-digicolor.c @@ -202,5 +202,5 @@ static int __init digicolor_timer_init(struct device_node *node) return 0; } -CLOCKSOURCE_OF_DECLARE_RET(conexant_digicolor, "cnxt,cx92755-timer", +CLOCKSOURCE_OF_DECLARE(conexant_digicolor, "cnxt,cx92755-timer", digicolor_timer_init); diff --git a/drivers/clocksource/timer-imx-gpt.c b/drivers/clocksource/timer-imx-gpt.c index d5640a74..f595460 100644 --- a/drivers/clocksource/timer-imx-gpt.c +++ b/drivers/clocksource/timer-imx-gpt.c @@ -545,15 +545,15 @@ static int __init imx6dl_timer_init_dt(struct device_node *np) return mxc_timer_init_dt(np, GPT_TYPE_IMX6DL); } -CLOCKSOURCE_OF_DECLARE_RET(imx1_timer, "fsl,imx1-gpt", imx1_timer_init_dt); -CLOCKSOURCE_OF_DECLARE_RET(imx21_timer, "fsl,imx21-gpt", imx21_timer_init_dt); -CLOCKSOURCE_OF_DECLARE_RET(imx27_timer, "fsl,imx27-gpt", imx21_timer_init_dt); -CLOCKSOURCE_OF_DECLARE_RET(imx31_timer, "fsl,imx31-gpt", imx31_timer_init_dt); -CLOCKSOURCE_OF_DECLARE_RET(imx25_timer, "fsl,imx25-gpt", imx31_timer_init_dt); -CLOCKSOURCE_OF_DECLARE_RET(imx50_timer, "fsl,imx50-gpt", imx31_timer_init_dt); -CLOCKSOURCE_OF_DECLARE_RET(imx51_timer, "fsl,imx51-gpt", imx31_timer_init_dt); -CLOCKSOURCE_OF_DECLARE_RET(imx53_timer, "fsl,imx53-gpt", imx31_timer_init_dt); -CLOCKSOURCE_OF_DECLARE_RET(imx6q_timer, "fsl,imx6q-gpt", imx31_timer_init_dt); -CLOCKSOURCE_OF_DECLARE_RET(imx6dl_timer, "fsl,imx6dl-gpt", imx6dl_timer_init_dt); -CLOCKSOURCE_OF_DECLARE_RET(imx6sl_timer, "fsl,imx6sl-gpt", imx6dl_timer_init_dt); -CLOCKSOURCE_OF_DECLARE_RET(imx6sx_timer, "fsl,imx6sx-gpt", imx6dl_timer_init_dt); +CLOCKSOURCE_OF_DECLARE(imx1_timer, "fsl,imx1-gpt", imx1_timer_init_dt); +CLOCKSOURCE_OF_DECLARE(imx21_timer, "fsl,imx21-gpt", imx21_timer_init_dt); +CLOCKSOURCE_OF_DECLARE(imx27_timer, "fsl,imx27-gpt", imx21_timer_init_dt); +CLOCKSOURCE_OF_DECLARE(imx31_timer, "fsl,imx31-gpt", imx31_timer_init_dt); +CLOCKSOURCE_OF_DECLARE(imx25_timer, "fsl,imx25-gpt", imx31_timer_init_dt); +CLOCKSOURCE_OF_DECLARE(imx50_timer, "fsl,imx50-gpt", imx31_timer_init_dt); +CLOCKSOURCE_OF_DECLARE(imx51_timer, "fsl,imx51-gpt", imx31_timer_init_dt); +CLOCKSOURCE_OF_DECLARE(imx53_timer, "fsl,imx53-gpt", imx31_timer_init_dt); +CLOCKSOURCE_OF_DECLARE(imx6q_timer, "fsl,imx6q-gpt", imx31_timer_init_dt); +CLOCKSOURCE_OF_DECLARE(imx6dl_timer, "fsl,imx6dl-gpt", imx6dl_timer_init_dt); +CLOCKSOURCE_OF_DECLARE(imx6sl_timer, "fsl,imx6sl-gpt", imx6dl_timer_init_dt); +CLOCKSOURCE_OF_DECLARE(imx6sx_timer, "fsl,imx6sx-gpt", imx6dl_timer_init_dt); diff --git a/drivers/clocksource/timer-integrator-ap.c b/drivers/clocksource/timer-integrator-ap.c index 675face..df6e672 100644 --- a/drivers/clocksource/timer-integrator-ap.c +++ b/drivers/clocksource/timer-integrator-ap.c @@ -232,5 +232,5 @@ static int __init integrator_ap_timer_init_of(struct device_node *node) return 0; } -CLOCKSOURCE_OF_DECLARE_RET(integrator_ap_timer, "arm,integrator-timer", +CLOCKSOURCE_OF_DECLARE(integrator_ap_timer, "arm,integrator-timer", integrator_ap_timer_init_of); diff --git a/drivers/clocksource/timer-keystone.c b/drivers/clocksource/timer-keystone.c index 4199823..ab68a47 100644 --- a/drivers/clocksource/timer-keystone.c +++ b/drivers/clocksource/timer-keystone.c @@ -226,5 +226,5 @@ err: return error; } -CLOCKSOURCE_OF_DECLARE_RET(keystone_timer, "ti,keystone-timer", +CLOCKSOURCE_OF_DECLARE(keystone_timer, "ti,keystone-timer", keystone_timer_init); diff --git a/drivers/clocksource/timer-nps.c b/drivers/clocksource/timer-nps.c index b5c7b2b..70c149a 100644 --- a/drivers/clocksource/timer-nps.c +++ b/drivers/clocksource/timer-nps.c @@ -96,5 +96,5 @@ static int __init nps_timer_init(struct device_node *node) return nps_setup_clocksource(node, clk); } -CLOCKSOURCE_OF_DECLARE_RET(ezchip_nps400_clksrc, "ezchip,nps400-timer", - nps_timer_init); +CLOCKSOURCE_OF_DECLARE(ezchip_nps400_clksrc, "ezchip,nps400-timer", + nps_timer_init); diff --git a/drivers/clocksource/timer-oxnas-rps.c b/drivers/clocksource/timer-oxnas-rps.c index 0d99f40..bd887e2 100644 --- a/drivers/clocksource/timer-oxnas-rps.c +++ b/drivers/clocksource/timer-oxnas-rps.c @@ -293,5 +293,5 @@ err_alloc: return ret; } -CLOCKSOURCE_OF_DECLARE_RET(ox810se_rps, - "oxsemi,ox810se-rps-timer", oxnas_rps_timer_init); +CLOCKSOURCE_OF_DECLARE(ox810se_rps, + "oxsemi,ox810se-rps-timer", oxnas_rps_timer_init); diff --git a/drivers/clocksource/timer-prima2.c b/drivers/clocksource/timer-prima2.c index 7b1084d..dae8a66 100644 --- a/drivers/clocksource/timer-prima2.c +++ b/drivers/clocksource/timer-prima2.c @@ -246,5 +246,5 @@ static int __init sirfsoc_prima2_timer_init(struct device_node *np) return 0; } -CLOCKSOURCE_OF_DECLARE_RET(sirfsoc_prima2_timer, +CLOCKSOURCE_OF_DECLARE(sirfsoc_prima2_timer, "sirf,prima2-tick", sirfsoc_prima2_timer_init); diff --git a/drivers/clocksource/timer-sp804.c b/drivers/clocksource/timer-sp804.c index 3dc47ef..d078633 100644 --- a/drivers/clocksource/timer-sp804.c +++ b/drivers/clocksource/timer-sp804.c @@ -287,7 +287,7 @@ err: iounmap(base); return ret; } -CLOCKSOURCE_OF_DECLARE_RET(sp804, "arm,sp804", sp804_of_init); +CLOCKSOURCE_OF_DECLARE(sp804, "arm,sp804", sp804_of_init); static int __init integrator_cp_of_init(struct device_node *np) { @@ -335,4 +335,4 @@ err: iounmap(base); return ret; } -CLOCKSOURCE_OF_DECLARE_RET(intcp, "arm,integrator-cp-timer", integrator_cp_of_init); +CLOCKSOURCE_OF_DECLARE(intcp, "arm,integrator-cp-timer", integrator_cp_of_init); diff --git a/drivers/clocksource/timer-stm32.c b/drivers/clocksource/timer-stm32.c index d5bf352..1b2574c 100644 --- a/drivers/clocksource/timer-stm32.c +++ b/drivers/clocksource/timer-stm32.c @@ -187,4 +187,4 @@ err_clk_get: return ret; } -CLOCKSOURCE_OF_DECLARE_RET(stm32, "st,stm32-timer", stm32_clockevent_init); +CLOCKSOURCE_OF_DECLARE(stm32, "st,stm32-timer", stm32_clockevent_init); diff --git a/drivers/clocksource/timer-sun5i.c b/drivers/clocksource/timer-sun5i.c index f0a3ffb..c184eb8 100644 --- a/drivers/clocksource/timer-sun5i.c +++ b/drivers/clocksource/timer-sun5i.c @@ -346,7 +346,7 @@ static int __init sun5i_timer_init(struct device_node *node) return sun5i_setup_clockevent(node, timer_base, clk, irq); } -CLOCKSOURCE_OF_DECLARE_RET(sun5i_a13, "allwinner,sun5i-a13-hstimer", +CLOCKSOURCE_OF_DECLARE(sun5i_a13, "allwinner,sun5i-a13-hstimer", sun5i_timer_init); -CLOCKSOURCE_OF_DECLARE_RET(sun7i_a20, "allwinner,sun7i-a20-hstimer", +CLOCKSOURCE_OF_DECLARE(sun7i_a20, "allwinner,sun7i-a20-hstimer", sun5i_timer_init); diff --git a/drivers/clocksource/timer-ti-32k.c b/drivers/clocksource/timer-ti-32k.c index e4ad3c6e..92b7e39 100644 --- a/drivers/clocksource/timer-ti-32k.c +++ b/drivers/clocksource/timer-ti-32k.c @@ -124,5 +124,5 @@ static int __init ti_32k_timer_init(struct device_node *np) return 0; } -CLOCKSOURCE_OF_DECLARE_RET(ti_32k_timer, "ti,omap-counter32k", +CLOCKSOURCE_OF_DECLARE(ti_32k_timer, "ti,omap-counter32k", ti_32k_timer_init); diff --git a/drivers/clocksource/timer-u300.c b/drivers/clocksource/timer-u300.c index a6a0dec..704e40c 100644 --- a/drivers/clocksource/timer-u300.c +++ b/drivers/clocksource/timer-u300.c @@ -458,5 +458,5 @@ static int __init u300_timer_init_of(struct device_node *np) return 0; } -CLOCKSOURCE_OF_DECLARE_RET(u300_timer, "stericsson,u300-apptimer", +CLOCKSOURCE_OF_DECLARE(u300_timer, "stericsson,u300-apptimer", u300_timer_init_of); diff --git a/drivers/clocksource/versatile.c b/drivers/clocksource/versatile.c index 8daeffa..220b490 100644 --- a/drivers/clocksource/versatile.c +++ b/drivers/clocksource/versatile.c @@ -38,7 +38,7 @@ static int __init versatile_sched_clock_init(struct device_node *node) return 0; } -CLOCKSOURCE_OF_DECLARE_RET(vexpress, "arm,vexpress-sysreg", +CLOCKSOURCE_OF_DECLARE(vexpress, "arm,vexpress-sysreg", versatile_sched_clock_init); -CLOCKSOURCE_OF_DECLARE_RET(versatile, "arm,versatile-sysreg", +CLOCKSOURCE_OF_DECLARE(versatile, "arm,versatile-sysreg", versatile_sched_clock_init); diff --git a/drivers/clocksource/vf_pit_timer.c b/drivers/clocksource/vf_pit_timer.c index ca4dff4..55d8d84 100644 --- a/drivers/clocksource/vf_pit_timer.c +++ b/drivers/clocksource/vf_pit_timer.c @@ -201,4 +201,4 @@ static int __init pit_timer_init(struct device_node *np) return pit_clockevent_init(clk_rate, irq); } -CLOCKSOURCE_OF_DECLARE_RET(vf610, "fsl,vf610-pit", pit_timer_init); +CLOCKSOURCE_OF_DECLARE(vf610, "fsl,vf610-pit", pit_timer_init); diff --git a/drivers/clocksource/vt8500_timer.c b/drivers/clocksource/vt8500_timer.c index 1bc8707..b150694 100644 --- a/drivers/clocksource/vt8500_timer.c +++ b/drivers/clocksource/vt8500_timer.c @@ -165,4 +165,4 @@ static int __init vt8500_timer_init(struct device_node *np) return 0; } -CLOCKSOURCE_OF_DECLARE_RET(vt8500, "via,vt8500-timer", vt8500_timer_init); +CLOCKSOURCE_OF_DECLARE(vt8500, "via,vt8500-timer", vt8500_timer_init); diff --git a/drivers/clocksource/zevio-timer.c b/drivers/clocksource/zevio-timer.c index cb4cf05..9a53f5e 100644 --- a/drivers/clocksource/zevio-timer.c +++ b/drivers/clocksource/zevio-timer.c @@ -215,4 +215,4 @@ static int __init zevio_timer_init(struct device_node *node) return zevio_timer_add(node); } -CLOCKSOURCE_OF_DECLARE_RET(zevio_timer, "lsi,zevio-timer", zevio_timer_init); +CLOCKSOURCE_OF_DECLARE(zevio_timer, "lsi,zevio-timer", zevio_timer_init); diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h index 8c6c626..6a67ab9 100644 --- a/include/asm-generic/vmlinux.lds.h +++ b/include/asm-generic/vmlinux.lds.h @@ -173,7 +173,6 @@ *(__##name##_of_table_end) #define CLKSRC_OF_TABLES() OF_TABLE(CONFIG_CLKSRC_OF, clksrc) -#define CLKSRC_RET_OF_TABLES() OF_TABLE(CONFIG_CLKSRC_OF, clksrc_ret) #define IRQCHIP_OF_MATCH_TABLE() OF_TABLE(CONFIG_IRQCHIP, irqchip) #define CLK_OF_TABLES() OF_TABLE(CONFIG_COMMON_CLK, clk) #define IOMMU_OF_TABLES() OF_TABLE(CONFIG_OF_IOMMU, iommu) @@ -532,7 +531,6 @@ CLK_OF_TABLES() \ RESERVEDMEM_OF_TABLES() \ CLKSRC_OF_TABLES() \ - CLKSRC_RET_OF_TABLES() \ IOMMU_OF_TABLES() \ CPU_METHOD_OF_TABLES() \ CPUIDLE_METHOD_OF_TABLES() \ diff --git a/include/linux/clocksource.h b/include/linux/clocksource.h index 15c3839..0839818 100644 --- a/include/linux/clocksource.h +++ b/include/linux/clocksource.h @@ -244,10 +244,7 @@ extern int clocksource_mmio_init(void __iomem *, const char *, extern int clocksource_i8253_init(void); #define CLOCKSOURCE_OF_DECLARE(name, compat, fn) \ - OF_DECLARE_1(clksrc, name, compat, fn) - -#define CLOCKSOURCE_OF_DECLARE_RET(name, compat, fn) \ - OF_DECLARE_1_RET(clksrc_ret, name, compat, fn) + OF_DECLARE_1_RET(clksrc, name, compat, fn) #ifdef CONFIG_CLKSRC_PROBE extern void clocksource_probe(void); -- cgit v0.10.2 From b81ea968706bdb5c2f2af62c5700573a32ab310a Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Thu, 2 Jun 2016 22:44:49 +0200 Subject: clk: Add missing clk_get_sys() stub When compiling with the COMPILE_TEST option set, the clps711x does not compile because of the clk_get_sys() noop stub missing. Signed-off-by: Daniel Lezcano Reviewed-by: Michael Turquette diff --git a/include/linux/clk.h b/include/linux/clk.h index 0df4a51..834179f 100644 --- a/include/linux/clk.h +++ b/include/linux/clk.h @@ -461,6 +461,10 @@ static inline struct clk *clk_get_parent(struct clk *clk) return NULL; } +static inline struct clk *clk_get_sys(const char *dev_id, const char *con_id) +{ + return NULL; +} #endif /* clk_prepare_enable helps cases using clk_enable in non-atomic context. */ -- cgit v0.10.2 From 40e878aaa5d4afd0d2f018b1034b46322c420330 Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Thu, 2 Jun 2016 22:59:34 +0200 Subject: clocksource/drivers/bcm_kona: Remove useless header The driver includes the header but it is pointless. Remove it. Signed-off-by: Daniel Lezcano diff --git a/drivers/clocksource/bcm_kona_timer.c b/drivers/clocksource/bcm_kona_timer.c index 86f87be3d..7e3fd37 100644 --- a/drivers/clocksource/bcm_kona_timer.c +++ b/drivers/clocksource/bcm_kona_timer.c @@ -20,7 +20,6 @@ #include #include -#include #include #include -- cgit v0.10.2 From 2ea879a7cf544e05c7cd0bfd569857ec2a8a75a9 Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Thu, 2 Jun 2016 18:35:38 +0200 Subject: clocksource/drivers/bcm2835: Add the COMPILE_TEST option Change the Kconfig option logic to fullfil with the current approach. A new Kconfig option is added, CONFIG_BCM2835_TIMER and is selected by the platform. Then the clocksource's Kconfig is changed to make this option selectable by the user if the COMPILE_TEST option is set. Otherwise, it is up to the platform's Kconfig to select the timer. Signed-off-by: Daniel Lezcano diff --git a/arch/arm/mach-bcm/Kconfig b/arch/arm/mach-bcm/Kconfig index 68ab641..1284ce1 100644 --- a/arch/arm/mach-bcm/Kconfig +++ b/arch/arm/mach-bcm/Kconfig @@ -143,6 +143,7 @@ config ARCH_BCM2835 select ARM_TIMER_SP804 select HAVE_ARM_ARCH_TIMER if ARCH_MULTI_V7 select CLKSRC_OF + select BCM2835_TIMER select PINCTRL select PINCTRL_BCM2835 help diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig index d4b9e04..0275b16 100644 --- a/drivers/clocksource/Kconfig +++ b/drivers/clocksource/Kconfig @@ -27,6 +27,13 @@ config CLKBLD_I8253 config CLKSRC_MMIO bool +config BCM2835_TIMER + bool "BCM2835 timer driver" if COMPILE_TEST + depends on GENERIC_CLOCKEVENTS + select CLKSRC_MMIO + help + Enables the support for the BCM2835 timer driver. + config DIGICOLOR_TIMER bool "Digicolor timer driver" if COMPILE_TEST depends on GENERIC_CLOCKEVENTS diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile index bc66981..008d8a0 100644 --- a/drivers/clocksource/Makefile +++ b/drivers/clocksource/Makefile @@ -19,7 +19,7 @@ obj-$(CONFIG_CLKSRC_NOMADIK_MTU) += nomadik-mtu.o obj-$(CONFIG_CLKSRC_DBX500_PRCMU) += clksrc-dbx500-prcmu.o obj-$(CONFIG_ARMADA_370_XP_TIMER) += time-armada-370-xp.o obj-$(CONFIG_ORION_TIMER) += time-orion.o -obj-$(CONFIG_ARCH_BCM2835) += bcm2835_timer.o +obj-$(CONFIG_BCM2835_TIMER) += bcm2835_timer.o obj-$(CONFIG_ARCH_CLPS711X) += clps711x-timer.o obj-$(CONFIG_ARCH_ATLAS7) += timer-atlas7.o obj-$(CONFIG_ARCH_MOXART) += moxart_timer.o -- cgit v0.10.2 From e2146d8650764638784205cf51378f01bbd098b6 Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Thu, 2 Jun 2016 18:41:52 +0200 Subject: clocksource/drivers/armv7m_systick: Add the COMPILE_TEST option In order to increase the compilation test coverage, add the COMPILE_TEST so the driver can be compiled even if it does not belong to the platform or the architecture. The io.h header inclusion is also added as it the driver does not compile on UM platform. Signed-off-by: Daniel Lezcano diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig index 0275b16..01ecd88 100644 --- a/drivers/clocksource/Kconfig +++ b/drivers/clocksource/Kconfig @@ -250,7 +250,7 @@ config CLKSRC_ARM_GLOBAL_TIMER_SCHED_CLOCK Use ARM global timer clock source as sched_clock config ARMV7M_SYSTICK - bool + bool "Support for the ARMv7M system time" if COMPILE_TEST select CLKSRC_OF if OF select CLKSRC_MMIO help diff --git a/drivers/clocksource/armv7m_systick.c b/drivers/clocksource/armv7m_systick.c index e93af1f..a315491 100644 --- a/drivers/clocksource/armv7m_systick.c +++ b/drivers/clocksource/armv7m_systick.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include -- cgit v0.10.2 From 1cad71e35f88bd41b954e9984c7d2a8ce3924db0 Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Thu, 2 Jun 2016 19:20:36 +0200 Subject: clocksource/drivers/bcm_kona: Add the COMPILE_TEST option Change the Kconfig option logic to fullfil with the current approach. A new Kconfig option is added, CONFIG_BCM_KONA_TIMER and is selected by the platform. Then the clocksource's Kconfig is changed to make this option selectable by the user if the COMPILE_TEST option is set. Otherwise, it is up to the platform's Kconfig to select the timer. Signed-off-by: Daniel Lezcano diff --git a/arch/arm/mach-bcm/Kconfig b/arch/arm/mach-bcm/Kconfig index 1284ce1..4f1709b 100644 --- a/arch/arm/mach-bcm/Kconfig +++ b/arch/arm/mach-bcm/Kconfig @@ -89,6 +89,7 @@ config ARCH_BCM_MOBILE select HAVE_ARM_ARCH_TIMER select PINCTRL select ARCH_BCM_MOBILE_SMP if SMP + select BCM_KONA_TIMER help This enables support for systems based on Broadcom mobile SoCs. diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig index 01ecd88..a3cccf5 100644 --- a/drivers/clocksource/Kconfig +++ b/drivers/clocksource/Kconfig @@ -34,6 +34,13 @@ config BCM2835_TIMER help Enables the support for the BCM2835 timer driver. +config BCM_KONA_TIMER + bool "BCM mobile timer driver" if COMPILE_TEST + depends on GENERIC_CLOCKEVENTS + select CLKSRC_MMIO + help + Enables the support for the BCM Kona mobile timer driver. + config DIGICOLOR_TIMER bool "Digicolor timer driver" if COMPILE_TEST depends on GENERIC_CLOCKEVENTS diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile index 008d8a0..df99c92 100644 --- a/drivers/clocksource/Makefile +++ b/drivers/clocksource/Makefile @@ -33,7 +33,7 @@ obj-$(CONFIG_MESON6_TIMER) += meson6_timer.o obj-$(CONFIG_TEGRA_TIMER) += tegra20_timer.o obj-$(CONFIG_VT8500_TIMER) += vt8500_timer.o obj-$(CONFIG_ARCH_NSPIRE) += zevio-timer.o -obj-$(CONFIG_ARCH_BCM_MOBILE) += bcm_kona_timer.o +obj-$(CONFIG_BCM_KONA_TIMER) += bcm_kona_timer.o obj-$(CONFIG_CADENCE_TTC_TIMER) += cadence_ttc_timer.o obj-$(CONFIG_CLKSRC_EFM32) += time-efm32.o obj-$(CONFIG_CLKSRC_STM32) += timer-stm32.o -- cgit v0.10.2 From ecf0efdc98cd46886fa119492f052ab3eaba9ddf Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Thu, 2 Jun 2016 20:06:54 +0200 Subject: clocksource/drivers/clps_711x: Add the COMPILE_TEST option Change the Kconfig option logic to fullfil with the current approach. A new Kconfig option is added, CONFIG_CLPS711X_TIMER and is selected by the platform. Then the clocksource's Kconfig is changed to make this option selectable by the user if the COMPILE_TEST option is set. Otherwise, it is up to the platform's Kconfig to select the timer. Signed-off-by: Daniel Lezcano diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 90542db..f0636ec9 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -358,10 +358,10 @@ config ARCH_CLPS711X bool "Cirrus Logic CLPS711x/EP721x/EP731x-based" select ARCH_REQUIRE_GPIOLIB select AUTO_ZRELADDR - select CLKSRC_MMIO select COMMON_CLK select CPU_ARM720T select GENERIC_CLOCKEVENTS + select CLPS711X_TIMER select MFD_SYSCON select SOC_BUS help diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig index a3cccf5..f41eef2 100644 --- a/drivers/clocksource/Kconfig +++ b/drivers/clocksource/Kconfig @@ -155,6 +155,13 @@ config CLKSRC_DBX500_PRCMU help Use the always on PRCMU Timer as clocksource +config CLPS711X_TIMER + bool "Cirrus logic timer driver" if COMPILE_TEST + depends on GENERIC_CLOCKEVENTS + select CLKSRC_MMIO + help + Enables support for the Cirrus Logic PS711 timer. + config CLKSRC_DBX500_PRCMU_SCHED_CLOCK bool "Clocksource PRCMU Timer sched_clock" depends on (CLKSRC_DBX500_PRCMU && !CLKSRC_NOMADIK_MTU_SCHED_CLOCK) diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile index df99c92..25e599c 100644 --- a/drivers/clocksource/Makefile +++ b/drivers/clocksource/Makefile @@ -20,7 +20,7 @@ obj-$(CONFIG_CLKSRC_DBX500_PRCMU) += clksrc-dbx500-prcmu.o obj-$(CONFIG_ARMADA_370_XP_TIMER) += time-armada-370-xp.o obj-$(CONFIG_ORION_TIMER) += time-orion.o obj-$(CONFIG_BCM2835_TIMER) += bcm2835_timer.o -obj-$(CONFIG_ARCH_CLPS711X) += clps711x-timer.o +obj-$(CONFIG_CLPS711X_TIMER) += clps711x-timer.o obj-$(CONFIG_ARCH_ATLAS7) += timer-atlas7.o obj-$(CONFIG_ARCH_MOXART) += moxart_timer.o obj-$(CONFIG_ARCH_MXS) += mxs_timer.o -- cgit v0.10.2 From b56d5d218499404b2abfd6f33a6d480312bf8a92 Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Fri, 3 Jun 2016 13:11:39 +0200 Subject: clocksource/drivers/atlas7: Add the COMPILE_TEST option Change the Kconfig option logic to fullfil with the current approach. A new Kconfig option is added, CONFIG_ATLAS7_TIMER and is selected by the platform. Then the clocksource's Kconfig is changed to make this option selectable by the user if the COMPILE_TEST option is set. Otherwise, it is up to the platform's Kconfig to select the timer. Signed-off-by: Daniel Lezcano diff --git a/arch/arm/mach-prima2/Kconfig b/arch/arm/mach-prima2/Kconfig index 0cf4426..2db8d24 100644 --- a/arch/arm/mach-prima2/Kconfig +++ b/arch/arm/mach-prima2/Kconfig @@ -28,6 +28,7 @@ config ARCH_ATLAS7 default y select ARM_GIC select CPU_V7 + select ATLAS7_TIMER select HAVE_ARM_SCU if SMP select HAVE_SMP help diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig index f41eef2..669dd3c 100644 --- a/drivers/clocksource/Kconfig +++ b/drivers/clocksource/Kconfig @@ -162,6 +162,13 @@ config CLPS711X_TIMER help Enables support for the Cirrus Logic PS711 timer. +config ATLAS7_TIMER + bool "Atlas7 timer driver" if COMPILE_TEST + depends on GENERIC_CLOCKEVENTS + select CLKSRC_MMIO + help + Enables support for the Atlas7 timer. + config CLKSRC_DBX500_PRCMU_SCHED_CLOCK bool "Clocksource PRCMU Timer sched_clock" depends on (CLKSRC_DBX500_PRCMU && !CLKSRC_NOMADIK_MTU_SCHED_CLOCK) diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile index 25e599c..7abf144 100644 --- a/drivers/clocksource/Makefile +++ b/drivers/clocksource/Makefile @@ -21,7 +21,7 @@ obj-$(CONFIG_ARMADA_370_XP_TIMER) += time-armada-370-xp.o obj-$(CONFIG_ORION_TIMER) += time-orion.o obj-$(CONFIG_BCM2835_TIMER) += bcm2835_timer.o obj-$(CONFIG_CLPS711X_TIMER) += clps711x-timer.o -obj-$(CONFIG_ARCH_ATLAS7) += timer-atlas7.o +obj-$(CONFIG_ATLAS7_TIMER) += timer-atlas7.o obj-$(CONFIG_ARCH_MOXART) += moxart_timer.o obj-$(CONFIG_ARCH_MXS) += mxs_timer.o obj-$(CONFIG_CLKSRC_PXA) += pxa_timer.o -- cgit v0.10.2 From 419be9e36cf2349f15d0b7280ba46be6f9da7a61 Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Fri, 3 Jun 2016 13:29:03 +0200 Subject: clocksource/drivers/moxart: Add the COMPILE_TEST option Change the Kconfig option logic to fullfil with the current approach. A new Kconfig option is added, CONFIG_MOXART_TIMER and is selected by the platform. Then the clocksource's Kconfig is changed to make this option selectable by the user if the COMPILE_TEST option is set. Otherwise, it is up to the platform's Kconfig to select the timer. Signed-off-by: Daniel Lezcano diff --git a/arch/arm/mach-moxart/Kconfig b/arch/arm/mach-moxart/Kconfig index 180d9d2..ddc79ce 100644 --- a/arch/arm/mach-moxart/Kconfig +++ b/arch/arm/mach-moxart/Kconfig @@ -3,7 +3,7 @@ menuconfig ARCH_MOXART depends on ARCH_MULTI_V4 select CPU_FA526 select ARM_DMA_MEM_BUFFERABLE - select CLKSRC_MMIO + select MOXART_TIMER select GENERIC_IRQ_CHIP select ARCH_REQUIRE_GPIOLIB select PHYLIB if NETDEVICES diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig index 669dd3c..db2c5ff 100644 --- a/drivers/clocksource/Kconfig +++ b/drivers/clocksource/Kconfig @@ -169,6 +169,13 @@ config ATLAS7_TIMER help Enables support for the Atlas7 timer. +config MOXART_TIMER + bool "Moxart timer driver" if COMPILE_TEST + depends on GENERIC_CLOCKEVENTS + select CLKSRC_MMIO + help + Enables support for the Moxart timer. + config CLKSRC_DBX500_PRCMU_SCHED_CLOCK bool "Clocksource PRCMU Timer sched_clock" depends on (CLKSRC_DBX500_PRCMU && !CLKSRC_NOMADIK_MTU_SCHED_CLOCK) diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile index 7abf144..e64e37a 100644 --- a/drivers/clocksource/Makefile +++ b/drivers/clocksource/Makefile @@ -22,7 +22,7 @@ obj-$(CONFIG_ORION_TIMER) += time-orion.o obj-$(CONFIG_BCM2835_TIMER) += bcm2835_timer.o obj-$(CONFIG_CLPS711X_TIMER) += clps711x-timer.o obj-$(CONFIG_ATLAS7_TIMER) += timer-atlas7.o -obj-$(CONFIG_ARCH_MOXART) += moxart_timer.o +obj-$(CONFIG_MOXART_TIMER) += moxart_timer.o obj-$(CONFIG_ARCH_MXS) += mxs_timer.o obj-$(CONFIG_CLKSRC_PXA) += pxa_timer.o obj-$(CONFIG_ARCH_PRIMA2) += timer-prima2.o -- cgit v0.10.2 From 6e525044c716aedf92f41893f00417d557a872d2 Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Fri, 3 Jun 2016 13:35:33 +0200 Subject: clocksource/drivers/mxs: Remove useless header The driver includes the header but it is pointless. Remove it. Signed-off-by: Daniel Lezcano diff --git a/drivers/clocksource/mxs_timer.c b/drivers/clocksource/mxs_timer.c index 630a8d3..0ba0a91 100644 --- a/drivers/clocksource/mxs_timer.c +++ b/drivers/clocksource/mxs_timer.c @@ -31,8 +31,6 @@ #include #include -#include - /* * There are 2 versions of the timrot on Freescale MXS-based SoCs. * The v1 on MX23 only gets 16 bits counter, while v2 on MX28 -- cgit v0.10.2 From d81c50a0360f8a186150b9bb572d5e0514c25ce9 Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Fri, 3 Jun 2016 13:36:18 +0200 Subject: clocksource/drivers/mxs: Add the COMPILE_TEST option Change the Kconfig option logic to fullfil with the current approach. A new Kconfig option is added, CONFIG_MXS_TIMER and is selected by the platform. Then the clocksource's Kconfig is changed to make this option selectable by the user if the COMPILE_TEST option is set. Otherwise, it is up to the platform's Kconfig to select the timer. Signed-off-by: Daniel Lezcano diff --git a/arch/arm/mach-mxs/Kconfig b/arch/arm/mach-mxs/Kconfig index 8479413..68a3a9e 100644 --- a/arch/arm/mach-mxs/Kconfig +++ b/arch/arm/mach-mxs/Kconfig @@ -16,7 +16,7 @@ config ARCH_MXS bool "Freescale MXS (i.MX23, i.MX28) support" depends on ARCH_MULTI_V5 select ARCH_REQUIRE_GPIOLIB - select CLKSRC_MMIO + select MXS_TIMER select PINCTRL select SOC_BUS select SOC_IMX23 diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig index db2c5ff..5d70cdf 100644 --- a/drivers/clocksource/Kconfig +++ b/drivers/clocksource/Kconfig @@ -176,6 +176,14 @@ config MOXART_TIMER help Enables support for the Moxart timer. +config MXS_TIMER + bool "Mxs timer driver" if COMPILE_TEST + depends on GENERIC_CLOCKEVENTS + select CLKSRC_MMIO + select STMP_DEVICE + help + Enables support for the Mxs timer. + config CLKSRC_DBX500_PRCMU_SCHED_CLOCK bool "Clocksource PRCMU Timer sched_clock" depends on (CLKSRC_DBX500_PRCMU && !CLKSRC_NOMADIK_MTU_SCHED_CLOCK) diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile index e64e37a..1360bba 100644 --- a/drivers/clocksource/Makefile +++ b/drivers/clocksource/Makefile @@ -23,7 +23,7 @@ obj-$(CONFIG_BCM2835_TIMER) += bcm2835_timer.o obj-$(CONFIG_CLPS711X_TIMER) += clps711x-timer.o obj-$(CONFIG_ATLAS7_TIMER) += timer-atlas7.o obj-$(CONFIG_MOXART_TIMER) += moxart_timer.o -obj-$(CONFIG_ARCH_MXS) += mxs_timer.o +obj-$(CONFIG_MXS_TIMER) += mxs_timer.o obj-$(CONFIG_CLKSRC_PXA) += pxa_timer.o obj-$(CONFIG_ARCH_PRIMA2) += timer-prima2.o obj-$(CONFIG_ARCH_U300) += timer-u300.o -- cgit v0.10.2 From 4929409b202ac3dbfb657b0e3edeffaab2856c2b Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Fri, 3 Jun 2016 13:43:58 +0200 Subject: clocksource/drivers/prima2: Remove useless header The driver includes the header but it is pointless. Remove it. Signed-off-by: Daniel Lezcano diff --git a/drivers/clocksource/timer-prima2.c b/drivers/clocksource/timer-prima2.c index dae8a66..c32148e 100644 --- a/drivers/clocksource/timer-prima2.c +++ b/drivers/clocksource/timer-prima2.c @@ -19,7 +19,6 @@ #include #include #include -#include #define PRIMA2_CLOCK_FREQ 1000000 -- cgit v0.10.2 From f3550d499576c423db0d902930cf8d848fe09744 Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Fri, 3 Jun 2016 14:28:38 +0200 Subject: clocksource/drivers/prima2: Add the COMPILE_TEST option Change the Kconfig option logic to fullfil with the current approach. A new Kconfig option is added, CONFIG_PRIMA2_TIMER and is selected by the platform. Then the clocksource's Kconfig is changed to make this option selectable by the user if the COMPILE_TEST option is set. Otherwise, it is up to the platform's Kconfig to select the timer. Signed-off-by: Daniel Lezcano diff --git a/arch/arm/mach-prima2/Kconfig b/arch/arm/mach-prima2/Kconfig index 2db8d24..9e938f2 100644 --- a/arch/arm/mach-prima2/Kconfig +++ b/arch/arm/mach-prima2/Kconfig @@ -39,6 +39,7 @@ config ARCH_PRIMA2 default y select SIRF_IRQ select ZONE_DMA + select PRIMA2_TIMER help Support for CSR SiRFSoC ARM Cortex A9 Platform diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig index 5d70cdf..c350fbd 100644 --- a/drivers/clocksource/Kconfig +++ b/drivers/clocksource/Kconfig @@ -184,6 +184,13 @@ config MXS_TIMER help Enables support for the Mxs timer. +config PRIMA2_TIMER + bool "Prima2 timer driver" if COMPILE_TEST + depends on GENERIC_CLOCKEVENTS + select CLKSRC_MMIO + help + Enables support for the Prima2 timer. + config CLKSRC_DBX500_PRCMU_SCHED_CLOCK bool "Clocksource PRCMU Timer sched_clock" depends on (CLKSRC_DBX500_PRCMU && !CLKSRC_NOMADIK_MTU_SCHED_CLOCK) diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile index 1360bba..b419d5d 100644 --- a/drivers/clocksource/Makefile +++ b/drivers/clocksource/Makefile @@ -25,7 +25,7 @@ obj-$(CONFIG_ATLAS7_TIMER) += timer-atlas7.o obj-$(CONFIG_MOXART_TIMER) += moxart_timer.o obj-$(CONFIG_MXS_TIMER) += mxs_timer.o obj-$(CONFIG_CLKSRC_PXA) += pxa_timer.o -obj-$(CONFIG_ARCH_PRIMA2) += timer-prima2.o +obj-$(CONFIG_PRIMA2_TIMER) += timer-prima2.o obj-$(CONFIG_ARCH_U300) += timer-u300.o obj-$(CONFIG_SUN4I_TIMER) += sun4i_timer.o obj-$(CONFIG_SUN5I_HSTIMER) += timer-sun5i.o -- cgit v0.10.2 From 85f98db4adbbd3ec6b41537d31241b59bf47c66f Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Fri, 3 Jun 2016 14:31:16 +0200 Subject: clocksource/drivers/u300: Add the COMPILE_TEST option Change the Kconfig option logic to fullfil with the current approach. A new Kconfig option is added, CONFIG_U300_TIMER and is selected by the platform. Then the clocksource's Kconfig is changed to make this option selectable by the user if the COMPILE_TEST option is set. Otherwise, it is up to the platform's Kconfig to select the timer. Due on the delay specific code, this driver will compile only on the ARM architecture. Signed-off-by: Daniel Lezcano diff --git a/arch/arm/mach-u300/Kconfig b/arch/arm/mach-u300/Kconfig index 301a984..4fdc342 100644 --- a/arch/arm/mach-u300/Kconfig +++ b/arch/arm/mach-u300/Kconfig @@ -4,7 +4,7 @@ menuconfig ARCH_U300 select ARCH_REQUIRE_GPIOLIB select ARM_AMBA select ARM_VIC - select CLKSRC_MMIO + select U300_TIMER select CPU_ARM926T select HAVE_TCM select PINCTRL diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig index c350fbd..d425f80 100644 --- a/drivers/clocksource/Kconfig +++ b/drivers/clocksource/Kconfig @@ -191,6 +191,14 @@ config PRIMA2_TIMER help Enables support for the Prima2 timer. +config U300_TIMER + bool "U300 timer driver" if COMPILE_TEST + depends on GENERIC_CLOCKEVENTS + depends on ARM + select CLKSRC_MMIO + help + Enables support for the U300 timer. + config CLKSRC_DBX500_PRCMU_SCHED_CLOCK bool "Clocksource PRCMU Timer sched_clock" depends on (CLKSRC_DBX500_PRCMU && !CLKSRC_NOMADIK_MTU_SCHED_CLOCK) diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile index b419d5d..adbc3a8 100644 --- a/drivers/clocksource/Makefile +++ b/drivers/clocksource/Makefile @@ -26,7 +26,7 @@ obj-$(CONFIG_MOXART_TIMER) += moxart_timer.o obj-$(CONFIG_MXS_TIMER) += mxs_timer.o obj-$(CONFIG_CLKSRC_PXA) += pxa_timer.o obj-$(CONFIG_PRIMA2_TIMER) += timer-prima2.o -obj-$(CONFIG_ARCH_U300) += timer-u300.o +obj-$(CONFIG_U300_TIMER) += timer-u300.o obj-$(CONFIG_SUN4I_TIMER) += sun4i_timer.o obj-$(CONFIG_SUN5I_HSTIMER) += timer-sun5i.o obj-$(CONFIG_MESON6_TIMER) += meson6_timer.o -- cgit v0.10.2 From d683b9dcc8a8d743f7b660ff3b77ccfbe652e4b9 Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Fri, 3 Jun 2016 15:03:21 +0200 Subject: clocksource/drivers/nspire: Add the COMPILE_TEST option Change the Kconfig option logic to fullfil with the current approach. A new Kconfig option is added, CONFIG_NSPIRE_TIMER and is selected by the platform. Then the clocksource's Kconfig is changed to make this option selectable by the user if the COMPILE_TEST option is set. Otherwise, it is up to the platform's Kconfig to select the timer. Signed-off-by: Daniel Lezcano diff --git a/arch/arm/mach-nspire/Kconfig b/arch/arm/mach-nspire/Kconfig index bc41f26..d498530 100644 --- a/arch/arm/mach-nspire/Kconfig +++ b/arch/arm/mach-nspire/Kconfig @@ -7,5 +7,6 @@ config ARCH_NSPIRE select ARM_AMBA select ARM_VIC select ARM_TIMER_SP804 + select NSPIRE_TIMER help This enables support for systems using the TI-NSPIRE CPU diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig index d425f80..0cfc4bf 100644 --- a/drivers/clocksource/Kconfig +++ b/drivers/clocksource/Kconfig @@ -199,6 +199,13 @@ config U300_TIMER help Enables support for the U300 timer. +config NSPIRE_TIMER + bool "NSpire timer driver" if COMPILE_TEST + depends on GENERIC_CLOCKEVENTS + select CLKSRC_MMIO + help + Enables support for the Nspire timer. + config CLKSRC_DBX500_PRCMU_SCHED_CLOCK bool "Clocksource PRCMU Timer sched_clock" depends on (CLKSRC_DBX500_PRCMU && !CLKSRC_NOMADIK_MTU_SCHED_CLOCK) diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile index adbc3a8..d888c98 100644 --- a/drivers/clocksource/Makefile +++ b/drivers/clocksource/Makefile @@ -32,7 +32,7 @@ obj-$(CONFIG_SUN5I_HSTIMER) += timer-sun5i.o obj-$(CONFIG_MESON6_TIMER) += meson6_timer.o obj-$(CONFIG_TEGRA_TIMER) += tegra20_timer.o obj-$(CONFIG_VT8500_TIMER) += vt8500_timer.o -obj-$(CONFIG_ARCH_NSPIRE) += zevio-timer.o +obj-$(CONFIG_NSPIRE_TIMER) += zevio-timer.o obj-$(CONFIG_BCM_KONA_TIMER) += bcm_kona_timer.o obj-$(CONFIG_CADENCE_TTC_TIMER) += cadence_ttc_timer.o obj-$(CONFIG_CLKSRC_EFM32) += time-efm32.o -- cgit v0.10.2 From c12547a00dfd3aaacfd5ce362ee4b9585c320054 Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Fri, 3 Jun 2016 15:05:05 +0200 Subject: clocksource/drivers/keystone: Add the COMPILE_TEST option Change the Kconfig option logic to fullfil with the current approach. A new Kconfig option is added, CONFIG_KEYSTONE_TIMER and is selected by the platform. Then the clocksource's Kconfig is changed to make this option selectable by the user if the COMPILE_TEST option is set. Otherwise, it is up to the platform's Kconfig to select the timer. Signed-off-by: Daniel Lezcano diff --git a/arch/arm/mach-keystone/Kconfig b/arch/arm/mach-keystone/Kconfig index ea955f6db..bac577b 100644 --- a/arch/arm/mach-keystone/Kconfig +++ b/arch/arm/mach-keystone/Kconfig @@ -4,7 +4,7 @@ config ARCH_KEYSTONE depends on ARM_PATCH_PHYS_VIRT select ARM_GIC select HAVE_ARM_ARCH_TIMER - select CLKSRC_MMIO + select KEYSTONE_TIMER select ARM_ERRATA_798181 if SMP select COMMON_CLK_KEYSTONE select ARCH_SUPPORTS_BIG_ENDIAN diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig index 0cfc4bf..7e5709a 100644 --- a/drivers/clocksource/Kconfig +++ b/drivers/clocksource/Kconfig @@ -206,6 +206,14 @@ config NSPIRE_TIMER help Enables support for the Nspire timer. +config KEYSTONE_TIMER + bool "Keystone timer driver" if COMPILE_TEST + depends on GENERIC_CLOCKEVENTS + depends on ARM || ARM64 + select CLKSRC_MMIO + help + Enables support for the Keystone timer. + config CLKSRC_DBX500_PRCMU_SCHED_CLOCK bool "Clocksource PRCMU Timer sched_clock" depends on (CLKSRC_DBX500_PRCMU && !CLKSRC_NOMADIK_MTU_SCHED_CLOCK) diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile index d888c98..a818431 100644 --- a/drivers/clocksource/Makefile +++ b/drivers/clocksource/Makefile @@ -56,7 +56,7 @@ obj-$(CONFIG_ARMV7M_SYSTICK) += armv7m_systick.o obj-$(CONFIG_ARM_TIMER_SP804) += timer-sp804.o obj-$(CONFIG_CLKSRC_METAG_GENERIC) += metag_generic.o obj-$(CONFIG_ARCH_HAS_TICK_BROADCAST) += dummy_timer.o -obj-$(CONFIG_ARCH_KEYSTONE) += timer-keystone.o +obj-$(CONFIG_KEYSTONE_TIMER) += timer-keystone.o obj-$(CONFIG_ARCH_INTEGRATOR_AP) += timer-integrator-ap.o obj-$(CONFIG_CLKSRC_VERSATILE) += versatile.o obj-$(CONFIG_CLKSRC_MIPS_GIC) += mips-gic-timer.o -- cgit v0.10.2 From 568c0342e494fa4c05377c6c83c653afa350985a Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Fri, 3 Jun 2016 15:11:21 +0200 Subject: clocksource/drivers/integrator-ap: Add the COMPILE_TEST option Change the Kconfig option logic to fullfil with the current approach. A new Kconfig option is added, CONFIG_INTEGRATOR_AP_TIMER and is selected by the platform. Then the clocksource's Kconfig is changed to make this option selectable by the user if the COMPILE_TEST option is set. Otherwise, it is up to the platform's Kconfig to select the timer. Signed-off-by: Daniel Lezcano diff --git a/arch/arm/mach-integrator/Kconfig b/arch/arm/mach-integrator/Kconfig index b2a85ba..291262e 100644 --- a/arch/arm/mach-integrator/Kconfig +++ b/arch/arm/mach-integrator/Kconfig @@ -20,7 +20,7 @@ if ARCH_INTEGRATOR config ARCH_INTEGRATOR_AP bool "Support Integrator/AP and Integrator/PP2 platforms" - select CLKSRC_MMIO + select INTEGRATOR_AP_TIMER select MIGHT_HAVE_PCI select SERIAL_AMBA_PL010 if TTY select SERIAL_AMBA_PL010_CONSOLE if TTY diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig index 7e5709a..8055b37 100644 --- a/drivers/clocksource/Kconfig +++ b/drivers/clocksource/Kconfig @@ -214,6 +214,13 @@ config KEYSTONE_TIMER help Enables support for the Keystone timer. +config INTEGRATOR_AP_TIMER + bool "Integrator-ap timer driver" if COMPILE_TEST + depends on GENERIC_CLOCKEVENTS + select CLKSRC_MMIO + help + Enables support for the Integrator-ap timer. + config CLKSRC_DBX500_PRCMU_SCHED_CLOCK bool "Clocksource PRCMU Timer sched_clock" depends on (CLKSRC_DBX500_PRCMU && !CLKSRC_NOMADIK_MTU_SCHED_CLOCK) diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile index a818431..fd9d6df 100644 --- a/drivers/clocksource/Makefile +++ b/drivers/clocksource/Makefile @@ -57,7 +57,7 @@ obj-$(CONFIG_ARM_TIMER_SP804) += timer-sp804.o obj-$(CONFIG_CLKSRC_METAG_GENERIC) += metag_generic.o obj-$(CONFIG_ARCH_HAS_TICK_BROADCAST) += dummy_timer.o obj-$(CONFIG_KEYSTONE_TIMER) += timer-keystone.o -obj-$(CONFIG_ARCH_INTEGRATOR_AP) += timer-integrator-ap.o +obj-$(CONFIG_INTEGRATOR_AP_TIMER) += timer-integrator-ap.o obj-$(CONFIG_CLKSRC_VERSATILE) += versatile.o obj-$(CONFIG_CLKSRC_MIPS_GIC) += mips-gic-timer.o obj-$(CONFIG_CLKSRC_TANGO_XTAL) += tango_xtal.o -- cgit v0.10.2 From 67a87a43b9117029446bea6397675bc6f7725a5a Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Mon, 6 Jun 2016 14:34:28 +0200 Subject: clocksource/drivers/arm_global_timer: Add the COMPILE_TEST option Change the Kconfig option logic to fullfil with the current approach, allowing the user to compile the driver on different platforms. Signed-off-by: Daniel Lezcano diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig index 8055b37..1711079 100644 --- a/drivers/clocksource/Kconfig +++ b/drivers/clocksource/Kconfig @@ -304,8 +304,9 @@ config ARM_ARCH_TIMER_EVTSTREAM hardware anomalies of missing events. config ARM_GLOBAL_TIMER - bool + bool "Support for the ARM global timer" if COMPILE_TEST select CLKSRC_OF if OF + depends on ARM help This options enables support for the ARM global timer unit -- cgit v0.10.2 From b988d3f085f07deca70ba8b90f77a84af8a334a3 Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Mon, 6 Jun 2016 19:08:39 +0200 Subject: clocksource/drivers/timer-atmel-st: Add the COMPILE_TEST option Change the Kconfig option logic to fullfil with the current approach, allowing the user to compile the driver on different platforms. Signed-off-by: Daniel Lezcano diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig index 1711079..3086e74 100644 --- a/drivers/clocksource/Kconfig +++ b/drivers/clocksource/Kconfig @@ -335,9 +335,12 @@ config ATMEL_PIT def_bool SOC_AT91SAM9 || SOC_SAMA5 config ATMEL_ST - bool + bool "Atmel ST timer support" if COMPILE_TEST + depends on GENERIC_CLOCKEVENTS select CLKSRC_OF select MFD_SYSCON + help + Support for the Atmel ST timer. config CLKSRC_METAG_GENERIC def_bool y if METAG -- cgit v0.10.2 From 5cc87a4df5009c1cbe9e087ad16c0bacdae06809 Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Tue, 7 Jun 2016 11:05:01 +0200 Subject: clocksource/drivers/versatile: Add the COMPILE_TEST option Change the Kconfig option logic to fullfil with the current approach, allowing the user to compile the driver on different platforms. The current option let the user to select the clocksource or not. The Kconfig option policy is to let the platform to select the timer automatically. Add the COMPILE_TEST option, so the prompt to select the driver will be showed only when COMPILE_TEST is set and will let this driver to compile on different platform, thus increasing the compilation test coverage. Signed-off-by: Daniel Lezcano diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig index 3086e74..7acdf3d 100644 --- a/drivers/clocksource/Kconfig +++ b/drivers/clocksource/Kconfig @@ -453,8 +453,8 @@ config CLKSRC_QCOM Qualcomm SoCs. config CLKSRC_VERSATILE - bool "ARM Versatile (Express) reference platforms clock source" - depends on PLAT_VERSATILE && GENERIC_SCHED_CLOCK && !ARCH_USES_GETTIMEOFFSET + bool "ARM Versatile (Express) reference platforms clock source" if COMPILE_TEST + depends on GENERIC_SCHED_CLOCK && !ARCH_USES_GETTIMEOFFSET select CLKSRC_OF default y if MFD_VEXPRESS_SYSREG help -- cgit v0.10.2 From 46fd5c6b3059462131caa4d52691c9c5666c3223 Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Mon, 27 Jun 2016 17:30:13 +0100 Subject: clocksource/drivers/arm_arch_timer: Control the evtstrm via the cmdline Disabling the eventstream can be useful for both remotely debugging a deployed production system and development of code using WFE-based polling loops. Whilst this can currently be controlled via a Kconfig option (CONFIG_ARM_ARCH_TIMER_EVTSTREAM), it's often desirable to toggle the feature on the command line, so this patch adds a new command-line option ("clocksource.arm_arch_timer.evtstrm") to do just that. The default behaviour is determined based on CONFIG_ARM_ARCH_TIMER_EVTSTREAM. Cc: Marc Zyngier Cc: Mark Rutland Signed-off-by: Will Deacon Signed-off-by: Daniel Lezcano diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index 82b42c9..2c92f1d 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -687,6 +687,14 @@ bytes respectively. Such letter suffixes can also be entirely omitted. [SPARC64] tick [X86-64] hpet,tsc + clocksource.arm_arch_timer.evtstrm= + [ARM,ARM64] + Format: + Enable/disable the eventstream feature of the ARM + architected timer so that code using WFE-based polling + loops can be debugged more effectively on production + systems. + clearcpuid=BITNUM [X86] Disable CPUID feature X for the kernel. See arch/x86/include/asm/cpufeatures.h for the valid bit diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig index 7acdf3d..5677886 100644 --- a/drivers/clocksource/Kconfig +++ b/drivers/clocksource/Kconfig @@ -288,14 +288,16 @@ config ARM_ARCH_TIMER select CLKSRC_ACPI if ACPI config ARM_ARCH_TIMER_EVTSTREAM - bool "Support for ARM architected timer event stream generation" + bool "Enable ARM architected timer event stream generation by default" default y if ARM_ARCH_TIMER depends on ARM_ARCH_TIMER help - This option enables support for event stream generation based on - the ARM architected timer. It is used for waking up CPUs executing - the wfe instruction at a frequency represented as a power-of-2 - divisor of the clock rate. + This option enables support by default for event stream generation + based on the ARM architected timer. It is used for waking up CPUs + executing the wfe instruction at a frequency represented as a + power-of-2 divisor of the clock rate. The behaviour can also be + overridden on the command line using the + clocksource.arm_arch_timer.evtstream parameter. The main use of the event stream is wfe-based timeouts of userspace locking implementations. It might also be useful for imposing timeout on wfe to safeguard against any programming errors in case an expected diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c index 9e33309..5effd30 100644 --- a/drivers/clocksource/arm_arch_timer.c +++ b/drivers/clocksource/arm_arch_timer.c @@ -79,6 +79,14 @@ static enum ppi_nr arch_timer_uses_ppi = VIRT_PPI; static bool arch_timer_c3stop; static bool arch_timer_mem_use_virtual; +static bool evtstrm_enable = IS_ENABLED(CONFIG_ARM_ARCH_TIMER_EVTSTREAM); + +static int __init early_evtstrm_cfg(char *buf) +{ + return strtobool(buf, &evtstrm_enable); +} +early_param("clocksource.arm_arch_timer.evtstrm", early_evtstrm_cfg); + /* * Architected system timer support. */ @@ -372,7 +380,7 @@ static int arch_timer_setup(struct clock_event_device *clk) enable_percpu_irq(arch_timer_ppi[PHYS_NONSECURE_PPI], 0); arch_counter_set_user_access(); - if (IS_ENABLED(CONFIG_ARM_ARCH_TIMER_EVTSTREAM)) + if (evtstrm_enable) arch_timer_configure_evtstream(); return 0; -- cgit v0.10.2 From f5ce45736b5036e73e7ffa800a1137ad778d186e Mon Sep 17 00:00:00 2001 From: Wang Nan Date: Sat, 25 Jun 2016 01:41:58 +0000 Subject: perf build: Add libbabeltrace to build-test 'make build-test' doesn't test LIBBABELTRACE=1. It misses a building failure caused by commit 41840d211c51 ("perf config: Move config declarations from util/cache.h to util/config.h"), breaks bisect. Add LIBBABELTRACE=1 to build-test. Signed-off-by: Wang Nan Cc: Jiri Olsa Cc: Zefan Li Cc: pi3orama@163.com Link: http://lkml.kernel.org/r/1466818918-131281-1-git-send-email-wangnan0@huawei.com Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/tests/make b/tools/perf/tests/make index cac15d9..51966d9 100644 --- a/tools/perf/tests/make +++ b/tools/perf/tests/make @@ -81,6 +81,7 @@ make_no_libbionic := NO_LIBBIONIC=1 make_no_auxtrace := NO_AUXTRACE=1 make_no_libbpf := NO_LIBBPF=1 make_no_libcrypto := NO_LIBCRYPTO=1 +make_with_babeltrace:= LIBBABELTRACE=1 make_tags := tags make_cscope := cscope make_help := help @@ -136,6 +137,7 @@ run += make_no_libaudit run += make_no_libbionic run += make_no_auxtrace run += make_no_libbpf +run += make_with_babeltrace run += make_help run += make_doc run += make_perf_o -- cgit v0.10.2 From f6c12a004c149a7b0ea1332fa715979888dd4695 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Fri, 24 Jun 2016 14:40:24 +0200 Subject: perf data convert: Include config.h header MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Otherwise some compiler might scream: $ make LIBBABELTRACE_DIR=/opt/libbabeltrace/ LIBBABELTRACE=1 BUILD: Doing 'make -j4' parallel build CC util/data-convert-bt.o util/data-convert-bt.c: In function ‘convert__config’: util/data-convert-bt.c:1299:19: error: implicit declaration of function ‘perf_config_u64’ [-Werror=implicit-function-declaration] c->queue_size = perf_config_u64(var, value); ... Signed-off-by: Jiri Olsa Cc: David Ahern Cc: He Kuang Cc: Marc Kleine-Budde Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Taeung Song Cc: Wang Nan Fixes: 41840d211c51 ("perf config: Move config declarations from util/cache.h to util/config.h") Link: http://lkml.kernel.org/r/1466772025-17471-1-git-send-email-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/util/data-convert-bt.c b/tools/perf/util/data-convert-bt.c index 4b59879..7b1bc24 100644 --- a/tools/perf/util/data-convert-bt.c +++ b/tools/perf/util/data-convert-bt.c @@ -26,6 +26,7 @@ #include "evlist.h" #include "evsel.h" #include "machine.h" +#include "config.h" #define pr_N(n, fmt, ...) \ eprintf(n, debug_data_convert, fmt, ##__VA_ARGS__) -- cgit v0.10.2 From cda57a8c74aa326cbb1a1e2f7d30f8c76983e70c Mon Sep 17 00:00:00 2001 From: Wang Nan Date: Mon, 27 Jun 2016 10:24:03 +0000 Subject: perf record: Move mmap setup block to separate function Following commits introduce multiple evlists to record. This patch extracts perf_evlist__mmap_ex() processing to a new function, creates record__mmap() and record__mmap_evlist() to wrap perf_evlist__mmap_ex() and its error processing. They will be improvemented to create mmap for all evlists. Signed-off-by: Wang Nan Cc: He Kuang Cc: Jiri Olsa Cc: Masami Hiramatsu Cc: Namhyung Kim Cc: Nilay Vaish Cc: Zefan Li Cc: pi3orama@163.com Link: http://lkml.kernel.org/r/1467023052-146749-2-git-send-email-wangnan0@huawei.com Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index 81411b1..7eb8d7d 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -342,6 +342,40 @@ int auxtrace_record__snapshot_start(struct auxtrace_record *itr __maybe_unused) #endif +static int record__mmap_evlist(struct record *rec, + struct perf_evlist *evlist) +{ + struct record_opts *opts = &rec->opts; + char msg[512]; + + if (perf_evlist__mmap_ex(evlist, opts->mmap_pages, false, + opts->auxtrace_mmap_pages, + opts->auxtrace_snapshot_mode) < 0) { + if (errno == EPERM) { + pr_err("Permission error mapping pages.\n" + "Consider increasing " + "/proc/sys/kernel/perf_event_mlock_kb,\n" + "or try again with a smaller value of -m/--mmap_pages.\n" + "(current value: %u,%u)\n", + opts->mmap_pages, opts->auxtrace_mmap_pages); + return -errno; + } else { + pr_err("failed to mmap with %d (%s)\n", errno, + strerror_r(errno, msg, sizeof(msg))); + if (errno) + return -errno; + else + return -EINVAL; + } + } + return 0; +} + +static int record__mmap(struct record *rec) +{ + return record__mmap_evlist(rec, rec->evlist); +} + static int record__open(struct record *rec) { char msg[512]; @@ -378,27 +412,9 @@ try_again: goto out; } - if (perf_evlist__mmap_ex(evlist, opts->mmap_pages, false, - opts->auxtrace_mmap_pages, - opts->auxtrace_snapshot_mode) < 0) { - if (errno == EPERM) { - pr_err("Permission error mapping pages.\n" - "Consider increasing " - "/proc/sys/kernel/perf_event_mlock_kb,\n" - "or try again with a smaller value of -m/--mmap_pages.\n" - "(current value: %u,%u)\n", - opts->mmap_pages, opts->auxtrace_mmap_pages); - rc = -errno; - } else { - pr_err("failed to mmap with %d (%s)\n", errno, - strerror_r(errno, msg, sizeof(msg))); - if (errno) - rc = -errno; - else - rc = -EINVAL; - } + rc = record__mmap(rec); + if (rc) goto out; - } session->evlist = evlist; perf_session__set_id_hdr_size(session); -- cgit v0.10.2 From cb21686b7d37776cfd34793f08d6466ce9091a7d Mon Sep 17 00:00:00 2001 From: Wang Nan Date: Mon, 27 Jun 2016 10:24:04 +0000 Subject: perf record: Prepare reading from multiple evlists in record__mmap_read_all() Following commits introduce new evlists to record. This patch adjusts record__mmap_read_all() and record__mmap_read(): converting original record__mmap_read_all() to record__mmap_read_evlist(), read from one evlist; makes record__mmap_read() reading from specific evlist. record__mmap_read_all() will be improved to read from multiple evlists. Signed-off-by: Wang Nan Cc: He Kuang Cc: Jiri Olsa Cc: Masami Hiramatsu Cc: Namhyung Kim Cc: Nilay Vaish Cc: Zefan Li Cc: pi3orama@163.com Link: http://lkml.kernel.org/r/1467023052-146749-3-git-send-email-wangnan0@huawei.com Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index 7eb8d7d..18e9abc 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -132,9 +132,9 @@ rb_find_range(struct perf_evlist *evlist, return backward_rb_find_range(data, mask, head, start, end); } -static int record__mmap_read(struct record *rec, int idx) +static int record__mmap_read(struct record *rec, struct perf_evlist *evlist, int idx) { - struct perf_mmap *md = &rec->evlist->mmap[idx]; + struct perf_mmap *md = &evlist->mmap[idx]; u64 head = perf_mmap__read_head(md); u64 old = md->prev; u64 end = head, start = old; @@ -143,7 +143,7 @@ static int record__mmap_read(struct record *rec, int idx) void *buf; int rc = 0; - if (rb_find_range(rec->evlist, data, md->mask, head, + if (rb_find_range(evlist, data, md->mask, head, old, &start, &end)) return -1; @@ -157,7 +157,7 @@ static int record__mmap_read(struct record *rec, int idx) WARN_ONCE(1, "failed to keep up with mmap data. (warn only once)\n"); md->prev = head; - perf_evlist__mmap_consume(rec->evlist, idx); + perf_evlist__mmap_consume(evlist, idx); return 0; } @@ -182,7 +182,7 @@ static int record__mmap_read(struct record *rec, int idx) } md->prev = head; - perf_evlist__mmap_consume(rec->evlist, idx); + perf_evlist__mmap_consume(evlist, idx); out: return rc; } @@ -498,17 +498,20 @@ static struct perf_event_header finished_round_event = { .type = PERF_RECORD_FINISHED_ROUND, }; -static int record__mmap_read_all(struct record *rec) +static int record__mmap_read_evlist(struct record *rec, struct perf_evlist *evlist) { u64 bytes_written = rec->bytes_written; int i; int rc = 0; - for (i = 0; i < rec->evlist->nr_mmaps; i++) { - struct auxtrace_mmap *mm = &rec->evlist->mmap[i].auxtrace_mmap; + if (!evlist) + return 0; + + for (i = 0; i < evlist->nr_mmaps; i++) { + struct auxtrace_mmap *mm = &evlist->mmap[i].auxtrace_mmap; - if (rec->evlist->mmap[i].base) { - if (record__mmap_read(rec, i) != 0) { + if (evlist->mmap[i].base) { + if (record__mmap_read(rec, evlist, i) != 0) { rc = -1; goto out; } @@ -532,6 +535,17 @@ out: return rc; } +static int record__mmap_read_all(struct record *rec) +{ + int err; + + err = record__mmap_read_evlist(rec, rec->evlist); + if (err) + return err; + + return err; +} + static void record__init_features(struct record *rec) { struct perf_session *session = rec->session; -- cgit v0.10.2 From ee667f947c926eda1b8d6eccd0894bfbed75b6e3 Mon Sep 17 00:00:00 2001 From: Wang Nan Date: Mon, 27 Jun 2016 10:24:05 +0000 Subject: perf record: Prepare picking perf_event_mmap_page from multiple evlists Following commits introduce new evlists to record. This patch adjusts record__pick_pc() and introduces perf_evlist__pick_pc() to read control page from one specific evlist. record__pick_pc() will be improved to search control page from multiple evlists. Signed-off-by: Wang Nan Cc: He Kuang Cc: Jiri Olsa Cc: Masami Hiramatsu Cc: Namhyung Kim Cc: Nilay Vaish Cc: Zefan Li Cc: pi3orama@163.com Link: http://lkml.kernel.org/r/1467023052-146749-4-git-send-email-wangnan0@huawei.com Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index 18e9abc..b2b3b60 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -686,10 +686,21 @@ perf_event__synth_time_conv(const struct perf_event_mmap_page *pc __maybe_unused return 0; } +static const struct perf_event_mmap_page * +perf_evlist__pick_pc(struct perf_evlist *evlist) +{ + if (evlist && evlist->mmap && evlist->mmap[0].base) + return evlist->mmap[0].base; + return NULL; +} + static const struct perf_event_mmap_page *record__pick_pc(struct record *rec) { - if (rec->evlist && rec->evlist->mmap && rec->evlist->mmap[0].base) - return rec->evlist->mmap[0].base; + const struct perf_event_mmap_page *pc; + + pc = perf_evlist__pick_pc(rec->evlist); + if (pc) + return pc; return NULL; } -- cgit v0.10.2 From ed7b630b310775f3b6c0b360ede7a12cd8dff6fe Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Fri, 24 Jun 2016 14:40:25 +0200 Subject: perf symbols: Use proper dso name for is_regular_file Marc reported use of uninitialized memory: > In commit "403567217d3f perf symbols: Do not read symbols/data from > device files" a check to uninitialzied memory was added. This leads to > the following valgrind output: > > ==24515== Syscall param stat(file_name) points to uninitialised byte(s) > ==24515== at 0x75B26D5: _xstat (in /lib/x86_64-linux-gnu/libc-2.22.so) > ==24515== by 0x4E548D: stat (stat.h:454) > ==24515== by 0x4E548D: is_regular_file (util.c:687) > ==24515== by 0x4A5BEE: dso__load (symbol.c:1435) > ==24515== by 0x4BB1AE: map__load (map.c:289) > ==24515== by 0x4BB1AE: map__find_symbol (map.c:333) > ==24515== by 0x4835B3: thread__find_addr_location (event.c:1300) > ==24515== by 0x4B5342: add_callchain_ip (machine.c:1652) > ==24515== by 0x4B5342: thread__resolve_callchain_sample (machine.c:1906) > ==24515== by 0x4B9E7D: thread__resolve_callchain (machine.c:1958) > ==24515== by 0x441B3E: process_event (builtin-script.c:795) > ==24515== by 0x441B3E: process_sample_event (builtin-script.c:920) > ==24515== by 0x4BEE29: perf_evlist__deliver_sample (session.c:1192) > ==24515== by 0x4BEE29: machines__deliver_event (session.c:1229) > ==24515== by 0x4BF770: perf_session__deliver_event (session.c:1286) > ==24515== by 0x4BF770: ordered_events__deliver_event (session.c:114) > ==24515== by 0x4C1D17: __ordered_events__flush (ordered-events.c:207) > ==24515== by 0x4C1D17: ordered_events__flush.part.3 (ordered-events.c:274) > ==24515== by 0x4BF44C: perf_session__process_user_event (session.c:1325) > ==24515== by 0x4BF44C: perf_session__process_event (session.c:1451) > ==24515== Address 0x807c6a0 is 0 bytes inside a block of size 4,096 alloc'd > ==24515== at 0x4C29C0F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) > ==24515== by 0x4A5BCB: dso__load (symbol.c:1421) > ==24515== by 0x4BB1AE: map__load (map.c:289) > ==24515== by 0x4BB1AE: map__find_symbol (map.c:333) > ==24515== by 0x4835B3: thread__find_addr_location (event.c:1300) > ==24515== by 0x4B5342: add_callchain_ip (machine.c:1652) > ==24515== by 0x4B5342: thread__resolve_callchain_sample (machine.c:1906) > ==24515== by 0x4B9E7D: thread__resolve_callchain (machine.c:1958) > ==24515== by 0x441B3E: process_event (builtin-script.c:795) > ==24515== by 0x441B3E: process_sample_event (builtin-script.c:920) > ==24515== by 0x4BEE29: perf_evlist__deliver_sample (session.c:1192) > ==24515== by 0x4BEE29: machines__deliver_event (session.c:1229) > ==24515== by 0x4BF770: perf_session__deliver_event (session.c:1286) > ==24515== by 0x4BF770: ordered_events__deliver_event (session.c:114) > ==24515== by 0x4C1D17: __ordered_events__flush (ordered-events.c:207) > ==24515== by 0x4C1D17: ordered_events__flush.part.3 (ordered-events.c:274) > ==24515== by 0x4BF44C: perf_session__process_user_event (session.c:1325) > ==24515== by 0x4BF44C: perf_session__process_event (session.c:1451) > ==24515== by 0x4C0EAC: __perf_session__process_events (session.c:1804) > ==24515== by 0x4C0EAC: perf_session__process_events (session.c:1858) The reason was a typo that passed global 'name' variable as the is_regular_file argument instead dso->long_name. Reported-by: Marc Kleine-Budde Signed-off-by: Jiri Olsa Acked-by: Marc Kleine-Budde Cc: David Ahern Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Wang Nan Fixes: 403567217d3f ("perf symbols: Do not read symbols/data from device files") Link: http://lkml.kernel.org/r/1466772025-17471-2-git-send-email-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index b044f1a..37e8d20 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c @@ -1430,7 +1430,7 @@ int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter) * Read the build id if possible. This is required for * DSO_BINARY_TYPE__BUILDID_DEBUGINFO to work */ - if (is_regular_file(name) && + if (is_regular_file(dso->long_name) && filename__read_build_id(dso->long_name, build_id, BUILD_ID_SIZE) > 0) dso__set_build_id(dso, build_id); -- cgit v0.10.2 From 069ee5c488d161f539bb897b1bc64b83f9773221 Mon Sep 17 00:00:00 2001 From: Wang Nan Date: Fri, 24 Jun 2016 11:22:06 +0000 Subject: perf data ctf: Add value_set_string() helper There are many value_set_##x helper for integer, but only for integer. This patch adds value_set_string() helper to help following commits create string fields. Signed-off-by: Wang Nan Acked-by: Jiri Olsa Cc: Zefan Li Cc: pi3orama@163.com Link: http://lkml.kernel.org/r/1466767332-114472-2-git-send-email-wangnan0@huawei.com Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/util/data-convert-bt.c b/tools/perf/util/data-convert-bt.c index 7b1bc24..4b68e7b 100644 --- a/tools/perf/util/data-convert-bt.c +++ b/tools/perf/util/data-convert-bt.c @@ -141,6 +141,36 @@ FUNC_VALUE_SET(s64) FUNC_VALUE_SET(u64) __FUNC_VALUE_SET(u64_hex, u64) +static int string_set_value(struct bt_ctf_field *field, const char *string); +static __maybe_unused int +value_set_string(struct ctf_writer *cw, struct bt_ctf_event *event, + const char *name, const char *string) +{ + struct bt_ctf_field_type *type = cw->data.string; + struct bt_ctf_field *field; + int ret = 0; + + field = bt_ctf_field_create(type); + if (!field) { + pr_err("failed to create a field %s\n", name); + return -1; + } + + ret = string_set_value(field, string); + if (ret) { + pr_err("failed to set value %s\n", name); + goto err_put_field; + } + + ret = bt_ctf_event_set_payload(event, name, field); + if (ret) + pr_err("failed to set payload %s\n", name); + +err_put_field: + bt_ctf_field_put(field); + return ret; +} + static struct bt_ctf_field_type* get_tracepoint_field_type(struct ctf_writer *cw, struct format_field *field) { -- cgit v0.10.2 From 3275f68e50290acd04612c6af41173fe83fdf4b0 Mon Sep 17 00:00:00 2001 From: Wang Nan Date: Fri, 24 Jun 2016 11:22:07 +0000 Subject: perf data ctf: Pass convert options through opts structure Following commits will add new option to 'perf data convert'. All options should be grouped into a structure and passed to low level converter (currently there's only one converter). Introduce data-convert.h and define 'struct perf_data_convert_opts' in it. Pass 'force' through opts. Signed-off-by: Wang Nan Acked-by: Jiri Olsa Cc: Zefan Li Cc: pi3orama@163.com Link: http://lkml.kernel.org/r/1466767332-114472-3-git-send-email-wangnan0@huawei.com Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/builtin-data.c b/tools/perf/builtin-data.c index b97bc15..38111a9 100644 --- a/tools/perf/builtin-data.c +++ b/tools/perf/builtin-data.c @@ -3,6 +3,7 @@ #include "perf.h" #include "debug.h" #include +#include "data-convert.h" #include "data-convert-bt.h" typedef int (*data_cmd_fn_t)(int argc, const char **argv, const char *prefix); @@ -53,14 +54,16 @@ static int cmd_data_convert(int argc, const char **argv, const char *prefix __maybe_unused) { const char *to_ctf = NULL; - bool force = false; + struct perf_data_convert_opts opts = { + .force = false, + }; const struct option options[] = { OPT_INCR('v', "verbose", &verbose, "be more verbose"), OPT_STRING('i', "input", &input_name, "file", "input file name"), #ifdef HAVE_LIBBABELTRACE_SUPPORT OPT_STRING(0, "to-ctf", &to_ctf, NULL, "Convert to CTF format"), #endif - OPT_BOOLEAN('f', "force", &force, "don't complain, do it"), + OPT_BOOLEAN('f', "force", &opts.force, "don't complain, do it"), OPT_END() }; @@ -78,7 +81,7 @@ static int cmd_data_convert(int argc, const char **argv, if (to_ctf) { #ifdef HAVE_LIBBABELTRACE_SUPPORT - return bt_convert__perf2ctf(input_name, to_ctf, force); + return bt_convert__perf2ctf(input_name, to_ctf, &opts); #else pr_err("The libbabeltrace support is not compiled in.\n"); return -1; diff --git a/tools/perf/util/data-convert-bt.c b/tools/perf/util/data-convert-bt.c index 4b68e7b..09571b3 100644 --- a/tools/perf/util/data-convert-bt.c +++ b/tools/perf/util/data-convert-bt.c @@ -1304,13 +1304,14 @@ static int convert__config(const char *var, const char *value, void *cb) return 0; } -int bt_convert__perf2ctf(const char *input, const char *path, bool force) +int bt_convert__perf2ctf(const char *input, const char *path, + struct perf_data_convert_opts *opts) { struct perf_session *session; struct perf_data_file file = { .path = input, .mode = PERF_DATA_MODE_READ, - .force = force, + .force = opts->force, }; struct convert c = { .tool = { diff --git a/tools/perf/util/data-convert-bt.h b/tools/perf/util/data-convert-bt.h index 4c20434..9a3b587 100644 --- a/tools/perf/util/data-convert-bt.h +++ b/tools/perf/util/data-convert-bt.h @@ -1,8 +1,10 @@ #ifndef __DATA_CONVERT_BT_H #define __DATA_CONVERT_BT_H +#include "data-convert.h" #ifdef HAVE_LIBBABELTRACE_SUPPORT -int bt_convert__perf2ctf(const char *input_name, const char *to_ctf, bool force); +int bt_convert__perf2ctf(const char *input_name, const char *to_ctf, + struct perf_data_convert_opts *opts); #endif /* HAVE_LIBBABELTRACE_SUPPORT */ #endif /* __DATA_CONVERT_BT_H */ diff --git a/tools/perf/util/data-convert.h b/tools/perf/util/data-convert.h new file mode 100644 index 0000000..97cfd36 --- /dev/null +++ b/tools/perf/util/data-convert.h @@ -0,0 +1,8 @@ +#ifndef __DATA_CONVERT_H +#define __DATA_CONVERT_H + +struct perf_data_convert_opts { + bool force; +}; + +#endif /* __DATA_CONVERT_H */ -- cgit v0.10.2 From f02a6489d1e181c6c2731e80ff37024a130c326a Mon Sep 17 00:00:00 2001 From: Wang Nan Date: Fri, 24 Jun 2016 11:22:08 +0000 Subject: perf data ctf: Add 'all' option If 'all' option is selected, 'perf data convert' should convert not only samples, but non-sample events such as comm and fork. Add this option in perf_data_convert_opts. Following commits will add cmdline option to select it. Signed-off-by: Wang Nan Acked-by: Jiri Olsa Cc: Zefan Li Cc: pi3orama@163.com Link: http://lkml.kernel.org/r/1466767332-114472-4-git-send-email-wangnan0@huawei.com Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/builtin-data.c b/tools/perf/builtin-data.c index 38111a9..ddfe3ac4 100644 --- a/tools/perf/builtin-data.c +++ b/tools/perf/builtin-data.c @@ -56,6 +56,7 @@ static int cmd_data_convert(int argc, const char **argv, const char *to_ctf = NULL; struct perf_data_convert_opts opts = { .force = false, + .all = false, }; const struct option options[] = { OPT_INCR('v', "verbose", &verbose, "be more verbose"), diff --git a/tools/perf/util/data-convert.h b/tools/perf/util/data-convert.h index 97cfd36..5314962 100644 --- a/tools/perf/util/data-convert.h +++ b/tools/perf/util/data-convert.h @@ -3,6 +3,7 @@ struct perf_data_convert_opts { bool force; + bool all; }; #endif /* __DATA_CONVERT_H */ -- cgit v0.10.2 From 8ee4c46c5ec2481dd18098c5604f791ff911d427 Mon Sep 17 00:00:00 2001 From: Wang Nan Date: Fri, 24 Jun 2016 11:22:09 +0000 Subject: perf data ctf: Prepare collect non-sample events Following commits are going to allow 'perf data convert' to collect not only samples, but also non-sample events like comm and fork. In this patch we count non-sample events using c.non_sample_count, and prepare to print number of both type of events like: # ~/perf data convert --all --to-ctf ./out.ctf [ perf data convert: Converted 'perf.data' into CTF data './out.ctf' ] [ perf data convert: Converted and wrote 0.846 MB (6508 samples, 686 non-samples) ] Signed-off-by: Wang Nan Acked-by: Jiri Olsa Cc: Zefan Li Cc: pi3orama@163.com Link: http://lkml.kernel.org/r/1466767332-114472-5-git-send-email-wangnan0@huawei.com Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/util/data-convert-bt.c b/tools/perf/util/data-convert-bt.c index 09571b3..3b3ac7c 100644 --- a/tools/perf/util/data-convert-bt.c +++ b/tools/perf/util/data-convert-bt.c @@ -77,6 +77,7 @@ struct convert { u64 events_size; u64 events_count; + u64 non_sample_count; /* Ordered events configured queue size. */ u64 queue_size; @@ -1369,10 +1370,15 @@ int bt_convert__perf2ctf(const char *input, const char *path, file.path, path); fprintf(stderr, - "[ perf data convert: Converted and wrote %.3f MB (%" PRIu64 " samples) ]\n", + "[ perf data convert: Converted and wrote %.3f MB (%" PRIu64 " samples", (double) c.events_size / 1024.0 / 1024.0, c.events_count); + if (!c.non_sample_count) + fprintf(stderr, ") ]\n"); + else + fprintf(stderr, ", %" PRIu64 " non-samples) ]\n", c.non_sample_count); + cleanup_events(session); perf_session__delete(session); ctf_writer__cleanup(cw); -- cgit v0.10.2 From f5a08ceda55bee91f879d2ac19edeb4a8916d04f Mon Sep 17 00:00:00 2001 From: Wang Nan Date: Fri, 24 Jun 2016 11:22:10 +0000 Subject: perf data ctf: Generate comm event to CTF output If 'all' is selected, convert comm event to output CTF stream. setup_non_sample_events() is called if non_sample is selected. It creates a comm_class for comm event. Use macros to generate and process_comm_event and add_comm_event. These macros can be reused for other non-sample events. Signed-off-by: Wang Nan Acked-by: Jiri Olsa Cc: Zefan Li Cc: pi3orama@163.com Link: http://lkml.kernel.org/r/1466767332-114472-6-git-send-email-wangnan0@huawei.com Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/util/data-convert-bt.c b/tools/perf/util/data-convert-bt.c index 3b3ac7c..5dd62ba 100644 --- a/tools/perf/util/data-convert-bt.c +++ b/tools/perf/util/data-convert-bt.c @@ -69,6 +69,7 @@ struct ctf_writer { }; struct bt_ctf_field_type *array[6]; } data; + struct bt_ctf_event_class *comm_class; }; struct convert { @@ -763,6 +764,57 @@ static int process_sample_event(struct perf_tool *tool, return cs ? 0 : -1; } +#define __NON_SAMPLE_SET_FIELD(_name, _type, _field) \ +do { \ + ret = value_set_##_type(cw, event, #_field, _event->_name._field);\ + if (ret) \ + return -1; \ +} while(0) + +#define __FUNC_PROCESS_NON_SAMPLE(_name, body) \ +static int process_##_name##_event(struct perf_tool *tool, \ + union perf_event *_event, \ + struct perf_sample *sample, \ + struct machine *machine) \ +{ \ + struct convert *c = container_of(tool, struct convert, tool);\ + struct ctf_writer *cw = &c->writer; \ + struct bt_ctf_event_class *event_class = cw->_name##_class;\ + struct bt_ctf_event *event; \ + struct ctf_stream *cs; \ + int ret; \ + \ + c->non_sample_count++; \ + c->events_size += _event->header.size; \ + event = bt_ctf_event_create(event_class); \ + if (!event) { \ + pr_err("Failed to create an CTF event\n"); \ + return -1; \ + } \ + \ + bt_ctf_clock_set_time(cw->clock, sample->time); \ + body \ + cs = ctf_stream(cw, 0); \ + if (cs) { \ + if (is_flush_needed(cs)) \ + ctf_stream__flush(cs); \ + \ + cs->count++; \ + bt_ctf_stream_append_event(cs->stream, event); \ + } \ + bt_ctf_event_put(event); \ + \ + return perf_event__process_##_name(tool, _event, sample, machine);\ +} + +__FUNC_PROCESS_NON_SAMPLE(comm, + __NON_SAMPLE_SET_FIELD(comm, u32, pid); + __NON_SAMPLE_SET_FIELD(comm, u32, tid); + __NON_SAMPLE_SET_FIELD(comm, string, comm); +) +#undef __NON_SAMPLE_SET_FIELD +#undef __FUNC_PROCESS_NON_SAMPLE + /* If dup < 0, add a prefix. Else, add _dupl_X suffix. */ static char *change_name(char *name, char *orig_name, int dup) { @@ -1037,6 +1089,58 @@ static int setup_events(struct ctf_writer *cw, struct perf_session *session) return 0; } +#define __NON_SAMPLE_ADD_FIELD(t, n) \ + do { \ + pr2(" field '%s'\n", #n); \ + if (bt_ctf_event_class_add_field(event_class, cw->data.t, #n)) {\ + pr_err("Failed to add field '%s';\n", #n);\ + return -1; \ + } \ + } while(0) + +#define __FUNC_ADD_NON_SAMPLE_EVENT_CLASS(_name, body) \ +static int add_##_name##_event(struct ctf_writer *cw) \ +{ \ + struct bt_ctf_event_class *event_class; \ + int ret; \ + \ + pr("Adding "#_name" event\n"); \ + event_class = bt_ctf_event_class_create("perf_" #_name);\ + if (!event_class) \ + return -1; \ + body \ + \ + ret = bt_ctf_stream_class_add_event_class(cw->stream_class, event_class);\ + if (ret) { \ + pr("Failed to add event class '"#_name"' into stream.\n");\ + return ret; \ + } \ + \ + cw->_name##_class = event_class; \ + bt_ctf_event_class_put(event_class); \ + return 0; \ +} + +__FUNC_ADD_NON_SAMPLE_EVENT_CLASS(comm, + __NON_SAMPLE_ADD_FIELD(u32, pid); + __NON_SAMPLE_ADD_FIELD(u32, tid); + __NON_SAMPLE_ADD_FIELD(string, comm); +) + +#undef __NON_SAMPLE_ADD_FIELD +#undef __FUNC_ADD_NON_SAMPLE_EVENT_CLASS + +static int setup_non_sample_events(struct ctf_writer *cw, + struct perf_session *session __maybe_unused) +{ + int ret; + + ret = add_comm_event(cw); + if (ret) + return ret; + return 0; +} + static void cleanup_events(struct perf_session *session) { struct perf_evlist *evlist = session->evlist; @@ -1332,6 +1436,9 @@ int bt_convert__perf2ctf(const char *input, const char *path, struct ctf_writer *cw = &c.writer; int err = -1; + if (opts->all) + c.tool.comm = process_comm_event; + perf_config(convert__config, &c); /* CTF writer */ @@ -1356,6 +1463,9 @@ int bt_convert__perf2ctf(const char *input, const char *path, if (setup_events(cw, session)) goto free_session; + if (opts->all && setup_non_sample_events(cw, session)) + goto free_session; + if (setup_streams(cw, session)) goto free_session; -- cgit v0.10.2 From 9e1a7ea19f9f8e3e40c5ad1a5cc3615c1746ae7b Mon Sep 17 00:00:00 2001 From: Wang Nan Date: Fri, 24 Jun 2016 11:22:11 +0000 Subject: perf data ctf: Add '--all' option for 'perf data convert' After this patch, 'perf data convert' convert comm events to output CTF stream. Result: # perf record -a sleep 1 [ perf record: Woken up 1 times to write data ] [ perf record: Captured and wrote 0.378 MB perf.data (73 samples) ] # perf data convert --to-ctf ./out.ctf [ perf data convert: Converted 'perf.data' into CTF data './out.ctf' ] [ perf data convert: Converted and wrote 0.003 MB (73 samples) ] # babeltrace --clock-seconds ./out.ctf/ [10627.402515791] (+?.?????????) cycles:ppp: { cpu_id = 0 }, { perf_ip = 0xFFFFFFFF81065AF4, perf_tid = 0, perf_pid = 0, perf_period = 1 } [10627.402518972] (+0.000003181) cycles:ppp: { cpu_id = 0 }, { perf_ip = 0xFFFFFFFF81065AF4, perf_tid = 0, perf_pid = 0, perf_period = 1 } ... // only sample event is converted # perf data convert --all --to-ctf ./out.ctf [ perf data convert: Converted 'perf.data' into CTF data './out.ctf' ] [ perf data convert: Converted and wrote 0.023 MB (73 samples, 384 non-samples) ] # babeltrace --clock-seconds ./out.ctf/ [ 0.000000000] (+?.?????????) perf_comm: { cpu_id = 0 }, { pid = 1, tid = 1, comm = "init" } [ 0.000000000] (+0.000000000) perf_comm: { cpu_id = 0 }, { pid = 2, tid = 2, comm = "kthreadd" } [ 0.000000000] (+0.000000000) perf_comm: { cpu_id = 0 }, { pid = 3, tid = 3, comm = "ksoftirqd/0" } ... // comm events are converted [10627.402515791] (+10627.402515791) cycles:ppp: { cpu_id = 0 }, { perf_ip = 0xFFFFFFFF81065AF4, perf_tid = 0, perf_pid = 0, perf_period = 1 } [10627.402518972] (+0.000003181) cycles:ppp: { cpu_id = 0 }, { perf_ip = 0xFFFFFFFF81065AF4, perf_tid = 0, perf_pid = 0, perf_period = 1 } ... // samples are also converted Signed-off-by: Wang Nan Acked-by: Jiri Olsa Cc: Zefan Li Cc: pi3orama@163.com Link: http://lkml.kernel.org/r/1466767332-114472-7-git-send-email-wangnan0@huawei.com Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/Documentation/perf-data.txt b/tools/perf/Documentation/perf-data.txt index be8fa1a..f0796a4 100644 --- a/tools/perf/Documentation/perf-data.txt +++ b/tools/perf/Documentation/perf-data.txt @@ -34,6 +34,10 @@ OPTIONS for 'convert' --verbose:: Be more verbose (show counter open errors, etc). +--all:: + Convert all events, including non-sample events (comm, fork, ...), to output. + Default is off, only convert samples. + SEE ALSO -------- linkperf:perf[1] diff --git a/tools/perf/builtin-data.c b/tools/perf/builtin-data.c index ddfe3ac4..7ad6e17 100644 --- a/tools/perf/builtin-data.c +++ b/tools/perf/builtin-data.c @@ -65,6 +65,7 @@ static int cmd_data_convert(int argc, const char **argv, OPT_STRING(0, "to-ctf", &to_ctf, NULL, "Convert to CTF format"), #endif OPT_BOOLEAN('f', "force", &opts.force, "don't complain, do it"), + OPT_BOOLEAN(0, "all", &opts.all, "Convert all events"), OPT_END() }; -- cgit v0.10.2 From ebccba3fe0a02f622f80e6be0e8ecb1a9a3ed983 Mon Sep 17 00:00:00 2001 From: Wang Nan Date: Fri, 24 Jun 2016 11:22:12 +0000 Subject: perf data ctf: Generate fork and exit events to CTF output If 'all' is selected, convert fork and exit events to output CTF stream. Signed-off-by: Wang Nan Acked-by: Jiri Olsa Cc: Zefan Li Cc: pi3orama@163.com Link: http://lkml.kernel.org/r/1466767332-114472-8-git-send-email-wangnan0@huawei.com Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/util/data-convert-bt.c b/tools/perf/util/data-convert-bt.c index 5dd62ba..4f979bb 100644 --- a/tools/perf/util/data-convert-bt.c +++ b/tools/perf/util/data-convert-bt.c @@ -70,6 +70,8 @@ struct ctf_writer { struct bt_ctf_field_type *array[6]; } data; struct bt_ctf_event_class *comm_class; + struct bt_ctf_event_class *exit_class; + struct bt_ctf_event_class *fork_class; }; struct convert { @@ -812,6 +814,21 @@ __FUNC_PROCESS_NON_SAMPLE(comm, __NON_SAMPLE_SET_FIELD(comm, u32, tid); __NON_SAMPLE_SET_FIELD(comm, string, comm); ) +__FUNC_PROCESS_NON_SAMPLE(fork, + __NON_SAMPLE_SET_FIELD(fork, u32, pid); + __NON_SAMPLE_SET_FIELD(fork, u32, ppid); + __NON_SAMPLE_SET_FIELD(fork, u32, tid); + __NON_SAMPLE_SET_FIELD(fork, u32, ptid); + __NON_SAMPLE_SET_FIELD(fork, u64, time); +) + +__FUNC_PROCESS_NON_SAMPLE(exit, + __NON_SAMPLE_SET_FIELD(fork, u32, pid); + __NON_SAMPLE_SET_FIELD(fork, u32, ppid); + __NON_SAMPLE_SET_FIELD(fork, u32, tid); + __NON_SAMPLE_SET_FIELD(fork, u32, ptid); + __NON_SAMPLE_SET_FIELD(fork, u64, time); +) #undef __NON_SAMPLE_SET_FIELD #undef __FUNC_PROCESS_NON_SAMPLE @@ -1127,6 +1144,22 @@ __FUNC_ADD_NON_SAMPLE_EVENT_CLASS(comm, __NON_SAMPLE_ADD_FIELD(string, comm); ) +__FUNC_ADD_NON_SAMPLE_EVENT_CLASS(fork, + __NON_SAMPLE_ADD_FIELD(u32, pid); + __NON_SAMPLE_ADD_FIELD(u32, ppid); + __NON_SAMPLE_ADD_FIELD(u32, tid); + __NON_SAMPLE_ADD_FIELD(u32, ptid); + __NON_SAMPLE_ADD_FIELD(u64, time); +) + +__FUNC_ADD_NON_SAMPLE_EVENT_CLASS(exit, + __NON_SAMPLE_ADD_FIELD(u32, pid); + __NON_SAMPLE_ADD_FIELD(u32, ppid); + __NON_SAMPLE_ADD_FIELD(u32, tid); + __NON_SAMPLE_ADD_FIELD(u32, ptid); + __NON_SAMPLE_ADD_FIELD(u64, time); +) + #undef __NON_SAMPLE_ADD_FIELD #undef __FUNC_ADD_NON_SAMPLE_EVENT_CLASS @@ -1138,6 +1171,12 @@ static int setup_non_sample_events(struct ctf_writer *cw, ret = add_comm_event(cw); if (ret) return ret; + ret = add_exit_event(cw); + if (ret) + return ret; + ret = add_fork_event(cw); + if (ret) + return ret; return 0; } @@ -1436,8 +1475,11 @@ int bt_convert__perf2ctf(const char *input, const char *path, struct ctf_writer *cw = &c.writer; int err = -1; - if (opts->all) + if (opts->all) { c.tool.comm = process_comm_event; + c.tool.exit = process_exit_event; + c.tool.fork = process_fork_event; + } perf_config(convert__config, &c); -- cgit v0.10.2 From 54e430bbd490e18ab116afa4cd90dcc45787b3df Mon Sep 17 00:00:00 2001 From: Brian King Date: Mon, 27 Jun 2016 09:09:40 -0500 Subject: ipr: Clear interrupt on croc/crocodile when running with LSI If we fall back to using LSI on the Croc or Crocodile chip we need to clear the interrupt so we don't hang the system. Cc: Tested-by: Benjamin Herrenschmidt Signed-off-by: Brian King Signed-off-by: Martin K. Petersen diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c index d6a691e..d6803a9 100644 --- a/drivers/scsi/ipr.c +++ b/drivers/scsi/ipr.c @@ -10093,6 +10093,7 @@ static int ipr_probe_ioa(struct pci_dev *pdev, ioa_cfg->intr_flag = IPR_USE_MSI; else { ioa_cfg->intr_flag = IPR_USE_LSI; + ioa_cfg->clear_isr = 1; ioa_cfg->nvectors = 1; dev_info(&pdev->dev, "Cannot enable MSI.\n"); } -- cgit v0.10.2 From 5e7ff2ca7f2da55fe777167849d0c93403bd0dc8 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Thu, 23 Jun 2016 15:05:26 -0400 Subject: SCSI: fix new bug in scsi_dev_info_list string matching Commit b704f70ce200 ("SCSI: fix bug in scsi_dev_info_list matching") changed the way vendor- and model-string matching was carried out in the routine that looks up entries in a SCSI devinfo list. The new matching code failed to take into account the case of a maximum-length string; in such cases it could end up testing for a terminating '\0' byte beyond the end of the memory allocated to the string. This out-of-bounds bug was detected by UBSAN. I don't know if anybody has actually encountered this bug. The symptom would be that a device entry in the blacklist might not be matched properly if it contained an 8-character vendor name or a 16-character model name. Such entries certainly exist in scsi_static_device_list. This patch fixes the problem by adding a check for a maximum-length string before the '\0' test. Signed-off-by: Alan Stern Fixes: b704f70ce200 ("SCSI: fix bug in scsi_dev_info_list matching") Tested-by: Wilfried Klaebe CC: # v4.4+ Signed-off-by: Martin K. Petersen diff --git a/drivers/scsi/scsi_devinfo.c b/drivers/scsi/scsi_devinfo.c index ff41c31..eaccd65 100644 --- a/drivers/scsi/scsi_devinfo.c +++ b/drivers/scsi/scsi_devinfo.c @@ -429,7 +429,7 @@ static struct scsi_dev_info_list *scsi_dev_info_list_find(const char *vendor, * here, and we don't know what device it is * trying to work with, leave it as-is. */ - vmax = 8; /* max length of vendor */ + vmax = sizeof(devinfo->vendor); vskip = vendor; while (vmax > 0 && *vskip == ' ') { vmax--; @@ -439,7 +439,7 @@ static struct scsi_dev_info_list *scsi_dev_info_list_find(const char *vendor, while (vmax > 0 && vskip[vmax - 1] == ' ') --vmax; - mmax = 16; /* max length of model */ + mmax = sizeof(devinfo->model); mskip = model; while (mmax > 0 && *mskip == ' ') { mmax--; @@ -455,10 +455,12 @@ static struct scsi_dev_info_list *scsi_dev_info_list_find(const char *vendor, * Behave like the older version of get_device_flags. */ if (memcmp(devinfo->vendor, vskip, vmax) || - devinfo->vendor[vmax]) + (vmax < sizeof(devinfo->vendor) && + devinfo->vendor[vmax])) continue; if (memcmp(devinfo->model, mskip, mmax) || - devinfo->model[mmax]) + (mmax < sizeof(devinfo->model) && + devinfo->model[mmax])) continue; return devinfo; } else { -- cgit v0.10.2 From eee25ab19de632af1ab4d2ac50bfc5006802e664 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Tue, 28 Jun 2016 22:11:14 +0200 Subject: ARM: dts: sun7i: Fix pll3x2 and pll7x2 not having a parent clock Fix pll3x2 and pll7x2 not having a parent clock, specifically this fixes the kernel turning of pll3 while simplefb is using it when uboot has configured things to use pll3x2 as lcd ch clk parent. Signed-off-by: Hans de Goede Signed-off-by: Maxime Ripard diff --git a/arch/arm/boot/dts/sun7i-a20.dtsi b/arch/arm/boot/dts/sun7i-a20.dtsi index f480051..2c34bbb 100644 --- a/arch/arm/boot/dts/sun7i-a20.dtsi +++ b/arch/arm/boot/dts/sun7i-a20.dtsi @@ -232,6 +232,7 @@ pll3x2: pll3x2_clk { #clock-cells = <0>; compatible = "fixed-factor-clock"; + clocks = <&pll3>; clock-div = <1>; clock-mult = <2>; clock-output-names = "pll3-2x"; @@ -273,6 +274,7 @@ pll7x2: pll7x2_clk { #clock-cells = <0>; compatible = "fixed-factor-clock"; + clocks = <&pll7>; clock-div = <1>; clock-mult = <2>; clock-output-names = "pll7-2x"; -- cgit v0.10.2 From 0d7995031a8e7a34e5638d57a44a51aae39e321c Mon Sep 17 00:00:00 2001 From: Yoshihiro Shimoda Date: Mon, 27 Jun 2016 21:09:18 +0900 Subject: usb: renesas_usbhs: show error code when probe failed To know why the driver probing failed, this patch shows error code. Signed-off-by: Yoshihiro Shimoda Signed-off-by: Felipe Balbi diff --git a/drivers/usb/renesas_usbhs/common.c b/drivers/usb/renesas_usbhs/common.c index baeb7d2..8fbbc2d 100644 --- a/drivers/usb/renesas_usbhs/common.c +++ b/drivers/usb/renesas_usbhs/common.c @@ -697,7 +697,7 @@ probe_end_fifo_exit: probe_end_pipe_exit: usbhs_pipe_remove(priv); - dev_info(&pdev->dev, "probe failed\n"); + dev_info(&pdev->dev, "probe failed (%d)\n", ret); return ret; } -- cgit v0.10.2 From e135ab7405f562c7709806e355b1521ee68548dc Mon Sep 17 00:00:00 2001 From: Nicolas Iooss Date: Sun, 26 Jun 2016 10:12:38 +0200 Subject: usb: dwc2: add printf attribute to cat_printf() As cat_printf() uses printf format strings in its parameters, adding __printf attribute allows the compiler to detect at compile-time some errors related to format strings (with -Wformat warning flag). Signed-off-by: Nicolas Iooss Acked-by: John Youn Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc2/hcd_queue.c b/drivers/usb/dwc2/hcd_queue.c index b5c7793..1375435 100644 --- a/drivers/usb/dwc2/hcd_queue.c +++ b/drivers/usb/dwc2/hcd_queue.c @@ -367,7 +367,8 @@ static void pmap_unschedule(unsigned long *map, int bits_per_period, * @fmt: The format for printf. * @...: The args for printf. */ -static void cat_printf(char **buf, size_t *size, const char *fmt, ...) +static __printf(3, 4) +void cat_printf(char **buf, size_t *size, const char *fmt, ...) { va_list args; int i; -- cgit v0.10.2 From e43470dbdfe8922f9b2962184336efaa71e59727 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Fri, 24 Jun 2016 09:30:26 +0200 Subject: USB: dwc2-usb: add USB_GADGET dependency The driver selects NOP_USB_XCEIV, which can only be built-in if USB_GADGET is either disabled or also built-in, so with USB_DWC2_PCI=y and USB_GADGET=m, NOP_USB_XCEIV is also built-in and we get this link error: drivers/usb/built-in.o: In function `nop_set_peripheral': (text+0x1927c): undefined reference to `usb_gadget_vbus_connect' drivers/usb/built-in.o: In function `nop_gpio_vbus_thread': (text+0x197a0): undefined reference to `usb_gadget_vbus_connect' (text+0x19830): undefined reference to `usb_gadget_vbus_disconnect' This adds the same dependency for the dwc2 driver to avoid that broken configuration. Signed-off-by: Arnd Bergmann Acked-by: John Youn Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc2/Kconfig b/drivers/usb/dwc2/Kconfig index c1f29ca..e838701 100644 --- a/drivers/usb/dwc2/Kconfig +++ b/drivers/usb/dwc2/Kconfig @@ -55,6 +55,7 @@ endchoice config USB_DWC2_PCI tristate "DWC2 PCI" depends on PCI + depends on USB_GADGET || !USB_GADGET default n select NOP_USB_XCEIV help -- cgit v0.10.2 From 44963d649da63ce8ed8f41b8a267c745ca1ec0b0 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 24 Jun 2016 15:23:16 +0300 Subject: usb: gadget: f_fs: check for allocation failure MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Return -ENOMEM if kmalloc() fails. Fixes: 9353afbbfa7b ('usb: gadget: f_fs: buffer data from ‘oversized’ OUT requests') Signed-off-by: Dan Carpenter Acked-by: Michal Nazarewicz Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c index a91fcb0..5c8429f 100644 --- a/drivers/usb/gadget/function/f_fs.c +++ b/drivers/usb/gadget/function/f_fs.c @@ -775,6 +775,8 @@ static ssize_t __ffs_epfile_read_data(struct ffs_epfile *epfile, data_len -= ret; buf = kmalloc(sizeof(*buf) + data_len, GFP_KERNEL); + if (!buf) + return -ENOMEM; buf->length = data_len; buf->data = buf->storage; memcpy(buf->storage, data + ret, data_len); -- cgit v0.10.2 From 4fdef698383db07d829da567e0e405fc41ff3a89 Mon Sep 17 00:00:00 2001 From: Yoshihiro Shimoda Date: Wed, 8 Jun 2016 16:32:49 +0900 Subject: usb: renesas_usbhs: fix NULL pointer dereference in xfer_work() This patch fixes an issue that the xfer_work() is possible to cause NULL pointer dereference if the usb cable is disconnected while data transfer is running. In such case, a gadget driver may call usb_ep_disable()) before xfer_work() is actually called. In this case, the usbhs_pkt_pop() will call usbhsf_fifo_unselect(), and then usbhs_pipe_to_fifo() in xfer_work() will return NULL. Fixes: e73a989 ("usb: renesas_usbhs: add DMAEngine support") Cc: # v3.1+ Signed-off-by: Yoshihiro Shimoda Signed-off-by: Felipe Balbi diff --git a/drivers/usb/renesas_usbhs/fifo.c b/drivers/usb/renesas_usbhs/fifo.c index 7be4e7d..280ed5f 100644 --- a/drivers/usb/renesas_usbhs/fifo.c +++ b/drivers/usb/renesas_usbhs/fifo.c @@ -810,20 +810,27 @@ static void xfer_work(struct work_struct *work) { struct usbhs_pkt *pkt = container_of(work, struct usbhs_pkt, work); struct usbhs_pipe *pipe = pkt->pipe; - struct usbhs_fifo *fifo = usbhs_pipe_to_fifo(pipe); + struct usbhs_fifo *fifo; struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); struct dma_async_tx_descriptor *desc; - struct dma_chan *chan = usbhsf_dma_chan_get(fifo, pkt); + struct dma_chan *chan; struct device *dev = usbhs_priv_to_dev(priv); enum dma_transfer_direction dir; + unsigned long flags; + usbhs_lock(priv, flags); + fifo = usbhs_pipe_to_fifo(pipe); + if (!fifo) + goto xfer_work_end; + + chan = usbhsf_dma_chan_get(fifo, pkt); dir = usbhs_pipe_is_dir_in(pipe) ? DMA_DEV_TO_MEM : DMA_MEM_TO_DEV; desc = dmaengine_prep_slave_single(chan, pkt->dma + pkt->actual, pkt->trans, dir, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); if (!desc) - return; + goto xfer_work_end; desc->callback = usbhsf_dma_complete; desc->callback_param = pipe; @@ -831,7 +838,7 @@ static void xfer_work(struct work_struct *work) pkt->cookie = dmaengine_submit(desc); if (pkt->cookie < 0) { dev_err(dev, "Failed to submit dma descriptor\n"); - return; + goto xfer_work_end; } dev_dbg(dev, " %s %d (%d/ %d)\n", @@ -842,6 +849,9 @@ static void xfer_work(struct work_struct *work) usbhs_pipe_set_trans_count_if_bulk(pipe, pkt->trans); dma_async_issue_pending(chan); usbhs_pipe_enable(pipe); + +xfer_work_end: + usbhs_unlock(priv, flags); } /* -- cgit v0.10.2 From 15e4292a2d21e9997fdb2b8c014cc461b3f268f0 Mon Sep 17 00:00:00 2001 From: Yoshihiro Shimoda Date: Wed, 8 Jun 2016 16:32:50 +0900 Subject: usb: renesas_usbhs: protect the CFIFOSEL setting in usbhsg_ep_enable() This patch fixes an issue that the CFIFOSEL register value is possible to be changed by usbhsg_ep_enable() wrongly. And then, a data transfer using CFIFO may not work correctly. For example: # modprobe g_multi file=usb-storage.bin # ifconfig usb0 192.168.1.1 up (During the USB host is sending file to the mass storage) # ifconfig usb0 down In this case, since the u_ether.c may call usb_ep_enable() in eth_stop(), if the renesas_usbhs driver is also using CFIFO for mass storage, the mass storage may not work correctly. So, this patch adds usbhs_lock() and usbhs_unlock() calling in usbhsg_ep_enable() to protect CFIFOSEL register. This is because: - CFIFOSEL.CURPIPE = 0 is also needed for the pipe configuration - The CFIFOSEL (fifo->sel) is already protected by usbhs_lock() Fixes: 97664a207bc2 ("usb: renesas_usbhs: shrink spin lock area") Cc: # v3.1+ Signed-off-by: Yoshihiro Shimoda Signed-off-by: Felipe Balbi diff --git a/drivers/usb/renesas_usbhs/mod_gadget.c b/drivers/usb/renesas_usbhs/mod_gadget.c index 30345c2..50f3363 100644 --- a/drivers/usb/renesas_usbhs/mod_gadget.c +++ b/drivers/usb/renesas_usbhs/mod_gadget.c @@ -585,6 +585,9 @@ static int usbhsg_ep_enable(struct usb_ep *ep, struct usbhs_priv *priv = usbhsg_gpriv_to_priv(gpriv); struct usbhs_pipe *pipe; int ret = -EIO; + unsigned long flags; + + usbhs_lock(priv, flags); /* * if it already have pipe, @@ -593,7 +596,8 @@ static int usbhsg_ep_enable(struct usb_ep *ep, if (uep->pipe) { usbhs_pipe_clear(uep->pipe); usbhs_pipe_sequence_data0(uep->pipe); - return 0; + ret = 0; + goto usbhsg_ep_enable_end; } pipe = usbhs_pipe_malloc(priv, @@ -621,6 +625,9 @@ static int usbhsg_ep_enable(struct usb_ep *ep, ret = 0; } +usbhsg_ep_enable_end: + usbhs_unlock(priv, flags); + return ret; } -- cgit v0.10.2 From 6858107e78b4ecb9f244db814ffbdba1b5ce759b Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Wed, 29 Jun 2016 10:27:52 +0530 Subject: ALSA: hda - Add PCI ID for Kabylake-H Kabylake-H shows up as PCI ID 0xa2f0. We missed adding this earlier with other KBL IDs. Signed-off-by: Vinod Koul Cc: Signed-off-by: Takashi Iwai diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 94089fc..e320c44 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -367,9 +367,10 @@ enum { #define IS_SKL_LP(pci) ((pci)->vendor == 0x8086 && (pci)->device == 0x9d70) #define IS_KBL(pci) ((pci)->vendor == 0x8086 && (pci)->device == 0xa171) #define IS_KBL_LP(pci) ((pci)->vendor == 0x8086 && (pci)->device == 0x9d71) +#define IS_KBL_H(pci) ((pci)->vendor == 0x8086 && (pci)->device == 0xa2f0) #define IS_BXT(pci) ((pci)->vendor == 0x8086 && (pci)->device == 0x5a98) #define IS_SKL_PLUS(pci) (IS_SKL(pci) || IS_SKL_LP(pci) || IS_BXT(pci)) || \ - IS_KBL(pci) || IS_KBL_LP(pci) + IS_KBL(pci) || IS_KBL_LP(pci) || IS_KBL_H(pci) static char *driver_short_names[] = { [AZX_DRIVER_ICH] = "HDA Intel", @@ -2190,6 +2191,9 @@ static const struct pci_device_id azx_ids[] = { /* Kabylake-LP */ { PCI_DEVICE(0x8086, 0x9d71), .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_SKYLAKE }, + /* Kabylake-H */ + { PCI_DEVICE(0x8086, 0xa2f0), + .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_SKYLAKE }, /* Broxton-P(Apollolake) */ { PCI_DEVICE(0x8086, 0x5a98), .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_BROXTON }, -- cgit v0.10.2 From bc92126012c8c84988eebbbf9c8a246949b07462 Mon Sep 17 00:00:00 2001 From: Chanwoo Choi Date: Mon, 27 Jun 2016 21:09:04 +0900 Subject: extcon: Fix the wrong description about extcon_set/get_cable_state_() This patch fixes the wrong description about extcon_set/get_cable_state_() because they use the unique id of external connector instead of legacy name. Signed-off-by: Chanwoo Choi diff --git a/include/linux/extcon.h b/include/linux/extcon.h index 7bf530f..6100441 100644 --- a/include/linux/extcon.h +++ b/include/linux/extcon.h @@ -165,7 +165,7 @@ extern int extcon_update_state(struct extcon_dev *edev, u32 mask, u32 state); /* * get/set_cable_state access each bit of the 32b encoded state value. - * They are used to access the status of each cable based on the cable_name. + * They are used to access the status of each cable based on the cable id. */ extern int extcon_get_cable_state_(struct extcon_dev *edev, unsigned int id); extern int extcon_set_cable_state_(struct extcon_dev *edev, unsigned int id, -- cgit v0.10.2 From d4897e1935552663030fe7681a53eccc58d6aebd Mon Sep 17 00:00:00 2001 From: Andi Kleen Date: Fri, 24 Jun 2016 13:41:25 -0700 Subject: perf tools: Add documentation for perf.data on disk format Add some documentation for the on disk format of perf.data. This is not documenting the actual perf events -- which are documented in perf_event.h -- but just the additional headers that perf record adds around them when writing the data to disk. Signed-off-by: Andi Kleen Cc: Adrian Hunter Cc: Jiri Olsa Link: http://lkml.kernel.org/r/1466800885-12974-1-git-send-email-andi@firstfloor.org Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/Documentation/perf.data-file-format.txt b/tools/perf/Documentation/perf.data-file-format.txt new file mode 100644 index 0000000..fdc99fe --- /dev/null +++ b/tools/perf/Documentation/perf.data-file-format.txt @@ -0,0 +1,442 @@ +perf.data format + +Uptodate as of v4.7 + +This document describes the on-disk perf.data format, generated by perf record +or perf inject and consumed by the other perf tools. + +On a high level perf.data contains the events generated by the PMUs, plus metadata. + +All fields are in native-endian of the machine that generated the perf.data. + +When perf is writing to a pipe it uses a special version of the file +format that does not rely on seeking to adjust data offsets. This +format is not described here. The pipe version can be converted to +normal perf.data with perf inject. + +The file starts with a perf_header: + +struct perf_header { + char magic[8]; /* PERFILE2 */ + uint64_t size; /* size of the header */ + uint64_t attr_size; /* size of an attribute in attrs */ + struct perf_file_section attrs; + struct perf_file_section data; + struct perf_file_section event_types; + uint64_t flags; + uint64_t flags1[3]; +}; + +The magic number identifies the perf file and the version. Current perf versions +use PERFILE2. Old perf versions generated a version 1 format (PERFFILE). Version 1 +is not described here. The magic number also identifies the endian. When the +magic value is 64bit byte swapped compared the file is in non-native +endian. + +A perf_file_section contains a pointer to another section of the perf file. +The header contains three such pointers: for attributes, data and event types. + +struct perf_file_section { + uint64_t offset; /* offset from start of file */ + uint64_t size; /* size of the section */ +}; + +Flags section: + +The header is followed by different optional headers, described by the bits set +in flags. Only headers for which the bit is set are included. Each header +consists of a perf_file_section located after the initial header. +The respective perf_file_section points to the data of the additional +header and defines its size. + +Some headers consist of strings, which are defined like this: + +struct perf_header_string { + uint32_t len; + char string[len]; /* zero terminated */ +}; + +Some headers consist of a sequence of strings, which start with a + +struct perf_header_string_list { + uint32_t nr; + struct perf_header_string strings[nr]; /* variable length records */ +}; + +The bits are the flags bits in a 256 bit bitmap starting with +flags. These define the valid bits: + + HEADER_RESERVED = 0, /* always cleared */ + HEADER_FIRST_FEATURE = 1, + HEADER_TRACING_DATA = 1, + +Describe me. + + HEADER_BUILD_ID = 2, + +The header consists of an sequence of build_id_event. The size of each record +is defined by header.size (see perf_event.h). Each event defines a ELF build id +for a executable file name for a pid. An ELF build id is a unique identifier +assigned by the linker to an executable. + +struct build_id_event { + struct perf_event_header header; + pid_t pid; + uint8_t build_id[24]; + char filename[header.size - offsetof(struct build_id_event, filename)]; +}; + + HEADER_HOSTNAME = 3, + +A perf_header_string with the hostname where the data was collected +(uname -n) + + HEADER_OSRELEASE = 4, + +A perf_header_string with the os release where the data was collected +(uname -r) + + HEADER_VERSION = 5, + +A perf_header_string with the perf user tool version where the +data was collected. This is the same as the version of the source tree +the perf tool was built from. + + HEADER_ARCH = 6, + +A perf_header_string with the CPU architecture (uname -m) + + HEADER_NRCPUS = 7, + +A structure defining the number of CPUs. + +struct nr_cpus { + uint32_t nr_cpus_online; + uint32_t nr_cpus_available; /* CPUs not yet onlined */ +}; + + HEADER_CPUDESC = 8, + +A perf_header_string with description of the CPU. On x86 this is the model name +in /proc/cpuinfo + + HEADER_CPUID = 9, + +A perf_header_string with the exact CPU type. On x86 this is +vendor,family,model,stepping. For example: GenuineIntel,6,69,1 + + HEADER_TOTAL_MEM = 10, + +An uint64_t with the total memory in bytes. + + HEADER_CMDLINE = 11, + +A perf_header_string with the perf command line used to collect the data. + + HEADER_EVENT_DESC = 12, + +Another description of the perf_event_attrs, more detailed than header.attrs +including IDs and names. See perf_event.h or the man page for a description +of a struct perf_event_attr. + +struct { + uint32_t nr; /* number of events */ + uint32_t attr_size; /* size of each perf_event_attr */ + struct { + struct perf_event_attr attr; /* size of attr_size */ + uint32_t nr_ids; + struct perf_header_string event_string; + uint64_t ids[nr_ids]; + } events[nr]; /* Variable length records */ +}; + + HEADER_CPU_TOPOLOGY = 13, + +String lists defining the core and CPU threads topology. + +struct { + struct perf_header_string_list cores; /* Variable length */ + struct perf_header_string_list threads; /* Variable length */ +}; + +Example: + sibling cores : 0-3 + sibling threads : 0-1 + sibling threads : 2-3 + + HEADER_NUMA_TOPOLOGY = 14, + + A list of NUMA node descriptions + +struct { + uint32_t nr; + struct { + uint32_t nodenr; + uint64_t mem_total; + uint64_t mem_free; + struct perf_header_string cpus; + } nodes[nr]; /* Variable length records */ +}; + + HEADER_BRANCH_STACK = 15, + +Not implemented in perf. + + HEADER_PMU_MAPPINGS = 16, + + A list of PMU structures, defining the different PMUs supported by perf. + +struct { + uint32_t nr; + struct pmu { + uint32_t pmu_type; + struct perf_header_string pmu_name; + } [nr]; /* Variable length records */ +}; + + HEADER_GROUP_DESC = 17, + + Description of counter groups ({...} in perf syntax) + +struct { + uint32_t nr; + struct { + struct perf_header_string string; + uint32_t leader_idx; + uint32_t nr_members; + } [nr]; /* Variable length records */ +}; + + HEADER_AUXTRACE = 18, + +Define additional auxtrace areas in the perf.data. auxtrace is used to store +undecoded hardware tracing information, such as Intel Processor Trace data. + +/** + * struct auxtrace_index_entry - indexes a AUX area tracing event within a + * perf.data file. + * @file_offset: offset within the perf.data file + * @sz: size of the event + */ +struct auxtrace_index_entry { + u64 file_offset; + u64 sz; +}; + +#define PERF_AUXTRACE_INDEX_ENTRY_COUNT 256 + +/** + * struct auxtrace_index - index of AUX area tracing events within a perf.data + * file. + * @list: linking a number of arrays of entries + * @nr: number of entries + * @entries: array of entries + */ +struct auxtrace_index { + struct list_head list; + size_t nr; + struct auxtrace_index_entry entries[PERF_AUXTRACE_INDEX_ENTRY_COUNT]; +}; + + other bits are reserved and should ignored for now + HEADER_FEAT_BITS = 256, + +Attributes + +This is an array of perf_event_attrs, each attr_size bytes long, which defines +each event collected. See perf_event.h or the man page for a detailed +description. + +Data + +This section is the bulk of the file. It consist of a stream of perf_events +describing events. This matches the format generated by the kernel. +See perf_event.h or the manpage for a detailed description. + +Some notes on parsing: + +Ordering + +The events are not necessarily in time stamp order, as they can be +collected in parallel on different CPUs. If the events should be +processed in time order they need to be sorted first. It is possible +to only do a partial sort using the FINISHED_ROUND event header (see +below). perf record guarantees that there is no reordering over a +FINISHED_ROUND. + +ID vs IDENTIFIER + +When the event stream contains multiple events each event is identified +by an ID. This can be either through the PERF_SAMPLE_ID or the +PERF_SAMPLE_IDENTIFIER header. The PERF_SAMPLE_IDENTIFIER header is +at a fixed offset from the event header, which allows reliable +parsing of the header. Relying on ID may be ambigious. +IDENTIFIER is only supported by newer Linux kernels. + +Perf record specific events: + +In addition to the kernel generated event types perf record adds its +own event types (in addition it also synthesizes some kernel events, +for example MMAP events) + + PERF_RECORD_USER_TYPE_START = 64, + PERF_RECORD_HEADER_ATTR = 64, + +struct attr_event { + struct perf_event_header header; + struct perf_event_attr attr; + uint64_t id[]; +}; + + PERF_RECORD_HEADER_EVENT_TYPE = 65, /* depreceated */ + +#define MAX_EVENT_NAME 64 + +struct perf_trace_event_type { + uint64_t event_id; + char name[MAX_EVENT_NAME]; +}; + +struct event_type_event { + struct perf_event_header header; + struct perf_trace_event_type event_type; +}; + + + PERF_RECORD_HEADER_TRACING_DATA = 66, + +Describe me + +struct tracing_data_event { + struct perf_event_header header; + uint32_t size; +}; + + PERF_RECORD_HEADER_BUILD_ID = 67, + +Define a ELF build ID for a referenced executable. + + struct build_id_event; /* See above */ + + PERF_RECORD_FINISHED_ROUND = 68, + +No event reordering over this header. No payload. + + PERF_RECORD_ID_INDEX = 69, + +Map event ids to CPUs and TIDs. + +struct id_index_entry { + uint64_t id; + uint64_t idx; + uint64_t cpu; + uint64_t tid; +}; + +struct id_index_event { + struct perf_event_header header; + uint64_t nr; + struct id_index_entry entries[nr]; +}; + + PERF_RECORD_AUXTRACE_INFO = 70, + +Auxtrace type specific information. Describe me + +struct auxtrace_info_event { + struct perf_event_header header; + uint32_t type; + uint32_t reserved__; /* For alignment */ + uint64_t priv[]; +}; + + PERF_RECORD_AUXTRACE = 71, + +Defines auxtrace data. Followed by the actual data. The contents of +the auxtrace data is dependent on the event and the CPU. For example +for Intel Processor Trace it contains Processor Trace data generated +by the CPU. + +struct auxtrace_event { + struct perf_event_header header; + uint64_t size; + uint64_t offset; + uint64_t reference; + uint32_t idx; + uint32_t tid; + uint32_t cpu; + uint32_t reserved__; /* For alignment */ +}; + +struct aux_event { + struct perf_event_header header; + uint64_t aux_offset; + uint64_t aux_size; + uint64_t flags; +}; + + PERF_RECORD_AUXTRACE_ERROR = 72, + +Describes an error in hardware tracing + +enum auxtrace_error_type { + PERF_AUXTRACE_ERROR_ITRACE = 1, + PERF_AUXTRACE_ERROR_MAX +}; + +#define MAX_AUXTRACE_ERROR_MSG 64 + +struct auxtrace_error_event { + struct perf_event_header header; + uint32_t type; + uint32_t code; + uint32_t cpu; + uint32_t pid; + uint32_t tid; + uint32_t reserved__; /* For alignment */ + uint64_t ip; + char msg[MAX_AUXTRACE_ERROR_MSG]; +}; + +Event types + +Define the event attributes with their IDs. + +An array bound by the perf_file_section size. + + struct { + struct perf_event_attr attr; /* Size defined by header.attr_size */ + struct perf_file_section ids; + } + +ids points to a array of uint64_t defining the ids for event attr attr. + +References: + +include/uapi/linux/perf_event.h + +This is the canonical description of the kernel generated perf_events +and the perf_event_attrs. + +perf_events manpage + +A manpage describing perf_event and perf_event_attr is here: +http://web.eece.maine.edu/~vweaver/projects/perf_events/programming.html +This tends to be slightly behind the kernel include, but has better +descriptions. An (typically older) version of the man page may be +included with the standard Linux man pages, available with "man +perf_events" + +pmu-tools + +https://github.com/andikleen/pmu-tools/tree/master/parser + +A definition of the perf.data format in python "construct" format is available +in pmu-tools parser. This allows to read perf.data from python and dump it. + +quipper + +The quipper C++ parser is available at +https://chromium.googlesource.com/chromiumos/platform/chromiumos-wide-profiling/ +Unfortunately this parser tends to be many versions behind and may not be able +to parse data files generated by recent perf. -- cgit v0.10.2 From de8a63bd5076761fad4e236c93350fdf297708be Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Tue, 28 Jun 2016 13:23:37 +0100 Subject: tools lib bpf: Fix spelling mistake: "missmatch" -> "mismatch" Trivial fix to spelling mistake Signed-off-by: Colin King Acked-by: Wang Nan Cc: Alexei Starovoitov Cc: He Kuang Cc: Namhyung Kim Link: http://lkml.kernel.org/r/1467116617-8318-1-git-send-email-colin.king@canonical.com Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c index 462e526..a7cb40a 100644 --- a/tools/lib/bpf/libbpf.c +++ b/tools/lib/bpf/libbpf.c @@ -71,7 +71,7 @@ static const char *libbpf_strerror_table[NR_ERRNO] = { [ERRCODE_OFFSET(LIBELF)] = "Something wrong in libelf", [ERRCODE_OFFSET(FORMAT)] = "BPF object format invalid", [ERRCODE_OFFSET(KVERSION)] = "'version' section incorrect or lost", - [ERRCODE_OFFSET(ENDIAN)] = "Endian missmatch", + [ERRCODE_OFFSET(ENDIAN)] = "Endian mismatch", [ERRCODE_OFFSET(INTERNAL)] = "Internal error in libbpf", [ERRCODE_OFFSET(RELOC)] = "Relocation failed", [ERRCODE_OFFSET(VERIFY)] = "Kernel verifier blocks program loading", diff --git a/tools/lib/bpf/libbpf.h b/tools/lib/bpf/libbpf.h index 722f46b..148df36 100644 --- a/tools/lib/bpf/libbpf.h +++ b/tools/lib/bpf/libbpf.h @@ -19,7 +19,7 @@ enum libbpf_errno { LIBBPF_ERRNO__LIBELF = __LIBBPF_ERRNO__START, LIBBPF_ERRNO__FORMAT, /* BPF object format invalid */ LIBBPF_ERRNO__KVERSION, /* Incorrect or no 'version' section */ - LIBBPF_ERRNO__ENDIAN, /* Endian missmatch */ + LIBBPF_ERRNO__ENDIAN, /* Endian mismatch */ LIBBPF_ERRNO__INTERNAL, /* Internal error in libbpf */ LIBBPF_ERRNO__RELOC, /* Relocation failed */ LIBBPF_ERRNO__LOAD, /* Load program failure for unknown reason */ -- cgit v0.10.2 From 62db7152c924e4c060e42b34a69cd39658e8a0dc Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 29 Jun 2016 15:23:08 +0200 Subject: ALSA: au88x0: Fix calculation in vortex_wtdma_bufshift() vortex_wtdma_bufshift() function does calculate the page index wrongly, first masking then shift, which always results in zero. The proper computation is to first shift, then mask. Reported-by: Dan Carpenter Cc: Signed-off-by: Takashi Iwai diff --git a/sound/pci/au88x0/au88x0_core.c b/sound/pci/au88x0/au88x0_core.c index 4a054d7..d3125c1 100644 --- a/sound/pci/au88x0/au88x0_core.c +++ b/sound/pci/au88x0/au88x0_core.c @@ -1444,9 +1444,8 @@ static int vortex_wtdma_bufshift(vortex_t * vortex, int wtdma) int page, p, pp, delta, i; page = - (hwread(vortex->mmio, VORTEX_WTDMA_STAT + (wtdma << 2)) & - WT_SUBBUF_MASK) - >> WT_SUBBUF_SHIFT; + (hwread(vortex->mmio, VORTEX_WTDMA_STAT + (wtdma << 2)) + >> WT_SUBBUF_SHIFT) & WT_SUBBUF_MASK; if (dma->nr_periods >= 4) delta = (page - dma->period_real) & 3; else { -- cgit v0.10.2 From 838086414b3cda5c592591f2b82256996306dab6 Mon Sep 17 00:00:00 2001 From: Jarod Wilson Date: Thu, 9 Jun 2016 19:50:13 -0400 Subject: e1000e: keep Rx/Tx HW_VLAN_CTAG in sync The bit in the e1000 driver that mentions explicitly that the hardware has no support for separate RX/TX VLAN accel toggling rings true for e1000e as well, and thus both NETIF_F_HW_VLAN_CTAG_RX and NETIF_F_HW_VLAN_CTAG_TX need to be kept in sync. Revert a portion of commit 889ad456660461 ("e1000e: keep VLAN interfaces functional after rxvlan off") since keeping the bits in sync resolves the original issue. Signed-off-by: Jarod Wilson Tested-by: Aaron Brown Signed-off-by: Jeff Kirsher diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c index 73f7452..2b2e2f8 100644 --- a/drivers/net/ethernet/intel/e1000e/netdev.c +++ b/drivers/net/ethernet/intel/e1000e/netdev.c @@ -154,16 +154,6 @@ void __ew32(struct e1000_hw *hw, unsigned long reg, u32 val) writel(val, hw->hw_addr + reg); } -static bool e1000e_vlan_used(struct e1000_adapter *adapter) -{ - u16 vid; - - for_each_set_bit(vid, adapter->active_vlans, VLAN_N_VID) - return true; - - return false; -} - /** * e1000_regdump - register printout routine * @hw: pointer to the HW structure @@ -3453,8 +3443,7 @@ static void e1000e_set_rx_mode(struct net_device *netdev) ew32(RCTL, rctl); - if (netdev->features & NETIF_F_HW_VLAN_CTAG_RX || - e1000e_vlan_used(adapter)) + if (netdev->features & NETIF_F_HW_VLAN_CTAG_RX) e1000e_vlan_strip_enable(adapter); else e1000e_vlan_strip_disable(adapter); @@ -6926,6 +6915,14 @@ static netdev_features_t e1000_fix_features(struct net_device *netdev, if ((hw->mac.type >= e1000_pch2lan) && (netdev->mtu > ETH_DATA_LEN)) features &= ~NETIF_F_RXFCS; + /* Since there is no support for separate Rx/Tx vlan accel + * enable/disable make sure Tx flag is always in same state as Rx. + */ + if (features & NETIF_F_HW_VLAN_CTAG_RX) + features |= NETIF_F_HW_VLAN_CTAG_TX; + else + features &= ~NETIF_F_HW_VLAN_CTAG_TX; + return features; } -- cgit v0.10.2 From b3a3c5176c146ec7de653a3062237620464175fb Mon Sep 17 00:00:00 2001 From: Xin Long Date: Fri, 13 May 2016 01:51:55 +0800 Subject: ixgbevf: ixgbevf_write/read_posted_mbx should use IXGBE_ERR_MBX to initialize ret_val Now ixgbevf_write/read_posted_mbx use -IXGBE_ERR_MBX as the initiative return value, but it's incorrect, cause in ixgbevf_vlan_rx_add_vid(), it use err == IXGBE_ERR_MBX, the err returned from mac.ops.set_vfta, and in ixgbevf_set_vfta_vf, it return from write/read_posted. so we should initialize err with IXGBE_ERR_MBX, instead of -IXGBE_ERR_MBX. With this fix, the other functions that called it also can work well, cause they only care about if err is 0 or not. Signed-off-by: Xin Long Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher diff --git a/drivers/net/ethernet/intel/ixgbevf/mbx.c b/drivers/net/ethernet/intel/ixgbevf/mbx.c index 61a80da..2819abc 100644 --- a/drivers/net/ethernet/intel/ixgbevf/mbx.c +++ b/drivers/net/ethernet/intel/ixgbevf/mbx.c @@ -85,7 +85,7 @@ static s32 ixgbevf_poll_for_ack(struct ixgbe_hw *hw) static s32 ixgbevf_read_posted_mbx(struct ixgbe_hw *hw, u32 *msg, u16 size) { struct ixgbe_mbx_info *mbx = &hw->mbx; - s32 ret_val = -IXGBE_ERR_MBX; + s32 ret_val = IXGBE_ERR_MBX; if (!mbx->ops.read) goto out; @@ -111,7 +111,7 @@ out: static s32 ixgbevf_write_posted_mbx(struct ixgbe_hw *hw, u32 *msg, u16 size) { struct ixgbe_mbx_info *mbx = &hw->mbx; - s32 ret_val = -IXGBE_ERR_MBX; + s32 ret_val = IXGBE_ERR_MBX; /* exit if either we can't write or there isn't a defined timeout */ if (!mbx->ops.write || !mbx->timeout) -- cgit v0.10.2 From 7b427a59538a98161321aa46c13f4ea81b43f4eb Mon Sep 17 00:00:00 2001 From: Bob Liu Date: Mon, 27 Jun 2016 16:33:24 +0800 Subject: xen-blkfront: save uncompleted reqs in blkfront_resume() Uncompleted reqs used to be 'saved and resubmitted' in blkfront_recover() during migration, but that's too late after multi-queue was introduced. After a migrate to another host (which may not have multiqueue support), the number of rings (block hardware queues) may be changed and the ring and shadow structure will also be reallocated. The blkfront_recover() then can't 'save and resubmit' the real uncompleted reqs because shadow structure have been reallocated. This patch fixes this issue by moving the 'save' logic out of blkfront_recover() to earlier place in blkfront_resume(). The 'resubmit' is not changed and still in blkfront_recover(). Signed-off-by: Bob Liu Signed-off-by: Konrad Rzeszutek Wilk Cc: stable@vger.kernel.org diff --git a/drivers/block/xen-blkfront.c b/drivers/block/xen-blkfront.c index 2e6d1e9..fcc5b4e 100644 --- a/drivers/block/xen-blkfront.c +++ b/drivers/block/xen-blkfront.c @@ -207,6 +207,9 @@ struct blkfront_info struct blk_mq_tag_set tag_set; struct blkfront_ring_info *rinfo; unsigned int nr_rings; + /* Save uncomplete reqs and bios for migration. */ + struct list_head requests; + struct bio_list bio_list; }; static unsigned int nr_minors; @@ -2002,69 +2005,22 @@ static int blkif_recover(struct blkfront_info *info) { unsigned int i, r_index; struct request *req, *n; - struct blk_shadow *copy; int rc; struct bio *bio, *cloned_bio; - struct bio_list bio_list, merge_bio; unsigned int segs, offset; int pending, size; struct split_bio *split_bio; - struct list_head requests; blkfront_gather_backend_features(info); segs = info->max_indirect_segments ? : BLKIF_MAX_SEGMENTS_PER_REQUEST; blk_queue_max_segments(info->rq, segs); - bio_list_init(&bio_list); - INIT_LIST_HEAD(&requests); for (r_index = 0; r_index < info->nr_rings; r_index++) { - struct blkfront_ring_info *rinfo; - - rinfo = &info->rinfo[r_index]; - /* Stage 1: Make a safe copy of the shadow state. */ - copy = kmemdup(rinfo->shadow, sizeof(rinfo->shadow), - GFP_NOIO | __GFP_REPEAT | __GFP_HIGH); - if (!copy) - return -ENOMEM; - - /* Stage 2: Set up free list. */ - memset(&rinfo->shadow, 0, sizeof(rinfo->shadow)); - for (i = 0; i < BLK_RING_SIZE(info); i++) - rinfo->shadow[i].req.u.rw.id = i+1; - rinfo->shadow_free = rinfo->ring.req_prod_pvt; - rinfo->shadow[BLK_RING_SIZE(info)-1].req.u.rw.id = 0x0fffffff; + struct blkfront_ring_info *rinfo = &info->rinfo[r_index]; rc = blkfront_setup_indirect(rinfo); - if (rc) { - kfree(copy); + if (rc) return rc; - } - - for (i = 0; i < BLK_RING_SIZE(info); i++) { - /* Not in use? */ - if (!copy[i].request) - continue; - - /* - * Get the bios in the request so we can re-queue them. - */ - if (copy[i].request->cmd_flags & - (REQ_FLUSH | REQ_FUA | REQ_DISCARD | REQ_SECURE)) { - /* - * Flush operations don't contain bios, so - * we need to requeue the whole request - */ - list_add(©[i].request->queuelist, &requests); - continue; - } - merge_bio.head = copy[i].request->bio; - merge_bio.tail = copy[i].request->biotail; - bio_list_merge(&bio_list, &merge_bio); - copy[i].request->bio = NULL; - blk_end_request_all(copy[i].request, 0); - } - - kfree(copy); } xenbus_switch_state(info->xbdev, XenbusStateConnected); @@ -2079,7 +2035,7 @@ static int blkif_recover(struct blkfront_info *info) kick_pending_request_queues(rinfo); } - list_for_each_entry_safe(req, n, &requests, queuelist) { + list_for_each_entry_safe(req, n, &info->requests, queuelist) { /* Requeue pending requests (flush or discard) */ list_del_init(&req->queuelist); BUG_ON(req->nr_phys_segments > segs); @@ -2087,7 +2043,7 @@ static int blkif_recover(struct blkfront_info *info) } blk_mq_kick_requeue_list(info->rq); - while ((bio = bio_list_pop(&bio_list)) != NULL) { + while ((bio = bio_list_pop(&info->bio_list)) != NULL) { /* Traverse the list of pending bios and re-queue them */ if (bio_segments(bio) > segs) { /* @@ -2133,9 +2089,42 @@ static int blkfront_resume(struct xenbus_device *dev) { struct blkfront_info *info = dev_get_drvdata(&dev->dev); int err = 0; + unsigned int i, j; dev_dbg(&dev->dev, "blkfront_resume: %s\n", dev->nodename); + bio_list_init(&info->bio_list); + INIT_LIST_HEAD(&info->requests); + for (i = 0; i < info->nr_rings; i++) { + struct blkfront_ring_info *rinfo = &info->rinfo[i]; + struct bio_list merge_bio; + struct blk_shadow *shadow = rinfo->shadow; + + for (j = 0; j < BLK_RING_SIZE(info); j++) { + /* Not in use? */ + if (!shadow[j].request) + continue; + + /* + * Get the bios in the request so we can re-queue them. + */ + if (shadow[j].request->cmd_flags & + (REQ_FLUSH | REQ_FUA | REQ_DISCARD | REQ_SECURE)) { + /* + * Flush operations don't contain bios, so + * we need to requeue the whole request + */ + list_add(&shadow[j].request->queuelist, &info->requests); + continue; + } + merge_bio.head = shadow[j].request->bio; + merge_bio.tail = shadow[j].request->biotail; + bio_list_merge(&info->bio_list, &merge_bio); + shadow[j].request->bio = NULL; + blk_mq_end_request(shadow[j].request, 0); + } + } + blkif_free(info, info->connected == BLKIF_STATE_CONNECTED); err = negotiate_mq(info); -- cgit v0.10.2 From 9a9b6aa6a8759c83024627d681eff982d6ee03b7 Mon Sep 17 00:00:00 2001 From: Douglas Anderson Date: Tue, 28 Jun 2016 10:32:00 -0700 Subject: Input: add SW_PEN_INSERTED define Some devices with a pen may have a switch that can be used to detect when the pen is inserted or removed to a slot on the device. Let's add a define to the input event codes so that everyone can be on the same page for what event we should generate when the pen is inserted or removed. In general the pen switch could be used by the software on the device to kick off any number of actions when the pen is inserted or removed. Signed-off-by: Douglas Anderson Signed-off-by: Dmitry Torokhov diff --git a/include/uapi/linux/input-event-codes.h b/include/uapi/linux/input-event-codes.h index 737fa32..d6d071f 100644 --- a/include/uapi/linux/input-event-codes.h +++ b/include/uapi/linux/input-event-codes.h @@ -780,6 +780,7 @@ #define SW_ROTATE_LOCK 0x0c /* set = rotate locked/disabled */ #define SW_LINEIN_INSERT 0x0d /* set = inserted */ #define SW_MUTE_DEVICE 0x0e /* set = device disabled */ +#define SW_PEN_INSERTED 0x0f /* set = pen inserted */ #define SW_MAX 0x0f #define SW_CNT (SW_MAX+1) -- cgit v0.10.2 From caca925fca4fb30c67be88cacbe908eec6721e43 Mon Sep 17 00:00:00 2001 From: Cameron Gutman Date: Wed, 29 Jun 2016 09:51:35 -0700 Subject: Input: xpad - validate USB endpoint count during probe This prevents a malicious USB device from causing an oops. Signed-off-by: Cameron Gutman Cc: stable@vger.kernel.org Signed-off-by: Dmitry Torokhov diff --git a/drivers/input/joystick/xpad.c b/drivers/input/joystick/xpad.c index 3438e98..a529a45 100644 --- a/drivers/input/joystick/xpad.c +++ b/drivers/input/joystick/xpad.c @@ -1431,6 +1431,9 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id int ep_irq_in_idx; int i, error; + if (intf->cur_altsetting->desc.bNumEndpoints != 2) + return -ENODEV; + for (i = 0; xpad_device[i].idVendor; i++) { if ((le16_to_cpu(udev->descriptor.idVendor) == xpad_device[i].idVendor) && (le16_to_cpu(udev->descriptor.idProduct) == xpad_device[i].idProduct)) -- cgit v0.10.2 From 4f14f5c11db161ab89b02f7196496ca32ca5dbf8 Mon Sep 17 00:00:00 2001 From: Alexander Shiyan Date: Sat, 25 Jun 2016 07:59:22 +0300 Subject: ASoC: fsl_ssi: Fix number of words per frame for I2S-slave mode The i.MX51 datasheet says: Chapter 56.1.2.4 I2S Mode ... When I2S modes are entered (I2S master (01) or I2S slave (10)), the following settings are recommended: ... - TX Frame Rate should be 2 i.e. (STCCR[12:8] = 1) - RX Frame Rate should be 2 i.e. (SRCCR[12:8] = 1) Chapter 56.3.3.12 SSI Transmit and Receive Clock Control Registers (STCCR & SRCCR) ... Bits 12-8 DC4-DC0 Frame Rate Divider Control. These bits are used to control the divide ratio for the programmable frame rate dividers. The divide ratio works on the word clock. In Normal mode, this ratio determines the word transfer rate. In Network mode, this ratio sets the number of words per frame. The divide ratio ranges from 1 to 32 in Normal mode and from 2 to 32 in Network mode. In Normal mode, a divide ratio of 1 (DC=00000) provides continuous periodic data word transfer. A bit-length frame sync must be used in this case. Function fsl_ssi_hw_params() setup Normal mode for MONO output, so with DC=0, SSI enters to continuous periodic data word transfer. To fix this, setup DC for any I2S mode. Patch has tested on custom board based on Digi CCMX-51 module (i.MX51). Signed-off-by: Alexander Shiyan Signed-off-by: Mark Brown diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c index 632ecc0..bedec4a 100644 --- a/sound/soc/fsl/fsl_ssi.c +++ b/sound/soc/fsl/fsl_ssi.c @@ -952,16 +952,16 @@ static int _fsl_ssi_set_dai_fmt(struct device *dev, ssi_private->i2s_mode = CCSR_SSI_SCR_NET; switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { case SND_SOC_DAIFMT_I2S: + regmap_update_bits(regs, CCSR_SSI_STCCR, + CCSR_SSI_SxCCR_DC_MASK, + CCSR_SSI_SxCCR_DC(2)); + regmap_update_bits(regs, CCSR_SSI_SRCCR, + CCSR_SSI_SxCCR_DC_MASK, + CCSR_SSI_SxCCR_DC(2)); switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { case SND_SOC_DAIFMT_CBM_CFS: case SND_SOC_DAIFMT_CBS_CFS: ssi_private->i2s_mode |= CCSR_SSI_SCR_I2S_MODE_MASTER; - regmap_update_bits(regs, CCSR_SSI_STCCR, - CCSR_SSI_SxCCR_DC_MASK, - CCSR_SSI_SxCCR_DC(2)); - regmap_update_bits(regs, CCSR_SSI_SRCCR, - CCSR_SSI_SxCCR_DC_MASK, - CCSR_SSI_SxCCR_DC(2)); break; case SND_SOC_DAIFMT_CBM_CFM: ssi_private->i2s_mode |= CCSR_SSI_SCR_I2S_MODE_SLAVE; -- cgit v0.10.2 From f8608985f851c917b3884b692d8e326b0210d34e Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Wed, 18 May 2016 16:16:51 +0200 Subject: configfs: Remove ppos increment in configfs_write_bin_file The simple_write_to_buffer() already increments the @ppos on success, see fs/libfs.c simple_write_to_buffer() comment: " On success, the number of bytes written is returned and the offset @ppos advanced by this number, or negative value is returned on error. " If the configfs_write_bin_file() is invoked with @count smaller than the total length of the written binary file, it will be invoked multiple times. Since configfs_write_bin_file() increments @ppos on success, after calling simple_write_to_buffer(), the @ppos is incremented twice. Subsequent invocation of configfs_write_bin_file() will result in the next piece of data being written to the offset twice as long as the length of the previous write, thus creating buffer with "holes" in it. The simple testcase using DTO follows: $ mkdir /sys/kernel/config/device-tree/overlays/1 $ dd bs=1 if=foo.dtbo of=/sys/kernel/config/device-tree/overlays/1/dtbo Without this patch, the testcase will result in twice as big buffer in the kernel, which is then passed to the cfs_overlay_item_dtbo_write() . Signed-off-by: Marek Vasut Cc: Geert Uytterhoeven Cc: Christoph Hellwig Cc: Pantelis Antoniou diff --git a/fs/configfs/file.c b/fs/configfs/file.c index 33b7ee3..bbc1252 100644 --- a/fs/configfs/file.c +++ b/fs/configfs/file.c @@ -357,8 +357,6 @@ configfs_write_bin_file(struct file *file, const char __user *buf, len = simple_write_to_buffer(buffer->bin_buffer, buffer->bin_buffer_size, ppos, buf, count); - if (len > 0) - *ppos += len; out: mutex_unlock(&buffer->mutex); return len; -- cgit v0.10.2 From f4e47f9f7b0bcbb1069b93bd719a1d34fb37d933 Mon Sep 17 00:00:00 2001 From: Ravi Bangoria Date: Thu, 30 Jun 2016 11:44:19 +0530 Subject: perf evsel: Utility function to fetch arch Add Utility function to fetch arch using evsel. (evsel->env->arch) Signed-off-by: Ravi Bangoria Cc: Ananth N Mavinakayanahalli Cc: Anton Blanchard Cc: Daniel Axtens Cc: David Laight Cc: Michael Ellerman Cc: Naveen N. Rao Link: http://lkml.kernel.org/r/1467267262-4589-2-git-send-email-ravi.bangoria@linux.vnet.ibm.com Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index 1d8f2bb..0fea724 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c @@ -2422,3 +2422,10 @@ int perf_evsel__open_strerror(struct perf_evsel *evsel, struct target *target, err, strerror_r(err, sbuf, sizeof(sbuf)), perf_evsel__name(evsel)); } + +char *perf_evsel__env_arch(struct perf_evsel *evsel) +{ + if (evsel && evsel->evlist && evsel->evlist->env) + return evsel->evlist->env->arch; + return NULL; +} diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h index 828ddd1..86fed7a 100644 --- a/tools/perf/util/evsel.h +++ b/tools/perf/util/evsel.h @@ -435,4 +435,6 @@ typedef int (*attr__fprintf_f)(FILE *, const char *, const char *, void *); int perf_event_attr__fprintf(FILE *fp, struct perf_event_attr *attr, attr__fprintf_f attr__fprintf, void *priv); +char *perf_evsel__env_arch(struct perf_evsel *evsel); + #endif /* __PERF_EVSEL_H */ -- cgit v0.10.2 From b44439e42912b9dcc510a0ff891809ea2cadc46b Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Mon, 20 Jun 2016 18:08:22 +0200 Subject: ARM: mvebu: compile pm code conditionally A cleanup to include the headers correctly caused another build problem: arch/arm/mach-mvebu/kirkwood-pm.c:70:13: error: redefinition of 'kirkwood_pm_init' arch/arm/mach-mvebu/kirkwood-pm.h:23:20: note: previous definition of 'kirkwood_pm_init' was here The underlying issue is that kirkwood-pm.o is not actually meant to be used when CONFIG_PM is disabled, so we should also leave it out of the Makefile. The same seems to be true for the PM code in MACH_MVEBU_V7, and I'm treating it the same way here. Signed-off-by: Arnd Bergmann Fixes: d705c1a66e15 ("ARM: Kirkwood: fix kirkwood_pm_init() declaration/type") Signed-off-by: Gregory CLEMENT diff --git a/arch/arm/mach-mvebu/Makefile b/arch/arm/mach-mvebu/Makefile index ecf9e0c..e53c6cf 100644 --- a/arch/arm/mach-mvebu/Makefile +++ b/arch/arm/mach-mvebu/Makefile @@ -7,9 +7,15 @@ CFLAGS_pmsu.o := -march=armv7-a obj-$(CONFIG_MACH_MVEBU_ANY) += system-controller.o mvebu-soc-id.o ifeq ($(CONFIG_MACH_MVEBU_V7),y) -obj-y += cpu-reset.o board-v7.o coherency.o coherency_ll.o pmsu.o pmsu_ll.o pm.o pm-board.o +obj-y += cpu-reset.o board-v7.o coherency.o coherency_ll.o pmsu.o pmsu_ll.o + +obj-$(CONFIG_PM) += pm.o pm-board.o obj-$(CONFIG_SMP) += platsmp.o headsmp.o platsmp-a9.o headsmp-a9.o endif obj-$(CONFIG_MACH_DOVE) += dove.o -obj-$(CONFIG_MACH_KIRKWOOD) += kirkwood.o kirkwood-pm.o + +ifeq ($(CONFIG_MACH_KIRKWOOD),y) +obj-y += kirkwood.o +obj-$(CONFIG_PM) += kirkwood-pm.o +endif -- cgit v0.10.2 From 53dd9b5f95dda95bcadda1b4680be42dfe1f9e5e Mon Sep 17 00:00:00 2001 From: "Peter Zijlstra (Intel)" Date: Thu, 30 Jun 2016 09:17:26 -0300 Subject: perf annotate: Simplify header dotted line sizing No need to use strlen, etc to figure that out, just use the return from printf(), it will tell how wide the following line needs to be. Signed-off-by: Peter Zijlstra (Intel) Cc: Jiri Olsa Link: http://lkml.kernel.org/r/20160630082955.GA30921@twins.programming.kicks-ass.net [ split from a larger patch ] Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index c385fec..78e5d6f 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -1528,7 +1528,7 @@ int symbol__annotate_printf(struct symbol *sym, struct map *map, int more = 0; u64 len; int width = 8; - int namelen, evsel_name_len, graph_dotted_len; + int graph_dotted_len; filename = strdup(dso->long_name); if (!filename) @@ -1540,17 +1540,14 @@ int symbol__annotate_printf(struct symbol *sym, struct map *map, d_filename = basename(filename); len = symbol__size(sym); - namelen = strlen(d_filename); - evsel_name_len = strlen(evsel_name); if (perf_evsel__is_group_event(evsel)) width *= evsel->nr_members; - printf(" %-*.*s| Source code & Disassembly of %s for %s\n", + graph_dotted_len = printf(" %-*.*s| Source code & Disassembly of %s for %s\n", width, width, "Percent", d_filename, evsel_name); - graph_dotted_len = width + namelen + evsel_name_len; - printf("-%-*.*s-----------------------------------------\n", + printf("%-*.*s----\n", graph_dotted_len, graph_dotted_len, graph_dotted_line); if (verbose) -- cgit v0.10.2 From fedbb6b4ff341c1e2120f4ffbf367fd78ac3e8f3 Mon Sep 17 00:00:00 2001 From: Shmulik Ladkani Date: Wed, 29 Jun 2016 21:47:03 +0300 Subject: ipv4: Fix ip_skb_dst_mtu to use the sk passed by ip_finish_output ip_skb_dst_mtu uses skb->sk, assuming it is an AF_INET socket (e.g. it calls ip_sk_use_pmtu which casts sk as an inet_sk). However, in the case of UDP tunneling, the skb->sk is not necessarily an inet socket (could be AF_PACKET socket, or AF_UNSPEC if arriving from tun/tap). OTOH, the sk passed as an argument throughout IP stack's output path is the one which is of PMTU interest: - In case of local sockets, sk is same as skb->sk; - In case of a udp tunnel, sk is the tunneling socket. Fix, by passing ip_finish_output's sk to ip_skb_dst_mtu. This augments 7026b1ddb6 'netfilter: Pass socket pointer down through okfn().' Signed-off-by: Shmulik Ladkani Reviewed-by: Hannes Frederic Sowa Signed-off-by: David S. Miller diff --git a/include/net/ip.h b/include/net/ip.h index 37165fb..08f36cd 100644 --- a/include/net/ip.h +++ b/include/net/ip.h @@ -313,10 +313,9 @@ static inline unsigned int ip_dst_mtu_maybe_forward(const struct dst_entry *dst, return min(dst->dev->mtu, IP_MAX_MTU); } -static inline unsigned int ip_skb_dst_mtu(const struct sk_buff *skb) +static inline unsigned int ip_skb_dst_mtu(struct sock *sk, + const struct sk_buff *skb) { - struct sock *sk = skb->sk; - if (!sk || !sk_fullsock(sk) || ip_sk_use_pmtu(sk)) { bool forwarding = IPCB(skb)->flags & IPSKB_FORWARDED; diff --git a/net/bridge/br_netfilter_hooks.c b/net/bridge/br_netfilter_hooks.c index 2d25979..77e7f69 100644 --- a/net/bridge/br_netfilter_hooks.c +++ b/net/bridge/br_netfilter_hooks.c @@ -700,7 +700,7 @@ static int br_nf_ip_fragment(struct net *net, struct sock *sk, struct sk_buff *skb, int (*output)(struct net *, struct sock *, struct sk_buff *)) { - unsigned int mtu = ip_skb_dst_mtu(skb); + unsigned int mtu = ip_skb_dst_mtu(sk, skb); struct iphdr *iph = ip_hdr(skb); if (unlikely(((iph->frag_off & htons(IP_DF)) && !skb->ignore_df) || diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c index 124bf0a..4bd4921 100644 --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c @@ -271,7 +271,7 @@ static int ip_finish_output(struct net *net, struct sock *sk, struct sk_buff *sk return dst_output(net, sk, skb); } #endif - mtu = ip_skb_dst_mtu(skb); + mtu = ip_skb_dst_mtu(sk, skb); if (skb_is_gso(skb)) return ip_finish_output_gso(net, sk, skb, mtu); @@ -541,7 +541,7 @@ int ip_do_fragment(struct net *net, struct sock *sk, struct sk_buff *skb, iph = ip_hdr(skb); - mtu = ip_skb_dst_mtu(skb); + mtu = ip_skb_dst_mtu(sk, skb); if (IPCB(skb)->frag_max_size && IPCB(skb)->frag_max_size < mtu) mtu = IPCB(skb)->frag_max_size; -- cgit v0.10.2 From 43daa96b166c3cf5ff30dfac0c5efa2620e4beab Mon Sep 17 00:00:00 2001 From: Soohoon Lee Date: Wed, 29 Jun 2016 15:07:21 -0400 Subject: usbnet: Stop RX Q on MTU change When MTU is changed unlink_urbs() flushes RX Q but mean while usbnet_bh() can fill up the Q at the same time. Depends on which HCD is down there unlink takes long time then the flush never ends. Signed-off-by: Soohoon Lee Reviewed-by: Kimball Murray Signed-off-by: David S. Miller diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c index 61ba464..6086a01 100644 --- a/drivers/net/usb/usbnet.c +++ b/drivers/net/usb/usbnet.c @@ -395,8 +395,11 @@ int usbnet_change_mtu (struct net_device *net, int new_mtu) dev->hard_mtu = net->mtu + net->hard_header_len; if (dev->rx_urb_size == old_hard_mtu) { dev->rx_urb_size = dev->hard_mtu; - if (dev->rx_urb_size > old_rx_urb_size) + if (dev->rx_urb_size > old_rx_urb_size) { + usbnet_pause_rx(dev); usbnet_unlink_rx_urbs(dev); + usbnet_resume_rx(dev); + } } /* max qlen depend on hard_mtu and rx_urb_size */ @@ -1508,8 +1511,9 @@ static void usbnet_bh (unsigned long param) } else if (netif_running (dev->net) && netif_device_present (dev->net) && netif_carrier_ok(dev->net) && - !timer_pending (&dev->delay) && - !test_bit (EVENT_RX_HALT, &dev->flags)) { + !timer_pending(&dev->delay) && + !test_bit(EVENT_RX_PAUSED, &dev->flags) && + !test_bit(EVENT_RX_HALT, &dev->flags)) { int temp = dev->rxq.qlen; if (temp < RX_QLEN(dev)) { -- cgit v0.10.2 From af61f96109b73fefbe0589c320d2219567f4f660 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 29 Jun 2016 16:38:30 +0200 Subject: extcon: link devres into core module Splitting the resource-managed functions into a separate module means that the extcon core now fails to build because the internal "extcon_dev_allocate" symbol is not exported: ERROR: extcon_dev_allocate [drivers/extcon/devres.ko] undefined! My guess is that the intention was not to have two separate modules (which could be fixed by adding an export, plus the normal MODULE_AUTHOR/MODULE_LICENSE/... fields), but have two source files in the same module. This fixes the Makefile accordingly, making the name of the module extcon_core.ko, which is created from building both extcon.c and devres.c. Fixes: b225d00f3ad2 ("extcon: Split out the resource-managed functions from extcon core") Signed-off-by: Arnd Bergmann Signed-off-by: Chanwoo Choi diff --git a/drivers/extcon/Makefile b/drivers/extcon/Makefile index 423ebc8..972c813 100644 --- a/drivers/extcon/Makefile +++ b/drivers/extcon/Makefile @@ -2,7 +2,8 @@ # Makefile for external connector class (extcon) devices # -obj-$(CONFIG_EXTCON) += extcon.o devres.o +obj-$(CONFIG_EXTCON) += extcon-core.o +extcon-core-objs += extcon.o devres.o obj-$(CONFIG_EXTCON_ADC_JACK) += extcon-adc-jack.o obj-$(CONFIG_EXTCON_ARIZONA) += extcon-arizona.o obj-$(CONFIG_EXTCON_AXP288) += extcon-axp288.o -- cgit v0.10.2 From eaaa7ec71bff4cb34d9025ed89068d4b3cac3df0 Mon Sep 17 00:00:00 2001 From: Gregor Boirie Date: Wed, 9 Mar 2016 19:05:48 +0100 Subject: timekeeping: export get_monotonic_coarse64 symbol EXPORT_SYMBOL() get_monotonic_coarse64 for new IIO timestamping clock selection usage. This provides user apps the ability to request a particular IIO device to timestamp samples using a monotonic coarse clock granularity. Signed-off-by: Gregor Boirie Signed-off-by: Jonathan Cameron diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c index 479d25c..255e225 100644 --- a/kernel/time/timekeeping.c +++ b/kernel/time/timekeeping.c @@ -2186,6 +2186,7 @@ struct timespec64 get_monotonic_coarse64(void) return now; } +EXPORT_SYMBOL(get_monotonic_coarse64); /* * Must hold jiffies_lock -- cgit v0.10.2 From bc2b7dab629a51e8beb5fda4222c62a23b729f26 Mon Sep 17 00:00:00 2001 From: Gregor Boirie Date: Wed, 9 Mar 2016 19:05:49 +0100 Subject: iio:core: timestamping clock selection support Adds a new per-device sysfs attribute "current_timestamp_clock" to allow userspace to select a particular POSIX clock for buffered samples and events timestamping. Following clocks, as listed in clock_gettime(2), are supported: CLOCK_REALTIME, CLOCK_MONOTONIC, CLOCK_MONOTONIC_RAW, CLOCK_REALTIME_COARSE, CLOCK_MONOTONIC_COARSE, CLOCK_BOOTTIME and CLOCK_TAI. Signed-off-by: Gregor Boirie Acked-by: Sanchayan Maity Signed-off-by: Jonathan Cameron diff --git a/Documentation/ABI/testing/sysfs-bus-iio b/Documentation/ABI/testing/sysfs-bus-iio index e7f590c..fee35c0 100644 --- a/Documentation/ABI/testing/sysfs-bus-iio +++ b/Documentation/ABI/testing/sysfs-bus-iio @@ -32,6 +32,13 @@ Description: Description of the physical chip / device for device X. Typically a part number. +What: /sys/bus/iio/devices/iio:deviceX/timestamp_clock +KernelVersion: 4.5 +Contact: linux-iio@vger.kernel.org +Description: + String identifying current posix clock used to timestamp + buffered samples and events for device X. + What: /sys/bus/iio/devices/iio:deviceX/sampling_frequency What: /sys/bus/iio/devices/iio:deviceX/buffer/sampling_frequency What: /sys/bus/iio/devices/triggerX/sampling_frequency diff --git a/Documentation/DocBook/iio.tmpl b/Documentation/DocBook/iio.tmpl index f525bf5..e2ab6a1 100644 --- a/Documentation/DocBook/iio.tmpl +++ b/Documentation/DocBook/iio.tmpl @@ -594,7 +594,7 @@ irqreturn_t sensor_iio_pollfunc(int irq, void *p) { - pf->timestamp = iio_get_time_ns(); + pf->timestamp = iio_get_time_ns((struct indio_dev *)p); return IRQ_WAKE_THREAD; } diff --git a/drivers/iio/accel/bma180.c b/drivers/iio/accel/bma180.c index f04b884..e3f88ba 100644 --- a/drivers/iio/accel/bma180.c +++ b/drivers/iio/accel/bma180.c @@ -654,7 +654,7 @@ static irqreturn_t bma180_trigger_handler(int irq, void *p) struct iio_poll_func *pf = p; struct iio_dev *indio_dev = pf->indio_dev; struct bma180_data *data = iio_priv(indio_dev); - int64_t time_ns = iio_get_time_ns(); + s64 time_ns = iio_get_time_ns(indio_dev); int bit, ret, i = 0; mutex_lock(&data->mutex); diff --git a/drivers/iio/accel/bmc150-accel-core.c b/drivers/iio/accel/bmc150-accel-core.c index 197e693..bf17aae 100644 --- a/drivers/iio/accel/bmc150-accel-core.c +++ b/drivers/iio/accel/bmc150-accel-core.c @@ -901,7 +901,7 @@ static int __bmc150_accel_fifo_flush(struct iio_dev *indio_dev, */ if (!irq) { data->old_timestamp = data->timestamp; - data->timestamp = iio_get_time_ns(); + data->timestamp = iio_get_time_ns(indio_dev); } /* @@ -1303,7 +1303,7 @@ static irqreturn_t bmc150_accel_irq_handler(int irq, void *private) int i; data->old_timestamp = data->timestamp; - data->timestamp = iio_get_time_ns(); + data->timestamp = iio_get_time_ns(indio_dev); for (i = 0; i < BMC150_ACCEL_TRIGGERS; i++) { if (data->triggers[i].enabled) { diff --git a/drivers/iio/accel/kxcjk-1013.c b/drivers/iio/accel/kxcjk-1013.c index bfe219a..765a723 100644 --- a/drivers/iio/accel/kxcjk-1013.c +++ b/drivers/iio/accel/kxcjk-1013.c @@ -1129,7 +1129,7 @@ static irqreturn_t kxcjk1013_data_rdy_trig_poll(int irq, void *private) struct iio_dev *indio_dev = private; struct kxcjk1013_data *data = iio_priv(indio_dev); - data->timestamp = iio_get_time_ns(); + data->timestamp = iio_get_time_ns(indio_dev); if (data->dready_trigger_on) iio_trigger_poll(data->dready_trig); diff --git a/drivers/iio/accel/mma7455_core.c b/drivers/iio/accel/mma7455_core.c index c902f54..6551085 100644 --- a/drivers/iio/accel/mma7455_core.c +++ b/drivers/iio/accel/mma7455_core.c @@ -97,7 +97,8 @@ static irqreturn_t mma7455_trigger_handler(int irq, void *p) if (ret) goto done; - iio_push_to_buffers_with_timestamp(indio_dev, buf, iio_get_time_ns()); + iio_push_to_buffers_with_timestamp(indio_dev, buf, + iio_get_time_ns(indio_dev)); done: iio_trigger_notify_done(indio_dev->trig); diff --git a/drivers/iio/accel/mma8452.c b/drivers/iio/accel/mma8452.c index 799fe64..c0df283 100644 --- a/drivers/iio/accel/mma8452.c +++ b/drivers/iio/accel/mma8452.c @@ -917,7 +917,7 @@ static int mma8452_write_event_config(struct iio_dev *indio_dev, static void mma8452_transient_interrupt(struct iio_dev *indio_dev) { struct mma8452_data *data = iio_priv(indio_dev); - s64 ts = iio_get_time_ns(); + s64 ts = iio_get_time_ns(indio_dev); int src; src = i2c_smbus_read_byte_data(data->client, data->chip_info->ev_src); @@ -997,7 +997,7 @@ static irqreturn_t mma8452_trigger_handler(int irq, void *p) goto done; iio_push_to_buffers_with_timestamp(indio_dev, buffer, - iio_get_time_ns()); + iio_get_time_ns(indio_dev)); done: iio_trigger_notify_done(indio_dev->trig); diff --git a/drivers/iio/accel/mma9551.c b/drivers/iio/accel/mma9551.c index d899a4d..bf27044 100644 --- a/drivers/iio/accel/mma9551.c +++ b/drivers/iio/accel/mma9551.c @@ -391,7 +391,7 @@ static irqreturn_t mma9551_event_handler(int irq, void *private) iio_push_event(indio_dev, IIO_MOD_EVENT_CODE(IIO_INCLI, 0, (mma_axis + 1), IIO_EV_TYPE_ROC, IIO_EV_DIR_RISING), - iio_get_time_ns()); + iio_get_time_ns(indio_dev)); out: mutex_unlock(&data->mutex); diff --git a/drivers/iio/accel/mma9553.c b/drivers/iio/accel/mma9553.c index bb05f3e..36bf197 100644 --- a/drivers/iio/accel/mma9553.c +++ b/drivers/iio/accel/mma9553.c @@ -1001,7 +1001,7 @@ static irqreturn_t mma9553_irq_handler(int irq, void *private) struct iio_dev *indio_dev = private; struct mma9553_data *data = iio_priv(indio_dev); - data->timestamp = iio_get_time_ns(); + data->timestamp = iio_get_time_ns(indio_dev); /* * Since we only configure the interrupt pin when an * event is enabled, we are sure we have at least diff --git a/drivers/iio/adc/ad7291.c b/drivers/iio/adc/ad7291.c index c0eabf1..0376309 100644 --- a/drivers/iio/adc/ad7291.c +++ b/drivers/iio/adc/ad7291.c @@ -115,7 +115,7 @@ static irqreturn_t ad7291_event_handler(int irq, void *private) u16 t_status, v_status; u16 command; int i; - s64 timestamp = iio_get_time_ns(); + s64 timestamp = iio_get_time_ns(indio_dev); if (ad7291_i2c_read(chip, AD7291_T_ALERT_STATUS, &t_status)) return IRQ_HANDLED; diff --git a/drivers/iio/adc/ad7298.c b/drivers/iio/adc/ad7298.c index 62bb8f7..5dd0742 100644 --- a/drivers/iio/adc/ad7298.c +++ b/drivers/iio/adc/ad7298.c @@ -163,7 +163,7 @@ static irqreturn_t ad7298_trigger_handler(int irq, void *p) goto done; iio_push_to_buffers_with_timestamp(indio_dev, st->rx_buf, - iio_get_time_ns()); + iio_get_time_ns(indio_dev)); done: iio_trigger_notify_done(indio_dev->trig); diff --git a/drivers/iio/adc/ad7476.c b/drivers/iio/adc/ad7476.c index 810c9a9..a819be2 100644 --- a/drivers/iio/adc/ad7476.c +++ b/drivers/iio/adc/ad7476.c @@ -70,7 +70,7 @@ static irqreturn_t ad7476_trigger_handler(int irq, void *p) goto done; iio_push_to_buffers_with_timestamp(indio_dev, st->data, - iio_get_time_ns()); + iio_get_time_ns(indio_dev)); done: iio_trigger_notify_done(indio_dev->trig); diff --git a/drivers/iio/adc/ad7887.c b/drivers/iio/adc/ad7887.c index ee2ccc1..1bc363b 100644 --- a/drivers/iio/adc/ad7887.c +++ b/drivers/iio/adc/ad7887.c @@ -122,7 +122,7 @@ static irqreturn_t ad7887_trigger_handler(int irq, void *p) goto done; iio_push_to_buffers_with_timestamp(indio_dev, st->data, - iio_get_time_ns()); + iio_get_time_ns(indio_dev)); done: iio_trigger_notify_done(indio_dev->trig); diff --git a/drivers/iio/adc/ad7923.c b/drivers/iio/adc/ad7923.c index ff444c1..1337116 100644 --- a/drivers/iio/adc/ad7923.c +++ b/drivers/iio/adc/ad7923.c @@ -181,7 +181,7 @@ static irqreturn_t ad7923_trigger_handler(int irq, void *p) goto done; iio_push_to_buffers_with_timestamp(indio_dev, st->rx_buf, - iio_get_time_ns()); + iio_get_time_ns(indio_dev)); done: iio_trigger_notify_done(indio_dev->trig); diff --git a/drivers/iio/adc/ad799x.c b/drivers/iio/adc/ad799x.c index ec0200d..5428476 100644 --- a/drivers/iio/adc/ad799x.c +++ b/drivers/iio/adc/ad799x.c @@ -212,7 +212,7 @@ static irqreturn_t ad799x_trigger_handler(int irq, void *p) goto out; iio_push_to_buffers_with_timestamp(indio_dev, st->rx_buf, - iio_get_time_ns()); + iio_get_time_ns(indio_dev)); out: iio_trigger_notify_done(indio_dev->trig); @@ -502,7 +502,7 @@ static irqreturn_t ad799x_event_handler(int irq, void *private) (i >> 1), IIO_EV_TYPE_THRESH, IIO_EV_DIR_FALLING), - iio_get_time_ns()); + iio_get_time_ns(indio_dev)); } done: diff --git a/drivers/iio/adc/cc10001_adc.c b/drivers/iio/adc/cc10001_adc.c index 8254f52..91636c0 100644 --- a/drivers/iio/adc/cc10001_adc.c +++ b/drivers/iio/adc/cc10001_adc.c @@ -186,7 +186,7 @@ done: if (!sample_invalid) iio_push_to_buffers_with_timestamp(indio_dev, data, - iio_get_time_ns()); + iio_get_time_ns(indio_dev)); iio_trigger_notify_done(indio_dev->trig); return IRQ_HANDLED; diff --git a/drivers/iio/adc/hi8435.c b/drivers/iio/adc/hi8435.c index c73c6c6..c62bdb0 100644 --- a/drivers/iio/adc/hi8435.c +++ b/drivers/iio/adc/hi8435.c @@ -400,7 +400,7 @@ static void hi8435_iio_push_event(struct iio_dev *idev, unsigned int val) iio_push_event(idev, IIO_UNMOD_EVENT_CODE(IIO_VOLTAGE, i, IIO_EV_TYPE_THRESH, dir), - iio_get_time_ns()); + iio_get_time_ns(idev)); } } diff --git a/drivers/iio/adc/ina2xx-adc.c b/drivers/iio/adc/ina2xx-adc.c index 502f2fb..b95ce5d 100644 --- a/drivers/iio/adc/ina2xx-adc.c +++ b/drivers/iio/adc/ina2xx-adc.c @@ -465,7 +465,7 @@ static int ina2xx_work_buffer(struct iio_dev *indio_dev) s64 time_a, time_b; unsigned int alert; - time_a = iio_get_time_ns(); + time_a = iio_get_time_ns(indio_dev); /* * Because the timer thread and the chip conversion clock @@ -504,7 +504,7 @@ static int ina2xx_work_buffer(struct iio_dev *indio_dev) data[i++] = val; } - time_b = iio_get_time_ns(); + time_b = iio_get_time_ns(indio_dev); iio_push_to_buffers_with_timestamp(indio_dev, (unsigned int *)data, time_a); @@ -554,7 +554,7 @@ static int ina2xx_buffer_enable(struct iio_dev *indio_dev) dev_dbg(&indio_dev->dev, "Async readout mode: %d\n", chip->allow_async_readout); - chip->prev_ns = iio_get_time_ns(); + chip->prev_ns = iio_get_time_ns(indio_dev); chip->task = kthread_run(ina2xx_capture_thread, (void *)indio_dev, "%s:%d-%uus", indio_dev->name, indio_dev->id, diff --git a/drivers/iio/adc/max1363.c b/drivers/iio/adc/max1363.c index 998dc3c..73af306 100644 --- a/drivers/iio/adc/max1363.c +++ b/drivers/iio/adc/max1363.c @@ -788,7 +788,7 @@ static irqreturn_t max1363_event_handler(int irq, void *private) { struct iio_dev *indio_dev = private; struct max1363_state *st = iio_priv(indio_dev); - s64 timestamp = iio_get_time_ns(); + s64 timestamp = iio_get_time_ns(indio_dev); unsigned long mask, loc; u8 rx; u8 tx[2] = { st->setupbyte, @@ -1506,7 +1506,8 @@ static irqreturn_t max1363_trigger_handler(int irq, void *p) if (b_sent < 0) goto done_free; - iio_push_to_buffers_with_timestamp(indio_dev, rxbuf, iio_get_time_ns()); + iio_push_to_buffers_with_timestamp(indio_dev, rxbuf, + iio_get_time_ns(indio_dev)); done_free: kfree(rxbuf); diff --git a/drivers/iio/adc/ti-adc081c.c b/drivers/iio/adc/ti-adc081c.c index f8807ad..283d2a1 100644 --- a/drivers/iio/adc/ti-adc081c.c +++ b/drivers/iio/adc/ti-adc081c.c @@ -139,7 +139,8 @@ static irqreturn_t adc081c_trigger_handler(int irq, void *p) if (ret < 0) goto out; buf[0] = ret; - iio_push_to_buffers_with_timestamp(indio_dev, buf, iio_get_time_ns()); + iio_push_to_buffers_with_timestamp(indio_dev, buf, + iio_get_time_ns(indio_dev)); out: iio_trigger_notify_done(indio_dev->trig); return IRQ_HANDLED; diff --git a/drivers/iio/adc/ti-ads1015.c b/drivers/iio/adc/ti-ads1015.c index 8be192a..c9574af0 100644 --- a/drivers/iio/adc/ti-ads1015.c +++ b/drivers/iio/adc/ti-ads1015.c @@ -288,7 +288,8 @@ static irqreturn_t ads1015_trigger_handler(int irq, void *p) buf[0] = res; mutex_unlock(&data->lock); - iio_push_to_buffers_with_timestamp(indio_dev, buf, iio_get_time_ns()); + iio_push_to_buffers_with_timestamp(indio_dev, buf, + iio_get_time_ns(indio_dev)); err: iio_trigger_notify_done(indio_dev->trig); diff --git a/drivers/iio/adc/vf610_adc.c b/drivers/iio/adc/vf610_adc.c index 653bf13..228a003 100644 --- a/drivers/iio/adc/vf610_adc.c +++ b/drivers/iio/adc/vf610_adc.c @@ -594,7 +594,8 @@ static irqreturn_t vf610_adc_isr(int irq, void *dev_id) if (iio_buffer_enabled(indio_dev)) { info->buffer[0] = info->value; iio_push_to_buffers_with_timestamp(indio_dev, - info->buffer, iio_get_time_ns()); + info->buffer, + iio_get_time_ns(indio_dev)); iio_trigger_notify_done(indio_dev->trig); } else complete(&info->completion); diff --git a/drivers/iio/adc/xilinx-xadc-events.c b/drivers/iio/adc/xilinx-xadc-events.c index edcf3aa..6d5c2a6 100644 --- a/drivers/iio/adc/xilinx-xadc-events.c +++ b/drivers/iio/adc/xilinx-xadc-events.c @@ -46,7 +46,7 @@ static void xadc_handle_event(struct iio_dev *indio_dev, unsigned int event) iio_push_event(indio_dev, IIO_UNMOD_EVENT_CODE(chan->type, chan->channel, IIO_EV_TYPE_THRESH, IIO_EV_DIR_RISING), - iio_get_time_ns()); + iio_get_time_ns(indio_dev)); } else { /* * For other channels we don't know whether it is a upper or @@ -56,7 +56,7 @@ static void xadc_handle_event(struct iio_dev *indio_dev, unsigned int event) iio_push_event(indio_dev, IIO_UNMOD_EVENT_CODE(chan->type, chan->channel, IIO_EV_TYPE_THRESH, IIO_EV_DIR_EITHER), - iio_get_time_ns()); + iio_get_time_ns(indio_dev)); } } diff --git a/drivers/iio/chemical/atlas-ph-sensor.c b/drivers/iio/chemical/atlas-ph-sensor.c index 02e85db..ae038a5 100644 --- a/drivers/iio/chemical/atlas-ph-sensor.c +++ b/drivers/iio/chemical/atlas-ph-sensor.c @@ -343,7 +343,7 @@ static irqreturn_t atlas_trigger_handler(int irq, void *private) if (!ret) iio_push_to_buffers_with_timestamp(indio_dev, data->buffer, - iio_get_time_ns()); + iio_get_time_ns(indio_dev)); iio_trigger_notify_done(indio_dev->trig); diff --git a/drivers/iio/common/st_sensors/st_sensors_buffer.c b/drivers/iio/common/st_sensors/st_sensors_buffer.c index 50afc0f..7c84e90 100644 --- a/drivers/iio/common/st_sensors/st_sensors_buffer.c +++ b/drivers/iio/common/st_sensors/st_sensors_buffer.c @@ -62,7 +62,7 @@ irqreturn_t st_sensors_trigger_handler(int irq, void *p) if (sdata->hw_irq_trigger) timestamp = sdata->hw_timestamp; else - timestamp = iio_get_time_ns(); + timestamp = iio_get_time_ns(indio_dev); len = st_sensors_get_buffer_element(indio_dev, sdata->buffer_data); if (len < 0) diff --git a/drivers/iio/common/st_sensors/st_sensors_trigger.c b/drivers/iio/common/st_sensors/st_sensors_trigger.c index 296e4ff..fab494d 100644 --- a/drivers/iio/common/st_sensors/st_sensors_trigger.c +++ b/drivers/iio/common/st_sensors/st_sensors_trigger.c @@ -29,7 +29,7 @@ irqreturn_t st_sensors_irq_handler(int irq, void *p) struct st_sensor_data *sdata = iio_priv(indio_dev); /* Get the time stamp as close in time as possible */ - sdata->hw_timestamp = iio_get_time_ns(); + sdata->hw_timestamp = iio_get_time_ns(indio_dev); return IRQ_WAKE_THREAD; } diff --git a/drivers/iio/dac/ad5421.c b/drivers/iio/dac/ad5421.c index 968712b..559061a 100644 --- a/drivers/iio/dac/ad5421.c +++ b/drivers/iio/dac/ad5421.c @@ -242,7 +242,7 @@ static irqreturn_t ad5421_fault_handler(int irq, void *data) 0, IIO_EV_TYPE_THRESH, IIO_EV_DIR_RISING), - iio_get_time_ns()); + iio_get_time_ns(indio_dev)); } if (events & AD5421_FAULT_UNDER_CURRENT) { @@ -251,7 +251,7 @@ static irqreturn_t ad5421_fault_handler(int irq, void *data) 0, IIO_EV_TYPE_THRESH, IIO_EV_DIR_FALLING), - iio_get_time_ns()); + iio_get_time_ns(indio_dev)); } if (events & AD5421_FAULT_TEMP_OVER_140) { @@ -260,7 +260,7 @@ static irqreturn_t ad5421_fault_handler(int irq, void *data) 0, IIO_EV_TYPE_MAG, IIO_EV_DIR_RISING), - iio_get_time_ns()); + iio_get_time_ns(indio_dev)); } old_fault = fault; diff --git a/drivers/iio/dac/ad5504.c b/drivers/iio/dac/ad5504.c index 4e4c20d..788b3d6 100644 --- a/drivers/iio/dac/ad5504.c +++ b/drivers/iio/dac/ad5504.c @@ -223,7 +223,7 @@ static irqreturn_t ad5504_event_handler(int irq, void *private) 0, IIO_EV_TYPE_THRESH, IIO_EV_DIR_RISING), - iio_get_time_ns()); + iio_get_time_ns((struct iio_dev *)private)); return IRQ_HANDLED; } diff --git a/drivers/iio/dummy/iio_simple_dummy_buffer.c b/drivers/iio/dummy/iio_simple_dummy_buffer.c index cf44a6f..b383892 100644 --- a/drivers/iio/dummy/iio_simple_dummy_buffer.c +++ b/drivers/iio/dummy/iio_simple_dummy_buffer.c @@ -85,7 +85,8 @@ static irqreturn_t iio_simple_dummy_trigger_h(int irq, void *p) } } - iio_push_to_buffers_with_timestamp(indio_dev, data, iio_get_time_ns()); + iio_push_to_buffers_with_timestamp(indio_dev, data, + iio_get_time_ns(indio_dev)); kfree(data); diff --git a/drivers/iio/dummy/iio_simple_dummy_events.c b/drivers/iio/dummy/iio_simple_dummy_events.c index 6eb600f..ed63ffd 100644 --- a/drivers/iio/dummy/iio_simple_dummy_events.c +++ b/drivers/iio/dummy/iio_simple_dummy_events.c @@ -158,7 +158,7 @@ static irqreturn_t iio_simple_dummy_get_timestamp(int irq, void *private) struct iio_dev *indio_dev = private; struct iio_dummy_state *st = iio_priv(indio_dev); - st->event_timestamp = iio_get_time_ns(); + st->event_timestamp = iio_get_time_ns(indio_dev); return IRQ_WAKE_THREAD; } diff --git a/drivers/iio/gyro/bmg160_core.c b/drivers/iio/gyro/bmg160_core.c index 7ccc044..8155251 100644 --- a/drivers/iio/gyro/bmg160_core.c +++ b/drivers/iio/gyro/bmg160_core.c @@ -885,25 +885,25 @@ static irqreturn_t bmg160_event_handler(int irq, void *private) if (val & BMG160_ANY_MOTION_BIT_X) iio_push_event(indio_dev, IIO_MOD_EVENT_CODE(IIO_ANGL_VEL, - 0, - IIO_MOD_X, - IIO_EV_TYPE_ROC, - dir), - iio_get_time_ns()); + 0, + IIO_MOD_X, + IIO_EV_TYPE_ROC, + dir), + iio_get_time_ns(indio_dev)); if (val & BMG160_ANY_MOTION_BIT_Y) iio_push_event(indio_dev, IIO_MOD_EVENT_CODE(IIO_ANGL_VEL, - 0, - IIO_MOD_Y, - IIO_EV_TYPE_ROC, - dir), - iio_get_time_ns()); + 0, + IIO_MOD_Y, + IIO_EV_TYPE_ROC, + dir), + iio_get_time_ns(indio_dev)); if (val & BMG160_ANY_MOTION_BIT_Z) iio_push_event(indio_dev, IIO_MOD_EVENT_CODE(IIO_ANGL_VEL, - 0, - IIO_MOD_Z, - IIO_EV_TYPE_ROC, - dir), - iio_get_time_ns()); + 0, + IIO_MOD_Z, + IIO_EV_TYPE_ROC, + dir), + iio_get_time_ns(indio_dev)); ack_intr_status: if (!data->dready_trigger_on) { diff --git a/drivers/iio/iio_core.h b/drivers/iio/iio_core.h index 3598835..4c45488 100644 --- a/drivers/iio/iio_core.h +++ b/drivers/iio/iio_core.h @@ -79,4 +79,7 @@ void iio_device_unregister_eventset(struct iio_dev *indio_dev); void iio_device_wakeup_eventset(struct iio_dev *indio_dev); int iio_event_getfd(struct iio_dev *indio_dev); +struct iio_event_interface; +bool iio_event_enabled(const struct iio_event_interface *ev_int); + #endif diff --git a/drivers/iio/imu/bmi160/bmi160_core.c b/drivers/iio/imu/bmi160/bmi160_core.c index 97928d5..e0251b8 100644 --- a/drivers/iio/imu/bmi160/bmi160_core.c +++ b/drivers/iio/imu/bmi160/bmi160_core.c @@ -411,7 +411,8 @@ static irqreturn_t bmi160_trigger_handler(int irq, void *p) buf[j++] = sample; } - iio_push_to_buffers_with_timestamp(indio_dev, buf, iio_get_time_ns()); + iio_push_to_buffers_with_timestamp(indio_dev, buf, + iio_get_time_ns(indio_dev)); done: iio_trigger_notify_done(indio_dev->trig); return IRQ_HANDLED; diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_ring.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_ring.c index d070062..3a9f3ea 100644 --- a/drivers/iio/imu/inv_mpu6050/inv_mpu_ring.c +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_ring.c @@ -107,7 +107,7 @@ irqreturn_t inv_mpu6050_irq_handler(int irq, void *p) struct inv_mpu6050_state *st = iio_priv(indio_dev); s64 timestamp; - timestamp = iio_get_time_ns(); + timestamp = iio_get_time_ns(indio_dev); kfifo_in_spinlocked(&st->timestamps, ×tamp, 1, &st->time_stamp_lock); diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c index 2a85bd8..f914d5d 100644 --- a/drivers/iio/industrialio-core.c +++ b/drivers/iio/industrialio-core.c @@ -178,6 +178,86 @@ ssize_t iio_read_const_attr(struct device *dev, } EXPORT_SYMBOL(iio_read_const_attr); +static int iio_device_set_clock(struct iio_dev *indio_dev, clockid_t clock_id) +{ + int ret; + const struct iio_event_interface *ev_int = indio_dev->event_interface; + + ret = mutex_lock_interruptible(&indio_dev->mlock); + if (ret) + return ret; + if ((ev_int && iio_event_enabled(ev_int)) || + iio_buffer_enabled(indio_dev)) { + mutex_unlock(&indio_dev->mlock); + return -EBUSY; + } + indio_dev->clock_id = clock_id; + mutex_unlock(&indio_dev->mlock); + + return 0; +} + +/** + * iio_get_time_ns() - utility function to get a time stamp for events etc + * @indio_dev: device + */ +s64 iio_get_time_ns(const struct iio_dev *indio_dev) +{ + struct timespec tp; + + switch (iio_device_get_clock(indio_dev)) { + case CLOCK_REALTIME: + ktime_get_real_ts(&tp); + break; + case CLOCK_MONOTONIC: + ktime_get_ts(&tp); + break; + case CLOCK_MONOTONIC_RAW: + getrawmonotonic(&tp); + break; + case CLOCK_REALTIME_COARSE: + tp = current_kernel_time(); + break; + case CLOCK_MONOTONIC_COARSE: + tp = get_monotonic_coarse(); + break; + case CLOCK_BOOTTIME: + get_monotonic_boottime(&tp); + break; + case CLOCK_TAI: + timekeeping_clocktai(&tp); + break; + default: + BUG(); + } + + return timespec_to_ns(&tp); +} +EXPORT_SYMBOL(iio_get_time_ns); + +/** + * iio_get_time_res() - utility function to get time stamp clock resolution in + * nano seconds. + * @indio_dev: device + */ +unsigned int iio_get_time_res(const struct iio_dev *indio_dev) +{ + switch (iio_device_get_clock(indio_dev)) { + case CLOCK_REALTIME: + case CLOCK_MONOTONIC: + case CLOCK_MONOTONIC_RAW: + case CLOCK_BOOTTIME: + case CLOCK_TAI: + return hrtimer_resolution; + case CLOCK_REALTIME_COARSE: + case CLOCK_MONOTONIC_COARSE: + return LOW_RES_NSEC; + default: + BUG(); + } +} +EXPORT_SYMBOL(iio_get_time_res); + static int __init iio_init(void) { int ret; @@ -990,11 +1070,91 @@ static ssize_t iio_show_dev_name(struct device *dev, static DEVICE_ATTR(name, S_IRUGO, iio_show_dev_name, NULL); +static ssize_t iio_show_timestamp_clock(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + const struct iio_dev *indio_dev = dev_to_iio_dev(dev); + const clockid_t clk = iio_device_get_clock(indio_dev); + const char *name; + ssize_t sz; + + switch (clk) { + case CLOCK_REALTIME: + name = "realtime\n"; + sz = sizeof("realtime\n"); + break; + case CLOCK_MONOTONIC: + name = "monotonic\n"; + sz = sizeof("monotonic\n"); + break; + case CLOCK_MONOTONIC_RAW: + name = "monotonic_raw\n"; + sz = sizeof("monotonic_raw\n"); + break; + case CLOCK_REALTIME_COARSE: + name = "realtime_coarse\n"; + sz = sizeof("realtime_coarse\n"); + break; + case CLOCK_MONOTONIC_COARSE: + name = "monotonic_coarse\n"; + sz = sizeof("monotonic_coarse\n"); + break; + case CLOCK_BOOTTIME: + name = "boottime\n"; + sz = sizeof("boottime\n"); + break; + case CLOCK_TAI: + name = "tai\n"; + sz = sizeof("tai\n"); + break; + default: + BUG(); + } + + memcpy(buf, name, sz); + return sz; +} + +static ssize_t iio_store_timestamp_clock(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t len) +{ + clockid_t clk; + int ret; + + if (sysfs_streq(buf, "realtime")) + clk = CLOCK_REALTIME; + else if (sysfs_streq(buf, "monotonic")) + clk = CLOCK_MONOTONIC; + else if (sysfs_streq(buf, "monotonic_raw")) + clk = CLOCK_MONOTONIC_RAW; + else if (sysfs_streq(buf, "realtime_coarse")) + clk = CLOCK_REALTIME_COARSE; + else if (sysfs_streq(buf, "monotonic_coarse")) + clk = CLOCK_MONOTONIC_COARSE; + else if (sysfs_streq(buf, "boottime")) + clk = CLOCK_BOOTTIME; + else if (sysfs_streq(buf, "tai")) + clk = CLOCK_TAI; + else + return -EINVAL; + + ret = iio_device_set_clock(dev_to_iio_dev(dev), clk); + if (ret) + return ret; + + return len; +} + +static DEVICE_ATTR(current_timestamp_clock, S_IRUGO | S_IWUSR, + iio_show_timestamp_clock, iio_store_timestamp_clock); + static int iio_device_register_sysfs(struct iio_dev *indio_dev) { int i, ret = 0, attrcount, attrn, attrcount_orig = 0; struct iio_dev_attr *p; - struct attribute **attr; + struct attribute **attr, *clk = NULL; /* First count elements in any existing group */ if (indio_dev->info->attrs) { @@ -1009,16 +1169,25 @@ static int iio_device_register_sysfs(struct iio_dev *indio_dev) */ if (indio_dev->channels) for (i = 0; i < indio_dev->num_channels; i++) { - ret = iio_device_add_channel_sysfs(indio_dev, - &indio_dev - ->channels[i]); + const struct iio_chan_spec *chan = + &indio_dev->channels[i]; + + if (chan->type == IIO_TIMESTAMP) + clk = &dev_attr_current_timestamp_clock.attr; + + ret = iio_device_add_channel_sysfs(indio_dev, chan); if (ret < 0) goto error_clear_attrs; attrcount += ret; } + if (indio_dev->event_interface) + clk = &dev_attr_current_timestamp_clock.attr; + if (indio_dev->name) attrcount++; + if (clk) + attrcount++; indio_dev->chan_attr_group.attrs = kcalloc(attrcount + 1, sizeof(indio_dev->chan_attr_group.attrs[0]), @@ -1039,6 +1208,8 @@ static int iio_device_register_sysfs(struct iio_dev *indio_dev) indio_dev->chan_attr_group.attrs[attrn++] = &p->dev_attr.attr; if (indio_dev->name) indio_dev->chan_attr_group.attrs[attrn++] = &dev_attr_name.attr; + if (clk) + indio_dev->chan_attr_group.attrs[attrn++] = clk; indio_dev->groups[indio_dev->groupcounter++] = &indio_dev->chan_attr_group; diff --git a/drivers/iio/industrialio-event.c b/drivers/iio/industrialio-event.c index cae332b..0ebfc92 100644 --- a/drivers/iio/industrialio-event.c +++ b/drivers/iio/industrialio-event.c @@ -44,6 +44,11 @@ struct iio_event_interface { struct mutex read_lock; }; +bool iio_event_enabled(const struct iio_event_interface *ev_int) +{ + return !!test_bit(IIO_BUSY_BIT_POS, &ev_int->flags); +} + /** * iio_push_event() - try to add event to the list for userspace reading * @indio_dev: IIO device structure @@ -60,7 +65,7 @@ int iio_push_event(struct iio_dev *indio_dev, u64 ev_code, s64 timestamp) int copied; /* Does anyone care? */ - if (test_bit(IIO_BUSY_BIT_POS, &ev_int->flags)) { + if (iio_event_enabled(ev_int)) { ev.id = ev_code; ev.timestamp = timestamp; @@ -180,8 +185,14 @@ int iio_event_getfd(struct iio_dev *indio_dev) if (ev_int == NULL) return -ENODEV; - if (test_and_set_bit(IIO_BUSY_BIT_POS, &ev_int->flags)) - return -EBUSY; + fd = mutex_lock_interruptible(&indio_dev->mlock); + if (fd) + return fd; + + if (test_and_set_bit(IIO_BUSY_BIT_POS, &ev_int->flags)) { + fd = -EBUSY; + goto unlock; + } iio_device_get(indio_dev); @@ -194,6 +205,8 @@ int iio_event_getfd(struct iio_dev *indio_dev) kfifo_reset_out(&ev_int->det_events); } +unlock: + mutex_unlock(&indio_dev->mlock); return fd; } diff --git a/drivers/iio/industrialio-trigger.c b/drivers/iio/industrialio-trigger.c index 98457f0..7ad82fd 100644 --- a/drivers/iio/industrialio-trigger.c +++ b/drivers/iio/industrialio-trigger.c @@ -289,7 +289,7 @@ static int iio_trigger_detach_poll_func(struct iio_trigger *trig, irqreturn_t iio_pollfunc_store_time(int irq, void *p) { struct iio_poll_func *pf = p; - pf->timestamp = iio_get_time_ns(); + pf->timestamp = iio_get_time_ns(pf->indio_dev); return IRQ_WAKE_THREAD; } EXPORT_SYMBOL(iio_pollfunc_store_time); diff --git a/drivers/iio/light/acpi-als.c b/drivers/iio/light/acpi-als.c index 53201d9..f0b47c5 100644 --- a/drivers/iio/light/acpi-als.c +++ b/drivers/iio/light/acpi-als.c @@ -118,7 +118,7 @@ static void acpi_als_notify(struct acpi_device *device, u32 event) struct iio_dev *indio_dev = acpi_driver_data(device); struct acpi_als *als = iio_priv(indio_dev); s32 *buffer = als->evt_buffer; - s64 time_ns = iio_get_time_ns(); + s64 time_ns = iio_get_time_ns(indio_dev); s32 val; int ret; diff --git a/drivers/iio/light/adjd_s311.c b/drivers/iio/light/adjd_s311.c index 09ad5f1..0113fc8 100644 --- a/drivers/iio/light/adjd_s311.c +++ b/drivers/iio/light/adjd_s311.c @@ -118,7 +118,7 @@ static irqreturn_t adjd_s311_trigger_handler(int irq, void *p) struct iio_poll_func *pf = p; struct iio_dev *indio_dev = pf->indio_dev; struct adjd_s311_data *data = iio_priv(indio_dev); - s64 time_ns = iio_get_time_ns(); + s64 time_ns = iio_get_time_ns(indio_dev); int i, j = 0; int ret = adjd_s311_req_data(indio_dev); diff --git a/drivers/iio/light/apds9300.c b/drivers/iio/light/apds9300.c index e1b9fa5..649b26f 100644 --- a/drivers/iio/light/apds9300.c +++ b/drivers/iio/light/apds9300.c @@ -396,7 +396,7 @@ static irqreturn_t apds9300_interrupt_handler(int irq, void *private) IIO_UNMOD_EVENT_CODE(IIO_INTENSITY, 0, IIO_EV_TYPE_THRESH, IIO_EV_DIR_EITHER), - iio_get_time_ns()); + iio_get_time_ns(dev_info)); apds9300_clear_intr(data); diff --git a/drivers/iio/light/apds9960.c b/drivers/iio/light/apds9960.c index 651d57b..a4304ed 100644 --- a/drivers/iio/light/apds9960.c +++ b/drivers/iio/light/apds9960.c @@ -807,7 +807,7 @@ static irqreturn_t apds9960_interrupt_handler(int irq, void *private) IIO_UNMOD_EVENT_CODE(IIO_INTENSITY, 0, IIO_EV_TYPE_THRESH, IIO_EV_DIR_EITHER), - iio_get_time_ns()); + iio_get_time_ns(indio_dev)); regmap_write(data->regmap, APDS9960_REG_CICLEAR, 1); } @@ -816,7 +816,7 @@ static irqreturn_t apds9960_interrupt_handler(int irq, void *private) IIO_UNMOD_EVENT_CODE(IIO_PROXIMITY, 0, IIO_EV_TYPE_THRESH, IIO_EV_DIR_EITHER), - iio_get_time_ns()); + iio_get_time_ns(indio_dev)); regmap_write(data->regmap, APDS9960_REG_PICLEAR, 1); } diff --git a/drivers/iio/light/cm36651.c b/drivers/iio/light/cm36651.c index c8d7b5e..9d66e89 100644 --- a/drivers/iio/light/cm36651.c +++ b/drivers/iio/light/cm36651.c @@ -268,7 +268,7 @@ static irqreturn_t cm36651_irq_handler(int irq, void *data) CM36651_CMD_READ_RAW_PROXIMITY, IIO_EV_TYPE_THRESH, ev_dir); - iio_push_event(indio_dev, ev_code, iio_get_time_ns()); + iio_push_event(indio_dev, ev_code, iio_get_time_ns(indio_dev)); return IRQ_HANDLED; } diff --git a/drivers/iio/light/gp2ap020a00f.c b/drivers/iio/light/gp2ap020a00f.c index af73af3..6ada914 100644 --- a/drivers/iio/light/gp2ap020a00f.c +++ b/drivers/iio/light/gp2ap020a00f.c @@ -851,7 +851,7 @@ static irqreturn_t gp2ap020a00f_prox_sensing_handler(int irq, void *data) GP2AP020A00F_SCAN_MODE_PROXIMITY, IIO_EV_TYPE_ROC, IIO_EV_DIR_RISING), - iio_get_time_ns()); + iio_get_time_ns(indio_dev)); } else { iio_push_event(indio_dev, IIO_UNMOD_EVENT_CODE( @@ -859,7 +859,7 @@ static irqreturn_t gp2ap020a00f_prox_sensing_handler(int irq, void *data) GP2AP020A00F_SCAN_MODE_PROXIMITY, IIO_EV_TYPE_ROC, IIO_EV_DIR_FALLING), - iio_get_time_ns()); + iio_get_time_ns(indio_dev)); } } @@ -925,7 +925,7 @@ static irqreturn_t gp2ap020a00f_thresh_event_handler(int irq, void *data) IIO_MOD_LIGHT_CLEAR, IIO_EV_TYPE_THRESH, IIO_EV_DIR_RISING), - iio_get_time_ns()); + iio_get_time_ns(indio_dev)); } if (test_bit(GP2AP020A00F_FLAG_ALS_FALLING_EV, &priv->flags)) { @@ -939,7 +939,7 @@ static irqreturn_t gp2ap020a00f_thresh_event_handler(int irq, void *data) IIO_MOD_LIGHT_CLEAR, IIO_EV_TYPE_THRESH, IIO_EV_DIR_FALLING), - iio_get_time_ns()); + iio_get_time_ns(indio_dev)); } } diff --git a/drivers/iio/light/isl29125.c b/drivers/iio/light/isl29125.c index a6b9d66..f48b9e5 100644 --- a/drivers/iio/light/isl29125.c +++ b/drivers/iio/light/isl29125.c @@ -188,7 +188,7 @@ static irqreturn_t isl29125_trigger_handler(int irq, void *p) } iio_push_to_buffers_with_timestamp(indio_dev, data->buffer, - iio_get_time_ns()); + iio_get_time_ns(indio_dev)); done: iio_trigger_notify_done(indio_dev->trig); diff --git a/drivers/iio/light/lm3533-als.c b/drivers/iio/light/lm3533-als.c index e56937c..f409c20 100644 --- a/drivers/iio/light/lm3533-als.c +++ b/drivers/iio/light/lm3533-als.c @@ -267,7 +267,7 @@ static irqreturn_t lm3533_als_isr(int irq, void *dev_id) 0, IIO_EV_TYPE_THRESH, IIO_EV_DIR_EITHER), - iio_get_time_ns()); + iio_get_time_ns(indio_dev)); out: return IRQ_HANDLED; } diff --git a/drivers/iio/light/ltr501.c b/drivers/iio/light/ltr501.c index 6bf89d8..3afc53a 100644 --- a/drivers/iio/light/ltr501.c +++ b/drivers/iio/light/ltr501.c @@ -1256,7 +1256,8 @@ static irqreturn_t ltr501_trigger_handler(int irq, void *p) buf[j++] = psdata & LTR501_PS_DATA_MASK; } - iio_push_to_buffers_with_timestamp(indio_dev, buf, iio_get_time_ns()); + iio_push_to_buffers_with_timestamp(indio_dev, buf, + iio_get_time_ns(indio_dev)); done: iio_trigger_notify_done(indio_dev->trig); @@ -1282,14 +1283,14 @@ static irqreturn_t ltr501_interrupt_handler(int irq, void *private) IIO_UNMOD_EVENT_CODE(IIO_INTENSITY, 0, IIO_EV_TYPE_THRESH, IIO_EV_DIR_EITHER), - iio_get_time_ns()); + iio_get_time_ns(indio_dev)); if (status & LTR501_STATUS_PS_INTR) iio_push_event(indio_dev, IIO_UNMOD_EVENT_CODE(IIO_PROXIMITY, 0, IIO_EV_TYPE_THRESH, IIO_EV_DIR_EITHER), - iio_get_time_ns()); + iio_get_time_ns(indio_dev)); return IRQ_HANDLED; } diff --git a/drivers/iio/light/max44000.c b/drivers/iio/light/max44000.c index f17cb2e..6511b20 100644 --- a/drivers/iio/light/max44000.c +++ b/drivers/iio/light/max44000.c @@ -511,7 +511,8 @@ static irqreturn_t max44000_trigger_handler(int irq, void *p) } mutex_unlock(&data->lock); - iio_push_to_buffers_with_timestamp(indio_dev, buf, iio_get_time_ns()); + iio_push_to_buffers_with_timestamp(indio_dev, buf, + iio_get_time_ns(indio_dev)); iio_trigger_notify_done(indio_dev->trig); return IRQ_HANDLED; diff --git a/drivers/iio/light/opt3001.c b/drivers/iio/light/opt3001.c index b776c8e..78c9b3a 100644 --- a/drivers/iio/light/opt3001.c +++ b/drivers/iio/light/opt3001.c @@ -713,13 +713,13 @@ static irqreturn_t opt3001_irq(int irq, void *_iio) IIO_UNMOD_EVENT_CODE(IIO_LIGHT, 0, IIO_EV_TYPE_THRESH, IIO_EV_DIR_RISING), - iio_get_time_ns()); + iio_get_time_ns(iio)); if (ret & OPT3001_CONFIGURATION_FL) iio_push_event(iio, IIO_UNMOD_EVENT_CODE(IIO_LIGHT, 0, IIO_EV_TYPE_THRESH, IIO_EV_DIR_FALLING), - iio_get_time_ns()); + iio_get_time_ns(iio)); } else if (ret & OPT3001_CONFIGURATION_CRF) { ret = i2c_smbus_read_word_swapped(opt->client, OPT3001_RESULT); if (ret < 0) { diff --git a/drivers/iio/light/stk3310.c b/drivers/iio/light/stk3310.c index 9e847f8..45cf8b0 100644 --- a/drivers/iio/light/stk3310.c +++ b/drivers/iio/light/stk3310.c @@ -528,7 +528,7 @@ static irqreturn_t stk3310_irq_handler(int irq, void *private) struct iio_dev *indio_dev = private; struct stk3310_data *data = iio_priv(indio_dev); - data->timestamp = iio_get_time_ns(); + data->timestamp = iio_get_time_ns(indio_dev); return IRQ_WAKE_THREAD; } diff --git a/drivers/iio/light/tcs3414.c b/drivers/iio/light/tcs3414.c index 8a15fb5..a795afb 100644 --- a/drivers/iio/light/tcs3414.c +++ b/drivers/iio/light/tcs3414.c @@ -216,7 +216,7 @@ static irqreturn_t tcs3414_trigger_handler(int irq, void *p) } iio_push_to_buffers_with_timestamp(indio_dev, data->buffer, - iio_get_time_ns()); + iio_get_time_ns(indio_dev)); done: iio_trigger_notify_done(indio_dev->trig); diff --git a/drivers/iio/light/tcs3472.c b/drivers/iio/light/tcs3472.c index b29312f..3aa71e3 100644 --- a/drivers/iio/light/tcs3472.c +++ b/drivers/iio/light/tcs3472.c @@ -202,7 +202,7 @@ static irqreturn_t tcs3472_trigger_handler(int irq, void *p) } iio_push_to_buffers_with_timestamp(indio_dev, data->buffer, - iio_get_time_ns()); + iio_get_time_ns(indio_dev)); done: iio_trigger_notify_done(indio_dev->trig); diff --git a/drivers/iio/light/tsl2563.c b/drivers/iio/light/tsl2563.c index 57b108c..04598ae 100644 --- a/drivers/iio/light/tsl2563.c +++ b/drivers/iio/light/tsl2563.c @@ -630,7 +630,7 @@ static irqreturn_t tsl2563_event_handler(int irq, void *private) 0, IIO_EV_TYPE_THRESH, IIO_EV_DIR_EITHER), - iio_get_time_ns()); + iio_get_time_ns(dev_info)); /* clear the interrupt and push the event */ i2c_smbus_write_byte(chip->client, TSL2563_CMD | TSL2563_CLEARINT); diff --git a/drivers/iio/light/us5182d.c b/drivers/iio/light/us5182d.c index 45bc2f7..20c40f7 100644 --- a/drivers/iio/light/us5182d.c +++ b/drivers/iio/light/us5182d.c @@ -833,7 +833,7 @@ static irqreturn_t us5182d_irq_thread_handler(int irq, void *private) dir = ret & US5182D_CFG0_PROX ? IIO_EV_DIR_RISING : IIO_EV_DIR_FALLING; ev = IIO_UNMOD_EVENT_CODE(IIO_PROXIMITY, 1, IIO_EV_TYPE_THRESH, dir); - iio_push_event(indio_dev, ev, iio_get_time_ns()); + iio_push_event(indio_dev, ev, iio_get_time_ns(indio_dev)); ret = i2c_smbus_write_byte_data(data->client, US5182D_REG_CFG0, ret & ~US5182D_CFG0_PX_IRQ); diff --git a/drivers/iio/magnetometer/ak8975.c b/drivers/iio/magnetometer/ak8975.c index 57d3654..2121b50 100644 --- a/drivers/iio/magnetometer/ak8975.c +++ b/drivers/iio/magnetometer/ak8975.c @@ -829,7 +829,8 @@ static void ak8975_fill_buffer(struct iio_dev *indio_dev) buff[1] = clamp_t(s16, le16_to_cpu(buff[1]), -def->range, def->range); buff[2] = clamp_t(s16, le16_to_cpu(buff[2]), -def->range, def->range); - iio_push_to_buffers_with_timestamp(indio_dev, buff, iio_get_time_ns()); + iio_push_to_buffers_with_timestamp(indio_dev, buff, + iio_get_time_ns(indio_dev)); return; unlock: diff --git a/drivers/iio/magnetometer/hmc5843_core.c b/drivers/iio/magnetometer/hmc5843_core.c index 77882b4..ba3e2a3 100644 --- a/drivers/iio/magnetometer/hmc5843_core.c +++ b/drivers/iio/magnetometer/hmc5843_core.c @@ -451,7 +451,7 @@ static irqreturn_t hmc5843_trigger_handler(int irq, void *p) goto done; iio_push_to_buffers_with_timestamp(indio_dev, data->buffer, - iio_get_time_ns()); + iio_get_time_ns(indio_dev)); done: iio_trigger_notify_done(indio_dev->trig); diff --git a/drivers/iio/magnetometer/mag3110.c b/drivers/iio/magnetometer/mag3110.c index 261d517..f2be4a0 100644 --- a/drivers/iio/magnetometer/mag3110.c +++ b/drivers/iio/magnetometer/mag3110.c @@ -261,7 +261,7 @@ static irqreturn_t mag3110_trigger_handler(int irq, void *p) } iio_push_to_buffers_with_timestamp(indio_dev, buffer, - iio_get_time_ns()); + iio_get_time_ns(indio_dev)); done: iio_trigger_notify_done(indio_dev->trig); diff --git a/drivers/iio/pressure/mpl3115.c b/drivers/iio/pressure/mpl3115.c index 01b2e0b..6392d7b 100644 --- a/drivers/iio/pressure/mpl3115.c +++ b/drivers/iio/pressure/mpl3115.c @@ -171,7 +171,7 @@ static irqreturn_t mpl3115_trigger_handler(int irq, void *p) mutex_unlock(&data->lock); iio_push_to_buffers_with_timestamp(indio_dev, buffer, - iio_get_time_ns()); + iio_get_time_ns(indio_dev)); done: iio_trigger_notify_done(indio_dev->trig); diff --git a/drivers/iio/pressure/ms5611_core.c b/drivers/iio/pressure/ms5611_core.c index 76578b0..feb41f8 100644 --- a/drivers/iio/pressure/ms5611_core.c +++ b/drivers/iio/pressure/ms5611_core.c @@ -224,7 +224,8 @@ static irqreturn_t ms5611_trigger_handler(int irq, void *p) if (ret < 0) goto err; - iio_push_to_buffers_with_timestamp(indio_dev, buf, iio_get_time_ns()); + iio_push_to_buffers_with_timestamp(indio_dev, buf, + iio_get_time_ns(indio_dev)); err: iio_trigger_notify_done(indio_dev->trig); diff --git a/drivers/iio/proximity/pulsedlight-lidar-lite-v2.c b/drivers/iio/proximity/pulsedlight-lidar-lite-v2.c index c0b0e82..3141c3c 100644 --- a/drivers/iio/proximity/pulsedlight-lidar-lite-v2.c +++ b/drivers/iio/proximity/pulsedlight-lidar-lite-v2.c @@ -238,7 +238,7 @@ static irqreturn_t lidar_trigger_handler(int irq, void *private) ret = lidar_get_measurement(data, data->buffer); if (!ret) { iio_push_to_buffers_with_timestamp(indio_dev, data->buffer, - iio_get_time_ns()); + iio_get_time_ns(indio_dev)); } else if (ret != -EINVAL) { dev_err(&data->client->dev, "cannot read LIDAR measurement"); } diff --git a/drivers/iio/proximity/sx9500.c b/drivers/iio/proximity/sx9500.c index 66cd09a..1d74b3a 100644 --- a/drivers/iio/proximity/sx9500.c +++ b/drivers/iio/proximity/sx9500.c @@ -492,7 +492,7 @@ static void sx9500_push_events(struct iio_dev *indio_dev) dir = new_prox ? IIO_EV_DIR_FALLING : IIO_EV_DIR_RISING; ev = IIO_UNMOD_EVENT_CODE(IIO_PROXIMITY, chan, IIO_EV_TYPE_THRESH, dir); - iio_push_event(indio_dev, ev, iio_get_time_ns()); + iio_push_event(indio_dev, ev, iio_get_time_ns(indio_dev)); data->prox_stat[chan] = new_prox; } } @@ -669,7 +669,7 @@ static irqreturn_t sx9500_trigger_handler(int irq, void *private) } iio_push_to_buffers_with_timestamp(indio_dev, data->buffer, - iio_get_time_ns()); + iio_get_time_ns(indio_dev)); out: mutex_unlock(&data->mutex); diff --git a/drivers/staging/iio/accel/lis3l02dq_core.c b/drivers/staging/iio/accel/lis3l02dq_core.c index 7a6fed3..5c3410a 100644 --- a/drivers/staging/iio/accel/lis3l02dq_core.c +++ b/drivers/staging/iio/accel/lis3l02dq_core.c @@ -451,7 +451,7 @@ static irqreturn_t lis3l02dq_event_handler(int irq, void *private) struct iio_dev *indio_dev = private; u8 t; - s64 timestamp = iio_get_time_ns(); + s64 timestamp = iio_get_time_ns(indio_dev); lis3l02dq_spi_read_reg_8(indio_dev, LIS3L02DQ_REG_WAKE_UP_SRC_ADDR, diff --git a/drivers/staging/iio/accel/sca3000_core.c b/drivers/staging/iio/accel/sca3000_core.c index 53c5425..aacf643 100644 --- a/drivers/staging/iio/accel/sca3000_core.c +++ b/drivers/staging/iio/accel/sca3000_core.c @@ -774,7 +774,7 @@ static irqreturn_t sca3000_event_handler(int irq, void *private) struct iio_dev *indio_dev = private; struct sca3000_state *st = iio_priv(indio_dev); int ret, val; - s64 last_timestamp = iio_get_time_ns(); + s64 last_timestamp = iio_get_time_ns(indio_dev); /* * Could lead if badly timed to an extra read of status reg, diff --git a/drivers/staging/iio/adc/ad7280a.c b/drivers/staging/iio/adc/ad7280a.c index a06b46c..2177f1d 100644 --- a/drivers/staging/iio/adc/ad7280a.c +++ b/drivers/staging/iio/adc/ad7280a.c @@ -705,7 +705,7 @@ static irqreturn_t ad7280_event_handler(int irq, void *private) IIO_EV_DIR_RISING, IIO_EV_TYPE_THRESH, 0, 0, 0), - iio_get_time_ns()); + iio_get_time_ns(indio_dev)); else if (((channels[i] >> 11) & 0xFFF) <= st->cell_threshlow) iio_push_event(indio_dev, @@ -715,7 +715,7 @@ static irqreturn_t ad7280_event_handler(int irq, void *private) IIO_EV_DIR_FALLING, IIO_EV_TYPE_THRESH, 0, 0, 0), - iio_get_time_ns()); + iio_get_time_ns(indio_dev)); } else { if (((channels[i] >> 11) & 0xFFF) >= st->aux_threshhigh) iio_push_event(indio_dev, @@ -724,7 +724,7 @@ static irqreturn_t ad7280_event_handler(int irq, void *private) 0, IIO_EV_TYPE_THRESH, IIO_EV_DIR_RISING), - iio_get_time_ns()); + iio_get_time_ns(indio_dev)); else if (((channels[i] >> 11) & 0xFFF) <= st->aux_threshlow) iio_push_event(indio_dev, @@ -733,7 +733,7 @@ static irqreturn_t ad7280_event_handler(int irq, void *private) 0, IIO_EV_TYPE_THRESH, IIO_EV_DIR_FALLING), - iio_get_time_ns()); + iio_get_time_ns(indio_dev)); } } diff --git a/drivers/staging/iio/adc/ad7606_ring.c b/drivers/staging/iio/adc/ad7606_ring.c index a6f8eb1..0572df9 100644 --- a/drivers/staging/iio/adc/ad7606_ring.c +++ b/drivers/staging/iio/adc/ad7606_ring.c @@ -77,7 +77,8 @@ static void ad7606_poll_bh_to_ring(struct work_struct *work_s) goto done; } - iio_push_to_buffers_with_timestamp(indio_dev, buf, iio_get_time_ns()); + iio_push_to_buffers_with_timestamp(indio_dev, buf, + iio_get_time_ns(indio_dev)); done: gpio_set_value(st->pdata->gpio_convst, 0); iio_trigger_notify_done(indio_dev->trig); diff --git a/drivers/staging/iio/adc/ad7816.c b/drivers/staging/iio/adc/ad7816.c index ac3735c..5e8115b 100644 --- a/drivers/staging/iio/adc/ad7816.c +++ b/drivers/staging/iio/adc/ad7816.c @@ -253,7 +253,8 @@ static const struct attribute_group ad7816_attribute_group = { static irqreturn_t ad7816_event_handler(int irq, void *private) { - iio_push_event(private, IIO_EVENT_CODE_AD7816_OTI, iio_get_time_ns()); + iio_push_event(private, IIO_EVENT_CODE_AD7816_OTI, + iio_get_time_ns((struct iio_dev *)private)); return IRQ_HANDLED; } diff --git a/drivers/staging/iio/addac/adt7316.c b/drivers/staging/iio/addac/adt7316.c index a10e7d8..3faffe5 100644 --- a/drivers/staging/iio/addac/adt7316.c +++ b/drivers/staging/iio/addac/adt7316.c @@ -1752,7 +1752,7 @@ static irqreturn_t adt7316_event_handler(int irq, void *private) if ((chip->id & ID_FAMILY_MASK) != ID_ADT75XX) stat1 &= 0x1F; - time = iio_get_time_ns(); + time = iio_get_time_ns(indio_dev); if (stat1 & BIT(0)) iio_push_event(indio_dev, IIO_UNMOD_EVENT_CODE(IIO_TEMP, 0, @@ -1804,7 +1804,7 @@ static irqreturn_t adt7316_event_handler(int irq, void *private) 0, IIO_EV_TYPE_THRESH, IIO_EV_DIR_RISING), - iio_get_time_ns()); + iio_get_time_ns(indio_dev)); } return IRQ_HANDLED; diff --git a/drivers/staging/iio/cdc/ad7150.c b/drivers/staging/iio/cdc/ad7150.c index f6b9a10..5578a07 100644 --- a/drivers/staging/iio/cdc/ad7150.c +++ b/drivers/staging/iio/cdc/ad7150.c @@ -493,7 +493,7 @@ static irqreturn_t ad7150_event_handler(int irq, void *private) struct iio_dev *indio_dev = private; struct ad7150_chip_info *chip = iio_priv(indio_dev); u8 int_status; - s64 timestamp = iio_get_time_ns(); + s64 timestamp = iio_get_time_ns(indio_dev); int ret; ret = i2c_smbus_read_byte_data(chip->client, AD7150_STATUS); diff --git a/drivers/staging/iio/light/tsl2x7x_core.c b/drivers/staging/iio/light/tsl2x7x_core.c index d553c8e..ea15bc1 100644 --- a/drivers/staging/iio/light/tsl2x7x_core.c +++ b/drivers/staging/iio/light/tsl2x7x_core.c @@ -1554,7 +1554,7 @@ static irqreturn_t tsl2x7x_event_handler(int irq, void *private) { struct iio_dev *indio_dev = private; struct tsl2X7X_chip *chip = iio_priv(indio_dev); - s64 timestamp = iio_get_time_ns(); + s64 timestamp = iio_get_time_ns(indio_dev); int ret; u8 value; diff --git a/include/linux/iio/iio.h b/include/linux/iio/iio.h index 7c29cb0..854e2da 100644 --- a/include/linux/iio/iio.h +++ b/include/linux/iio/iio.h @@ -312,13 +312,8 @@ static inline bool iio_channel_has_info(const struct iio_chan_spec *chan, }, \ } -/** - * iio_get_time_ns() - utility function to get a time stamp for events etc - **/ -static inline s64 iio_get_time_ns(void) -{ - return ktime_get_real_ns(); -} +s64 iio_get_time_ns(const struct iio_dev *indio_dev); +unsigned int iio_get_time_res(const struct iio_dev *indio_dev); /* Device operating modes */ #define INDIO_DIRECT_MODE 0x01 @@ -497,6 +492,7 @@ struct iio_buffer_setup_ops { * @chan_attr_group: [INTERN] group for all attrs in base directory * @name: [DRIVER] name of the device. * @info: [DRIVER] callbacks and constant info from driver + * @clock_id: [INTERN] timestamping clock posix identifier * @info_exist_lock: [INTERN] lock to prevent use during removal * @setup_ops: [DRIVER] callbacks to call before and after buffer * enable/disable @@ -537,6 +533,7 @@ struct iio_dev { struct attribute_group chan_attr_group; const char *name; const struct iio_info *info; + clockid_t clock_id; struct mutex info_exist_lock; const struct iio_buffer_setup_ops *setup_ops; struct cdev chrdev; @@ -565,7 +562,7 @@ extern struct bus_type iio_bus_type; /** * iio_device_put() - reference counted deallocation of struct device - * @indio_dev: IIO device structure containing the device + * @indio_dev: IIO device structure containing the device **/ static inline void iio_device_put(struct iio_dev *indio_dev) { @@ -574,6 +571,15 @@ static inline void iio_device_put(struct iio_dev *indio_dev) } /** + * iio_device_get_clock() - Retrieve current timestamping clock for the device + * @indio_dev: IIO device structure containing the device + */ +static inline clockid_t iio_device_get_clock(const struct iio_dev *indio_dev) +{ + return indio_dev->clock_id; +} + +/** * dev_to_iio_dev() - Get IIO device struct from a device struct * @dev: The device embedded in the IIO device * -- cgit v0.10.2 From 8d2c7ef80bc8a66b8c6d657a857403f93952604f Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Thu, 30 Jun 2016 03:48:45 +0200 Subject: iio: pressure: bmp280: augment DT bindings This adds standard device tree bindings for a reset GPIO line, and the VDDD and VDDA power regulators. Cc: devicetree@vger.kernel.org Acked-by: Rob Herring Signed-off-by: Linus Walleij Signed-off-by: Jonathan Cameron diff --git a/Documentation/devicetree/bindings/iio/pressure/bmp085.txt b/Documentation/devicetree/bindings/iio/pressure/bmp085.txt index d7a6deb..c7198a0 100644 --- a/Documentation/devicetree/bindings/iio/pressure/bmp085.txt +++ b/Documentation/devicetree/bindings/iio/pressure/bmp085.txt @@ -1,7 +1,11 @@ -BMP085/BMP18x digital pressure sensors +BMP085/BMP18x/BMP28x digital pressure sensors Required properties: -- compatible: bosch,bmp085 +- compatible: must be one of: + "bosch,bmp085" + "bosch,bmp180" + "bosch,bmp280" + "bosch,bme280" Optional properties: - chip-id: configurable chip id for non-default chip revisions @@ -10,6 +14,10 @@ Optional properties: value range is 0-3 with rising sensitivity. - interrupt-parent: should be the phandle for the interrupt controller - interrupts: interrupt mapping for IRQ +- reset-gpios: a GPIO line handling reset of the sensor: as the line is + active low, it should be marked GPIO_ACTIVE_LOW (see gpio/gpio.txt) +- vddd-supply: digital voltage regulator (see regulator/regulator.txt) +- vdda-supply: analog voltage regulator (see regulator/regulator.txt) Example: @@ -21,4 +29,7 @@ pressure@77 { default-oversampling = <2>; interrupt-parent = <&gpio0>; interrupts = <25 IRQ_TYPE_EDGE_RISING>; + reset-gpios = <&gpio0 26 GPIO_ACTIVE_LOW>; + vddd-supply = <&foo>; + vdda-supply = <&bar>; }; -- cgit v0.10.2 From 78f5027132243b7071dc59ea6f717e2c48e12031 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Thu, 30 Jun 2016 03:48:46 +0200 Subject: iio: pressure: bmp280: support device tree initialization This adds device tree support to the BMP085, BMP180 and BMP280 pressure sensors. Tested on the Qualcomm APQ8060 Dragonboard: iio:device1$ cat in_temp_input 26700 iio:device1$ cat in_pressure_input 99.185000000 Signed-off-by: Linus Walleij Signed-off-by: Jonathan Cameron diff --git a/drivers/iio/pressure/bmp280.c b/drivers/iio/pressure/bmp280.c index dbbcd6d..a147ce2 100644 --- a/drivers/iio/pressure/bmp280.c +++ b/drivers/iio/pressure/bmp280.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -1094,6 +1095,19 @@ static const struct acpi_device_id bmp280_acpi_match[] = { }; MODULE_DEVICE_TABLE(acpi, bmp280_acpi_match); +#ifdef CONFIG_OF +static const struct of_device_id bmp280_of_match[] = { + { .compatible = "bosch,bme280", .data = (void *)BME280_CHIP_ID }, + { .compatible = "bosch,bmp280", .data = (void *)BMP280_CHIP_ID }, + { .compatible = "bosch,bmp180", .data = (void *)BMP180_CHIP_ID }, + { .compatible = "bosch,bmp085", .data = (void *)BMP180_CHIP_ID }, + { }, +}; +MODULE_DEVICE_TABLE(of, bmp280_of_match); +#else +#define bmp280_of_match NULL +#endif + static const struct i2c_device_id bmp280_id[] = { {"bmp280", BMP280_CHIP_ID }, {"bmp180", BMP180_CHIP_ID }, @@ -1107,6 +1121,7 @@ static struct i2c_driver bmp280_driver = { .driver = { .name = "bmp280", .acpi_match_table = ACPI_PTR(bmp280_acpi_match), + .of_match_table = of_match_ptr(bmp280_of_match), }, .probe = bmp280_probe, .id_table = bmp280_id, -- cgit v0.10.2 From c5842b47b2945d6db24b4db6b2c7364e94cbc78b Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Thu, 30 Jun 2016 03:48:47 +0200 Subject: iio: pressure: bmp280: add reset GPIO line handling On the APQ8060 Dragonboard the reset line to the BMP085 pressure sensor is not deasserted on boot, so the driver needs to handle this. For a simple GPIO line supplied as a descriptor (from a board file, device tree or ACPI) this does the trick. Signed-off-by: Linus Walleij Signed-off-by: Jonathan Cameron diff --git a/drivers/iio/pressure/bmp280.c b/drivers/iio/pressure/bmp280.c index a147ce2..77172f0 100644 --- a/drivers/iio/pressure/bmp280.c +++ b/drivers/iio/pressure/bmp280.c @@ -23,6 +23,7 @@ #include #include #include +#include /* BMP280 specific registers */ #define BMP280_REG_HUMIDITY_LSB 0xFE @@ -1024,6 +1025,7 @@ static int bmp280_probe(struct i2c_client *client, struct iio_dev *indio_dev; struct bmp280_data *data; unsigned int chip_id; + struct gpio_desc *gpiod; indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); if (!indio_dev) @@ -1063,6 +1065,14 @@ static int bmp280_probe(struct i2c_client *client, return -EINVAL; } + /* Bring chip out of reset if there is an assigned GPIO line */ + gpiod = devm_gpiod_get(&client->dev, "reset", GPIOD_OUT_HIGH); + /* Deassert the signal */ + if (!IS_ERR(gpiod)) { + dev_info(&client->dev, "release reset\n"); + gpiod_set_value(gpiod, 0); + } + data->regmap = devm_regmap_init_i2c(client, data->chip_info->regmap_config); if (IS_ERR(data->regmap)) { -- cgit v0.10.2 From 90e96fdd012925871a1a21b5eaeab4b027682d6a Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Wed, 29 Jun 2016 14:08:33 +0200 Subject: iio: magn: ak8975: fix regulator usage IS_ERR_OR_NULL() should never be used with regulators because a NULL pointer may be a perfectly valid dummy regulator We should always succeed to fetch and enable a regulator, but it may be a dummy. That is fine, so bail out for any real errors or probe deferrals Include the error code in the warning print so we know what kind of problem we're dealing with (for example it is nice to see if it is a probe deferral). As we will bail out of probe if the regulator is erroneous, just issue regulator_disable() on the poweroff path: it will succeed. Cc: Mark Brown Cc: Lars-Peter Clausen Lars-Peter Clausen Signed-off-by: Linus Walleij Signed-off-by: Jonathan Cameron diff --git a/drivers/iio/magnetometer/ak8975.c b/drivers/iio/magnetometer/ak8975.c index 2121b50..def693c 100644 --- a/drivers/iio/magnetometer/ak8975.c +++ b/drivers/iio/magnetometer/ak8975.c @@ -389,17 +389,16 @@ static int ak8975_power_on(struct i2c_client *client) int ret; data->vdd = devm_regulator_get(&client->dev, "vdd"); - if (IS_ERR_OR_NULL(data->vdd)) { + if (IS_ERR(data->vdd)) { ret = PTR_ERR(data->vdd); - if (ret == -ENODEV) - ret = 0; } else { ret = regulator_enable(data->vdd); } - - if (ret) - dev_err(&client->dev, "failed to enable Vdd supply: %d\n", ret); - return ret; + if (ret) { + dev_warn(&client->dev, + "Failed to enable specified Vdd supply\n"); + return ret; + } } /* Disable attached power regulator if any. */ @@ -408,8 +407,7 @@ static void ak8975_power_off(const struct i2c_client *client) const struct iio_dev *indio_dev = i2c_get_clientdata(client); const struct ak8975_data *data = iio_priv(indio_dev); - if (!IS_ERR_OR_NULL(data->vdd)) - regulator_disable(data->vdd); + regulator_disable(data->vdd); } /* -- cgit v0.10.2 From b21d3f3452ec3a060c8f576a97adfdd4329b3157 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Wed, 29 Jun 2016 14:08:34 +0200 Subject: iio: magn: ak8975: add Vid regulator The AK8975 has two power sources: Vdd (analog voltage supply) and Vid (digital voltage supply). Optionally also obtain the Vid supply regulator and enable it. If an error occurs when enabling one of the regulators: bail out. Cc: Gregor Boirie Cc: Richard Leitner Cc: Krzysztof Kozlowski Cc: Lars-Peter Clausen Signed-off-by: Linus Walleij Signed-off-by: Jonathan Cameron diff --git a/drivers/iio/magnetometer/ak8975.c b/drivers/iio/magnetometer/ak8975.c index def693c..ca69f8d 100644 --- a/drivers/iio/magnetometer/ak8975.c +++ b/drivers/iio/magnetometer/ak8975.c @@ -379,6 +379,7 @@ struct ak8975_data { u8 cntl_cache; struct iio_mount_matrix orientation; struct regulator *vdd; + struct regulator *vid; }; /* Enable attached power regulator if any. */ @@ -399,6 +400,19 @@ static int ak8975_power_on(struct i2c_client *client) "Failed to enable specified Vdd supply\n"); return ret; } + + data->vid = devm_regulator_get(&client->dev, "vid"); + if (IS_ERR(data->vid)) { + ret = PTR_ERR(data->vid); + } else { + ret = regulator_enable(data->vid); + } + if (ret) { + dev_warn(&client->dev, + "Failed to enable specified Vid supply\n"); + return ret; + } + return 0; } /* Disable attached power regulator if any. */ @@ -407,6 +421,7 @@ static void ak8975_power_off(const struct i2c_client *client) const struct iio_dev *indio_dev = i2c_get_clientdata(client); const struct ak8975_data *data = iio_priv(indio_dev); + regulator_disable(data->vid); regulator_disable(data->vdd); } -- cgit v0.10.2 From 9e6c16d98987f6d5df8e59f61b20140d2f1bdcb4 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Wed, 29 Jun 2016 14:08:35 +0200 Subject: iio: magn: ak8975: refactor regulator handlers Move the regulator_get() calls directly into the probe() function, keep only the power_on()/power_off() functions to flick the regulators on/off. Signed-off-by: Linus Walleij Signed-off-by: Jonathan Cameron diff --git a/drivers/iio/magnetometer/ak8975.c b/drivers/iio/magnetometer/ak8975.c index ca69f8d..6915bd1 100644 --- a/drivers/iio/magnetometer/ak8975.c +++ b/drivers/iio/magnetometer/ak8975.c @@ -383,32 +383,19 @@ struct ak8975_data { }; /* Enable attached power regulator if any. */ -static int ak8975_power_on(struct i2c_client *client) +static int ak8975_power_on(const struct ak8975_data *data) { - const struct iio_dev *indio_dev = i2c_get_clientdata(client); - struct ak8975_data *data = iio_priv(indio_dev); int ret; - data->vdd = devm_regulator_get(&client->dev, "vdd"); - if (IS_ERR(data->vdd)) { - ret = PTR_ERR(data->vdd); - } else { - ret = regulator_enable(data->vdd); - } + ret = regulator_enable(data->vdd); if (ret) { - dev_warn(&client->dev, + dev_warn(&data->client->dev, "Failed to enable specified Vdd supply\n"); return ret; } - - data->vid = devm_regulator_get(&client->dev, "vid"); - if (IS_ERR(data->vid)) { - ret = PTR_ERR(data->vid); - } else { - ret = regulator_enable(data->vid); - } + ret = regulator_enable(data->vid); if (ret) { - dev_warn(&client->dev, + dev_warn(&data->client->dev, "Failed to enable specified Vid supply\n"); return ret; } @@ -416,11 +403,8 @@ static int ak8975_power_on(struct i2c_client *client) } /* Disable attached power regulator if any. */ -static void ak8975_power_off(const struct i2c_client *client) +static void ak8975_power_off(const struct ak8975_data *data) { - const struct iio_dev *indio_dev = i2c_get_clientdata(client); - const struct ak8975_data *data = iio_priv(indio_dev); - regulator_disable(data->vid); regulator_disable(data->vdd); } @@ -937,7 +921,15 @@ static int ak8975_probe(struct i2c_client *client, data->def = &ak_def_array[chipset]; - err = ak8975_power_on(client); + /* Fetch the regulators */ + data->vdd = devm_regulator_get(&client->dev, "vdd"); + if (IS_ERR(data->vdd)) + return PTR_ERR(data->vdd); + data->vid = devm_regulator_get(&client->dev, "vid"); + if (IS_ERR(data->vid)) + return PTR_ERR(data->vid); + + err = ak8975_power_on(data); if (err) return err; @@ -982,17 +974,18 @@ static int ak8975_probe(struct i2c_client *client, cleanup_buffer: iio_triggered_buffer_cleanup(indio_dev); power_off: - ak8975_power_off(client); + ak8975_power_off(data); return err; } static int ak8975_remove(struct i2c_client *client) { struct iio_dev *indio_dev = i2c_get_clientdata(client); + struct ak8975_data *data = iio_priv(indio_dev); iio_device_unregister(indio_dev); iio_triggered_buffer_cleanup(indio_dev); - ak8975_power_off(client); + ak8975_power_off(data); return 0; } -- cgit v0.10.2 From b1037c1a498f9bb3b5a81c2f243c605c190da754 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Wed, 29 Jun 2016 14:08:36 +0200 Subject: iio: magn: ak8975: allow a delay after enabling regulators The datasheet actually specifies that we need to wait atleast 500us after powering on the device before trying to set mode. Signed-off-by: Linus Walleij Signed-off-by: Jonathan Cameron diff --git a/drivers/iio/magnetometer/ak8975.c b/drivers/iio/magnetometer/ak8975.c index 6915bd1..bf3ffc4 100644 --- a/drivers/iio/magnetometer/ak8975.c +++ b/drivers/iio/magnetometer/ak8975.c @@ -399,6 +399,12 @@ static int ak8975_power_on(const struct ak8975_data *data) "Failed to enable specified Vid supply\n"); return ret; } + /* + * According to the datasheet the power supply rise time i 200us + * and the minimum wait time before mode setting is 100us, in + * total 300 us. Add some margin and say minimum 500us here. + */ + usleep_range(500, 1000); return 0; } -- cgit v0.10.2 From 8d06cd25f745db8905e303cc915932cc50aa0ae5 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Wed, 29 Jun 2016 14:08:37 +0200 Subject: iio: magn: ak8975: make sure to power down at remove() The code was not powering the magnetometer down properly at remove(): just cutting the regulators without first setting the device in power off mode. Fix this. Signed-off-by: Linus Walleij Reviewed-by: Ulf Hansson Signed-off-by: Jonathan Cameron diff --git a/drivers/iio/magnetometer/ak8975.c b/drivers/iio/magnetometer/ak8975.c index bf3ffc4..3e12201 100644 --- a/drivers/iio/magnetometer/ak8975.c +++ b/drivers/iio/magnetometer/ak8975.c @@ -991,6 +991,7 @@ static int ak8975_remove(struct i2c_client *client) iio_device_unregister(indio_dev); iio_triggered_buffer_cleanup(indio_dev); + ak8975_set_mode(data, POWER_DOWN); ak8975_power_off(data); return 0; -- cgit v0.10.2 From cde4cb5dd4221a3999ea804e85ad3dc48f3f5b78 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Wed, 29 Jun 2016 14:08:38 +0200 Subject: iio: magn: ak8975: deploy runtime and system PM This adds runtime PM support to the AK8975 driver. It solves two problems: - After reading the first value the chip was left in MODE_ONCE, meaning (presumably) it may be consuming more power. Now the runtime PM hooks kick in and set it to POWER_DOWN. - Regulators were simply enabled and left on, making it impossible to turn the power consuming regulators off because of the increased refcount. We now disable the regulators at autosuspend. - We also handle system suspend: by using pm_runtime_force_suspend() and pm_runtime_force_resume() from the system PM sleep hooks, the runtime PM code is managing the power also for this case. It is currently not completely optimal: when the system resumes the AK8975 goes into active mode even if noone is going to use it: currently the force calls need to be paired, but the runtime PM people are working on making it possible to leave devices runtime suspended when coming back from sleep. Inspired by my work on the BH1780 light sensor driver. Signed-off-by: Linus Walleij Reviewed-by: Ulf Hansson Signed-off-by: Jonathan Cameron diff --git a/drivers/iio/magnetometer/ak8975.c b/drivers/iio/magnetometer/ak8975.c index 3e12201..af8606c 100644 --- a/drivers/iio/magnetometer/ak8975.c +++ b/drivers/iio/magnetometer/ak8975.c @@ -33,6 +33,7 @@ #include #include #include +#include #include #include @@ -692,6 +693,8 @@ static int ak8975_read_axis(struct iio_dev *indio_dev, int index, int *val) u16 buff; int ret; + pm_runtime_get_sync(&data->client->dev); + mutex_lock(&data->lock); ret = ak8975_start_read_axis(data, client); @@ -706,6 +709,9 @@ static int ak8975_read_axis(struct iio_dev *indio_dev, int index, int *val) mutex_unlock(&data->lock); + pm_runtime_mark_last_busy(&data->client->dev); + pm_runtime_put_autosuspend(&data->client->dev); + /* Swap bytes and convert to valid range. */ buff = le16_to_cpu(buff); *val = clamp_t(s16, buff, -def->range, def->range); @@ -975,6 +981,18 @@ static int ak8975_probe(struct i2c_client *client, goto cleanup_buffer; } + /* Enable runtime PM */ + pm_runtime_get_noresume(&client->dev); + pm_runtime_set_active(&client->dev); + pm_runtime_enable(&client->dev); + /* + * The device comes online in 500us, so add two orders of magnitude + * of delay before autosuspending: 50 ms. + */ + pm_runtime_set_autosuspend_delay(&client->dev, 50); + pm_runtime_use_autosuspend(&client->dev); + pm_runtime_put(&client->dev); + return 0; cleanup_buffer: @@ -989,6 +1007,9 @@ static int ak8975_remove(struct i2c_client *client) struct iio_dev *indio_dev = i2c_get_clientdata(client); struct ak8975_data *data = iio_priv(indio_dev); + pm_runtime_get_sync(&client->dev); + pm_runtime_put_noidle(&client->dev); + pm_runtime_disable(&client->dev); iio_device_unregister(indio_dev); iio_triggered_buffer_cleanup(indio_dev); ak8975_set_mode(data, POWER_DOWN); @@ -997,6 +1018,56 @@ static int ak8975_remove(struct i2c_client *client) return 0; } +#ifdef CONFIG_PM +static int ak8975_runtime_suspend(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct iio_dev *indio_dev = i2c_get_clientdata(client); + struct ak8975_data *data = iio_priv(indio_dev); + int ret; + + /* Set the device in power down if it wasn't already */ + ret = ak8975_set_mode(data, POWER_DOWN); + if (ret < 0) { + dev_err(&client->dev, "Error in setting power-down mode\n"); + return ret; + } + /* Next cut the regulators */ + ak8975_power_off(data); + + return 0; +} + +static int ak8975_runtime_resume(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct iio_dev *indio_dev = i2c_get_clientdata(client); + struct ak8975_data *data = iio_priv(indio_dev); + int ret; + + /* Take up the regulators */ + ak8975_power_on(data); + /* + * We come up in powered down mode, the reading routines will + * put us in the mode to read values later. + */ + ret = ak8975_set_mode(data, POWER_DOWN); + if (ret < 0) { + dev_err(&client->dev, "Error in setting power-down mode\n"); + return ret; + } + + return 0; +} +#endif /* CONFIG_PM */ + +static const struct dev_pm_ops ak8975_dev_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, + pm_runtime_force_resume) + SET_RUNTIME_PM_OPS(ak8975_runtime_suspend, + ak8975_runtime_resume, NULL) +}; + static const struct i2c_device_id ak8975_id[] = { {"ak8975", AK8975}, {"ak8963", AK8963}, @@ -1024,6 +1095,7 @@ MODULE_DEVICE_TABLE(of, ak8975_of_match); static struct i2c_driver ak8975_driver = { .driver = { .name = "ak8975", + .pm = &ak8975_dev_pm_ops, .of_match_table = of_match_ptr(ak8975_of_match), .acpi_match_table = ACPI_PTR(ak_acpi_match), }, -- cgit v0.10.2 From 0b340405fca980b12a2ddafdd4536ad6fb624755 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Mon, 20 Jun 2016 12:20:58 +0200 Subject: drm/sun4i: Report proper vblank The sun4i display engine doesn't have any vblank counter. Use the proper helper for that. Signed-off-by: Maxime Ripard diff --git a/drivers/gpu/drm/sun4i/sun4i_drv.c b/drivers/gpu/drm/sun4i/sun4i_drv.c index 257d2b4..cbe4a25 100644 --- a/drivers/gpu/drm/sun4i/sun4i_drv.c +++ b/drivers/gpu/drm/sun4i/sun4i_drv.c @@ -92,7 +92,7 @@ static struct drm_driver sun4i_drv_driver = { /* Frame Buffer Operations */ /* VBlank Operations */ - .get_vblank_counter = drm_vblank_count, + .get_vblank_counter = drm_vblank_no_hw_counter, .enable_vblank = sun4i_drv_enable_vblank, .disable_vblank = sun4i_drv_disable_vblank, }; -- cgit v0.10.2 From 2cd368300aa5bcec40c079ee5096287847506504 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Mon, 20 Jun 2016 12:20:59 +0200 Subject: drm/sun4i: Send vblank event when the CRTC is disabled So far, we were missing to send the vblank event when disabling the CRTC, making us never report the last vblank event. This was causing a time out on the page flip, which should be solved now. Signed-off-by: Maxime Ripard diff --git a/drivers/gpu/drm/sun4i/sun4i_crtc.c b/drivers/gpu/drm/sun4i/sun4i_crtc.c index 4182a21..41cacec 100644 --- a/drivers/gpu/drm/sun4i/sun4i_crtc.c +++ b/drivers/gpu/drm/sun4i/sun4i_crtc.c @@ -65,6 +65,14 @@ static void sun4i_crtc_disable(struct drm_crtc *crtc) DRM_DEBUG_DRIVER("Disabling the CRTC\n"); sun4i_tcon_disable(drv->tcon); + + if (crtc->state->event && !crtc->state->active) { + spin_lock_irq(&crtc->dev->event_lock); + drm_crtc_send_vblank_event(crtc, crtc->state->event); + spin_unlock_irq(&crtc->dev->event_lock); + + crtc->state->event = NULL; + } } static void sun4i_crtc_enable(struct drm_crtc *crtc) -- cgit v0.10.2 From 74524955556096a0b2a821a49b4d0abebad3ee16 Mon Sep 17 00:00:00 2001 From: Tahsin Erdogan Date: Thu, 16 Jun 2016 05:15:33 -0700 Subject: writeback: inode cgroup wb switch should not call ihold() Asynchronous wb switching of inodes takes an additional ref count on an inode to make sure inode remains valid until switchover is completed. However, anyone calling ihold() must already have a ref count on inode, but in this case inode->i_count may already be zero: ------------[ cut here ]------------ WARNING: CPU: 1 PID: 917 at fs/inode.c:397 ihold+0x2b/0x30 CPU: 1 PID: 917 Comm: kworker/u4:5 Not tainted 4.7.0-rc2+ #49 Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS Bochs 01/01/2011 Workqueue: writeback wb_workfn (flush-8:16) 0000000000000000 ffff88007ca0fb58 ffffffff805990af 0000000000000000 0000000000000000 ffff88007ca0fb98 ffffffff80268702 0000018d000004e2 ffff88007cef40e8 ffff88007c9b89a8 ffff880079e3a740 0000000000000003 Call Trace: [] dump_stack+0x4d/0x6e [] __warn+0xc2/0xe0 [] warn_slowpath_null+0x18/0x20 [] ihold+0x2b/0x30 [] inode_switch_wbs+0x11c/0x180 [] wbc_detach_inode+0x170/0x1a0 [] writeback_sb_inodes+0x21c/0x530 [] wb_writeback+0xee/0x1e0 [] wb_workfn+0xd7/0x280 [] ? try_to_wake_up+0x1b1/0x2b0 [] process_one_work+0x129/0x300 [] worker_thread+0x126/0x480 [] ? __schedule+0x1c7/0x561 [] ? process_one_work+0x300/0x300 [] kthread+0xc4/0xe0 [] ? kfree+0xc8/0x100 [] ret_from_fork+0x1f/0x40 [] ? __kthread_parkme+0x70/0x70 ---[ end trace aaefd2fd9f306bc4 ]--- Signed-off-by: Tahsin Erdogan Acked-by: Tejun Heo Reviewed-by: Jan Kara Signed-off-by: Jens Axboe diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c index 989a2ce..fe7e83a 100644 --- a/fs/fs-writeback.c +++ b/fs/fs-writeback.c @@ -483,9 +483,9 @@ static void inode_switch_wbs(struct inode *inode, int new_wb_id) goto out_free; } inode->i_state |= I_WB_SWITCH; + __iget(inode); spin_unlock(&inode->i_lock); - ihold(inode); isw->inode = inode; atomic_inc(&isw_nr_in_flight); -- cgit v0.10.2 From 135cce1bf12bd30d7d66360022f9dac6ea3a07cd Mon Sep 17 00:00:00 2001 From: "Peter Zijlstra (Intel)" Date: Thu, 30 Jun 2016 10:29:55 +0200 Subject: perf annotate: Add number of samples to the header Staring at annotations of large functions is useless if there's only a few samples in them. Report the number of samples in the header to make this easier to determine. Committer note: The change amounts to: - Percent | Source code & Disassembly of perf-vdso.so for cycles:u ------------------------------------------------------------------ + Percent | Source code & Disassembly of perf-vdso.so for cycles:u (3278 samples) +-------------------------------------------------------------------------------- Signed-off-by: Peter Zijlstra (Intel) Cc: Jiri Olsa Link: http://lkml.kernel.org/r/20160630082955.GA30921@twins.programming.kicks-ass.net [ split from a larger patch ] Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index 78e5d6f..e9825fe 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -1522,6 +1522,7 @@ int symbol__annotate_printf(struct symbol *sym, struct map *map, const char *d_filename; const char *evsel_name = perf_evsel__name(evsel); struct annotation *notes = symbol__annotation(sym); + struct sym_hist *h = annotation__histogram(notes, evsel->idx); struct disasm_line *pos, *queue = NULL; u64 start = map__rip_2objdump(map, sym->start); int printed = 2, queue_len = 0; @@ -1544,8 +1545,8 @@ int symbol__annotate_printf(struct symbol *sym, struct map *map, if (perf_evsel__is_group_event(evsel)) width *= evsel->nr_members; - graph_dotted_len = printf(" %-*.*s| Source code & Disassembly of %s for %s\n", - width, width, "Percent", d_filename, evsel_name); + graph_dotted_len = printf(" %-*.*s| Source code & Disassembly of %s for %s (%" PRIu64 " samples)\n", + width, width, "Percent", d_filename, evsel_name, h->sum); printf("%-*.*s----\n", graph_dotted_len, graph_dotted_len, graph_dotted_line); -- cgit v0.10.2 From a41af25b3c317331743dc53defaa3f2e03d255cb Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 30 Jun 2016 11:57:33 -0300 Subject: perf trace beauty sched_policy: Define SCHED_RESET_ON_FORK for older systems RHEL5 for instance doesn't have this one, help it. Cc: Adrian Hunter Cc: David Ahern Cc: Jiri Olsa Cc: Namhyung Kim Cc: Wang Nan Link: http://lkml.kernel.org/n/tip-3adewnii78zi110eovfciopy@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/trace/beauty/sched_policy.c b/tools/perf/trace/beauty/sched_policy.c index c205bc6..3477529 100644 --- a/tools/perf/trace/beauty/sched_policy.c +++ b/tools/perf/trace/beauty/sched_policy.c @@ -9,6 +9,9 @@ #ifndef SCHED_DEADLINE #define SCHED_DEADLINE 6 #endif +#ifndef SCHED_RESET_ON_FORK +#define SCHED_RESET_ON_FORK 0x40000000 +#endif static size_t syscall_arg__scnprintf_sched_policy(char *bf, size_t size, struct syscall_arg *arg) -- cgit v0.10.2 From 3be28870c05ad09dfff4dbefe71b02aba5dba569 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 30 Jun 2016 12:00:58 -0300 Subject: perf trace beauty eventfd: No need to include eventfd.h Old systems such as RHEL5 lack this file, and what we need is already under ifdefs, so just ditch this #include. Cc: Adrian Hunter Cc: David Ahern Cc: Jiri Olsa Cc: Namhyung Kim Cc: Wang Nan Link: http://lkml.kernel.org/n/tip-dzbjfllw6znuoy37skwnwa4r@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/trace/beauty/eventfd.c b/tools/perf/trace/beauty/eventfd.c index d64f4a9..b08f21e 100644 --- a/tools/perf/trace/beauty/eventfd.c +++ b/tools/perf/trace/beauty/eventfd.c @@ -1,5 +1,3 @@ -#include - #ifndef EFD_SEMAPHORE #define EFD_SEMAPHORE 1 #endif -- cgit v0.10.2 From f3069249e9e6b0ce303c3547dfa2960ee2e95b61 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Tue, 28 Jun 2016 13:29:02 +0200 Subject: perf tools: Allow to reset open files counter I hit a bug when running test suite without forking each test (-F option): $ perf test -F dso 8: Test dso data read : Ok 9: Test dso data cache : FAILED! 10: Test dso data reopen : FAILED! The reason the session file limit is set just once for perf process so we need to reset it for each test, otherwise wrong limit is taken into account. Signed-off-by: Jiri Olsa Tested-by: Arnaldo Carvalho de Melo Tested-by: Nilay Vaish Cc: David Ahern Cc: Namhyung Kim Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1467113345-12669-2-git-send-email-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/tests/dso-data.c b/tools/perf/tests/dso-data.c index 8cf0d9e..13725e0 100644 --- a/tools/perf/tests/dso-data.c +++ b/tools/perf/tests/dso-data.c @@ -251,6 +251,9 @@ int test__dso_data_cache(int subtest __maybe_unused) long nr_end, nr = open_files_cnt(); int dso_cnt, limit, i, fd; + /* Rest the internal dso open counter limit. */ + reset_fd_limit(); + memset(&machine, 0, sizeof(machine)); /* set as system limit */ @@ -312,6 +315,9 @@ int test__dso_data_reopen(int subtest __maybe_unused) #define dso_1 (dsos[1]) #define dso_2 (dsos[2]) + /* Rest the internal dso open counter limit. */ + reset_fd_limit(); + memset(&machine, 0, sizeof(machine)); /* diff --git a/tools/perf/util/dso.c b/tools/perf/util/dso.c index 5d286f5..e1de6cc 100644 --- a/tools/perf/util/dso.c +++ b/tools/perf/util/dso.c @@ -442,17 +442,27 @@ static rlim_t get_fd_limit(void) return limit; } -static bool may_cache_fd(void) +static rlim_t fd_limit; + +/* + * Used only by tests/dso-data.c to reset the environment + * for tests. I dont expect we should change this during + * standard runtime. + */ +void reset_fd_limit(void) { - static rlim_t limit; + fd_limit = 0; +} - if (!limit) - limit = get_fd_limit(); +static bool may_cache_fd(void) +{ + if (!fd_limit) + fd_limit = get_fd_limit(); - if (limit == RLIM_INFINITY) + if (fd_limit == RLIM_INFINITY) return true; - return limit > (rlim_t) dso__data_open_cnt; + return fd_limit > (rlim_t) dso__data_open_cnt; } /* diff --git a/tools/perf/util/dso.h b/tools/perf/util/dso.h index 76d79d0..a571f24 100644 --- a/tools/perf/util/dso.h +++ b/tools/perf/util/dso.h @@ -360,4 +360,6 @@ enum dso_type dso__type(struct dso *dso, struct machine *machine); int dso__strerror_load(struct dso *dso, char *buf, size_t buflen); +void reset_fd_limit(void); + #endif /* __PERF_DSO */ -- cgit v0.10.2 From 8fbc38aaaf542433ef195e5fae704c56d1c071e6 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Tue, 28 Jun 2016 13:29:03 +0200 Subject: perf tests: Fix thread map test for -F option I hit a bug when running test suite without forking each test (-F option): $ perf test -Fv ... 34: Test thread map : --- start --- FAILED tests/thread-map.c:24 wrong comm ---- end ---- Test thread map: FAILED! The reason was the process name wasn't 'perf' as expected by the test, because other tests set the name as well. Setting it explicitly now. Signed-off-by: Jiri Olsa Tested-by: Arnaldo Carvalho de Melo Tested-by: Nilay Vaish Cc: David Ahern Cc: Namhyung Kim Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1467113345-12669-3-git-send-email-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/tests/thread-map.c b/tools/perf/tests/thread-map.c index fccde84..cee2a2c 100644 --- a/tools/perf/tests/thread-map.c +++ b/tools/perf/tests/thread-map.c @@ -1,13 +1,20 @@ #include #include +#include #include "tests.h" #include "thread_map.h" #include "debug.h" +#define NAME (const char *) "perf" +#define NAMEUL (unsigned long) NAME + int test__thread_map(int subtest __maybe_unused) { struct thread_map *map; + TEST_ASSERT_VAL("failed to set process name", + !prctl(PR_SET_NAME, NAMEUL, 0, 0, 0)); + /* test map on current pid */ map = thread_map__new_by_pid(getpid()); TEST_ASSERT_VAL("failed to alloc map", map); @@ -19,7 +26,7 @@ int test__thread_map(int subtest __maybe_unused) thread_map__pid(map, 0) == getpid()); TEST_ASSERT_VAL("wrong comm", thread_map__comm(map, 0) && - !strcmp(thread_map__comm(map, 0), "perf")); + !strcmp(thread_map__comm(map, 0), NAME)); TEST_ASSERT_VAL("wrong refcnt", atomic_read(&map->refcnt) == 1); thread_map__put(map); @@ -51,7 +58,7 @@ static int process_event(struct perf_tool *tool __maybe_unused, TEST_ASSERT_VAL("wrong nr", map->nr == 1); TEST_ASSERT_VAL("wrong pid", map->entries[0].pid == (u64) getpid()); - TEST_ASSERT_VAL("wrong comm", !strcmp(map->entries[0].comm, "perf")); + TEST_ASSERT_VAL("wrong comm", !strcmp(map->entries[0].comm, NAME)); threads = thread_map__new_event(&event->thread_map); TEST_ASSERT_VAL("failed to alloc map", threads); @@ -61,7 +68,7 @@ static int process_event(struct perf_tool *tool __maybe_unused, thread_map__pid(threads, 0) == getpid()); TEST_ASSERT_VAL("wrong comm", thread_map__comm(threads, 0) && - !strcmp(thread_map__comm(threads, 0), "perf")); + !strcmp(thread_map__comm(threads, 0), NAME)); TEST_ASSERT_VAL("wrong refcnt", atomic_read(&threads->refcnt) == 1); thread_map__put(threads); @@ -72,6 +79,9 @@ int test__thread_map_synthesize(int subtest __maybe_unused) { struct thread_map *threads; + TEST_ASSERT_VAL("failed to set process name", + !prctl(PR_SET_NAME, NAMEUL, 0, 0, 0)); + /* test map on current pid */ threads = thread_map__new_by_pid(getpid()); TEST_ASSERT_VAL("failed to alloc map", threads); -- cgit v0.10.2 From 7fa9b8fba0b55edd1ff5b8ea696ec75fc5f6194c Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Tue, 28 Jun 2016 13:29:01 +0200 Subject: perf test: Add -F/--dont-fork option Adding -F/--dont-fork option to bypass forking for each test. It's useful for debugging test. Signed-off-by: Jiri Olsa Tested-by: Arnaldo Carvalho de Melo Tested-by: Nilay Vaish Cc: David Ahern Cc: Namhyung Kim Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1467113345-12669-1-git-send-email-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/Documentation/perf-test.txt b/tools/perf/Documentation/perf-test.txt index 31a5c3e..b329c65 100644 --- a/tools/perf/Documentation/perf-test.txt +++ b/tools/perf/Documentation/perf-test.txt @@ -30,3 +30,7 @@ OPTIONS -v:: --verbose:: Be more verbose. + +-F:: +--dont-fork:: + Do not fork child for each test, run all tests within single process. diff --git a/tools/perf/tests/builtin-test.c b/tools/perf/tests/builtin-test.c index 0e95c20..5781c16 100644 --- a/tools/perf/tests/builtin-test.c +++ b/tools/perf/tests/builtin-test.c @@ -14,6 +14,8 @@ #include #include "symbol.h" +static bool dont_fork; + struct test __weak arch_tests[] = { { .func = NULL, @@ -247,7 +249,7 @@ static bool perf_test__matches(struct test *test, int curr, int argc, const char static int run_test(struct test *test, int subtest) { - int status, err = -1, child = fork(); + int status, err = -1, child = dont_fork ? 0 : fork(); char sbuf[STRERR_BUFSIZE]; if (child < 0) { @@ -257,34 +259,41 @@ static int run_test(struct test *test, int subtest) } if (!child) { - pr_debug("test child forked, pid %d\n", getpid()); - if (!verbose) { - int nullfd = open("/dev/null", O_WRONLY); - if (nullfd >= 0) { - close(STDERR_FILENO); - close(STDOUT_FILENO); - - dup2(nullfd, STDOUT_FILENO); - dup2(STDOUT_FILENO, STDERR_FILENO); - close(nullfd); + if (!dont_fork) { + pr_debug("test child forked, pid %d\n", getpid()); + + if (!verbose) { + int nullfd = open("/dev/null", O_WRONLY); + + if (nullfd >= 0) { + close(STDERR_FILENO); + close(STDOUT_FILENO); + + dup2(nullfd, STDOUT_FILENO); + dup2(STDOUT_FILENO, STDERR_FILENO); + close(nullfd); + } + } else { + signal(SIGSEGV, sighandler_dump_stack); + signal(SIGFPE, sighandler_dump_stack); } - } else { - signal(SIGSEGV, sighandler_dump_stack); - signal(SIGFPE, sighandler_dump_stack); } err = test->func(subtest); - exit(err); + if (!dont_fork) + exit(err); } - wait(&status); + if (!dont_fork) { + wait(&status); - if (WIFEXITED(status)) { - err = (signed char)WEXITSTATUS(status); - pr_debug("test child finished with %d\n", err); - } else if (WIFSIGNALED(status)) { - err = -1; - pr_debug("test child interrupted\n"); + if (WIFEXITED(status)) { + err = (signed char)WEXITSTATUS(status); + pr_debug("test child finished with %d\n", err); + } else if (WIFSIGNALED(status)) { + err = -1; + pr_debug("test child interrupted\n"); + } } return err; @@ -425,6 +434,8 @@ int cmd_test(int argc, const char **argv, const char *prefix __maybe_unused) OPT_STRING('s', "skip", &skip, "tests", "tests to skip"), OPT_INCR('v', "verbose", &verbose, "be more verbose (show symbol address, etc)"), + OPT_BOOLEAN('F', "dont-fork", &dont_fork, + "Do not fork for testcase"), OPT_END() }; const char * const test_subcommands[] = { "list", NULL }; -- cgit v0.10.2 From a24020e6b7cf6eb8b75d8bca6b89870b1cee6ba7 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Tue, 28 Jun 2016 13:29:04 +0200 Subject: perf tools: Change cpu_map__fprintf output Display cpu map in standard list form. (perf report -D output on perf stat data). before: 0x590 [0x18]: PERF_RECORD_CPU_MAP nr: 4 cpus: 0, 1, 2, 3 after: 0x590 [0x18]: PERF_RECORD_CPU_MAP: 0-3 Adding automated testcase. Signed-off-by: Jiri Olsa Tested-by: Arnaldo Carvalho de Melo Cc: David Ahern Cc: Namhyung Kim Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1467113345-12669-4-git-send-email-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/tests/builtin-test.c b/tools/perf/tests/builtin-test.c index 5781c16..07c14e9 100644 --- a/tools/perf/tests/builtin-test.c +++ b/tools/perf/tests/builtin-test.c @@ -214,6 +214,10 @@ static struct test generic_tests[] = { .func = test__backward_ring_buffer, }, { + .desc = "Test cpu map print", + .func = test__cpu_map_print, + }, + { .func = NULL, }, }; diff --git a/tools/perf/tests/cpumap.c b/tools/perf/tests/cpumap.c index 4cb6418..c9ec5f8 100644 --- a/tools/perf/tests/cpumap.c +++ b/tools/perf/tests/cpumap.c @@ -86,3 +86,27 @@ int test__cpu_map_synthesize(int subtest __maybe_unused) cpu_map__put(cpus); return 0; } + +static int cpu_map_print(const char *str) +{ + struct cpu_map *map = cpu_map__new(str); + char buf[100]; + + if (!map) + return -1; + + cpu_map__snprint(map, buf, sizeof(buf)); + return !strcmp(buf, str); +} + +int test__cpu_map_print(int subtest __maybe_unused) +{ + TEST_ASSERT_VAL("failed to convert map", cpu_map_print("1")); + TEST_ASSERT_VAL("failed to convert map", cpu_map_print("1,5")); + TEST_ASSERT_VAL("failed to convert map", cpu_map_print("1,3,5,7,9,11,13,15,17,19,21-40")); + TEST_ASSERT_VAL("failed to convert map", cpu_map_print("2-5")); + TEST_ASSERT_VAL("failed to convert map", cpu_map_print("1,3-6,8-10,24,35-37")); + TEST_ASSERT_VAL("failed to convert map", cpu_map_print("1,3-6,8-10,24,35-37")); + TEST_ASSERT_VAL("failed to convert map", cpu_map_print("1-10,12-20,22-30,32-40")); + return 0; +} diff --git a/tools/perf/tests/tests.h b/tools/perf/tests/tests.h index c57e72c..52f9695 100644 --- a/tools/perf/tests/tests.h +++ b/tools/perf/tests/tests.h @@ -87,6 +87,7 @@ int test__synthesize_stat_round(int subtest); int test__event_update(int subtest); int test__event_times(int subtest); int test__backward_ring_buffer(int subtest); +int test__cpu_map_print(int subtest); #if defined(__arm__) || defined(__aarch64__) #ifdef HAVE_DWARF_UNWIND_SUPPORT diff --git a/tools/perf/util/cpumap.c b/tools/perf/util/cpumap.c index 02d8016..15f83ac 100644 --- a/tools/perf/util/cpumap.c +++ b/tools/perf/util/cpumap.c @@ -236,13 +236,12 @@ struct cpu_map *cpu_map__new_data(struct cpu_map_data *data) size_t cpu_map__fprintf(struct cpu_map *map, FILE *fp) { - int i; - size_t printed = fprintf(fp, "%d cpu%s: ", - map->nr, map->nr > 1 ? "s" : ""); - for (i = 0; i < map->nr; ++i) - printed += fprintf(fp, "%s%d", i ? ", " : "", map->map[i]); +#define BUFSIZE 1024 + char buf[BUFSIZE]; - return printed + fprintf(fp, "\n"); + cpu_map__snprint(map, buf, sizeof(buf)); + return fprintf(fp, "%s\n", buf); +#undef BUFSIZE } struct cpu_map *cpu_map__dummy_new(void) @@ -599,3 +598,46 @@ bool cpu_map__has(struct cpu_map *cpus, int cpu) return false; } + +size_t cpu_map__snprint(struct cpu_map *map, char *buf, size_t size) +{ + int i, cpu, start = -1; + bool first = true; + size_t ret = 0; + +#define COMMA first ? "" : "," + + for (i = 0; i < map->nr + 1; i++) { + bool last = i == map->nr; + + cpu = last ? INT_MAX : map->map[i]; + + if (start == -1) { + start = i; + if (last) { + ret += snprintf(buf + ret, size - ret, + "%s%d", COMMA, + map->map[i]); + } + } else if (((i - start) != (cpu - map->map[start])) || last) { + int end = i - 1; + + if (start == end) { + ret += snprintf(buf + ret, size - ret, + "%s%d", COMMA, + map->map[start]); + } else { + ret += snprintf(buf + ret, size - ret, + "%s%d-%d", COMMA, + map->map[start], map->map[end]); + } + first = false; + start = i; + } + } + +#undef COMMA + + pr_debug("cpumask list: %s\n", buf); + return ret; +} diff --git a/tools/perf/util/cpumap.h b/tools/perf/util/cpumap.h index 1a0a350..206dc55 100644 --- a/tools/perf/util/cpumap.h +++ b/tools/perf/util/cpumap.h @@ -19,6 +19,7 @@ struct cpu_map *cpu_map__empty_new(int nr); struct cpu_map *cpu_map__dummy_new(void); struct cpu_map *cpu_map__new_data(struct cpu_map_data *data); struct cpu_map *cpu_map__read(FILE *file); +size_t cpu_map__snprint(struct cpu_map *map, char *buf, size_t size); size_t cpu_map__fprintf(struct cpu_map *map, FILE *fp); int cpu_map__get_socket_id(int cpu); int cpu_map__get_socket(struct cpu_map *map, int idx, void *data); diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c index 9b141f1..e20438b 100644 --- a/tools/perf/util/event.c +++ b/tools/perf/util/event.c @@ -1092,7 +1092,7 @@ size_t perf_event__fprintf_cpu_map(union perf_event *event, FILE *fp) struct cpu_map *cpus = cpu_map__new_data(&event->cpu_map.data); size_t ret; - ret = fprintf(fp, " nr: "); + ret = fprintf(fp, ": "); if (cpus) ret += cpu_map__fprintf(cpus, fp); -- cgit v0.10.2 From 65c0554b73c920023cc8998802e508b798113b46 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Thu, 30 Jun 2016 18:11:41 +0200 Subject: x86/power/64: Fix kernel text mapping corruption during image restoration Logan Gunthorpe reports that hibernation stopped working reliably for him after commit ab76f7b4ab23 (x86/mm: Set NX on gap between __ex_table and rodata). That turns out to be a consequence of a long-standing issue with the 64-bit image restoration code on x86, which is that the temporary page tables set up by it to avoid page tables corruption when the last bits of the image kernel's memory contents are copied into their original page frames re-use the boot kernel's text mapping, but that mapping may very well get corrupted just like any other part of the page tables. Of course, if that happens, the final jump to the image kernel's entry point will go to nowhere. The exact reason why commit ab76f7b4ab23 matters here is that it sometimes causes a PMD of a large page to be split into PTEs that are allocated dynamically and get corrupted during image restoration as described above. To fix that issue note that the code copying the last bits of the image kernel's memory contents to the page frames occupied by them previoulsy doesn't use the kernel text mapping, because it runs from a special page covered by the identity mapping set up for that code from scratch. Hence, the kernel text mapping is only needed before that code starts to run and then it will only be used just for the final jump to the image kernel's entry point. Accordingly, the temporary page tables set up in swsusp_arch_resume() on x86-64 need to contain the kernel text mapping too. That mapping is only going to be used for the final jump to the image kernel, so it only needs to cover the image kernel's entry point, because the first thing the image kernel does after getting control back is to switch over to its own original page tables. Moreover, the virtual address of the image kernel's entry point in that mapping has to be the same as the one mapped by the image kernel's page tables. With that in mind, modify the x86-64's arch_hibernation_header_save() and arch_hibernation_header_restore() routines to pass the physical address of the image kernel's entry point (in addition to its virtual address) to the boot kernel (a small piece of assembly code involved in passing the entry point's virtual address to the image kernel is not necessary any more after that, so drop it). Update RESTORE_MAGIC too to reflect the image header format change. Next, in set_up_temporary_mappings(), use the physical and virtual addresses of the image kernel's entry point passed in the image header to set up a minimum kernel text mapping (using memory pages that won't be overwritten by the image kernel's memory contents) that will map those addresses to each other as appropriate. This makes the concern about the possible corruption of the original boot kernel text mapping go away and if the the minimum kernel text mapping used for the final jump marks the image kernel's entry point memory as executable, the jump to it is guaraneed to succeed. Fixes: ab76f7b4ab23 (x86/mm: Set NX on gap between __ex_table and rodata) Link: http://marc.info/?l=linux-pm&m=146372852823760&w=2 Reported-by: Logan Gunthorpe Reported-and-tested-by: Borislav Petkov Tested-by: Kees Cook Signed-off-by: Rafael J. Wysocki diff --git a/arch/x86/power/hibernate_64.c b/arch/x86/power/hibernate_64.c index 009947d..f2b5e6a 100644 --- a/arch/x86/power/hibernate_64.c +++ b/arch/x86/power/hibernate_64.c @@ -19,6 +19,7 @@ #include #include #include +#include /* Defined in hibernate_asm_64.S */ extern asmlinkage __visible int restore_image(void); @@ -28,6 +29,7 @@ extern asmlinkage __visible int restore_image(void); * kernel's text (this value is passed in the image header). */ unsigned long restore_jump_address __visible; +unsigned long jump_address_phys; /* * Value of the cr3 register from before the hibernation (this value is passed @@ -37,7 +39,43 @@ unsigned long restore_cr3 __visible; pgd_t *temp_level4_pgt __visible; -void *relocated_restore_code __visible; +unsigned long relocated_restore_code __visible; + +static int set_up_temporary_text_mapping(void) +{ + pmd_t *pmd; + pud_t *pud; + + /* + * The new mapping only has to cover the page containing the image + * kernel's entry point (jump_address_phys), because the switch over to + * it is carried out by relocated code running from a page allocated + * specifically for this purpose and covered by the identity mapping, so + * the temporary kernel text mapping is only needed for the final jump. + * Moreover, in that mapping the virtual address of the image kernel's + * entry point must be the same as its virtual address in the image + * kernel (restore_jump_address), so the image kernel's + * restore_registers() code doesn't find itself in a different area of + * the virtual address space after switching over to the original page + * tables used by the image kernel. + */ + pud = (pud_t *)get_safe_page(GFP_ATOMIC); + if (!pud) + return -ENOMEM; + + pmd = (pmd_t *)get_safe_page(GFP_ATOMIC); + if (!pmd) + return -ENOMEM; + + set_pmd(pmd + pmd_index(restore_jump_address), + __pmd((jump_address_phys & PMD_MASK) | __PAGE_KERNEL_LARGE_EXEC)); + set_pud(pud + pud_index(restore_jump_address), + __pud(__pa(pmd) | _KERNPG_TABLE)); + set_pgd(temp_level4_pgt + pgd_index(restore_jump_address), + __pgd(__pa(pud) | _KERNPG_TABLE)); + + return 0; +} static void *alloc_pgt_page(void *context) { @@ -59,9 +97,10 @@ static int set_up_temporary_mappings(void) if (!temp_level4_pgt) return -ENOMEM; - /* It is safe to reuse the original kernel mapping */ - set_pgd(temp_level4_pgt + pgd_index(__START_KERNEL_map), - init_level4_pgt[pgd_index(__START_KERNEL_map)]); + /* Prepare a temporary mapping for the kernel text */ + result = set_up_temporary_text_mapping(); + if (result) + return result; /* Set up the direct mapping from scratch */ for (i = 0; i < nr_pfn_mapped; i++) { @@ -78,19 +117,50 @@ static int set_up_temporary_mappings(void) return 0; } +static int relocate_restore_code(void) +{ + pgd_t *pgd; + pud_t *pud; + + relocated_restore_code = get_safe_page(GFP_ATOMIC); + if (!relocated_restore_code) + return -ENOMEM; + + memcpy((void *)relocated_restore_code, &core_restore_code, PAGE_SIZE); + + /* Make the page containing the relocated code executable */ + pgd = (pgd_t *)__va(read_cr3()) + pgd_index(relocated_restore_code); + pud = pud_offset(pgd, relocated_restore_code); + if (pud_large(*pud)) { + set_pud(pud, __pud(pud_val(*pud) & ~_PAGE_NX)); + } else { + pmd_t *pmd = pmd_offset(pud, relocated_restore_code); + + if (pmd_large(*pmd)) { + set_pmd(pmd, __pmd(pmd_val(*pmd) & ~_PAGE_NX)); + } else { + pte_t *pte = pte_offset_kernel(pmd, relocated_restore_code); + + set_pte(pte, __pte(pte_val(*pte) & ~_PAGE_NX)); + } + } + __flush_tlb_all(); + + return 0; +} + int swsusp_arch_resume(void) { int error; /* We have got enough memory and from now on we cannot recover */ - if ((error = set_up_temporary_mappings())) + error = set_up_temporary_mappings(); + if (error) return error; - relocated_restore_code = (void *)get_safe_page(GFP_ATOMIC); - if (!relocated_restore_code) - return -ENOMEM; - memcpy(relocated_restore_code, &core_restore_code, - &restore_registers - &core_restore_code); + error = relocate_restore_code(); + if (error) + return error; restore_image(); return 0; @@ -109,11 +179,12 @@ int pfn_is_nosave(unsigned long pfn) struct restore_data_record { unsigned long jump_address; + unsigned long jump_address_phys; unsigned long cr3; unsigned long magic; }; -#define RESTORE_MAGIC 0x0123456789ABCDEFUL +#define RESTORE_MAGIC 0x123456789ABCDEF0UL /** * arch_hibernation_header_save - populate the architecture specific part @@ -126,7 +197,8 @@ int arch_hibernation_header_save(void *addr, unsigned int max_size) if (max_size < sizeof(struct restore_data_record)) return -EOVERFLOW; - rdr->jump_address = restore_jump_address; + rdr->jump_address = (unsigned long)&restore_registers; + rdr->jump_address_phys = __pa_symbol(&restore_registers); rdr->cr3 = restore_cr3; rdr->magic = RESTORE_MAGIC; return 0; @@ -142,6 +214,7 @@ int arch_hibernation_header_restore(void *addr) struct restore_data_record *rdr = addr; restore_jump_address = rdr->jump_address; + jump_address_phys = rdr->jump_address_phys; restore_cr3 = rdr->cr3; return (rdr->magic == RESTORE_MAGIC) ? 0 : -EINVAL; } diff --git a/arch/x86/power/hibernate_asm_64.S b/arch/x86/power/hibernate_asm_64.S index 4400a43..3177c2b 100644 --- a/arch/x86/power/hibernate_asm_64.S +++ b/arch/x86/power/hibernate_asm_64.S @@ -44,9 +44,6 @@ ENTRY(swsusp_arch_suspend) pushfq popq pt_regs_flags(%rax) - /* save the address of restore_registers */ - movq $restore_registers, %rax - movq %rax, restore_jump_address(%rip) /* save cr3 */ movq %cr3, %rax movq %rax, restore_cr3(%rip) @@ -57,31 +54,34 @@ ENTRY(swsusp_arch_suspend) ENDPROC(swsusp_arch_suspend) ENTRY(restore_image) - /* switch to temporary page tables */ - movq $__PAGE_OFFSET, %rdx - movq temp_level4_pgt(%rip), %rax - subq %rdx, %rax - movq %rax, %cr3 - /* Flush TLB */ - movq mmu_cr4_features(%rip), %rax - movq %rax, %rdx - andq $~(X86_CR4_PGE), %rdx - movq %rdx, %cr4; # turn off PGE - movq %cr3, %rcx; # flush TLB - movq %rcx, %cr3; - movq %rax, %cr4; # turn PGE back on - /* prepare to jump to the image kernel */ - movq restore_jump_address(%rip), %rax - movq restore_cr3(%rip), %rbx + movq restore_jump_address(%rip), %r8 + movq restore_cr3(%rip), %r9 + + /* prepare to switch to temporary page tables */ + movq temp_level4_pgt(%rip), %rax + movq mmu_cr4_features(%rip), %rbx /* prepare to copy image data to their original locations */ movq restore_pblist(%rip), %rdx + + /* jump to relocated restore code */ movq relocated_restore_code(%rip), %rcx jmpq *%rcx /* code below has been relocated to a safe page */ ENTRY(core_restore_code) + /* switch to temporary page tables */ + movq $__PAGE_OFFSET, %rcx + subq %rcx, %rax + movq %rax, %cr3 + /* flush TLB */ + movq %rbx, %rcx + andq $~(X86_CR4_PGE), %rcx + movq %rcx, %cr4; # turn off PGE + movq %cr3, %rcx; # flush TLB + movq %rcx, %cr3; + movq %rbx, %cr4; # turn PGE back on .Lloop: testq %rdx, %rdx jz .Ldone @@ -96,24 +96,17 @@ ENTRY(core_restore_code) /* progress to the next pbe */ movq pbe_next(%rdx), %rdx jmp .Lloop + .Ldone: /* jump to the restore_registers address from the image header */ - jmpq *%rax - /* - * NOTE: This assumes that the boot kernel's text mapping covers the - * image kernel's page containing restore_registers and the address of - * this page is the same as in the image kernel's text mapping (it - * should always be true, because the text mapping is linear, starting - * from 0, and is supposed to cover the entire kernel text for every - * kernel). - * - * code below belongs to the image kernel - */ + jmpq *%r8 + /* code below belongs to the image kernel */ + .align PAGE_SIZE ENTRY(restore_registers) FRAME_BEGIN /* go back to the original page tables */ - movq %rbx, %cr3 + movq %r9, %cr3 /* Flush TLB, including "global" things (vmalloc) */ movq mmu_cr4_features(%rip), %rax -- cgit v0.10.2 From 1ead852dd88779eda12cb09cc894a03d9abfe1ec Mon Sep 17 00:00:00 2001 From: Borislav Petkov Date: Thu, 16 Jun 2016 19:13:49 +0200 Subject: x86/amd_nb: Fix boot crash on non-AMD systems Fix boot crash that triggers if this driver is built into a kernel and run on non-AMD systems. AMD northbridges users call amd_cache_northbridges() and it returns a negative value to signal that we weren't able to cache/detect any northbridges on the system. At least, it should do so as all its callers expect it to do so. But it does return a negative value only when kmalloc() fails. Fix it to return -ENODEV if there are no NBs cached as otherwise, amd_nb users like amd64_edac, for example, which relies on it to know whether it should load or not, gets loaded on systems like Intel Xeons where it shouldn't. Reported-and-tested-by: Tony Battersby Signed-off-by: Borislav Petkov Cc: Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/1466097230-5333-2-git-send-email-bp@alien8.de Link: https://lkml.kernel.org/r/5761BEB0.9000807@cybernetics.com Signed-off-by: Ingo Molnar diff --git a/arch/x86/kernel/amd_nb.c b/arch/x86/kernel/amd_nb.c index a147e67..e991d5c 100644 --- a/arch/x86/kernel/amd_nb.c +++ b/arch/x86/kernel/amd_nb.c @@ -71,8 +71,8 @@ int amd_cache_northbridges(void) while ((misc = next_northbridge(misc, amd_nb_misc_ids)) != NULL) i++; - if (i == 0) - return 0; + if (!i) + return -ENODEV; nb = kzalloc(i * sizeof(struct amd_northbridge), GFP_KERNEL); if (!nb) -- cgit v0.10.2 From c76a093dc1415d364020b8b33f1e194ef4d26fd0 Mon Sep 17 00:00:00 2001 From: Masanari Iida Date: Fri, 1 Jul 2016 12:46:01 +0900 Subject: x86/Documentation: Fix various typos in Documentation/x86/ files Signed-off-by: Masanari Iida Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: corbet@lwn.net Cc: linux-doc@vger.kernel.org Link: http://lkml.kernel.org/r/20160701034601.30308-1-standby24x7@gmail.com Signed-off-by: Ingo Molnar diff --git a/Documentation/x86/intel_mpx.txt b/Documentation/x86/intel_mpx.txt index 1a5a121..85d0549 100644 --- a/Documentation/x86/intel_mpx.txt +++ b/Documentation/x86/intel_mpx.txt @@ -45,7 +45,7 @@ is how we expect the compiler, application and kernel to work together. MPX-instrumented. 3) The kernel detects that the CPU has MPX, allows the new prctl() to succeed, and notes the location of the bounds directory. Userspace is - expected to keep the bounds directory at that locationWe note it + expected to keep the bounds directory at that location. We note it instead of reading it each time because the 'xsave' operation needed to access the bounds directory register is an expensive operation. 4) If the application needs to spill bounds out of the 4 registers, it @@ -167,7 +167,7 @@ If a #BR is generated due to a bounds violation caused by MPX. We need to decode MPX instructions to get violation address and set this address into extended struct siginfo. -The _sigfault feild of struct siginfo is extended as follow: +The _sigfault field of struct siginfo is extended as follow: 87 /* SIGILL, SIGFPE, SIGSEGV, SIGBUS */ 88 struct { @@ -240,5 +240,5 @@ them at the same bounds table. This is allowed architecturally. See more information "Intel(R) Architecture Instruction Set Extensions Programming Reference" (9.3.4). -However, if users did this, the kernel might be fooled in to unmaping an +However, if users did this, the kernel might be fooled in to unmapping an in-use bounds table since it does not recognize sharing. diff --git a/Documentation/x86/tlb.txt b/Documentation/x86/tlb.txt index 39d1723..6a0607b 100644 --- a/Documentation/x86/tlb.txt +++ b/Documentation/x86/tlb.txt @@ -5,7 +5,7 @@ memory, it has two choices: from areas other than the one we are trying to flush will be destroyed and must be refilled later, at some cost. 2. Use the invlpg instruction to invalidate a single page at a - time. This could potentialy cost many more instructions, but + time. This could potentially cost many more instructions, but it is a much more precise operation, causing no collateral damage to other TLB entries. @@ -19,7 +19,7 @@ Which method to do depends on a few things: work. 3. The size of the TLB. The larger the TLB, the more collateral damage we do with a full flush. So, the larger the TLB, the - more attrative an individual flush looks. Data and + more attractive an individual flush looks. Data and instructions have separate TLBs, as do different page sizes. 4. The microarchitecture. The TLB has become a multi-level cache on modern CPUs, and the global flushes have become more diff --git a/Documentation/x86/x86_64/machinecheck b/Documentation/x86/x86_64/machinecheck index b1fb302..d0648a7 100644 --- a/Documentation/x86/x86_64/machinecheck +++ b/Documentation/x86/x86_64/machinecheck @@ -36,7 +36,7 @@ between all CPUs. check_interval How often to poll for corrected machine check errors, in seconds - (Note output is hexademical). Default 5 minutes. When the poller + (Note output is hexadecimal). Default 5 minutes. When the poller finds MCEs it triggers an exponential speedup (poll more often) on the polling interval. When the poller stops finding MCEs, it triggers an exponential backoff (poll less often) on the polling -- cgit v0.10.2 From 8e0469a4f3e647059c0ef8db961140ee25246fbd Mon Sep 17 00:00:00 2001 From: Alexander Shishkin Date: Tue, 28 Jun 2016 11:35:02 +0300 Subject: stm class: Add runtime power management handling Currently, there's no runtime pm in stm class devices, which makes it harder for the underlying hardware drivers to handle their power management. This patch applies the following runtime pm policy to stm class devices, which their parents can rely on for their power management tracking: * device is in use during character device writes, * delayed autosuspend is used to keep it active between adjacent writes, * device is in use while mmio regions are mapped, * device is is use while any stm_source devices are linked to it. Signed-off-by: Alexander Shishkin Reviewed-by: Mathieu Poirier Cc: Chunyan Zhang diff --git a/drivers/hwtracing/stm/core.c b/drivers/hwtracing/stm/core.c index ff31108..51f81d6 100644 --- a/drivers/hwtracing/stm/core.c +++ b/drivers/hwtracing/stm/core.c @@ -15,6 +15,7 @@ * as defined in MIPI STPv2 specification. */ +#include #include #include #include @@ -482,14 +483,40 @@ static ssize_t stm_char_write(struct file *file, const char __user *buf, return -EFAULT; } + pm_runtime_get_sync(&stm->dev); + count = stm_write(stm->data, stmf->output.master, stmf->output.channel, kbuf, count); + pm_runtime_mark_last_busy(&stm->dev); + pm_runtime_put_autosuspend(&stm->dev); kfree(kbuf); return count; } +static void stm_mmap_open(struct vm_area_struct *vma) +{ + struct stm_file *stmf = vma->vm_file->private_data; + struct stm_device *stm = stmf->stm; + + pm_runtime_get(&stm->dev); +} + +static void stm_mmap_close(struct vm_area_struct *vma) +{ + struct stm_file *stmf = vma->vm_file->private_data; + struct stm_device *stm = stmf->stm; + + pm_runtime_mark_last_busy(&stm->dev); + pm_runtime_put_autosuspend(&stm->dev); +} + +static const struct vm_operations_struct stm_mmap_vmops = { + .open = stm_mmap_open, + .close = stm_mmap_close, +}; + static int stm_char_mmap(struct file *file, struct vm_area_struct *vma) { struct stm_file *stmf = file->private_data; @@ -514,8 +541,11 @@ static int stm_char_mmap(struct file *file, struct vm_area_struct *vma) if (!phys) return -EINVAL; + pm_runtime_get_sync(&stm->dev); + vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); vma->vm_flags |= VM_IO | VM_DONTEXPAND | VM_DONTDUMP; + vma->vm_ops = &stm_mmap_vmops; vm_iomap_memory(vma, phys, size); return 0; @@ -701,6 +731,17 @@ int stm_register_device(struct device *parent, struct stm_data *stm_data, if (err) goto err_device; + /* + * Use delayed autosuspend to avoid bouncing back and forth + * on recurring character device writes, with the initial + * delay time of 2 seconds. + */ + pm_runtime_no_callbacks(&stm->dev); + pm_runtime_use_autosuspend(&stm->dev); + pm_runtime_set_autosuspend_delay(&stm->dev, 2000); + pm_runtime_set_suspended(&stm->dev); + pm_runtime_enable(&stm->dev); + return 0; err_device: @@ -724,6 +765,9 @@ void stm_unregister_device(struct stm_data *stm_data) struct stm_source_device *src, *iter; int i, ret; + pm_runtime_dont_use_autosuspend(&stm->dev); + pm_runtime_disable(&stm->dev); + mutex_lock(&stm->link_mutex); list_for_each_entry_safe(src, iter, &stm->link_list, link_entry) { ret = __stm_source_link_drop(src, stm); @@ -878,6 +922,8 @@ static int __stm_source_link_drop(struct stm_source_device *src, stm_output_free(link, &src->output); list_del_init(&src->link_entry); + pm_runtime_mark_last_busy(&link->dev); + pm_runtime_put_autosuspend(&link->dev); /* matches stm_find_device() from stm_source_link_store() */ stm_put_device(link); rcu_assign_pointer(src->link, NULL); @@ -971,8 +1017,11 @@ static ssize_t stm_source_link_store(struct device *dev, if (!link) return -EINVAL; + pm_runtime_get(&link->dev); + err = stm_source_link_add(src, link); if (err) { + pm_runtime_put_autosuspend(&link->dev); /* matches the stm_find_device() above */ stm_put_device(link); } @@ -1033,6 +1082,9 @@ int stm_source_register_device(struct device *parent, if (err) goto err; + pm_runtime_no_callbacks(&src->dev); + pm_runtime_forbid(&src->dev); + err = device_add(&src->dev); if (err) goto err; -- cgit v0.10.2 From 142dfeb20209607659ca85f15e7a3dd592a6dd20 Mon Sep 17 00:00:00 2001 From: Alexander Shishkin Date: Wed, 22 Jun 2016 13:48:21 +0300 Subject: intel_th: Add runtime power management handling Currently, an Intel TH (pci) device will be always active, because the devices on the 'intel_th' bus don't implement runtime pm to track their usage. To address this, this patch adds runtime pm support to the 'intel_th' bus and some additional bits for the hub. The 'output' type device is in use while a capture is active; the 'source' type device (STH) relies on its child stm class device for runtime pm tracking. Signed-off-by: Alexander Shishkin diff --git a/drivers/hwtracing/intel_th/core.c b/drivers/hwtracing/intel_th/core.c index 1be543e..fdd1763 100644 --- a/drivers/hwtracing/intel_th/core.c +++ b/drivers/hwtracing/intel_th/core.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include "intel_th.h" @@ -67,23 +68,33 @@ static int intel_th_probe(struct device *dev) hubdrv = to_intel_th_driver(hub->dev.driver); + pm_runtime_set_active(dev); + pm_runtime_no_callbacks(dev); + pm_runtime_enable(dev); + ret = thdrv->probe(to_intel_th_device(dev)); if (ret) - return ret; + goto out_pm; if (thdrv->attr_group) { ret = sysfs_create_group(&thdev->dev.kobj, thdrv->attr_group); - if (ret) { - thdrv->remove(thdev); - - return ret; - } + if (ret) + goto out; } if (thdev->type == INTEL_TH_OUTPUT && !intel_th_output_assigned(thdev)) + /* does not talk to hardware */ ret = hubdrv->assign(hub, thdev); +out: + if (ret) + thdrv->remove(thdev); + +out_pm: + if (ret) + pm_runtime_disable(dev); + return ret; } @@ -103,6 +114,8 @@ static int intel_th_remove(struct device *dev) if (thdrv->attr_group) sysfs_remove_group(&thdev->dev.kobj, thdrv->attr_group); + pm_runtime_get_sync(dev); + thdrv->remove(thdev); if (intel_th_output_assigned(thdev)) { @@ -110,9 +123,14 @@ static int intel_th_remove(struct device *dev) to_intel_th_driver(dev->parent->driver); if (hub->dev.driver) + /* does not talk to hardware */ hubdrv->unassign(hub, thdev); } + pm_runtime_disable(dev); + pm_runtime_set_active(dev); + pm_runtime_enable(dev); + return 0; } @@ -185,6 +203,7 @@ static int intel_th_output_activate(struct intel_th_device *thdev) { struct intel_th_driver *thdrv = to_intel_th_driver_or_null(thdev->dev.driver); + int ret = 0; if (!thdrv) return -ENODEV; @@ -192,12 +211,17 @@ static int intel_th_output_activate(struct intel_th_device *thdev) if (!try_module_get(thdrv->driver.owner)) return -ENODEV; + pm_runtime_get_sync(&thdev->dev); + if (thdrv->activate) - return thdrv->activate(thdev); + ret = thdrv->activate(thdev); + else + intel_th_trace_enable(thdev); - intel_th_trace_enable(thdev); + if (ret) + pm_runtime_put(&thdev->dev); - return 0; + return ret; } static void intel_th_output_deactivate(struct intel_th_device *thdev) @@ -213,6 +237,7 @@ static void intel_th_output_deactivate(struct intel_th_device *thdev) else intel_th_trace_disable(thdev); + pm_runtime_put(&thdev->dev); module_put(thdrv->driver.owner); } @@ -628,6 +653,10 @@ intel_th_alloc(struct device *dev, struct resource *devres, dev_set_drvdata(dev, th); + pm_runtime_no_callbacks(dev); + pm_runtime_put(dev); + pm_runtime_allow(dev); + err = intel_th_populate(th, devres, ndevres, irq); if (err) goto err_chrdev; @@ -635,6 +664,8 @@ intel_th_alloc(struct device *dev, struct resource *devres, return th; err_chrdev: + pm_runtime_forbid(dev); + __unregister_chrdev(th->major, 0, TH_POSSIBLE_OUTPUTS, "intel_th/output"); @@ -658,6 +689,9 @@ void intel_th_free(struct intel_th *th) intel_th_device_remove(th->hub); + pm_runtime_get_sync(th->dev); + pm_runtime_forbid(th->dev); + __unregister_chrdev(th->major, 0, TH_POSSIBLE_OUTPUTS, "intel_th/output"); @@ -682,6 +716,7 @@ int intel_th_trace_enable(struct intel_th_device *thdev) if (WARN_ON_ONCE(thdev->type != INTEL_TH_OUTPUT)) return -EINVAL; + pm_runtime_get_sync(&thdev->dev); hubdrv->enable(hub, &thdev->output); return 0; @@ -702,6 +737,7 @@ int intel_th_trace_disable(struct intel_th_device *thdev) return -EINVAL; hubdrv->disable(hub, &thdev->output); + pm_runtime_put(&thdev->dev); return 0; } diff --git a/drivers/hwtracing/intel_th/gth.c b/drivers/hwtracing/intel_th/gth.c index 9beea0b..4106eaf 100644 --- a/drivers/hwtracing/intel_th/gth.c +++ b/drivers/hwtracing/intel_th/gth.c @@ -22,6 +22,7 @@ #include #include #include +#include #include "intel_th.h" #include "gth.h" @@ -190,6 +191,11 @@ static ssize_t master_attr_store(struct device *dev, if (old_port >= 0) { gth->master[ma->master] = -1; clear_bit(ma->master, gth->output[old_port].master); + + /* + * if the port is active, program this setting, + * implies that runtime PM is on + */ if (gth->output[old_port].output->active) gth_master_set(gth, ma->master, -1); } @@ -204,7 +210,7 @@ static ssize_t master_attr_store(struct device *dev, set_bit(ma->master, gth->output[port].master); - /* if the port is active, program this setting */ + /* if the port is active, program this setting, see above */ if (gth->output[port].output->active) gth_master_set(gth, ma->master, port); } @@ -326,11 +332,15 @@ static ssize_t output_attr_show(struct device *dev, struct gth_device *gth = oa->gth; size_t count; + pm_runtime_get_sync(dev); + spin_lock(>h->gth_lock); count = snprintf(buf, PAGE_SIZE, "%x\n", gth_output_parm_get(gth, oa->port, oa->parm)); spin_unlock(>h->gth_lock); + pm_runtime_put(dev); + return count; } @@ -346,10 +356,14 @@ static ssize_t output_attr_store(struct device *dev, if (kstrtouint(buf, 16, &config) < 0) return -EINVAL; + pm_runtime_get_sync(dev); + spin_lock(>h->gth_lock); gth_output_parm_set(gth, oa->port, oa->parm, config); spin_unlock(>h->gth_lock); + pm_runtime_put(dev); + return count; } -- cgit v0.10.2 From 53c189f1762ba392b5c24a2f06382d5eb1399c25 Mon Sep 17 00:00:00 2001 From: Alexander Shishkin Date: Tue, 28 Jun 2016 11:34:03 +0300 Subject: intel_th: gth: Fix a source comment There's a kerneldoc comment that'd been derived from another one by way of copying-and-pasting but hadn't been subsequently amended to reflect the purpose of the function. Fix this. Signed-off-by: Alexander Shishkin diff --git a/drivers/hwtracing/intel_th/gth.c b/drivers/hwtracing/intel_th/gth.c index 4106eaf..33e0936 100644 --- a/drivers/hwtracing/intel_th/gth.c +++ b/drivers/hwtracing/intel_th/gth.c @@ -465,7 +465,7 @@ static int intel_th_output_attributes(struct gth_device *gth) } /** - * intel_th_gth_disable() - enable tracing to an output device + * intel_th_gth_disable() - disable tracing to an output device * @thdev: GTH device * @output: output device's descriptor * -- cgit v0.10.2 From bd581f239f2f190141820caa24c83bc72c82a347 Mon Sep 17 00:00:00 2001 From: Alexander Shishkin Date: Wed, 29 Jun 2016 19:35:22 +0300 Subject: intel_th: Document output device callbacks 'output' type device callbacks are missing from the kerneldoc description of the 'intel_th_driver' structure. Fix this. Signed-off-by: Alexander Shishkin diff --git a/drivers/hwtracing/intel_th/intel_th.h b/drivers/hwtracing/intel_th/intel_th.h index 0df22e3..20f57aa 100644 --- a/drivers/hwtracing/intel_th/intel_th.h +++ b/drivers/hwtracing/intel_th/intel_th.h @@ -114,6 +114,9 @@ intel_th_output_assigned(struct intel_th_device *thdev) * @unassign: deassociate an output type device from an output port * @enable: enable tracing for a given output device * @disable: disable tracing for a given output device + * @irq: interrupt callback + * @activate: enable tracing on the output's side + * @deactivate: disable tracing on the output's side * @fops: file operations for device nodes * @attr_group: attributes provided by the driver * -- cgit v0.10.2 From 0519e8b4cb2bda598f941088948129f9fe9e6acd Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 29 Jun 2016 22:01:34 +0300 Subject: x86/platform/intel-mid: Add pinctrl for Intel Merrifield Intel Merrifield uses a special address space reserved for Family-Level Interface Shim (FLIS) that allows consumers to mux and configure pins. Create a platform device for it. Signed-off-by: Andy Shevchenko Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/1467226894-107109-1-git-send-email-andriy.shevchenko@linux.intel.com [ Fixed typo. ] Signed-off-by: Ingo Molnar diff --git a/arch/x86/platform/intel-mid/device_libs/Makefile b/arch/x86/platform/intel-mid/device_libs/Makefile index abe8ba8..79e97ed 100644 --- a/arch/x86/platform/intel-mid/device_libs/Makefile +++ b/arch/x86/platform/intel-mid/device_libs/Makefile @@ -1,3 +1,5 @@ +# Family-Level Interface Shim (FLIS) +obj-$(subst m,y,$(CONFIG_PINCTRL_MERRIFIELD)) += platform_mrfld_pinctrl.o # IPC Devices obj-y += platform_ipc.o obj-$(subst m,y,$(CONFIG_MFD_INTEL_MSIC)) += platform_msic.o diff --git a/arch/x86/platform/intel-mid/device_libs/platform_mrfld_pinctrl.c b/arch/x86/platform/intel-mid/device_libs/platform_mrfld_pinctrl.c new file mode 100644 index 0000000..4de8a66 --- /dev/null +++ b/arch/x86/platform/intel-mid/device_libs/platform_mrfld_pinctrl.c @@ -0,0 +1,43 @@ +/* + * Intel Merrifield FLIS platform device initialization file + * + * Copyright (C) 2016, Intel Corporation + * + * Author: Andy Shevchenko + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; version 2 + * of the License. + */ + +#include +#include +#include + +#include + +#define FLIS_BASE_ADDR 0xff0c0000 +#define FLIS_LENGTH 0x8000 + +static struct resource mrfld_pinctrl_mmio_resource = { + .start = FLIS_BASE_ADDR, + .end = FLIS_BASE_ADDR + FLIS_LENGTH - 1, + .flags = IORESOURCE_MEM, +}; + +static struct platform_device mrfld_pinctrl_device = { + .name = "pinctrl-merrifield", + .id = PLATFORM_DEVID_NONE, + .resource = &mrfld_pinctrl_mmio_resource, + .num_resources = 1, +}; + +static int __init mrfld_pinctrl_init(void) +{ + if (intel_mid_identify_cpu() == INTEL_MID_CPU_CHIP_TANGIER) + return platform_device_register(&mrfld_pinctrl_device); + + return -ENODEV; +} +arch_initcall(mrfld_pinctrl_init); -- cgit v0.10.2 From 9216a97a12b069c62f0e927a9f54be4883648a0f Mon Sep 17 00:00:00 2001 From: Sony Chacko Date: Wed, 29 Jun 2016 17:51:34 -0400 Subject: qlcnic: add wmb() call in transmit data path. Call wmb() to ensure writes are complete before hardware fetches updated Tx descriptors. Signed-off-by: Sony Chacko Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c index 607bb7d..87c642d 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c @@ -772,6 +772,8 @@ netdev_tx_t qlcnic_xmit_frame(struct sk_buff *skb, struct net_device *netdev) tx_ring->tx_stats.tx_bytes += skb->len; tx_ring->tx_stats.xmit_called++; + /* Ensure writes are complete before HW fetches Tx descriptors */ + wmb(); qlcnic_update_cmd_producer(tx_ring); return NETDEV_TX_OK; -- cgit v0.10.2 From f95ae8a0edba1cb85110df4f1c96786419a0472f Mon Sep 17 00:00:00 2001 From: hayeswang Date: Thu, 30 Jun 2016 15:33:35 +0800 Subject: r8152: clear LINK_OFF_WAKE_EN after autoresume LINK_OFF_WAKE_EN should be cleared after autoresume, otherwise after system suspend, the system would wake up when linking off occurs. Signed-off-by: Hayes Wang Signed-off-by: David S. Miller diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c index 4e257b8..d7f20a9 100644 --- a/drivers/net/usb/r8152.c +++ b/drivers/net/usb/r8152.c @@ -2421,7 +2421,18 @@ static void rtl_runtime_suspend_enable(struct r8152 *tp, bool enable) ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CRWECR, CRWECR_NORAML); } else { + u32 ocp_data; + __rtl_set_wol(tp, tp->saved_wolopts); + + ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CRWECR, CRWECR_CONFIG); + + ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_CONFIG34); + ocp_data &= ~LINK_OFF_WAKE_EN; + ocp_write_word(tp, MCU_TYPE_PLA, PLA_CONFIG34, ocp_data); + + ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CRWECR, CRWECR_NORAML); + r8153_u2p3en(tp, true); r8153_u1u2en(tp, true); } -- cgit v0.10.2 From 3d8c4530e50dc030efcec575aa69483439fc6fda Mon Sep 17 00:00:00 2001 From: Russell King - ARM Linux Date: Thu, 30 Jun 2016 10:36:15 +0100 Subject: net: mvneta: fix open() error cleanup If mvneta_mdio_probe() fails, a kernel warning is triggered due to missing cleanup in the error path. Add the necessary cleanup. ------------[ cut here ]------------ WARNING: CPU: 1 PID: 281 at kernel/irq/manage.c:1814 __free_percpu_irq+0xfc/0x130 percpu IRQ 38 still enabled on CPU0! Modules linked in: bnep bluetooth xhci_plat_hcd xhci_hcd marvell_cesa armada_thermal des_generic ehci_orion mcp3021 spi_orion sfp mdio_i2c evbug fuse CPU: 1 PID: 281 Comm: connmand Not tainted 4.7.0-rc2+ #53 Hardware name: Marvell Armada 380/385 (Device Tree) Backtrace: [] (dump_backtrace) from [] (show_stack+0x18/0x1c) r6:60010093 r5:ffffffff r4:00000000 r3:dc8ba500 [] (show_stack) from [] (dump_stack+0xa4/0xdc) [] (dump_stack) from [] (__warn+0xd8/0x104) r6:c081e6a0 r5:00000000 r4:edfe5d50 r3:dc8ba500 [] (__warn) from [] (warn_slowpath_fmt+0x40/0x48) r10:a0010013 r8:c09356f8 r7:00000026 r6:ef11a260 r5:edd7b980 r4:ef11a200 [] (warn_slowpath_fmt) from [] (__free_percpu_irq+0xfc/0x130) r3:00000026 r2:c081e7ac [] (__free_percpu_irq) from [] (free_percpu_irq+0x48/0x74) r10:00008914 r8:00000000 r7:ffffffed r6:c09356f8 r5:00000026 r4:ef11a200 [] (free_percpu_irq) from [] (mvneta_open+0x118/0x134) r6:ffffffed r5:ef01e640 r4:ef01e000 r3:ef01e000 [] (mvneta_open) from [] (__dev_open+0xa4/0x108) r7:ef01e030 r6:c06ff3d8 r5:ffff9003 r4:ef01e000 [] (__dev_open) from [] (__dev_change_flags+0x94/0x150) r7:00001002 r6:00000001 r5:ffff9003 r4:ef01e000 [] (__dev_change_flags) from [] (dev_change_flags+0x20/0x50) r8:00000000 r7:c09334c8 r6:00001002 r5:00000148 r4:ef01e000 r3:00008914 [] (dev_change_flags) from [] (devinet_ioctl+0x6f4/0x7e0) r8:00000000 r7:c09334c8 r6:00000000 r5:ee87200c r4:00000000 r3:00008914 [] (devinet_ioctl) from [] (inet_ioctl+0x1b8/0x1c8) r10:beb4499c r9:edfe4000 r8:ecf13280 r7:c096cf00 r6:beb4499c r5:eef7c240 r4:00008914 [] (inet_ioctl) from [] (sock_ioctl+0x78/0x300) [] (sock_ioctl) from [] (do_vfs_ioctl+0x98/0xa60) r7:00000011 r6:00008914 r5:00000011 r4:c01568d0 [] (do_vfs_ioctl) from [] (SyS_ioctl+0x3c/0x60) r10:00000000 r9:edfe4000 r8:beb4499c r7:00000011 r6:00008914 r5:ecf13280 r4:ecf13280 [] (SyS_ioctl) from [] (ret_fast_syscall+0x0/0x1c) r8:c0010004 r7:00000036 r6:00000011 r5:000a2978 r4:00000000 r3:00009003 ---[ end trace 711f625d5b04b3a7 ]--- Signed-off-by: Russell King Tested-by: Jon Nettleton Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/marvell/mvneta.c b/drivers/net/ethernet/marvell/mvneta.c index a6d26d3..d5d263b 100644 --- a/drivers/net/ethernet/marvell/mvneta.c +++ b/drivers/net/ethernet/marvell/mvneta.c @@ -3458,6 +3458,8 @@ static int mvneta_open(struct net_device *dev) return 0; err_free_irq: + unregister_cpu_notifier(&pp->cpu_notifier); + on_each_cpu(mvneta_percpu_disable, pp, true); free_percpu_irq(pp->dev->irq, pp->ports); err_cleanup_txqs: mvneta_cleanup_txqs(pp); -- cgit v0.10.2 From fdfe3b32db70aa49d1d60a1ddd2280099174bddb Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Fri, 1 Jul 2016 09:49:05 +0800 Subject: ASoC: rt5645: fix reg-2f default value. The default value of reg-2f in codec rt5650 is 0x5002, not 0x1002. Signed-off-by: Bard Liao Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c index 3c6594d..d70847c 100644 --- a/sound/soc/codecs/rt5645.c +++ b/sound/soc/codecs/rt5645.c @@ -253,7 +253,7 @@ static const struct reg_default rt5650_reg[] = { { 0x2b, 0x5454 }, { 0x2c, 0xaaa0 }, { 0x2d, 0x0000 }, - { 0x2f, 0x1002 }, + { 0x2f, 0x5002 }, { 0x31, 0x5000 }, { 0x32, 0x0000 }, { 0x33, 0x0000 }, -- cgit v0.10.2 From f87fda00b6ed232a817c655b8d179b48bde8fdbe Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 30 Jun 2016 16:13:41 +0200 Subject: bonding: prevent out of bound accesses ether_addr_equal_64bits() requires some care about its arguments, namely that 8 bytes might be read, even if last 2 byte values are not used. KASan detected a violation with null_mac_addr and lacpdu_mcast_addr in bond_3ad.c Same problem with mac_bcast[] and mac_v6_allmcast[] in bond_alb.c : Although the 8-byte alignment was there, KASan would detect out of bound accesses. Fixes: 815117adaf5b ("bonding: use ether_addr_equal_unaligned for bond addr compare") Fixes: bb54e58929f3 ("bonding: Verify RX LACPDU has proper dest mac-addr") Fixes: 885a136c52a8 ("bonding: use compare_ether_addr_64bits() in ALB") Signed-off-by: Eric Dumazet Reported-by: Dmitry Vyukov Acked-by: Dmitry Vyukov Acked-by: Nikolay Aleksandrov Acked-by: Ding Tianhong Signed-off-by: David S. Miller diff --git a/drivers/net/bonding/bond_3ad.c b/drivers/net/bonding/bond_3ad.c index ca81f46..edc70ff 100644 --- a/drivers/net/bonding/bond_3ad.c +++ b/drivers/net/bonding/bond_3ad.c @@ -101,11 +101,14 @@ enum ad_link_speed_type { #define MAC_ADDRESS_EQUAL(A, B) \ ether_addr_equal_64bits((const u8 *)A, (const u8 *)B) -static struct mac_addr null_mac_addr = { { 0, 0, 0, 0, 0, 0 } }; +static const u8 null_mac_addr[ETH_ALEN + 2] __long_aligned = { + 0, 0, 0, 0, 0, 0 +}; static u16 ad_ticks_per_sec; static const int ad_delta_in_ticks = (AD_TIMER_INTERVAL * HZ) / 1000; -static const u8 lacpdu_mcast_addr[ETH_ALEN] = MULTICAST_LACPDU_ADDR; +static const u8 lacpdu_mcast_addr[ETH_ALEN + 2] __long_aligned = + MULTICAST_LACPDU_ADDR; /* ================= main 802.3ad protocol functions ================== */ static int ad_lacpdu_send(struct port *port); @@ -1739,7 +1742,7 @@ static void ad_clear_agg(struct aggregator *aggregator) aggregator->is_individual = false; aggregator->actor_admin_aggregator_key = 0; aggregator->actor_oper_aggregator_key = 0; - aggregator->partner_system = null_mac_addr; + eth_zero_addr(aggregator->partner_system.mac_addr_value); aggregator->partner_system_priority = 0; aggregator->partner_oper_aggregator_key = 0; aggregator->receive_state = 0; @@ -1761,7 +1764,7 @@ static void ad_initialize_agg(struct aggregator *aggregator) if (aggregator) { ad_clear_agg(aggregator); - aggregator->aggregator_mac_address = null_mac_addr; + eth_zero_addr(aggregator->aggregator_mac_address.mac_addr_value); aggregator->aggregator_identifier = 0; aggregator->slave = NULL; } diff --git a/drivers/net/bonding/bond_alb.c b/drivers/net/bonding/bond_alb.c index c5ac160..551f0f8 100644 --- a/drivers/net/bonding/bond_alb.c +++ b/drivers/net/bonding/bond_alb.c @@ -42,13 +42,10 @@ -#ifndef __long_aligned -#define __long_aligned __attribute__((aligned((sizeof(long))))) -#endif -static const u8 mac_bcast[ETH_ALEN] __long_aligned = { +static const u8 mac_bcast[ETH_ALEN + 2] __long_aligned = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; -static const u8 mac_v6_allmcast[ETH_ALEN] __long_aligned = { +static const u8 mac_v6_allmcast[ETH_ALEN + 2] __long_aligned = { 0x33, 0x33, 0x00, 0x00, 0x00, 0x01 }; static const int alb_delta_in_ticks = HZ / ALB_TIMER_TICKS_PER_SEC; diff --git a/include/net/bonding.h b/include/net/bonding.h index 791800d..6360c25 100644 --- a/include/net/bonding.h +++ b/include/net/bonding.h @@ -34,6 +34,9 @@ #define BOND_DEFAULT_MIIMON 100 +#ifndef __long_aligned +#define __long_aligned __attribute__((aligned((sizeof(long))))) +#endif /* * Less bad way to call ioctl from within the kernel; this needs to be * done some other way to get the call out of interrupt context. @@ -138,7 +141,9 @@ struct bond_params { struct reciprocal_value reciprocal_packets_per_slave; u16 ad_actor_sys_prio; u16 ad_user_port_key; - u8 ad_actor_system[ETH_ALEN]; + + /* 2 bytes of padding : see ether_addr_equal_64bits() */ + u8 ad_actor_system[ETH_ALEN + 2]; }; struct bond_parm_tbl { -- cgit v0.10.2 From 0d834442cc247c7b3f3bd6019512ae03e96dd99a Mon Sep 17 00:00:00 2001 From: Mohamad Haj Yahia Date: Thu, 30 Jun 2016 17:34:38 +0300 Subject: net/mlx5: Fix teardown errors that happen in pci error handler In case of internal error state we will simulate the commands status through the return value translation function, but we need to simulate all the teardown fw commands as successful so we will not have fw command failure prints. This also fix memory leaks that happen because we skip teardown stages due to failed fw commands. Fixes: 89d44f0a6c73 ('net/mlx5_core: Add pci error handlers to mlx5_core driver') Signed-off-by: Mohamad Haj Yahia Signed-off-by: Saeed Mahameed Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/mellanox/mlx5/core/cmd.c b/drivers/net/ethernet/mellanox/mlx5/core/cmd.c index 0b49862..fda43bc 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/cmd.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/cmd.c @@ -295,6 +295,12 @@ static int mlx5_internal_err_ret_value(struct mlx5_core_dev *dev, u16 op, case MLX5_CMD_OP_DESTROY_FLOW_GROUP: case MLX5_CMD_OP_DELETE_FLOW_TABLE_ENTRY: case MLX5_CMD_OP_DEALLOC_FLOW_COUNTER: + case MLX5_CMD_OP_2ERR_QP: + case MLX5_CMD_OP_2RST_QP: + case MLX5_CMD_OP_MODIFY_NIC_VPORT_CONTEXT: + case MLX5_CMD_OP_MODIFY_FLOW_TABLE: + case MLX5_CMD_OP_SET_FLOW_TABLE_ENTRY: + case MLX5_CMD_OP_SET_FLOW_TABLE_ROOT: return MLX5_CMD_STAT_OK; case MLX5_CMD_OP_QUERY_HCA_CAP: @@ -321,8 +327,6 @@ static int mlx5_internal_err_ret_value(struct mlx5_core_dev *dev, u16 op, case MLX5_CMD_OP_RTR2RTS_QP: case MLX5_CMD_OP_RTS2RTS_QP: case MLX5_CMD_OP_SQERR2RTS_QP: - case MLX5_CMD_OP_2ERR_QP: - case MLX5_CMD_OP_2RST_QP: case MLX5_CMD_OP_QUERY_QP: case MLX5_CMD_OP_SQD_RTS_QP: case MLX5_CMD_OP_INIT2INIT_QP: @@ -342,7 +346,6 @@ static int mlx5_internal_err_ret_value(struct mlx5_core_dev *dev, u16 op, case MLX5_CMD_OP_QUERY_ESW_VPORT_CONTEXT: case MLX5_CMD_OP_MODIFY_ESW_VPORT_CONTEXT: case MLX5_CMD_OP_QUERY_NIC_VPORT_CONTEXT: - case MLX5_CMD_OP_MODIFY_NIC_VPORT_CONTEXT: case MLX5_CMD_OP_QUERY_ROCE_ADDRESS: case MLX5_CMD_OP_SET_ROCE_ADDRESS: case MLX5_CMD_OP_QUERY_HCA_VPORT_CONTEXT: @@ -390,11 +393,12 @@ static int mlx5_internal_err_ret_value(struct mlx5_core_dev *dev, u16 op, case MLX5_CMD_OP_CREATE_RQT: case MLX5_CMD_OP_MODIFY_RQT: case MLX5_CMD_OP_QUERY_RQT: + case MLX5_CMD_OP_CREATE_FLOW_TABLE: case MLX5_CMD_OP_QUERY_FLOW_TABLE: case MLX5_CMD_OP_CREATE_FLOW_GROUP: case MLX5_CMD_OP_QUERY_FLOW_GROUP: - case MLX5_CMD_OP_SET_FLOW_TABLE_ENTRY: + case MLX5_CMD_OP_QUERY_FLOW_TABLE_ENTRY: case MLX5_CMD_OP_ALLOC_FLOW_COUNTER: case MLX5_CMD_OP_QUERY_FLOW_COUNTER: -- cgit v0.10.2 From c1d4d2e92ad670168a17a57dfa182a5a5baa72d4 Mon Sep 17 00:00:00 2001 From: Mohamad Haj Yahia Date: Thu, 30 Jun 2016 17:34:39 +0300 Subject: net/mlx5: Avoid calling sleeping function by the health poll thread In internal error state the health poll thread will eventually call synchronize_irq() (to safely trigger command completions) which might sleep, so we are calling sleeping function from atomic context which is invalid. Here we move trigger_cmd_completions(dev) to enter error state which is the earliest stage in error state handling. This way we won't need to wait for next health poll to trigger command completions and will solve the scheduling while atomic issue. mlx5_enter_error_state can be called from two contexts, protect it with dev->intf_state_lock Fixes: 89d44f0a6c73 ('net/mlx5_core: Add pci error handlers to mlx5_core driver') Signed-off-by: Mohamad Haj Yahia Signed-off-by: Saeed Mahameed Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/mellanox/mlx5/core/health.c b/drivers/net/ethernet/mellanox/mlx5/core/health.c index 42d16b9..96a5946 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/health.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/health.c @@ -108,15 +108,21 @@ static int in_fatal(struct mlx5_core_dev *dev) void mlx5_enter_error_state(struct mlx5_core_dev *dev) { + mutex_lock(&dev->intf_state_mutex); if (dev->state == MLX5_DEVICE_STATE_INTERNAL_ERROR) - return; + goto unlock; mlx5_core_err(dev, "start\n"); - if (pci_channel_offline(dev->pdev) || in_fatal(dev)) + if (pci_channel_offline(dev->pdev) || in_fatal(dev)) { dev->state = MLX5_DEVICE_STATE_INTERNAL_ERROR; + trigger_cmd_completions(dev); + } mlx5_core_event(dev, MLX5_DEV_EVENT_SYS_ERROR, 0); mlx5_core_err(dev, "end\n"); + +unlock: + mutex_unlock(&dev->intf_state_mutex); } static void mlx5_handle_bad_state(struct mlx5_core_dev *dev) @@ -245,7 +251,6 @@ static void poll_health(unsigned long data) u32 count; if (dev->state == MLX5_DEVICE_STATE_INTERNAL_ERROR) { - trigger_cmd_completions(dev); mod_timer(&health->timer, get_next_poll_jiffies()); return; } -- cgit v0.10.2 From 5adff6a0886273eb426360400f120443833760a3 Mon Sep 17 00:00:00 2001 From: Daniel Jurgens Date: Thu, 30 Jun 2016 17:34:40 +0300 Subject: net/mlx5: Fix incorrect page count when in internal error Change page cleanup flow when in internal error to properly decrement the page counts when reclaiming pages. The prevents timing out waiting for extra pages that were actually cleaned up previously. fixes: 89d44f0a6c73 ('net/mlx5_core: Add pci error handlers to mlx5_core driver') Signed-off-by: Daniel Jurgens Signed-off-by: Saeed Mahameed Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/mellanox/mlx5/core/pagealloc.c b/drivers/net/ethernet/mellanox/mlx5/core/pagealloc.c index 9eeee05..32dea35 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/pagealloc.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/pagealloc.c @@ -345,7 +345,6 @@ retry: func_id, npages, err); goto out_4k; } - dev->priv.fw_pages += npages; err = mlx5_cmd_status_to_err(&out.hdr); if (err) { @@ -373,6 +372,33 @@ out_free: return err; } +static int reclaim_pages_cmd(struct mlx5_core_dev *dev, + struct mlx5_manage_pages_inbox *in, int in_size, + struct mlx5_manage_pages_outbox *out, int out_size) +{ + struct fw_page *fwp; + struct rb_node *p; + u32 npages; + u32 i = 0; + + if (dev->state != MLX5_DEVICE_STATE_INTERNAL_ERROR) + return mlx5_cmd_exec_check_status(dev, (u32 *)in, in_size, + (u32 *)out, out_size); + + npages = be32_to_cpu(in->num_entries); + + p = rb_first(&dev->priv.page_root); + while (p && i < npages) { + fwp = rb_entry(p, struct fw_page, rb_node); + out->pas[i] = cpu_to_be64(fwp->addr); + p = rb_next(p); + i++; + } + + out->num_entries = cpu_to_be32(i); + return 0; +} + static int reclaim_pages(struct mlx5_core_dev *dev, u32 func_id, int npages, int *nclaimed) { @@ -398,15 +424,9 @@ static int reclaim_pages(struct mlx5_core_dev *dev, u32 func_id, int npages, in.func_id = cpu_to_be16(func_id); in.num_entries = cpu_to_be32(npages); mlx5_core_dbg(dev, "npages %d, outlen %d\n", npages, outlen); - err = mlx5_cmd_exec(dev, &in, sizeof(in), out, outlen); + err = reclaim_pages_cmd(dev, &in, sizeof(in), out, outlen); if (err) { - mlx5_core_err(dev, "failed reclaiming pages\n"); - goto out_free; - } - dev->priv.fw_pages -= npages; - - if (out->hdr.status) { - err = mlx5_cmd_status_to_err(&out->hdr); + mlx5_core_err(dev, "failed reclaiming pages: err %d\n", err); goto out_free; } @@ -417,13 +437,15 @@ static int reclaim_pages(struct mlx5_core_dev *dev, u32 func_id, int npages, err = -EINVAL; goto out_free; } - if (nclaimed) - *nclaimed = num_claimed; for (i = 0; i < num_claimed; i++) { addr = be64_to_cpu(out->pas[i]); free_4k(dev, addr); } + + if (nclaimed) + *nclaimed = num_claimed; + dev->priv.fw_pages -= num_claimed; if (func_id) dev->priv.vfs_pages -= num_claimed; @@ -514,14 +536,10 @@ int mlx5_reclaim_startup_pages(struct mlx5_core_dev *dev) p = rb_first(&dev->priv.page_root); if (p) { fwp = rb_entry(p, struct fw_page, rb_node); - if (dev->state == MLX5_DEVICE_STATE_INTERNAL_ERROR) { - free_4k(dev, fwp->addr); - nclaimed = 1; - } else { - err = reclaim_pages(dev, fwp->func_id, - optimal_reclaimed_pages(), - &nclaimed); - } + err = reclaim_pages(dev, fwp->func_id, + optimal_reclaimed_pages(), + &nclaimed); + if (err) { mlx5_core_warn(dev, "failed reclaiming pages (%d)\n", err); @@ -536,6 +554,13 @@ int mlx5_reclaim_startup_pages(struct mlx5_core_dev *dev) } } while (p); + WARN(dev->priv.fw_pages, + "FW pages counter is %d after reclaiming all pages\n", + dev->priv.fw_pages); + WARN(dev->priv.vfs_pages, + "VFs FW pages counter is %d after reclaiming all pages\n", + dev->priv.vfs_pages); + return 0; } -- cgit v0.10.2 From d57847dc4177c6fd8d950cb533f5edf0eab45b11 Mon Sep 17 00:00:00 2001 From: Daniel Jurgens Date: Thu, 30 Jun 2016 17:34:41 +0300 Subject: net/mlx5: Fix wait_vital for VFs and remove fixed sleep The device ID for VFs is in a different location than PFs. This results in the poll always timing out for VFs. There's no good way to read the VF device ID without using the PF's configuration space. Switch to waiting for the health poll to start incrementing. Also remove the 1s sleep at the beginning. fixes: 89d44f0a6c73 ('net/mlx5_core: Add pci error handlers to mlx5_core driver') Signed-off-by: Daniel Jurgens Signed-off-by: Saeed Mahameed Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/mellanox/mlx5/core/main.c b/drivers/net/ethernet/mellanox/mlx5/core/main.c index c65f4a1..6695893 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/main.c @@ -1422,46 +1422,31 @@ void mlx5_disable_device(struct mlx5_core_dev *dev) mlx5_pci_err_detected(dev->pdev, 0); } -/* wait for the device to show vital signs. For now we check - * that we can read the device ID and that the health buffer - * shows a non zero value which is different than 0xffffffff +/* wait for the device to show vital signs by waiting + * for the health counter to start counting. */ -static void wait_vital(struct pci_dev *pdev) +static int wait_vital(struct pci_dev *pdev) { struct mlx5_core_dev *dev = pci_get_drvdata(pdev); struct mlx5_core_health *health = &dev->priv.health; const int niter = 100; + u32 last_count = 0; u32 count; - u16 did; int i; - /* Wait for firmware to be ready after reset */ - msleep(1000); - for (i = 0; i < niter; i++) { - if (pci_read_config_word(pdev, 2, &did)) { - dev_warn(&pdev->dev, "failed reading config word\n"); - break; - } - if (did == pdev->device) { - dev_info(&pdev->dev, "device ID correctly read after %d iterations\n", i); - break; - } - msleep(50); - } - if (i == niter) - dev_warn(&pdev->dev, "%s-%d: could not read device ID\n", __func__, __LINE__); - for (i = 0; i < niter; i++) { count = ioread32be(health->health_counter); if (count && count != 0xffffffff) { - dev_info(&pdev->dev, "Counter value 0x%x after %d iterations\n", count, i); - break; + if (last_count && last_count != count) { + dev_info(&pdev->dev, "Counter value 0x%x after %d iterations\n", count, i); + return 0; + } + last_count = count; } msleep(50); } - if (i == niter) - dev_warn(&pdev->dev, "%s-%d: could not read device ID\n", __func__, __LINE__); + return -ETIMEDOUT; } static void mlx5_pci_resume(struct pci_dev *pdev) @@ -1473,7 +1458,11 @@ static void mlx5_pci_resume(struct pci_dev *pdev) dev_info(&pdev->dev, "%s was called\n", __func__); pci_save_state(pdev); - wait_vital(pdev); + err = wait_vital(pdev); + if (err) { + dev_err(&pdev->dev, "%s: wait_vital timed out\n", __func__); + return; + } err = mlx5_load_one(dev, priv); if (err) -- cgit v0.10.2 From 9cba4ebcf374c3772f6eb61f2d065294b2451b49 Mon Sep 17 00:00:00 2001 From: Mohamad Haj Yahia Date: Thu, 30 Jun 2016 17:34:42 +0300 Subject: net/mlx5: Fix potential deadlock in command mode change Call command completion handler in case of timeout when working in interrupts mode. Avoid flushing the commands workqueue after acquiring the semaphores to prevent a potential deadlock. Fixes: e126ba97dba9 ('mlx5: Add driver for Mellanox Connect-IB adapters') Signed-off-by: Mohamad Haj Yahia Signed-off-by: Saeed Mahameed Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/mellanox/mlx5/core/cmd.c b/drivers/net/ethernet/mellanox/mlx5/core/cmd.c index fda43bc..74067f5 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/cmd.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/cmd.c @@ -710,13 +710,13 @@ static int wait_func(struct mlx5_core_dev *dev, struct mlx5_cmd_work_ent *ent) if (cmd->mode == CMD_MODE_POLLING) { wait_for_completion(&ent->done); - err = ent->ret; - } else { - if (!wait_for_completion_timeout(&ent->done, timeout)) - err = -ETIMEDOUT; - else - err = 0; + } else if (!wait_for_completion_timeout(&ent->done, timeout)) { + ent->ret = -ETIMEDOUT; + mlx5_cmd_comp_handler(dev, 1UL << ent->idx); } + + err = ent->ret; + if (err == -ETIMEDOUT) { mlx5_core_warn(dev, "%s(0x%x) timeout. Will cause a leak of a command resource\n", mlx5_command_str(msg_to_opcode(ent->in)), @@ -774,28 +774,26 @@ static int mlx5_cmd_invoke(struct mlx5_core_dev *dev, struct mlx5_cmd_msg *in, goto out_free; } - if (!callback) { - err = wait_func(dev, ent); - if (err == -ETIMEDOUT) - goto out; - - ds = ent->ts2 - ent->ts1; - op = be16_to_cpu(((struct mlx5_inbox_hdr *)in->first.data)->opcode); - if (op < ARRAY_SIZE(cmd->stats)) { - stats = &cmd->stats[op]; - spin_lock_irq(&stats->lock); - stats->sum += ds; - ++stats->n; - spin_unlock_irq(&stats->lock); - } - mlx5_core_dbg_mask(dev, 1 << MLX5_CMD_TIME, - "fw exec time for %s is %lld nsec\n", - mlx5_command_str(op), ds); - *status = ent->status; - free_cmd(ent); - } + if (callback) + goto out; - return err; + err = wait_func(dev, ent); + if (err == -ETIMEDOUT) + goto out_free; + + ds = ent->ts2 - ent->ts1; + op = be16_to_cpu(((struct mlx5_inbox_hdr *)in->first.data)->opcode); + if (op < ARRAY_SIZE(cmd->stats)) { + stats = &cmd->stats[op]; + spin_lock_irq(&stats->lock); + stats->sum += ds; + ++stats->n; + spin_unlock_irq(&stats->lock); + } + mlx5_core_dbg_mask(dev, 1 << MLX5_CMD_TIME, + "fw exec time for %s is %lld nsec\n", + mlx5_command_str(op), ds); + *status = ent->status; out_free: free_cmd(ent); @@ -1185,41 +1183,30 @@ err_dbg: return err; } -void mlx5_cmd_use_events(struct mlx5_core_dev *dev) +static void mlx5_cmd_change_mod(struct mlx5_core_dev *dev, int mode) { struct mlx5_cmd *cmd = &dev->cmd; int i; for (i = 0; i < cmd->max_reg_cmds; i++) down(&cmd->sem); - down(&cmd->pages_sem); - flush_workqueue(cmd->wq); - - cmd->mode = CMD_MODE_EVENTS; + cmd->mode = mode; up(&cmd->pages_sem); for (i = 0; i < cmd->max_reg_cmds; i++) up(&cmd->sem); } -void mlx5_cmd_use_polling(struct mlx5_core_dev *dev) +void mlx5_cmd_use_events(struct mlx5_core_dev *dev) { - struct mlx5_cmd *cmd = &dev->cmd; - int i; - - for (i = 0; i < cmd->max_reg_cmds; i++) - down(&cmd->sem); - - down(&cmd->pages_sem); - - flush_workqueue(cmd->wq); - cmd->mode = CMD_MODE_POLLING; + mlx5_cmd_change_mod(dev, CMD_MODE_EVENTS); +} - up(&cmd->pages_sem); - for (i = 0; i < cmd->max_reg_cmds; i++) - up(&cmd->sem); +void mlx5_cmd_use_polling(struct mlx5_core_dev *dev) +{ + mlx5_cmd_change_mod(dev, CMD_MODE_POLLING); } static void free_msg(struct mlx5_core_dev *dev, struct mlx5_cmd_msg *msg) -- cgit v0.10.2 From 65ee67084589c1783a74b4a4a5db38d7264ec8b5 Mon Sep 17 00:00:00 2001 From: Mohamad Haj Yahia Date: Thu, 30 Jun 2016 17:34:43 +0300 Subject: net/mlx5: Add timeout handle to commands with callback The current implementation does not handle timeout in case of command with callback request, and this can lead to deadlock if the command doesn't get fw response. Add delayed callback timeout work before posting the command to fw. In case of real fw command completion we will cancel the delayed work. In case of fw command timeout the callback timeout handler will be called and it will simulate fw completion with timeout error. Fixes: e126ba97dba9 ('mlx5: Add driver for Mellanox Connect-IB adapters') Signed-off-by: Mohamad Haj Yahia Signed-off-by: Saeed Mahameed Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/mellanox/mlx5/core/cmd.c b/drivers/net/ethernet/mellanox/mlx5/core/cmd.c index 74067f5..d6e2a1c 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/cmd.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/cmd.c @@ -606,11 +606,36 @@ static void dump_command(struct mlx5_core_dev *dev, pr_debug("\n"); } +static u16 msg_to_opcode(struct mlx5_cmd_msg *in) +{ + struct mlx5_inbox_hdr *hdr = (struct mlx5_inbox_hdr *)(in->first.data); + + return be16_to_cpu(hdr->opcode); +} + +static void cb_timeout_handler(struct work_struct *work) +{ + struct delayed_work *dwork = container_of(work, struct delayed_work, + work); + struct mlx5_cmd_work_ent *ent = container_of(dwork, + struct mlx5_cmd_work_ent, + cb_timeout_work); + struct mlx5_core_dev *dev = container_of(ent->cmd, struct mlx5_core_dev, + cmd); + + ent->ret = -ETIMEDOUT; + mlx5_core_warn(dev, "%s(0x%x) timeout. Will cause a leak of a command resource\n", + mlx5_command_str(msg_to_opcode(ent->in)), + msg_to_opcode(ent->in)); + mlx5_cmd_comp_handler(dev, 1UL << ent->idx); +} + static void cmd_work_handler(struct work_struct *work) { struct mlx5_cmd_work_ent *ent = container_of(work, struct mlx5_cmd_work_ent, work); struct mlx5_cmd *cmd = ent->cmd; struct mlx5_core_dev *dev = container_of(cmd, struct mlx5_core_dev, cmd); + unsigned long cb_timeout = msecs_to_jiffies(MLX5_CMD_TIMEOUT_MSEC); struct mlx5_cmd_layout *lay; struct semaphore *sem; unsigned long flags; @@ -651,6 +676,9 @@ static void cmd_work_handler(struct work_struct *work) dump_command(dev, ent, 1); ent->ts1 = ktime_get_ns(); + if (ent->callback) + schedule_delayed_work(&ent->cb_timeout_work, cb_timeout); + /* ring doorbell after the descriptor is valid */ mlx5_core_dbg(dev, "writing 0x%x to command doorbell\n", 1 << ent->idx); wmb(); @@ -695,13 +723,6 @@ static const char *deliv_status_to_str(u8 status) } } -static u16 msg_to_opcode(struct mlx5_cmd_msg *in) -{ - struct mlx5_inbox_hdr *hdr = (struct mlx5_inbox_hdr *)(in->first.data); - - return be16_to_cpu(hdr->opcode); -} - static int wait_func(struct mlx5_core_dev *dev, struct mlx5_cmd_work_ent *ent) { unsigned long timeout = msecs_to_jiffies(MLX5_CMD_TIMEOUT_MSEC); @@ -765,6 +786,7 @@ static int mlx5_cmd_invoke(struct mlx5_core_dev *dev, struct mlx5_cmd_msg *in, if (!callback) init_completion(&ent->done); + INIT_DELAYED_WORK(&ent->cb_timeout_work, cb_timeout_handler); INIT_WORK(&ent->work, cmd_work_handler); if (page_queue) { cmd_work_handler(&ent->work); @@ -1242,6 +1264,8 @@ void mlx5_cmd_comp_handler(struct mlx5_core_dev *dev, u64 vec) struct semaphore *sem; ent = cmd->ent_arr[i]; + if (ent->callback) + cancel_delayed_work(&ent->cb_timeout_work); if (ent->page_queue) sem = &cmd->pages_sem; else diff --git a/include/linux/mlx5/driver.h b/include/linux/mlx5/driver.h index 80776d0..fd72ecf 100644 --- a/include/linux/mlx5/driver.h +++ b/include/linux/mlx5/driver.h @@ -629,6 +629,7 @@ struct mlx5_cmd_work_ent { void *uout; int uout_size; mlx5_cmd_cbk_t callback; + struct delayed_work cb_timeout_work; void *context; int idx; struct completion done; -- cgit v0.10.2 From 29429f3300a378f7c29583b4c2c2ef29e2190a69 Mon Sep 17 00:00:00 2001 From: Daniel Jurgens Date: Thu, 30 Jun 2016 17:34:44 +0300 Subject: net/mlx5e: Timeout if SQ doesn't flush during close Avoid an infinite loop by timing out waiting for the SQ to flush. Also clean up the TX descriptors if that happens. Fixes: f62b8bb8f2d3 ('net/mlx5: Extend mlx5_core to support ConnectX-4 Ethernet functionality') Signed-off-by: Daniel Jurgens Signed-off-by: Saeed Mahameed Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en.h b/drivers/net/ethernet/mellanox/mlx5/core/en.h index baa991a..c22d8c8 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/en.h @@ -305,6 +305,7 @@ struct mlx5e_sq_dma { enum { MLX5E_SQ_STATE_WAKE_TXQ_ENABLE, MLX5E_SQ_STATE_BF_ENABLE, + MLX5E_SQ_STATE_TX_TIMEOUT, }; struct mlx5e_ico_wqe_info { @@ -589,6 +590,7 @@ void mlx5e_cq_error_event(struct mlx5_core_cq *mcq, enum mlx5_event event); int mlx5e_napi_poll(struct napi_struct *napi, int budget); bool mlx5e_poll_tx_cq(struct mlx5e_cq *cq, int napi_budget); int mlx5e_poll_rx_cq(struct mlx5e_cq *cq, int budget); +void mlx5e_free_tx_descs(struct mlx5e_sq *sq); void mlx5e_handle_rx_cqe(struct mlx5e_rq *rq, struct mlx5_cqe64 *cqe); void mlx5e_handle_rx_cqe_mpwrq(struct mlx5e_rq *rq, struct mlx5_cqe64 *cqe); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c index cb6defd..b94c84b 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c @@ -39,6 +39,13 @@ #include "eswitch.h" #include "vxlan.h" +enum { + MLX5_EN_QP_FLUSH_TIMEOUT_MS = 5000, + MLX5_EN_QP_FLUSH_MSLEEP_QUANT = 20, + MLX5_EN_QP_FLUSH_MAX_ITER = MLX5_EN_QP_FLUSH_TIMEOUT_MS / + MLX5_EN_QP_FLUSH_MSLEEP_QUANT, +}; + struct mlx5e_rq_param { u32 rqc[MLX5_ST_SZ_DW(rqc)]; struct mlx5_wq_param wq; @@ -782,6 +789,9 @@ static inline void netif_tx_disable_queue(struct netdev_queue *txq) static void mlx5e_close_sq(struct mlx5e_sq *sq) { + int tout = 0; + int err; + if (sq->txq) { clear_bit(MLX5E_SQ_STATE_WAKE_TXQ_ENABLE, &sq->state); /* prevent netif_tx_wake_queue */ @@ -792,15 +802,24 @@ static void mlx5e_close_sq(struct mlx5e_sq *sq) if (mlx5e_sq_has_room_for(sq, 1)) mlx5e_send_nop(sq, true); - mlx5e_modify_sq(sq, MLX5_SQC_STATE_RDY, MLX5_SQC_STATE_ERR); + err = mlx5e_modify_sq(sq, MLX5_SQC_STATE_RDY, + MLX5_SQC_STATE_ERR); + if (err) + set_bit(MLX5E_SQ_STATE_TX_TIMEOUT, &sq->state); } - while (sq->cc != sq->pc) /* wait till sq is empty */ - msleep(20); + /* wait till sq is empty, unless a TX timeout occurred on this SQ */ + while (sq->cc != sq->pc && + !test_bit(MLX5E_SQ_STATE_TX_TIMEOUT, &sq->state)) { + msleep(MLX5_EN_QP_FLUSH_MSLEEP_QUANT); + if (tout++ > MLX5_EN_QP_FLUSH_MAX_ITER) + set_bit(MLX5E_SQ_STATE_TX_TIMEOUT, &sq->state); + } /* avoid destroying sq before mlx5e_poll_tx_cq() is done with it */ napi_synchronize(&sq->channel->napi); + mlx5e_free_tx_descs(sq); mlx5e_disable_sq(sq); mlx5e_destroy_sq(sq); } diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c b/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c index 5a750b9cd..65e3bce 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c @@ -341,6 +341,35 @@ netdev_tx_t mlx5e_xmit(struct sk_buff *skb, struct net_device *dev) return mlx5e_sq_xmit(sq, skb); } +void mlx5e_free_tx_descs(struct mlx5e_sq *sq) +{ + struct mlx5e_tx_wqe_info *wi; + struct sk_buff *skb; + u16 ci; + int i; + + while (sq->cc != sq->pc) { + ci = sq->cc & sq->wq.sz_m1; + skb = sq->skb[ci]; + wi = &sq->wqe_info[ci]; + + if (!skb) { /* nop */ + sq->cc++; + continue; + } + + for (i = 0; i < wi->num_dma; i++) { + struct mlx5e_sq_dma *dma = + mlx5e_dma_get(sq, sq->dma_fifo_cc++); + + mlx5e_tx_dma_unmap(sq->pdev, dma); + } + + dev_kfree_skb_any(skb); + sq->cc += wi->num_wqebbs; + } +} + bool mlx5e_poll_tx_cq(struct mlx5e_cq *cq, int napi_budget) { struct mlx5e_sq *sq; @@ -352,6 +381,9 @@ bool mlx5e_poll_tx_cq(struct mlx5e_cq *cq, int napi_budget) sq = container_of(cq, struct mlx5e_sq, cq); + if (unlikely(test_bit(MLX5E_SQ_STATE_TX_TIMEOUT, &sq->state))) + return false; + npkts = 0; nbytes = 0; -- cgit v0.10.2 From 3947ca1859999ac00698c0da0d233813a93d288a Mon Sep 17 00:00:00 2001 From: Daniel Jurgens Date: Thu, 30 Jun 2016 17:34:45 +0300 Subject: net/mlx5e: Implement ndo_tx_timeout callback Add callback to handle TX timeouts. Fixes: f62b8bb8f2d3 ('net/mlx5: Extend mlx5_core to support ConnectX-4 Ethernet functionality') Signed-off-by: Daniel Jurgens Signed-off-by: Saeed Mahameed Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en.h b/drivers/net/ethernet/mellanox/mlx5/core/en.h index c22d8c8..244aced 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/en.h @@ -539,6 +539,7 @@ struct mlx5e_priv { struct workqueue_struct *wq; struct work_struct update_carrier_work; struct work_struct set_rx_mode_work; + struct work_struct tx_timeout_work; struct delayed_work update_stats_work; struct mlx5_core_dev *mdev; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c index b94c84b..38c1286 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c @@ -98,6 +98,26 @@ static void mlx5e_update_carrier_work(struct work_struct *work) mutex_unlock(&priv->state_lock); } +static void mlx5e_tx_timeout_work(struct work_struct *work) +{ + struct mlx5e_priv *priv = container_of(work, struct mlx5e_priv, + tx_timeout_work); + int err; + + rtnl_lock(); + mutex_lock(&priv->state_lock); + if (!test_bit(MLX5E_STATE_OPENED, &priv->state)) + goto unlock; + mlx5e_close_locked(priv->netdev); + err = mlx5e_open_locked(priv->netdev); + if (err) + netdev_err(priv->netdev, "mlx5e_open_locked failed recovering from a tx_timeout, err(%d).\n", + err); +unlock: + mutex_unlock(&priv->state_lock); + rtnl_unlock(); +} + static void mlx5e_update_sw_counters(struct mlx5e_priv *priv) { struct mlx5e_sw_stats *s = &priv->stats.sw; @@ -2609,6 +2629,29 @@ static netdev_features_t mlx5e_features_check(struct sk_buff *skb, return features; } +static void mlx5e_tx_timeout(struct net_device *dev) +{ + struct mlx5e_priv *priv = netdev_priv(dev); + bool sched_work = false; + int i; + + netdev_err(dev, "TX timeout detected\n"); + + for (i = 0; i < priv->params.num_channels * priv->params.num_tc; i++) { + struct mlx5e_sq *sq = priv->txq_to_sq_map[i]; + + if (!netif_tx_queue_stopped(netdev_get_tx_queue(dev, i))) + continue; + sched_work = true; + set_bit(MLX5E_SQ_STATE_TX_TIMEOUT, &sq->state); + netdev_err(dev, "TX timeout on queue: %d, SQ: 0x%x, CQ: 0x%x, SQ Cons: 0x%x SQ Prod: 0x%x\n", + i, sq->sqn, sq->cq.mcq.cqn, sq->cc, sq->pc); + } + + if (sched_work && test_bit(MLX5E_STATE_OPENED, &priv->state)) + schedule_work(&priv->tx_timeout_work); +} + static const struct net_device_ops mlx5e_netdev_ops_basic = { .ndo_open = mlx5e_open, .ndo_stop = mlx5e_close, @@ -2626,6 +2669,7 @@ static const struct net_device_ops mlx5e_netdev_ops_basic = { #ifdef CONFIG_RFS_ACCEL .ndo_rx_flow_steer = mlx5e_rx_flow_steer, #endif + .ndo_tx_timeout = mlx5e_tx_timeout, }; static const struct net_device_ops mlx5e_netdev_ops_sriov = { @@ -2655,6 +2699,7 @@ static const struct net_device_ops mlx5e_netdev_ops_sriov = { .ndo_get_vf_config = mlx5e_get_vf_config, .ndo_set_vf_link_state = mlx5e_set_vf_link_state, .ndo_get_vf_stats = mlx5e_get_vf_stats, + .ndo_tx_timeout = mlx5e_tx_timeout, }; static int mlx5e_check_required_hca_cap(struct mlx5_core_dev *mdev) @@ -2857,6 +2902,7 @@ static void mlx5e_build_netdev_priv(struct mlx5_core_dev *mdev, INIT_WORK(&priv->update_carrier_work, mlx5e_update_carrier_work); INIT_WORK(&priv->set_rx_mode_work, mlx5e_set_rx_mode_work); + INIT_WORK(&priv->tx_timeout_work, mlx5e_tx_timeout_work); INIT_DELAYED_WORK(&priv->update_stats_work, mlx5e_update_stats_work); } -- cgit v0.10.2 From 6cd392a082deca8accec5c50b5b3fc1a9de5bfa2 Mon Sep 17 00:00:00 2001 From: Daniel Jurgens Date: Thu, 30 Jun 2016 17:34:46 +0300 Subject: net/mlx5e: Handle RQ flush in error cases Add a timeout to avoid an infinite loop waiting for RQ's to flush. This occurs during AER/EEH and will also happen if the device stops posting completions due to internal error or reset, or if moving the RQ to the error state fails. Also cleanup posted receive resources when closing the RQ. Fixes: f62b8bb8f2d3 ('net/mlx5: Extend mlx5_core to support ConnectX-4 Ethernet functionality') Signed-off-by: Daniel Jurgens Signed-off-by: Saeed Mahameed Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en.h b/drivers/net/ethernet/mellanox/mlx5/core/en.h index 244aced..b429591 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/en.h @@ -191,6 +191,7 @@ struct mlx5e_tstamp { enum { MLX5E_RQ_STATE_POST_WQES_ENABLE, MLX5E_RQ_STATE_UMR_WQE_IN_PROGRESS, + MLX5E_RQ_STATE_FLUSH_TIMEOUT, }; struct mlx5e_cq { @@ -220,6 +221,8 @@ typedef void (*mlx5e_fp_handle_rx_cqe)(struct mlx5e_rq *rq, typedef int (*mlx5e_fp_alloc_wqe)(struct mlx5e_rq *rq, struct mlx5e_rx_wqe *wqe, u16 ix); +typedef void (*mlx5e_fp_dealloc_wqe)(struct mlx5e_rq *rq, u16 ix); + struct mlx5e_dma_info { struct page *page; dma_addr_t addr; @@ -241,6 +244,7 @@ struct mlx5e_rq { struct mlx5e_cq cq; mlx5e_fp_handle_rx_cqe handle_rx_cqe; mlx5e_fp_alloc_wqe alloc_wqe; + mlx5e_fp_dealloc_wqe dealloc_wqe; unsigned long state; int ix; @@ -592,12 +596,15 @@ int mlx5e_napi_poll(struct napi_struct *napi, int budget); bool mlx5e_poll_tx_cq(struct mlx5e_cq *cq, int napi_budget); int mlx5e_poll_rx_cq(struct mlx5e_cq *cq, int budget); void mlx5e_free_tx_descs(struct mlx5e_sq *sq); +void mlx5e_free_rx_descs(struct mlx5e_rq *rq); void mlx5e_handle_rx_cqe(struct mlx5e_rq *rq, struct mlx5_cqe64 *cqe); void mlx5e_handle_rx_cqe_mpwrq(struct mlx5e_rq *rq, struct mlx5_cqe64 *cqe); bool mlx5e_post_rx_wqes(struct mlx5e_rq *rq); int mlx5e_alloc_rx_wqe(struct mlx5e_rq *rq, struct mlx5e_rx_wqe *wqe, u16 ix); int mlx5e_alloc_rx_mpwqe(struct mlx5e_rq *rq, struct mlx5e_rx_wqe *wqe, u16 ix); +void mlx5e_dealloc_rx_wqe(struct mlx5e_rq *rq, u16 ix); +void mlx5e_dealloc_rx_mpwqe(struct mlx5e_rq *rq, u16 ix); void mlx5e_post_rx_fragmented_mpwqe(struct mlx5e_rq *rq); void mlx5e_complete_rx_linear_mpwqe(struct mlx5e_rq *rq, struct mlx5_cqe64 *cqe, diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c index 38c1286..103feab 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c @@ -332,6 +332,7 @@ static int mlx5e_create_rq(struct mlx5e_channel *c, } rq->handle_rx_cqe = mlx5e_handle_rx_cqe_mpwrq; rq->alloc_wqe = mlx5e_alloc_rx_mpwqe; + rq->dealloc_wqe = mlx5e_dealloc_rx_mpwqe; rq->mpwqe_stride_sz = BIT(priv->params.mpwqe_log_stride_sz); rq->mpwqe_num_strides = BIT(priv->params.mpwqe_log_num_strides); @@ -347,6 +348,7 @@ static int mlx5e_create_rq(struct mlx5e_channel *c, } rq->handle_rx_cqe = mlx5e_handle_rx_cqe; rq->alloc_wqe = mlx5e_alloc_rx_wqe; + rq->dealloc_wqe = mlx5e_dealloc_rx_wqe; rq->wqe_sz = (priv->params.lro_en) ? priv->params.lro_wqe_sz : @@ -552,17 +554,25 @@ err_destroy_rq: static void mlx5e_close_rq(struct mlx5e_rq *rq) { + int tout = 0; + int err; + clear_bit(MLX5E_RQ_STATE_POST_WQES_ENABLE, &rq->state); napi_synchronize(&rq->channel->napi); /* prevent mlx5e_post_rx_wqes */ - mlx5e_modify_rq_state(rq, MLX5_RQC_STATE_RDY, MLX5_RQC_STATE_ERR); - while (!mlx5_wq_ll_is_empty(&rq->wq)) - msleep(20); + err = mlx5e_modify_rq_state(rq, MLX5_RQC_STATE_RDY, MLX5_RQC_STATE_ERR); + while (!mlx5_wq_ll_is_empty(&rq->wq) && !err && + tout++ < MLX5_EN_QP_FLUSH_MAX_ITER) + msleep(MLX5_EN_QP_FLUSH_MSLEEP_QUANT); + + if (err || tout == MLX5_EN_QP_FLUSH_MAX_ITER) + set_bit(MLX5E_RQ_STATE_FLUSH_TIMEOUT, &rq->state); /* avoid destroying rq before mlx5e_poll_rx_cq() is done with it */ napi_synchronize(&rq->channel->napi); mlx5e_disable_rq(rq); + mlx5e_free_rx_descs(rq); mlx5e_destroy_rq(rq); } diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c b/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c index 022acc2..9f2a16a 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c @@ -212,6 +212,20 @@ err_free_skb: return -ENOMEM; } +void mlx5e_dealloc_rx_wqe(struct mlx5e_rq *rq, u16 ix) +{ + struct sk_buff *skb = rq->skb[ix]; + + if (skb) { + rq->skb[ix] = NULL; + dma_unmap_single(rq->pdev, + *((dma_addr_t *)skb->cb), + rq->wqe_sz, + DMA_FROM_DEVICE); + dev_kfree_skb(skb); + } +} + static inline int mlx5e_mpwqe_strides_per_page(struct mlx5e_rq *rq) { return rq->mpwqe_num_strides >> MLX5_MPWRQ_WQE_PAGE_ORDER; @@ -574,6 +588,30 @@ int mlx5e_alloc_rx_mpwqe(struct mlx5e_rq *rq, struct mlx5e_rx_wqe *wqe, u16 ix) return 0; } +void mlx5e_dealloc_rx_mpwqe(struct mlx5e_rq *rq, u16 ix) +{ + struct mlx5e_mpw_info *wi = &rq->wqe_info[ix]; + + wi->free_wqe(rq, wi); +} + +void mlx5e_free_rx_descs(struct mlx5e_rq *rq) +{ + struct mlx5_wq_ll *wq = &rq->wq; + struct mlx5e_rx_wqe *wqe; + __be16 wqe_ix_be; + u16 wqe_ix; + + while (!mlx5_wq_ll_is_empty(wq)) { + wqe_ix_be = *wq->tail_next; + wqe_ix = be16_to_cpu(wqe_ix_be); + wqe = mlx5_wq_ll_get_wqe(&rq->wq, wqe_ix); + rq->dealloc_wqe(rq, wqe_ix); + mlx5_wq_ll_pop(&rq->wq, wqe_ix_be, + &wqe->next.next_wqe_index); + } +} + #define RQ_CANNOT_POST(rq) \ (!test_bit(MLX5E_RQ_STATE_POST_WQES_ENABLE, &rq->state) || \ test_bit(MLX5E_RQ_STATE_UMR_WQE_IN_PROGRESS, &rq->state)) @@ -878,6 +916,9 @@ int mlx5e_poll_rx_cq(struct mlx5e_cq *cq, int budget) struct mlx5e_rq *rq = container_of(cq, struct mlx5e_rq, cq); int work_done = 0; + if (unlikely(test_bit(MLX5E_RQ_STATE_FLUSH_TIMEOUT, &rq->state))) + return 0; + if (cq->decmprs_left) work_done += mlx5e_decompress_cqes_cont(rq, cq, 0, budget); -- cgit v0.10.2 From e3a19b53cbb0e6738b7a547f262179065b72e3fa Mon Sep 17 00:00:00 2001 From: Matthew Finlay Date: Thu, 30 Jun 2016 17:34:47 +0300 Subject: net/mlx5e: Copy all L2 headers into inline segment ConnectX4-Lx uses an inline wqe mode that currently defaults to requiring the entire L2 header be included in the wqe. This patch fixes mlx5e_get_inline_hdr_size() to account for all L2 headers (VLAN, QinQ, etc) using skb_network_offset(skb). Fixes: e586b3b0baee ("net/mlx5: Ethernet Datapath files") Signed-off-by: Matthew Finlay Signed-off-by: Saeed Mahameed Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c b/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c index 65e3bce..42a5f06 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c @@ -123,7 +123,7 @@ static inline u16 mlx5e_get_inline_hdr_size(struct mlx5e_sq *sq, * headers and occur before the data gather. * Therefore these headers must be copied into the WQE */ -#define MLX5E_MIN_INLINE ETH_HLEN +#define MLX5E_MIN_INLINE (ETH_HLEN + VLAN_HLEN) if (bf) { u16 ihs = skb_headlen(skb); @@ -135,7 +135,7 @@ static inline u16 mlx5e_get_inline_hdr_size(struct mlx5e_sq *sq, return skb_headlen(skb); } - return MLX5E_MIN_INLINE; + return max(skb_network_offset(skb), MLX5E_MIN_INLINE); } static inline void mlx5e_tx_skb_pull_inline(unsigned char **skb_data, -- cgit v0.10.2 From 7ccdd0841b305323e10e779c476d3fbae2165756 Mon Sep 17 00:00:00 2001 From: Rana Shahout Date: Thu, 30 Jun 2016 17:34:48 +0300 Subject: net/mlx5e: Fix select queue callback The default fallback function used by mlx5e select queue can return any TX queues in range [0..dev->num_real_tx_queues). The current implementation assumes that the fallback function returns a number in the range [0.. number of channels). Actually dev->num_real_tx_queues = (number of channels) * dev->num_tc; which is more than the expected range if num_tc is configured and could lead to crashes. To fix this we test if num_tc is not configured we can safely return the fallback suggestion, if not we will reciprocal_scale the fallback result and normalize it to the desired range. Fixes: 08fb1dacdd76 ('net/mlx5e: Support DCBNL IEEE ETS') Signed-off-by: Rana Shahout Signed-off-by: Saeed Mahameed Reported-by: Doug Ledford Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c index 103feab..216fe3e 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c @@ -1707,8 +1707,11 @@ static void mlx5e_netdev_set_tcs(struct net_device *netdev) netdev_set_num_tc(netdev, ntc); + /* Map netdev TCs to offset 0 + * We have our own UP to TXQ mapping for QoS + */ for (tc = 0; tc < ntc; tc++) - netdev_set_tc_queue(netdev, tc, nch, tc * nch); + netdev_set_tc_queue(netdev, tc, nch, 0); } int mlx5e_open_locked(struct net_device *netdev) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c b/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c index 42a5f06..5740b46 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c @@ -110,8 +110,20 @@ u16 mlx5e_select_queue(struct net_device *dev, struct sk_buff *skb, { struct mlx5e_priv *priv = netdev_priv(dev); int channel_ix = fallback(dev, skb); - int up = (netdev_get_num_tc(dev) && skb_vlan_tag_present(skb)) ? - skb->vlan_tci >> VLAN_PRIO_SHIFT : 0; + int up = 0; + + if (!netdev_get_num_tc(dev)) + return channel_ix; + + if (skb_vlan_tag_present(skb)) + up = skb->vlan_tci >> VLAN_PRIO_SHIFT; + + /* channel_ix can be larger than num_channels since + * dev->num_real_tx_queues = num_channels * num_tc + */ + if (channel_ix >= priv->params.num_channels) + channel_ix = reciprocal_scale(channel_ix, + priv->params.num_channels); return priv->channeltc_to_txq_map[channel_ix][up]; } -- cgit v0.10.2 From cdcf11212b22ff8e3de88ced1a6eda5bb950e120 Mon Sep 17 00:00:00 2001 From: Rana Shahout Date: Thu, 30 Jun 2016 17:34:49 +0300 Subject: net/mlx5e: Validate BW weight values of ETS Valid weight assigned to ETS TClass values are 1-100 Fixes: 08fb1dacdd76 ('net/mlx5e: Support DCBNL IEEE ETS') Signed-off-by: Rana Shahout Signed-off-by: Saeed Mahameed Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en.h b/drivers/net/ethernet/mellanox/mlx5/core/en.h index b429591..943b1bd 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/en.h @@ -145,7 +145,6 @@ struct mlx5e_umr_wqe { #ifdef CONFIG_MLX5_CORE_EN_DCB #define MLX5E_MAX_BW_ALLOC 100 /* Max percentage of BW allocation */ -#define MLX5E_MIN_BW_ALLOC 1 /* Min percentage of BW allocation */ #endif struct mlx5e_params { diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_dcbnl.c b/drivers/net/ethernet/mellanox/mlx5/core/en_dcbnl.c index b2db180..c585349 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_dcbnl.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_dcbnl.c @@ -96,7 +96,7 @@ static void mlx5e_build_tc_tx_bw(struct ieee_ets *ets, u8 *tc_tx_bw, tc_tx_bw[i] = MLX5E_MAX_BW_ALLOC; break; case IEEE_8021QAZ_TSA_ETS: - tc_tx_bw[i] = ets->tc_tx_bw[i] ?: MLX5E_MIN_BW_ALLOC; + tc_tx_bw[i] = ets->tc_tx_bw[i]; break; } } @@ -140,8 +140,12 @@ static int mlx5e_dbcnl_validate_ets(struct ieee_ets *ets) /* Validate Bandwidth Sum */ for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) { - if (ets->tc_tsa[i] == IEEE_8021QAZ_TSA_ETS) + if (ets->tc_tsa[i] == IEEE_8021QAZ_TSA_ETS) { + if (!ets->tc_tx_bw[i]) + return -EINVAL; + bw_sum += ets->tc_tx_bw[i]; + } } if (bw_sum != 0 && bw_sum != 100) -- cgit v0.10.2 From 87424ad52d76535234f217637fcaadcd2ef2334d Mon Sep 17 00:00:00 2001 From: Shaker Daibes Date: Thu, 30 Jun 2016 17:34:50 +0300 Subject: net/mlx5e: Log link state changes Add Link UP/Down prints to kernel log when link state changes Signed-off-by: Shaker Daibes Signed-off-by: Saeed Mahameed Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c index 216fe3e..7a0dca2 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c @@ -81,10 +81,13 @@ static void mlx5e_update_carrier(struct mlx5e_priv *priv) port_state = mlx5_query_vport_state(mdev, MLX5_QUERY_VPORT_STATE_IN_OP_MOD_VNIC_VPORT, 0); - if (port_state == VPORT_STATE_UP) + if (port_state == VPORT_STATE_UP) { + netdev_info(priv->netdev, "Link up\n"); netif_carrier_on(priv->netdev); - else + } else { + netdev_info(priv->netdev, "Link down\n"); netif_carrier_off(priv->netdev); + } } static void mlx5e_update_carrier_work(struct work_struct *work) -- cgit v0.10.2 From 6168f8ed01dc46a277908938294f1132d723f58d Mon Sep 17 00:00:00 2001 From: Wei Jiangang Date: Wed, 29 Jun 2016 12:51:50 +0800 Subject: timers/nohz: Fix several typos Signed-off-by: Wei Jiangang Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: fenghua.yu@intel.com Link: http://lkml.kernel.org/r/1467175910-2966-2-git-send-email-weijg.fnst@cn.fujitsu.com Signed-off-by: Ingo Molnar diff --git a/kernel/time/tick-sched.c b/kernel/time/tick-sched.c index 536ada8..6d83e9c 100644 --- a/kernel/time/tick-sched.c +++ b/kernel/time/tick-sched.c @@ -61,7 +61,7 @@ static void tick_do_update_jiffies64(ktime_t now) if (delta.tv64 < tick_period.tv64) return; - /* Reevalute with jiffies_lock held */ + /* Reevaluate with jiffies_lock held */ write_seqlock(&jiffies_lock); delta = ktime_sub(now, last_jiffies_update); @@ -117,7 +117,7 @@ static void tick_sched_do_timer(ktime_t now) /* * Check if the do_timer duty was dropped. We don't care about * concurrency: This happens only when the cpu in charge went - * into a long sleep. If two cpus happen to assign themself to + * into a long sleep. If two cpus happen to assign themselves to * this duty, then the jiffies update is still serialized by * jiffies_lock. */ @@ -571,7 +571,7 @@ static ktime_t tick_nohz_start_idle(struct tick_sched *ts) * @last_update_time: variable to store update time in. Do not update * counters if NULL. * - * Return the cummulative idle time (since boot) for a given + * Return the cumulative idle time (since boot) for a given * CPU, in microseconds. * * This time is measured via accounting rather than sampling, @@ -612,7 +612,7 @@ EXPORT_SYMBOL_GPL(get_cpu_idle_time_us); * @last_update_time: variable to store update time in. Do not update * counters if NULL. * - * Return the cummulative iowait time (since boot) for a given + * Return the cumulative iowait time (since boot) for a given * CPU, in microseconds. * * This time is measured via accounting rather than sampling, @@ -733,7 +733,7 @@ static ktime_t tick_nohz_stop_sched_tick(struct tick_sched *ts, * do_timer() never invoked. Keep track of the fact that it * was the one which had the do_timer() duty last. If this cpu * is the one which had the do_timer() duty last, we limit the - * sleep time to the timekeeping max_deferement value. + * sleep time to the timekeeping max_deferment value. * Otherwise we can sleep as long as we want. */ delta = timekeeping_max_deferment(); -- cgit v0.10.2 From 0de7611a1031f25b713fda7d36de44f17c2ed790 Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Fri, 1 Jul 2016 12:42:35 +0200 Subject: timers/nohz: Capitalize 'CPU' consistently While reviewing another patch I noticed that kernel/time/tick-sched.c had a charmingly (confusingly, annoyingly) rich set of variants for spelling 'CPU': cpu cpus CPU CPUs per CPU per-CPU per cpu ... sometimes these were mixed even within the same comment block! Compress these variants down to a single consistent set of: CPU CPUs per-CPU Cc: Frederic Weisbecker Cc: Thomas Gleixner Cc: Linus Torvalds Cc: Peter Zijlstra Cc: linux-kernel@vger.kernel.org Signed-off-by: Ingo Molnar diff --git a/kernel/time/tick-sched.c b/kernel/time/tick-sched.c index 6d83e9c..db57d1b 100644 --- a/kernel/time/tick-sched.c +++ b/kernel/time/tick-sched.c @@ -31,7 +31,7 @@ #include /* - * Per cpu nohz control structure + * Per-CPU nohz control structure */ static DEFINE_PER_CPU(struct tick_sched, tick_cpu_sched); @@ -116,8 +116,8 @@ static void tick_sched_do_timer(ktime_t now) #ifdef CONFIG_NO_HZ_COMMON /* * Check if the do_timer duty was dropped. We don't care about - * concurrency: This happens only when the cpu in charge went - * into a long sleep. If two cpus happen to assign themselves to + * concurrency: This happens only when the CPU in charge went + * into a long sleep. If two CPUs happen to assign themselves to * this duty, then the jiffies update is still serialized by * jiffies_lock. */ @@ -349,7 +349,7 @@ void tick_nohz_dep_clear_signal(struct signal_struct *sig, enum tick_dep_bits bi /* * Re-evaluate the need for the tick as we switch the current task. * It might need the tick due to per task/process properties: - * perf events, posix cpu timers, ... + * perf events, posix CPU timers, ... */ void __tick_nohz_task_switch(void) { @@ -509,8 +509,8 @@ int tick_nohz_tick_stopped(void) * * In case the sched_tick was stopped on this CPU, we have to check if jiffies * must be updated. Otherwise an interrupt handler could use a stale jiffy - * value. We do this unconditionally on any cpu, as we don't know whether the - * cpu, which has the update task assigned is in a long sleep. + * value. We do this unconditionally on any CPU, as we don't know whether the + * CPU, which has the update task assigned is in a long sleep. */ static void tick_nohz_update_jiffies(ktime_t now) { @@ -526,7 +526,7 @@ static void tick_nohz_update_jiffies(ktime_t now) } /* - * Updates the per cpu time idle statistics counters + * Updates the per-CPU time idle statistics counters */ static void update_ts_time_stats(int cpu, struct tick_sched *ts, ktime_t now, u64 *last_update_time) @@ -566,7 +566,7 @@ static ktime_t tick_nohz_start_idle(struct tick_sched *ts) } /** - * get_cpu_idle_time_us - get the total idle time of a cpu + * get_cpu_idle_time_us - get the total idle time of a CPU * @cpu: CPU number to query * @last_update_time: variable to store update time in. Do not update * counters if NULL. @@ -607,7 +607,7 @@ u64 get_cpu_idle_time_us(int cpu, u64 *last_update_time) EXPORT_SYMBOL_GPL(get_cpu_idle_time_us); /** - * get_cpu_iowait_time_us - get the total iowait time of a cpu + * get_cpu_iowait_time_us - get the total iowait time of a CPU * @cpu: CPU number to query * @last_update_time: variable to store update time in. Do not update * counters if NULL. @@ -726,12 +726,12 @@ static ktime_t tick_nohz_stop_sched_tick(struct tick_sched *ts, } /* - * If this cpu is the one which updates jiffies, then give up - * the assignment and let it be taken by the cpu which runs - * the tick timer next, which might be this cpu as well. If we + * If this CPU is the one which updates jiffies, then give up + * the assignment and let it be taken by the CPU which runs + * the tick timer next, which might be this CPU as well. If we * don't drop this here the jiffies might be stale and * do_timer() never invoked. Keep track of the fact that it - * was the one which had the do_timer() duty last. If this cpu + * was the one which had the do_timer() duty last. If this CPU * is the one which had the do_timer() duty last, we limit the * sleep time to the timekeeping max_deferment value. * Otherwise we can sleep as long as we want. @@ -841,9 +841,9 @@ static void tick_nohz_full_update_tick(struct tick_sched *ts) static bool can_stop_idle_tick(int cpu, struct tick_sched *ts) { /* - * If this cpu is offline and it is the one which updates + * If this CPU is offline and it is the one which updates * jiffies, then give up the assignment and let it be taken by - * the cpu which runs the tick timer next. If we don't drop + * the CPU which runs the tick timer next. If we don't drop * this here the jiffies might be stale and do_timer() never * invoked. */ @@ -933,11 +933,11 @@ void tick_nohz_idle_enter(void) WARN_ON_ONCE(irqs_disabled()); /* - * Update the idle state in the scheduler domain hierarchy - * when tick_nohz_stop_sched_tick() is called from the idle loop. - * State will be updated to busy during the first busy tick after - * exiting idle. - */ + * Update the idle state in the scheduler domain hierarchy + * when tick_nohz_stop_sched_tick() is called from the idle loop. + * State will be updated to busy during the first busy tick after + * exiting idle. + */ set_cpu_sd_state_idle(); local_irq_disable(); @@ -1211,7 +1211,7 @@ void tick_setup_sched_timer(void) hrtimer_init(&ts->sched_timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS); ts->sched_timer.function = tick_sched_timer; - /* Get the next period (per cpu) */ + /* Get the next period (per-CPU) */ hrtimer_set_expires(&ts->sched_timer, tick_init_jiffy_update()); /* Offset the tick to avert jiffies_lock contention. */ -- cgit v0.10.2 From 9cc1c73ad66610bffc80b691136ffc1e9a3b1a58 Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Sun, 24 Apr 2016 01:18:21 +0200 Subject: netfilter: conntrack: avoid integer overflow when resizing Can overflow so we might allocate very small table when bucket count is high on a 32bit platform. Note: resize is only possible from init_netns. Signed-off-by: Florian Westphal Signed-off-by: Pablo Neira Ayuso diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c index f204274..62c42e9 100644 --- a/net/netfilter/nf_conntrack_core.c +++ b/net/netfilter/nf_conntrack_core.c @@ -1601,8 +1601,15 @@ void *nf_ct_alloc_hashtable(unsigned int *sizep, int nulls) unsigned int nr_slots, i; size_t sz; + if (*sizep > (UINT_MAX / sizeof(struct hlist_nulls_head))) + return NULL; + BUILD_BUG_ON(sizeof(struct hlist_nulls_head) != sizeof(struct hlist_head)); nr_slots = *sizep = roundup(*sizep, PAGE_SIZE / sizeof(struct hlist_nulls_head)); + + if (nr_slots > (UINT_MAX / sizeof(struct hlist_nulls_head))) + return NULL; + sz = nr_slots * sizeof(struct hlist_nulls_head); hash = (void *)__get_free_pages(GFP_KERNEL | __GFP_NOWARN | __GFP_ZERO, get_order(sz)); -- cgit v0.10.2 From bc0622302f344551050995491b7d14176f39c628 Mon Sep 17 00:00:00 2001 From: Masami Hiramatsu Date: Fri, 1 Jul 2016 17:03:12 +0900 Subject: perf probe: Use cache entry if possible Before analyzing debuginfo, try to find a corresponding entry from probe cache always. This does not depend on --cache, the --cache enables to store/update cache, but looking up the cache is always enabled. Signed-off-by: Masami Hiramatsu Signed-off-by: Masami Hiramatsu Cc: Ananth N Mavinakayanahalli Cc: Brendan Gregg Cc: Hemant Kumar Cc: Namhyung Kim Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/146736019226.27797.16366402884098398857.stgit@devbox Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c index 55f41d5..47b6b8b 100644 --- a/tools/perf/util/probe-event.c +++ b/tools/perf/util/probe-event.c @@ -2474,17 +2474,24 @@ static int probe_trace_event__set_name(struct probe_trace_event *tev, char buf[64]; int ret; + /* If probe_event or trace_event already have the name, reuse it */ if (pev->event) event = pev->event; - else + else if (tev->event) + event = tev->event; + else { + /* Or generate new one from probe point */ if (pev->point.function && (strncmp(pev->point.function, "0x", 2) != 0) && !strisglob(pev->point.function)) event = pev->point.function; else event = tev->point.realname; + } if (pev->group) group = pev->group; + else if (tev->group) + group = tev->group; else group = PERFPROBE_GROUP; @@ -2531,7 +2538,7 @@ static int __add_probe_trace_events(struct perf_probe_event *pev, for (i = 0; i < ntevs; i++) { tev = &tevs[i]; /* Skip if the symbol is out of .text or blacklisted */ - if (!tev->point.symbol) + if (!tev->point.symbol && !pev->uprobes) continue; /* Set new name for tev (and update namelist) */ @@ -2844,6 +2851,55 @@ errout: bool __weak arch__prefers_symtab(void) { return false; } +static int find_probe_trace_events_from_cache(struct perf_probe_event *pev, + struct probe_trace_event **tevs) +{ + struct probe_cache *cache; + struct probe_cache_entry *entry; + struct probe_trace_event *tev; + struct str_node *node; + int ret, i; + + cache = probe_cache__new(pev->target); + if (!cache) + return 0; + + entry = probe_cache__find(cache, pev); + if (!entry) { + ret = 0; + goto out; + } + + ret = strlist__nr_entries(entry->tevlist); + if (ret > probe_conf.max_probes) { + pr_debug("Too many entries matched in the cache of %s\n", + pev->target ? : "kernel"); + ret = -E2BIG; + goto out; + } + + *tevs = zalloc(ret * sizeof(*tev)); + if (!*tevs) { + ret = -ENOMEM; + goto out; + } + + i = 0; + strlist__for_each_entry(node, entry->tevlist) { + tev = &(*tevs)[i++]; + ret = parse_probe_trace_command(node->s, tev); + if (ret < 0) + goto out; + /* Set the uprobes attribute as same as original */ + tev->uprobes = pev->uprobes; + } + ret = i; + +out: + probe_cache__delete(cache); + return ret; +} + static int convert_to_probe_trace_events(struct perf_probe_event *pev, struct probe_trace_event **tevs) { @@ -2866,6 +2922,11 @@ static int convert_to_probe_trace_events(struct perf_probe_event *pev, if (ret > 0) return ret; + /* At first, we need to lookup cache entry */ + ret = find_probe_trace_events_from_cache(pev, tevs); + if (ret > 0) + return ret; /* Found in probe cache */ + if (arch__prefers_symtab() && !perf_probe_event_need_dwarf(pev)) { ret = find_probe_trace_events_from_map(pev, tevs); if (ret > 0) diff --git a/tools/perf/util/probe-file.c b/tools/perf/util/probe-file.c index 1c12c1a..a94ee47 100644 --- a/tools/perf/util/probe-file.c +++ b/tools/perf/util/probe-file.c @@ -524,7 +524,7 @@ static bool streql(const char *a, const char *b) return !strcmp(a, b); } -static struct probe_cache_entry * +struct probe_cache_entry * probe_cache__find(struct probe_cache *pcache, struct perf_probe_event *pev) { struct probe_cache_entry *entry = NULL; @@ -548,6 +548,24 @@ found: return entry; } +struct probe_cache_entry * +probe_cache__find_by_name(struct probe_cache *pcache, + const char *group, const char *event) +{ + struct probe_cache_entry *entry = NULL; + + list_for_each_entry(entry, &pcache->entries, node) { + /* Hit if same event name or same command-string */ + if (streql(entry->pev.group, group) && + streql(entry->pev.event, event)) + goto found; + } + entry = NULL; + +found: + return entry; +} + int probe_cache__add_entry(struct probe_cache *pcache, struct perf_probe_event *pev, struct probe_trace_event *tevs, int ntevs) diff --git a/tools/perf/util/probe-file.h b/tools/perf/util/probe-file.h index d872e3d..910aa74 100644 --- a/tools/perf/util/probe-file.h +++ b/tools/perf/util/probe-file.h @@ -38,5 +38,8 @@ int probe_cache__add_entry(struct probe_cache *pcache, int probe_cache__commit(struct probe_cache *pcache); void probe_cache__purge(struct probe_cache *pcache); void probe_cache__delete(struct probe_cache *pcache); - +struct probe_cache_entry *probe_cache__find(struct probe_cache *pcache, + struct perf_probe_event *pev); +struct probe_cache_entry *probe_cache__find_by_name(struct probe_cache *pcache, + const char *group, const char *event); #endif -- cgit v0.10.2 From 1f3736c9c833e40ac4d3a8dc6d661e341df8a259 Mon Sep 17 00:00:00 2001 From: Masami Hiramatsu Date: Fri, 1 Jul 2016 17:03:26 +0900 Subject: perf probe: Show all cached probes perf probe --list shows all cached probes when --cache is given. Each caches are shown with on which binary that probed. E.g.: ----- # perf probe --cache vfs_read \$params # perf probe --cache -x /lib64/libc-2.17.so getaddrinfo \$params # perf probe --cache --list [kernel.kallsyms] (1466a0a250b5d0070c6d0f03c5fed30b237970a1): vfs_read $params /usr/lib64/libc-2.17.so (c31ffe7942bfd77b2fca8f9bd5709d387a86d3bc): getaddrinfo $params ----- Note that $params requires debuginfo. Signed-off-by: Masami Hiramatsu Signed-off-by: Masami Hiramatsu Tested-by: Arnaldo Carvalho de Melo Cc: Ananth N Mavinakayanahalli Cc: Brendan Gregg Cc: Hemant Kumar Cc: Namhyung Kim Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/146736020674.27797.13488316780383460180.stgit@devbox Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/Documentation/perf-probe.txt b/tools/perf/Documentation/perf-probe.txt index 947db6f..5a70d45 100644 --- a/tools/perf/Documentation/perf-probe.txt +++ b/tools/perf/Documentation/perf-probe.txt @@ -67,7 +67,10 @@ OPTIONS -l:: --list[=[GROUP:]EVENT]:: - List up current probe events. This can also accept filtering patterns of event names. + List up current probe events. This can also accept filtering patterns of + event names. + When this is used with --cache, perf shows all cached probes instead of + the live probes. -L:: --line=:: @@ -110,8 +113,9 @@ OPTIONS adding and removal operations. --cache:: - Cache the probes (with --add option). Any events which successfully added + (With --add) Cache the probes. Any events which successfully added are also stored in the cache file. + (With --list) Show cached probes. --max-probes=NUM:: Set the maximum number of probe points for an event. Default is 128. diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c index 3426232..0bb9084 100644 --- a/tools/perf/builtin-probe.c +++ b/tools/perf/builtin-probe.c @@ -44,7 +44,7 @@ #define DEFAULT_VAR_FILTER "!__k???tab_* & !__crc_*" #define DEFAULT_FUNC_FILTER "!_*" -#define DEFAULT_LIST_FILTER "*:*" +#define DEFAULT_LIST_FILTER "*" /* Session management structure */ static struct { diff --git a/tools/perf/util/build-id.c b/tools/perf/util/build-id.c index 62b1473..1c49620 100644 --- a/tools/perf/util/build-id.c +++ b/tools/perf/util/build-id.c @@ -165,8 +165,7 @@ retry: return NULL; } -static char *build_id_cache__linkname(const char *sbuild_id, char *bf, - size_t size) +char *build_id_cache__linkname(const char *sbuild_id, char *bf, size_t size) { char *tmp = bf; int ret = asnprintf(&bf, size, "%s/.build-id/%.2s/%s", buildid_dir, @@ -176,6 +175,36 @@ static char *build_id_cache__linkname(const char *sbuild_id, char *bf, return bf; } +char *build_id_cache__origname(const char *sbuild_id) +{ + char *linkname; + char buf[PATH_MAX]; + char *ret = NULL, *p; + size_t offs = 5; /* == strlen("../..") */ + + linkname = build_id_cache__linkname(sbuild_id, NULL, 0); + if (!linkname) + return NULL; + + if (readlink(linkname, buf, PATH_MAX) < 0) + goto out; + /* The link should be "../../" */ + p = strrchr(buf, '/'); /* Cut off the "/" */ + if (p && (p > buf + offs)) { + *p = '\0'; + if (buf[offs + 1] == '[') + offs++; /* + * This is a DSO name, like [kernel.kallsyms]. + * Skip the first '/', since this is not the + * cache of a regular file. + */ + ret = strdup(buf + offs); /* Skip "../..[/]" */ + } +out: + free(linkname); + return ret; +} + static const char *build_id_cache__basename(bool is_kallsyms, bool is_vdso) { return is_kallsyms ? "kallsyms" : (is_vdso ? "vdso" : "elf"); @@ -387,6 +416,81 @@ void disable_buildid_cache(void) no_buildid_cache = true; } +static bool lsdir_bid_head_filter(const char *name __maybe_unused, + struct dirent *d __maybe_unused) +{ + return (strlen(d->d_name) == 2) && + isxdigit(d->d_name[0]) && isxdigit(d->d_name[1]); +} + +static bool lsdir_bid_tail_filter(const char *name __maybe_unused, + struct dirent *d __maybe_unused) +{ + int i = 0; + while (isxdigit(d->d_name[i]) && i < SBUILD_ID_SIZE - 3) + i++; + return (i == SBUILD_ID_SIZE - 3) && (d->d_name[i] == '\0'); +} + +struct strlist *build_id_cache__list_all(void) +{ + struct strlist *toplist, *linklist = NULL, *bidlist; + struct str_node *nd, *nd2; + char *topdir, *linkdir = NULL; + char sbuild_id[SBUILD_ID_SIZE]; + + /* Open the top-level directory */ + if (asprintf(&topdir, "%s/.build-id/", buildid_dir) < 0) + return NULL; + + bidlist = strlist__new(NULL, NULL); + if (!bidlist) + goto out; + + toplist = lsdir(topdir, lsdir_bid_head_filter); + if (!toplist) { + pr_debug("Error in lsdir(%s): %d\n", topdir, errno); + /* If there is no buildid cache, return an empty list */ + if (errno == ENOENT) + goto out; + goto err_out; + } + + strlist__for_each_entry(nd, toplist) { + if (asprintf(&linkdir, "%s/%s", topdir, nd->s) < 0) + goto err_out; + /* Open the lower-level directory */ + linklist = lsdir(linkdir, lsdir_bid_tail_filter); + if (!linklist) { + pr_debug("Error in lsdir(%s): %d\n", linkdir, errno); + goto err_out; + } + strlist__for_each_entry(nd2, linklist) { + if (snprintf(sbuild_id, SBUILD_ID_SIZE, "%s%s", + nd->s, nd2->s) != SBUILD_ID_SIZE - 1) + goto err_out; + if (strlist__add(bidlist, sbuild_id) < 0) + goto err_out; + } + strlist__delete(linklist); + zfree(&linkdir); + } + +out_free: + strlist__delete(toplist); +out: + free(topdir); + + return bidlist; + +err_out: + strlist__delete(linklist); + zfree(&linkdir); + strlist__delete(bidlist); + bidlist = NULL; + goto out_free; +} + char *build_id_cache__cachedir(const char *sbuild_id, const char *name, bool is_kallsyms, bool is_vdso) { diff --git a/tools/perf/util/build-id.h b/tools/perf/util/build-id.h index d8c7f2f..b742e27 100644 --- a/tools/perf/util/build-id.h +++ b/tools/perf/util/build-id.h @@ -30,8 +30,11 @@ bool perf_session__read_build_ids(struct perf_session *session, bool with_hits); int perf_session__write_buildid_table(struct perf_session *session, int fd); int perf_session__cache_build_ids(struct perf_session *session); +char *build_id_cache__origname(const char *sbuild_id); +char *build_id_cache__linkname(const char *sbuild_id, char *bf, size_t size); char *build_id_cache__cachedir(const char *sbuild_id, const char *name, bool is_kallsyms, bool is_vdso); +struct strlist *build_id_cache__list_all(void); int build_id_cache__list_build_ids(const char *pathname, struct strlist **result); bool build_id_cache__cached(const char *sbuild_id); diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c index 47b6b8b..f81b5dd 100644 --- a/tools/perf/util/probe-event.c +++ b/tools/perf/util/probe-event.c @@ -2366,6 +2366,9 @@ int show_perf_probe_events(struct strfilter *filter) setup_pager(); + if (probe_conf.cache) + return probe_cache__show_all_caches(filter); + ret = init_probe_symbol_maps(false); if (ret < 0) return ret; diff --git a/tools/perf/util/probe-file.c b/tools/perf/util/probe-file.c index a94ee47..156e3d8 100644 --- a/tools/perf/util/probe-file.c +++ b/tools/perf/util/probe-file.c @@ -367,10 +367,17 @@ static int probe_cache__open(struct probe_cache *pcache, const char *target) { char cpath[PATH_MAX]; char sbuildid[SBUILD_ID_SIZE]; - char *dir_name; + char *dir_name = NULL; bool is_kallsyms = !target; int ret, fd; + if (target && build_id_cache__cached(target)) { + /* This is a cached buildid */ + strncpy(sbuildid, target, SBUILD_ID_SIZE); + dir_name = build_id_cache__linkname(sbuildid, NULL, 0); + goto found; + } + if (target) ret = filename__sprintf_build_id(target, sbuildid); else { @@ -394,8 +401,11 @@ static int probe_cache__open(struct probe_cache *pcache, const char *target) dir_name = build_id_cache__cachedir(sbuildid, target, is_kallsyms, false); - if (!dir_name) +found: + if (!dir_name) { + pr_debug("Failed to get cache from %s\n", target); return -ENOMEM; + } snprintf(cpath, PATH_MAX, "%s/probes", dir_name); fd = open(cpath, O_CREAT | O_RDWR, 0644); @@ -673,3 +683,55 @@ int probe_cache__commit(struct probe_cache *pcache) out: return ret; } + +static int probe_cache__show_entries(struct probe_cache *pcache, + struct strfilter *filter) +{ + struct probe_cache_entry *entry; + char buf[128], *ptr; + + list_for_each_entry(entry, &pcache->entries, node) { + if (entry->pev.event) { + ptr = buf; + snprintf(buf, 128, "%s:%s", + entry->pev.group, entry->pev.event); + } else + ptr = entry->spev; + if (strfilter__compare(filter, ptr)) + printf("%s\n", entry->spev); + } + return 0; +} + +/* Show all cached probes */ +int probe_cache__show_all_caches(struct strfilter *filter) +{ + struct probe_cache *pcache; + struct strlist *bidlist; + struct str_node *nd; + char *buf = strfilter__string(filter); + + pr_debug("list cache with filter: %s\n", buf); + free(buf); + + bidlist = build_id_cache__list_all(); + if (!bidlist) { + pr_debug("Failed to get buildids: %d\n", errno); + return -EINVAL; + } + strlist__for_each_entry(nd, bidlist) { + pcache = probe_cache__new(nd->s); + if (!pcache) + continue; + if (!list_empty(&pcache->entries)) { + buf = build_id_cache__origname(nd->s); + printf("%s (%s):\n", buf, nd->s); + free(buf); + probe_cache__show_entries(pcache, filter); + } + probe_cache__delete(pcache); + } + strlist__delete(bidlist); + + return 0; +} diff --git a/tools/perf/util/probe-file.h b/tools/perf/util/probe-file.h index 910aa74..0009b8a 100644 --- a/tools/perf/util/probe-file.h +++ b/tools/perf/util/probe-file.h @@ -42,4 +42,5 @@ struct probe_cache_entry *probe_cache__find(struct probe_cache *pcache, struct perf_probe_event *pev); struct probe_cache_entry *probe_cache__find_by_name(struct probe_cache *pcache, const char *group, const char *event); +int probe_cache__show_all_caches(struct strfilter *filter); #endif -- cgit v0.10.2 From 4a0f65c102ec3a718b4a0b90981232b6cb019477 Mon Sep 17 00:00:00 2001 From: Masami Hiramatsu Date: Fri, 1 Jul 2016 17:03:36 +0900 Subject: perf probe: Remove caches when --cache is given 'perf probe --del' removes caches when '--cache' is given. Note that the delete pattern is not the same as for normal events. If you cached probes with event name, --del "eventname" works as expected. However, if you skipped it, the cached probes doesn't have actual event name. In that case --del "probe-desc" is required (wildcard is acceptable). For example a cache entry has the probe-desc "vfs_read $params", you can remove it with --del 'vfs_read*'. ----- # perf probe --cache --list /[kernel.kallsyms] (1466a0a250b5d0070c6d0f03c5fed30b237970a1): vfs_read $params /usr/lib64/libc-2.17.so (c31ffe7942bfd77b2fca8f9bd5709d387a86d3bc): getaddrinfo $params # perf probe --cache --del vfs_read\* Removed cached event: probe:vfs_read # perf probe --cache --list /[kernel.kallsyms] (1466a0a250b5d0070c6d0f03c5fed30b237970a1): /usr/lib64/libc-2.17.so (c31ffe7942bfd77b2fca8f9bd5709d387a86d3bc): getaddrinfo $params ----- Signed-off-by: Masami Hiramatsu Signed-off-by: Masami Hiramatsu Tested-by: Arnaldo Carvalho de Melo Cc: Ananth N Mavinakayanahalli Cc: Brendan Gregg Cc: Hemant Kumar Cc: Namhyung Kim Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/146736021651.27797.10250879847070772920.stgit@devbox Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/Documentation/perf-probe.txt b/tools/perf/Documentation/perf-probe.txt index 5a70d45..8d09173 100644 --- a/tools/perf/Documentation/perf-probe.txt +++ b/tools/perf/Documentation/perf-probe.txt @@ -116,6 +116,7 @@ OPTIONS (With --add) Cache the probes. Any events which successfully added are also stored in the cache file. (With --list) Show cached probes. + (With --del) Remove cached probes. --max-probes=NUM:: Set the maximum number of probe points for an event. Default is 128. diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c index 0bb9084..a1a5cd1 100644 --- a/tools/perf/builtin-probe.c +++ b/tools/perf/builtin-probe.c @@ -363,6 +363,32 @@ out_cleanup: return ret; } +static int del_perf_probe_caches(struct strfilter *filter) +{ + struct probe_cache *cache; + struct strlist *bidlist; + struct str_node *nd; + int ret; + + bidlist = build_id_cache__list_all(); + if (!bidlist) { + ret = -errno; + pr_debug("Failed to get buildids: %d\n", ret); + return ret ?: -ENOMEM; + } + + strlist__for_each_entry(nd, bidlist) { + cache = probe_cache__new(nd->s); + if (!cache) + continue; + if (probe_cache__filter_purge(cache, filter) < 0 || + probe_cache__commit(cache) < 0) + pr_warning("Failed to remove entries for %s\n", nd->s); + probe_cache__delete(cache); + } + return 0; +} + static int perf_del_probe_events(struct strfilter *filter) { int ret, ret2, ufd = -1, kfd = -1; @@ -375,6 +401,9 @@ static int perf_del_probe_events(struct strfilter *filter) pr_debug("Delete filter: \'%s\'\n", str); + if (probe_conf.cache) + return del_perf_probe_caches(filter); + /* Get current event names */ ret = probe_file__open_both(&kfd, &ufd, PF_FL_RW); if (ret < 0) diff --git a/tools/perf/util/probe-file.c b/tools/perf/util/probe-file.c index 156e3d8..6cb6ec0 100644 --- a/tools/perf/util/probe-file.c +++ b/tools/perf/util/probe-file.c @@ -684,20 +684,40 @@ out: return ret; } +static bool probe_cache_entry__compare(struct probe_cache_entry *entry, + struct strfilter *filter) +{ + char buf[128], *ptr = entry->spev; + + if (entry->pev.event) { + snprintf(buf, 128, "%s:%s", entry->pev.group, entry->pev.event); + ptr = buf; + } + return strfilter__compare(filter, ptr); +} + +int probe_cache__filter_purge(struct probe_cache *pcache, + struct strfilter *filter) +{ + struct probe_cache_entry *entry, *tmp; + + list_for_each_entry_safe(entry, tmp, &pcache->entries, node) { + if (probe_cache_entry__compare(entry, filter)) { + pr_info("Removed cached event: %s\n", entry->spev); + list_del_init(&entry->node); + probe_cache_entry__delete(entry); + } + } + return 0; +} + static int probe_cache__show_entries(struct probe_cache *pcache, struct strfilter *filter) { struct probe_cache_entry *entry; - char buf[128], *ptr; list_for_each_entry(entry, &pcache->entries, node) { - if (entry->pev.event) { - ptr = buf; - snprintf(buf, 128, "%s:%s", - entry->pev.group, entry->pev.event); - } else - ptr = entry->spev; - if (strfilter__compare(filter, ptr)) + if (probe_cache_entry__compare(entry, filter)) printf("%s\n", entry->spev); } return 0; diff --git a/tools/perf/util/probe-file.h b/tools/perf/util/probe-file.h index 0009b8a..0ed1fc5 100644 --- a/tools/perf/util/probe-file.h +++ b/tools/perf/util/probe-file.h @@ -38,6 +38,8 @@ int probe_cache__add_entry(struct probe_cache *pcache, int probe_cache__commit(struct probe_cache *pcache); void probe_cache__purge(struct probe_cache *pcache); void probe_cache__delete(struct probe_cache *pcache); +int probe_cache__filter_purge(struct probe_cache *pcache, + struct strfilter *filter); struct probe_cache_entry *probe_cache__find(struct probe_cache *pcache, struct perf_probe_event *pev); struct probe_cache_entry *probe_cache__find_by_name(struct probe_cache *pcache, -- cgit v0.10.2 From 8ba8682107ee2ca3347354e018865d8e1967c5f4 Mon Sep 17 00:00:00 2001 From: Omar Sandoval Date: Fri, 1 Jul 2016 00:39:35 -0700 Subject: block: fix use-after-free in sys_ioprio_get() get_task_ioprio() accesses the task->io_context without holding the task lock and thus can race with exit_io_context(), leading to a use-after-free. The reproducer below hits this within a few seconds on my 4-core QEMU VM: #define _GNU_SOURCE #include #include #include #include int main(int argc, char **argv) { pid_t pid, child; long nproc, i; /* ioprio_set(IOPRIO_WHO_PROCESS, 0, IOPRIO_PRIO_VALUE(IOPRIO_CLASS_IDLE, 0)); */ syscall(SYS_ioprio_set, 1, 0, 0x6000); nproc = sysconf(_SC_NPROCESSORS_ONLN); for (i = 0; i < nproc; i++) { pid = fork(); assert(pid != -1); if (pid == 0) { for (;;) { pid = fork(); assert(pid != -1); if (pid == 0) { _exit(0); } else { child = wait(NULL); assert(child == pid); } } } pid = fork(); assert(pid != -1); if (pid == 0) { for (;;) { /* ioprio_get(IOPRIO_WHO_PGRP, 0); */ syscall(SYS_ioprio_get, 2, 0); } } } for (;;) { /* ioprio_get(IOPRIO_WHO_PGRP, 0); */ syscall(SYS_ioprio_get, 2, 0); } return 0; } This gets us KASAN dumps like this: [ 35.526914] ================================================================== [ 35.530009] BUG: KASAN: out-of-bounds in get_task_ioprio+0x7b/0x90 at addr ffff880066f34e6c [ 35.530009] Read of size 2 by task ioprio-gpf/363 [ 35.530009] ============================================================================= [ 35.530009] BUG blkdev_ioc (Not tainted): kasan: bad access detected [ 35.530009] ----------------------------------------------------------------------------- [ 35.530009] Disabling lock debugging due to kernel taint [ 35.530009] INFO: Allocated in create_task_io_context+0x2b/0x370 age=0 cpu=0 pid=360 [ 35.530009] ___slab_alloc+0x55d/0x5a0 [ 35.530009] __slab_alloc.isra.20+0x2b/0x40 [ 35.530009] kmem_cache_alloc_node+0x84/0x200 [ 35.530009] create_task_io_context+0x2b/0x370 [ 35.530009] get_task_io_context+0x92/0xb0 [ 35.530009] copy_process.part.8+0x5029/0x5660 [ 35.530009] _do_fork+0x155/0x7e0 [ 35.530009] SyS_clone+0x19/0x20 [ 35.530009] do_syscall_64+0x195/0x3a0 [ 35.530009] return_from_SYSCALL_64+0x0/0x6a [ 35.530009] INFO: Freed in put_io_context+0xe7/0x120 age=0 cpu=0 pid=1060 [ 35.530009] __slab_free+0x27b/0x3d0 [ 35.530009] kmem_cache_free+0x1fb/0x220 [ 35.530009] put_io_context+0xe7/0x120 [ 35.530009] put_io_context_active+0x238/0x380 [ 35.530009] exit_io_context+0x66/0x80 [ 35.530009] do_exit+0x158e/0x2b90 [ 35.530009] do_group_exit+0xe5/0x2b0 [ 35.530009] SyS_exit_group+0x1d/0x20 [ 35.530009] entry_SYSCALL_64_fastpath+0x1a/0xa4 [ 35.530009] INFO: Slab 0xffffea00019bcd00 objects=20 used=4 fp=0xffff880066f34ff0 flags=0x1fffe0000004080 [ 35.530009] INFO: Object 0xffff880066f34e58 @offset=3672 fp=0x0000000000000001 [ 35.530009] ================================================================== Fix it by grabbing the task lock while we poke at the io_context. Cc: stable@vger.kernel.org Reported-by: Dmitry Vyukov Signed-off-by: Omar Sandoval Signed-off-by: Jens Axboe diff --git a/block/ioprio.c b/block/ioprio.c index cc7800e..01b8116 100644 --- a/block/ioprio.c +++ b/block/ioprio.c @@ -150,8 +150,10 @@ static int get_task_ioprio(struct task_struct *p) if (ret) goto out; ret = IOPRIO_PRIO_VALUE(IOPRIO_CLASS_NONE, IOPRIO_NORM); + task_lock(p); if (p->io_context) ret = p->io_context->ioprio; + task_unlock(p); out: return ret; } -- cgit v0.10.2 From f76a28a69a103b8789d2430a193af558f4c85364 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Thu, 30 Jun 2016 14:26:17 +0200 Subject: xhci: free the correct ring gcc warns about what first looks like a reference to an uninitialized variable: drivers/usb/host/xhci-ring.c: In function 'handle_cmd_completion': drivers/usb/host/xhci-ring.c:753:4: error: 'ep_ring' may be used uninitialized in this function [-Werror=maybe-uninitialized] xhci_unmap_td_bounce_buffer(xhci, ep_ring, cur_td); ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ drivers/usb/host/xhci-ring.c:647:20: note: 'ep_ring' was declared here struct xhci_ring *ep_ring; ^~~~~~~ It's clear to see that the list_empty() check means it can never be uninitialized, however it still looks wrong: When ep->cancelled_td_list contains more than one entry, the ep_ring variable will point to the ring that was retrieved from the last urb, and we have to look it up again in the second loop instead, which fixes the behavior and gets rid of the warning too. Signed-off-by: Arnd Bergmann Fixes: f9c589e142d0 ("xhci: TD-fragment, align the unsplittable case with a bounce buffer") Acked-by: Mathias Nyman Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index 21e1dd6..918e0c7 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -749,6 +749,7 @@ remove_finished_td: /* Doesn't matter what we pass for status, since the core will * just overwrite it (because the URB has been unlinked). */ + ep_ring = xhci_urb_to_transfer_ring(xhci, cur_td->urb); if (ep_ring && cur_td->bounce_seg) xhci_unmap_td_bounce_buffer(xhci, ep_ring, cur_td); xhci_giveback_urb_in_irq(xhci, cur_td, 0); -- cgit v0.10.2 From 322832f2f19e04c866a0ce4bdac8cff8e695f2b3 Mon Sep 17 00:00:00 2001 From: Roger Quadros Date: Thu, 30 Jun 2016 14:54:17 +0300 Subject: usb: dwc3: host: Fix broken XHCI host Looks like we lost all changes related to commit 9522def40065 ("usb: dwc3: core: cleanup IRQ resources") in host.c when Felipe's next branch was merged into Greg's next branch. Fixes 215db948181 ("Merge tag 'usb-for-v4.8' of git://git.kernel.org/pub/scm/linux/kernel/git/balbi/usb into usb-next") Signed-off-by: Roger Quadros Acked-by: Felipe Balbi Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/dwc3/host.c b/drivers/usb/dwc3/host.c index 67f90d7..f6533c6 100644 --- a/drivers/usb/dwc3/host.c +++ b/drivers/usb/dwc3/host.c @@ -23,7 +23,48 @@ int dwc3_host_init(struct dwc3 *dwc) { struct property_entry props[2]; struct platform_device *xhci; - int ret; + int ret, irq; + struct resource *res; + struct platform_device *dwc3_pdev = to_platform_device(dwc->dev); + + irq = platform_get_irq_byname(dwc3_pdev, "host"); + if (irq == -EPROBE_DEFER) + return irq; + + if (irq <= 0) { + irq = platform_get_irq_byname(dwc3_pdev, "dwc_usb3"); + if (irq == -EPROBE_DEFER) + return irq; + + if (irq <= 0) { + irq = platform_get_irq(dwc3_pdev, 0); + if (irq <= 0) { + if (irq != -EPROBE_DEFER) { + dev_err(dwc->dev, + "missing host IRQ\n"); + } + if (!irq) + irq = -EINVAL; + return irq; + } else { + res = platform_get_resource(dwc3_pdev, + IORESOURCE_IRQ, 0); + } + } else { + res = platform_get_resource_byname(dwc3_pdev, + IORESOURCE_IRQ, + "dwc_usb3"); + } + + } else { + res = platform_get_resource_byname(dwc3_pdev, IORESOURCE_IRQ, + "host"); + } + + dwc->xhci_resources[1].start = irq; + dwc->xhci_resources[1].end = irq; + dwc->xhci_resources[1].flags = res->flags; + dwc->xhci_resources[1].name = res->name; xhci = platform_device_alloc("xhci-hcd", PLATFORM_DEVID_AUTO); if (!xhci) { -- cgit v0.10.2 From a9cd9c044aa90ba2b31d1bf3e3432f38fb1d25fe Mon Sep 17 00:00:00 2001 From: Sinclair Yeh Date: Wed, 29 Jun 2016 16:31:01 -0700 Subject: drm/vmwgfx: Add a check to handle host message failure Discovered by static code analysis tool. If for some reason communication with the host fails more than preset number of retries, return an error instead of return garbage. Signed-off-by: Sinclair Yeh Reviewed-by: Charmaine Lee Reported-by: Dan Carpenter diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_msg.c b/drivers/gpu/drm/vmwgfx/vmwgfx_msg.c index f0374f9..e57a0ba 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_msg.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_msg.c @@ -300,6 +300,9 @@ static int vmw_recv_msg(struct rpc_channel *channel, void **msg, break; } + if (retries == RETRIES) + return -EINVAL; + *msg_len = reply_len; *msg = reply; -- cgit v0.10.2 From 7c20d213dd3cd6295bf9162730e7a368af957854 Mon Sep 17 00:00:00 2001 From: Sinclair Yeh Date: Wed, 29 Jun 2016 11:29:47 -0700 Subject: drm/vmwgfx: Work around mode set failure in 2D VMs In a low-memory 2D VM, fbdev can take up a large percentage of available memory, making them unavailable for other DRM clients. Since we do not take fbdev into account when filtering modes, we end up claiming to support more modes than we actually do. As a result, users get a black screen when setting a mode too large for current available memory. In a low-memory VM configuration, users can get a black screen for a mode as low as 1024x768. The current mode filtering mechanism keys off of SVGA_REG_SUGGESTED_GBOBJECT_MEM_SIZE_KB, i.e. the maximum amount of surface memory we have. Since this value is a performance suggestion, not a hard limit, and since there should not be much of a performance impact for a 2D VM, rather than filtering out more modes, we will just allow ourselves to exceed the SVGA's performance suggestion. Also changed assumed bpp to 32 from 16 to make sure we can actually support all the modes listed. Signed-off-by: Sinclair Yeh Reviewed-by: Thomas Hellstrom Cc: diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c index 9fcd820..fc9ad00 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c @@ -706,6 +706,13 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset) vmw_read(dev_priv, SVGA_REG_SUGGESTED_GBOBJECT_MEM_SIZE_KB); + /* + * Workaround for low memory 2D VMs to compensate for the + * allocation taken by fbdev + */ + if (!(dev_priv->capabilities & SVGA_CAP_3D)) + mem_size *= 2; + dev_priv->max_mob_pages = mem_size * 1024 / PAGE_SIZE; dev_priv->prim_bb_mem = vmw_read(dev_priv, diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c index 55231cc..077f16d 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c @@ -1553,14 +1553,7 @@ int vmw_du_connector_fill_modes(struct drm_connector *connector, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) }; int i; - u32 assumed_bpp = 2; - - /* - * If using screen objects, then assume 32-bpp because that's what the - * SVGA device is assuming - */ - if (dev_priv->active_display_unit == vmw_du_screen_object) - assumed_bpp = 4; + u32 assumed_bpp = 4; if (dev_priv->active_display_unit == vmw_du_screen_target) { max_width = min(max_width, dev_priv->stdu_max_width); -- cgit v0.10.2 From 04319d89fbec72dfd60738003c3813b97c1d5f5a Mon Sep 17 00:00:00 2001 From: Sinclair Yeh Date: Wed, 29 Jun 2016 12:15:48 -0700 Subject: drm/vmwgfx: Add an option to change assumed FB bpp Offer an option for advanced users who want larger modes at 16bpp. This becomes necessary after the fix: "Work around mode set failure in 2D VMs." Without this patch, there would be no way for existing advanced users to get to a high res mode, and the regression is they will likely get a black screen after a software update on their current VM. Signed-off-by: Sinclair Yeh Reviewed-by: Thomas Hellstrom Cc: diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c index fc9ad00..8d528fc 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c @@ -233,6 +233,7 @@ static int vmw_force_iommu; static int vmw_restrict_iommu; static int vmw_force_coherent; static int vmw_restrict_dma_mask; +static int vmw_assume_16bpp; static int vmw_probe(struct pci_dev *, const struct pci_device_id *); static void vmw_master_init(struct vmw_master *); @@ -249,6 +250,8 @@ MODULE_PARM_DESC(force_coherent, "Force coherent TTM pages"); module_param_named(force_coherent, vmw_force_coherent, int, 0600); MODULE_PARM_DESC(restrict_dma_mask, "Restrict DMA mask to 44 bits with IOMMU"); module_param_named(restrict_dma_mask, vmw_restrict_dma_mask, int, 0600); +MODULE_PARM_DESC(assume_16bpp, "Assume 16-bpp when filtering modes"); +module_param_named(assume_16bpp, vmw_assume_16bpp, int, 0600); static void vmw_print_capabilities(uint32_t capabilities) @@ -660,6 +663,8 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset) dev_priv->vram_start = pci_resource_start(dev->pdev, 1); dev_priv->mmio_start = pci_resource_start(dev->pdev, 2); + dev_priv->assume_16bpp = !!vmw_assume_16bpp; + dev_priv->enable_fb = enable_fbdev; vmw_write(dev_priv, SVGA_REG_ID, SVGA_ID_2); diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h index 1980e2a..89fb194 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h @@ -386,6 +386,7 @@ struct vmw_private { spinlock_t hw_lock; spinlock_t cap_lock; bool has_dx; + bool assume_16bpp; /* * VGA registers. diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c index 077f16d..e29da45 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c @@ -1555,6 +1555,9 @@ int vmw_du_connector_fill_modes(struct drm_connector *connector, int i; u32 assumed_bpp = 4; + if (dev_priv->assume_16bpp) + assumed_bpp = 2; + if (dev_priv->active_display_unit == vmw_du_screen_target) { max_width = min(max_width, dev_priv->stdu_max_width); max_height = min(max_height, dev_priv->stdu_max_height); -- cgit v0.10.2 From 94477bff390aa4612d2332c8abafaae0a13d6923 Mon Sep 17 00:00:00 2001 From: Sinclair Yeh Date: Wed, 29 Jun 2016 12:58:49 -0700 Subject: drm/ttm: Make ttm_bo_mem_compat available There are cases where it is desired to see if a proposed placement is compatible with a buffer object before calling ttm_bo_validate(). Signed-off-by: Sinclair Yeh Reviewed-by: Thomas Hellstrom Cc: --- This is the first of a 3-patch series to fix a black screen issue observed on Ubuntu 16.04 server. diff --git a/drivers/gpu/drm/ttm/ttm_bo.c b/drivers/gpu/drm/ttm/ttm_bo.c index 39386f5..a71cf98 100644 --- a/drivers/gpu/drm/ttm/ttm_bo.c +++ b/drivers/gpu/drm/ttm/ttm_bo.c @@ -1034,9 +1034,9 @@ out_unlock: return ret; } -static bool ttm_bo_mem_compat(struct ttm_placement *placement, - struct ttm_mem_reg *mem, - uint32_t *new_flags) +bool ttm_bo_mem_compat(struct ttm_placement *placement, + struct ttm_mem_reg *mem, + uint32_t *new_flags) { int i; @@ -1068,6 +1068,7 @@ static bool ttm_bo_mem_compat(struct ttm_placement *placement, return false; } +EXPORT_SYMBOL(ttm_bo_mem_compat); int ttm_bo_validate(struct ttm_buffer_object *bo, struct ttm_placement *placement, diff --git a/include/drm/ttm/ttm_bo_api.h b/include/drm/ttm/ttm_bo_api.h index c801d90..4cecb0b 100644 --- a/include/drm/ttm/ttm_bo_api.h +++ b/include/drm/ttm/ttm_bo_api.h @@ -316,6 +316,20 @@ ttm_bo_reference(struct ttm_buffer_object *bo) */ extern int ttm_bo_wait(struct ttm_buffer_object *bo, bool interruptible, bool no_wait); + +/** + * ttm_bo_mem_compat - Check if proposed placement is compatible with a bo + * + * @placement: Return immediately if buffer is busy. + * @mem: The struct ttm_mem_reg indicating the region where the bo resides + * @new_flags: Describes compatible placement found + * + * Returns true if the placement is compatible + */ +extern bool ttm_bo_mem_compat(struct ttm_placement *placement, + struct ttm_mem_reg *mem, + uint32_t *new_flags); + /** * ttm_bo_validate * -- cgit v0.10.2 From 4ed7e2242b637bc4af0416e4aa9f945db30fb44a Mon Sep 17 00:00:00 2001 From: Sinclair Yeh Date: Wed, 29 Jun 2016 13:20:26 -0700 Subject: drm/vmwgfx: Check pin count before attempting to move a buffer In certain scenarios, e.g. when fbdev is enabled, we can get into a situation where a vmw_framebuffer_pin() is called on a buffer that is already pinned. When this happens, ttm_bo_validate() will unintentially remove the TTM_PL_FLAG_NO_EVICT flag, thus unpinning it, and leaving no way to actually pin the buffer again. To prevent this, if a buffer is already pinned, then instead of calling ttm_bo_validate(), just make sure the proposed placement is compatible with the existing placement. Signed-off-by: Sinclair Yeh Reviewed-by: Thomas Hellstrom Cc: --- This is the 2nd patch in a 3-patch series to fix a console black screen issue on Ubuntu 16.04 server. This fixes a BUG_ON() condition where a pinned buffer gets accidentally put onto the LRU list. diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_dmabuf.c b/drivers/gpu/drm/vmwgfx/vmwgfx_dmabuf.c index 9b078a4..0cd8890 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_dmabuf.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_dmabuf.c @@ -49,6 +49,7 @@ int vmw_dmabuf_pin_in_placement(struct vmw_private *dev_priv, { struct ttm_buffer_object *bo = &buf->base; int ret; + uint32_t new_flags; ret = ttm_write_lock(&dev_priv->reservation_sem, interruptible); if (unlikely(ret != 0)) @@ -60,7 +61,12 @@ int vmw_dmabuf_pin_in_placement(struct vmw_private *dev_priv, if (unlikely(ret != 0)) goto err; - ret = ttm_bo_validate(bo, placement, interruptible, false); + if (buf->pin_count > 0) + ret = ttm_bo_mem_compat(placement, &bo->mem, + &new_flags) == true ? 0 : -EINVAL; + else + ret = ttm_bo_validate(bo, placement, interruptible, false); + if (!ret) vmw_bo_pin_reserved(buf, true); @@ -91,6 +97,7 @@ int vmw_dmabuf_pin_in_vram_or_gmr(struct vmw_private *dev_priv, { struct ttm_buffer_object *bo = &buf->base; int ret; + uint32_t new_flags; ret = ttm_write_lock(&dev_priv->reservation_sem, interruptible); if (unlikely(ret != 0)) @@ -102,6 +109,12 @@ int vmw_dmabuf_pin_in_vram_or_gmr(struct vmw_private *dev_priv, if (unlikely(ret != 0)) goto err; + if (buf->pin_count > 0) { + ret = ttm_bo_mem_compat(&vmw_vram_gmr_placement, &bo->mem, + &new_flags) == true ? 0 : -EINVAL; + goto out_unreserve; + } + ret = ttm_bo_validate(bo, &vmw_vram_gmr_placement, interruptible, false); if (likely(ret == 0) || ret == -ERESTARTSYS) @@ -161,6 +174,7 @@ int vmw_dmabuf_pin_in_start_of_vram(struct vmw_private *dev_priv, struct ttm_placement placement; struct ttm_place place; int ret = 0; + uint32_t new_flags; place = vmw_vram_placement.placement[0]; place.lpfn = bo->num_pages; @@ -185,10 +199,15 @@ int vmw_dmabuf_pin_in_start_of_vram(struct vmw_private *dev_priv, */ if (bo->mem.mem_type == TTM_PL_VRAM && bo->mem.start < bo->num_pages && - bo->mem.start > 0) + bo->mem.start > 0 && + buf->pin_count == 0) (void) ttm_bo_validate(bo, &vmw_sys_placement, false, false); - ret = ttm_bo_validate(bo, &placement, interruptible, false); + if (buf->pin_count > 0) + ret = ttm_bo_mem_compat(&placement, &bo->mem, + &new_flags) == true ? 0 : -EINVAL; + else + ret = ttm_bo_validate(bo, &placement, interruptible, false); /* For some reason we didn't end up at the start of vram */ WARN_ON(ret == 0 && bo->offset != 0); -- cgit v0.10.2 From d5f1a291e32309324a8c481ed84b5c118d1360ea Mon Sep 17 00:00:00 2001 From: Sinclair Yeh Date: Wed, 29 Jun 2016 13:23:18 -0700 Subject: drm/vmwgfx: Delay pinning fbdev framebuffer until after mode set For the Screen Object display unit, we need to reserve a guest-invisible region equal to the size of the framebuffer for the host. This region can only be reserved in VRAM, whereas the guest-visible framebuffer can be reserved in either VRAM or GMR. As such priority should be given to the guest-invisible region otherwise in a limited VRAM situation, we can fail to allocate this region. This patch makes it so that vmw_sou_backing_alloc() is called before the framebuffer is pinned. Signed-off-by: Sinclair Yeh Reviewed-by: Thomas Hellstrom Cc: --- This is the last patch of a 3-patch series to fix console black screen issue on Ubuntu 16.04 server diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c b/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c index 679a4cb..66eaa30 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c @@ -517,28 +517,6 @@ static int vmw_fb_kms_framebuffer(struct fb_info *info) par->set_fb = &vfb->base; - if (!par->bo_ptr) { - /* - * Pin before mapping. Since we don't know in what placement - * to pin, call into KMS to do it for us. - */ - ret = vfb->pin(vfb); - if (ret) { - DRM_ERROR("Could not pin the fbdev framebuffer.\n"); - return ret; - } - - ret = ttm_bo_kmap(&par->vmw_bo->base, 0, - par->vmw_bo->base.num_pages, &par->map); - if (ret) { - vfb->unpin(vfb); - DRM_ERROR("Could not map the fbdev framebuffer.\n"); - return ret; - } - - par->bo_ptr = ttm_kmap_obj_virtual(&par->map, &par->bo_iowrite); - } - return 0; } @@ -601,6 +579,31 @@ static int vmw_fb_set_par(struct fb_info *info) if (ret) goto out_unlock; + if (!par->bo_ptr) { + struct vmw_framebuffer *vfb = vmw_framebuffer_to_vfb(set.fb); + + /* + * Pin before mapping. Since we don't know in what placement + * to pin, call into KMS to do it for us. + */ + ret = vfb->pin(vfb); + if (ret) { + DRM_ERROR("Could not pin the fbdev framebuffer.\n"); + return ret; + } + + ret = ttm_bo_kmap(&par->vmw_bo->base, 0, + par->vmw_bo->base.num_pages, &par->map); + if (ret) { + vfb->unpin(vfb); + DRM_ERROR("Could not map the fbdev framebuffer.\n"); + return ret; + } + + par->bo_ptr = ttm_kmap_obj_virtual(&par->map, &par->bo_iowrite); + } + + vmw_fb_dirty_mark(par, par->fb_x, par->fb_y, par->set_fb->width, par->set_fb->height); -- cgit v0.10.2 From beca4cf55323147ca9c8a98de1871be6e4fe8f34 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Wed, 29 Jun 2016 13:37:35 -0700 Subject: drm/vmwgfx: Fix corner case screen target management When the surface backing a framebuffer doesn't match the framebuffer's dimensions, the screen target code would test the framebuffer dimensions rather than the surface dimensions when deciding whether to bind the surface as a screen target directly. This causes a screen target - surface dimension mismatch and a subsequent device error. Fix this by testing against the surface dimension. v2: Fix review comments by Sinclair Yeh. Signed-off-by: Thomas Hellstrom Reviewed-by: Sinclair Yeh Cc: diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c b/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c index 9ca818f..41932a7 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c @@ -399,8 +399,10 @@ static int vmw_stdu_bind_fb(struct vmw_private *dev_priv, WARN_ON_ONCE(!stdu->defined); - if (!vfb->dmabuf && new_fb->width == mode->hdisplay && - new_fb->height == mode->vdisplay) + new_vfbs = (vfb->dmabuf) ? NULL : vmw_framebuffer_to_vfbs(new_fb); + + if (new_vfbs && new_vfbs->surface->base_size.width == mode->hdisplay && + new_vfbs->surface->base_size.height == mode->vdisplay) new_content_type = SAME_AS_DISPLAY; else if (vfb->dmabuf) new_content_type = SEPARATE_DMA; @@ -444,7 +446,6 @@ static int vmw_stdu_bind_fb(struct vmw_private *dev_priv, content_srf.mip_levels[0] = 1; content_srf.multisample_count = 0; } else { - new_vfbs = vmw_framebuffer_to_vfbs(new_fb); content_srf = *new_vfbs->surface; } @@ -464,7 +465,6 @@ static int vmw_stdu_bind_fb(struct vmw_private *dev_priv, return ret; } } else if (new_content_type == SAME_AS_DISPLAY) { - new_vfbs = vmw_framebuffer_to_vfbs(new_fb); new_display_srf = vmw_surface_reference(new_vfbs->surface); } -- cgit v0.10.2 From eb70db8756717b90c01ccc765fdefc4dd969fc74 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Fri, 1 Jul 2016 16:07:50 -0400 Subject: packet: Use symmetric hash for PACKET_FANOUT_HASH. People who use PACKET_FANOUT_HASH want a symmetric hash, meaning that they want packets going in both directions on a flow to hash to the same bucket. The core kernel SKB hash became non-symmetric when the ipv6 flow label and other entities were incorporated into the standard flow hash order to increase entropy. But there are no users of PACKET_FANOUT_HASH who want an assymetric hash, they all want a symmetric one. Therefore, use the flow dissector to compute a flat symmetric hash over only the protocol, addresses and ports. This hash does not get installed into and override the normal skb hash, so this change has no effect whatsoever on the rest of the stack. Reported-by: Eric Leblond Tested-by: Eric Leblond Signed-off-by: David S. Miller diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index ee38a41..24859d4 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -1062,6 +1062,7 @@ __skb_set_sw_hash(struct sk_buff *skb, __u32 hash, bool is_l4) } void __skb_get_hash(struct sk_buff *skb); +u32 __skb_get_hash_symmetric(struct sk_buff *skb); u32 skb_get_poff(const struct sk_buff *skb); u32 __skb_get_poff(const struct sk_buff *skb, void *data, const struct flow_keys *keys, int hlen); diff --git a/net/core/flow_dissector.c b/net/core/flow_dissector.c index a669dea..61ad43f 100644 --- a/net/core/flow_dissector.c +++ b/net/core/flow_dissector.c @@ -651,6 +651,23 @@ void make_flow_keys_digest(struct flow_keys_digest *digest, } EXPORT_SYMBOL(make_flow_keys_digest); +static struct flow_dissector flow_keys_dissector_symmetric __read_mostly; + +u32 __skb_get_hash_symmetric(struct sk_buff *skb) +{ + struct flow_keys keys; + + __flow_hash_secret_init(); + + memset(&keys, 0, sizeof(keys)); + __skb_flow_dissect(skb, &flow_keys_dissector_symmetric, &keys, + NULL, 0, 0, 0, + FLOW_DISSECTOR_F_STOP_AT_FLOW_LABEL); + + return __flow_hash_from_keys(&keys, hashrnd); +} +EXPORT_SYMBOL_GPL(__skb_get_hash_symmetric); + /** * __skb_get_hash: calculate a flow hash * @skb: sk_buff to calculate flow hash from @@ -868,6 +885,29 @@ static const struct flow_dissector_key flow_keys_dissector_keys[] = { }, }; +static const struct flow_dissector_key flow_keys_dissector_symmetric_keys[] = { + { + .key_id = FLOW_DISSECTOR_KEY_CONTROL, + .offset = offsetof(struct flow_keys, control), + }, + { + .key_id = FLOW_DISSECTOR_KEY_BASIC, + .offset = offsetof(struct flow_keys, basic), + }, + { + .key_id = FLOW_DISSECTOR_KEY_IPV4_ADDRS, + .offset = offsetof(struct flow_keys, addrs.v4addrs), + }, + { + .key_id = FLOW_DISSECTOR_KEY_IPV6_ADDRS, + .offset = offsetof(struct flow_keys, addrs.v6addrs), + }, + { + .key_id = FLOW_DISSECTOR_KEY_PORTS, + .offset = offsetof(struct flow_keys, ports), + }, +}; + static const struct flow_dissector_key flow_keys_buf_dissector_keys[] = { { .key_id = FLOW_DISSECTOR_KEY_CONTROL, @@ -889,6 +929,9 @@ static int __init init_default_flow_dissectors(void) skb_flow_dissector_init(&flow_keys_dissector, flow_keys_dissector_keys, ARRAY_SIZE(flow_keys_dissector_keys)); + skb_flow_dissector_init(&flow_keys_dissector_symmetric, + flow_keys_dissector_symmetric_keys, + ARRAY_SIZE(flow_keys_dissector_symmetric_keys)); skb_flow_dissector_init(&flow_keys_buf_dissector, flow_keys_buf_dissector_keys, ARRAY_SIZE(flow_keys_buf_dissector_keys)); diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index 9bff6ef..9f0983f 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c @@ -1341,7 +1341,7 @@ static unsigned int fanout_demux_hash(struct packet_fanout *f, struct sk_buff *skb, unsigned int num) { - return reciprocal_scale(skb_get_hash(skb), num); + return reciprocal_scale(__skb_get_hash_symmetric(skb), num); } static unsigned int fanout_demux_lb(struct packet_fanout *f, -- cgit v0.10.2 From 82a31b9231f02d9c1b7b290a46999d517b0d312a Mon Sep 17 00:00:00 2001 From: WANG Cong Date: Thu, 30 Jun 2016 10:15:22 -0700 Subject: net_sched: fix mirrored packets checksum Similar to commit 9b368814b336 ("net: fix bridge multicast packet checksum validation") we need to fixup the checksum for CHECKSUM_COMPLETE when pushing skb on RX path. Otherwise we get similar splats. Cc: Jamal Hadi Salim Cc: Tom Herbert Signed-off-by: Cong Wang Acked-by: Jamal Hadi Salim Signed-off-by: David S. Miller diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index 24859d4..f39b371 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -2871,6 +2871,25 @@ static inline void skb_postpush_rcsum(struct sk_buff *skb, } /** + * skb_push_rcsum - push skb and update receive checksum + * @skb: buffer to update + * @len: length of data pulled + * + * This function performs an skb_push on the packet and updates + * the CHECKSUM_COMPLETE checksum. It should be used on + * receive path processing instead of skb_push unless you know + * that the checksum difference is zero (e.g., a valid IP header) + * or you are setting ip_summed to CHECKSUM_NONE. + */ +static inline unsigned char *skb_push_rcsum(struct sk_buff *skb, + unsigned int len) +{ + skb_push(skb, len); + skb_postpush_rcsum(skb, skb->data, len); + return skb->data; +} + +/** * pskb_trim_rcsum - trim received skb and update checksum * @skb: buffer to trim * @len: new length diff --git a/net/core/skbuff.c b/net/core/skbuff.c index f2b77e5..eb12d21 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -3016,24 +3016,6 @@ int skb_append_pagefrags(struct sk_buff *skb, struct page *page, EXPORT_SYMBOL_GPL(skb_append_pagefrags); /** - * skb_push_rcsum - push skb and update receive checksum - * @skb: buffer to update - * @len: length of data pulled - * - * This function performs an skb_push on the packet and updates - * the CHECKSUM_COMPLETE checksum. It should be used on - * receive path processing instead of skb_push unless you know - * that the checksum difference is zero (e.g., a valid IP header) - * or you are setting ip_summed to CHECKSUM_NONE. - */ -static unsigned char *skb_push_rcsum(struct sk_buff *skb, unsigned len) -{ - skb_push(skb, len); - skb_postpush_rcsum(skb, skb->data, len); - return skb->data; -} - -/** * skb_pull_rcsum - pull skb and update receive checksum * @skb: buffer to update * @len: length of data pulled diff --git a/net/sched/act_mirred.c b/net/sched/act_mirred.c index 128942b..1f5bd6c 100644 --- a/net/sched/act_mirred.c +++ b/net/sched/act_mirred.c @@ -181,7 +181,7 @@ static int tcf_mirred(struct sk_buff *skb, const struct tc_action *a, if (!(at & AT_EGRESS)) { if (m->tcfm_ok_push) - skb_push(skb2, skb->mac_len); + skb_push_rcsum(skb2, skb->mac_len); } /* mirror is always swallowed */ -- cgit v0.10.2 From 79c62220d74a4a3f961a2cb7320da09eebf5daf7 Mon Sep 17 00:00:00 2001 From: Daniel Borkmann Date: Fri, 1 Jul 2016 00:00:54 +0200 Subject: macsec: set actual real device for xmit when !protect_frames Avoid recursions of dev_queue_xmit() to the wrong net device when frames are unprotected, since at that time skb->dev still points to our own macsec dev and unlike macsec_encrypt_finish() dev pointer doesn't get updated to real underlying device. Fixes: c09440f7dcb3 ("macsec: introduce IEEE 802.1AE driver") Signed-off-by: Daniel Borkmann Acked-by: Sabrina Dubroca Acked-by: Hannes Frederic Sowa Signed-off-by: David S. Miller diff --git a/drivers/net/macsec.c b/drivers/net/macsec.c index 0e7eff7..8bcd78f 100644 --- a/drivers/net/macsec.c +++ b/drivers/net/macsec.c @@ -2640,6 +2640,7 @@ static netdev_tx_t macsec_start_xmit(struct sk_buff *skb, u64_stats_update_begin(&secy_stats->syncp); secy_stats->stats.OutPktsUntagged++; u64_stats_update_end(&secy_stats->syncp); + skb->dev = macsec->real_dev; len = skb->len; ret = dev_queue_xmit(skb); count_tx(dev, ret, len); -- cgit v0.10.2 From 016eb55157166132b094e53434748cae35e18455 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Thu, 30 Jun 2016 13:27:20 -0700 Subject: net: bcmsysport: Device stats are unsigned long On 64bits kernels, device stats are 64bits wide, not 32bits. Fixes: 80105befdb4b ("net: systemport: add Broadcom SYSTEMPORT Ethernet MAC driver") Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/broadcom/bcmsysport.c b/drivers/net/ethernet/broadcom/bcmsysport.c index 543bf38..bfa26a2 100644 --- a/drivers/net/ethernet/broadcom/bcmsysport.c +++ b/drivers/net/ethernet/broadcom/bcmsysport.c @@ -392,7 +392,7 @@ static void bcm_sysport_get_stats(struct net_device *dev, else p = (char *)priv; p += s->stat_offset; - data[i] = *(u32 *)p; + data[i] = *(unsigned long *)p; } } -- cgit v0.10.2 From 55e77a3e8297581c919b45adcc4d0815b69afa84 Mon Sep 17 00:00:00 2001 From: Richard Alpe Date: Fri, 1 Jul 2016 11:11:21 +0200 Subject: tipc: fix nl compat regression for link statistics Fix incorrect use of nla_strlcpy() where the first NLA_HDRLEN bytes of the link name where left out. Making the output of tipc-config -ls look something like: Link statistics: dcast-link 1:data0-1.1.2:data0 1:data0-1.1.3:data0 Also, for the record, the patch that introduce this regression claims "Sending the whole object out can cause a leak". Which isn't very likely as this is a compat layer, where the data we are parsing is generated by us and we know the string to be NULL terminated. But you can of course never be to secure. Fixes: 5d2be1422e02 (tipc: fix an infoleak in tipc_nl_compat_link_dump) Signed-off-by: Richard Alpe Signed-off-by: David S. Miller diff --git a/net/tipc/netlink_compat.c b/net/tipc/netlink_compat.c index 3ad9fab..1fd4647 100644 --- a/net/tipc/netlink_compat.c +++ b/net/tipc/netlink_compat.c @@ -604,7 +604,7 @@ static int tipc_nl_compat_link_dump(struct tipc_nl_compat_msg *msg, link_info.dest = nla_get_flag(link[TIPC_NLA_LINK_DEST]); link_info.up = htonl(nla_get_flag(link[TIPC_NLA_LINK_UP])); - nla_strlcpy(link_info.str, nla_data(link[TIPC_NLA_LINK_NAME]), + nla_strlcpy(link_info.str, link[TIPC_NLA_LINK_NAME], TIPC_MAX_LINK_NAME); return tipc_add_tlv(msg->rep, TIPC_TLV_LINK_INFO, -- cgit v0.10.2 From 4a6e68bf96c1fa293717d2f00a68a68c92fa4150 Mon Sep 17 00:00:00 2001 From: Sinan Kaya Date: Wed, 29 Jun 2016 04:27:35 -0400 Subject: ACPI,PCI,IRQ: factor in PCI possible The change introduced in commit 103544d86976 (ACPI,PCI,IRQ: reduce resource requirements) omitted the initially applied PCI_POSSIBLE penalty when the IRQ is active. Incorrect calculation of the penalty leads the ACPI code to assigning a wrong interrupt number to a PCI INTx interrupt. This would not be as bad as it sounds in theory. It would just cause the interrupts to be shared and result in performance penalty. However, some drivers (like the parallel port driver) don't like interrupt sharing and in the above case they will causes all of the PCI drivers wanting to share the interrupt to be unable to request it. The issue has not been caught in testing because the behavior is platform-specific and depends on the peripherals ending up sharing the IRQ and their drivers. Before the above commit the code would add the PCI_POSSIBLE value divided by the number of possible IRQ users to the IRQ penalty during initialization. Later in that code path, if the IRQ is chosen as the active IRQ or if it is used by ISA; additional penalties are added. Fixes: 103544d86976 (ACPI,PCI,IRQ: reduce resource requirements) Signed-off-by: Sinan Kaya Tested-by: Wim Osterholt [ rjw: Changelog ] Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/pci_link.c b/drivers/acpi/pci_link.c index 4ed4061..db7be62 100644 --- a/drivers/acpi/pci_link.c +++ b/drivers/acpi/pci_link.c @@ -470,6 +470,7 @@ static int acpi_irq_pci_sharing_penalty(int irq) { struct acpi_pci_link *link; int penalty = 0; + int i; list_for_each_entry(link, &acpi_link_list, list) { /* @@ -478,18 +479,14 @@ static int acpi_irq_pci_sharing_penalty(int irq) */ if (link->irq.active && link->irq.active == irq) penalty += PIRQ_PENALTY_PCI_USING; - else { - int i; - - /* - * If a link is inactive, penalize the IRQs it - * might use, but not as severely. - */ - for (i = 0; i < link->irq.possible_count; i++) - if (link->irq.possible[i] == irq) - penalty += PIRQ_PENALTY_PCI_POSSIBLE / - link->irq.possible_count; - } + + /* + * penalize the IRQs PCI might use, but not as severely. + */ + for (i = 0; i < link->irq.possible_count; i++) + if (link->irq.possible[i] == irq) + penalty += PIRQ_PENALTY_PCI_POSSIBLE / + link->irq.possible_count; } return penalty; -- cgit v0.10.2 From 487cf917ed0d12afaf403d9d77684bf44b8c13be Mon Sep 17 00:00:00 2001 From: Sinan Kaya Date: Wed, 29 Jun 2016 04:27:36 -0400 Subject: Revert "ACPI, PCI, IRQ: remove redundant code in acpi_irq_penalty_init()" Trying to make the ISA and PCI init functionality common turned out to be a bad idea, because the ISA path depends on external functionality. Restore the previous behavior and limit the refactoring to PCI interrupts only. Fixes: 1fcb6a813c4f "ACPI,PCI,IRQ: remove redundant code in acpi_irq_penalty_init()" Signed-off-by: Sinan Kaya Tested-by: Wim Osterholt Signed-off-by: Rafael J. Wysocki diff --git a/arch/x86/pci/acpi.c b/arch/x86/pci/acpi.c index b2a4e2a..3cd6983 100644 --- a/arch/x86/pci/acpi.c +++ b/arch/x86/pci/acpi.c @@ -396,6 +396,7 @@ int __init pci_acpi_init(void) return -ENODEV; printk(KERN_INFO "PCI: Using ACPI for IRQ routing\n"); + acpi_irq_penalty_init(); pcibios_enable_irq = acpi_pci_irq_enable; pcibios_disable_irq = acpi_pci_irq_disable; x86_init.pci.init_irq = x86_init_noop; diff --git a/drivers/acpi/pci_link.c b/drivers/acpi/pci_link.c index db7be62..606083b 100644 --- a/drivers/acpi/pci_link.c +++ b/drivers/acpi/pci_link.c @@ -517,6 +517,42 @@ static int acpi_irq_get_penalty(int irq) return penalty; } +int __init acpi_irq_penalty_init(void) +{ + struct acpi_pci_link *link; + int i; + + /* + * Update penalties to facilitate IRQ balancing. + */ + list_for_each_entry(link, &acpi_link_list, list) { + + /* + * reflect the possible and active irqs in the penalty table -- + * useful for breaking ties. + */ + if (link->irq.possible_count) { + int penalty = + PIRQ_PENALTY_PCI_POSSIBLE / + link->irq.possible_count; + + for (i = 0; i < link->irq.possible_count; i++) { + if (link->irq.possible[i] < ACPI_MAX_ISA_IRQS) + acpi_isa_irq_penalty[link->irq. + possible[i]] += + penalty; + } + + } else if (link->irq.active && + (link->irq.active < ACPI_MAX_ISA_IRQS)) { + acpi_isa_irq_penalty[link->irq.active] += + PIRQ_PENALTY_PCI_POSSIBLE; + } + } + + return 0; +} + static int acpi_irq_balance = -1; /* 0: static, 1: balance */ static int acpi_pci_link_allocate(struct acpi_pci_link *link) diff --git a/include/acpi/acpi_drivers.h b/include/acpi/acpi_drivers.h index 797ae2e..29c6912 100644 --- a/include/acpi/acpi_drivers.h +++ b/include/acpi/acpi_drivers.h @@ -78,6 +78,7 @@ /* ACPI PCI Interrupt Link (pci_link.c) */ +int acpi_irq_penalty_init(void); int acpi_pci_link_allocate_irq(acpi_handle handle, int index, int *triggering, int *polarity, char **name); int acpi_pci_link_free_irq(acpi_handle handle); -- cgit v0.10.2 From f7eca374f000bd8bd6aacc2619475fdba0b7ecca Mon Sep 17 00:00:00 2001 From: Sinan Kaya Date: Wed, 29 Jun 2016 04:27:37 -0400 Subject: ACPI,PCI,IRQ: separate ISA penalty calculation Since commit 103544d86976 (ACPI,PCI,IRQ: reduce resource requirements) the penalty values are calculated on the fly rather than at boot time. This works fine for PCI interrupts but not so well for ISA interrupts. The information on whether or not an ISA interrupt is in use is not available to the pci_link.c code directly. That information is obtained from the outside via acpi_penalize_isa_irq(). [If its "active" argument is true, then the IRQ is in use by ISA.] Since the current code relies on PCI Link objects for determination of penalties, we are factoring in the PCI penalty twice after acpi_penalize_isa_irq() function is called. To avoid that, limit the newly added functionality to just PCI interrupts so that old behavior is still maintained. Fixes: 103544d86976 (ACPI,PCI,IRQ: reduce resource requirements) Signed-off-by: Sinan Kaya Tested-by: Wim Osterholt Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/pci_link.c b/drivers/acpi/pci_link.c index 606083b..c983bf7 100644 --- a/drivers/acpi/pci_link.c +++ b/drivers/acpi/pci_link.c @@ -496,9 +496,6 @@ static int acpi_irq_get_penalty(int irq) { int penalty = 0; - if (irq < ACPI_MAX_ISA_IRQS) - penalty += acpi_isa_irq_penalty[irq]; - /* * Penalize IRQ used by ACPI SCI. If ACPI SCI pin attributes conflict * with PCI IRQ attributes, mark ACPI SCI as ISA_ALWAYS so it won't be @@ -513,6 +510,9 @@ static int acpi_irq_get_penalty(int irq) penalty += PIRQ_PENALTY_PCI_USING; } + if (irq < ACPI_MAX_ISA_IRQS) + return penalty + acpi_isa_irq_penalty[irq]; + penalty += acpi_irq_pci_sharing_penalty(irq); return penalty; } -- cgit v0.10.2 From 5d5c4c139dd766dff903ba35d72fb3ec90022e91 Mon Sep 17 00:00:00 2001 From: Peter Chen Date: Fri, 1 Jul 2016 18:41:55 +0900 Subject: extcon: add missing of_node_put after calling of_parse_phandle of_node_put needs to be called when the device node which is got from of_parse_phandle has finished using. Signed-off-by: Peter Chen Signed-off-by: Chanwoo Choi diff --git a/drivers/extcon/extcon.c b/drivers/extcon/extcon.c index 862334e..8682efc 100644 --- a/drivers/extcon/extcon.c +++ b/drivers/extcon/extcon.c @@ -861,10 +861,12 @@ struct extcon_dev *extcon_get_edev_by_phandle(struct device *dev, int index) list_for_each_entry(edev, &extcon_dev_list, entry) { if (edev->dev.parent && edev->dev.parent->of_node == node) { mutex_unlock(&extcon_dev_list_lock); + of_node_put(node); return edev; } } mutex_unlock(&extcon_dev_list_lock); + of_node_put(node); return ERR_PTR(-EPROBE_DEFER); } -- cgit v0.10.2 From 1b6cf310103799f371066453f55755088b008be0 Mon Sep 17 00:00:00 2001 From: Venkat Reddy Talla Date: Thu, 30 Jun 2016 17:54:00 +0900 Subject: extcon: adc-jack: add suspend/resume support adding suspend and resume funtionality for extcon-adc-jack driver to configure system wake up for extcon events, also adding support to enable/disable system wakeup through flag wakeup_source based on platform requirement. Signed-off-by: Venkat Reddy Talla Signed-off-by: Chanwoo Choi diff --git a/drivers/extcon/extcon-adc-jack.c b/drivers/extcon/extcon-adc-jack.c index 7fc0ae1..44e48aa 100644 --- a/drivers/extcon/extcon-adc-jack.c +++ b/drivers/extcon/extcon-adc-jack.c @@ -38,6 +38,7 @@ * @chan: iio channel being queried. */ struct adc_jack_data { + struct device *dev; struct extcon_dev *edev; const unsigned int **cable_names; @@ -49,6 +50,7 @@ struct adc_jack_data { struct delayed_work handler; struct iio_channel *chan; + bool wakeup_source; }; static void adc_jack_handler(struct work_struct *work) @@ -105,6 +107,7 @@ static int adc_jack_probe(struct platform_device *pdev) return -EINVAL; } + data->dev = &pdev->dev; data->edev = devm_extcon_dev_allocate(&pdev->dev, pdata->cable_names); if (IS_ERR(data->edev)) { dev_err(&pdev->dev, "failed to allocate extcon device\n"); @@ -128,6 +131,7 @@ static int adc_jack_probe(struct platform_device *pdev) return PTR_ERR(data->chan); data->handling_delay = msecs_to_jiffies(pdata->handling_delay_ms); + data->wakeup_source = pdata->wakeup_source; INIT_DEFERRABLE_WORK(&data->handler, adc_jack_handler); @@ -151,6 +155,9 @@ static int adc_jack_probe(struct platform_device *pdev) return err; } + if (data->wakeup_source) + device_init_wakeup(&pdev->dev, 1); + return 0; } @@ -165,11 +172,38 @@ static int adc_jack_remove(struct platform_device *pdev) return 0; } +#ifdef CONFIG_PM_SLEEP +static int adc_jack_suspend(struct device *dev) +{ + struct adc_jack_data *data = dev_get_drvdata(dev); + + cancel_delayed_work_sync(&data->handler); + if (device_may_wakeup(data->dev)) + enable_irq_wake(data->irq); + + return 0; +} + +static int adc_jack_resume(struct device *dev) +{ + struct adc_jack_data *data = dev_get_drvdata(dev); + + if (device_may_wakeup(data->dev)) + disable_irq_wake(data->irq); + + return 0; +} +#endif /* CONFIG_PM_SLEEP */ + +static SIMPLE_DEV_PM_OPS(adc_jack_pm_ops, + adc_jack_suspend, adc_jack_resume); + static struct platform_driver adc_jack_driver = { .probe = adc_jack_probe, .remove = adc_jack_remove, .driver = { .name = "adc-jack", + .pm = &adc_jack_pm_ops, }, }; diff --git a/include/linux/extcon/extcon-adc-jack.h b/include/linux/extcon/extcon-adc-jack.h index 53c6080..ac85f20 100644 --- a/include/linux/extcon/extcon-adc-jack.h +++ b/include/linux/extcon/extcon-adc-jack.h @@ -53,6 +53,7 @@ struct adc_jack_cond { * milli-seconds after the interrupt occurs. You may * describe such delays with @handling_delay_ms, which * is rounded-off by jiffies. + * @wakeup_source: flag to wake up the system for extcon events. */ struct adc_jack_pdata { const char *name; @@ -65,6 +66,7 @@ struct adc_jack_pdata { unsigned long irq_flags; unsigned long handling_delay_ms; /* in ms */ + bool wakeup_source; }; #endif /* _EXTCON_ADC_JACK_H */ -- cgit v0.10.2 From a8b7d7709dc6db7d6d8a9a04aa9d49b029a27203 Mon Sep 17 00:00:00 2001 From: Matt Corallo Date: Thu, 30 Jun 2016 19:46:16 +0000 Subject: net: stmmac: Fix null-function call in ISR on stmmac1000 (resent due to overhelpful mail client corrupting patch) At least on Meson GXBB, the CORE_IRQ_MTL_RX_OVERFLOW interrupt is thrown with the stmmac1000 driver, which does not support set_rx_tail_ptr. With this patch and the clock fixes, 1G ethernet works on ODROID-C2. Signed-off-by: Matt Corallo Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index a473c18..e407126 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -2804,7 +2804,7 @@ static irqreturn_t stmmac_interrupt(int irq, void *dev_id) priv->tx_path_in_lpi_mode = true; if (status & CORE_IRQ_TX_PATH_EXIT_LPI_MODE) priv->tx_path_in_lpi_mode = false; - if (status & CORE_IRQ_MTL_RX_OVERFLOW) + if (status & CORE_IRQ_MTL_RX_OVERFLOW && priv->hw->dma->set_rx_tail_ptr) priv->hw->dma->set_rx_tail_ptr(priv->ioaddr, priv->rx_tail_addr, STMMAC_CHAN0); -- cgit v0.10.2 From 373819ec391de0d11f63b10b2fb69ef2854236ca Mon Sep 17 00:00:00 2001 From: Sergio Valverde Date: Fri, 1 Jul 2016 11:44:30 -0600 Subject: enc28j60: Fix race condition in enc28j60 driver The interrupt worker code for the enc28j60 relies only on the TXIF flag to determinate if the packet transmission was completed. However the datasheet specifies in section 12.1.3 that TXERIF will clear the TXRTS after a transmit abort. Also in section 12.1.4 that TXIF will be set when TXRTS transitions from '1' to '0'. Therefore the TXIF flag is enabled during transmission errors. This causes a race condition, since the worker code will invoke enc28j60_tx_clear() -> netif_wake_queue(), potentially invoking the ndo_start_xmit function to send a new packet. The enc28j60_send_packet function uses a workqueue that invokes enc28j60_hw_tx(). In between this function is called, the worker from the interrupt handler will enter the path for error handler because of the TXERIF flag, causing to invoke enc28j60_tx_clear() again and releasing the packet scheduled for transmission, causing a kernel crash with due a NULL pointer. These crashes due a NULL pointer were observed under stress conditions of the device. A BUG_ON() sequence was used to validate the issue was fixed, and has been running without problems for 2 years now. Signed-off-by: Diego Dompe Acked-by: Sergio Valverde Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/microchip/enc28j60.c b/drivers/net/ethernet/microchip/enc28j60.c index 7066954..0a26b11 100644 --- a/drivers/net/ethernet/microchip/enc28j60.c +++ b/drivers/net/ethernet/microchip/enc28j60.c @@ -1151,7 +1151,8 @@ static void enc28j60_irq_work_handler(struct work_struct *work) enc28j60_phy_read(priv, PHIR); } /* TX complete handler */ - if ((intflags & EIR_TXIF) != 0) { + if (((intflags & EIR_TXIF) != 0) && + ((intflags & EIR_TXERIF) == 0)) { bool err = false; loop++; if (netif_msg_intr(priv)) @@ -1203,7 +1204,7 @@ static void enc28j60_irq_work_handler(struct work_struct *work) enc28j60_tx_clear(ndev, true); } else enc28j60_tx_clear(ndev, true); - locked_reg_bfclr(priv, EIR, EIR_TXERIF); + locked_reg_bfclr(priv, EIR, EIR_TXERIF | EIR_TXIF); } /* RX Error handler */ if ((intflags & EIR_RXERIF) != 0) { @@ -1238,6 +1239,8 @@ static void enc28j60_irq_work_handler(struct work_struct *work) */ static void enc28j60_hw_tx(struct enc28j60_net *priv) { + BUG_ON(!priv->tx_skb); + if (netif_msg_tx_queued(priv)) printk(KERN_DEBUG DRV_NAME ": Tx Packet Len:%d\n", priv->tx_skb->len); -- cgit v0.10.2 From b291c418172f2cfbe009d81cd9a92f7a2de7c579 Mon Sep 17 00:00:00 2001 From: Stefan Hauser Date: Fri, 1 Jul 2016 22:35:03 +0200 Subject: net: phy: dp83867: Fix initialization of PHYCR register When initializing the PHY control register, the FIFO depth bits are written without reading the previous register value, i.e. all other bits are overwritten with zero. This disables automatic MDI-X configuration, which is enabled by default. Fix initialization by doing a read/modify/write operation. Signed-off-by: Stefan Hauser Reviewed-by: Florian Fainelli Signed-off-by: David S. Miller diff --git a/drivers/net/phy/dp83867.c b/drivers/net/phy/dp83867.c index 2afa61b..91177a4 100644 --- a/drivers/net/phy/dp83867.c +++ b/drivers/net/phy/dp83867.c @@ -57,6 +57,7 @@ /* PHY CTRL bits */ #define DP83867_PHYCR_FIFO_DEPTH_SHIFT 14 +#define DP83867_PHYCR_FIFO_DEPTH_MASK (3 << 14) /* RGMIIDCTL bits */ #define DP83867_RGMII_TX_CLK_DELAY_SHIFT 4 @@ -133,8 +134,8 @@ static int dp83867_of_init(struct phy_device *phydev) static int dp83867_config_init(struct phy_device *phydev) { struct dp83867_private *dp83867; - int ret; - u16 val, delay; + int ret, val; + u16 delay; if (!phydev->priv) { dp83867 = devm_kzalloc(&phydev->mdio.dev, sizeof(*dp83867), @@ -151,8 +152,12 @@ static int dp83867_config_init(struct phy_device *phydev) } if (phy_interface_is_rgmii(phydev)) { - ret = phy_write(phydev, MII_DP83867_PHYCTRL, - (dp83867->fifo_depth << DP83867_PHYCR_FIFO_DEPTH_SHIFT)); + val = phy_read(phydev, MII_DP83867_PHYCTRL); + if (val < 0) + return val; + val &= ~DP83867_PHYCR_FIFO_DEPTH_MASK; + val |= (dp83867->fifo_depth << DP83867_PHYCR_FIFO_DEPTH_SHIFT); + ret = phy_write(phydev, MII_DP83867_PHYCTRL, val); if (ret) return ret; } -- cgit v0.10.2 From 90efe05562921768d34e44c0292703ea3168ba8d Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Wed, 29 Jun 2016 15:14:42 +0200 Subject: iio: st_sensors: harden interrupt handling Leonard Crestez observed the following phenomenon: when using hard interrupt triggers (the DRDY line coming out of an ST sensor) sometimes a new value would arrive while reading the previous value, due to latencies in the system. We discovered that the ST hardware as far as can be observed is designed for level interrupts: the DRDY line will be held asserted as long as there are new values coming. The interrupt handler should be re-entered until we're out of values to handle from the sensor. If interrupts were handled as occurring on the edges (usually low-to-high) new values could appear and the line be held asserted after that, and these values would be missed, the interrupt handler would also lock up as new data was available, but as no new edges occurs on the DRDY signal, nothing happens: the edge detector only detects edges. To counter this, do the following: - Accept interrupt lines to be flagged as level interrupts using IRQF_TRIGGER_HIGH and IRQF_TRIGGER_LOW. If the line is marked like this (in the device tree node or ACPI table or similar) it will be utilized as a level IRQ. We mark the line with IRQF_ONESHOT and mask the IRQ while processing a sample, then the top half will be entered again if new values are available. - If we are flagged as using edge interrupts with IRQF_TRIGGER_RISING or IRQF_TRIGGER_FALLING: remove IRQF_ONESHOT so that the interrupt line is not masked while running the thread part of the interrupt. This way we will never miss an interrupt, then introduce a loop that polls the data ready registers repeatedly until no new samples are available, then exit the interrupt handler. This way we know no new values are available when the interrupt handler exits and new (edge) interrupts will be triggered when data arrives. Take some extra care to update the timestamp in the poll loop if this happens. The timestamp will not be 100% perfect, but it will at least be closer to the actual events. Usually the extra poll loop will handle the new samples, but once in a blue moon, we get a new IRQ while exiting the loop, before returning from the thread IRQ bottom half with IRQ_HANDLED. On these rare occasions, the removal of IRQF_ONESHOT means the interrupt will immediately fire again. - If no interrupt type is indicated from the DT/ACPI, choose IRQF_TRIGGER_RISING as default, as this is necessary for legacy boards. Tested successfully on the LIS331DL and L3G4200D by setting sampling frequency to 400Hz/800Hz and stressing the system: extra reads in the threaded interrupt handler occurs. Cc: Giuseppe Barba Cc: Denis Ciocca Tested-by: Crestez Dan Leonard Reported-by: Crestez Dan Leonard Signed-off-by: Linus Walleij Signed-off-by: Jonathan Cameron diff --git a/drivers/iio/common/st_sensors/st_sensors_buffer.c b/drivers/iio/common/st_sensors/st_sensors_buffer.c index 7c84e90..2371fc8 100644 --- a/drivers/iio/common/st_sensors/st_sensors_buffer.c +++ b/drivers/iio/common/st_sensors/st_sensors_buffer.c @@ -58,7 +58,12 @@ irqreturn_t st_sensors_trigger_handler(int irq, void *p) struct st_sensor_data *sdata = iio_priv(indio_dev); s64 timestamp; - /* If we do timetamping here, do it before reading the values */ + /* + * If we do timetamping here, do it before reading the values, because + * once we've read the values, new interrupts can occur (when using + * the hardware trigger) and the hw_timestamp may get updated. + * By storing it in a local variable first, we are safe. + */ if (sdata->hw_irq_trigger) timestamp = sdata->hw_timestamp; else diff --git a/drivers/iio/common/st_sensors/st_sensors_trigger.c b/drivers/iio/common/st_sensors/st_sensors_trigger.c index fab494d..e66f12e 100644 --- a/drivers/iio/common/st_sensors/st_sensors_trigger.c +++ b/drivers/iio/common/st_sensors/st_sensors_trigger.c @@ -18,6 +18,50 @@ #include "st_sensors_core.h" /** + * st_sensors_new_samples_available() - check if more samples came in + * returns: + * 0 - no new samples available + * 1 - new samples available + * negative - error or unknown + */ +static int st_sensors_new_samples_available(struct iio_dev *indio_dev, + struct st_sensor_data *sdata) +{ + u8 status; + int ret; + + /* How would I know if I can't check it? */ + if (!sdata->sensor_settings->drdy_irq.addr_stat_drdy) + return -EINVAL; + + /* No scan mask, no interrupt */ + if (!indio_dev->active_scan_mask) + return 0; + + ret = sdata->tf->read_byte(&sdata->tb, sdata->dev, + sdata->sensor_settings->drdy_irq.addr_stat_drdy, + &status); + if (ret < 0) { + dev_err(sdata->dev, + "error checking samples available\n"); + return ret; + } + /* + * the lower bits of .active_scan_mask[0] is directly mapped + * to the channels on the sensor: either bit 0 for + * one-dimensional sensors, or e.g. x,y,z for accelerometers, + * gyroscopes or magnetometers. No sensor use more than 3 + * channels, so cut the other status bits here. + */ + status &= 0x07; + + if (status & (u8)indio_dev->active_scan_mask[0]) + return 1; + + return 0; +} + +/** * st_sensors_irq_handler() - top half of the IRQ-based triggers * @irq: irq number * @p: private handler data @@ -43,44 +87,43 @@ irqreturn_t st_sensors_irq_thread(int irq, void *p) struct iio_trigger *trig = p; struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig); struct st_sensor_data *sdata = iio_priv(indio_dev); - int ret; /* * If this trigger is backed by a hardware interrupt and we have a - * status register, check if this IRQ came from us + * status register, check if this IRQ came from us. Notice that + * we will process also if st_sensors_new_samples_available() + * returns negative: if we can't check status, then poll + * unconditionally. */ - if (sdata->sensor_settings->drdy_irq.addr_stat_drdy) { - u8 status; - - ret = sdata->tf->read_byte(&sdata->tb, sdata->dev, - sdata->sensor_settings->drdy_irq.addr_stat_drdy, - &status); - if (ret < 0) { - dev_err(sdata->dev, "could not read channel status\n"); - goto out_poll; - } - /* - * the lower bits of .active_scan_mask[0] is directly mapped - * to the channels on the sensor: either bit 0 for - * one-dimensional sensors, or e.g. x,y,z for accelerometers, - * gyroscopes or magnetometers. No sensor use more than 3 - * channels, so cut the other status bits here. - */ - status &= 0x07; + if (sdata->hw_irq_trigger && + st_sensors_new_samples_available(indio_dev, sdata)) { + iio_trigger_poll_chained(p); + } else { + dev_dbg(sdata->dev, "spurious IRQ\n"); + return IRQ_NONE; + } - /* - * If this was not caused by any channels on this sensor, - * return IRQ_NONE - */ - if (!indio_dev->active_scan_mask) - return IRQ_NONE; - if (!(status & (u8)indio_dev->active_scan_mask[0])) - return IRQ_NONE; + /* + * If we have proper level IRQs the handler will be re-entered if + * the line is still active, so return here and come back in through + * the top half if need be. + */ + if (!sdata->edge_irq) + return IRQ_HANDLED; + + /* + * If we are using egde IRQs, new samples arrived while processing + * the IRQ and those may be missed unless we pick them here, so poll + * again. If the sensor delivery frequency is very high, this thread + * turns into a polled loop handler. + */ + while (sdata->hw_irq_trigger && + st_sensors_new_samples_available(indio_dev, sdata)) { + dev_dbg(sdata->dev, "more samples came in during polling\n"); + sdata->hw_timestamp = iio_get_time_ns(indio_dev); + iio_trigger_poll_chained(p); } -out_poll: - /* It's our IRQ: proceed to handle the register polling */ - iio_trigger_poll_chained(p); return IRQ_HANDLED; } @@ -107,13 +150,18 @@ int st_sensors_allocate_trigger(struct iio_dev *indio_dev, * If the IRQ is triggered on falling edge, we need to mark the * interrupt as active low, if the hardware supports this. */ - if (irq_trig == IRQF_TRIGGER_FALLING) { + switch(irq_trig) { + case IRQF_TRIGGER_FALLING: + case IRQF_TRIGGER_LOW: if (!sdata->sensor_settings->drdy_irq.addr_ihl) { dev_err(&indio_dev->dev, - "falling edge specified for IRQ but hardware " - "only support rising edge, will request " - "rising edge\n"); - irq_trig = IRQF_TRIGGER_RISING; + "falling/low specified for IRQ " + "but hardware only support rising/high: " + "will request rising/high\n"); + if (irq_trig == IRQF_TRIGGER_FALLING) + irq_trig = IRQF_TRIGGER_RISING; + if (irq_trig == IRQF_TRIGGER_LOW) + irq_trig = IRQF_TRIGGER_HIGH; } else { /* Set up INT active low i.e. falling edge */ err = st_sensors_write_data_with_mask(indio_dev, @@ -122,20 +170,39 @@ int st_sensors_allocate_trigger(struct iio_dev *indio_dev, if (err < 0) goto iio_trigger_free; dev_info(&indio_dev->dev, - "interrupts on the falling edge\n"); + "interrupts on the falling edge or " + "active low level\n"); } - } else if (irq_trig == IRQF_TRIGGER_RISING) { + break; + case IRQF_TRIGGER_RISING: dev_info(&indio_dev->dev, "interrupts on the rising edge\n"); - - } else { + break; + case IRQF_TRIGGER_HIGH: + dev_info(&indio_dev->dev, + "interrupts active high level\n"); + break; + default: + /* This is the most preferred mode, if possible */ dev_err(&indio_dev->dev, - "unsupported IRQ trigger specified (%lx), only " - "rising and falling edges supported, enforce " + "unsupported IRQ trigger specified (%lx), enforce " "rising edge\n", irq_trig); irq_trig = IRQF_TRIGGER_RISING; } + /* Tell the interrupt handler that we're dealing with edges */ + if (irq_trig == IRQF_TRIGGER_FALLING || + irq_trig == IRQF_TRIGGER_RISING) + sdata->edge_irq = true; + else + /* + * If we're not using edges (i.e. level interrupts) we + * just mask off the IRQ, handle one interrupt, then + * if the line is still low, we return to the + * interrupt handler top half again and start over. + */ + irq_trig |= IRQF_ONESHOT; + /* * If the interrupt pin is Open Drain, by definition this * means that the interrupt line may be shared with other @@ -148,9 +215,6 @@ int st_sensors_allocate_trigger(struct iio_dev *indio_dev, sdata->sensor_settings->drdy_irq.addr_stat_drdy) irq_trig |= IRQF_SHARED; - /* Let's create an interrupt thread masking the hard IRQ here */ - irq_trig |= IRQF_ONESHOT; - err = request_threaded_irq(sdata->get_irq_data_ready(indio_dev), st_sensors_irq_handler, st_sensors_irq_thread, diff --git a/include/linux/iio/common/st_sensors.h b/include/linux/iio/common/st_sensors.h index 28052cd..228bd44 100644 --- a/include/linux/iio/common/st_sensors.h +++ b/include/linux/iio/common/st_sensors.h @@ -223,6 +223,7 @@ struct st_sensor_settings { * @get_irq_data_ready: Function to get the IRQ used for data ready signal. * @tf: Transfer function structure used by I/O operations. * @tb: Transfer buffers and mutex used by I/O operations. + * @edge_irq: the IRQ triggers on edges and need special handling. * @hw_irq_trigger: if we're using the hardware interrupt on the sensor. * @hw_timestamp: Latest timestamp from the interrupt handler, when in use. */ @@ -250,6 +251,7 @@ struct st_sensor_data { const struct st_sensor_transfer_function *tf; struct st_sensor_transfer_buffer tb; + bool edge_irq; bool hw_irq_trigger; s64 hw_timestamp; }; -- cgit v0.10.2 From 9010ae4a8dee29e5886e86682799dde0eee7f447 Mon Sep 17 00:00:00 2001 From: Stephane Eranian Date: Fri, 1 Jul 2016 15:22:22 -0700 Subject: perf/x86/intel: Update event constraints when HT is off This patch updates the event constraints for non-PEBS mode for Intel Broadwell and Skylake processors. When HT is off, each CPU gets 8 generic counters. However, not all events can be programmed on any of the 8 counters. This patch adds the constraints for the MEM_* events which can only be measured on the bottom 4 counters. The constraints are also valid when HT is off because, then, there are only 4 generic counters and they are the bottom counters. Signed-off-by: Stephane Eranian Cc: Alexander Shishkin Cc: Arnaldo Carvalho de Melo Cc: Jiri Olsa Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: Vince Weaver Cc: kan.liang@intel.com Link: http://lkml.kernel.org/r/1467411742-13245-1-git-send-email-eranian@google.com Signed-off-by: Ingo Molnar diff --git a/arch/x86/events/intel/core.c b/arch/x86/events/intel/core.c index 7c66695..9b4f9d3 100644 --- a/arch/x86/events/intel/core.c +++ b/arch/x86/events/intel/core.c @@ -115,6 +115,10 @@ static struct event_constraint intel_snb_event_constraints[] __read_mostly = INTEL_UEVENT_CONSTRAINT(0x04a3, 0xf), /* CYCLE_ACTIVITY.CYCLES_NO_DISPATCH */ INTEL_UEVENT_CONSTRAINT(0x02a3, 0x4), /* CYCLE_ACTIVITY.CYCLES_L1D_PENDING */ + /* + * When HT is off these events can only run on the bottom 4 counters + * When HT is on, they are impacted by the HT bug and require EXCL access + */ INTEL_EXCLEVT_CONSTRAINT(0xd0, 0xf), /* MEM_UOPS_RETIRED.* */ INTEL_EXCLEVT_CONSTRAINT(0xd1, 0xf), /* MEM_LOAD_UOPS_RETIRED.* */ INTEL_EXCLEVT_CONSTRAINT(0xd2, 0xf), /* MEM_LOAD_UOPS_LLC_HIT_RETIRED.* */ @@ -139,6 +143,10 @@ static struct event_constraint intel_ivb_event_constraints[] __read_mostly = INTEL_UEVENT_CONSTRAINT(0x0ca3, 0x4), /* CYCLE_ACTIVITY.STALLS_L1D_PENDING */ INTEL_UEVENT_CONSTRAINT(0x01c0, 0x2), /* INST_RETIRED.PREC_DIST */ + /* + * When HT is off these events can only run on the bottom 4 counters + * When HT is on, they are impacted by the HT bug and require EXCL access + */ INTEL_EXCLEVT_CONSTRAINT(0xd0, 0xf), /* MEM_UOPS_RETIRED.* */ INTEL_EXCLEVT_CONSTRAINT(0xd1, 0xf), /* MEM_LOAD_UOPS_RETIRED.* */ INTEL_EXCLEVT_CONSTRAINT(0xd2, 0xf), /* MEM_LOAD_UOPS_LLC_HIT_RETIRED.* */ @@ -182,6 +190,16 @@ struct event_constraint intel_skl_event_constraints[] = { FIXED_EVENT_CONSTRAINT(0x003c, 1), /* CPU_CLK_UNHALTED.CORE */ FIXED_EVENT_CONSTRAINT(0x0300, 2), /* CPU_CLK_UNHALTED.REF */ INTEL_UEVENT_CONSTRAINT(0x1c0, 0x2), /* INST_RETIRED.PREC_DIST */ + + /* + * when HT is off, these can only run on the bottom 4 counters + */ + INTEL_EVENT_CONSTRAINT(0xd0, 0xf), /* MEM_INST_RETIRED.* */ + INTEL_EVENT_CONSTRAINT(0xd1, 0xf), /* MEM_LOAD_RETIRED.* */ + INTEL_EVENT_CONSTRAINT(0xd2, 0xf), /* MEM_LOAD_L3_HIT_RETIRED.* */ + INTEL_EVENT_CONSTRAINT(0xcd, 0xf), /* MEM_TRANS_RETIRED.* */ + INTEL_EVENT_CONSTRAINT(0xc6, 0xf), /* FRONTEND_RETIRED.* */ + EVENT_CONSTRAINT_END }; @@ -250,6 +268,10 @@ static struct event_constraint intel_hsw_event_constraints[] = { /* CYCLE_ACTIVITY.CYCLES_NO_EXECUTE */ INTEL_UEVENT_CONSTRAINT(0x04a3, 0xf), + /* + * When HT is off these events can only run on the bottom 4 counters + * When HT is on, they are impacted by the HT bug and require EXCL access + */ INTEL_EXCLEVT_CONSTRAINT(0xd0, 0xf), /* MEM_UOPS_RETIRED.* */ INTEL_EXCLEVT_CONSTRAINT(0xd1, 0xf), /* MEM_LOAD_UOPS_RETIRED.* */ INTEL_EXCLEVT_CONSTRAINT(0xd2, 0xf), /* MEM_LOAD_UOPS_LLC_HIT_RETIRED.* */ @@ -264,6 +286,13 @@ struct event_constraint intel_bdw_event_constraints[] = { FIXED_EVENT_CONSTRAINT(0x0300, 2), /* CPU_CLK_UNHALTED.REF */ INTEL_UEVENT_CONSTRAINT(0x148, 0x4), /* L1D_PEND_MISS.PENDING */ INTEL_UBIT_EVENT_CONSTRAINT(0x8a3, 0x4), /* CYCLE_ACTIVITY.CYCLES_L1D_MISS */ + /* + * when HT is off, these can only run on the bottom 4 counters + */ + INTEL_EVENT_CONSTRAINT(0xd0, 0xf), /* MEM_INST_RETIRED.* */ + INTEL_EVENT_CONSTRAINT(0xd1, 0xf), /* MEM_LOAD_RETIRED.* */ + INTEL_EVENT_CONSTRAINT(0xd2, 0xf), /* MEM_LOAD_L3_HIT_RETIRED.* */ + INTEL_EVENT_CONSTRAINT(0xcd, 0xf), /* MEM_TRANS_RETIRED.* */ EVENT_CONSTRAINT_END }; -- cgit v0.10.2 From fc18822510721fe694d273c5211c71ea52796d76 Mon Sep 17 00:00:00 2001 From: Josh Poimboeuf Date: Fri, 1 Jul 2016 23:02:05 -0500 Subject: perf/x86: Fix 32-bit perf user callgraph collection A basic perf callgraph record operation causes an immediate panic on a 32-bit kernel compiled with CONFIG_CC_STACKPROTECTOR=y: $ perf record -g ls Kernel panic - not syncing: stack-protector: Kernel stack is corrupted in: c0404fbd CPU: 0 PID: 998 Comm: ls Not tainted 4.7.0-rc5+ #1 Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.9.1-1.fc24 04/01/2014 c0dd5967 ff7afe1c 00000086 f41dbc2c c07445a0 464c457f f41dbca8 f41dbc44 c05646f4 f41dbca8 464c457f f41dbca8 464c457f f41dbc54 c04625be c0ce56fc c0404fbd f41dbc88 c0404fbd b74668f0 f41dc000 00000000 c0000000 00000000 Call Trace: [] dump_stack+0x58/0x78 [] panic+0x8e/0x1c6 [] __stack_chk_fail+0x1e/0x30 [] ? perf_callchain_user+0x22d/0x230 [] perf_callchain_user+0x22d/0x230 [] get_perf_callchain+0x1ff/0x270 [] perf_callchain+0x78/0x90 [] perf_prepare_sample+0x24b/0x370 [] perf_event_output_forward+0x24/0x70 [] __perf_event_overflow+0xa0/0x210 [] ? cpu_clock_event_read+0x43/0x50 [] perf_swevent_hrtimer+0x101/0x180 [] ? kmap_atomic_prot+0x35/0x140 [] ? get_page_from_freelist+0x279/0x950 [] ? vma_interval_tree_remove+0x158/0x230 [] ? wp_page_copy.isra.82+0x2f4/0x630 [] ? page_add_file_rmap+0x1d/0x50 [] ? unlock_page+0x61/0x80 [] ? filemap_map_pages+0x305/0x320 [] ? handle_mm_fault+0xb7f/0x1560 [] ? timerqueue_del+0x1b/0x70 [] ? __remove_hrtimer+0x2e/0x60 [] __hrtimer_run_queues+0xcb/0x2a0 [] ? __perf_event_overflow+0x210/0x210 [] hrtimer_interrupt+0x8a/0x180 [] local_apic_timer_interrupt+0x32/0x60 [] smp_apic_timer_interrupt+0x33/0x50 [] apic_timer_interrupt+0x34/0x3c Kernel Offset: disabled ---[ end Kernel panic - not syncing: stack-protector: Kernel stack is corrupted in: c0404fbd The panic is caused by the fact that perf_callchain_user() mistakenly assumes it's 64-bit only and ends up corrupting the stack. Signed-off-by: Josh Poimboeuf Cc: Alexander Shishkin Cc: Arnaldo Carvalho de Melo Cc: Arnaldo Carvalho de Melo Cc: Jiri Olsa Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Thomas Gleixner Cc: Vince Weaver Cc: stable@vger.kernel.org # v4.5+ Fixes: 75925e1ad7f5 ("perf/x86: Optimize stack walk user accesses") Link: http://lkml.kernel.org/r/1a547f5077ec30f75f9b57074837c3c80df86e5e.1467432113.git.jpoimboe@redhat.com Signed-off-by: Ingo Molnar diff --git a/arch/x86/events/core.c b/arch/x86/events/core.c index 33787ee..26ced53 100644 --- a/arch/x86/events/core.c +++ b/arch/x86/events/core.c @@ -2319,7 +2319,7 @@ void perf_callchain_user(struct perf_callchain_entry_ctx *entry, struct pt_regs *regs) { struct stack_frame frame; - const void __user *fp; + const unsigned long __user *fp; if (perf_guest_cbs && perf_guest_cbs->is_in_guest()) { /* TODO: We don't support guest os callchain now */ @@ -2332,7 +2332,7 @@ perf_callchain_user(struct perf_callchain_entry_ctx *entry, struct pt_regs *regs if (regs->flags & (X86_VM_MASK | PERF_EFLAGS_VM)) return; - fp = (void __user *)regs->bp; + fp = (unsigned long __user *)regs->bp; perf_callchain_store(entry, regs->ip); @@ -2345,16 +2345,17 @@ perf_callchain_user(struct perf_callchain_entry_ctx *entry, struct pt_regs *regs pagefault_disable(); while (entry->nr < entry->max_stack) { unsigned long bytes; + frame.next_frame = NULL; frame.return_address = 0; - if (!access_ok(VERIFY_READ, fp, 16)) + if (!access_ok(VERIFY_READ, fp, sizeof(*fp) * 2)) break; - bytes = __copy_from_user_nmi(&frame.next_frame, fp, 8); + bytes = __copy_from_user_nmi(&frame.next_frame, fp, sizeof(*fp)); if (bytes != 0) break; - bytes = __copy_from_user_nmi(&frame.return_address, fp+8, 8); + bytes = __copy_from_user_nmi(&frame.return_address, fp + 1, sizeof(*fp)); if (bytes != 0) break; -- cgit v0.10.2 From 60b1addba2de4267bfd07ce7e769b30e9f074c2a Mon Sep 17 00:00:00 2001 From: Bijosh Thykkoottathil Date: Mon, 27 Jun 2016 15:37:41 +0000 Subject: drivers:iio:light:isl29125: added macros for sensing range Added macros for sensing range as the corresponding magic numbers were used at multiple places. - ISL29125_SENSING_RANGE_0 for 375 lux full range - ISL29125_SENSING_RANGE_1 for 10k lux full range Signed-off-by: Bijosh Thykkoottathil Signed-off-by: Jonathan Cameron diff --git a/drivers/iio/light/isl29125.c b/drivers/iio/light/isl29125.c index f48b9e5..1d2c0c8 100644 --- a/drivers/iio/light/isl29125.c +++ b/drivers/iio/light/isl29125.c @@ -44,6 +44,9 @@ #define ISL29125_MODE_B 0x3 #define ISL29125_MODE_RGB 0x5 +#define ISL29125_SENSING_RANGE_0 5722 /* 375 lux full range */ +#define ISL29125_SENSING_RANGE_1 152590 /* 10k lux full range */ + #define ISL29125_MODE_RANGE BIT(3) #define ISL29125_STATUS_CONV BIT(1) @@ -139,9 +142,9 @@ static int isl29125_read_raw(struct iio_dev *indio_dev, case IIO_CHAN_INFO_SCALE: *val = 0; if (data->conf1 & ISL29125_MODE_RANGE) - *val2 = 152590; /* 10k lux full range */ + *val2 = ISL29125_SENSING_RANGE_1; /*10k lux full range*/ else - *val2 = 5722; /* 375 lux full range */ + *val2 = ISL29125_SENSING_RANGE_0; /*375 lux full range*/ return IIO_VAL_INT_PLUS_MICRO; } return -EINVAL; @@ -157,9 +160,9 @@ static int isl29125_write_raw(struct iio_dev *indio_dev, case IIO_CHAN_INFO_SCALE: if (val != 0) return -EINVAL; - if (val2 == 152590) + if (val2 == ISL29125_SENSING_RANGE_1) data->conf1 |= ISL29125_MODE_RANGE; - else if (val2 == 5722) + else if (val2 == ISL29125_SENSING_RANGE_0) data->conf1 &= ~ISL29125_MODE_RANGE; else return -EINVAL; -- cgit v0.10.2 From bd525e6c7521c45785c87d6ecade4e047634cd3c Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Thu, 30 Jun 2016 03:48:48 +0200 Subject: iio: pressure: bmp280: support supply regulators The BMP085/BMP180/BMP280 is supplied with two power sources: VDDA (analog power) and VDDD (digital power). As these may come from regulators (as on the APQ8060 Dragonboard) we need the driver to attempt to fetch and enable these regulators. We FAIL if we cannot: boards should either define: - Proper regulators if present - Define fixed regulators if power is hardwired to the component - Rely on dummy regulators (will be present on all DT systems and any boardfile system that calls regulator_has_full_constraints(). Cc: Mark Brown Signed-off-by: Linus Walleij Signed-off-by: Jonathan Cameron diff --git a/drivers/iio/pressure/bmp280.c b/drivers/iio/pressure/bmp280.c index 77172f0..f5d0875 100644 --- a/drivers/iio/pressure/bmp280.c +++ b/drivers/iio/pressure/bmp280.c @@ -24,6 +24,7 @@ #include #include #include +#include /* BMP280 specific registers */ #define BMP280_REG_HUMIDITY_LSB 0xFE @@ -124,6 +125,9 @@ struct bmp280_data { struct mutex lock; struct regmap *regmap; const struct bmp280_chip_info *chip_info; + struct regulator *vddd; + struct regulator *vdda; + unsigned int start_up_time; /* in milliseconds */ /* log of base 2 of oversampling rate */ u8 oversampling_press; @@ -1047,12 +1051,14 @@ static int bmp280_probe(struct i2c_client *client, data->chip_info = &bmp180_chip_info; data->oversampling_press = ilog2(8); data->oversampling_temp = ilog2(1); + data->start_up_time = 10; break; case BMP280_CHIP_ID: indio_dev->num_channels = 2; data->chip_info = &bmp280_chip_info; data->oversampling_press = ilog2(16); data->oversampling_temp = ilog2(2); + data->start_up_time = 2; break; case BME280_CHIP_ID: indio_dev->num_channels = 3; @@ -1060,11 +1066,37 @@ static int bmp280_probe(struct i2c_client *client, data->oversampling_press = ilog2(16); data->oversampling_humid = ilog2(16); data->oversampling_temp = ilog2(2); + data->start_up_time = 2; break; default: return -EINVAL; } + /* Bring up regulators */ + data->vddd = devm_regulator_get(&client->dev, "vddd"); + if (IS_ERR(data->vddd)) { + dev_err(&client->dev, "failed to get VDDD regulator\n"); + return PTR_ERR(data->vddd); + } + ret = regulator_enable(data->vddd); + if (ret) { + dev_err(&client->dev, "failed to enable VDDD regulator\n"); + return ret; + } + data->vdda = devm_regulator_get(&client->dev, "vdda"); + if (IS_ERR(data->vdda)) { + dev_err(&client->dev, "failed to get VDDA regulator\n"); + ret = PTR_ERR(data->vddd); + goto out_disable_vddd; + } + ret = regulator_enable(data->vdda); + if (ret) { + dev_err(&client->dev, "failed to enable VDDA regulator\n"); + goto out_disable_vddd; + } + /* Wait to make sure we started up properly */ + mdelay(data->start_up_time); + /* Bring chip out of reset if there is an assigned GPIO line */ gpiod = devm_gpiod_get(&client->dev, "reset", GPIOD_OUT_HIGH); /* Deassert the signal */ @@ -1077,7 +1109,8 @@ static int bmp280_probe(struct i2c_client *client, data->chip_info->regmap_config); if (IS_ERR(data->regmap)) { dev_err(&client->dev, "failed to allocate register map\n"); - return PTR_ERR(data->regmap); + ret = PTR_ERR(data->regmap); + goto out_disable_vdda; } ret = regmap_read(data->regmap, BMP280_REG_ID, &chip_id); @@ -1086,14 +1119,38 @@ static int bmp280_probe(struct i2c_client *client, if (chip_id != id->driver_data) { dev_err(&client->dev, "bad chip id. expected %lx got %x\n", id->driver_data, chip_id); - return -EINVAL; + ret = -EINVAL; + goto out_disable_vdda; } ret = data->chip_info->chip_config(data); if (ret < 0) - return ret; + goto out_disable_vdda; - return devm_iio_device_register(&client->dev, indio_dev); + i2c_set_clientdata(client, indio_dev); + + ret = iio_device_register(indio_dev); + if (ret) + goto out_disable_vdda; + + return 0; + +out_disable_vdda: + regulator_disable(data->vdda); +out_disable_vddd: + regulator_disable(data->vddd); + return ret; +} + +static int bmp280_remove(struct i2c_client *client) +{ + struct iio_dev *indio_dev = i2c_get_clientdata(client); + struct bmp280_data *data = iio_priv(indio_dev); + + iio_device_unregister(indio_dev); + regulator_disable(data->vdda); + regulator_disable(data->vddd); + return 0; } static const struct acpi_device_id bmp280_acpi_match[] = { @@ -1134,6 +1191,7 @@ static struct i2c_driver bmp280_driver = { .of_match_table = of_match_ptr(bmp280_of_match), }, .probe = bmp280_probe, + .remove = bmp280_remove, .id_table = bmp280_id, }; module_i2c_driver(bmp280_driver); -- cgit v0.10.2 From 14e8015f8569d9634479a4a461e7c138d60d99ca Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Thu, 30 Jun 2016 03:48:49 +0200 Subject: iio: pressure: bmp280: split driver in logical parts This splits the BMP280 driver in three logical parts: the core driver bmp280-core that only operated on a struct device * and a struct regmap *, the regmap driver bmp280-regmap that can be shared between I2C and other transports and the I2C module driver bmp280-i2c. Cleverly bake all functionality into a single object bmp280.o so that we still get the same module binary built for the device in the end, without any fuzz exporting symbols to the left and right. Signed-off-by: Linus Walleij Signed-off-by: Jonathan Cameron diff --git a/drivers/iio/pressure/Makefile b/drivers/iio/pressure/Makefile index 17d6e7a..2d98a7f 100644 --- a/drivers/iio/pressure/Makefile +++ b/drivers/iio/pressure/Makefile @@ -4,6 +4,7 @@ # When adding new entries keep the list in alphabetical order obj-$(CONFIG_BMP280) += bmp280.o +bmp280-objs := bmp280-core.o bmp280-regmap.o bmp280-i2c.o obj-$(CONFIG_HID_SENSOR_PRESS) += hid-sensor-press.o obj-$(CONFIG_HP03) += hp03.o obj-$(CONFIG_MPL115) += mpl115.o diff --git a/drivers/iio/pressure/bmp280-core.c b/drivers/iio/pressure/bmp280-core.c new file mode 100644 index 0000000..83b96fe --- /dev/null +++ b/drivers/iio/pressure/bmp280-core.c @@ -0,0 +1,968 @@ +/* + * Copyright (c) 2014 Intel Corporation + * + * Driver for Bosch Sensortec BMP180 and BMP280 digital pressure sensor. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Datasheet: + * https://ae-bst.resource.bosch.com/media/_tech/media/datasheets/BST-BMP180-DS000-121.pdf + * https://ae-bst.resource.bosch.com/media/_tech/media/datasheets/BST-BMP280-DS001-12.pdf + * https://ae-bst.resource.bosch.com/media/_tech/media/datasheets/BST-BME280_DS001-11.pdf + */ + +#define pr_fmt(fmt) "bmp280: " fmt + +#include +#include +#include +#include +#include +#include +#include + +#include "bmp280.h" + +struct bmp280_data { + struct device *dev; + struct mutex lock; + struct regmap *regmap; + const struct bmp280_chip_info *chip_info; + struct regulator *vddd; + struct regulator *vdda; + unsigned int start_up_time; /* in milliseconds */ + + /* log of base 2 of oversampling rate */ + u8 oversampling_press; + u8 oversampling_temp; + u8 oversampling_humid; + + /* + * Carryover value from temperature conversion, used in pressure + * calculation. + */ + s32 t_fine; +}; + +struct bmp280_chip_info { + const int *oversampling_temp_avail; + int num_oversampling_temp_avail; + + const int *oversampling_press_avail; + int num_oversampling_press_avail; + + const int *oversampling_humid_avail; + int num_oversampling_humid_avail; + + int (*chip_config)(struct bmp280_data *); + int (*read_temp)(struct bmp280_data *, int *); + int (*read_press)(struct bmp280_data *, int *, int *); + int (*read_humid)(struct bmp280_data *, int *, int *); +}; + +/* + * These enums are used for indexing into the array of compensation + * parameters for BMP280. + */ +enum { T1, T2, T3 }; +enum { P1, P2, P3, P4, P5, P6, P7, P8, P9 }; + +static const struct iio_chan_spec bmp280_channels[] = { + { + .type = IIO_PRESSURE, + .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED) | + BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), + }, + { + .type = IIO_TEMP, + .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED) | + BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), + }, + { + .type = IIO_HUMIDITYRELATIVE, + .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED) | + BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), + }, +}; + +/* + * Returns humidity in percent, resolution is 0.01 percent. Output value of + * "47445" represents 47445/1024 = 46.333 %RH. + * + * Taken from BME280 datasheet, Section 4.2.3, "Compensation formula". + */ + +static u32 bmp280_compensate_humidity(struct bmp280_data *data, + s32 adc_humidity) +{ + struct device *dev = data->dev; + unsigned int H1, H3, tmp; + int H2, H4, H5, H6, ret, var; + + ret = regmap_read(data->regmap, BMP280_REG_COMP_H1, &H1); + if (ret < 0) { + dev_err(dev, "failed to read H1 comp value\n"); + return ret; + } + + ret = regmap_bulk_read(data->regmap, BMP280_REG_COMP_H2, &tmp, 2); + if (ret < 0) { + dev_err(dev, "failed to read H2 comp value\n"); + return ret; + } + H2 = sign_extend32(le16_to_cpu(tmp), 15); + + ret = regmap_read(data->regmap, BMP280_REG_COMP_H3, &H3); + if (ret < 0) { + dev_err(dev, "failed to read H3 comp value\n"); + return ret; + } + + ret = regmap_bulk_read(data->regmap, BMP280_REG_COMP_H4, &tmp, 2); + if (ret < 0) { + dev_err(dev, "failed to read H4 comp value\n"); + return ret; + } + H4 = sign_extend32(((be16_to_cpu(tmp) >> 4) & 0xff0) | + (be16_to_cpu(tmp) & 0xf), 11); + + ret = regmap_bulk_read(data->regmap, BMP280_REG_COMP_H5, &tmp, 2); + if (ret < 0) { + dev_err(dev, "failed to read H5 comp value\n"); + return ret; + } + H5 = sign_extend32(((le16_to_cpu(tmp) >> 4) & 0xfff), 11); + + ret = regmap_read(data->regmap, BMP280_REG_COMP_H6, &tmp); + if (ret < 0) { + dev_err(dev, "failed to read H6 comp value\n"); + return ret; + } + H6 = sign_extend32(tmp, 7); + + var = ((s32)data->t_fine) - 76800; + var = ((((adc_humidity << 14) - (H4 << 20) - (H5 * var)) + 16384) >> 15) + * (((((((var * H6) >> 10) * (((var * H3) >> 11) + 32768)) >> 10) + + 2097152) * H2 + 8192) >> 14); + var -= ((((var >> 15) * (var >> 15)) >> 7) * H1) >> 4; + + return var >> 12; +}; + +/* + * Returns temperature in DegC, resolution is 0.01 DegC. Output value of + * "5123" equals 51.23 DegC. t_fine carries fine temperature as global + * value. + * + * Taken from datasheet, Section 3.11.3, "Compensation formula". + */ +static s32 bmp280_compensate_temp(struct bmp280_data *data, + s32 adc_temp) +{ + int ret; + s32 var1, var2; + __le16 buf[BMP280_COMP_TEMP_REG_COUNT / 2]; + + ret = regmap_bulk_read(data->regmap, BMP280_REG_COMP_TEMP_START, + buf, BMP280_COMP_TEMP_REG_COUNT); + if (ret < 0) { + dev_err(data->dev, + "failed to read temperature calibration parameters\n"); + return ret; + } + + /* + * The double casts are necessary because le16_to_cpu returns an + * unsigned 16-bit value. Casting that value directly to a + * signed 32-bit will not do proper sign extension. + * + * Conversely, T1 and P1 are unsigned values, so they can be + * cast straight to the larger type. + */ + var1 = (((adc_temp >> 3) - ((s32)le16_to_cpu(buf[T1]) << 1)) * + ((s32)(s16)le16_to_cpu(buf[T2]))) >> 11; + var2 = (((((adc_temp >> 4) - ((s32)le16_to_cpu(buf[T1]))) * + ((adc_temp >> 4) - ((s32)le16_to_cpu(buf[T1])))) >> 12) * + ((s32)(s16)le16_to_cpu(buf[T3]))) >> 14; + data->t_fine = var1 + var2; + + return (data->t_fine * 5 + 128) >> 8; +} + +/* + * Returns pressure in Pa as unsigned 32 bit integer in Q24.8 format (24 + * integer bits and 8 fractional bits). Output value of "24674867" + * represents 24674867/256 = 96386.2 Pa = 963.862 hPa + * + * Taken from datasheet, Section 3.11.3, "Compensation formula". + */ +static u32 bmp280_compensate_press(struct bmp280_data *data, + s32 adc_press) +{ + int ret; + s64 var1, var2, p; + __le16 buf[BMP280_COMP_PRESS_REG_COUNT / 2]; + + ret = regmap_bulk_read(data->regmap, BMP280_REG_COMP_PRESS_START, + buf, BMP280_COMP_PRESS_REG_COUNT); + if (ret < 0) { + dev_err(data->dev, + "failed to read pressure calibration parameters\n"); + return ret; + } + + var1 = ((s64)data->t_fine) - 128000; + var2 = var1 * var1 * (s64)(s16)le16_to_cpu(buf[P6]); + var2 += (var1 * (s64)(s16)le16_to_cpu(buf[P5])) << 17; + var2 += ((s64)(s16)le16_to_cpu(buf[P4])) << 35; + var1 = ((var1 * var1 * (s64)(s16)le16_to_cpu(buf[P3])) >> 8) + + ((var1 * (s64)(s16)le16_to_cpu(buf[P2])) << 12); + var1 = ((((s64)1) << 47) + var1) * ((s64)le16_to_cpu(buf[P1])) >> 33; + + if (var1 == 0) + return 0; + + p = ((((s64)1048576 - adc_press) << 31) - var2) * 3125; + p = div64_s64(p, var1); + var1 = (((s64)(s16)le16_to_cpu(buf[P9])) * (p >> 13) * (p >> 13)) >> 25; + var2 = (((s64)(s16)le16_to_cpu(buf[P8])) * p) >> 19; + p = ((p + var1 + var2) >> 8) + (((s64)(s16)le16_to_cpu(buf[P7])) << 4); + + return (u32)p; +} + +static int bmp280_read_temp(struct bmp280_data *data, + int *val) +{ + int ret; + __be32 tmp = 0; + s32 adc_temp, comp_temp; + + ret = regmap_bulk_read(data->regmap, BMP280_REG_TEMP_MSB, + (u8 *) &tmp, 3); + if (ret < 0) { + dev_err(data->dev, "failed to read temperature\n"); + return ret; + } + + adc_temp = be32_to_cpu(tmp) >> 12; + comp_temp = bmp280_compensate_temp(data, adc_temp); + + /* + * val might be NULL if we're called by the read_press routine, + * who only cares about the carry over t_fine value. + */ + if (val) { + *val = comp_temp * 10; + return IIO_VAL_INT; + } + + return 0; +} + +static int bmp280_read_press(struct bmp280_data *data, + int *val, int *val2) +{ + int ret; + __be32 tmp = 0; + s32 adc_press; + u32 comp_press; + + /* Read and compensate temperature so we get a reading of t_fine. */ + ret = bmp280_read_temp(data, NULL); + if (ret < 0) + return ret; + + ret = regmap_bulk_read(data->regmap, BMP280_REG_PRESS_MSB, + (u8 *) &tmp, 3); + if (ret < 0) { + dev_err(data->dev, "failed to read pressure\n"); + return ret; + } + + adc_press = be32_to_cpu(tmp) >> 12; + comp_press = bmp280_compensate_press(data, adc_press); + + *val = comp_press; + *val2 = 256000; + + return IIO_VAL_FRACTIONAL; +} + +static int bmp280_read_humid(struct bmp280_data *data, int *val, int *val2) +{ + int ret; + __be16 tmp = 0; + s32 adc_humidity; + u32 comp_humidity; + + /* Read and compensate temperature so we get a reading of t_fine. */ + ret = bmp280_read_temp(data, NULL); + if (ret < 0) + return ret; + + ret = regmap_bulk_read(data->regmap, BMP280_REG_HUMIDITY_MSB, + (u8 *) &tmp, 2); + if (ret < 0) { + dev_err(data->dev, "failed to read humidity\n"); + return ret; + } + + adc_humidity = be16_to_cpu(tmp); + comp_humidity = bmp280_compensate_humidity(data, adc_humidity); + + *val = comp_humidity; + *val2 = 1024; + + return IIO_VAL_FRACTIONAL; +} + +static int bmp280_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, long mask) +{ + int ret; + struct bmp280_data *data = iio_priv(indio_dev); + + mutex_lock(&data->lock); + + switch (mask) { + case IIO_CHAN_INFO_PROCESSED: + switch (chan->type) { + case IIO_HUMIDITYRELATIVE: + ret = data->chip_info->read_humid(data, val, val2); + break; + case IIO_PRESSURE: + ret = data->chip_info->read_press(data, val, val2); + break; + case IIO_TEMP: + ret = data->chip_info->read_temp(data, val); + break; + default: + ret = -EINVAL; + break; + } + break; + case IIO_CHAN_INFO_OVERSAMPLING_RATIO: + switch (chan->type) { + case IIO_HUMIDITYRELATIVE: + *val = 1 << data->oversampling_humid; + ret = IIO_VAL_INT; + break; + case IIO_PRESSURE: + *val = 1 << data->oversampling_press; + ret = IIO_VAL_INT; + break; + case IIO_TEMP: + *val = 1 << data->oversampling_temp; + ret = IIO_VAL_INT; + break; + default: + ret = -EINVAL; + break; + } + break; + default: + ret = -EINVAL; + break; + } + + mutex_unlock(&data->lock); + + return ret; +} + +static int bmp280_write_oversampling_ratio_humid(struct bmp280_data *data, + int val) +{ + int i; + const int *avail = data->chip_info->oversampling_humid_avail; + const int n = data->chip_info->num_oversampling_humid_avail; + + for (i = 0; i < n; i++) { + if (avail[i] == val) { + data->oversampling_humid = ilog2(val); + + return data->chip_info->chip_config(data); + } + } + return -EINVAL; +} + +static int bmp280_write_oversampling_ratio_temp(struct bmp280_data *data, + int val) +{ + int i; + const int *avail = data->chip_info->oversampling_temp_avail; + const int n = data->chip_info->num_oversampling_temp_avail; + + for (i = 0; i < n; i++) { + if (avail[i] == val) { + data->oversampling_temp = ilog2(val); + + return data->chip_info->chip_config(data); + } + } + return -EINVAL; +} + +static int bmp280_write_oversampling_ratio_press(struct bmp280_data *data, + int val) +{ + int i; + const int *avail = data->chip_info->oversampling_press_avail; + const int n = data->chip_info->num_oversampling_press_avail; + + for (i = 0; i < n; i++) { + if (avail[i] == val) { + data->oversampling_press = ilog2(val); + + return data->chip_info->chip_config(data); + } + } + return -EINVAL; +} + +static int bmp280_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int val, int val2, long mask) +{ + int ret = 0; + struct bmp280_data *data = iio_priv(indio_dev); + + switch (mask) { + case IIO_CHAN_INFO_OVERSAMPLING_RATIO: + mutex_lock(&data->lock); + switch (chan->type) { + case IIO_HUMIDITYRELATIVE: + ret = bmp280_write_oversampling_ratio_humid(data, val); + break; + case IIO_PRESSURE: + ret = bmp280_write_oversampling_ratio_press(data, val); + break; + case IIO_TEMP: + ret = bmp280_write_oversampling_ratio_temp(data, val); + break; + default: + ret = -EINVAL; + break; + } + mutex_unlock(&data->lock); + break; + default: + return -EINVAL; + } + + return ret; +} + +static ssize_t bmp280_show_avail(char *buf, const int *vals, const int n) +{ + size_t len = 0; + int i; + + for (i = 0; i < n; i++) + len += scnprintf(buf + len, PAGE_SIZE - len, "%d ", vals[i]); + + buf[len - 1] = '\n'; + + return len; +} + +static ssize_t bmp280_show_temp_oversampling_avail(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct bmp280_data *data = iio_priv(dev_to_iio_dev(dev)); + + return bmp280_show_avail(buf, data->chip_info->oversampling_temp_avail, + data->chip_info->num_oversampling_temp_avail); +} + +static ssize_t bmp280_show_press_oversampling_avail(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct bmp280_data *data = iio_priv(dev_to_iio_dev(dev)); + + return bmp280_show_avail(buf, data->chip_info->oversampling_press_avail, + data->chip_info->num_oversampling_press_avail); +} + +static IIO_DEVICE_ATTR(in_temp_oversampling_ratio_available, + S_IRUGO, bmp280_show_temp_oversampling_avail, NULL, 0); + +static IIO_DEVICE_ATTR(in_pressure_oversampling_ratio_available, + S_IRUGO, bmp280_show_press_oversampling_avail, NULL, 0); + +static struct attribute *bmp280_attributes[] = { + &iio_dev_attr_in_temp_oversampling_ratio_available.dev_attr.attr, + &iio_dev_attr_in_pressure_oversampling_ratio_available.dev_attr.attr, + NULL, +}; + +static const struct attribute_group bmp280_attrs_group = { + .attrs = bmp280_attributes, +}; + +static const struct iio_info bmp280_info = { + .driver_module = THIS_MODULE, + .read_raw = &bmp280_read_raw, + .write_raw = &bmp280_write_raw, + .attrs = &bmp280_attrs_group, +}; + +static int bmp280_chip_config(struct bmp280_data *data) +{ + int ret; + u8 osrs = BMP280_OSRS_TEMP_X(data->oversampling_temp + 1) | + BMP280_OSRS_PRESS_X(data->oversampling_press + 1); + + ret = regmap_update_bits(data->regmap, BMP280_REG_CTRL_MEAS, + BMP280_OSRS_TEMP_MASK | + BMP280_OSRS_PRESS_MASK | + BMP280_MODE_MASK, + osrs | BMP280_MODE_NORMAL); + if (ret < 0) { + dev_err(data->dev, + "failed to write ctrl_meas register\n"); + return ret; + } + + ret = regmap_update_bits(data->regmap, BMP280_REG_CONFIG, + BMP280_FILTER_MASK, + BMP280_FILTER_4X); + if (ret < 0) { + dev_err(data->dev, + "failed to write config register\n"); + return ret; + } + + return ret; +} + +static const int bmp280_oversampling_avail[] = { 1, 2, 4, 8, 16 }; + +static const struct bmp280_chip_info bmp280_chip_info = { + .oversampling_temp_avail = bmp280_oversampling_avail, + .num_oversampling_temp_avail = ARRAY_SIZE(bmp280_oversampling_avail), + + .oversampling_press_avail = bmp280_oversampling_avail, + .num_oversampling_press_avail = ARRAY_SIZE(bmp280_oversampling_avail), + + .chip_config = bmp280_chip_config, + .read_temp = bmp280_read_temp, + .read_press = bmp280_read_press, +}; + +static int bme280_chip_config(struct bmp280_data *data) +{ + int ret = bmp280_chip_config(data); + u8 osrs = BMP280_OSRS_HUMIDITIY_X(data->oversampling_humid + 1); + + if (ret < 0) + return ret; + + return regmap_update_bits(data->regmap, BMP280_REG_CTRL_HUMIDITY, + BMP280_OSRS_HUMIDITY_MASK, osrs); +} + +static const struct bmp280_chip_info bme280_chip_info = { + .oversampling_temp_avail = bmp280_oversampling_avail, + .num_oversampling_temp_avail = ARRAY_SIZE(bmp280_oversampling_avail), + + .oversampling_press_avail = bmp280_oversampling_avail, + .num_oversampling_press_avail = ARRAY_SIZE(bmp280_oversampling_avail), + + .oversampling_humid_avail = bmp280_oversampling_avail, + .num_oversampling_humid_avail = ARRAY_SIZE(bmp280_oversampling_avail), + + .chip_config = bme280_chip_config, + .read_temp = bmp280_read_temp, + .read_press = bmp280_read_press, + .read_humid = bmp280_read_humid, +}; + +static int bmp180_measure(struct bmp280_data *data, u8 ctrl_meas) +{ + int ret; + const int conversion_time_max[] = { 4500, 7500, 13500, 25500 }; + unsigned int delay_us; + unsigned int ctrl; + + ret = regmap_write(data->regmap, BMP280_REG_CTRL_MEAS, ctrl_meas); + if (ret) + return ret; + + if (ctrl_meas == BMP180_MEAS_TEMP) + delay_us = 4500; + else + delay_us = conversion_time_max[data->oversampling_press]; + + usleep_range(delay_us, delay_us + 1000); + + ret = regmap_read(data->regmap, BMP280_REG_CTRL_MEAS, &ctrl); + if (ret) + return ret; + + /* The value of this bit reset to "0" after conversion is complete */ + if (ctrl & BMP180_MEAS_SCO) + return -EIO; + + return 0; +} + +static int bmp180_read_adc_temp(struct bmp280_data *data, int *val) +{ + int ret; + __be16 tmp = 0; + + ret = bmp180_measure(data, BMP180_MEAS_TEMP); + if (ret) + return ret; + + ret = regmap_bulk_read(data->regmap, BMP180_REG_OUT_MSB, (u8 *)&tmp, 2); + if (ret) + return ret; + + *val = be16_to_cpu(tmp); + + return 0; +} + +/* + * These enums are used for indexing into the array of calibration + * coefficients for BMP180. + */ +enum { AC1, AC2, AC3, AC4, AC5, AC6, B1, B2, MB, MC, MD }; + +struct bmp180_calib { + s16 AC1; + s16 AC2; + s16 AC3; + u16 AC4; + u16 AC5; + u16 AC6; + s16 B1; + s16 B2; + s16 MB; + s16 MC; + s16 MD; +}; + +static int bmp180_read_calib(struct bmp280_data *data, + struct bmp180_calib *calib) +{ + int ret; + int i; + __be16 buf[BMP180_REG_CALIB_COUNT / 2]; + + ret = regmap_bulk_read(data->regmap, BMP180_REG_CALIB_START, buf, + sizeof(buf)); + + if (ret < 0) + return ret; + + /* None of the words has the value 0 or 0xFFFF */ + for (i = 0; i < ARRAY_SIZE(buf); i++) { + if (buf[i] == cpu_to_be16(0) || buf[i] == cpu_to_be16(0xffff)) + return -EIO; + } + + calib->AC1 = be16_to_cpu(buf[AC1]); + calib->AC2 = be16_to_cpu(buf[AC2]); + calib->AC3 = be16_to_cpu(buf[AC3]); + calib->AC4 = be16_to_cpu(buf[AC4]); + calib->AC5 = be16_to_cpu(buf[AC5]); + calib->AC6 = be16_to_cpu(buf[AC6]); + calib->B1 = be16_to_cpu(buf[B1]); + calib->B2 = be16_to_cpu(buf[B2]); + calib->MB = be16_to_cpu(buf[MB]); + calib->MC = be16_to_cpu(buf[MC]); + calib->MD = be16_to_cpu(buf[MD]); + + return 0; +} + +/* + * Returns temperature in DegC, resolution is 0.1 DegC. + * t_fine carries fine temperature as global value. + * + * Taken from datasheet, Section 3.5, "Calculating pressure and temperature". + */ +static s32 bmp180_compensate_temp(struct bmp280_data *data, s32 adc_temp) +{ + int ret; + s32 x1, x2; + struct bmp180_calib calib; + + ret = bmp180_read_calib(data, &calib); + if (ret < 0) { + dev_err(data->dev, + "failed to read calibration coefficients\n"); + return ret; + } + + x1 = ((adc_temp - calib.AC6) * calib.AC5) >> 15; + x2 = (calib.MC << 11) / (x1 + calib.MD); + data->t_fine = x1 + x2; + + return (data->t_fine + 8) >> 4; +} + +static int bmp180_read_temp(struct bmp280_data *data, int *val) +{ + int ret; + s32 adc_temp, comp_temp; + + ret = bmp180_read_adc_temp(data, &adc_temp); + if (ret) + return ret; + + comp_temp = bmp180_compensate_temp(data, adc_temp); + + /* + * val might be NULL if we're called by the read_press routine, + * who only cares about the carry over t_fine value. + */ + if (val) { + *val = comp_temp * 100; + return IIO_VAL_INT; + } + + return 0; +} + +static int bmp180_read_adc_press(struct bmp280_data *data, int *val) +{ + int ret; + __be32 tmp = 0; + u8 oss = data->oversampling_press; + + ret = bmp180_measure(data, BMP180_MEAS_PRESS_X(oss)); + if (ret) + return ret; + + ret = regmap_bulk_read(data->regmap, BMP180_REG_OUT_MSB, (u8 *)&tmp, 3); + if (ret) + return ret; + + *val = (be32_to_cpu(tmp) >> 8) >> (8 - oss); + + return 0; +} + +/* + * Returns pressure in Pa, resolution is 1 Pa. + * + * Taken from datasheet, Section 3.5, "Calculating pressure and temperature". + */ +static u32 bmp180_compensate_press(struct bmp280_data *data, s32 adc_press) +{ + int ret; + s32 x1, x2, x3, p; + s32 b3, b6; + u32 b4, b7; + s32 oss = data->oversampling_press; + struct bmp180_calib calib; + + ret = bmp180_read_calib(data, &calib); + if (ret < 0) { + dev_err(data->dev, + "failed to read calibration coefficients\n"); + return ret; + } + + b6 = data->t_fine - 4000; + x1 = (calib.B2 * (b6 * b6 >> 12)) >> 11; + x2 = calib.AC2 * b6 >> 11; + x3 = x1 + x2; + b3 = ((((s32)calib.AC1 * 4 + x3) << oss) + 2) / 4; + x1 = calib.AC3 * b6 >> 13; + x2 = (calib.B1 * ((b6 * b6) >> 12)) >> 16; + x3 = (x1 + x2 + 2) >> 2; + b4 = calib.AC4 * (u32)(x3 + 32768) >> 15; + b7 = ((u32)adc_press - b3) * (50000 >> oss); + if (b7 < 0x80000000) + p = (b7 * 2) / b4; + else + p = (b7 / b4) * 2; + + x1 = (p >> 8) * (p >> 8); + x1 = (x1 * 3038) >> 16; + x2 = (-7357 * p) >> 16; + + return p + ((x1 + x2 + 3791) >> 4); +} + +static int bmp180_read_press(struct bmp280_data *data, + int *val, int *val2) +{ + int ret; + s32 adc_press; + u32 comp_press; + + /* Read and compensate temperature so we get a reading of t_fine. */ + ret = bmp180_read_temp(data, NULL); + if (ret) + return ret; + + ret = bmp180_read_adc_press(data, &adc_press); + if (ret) + return ret; + + comp_press = bmp180_compensate_press(data, adc_press); + + *val = comp_press; + *val2 = 1000; + + return IIO_VAL_FRACTIONAL; +} + +static int bmp180_chip_config(struct bmp280_data *data) +{ + return 0; +} + +static const int bmp180_oversampling_temp_avail[] = { 1 }; +static const int bmp180_oversampling_press_avail[] = { 1, 2, 4, 8 }; + +static const struct bmp280_chip_info bmp180_chip_info = { + .oversampling_temp_avail = bmp180_oversampling_temp_avail, + .num_oversampling_temp_avail = + ARRAY_SIZE(bmp180_oversampling_temp_avail), + + .oversampling_press_avail = bmp180_oversampling_press_avail, + .num_oversampling_press_avail = + ARRAY_SIZE(bmp180_oversampling_press_avail), + + .chip_config = bmp180_chip_config, + .read_temp = bmp180_read_temp, + .read_press = bmp180_read_press, +}; + +int bmp280_common_probe(struct device *dev, + struct regmap *regmap, + unsigned int chip, + const char *name) +{ + int ret; + struct iio_dev *indio_dev; + struct bmp280_data *data; + unsigned int chip_id; + struct gpio_desc *gpiod; + + indio_dev = devm_iio_device_alloc(dev, sizeof(*data)); + if (!indio_dev) + return -ENOMEM; + + data = iio_priv(indio_dev); + mutex_init(&data->lock); + data->dev = dev; + + indio_dev->dev.parent = dev; + indio_dev->name = name; + indio_dev->channels = bmp280_channels; + indio_dev->info = &bmp280_info; + indio_dev->modes = INDIO_DIRECT_MODE; + + switch (chip) { + case BMP180_CHIP_ID: + indio_dev->num_channels = 2; + data->chip_info = &bmp180_chip_info; + data->oversampling_press = ilog2(8); + data->oversampling_temp = ilog2(1); + data->start_up_time = 10; + break; + case BMP280_CHIP_ID: + indio_dev->num_channels = 2; + data->chip_info = &bmp280_chip_info; + data->oversampling_press = ilog2(16); + data->oversampling_temp = ilog2(2); + data->start_up_time = 2; + break; + case BME280_CHIP_ID: + indio_dev->num_channels = 3; + data->chip_info = &bme280_chip_info; + data->oversampling_press = ilog2(16); + data->oversampling_humid = ilog2(16); + data->oversampling_temp = ilog2(2); + data->start_up_time = 2; + break; + default: + return -EINVAL; + } + + /* Bring up regulators */ + data->vddd = devm_regulator_get(dev, "vddd"); + if (IS_ERR(data->vddd)) { + dev_err(dev, "failed to get VDDD regulator\n"); + return PTR_ERR(data->vddd); + } + ret = regulator_enable(data->vddd); + if (ret) { + dev_err(dev, "failed to enable VDDD regulator\n"); + return ret; + } + data->vdda = devm_regulator_get(dev, "vdda"); + if (IS_ERR(data->vdda)) { + dev_err(dev, "failed to get VDDA regulator\n"); + ret = PTR_ERR(data->vddd); + goto out_disable_vddd; + } + ret = regulator_enable(data->vdda); + if (ret) { + dev_err(dev, "failed to enable VDDA regulator\n"); + goto out_disable_vddd; + } + /* Wait to make sure we started up properly */ + mdelay(data->start_up_time); + + /* Bring chip out of reset if there is an assigned GPIO line */ + gpiod = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH); + /* Deassert the signal */ + if (!IS_ERR(gpiod)) { + dev_info(dev, "release reset\n"); + gpiod_set_value(gpiod, 0); + } + + data->regmap = regmap; + ret = regmap_read(regmap, BMP280_REG_ID, &chip_id); + if (ret < 0) + goto out_disable_vdda; + if (chip_id != chip) { + dev_err(dev, "bad chip id: expected %x got %x\n", + chip, chip_id); + ret = -EINVAL; + goto out_disable_vdda; + } + + ret = data->chip_info->chip_config(data); + if (ret < 0) + goto out_disable_vdda; + + dev_set_drvdata(dev, indio_dev); + + ret = iio_device_register(indio_dev); + if (ret) + goto out_disable_vdda; + + return 0; + +out_disable_vdda: + regulator_disable(data->vdda); +out_disable_vddd: + regulator_disable(data->vddd); + return ret; +} + +int bmp280_common_remove(struct device *dev) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct bmp280_data *data = iio_priv(indio_dev); + + iio_device_unregister(indio_dev); + regulator_disable(data->vdda); + regulator_disable(data->vddd); + return 0; +} diff --git a/drivers/iio/pressure/bmp280-i2c.c b/drivers/iio/pressure/bmp280-i2c.c new file mode 100644 index 0000000..7c70ee1 --- /dev/null +++ b/drivers/iio/pressure/bmp280-i2c.c @@ -0,0 +1,89 @@ +#include +#include +#include +#include +#include + +#include "bmp280.h" + +static int bmp280_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct regmap *regmap; + const struct regmap_config *regmap_config; + + switch (id->driver_data) { + case BMP180_CHIP_ID: + regmap_config = &bmp180_regmap_config; + break; + case BMP280_CHIP_ID: + case BME280_CHIP_ID: + regmap_config = &bmp280_regmap_config; + break; + default: + return -EINVAL; + } + + regmap = devm_regmap_init_i2c(client, regmap_config); + if (IS_ERR(regmap)) { + dev_err(&client->dev, "failed to allocate register map\n"); + return PTR_ERR(regmap); + } + + return bmp280_common_probe(&client->dev, + regmap, + id->driver_data, + id->name); +} + +static int bmp280_i2c_remove(struct i2c_client *client) +{ + return bmp280_common_remove(&client->dev); +} + +static const struct acpi_device_id bmp280_acpi_i2c_match[] = { + {"BMP0280", BMP280_CHIP_ID }, + {"BMP0180", BMP180_CHIP_ID }, + {"BMP0085", BMP180_CHIP_ID }, + {"BME0280", BME280_CHIP_ID }, + { }, +}; +MODULE_DEVICE_TABLE(acpi, bmp280_acpi_i2c_match); + +#ifdef CONFIG_OF +static const struct of_device_id bmp280_of_i2c_match[] = { + { .compatible = "bosch,bme280", .data = (void *)BME280_CHIP_ID }, + { .compatible = "bosch,bmp280", .data = (void *)BMP280_CHIP_ID }, + { .compatible = "bosch,bmp180", .data = (void *)BMP180_CHIP_ID }, + { .compatible = "bosch,bmp085", .data = (void *)BMP180_CHIP_ID }, + { }, +}; +MODULE_DEVICE_TABLE(of, bmp280_of_i2c_match); +#else +#define bmp280_of_i2c_match NULL +#endif + +static const struct i2c_device_id bmp280_i2c_id[] = { + {"bmp280", BMP280_CHIP_ID }, + {"bmp180", BMP180_CHIP_ID }, + {"bmp085", BMP180_CHIP_ID }, + {"bme280", BME280_CHIP_ID }, + { }, +}; +MODULE_DEVICE_TABLE(i2c, bmp280_i2c_id); + +static struct i2c_driver bmp280_i2c_driver = { + .driver = { + .name = "bmp280", + .acpi_match_table = ACPI_PTR(bmp280_acpi_i2c_match), + .of_match_table = of_match_ptr(bmp280_of_i2c_match), + }, + .probe = bmp280_i2c_probe, + .remove = bmp280_i2c_remove, + .id_table = bmp280_i2c_id, +}; +module_i2c_driver(bmp280_i2c_driver); + +MODULE_AUTHOR("Vlad Dogaru "); +MODULE_DESCRIPTION("Driver for Bosch Sensortec BMP180/BMP280 pressure and temperature sensor"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/iio/pressure/bmp280-regmap.c b/drivers/iio/pressure/bmp280-regmap.c new file mode 100644 index 0000000..3341189 --- /dev/null +++ b/drivers/iio/pressure/bmp280-regmap.c @@ -0,0 +1,81 @@ +#include +#include + +#include "bmp280.h" + +static bool bmp180_is_writeable_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case BMP280_REG_CTRL_MEAS: + case BMP280_REG_RESET: + return true; + default: + return false; + }; +} + +static bool bmp180_is_volatile_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case BMP180_REG_OUT_XLSB: + case BMP180_REG_OUT_LSB: + case BMP180_REG_OUT_MSB: + case BMP280_REG_CTRL_MEAS: + return true; + default: + return false; + } +} + +const struct regmap_config bmp180_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + + .max_register = BMP180_REG_OUT_XLSB, + .cache_type = REGCACHE_RBTREE, + + .writeable_reg = bmp180_is_writeable_reg, + .volatile_reg = bmp180_is_volatile_reg, +}; + +static bool bmp280_is_writeable_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case BMP280_REG_CONFIG: + case BMP280_REG_CTRL_HUMIDITY: + case BMP280_REG_CTRL_MEAS: + case BMP280_REG_RESET: + return true; + default: + return false; + }; +} + +static bool bmp280_is_volatile_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case BMP280_REG_HUMIDITY_LSB: + case BMP280_REG_HUMIDITY_MSB: + case BMP280_REG_TEMP_XLSB: + case BMP280_REG_TEMP_LSB: + case BMP280_REG_TEMP_MSB: + case BMP280_REG_PRESS_XLSB: + case BMP280_REG_PRESS_LSB: + case BMP280_REG_PRESS_MSB: + case BMP280_REG_STATUS: + return true; + default: + return false; + } +} + +const struct regmap_config bmp280_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + + .max_register = BMP280_REG_HUMIDITY_LSB, + .cache_type = REGCACHE_RBTREE, + + .writeable_reg = bmp280_is_writeable_reg, + .volatile_reg = bmp280_is_volatile_reg, +}; diff --git a/drivers/iio/pressure/bmp280.c b/drivers/iio/pressure/bmp280.c deleted file mode 100644 index f5d0875..0000000 --- a/drivers/iio/pressure/bmp280.c +++ /dev/null @@ -1,1201 +0,0 @@ -/* - * Copyright (c) 2014 Intel Corporation - * - * Driver for Bosch Sensortec BMP180 and BMP280 digital pressure sensor. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Datasheet: - * https://ae-bst.resource.bosch.com/media/_tech/media/datasheets/BST-BMP180-DS000-121.pdf - * https://ae-bst.resource.bosch.com/media/_tech/media/datasheets/BST-BMP280-DS001-12.pdf - * https://ae-bst.resource.bosch.com/media/_tech/media/datasheets/BST-BME280_DS001-11.pdf - */ - -#define pr_fmt(fmt) "bmp280: " fmt - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* BMP280 specific registers */ -#define BMP280_REG_HUMIDITY_LSB 0xFE -#define BMP280_REG_HUMIDITY_MSB 0xFD -#define BMP280_REG_TEMP_XLSB 0xFC -#define BMP280_REG_TEMP_LSB 0xFB -#define BMP280_REG_TEMP_MSB 0xFA -#define BMP280_REG_PRESS_XLSB 0xF9 -#define BMP280_REG_PRESS_LSB 0xF8 -#define BMP280_REG_PRESS_MSB 0xF7 - -#define BMP280_REG_CONFIG 0xF5 -#define BMP280_REG_CTRL_MEAS 0xF4 -#define BMP280_REG_STATUS 0xF3 -#define BMP280_REG_CTRL_HUMIDITY 0xF2 - -/* Due to non linear mapping, and data sizes we can't do a bulk read */ -#define BMP280_REG_COMP_H1 0xA1 -#define BMP280_REG_COMP_H2 0xE1 -#define BMP280_REG_COMP_H3 0xE3 -#define BMP280_REG_COMP_H4 0xE4 -#define BMP280_REG_COMP_H5 0xE5 -#define BMP280_REG_COMP_H6 0xE7 - -#define BMP280_REG_COMP_TEMP_START 0x88 -#define BMP280_COMP_TEMP_REG_COUNT 6 - -#define BMP280_REG_COMP_PRESS_START 0x8E -#define BMP280_COMP_PRESS_REG_COUNT 18 - -#define BMP280_FILTER_MASK (BIT(4) | BIT(3) | BIT(2)) -#define BMP280_FILTER_OFF 0 -#define BMP280_FILTER_2X BIT(2) -#define BMP280_FILTER_4X BIT(3) -#define BMP280_FILTER_8X (BIT(3) | BIT(2)) -#define BMP280_FILTER_16X BIT(4) - -#define BMP280_OSRS_HUMIDITY_MASK (BIT(2) | BIT(1) | BIT(0)) -#define BMP280_OSRS_HUMIDITIY_X(osrs_h) ((osrs_h) << 0) -#define BMP280_OSRS_HUMIDITY_SKIP 0 -#define BMP280_OSRS_HUMIDITY_1X BMP280_OSRS_HUMIDITIY_X(1) -#define BMP280_OSRS_HUMIDITY_2X BMP280_OSRS_HUMIDITIY_X(2) -#define BMP280_OSRS_HUMIDITY_4X BMP280_OSRS_HUMIDITIY_X(3) -#define BMP280_OSRS_HUMIDITY_8X BMP280_OSRS_HUMIDITIY_X(4) -#define BMP280_OSRS_HUMIDITY_16X BMP280_OSRS_HUMIDITIY_X(5) - -#define BMP280_OSRS_TEMP_MASK (BIT(7) | BIT(6) | BIT(5)) -#define BMP280_OSRS_TEMP_SKIP 0 -#define BMP280_OSRS_TEMP_X(osrs_t) ((osrs_t) << 5) -#define BMP280_OSRS_TEMP_1X BMP280_OSRS_TEMP_X(1) -#define BMP280_OSRS_TEMP_2X BMP280_OSRS_TEMP_X(2) -#define BMP280_OSRS_TEMP_4X BMP280_OSRS_TEMP_X(3) -#define BMP280_OSRS_TEMP_8X BMP280_OSRS_TEMP_X(4) -#define BMP280_OSRS_TEMP_16X BMP280_OSRS_TEMP_X(5) - -#define BMP280_OSRS_PRESS_MASK (BIT(4) | BIT(3) | BIT(2)) -#define BMP280_OSRS_PRESS_SKIP 0 -#define BMP280_OSRS_PRESS_X(osrs_p) ((osrs_p) << 2) -#define BMP280_OSRS_PRESS_1X BMP280_OSRS_PRESS_X(1) -#define BMP280_OSRS_PRESS_2X BMP280_OSRS_PRESS_X(2) -#define BMP280_OSRS_PRESS_4X BMP280_OSRS_PRESS_X(3) -#define BMP280_OSRS_PRESS_8X BMP280_OSRS_PRESS_X(4) -#define BMP280_OSRS_PRESS_16X BMP280_OSRS_PRESS_X(5) - -#define BMP280_MODE_MASK (BIT(1) | BIT(0)) -#define BMP280_MODE_SLEEP 0 -#define BMP280_MODE_FORCED BIT(0) -#define BMP280_MODE_NORMAL (BIT(1) | BIT(0)) - -/* BMP180 specific registers */ -#define BMP180_REG_OUT_XLSB 0xF8 -#define BMP180_REG_OUT_LSB 0xF7 -#define BMP180_REG_OUT_MSB 0xF6 - -#define BMP180_REG_CALIB_START 0xAA -#define BMP180_REG_CALIB_COUNT 22 - -#define BMP180_MEAS_SCO BIT(5) -#define BMP180_MEAS_TEMP (0x0E | BMP180_MEAS_SCO) -#define BMP180_MEAS_PRESS_X(oss) ((oss) << 6 | 0x14 | BMP180_MEAS_SCO) -#define BMP180_MEAS_PRESS_1X BMP180_MEAS_PRESS_X(0) -#define BMP180_MEAS_PRESS_2X BMP180_MEAS_PRESS_X(1) -#define BMP180_MEAS_PRESS_4X BMP180_MEAS_PRESS_X(2) -#define BMP180_MEAS_PRESS_8X BMP180_MEAS_PRESS_X(3) - -/* BMP180 and BMP280 common registers */ -#define BMP280_REG_CTRL_MEAS 0xF4 -#define BMP280_REG_RESET 0xE0 -#define BMP280_REG_ID 0xD0 - -#define BMP180_CHIP_ID 0x55 -#define BMP280_CHIP_ID 0x58 -#define BME280_CHIP_ID 0x60 -#define BMP280_SOFT_RESET_VAL 0xB6 - -struct bmp280_data { - struct i2c_client *client; - struct mutex lock; - struct regmap *regmap; - const struct bmp280_chip_info *chip_info; - struct regulator *vddd; - struct regulator *vdda; - unsigned int start_up_time; /* in milliseconds */ - - /* log of base 2 of oversampling rate */ - u8 oversampling_press; - u8 oversampling_temp; - u8 oversampling_humid; - - /* - * Carryover value from temperature conversion, used in pressure - * calculation. - */ - s32 t_fine; -}; - -struct bmp280_chip_info { - const struct regmap_config *regmap_config; - - const int *oversampling_temp_avail; - int num_oversampling_temp_avail; - - const int *oversampling_press_avail; - int num_oversampling_press_avail; - - const int *oversampling_humid_avail; - int num_oversampling_humid_avail; - - int (*chip_config)(struct bmp280_data *); - int (*read_temp)(struct bmp280_data *, int *); - int (*read_press)(struct bmp280_data *, int *, int *); - int (*read_humid)(struct bmp280_data *, int *, int *); -}; - -/* - * These enums are used for indexing into the array of compensation - * parameters for BMP280. - */ -enum { T1, T2, T3 }; -enum { P1, P2, P3, P4, P5, P6, P7, P8, P9 }; - -static const struct iio_chan_spec bmp280_channels[] = { - { - .type = IIO_PRESSURE, - .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED) | - BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), - }, - { - .type = IIO_TEMP, - .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED) | - BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), - }, - { - .type = IIO_HUMIDITYRELATIVE, - .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED) | - BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), - }, -}; - -static bool bmp280_is_writeable_reg(struct device *dev, unsigned int reg) -{ - switch (reg) { - case BMP280_REG_CONFIG: - case BMP280_REG_CTRL_HUMIDITY: - case BMP280_REG_CTRL_MEAS: - case BMP280_REG_RESET: - return true; - default: - return false; - }; -} - -static bool bmp280_is_volatile_reg(struct device *dev, unsigned int reg) -{ - switch (reg) { - case BMP280_REG_HUMIDITY_LSB: - case BMP280_REG_HUMIDITY_MSB: - case BMP280_REG_TEMP_XLSB: - case BMP280_REG_TEMP_LSB: - case BMP280_REG_TEMP_MSB: - case BMP280_REG_PRESS_XLSB: - case BMP280_REG_PRESS_LSB: - case BMP280_REG_PRESS_MSB: - case BMP280_REG_STATUS: - return true; - default: - return false; - } -} - -static const struct regmap_config bmp280_regmap_config = { - .reg_bits = 8, - .val_bits = 8, - - .max_register = BMP280_REG_HUMIDITY_LSB, - .cache_type = REGCACHE_RBTREE, - - .writeable_reg = bmp280_is_writeable_reg, - .volatile_reg = bmp280_is_volatile_reg, -}; - -/* - * Returns humidity in percent, resolution is 0.01 percent. Output value of - * "47445" represents 47445/1024 = 46.333 %RH. - * - * Taken from BME280 datasheet, Section 4.2.3, "Compensation formula". - */ - -static u32 bmp280_compensate_humidity(struct bmp280_data *data, - s32 adc_humidity) -{ - struct device *dev = &data->client->dev; - unsigned int H1, H3, tmp; - int H2, H4, H5, H6, ret, var; - - ret = regmap_read(data->regmap, BMP280_REG_COMP_H1, &H1); - if (ret < 0) { - dev_err(dev, "failed to read H1 comp value\n"); - return ret; - } - - ret = regmap_bulk_read(data->regmap, BMP280_REG_COMP_H2, &tmp, 2); - if (ret < 0) { - dev_err(dev, "failed to read H2 comp value\n"); - return ret; - } - H2 = sign_extend32(le16_to_cpu(tmp), 15); - - ret = regmap_read(data->regmap, BMP280_REG_COMP_H3, &H3); - if (ret < 0) { - dev_err(dev, "failed to read H3 comp value\n"); - return ret; - } - - ret = regmap_bulk_read(data->regmap, BMP280_REG_COMP_H4, &tmp, 2); - if (ret < 0) { - dev_err(dev, "failed to read H4 comp value\n"); - return ret; - } - H4 = sign_extend32(((be16_to_cpu(tmp) >> 4) & 0xff0) | - (be16_to_cpu(tmp) & 0xf), 11); - - ret = regmap_bulk_read(data->regmap, BMP280_REG_COMP_H5, &tmp, 2); - if (ret < 0) { - dev_err(dev, "failed to read H5 comp value\n"); - return ret; - } - H5 = sign_extend32(((le16_to_cpu(tmp) >> 4) & 0xfff), 11); - - ret = regmap_read(data->regmap, BMP280_REG_COMP_H6, &tmp); - if (ret < 0) { - dev_err(dev, "failed to read H6 comp value\n"); - return ret; - } - H6 = sign_extend32(tmp, 7); - - var = ((s32)data->t_fine) - 76800; - var = ((((adc_humidity << 14) - (H4 << 20) - (H5 * var)) + 16384) >> 15) - * (((((((var * H6) >> 10) * (((var * H3) >> 11) + 32768)) >> 10) - + 2097152) * H2 + 8192) >> 14); - var -= ((((var >> 15) * (var >> 15)) >> 7) * H1) >> 4; - - return var >> 12; -}; - -/* - * Returns temperature in DegC, resolution is 0.01 DegC. Output value of - * "5123" equals 51.23 DegC. t_fine carries fine temperature as global - * value. - * - * Taken from datasheet, Section 3.11.3, "Compensation formula". - */ -static s32 bmp280_compensate_temp(struct bmp280_data *data, - s32 adc_temp) -{ - int ret; - s32 var1, var2; - __le16 buf[BMP280_COMP_TEMP_REG_COUNT / 2]; - - ret = regmap_bulk_read(data->regmap, BMP280_REG_COMP_TEMP_START, - buf, BMP280_COMP_TEMP_REG_COUNT); - if (ret < 0) { - dev_err(&data->client->dev, - "failed to read temperature calibration parameters\n"); - return ret; - } - - /* - * The double casts are necessary because le16_to_cpu returns an - * unsigned 16-bit value. Casting that value directly to a - * signed 32-bit will not do proper sign extension. - * - * Conversely, T1 and P1 are unsigned values, so they can be - * cast straight to the larger type. - */ - var1 = (((adc_temp >> 3) - ((s32)le16_to_cpu(buf[T1]) << 1)) * - ((s32)(s16)le16_to_cpu(buf[T2]))) >> 11; - var2 = (((((adc_temp >> 4) - ((s32)le16_to_cpu(buf[T1]))) * - ((adc_temp >> 4) - ((s32)le16_to_cpu(buf[T1])))) >> 12) * - ((s32)(s16)le16_to_cpu(buf[T3]))) >> 14; - data->t_fine = var1 + var2; - - return (data->t_fine * 5 + 128) >> 8; -} - -/* - * Returns pressure in Pa as unsigned 32 bit integer in Q24.8 format (24 - * integer bits and 8 fractional bits). Output value of "24674867" - * represents 24674867/256 = 96386.2 Pa = 963.862 hPa - * - * Taken from datasheet, Section 3.11.3, "Compensation formula". - */ -static u32 bmp280_compensate_press(struct bmp280_data *data, - s32 adc_press) -{ - int ret; - s64 var1, var2, p; - __le16 buf[BMP280_COMP_PRESS_REG_COUNT / 2]; - - ret = regmap_bulk_read(data->regmap, BMP280_REG_COMP_PRESS_START, - buf, BMP280_COMP_PRESS_REG_COUNT); - if (ret < 0) { - dev_err(&data->client->dev, - "failed to read pressure calibration parameters\n"); - return ret; - } - - var1 = ((s64)data->t_fine) - 128000; - var2 = var1 * var1 * (s64)(s16)le16_to_cpu(buf[P6]); - var2 += (var1 * (s64)(s16)le16_to_cpu(buf[P5])) << 17; - var2 += ((s64)(s16)le16_to_cpu(buf[P4])) << 35; - var1 = ((var1 * var1 * (s64)(s16)le16_to_cpu(buf[P3])) >> 8) + - ((var1 * (s64)(s16)le16_to_cpu(buf[P2])) << 12); - var1 = ((((s64)1) << 47) + var1) * ((s64)le16_to_cpu(buf[P1])) >> 33; - - if (var1 == 0) - return 0; - - p = ((((s64)1048576 - adc_press) << 31) - var2) * 3125; - p = div64_s64(p, var1); - var1 = (((s64)(s16)le16_to_cpu(buf[P9])) * (p >> 13) * (p >> 13)) >> 25; - var2 = (((s64)(s16)le16_to_cpu(buf[P8])) * p) >> 19; - p = ((p + var1 + var2) >> 8) + (((s64)(s16)le16_to_cpu(buf[P7])) << 4); - - return (u32)p; -} - -static int bmp280_read_temp(struct bmp280_data *data, - int *val) -{ - int ret; - __be32 tmp = 0; - s32 adc_temp, comp_temp; - - ret = regmap_bulk_read(data->regmap, BMP280_REG_TEMP_MSB, - (u8 *) &tmp, 3); - if (ret < 0) { - dev_err(&data->client->dev, "failed to read temperature\n"); - return ret; - } - - adc_temp = be32_to_cpu(tmp) >> 12; - comp_temp = bmp280_compensate_temp(data, adc_temp); - - /* - * val might be NULL if we're called by the read_press routine, - * who only cares about the carry over t_fine value. - */ - if (val) { - *val = comp_temp * 10; - return IIO_VAL_INT; - } - - return 0; -} - -static int bmp280_read_press(struct bmp280_data *data, - int *val, int *val2) -{ - int ret; - __be32 tmp = 0; - s32 adc_press; - u32 comp_press; - - /* Read and compensate temperature so we get a reading of t_fine. */ - ret = bmp280_read_temp(data, NULL); - if (ret < 0) - return ret; - - ret = regmap_bulk_read(data->regmap, BMP280_REG_PRESS_MSB, - (u8 *) &tmp, 3); - if (ret < 0) { - dev_err(&data->client->dev, "failed to read pressure\n"); - return ret; - } - - adc_press = be32_to_cpu(tmp) >> 12; - comp_press = bmp280_compensate_press(data, adc_press); - - *val = comp_press; - *val2 = 256000; - - return IIO_VAL_FRACTIONAL; -} - -static int bmp280_read_humid(struct bmp280_data *data, int *val, int *val2) -{ - int ret; - __be16 tmp = 0; - s32 adc_humidity; - u32 comp_humidity; - - /* Read and compensate temperature so we get a reading of t_fine. */ - ret = bmp280_read_temp(data, NULL); - if (ret < 0) - return ret; - - ret = regmap_bulk_read(data->regmap, BMP280_REG_HUMIDITY_MSB, - (u8 *) &tmp, 2); - if (ret < 0) { - dev_err(&data->client->dev, "failed to read humidity\n"); - return ret; - } - - adc_humidity = be16_to_cpu(tmp); - comp_humidity = bmp280_compensate_humidity(data, adc_humidity); - - *val = comp_humidity; - *val2 = 1024; - - return IIO_VAL_FRACTIONAL; -} - -static int bmp280_read_raw(struct iio_dev *indio_dev, - struct iio_chan_spec const *chan, - int *val, int *val2, long mask) -{ - int ret; - struct bmp280_data *data = iio_priv(indio_dev); - - mutex_lock(&data->lock); - - switch (mask) { - case IIO_CHAN_INFO_PROCESSED: - switch (chan->type) { - case IIO_HUMIDITYRELATIVE: - ret = data->chip_info->read_humid(data, val, val2); - break; - case IIO_PRESSURE: - ret = data->chip_info->read_press(data, val, val2); - break; - case IIO_TEMP: - ret = data->chip_info->read_temp(data, val); - break; - default: - ret = -EINVAL; - break; - } - break; - case IIO_CHAN_INFO_OVERSAMPLING_RATIO: - switch (chan->type) { - case IIO_HUMIDITYRELATIVE: - *val = 1 << data->oversampling_humid; - ret = IIO_VAL_INT; - break; - case IIO_PRESSURE: - *val = 1 << data->oversampling_press; - ret = IIO_VAL_INT; - break; - case IIO_TEMP: - *val = 1 << data->oversampling_temp; - ret = IIO_VAL_INT; - break; - default: - ret = -EINVAL; - break; - } - break; - default: - ret = -EINVAL; - break; - } - - mutex_unlock(&data->lock); - - return ret; -} - -static int bmp280_write_oversampling_ratio_humid(struct bmp280_data *data, - int val) -{ - int i; - const int *avail = data->chip_info->oversampling_humid_avail; - const int n = data->chip_info->num_oversampling_humid_avail; - - for (i = 0; i < n; i++) { - if (avail[i] == val) { - data->oversampling_humid = ilog2(val); - - return data->chip_info->chip_config(data); - } - } - return -EINVAL; -} - -static int bmp280_write_oversampling_ratio_temp(struct bmp280_data *data, - int val) -{ - int i; - const int *avail = data->chip_info->oversampling_temp_avail; - const int n = data->chip_info->num_oversampling_temp_avail; - - for (i = 0; i < n; i++) { - if (avail[i] == val) { - data->oversampling_temp = ilog2(val); - - return data->chip_info->chip_config(data); - } - } - return -EINVAL; -} - -static int bmp280_write_oversampling_ratio_press(struct bmp280_data *data, - int val) -{ - int i; - const int *avail = data->chip_info->oversampling_press_avail; - const int n = data->chip_info->num_oversampling_press_avail; - - for (i = 0; i < n; i++) { - if (avail[i] == val) { - data->oversampling_press = ilog2(val); - - return data->chip_info->chip_config(data); - } - } - return -EINVAL; -} - -static int bmp280_write_raw(struct iio_dev *indio_dev, - struct iio_chan_spec const *chan, - int val, int val2, long mask) -{ - int ret = 0; - struct bmp280_data *data = iio_priv(indio_dev); - - switch (mask) { - case IIO_CHAN_INFO_OVERSAMPLING_RATIO: - mutex_lock(&data->lock); - switch (chan->type) { - case IIO_HUMIDITYRELATIVE: - ret = bmp280_write_oversampling_ratio_humid(data, val); - break; - case IIO_PRESSURE: - ret = bmp280_write_oversampling_ratio_press(data, val); - break; - case IIO_TEMP: - ret = bmp280_write_oversampling_ratio_temp(data, val); - break; - default: - ret = -EINVAL; - break; - } - mutex_unlock(&data->lock); - break; - default: - return -EINVAL; - } - - return ret; -} - -static ssize_t bmp280_show_avail(char *buf, const int *vals, const int n) -{ - size_t len = 0; - int i; - - for (i = 0; i < n; i++) - len += scnprintf(buf + len, PAGE_SIZE - len, "%d ", vals[i]); - - buf[len - 1] = '\n'; - - return len; -} - -static ssize_t bmp280_show_temp_oversampling_avail(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct bmp280_data *data = iio_priv(dev_to_iio_dev(dev)); - - return bmp280_show_avail(buf, data->chip_info->oversampling_temp_avail, - data->chip_info->num_oversampling_temp_avail); -} - -static ssize_t bmp280_show_press_oversampling_avail(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct bmp280_data *data = iio_priv(dev_to_iio_dev(dev)); - - return bmp280_show_avail(buf, data->chip_info->oversampling_press_avail, - data->chip_info->num_oversampling_press_avail); -} - -static IIO_DEVICE_ATTR(in_temp_oversampling_ratio_available, - S_IRUGO, bmp280_show_temp_oversampling_avail, NULL, 0); - -static IIO_DEVICE_ATTR(in_pressure_oversampling_ratio_available, - S_IRUGO, bmp280_show_press_oversampling_avail, NULL, 0); - -static struct attribute *bmp280_attributes[] = { - &iio_dev_attr_in_temp_oversampling_ratio_available.dev_attr.attr, - &iio_dev_attr_in_pressure_oversampling_ratio_available.dev_attr.attr, - NULL, -}; - -static const struct attribute_group bmp280_attrs_group = { - .attrs = bmp280_attributes, -}; - -static const struct iio_info bmp280_info = { - .driver_module = THIS_MODULE, - .read_raw = &bmp280_read_raw, - .write_raw = &bmp280_write_raw, - .attrs = &bmp280_attrs_group, -}; - -static int bmp280_chip_config(struct bmp280_data *data) -{ - int ret; - u8 osrs = BMP280_OSRS_TEMP_X(data->oversampling_temp + 1) | - BMP280_OSRS_PRESS_X(data->oversampling_press + 1); - - ret = regmap_update_bits(data->regmap, BMP280_REG_CTRL_MEAS, - BMP280_OSRS_TEMP_MASK | - BMP280_OSRS_PRESS_MASK | - BMP280_MODE_MASK, - osrs | BMP280_MODE_NORMAL); - if (ret < 0) { - dev_err(&data->client->dev, - "failed to write ctrl_meas register\n"); - return ret; - } - - ret = regmap_update_bits(data->regmap, BMP280_REG_CONFIG, - BMP280_FILTER_MASK, - BMP280_FILTER_4X); - if (ret < 0) { - dev_err(&data->client->dev, - "failed to write config register\n"); - return ret; - } - - return ret; -} - -static const int bmp280_oversampling_avail[] = { 1, 2, 4, 8, 16 }; - -static const struct bmp280_chip_info bmp280_chip_info = { - .regmap_config = &bmp280_regmap_config, - - .oversampling_temp_avail = bmp280_oversampling_avail, - .num_oversampling_temp_avail = ARRAY_SIZE(bmp280_oversampling_avail), - - .oversampling_press_avail = bmp280_oversampling_avail, - .num_oversampling_press_avail = ARRAY_SIZE(bmp280_oversampling_avail), - - .chip_config = bmp280_chip_config, - .read_temp = bmp280_read_temp, - .read_press = bmp280_read_press, -}; - -static int bme280_chip_config(struct bmp280_data *data) -{ - int ret = bmp280_chip_config(data); - u8 osrs = BMP280_OSRS_HUMIDITIY_X(data->oversampling_humid + 1); - - if (ret < 0) - return ret; - - return regmap_update_bits(data->regmap, BMP280_REG_CTRL_HUMIDITY, - BMP280_OSRS_HUMIDITY_MASK, osrs); -} - -static const struct bmp280_chip_info bme280_chip_info = { - .regmap_config = &bmp280_regmap_config, - - .oversampling_temp_avail = bmp280_oversampling_avail, - .num_oversampling_temp_avail = ARRAY_SIZE(bmp280_oversampling_avail), - - .oversampling_press_avail = bmp280_oversampling_avail, - .num_oversampling_press_avail = ARRAY_SIZE(bmp280_oversampling_avail), - - .oversampling_humid_avail = bmp280_oversampling_avail, - .num_oversampling_humid_avail = ARRAY_SIZE(bmp280_oversampling_avail), - - .chip_config = bme280_chip_config, - .read_temp = bmp280_read_temp, - .read_press = bmp280_read_press, - .read_humid = bmp280_read_humid, -}; - - -static bool bmp180_is_writeable_reg(struct device *dev, unsigned int reg) -{ - switch (reg) { - case BMP280_REG_CTRL_MEAS: - case BMP280_REG_RESET: - return true; - default: - return false; - }; -} - -static bool bmp180_is_volatile_reg(struct device *dev, unsigned int reg) -{ - switch (reg) { - case BMP180_REG_OUT_XLSB: - case BMP180_REG_OUT_LSB: - case BMP180_REG_OUT_MSB: - case BMP280_REG_CTRL_MEAS: - return true; - default: - return false; - } -} - -static const struct regmap_config bmp180_regmap_config = { - .reg_bits = 8, - .val_bits = 8, - - .max_register = BMP180_REG_OUT_XLSB, - .cache_type = REGCACHE_RBTREE, - - .writeable_reg = bmp180_is_writeable_reg, - .volatile_reg = bmp180_is_volatile_reg, -}; - -static int bmp180_measure(struct bmp280_data *data, u8 ctrl_meas) -{ - int ret; - const int conversion_time_max[] = { 4500, 7500, 13500, 25500 }; - unsigned int delay_us; - unsigned int ctrl; - - ret = regmap_write(data->regmap, BMP280_REG_CTRL_MEAS, ctrl_meas); - if (ret) - return ret; - - if (ctrl_meas == BMP180_MEAS_TEMP) - delay_us = 4500; - else - delay_us = conversion_time_max[data->oversampling_press]; - - usleep_range(delay_us, delay_us + 1000); - - ret = regmap_read(data->regmap, BMP280_REG_CTRL_MEAS, &ctrl); - if (ret) - return ret; - - /* The value of this bit reset to "0" after conversion is complete */ - if (ctrl & BMP180_MEAS_SCO) - return -EIO; - - return 0; -} - -static int bmp180_read_adc_temp(struct bmp280_data *data, int *val) -{ - int ret; - __be16 tmp = 0; - - ret = bmp180_measure(data, BMP180_MEAS_TEMP); - if (ret) - return ret; - - ret = regmap_bulk_read(data->regmap, BMP180_REG_OUT_MSB, (u8 *)&tmp, 2); - if (ret) - return ret; - - *val = be16_to_cpu(tmp); - - return 0; -} - -/* - * These enums are used for indexing into the array of calibration - * coefficients for BMP180. - */ -enum { AC1, AC2, AC3, AC4, AC5, AC6, B1, B2, MB, MC, MD }; - -struct bmp180_calib { - s16 AC1; - s16 AC2; - s16 AC3; - u16 AC4; - u16 AC5; - u16 AC6; - s16 B1; - s16 B2; - s16 MB; - s16 MC; - s16 MD; -}; - -static int bmp180_read_calib(struct bmp280_data *data, - struct bmp180_calib *calib) -{ - int ret; - int i; - __be16 buf[BMP180_REG_CALIB_COUNT / 2]; - - ret = regmap_bulk_read(data->regmap, BMP180_REG_CALIB_START, buf, - sizeof(buf)); - - if (ret < 0) - return ret; - - /* None of the words has the value 0 or 0xFFFF */ - for (i = 0; i < ARRAY_SIZE(buf); i++) { - if (buf[i] == cpu_to_be16(0) || buf[i] == cpu_to_be16(0xffff)) - return -EIO; - } - - calib->AC1 = be16_to_cpu(buf[AC1]); - calib->AC2 = be16_to_cpu(buf[AC2]); - calib->AC3 = be16_to_cpu(buf[AC3]); - calib->AC4 = be16_to_cpu(buf[AC4]); - calib->AC5 = be16_to_cpu(buf[AC5]); - calib->AC6 = be16_to_cpu(buf[AC6]); - calib->B1 = be16_to_cpu(buf[B1]); - calib->B2 = be16_to_cpu(buf[B2]); - calib->MB = be16_to_cpu(buf[MB]); - calib->MC = be16_to_cpu(buf[MC]); - calib->MD = be16_to_cpu(buf[MD]); - - return 0; -} - -/* - * Returns temperature in DegC, resolution is 0.1 DegC. - * t_fine carries fine temperature as global value. - * - * Taken from datasheet, Section 3.5, "Calculating pressure and temperature". - */ -static s32 bmp180_compensate_temp(struct bmp280_data *data, s32 adc_temp) -{ - int ret; - s32 x1, x2; - struct bmp180_calib calib; - - ret = bmp180_read_calib(data, &calib); - if (ret < 0) { - dev_err(&data->client->dev, - "failed to read calibration coefficients\n"); - return ret; - } - - x1 = ((adc_temp - calib.AC6) * calib.AC5) >> 15; - x2 = (calib.MC << 11) / (x1 + calib.MD); - data->t_fine = x1 + x2; - - return (data->t_fine + 8) >> 4; -} - -static int bmp180_read_temp(struct bmp280_data *data, int *val) -{ - int ret; - s32 adc_temp, comp_temp; - - ret = bmp180_read_adc_temp(data, &adc_temp); - if (ret) - return ret; - - comp_temp = bmp180_compensate_temp(data, adc_temp); - - /* - * val might be NULL if we're called by the read_press routine, - * who only cares about the carry over t_fine value. - */ - if (val) { - *val = comp_temp * 100; - return IIO_VAL_INT; - } - - return 0; -} - -static int bmp180_read_adc_press(struct bmp280_data *data, int *val) -{ - int ret; - __be32 tmp = 0; - u8 oss = data->oversampling_press; - - ret = bmp180_measure(data, BMP180_MEAS_PRESS_X(oss)); - if (ret) - return ret; - - ret = regmap_bulk_read(data->regmap, BMP180_REG_OUT_MSB, (u8 *)&tmp, 3); - if (ret) - return ret; - - *val = (be32_to_cpu(tmp) >> 8) >> (8 - oss); - - return 0; -} - -/* - * Returns pressure in Pa, resolution is 1 Pa. - * - * Taken from datasheet, Section 3.5, "Calculating pressure and temperature". - */ -static u32 bmp180_compensate_press(struct bmp280_data *data, s32 adc_press) -{ - int ret; - s32 x1, x2, x3, p; - s32 b3, b6; - u32 b4, b7; - s32 oss = data->oversampling_press; - struct bmp180_calib calib; - - ret = bmp180_read_calib(data, &calib); - if (ret < 0) { - dev_err(&data->client->dev, - "failed to read calibration coefficients\n"); - return ret; - } - - b6 = data->t_fine - 4000; - x1 = (calib.B2 * (b6 * b6 >> 12)) >> 11; - x2 = calib.AC2 * b6 >> 11; - x3 = x1 + x2; - b3 = ((((s32)calib.AC1 * 4 + x3) << oss) + 2) / 4; - x1 = calib.AC3 * b6 >> 13; - x2 = (calib.B1 * ((b6 * b6) >> 12)) >> 16; - x3 = (x1 + x2 + 2) >> 2; - b4 = calib.AC4 * (u32)(x3 + 32768) >> 15; - b7 = ((u32)adc_press - b3) * (50000 >> oss); - if (b7 < 0x80000000) - p = (b7 * 2) / b4; - else - p = (b7 / b4) * 2; - - x1 = (p >> 8) * (p >> 8); - x1 = (x1 * 3038) >> 16; - x2 = (-7357 * p) >> 16; - - return p + ((x1 + x2 + 3791) >> 4); -} - -static int bmp180_read_press(struct bmp280_data *data, - int *val, int *val2) -{ - int ret; - s32 adc_press; - u32 comp_press; - - /* Read and compensate temperature so we get a reading of t_fine. */ - ret = bmp180_read_temp(data, NULL); - if (ret) - return ret; - - ret = bmp180_read_adc_press(data, &adc_press); - if (ret) - return ret; - - comp_press = bmp180_compensate_press(data, adc_press); - - *val = comp_press; - *val2 = 1000; - - return IIO_VAL_FRACTIONAL; -} - -static int bmp180_chip_config(struct bmp280_data *data) -{ - return 0; -} - -static const int bmp180_oversampling_temp_avail[] = { 1 }; -static const int bmp180_oversampling_press_avail[] = { 1, 2, 4, 8 }; - -static const struct bmp280_chip_info bmp180_chip_info = { - .regmap_config = &bmp180_regmap_config, - - .oversampling_temp_avail = bmp180_oversampling_temp_avail, - .num_oversampling_temp_avail = - ARRAY_SIZE(bmp180_oversampling_temp_avail), - - .oversampling_press_avail = bmp180_oversampling_press_avail, - .num_oversampling_press_avail = - ARRAY_SIZE(bmp180_oversampling_press_avail), - - .chip_config = bmp180_chip_config, - .read_temp = bmp180_read_temp, - .read_press = bmp180_read_press, -}; - -static int bmp280_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - int ret; - struct iio_dev *indio_dev; - struct bmp280_data *data; - unsigned int chip_id; - struct gpio_desc *gpiod; - - indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); - if (!indio_dev) - return -ENOMEM; - - data = iio_priv(indio_dev); - mutex_init(&data->lock); - data->client = client; - - indio_dev->dev.parent = &client->dev; - indio_dev->name = id->name; - indio_dev->channels = bmp280_channels; - indio_dev->info = &bmp280_info; - indio_dev->modes = INDIO_DIRECT_MODE; - - switch (id->driver_data) { - case BMP180_CHIP_ID: - indio_dev->num_channels = 2; - data->chip_info = &bmp180_chip_info; - data->oversampling_press = ilog2(8); - data->oversampling_temp = ilog2(1); - data->start_up_time = 10; - break; - case BMP280_CHIP_ID: - indio_dev->num_channels = 2; - data->chip_info = &bmp280_chip_info; - data->oversampling_press = ilog2(16); - data->oversampling_temp = ilog2(2); - data->start_up_time = 2; - break; - case BME280_CHIP_ID: - indio_dev->num_channels = 3; - data->chip_info = &bme280_chip_info; - data->oversampling_press = ilog2(16); - data->oversampling_humid = ilog2(16); - data->oversampling_temp = ilog2(2); - data->start_up_time = 2; - break; - default: - return -EINVAL; - } - - /* Bring up regulators */ - data->vddd = devm_regulator_get(&client->dev, "vddd"); - if (IS_ERR(data->vddd)) { - dev_err(&client->dev, "failed to get VDDD regulator\n"); - return PTR_ERR(data->vddd); - } - ret = regulator_enable(data->vddd); - if (ret) { - dev_err(&client->dev, "failed to enable VDDD regulator\n"); - return ret; - } - data->vdda = devm_regulator_get(&client->dev, "vdda"); - if (IS_ERR(data->vdda)) { - dev_err(&client->dev, "failed to get VDDA regulator\n"); - ret = PTR_ERR(data->vddd); - goto out_disable_vddd; - } - ret = regulator_enable(data->vdda); - if (ret) { - dev_err(&client->dev, "failed to enable VDDA regulator\n"); - goto out_disable_vddd; - } - /* Wait to make sure we started up properly */ - mdelay(data->start_up_time); - - /* Bring chip out of reset if there is an assigned GPIO line */ - gpiod = devm_gpiod_get(&client->dev, "reset", GPIOD_OUT_HIGH); - /* Deassert the signal */ - if (!IS_ERR(gpiod)) { - dev_info(&client->dev, "release reset\n"); - gpiod_set_value(gpiod, 0); - } - - data->regmap = devm_regmap_init_i2c(client, - data->chip_info->regmap_config); - if (IS_ERR(data->regmap)) { - dev_err(&client->dev, "failed to allocate register map\n"); - ret = PTR_ERR(data->regmap); - goto out_disable_vdda; - } - - ret = regmap_read(data->regmap, BMP280_REG_ID, &chip_id); - if (ret < 0) - return ret; - if (chip_id != id->driver_data) { - dev_err(&client->dev, "bad chip id. expected %lx got %x\n", - id->driver_data, chip_id); - ret = -EINVAL; - goto out_disable_vdda; - } - - ret = data->chip_info->chip_config(data); - if (ret < 0) - goto out_disable_vdda; - - i2c_set_clientdata(client, indio_dev); - - ret = iio_device_register(indio_dev); - if (ret) - goto out_disable_vdda; - - return 0; - -out_disable_vdda: - regulator_disable(data->vdda); -out_disable_vddd: - regulator_disable(data->vddd); - return ret; -} - -static int bmp280_remove(struct i2c_client *client) -{ - struct iio_dev *indio_dev = i2c_get_clientdata(client); - struct bmp280_data *data = iio_priv(indio_dev); - - iio_device_unregister(indio_dev); - regulator_disable(data->vdda); - regulator_disable(data->vddd); - return 0; -} - -static const struct acpi_device_id bmp280_acpi_match[] = { - {"BMP0280", BMP280_CHIP_ID }, - {"BMP0180", BMP180_CHIP_ID }, - {"BMP0085", BMP180_CHIP_ID }, - {"BME0280", BME280_CHIP_ID }, - { }, -}; -MODULE_DEVICE_TABLE(acpi, bmp280_acpi_match); - -#ifdef CONFIG_OF -static const struct of_device_id bmp280_of_match[] = { - { .compatible = "bosch,bme280", .data = (void *)BME280_CHIP_ID }, - { .compatible = "bosch,bmp280", .data = (void *)BMP280_CHIP_ID }, - { .compatible = "bosch,bmp180", .data = (void *)BMP180_CHIP_ID }, - { .compatible = "bosch,bmp085", .data = (void *)BMP180_CHIP_ID }, - { }, -}; -MODULE_DEVICE_TABLE(of, bmp280_of_match); -#else -#define bmp280_of_match NULL -#endif - -static const struct i2c_device_id bmp280_id[] = { - {"bmp280", BMP280_CHIP_ID }, - {"bmp180", BMP180_CHIP_ID }, - {"bmp085", BMP180_CHIP_ID }, - {"bme280", BME280_CHIP_ID }, - { }, -}; -MODULE_DEVICE_TABLE(i2c, bmp280_id); - -static struct i2c_driver bmp280_driver = { - .driver = { - .name = "bmp280", - .acpi_match_table = ACPI_PTR(bmp280_acpi_match), - .of_match_table = of_match_ptr(bmp280_of_match), - }, - .probe = bmp280_probe, - .remove = bmp280_remove, - .id_table = bmp280_id, -}; -module_i2c_driver(bmp280_driver); - -MODULE_AUTHOR("Vlad Dogaru "); -MODULE_DESCRIPTION("Driver for Bosch Sensortec BMP180/BMP280 pressure and temperature sensor"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/iio/pressure/bmp280.h b/drivers/iio/pressure/bmp280.h new file mode 100644 index 0000000..b9fc28c --- /dev/null +++ b/drivers/iio/pressure/bmp280.h @@ -0,0 +1,108 @@ +#include +#include +#include + +/* BMP280 specific registers */ +#define BMP280_REG_HUMIDITY_LSB 0xFE +#define BMP280_REG_HUMIDITY_MSB 0xFD +#define BMP280_REG_TEMP_XLSB 0xFC +#define BMP280_REG_TEMP_LSB 0xFB +#define BMP280_REG_TEMP_MSB 0xFA +#define BMP280_REG_PRESS_XLSB 0xF9 +#define BMP280_REG_PRESS_LSB 0xF8 +#define BMP280_REG_PRESS_MSB 0xF7 + +#define BMP280_REG_CONFIG 0xF5 +#define BMP280_REG_CTRL_MEAS 0xF4 +#define BMP280_REG_STATUS 0xF3 +#define BMP280_REG_CTRL_HUMIDITY 0xF2 + +/* Due to non linear mapping, and data sizes we can't do a bulk read */ +#define BMP280_REG_COMP_H1 0xA1 +#define BMP280_REG_COMP_H2 0xE1 +#define BMP280_REG_COMP_H3 0xE3 +#define BMP280_REG_COMP_H4 0xE4 +#define BMP280_REG_COMP_H5 0xE5 +#define BMP280_REG_COMP_H6 0xE7 + +#define BMP280_REG_COMP_TEMP_START 0x88 +#define BMP280_COMP_TEMP_REG_COUNT 6 + +#define BMP280_REG_COMP_PRESS_START 0x8E +#define BMP280_COMP_PRESS_REG_COUNT 18 + +#define BMP280_FILTER_MASK (BIT(4) | BIT(3) | BIT(2)) +#define BMP280_FILTER_OFF 0 +#define BMP280_FILTER_2X BIT(2) +#define BMP280_FILTER_4X BIT(3) +#define BMP280_FILTER_8X (BIT(3) | BIT(2)) +#define BMP280_FILTER_16X BIT(4) + +#define BMP280_OSRS_HUMIDITY_MASK (BIT(2) | BIT(1) | BIT(0)) +#define BMP280_OSRS_HUMIDITIY_X(osrs_h) ((osrs_h) << 0) +#define BMP280_OSRS_HUMIDITY_SKIP 0 +#define BMP280_OSRS_HUMIDITY_1X BMP280_OSRS_HUMIDITIY_X(1) +#define BMP280_OSRS_HUMIDITY_2X BMP280_OSRS_HUMIDITIY_X(2) +#define BMP280_OSRS_HUMIDITY_4X BMP280_OSRS_HUMIDITIY_X(3) +#define BMP280_OSRS_HUMIDITY_8X BMP280_OSRS_HUMIDITIY_X(4) +#define BMP280_OSRS_HUMIDITY_16X BMP280_OSRS_HUMIDITIY_X(5) + +#define BMP280_OSRS_TEMP_MASK (BIT(7) | BIT(6) | BIT(5)) +#define BMP280_OSRS_TEMP_SKIP 0 +#define BMP280_OSRS_TEMP_X(osrs_t) ((osrs_t) << 5) +#define BMP280_OSRS_TEMP_1X BMP280_OSRS_TEMP_X(1) +#define BMP280_OSRS_TEMP_2X BMP280_OSRS_TEMP_X(2) +#define BMP280_OSRS_TEMP_4X BMP280_OSRS_TEMP_X(3) +#define BMP280_OSRS_TEMP_8X BMP280_OSRS_TEMP_X(4) +#define BMP280_OSRS_TEMP_16X BMP280_OSRS_TEMP_X(5) + +#define BMP280_OSRS_PRESS_MASK (BIT(4) | BIT(3) | BIT(2)) +#define BMP280_OSRS_PRESS_SKIP 0 +#define BMP280_OSRS_PRESS_X(osrs_p) ((osrs_p) << 2) +#define BMP280_OSRS_PRESS_1X BMP280_OSRS_PRESS_X(1) +#define BMP280_OSRS_PRESS_2X BMP280_OSRS_PRESS_X(2) +#define BMP280_OSRS_PRESS_4X BMP280_OSRS_PRESS_X(3) +#define BMP280_OSRS_PRESS_8X BMP280_OSRS_PRESS_X(4) +#define BMP280_OSRS_PRESS_16X BMP280_OSRS_PRESS_X(5) + +#define BMP280_MODE_MASK (BIT(1) | BIT(0)) +#define BMP280_MODE_SLEEP 0 +#define BMP280_MODE_FORCED BIT(0) +#define BMP280_MODE_NORMAL (BIT(1) | BIT(0)) + +/* BMP180 specific registers */ +#define BMP180_REG_OUT_XLSB 0xF8 +#define BMP180_REG_OUT_LSB 0xF7 +#define BMP180_REG_OUT_MSB 0xF6 + +#define BMP180_REG_CALIB_START 0xAA +#define BMP180_REG_CALIB_COUNT 22 + +#define BMP180_MEAS_SCO BIT(5) +#define BMP180_MEAS_TEMP (0x0E | BMP180_MEAS_SCO) +#define BMP180_MEAS_PRESS_X(oss) ((oss) << 6 | 0x14 | BMP180_MEAS_SCO) +#define BMP180_MEAS_PRESS_1X BMP180_MEAS_PRESS_X(0) +#define BMP180_MEAS_PRESS_2X BMP180_MEAS_PRESS_X(1) +#define BMP180_MEAS_PRESS_4X BMP180_MEAS_PRESS_X(2) +#define BMP180_MEAS_PRESS_8X BMP180_MEAS_PRESS_X(3) + +/* BMP180 and BMP280 common registers */ +#define BMP280_REG_CTRL_MEAS 0xF4 +#define BMP280_REG_RESET 0xE0 +#define BMP280_REG_ID 0xD0 + +#define BMP180_CHIP_ID 0x55 +#define BMP280_CHIP_ID 0x58 +#define BME280_CHIP_ID 0x60 +#define BMP280_SOFT_RESET_VAL 0xB6 + +/* Regmap configurations */ +extern const struct regmap_config bmp180_regmap_config; +extern const struct regmap_config bmp280_regmap_config; + +/* Probe called from different transports */ +int bmp280_common_probe(struct device *dev, + struct regmap *regmap, + unsigned int chip, + const char *name); +int bmp280_common_remove(struct device *dev); -- cgit v0.10.2 From 17118843a563c681aaafb29621befba02f28c592 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Thu, 30 Jun 2016 03:48:50 +0200 Subject: iio: pressure: bmp280: split off an I2C Kconfig entry This creates a separate BMP280_I2C Kconfig entry that gets selected by BMP280 for I2C transport. As we currently only support I2C transport there is not much practical change other than getting a separate object file (or module) for the I2C driver part. The old Kconfig symbol BMP280 will still select the stuff we need so that oldconfig and old defconfigs works fine. Tested-by: Akinobu Mita Signed-off-by: Linus Walleij Signed-off-by: Jonathan Cameron diff --git a/drivers/iio/pressure/Kconfig b/drivers/iio/pressure/Kconfig index 8d654f6..3d0d311 100644 --- a/drivers/iio/pressure/Kconfig +++ b/drivers/iio/pressure/Kconfig @@ -6,17 +6,24 @@ menu "Pressure sensors" config BMP280 - tristate "Bosch Sensortec BMP180 and BMP280 pressure sensor driver" + tristate "Bosch Sensortec BMP180/BMP280 pressure sensor I2C driver" depends on I2C depends on !(BMP085_I2C=y || BMP085_I2C=m) - select REGMAP_I2C + select REGMAP + select BMP280_I2C if (I2C) help Say yes here to build support for Bosch Sensortec BMP180 and BMP280 pressure and temperature sensors. Also supports the BE280 with - an additional humidty sensor channel. + an additional humidity sensor channel. - To compile this driver as a module, choose M here: the module - will be called bmp280. + To compile this driver as a module, choose M here: the modules + will be called bmp280-i2c and bmp280. + +config BMP280_I2C + tristate + depends on BMP280 + depends on I2C + select REGMAP_I2C config HID_SENSOR_PRESS depends on HID_SENSOR_HUB diff --git a/drivers/iio/pressure/Makefile b/drivers/iio/pressure/Makefile index 2d98a7f..736f430 100644 --- a/drivers/iio/pressure/Makefile +++ b/drivers/iio/pressure/Makefile @@ -4,7 +4,8 @@ # When adding new entries keep the list in alphabetical order obj-$(CONFIG_BMP280) += bmp280.o -bmp280-objs := bmp280-core.o bmp280-regmap.o bmp280-i2c.o +bmp280-objs := bmp280-core.o bmp280-regmap.o +obj-$(CONFIG_BMP280_I2C) += bmp280-i2c.o obj-$(CONFIG_HID_SENSOR_PRESS) += hid-sensor-press.o obj-$(CONFIG_HP03) += hp03.o obj-$(CONFIG_MPL115) += mpl115.o diff --git a/drivers/iio/pressure/bmp280-core.c b/drivers/iio/pressure/bmp280-core.c index 83b96fe..f1b5f8c 100644 --- a/drivers/iio/pressure/bmp280-core.c +++ b/drivers/iio/pressure/bmp280-core.c @@ -16,6 +16,7 @@ #define pr_fmt(fmt) "bmp280: " fmt #include +#include #include #include #include @@ -955,6 +956,7 @@ out_disable_vddd: regulator_disable(data->vddd); return ret; } +EXPORT_SYMBOL(bmp280_common_probe); int bmp280_common_remove(struct device *dev) { @@ -966,3 +968,8 @@ int bmp280_common_remove(struct device *dev) regulator_disable(data->vddd); return 0; } +EXPORT_SYMBOL(bmp280_common_remove); + +MODULE_AUTHOR("Vlad Dogaru "); +MODULE_DESCRIPTION("Driver for Bosch Sensortec BMP180/BMP280 pressure and temperature sensor"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/iio/pressure/bmp280-regmap.c b/drivers/iio/pressure/bmp280-regmap.c index 3341189..6807113 100644 --- a/drivers/iio/pressure/bmp280-regmap.c +++ b/drivers/iio/pressure/bmp280-regmap.c @@ -1,4 +1,5 @@ #include +#include #include #include "bmp280.h" @@ -37,6 +38,7 @@ const struct regmap_config bmp180_regmap_config = { .writeable_reg = bmp180_is_writeable_reg, .volatile_reg = bmp180_is_volatile_reg, }; +EXPORT_SYMBOL(bmp180_regmap_config); static bool bmp280_is_writeable_reg(struct device *dev, unsigned int reg) { @@ -79,3 +81,4 @@ const struct regmap_config bmp280_regmap_config = { .writeable_reg = bmp280_is_writeable_reg, .volatile_reg = bmp280_is_volatile_reg, }; +EXPORT_SYMBOL(bmp280_regmap_config); -- cgit v0.10.2 From b26b4e91700ff45d033eeaac91597d6d479378a4 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Thu, 30 Jun 2016 03:48:51 +0200 Subject: iio: pressure: bmp280: add SPI interface driver This patch mimics the SPI functionality found in the misc driver in drivers/misc/bh085-spi.c to make it possible to reuse the existing BMP280/BMP180/BMP085 driver with all clients of the other driver. The adoption is straight-forward since like the other driver, it is a simple matter of using regmap. This driver is also so obviously inspired/copied from the old misc driver in drivers/misc/bmp085.c that I just took the liberty to add in the authors of the other drivers + self in the core driver file. The MISC driver also supports a variant named "BMP181" so include that here to be complete in comparison to the old driver. The bus mapping code for SPI was written by Akinobu Mita. Signed-off-by: Akinobu Mita Tested-by: Akinobu Mita Signed-off-by: Linus Walleij Signed-off-by: Jonathan Cameron diff --git a/drivers/iio/pressure/Kconfig b/drivers/iio/pressure/Kconfig index 3d0d311..d130cdc 100644 --- a/drivers/iio/pressure/Kconfig +++ b/drivers/iio/pressure/Kconfig @@ -7,17 +7,20 @@ menu "Pressure sensors" config BMP280 tristate "Bosch Sensortec BMP180/BMP280 pressure sensor I2C driver" - depends on I2C + depends on (I2C || SPI_MASTER) depends on !(BMP085_I2C=y || BMP085_I2C=m) + depends on !(BMP085_SPI=y || BMP085_SPI=m) select REGMAP select BMP280_I2C if (I2C) + select BMP280_SPI if (SPI_MASTER) help Say yes here to build support for Bosch Sensortec BMP180 and BMP280 pressure and temperature sensors. Also supports the BE280 with an additional humidity sensor channel. - To compile this driver as a module, choose M here: the modules - will be called bmp280-i2c and bmp280. + To compile this driver as a module, choose M here: the core module + will be called bmp280 and you will also get bmp280-i2c for I2C + and/or bmp280-spi for SPI support. config BMP280_I2C tristate @@ -25,6 +28,12 @@ config BMP280_I2C depends on I2C select REGMAP_I2C +config BMP280_SPI + tristate + depends on BMP280 + depends on SPI_MASTER + select REGMAP + config HID_SENSOR_PRESS depends on HID_SENSOR_HUB select IIO_BUFFER diff --git a/drivers/iio/pressure/Makefile b/drivers/iio/pressure/Makefile index 736f430..7f395be 100644 --- a/drivers/iio/pressure/Makefile +++ b/drivers/iio/pressure/Makefile @@ -6,6 +6,7 @@ obj-$(CONFIG_BMP280) += bmp280.o bmp280-objs := bmp280-core.o bmp280-regmap.o obj-$(CONFIG_BMP280_I2C) += bmp280-i2c.o +obj-$(CONFIG_BMP280_SPI) += bmp280-spi.o obj-$(CONFIG_HID_SENSOR_PRESS) += hid-sensor-press.o obj-$(CONFIG_HP03) += hp03.o obj-$(CONFIG_MPL115) += mpl115.o diff --git a/drivers/iio/pressure/bmp280-core.c b/drivers/iio/pressure/bmp280-core.c index f1b5f8c..43bd0b0 100644 --- a/drivers/iio/pressure/bmp280-core.c +++ b/drivers/iio/pressure/bmp280-core.c @@ -1,5 +1,9 @@ /* + * Copyright (c) 2010 Christoph Mair + * Copyright (c) 2012 Bosch Sensortec GmbH + * Copyright (c) 2012 Unixphere AB * Copyright (c) 2014 Intel Corporation + * Copyright (c) 2016 Linus Walleij * * Driver for Bosch Sensortec BMP180 and BMP280 digital pressure sensor. * diff --git a/drivers/iio/pressure/bmp280-spi.c b/drivers/iio/pressure/bmp280-spi.c new file mode 100644 index 0000000..216e64b --- /dev/null +++ b/drivers/iio/pressure/bmp280-spi.c @@ -0,0 +1,123 @@ +/* + * SPI interface for the BMP280 driver + * + * Inspired by the older BMP085 driver drivers/misc/bmp085-spi.c + */ +#include +#include +#include +#include + +#include "bmp280.h" + +static int bmp280_regmap_spi_write(void *context, const void *data, + size_t count) +{ + struct device *dev = context; + struct spi_device *spi = to_spi_device(dev); + u8 buf[2]; + + memcpy(buf, data, 2); + /* + * The SPI register address (= full register address without bit 7) and + * the write command (bit7 = RW = '0') + */ + buf[0] &= ~0x80; + + return spi_write_then_read(spi, buf, 2, NULL, 0); +} + +static int bmp280_regmap_spi_read(void *context, const void *reg, + size_t reg_size, void *val, size_t val_size) +{ + struct device *dev = context; + struct spi_device *spi = to_spi_device(dev); + + return spi_write_then_read(spi, reg, reg_size, val, val_size); +} + +static struct regmap_bus bmp280_regmap_bus = { + .write = bmp280_regmap_spi_write, + .read = bmp280_regmap_spi_read, + .reg_format_endian_default = REGMAP_ENDIAN_BIG, + .val_format_endian_default = REGMAP_ENDIAN_BIG, +}; + +static int bmp280_spi_probe(struct spi_device *spi) +{ + const struct spi_device_id *id = spi_get_device_id(spi); + struct regmap *regmap; + const struct regmap_config *regmap_config; + int ret; + + spi->bits_per_word = 8; + ret = spi_setup(spi); + if (ret < 0) { + dev_err(&spi->dev, "spi_setup failed!\n"); + return ret; + } + + switch (id->driver_data) { + case BMP180_CHIP_ID: + regmap_config = &bmp180_regmap_config; + break; + case BMP280_CHIP_ID: + case BME280_CHIP_ID: + regmap_config = &bmp280_regmap_config; + break; + default: + return -EINVAL; + } + + regmap = devm_regmap_init(&spi->dev, + &bmp280_regmap_bus, + &spi->dev, + regmap_config); + if (IS_ERR(regmap)) { + dev_err(&spi->dev, "failed to allocate register map\n"); + return PTR_ERR(regmap); + } + + return bmp280_common_probe(&spi->dev, + regmap, + id->driver_data, + id->name); +} + +static int bmp280_spi_remove(struct spi_device *spi) +{ + return bmp280_common_remove(&spi->dev); +} + +static const struct of_device_id bmp280_of_spi_match[] = { + { .compatible = "bosch,bmp085", }, + { .compatible = "bosch,bmp180", }, + { .compatible = "bosch,bmp181", }, + { .compatible = "bosch,bmp280", }, + { .compatible = "bosch,bme280", }, + { }, +}; +MODULE_DEVICE_TABLE(of, bmp280_of_spi_match); + +static const struct spi_device_id bmp280_spi_id[] = { + { "bmp180", BMP180_CHIP_ID }, + { "bmp181", BMP180_CHIP_ID }, + { "bmp280", BMP280_CHIP_ID }, + { "bme280", BME280_CHIP_ID }, + { } +}; +MODULE_DEVICE_TABLE(spi, bmp280_spi_id); + +static struct spi_driver bmp280_spi_driver = { + .driver = { + .name = "bmp280", + .of_match_table = bmp280_of_spi_match, + }, + .id_table = bmp280_spi_id, + .probe = bmp280_spi_probe, + .remove = bmp280_spi_remove, +}; +module_spi_driver(bmp280_spi_driver); + +MODULE_DESCRIPTION("BMP280 SPI bus driver"); +MODULE_LICENSE("GPL"); -- cgit v0.10.2 From aae9539496510a728bfe7d555b3ecfd5a146359a Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Thu, 30 Jun 2016 03:48:52 +0200 Subject: iio: pressure: bmp280: add support for BMP085 EOC interrupt The first version of this sensor, BMP085, supports sending an End-of-Conversion (EOC) interrupt. Add code to support this using a completion, in a similar vein as drivers/misc/bmp085.c does. Make sure to check that we are given a rising edge, because the EOC line goes from low-to-high when the conversion is ready. Signed-off-by: Linus Walleij Signed-off-by: Jonathan Cameron diff --git a/drivers/iio/pressure/bmp280-core.c b/drivers/iio/pressure/bmp280-core.c index 43bd0b0..3ebd84f 100644 --- a/drivers/iio/pressure/bmp280-core.c +++ b/drivers/iio/pressure/bmp280-core.c @@ -27,6 +27,9 @@ #include #include #include +#include +#include /* For irq_get_irq_data() */ +#include #include "bmp280.h" @@ -34,6 +37,8 @@ struct bmp280_data { struct device *dev; struct mutex lock; struct regmap *regmap; + struct completion done; + bool use_eoc; const struct bmp280_chip_info *chip_info; struct regulator *vddd; struct regulator *vdda; @@ -595,16 +600,32 @@ static int bmp180_measure(struct bmp280_data *data, u8 ctrl_meas) unsigned int delay_us; unsigned int ctrl; + if (data->use_eoc) + init_completion(&data->done); + ret = regmap_write(data->regmap, BMP280_REG_CTRL_MEAS, ctrl_meas); if (ret) return ret; - if (ctrl_meas == BMP180_MEAS_TEMP) - delay_us = 4500; - else - delay_us = conversion_time_max[data->oversampling_press]; - - usleep_range(delay_us, delay_us + 1000); + if (data->use_eoc) { + /* + * If we have a completion interrupt, use it, wait up to + * 100ms. The longest conversion time listed is 76.5 ms for + * advanced resolution mode. + */ + ret = wait_for_completion_timeout(&data->done, + 1 + msecs_to_jiffies(100)); + if (!ret) + dev_err(data->dev, "timeout waiting for completion\n"); + } else { + if (ctrl_meas == BMP180_MEAS_TEMP) + delay_us = 4500; + else + delay_us = + conversion_time_max[data->oversampling_press]; + + usleep_range(delay_us, delay_us + 1000); + } ret = regmap_read(data->regmap, BMP280_REG_CTRL_MEAS, &ctrl); if (ret) @@ -846,10 +867,51 @@ static const struct bmp280_chip_info bmp180_chip_info = { .read_press = bmp180_read_press, }; +static irqreturn_t bmp085_eoc_irq(int irq, void *d) +{ + struct bmp280_data *data = d; + + complete(&data->done); + + return IRQ_HANDLED; +} + +static int bmp085_fetch_eoc_irq(struct device *dev, + const char *name, + int irq, + struct bmp280_data *data) +{ + unsigned long irq_trig; + int ret; + + irq_trig = irqd_get_trigger_type(irq_get_irq_data(irq)); + if (irq_trig != IRQF_TRIGGER_RISING) { + dev_err(dev, "non-rising trigger given for EOC interrupt, " + "trying to enforce it\n"); + irq_trig = IRQF_TRIGGER_RISING; + } + ret = devm_request_threaded_irq(dev, + irq, + bmp085_eoc_irq, + NULL, + irq_trig, + name, + data); + if (ret) { + /* Bail out without IRQ but keep the driver in place */ + dev_err(dev, "unable to request DRDY IRQ\n"); + return 0; + } + + data->use_eoc = true; + return 0; +} + int bmp280_common_probe(struct device *dev, struct regmap *regmap, unsigned int chip, - const char *name) + const char *name, + int irq) { int ret; struct iio_dev *indio_dev; @@ -948,6 +1010,17 @@ int bmp280_common_probe(struct device *dev, dev_set_drvdata(dev, indio_dev); + /* + * Attempt to grab an optional EOC IRQ - only the BMP085 has this + * however as it happens, the BMP085 shares the chip ID of BMP180 + * so we look for an IRQ if we have that. + */ + if (irq > 0 || (chip_id == BMP180_CHIP_ID)) { + ret = bmp085_fetch_eoc_irq(dev, name, irq, data); + if (ret) + goto out_disable_vdda; + } + ret = iio_device_register(indio_dev); if (ret) goto out_disable_vdda; diff --git a/drivers/iio/pressure/bmp280-i2c.c b/drivers/iio/pressure/bmp280-i2c.c index 7c70ee1..8cf8a90 100644 --- a/drivers/iio/pressure/bmp280-i2c.c +++ b/drivers/iio/pressure/bmp280-i2c.c @@ -33,7 +33,8 @@ static int bmp280_i2c_probe(struct i2c_client *client, return bmp280_common_probe(&client->dev, regmap, id->driver_data, - id->name); + id->name, + client->irq); } static int bmp280_i2c_remove(struct i2c_client *client) diff --git a/drivers/iio/pressure/bmp280-spi.c b/drivers/iio/pressure/bmp280-spi.c index 216e64b..cd365ba 100644 --- a/drivers/iio/pressure/bmp280-spi.c +++ b/drivers/iio/pressure/bmp280-spi.c @@ -81,7 +81,8 @@ static int bmp280_spi_probe(struct spi_device *spi) return bmp280_common_probe(&spi->dev, regmap, id->driver_data, - id->name); + id->name, + spi->irq); } static int bmp280_spi_remove(struct spi_device *spi) diff --git a/drivers/iio/pressure/bmp280.h b/drivers/iio/pressure/bmp280.h index b9fc28c..573334b 100644 --- a/drivers/iio/pressure/bmp280.h +++ b/drivers/iio/pressure/bmp280.h @@ -104,5 +104,6 @@ extern const struct regmap_config bmp280_regmap_config; int bmp280_common_probe(struct device *dev, struct regmap *regmap, unsigned int chip, - const char *name); + const char *name, + int irq); int bmp280_common_remove(struct device *dev); -- cgit v0.10.2 From 3d838118c6aa73ae28e49bd9a014e2e9bd6ed3ab Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Thu, 30 Jun 2016 03:48:53 +0200 Subject: iio: pressure: bmp280: add power management The PM280 has an internal standby-mode, but to really save power we should shut the sensor down and disconnect the power. With the proper .pm hooks we can enable both runtime and system power management of the sensor. We use the *force callbacks from the system PM hooks. When the sensor comes back we always reconfigure it to make sure it is ready to roll as expected. Cc: Ulf Hansson Signed-off-by: Linus Walleij Signed-off-by: Jonathan Cameron diff --git a/drivers/iio/pressure/bmp280-core.c b/drivers/iio/pressure/bmp280-core.c index 3ebd84f..f25df7f 100644 --- a/drivers/iio/pressure/bmp280-core.c +++ b/drivers/iio/pressure/bmp280-core.c @@ -30,6 +30,7 @@ #include #include /* For irq_get_irq_data() */ #include +#include #include "bmp280.h" @@ -336,6 +337,7 @@ static int bmp280_read_raw(struct iio_dev *indio_dev, int ret; struct bmp280_data *data = iio_priv(indio_dev); + pm_runtime_get_sync(data->dev); mutex_lock(&data->lock); switch (mask) { @@ -380,6 +382,8 @@ static int bmp280_read_raw(struct iio_dev *indio_dev, } mutex_unlock(&data->lock); + pm_runtime_mark_last_busy(data->dev); + pm_runtime_put_autosuspend(data->dev); return ret; } @@ -444,6 +448,7 @@ static int bmp280_write_raw(struct iio_dev *indio_dev, switch (mask) { case IIO_CHAN_INFO_OVERSAMPLING_RATIO: + pm_runtime_get_sync(data->dev); mutex_lock(&data->lock); switch (chan->type) { case IIO_HUMIDITYRELATIVE: @@ -460,6 +465,8 @@ static int bmp280_write_raw(struct iio_dev *indio_dev, break; } mutex_unlock(&data->lock); + pm_runtime_mark_last_busy(data->dev); + pm_runtime_put_autosuspend(data->dev); break; default: return -EINVAL; @@ -1021,12 +1028,29 @@ int bmp280_common_probe(struct device *dev, goto out_disable_vdda; } + /* Enable runtime PM */ + pm_runtime_get_noresume(dev); + pm_runtime_set_active(dev); + pm_runtime_enable(dev); + /* + * Set autosuspend to two orders of magnitude larger than the + * start-up time. + */ + pm_runtime_set_autosuspend_delay(dev, data->start_up_time *100); + pm_runtime_use_autosuspend(dev); + pm_runtime_put(dev); + ret = iio_device_register(indio_dev); if (ret) - goto out_disable_vdda; + goto out_runtime_pm_disable; + return 0; +out_runtime_pm_disable: + pm_runtime_get_sync(data->dev); + pm_runtime_put_noidle(data->dev); + pm_runtime_disable(data->dev); out_disable_vdda: regulator_disable(data->vdda); out_disable_vddd: @@ -1041,12 +1065,51 @@ int bmp280_common_remove(struct device *dev) struct bmp280_data *data = iio_priv(indio_dev); iio_device_unregister(indio_dev); + pm_runtime_get_sync(data->dev); + pm_runtime_put_noidle(data->dev); + pm_runtime_disable(data->dev); regulator_disable(data->vdda); regulator_disable(data->vddd); return 0; } EXPORT_SYMBOL(bmp280_common_remove); +#ifdef CONFIG_PM +static int bmp280_runtime_suspend(struct device *dev) +{ + struct bmp280_data *data = dev_get_drvdata(dev); + int ret; + + ret = regulator_disable(data->vdda); + if (ret) + return ret; + return regulator_disable(data->vddd); +} + +static int bmp280_runtime_resume(struct device *dev) +{ + struct bmp280_data *data = dev_get_drvdata(dev); + int ret; + + ret = regulator_enable(data->vddd); + if (ret) + return ret; + ret = regulator_enable(data->vdda); + if (ret) + return ret; + msleep(data->start_up_time); + return data->chip_info->chip_config(data); +} +#endif /* CONFIG_PM */ + +const struct dev_pm_ops bmp280_dev_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, + pm_runtime_force_resume) + SET_RUNTIME_PM_OPS(bmp280_runtime_suspend, + bmp280_runtime_resume, NULL) +}; +EXPORT_SYMBOL(bmp280_dev_pm_ops); + MODULE_AUTHOR("Vlad Dogaru "); MODULE_DESCRIPTION("Driver for Bosch Sensortec BMP180/BMP280 pressure and temperature sensor"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/iio/pressure/bmp280-i2c.c b/drivers/iio/pressure/bmp280-i2c.c index 8cf8a90..03742b1 100644 --- a/drivers/iio/pressure/bmp280-i2c.c +++ b/drivers/iio/pressure/bmp280-i2c.c @@ -78,6 +78,7 @@ static struct i2c_driver bmp280_i2c_driver = { .name = "bmp280", .acpi_match_table = ACPI_PTR(bmp280_acpi_i2c_match), .of_match_table = of_match_ptr(bmp280_of_i2c_match), + .pm = &bmp280_dev_pm_ops, }, .probe = bmp280_i2c_probe, .remove = bmp280_i2c_remove, diff --git a/drivers/iio/pressure/bmp280-spi.c b/drivers/iio/pressure/bmp280-spi.c index cd365ba..17bc955 100644 --- a/drivers/iio/pressure/bmp280-spi.c +++ b/drivers/iio/pressure/bmp280-spi.c @@ -113,6 +113,7 @@ static struct spi_driver bmp280_spi_driver = { .driver = { .name = "bmp280", .of_match_table = bmp280_of_spi_match, + .pm = &bmp280_dev_pm_ops, }, .id_table = bmp280_spi_id, .probe = bmp280_spi_probe, diff --git a/drivers/iio/pressure/bmp280.h b/drivers/iio/pressure/bmp280.h index 573334b..2c770e1 100644 --- a/drivers/iio/pressure/bmp280.h +++ b/drivers/iio/pressure/bmp280.h @@ -107,3 +107,6 @@ int bmp280_common_probe(struct device *dev, const char *name, int irq); int bmp280_common_remove(struct device *dev); + +/* PM ops */ +extern const struct dev_pm_ops bmp280_dev_pm_ops; -- cgit v0.10.2 From b33b7d5ac30616aca73cc13a3dc06ac45d166ea0 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Thu, 30 Jun 2016 03:48:54 +0200 Subject: iio: pressure: bmp280: read calibration data once The calibration data is described as coming from an E2PROM and that means it does not change. Just read it once at probe time and store it in the device state container. Also toss the calibration data into the entropy pool since it is device unique. Reviewed-by: Vlad Dogaru Signed-off-by: Linus Walleij Signed-off-by: Jonathan Cameron diff --git a/drivers/iio/pressure/bmp280-core.c b/drivers/iio/pressure/bmp280-core.c index f25df7f..6943688 100644 --- a/drivers/iio/pressure/bmp280-core.c +++ b/drivers/iio/pressure/bmp280-core.c @@ -31,9 +31,30 @@ #include /* For irq_get_irq_data() */ #include #include +#include #include "bmp280.h" +/* + * These enums are used for indexing into the array of calibration + * coefficients for BMP180. + */ +enum { AC1, AC2, AC3, AC4, AC5, AC6, B1, B2, MB, MC, MD }; + +struct bmp180_calib { + s16 AC1; + s16 AC2; + s16 AC3; + u16 AC4; + u16 AC5; + u16 AC6; + s16 B1; + s16 B2; + s16 MB; + s16 MC; + s16 MD; +}; + struct bmp280_data { struct device *dev; struct mutex lock; @@ -41,6 +62,7 @@ struct bmp280_data { struct completion done; bool use_eoc; const struct bmp280_chip_info *chip_info; + struct bmp180_calib calib; struct regulator *vddd; struct regulator *vdda; unsigned int start_up_time; /* in milliseconds */ @@ -663,26 +685,6 @@ static int bmp180_read_adc_temp(struct bmp280_data *data, int *val) return 0; } -/* - * These enums are used for indexing into the array of calibration - * coefficients for BMP180. - */ -enum { AC1, AC2, AC3, AC4, AC5, AC6, B1, B2, MB, MC, MD }; - -struct bmp180_calib { - s16 AC1; - s16 AC2; - s16 AC3; - u16 AC4; - u16 AC5; - u16 AC6; - s16 B1; - s16 B2; - s16 MB; - s16 MC; - s16 MD; -}; - static int bmp180_read_calib(struct bmp280_data *data, struct bmp180_calib *calib) { @@ -702,6 +704,9 @@ static int bmp180_read_calib(struct bmp280_data *data, return -EIO; } + /* Toss the calibration data into the entropy pool */ + add_device_randomness(buf, sizeof(buf)); + calib->AC1 = be16_to_cpu(buf[AC1]); calib->AC2 = be16_to_cpu(buf[AC2]); calib->AC3 = be16_to_cpu(buf[AC3]); @@ -725,19 +730,11 @@ static int bmp180_read_calib(struct bmp280_data *data, */ static s32 bmp180_compensate_temp(struct bmp280_data *data, s32 adc_temp) { - int ret; s32 x1, x2; - struct bmp180_calib calib; + struct bmp180_calib *calib = &data->calib; - ret = bmp180_read_calib(data, &calib); - if (ret < 0) { - dev_err(data->dev, - "failed to read calibration coefficients\n"); - return ret; - } - - x1 = ((adc_temp - calib.AC6) * calib.AC5) >> 15; - x2 = (calib.MC << 11) / (x1 + calib.MD); + x1 = ((adc_temp - calib->AC6) * calib->AC5) >> 15; + x2 = (calib->MC << 11) / (x1 + calib->MD); data->t_fine = x1 + x2; return (data->t_fine + 8) >> 4; @@ -792,29 +789,21 @@ static int bmp180_read_adc_press(struct bmp280_data *data, int *val) */ static u32 bmp180_compensate_press(struct bmp280_data *data, s32 adc_press) { - int ret; s32 x1, x2, x3, p; s32 b3, b6; u32 b4, b7; s32 oss = data->oversampling_press; - struct bmp180_calib calib; - - ret = bmp180_read_calib(data, &calib); - if (ret < 0) { - dev_err(data->dev, - "failed to read calibration coefficients\n"); - return ret; - } + struct bmp180_calib *calib = &data->calib; b6 = data->t_fine - 4000; - x1 = (calib.B2 * (b6 * b6 >> 12)) >> 11; - x2 = calib.AC2 * b6 >> 11; + x1 = (calib->B2 * (b6 * b6 >> 12)) >> 11; + x2 = calib->AC2 * b6 >> 11; x3 = x1 + x2; - b3 = ((((s32)calib.AC1 * 4 + x3) << oss) + 2) / 4; - x1 = calib.AC3 * b6 >> 13; - x2 = (calib.B1 * ((b6 * b6) >> 12)) >> 16; + b3 = ((((s32)calib->AC1 * 4 + x3) << oss) + 2) / 4; + x1 = calib->AC3 * b6 >> 13; + x2 = (calib->B1 * ((b6 * b6) >> 12)) >> 16; x3 = (x1 + x2 + 2) >> 2; - b4 = calib.AC4 * (u32)(x3 + 32768) >> 15; + b4 = calib->AC4 * (u32)(x3 + 32768) >> 15; b7 = ((u32)adc_press - b3) * (50000 >> oss); if (b7 < 0x80000000) p = (b7 * 2) / b4; @@ -1018,6 +1007,19 @@ int bmp280_common_probe(struct device *dev, dev_set_drvdata(dev, indio_dev); /* + * The BMP085 and BMP180 has calibration in an E2PROM, read it out + * at probe time. It will not change. + */ + if (chip_id == BMP180_CHIP_ID) { + ret = bmp180_read_calib(data, &data->calib); + if (ret < 0) { + dev_err(data->dev, + "failed to read calibration coefficients\n"); + goto out_disable_vdda; + } + } + + /* * Attempt to grab an optional EOC IRQ - only the BMP085 has this * however as it happens, the BMP085 shares the chip ID of BMP180 * so we look for an IRQ if we have that. -- cgit v0.10.2 From d3c4d0ab3b4e7cdfe5a209ba4d58bf5787e7c47f Mon Sep 17 00:00:00 2001 From: Raveendra Padasalagi Date: Tue, 28 Jun 2016 13:10:34 +0530 Subject: Documentation: DT: Add iproc-static-adc binding The patch adds devicetree binding document for broadcom's iproc-static-adc controller driver. Signed-off-by: Raveendra Padasalagi Reviewed-by: Ray Jui Reviewed-by: Scott Branden Acked-by: Rob Herring Signed-off-by: Jonathan Cameron diff --git a/Documentation/devicetree/bindings/iio/adc/brcm,iproc-static-adc.txt b/Documentation/devicetree/bindings/iio/adc/brcm,iproc-static-adc.txt new file mode 100644 index 0000000..caaaed7 --- /dev/null +++ b/Documentation/devicetree/bindings/iio/adc/brcm,iproc-static-adc.txt @@ -0,0 +1,41 @@ +* Broadcom's IPROC Static ADC controller + +Broadcom iProc ADC controller has 8 channels 10bit ADC. +Allows user to convert analog input voltage values to digital. + +Required properties: + +- compatible: Must be "brcm,iproc-static-adc" + +- adc-syscon: Handler of syscon node defining physical base address of the + controller and length of memory mapped region. + +- #io-channel-cells = <1>; As ADC has multiple outputs + refer to Documentation/devicetree/bindings/iio/iio-bindings.txt for details. + +- io-channel-ranges: + refer to Documentation/devicetree/bindings/iio/iio-bindings.txt for details. + +- clocks: Clock used for this block. + +- clock-names: Clock name should be given as tsc_clk. + +- interrupts: interrupt line number. + +For example: + + ts_adc_syscon: ts_adc_syscon@180a6000 { + compatible = "brcm,iproc-ts-adc-syscon","syscon"; + reg = <0x180a6000 0xc30>; + }; + + adc: adc@180a6000 { + compatible = "brcm,iproc-static-adc"; + adc-syscon = <&ts_adc_syscon>; + #io-channel-cells = <1>; + io-channel-ranges; + clocks = <&asiu_clks BCM_CYGNUS_ASIU_ADC_CLK>; + clock-names = "tsc_clk"; + interrupts = ; + status = "disabled"; + }; -- cgit v0.10.2 From 4324c97ecedcba8a548bcff9d620880e11359425 Mon Sep 17 00:00:00 2001 From: Raveendra Padasalagi Date: Tue, 28 Jun 2016 13:10:35 +0530 Subject: iio: Add driver for Broadcom iproc-static-adc This patch adds basic driver implementation for Broadcom's static adc controller used in iProc SoC's family. Signed-off-by: Raveendra Padasalagi Reviewed-by: Ray Jui Reviewed-by: Scott Branden Signed-off-by: Jonathan Cameron diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig index 25378c5..1de31bd 100644 --- a/drivers/iio/adc/Kconfig +++ b/drivers/iio/adc/Kconfig @@ -153,6 +153,18 @@ config AXP288_ADC To compile this driver as a module, choose M here: the module will be called axp288_adc. +config BCM_IPROC_ADC + tristate "Broadcom IPROC ADC driver" + depends on ARCH_BCM_IPROC || COMPILE_TEST + depends on MFD_SYSCON + default ARCH_BCM_CYGNUS + help + Say Y here if you want to add support for the Broadcom static + ADC driver. + + Broadcom iProc ADC driver. Broadcom iProc ADC controller has 8 + channels. The driver allows the user to read voltage values. + config BERLIN2_ADC tristate "Marvell Berlin2 ADC driver" depends on ARCH_BERLIN diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile index 38638d4..0ba0d50 100644 --- a/drivers/iio/adc/Makefile +++ b/drivers/iio/adc/Makefile @@ -16,6 +16,7 @@ obj-$(CONFIG_AD799X) += ad799x.o obj-$(CONFIG_AT91_ADC) += at91_adc.o obj-$(CONFIG_AT91_SAMA5D2_ADC) += at91-sama5d2_adc.o obj-$(CONFIG_AXP288_ADC) += axp288_adc.o +obj-$(CONFIG_BCM_IPROC_ADC) += bcm_iproc_adc.o obj-$(CONFIG_BERLIN2_ADC) += berlin2-adc.o obj-$(CONFIG_CC10001_ADC) += cc10001_adc.o obj-$(CONFIG_DA9150_GPADC) += da9150-gpadc.o diff --git a/drivers/iio/adc/bcm_iproc_adc.c b/drivers/iio/adc/bcm_iproc_adc.c new file mode 100644 index 0000000..21d38c8 --- /dev/null +++ b/drivers/iio/adc/bcm_iproc_adc.c @@ -0,0 +1,644 @@ +/* + * Copyright 2016 Broadcom + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License, version 2, as + * published by the Free Software Foundation (the "GPL"). + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License version 2 (GPLv2) for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 (GPLv2) along with this source code. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +/* Below Register's are common to IPROC ADC and Touchscreen IP */ +#define IPROC_REGCTL1 0x00 +#define IPROC_REGCTL2 0x04 +#define IPROC_INTERRUPT_THRES 0x08 +#define IPROC_INTERRUPT_MASK 0x0c +#define IPROC_INTERRUPT_STATUS 0x10 +#define IPROC_ANALOG_CONTROL 0x1c +#define IPROC_CONTROLLER_STATUS 0x14 +#define IPROC_AUX_DATA 0x20 +#define IPROC_SOFT_BYPASS_CONTROL 0x38 +#define IPROC_SOFT_BYPASS_DATA 0x3C + +/* IPROC ADC Channel register offsets */ +#define IPROC_ADC_CHANNEL_REGCTL1 0x800 +#define IPROC_ADC_CHANNEL_REGCTL2 0x804 +#define IPROC_ADC_CHANNEL_STATUS 0x808 +#define IPROC_ADC_CHANNEL_INTERRUPT_STATUS 0x80c +#define IPROC_ADC_CHANNEL_INTERRUPT_MASK 0x810 +#define IPROC_ADC_CHANNEL_DATA 0x814 +#define IPROC_ADC_CHANNEL_OFFSET 0x20 + +/* Bit definitions for IPROC_REGCTL2 */ +#define IPROC_ADC_AUXIN_SCAN_ENA BIT(0) +#define IPROC_ADC_PWR_LDO BIT(5) +#define IPROC_ADC_PWR_ADC BIT(4) +#define IPROC_ADC_PWR_BG BIT(3) +#define IPROC_ADC_CONTROLLER_EN BIT(17) + +/* Bit definitions for IPROC_INTERRUPT_MASK and IPROC_INTERRUPT_STATUS */ +#define IPROC_ADC_AUXDATA_RDY_INTR BIT(3) +#define IPROC_ADC_INTR 9 +#define IPROC_ADC_INTR_MASK (0xFF << IPROC_ADC_INTR) + +/* Bit definitions for IPROC_ANALOG_CONTROL */ +#define IPROC_ADC_CHANNEL_SEL 11 +#define IPROC_ADC_CHANNEL_SEL_MASK (0x7 << IPROC_ADC_CHANNEL_SEL) + +/* Bit definitions for IPROC_ADC_CHANNEL_REGCTL1 */ +#define IPROC_ADC_CHANNEL_ROUNDS 0x2 +#define IPROC_ADC_CHANNEL_ROUNDS_MASK (0x3F << IPROC_ADC_CHANNEL_ROUNDS) +#define IPROC_ADC_CHANNEL_MODE 0x1 +#define IPROC_ADC_CHANNEL_MODE_MASK (0x1 << IPROC_ADC_CHANNEL_MODE) +#define IPROC_ADC_CHANNEL_MODE_TDM 0x1 +#define IPROC_ADC_CHANNEL_MODE_SNAPSHOT 0x0 +#define IPROC_ADC_CHANNEL_ENABLE 0x0 +#define IPROC_ADC_CHANNEL_ENABLE_MASK 0x1 + +/* Bit definitions for IPROC_ADC_CHANNEL_REGCTL2 */ +#define IPROC_ADC_CHANNEL_WATERMARK 0x0 +#define IPROC_ADC_CHANNEL_WATERMARK_MASK \ + (0x3F << IPROC_ADC_CHANNEL_WATERMARK) + +#define IPROC_ADC_WATER_MARK_LEVEL 0x1 + +/* Bit definitions for IPROC_ADC_CHANNEL_STATUS */ +#define IPROC_ADC_CHANNEL_DATA_LOST 0x0 +#define IPROC_ADC_CHANNEL_DATA_LOST_MASK \ + (0x0 << IPROC_ADC_CHANNEL_DATA_LOST) +#define IPROC_ADC_CHANNEL_VALID_ENTERIES 0x1 +#define IPROC_ADC_CHANNEL_VALID_ENTERIES_MASK \ + (0xFF << IPROC_ADC_CHANNEL_VALID_ENTERIES) +#define IPROC_ADC_CHANNEL_TOTAL_ENTERIES 0x9 +#define IPROC_ADC_CHANNEL_TOTAL_ENTERIES_MASK \ + (0xFF << IPROC_ADC_CHANNEL_TOTAL_ENTERIES) + +/* Bit definitions for IPROC_ADC_CHANNEL_INTERRUPT_MASK */ +#define IPROC_ADC_CHANNEL_WTRMRK_INTR 0x0 +#define IPROC_ADC_CHANNEL_WTRMRK_INTR_MASK \ + (0x1 << IPROC_ADC_CHANNEL_WTRMRK_INTR) +#define IPROC_ADC_CHANNEL_FULL_INTR 0x1 +#define IPROC_ADC_CHANNEL_FULL_INTR_MASK \ + (0x1 << IPROC_ADC_IPROC_ADC_CHANNEL_FULL_INTR) +#define IPROC_ADC_CHANNEL_EMPTY_INTR 0x2 +#define IPROC_ADC_CHANNEL_EMPTY_INTR_MASK \ + (0x1 << IPROC_ADC_CHANNEL_EMPTY_INTR) + +#define IPROC_ADC_WATER_MARK_INTR_ENABLE 0x1 + +/* Number of time to retry a set of the interrupt mask reg */ +#define IPROC_ADC_INTMASK_RETRY_ATTEMPTS 10 + +#define IPROC_ADC_READ_TIMEOUT (HZ*2) + +#define iproc_adc_dbg_reg(dev, priv, reg) \ +do { \ + u32 val; \ + regmap_read(priv->regmap, reg, &val); \ + dev_dbg(dev, "%20s= 0x%08x\n", #reg, val); \ +} while (0) + +struct iproc_adc_priv { + struct regmap *regmap; + struct clk *adc_clk; + struct mutex mutex; + int irqno; + int chan_val; + int chan_id; + struct completion completion; +}; + +static void iproc_adc_reg_dump(struct iio_dev *indio_dev) +{ + struct device *dev = &indio_dev->dev; + struct iproc_adc_priv *adc_priv = iio_priv(indio_dev); + + iproc_adc_dbg_reg(dev, adc_priv, IPROC_REGCTL1); + iproc_adc_dbg_reg(dev, adc_priv, IPROC_REGCTL2); + iproc_adc_dbg_reg(dev, adc_priv, IPROC_INTERRUPT_THRES); + iproc_adc_dbg_reg(dev, adc_priv, IPROC_INTERRUPT_MASK); + iproc_adc_dbg_reg(dev, adc_priv, IPROC_INTERRUPT_STATUS); + iproc_adc_dbg_reg(dev, adc_priv, IPROC_CONTROLLER_STATUS); + iproc_adc_dbg_reg(dev, adc_priv, IPROC_ANALOG_CONTROL); + iproc_adc_dbg_reg(dev, adc_priv, IPROC_AUX_DATA); + iproc_adc_dbg_reg(dev, adc_priv, IPROC_SOFT_BYPASS_CONTROL); + iproc_adc_dbg_reg(dev, adc_priv, IPROC_SOFT_BYPASS_DATA); +} + +static irqreturn_t iproc_adc_interrupt_handler(int irq, void *data) +{ + u32 channel_intr_status; + u32 intr_status; + u32 intr_mask; + struct iio_dev *indio_dev = data; + struct iproc_adc_priv *adc_priv = iio_priv(indio_dev); + + /* + * This interrupt is shared with the touchscreen driver. + * Make sure this interrupt is intended for us. + * Handle only ADC channel specific interrupts. + */ + regmap_read(adc_priv->regmap, IPROC_INTERRUPT_STATUS, &intr_status); + regmap_read(adc_priv->regmap, IPROC_INTERRUPT_MASK, &intr_mask); + intr_status = intr_status & intr_mask; + channel_intr_status = (intr_status & IPROC_ADC_INTR_MASK) >> + IPROC_ADC_INTR; + if (channel_intr_status) + return IRQ_WAKE_THREAD; + + return IRQ_NONE; +} + +static irqreturn_t iproc_adc_interrupt_thread(int irq, void *data) +{ + irqreturn_t retval = IRQ_NONE; + struct iproc_adc_priv *adc_priv; + struct iio_dev *indio_dev = data; + unsigned int valid_entries; + u32 intr_status; + u32 intr_channels; + u32 channel_status; + u32 ch_intr_status; + + adc_priv = iio_priv(indio_dev); + + regmap_read(adc_priv->regmap, IPROC_INTERRUPT_STATUS, &intr_status); + dev_dbg(&indio_dev->dev, "iproc_adc_interrupt_thread(),INTRPT_STS:%x\n", + intr_status); + + intr_channels = (intr_status & IPROC_ADC_INTR_MASK) >> IPROC_ADC_INTR; + if (intr_channels) { + regmap_read(adc_priv->regmap, + IPROC_ADC_CHANNEL_INTERRUPT_STATUS + + IPROC_ADC_CHANNEL_OFFSET * adc_priv->chan_id, + &ch_intr_status); + + if (ch_intr_status & IPROC_ADC_CHANNEL_WTRMRK_INTR_MASK) { + regmap_read(adc_priv->regmap, + IPROC_ADC_CHANNEL_STATUS + + IPROC_ADC_CHANNEL_OFFSET * + adc_priv->chan_id, + &channel_status); + + valid_entries = ((channel_status & + IPROC_ADC_CHANNEL_VALID_ENTERIES_MASK) >> + IPROC_ADC_CHANNEL_VALID_ENTERIES); + if (valid_entries >= 1) { + regmap_read(adc_priv->regmap, + IPROC_ADC_CHANNEL_DATA + + IPROC_ADC_CHANNEL_OFFSET * + adc_priv->chan_id, + &adc_priv->chan_val); + complete(&adc_priv->completion); + } else { + dev_err(&indio_dev->dev, + "No data rcvd on channel %d\n", + adc_priv->chan_id); + } + regmap_write(adc_priv->regmap, + IPROC_ADC_CHANNEL_INTERRUPT_MASK + + IPROC_ADC_CHANNEL_OFFSET * + adc_priv->chan_id, + (ch_intr_status & + ~(IPROC_ADC_CHANNEL_WTRMRK_INTR_MASK))); + } + regmap_write(adc_priv->regmap, + IPROC_ADC_CHANNEL_INTERRUPT_STATUS + + IPROC_ADC_CHANNEL_OFFSET * adc_priv->chan_id, + ch_intr_status); + regmap_write(adc_priv->regmap, IPROC_INTERRUPT_STATUS, + intr_channels); + retval = IRQ_HANDLED; + } + + return retval; +} + +static int iproc_adc_do_read(struct iio_dev *indio_dev, + int channel, + u16 *p_adc_data) +{ + int read_len = 0; + u32 val; + u32 mask; + u32 val_check; + int failed_cnt = 0; + struct iproc_adc_priv *adc_priv = iio_priv(indio_dev); + + mutex_lock(&adc_priv->mutex); + + /* + * After a read is complete the ADC interrupts will be disabled so + * we can assume this section of code is safe from interrupts. + */ + adc_priv->chan_val = -1; + adc_priv->chan_id = channel; + + reinit_completion(&adc_priv->completion); + /* Clear any pending interrupt */ + regmap_update_bits(adc_priv->regmap, IPROC_INTERRUPT_STATUS, + IPROC_ADC_INTR_MASK | IPROC_ADC_AUXDATA_RDY_INTR, + ((0x0 << channel) << IPROC_ADC_INTR) | + IPROC_ADC_AUXDATA_RDY_INTR); + + /* Configure channel for snapshot mode and enable */ + val = (BIT(IPROC_ADC_CHANNEL_ROUNDS) | + (IPROC_ADC_CHANNEL_MODE_SNAPSHOT << IPROC_ADC_CHANNEL_MODE) | + (0x1 << IPROC_ADC_CHANNEL_ENABLE)); + + mask = IPROC_ADC_CHANNEL_ROUNDS_MASK | IPROC_ADC_CHANNEL_MODE_MASK | + IPROC_ADC_CHANNEL_ENABLE_MASK; + regmap_update_bits(adc_priv->regmap, (IPROC_ADC_CHANNEL_REGCTL1 + + IPROC_ADC_CHANNEL_OFFSET * channel), + mask, val); + + /* Set the Watermark for a channel */ + regmap_update_bits(adc_priv->regmap, (IPROC_ADC_CHANNEL_REGCTL2 + + IPROC_ADC_CHANNEL_OFFSET * channel), + IPROC_ADC_CHANNEL_WATERMARK_MASK, + 0x1); + + /* Enable water mark interrupt */ + regmap_update_bits(adc_priv->regmap, (IPROC_ADC_CHANNEL_INTERRUPT_MASK + + IPROC_ADC_CHANNEL_OFFSET * + channel), + IPROC_ADC_CHANNEL_WTRMRK_INTR_MASK, + IPROC_ADC_WATER_MARK_INTR_ENABLE); + regmap_read(adc_priv->regmap, IPROC_INTERRUPT_MASK, &val); + + /* Enable ADC interrupt for a channel */ + val |= (BIT(channel) << IPROC_ADC_INTR); + regmap_write(adc_priv->regmap, IPROC_INTERRUPT_MASK, val); + + /* + * There seems to be a very rare issue where writing to this register + * does not take effect. To work around the issue we will try multiple + * writes. In total we will spend about 10*10 = 100 us attempting this. + * Testing has shown that this may loop a few time, but we have never + * hit the full count. + */ + regmap_read(adc_priv->regmap, IPROC_INTERRUPT_MASK, &val_check); + while (val_check != val) { + failed_cnt++; + + if (failed_cnt > IPROC_ADC_INTMASK_RETRY_ATTEMPTS) + break; + + udelay(10); + regmap_update_bits(adc_priv->regmap, IPROC_INTERRUPT_MASK, + IPROC_ADC_INTR_MASK, + ((0x1 << channel) << + IPROC_ADC_INTR)); + + regmap_read(adc_priv->regmap, IPROC_INTERRUPT_MASK, &val_check); + } + + if (failed_cnt) { + dev_dbg(&indio_dev->dev, + "IntMask failed (%d times)", failed_cnt); + if (failed_cnt > IPROC_ADC_INTMASK_RETRY_ATTEMPTS) { + dev_err(&indio_dev->dev, + "IntMask set failed. Read will likely fail."); + read_len = -EIO; + goto adc_err; + }; + } + regmap_read(adc_priv->regmap, IPROC_INTERRUPT_MASK, &val_check); + + if (wait_for_completion_timeout(&adc_priv->completion, + IPROC_ADC_READ_TIMEOUT) > 0) { + + /* Only the lower 16 bits are relevant */ + *p_adc_data = adc_priv->chan_val & 0xFFFF; + read_len = sizeof(*p_adc_data); + + } else { + /* + * We never got the interrupt, something went wrong. + * Perhaps the interrupt may still be coming, we do not want + * that now. Lets disable the ADC interrupt, and clear the + * status to put it back in to normal state. + */ + read_len = -ETIMEDOUT; + goto adc_err; + } + mutex_unlock(&adc_priv->mutex); + + return read_len; + +adc_err: + regmap_update_bits(adc_priv->regmap, IPROC_INTERRUPT_MASK, + IPROC_ADC_INTR_MASK, + ((0x0 << channel) << IPROC_ADC_INTR)); + + regmap_update_bits(adc_priv->regmap, IPROC_INTERRUPT_STATUS, + IPROC_ADC_INTR_MASK, + ((0x0 << channel) << IPROC_ADC_INTR)); + + dev_err(&indio_dev->dev, "Timed out waiting for ADC data!\n"); + iproc_adc_reg_dump(indio_dev); + mutex_unlock(&adc_priv->mutex); + + return read_len; +} + +static int iproc_adc_enable(struct iio_dev *indio_dev) +{ + u32 val; + u32 channel_id; + struct iproc_adc_priv *adc_priv = iio_priv(indio_dev); + int ret; + + /* Set i_amux = 3b'000, select channel 0 */ + ret = regmap_update_bits(adc_priv->regmap, IPROC_ANALOG_CONTROL, + IPROC_ADC_CHANNEL_SEL_MASK, 0); + if (ret) { + dev_err(&indio_dev->dev, + "failed to write IPROC_ANALOG_CONTROL %d\n", ret); + return ret; + } + adc_priv->chan_val = -1; + + /* + * PWR up LDO, ADC, and Band Gap (0 to enable) + * Also enable ADC controller (set high) + */ + ret = regmap_read(adc_priv->regmap, IPROC_REGCTL2, &val); + if (ret) { + dev_err(&indio_dev->dev, + "failed to read IPROC_REGCTL2 %d\n", ret); + return ret; + } + + val &= ~(IPROC_ADC_PWR_LDO | IPROC_ADC_PWR_ADC | IPROC_ADC_PWR_BG); + + ret = regmap_write(adc_priv->regmap, IPROC_REGCTL2, val); + if (ret) { + dev_err(&indio_dev->dev, + "failed to write IPROC_REGCTL2 %d\n", ret); + return ret; + } + + ret = regmap_read(adc_priv->regmap, IPROC_REGCTL2, &val); + if (ret) { + dev_err(&indio_dev->dev, + "failed to read IPROC_REGCTL2 %d\n", ret); + return ret; + } + + val |= IPROC_ADC_CONTROLLER_EN; + ret = regmap_write(adc_priv->regmap, IPROC_REGCTL2, val); + if (ret) { + dev_err(&indio_dev->dev, + "failed to write IPROC_REGCTL2 %d\n", ret); + return ret; + } + + for (channel_id = 0; channel_id < indio_dev->num_channels; + channel_id++) { + ret = regmap_write(adc_priv->regmap, + IPROC_ADC_CHANNEL_INTERRUPT_MASK + + IPROC_ADC_CHANNEL_OFFSET * channel_id, 0); + if (ret) { + dev_err(&indio_dev->dev, + "failed to write ADC_CHANNEL_INTERRUPT_MASK %d\n", + ret); + return ret; + } + + ret = regmap_write(adc_priv->regmap, + IPROC_ADC_CHANNEL_INTERRUPT_STATUS + + IPROC_ADC_CHANNEL_OFFSET * channel_id, 0); + if (ret) { + dev_err(&indio_dev->dev, + "failed to write ADC_CHANNEL_INTERRUPT_STATUS %d\n", + ret); + return ret; + } + } + + return 0; +} + +static void iproc_adc_disable(struct iio_dev *indio_dev) +{ + u32 val; + int ret; + struct iproc_adc_priv *adc_priv = iio_priv(indio_dev); + + ret = regmap_read(adc_priv->regmap, IPROC_REGCTL2, &val); + if (ret) { + dev_err(&indio_dev->dev, + "failed to read IPROC_REGCTL2 %d\n", ret); + return; + } + + val &= ~IPROC_ADC_CONTROLLER_EN; + ret = regmap_write(adc_priv->regmap, IPROC_REGCTL2, val); + if (ret) { + dev_err(&indio_dev->dev, + "failed to write IPROC_REGCTL2 %d\n", ret); + return; + } +} + +static int iproc_adc_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, + int *val2, + long mask) +{ + u16 adc_data; + int err; + + switch (mask) { + case IIO_CHAN_INFO_RAW: + err = iproc_adc_do_read(indio_dev, chan->channel, &adc_data); + if (err < 0) + return err; + *val = adc_data; + return IIO_VAL_INT; + case IIO_CHAN_INFO_SCALE: + switch (chan->type) { + case IIO_VOLTAGE: + *val = 1800; + *val2 = 10; + return IIO_VAL_FRACTIONAL_LOG2; + default: + return -EINVAL; + } + default: + return -EINVAL; + } +} + +static const struct iio_info iproc_adc_iio_info = { + .read_raw = &iproc_adc_read_raw, + .driver_module = THIS_MODULE, +}; + +#define IPROC_ADC_CHANNEL(_index, _id) { \ + .type = IIO_VOLTAGE, \ + .indexed = 1, \ + .channel = _index, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ + .datasheet_name = _id, \ +} + +static const struct iio_chan_spec iproc_adc_iio_channels[] = { + IPROC_ADC_CHANNEL(0, "adc0"), + IPROC_ADC_CHANNEL(1, "adc1"), + IPROC_ADC_CHANNEL(2, "adc2"), + IPROC_ADC_CHANNEL(3, "adc3"), + IPROC_ADC_CHANNEL(4, "adc4"), + IPROC_ADC_CHANNEL(5, "adc5"), + IPROC_ADC_CHANNEL(6, "adc6"), + IPROC_ADC_CHANNEL(7, "adc7"), +}; + +static int iproc_adc_probe(struct platform_device *pdev) +{ + struct iproc_adc_priv *adc_priv; + struct iio_dev *indio_dev = NULL; + int ret; + + indio_dev = devm_iio_device_alloc(&pdev->dev, + sizeof(*adc_priv)); + if (!indio_dev) { + dev_err(&pdev->dev, "failed to allocate iio device\n"); + return -ENOMEM; + } + + adc_priv = iio_priv(indio_dev); + platform_set_drvdata(pdev, indio_dev); + + mutex_init(&adc_priv->mutex); + + init_completion(&adc_priv->completion); + + adc_priv->regmap = syscon_regmap_lookup_by_phandle(pdev->dev.of_node, + "adc-syscon"); + if (IS_ERR(adc_priv->regmap)) { + dev_err(&pdev->dev, "failed to get handle for tsc syscon\n"); + ret = PTR_ERR(adc_priv->regmap); + return ret; + } + + adc_priv->adc_clk = devm_clk_get(&pdev->dev, "tsc_clk"); + if (IS_ERR(adc_priv->adc_clk)) { + dev_err(&pdev->dev, + "failed getting clock tsc_clk\n"); + ret = PTR_ERR(adc_priv->adc_clk); + return ret; + } + + adc_priv->irqno = platform_get_irq(pdev, 0); + if (adc_priv->irqno <= 0) { + dev_err(&pdev->dev, "platform_get_irq failed\n"); + ret = -ENODEV; + return ret; + } + + ret = regmap_update_bits(adc_priv->regmap, IPROC_REGCTL2, + IPROC_ADC_AUXIN_SCAN_ENA, 0); + if (ret) { + dev_err(&pdev->dev, "failed to write IPROC_REGCTL2 %d\n", ret); + return ret; + } + + ret = devm_request_threaded_irq(&pdev->dev, adc_priv->irqno, + iproc_adc_interrupt_thread, + iproc_adc_interrupt_handler, + IRQF_SHARED, "iproc-adc", indio_dev); + if (ret) { + dev_err(&pdev->dev, "request_irq error %d\n", ret); + return ret; + } + + ret = clk_prepare_enable(adc_priv->adc_clk); + if (ret) { + dev_err(&pdev->dev, + "clk_prepare_enable failed %d\n", ret); + return ret; + } + + ret = iproc_adc_enable(indio_dev); + if (ret) { + dev_err(&pdev->dev, "failed to enable adc %d\n", ret); + goto err_adc_enable; + } + + indio_dev->name = "iproc-static-adc"; + indio_dev->dev.parent = &pdev->dev; + indio_dev->dev.of_node = pdev->dev.of_node; + indio_dev->info = &iproc_adc_iio_info; + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->channels = iproc_adc_iio_channels; + indio_dev->num_channels = ARRAY_SIZE(iproc_adc_iio_channels); + + ret = iio_device_register(indio_dev); + if (ret) { + dev_err(&pdev->dev, "iio_device_register failed:err %d\n", ret); + goto err_clk; + } + + return 0; + +err_clk: + iproc_adc_disable(indio_dev); +err_adc_enable: + clk_disable_unprepare(adc_priv->adc_clk); + + return ret; +} + +static int iproc_adc_remove(struct platform_device *pdev) +{ + struct iio_dev *indio_dev = platform_get_drvdata(pdev); + struct iproc_adc_priv *adc_priv = iio_priv(indio_dev); + + iio_device_unregister(indio_dev); + iproc_adc_disable(indio_dev); + clk_disable_unprepare(adc_priv->adc_clk); + + return 0; +} + +static const struct of_device_id iproc_adc_of_match[] = { + {.compatible = "brcm,iproc-static-adc", }, + { }, +}; +MODULE_DEVICE_TABLE(of, iproc_adc_of_match); + +static struct platform_driver iproc_adc_driver = { + .probe = iproc_adc_probe, + .remove = iproc_adc_remove, + .driver = { + .name = "iproc-static-adc", + .of_match_table = of_match_ptr(iproc_adc_of_match), + }, +}; +module_platform_driver(iproc_adc_driver); + +MODULE_DESCRIPTION("Broadcom iProc ADC controller driver"); +MODULE_AUTHOR("Raveendra Padasalagi "); +MODULE_LICENSE("GPL v2"); -- cgit v0.10.2 From bf61f5d2266cc6c117483c8ca4c73771a32e2fba Mon Sep 17 00:00:00 2001 From: Steffen Trumtrar Date: Thu, 21 Apr 2016 12:49:00 +0200 Subject: iio: bmg160: add callbacks for the filter frequency The filter frequency and sample rate have a fixed relationship. Only the filter frequency is unique, however. Currently the driver ignores the filter settings for 32 Hz and 64 Hz. This patch adds the necessary callbacks to be able to configure and read the filter setting from sysfs. Signed-off-by: Steffen Trumtrar Signed-off-by: Jonathan Cameron diff --git a/drivers/iio/gyro/bmg160_core.c b/drivers/iio/gyro/bmg160_core.c index 8155251..f7fcfa8 100644 --- a/drivers/iio/gyro/bmg160_core.c +++ b/drivers/iio/gyro/bmg160_core.c @@ -50,6 +50,7 @@ #define BMG160_REG_PMU_BW 0x10 #define BMG160_NO_FILTER 0 #define BMG160_DEF_BW 100 +#define BMG160_REG_PMU_BW_RES BIT(7) #define BMG160_REG_INT_MAP_0 0x17 #define BMG160_INT_MAP_0_BIT_ANY BIT(1) @@ -100,7 +101,6 @@ struct bmg160_data { struct iio_trigger *motion_trig; struct mutex mutex; s16 buffer[8]; - u8 bw_bits; u32 dps_range; int ev_enable_state; int slope_thres; @@ -117,13 +117,16 @@ enum bmg160_axis { }; static const struct { - int val; + int odr; + int filter; int bw_bits; -} bmg160_samp_freq_table[] = { {100, 0x07}, - {200, 0x06}, - {400, 0x03}, - {1000, 0x02}, - {2000, 0x01} }; +} bmg160_samp_freq_table[] = { {100, 32, 0x07}, + {200, 64, 0x06}, + {100, 12, 0x05}, + {200, 23, 0x04}, + {400, 47, 0x03}, + {1000, 116, 0x02}, + {2000, 230, 0x01} }; static const struct { int scale; @@ -153,7 +156,7 @@ static int bmg160_convert_freq_to_bit(int val) int i; for (i = 0; i < ARRAY_SIZE(bmg160_samp_freq_table); ++i) { - if (bmg160_samp_freq_table[i].val == val) + if (bmg160_samp_freq_table[i].odr == val) return bmg160_samp_freq_table[i].bw_bits; } @@ -176,7 +179,53 @@ static int bmg160_set_bw(struct bmg160_data *data, int val) return ret; } - data->bw_bits = bw_bits; + return 0; +} + +static int bmg160_get_filter(struct bmg160_data *data, int *val) +{ + struct device *dev = regmap_get_device(data->regmap); + int ret; + int i; + unsigned int bw_bits; + + ret = regmap_read(data->regmap, BMG160_REG_PMU_BW, &bw_bits); + if (ret < 0) { + dev_err(dev, "Error reading reg_pmu_bw\n"); + return ret; + } + + /* Ignore the readonly reserved bit. */ + bw_bits &= ~BMG160_REG_PMU_BW_RES; + + for (i = 0; i < ARRAY_SIZE(bmg160_samp_freq_table); ++i) { + if (bmg160_samp_freq_table[i].bw_bits == bw_bits) + break; + } + + *val = bmg160_samp_freq_table[i].filter; + + return ret ? ret : IIO_VAL_INT; +} + + +static int bmg160_set_filter(struct bmg160_data *data, int val) +{ + struct device *dev = regmap_get_device(data->regmap); + int ret; + int i; + + for (i = 0; i < ARRAY_SIZE(bmg160_samp_freq_table); ++i) { + if (bmg160_samp_freq_table[i].filter == val) + break; + } + + ret = regmap_write(data->regmap, BMG160_REG_PMU_BW, + bmg160_samp_freq_table[i].bw_bits); + if (ret < 0) { + dev_err(dev, "Error writing reg_pmu_bw\n"); + return ret; + } return 0; } @@ -386,11 +435,23 @@ static int bmg160_setup_new_data_interrupt(struct bmg160_data *data, static int bmg160_get_bw(struct bmg160_data *data, int *val) { + struct device *dev = regmap_get_device(data->regmap); int i; + unsigned int bw_bits; + int ret; + + ret = regmap_read(data->regmap, BMG160_REG_PMU_BW, &bw_bits); + if (ret < 0) { + dev_err(dev, "Error reading reg_pmu_bw\n"); + return ret; + } + + /* Ignore the readonly reserved bit. */ + bw_bits &= ~BMG160_REG_PMU_BW_RES; for (i = 0; i < ARRAY_SIZE(bmg160_samp_freq_table); ++i) { - if (bmg160_samp_freq_table[i].bw_bits == data->bw_bits) { - *val = bmg160_samp_freq_table[i].val; + if (bmg160_samp_freq_table[i].bw_bits == bw_bits) { + *val = bmg160_samp_freq_table[i].odr; return IIO_VAL_INT; } } @@ -507,6 +568,8 @@ static int bmg160_read_raw(struct iio_dev *indio_dev, return IIO_VAL_INT; } else return -EINVAL; + case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY: + return bmg160_get_filter(data, val); case IIO_CHAN_INFO_SCALE: *val = 0; switch (chan->type) { @@ -571,6 +634,26 @@ static int bmg160_write_raw(struct iio_dev *indio_dev, ret = bmg160_set_power_state(data, false); mutex_unlock(&data->mutex); return ret; + case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY: + if (val2) + return -EINVAL; + + mutex_lock(&data->mutex); + ret = bmg160_set_power_state(data, true); + if (ret < 0) { + bmg160_set_power_state(data, false); + mutex_unlock(&data->mutex); + return ret; + } + ret = bmg160_set_filter(data, val); + if (ret < 0) { + bmg160_set_power_state(data, false); + mutex_unlock(&data->mutex); + return ret; + } + ret = bmg160_set_power_state(data, false); + mutex_unlock(&data->mutex); + return ret; case IIO_CHAN_INFO_SCALE: if (val) return -EINVAL; @@ -728,7 +811,8 @@ static const struct iio_event_spec bmg160_event = { .channel2 = IIO_MOD_##_axis, \ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \ - BIT(IIO_CHAN_INFO_SAMP_FREQ), \ + BIT(IIO_CHAN_INFO_SAMP_FREQ) | \ + BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY), \ .scan_index = AXIS_##_axis, \ .scan_type = { \ .sign = 's', \ -- cgit v0.10.2 From 55389e8bc5dce8931d9c46d83c534c4997565e97 Mon Sep 17 00:00:00 2001 From: Florian Vaussard Date: Thu, 30 Jun 2016 09:43:05 +0200 Subject: iio: adc: max1363: Add device tree binding documentation Add the device tree documentation for all the supported parts. Mandatory binding is the compatible string and the slave I2C address. Optional properties can be used to specify the Vcc / Vref regulators, as well as the IRQ line if available. Acked-by: Rob Herring Signed-off-by: Florian Vaussard Signed-off-by: Jonathan Cameron diff --git a/Documentation/devicetree/bindings/iio/adc/max1363.txt b/Documentation/devicetree/bindings/iio/adc/max1363.txt new file mode 100644 index 0000000..94a9011 --- /dev/null +++ b/Documentation/devicetree/bindings/iio/adc/max1363.txt @@ -0,0 +1,63 @@ +* Maxim 1x3x/136x/116xx Analog to Digital Converter (ADC) + +The node for this driver must be a child node of a I2C controller, hence +all mandatory properties for your controller must be specified. See directory: + + Documentation/devicetree/bindings/i2c + +for more details. + +Required properties: + - compatible: Should be one of + "maxim,max1361" + "maxim,max1362" + "maxim,max1363" + "maxim,max1364" + "maxim,max1036" + "maxim,max1037" + "maxim,max1038" + "maxim,max1039" + "maxim,max1136" + "maxim,max1137" + "maxim,max1138" + "maxim,max1139" + "maxim,max1236" + "maxim,max1237" + "maxim,max1238" + "maxim,max1239" + "maxim,max11600" + "maxim,max11601" + "maxim,max11602" + "maxim,max11603" + "maxim,max11604" + "maxim,max11605" + "maxim,max11606" + "maxim,max11607" + "maxim,max11608" + "maxim,max11609" + "maxim,max11610" + "maxim,max11611" + "maxim,max11612" + "maxim,max11613" + "maxim,max11614" + "maxim,max11615" + "maxim,max11616" + "maxim,max11617" + "maxim,max11644" + "maxim,max11645" + "maxim,max11646" + "maxim,max11647" + - reg: Should contain the ADC I2C address + +Optional properties: + - vcc-supply: phandle to the regulator that provides power to the ADC. + - vref-supply: phandle to the regulator for ADC reference voltage. + - interrupts: IRQ line for the ADC. If not used the driver will use + polling. + +Example: +adc: max11644@36 { + compatible = "maxim,max11644"; + reg = <0x36>; + vref-supply = <&adc_vref>; +}; -- cgit v0.10.2 From 152c9aa00d546dac55095f620ea068965ef06dc7 Mon Sep 17 00:00:00 2001 From: Florian Vaussard Date: Thu, 30 Jun 2016 09:43:06 +0200 Subject: iio: adc: max1363: Add device tree binding This patch adds the necessary device tree binding to allow DT probing of currently supported parts. Signed-off-by: Florian Vaussard Signed-off-by: Jonathan Cameron diff --git a/drivers/iio/adc/max1363.c b/drivers/iio/adc/max1363.c index 73af306..3b53c2e 100644 --- a/drivers/iio/adc/max1363.c +++ b/drivers/iio/adc/max1363.c @@ -25,6 +25,8 @@ #include #include #include +#include +#include #include #include @@ -1517,6 +1519,56 @@ done: return IRQ_HANDLED; } +#ifdef CONFIG_OF + +#define MAX1363_COMPATIBLE(of_compatible, cfg) { \ + .compatible = of_compatible, \ + .data = &max1363_chip_info_tbl[cfg], \ +} + +static const struct of_device_id max1363_of_match[] = { + MAX1363_COMPATIBLE("maxim,max1361", max1361), + MAX1363_COMPATIBLE("maxim,max1362", max1362), + MAX1363_COMPATIBLE("maxim,max1363", max1363), + MAX1363_COMPATIBLE("maxim,max1364", max1364), + MAX1363_COMPATIBLE("maxim,max1036", max1036), + MAX1363_COMPATIBLE("maxim,max1037", max1037), + MAX1363_COMPATIBLE("maxim,max1038", max1038), + MAX1363_COMPATIBLE("maxim,max1039", max1039), + MAX1363_COMPATIBLE("maxim,max1136", max1136), + MAX1363_COMPATIBLE("maxim,max1137", max1137), + MAX1363_COMPATIBLE("maxim,max1138", max1138), + MAX1363_COMPATIBLE("maxim,max1139", max1139), + MAX1363_COMPATIBLE("maxim,max1236", max1236), + MAX1363_COMPATIBLE("maxim,max1237", max1237), + MAX1363_COMPATIBLE("maxim,max1238", max1238), + MAX1363_COMPATIBLE("maxim,max1239", max1239), + MAX1363_COMPATIBLE("maxim,max11600", max11600), + MAX1363_COMPATIBLE("maxim,max11601", max11601), + MAX1363_COMPATIBLE("maxim,max11602", max11602), + MAX1363_COMPATIBLE("maxim,max11603", max11603), + MAX1363_COMPATIBLE("maxim,max11604", max11604), + MAX1363_COMPATIBLE("maxim,max11605", max11605), + MAX1363_COMPATIBLE("maxim,max11606", max11606), + MAX1363_COMPATIBLE("maxim,max11607", max11607), + MAX1363_COMPATIBLE("maxim,max11608", max11608), + MAX1363_COMPATIBLE("maxim,max11609", max11609), + MAX1363_COMPATIBLE("maxim,max11610", max11610), + MAX1363_COMPATIBLE("maxim,max11611", max11611), + MAX1363_COMPATIBLE("maxim,max11612", max11612), + MAX1363_COMPATIBLE("maxim,max11613", max11613), + MAX1363_COMPATIBLE("maxim,max11614", max11614), + MAX1363_COMPATIBLE("maxim,max11615", max11615), + MAX1363_COMPATIBLE("maxim,max11616", max11616), + MAX1363_COMPATIBLE("maxim,max11617", max11617), + MAX1363_COMPATIBLE("maxim,max11644", max11644), + MAX1363_COMPATIBLE("maxim,max11645", max11645), + MAX1363_COMPATIBLE("maxim,max11646", max11646), + MAX1363_COMPATIBLE("maxim,max11647", max11647), + { /* sentinel */ } +}; +#endif + static int max1363_probe(struct i2c_client *client, const struct i2c_device_id *id) { @@ -1524,6 +1576,7 @@ static int max1363_probe(struct i2c_client *client, struct max1363_state *st; struct iio_dev *indio_dev; struct regulator *vref; + const struct of_device_id *match; indio_dev = devm_iio_device_alloc(&client->dev, sizeof(struct max1363_state)); @@ -1550,7 +1603,12 @@ static int max1363_probe(struct i2c_client *client, /* this is only used for device removal purposes */ i2c_set_clientdata(client, indio_dev); - st->chip_info = &max1363_chip_info_tbl[id->driver_data]; + match = of_match_device(of_match_ptr(max1363_of_match), + &client->dev); + if (match) + st->chip_info = of_device_get_match_data(&client->dev); + else + st->chip_info = &max1363_chip_info_tbl[id->driver_data]; st->client = client; st->vref_uv = st->chip_info->int_vref_mv * 1000; @@ -1693,6 +1751,7 @@ MODULE_DEVICE_TABLE(i2c, max1363_id); static struct i2c_driver max1363_driver = { .driver = { .name = "max1363", + .of_match_table = of_match_ptr(max1363_of_match), }, .probe = max1363_probe, .remove = max1363_remove, -- cgit v0.10.2 From 468c5620d094e9ead2a0b6802d3c490b4fb6ed03 Mon Sep 17 00:00:00 2001 From: Gregor Boirie Date: Thu, 30 Jun 2016 19:06:34 +0200 Subject: iio:imu:mpu6050: icm20608 initial support Introduce support for Invense ICM20608 IMU, a 6-axis motion tracking device that combines a 3-axis gyroscope and a 3-axis accelerometer: http://www.invensense.com/products/motion-tracking/6-axis/icm-20608-2 Signed-off-by: Gregor Boirie Signed-off-by: Jonathan Cameron diff --git a/drivers/iio/imu/inv_mpu6050/Kconfig b/drivers/iio/imu/inv_mpu6050/Kconfig index f756fee..5483b2e 100644 --- a/drivers/iio/imu/inv_mpu6050/Kconfig +++ b/drivers/iio/imu/inv_mpu6050/Kconfig @@ -13,8 +13,8 @@ config INV_MPU6050_I2C select INV_MPU6050_IIO select REGMAP_I2C help - This driver supports the Invensense MPU6050/6500/9150 motion tracking - devices over I2C. + This driver supports the Invensense MPU6050/6500/9150 and ICM20608 + motion tracking devices over I2C. This driver can be built as a module. The module will be called inv-mpu6050-i2c. @@ -24,7 +24,7 @@ config INV_MPU6050_SPI select INV_MPU6050_IIO select REGMAP_SPI help - This driver supports the Invensense MPU6000/6500/9150 motion tracking - devices over SPI. + This driver supports the Invensense MPU6050/6500/9150 and ICM20608 + motion tracking devices over SPI. This driver can be built as a module. The module will be called inv-mpu6050-spi. diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c index ee40dae..b9fcbf1 100644 --- a/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c @@ -113,6 +113,12 @@ static const struct inv_mpu6050_hw hw_info[] = { .reg = ®_set_6050, .config = &chip_config_6050, }, + { + .whoami = INV_ICM20608_WHOAMI_VALUE, + .name = "ICM20608", + .reg = ®_set_6500, + .config = &chip_config_6050, + }, }; int inv_mpu6050_switch_engine(struct inv_mpu6050_state *st, bool en, u32 mask) diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_i2c.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_i2c.c index e1fd7fa..19580d1 100644 --- a/drivers/iio/imu/inv_mpu6050/inv_mpu_i2c.c +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_i2c.c @@ -170,6 +170,7 @@ static const struct i2c_device_id inv_mpu_id[] = { {"mpu6050", INV_MPU6050}, {"mpu6500", INV_MPU6500}, {"mpu9150", INV_MPU9150}, + {"icm20608", INV_ICM20608}, {} }; diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h b/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h index 3bf8544c..f0e8c5d 100644 --- a/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h @@ -70,6 +70,7 @@ enum inv_devices { INV_MPU6500, INV_MPU6000, INV_MPU9150, + INV_ICM20608, INV_NUM_PARTS }; @@ -225,6 +226,7 @@ struct inv_mpu6050_state { #define INV_MPU6050_WHOAMI_VALUE 0x68 #define INV_MPU6500_WHOAMI_VALUE 0x70 #define INV_MPU9150_WHOAMI_VALUE 0x68 +#define INV_ICM20608_WHOAMI_VALUE 0xAF /* scan element definition */ enum inv_mpu6050_scan { diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_spi.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_spi.c index 190a4a5..6e6476d 100644 --- a/drivers/iio/imu/inv_mpu6050/inv_mpu_spi.c +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_spi.c @@ -82,6 +82,7 @@ static const struct spi_device_id inv_mpu_id[] = { {"mpu6000", INV_MPU6000}, {"mpu6500", INV_MPU6500}, {"mpu9150", INV_MPU9150}, + {"icm20608", INV_ICM20608}, {} }; -- cgit v0.10.2 From 294ea6f3a162fc0091e80170b8176bf326962d1c Mon Sep 17 00:00:00 2001 From: Florian Vaussard Date: Thu, 30 Jun 2016 09:34:48 +0200 Subject: iio: potentiometer: mcp4531: Add support for MCP454x, MCP456x, MCP464x and MCP466x This patch adds support for MCP454x, MCP456x, MCP464x and MCP466x parts. The main difference with currently supported parts (MCP453x and alike) is the addition of a non-volatile memory in order to recall the wiper setting at power-on. This feature is currently not supported and only the volatile memory is used to set the wiper. Signed-off-by: Florian Vaussard Acked-by: Peter Rosin Signed-off-by: Jonathan Cameron diff --git a/drivers/iio/potentiometer/Kconfig b/drivers/iio/potentiometer/Kconfig index 0941c8d4..55c2414 100644 --- a/drivers/iio/potentiometer/Kconfig +++ b/drivers/iio/potentiometer/Kconfig @@ -49,8 +49,10 @@ config MCP4531 depends on I2C help Say yes here to build support for the Microchip - MCP4531, MCP4532, MCP4551, MCP4552, - MCP4631, MCP4632, MCP4651, MCP4652 + MCP4531, MCP4532, MCP4541, MCP4542, + MCP4551, MCP4552, MCP4561, MCP4562, + MCP4631, MCP4632, MCP4641, MCP4642, + MCP4651, MCP4652, MCP4661, MCP4662 digital potentiomenter chips. To compile this driver as a module, choose M here: the diff --git a/drivers/iio/potentiometer/mcp4531.c b/drivers/iio/potentiometer/mcp4531.c index 3b72e1a..2251173 100644 --- a/drivers/iio/potentiometer/mcp4531.c +++ b/drivers/iio/potentiometer/mcp4531.c @@ -8,12 +8,20 @@ * DEVID #Wipers #Positions Resistor Opts (kOhm) i2c address * mcp4531 1 129 5, 10, 50, 100 010111x * mcp4532 1 129 5, 10, 50, 100 01011xx + * mcp4541 1 129 5, 10, 50, 100 010111x + * mcp4542 1 129 5, 10, 50, 100 01011xx * mcp4551 1 257 5, 10, 50, 100 010111x * mcp4552 1 257 5, 10, 50, 100 01011xx + * mcp4561 1 257 5, 10, 50, 100 010111x + * mcp4562 1 257 5, 10, 50, 100 01011xx * mcp4631 2 129 5, 10, 50, 100 0101xxx * mcp4632 2 129 5, 10, 50, 100 01011xx + * mcp4641 2 129 5, 10, 50, 100 0101xxx + * mcp4642 2 129 5, 10, 50, 100 01011xx * mcp4651 2 257 5, 10, 50, 100 0101xxx * mcp4652 2 257 5, 10, 50, 100 01011xx + * mcp4661 2 257 5, 10, 50, 100 0101xxx + * mcp4662 2 257 5, 10, 50, 100 01011xx * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published by @@ -37,18 +45,34 @@ enum mcp4531_type { MCP453x_103, MCP453x_503, MCP453x_104, + MCP454x_502, + MCP454x_103, + MCP454x_503, + MCP454x_104, MCP455x_502, MCP455x_103, MCP455x_503, MCP455x_104, + MCP456x_502, + MCP456x_103, + MCP456x_503, + MCP456x_104, MCP463x_502, MCP463x_103, MCP463x_503, MCP463x_104, + MCP464x_502, + MCP464x_103, + MCP464x_503, + MCP464x_104, MCP465x_502, MCP465x_103, MCP465x_503, MCP465x_104, + MCP466x_502, + MCP466x_103, + MCP466x_503, + MCP466x_104, }; static const struct mcp4531_cfg mcp4531_cfg[] = { @@ -56,18 +80,34 @@ static const struct mcp4531_cfg mcp4531_cfg[] = { [MCP453x_103] = { .wipers = 1, .max_pos = 128, .kohms = 10, }, [MCP453x_503] = { .wipers = 1, .max_pos = 128, .kohms = 50, }, [MCP453x_104] = { .wipers = 1, .max_pos = 128, .kohms = 100, }, + [MCP454x_502] = { .wipers = 1, .max_pos = 128, .kohms = 5, }, + [MCP454x_103] = { .wipers = 1, .max_pos = 128, .kohms = 10, }, + [MCP454x_503] = { .wipers = 1, .max_pos = 128, .kohms = 50, }, + [MCP454x_104] = { .wipers = 1, .max_pos = 128, .kohms = 100, }, [MCP455x_502] = { .wipers = 1, .max_pos = 256, .kohms = 5, }, [MCP455x_103] = { .wipers = 1, .max_pos = 256, .kohms = 10, }, [MCP455x_503] = { .wipers = 1, .max_pos = 256, .kohms = 50, }, [MCP455x_104] = { .wipers = 1, .max_pos = 256, .kohms = 100, }, + [MCP456x_502] = { .wipers = 1, .max_pos = 256, .kohms = 5, }, + [MCP456x_103] = { .wipers = 1, .max_pos = 256, .kohms = 10, }, + [MCP456x_503] = { .wipers = 1, .max_pos = 256, .kohms = 50, }, + [MCP456x_104] = { .wipers = 1, .max_pos = 256, .kohms = 100, }, [MCP463x_502] = { .wipers = 2, .max_pos = 128, .kohms = 5, }, [MCP463x_103] = { .wipers = 2, .max_pos = 128, .kohms = 10, }, [MCP463x_503] = { .wipers = 2, .max_pos = 128, .kohms = 50, }, [MCP463x_104] = { .wipers = 2, .max_pos = 128, .kohms = 100, }, + [MCP464x_502] = { .wipers = 2, .max_pos = 128, .kohms = 5, }, + [MCP464x_103] = { .wipers = 2, .max_pos = 128, .kohms = 10, }, + [MCP464x_503] = { .wipers = 2, .max_pos = 128, .kohms = 50, }, + [MCP464x_104] = { .wipers = 2, .max_pos = 128, .kohms = 100, }, [MCP465x_502] = { .wipers = 2, .max_pos = 256, .kohms = 5, }, [MCP465x_103] = { .wipers = 2, .max_pos = 256, .kohms = 10, }, [MCP465x_503] = { .wipers = 2, .max_pos = 256, .kohms = 50, }, [MCP465x_104] = { .wipers = 2, .max_pos = 256, .kohms = 100, }, + [MCP466x_502] = { .wipers = 2, .max_pos = 256, .kohms = 5, }, + [MCP466x_103] = { .wipers = 2, .max_pos = 256, .kohms = 10, }, + [MCP466x_503] = { .wipers = 2, .max_pos = 256, .kohms = 50, }, + [MCP466x_104] = { .wipers = 2, .max_pos = 256, .kohms = 100, }, }; #define MCP4531_WRITE (0 << 2) @@ -187,6 +227,14 @@ static const struct i2c_device_id mcp4531_id[] = { { "mcp4532-103", MCP453x_103 }, { "mcp4532-503", MCP453x_503 }, { "mcp4532-104", MCP453x_104 }, + { "mcp4541-502", MCP454x_502 }, + { "mcp4541-103", MCP454x_103 }, + { "mcp4541-503", MCP454x_503 }, + { "mcp4541-104", MCP454x_104 }, + { "mcp4542-502", MCP454x_502 }, + { "mcp4542-103", MCP454x_103 }, + { "mcp4542-503", MCP454x_503 }, + { "mcp4542-104", MCP454x_104 }, { "mcp4551-502", MCP455x_502 }, { "mcp4551-103", MCP455x_103 }, { "mcp4551-503", MCP455x_503 }, @@ -195,6 +243,14 @@ static const struct i2c_device_id mcp4531_id[] = { { "mcp4552-103", MCP455x_103 }, { "mcp4552-503", MCP455x_503 }, { "mcp4552-104", MCP455x_104 }, + { "mcp4561-502", MCP456x_502 }, + { "mcp4561-103", MCP456x_103 }, + { "mcp4561-503", MCP456x_503 }, + { "mcp4561-104", MCP456x_104 }, + { "mcp4562-502", MCP456x_502 }, + { "mcp4562-103", MCP456x_103 }, + { "mcp4562-503", MCP456x_503 }, + { "mcp4562-104", MCP456x_104 }, { "mcp4631-502", MCP463x_502 }, { "mcp4631-103", MCP463x_103 }, { "mcp4631-503", MCP463x_503 }, @@ -203,6 +259,14 @@ static const struct i2c_device_id mcp4531_id[] = { { "mcp4632-103", MCP463x_103 }, { "mcp4632-503", MCP463x_503 }, { "mcp4632-104", MCP463x_104 }, + { "mcp4641-502", MCP464x_502 }, + { "mcp4641-103", MCP464x_103 }, + { "mcp4641-503", MCP464x_503 }, + { "mcp4641-104", MCP464x_104 }, + { "mcp4642-502", MCP464x_502 }, + { "mcp4642-103", MCP464x_103 }, + { "mcp4642-503", MCP464x_503 }, + { "mcp4642-104", MCP464x_104 }, { "mcp4651-502", MCP465x_502 }, { "mcp4651-103", MCP465x_103 }, { "mcp4651-503", MCP465x_503 }, @@ -211,6 +275,14 @@ static const struct i2c_device_id mcp4531_id[] = { { "mcp4652-103", MCP465x_103 }, { "mcp4652-503", MCP465x_503 }, { "mcp4652-104", MCP465x_104 }, + { "mcp4661-502", MCP466x_502 }, + { "mcp4661-103", MCP466x_103 }, + { "mcp4661-503", MCP466x_503 }, + { "mcp4661-104", MCP466x_104 }, + { "mcp4662-502", MCP466x_502 }, + { "mcp4662-103", MCP466x_103 }, + { "mcp4662-503", MCP466x_503 }, + { "mcp4662-104", MCP466x_104 }, {} }; MODULE_DEVICE_TABLE(i2c, mcp4531_id); -- cgit v0.10.2 From deec2fadff6aa6a26e96cc12c7c8bacdc145b5af Mon Sep 17 00:00:00 2001 From: Florian Vaussard Date: Thu, 30 Jun 2016 09:34:49 +0200 Subject: iio: potentiometer: mcp4531: Add device tree binding documentation Add the device tree documentation for all the supported parts. Apart the compatible string and standard I2C binding, no other binding is currently needed. Signed-off-by: Florian Vaussard Acked-by: Rob Herring Signed-off-by: Jonathan Cameron diff --git a/Documentation/devicetree/bindings/i2c/trivial-devices.txt b/Documentation/devicetree/bindings/i2c/trivial-devices.txt index 53987449..acc5cd6 100644 --- a/Documentation/devicetree/bindings/i2c/trivial-devices.txt +++ b/Documentation/devicetree/bindings/i2c/trivial-devices.txt @@ -56,6 +56,70 @@ maxim,ds1050 5 Bit Programmable, Pulse-Width Modulator maxim,max1237 Low-Power, 4-/12-Channel, 2-Wire Serial, 12-Bit ADCs maxim,max6625 9-Bit/12-Bit Temperature Sensors with I²C-Compatible Serial Interface mc,rv3029c2 Real Time Clock Module with I2C-Bus +microchip,mcp4531-502 Microchip 7-bit Single I2C Digital Potentiometer (5k) +microchip,mcp4531-103 Microchip 7-bit Single I2C Digital Potentiometer (10k) +microchip,mcp4531-503 Microchip 7-bit Single I2C Digital Potentiometer (50k) +microchip,mcp4531-104 Microchip 7-bit Single I2C Digital Potentiometer (100k) +microchip,mcp4532-502 Microchip 7-bit Single I2C Digital Potentiometer (5k) +microchip,mcp4532-103 Microchip 7-bit Single I2C Digital Potentiometer (10k) +microchip,mcp4532-503 Microchip 7-bit Single I2C Digital Potentiometer (50k) +microchip,mcp4532-104 Microchip 7-bit Single I2C Digital Potentiometer (100k) +microchip,mcp4541-502 Microchip 7-bit Single I2C Digital Potentiometer with NV Memory (5k) +microchip,mcp4541-103 Microchip 7-bit Single I2C Digital Potentiometer with NV Memory (10k) +microchip,mcp4541-503 Microchip 7-bit Single I2C Digital Potentiometer with NV Memory (50k) +microchip,mcp4541-104 Microchip 7-bit Single I2C Digital Potentiometer with NV Memory (100k) +microchip,mcp4542-502 Microchip 7-bit Single I2C Digital Potentiometer with NV Memory (5k) +microchip,mcp4542-103 Microchip 7-bit Single I2C Digital Potentiometer with NV Memory (10k) +microchip,mcp4542-503 Microchip 7-bit Single I2C Digital Potentiometer with NV Memory (50k) +microchip,mcp4542-104 Microchip 7-bit Single I2C Digital Potentiometer with NV Memory (100k) +microchip,mcp4551-502 Microchip 8-bit Single I2C Digital Potentiometer (5k) +microchip,mcp4551-103 Microchip 8-bit Single I2C Digital Potentiometer (10k) +microchip,mcp4551-503 Microchip 8-bit Single I2C Digital Potentiometer (50k) +microchip,mcp4551-104 Microchip 8-bit Single I2C Digital Potentiometer (100k) +microchip,mcp4552-502 Microchip 8-bit Single I2C Digital Potentiometer (5k) +microchip,mcp4552-103 Microchip 8-bit Single I2C Digital Potentiometer (10k) +microchip,mcp4552-503 Microchip 8-bit Single I2C Digital Potentiometer (50k) +microchip,mcp4552-104 Microchip 8-bit Single I2C Digital Potentiometer (100k) +microchip,mcp4561-502 Microchip 8-bit Single I2C Digital Potentiometer with NV Memory (5k) +microchip,mcp4561-103 Microchip 8-bit Single I2C Digital Potentiometer with NV Memory (10k) +microchip,mcp4561-503 Microchip 8-bit Single I2C Digital Potentiometer with NV Memory (50k) +microchip,mcp4561-104 Microchip 8-bit Single I2C Digital Potentiometer with NV Memory (100k) +microchip,mcp4562-502 Microchip 8-bit Single I2C Digital Potentiometer with NV Memory (5k) +microchip,mcp4562-103 Microchip 8-bit Single I2C Digital Potentiometer with NV Memory (10k) +microchip,mcp4562-503 Microchip 8-bit Single I2C Digital Potentiometer with NV Memory (50k) +microchip,mcp4562-104 Microchip 8-bit Single I2C Digital Potentiometer with NV Memory (100k) +microchip,mcp4631-502 Microchip 7-bit Dual I2C Digital Potentiometer (5k) +microchip,mcp4631-103 Microchip 7-bit Dual I2C Digital Potentiometer (10k) +microchip,mcp4631-503 Microchip 7-bit Dual I2C Digital Potentiometer (50k) +microchip,mcp4631-104 Microchip 7-bit Dual I2C Digital Potentiometer (100k) +microchip,mcp4632-502 Microchip 7-bit Dual I2C Digital Potentiometer (5k) +microchip,mcp4632-103 Microchip 7-bit Dual I2C Digital Potentiometer (10k) +microchip,mcp4632-503 Microchip 7-bit Dual I2C Digital Potentiometer (50k) +microchip,mcp4632-104 Microchip 7-bit Dual I2C Digital Potentiometer (100k) +microchip,mcp4641-502 Microchip 7-bit Dual I2C Digital Potentiometer with NV Memory (5k) +microchip,mcp4641-103 Microchip 7-bit Dual I2C Digital Potentiometer with NV Memory (10k) +microchip,mcp4641-503 Microchip 7-bit Dual I2C Digital Potentiometer with NV Memory (50k) +microchip,mcp4641-104 Microchip 7-bit Dual I2C Digital Potentiometer with NV Memory (100k) +microchip,mcp4642-502 Microchip 7-bit Dual I2C Digital Potentiometer with NV Memory (5k) +microchip,mcp4642-103 Microchip 7-bit Dual I2C Digital Potentiometer with NV Memory (10k) +microchip,mcp4642-503 Microchip 7-bit Dual I2C Digital Potentiometer with NV Memory (50k) +microchip,mcp4642-104 Microchip 7-bit Dual I2C Digital Potentiometer with NV Memory (100k) +microchip,mcp4651-502 Microchip 8-bit Dual I2C Digital Potentiometer (5k) +microchip,mcp4651-103 Microchip 8-bit Dual I2C Digital Potentiometer (10k) +microchip,mcp4651-503 Microchip 8-bit Dual I2C Digital Potentiometer (50k) +microchip,mcp4651-104 Microchip 8-bit Dual I2C Digital Potentiometer (100k) +microchip,mcp4652-502 Microchip 8-bit Dual I2C Digital Potentiometer (5k) +microchip,mcp4652-103 Microchip 8-bit Dual I2C Digital Potentiometer (10k) +microchip,mcp4652-503 Microchip 8-bit Dual I2C Digital Potentiometer (50k) +microchip,mcp4652-104 Microchip 8-bit Dual I2C Digital Potentiometer (100k) +microchip,mcp4661-502 Microchip 8-bit Dual I2C Digital Potentiometer with NV Memory (5k) +microchip,mcp4661-103 Microchip 8-bit Dual I2C Digital Potentiometer with NV Memory (10k) +microchip,mcp4661-503 Microchip 8-bit Dual I2C Digital Potentiometer with NV Memory (50k) +microchip,mcp4661-104 Microchip 8-bit Dual I2C Digital Potentiometer with NV Memory (100k) +microchip,mcp4662-502 Microchip 8-bit Dual I2C Digital Potentiometer with NV Memory (5k) +microchip,mcp4662-103 Microchip 8-bit Dual I2C Digital Potentiometer with NV Memory (10k) +microchip,mcp4662-503 Microchip 8-bit Dual I2C Digital Potentiometer with NV Memory (50k) +microchip,mcp4662-104 Microchip 8-bit Dual I2C Digital Potentiometer with NV Memory (100k) national,lm63 Temperature sensor with integrated fan control national,lm75 I2C TEMP SENSOR national,lm80 Serial Interface ACPI-Compatible Microprocessor System Hardware Monitor -- cgit v0.10.2 From 2dc2e1899ec140153b26f51b4d985a5072ba642e Mon Sep 17 00:00:00 2001 From: Florian Vaussard Date: Thu, 30 Jun 2016 09:34:50 +0200 Subject: iio: potentiometer: mcp4531: Add device tree binding This patch adds the necessary device tree binding to allow DT probing of currently supported parts. Signed-off-by: Florian Vaussard Acked-by: Peter Rosin Signed-off-by: Jonathan Cameron diff --git a/drivers/iio/potentiometer/mcp4531.c b/drivers/iio/potentiometer/mcp4531.c index 2251173..13b6ae2 100644 --- a/drivers/iio/potentiometer/mcp4531.c +++ b/drivers/iio/potentiometer/mcp4531.c @@ -31,6 +31,8 @@ #include #include #include +#include +#include #include @@ -188,12 +190,89 @@ static const struct iio_info mcp4531_info = { .driver_module = THIS_MODULE, }; +#ifdef CONFIG_OF + +#define MCP4531_COMPATIBLE(of_compatible, cfg) { \ + .compatible = of_compatible, \ + .data = &mcp4531_cfg[cfg], \ +} + +static const struct of_device_id mcp4531_of_match[] = { + MCP4531_COMPATIBLE("microchip,mcp4531-502", MCP453x_502), + MCP4531_COMPATIBLE("microchip,mcp4531-103", MCP453x_103), + MCP4531_COMPATIBLE("microchip,mcp4531-503", MCP453x_503), + MCP4531_COMPATIBLE("microchip,mcp4531-104", MCP453x_104), + MCP4531_COMPATIBLE("microchip,mcp4532-502", MCP453x_502), + MCP4531_COMPATIBLE("microchip,mcp4532-103", MCP453x_103), + MCP4531_COMPATIBLE("microchip,mcp4532-503", MCP453x_503), + MCP4531_COMPATIBLE("microchip,mcp4532-104", MCP453x_104), + MCP4531_COMPATIBLE("microchip,mcp4541-502", MCP454x_502), + MCP4531_COMPATIBLE("microchip,mcp4541-103", MCP454x_103), + MCP4531_COMPATIBLE("microchip,mcp4541-503", MCP454x_503), + MCP4531_COMPATIBLE("microchip,mcp4541-104", MCP454x_104), + MCP4531_COMPATIBLE("microchip,mcp4542-502", MCP454x_502), + MCP4531_COMPATIBLE("microchip,mcp4542-103", MCP454x_103), + MCP4531_COMPATIBLE("microchip,mcp4542-503", MCP454x_503), + MCP4531_COMPATIBLE("microchip,mcp4542-104", MCP454x_104), + MCP4531_COMPATIBLE("microchip,mcp4551-502", MCP455x_502), + MCP4531_COMPATIBLE("microchip,mcp4551-103", MCP455x_103), + MCP4531_COMPATIBLE("microchip,mcp4551-503", MCP455x_503), + MCP4531_COMPATIBLE("microchip,mcp4551-104", MCP455x_104), + MCP4531_COMPATIBLE("microchip,mcp4552-502", MCP455x_502), + MCP4531_COMPATIBLE("microchip,mcp4552-103", MCP455x_103), + MCP4531_COMPATIBLE("microchip,mcp4552-503", MCP455x_503), + MCP4531_COMPATIBLE("microchip,mcp4552-104", MCP455x_104), + MCP4531_COMPATIBLE("microchip,mcp4561-502", MCP456x_502), + MCP4531_COMPATIBLE("microchip,mcp4561-103", MCP456x_103), + MCP4531_COMPATIBLE("microchip,mcp4561-503", MCP456x_503), + MCP4531_COMPATIBLE("microchip,mcp4561-104", MCP456x_104), + MCP4531_COMPATIBLE("microchip,mcp4562-502", MCP456x_502), + MCP4531_COMPATIBLE("microchip,mcp4562-103", MCP456x_103), + MCP4531_COMPATIBLE("microchip,mcp4562-503", MCP456x_503), + MCP4531_COMPATIBLE("microchip,mcp4562-104", MCP456x_104), + MCP4531_COMPATIBLE("microchip,mcp4631-502", MCP463x_502), + MCP4531_COMPATIBLE("microchip,mcp4631-103", MCP463x_103), + MCP4531_COMPATIBLE("microchip,mcp4631-503", MCP463x_503), + MCP4531_COMPATIBLE("microchip,mcp4631-104", MCP463x_104), + MCP4531_COMPATIBLE("microchip,mcp4632-502", MCP463x_502), + MCP4531_COMPATIBLE("microchip,mcp4632-103", MCP463x_103), + MCP4531_COMPATIBLE("microchip,mcp4632-503", MCP463x_503), + MCP4531_COMPATIBLE("microchip,mcp4632-104", MCP463x_104), + MCP4531_COMPATIBLE("microchip,mcp4641-502", MCP464x_502), + MCP4531_COMPATIBLE("microchip,mcp4641-103", MCP464x_103), + MCP4531_COMPATIBLE("microchip,mcp4641-503", MCP464x_503), + MCP4531_COMPATIBLE("microchip,mcp4641-104", MCP464x_104), + MCP4531_COMPATIBLE("microchip,mcp4642-502", MCP464x_502), + MCP4531_COMPATIBLE("microchip,mcp4642-103", MCP464x_103), + MCP4531_COMPATIBLE("microchip,mcp4642-503", MCP464x_503), + MCP4531_COMPATIBLE("microchip,mcp4642-104", MCP464x_104), + MCP4531_COMPATIBLE("microchip,mcp4651-502", MCP465x_502), + MCP4531_COMPATIBLE("microchip,mcp4651-103", MCP465x_103), + MCP4531_COMPATIBLE("microchip,mcp4651-503", MCP465x_503), + MCP4531_COMPATIBLE("microchip,mcp4651-104", MCP465x_104), + MCP4531_COMPATIBLE("microchip,mcp4652-502", MCP465x_502), + MCP4531_COMPATIBLE("microchip,mcp4652-103", MCP465x_103), + MCP4531_COMPATIBLE("microchip,mcp4652-503", MCP465x_503), + MCP4531_COMPATIBLE("microchip,mcp4652-104", MCP465x_104), + MCP4531_COMPATIBLE("microchip,mcp4661-502", MCP466x_502), + MCP4531_COMPATIBLE("microchip,mcp4661-103", MCP466x_103), + MCP4531_COMPATIBLE("microchip,mcp4661-503", MCP466x_503), + MCP4531_COMPATIBLE("microchip,mcp4661-104", MCP466x_104), + MCP4531_COMPATIBLE("microchip,mcp4662-502", MCP466x_502), + MCP4531_COMPATIBLE("microchip,mcp4662-103", MCP466x_103), + MCP4531_COMPATIBLE("microchip,mcp4662-503", MCP466x_503), + MCP4531_COMPATIBLE("microchip,mcp4662-104", MCP466x_104), + { /* sentinel */ } +}; +#endif + static int mcp4531_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct device *dev = &client->dev; struct mcp4531_data *data; struct iio_dev *indio_dev; + const struct of_device_id *match; if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WORD_DATA)) { @@ -207,7 +286,12 @@ static int mcp4531_probe(struct i2c_client *client, data = iio_priv(indio_dev); i2c_set_clientdata(client, indio_dev); data->client = client; - data->cfg = &mcp4531_cfg[id->driver_data]; + + match = of_match_device(of_match_ptr(mcp4531_of_match), dev); + if (match) + data->cfg = of_device_get_match_data(dev); + else + data->cfg = &mcp4531_cfg[id->driver_data]; indio_dev->dev.parent = dev; indio_dev->info = &mcp4531_info; @@ -290,6 +374,7 @@ MODULE_DEVICE_TABLE(i2c, mcp4531_id); static struct i2c_driver mcp4531_driver = { .driver = { .name = "mcp4531", + .of_match_table = of_match_ptr(mcp4531_of_match), }, .probe = mcp4531_probe, .id_table = mcp4531_id, -- cgit v0.10.2 From 3629153ce154cf475841d3d0d8cbb1bb1718269e Mon Sep 17 00:00:00 2001 From: Florian Vaussard Date: Thu, 30 Jun 2016 09:34:51 +0200 Subject: iio: potentiometer: Fix typo in Kconfig Fix s/potentiomenter/potentiometer/. Suggested-by: Peter Meerwald-Stadler Signed-off-by: Florian Vaussard Signed-off-by: Jonathan Cameron diff --git a/drivers/iio/potentiometer/Kconfig b/drivers/iio/potentiometer/Kconfig index 55c2414..2e9da1c 100644 --- a/drivers/iio/potentiometer/Kconfig +++ b/drivers/iio/potentiometer/Kconfig @@ -10,7 +10,7 @@ config DS1803 depends on I2C help Say yes here to build support for the Maxim Integrated DS1803 - digital potentiomenter chip. + digital potentiometer chip. To compile this driver as a module, choose M here: the module will be called ds1803. @@ -39,7 +39,7 @@ config MCP4131 MCP4241, MCP4242, MCP4251, MCP4252, MCP4261, MCP4262, - digital potentiomenter chips. + digital potentiometer chips. To compile this driver as a module, choose M here: the module will be called mcp4131. @@ -53,7 +53,7 @@ config MCP4531 MCP4551, MCP4552, MCP4561, MCP4562, MCP4631, MCP4632, MCP4641, MCP4642, MCP4651, MCP4652, MCP4661, MCP4662 - digital potentiomenter chips. + digital potentiometer chips. To compile this driver as a module, choose M here: the module will be called mcp4531. -- cgit v0.10.2 From 86a8280a7fe007d61b05fa8a352edc0595283dad Mon Sep 17 00:00:00 2001 From: Andrea Gelmini Date: Sat, 21 May 2016 13:57:20 +0200 Subject: m68k: Assorted spelling fixes - s/acccess/access/ - s/accoding/according/ - s/addad/added/ - s/addreess/address/ - s/allocatiom/allocation/ - s/Assember/Assembler/ - s/compactnes/compactness/ - s/conneced/connected/ - s/decending/descending/ - s/diectly/directly/ - s/diplacement/displacement/ Signed-off-by: Andrea Gelmini [geert: Squashed, fix arch/m68k/ifpsp060/src/pfpsp.S] Signed-off-by: Geert Uytterhoeven diff --git a/arch/m68k/coldfire/head.S b/arch/m68k/coldfire/head.S index fa31be2..73d92ea 100644 --- a/arch/m68k/coldfire/head.S +++ b/arch/m68k/coldfire/head.S @@ -288,7 +288,7 @@ _clear_bss: #endif /* - * Assember start up done, start code proper. + * Assembler start up done, start code proper. */ jsr start_kernel /* start Linux kernel */ diff --git a/arch/m68k/coldfire/m5272.c b/arch/m68k/coldfire/m5272.c index c525e4c..9abb1a4 100644 --- a/arch/m68k/coldfire/m5272.c +++ b/arch/m68k/coldfire/m5272.c @@ -111,7 +111,7 @@ void __init config_BSP(char *commandp, int size) /***************************************************************************/ /* - * Some 5272 based boards have the FEC ethernet diectly connected to + * Some 5272 based boards have the FEC ethernet directly connected to * an ethernet switch. In this case we need to use the fixed phy type, * and we need to declare it early in boot. */ diff --git a/arch/m68k/coldfire/pci.c b/arch/m68k/coldfire/pci.c index 821de92..6a640be 100644 --- a/arch/m68k/coldfire/pci.c +++ b/arch/m68k/coldfire/pci.c @@ -42,7 +42,7 @@ static unsigned long iospace; /* * We need to be carefull probing on bus 0 (directly connected to host - * bridge). We should only acccess the well defined possible devices in + * bridge). We should only access the well defined possible devices in * use, ignore aliases and the like. */ static unsigned char mcf_host_slot2sid[32] = { diff --git a/arch/m68k/ifpsp060/src/fpsp.S b/arch/m68k/ifpsp060/src/fpsp.S index 78cb60f..9bbffeb 100644 --- a/arch/m68k/ifpsp060/src/fpsp.S +++ b/arch/m68k/ifpsp060/src/fpsp.S @@ -10191,7 +10191,7 @@ xdnrm_con: xdnrm_sd: mov.l %a1,-(%sp) tst.b LOCAL_EX(%a0) # is denorm pos or neg? - smi.b %d1 # set d0 accodingly + smi.b %d1 # set d0 accordingly bsr.l unf_sub mov.l (%sp)+,%a1 xdnrm_exit: @@ -10990,7 +10990,7 @@ src_qnan_m: # routines where an instruction is selected by an index into # a large jump table corresponding to a given instruction which # has been decoded. Flow continues here where we now decode -# further accoding to the source operand type. +# further according to the source operand type. # global fsinh @@ -23196,14 +23196,14 @@ m_sign: # # 1. Branch on the sign of the adjusted exponent. # 2p.(positive exp) -# 2. Check M16 and the digits in lwords 2 and 3 in decending order. +# 2. Check M16 and the digits in lwords 2 and 3 in descending order. # 3. Add one for each zero encountered until a non-zero digit. # 4. Subtract the count from the exp. # 5. Check if the exp has crossed zero in #3 above; make the exp abs # and set SE. # 6. Multiply the mantissa by 10**count. # 2n.(negative exp) -# 2. Check the digits in lwords 3 and 2 in decending order. +# 2. Check the digits in lwords 3 and 2 in descending order. # 3. Add one for each zero encountered until a non-zero digit. # 4. Add the count to the exp. # 5. Check if the exp has crossed zero in #3 above; clear SE. diff --git a/arch/m68k/ifpsp060/src/pfpsp.S b/arch/m68k/ifpsp060/src/pfpsp.S index 4aedef9..3535e6c 100644 --- a/arch/m68k/ifpsp060/src/pfpsp.S +++ b/arch/m68k/ifpsp060/src/pfpsp.S @@ -13156,14 +13156,14 @@ m_sign: # # 1. Branch on the sign of the adjusted exponent. # 2p.(positive exp) -# 2. Check M16 and the digits in lwords 2 and 3 in decending order. +# 2. Check M16 and the digits in lwords 2 and 3 in descending order. # 3. Add one for each zero encountered until a non-zero digit. # 4. Subtract the count from the exp. # 5. Check if the exp has crossed zero in #3 above; make the exp abs # and set SE. # 6. Multiply the mantissa by 10**count. # 2n.(negative exp) -# 2. Check the digits in lwords 3 and 2 in decending order. +# 2. Check the digits in lwords 3 and 2 in descending order. # 3. Add one for each zero encountered until a non-zero digit. # 4. Add the count to the exp. # 5. Check if the exp has crossed zero in #3 above; clear SE. diff --git a/arch/m68k/include/asm/dma.h b/arch/m68k/include/asm/dma.h index 429fe26..208b4da 100644 --- a/arch/m68k/include/asm/dma.h +++ b/arch/m68k/include/asm/dma.h @@ -18,7 +18,7 @@ * AUG/22/2000 : added support for 32-bit Dual-Address-Mode (K) 2000 * Oliver Kamphenkel (O.Kamphenkel@tu-bs.de) * - * AUG/25/2000 : addad support for 8, 16 and 32-bit Single-Address-Mode (K)2000 + * AUG/25/2000 : added support for 8, 16 and 32-bit Single-Address-Mode (K)2000 * Oliver Kamphenkel (O.Kamphenkel@tu-bs.de) * * APR/18/2002 : added proper support for MCF5272 DMA controller. diff --git a/arch/m68k/include/asm/m525xsim.h b/arch/m68k/include/asm/m525xsim.h index f186459..699f20c 100644 --- a/arch/m68k/include/asm/m525xsim.h +++ b/arch/m68k/include/asm/m525xsim.h @@ -123,10 +123,10 @@ /* * I2C module. */ -#define MCFI2C_BASE0 (MCF_MBAR + 0x280) /* Base addreess I2C0 */ +#define MCFI2C_BASE0 (MCF_MBAR + 0x280) /* Base address I2C0 */ #define MCFI2C_SIZE0 0x20 /* Register set size */ -#define MCFI2C_BASE1 (MCF_MBAR2 + 0x440) /* Base addreess I2C1 */ +#define MCFI2C_BASE1 (MCF_MBAR2 + 0x440) /* Base address I2C1 */ #define MCFI2C_SIZE1 0x20 /* Register set size */ /* diff --git a/arch/m68k/include/asm/mcfmmu.h b/arch/m68k/include/asm/mcfmmu.h index 26cc3d5..8824236 100644 --- a/arch/m68k/include/asm/mcfmmu.h +++ b/arch/m68k/include/asm/mcfmmu.h @@ -38,7 +38,7 @@ /* * MMU Operation register. */ -#define MMUOR_UAA 0x00000001 /* Update allocatiom address */ +#define MMUOR_UAA 0x00000001 /* Update allocation address */ #define MMUOR_ACC 0x00000002 /* TLB access */ #define MMUOR_RD 0x00000004 /* TLB access read */ #define MMUOR_WR 0x00000000 /* TLB access write */ diff --git a/arch/m68k/include/asm/q40_master.h b/arch/m68k/include/asm/q40_master.h index fc5b362..c48d21b 100644 --- a/arch/m68k/include/asm/q40_master.h +++ b/arch/m68k/include/asm/q40_master.h @@ -1,6 +1,6 @@ /* * Q40 master Chip Control - * RTC stuff merged for compactnes.. + * RTC stuff merged for compactness. */ #ifndef _Q40_MASTER_H diff --git a/arch/m68k/mac/iop.c b/arch/m68k/mac/iop.c index 4d2adfb..7990b6f 100644 --- a/arch/m68k/mac/iop.c +++ b/arch/m68k/mac/iop.c @@ -60,7 +60,7 @@ * * The host talks to the IOPs using a rather simple message-passing scheme via * a shared memory area in the IOP RAM. Each IOP has seven "channels"; each - * channel is conneced to a specific software driver on the IOP. For example + * channel is connected to a specific software driver on the IOP. For example * on the SCC IOP there is one channel for each serial port. Each channel has * an incoming and and outgoing message queue with a depth of one. * diff --git a/arch/m68k/math-emu/fp_decode.h b/arch/m68k/math-emu/fp_decode.h index 759679d..6d1e760 100644 --- a/arch/m68k/math-emu/fp_decode.h +++ b/arch/m68k/math-emu/fp_decode.h @@ -130,7 +130,7 @@ do_fscc=0 bfextu %d2{#13,#3},%d0 .endm -| decode the 8bit diplacement from the brief extension word +| decode the 8bit displacement from the brief extension word .macro fp_decode_disp8 move.b %d2,%d0 ext.w %d0 -- cgit v0.10.2 From f5241dbdfef4404b4e80f0bda13e5c7ceba3ee4a Mon Sep 17 00:00:00 2001 From: Matt Ranostay Date: Thu, 30 Jun 2016 19:33:50 -0700 Subject: iio: adc: ti-ads1015: add indio_dev->dev.of_node reference Add the pointer to the device tree node of the ADC so that iio consumers can reference the respective channels. Signed-off-by: Matt Ranostay Acked-by: Daniel Baluta Signed-off-by: Jonathan Cameron diff --git a/drivers/iio/adc/ti-ads1015.c b/drivers/iio/adc/ti-ads1015.c index c9574af0..1ef39877 100644 --- a/drivers/iio/adc/ti-ads1015.c +++ b/drivers/iio/adc/ti-ads1015.c @@ -586,6 +586,7 @@ static int ads1015_probe(struct i2c_client *client, mutex_init(&data->lock); indio_dev->dev.parent = &client->dev; + indio_dev->dev.of_node = client->dev.of_node; indio_dev->name = ADS1015_DRV_NAME; indio_dev->modes = INDIO_DIRECT_MODE; -- cgit v0.10.2 From b541eaff4917a7429cd0e83cb3962383276db357 Mon Sep 17 00:00:00 2001 From: Matt Ranostay Date: Sat, 2 Jul 2016 17:26:33 -0700 Subject: iio: adc: add missing of_node references to iio_dev Adding missing indio_dev->dev.of_node references to allow iio consumers to access the device channels. Signed-off-by: Matt Ranostay Signed-off-by: Jonathan Cameron diff --git a/drivers/iio/adc/ad7266.c b/drivers/iio/adc/ad7266.c index 01240ae..e527bb6 100644 --- a/drivers/iio/adc/ad7266.c +++ b/drivers/iio/adc/ad7266.c @@ -437,6 +437,7 @@ static int ad7266_probe(struct spi_device *spi) st->spi = spi; indio_dev->dev.parent = &spi->dev; + indio_dev->dev.of_node = spi->dev.of_node; indio_dev->name = spi_get_device_id(spi)->name; indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->info = &ad7266_info; diff --git a/drivers/iio/adc/ad7291.c b/drivers/iio/adc/ad7291.c index 0376309..1d90b02 100644 --- a/drivers/iio/adc/ad7291.c +++ b/drivers/iio/adc/ad7291.c @@ -505,6 +505,7 @@ static int ad7291_probe(struct i2c_client *client, indio_dev->num_channels = ARRAY_SIZE(ad7291_channels); indio_dev->dev.parent = &client->dev; + indio_dev->dev.of_node = client->dev.of_node; indio_dev->info = &ad7291_info; indio_dev->modes = INDIO_DIRECT_MODE; diff --git a/drivers/iio/adc/ad7298.c b/drivers/iio/adc/ad7298.c index 5dd0742..10ec8fc 100644 --- a/drivers/iio/adc/ad7298.c +++ b/drivers/iio/adc/ad7298.c @@ -315,6 +315,7 @@ static int ad7298_probe(struct spi_device *spi) indio_dev->name = spi_get_device_id(spi)->name; indio_dev->dev.parent = &spi->dev; + indio_dev->dev.of_node = spi->dev.of_node; indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->channels = ad7298_channels; indio_dev->num_channels = ARRAY_SIZE(ad7298_channels); diff --git a/drivers/iio/adc/ad7476.c b/drivers/iio/adc/ad7476.c index a819be2..b7ecf9a 100644 --- a/drivers/iio/adc/ad7476.c +++ b/drivers/iio/adc/ad7476.c @@ -227,6 +227,7 @@ static int ad7476_probe(struct spi_device *spi) /* Establish that the iio_dev is a child of the spi device */ indio_dev->dev.parent = &spi->dev; + indio_dev->dev.of_node = spi->dev.of_node; indio_dev->name = spi_get_device_id(spi)->name; indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->channels = st->chip_info->channel; diff --git a/drivers/iio/adc/ad7791.c b/drivers/iio/adc/ad7791.c index 1dfe641..1817ebf 100644 --- a/drivers/iio/adc/ad7791.c +++ b/drivers/iio/adc/ad7791.c @@ -375,6 +375,7 @@ static int ad7791_probe(struct spi_device *spi) spi_set_drvdata(spi, indio_dev); indio_dev->dev.parent = &spi->dev; + indio_dev->dev.of_node = spi->dev.of_node; indio_dev->name = spi_get_device_id(spi)->name; indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->channels = st->info->channels; diff --git a/drivers/iio/adc/ad7793.c b/drivers/iio/adc/ad7793.c index a43722f..847789b 100644 --- a/drivers/iio/adc/ad7793.c +++ b/drivers/iio/adc/ad7793.c @@ -784,6 +784,7 @@ static int ad7793_probe(struct spi_device *spi) spi_set_drvdata(spi, indio_dev); indio_dev->dev.parent = &spi->dev; + indio_dev->dev.of_node = spi->dev.of_node; indio_dev->name = spi_get_device_id(spi)->name; indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->channels = st->chip_info->channels; diff --git a/drivers/iio/adc/ad7887.c b/drivers/iio/adc/ad7887.c index 1bc363b..7a483bf 100644 --- a/drivers/iio/adc/ad7887.c +++ b/drivers/iio/adc/ad7887.c @@ -264,6 +264,7 @@ static int ad7887_probe(struct spi_device *spi) /* Estabilish that the iio_dev is a child of the spi device */ indio_dev->dev.parent = &spi->dev; + indio_dev->dev.of_node = spi->dev.of_node; indio_dev->name = spi_get_device_id(spi)->name; indio_dev->info = &ad7887_info; indio_dev->modes = INDIO_DIRECT_MODE; diff --git a/drivers/iio/adc/ad7923.c b/drivers/iio/adc/ad7923.c index 1337116..77a675e 100644 --- a/drivers/iio/adc/ad7923.c +++ b/drivers/iio/adc/ad7923.c @@ -288,6 +288,7 @@ static int ad7923_probe(struct spi_device *spi) indio_dev->name = spi_get_device_id(spi)->name; indio_dev->dev.parent = &spi->dev; + indio_dev->dev.of_node = spi->dev.of_node; indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->channels = info->channels; indio_dev->num_channels = info->num_channels; diff --git a/drivers/iio/adc/ad799x.c b/drivers/iio/adc/ad799x.c index 5428476..b616376 100644 --- a/drivers/iio/adc/ad799x.c +++ b/drivers/iio/adc/ad799x.c @@ -806,6 +806,7 @@ static int ad799x_probe(struct i2c_client *client, st->client = client; indio_dev->dev.parent = &client->dev; + indio_dev->dev.of_node = client->dev.of_node; indio_dev->name = id->name; indio_dev->info = st->chip_config->info; diff --git a/drivers/iio/adc/hi8435.c b/drivers/iio/adc/hi8435.c index c62bdb0..678e8c7 100644 --- a/drivers/iio/adc/hi8435.c +++ b/drivers/iio/adc/hi8435.c @@ -455,6 +455,7 @@ static int hi8435_probe(struct spi_device *spi) mutex_init(&priv->lock); idev->dev.parent = &spi->dev; + idev->dev.of_node = spi->dev.of_node; idev->name = spi_get_device_id(spi)->name; idev->modes = INDIO_DIRECT_MODE; idev->info = &hi8435_info; diff --git a/drivers/iio/adc/ina2xx-adc.c b/drivers/iio/adc/ina2xx-adc.c index b95ce5d..955f3fd 100644 --- a/drivers/iio/adc/ina2xx-adc.c +++ b/drivers/iio/adc/ina2xx-adc.c @@ -691,6 +691,7 @@ static int ina2xx_probe(struct i2c_client *client, indio_dev->modes = INDIO_DIRECT_MODE | INDIO_BUFFER_SOFTWARE; indio_dev->dev.parent = &client->dev; + indio_dev->dev.of_node = client->dev.of_node; indio_dev->channels = ina2xx_channels; indio_dev->num_channels = ARRAY_SIZE(ina2xx_channels); indio_dev->name = id->name; diff --git a/drivers/iio/adc/max1027.c b/drivers/iio/adc/max1027.c index 41d495c..712fbd2 100644 --- a/drivers/iio/adc/max1027.c +++ b/drivers/iio/adc/max1027.c @@ -426,6 +426,7 @@ static int max1027_probe(struct spi_device *spi) indio_dev->name = spi_get_device_id(spi)->name; indio_dev->dev.parent = &spi->dev; + indio_dev->dev.of_node = spi->dev.of_node; indio_dev->info = &max1027_info; indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->channels = st->info->channels; diff --git a/drivers/iio/adc/max1363.c b/drivers/iio/adc/max1363.c index 3b53c2e..841a13c 100644 --- a/drivers/iio/adc/max1363.c +++ b/drivers/iio/adc/max1363.c @@ -1646,6 +1646,7 @@ static int max1363_probe(struct i2c_client *client, /* Establish that the iio_dev is a child of the i2c device */ indio_dev->dev.parent = &client->dev; + indio_dev->dev.of_node = client->dev.of_node; indio_dev->name = id->name; indio_dev->channels = st->chip_info->channels; indio_dev->num_channels = st->chip_info->num_channels; diff --git a/drivers/iio/adc/mcp320x.c b/drivers/iio/adc/mcp320x.c index a850ca7..634717a 100644 --- a/drivers/iio/adc/mcp320x.c +++ b/drivers/iio/adc/mcp320x.c @@ -308,6 +308,7 @@ static int mcp320x_probe(struct spi_device *spi) adc->spi = spi; indio_dev->dev.parent = &spi->dev; + indio_dev->dev.of_node = spi->dev.of_node; indio_dev->name = spi_get_device_id(spi)->name; indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->info = &mcp320x_info; diff --git a/drivers/iio/adc/mcp3422.c b/drivers/iio/adc/mcp3422.c index d1172dc..254135e 100644 --- a/drivers/iio/adc/mcp3422.c +++ b/drivers/iio/adc/mcp3422.c @@ -352,6 +352,7 @@ static int mcp3422_probe(struct i2c_client *client, mutex_init(&adc->lock); indio_dev->dev.parent = &client->dev; + indio_dev->dev.of_node = client->dev.of_node; indio_dev->name = dev_name(&client->dev); indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->info = &mcp3422_info; diff --git a/drivers/iio/adc/nau7802.c b/drivers/iio/adc/nau7802.c index 57365c5..db9b829 100644 --- a/drivers/iio/adc/nau7802.c +++ b/drivers/iio/adc/nau7802.c @@ -433,6 +433,7 @@ static int nau7802_probe(struct i2c_client *client, i2c_set_clientdata(client, indio_dev); indio_dev->dev.parent = &client->dev; + indio_dev->dev.of_node = client->dev.of_node; indio_dev->name = dev_name(&client->dev); indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->info = &nau7802_info; diff --git a/drivers/iio/adc/ti-adc081c.c b/drivers/iio/adc/ti-adc081c.c index 283d2a1..319172c 100644 --- a/drivers/iio/adc/ti-adc081c.c +++ b/drivers/iio/adc/ti-adc081c.c @@ -186,6 +186,7 @@ static int adc081c_probe(struct i2c_client *client, return err; iio->dev.parent = &client->dev; + iio->dev.of_node = client->dev.of_node; iio->name = dev_name(&client->dev); iio->modes = INDIO_DIRECT_MODE; iio->info = &adc081c_info; diff --git a/drivers/iio/adc/ti-adc0832.c b/drivers/iio/adc/ti-adc0832.c index 0afeac0..f4ba23e 100644 --- a/drivers/iio/adc/ti-adc0832.c +++ b/drivers/iio/adc/ti-adc0832.c @@ -194,6 +194,7 @@ static int adc0832_probe(struct spi_device *spi) indio_dev->name = spi_get_device_id(spi)->name; indio_dev->dev.parent = &spi->dev; + indio_dev->dev.of_node = spi->dev.of_node; indio_dev->info = &adc0832_info; indio_dev->modes = INDIO_DIRECT_MODE; diff --git a/drivers/iio/adc/ti-adc128s052.c b/drivers/iio/adc/ti-adc128s052.c index bc58867..89dfbd3 100644 --- a/drivers/iio/adc/ti-adc128s052.c +++ b/drivers/iio/adc/ti-adc128s052.c @@ -150,6 +150,7 @@ static int adc128_probe(struct spi_device *spi) spi_set_drvdata(spi, indio_dev); indio_dev->dev.parent = &spi->dev; + indio_dev->dev.of_node = spi->dev.of_node; indio_dev->name = spi_get_device_id(spi)->name; indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->info = &adc128_info; diff --git a/drivers/iio/adc/ti-ads8688.c b/drivers/iio/adc/ti-ads8688.c index 03e9070..c400439 100644 --- a/drivers/iio/adc/ti-ads8688.c +++ b/drivers/iio/adc/ti-ads8688.c @@ -421,6 +421,7 @@ static int ads8688_probe(struct spi_device *spi) indio_dev->name = spi_get_device_id(spi)->name; indio_dev->dev.parent = &spi->dev; + indio_dev->dev.of_node = spi->dev.of_node; indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->channels = st->chip_info->channels; indio_dev->num_channels = st->chip_info->num_channels; -- cgit v0.10.2 From b6140914fd079e43ea75a53429b47128584f033a Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Mon, 4 Jul 2016 17:39:22 +0900 Subject: genirq/msi: Remove unused MSI_FLAG_IDENTITY_MAP No user and we definitely don't want to grow one. Signed-off-by: Thomas Gleixner Reviewed-by: Bart Van Assche Cc: Christoph Hellwig Cc: linux-block@vger.kernel.org Cc: linux-pci@vger.kernel.org Cc: linux-nvme@lists.infradead.org Cc: axboe@fb.com Cc: agordeev@redhat.com Link: http://lkml.kernel.org/r/1467621574-8277-2-git-send-email-hch@lst.de Signed-off-by: Thomas Gleixner diff --git a/include/linux/msi.h b/include/linux/msi.h index 8b425c6..c33abfa 100644 --- a/include/linux/msi.h +++ b/include/linux/msi.h @@ -264,12 +264,10 @@ enum { * callbacks. */ MSI_FLAG_USE_DEF_CHIP_OPS = (1 << 1), - /* Build identity map between hwirq and irq */ - MSI_FLAG_IDENTITY_MAP = (1 << 2), /* Support multiple PCI MSI interrupts */ - MSI_FLAG_MULTI_PCI_MSI = (1 << 3), + MSI_FLAG_MULTI_PCI_MSI = (1 << 2), /* Support PCI MSIX interrupts */ - MSI_FLAG_PCI_MSIX = (1 << 4), + MSI_FLAG_PCI_MSIX = (1 << 3), }; int msi_domain_set_affinity(struct irq_data *data, const struct cpumask *mask, diff --git a/kernel/irq/msi.c b/kernel/irq/msi.c index 38e89ce..eb5bf2b 100644 --- a/kernel/irq/msi.c +++ b/kernel/irq/msi.c @@ -324,7 +324,7 @@ int msi_domain_alloc_irqs(struct irq_domain *domain, struct device *dev, struct msi_domain_ops *ops = info->ops; msi_alloc_info_t arg; struct msi_desc *desc; - int i, ret, virq = -1; + int i, ret, virq; ret = msi_domain_prepare_irqs(domain, dev, nvec, &arg); if (ret) @@ -332,12 +332,8 @@ int msi_domain_alloc_irqs(struct irq_domain *domain, struct device *dev, for_each_msi_entry(desc, dev) { ops->set_desc(&arg, desc); - if (info->flags & MSI_FLAG_IDENTITY_MAP) - virq = (int)ops->get_hwirq(info, &arg); - else - virq = -1; - virq = __irq_domain_alloc_irqs(domain, virq, desc->nvec_used, + virq = __irq_domain_alloc_irqs(domain, -1, desc->nvec_used, dev_to_node(dev), &arg, false); if (virq < 0) { ret = -ENOSPC; -- cgit v0.10.2 From 9c2555835bb3d34dfac52a0be943dcc4bedd650f Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Mon, 4 Jul 2016 17:39:23 +0900 Subject: genirq: Introduce IRQD_AFFINITY_MANAGED flag Interupts marked with this flag are excluded from user space interrupt affinity changes. Contrary to the IRQ_NO_BALANCING flag, the kernel internal affinity mechanism is not blocked. This flag will be used for multi-queue device interrupts. Signed-off-by: Thomas Gleixner Cc: Christoph Hellwig Cc: linux-block@vger.kernel.org Cc: linux-pci@vger.kernel.org Cc: linux-nvme@lists.infradead.org Cc: axboe@fb.com Cc: agordeev@redhat.com Link: http://lkml.kernel.org/r/1467621574-8277-3-git-send-email-hch@lst.de Signed-off-by: Thomas Gleixner diff --git a/include/linux/irq.h b/include/linux/irq.h index 4d758a7..f607481 100644 --- a/include/linux/irq.h +++ b/include/linux/irq.h @@ -197,6 +197,7 @@ struct irq_data { * IRQD_IRQ_INPROGRESS - In progress state of the interrupt * IRQD_WAKEUP_ARMED - Wakeup mode armed * IRQD_FORWARDED_TO_VCPU - The interrupt is forwarded to a VCPU + * IRQD_AFFINITY_MANAGED - Affinity is auto-managed by the kernel */ enum { IRQD_TRIGGER_MASK = 0xf, @@ -212,6 +213,7 @@ enum { IRQD_IRQ_INPROGRESS = (1 << 18), IRQD_WAKEUP_ARMED = (1 << 19), IRQD_FORWARDED_TO_VCPU = (1 << 20), + IRQD_AFFINITY_MANAGED = (1 << 21), }; #define __irqd_to_state(d) ACCESS_PRIVATE((d)->common, state_use_accessors) @@ -305,6 +307,11 @@ static inline void irqd_clr_forwarded_to_vcpu(struct irq_data *d) __irqd_to_state(d) &= ~IRQD_FORWARDED_TO_VCPU; } +static inline bool irqd_affinity_is_managed(struct irq_data *d) +{ + return __irqd_to_state(d) & IRQD_AFFINITY_MANAGED; +} + #undef __irqd_to_state static inline irq_hw_number_t irqd_to_hwirq(struct irq_data *d) diff --git a/kernel/irq/internals.h b/kernel/irq/internals.h index 09be2c9..b15aa3b 100644 --- a/kernel/irq/internals.h +++ b/kernel/irq/internals.h @@ -105,6 +105,8 @@ static inline void unregister_handler_proc(unsigned int irq, struct irqaction *action) { } #endif +extern bool irq_can_set_affinity_usr(unsigned int irq); + extern int irq_select_affinity_usr(unsigned int irq, struct cpumask *mask); extern void irq_set_thread_affinity(struct irq_desc *desc); diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c index ef0bc02..30658e9 100644 --- a/kernel/irq/manage.c +++ b/kernel/irq/manage.c @@ -115,12 +115,12 @@ EXPORT_SYMBOL(synchronize_irq); #ifdef CONFIG_SMP cpumask_var_t irq_default_affinity; -static int __irq_can_set_affinity(struct irq_desc *desc) +static bool __irq_can_set_affinity(struct irq_desc *desc) { if (!desc || !irqd_can_balance(&desc->irq_data) || !desc->irq_data.chip || !desc->irq_data.chip->irq_set_affinity) - return 0; - return 1; + return false; + return true; } /** @@ -134,6 +134,21 @@ int irq_can_set_affinity(unsigned int irq) } /** + * irq_can_set_affinity_usr - Check if affinity of a irq can be set from user space + * @irq: Interrupt to check + * + * Like irq_can_set_affinity() above, but additionally checks for the + * AFFINITY_MANAGED flag. + */ +bool irq_can_set_affinity_usr(unsigned int irq) +{ + struct irq_desc *desc = irq_to_desc(irq); + + return __irq_can_set_affinity(desc) && + !irqd_affinity_is_managed(&desc->irq_data); +} + +/** * irq_set_thread_affinity - Notify irq threads to adjust affinity * @desc: irq descriptor which has affitnity changed * diff --git a/kernel/irq/proc.c b/kernel/irq/proc.c index 4e1b947..40bdcdc 100644 --- a/kernel/irq/proc.c +++ b/kernel/irq/proc.c @@ -96,7 +96,7 @@ static ssize_t write_irq_affinity(int type, struct file *file, cpumask_var_t new_value; int err; - if (!irq_can_set_affinity(irq) || no_irq_affinity) + if (!irq_can_set_affinity_usr(irq) || no_irq_affinity) return -EIO; if (!alloc_cpumask_var(&new_value, GFP_KERNEL)) -- cgit v0.10.2 From 06ee6d571f0e350253a8fc3492316b2be007fae2 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Mon, 4 Jul 2016 17:39:24 +0900 Subject: genirq: Add affinity hint to irq allocation Add an extra argument to the irq(domain) allocation functions, so we can hand down affinity hints to the allocator. Thats necessary to implement proper support for multiqueue devices. Signed-off-by: Thomas Gleixner Cc: Christoph Hellwig Cc: linux-block@vger.kernel.org Cc: linux-pci@vger.kernel.org Cc: linux-nvme@lists.infradead.org Cc: axboe@fb.com Cc: agordeev@redhat.com Link: http://lkml.kernel.org/r/1467621574-8277-4-git-send-email-hch@lst.de Signed-off-by: Thomas Gleixner diff --git a/arch/sparc/kernel/irq_64.c b/arch/sparc/kernel/irq_64.c index e22416c..34a7930 100644 --- a/arch/sparc/kernel/irq_64.c +++ b/arch/sparc/kernel/irq_64.c @@ -242,7 +242,7 @@ unsigned int irq_alloc(unsigned int dev_handle, unsigned int dev_ino) { int irq; - irq = __irq_alloc_descs(-1, 1, 1, numa_node_id(), NULL); + irq = __irq_alloc_descs(-1, 1, 1, numa_node_id(), NULL, NULL); if (irq <= 0) goto out; diff --git a/arch/x86/kernel/apic/io_apic.c b/arch/x86/kernel/apic/io_apic.c index 446702e..7c4f90d 100644 --- a/arch/x86/kernel/apic/io_apic.c +++ b/arch/x86/kernel/apic/io_apic.c @@ -981,7 +981,7 @@ static int alloc_irq_from_domain(struct irq_domain *domain, int ioapic, u32 gsi, return __irq_domain_alloc_irqs(domain, irq, 1, ioapic_alloc_attr_node(info), - info, legacy); + info, legacy, NULL); } /* @@ -1014,7 +1014,8 @@ static int alloc_isa_irq_from_domain(struct irq_domain *domain, info->ioapic_pin)) return -ENOMEM; } else { - irq = __irq_domain_alloc_irqs(domain, irq, 1, node, info, true); + irq = __irq_domain_alloc_irqs(domain, irq, 1, node, info, true, + NULL); if (irq >= 0) { irq_data = irq_domain_get_irq_data(domain, irq); data = irq_data->chip_data; diff --git a/include/linux/irq.h b/include/linux/irq.h index f607481..39ce46a 100644 --- a/include/linux/irq.h +++ b/include/linux/irq.h @@ -708,11 +708,11 @@ static inline struct cpumask *irq_data_get_affinity_mask(struct irq_data *d) unsigned int arch_dynirq_lower_bound(unsigned int from); int __irq_alloc_descs(int irq, unsigned int from, unsigned int cnt, int node, - struct module *owner); + struct module *owner, const struct cpumask *affinity); /* use macros to avoid needing export.h for THIS_MODULE */ #define irq_alloc_descs(irq, from, cnt, node) \ - __irq_alloc_descs(irq, from, cnt, node, THIS_MODULE) + __irq_alloc_descs(irq, from, cnt, node, THIS_MODULE, NULL) #define irq_alloc_desc(node) \ irq_alloc_descs(-1, 0, 1, node) diff --git a/include/linux/irqdomain.h b/include/linux/irqdomain.h index f1f36e0..1aee0fb 100644 --- a/include/linux/irqdomain.h +++ b/include/linux/irqdomain.h @@ -39,6 +39,7 @@ struct irq_domain; struct of_device_id; struct irq_chip; struct irq_data; +struct cpumask; /* Number of irqs reserved for a legacy isa controller */ #define NUM_ISA_INTERRUPTS 16 @@ -217,7 +218,8 @@ extern struct irq_domain *irq_find_matching_fwspec(struct irq_fwspec *fwspec, enum irq_domain_bus_token bus_token); extern void irq_set_default_host(struct irq_domain *host); extern int irq_domain_alloc_descs(int virq, unsigned int nr_irqs, - irq_hw_number_t hwirq, int node); + irq_hw_number_t hwirq, int node, + const struct cpumask *affinity); static inline struct fwnode_handle *of_node_to_fwnode(struct device_node *node) { @@ -389,7 +391,7 @@ static inline struct irq_domain *irq_domain_add_hierarchy(struct irq_domain *par extern int __irq_domain_alloc_irqs(struct irq_domain *domain, int irq_base, unsigned int nr_irqs, int node, void *arg, - bool realloc); + bool realloc, const struct cpumask *affinity); extern void irq_domain_free_irqs(unsigned int virq, unsigned int nr_irqs); extern void irq_domain_activate_irq(struct irq_data *irq_data); extern void irq_domain_deactivate_irq(struct irq_data *irq_data); @@ -397,7 +399,8 @@ extern void irq_domain_deactivate_irq(struct irq_data *irq_data); static inline int irq_domain_alloc_irqs(struct irq_domain *domain, unsigned int nr_irqs, int node, void *arg) { - return __irq_domain_alloc_irqs(domain, -1, nr_irqs, node, arg, false); + return __irq_domain_alloc_irqs(domain, -1, nr_irqs, node, arg, false, + NULL); } extern int irq_domain_alloc_irqs_recursive(struct irq_domain *domain, diff --git a/kernel/irq/ipi.c b/kernel/irq/ipi.c index 89b49f6..4fd2351 100644 --- a/kernel/irq/ipi.c +++ b/kernel/irq/ipi.c @@ -76,7 +76,7 @@ int irq_reserve_ipi(struct irq_domain *domain, } } - virq = irq_domain_alloc_descs(-1, nr_irqs, 0, NUMA_NO_NODE); + virq = irq_domain_alloc_descs(-1, nr_irqs, 0, NUMA_NO_NODE, NULL); if (virq <= 0) { pr_warn("Can't reserve IPI, failed to alloc descs\n"); return -ENOMEM; diff --git a/kernel/irq/irqdesc.c b/kernel/irq/irqdesc.c index 8731e1c..b8df4fc 100644 --- a/kernel/irq/irqdesc.c +++ b/kernel/irq/irqdesc.c @@ -223,7 +223,7 @@ static void free_desc(unsigned int irq) } static int alloc_descs(unsigned int start, unsigned int cnt, int node, - struct module *owner) + const struct cpumask *affinity, struct module *owner) { struct irq_desc *desc; int i; @@ -333,6 +333,7 @@ static void free_desc(unsigned int irq) } static inline int alloc_descs(unsigned int start, unsigned int cnt, int node, + const struct cpumask *affinity, struct module *owner) { u32 i; @@ -453,12 +454,15 @@ EXPORT_SYMBOL_GPL(irq_free_descs); * @cnt: Number of consecutive irqs to allocate. * @node: Preferred node on which the irq descriptor should be allocated * @owner: Owning module (can be NULL) + * @affinity: Optional pointer to an affinity mask which hints where the + * irq descriptors should be allocated and which default + * affinities to use * * Returns the first irq number or error code */ int __ref __irq_alloc_descs(int irq, unsigned int from, unsigned int cnt, int node, - struct module *owner) + struct module *owner, const struct cpumask *affinity) { int start, ret; @@ -494,7 +498,7 @@ __irq_alloc_descs(int irq, unsigned int from, unsigned int cnt, int node, bitmap_set(allocated_irqs, start, cnt); mutex_unlock(&sparse_irq_lock); - return alloc_descs(start, cnt, node, owner); + return alloc_descs(start, cnt, node, affinity, owner); err: mutex_unlock(&sparse_irq_lock); @@ -512,7 +516,7 @@ EXPORT_SYMBOL_GPL(__irq_alloc_descs); */ unsigned int irq_alloc_hwirqs(int cnt, int node) { - int i, irq = __irq_alloc_descs(-1, 0, cnt, node, NULL); + int i, irq = __irq_alloc_descs(-1, 0, cnt, node, NULL, NULL); if (irq < 0) return 0; diff --git a/kernel/irq/irqdomain.c b/kernel/irq/irqdomain.c index 8798b6c..79459b7 100644 --- a/kernel/irq/irqdomain.c +++ b/kernel/irq/irqdomain.c @@ -481,7 +481,7 @@ unsigned int irq_create_mapping(struct irq_domain *domain, } /* Allocate a virtual interrupt number */ - virq = irq_domain_alloc_descs(-1, 1, hwirq, of_node_to_nid(of_node)); + virq = irq_domain_alloc_descs(-1, 1, hwirq, of_node_to_nid(of_node), NULL); if (virq <= 0) { pr_debug("-> virq allocation failed\n"); return 0; @@ -835,19 +835,23 @@ const struct irq_domain_ops irq_domain_simple_ops = { EXPORT_SYMBOL_GPL(irq_domain_simple_ops); int irq_domain_alloc_descs(int virq, unsigned int cnt, irq_hw_number_t hwirq, - int node) + int node, const struct cpumask *affinity) { unsigned int hint; if (virq >= 0) { - virq = irq_alloc_descs(virq, virq, cnt, node); + virq = __irq_alloc_descs(virq, virq, cnt, node, THIS_MODULE, + affinity); } else { hint = hwirq % nr_irqs; if (hint == 0) hint++; - virq = irq_alloc_descs_from(hint, cnt, node); - if (virq <= 0 && hint > 1) - virq = irq_alloc_descs_from(1, cnt, node); + virq = __irq_alloc_descs(-1, hint, cnt, node, THIS_MODULE, + affinity); + if (virq <= 0 && hint > 1) { + virq = __irq_alloc_descs(-1, 1, cnt, node, THIS_MODULE, + affinity); + } } return virq; @@ -1160,6 +1164,7 @@ int irq_domain_alloc_irqs_recursive(struct irq_domain *domain, * @node: NUMA node id for memory allocation * @arg: domain specific argument * @realloc: IRQ descriptors have already been allocated if true + * @affinity: Optional irq affinity mask for multiqueue devices * * Allocate IRQ numbers and initialized all data structures to support * hierarchy IRQ domains. @@ -1175,7 +1180,7 @@ int irq_domain_alloc_irqs_recursive(struct irq_domain *domain, */ int __irq_domain_alloc_irqs(struct irq_domain *domain, int irq_base, unsigned int nr_irqs, int node, void *arg, - bool realloc) + bool realloc, const struct cpumask *affinity) { int i, ret, virq; @@ -1193,7 +1198,8 @@ int __irq_domain_alloc_irqs(struct irq_domain *domain, int irq_base, if (realloc && irq_base >= 0) { virq = irq_base; } else { - virq = irq_domain_alloc_descs(irq_base, nr_irqs, 0, node); + virq = irq_domain_alloc_descs(irq_base, nr_irqs, 0, node, + affinity); if (virq < 0) { pr_debug("cannot allocate IRQ(base %d, count %d)\n", irq_base, nr_irqs); diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c index 30658e9..ad0aac6 100644 --- a/kernel/irq/manage.c +++ b/kernel/irq/manage.c @@ -353,10 +353,11 @@ static int setup_affinity(struct irq_desc *desc, struct cpumask *mask) return 0; /* - * Preserve an userspace affinity setup, but make sure that - * one of the targets is online. + * Preserve the managed affinity setting and an userspace affinity + * setup, but make sure that one of the targets is online. */ - if (irqd_has_set(&desc->irq_data, IRQD_AFFINITY_SET)) { + if (irqd_affinity_is_managed(&desc->irq_data) || + irqd_has_set(&desc->irq_data, IRQD_AFFINITY_SET)) { if (cpumask_intersects(desc->irq_common_data.affinity, cpu_online_mask)) set = desc->irq_common_data.affinity; diff --git a/kernel/irq/msi.c b/kernel/irq/msi.c index eb5bf2b..58dbbac 100644 --- a/kernel/irq/msi.c +++ b/kernel/irq/msi.c @@ -334,7 +334,8 @@ int msi_domain_alloc_irqs(struct irq_domain *domain, struct device *dev, ops->set_desc(&arg, desc); virq = __irq_domain_alloc_irqs(domain, -1, desc->nvec_used, - dev_to_node(dev), &arg, false); + dev_to_node(dev), &arg, false, + NULL); if (virq < 0) { ret = -ENOSPC; if (ops->handle_error) -- cgit v0.10.2 From 45ddcecbfa947f1dd8e8019bad9e90d6c9f2665c Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Mon, 4 Jul 2016 17:39:25 +0900 Subject: genirq: Use affinity hint in irqdesc allocation Use the affinity hint in the irqdesc allocator. The hint is used to determine the node for the allocation and to set the affinity of the interrupt. If multiple interrupts are allocated (multi-MSI) then the allocator iterates over the cpumask and for each set cpu it allocates on their node and sets the initial affinity to that cpu. If a single interrupt is allocated (MSI-X) then the allocator uses the first cpu in the mask to compute the allocation node and uses the mask for the initial affinity setting. Interrupts set up this way are marked with the AFFINITY_MANAGED flag to prevent userspace from messing with their affinity settings. Signed-off-by: Thomas Gleixner Cc: Christoph Hellwig Cc: linux-block@vger.kernel.org Cc: linux-pci@vger.kernel.org Cc: linux-nvme@lists.infradead.org Cc: axboe@fb.com Cc: agordeev@redhat.com Link: http://lkml.kernel.org/r/1467621574-8277-5-git-send-email-hch@lst.de Signed-off-by: Thomas Gleixner diff --git a/kernel/irq/irqdesc.c b/kernel/irq/irqdesc.c index b8df4fc..a623b44 100644 --- a/kernel/irq/irqdesc.c +++ b/kernel/irq/irqdesc.c @@ -68,9 +68,13 @@ static int alloc_masks(struct irq_desc *desc, gfp_t gfp, int node) return 0; } -static void desc_smp_init(struct irq_desc *desc, int node) +static void desc_smp_init(struct irq_desc *desc, int node, + const struct cpumask *affinity) { - cpumask_copy(desc->irq_common_data.affinity, irq_default_affinity); + if (!affinity) + affinity = irq_default_affinity; + cpumask_copy(desc->irq_common_data.affinity, affinity); + #ifdef CONFIG_GENERIC_PENDING_IRQ cpumask_clear(desc->pending_mask); #endif @@ -82,11 +86,12 @@ static void desc_smp_init(struct irq_desc *desc, int node) #else static inline int alloc_masks(struct irq_desc *desc, gfp_t gfp, int node) { return 0; } -static inline void desc_smp_init(struct irq_desc *desc, int node) { } +static inline void +desc_smp_init(struct irq_desc *desc, int node, const struct cpumask *affinity) { } #endif static void desc_set_defaults(unsigned int irq, struct irq_desc *desc, int node, - struct module *owner) + const struct cpumask *affinity, struct module *owner) { int cpu; @@ -107,7 +112,7 @@ static void desc_set_defaults(unsigned int irq, struct irq_desc *desc, int node, desc->owner = owner; for_each_possible_cpu(cpu) *per_cpu_ptr(desc->kstat_irqs, cpu) = 0; - desc_smp_init(desc, node); + desc_smp_init(desc, node, affinity); } int nr_irqs = NR_IRQS; @@ -158,7 +163,9 @@ void irq_unlock_sparse(void) mutex_unlock(&sparse_irq_lock); } -static struct irq_desc *alloc_desc(int irq, int node, struct module *owner) +static struct irq_desc *alloc_desc(int irq, int node, unsigned int flags, + const struct cpumask *affinity, + struct module *owner) { struct irq_desc *desc; gfp_t gfp = GFP_KERNEL; @@ -178,7 +185,8 @@ static struct irq_desc *alloc_desc(int irq, int node, struct module *owner) lockdep_set_class(&desc->lock, &irq_desc_lock_class); init_rcu_head(&desc->rcu); - desc_set_defaults(irq, desc, node, owner); + desc_set_defaults(irq, desc, node, affinity, owner); + irqd_set(&desc->irq_data, flags); return desc; @@ -225,11 +233,30 @@ static void free_desc(unsigned int irq) static int alloc_descs(unsigned int start, unsigned int cnt, int node, const struct cpumask *affinity, struct module *owner) { + const struct cpumask *mask = NULL; struct irq_desc *desc; - int i; + unsigned int flags; + int i, cpu = -1; + + if (affinity && cpumask_empty(affinity)) + return -EINVAL; + + flags = affinity ? IRQD_AFFINITY_MANAGED : 0; for (i = 0; i < cnt; i++) { - desc = alloc_desc(start + i, node, owner); + if (affinity) { + cpu = cpumask_next(cpu, affinity); + if (cpu >= nr_cpu_ids) + cpu = cpumask_first(affinity); + node = cpu_to_node(cpu); + + /* + * For single allocations we use the caller provided + * mask otherwise we use the mask of the target cpu + */ + mask = cnt == 1 ? affinity : cpumask_of(cpu); + } + desc = alloc_desc(start + i, node, flags, mask, owner); if (!desc) goto err; mutex_lock(&sparse_irq_lock); @@ -277,7 +304,7 @@ int __init early_irq_init(void) nr_irqs = initcnt; for (i = 0; i < initcnt; i++) { - desc = alloc_desc(i, node, NULL); + desc = alloc_desc(i, node, 0, NULL, NULL); set_bit(i, allocated_irqs); irq_insert_desc(i, desc); } @@ -311,7 +338,7 @@ int __init early_irq_init(void) alloc_masks(&desc[i], GFP_KERNEL, node); raw_spin_lock_init(&desc[i].lock); lockdep_set_class(&desc[i].lock, &irq_desc_lock_class); - desc_set_defaults(i, &desc[i], node, NULL); + desc_set_defaults(i, &desc[i], node, NULL, NULL); } return arch_early_irq_init(); } @@ -328,7 +355,7 @@ static void free_desc(unsigned int irq) unsigned long flags; raw_spin_lock_irqsave(&desc->lock, flags); - desc_set_defaults(irq, desc, irq_desc_get_node(desc), NULL); + desc_set_defaults(irq, desc, irq_desc_get_node(desc), NULL, NULL); raw_spin_unlock_irqrestore(&desc->lock, flags); } -- cgit v0.10.2 From 0972fa57f53525ffa6ced12d703750fc2791e3ce Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Mon, 4 Jul 2016 17:39:26 +0900 Subject: genirq/msi: Make use of affinity aware allocations Allow the MSI code to provide affinity hints per MSI descriptor. Signed-off-by: Thomas Gleixner Cc: Christoph Hellwig Cc: linux-block@vger.kernel.org Cc: linux-pci@vger.kernel.org Cc: linux-nvme@lists.infradead.org Cc: axboe@fb.com Cc: agordeev@redhat.com Link: http://lkml.kernel.org/r/1467621574-8277-6-git-send-email-hch@lst.de Signed-off-by: Thomas Gleixner diff --git a/include/linux/msi.h b/include/linux/msi.h index c33abfa..4f0bfe5 100644 --- a/include/linux/msi.h +++ b/include/linux/msi.h @@ -47,6 +47,7 @@ struct fsl_mc_msi_desc { * @nvec_used: The number of vectors used * @dev: Pointer to the device which uses this descriptor * @msg: The last set MSI message cached for reuse + * @affinity: Optional pointer to a cpu affinity mask for this descriptor * * @masked: [PCI MSI/X] Mask bits * @is_msix: [PCI MSI/X] True if MSI-X @@ -67,6 +68,7 @@ struct msi_desc { unsigned int nvec_used; struct device *dev; struct msi_msg msg; + const struct cpumask *affinity; union { /* PCI MSI/X specific data */ diff --git a/kernel/irq/msi.c b/kernel/irq/msi.c index 58dbbac..0e2a736 100644 --- a/kernel/irq/msi.c +++ b/kernel/irq/msi.c @@ -335,7 +335,7 @@ int msi_domain_alloc_irqs(struct irq_domain *domain, struct device *dev, virq = __irq_domain_alloc_irqs(domain, -1, desc->nvec_used, dev_to_node(dev), &arg, false, - NULL); + desc->affinity); if (virq < 0) { ret = -ENOSPC; if (ops->handle_error) -- cgit v0.10.2 From 5e385a6ef31fbbf2acbda770aecc2bc2ff933d17 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Mon, 4 Jul 2016 17:39:27 +0900 Subject: genirq: Add a helper to spread an affinity mask for MSI/MSI-X vectors This is lifted from the blk-mq code and adopted to use the affinity mask concept just introduced in the irq handling code. It tries to keep the algorithm the same as the one current used by blk-mq, but improvements like assining vectors on a per-node basis instead of just per sibling are possible with this simple move and refactoring. Signed-off-by: Christoph Hellwig Cc: linux-block@vger.kernel.org Cc: linux-pci@vger.kernel.org Cc: linux-nvme@lists.infradead.org Cc: axboe@fb.com Cc: agordeev@redhat.com Link: http://lkml.kernel.org/r/1467621574-8277-7-git-send-email-hch@lst.de Signed-off-by: Thomas Gleixner diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h index 9fcabeb..b6683f0 100644 --- a/include/linux/interrupt.h +++ b/include/linux/interrupt.h @@ -278,6 +278,8 @@ extern int irq_set_affinity_hint(unsigned int irq, const struct cpumask *m); extern int irq_set_affinity_notifier(unsigned int irq, struct irq_affinity_notify *notify); +struct cpumask *irq_create_affinity_mask(unsigned int *nr_vecs); + #else /* CONFIG_SMP */ static inline int irq_set_affinity(unsigned int irq, const struct cpumask *m) @@ -308,6 +310,12 @@ irq_set_affinity_notifier(unsigned int irq, struct irq_affinity_notify *notify) { return 0; } + +static inline struct cpumask *irq_create_affinity_mask(unsigned int *nr_vecs) +{ + *nr_vecs = 1; + return NULL; +} #endif /* CONFIG_SMP */ /* diff --git a/kernel/irq/Makefile b/kernel/irq/Makefile index 2ee42e9..1d3ee31 100644 --- a/kernel/irq/Makefile +++ b/kernel/irq/Makefile @@ -9,3 +9,4 @@ obj-$(CONFIG_GENERIC_IRQ_MIGRATION) += cpuhotplug.o obj-$(CONFIG_PM_SLEEP) += pm.o obj-$(CONFIG_GENERIC_MSI_IRQ) += msi.o obj-$(CONFIG_GENERIC_IRQ_IPI) += ipi.o +obj-$(CONFIG_SMP) += affinity.o diff --git a/kernel/irq/affinity.c b/kernel/irq/affinity.c new file mode 100644 index 0000000..f689593 --- /dev/null +++ b/kernel/irq/affinity.c @@ -0,0 +1,61 @@ + +#include +#include +#include +#include + +static int get_first_sibling(unsigned int cpu) +{ + unsigned int ret; + + ret = cpumask_first(topology_sibling_cpumask(cpu)); + if (ret < nr_cpu_ids) + return ret; + return cpu; +} + +/* + * Take a map of online CPUs and the number of available interrupt vectors + * and generate an output cpumask suitable for spreading MSI/MSI-X vectors + * so that they are distributed as good as possible around the CPUs. If + * more vectors than CPUs are available we'll map one to each CPU, + * otherwise we map one to the first sibling of each socket. + * + * If there are more vectors than CPUs we will still only have one bit + * set per CPU, but interrupt code will keep on assigning the vectors from + * the start of the bitmap until we run out of vectors. + */ +struct cpumask *irq_create_affinity_mask(unsigned int *nr_vecs) +{ + struct cpumask *affinity_mask; + unsigned int max_vecs = *nr_vecs; + + if (max_vecs == 1) + return NULL; + + affinity_mask = kzalloc(cpumask_size(), GFP_KERNEL); + if (!affinity_mask) { + *nr_vecs = 1; + return NULL; + } + + if (max_vecs >= num_online_cpus()) { + cpumask_copy(affinity_mask, cpu_online_mask); + *nr_vecs = num_online_cpus(); + } else { + unsigned int vecs = 0, cpu; + + for_each_online_cpu(cpu) { + if (cpu == get_first_sibling(cpu)) { + cpumask_set_cpu(cpu, affinity_mask); + vecs++; + } + + if (--max_vecs == 0) + break; + } + *nr_vecs = vecs; + } + + return affinity_mask; +} -- cgit v0.10.2 From 0caa7616a6aca449dd68b58cb29bd491d296c2d5 Mon Sep 17 00:00:00 2001 From: Aaron Campbell Date: Sat, 2 Jul 2016 21:23:24 -0300 Subject: iommu/vt-d: Fix infinite loop in free_all_cpu_cached_iovas Per VT-d spec Section 10.4.2 ("Capability Register"), the maximum number of possible domains is 64K; indeed this is the maximum value that the cap_ndoms() macro will expand to. Since the value 65536 will not fix in a u16, the 'did' variable must be promoted to an int, otherwise the test for < 65536 will always be true and the loop will never end. The symptom, in my case, was a hung machine during suspend. Fixes: 3bd4f9112f87 ("iommu/vt-d: Fix overflow of iommu->domains array") Signed-off-by: Aaron Campbell Signed-off-by: Joerg Roedel diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c index cfe410e..323dac9 100644 --- a/drivers/iommu/intel-iommu.c +++ b/drivers/iommu/intel-iommu.c @@ -4602,13 +4602,13 @@ static void free_all_cpu_cached_iovas(unsigned int cpu) for (i = 0; i < g_num_of_iommus; i++) { struct intel_iommu *iommu = g_iommus[i]; struct dmar_domain *domain; - u16 did; + int did; if (!iommu) continue; for (did = 0; did < cap_ndoms(iommu->cap); did++) { - domain = get_iommu_domain(iommu, did); + domain = get_iommu_domain(iommu, (u16)did); if (!domain) continue; -- cgit v0.10.2 From 65048f4dd9fae7335b48ab23a879119c0e7fa105 Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Tue, 28 Jun 2016 12:02:08 +0530 Subject: phy: xgene: rename "enum phy_mode" to "enum xgene_phy_mode" No functional change. Rename "enum phy_mode" to "enum xgene_phy_mode" in xgene phy driver in preparation for adding set_mode callback in phy core. Signed-off-by: Kishon Vijay Abraham I Reviewed-by: Loc Ho diff --git a/drivers/phy/phy-xgene.c b/drivers/phy/phy-xgene.c index 385362e..ae266e0 100644 --- a/drivers/phy/phy-xgene.c +++ b/drivers/phy/phy-xgene.c @@ -518,7 +518,7 @@ enum clk_type_t { CLK_INT_SING = 2, /* Internal single ended */ }; -enum phy_mode { +enum xgene_phy_mode { MODE_SATA = 0, /* List them for simple reference */ MODE_SGMII = 1, MODE_PCIE = 2, @@ -542,7 +542,7 @@ struct xgene_sata_override_param { struct xgene_phy_ctx { struct device *dev; struct phy *phy; - enum phy_mode mode; /* Mode of operation */ + enum xgene_phy_mode mode; /* Mode of operation */ enum clk_type_t clk_type; /* Input clock selection */ void __iomem *sds_base; /* PHY CSR base addr */ struct clk *clk; /* Optional clock */ -- cgit v0.10.2 From 300eb0139cf27044c67f6005ff17b8434c7843f0 Mon Sep 17 00:00:00 2001 From: David Lechner Date: Mon, 9 May 2016 18:39:59 -0500 Subject: phy: Add set_mode callback The initial use for this is for PHYs that have a mode related to USB OTG. There are several SoCs (e.g. TI OMAP and DA8xx) that have a mode setting in the USB PHY to override OTG VBUS and ID signals. Of course, the enum can be expaned in the future to include modes for other types of PHYs as well. Suggested-by: Kishon Vijay Abraham I Signed-off-by: David Lechner diff --git a/drivers/phy/phy-core.c b/drivers/phy/phy-core.c index b72e9a3..8eca906 100644 --- a/drivers/phy/phy-core.c +++ b/drivers/phy/phy-core.c @@ -342,6 +342,21 @@ int phy_power_off(struct phy *phy) } EXPORT_SYMBOL_GPL(phy_power_off); +int phy_set_mode(struct phy *phy, enum phy_mode mode) +{ + int ret; + + if (!phy || !phy->ops->set_mode) + return 0; + + mutex_lock(&phy->mutex); + ret = phy->ops->set_mode(phy, mode); + mutex_unlock(&phy->mutex); + + return ret; +} +EXPORT_SYMBOL_GPL(phy_set_mode); + /** * _of_phy_get() - lookup and obtain a reference to a phy by phandle * @np: device_node for which to get the phy diff --git a/include/linux/phy/phy.h b/include/linux/phy/phy.h index a810f2a..f08b672 100644 --- a/include/linux/phy/phy.h +++ b/include/linux/phy/phy.h @@ -22,12 +22,20 @@ struct phy; +enum phy_mode { + PHY_MODE_INVALID, + PHY_MODE_USB_HOST, + PHY_MODE_USB_DEVICE, + PHY_MODE_USB_OTG, +}; + /** * struct phy_ops - set of function pointers for performing phy operations * @init: operation to be performed for initializing phy * @exit: operation to be performed while exiting * @power_on: powering on the phy * @power_off: powering off the phy + * @set_mode: set the mode of the phy * @owner: the module owner containing the ops */ struct phy_ops { @@ -35,6 +43,7 @@ struct phy_ops { int (*exit)(struct phy *phy); int (*power_on)(struct phy *phy); int (*power_off)(struct phy *phy); + int (*set_mode)(struct phy *phy, enum phy_mode mode); struct module *owner; }; @@ -126,6 +135,7 @@ int phy_init(struct phy *phy); int phy_exit(struct phy *phy); int phy_power_on(struct phy *phy); int phy_power_off(struct phy *phy); +int phy_set_mode(struct phy *phy, enum phy_mode mode); static inline int phy_get_bus_width(struct phy *phy) { return phy->attrs.bus_width; @@ -233,6 +243,13 @@ static inline int phy_power_off(struct phy *phy) return -ENOSYS; } +static inline int phy_set_mode(struct phy *phy, enum phy_mode mode) +{ + if (!phy) + return 0; + return -ENOSYS; +} + static inline int phy_get_bus_width(struct phy *phy) { return -ENOSYS; -- cgit v0.10.2 From 3fa6993fef634e05d200d141a85df0b044572364 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 4 Jul 2016 14:02:15 +0200 Subject: ALSA: timer: Fix negative queue usage by racy accesses The user timer tu->qused counter may go to a negative value when multiple concurrent reads are performed since both the check and the decrement of tu->qused are done in two individual locked contexts. This results in bogus read outs, and the endless loop in the user-space side. The fix is to move the decrement of the tu->qused counter into the same spinlock context as the zero-check of the counter. Cc: Signed-off-by: Takashi Iwai diff --git a/sound/core/timer.c b/sound/core/timer.c index e722022..9a6157e 100644 --- a/sound/core/timer.c +++ b/sound/core/timer.c @@ -1955,6 +1955,7 @@ static ssize_t snd_timer_user_read(struct file *file, char __user *buffer, qhead = tu->qhead++; tu->qhead %= tu->queue_size; + tu->qused--; spin_unlock_irq(&tu->qlock); if (tu->tread) { @@ -1968,7 +1969,6 @@ static ssize_t snd_timer_user_read(struct file *file, char __user *buffer, } spin_lock_irq(&tu->qlock); - tu->qused--; if (err < 0) goto _error; result += unit; -- cgit v0.10.2 From dbd1b8ea43b17e2ed4acda72f83ea17f69408682 Mon Sep 17 00:00:00 2001 From: "Shreyas B. Prabhu" Date: Fri, 1 Jul 2016 09:24:14 -0500 Subject: cpuidle: Fix last_residency division Snooze is a poll idle state in powernv and pseries platforms. Snooze has a timeout so that if a CPU stays in snooze for more than target residency of the next available idle state, then it would exit thereby giving chance to the cpuidle governor to re-evaluate and promote the CPU to a deeper idle state. Therefore whenever snooze exits due to this timeout, its last_residency will be target_residency of the next deeper state. Commit e93e59ce5b85 "cpuidle: Replace ktime_get() with local_clock()" changed the math around last_residency calculation. Specifically, while converting last_residency value from nano- to microseconds, it carries out right shift by 10. Because of that, in snooze timeout exit scenarios last_residency calculated is roughly 2.3% less than target_residency of the next available state. This pattern is picked up by get_typical_interval() in the menu governor and therefore expected_interval in menu_select() is frequently less than the target_residency of any state other than snooze. Due to this we are entering snooze at a higher rate, thereby affecting the single thread performance. Fix this by using more precise division via ktime_us_delta(). Fixes: e93e59ce5b85 "cpuidle: Replace ktime_get() with local_clock()" Reported-by: Anton Blanchard Bisected-by: Shilpasri G Bhat Signed-off-by: Shreyas B. Prabhu Acked-by: Daniel Lezcano Acked-by: Balbir Singh Signed-off-by: Rafael J. Wysocki diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c index a4d0059..c73207a 100644 --- a/drivers/cpuidle/cpuidle.c +++ b/drivers/cpuidle/cpuidle.c @@ -173,7 +173,7 @@ int cpuidle_enter_state(struct cpuidle_device *dev, struct cpuidle_driver *drv, struct cpuidle_state *target_state = &drv->states[index]; bool broadcast = !!(target_state->flags & CPUIDLE_FLAG_TIMER_STOP); - u64 time_start, time_end; + ktime_t time_start, time_end; s64 diff; /* @@ -195,13 +195,13 @@ int cpuidle_enter_state(struct cpuidle_device *dev, struct cpuidle_driver *drv, sched_idle_set_state(target_state); trace_cpu_idle_rcuidle(index, dev->cpu); - time_start = local_clock(); + time_start = ns_to_ktime(local_clock()); stop_critical_timings(); entered_state = target_state->enter(dev, drv, index); start_critical_timings(); - time_end = local_clock(); + time_end = ns_to_ktime(local_clock()); trace_cpu_idle_rcuidle(PWR_EVENT_EXIT, dev->cpu); /* The cpu is no longer idle or about to enter idle. */ @@ -217,11 +217,7 @@ int cpuidle_enter_state(struct cpuidle_device *dev, struct cpuidle_driver *drv, if (!cpuidle_state_is_coupled(drv, index)) local_irq_enable(); - /* - * local_clock() returns the time in nanosecond, let's shift - * by 10 (divide by 1024) to have microsecond based time. - */ - diff = (time_end - time_start) >> 10; + diff = ktime_us_delta(time_end, time_start); if (diff > INT_MAX) diff = INT_MAX; -- cgit v0.10.2 From 5358aa3ea1d1f1d1b79c7f9e7c41449f584228fa Mon Sep 17 00:00:00 2001 From: David Lechner Date: Mon, 9 May 2016 18:39:58 -0500 Subject: dt-bindings: Add bindings for phy-da8xx-usb Device tree binding for new phy-da8xx-usb driver. Signed-off-by: David Lechner Acked-by: Rob Herring Signed-off-by: Kishon Vijay Abraham I diff --git a/Documentation/devicetree/bindings/phy/phy-da8xx-usb.txt b/Documentation/devicetree/bindings/phy/phy-da8xx-usb.txt new file mode 100644 index 0000000..c26478b --- /dev/null +++ b/Documentation/devicetree/bindings/phy/phy-da8xx-usb.txt @@ -0,0 +1,40 @@ +TI DA8xx/OMAP-L1xx/AM18xx USB PHY + +Required properties: + - compatible: must be "ti,da830-usb-phy". + - #phy-cells: must be 1. + +This device controls the PHY for both the USB 1.1 OHCI and USB 2.0 OTG +controllers on DA8xx SoCs. Consumers of this device should use index 0 for +the USB 2.0 phy device and index 1 for the USB 1.1 phy device. + +It also requires a "syscon" node with compatible = "ti,da830-cfgchip", "syscon" +to access the CFGCHIP2 register. + +Example: + + cfgchip: cfgchip@1417c { + compatible = "ti,da830-cfgchip", "syscon"; + reg = <0x1417c 0x14>; + }; + + usb_phy: usb-phy { + compatible = "ti,da830-usb-phy"; + #phy-cells = <1>; + }; + + usb20: usb@200000 { + compatible = "ti,da830-musb"; + reg = <0x200000 0x1000>; + interrupts = <58>; + phys = <&usb_phy 0>; + phy-names = "usb-phy"; + }; + + usb11: usb@225000 { + compatible = "ti,da830-ohci"; + reg = <0x225000 0x1000>; + interrupts = <59>; + phys = <&usb_phy 1>; + phy-names = "usb-phy"; + }; -- cgit v0.10.2 From f2e600411bad76317b6751caa3b5c20e321e54aa Mon Sep 17 00:00:00 2001 From: David Lechner Date: Mon, 9 May 2016 18:40:00 -0500 Subject: phy: da8xx-usb: new driver for DA8xx SoC USB PHY This is a new phy driver for the SoC USB controllers on the TI DA8xx family of microcontrollers. The USB 1.1 PHY is just a simple on/off. The USB 2.0 PHY also allows overriding the VBUS and ID pins. Signed-off-by: David Lechner Signed-off-by: Kishon Vijay Abraham I diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig index b869b98..02afc624 100644 --- a/drivers/phy/Kconfig +++ b/drivers/phy/Kconfig @@ -44,6 +44,16 @@ config ARMADA375_USBCLUSTER_PHY depends on OF && HAS_IOMEM select GENERIC_PHY +config PHY_DA8XX_USB + tristate "TI DA8xx USB PHY Driver" + depends on ARCH_DAVINCI_DA8XX + select GENERIC_PHY + select MFD_SYSCON + help + Enable this to support the USB PHY on DA8xx SoCs. + + This driver controls both the USB 1.1 PHY and the USB 2.0 PHY. + config PHY_DM816X_USB tristate "TI dm816x USB PHY driver" depends on ARCH_OMAP2PLUS diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile index 9c3e73c..fa8480e 100644 --- a/drivers/phy/Makefile +++ b/drivers/phy/Makefile @@ -6,6 +6,7 @@ obj-$(CONFIG_GENERIC_PHY) += phy-core.o obj-$(CONFIG_PHY_BCM_NS_USB2) += phy-bcm-ns-usb2.o obj-$(CONFIG_PHY_BERLIN_USB) += phy-berlin-usb.o obj-$(CONFIG_PHY_BERLIN_SATA) += phy-berlin-sata.o +obj-$(CONFIG_PHY_DA8XX_USB) += phy-da8xx-usb.o obj-$(CONFIG_PHY_DM816X_USB) += phy-dm816x-usb.o obj-$(CONFIG_ARMADA375_USBCLUSTER_PHY) += phy-armada375-usb2.o obj-$(CONFIG_BCM_KONA_USB2_PHY) += phy-bcm-kona-usb2.o diff --git a/drivers/phy/phy-da8xx-usb.c b/drivers/phy/phy-da8xx-usb.c new file mode 100644 index 0000000..b2e59b6 --- /dev/null +++ b/drivers/phy/phy-da8xx-usb.c @@ -0,0 +1,245 @@ +/* + * phy-da8xx-usb - TI DaVinci DA8xx USB PHY driver + * + * Copyright (C) 2016 David Lechner + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct da8xx_usb_phy { + struct phy_provider *phy_provider; + struct phy *usb11_phy; + struct phy *usb20_phy; + struct clk *usb11_clk; + struct clk *usb20_clk; + struct regmap *regmap; +}; + +static int da8xx_usb11_phy_power_on(struct phy *phy) +{ + struct da8xx_usb_phy *d_phy = phy_get_drvdata(phy); + int ret; + + ret = clk_prepare_enable(d_phy->usb11_clk); + if (ret) + return ret; + + regmap_write_bits(d_phy->regmap, CFGCHIP(2), CFGCHIP2_USB1SUSPENDM, + CFGCHIP2_USB1SUSPENDM); + + return 0; +} + +static int da8xx_usb11_phy_power_off(struct phy *phy) +{ + struct da8xx_usb_phy *d_phy = phy_get_drvdata(phy); + + regmap_write_bits(d_phy->regmap, CFGCHIP(2), CFGCHIP2_USB1SUSPENDM, 0); + + clk_disable_unprepare(d_phy->usb11_clk); + + return 0; +} + +static const struct phy_ops da8xx_usb11_phy_ops = { + .power_on = da8xx_usb11_phy_power_on, + .power_off = da8xx_usb11_phy_power_off, + .owner = THIS_MODULE, +}; + +static int da8xx_usb20_phy_power_on(struct phy *phy) +{ + struct da8xx_usb_phy *d_phy = phy_get_drvdata(phy); + int ret; + + ret = clk_prepare_enable(d_phy->usb20_clk); + if (ret) + return ret; + + regmap_write_bits(d_phy->regmap, CFGCHIP(2), CFGCHIP2_OTGPWRDN, 0); + + return 0; +} + +static int da8xx_usb20_phy_power_off(struct phy *phy) +{ + struct da8xx_usb_phy *d_phy = phy_get_drvdata(phy); + + regmap_write_bits(d_phy->regmap, CFGCHIP(2), CFGCHIP2_OTGPWRDN, + CFGCHIP2_OTGPWRDN); + + clk_disable_unprepare(d_phy->usb20_clk); + + return 0; +} + +static int da8xx_usb20_phy_set_mode(struct phy *phy, enum phy_mode mode) +{ + struct da8xx_usb_phy *d_phy = phy_get_drvdata(phy); + u32 val; + + switch (mode) { + case PHY_MODE_USB_HOST: /* Force VBUS valid, ID = 0 */ + val = CFGCHIP2_OTGMODE_FORCE_HOST; + break; + case PHY_MODE_USB_DEVICE: /* Force VBUS valid, ID = 1 */ + val = CFGCHIP2_OTGMODE_FORCE_DEVICE; + break; + case PHY_MODE_USB_OTG: /* Don't override the VBUS/ID comparators */ + val = CFGCHIP2_OTGMODE_NO_OVERRIDE; + break; + default: + return -EINVAL; + } + + regmap_write_bits(d_phy->regmap, CFGCHIP(2), CFGCHIP2_OTGMODE_MASK, + val); + + return 0; +} + +static const struct phy_ops da8xx_usb20_phy_ops = { + .power_on = da8xx_usb20_phy_power_on, + .power_off = da8xx_usb20_phy_power_off, + .set_mode = da8xx_usb20_phy_set_mode, + .owner = THIS_MODULE, +}; + +static struct phy *da8xx_usb_phy_of_xlate(struct device *dev, + struct of_phandle_args *args) +{ + struct da8xx_usb_phy *d_phy = dev_get_drvdata(dev); + + if (!d_phy) + return ERR_PTR(-ENODEV); + + switch (args->args[0]) { + case 0: + return d_phy->usb20_phy; + case 1: + return d_phy->usb11_phy; + default: + return ERR_PTR(-EINVAL); + } +} + +static int da8xx_usb_phy_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *node = dev->of_node; + struct da8xx_usb_phy *d_phy; + + d_phy = devm_kzalloc(dev, sizeof(*d_phy), GFP_KERNEL); + if (!d_phy) + return -ENOMEM; + + if (node) + d_phy->regmap = syscon_regmap_lookup_by_compatible( + "ti,da830-cfgchip"); + else + d_phy->regmap = syscon_regmap_lookup_by_pdevname("syscon.0"); + if (IS_ERR(d_phy->regmap)) { + dev_err(dev, "Failed to get syscon\n"); + return PTR_ERR(d_phy->regmap); + } + + d_phy->usb11_clk = devm_clk_get(dev, "usb11_phy"); + if (IS_ERR(d_phy->usb11_clk)) { + dev_err(dev, "Failed to get usb11_phy clock\n"); + return PTR_ERR(d_phy->usb11_clk); + } + + d_phy->usb20_clk = devm_clk_get(dev, "usb20_phy"); + if (IS_ERR(d_phy->usb20_clk)) { + dev_err(dev, "Failed to get usb20_phy clock\n"); + return PTR_ERR(d_phy->usb20_clk); + } + + d_phy->usb11_phy = devm_phy_create(dev, node, &da8xx_usb11_phy_ops); + if (IS_ERR(d_phy->usb11_phy)) { + dev_err(dev, "Failed to create usb11 phy\n"); + return PTR_ERR(d_phy->usb11_phy); + } + + d_phy->usb20_phy = devm_phy_create(dev, node, &da8xx_usb20_phy_ops); + if (IS_ERR(d_phy->usb20_phy)) { + dev_err(dev, "Failed to create usb20 phy\n"); + return PTR_ERR(d_phy->usb20_phy); + } + + platform_set_drvdata(pdev, d_phy); + phy_set_drvdata(d_phy->usb11_phy, d_phy); + phy_set_drvdata(d_phy->usb20_phy, d_phy); + + if (node) { + d_phy->phy_provider = devm_of_phy_provider_register(dev, + da8xx_usb_phy_of_xlate); + if (IS_ERR(d_phy->phy_provider)) { + dev_err(dev, "Failed to create phy provider\n"); + return PTR_ERR(d_phy->phy_provider); + } + } else { + int ret; + + ret = phy_create_lookup(d_phy->usb11_phy, "usb-phy", "ohci.0"); + if (ret) + dev_warn(dev, "Failed to create usb11 phy lookup\n"); + ret = phy_create_lookup(d_phy->usb20_phy, "usb-phy", + "musb-da8xx"); + if (ret) + dev_warn(dev, "Failed to create usb20 phy lookup\n"); + } + + return 0; +} + +static int da8xx_usb_phy_remove(struct platform_device *pdev) +{ + struct da8xx_usb_phy *d_phy = platform_get_drvdata(pdev); + + if (!pdev->dev.of_node) { + phy_remove_lookup(d_phy->usb20_phy, "usb-phy", "musb-da8xx"); + phy_remove_lookup(d_phy->usb11_phy, "usb-phy", "ohci.0"); + } + + return 0; +} + +static const struct of_device_id da8xx_usb_phy_ids[] = { + { .compatible = "ti,da830-usb-phy" }, + { } +}; +MODULE_DEVICE_TABLE(of, da8xx_usb_phy_ids); + +static struct platform_driver da8xx_usb_phy_driver = { + .probe = da8xx_usb_phy_probe, + .remove = da8xx_usb_phy_remove, + .driver = { + .name = "da8xx-usb-phy", + .of_match_table = da8xx_usb_phy_ids, + }, +}; + +module_platform_driver(da8xx_usb_phy_driver); + +MODULE_ALIAS("platform:da8xx-usb-phy"); +MODULE_AUTHOR("David Lechner "); +MODULE_DESCRIPTION("TI DA8xx USB PHY driver"); +MODULE_LICENSE("GPL v2"); -- cgit v0.10.2 From a0da445aabe49c31093ecf3930f531e3c63e0b83 Mon Sep 17 00:00:00 2001 From: Heiko Stuebner Date: Wed, 29 Jun 2016 00:12:58 +0200 Subject: phy: rockchip-usb: should be a child device of the GRF The usb-phy is fully enclosed in the general register files (GRF). Therefore as seen from the device-tree it shouldn't be a separate platform-device but instead a sub-device of the GRF - using the simply-mfd mechanism. As the usb-phy is part of the kernel for some releases now, we keep the old (and now deprecated) binding for compatibility purposes. Signed-off-by: Heiko Stuebner Signed-off-by: Kishon Vijay Abraham I diff --git a/Documentation/devicetree/bindings/phy/rockchip-usb-phy.txt b/Documentation/devicetree/bindings/phy/rockchip-usb-phy.txt index 68498d5..cc6be96 100644 --- a/Documentation/devicetree/bindings/phy/rockchip-usb-phy.txt +++ b/Documentation/devicetree/bindings/phy/rockchip-usb-phy.txt @@ -5,11 +5,13 @@ Required properties: "rockchip,rk3066a-usb-phy" "rockchip,rk3188-usb-phy" "rockchip,rk3288-usb-phy" - - rockchip,grf : phandle to the syscon managing the "general - register files" - #address-cells: should be 1 - #size-cells: should be 0 +Deprecated properties: + - rockchip,grf : phandle to the syscon managing the "general + register files" - phy should be a child of the GRF instead + Sub-nodes: Each PHY should be represented as a sub-node. @@ -28,14 +30,19 @@ Optional Properties: Example: -usbphy: phy { - compatible = "rockchip,rk3288-usb-phy"; - rockchip,grf = <&grf>; - #address-cells = <1>; - #size-cells = <0>; +grf: syscon@ff770000 { + compatible = "rockchip,rk3288-grf", "syscon", "simple-mfd"; + +... + + usbphy: phy { + compatible = "rockchip,rk3288-usb-phy"; + #address-cells = <1>; + #size-cells = <0>; - usbphy0: usb-phy0 { - #phy-cells = <0>; - reg = <0x320>; + usbphy0: usb-phy0 { + #phy-cells = <0>; + reg = <0x320>; + }; }; }; diff --git a/drivers/phy/phy-rockchip-usb.c b/drivers/phy/phy-rockchip-usb.c index d60b149..e66b5bf 100644 --- a/drivers/phy/phy-rockchip-usb.c +++ b/drivers/phy/phy-rockchip-usb.c @@ -397,8 +397,13 @@ static int rockchip_usb_phy_probe(struct platform_device *pdev) phy_base->pdata = match->data; phy_base->dev = dev; - phy_base->reg_base = syscon_regmap_lookup_by_phandle(dev->of_node, - "rockchip,grf"); + phy_base->reg_base = ERR_PTR(-ENODEV); + if (dev->parent && dev->parent->of_node) + phy_base->reg_base = syscon_node_to_regmap( + dev->parent->of_node); + if (IS_ERR(phy_base->reg_base)) + phy_base->reg_base = syscon_regmap_lookup_by_phandle( + dev->of_node, "rockchip,grf"); if (IS_ERR(phy_base->reg_base)) { dev_err(&pdev->dev, "Missing rockchip,grf property\n"); return PTR_ERR(phy_base->reg_base); @@ -463,7 +468,11 @@ static int __init rockchip_init_usb_uart(void) return -ENOTSUPP; } - grf = syscon_regmap_lookup_by_phandle(np, "rockchip,grf"); + grf = ERR_PTR(-ENODEV); + if (np->parent) + grf = syscon_node_to_regmap(np->parent); + if (IS_ERR(grf)) + grf = syscon_regmap_lookup_by_phandle(np, "rockchip,grf"); if (IS_ERR(grf)) { pr_err("%s: Missing rockchip,grf property, %lu\n", __func__, PTR_ERR(grf)); -- cgit v0.10.2 From b4bd4b2c4799919aa8c97143d54532aa4b815225 Mon Sep 17 00:00:00 2001 From: Peter Griffin Date: Wed, 8 Jun 2016 10:10:03 +0100 Subject: phy: phy-qcom-ufs-qmp-20nm: Remove site specific OOM error message kzalloc will issue its own error message including a dump_stack() so remote the site specific message. Signed-off-by: Peter Griffin Signed-off-by: Kishon Vijay Abraham I diff --git a/drivers/phy/phy-qcom-ufs-qmp-20nm.c b/drivers/phy/phy-qcom-ufs-qmp-20nm.c index b16ea77..770087a 100644 --- a/drivers/phy/phy-qcom-ufs-qmp-20nm.c +++ b/drivers/phy/phy-qcom-ufs-qmp-20nm.c @@ -196,7 +196,6 @@ static int ufs_qcom_phy_qmp_20nm_probe(struct platform_device *pdev) phy = devm_kzalloc(dev, sizeof(*phy), GFP_KERNEL); if (!phy) { - dev_err(dev, "%s: failed to allocate phy\n", __func__); err = -ENOMEM; goto out; } -- cgit v0.10.2 From 956bc8696ecfb9ec56edd3cd2d8eb9492c34229f Mon Sep 17 00:00:00 2001 From: Peter Griffin Date: Wed, 8 Jun 2016 10:10:02 +0100 Subject: phy: phy-qcom-ufs-qmp-14nm: Remove site specific OOM error message kzalloc will issue its own error message including a dump_stack() so remote the site specific message. Signed-off-by: Peter Griffin Signed-off-by: Kishon Vijay Abraham I diff --git a/drivers/phy/phy-qcom-ufs-qmp-14nm.c b/drivers/phy/phy-qcom-ufs-qmp-14nm.c index 56631e7..6ee5149 100644 --- a/drivers/phy/phy-qcom-ufs-qmp-14nm.c +++ b/drivers/phy/phy-qcom-ufs-qmp-14nm.c @@ -140,7 +140,6 @@ static int ufs_qcom_phy_qmp_14nm_probe(struct platform_device *pdev) phy = devm_kzalloc(dev, sizeof(*phy), GFP_KERNEL); if (!phy) { - dev_err(dev, "%s: failed to allocate phy\n", __func__); err = -ENOMEM; goto out; } -- cgit v0.10.2 From 91d96f06a760f5f36586e972281e239bb9508596 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Wed, 29 Jun 2016 20:14:10 +0200 Subject: phy-sun4i-usb: Add workaround for missing Vbus det interrupts on A31 The A31 companion pmic (axp221) does not generate vbus change interrupts when the board is driving vbus, so we must poll when using the pmic for vbus-det _and_ we're driving vbus. Signed-off-by: Hans de Goede Acked-by: Kishon Vijay Abraham I Signed-off-by: Kishon Vijay Abraham I diff --git a/drivers/phy/phy-sun4i-usb.c b/drivers/phy/phy-sun4i-usb.c index de3101f..0a45bc6 100644 --- a/drivers/phy/phy-sun4i-usb.c +++ b/drivers/phy/phy-sun4i-usb.c @@ -94,6 +94,7 @@ enum sun4i_usb_phy_type { sun4i_a10_phy, + sun6i_a31_phy, sun8i_a33_phy, sun8i_h3_phy, }; @@ -122,7 +123,6 @@ struct sun4i_usb_phy_data { /* phy0 / otg related variables */ struct extcon_dev *extcon; bool phy0_init; - bool phy0_poll; struct gpio_desc *id_det_gpio; struct gpio_desc *vbus_det_gpio; struct power_supply *vbus_power_supply; @@ -343,6 +343,24 @@ static bool sun4i_usb_phy0_have_vbus_det(struct sun4i_usb_phy_data *data) return data->vbus_det_gpio || data->vbus_power_supply; } +static bool sun4i_usb_phy0_poll(struct sun4i_usb_phy_data *data) +{ + if ((data->id_det_gpio && data->id_det_irq <= 0) || + (data->vbus_det_gpio && data->vbus_det_irq <= 0)) + return true; + + /* + * The A31 companion pmic (axp221) does not generate vbus change + * interrupts when the board is driving vbus, so we must poll + * when using the pmic for vbus-det _and_ we're driving vbus. + */ + if (data->cfg->type == sun6i_a31_phy && + data->vbus_power_supply && data->phys[0].regulator_on) + return true; + + return false; +} + static int sun4i_usb_phy_power_on(struct phy *_phy) { struct sun4i_usb_phy *phy = phy_get_drvdata(_phy); @@ -364,7 +382,7 @@ static int sun4i_usb_phy_power_on(struct phy *_phy) phy->regulator_on = true; /* We must report Vbus high within OTG_TIME_A_WAIT_VRISE msec. */ - if (phy->index == 0 && data->vbus_det_gpio && data->phy0_poll) + if (phy->index == 0 && sun4i_usb_phy0_poll(data)) mod_delayed_work(system_wq, &data->detect, DEBOUNCE_TIME); return 0; @@ -385,7 +403,7 @@ static int sun4i_usb_phy_power_off(struct phy *_phy) * phy0 vbus typically slowly discharges, sometimes this causes the * Vbus gpio to not trigger an edge irq on Vbus off, so force a rescan. */ - if (phy->index == 0 && data->vbus_det_gpio && !data->phy0_poll) + if (phy->index == 0 && !sun4i_usb_phy0_poll(data)) mod_delayed_work(system_wq, &data->detect, POLL_TIME); return 0; @@ -468,7 +486,7 @@ static void sun4i_usb_phy0_id_vbus_det_scan(struct work_struct *work) if (vbus_notify) extcon_set_cable_state_(data->extcon, EXTCON_USB, vbus_det); - if (data->phy0_poll) + if (sun4i_usb_phy0_poll(data)) queue_delayed_work(system_wq, &data->detect, POLL_TIME); } @@ -644,11 +662,6 @@ static int sun4i_usb_phy_probe(struct platform_device *pdev) } data->id_det_irq = gpiod_to_irq(data->id_det_gpio); - data->vbus_det_irq = gpiod_to_irq(data->vbus_det_gpio); - if ((data->id_det_gpio && data->id_det_irq <= 0) || - (data->vbus_det_gpio && data->vbus_det_irq <= 0)) - data->phy0_poll = true; - if (data->id_det_irq > 0) { ret = devm_request_irq(dev, data->id_det_irq, sun4i_usb_phy0_id_vbus_det_irq, @@ -660,6 +673,7 @@ static int sun4i_usb_phy_probe(struct platform_device *pdev) } } + data->vbus_det_irq = gpiod_to_irq(data->vbus_det_gpio); if (data->vbus_det_irq > 0) { ret = devm_request_irq(dev, data->vbus_det_irq, sun4i_usb_phy0_id_vbus_det_irq, @@ -711,7 +725,7 @@ static const struct sun4i_usb_phy_cfg sun5i_a13_cfg = { static const struct sun4i_usb_phy_cfg sun6i_a31_cfg = { .num_phys = 3, - .type = sun4i_a10_phy, + .type = sun6i_a31_phy, .disc_thresh = 3, .phyctl_offset = REG_PHYCTL_A10, .dedicated_clocks = true, -- cgit v0.10.2 From d33fb008e4dd807e451cdbcf90712a3d44bc011f Mon Sep 17 00:00:00 2001 From: Sudip Mukherjee Date: Sun, 3 Jul 2016 22:01:06 +0100 Subject: phy: rockhip-usb: use devm_add_action_or_reset() If devm_add_action() fails we are explicitly calling the cleanup to free the resources allocated. Lets use the helper devm_add_action_or_reset() and return directly in case of error, as we know that the cleanup function has been already called by the helper if there was any error. Signed-off-by: Sudip Mukherjee Reviewed-by: Heiko Stuebner Signed-off-by: Kishon Vijay Abraham I diff --git a/drivers/phy/phy-rockchip-usb.c b/drivers/phy/phy-rockchip-usb.c index e66b5bf..2a7381f 100644 --- a/drivers/phy/phy-rockchip-usb.c +++ b/drivers/phy/phy-rockchip-usb.c @@ -236,9 +236,10 @@ static int rockchip_usb_phy_init(struct rockchip_usb_phy_base *base, goto err_clk_prov; } - err = devm_add_action(base->dev, rockchip_usb_phy_action, rk_phy); + err = devm_add_action_or_reset(base->dev, rockchip_usb_phy_action, + rk_phy); if (err) - goto err_devm_action; + return err; rk_phy->phy = devm_phy_create(base->dev, child, &ops); if (IS_ERR(rk_phy->phy)) { @@ -256,9 +257,6 @@ static int rockchip_usb_phy_init(struct rockchip_usb_phy_base *base, else return rockchip_usb_phy_power(rk_phy, 1); -err_devm_action: - if (!rk_phy->uart_enabled) - of_clk_del_provider(child); err_clk_prov: if (!rk_phy->uart_enabled) clk_unregister(rk_phy->clk480m); -- cgit v0.10.2 From c14f8a4032efa73d9c4e155add47c19252b3bdf4 Mon Sep 17 00:00:00 2001 From: Yoshihiro Shimoda Date: Mon, 27 Jun 2016 15:36:53 +0900 Subject: phy: rcar-gen3-usb2: fix mutex_lock calling in interrupt This patch fixes an issue that the extcon_set_cable_state_() is possible to cause "BUG: scheduling while atomic" because this driver calls extcon_set_cable_state_() in the interrupt handler and mutex_lock() is possible to be called by like the following call trace. So, this patch adds a workqueue function to resolve this issue. [ 9.706504] BUG: scheduling while atomic: systemd-journal/25893/0x00010303 [ 9.714569] Modules linked in: [ 9.717629] CPU: 0 PID: 25893 Comm: systemd-journal Not tainted 4.7.0-rc4+ #86 [ 9.724844] Hardware name: Renesas Salvator-X board based on r8a7795 (DT) [ 9.731624] Call trace: [ 9.734077] [] dump_backtrace+0x0/0x1a8 [ 9.739470] [] show_stack+0x14/0x20 [ 9.744520] [] dump_stack+0x94/0xb8 [ 9.749568] [] __schedule_bug+0x44/0x58 [ 9.754966] [] __schedule+0x4e4/0x598 [ 9.760185] [] schedule+0x3c/0xa8 [ 9.765057] [] schedule_preempt_disabled+0x20/0x38 [ 9.771408] [] mutex_optimistic_spin+0x18c/0x1d0 [ 9.777583] [] __mutex_lock_slowpath+0x38/0x140 [ 9.783669] [] mutex_lock+0x44/0x60 [ 9.788717] [] kobject_uevent_env+0x250/0x500 [ 9.794634] [] extcon_update_state+0x220/0x298 [ 9.800634] [] extcon_set_cable_state_+0x78/0x88 [ 9.806812] [] rcar_gen3_device_recognition+0x5c/0xe0 [ 9.813420] [] rcar_gen3_phy_usb2_irq+0x3c/0x48 [ 9.819509] [] handle_irq_event_percpu+0x94/0x140 [ 9.825769] [] handle_irq_event+0x48/0x78 [ 9.831334] [] handle_fasteoi_irq+0xb8/0x1b0 [ 9.837162] [] generic_handle_irq+0x24/0x38 [ 9.842900] [] __handle_domain_irq+0x5c/0xb8 [ 9.848727] [] gic_handle_irq+0x58/0xb0 Reported-by: Simon Horman Fixes: 2b38543c8db1 ("phy: rcar-gen3-usb2: add extcon support") Signed-off-by: Yoshihiro Shimoda Signed-off-by: Kishon Vijay Abraham I diff --git a/drivers/phy/phy-rcar-gen3-usb2.c b/drivers/phy/phy-rcar-gen3-usb2.c index 4be3f5d..31156c9 100644 --- a/drivers/phy/phy-rcar-gen3-usb2.c +++ b/drivers/phy/phy-rcar-gen3-usb2.c @@ -21,6 +21,7 @@ #include #include #include +#include /******* USB2.0 Host registers (original offset is +0x200) *******/ #define USB2_INT_ENABLE 0x000 @@ -81,9 +82,25 @@ struct rcar_gen3_chan { struct extcon_dev *extcon; struct phy *phy; struct regulator *vbus; + struct work_struct work; + bool extcon_host; bool has_otg; }; +static void rcar_gen3_phy_usb2_work(struct work_struct *work) +{ + struct rcar_gen3_chan *ch = container_of(work, struct rcar_gen3_chan, + work); + + if (ch->extcon_host) { + extcon_set_cable_state_(ch->extcon, EXTCON_USB_HOST, true); + extcon_set_cable_state_(ch->extcon, EXTCON_USB, false); + } else { + extcon_set_cable_state_(ch->extcon, EXTCON_USB_HOST, false); + extcon_set_cable_state_(ch->extcon, EXTCON_USB, true); + } +} + static void rcar_gen3_set_host_mode(struct rcar_gen3_chan *ch, int host) { void __iomem *usb2_base = ch->base; @@ -130,8 +147,8 @@ static void rcar_gen3_init_for_host(struct rcar_gen3_chan *ch) rcar_gen3_set_host_mode(ch, 1); rcar_gen3_enable_vbus_ctrl(ch, 1); - extcon_set_cable_state_(ch->extcon, EXTCON_USB_HOST, true); - extcon_set_cable_state_(ch->extcon, EXTCON_USB, false); + ch->extcon_host = true; + schedule_work(&ch->work); } static void rcar_gen3_init_for_peri(struct rcar_gen3_chan *ch) @@ -140,8 +157,8 @@ static void rcar_gen3_init_for_peri(struct rcar_gen3_chan *ch) rcar_gen3_set_host_mode(ch, 0); rcar_gen3_enable_vbus_ctrl(ch, 0); - extcon_set_cable_state_(ch->extcon, EXTCON_USB_HOST, false); - extcon_set_cable_state_(ch->extcon, EXTCON_USB, true); + ch->extcon_host = false; + schedule_work(&ch->work); } static bool rcar_gen3_check_id(struct rcar_gen3_chan *ch) @@ -301,6 +318,7 @@ static int rcar_gen3_phy_usb2_probe(struct platform_device *pdev) if (irq >= 0) { int ret; + INIT_WORK(&channel->work, rcar_gen3_phy_usb2_work); irq = devm_request_irq(dev, irq, rcar_gen3_phy_usb2_irq, IRQF_SHARED, dev_name(dev), channel); if (irq < 0) -- cgit v0.10.2 From 4364e1a29be16b2783c0bcbc263f61236af64281 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Mon, 4 Jul 2016 15:32:25 +0200 Subject: genirq/msi: Fix broken debug output virq is not required to be the same for all msi descs. Use the base irq number from the desc in the debug printk. Reported-by: Ingo Molnar Signed-off-by: Thomas Gleixner diff --git a/kernel/irq/msi.c b/kernel/irq/msi.c index 0e2a736..5499935 100644 --- a/kernel/irq/msi.c +++ b/kernel/irq/msi.c @@ -353,6 +353,7 @@ int msi_domain_alloc_irqs(struct irq_domain *domain, struct device *dev, ops->msi_finish(&arg, 0); for_each_msi_entry(desc, dev) { + virq = desc->irq; if (desc->nvec_used == 1) dev_dbg(dev, "irq %d for MSI\n", virq); else -- cgit v0.10.2 From b99c2d913810e56682a538c9f2394d76fca808f8 Mon Sep 17 00:00:00 2001 From: Miklos Szeredi Date: Mon, 4 Jul 2016 16:49:48 +0200 Subject: ovl: handle ATTR_KILL* Before 4bacc9c9234c ("overlayfs: Make f_path...") file->f_path pointed to the underlying file, hence suid/sgid removal on write worked fine. After that patch file->f_path pointed to the overlay file, and the file mode bits weren't copied to overlay_inode->i_mode. So the suid/sgid removal simply stopped working. The fix is to copy the mode bits, but then ovl_setattr() needs to clear ATTR_MODE to avoid the BUG() in notify_change(). So do this first, then in the next patch copy the mode. Reported-by: Eryu Guan Signed-off-by: Miklos Szeredi Fixes: 4bacc9c9234c ("overlayfs: Make f_path always point to the overlay and f_inode to the underlay") Cc: diff --git a/fs/overlayfs/inode.c b/fs/overlayfs/inode.c index c831c2e..1233992 100644 --- a/fs/overlayfs/inode.c +++ b/fs/overlayfs/inode.c @@ -80,6 +80,9 @@ int ovl_setattr(struct dentry *dentry, struct iattr *attr) goto out_drop_write; } + if (attr->ia_valid & (ATTR_KILL_SUID|ATTR_KILL_SGID)) + attr->ia_valid &= ~ATTR_MODE; + inode_lock(upperdentry->d_inode); err = notify_change(upperdentry, attr, NULL); if (!err) -- cgit v0.10.2 From 07a2daab49c549a37b5b744cbebb6e3f445f12bc Mon Sep 17 00:00:00 2001 From: Vivek Goyal Date: Fri, 1 Jul 2016 16:34:25 -0400 Subject: ovl: Copy up underlying inode's ->i_mode to overlay inode Right now when a new overlay inode is created, we initialize overlay inode's ->i_mode from underlying inode ->i_mode but we retain only file type bits (S_IFMT) and discard permission bits. This patch changes it and retains permission bits too. This should allow overlay to do permission checks on overlay inode itself in task context. [SzM] It also fixes clearing suid/sgid bits on write. Signed-off-by: Vivek Goyal Reported-by: Eryu Guan Signed-off-by: Miklos Szeredi Fixes: 4bacc9c9234c ("overlayfs: Make f_path always point to the overlay and f_inode to the underlay") Cc: diff --git a/fs/overlayfs/inode.c b/fs/overlayfs/inode.c index 1233992..d1cdc60 100644 --- a/fs/overlayfs/inode.c +++ b/fs/overlayfs/inode.c @@ -413,12 +413,11 @@ struct inode *ovl_new_inode(struct super_block *sb, umode_t mode, if (!inode) return NULL; - mode &= S_IFMT; - inode->i_ino = get_next_ino(); inode->i_mode = mode; inode->i_flags |= S_NOATIME | S_NOCMTIME; + mode &= S_IFMT; switch (mode) { case S_IFDIR: inode->i_private = oe; diff --git a/fs/overlayfs/overlayfs.h b/fs/overlayfs/overlayfs.h index 4bd9b5b..cfbca53 100644 --- a/fs/overlayfs/overlayfs.h +++ b/fs/overlayfs/overlayfs.h @@ -187,6 +187,7 @@ static inline void ovl_copyattr(struct inode *from, struct inode *to) { to->i_uid = from->i_uid; to->i_gid = from->i_gid; + to->i_mode = from->i_mode; } /* dir.c */ -- cgit v0.10.2 From 87041a58d3b19455d39baed2a5e5bb43b58fb915 Mon Sep 17 00:00:00 2001 From: Colin Pitrat Date: Sat, 18 Jun 2016 19:05:04 +0100 Subject: gpio: sch: Fix Oops on module load on Asus Eee PC 1201 This fixes the issue descirbe in bug 117531 (https://bugzilla.kernel.org/show_bug.cgi?id=117531). It's a regression introduced in linux 4.5 that causes a Oops at load of gpio_sch and prevents powering off the computer. The issue is that sch_gpio_reg_set is called in sch_gpio_probe before gpio_chip data is initialized with the pointer to the sch_gpio struct. As sch_gpio_reg_set calls gpiochip_get_data, it returns NULL which causes the Oops. The patch follows Mika's advice (https://lkml.org/lkml/2016/5/9/61) and consists in modifying sch_gpio_reg_get and sch_gpio_reg_set to take a sch_gpio struct directly instead of a gpio_chip, which avoids the call to gpiochip_get_data. Thanks Mika for your patience with me :-) Cc: stable@vger.kernel.org Signed-off-by: Colin Pitrat Acked-by: Alexandre Courbot Acked-by: Mika Westerberg Signed-off-by: Linus Walleij diff --git a/drivers/gpio/gpio-sch.c b/drivers/gpio/gpio-sch.c index e85e753..eb43ae4 100644 --- a/drivers/gpio/gpio-sch.c +++ b/drivers/gpio/gpio-sch.c @@ -61,9 +61,8 @@ static unsigned sch_gpio_bit(struct sch_gpio *sch, unsigned gpio) return gpio % 8; } -static int sch_gpio_reg_get(struct gpio_chip *gc, unsigned gpio, unsigned reg) +static int sch_gpio_reg_get(struct sch_gpio *sch, unsigned gpio, unsigned reg) { - struct sch_gpio *sch = gpiochip_get_data(gc); unsigned short offset, bit; u8 reg_val; @@ -75,10 +74,9 @@ static int sch_gpio_reg_get(struct gpio_chip *gc, unsigned gpio, unsigned reg) return reg_val; } -static void sch_gpio_reg_set(struct gpio_chip *gc, unsigned gpio, unsigned reg, +static void sch_gpio_reg_set(struct sch_gpio *sch, unsigned gpio, unsigned reg, int val) { - struct sch_gpio *sch = gpiochip_get_data(gc); unsigned short offset, bit; u8 reg_val; @@ -98,14 +96,15 @@ static int sch_gpio_direction_in(struct gpio_chip *gc, unsigned gpio_num) struct sch_gpio *sch = gpiochip_get_data(gc); spin_lock(&sch->lock); - sch_gpio_reg_set(gc, gpio_num, GIO, 1); + sch_gpio_reg_set(sch, gpio_num, GIO, 1); spin_unlock(&sch->lock); return 0; } static int sch_gpio_get(struct gpio_chip *gc, unsigned gpio_num) { - return sch_gpio_reg_get(gc, gpio_num, GLV); + struct sch_gpio *sch = gpiochip_get_data(gc); + return sch_gpio_reg_get(sch, gpio_num, GLV); } static void sch_gpio_set(struct gpio_chip *gc, unsigned gpio_num, int val) @@ -113,7 +112,7 @@ static void sch_gpio_set(struct gpio_chip *gc, unsigned gpio_num, int val) struct sch_gpio *sch = gpiochip_get_data(gc); spin_lock(&sch->lock); - sch_gpio_reg_set(gc, gpio_num, GLV, val); + sch_gpio_reg_set(sch, gpio_num, GLV, val); spin_unlock(&sch->lock); } @@ -123,7 +122,7 @@ static int sch_gpio_direction_out(struct gpio_chip *gc, unsigned gpio_num, struct sch_gpio *sch = gpiochip_get_data(gc); spin_lock(&sch->lock); - sch_gpio_reg_set(gc, gpio_num, GIO, 0); + sch_gpio_reg_set(sch, gpio_num, GIO, 0); spin_unlock(&sch->lock); /* @@ -182,13 +181,13 @@ static int sch_gpio_probe(struct platform_device *pdev) * GPIO7 is configured by the CMC as SLPIOVR * Enable GPIO[9:8] core powered gpios explicitly */ - sch_gpio_reg_set(&sch->chip, 8, GEN, 1); - sch_gpio_reg_set(&sch->chip, 9, GEN, 1); + sch_gpio_reg_set(sch, 8, GEN, 1); + sch_gpio_reg_set(sch, 9, GEN, 1); /* * SUS_GPIO[2:0] enabled by default * Enable SUS_GPIO3 resume powered gpio explicitly */ - sch_gpio_reg_set(&sch->chip, 13, GEN, 1); + sch_gpio_reg_set(sch, 13, GEN, 1); break; case PCI_DEVICE_ID_INTEL_ITC_LPC: -- cgit v0.10.2 From 85b03b3033fd4eba82665b3b9902c095a08cc52f Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Sun, 3 Jul 2016 18:32:05 +0200 Subject: Revert "gpiolib: Split GPIO flags parsing and GPIO configuration" This reverts commit 923b93e451db876d1479d3e4458fce14fec31d1c. Make sure consumers do not overwrite gpio flags for pins that have already been claimed. While adding support for gpio drivers to refuse a request using unsupported flags, the order of when the requested flag was checked and the new flags were applied was reversed to that consumers could overwrite flags for already requested gpios. This not only affects device-tree setups where two drivers could request the same gpio using conflicting configurations, but also allowed user space to clear gpio flags for already claimed pins simply by attempting to export them through the sysfs interface. By for example clearing the FLAG_ACTIVE_LOW flag this way, user space could effectively change the polarity of a signal. Reverting this change obviously prevents gpio drivers from doing sanity checks on the flags in their request callbacks. Fortunately only one recently added driver (gpio-tps65218 in v4.6) appears to do this, and a follow up patch could restore this functionality through a different interface. Cc: stable # 4.4 Signed-off-by: Johan Hovold Signed-off-by: Linus Walleij diff --git a/drivers/gpio/gpiolib-legacy.c b/drivers/gpio/gpiolib-legacy.c index 3a5c701..8b83099 100644 --- a/drivers/gpio/gpiolib-legacy.c +++ b/drivers/gpio/gpiolib-legacy.c @@ -28,6 +28,10 @@ int gpio_request_one(unsigned gpio, unsigned long flags, const char *label) if (!desc && gpio_is_valid(gpio)) return -EPROBE_DEFER; + err = gpiod_request(desc, label); + if (err) + return err; + if (flags & GPIOF_OPEN_DRAIN) set_bit(FLAG_OPEN_DRAIN, &desc->flags); @@ -37,10 +41,6 @@ int gpio_request_one(unsigned gpio, unsigned long flags, const char *label) if (flags & GPIOF_ACTIVE_LOW) set_bit(FLAG_ACTIVE_LOW, &desc->flags); - err = gpiod_request(desc, label); - if (err) - return err; - if (flags & GPIOF_DIR_IN) err = gpiod_direction_input(desc); else diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 570771e..be74bd3 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -1352,14 +1352,6 @@ static int __gpiod_request(struct gpio_desc *desc, const char *label) spin_lock_irqsave(&gpio_lock, flags); } done: - if (status < 0) { - /* Clear flags that might have been set by the caller before - * requesting the GPIO. - */ - clear_bit(FLAG_ACTIVE_LOW, &desc->flags); - clear_bit(FLAG_OPEN_DRAIN, &desc->flags); - clear_bit(FLAG_OPEN_SOURCE, &desc->flags); - } spin_unlock_irqrestore(&gpio_lock, flags); return status; } @@ -2587,28 +2579,13 @@ struct gpio_desc *__must_check gpiod_get_optional(struct device *dev, } EXPORT_SYMBOL_GPL(gpiod_get_optional); -/** - * gpiod_parse_flags - helper function to parse GPIO lookup flags - * @desc: gpio to be setup - * @lflags: gpio_lookup_flags - returned from of_find_gpio() or - * of_get_gpio_hog() - * - * Set the GPIO descriptor flags based on the given GPIO lookup flags. - */ -static void gpiod_parse_flags(struct gpio_desc *desc, unsigned long lflags) -{ - if (lflags & GPIO_ACTIVE_LOW) - set_bit(FLAG_ACTIVE_LOW, &desc->flags); - if (lflags & GPIO_OPEN_DRAIN) - set_bit(FLAG_OPEN_DRAIN, &desc->flags); - if (lflags & GPIO_OPEN_SOURCE) - set_bit(FLAG_OPEN_SOURCE, &desc->flags); -} /** * gpiod_configure_flags - helper function to configure a given GPIO * @desc: gpio whose value will be assigned * @con_id: function within the GPIO consumer + * @lflags: gpio_lookup_flags - returned from of_find_gpio() or + * of_get_gpio_hog() * @dflags: gpiod_flags - optional GPIO initialization flags * * Return 0 on success, -ENOENT if no GPIO has been assigned to the @@ -2616,10 +2593,17 @@ static void gpiod_parse_flags(struct gpio_desc *desc, unsigned long lflags) * occurred while trying to acquire the GPIO. */ static int gpiod_configure_flags(struct gpio_desc *desc, const char *con_id, - enum gpiod_flags dflags) + unsigned long lflags, enum gpiod_flags dflags) { int status; + if (lflags & GPIO_ACTIVE_LOW) + set_bit(FLAG_ACTIVE_LOW, &desc->flags); + if (lflags & GPIO_OPEN_DRAIN) + set_bit(FLAG_OPEN_DRAIN, &desc->flags); + if (lflags & GPIO_OPEN_SOURCE) + set_bit(FLAG_OPEN_SOURCE, &desc->flags); + /* No particular flag request, return here... */ if (!(dflags & GPIOD_FLAGS_BIT_DIR_SET)) { pr_debug("no flags found for %s\n", con_id); @@ -2686,13 +2670,11 @@ struct gpio_desc *__must_check gpiod_get_index(struct device *dev, return desc; } - gpiod_parse_flags(desc, lookupflags); - status = gpiod_request(desc, con_id); if (status < 0) return ERR_PTR(status); - status = gpiod_configure_flags(desc, con_id, flags); + status = gpiod_configure_flags(desc, con_id, lookupflags, flags); if (status < 0) { dev_dbg(dev, "setup of GPIO %s failed\n", con_id); gpiod_put(desc); @@ -2748,6 +2730,10 @@ struct gpio_desc *fwnode_get_named_gpiod(struct fwnode_handle *fwnode, if (IS_ERR(desc)) return desc; + ret = gpiod_request(desc, NULL); + if (ret) + return ERR_PTR(ret); + if (active_low) set_bit(FLAG_ACTIVE_LOW, &desc->flags); @@ -2758,10 +2744,6 @@ struct gpio_desc *fwnode_get_named_gpiod(struct fwnode_handle *fwnode, set_bit(FLAG_OPEN_SOURCE, &desc->flags); } - ret = gpiod_request(desc, NULL); - if (ret) - return ERR_PTR(ret); - return desc; } EXPORT_SYMBOL_GPL(fwnode_get_named_gpiod); @@ -2814,8 +2796,6 @@ int gpiod_hog(struct gpio_desc *desc, const char *name, chip = gpiod_to_chip(desc); hwnum = gpio_chip_hwgpio(desc); - gpiod_parse_flags(desc, lflags); - local_desc = gpiochip_request_own_desc(chip, hwnum, name); if (IS_ERR(local_desc)) { status = PTR_ERR(local_desc); @@ -2824,7 +2804,7 @@ int gpiod_hog(struct gpio_desc *desc, const char *name, return status; } - status = gpiod_configure_flags(desc, name, dflags); + status = gpiod_configure_flags(desc, name, lflags, dflags); if (status < 0) { pr_err("setup of hog GPIO %s (chip %s, offset %d) failed, %d\n", name, chip->label, hwnum, status); -- cgit v0.10.2 From 4e68cfbf345c3b9109242483cd56d551d38c8b85 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 22 May 2016 20:39:29 +0100 Subject: iio: accel: st_accel: Add lis3l02dq support Time to finally kill off the venerable (it was one of my first drivers) lis3l02dq driver in favour of adding support in the st sensors framework. This does loose us the event support that driver always had, but I think that will reappear at some point and in the meantime the maintenance advantages of dropping the 'special' driver for this one part outweigh the issues. It's worth noting this part is ancient and I may well be the only person who still has any on hardware running recent kernels. It has a few 'quirks'. - No WAI register so that just became optional. - A BDU option that really does block updates. Completely. Whatever you do, you don't get any more data with it set. It is documented the same as more modern parts but I presume they are actually clearing for updates after a read of both bytes! - Fixed scale. - It's too quick. Even at slowest rate (280Hz) I can't read out fast enough on my board (stargate 2) to beat new data coming in. Linus' repeat read patch doesn't help in this case. It just means I get 10 readings before dying... So in reality this will get used with software triggers only unless someone has this long out of production device on a quick board. Signed-off-by: Jonathan Cameron Reviewed-by: Linus Walleij Cc: Denis CIOCCA Cc: Crestez Dan Leonard Signed-off-by: Jonathan Cameron diff --git a/drivers/iio/accel/st_accel.h b/drivers/iio/accel/st_accel.h index 57f83a6..f8dfdb6 100644 --- a/drivers/iio/accel/st_accel.h +++ b/drivers/iio/accel/st_accel.h @@ -29,6 +29,7 @@ #define LSM330_ACCEL_DEV_NAME "lsm330_accel" #define LSM303AGR_ACCEL_DEV_NAME "lsm303agr_accel" #define LIS2DH12_ACCEL_DEV_NAME "lis2dh12_accel" +#define LIS3L02DQ_ACCEL_DEV_NAME "lis3l02dq" /** * struct st_sensors_platform_data - default accel platform data diff --git a/drivers/iio/accel/st_accel_core.c b/drivers/iio/accel/st_accel_core.c index dce289a..da3fb06 100644 --- a/drivers/iio/accel/st_accel_core.c +++ b/drivers/iio/accel/st_accel_core.c @@ -215,6 +215,22 @@ #define ST_ACCEL_6_IHL_IRQ_MASK 0x80 #define ST_ACCEL_6_MULTIREAD_BIT true +/* CUSTOM VALUES FOR SENSOR 7 */ +#define ST_ACCEL_7_ODR_ADDR 0x20 +#define ST_ACCEL_7_ODR_MASK 0x30 +#define ST_ACCEL_7_ODR_AVL_280HZ_VAL 0x00 +#define ST_ACCEL_7_ODR_AVL_560HZ_VAL 0x01 +#define ST_ACCEL_7_ODR_AVL_1120HZ_VAL 0x02 +#define ST_ACCEL_7_ODR_AVL_4480HZ_VAL 0x03 +#define ST_ACCEL_7_PW_ADDR 0x20 +#define ST_ACCEL_7_PW_MASK 0xc0 +#define ST_ACCEL_7_FS_AVL_2_GAIN IIO_G_TO_M_S_2(488) +#define ST_ACCEL_7_BDU_ADDR 0x21 +#define ST_ACCEL_7_BDU_MASK 0x40 +#define ST_ACCEL_7_DRDY_IRQ_ADDR 0x21 +#define ST_ACCEL_7_DRDY_IRQ_INT1_MASK 0x04 +#define ST_ACCEL_7_MULTIREAD_BIT false + static const struct iio_chan_spec st_accel_8bit_channels[] = { ST_SENSORS_LSM_CHANNELS(IIO_ACCEL, BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE), @@ -662,6 +678,54 @@ static const struct st_sensor_settings st_accel_sensors_settings[] = { .multi_read_bit = ST_ACCEL_6_MULTIREAD_BIT, .bootime = 2, }, + { + /* No WAI register present */ + .sensors_supported = { + [0] = LIS3L02DQ_ACCEL_DEV_NAME, + }, + .ch = (struct iio_chan_spec *)st_accel_12bit_channels, + .odr = { + .addr = ST_ACCEL_7_ODR_ADDR, + .mask = ST_ACCEL_7_ODR_MASK, + .odr_avl = { + { 280, ST_ACCEL_7_ODR_AVL_280HZ_VAL, }, + { 560, ST_ACCEL_7_ODR_AVL_560HZ_VAL, }, + { 1120, ST_ACCEL_7_ODR_AVL_1120HZ_VAL, }, + { 4480, ST_ACCEL_7_ODR_AVL_4480HZ_VAL, }, + }, + }, + .pw = { + .addr = ST_ACCEL_7_PW_ADDR, + .mask = ST_ACCEL_7_PW_MASK, + .value_on = ST_SENSORS_DEFAULT_POWER_ON_VALUE, + .value_off = ST_SENSORS_DEFAULT_POWER_OFF_VALUE, + }, + .enable_axis = { + .addr = ST_SENSORS_DEFAULT_AXIS_ADDR, + .mask = ST_SENSORS_DEFAULT_AXIS_MASK, + }, + .fs = { + .fs_avl = { + [0] = { + .num = ST_ACCEL_FS_AVL_2G, + .gain = ST_ACCEL_7_FS_AVL_2_GAIN, + }, + }, + }, + /* + * The part has a BDU bit but if set the data is never + * updated so don't set it. + */ + .bdu = { + }, + .drdy_irq = { + .addr = ST_ACCEL_7_DRDY_IRQ_ADDR, + .mask_int1 = ST_ACCEL_7_DRDY_IRQ_INT1_MASK, + .addr_stat_drdy = ST_SENSORS_DEFAULT_STAT_ADDR, + }, + .multi_read_bit = ST_ACCEL_7_MULTIREAD_BIT, + .bootime = 2, + }, }; static int st_accel_read_raw(struct iio_dev *indio_dev, diff --git a/drivers/iio/accel/st_accel_i2c.c b/drivers/iio/accel/st_accel_i2c.c index 7333ee9..e9d427a 100644 --- a/drivers/iio/accel/st_accel_i2c.c +++ b/drivers/iio/accel/st_accel_i2c.c @@ -80,6 +80,10 @@ static const struct of_device_id st_accel_of_match[] = { .compatible = "st,h3lis331dl-accel", .data = H3LIS331DL_DRIVER_NAME, }, + { + .compatible = "st,lis3l02dq", + .data = LIS3L02DQ_ACCEL_DEV_NAME, + }, {}, }; MODULE_DEVICE_TABLE(of, st_accel_of_match); @@ -130,6 +134,7 @@ static const struct i2c_device_id st_accel_id_table[] = { { LSM330_ACCEL_DEV_NAME }, { LSM303AGR_ACCEL_DEV_NAME }, { LIS2DH12_ACCEL_DEV_NAME }, + { LIS3L02DQ_ACCEL_DEV_NAME }, {}, }; MODULE_DEVICE_TABLE(i2c, st_accel_id_table); diff --git a/drivers/iio/accel/st_accel_spi.c b/drivers/iio/accel/st_accel_spi.c index fcd5847..efd4394 100644 --- a/drivers/iio/accel/st_accel_spi.c +++ b/drivers/iio/accel/st_accel_spi.c @@ -59,6 +59,7 @@ static const struct spi_device_id st_accel_id_table[] = { { LSM330_ACCEL_DEV_NAME }, { LSM303AGR_ACCEL_DEV_NAME }, { LIS2DH12_ACCEL_DEV_NAME }, + { LIS3L02DQ_ACCEL_DEV_NAME }, {}, }; MODULE_DEVICE_TABLE(spi, st_accel_id_table); diff --git a/drivers/iio/common/st_sensors/st_sensors_core.c b/drivers/iio/common/st_sensors/st_sensors_core.c index 6db12ea..26ce325 100644 --- a/drivers/iio/common/st_sensors/st_sensors_core.c +++ b/drivers/iio/common/st_sensors/st_sensors_core.c @@ -550,7 +550,7 @@ int st_sensors_check_device_support(struct iio_dev *indio_dev, int num_sensors_list, const struct st_sensor_settings *sensor_settings) { - int i, n, err; + int i, n, err = 0; u8 wai; struct st_sensor_data *sdata = iio_priv(indio_dev); @@ -570,17 +570,21 @@ int st_sensors_check_device_support(struct iio_dev *indio_dev, return -ENODEV; } - err = sdata->tf->read_byte(&sdata->tb, sdata->dev, - sensor_settings[i].wai_addr, &wai); - if (err < 0) { - dev_err(&indio_dev->dev, "failed to read Who-Am-I register.\n"); - return err; - } + if (sensor_settings[i].wai_addr) { + err = sdata->tf->read_byte(&sdata->tb, sdata->dev, + sensor_settings[i].wai_addr, &wai); + if (err < 0) { + dev_err(&indio_dev->dev, + "failed to read Who-Am-I register.\n"); + return err; + } - if (sensor_settings[i].wai != wai) { - dev_err(&indio_dev->dev, "%s: WhoAmI mismatch (0x%x).\n", - indio_dev->name, wai); - return -EINVAL; + if (sensor_settings[i].wai != wai) { + dev_err(&indio_dev->dev, + "%s: WhoAmI mismatch (0x%x).\n", + indio_dev->name, wai); + return -EINVAL; + } } sdata->sensor_settings = -- cgit v0.10.2 From fc6bd7275bd4c1d7fce50c55370b0a3526869bd7 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 3 Jul 2016 14:55:50 +0100 Subject: staging:iio:lis3l02dq drop separate driver Retire this venerable driver as the basic support is now in the generic st-sensors accelerometer driver. There are a few missing features in the new driver: * Threshold events. * Access to the calibration adjustment registers (patch shortly) In exchange it brings a cleaner and more maintainable code base that actually gets tested more than once every few years. I'll actually be suprised if anyone other than me has a board with one of these on that is running an up to date kernel. Signed-off-by: Jonathan Cameron diff --git a/drivers/staging/iio/accel/Kconfig b/drivers/staging/iio/accel/Kconfig index f066aa3..1c994b5 100644 --- a/drivers/staging/iio/accel/Kconfig +++ b/drivers/staging/iio/accel/Kconfig @@ -51,20 +51,6 @@ config ADIS16240 To compile this driver as a module, say M here: the module will be called adis16240. -config LIS3L02DQ - tristate "ST Microelectronics LIS3L02DQ Accelerometer Driver" - depends on SPI - select IIO_TRIGGER if IIO_BUFFER - depends on !IIO_BUFFER || IIO_KFIFO_BUF - depends on GPIOLIB || COMPILE_TEST - help - Say Y here to build SPI support for the ST microelectronics - accelerometer. The driver supplies direct access via sysfs files - and an event interface via a character device. - - To compile this driver as a module, say M here: the module will be - called lis3l02dq. - config SCA3000 depends on IIO_BUFFER depends on SPI diff --git a/drivers/staging/iio/accel/Makefile b/drivers/staging/iio/accel/Makefile index 415329c..1810a43 100644 --- a/drivers/staging/iio/accel/Makefile +++ b/drivers/staging/iio/accel/Makefile @@ -14,9 +14,5 @@ obj-$(CONFIG_ADIS16209) += adis16209.o adis16240-y := adis16240_core.o obj-$(CONFIG_ADIS16240) += adis16240.o -lis3l02dq-y := lis3l02dq_core.o -lis3l02dq-$(CONFIG_IIO_BUFFER) += lis3l02dq_ring.o -obj-$(CONFIG_LIS3L02DQ) += lis3l02dq.o - sca3000-y := sca3000_core.o sca3000_ring.o obj-$(CONFIG_SCA3000) += sca3000.o diff --git a/drivers/staging/iio/accel/lis3l02dq.h b/drivers/staging/iio/accel/lis3l02dq.h deleted file mode 100644 index 6bd3d4d..0000000 --- a/drivers/staging/iio/accel/lis3l02dq.h +++ /dev/null @@ -1,217 +0,0 @@ -/* - * LISL02DQ.h -- support STMicroelectronics LISD02DQ - * 3d 2g Linear Accelerometers via SPI - * - * Copyright (c) 2007 Jonathan Cameron - * - * Loosely based upon tle62x0.c - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#ifndef SPI_LIS3L02DQ_H_ -#define SPI_LIS3L02DQ_H_ -#define LIS3L02DQ_READ_REG(a) ((a) | 0x80) -#define LIS3L02DQ_WRITE_REG(a) a - -/* Calibration parameters */ -#define LIS3L02DQ_REG_OFFSET_X_ADDR 0x16 -#define LIS3L02DQ_REG_OFFSET_Y_ADDR 0x17 -#define LIS3L02DQ_REG_OFFSET_Z_ADDR 0x18 - -#define LIS3L02DQ_REG_GAIN_X_ADDR 0x19 -#define LIS3L02DQ_REG_GAIN_Y_ADDR 0x1A -#define LIS3L02DQ_REG_GAIN_Z_ADDR 0x1B - -/* Control Register (1 of 2) */ -#define LIS3L02DQ_REG_CTRL_1_ADDR 0x20 -/* Power ctrl - either bit set corresponds to on*/ -#define LIS3L02DQ_REG_CTRL_1_PD_ON 0xC0 - -/* Decimation Factor */ -#define LIS3L02DQ_DEC_MASK 0x30 -#define LIS3L02DQ_REG_CTRL_1_DF_128 0x00 -#define LIS3L02DQ_REG_CTRL_1_DF_64 0x10 -#define LIS3L02DQ_REG_CTRL_1_DF_32 0x20 -#define LIS3L02DQ_REG_CTRL_1_DF_8 (0x10 | 0x20) - -/* Self Test Enable */ -#define LIS3L02DQ_REG_CTRL_1_SELF_TEST_ON 0x08 - -/* Axes enable ctrls */ -#define LIS3L02DQ_REG_CTRL_1_AXES_Z_ENABLE 0x04 -#define LIS3L02DQ_REG_CTRL_1_AXES_Y_ENABLE 0x02 -#define LIS3L02DQ_REG_CTRL_1_AXES_X_ENABLE 0x01 - -/* Control Register (2 of 2) */ -#define LIS3L02DQ_REG_CTRL_2_ADDR 0x21 - -/* Block Data Update only after MSB and LSB read */ -#define LIS3L02DQ_REG_CTRL_2_BLOCK_UPDATE 0x40 - -/* Set to big endian output */ -#define LIS3L02DQ_REG_CTRL_2_BIG_ENDIAN 0x20 - -/* Reboot memory content */ -#define LIS3L02DQ_REG_CTRL_2_REBOOT_MEMORY 0x10 - -/* Interrupt Enable - applies data ready to the RDY pad */ -#define LIS3L02DQ_REG_CTRL_2_ENABLE_INTERRUPT 0x08 - -/* Enable Data Ready Generation - relationship with previous unclear in docs */ -#define LIS3L02DQ_REG_CTRL_2_ENABLE_DATA_READY_GENERATION 0x04 - -/* SPI 3 wire mode */ -#define LIS3L02DQ_REG_CTRL_2_THREE_WIRE_SPI_MODE 0x02 - -/* Data alignment, default is 12 bit right justified - * - option for 16 bit left justified - */ -#define LIS3L02DQ_REG_CTRL_2_DATA_ALIGNMENT_16_BIT_LEFT_JUSTIFIED 0x01 - -/* Interrupt related stuff */ -#define LIS3L02DQ_REG_WAKE_UP_CFG_ADDR 0x23 - -/* Switch from or combination of conditions to and */ -#define LIS3L02DQ_REG_WAKE_UP_CFG_BOOLEAN_AND 0x80 - -/* Latch interrupt request, - * if on ack must be given by reading the ack register - */ -#define LIS3L02DQ_REG_WAKE_UP_CFG_LATCH_SRC 0x40 - -/* Z Interrupt on High (above threshold) */ -#define LIS3L02DQ_REG_WAKE_UP_CFG_INTERRUPT_Z_HIGH 0x20 -/* Z Interrupt on Low */ -#define LIS3L02DQ_REG_WAKE_UP_CFG_INTERRUPT_Z_LOW 0x10 -/* Y Interrupt on High */ -#define LIS3L02DQ_REG_WAKE_UP_CFG_INTERRUPT_Y_HIGH 0x08 -/* Y Interrupt on Low */ -#define LIS3L02DQ_REG_WAKE_UP_CFG_INTERRUPT_Y_LOW 0x04 -/* X Interrupt on High */ -#define LIS3L02DQ_REG_WAKE_UP_CFG_INTERRUPT_X_HIGH 0x02 -/* X Interrupt on Low */ -#define LIS3L02DQ_REG_WAKE_UP_CFG_INTERRUPT_X_LOW 0x01 - -/* Register that gives description of what caused interrupt - * - latched if set in CFG_ADDRES - */ -#define LIS3L02DQ_REG_WAKE_UP_SRC_ADDR 0x24 -/* top bit ignored */ -/* Interrupt Active */ -#define LIS3L02DQ_REG_WAKE_UP_SRC_INTERRUPT_ACTIVATED 0x40 -/* Interupts that have been triggered */ -#define LIS3L02DQ_REG_WAKE_UP_SRC_INTERRUPT_Z_HIGH 0x20 -#define LIS3L02DQ_REG_WAKE_UP_SRC_INTERRUPT_Z_LOW 0x10 -#define LIS3L02DQ_REG_WAKE_UP_SRC_INTERRUPT_Y_HIGH 0x08 -#define LIS3L02DQ_REG_WAKE_UP_SRC_INTERRUPT_Y_LOW 0x04 -#define LIS3L02DQ_REG_WAKE_UP_SRC_INTERRUPT_X_HIGH 0x02 -#define LIS3L02DQ_REG_WAKE_UP_SRC_INTERRUPT_X_LOW 0x01 - -#define LIS3L02DQ_REG_WAKE_UP_ACK_ADDR 0x25 - -/* Status register */ -#define LIS3L02DQ_REG_STATUS_ADDR 0x27 -/* XYZ axis data overrun - first is all overrun? */ -#define LIS3L02DQ_REG_STATUS_XYZ_OVERRUN 0x80 -#define LIS3L02DQ_REG_STATUS_Z_OVERRUN 0x40 -#define LIS3L02DQ_REG_STATUS_Y_OVERRUN 0x20 -#define LIS3L02DQ_REG_STATUS_X_OVERRUN 0x10 -/* XYZ new data available - first is all 3 available? */ -#define LIS3L02DQ_REG_STATUS_XYZ_NEW_DATA 0x08 -#define LIS3L02DQ_REG_STATUS_Z_NEW_DATA 0x04 -#define LIS3L02DQ_REG_STATUS_Y_NEW_DATA 0x02 -#define LIS3L02DQ_REG_STATUS_X_NEW_DATA 0x01 - -/* The accelerometer readings - low and high bytes. - * Form of high byte dependent on justification set in ctrl reg - */ -#define LIS3L02DQ_REG_OUT_X_L_ADDR 0x28 -#define LIS3L02DQ_REG_OUT_X_H_ADDR 0x29 -#define LIS3L02DQ_REG_OUT_Y_L_ADDR 0x2A -#define LIS3L02DQ_REG_OUT_Y_H_ADDR 0x2B -#define LIS3L02DQ_REG_OUT_Z_L_ADDR 0x2C -#define LIS3L02DQ_REG_OUT_Z_H_ADDR 0x2D - -/* Threshold values for all axes and both above and below thresholds - * - i.e. there is only one value - */ -#define LIS3L02DQ_REG_THS_L_ADDR 0x2E -#define LIS3L02DQ_REG_THS_H_ADDR 0x2F - -#define LIS3L02DQ_DEFAULT_CTRL1 (LIS3L02DQ_REG_CTRL_1_PD_ON \ - | LIS3L02DQ_REG_CTRL_1_AXES_Z_ENABLE \ - | LIS3L02DQ_REG_CTRL_1_AXES_Y_ENABLE \ - | LIS3L02DQ_REG_CTRL_1_AXES_X_ENABLE \ - | LIS3L02DQ_REG_CTRL_1_DF_128) - -#define LIS3L02DQ_DEFAULT_CTRL2 0 - -#define LIS3L02DQ_MAX_TX 12 -#define LIS3L02DQ_MAX_RX 12 -/** - * struct lis3l02dq_state - device instance specific data - * @us: actual spi_device - * @trig: data ready trigger registered with iio - * @buf_lock: mutex to protect tx and rx - * @tx: transmit buffer - * @rx: receive buffer - **/ -struct lis3l02dq_state { - struct spi_device *us; - struct iio_trigger *trig; - struct mutex buf_lock; - int gpio; - bool trigger_on; - - u8 tx[LIS3L02DQ_MAX_RX] ____cacheline_aligned; - u8 rx[LIS3L02DQ_MAX_RX] ____cacheline_aligned; -}; - -int lis3l02dq_spi_read_reg_8(struct iio_dev *indio_dev, - u8 reg_address, - u8 *val); - -int lis3l02dq_spi_write_reg_8(struct iio_dev *indio_dev, - u8 reg_address, - u8 val); - -int lis3l02dq_disable_all_events(struct iio_dev *indio_dev); - -#ifdef CONFIG_IIO_BUFFER -/* At the moment triggers are only used for buffer - * filling. This may change! - */ -void lis3l02dq_remove_trigger(struct iio_dev *indio_dev); -int lis3l02dq_probe_trigger(struct iio_dev *indio_dev); - -int lis3l02dq_configure_buffer(struct iio_dev *indio_dev); -void lis3l02dq_unconfigure_buffer(struct iio_dev *indio_dev); - -irqreturn_t lis3l02dq_data_rdy_trig_poll(int irq, void *private); -#define lis3l02dq_th lis3l02dq_data_rdy_trig_poll - -#else /* CONFIG_IIO_BUFFER */ -#define lis3l02dq_th lis3l02dq_nobuffer - -static inline void lis3l02dq_remove_trigger(struct iio_dev *indio_dev) -{ -} - -static inline int lis3l02dq_probe_trigger(struct iio_dev *indio_dev) -{ - return 0; -} - -static int lis3l02dq_configure_buffer(struct iio_dev *indio_dev) -{ - return 0; -} - -static inline void lis3l02dq_unconfigure_buffer(struct iio_dev *indio_dev) -{ -} -#endif /* CONFIG_IIO_BUFFER */ -#endif /* SPI_LIS3L02DQ_H_ */ diff --git a/drivers/staging/iio/accel/lis3l02dq_core.c b/drivers/staging/iio/accel/lis3l02dq_core.c deleted file mode 100644 index 5c3410a..0000000 --- a/drivers/staging/iio/accel/lis3l02dq_core.c +++ /dev/null @@ -1,814 +0,0 @@ -/* - * lis3l02dq.c support STMicroelectronics LISD02DQ - * 3d 2g Linear Accelerometers via SPI - * - * Copyright (c) 2007 Jonathan Cameron - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Settings: - * 16 bit left justified mode used. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include "lis3l02dq.h" - -/* At the moment the spi framework doesn't allow global setting of cs_change. - * It's in the likely to be added comment at the top of spi.h. - * This means that use cannot be made of spi_write etc. - */ -/* direct copy of the irq_default_primary_handler */ -#ifndef CONFIG_IIO_BUFFER -static irqreturn_t lis3l02dq_nobuffer(int irq, void *private) -{ - return IRQ_WAKE_THREAD; -} -#endif - -/** - * lis3l02dq_spi_read_reg_8() - read single byte from a single register - * @indio_dev: iio_dev for this actual device - * @reg_address: the address of the register to be read - * @val: pass back the resulting value - **/ -int lis3l02dq_spi_read_reg_8(struct iio_dev *indio_dev, - u8 reg_address, u8 *val) -{ - struct lis3l02dq_state *st = iio_priv(indio_dev); - int ret; - struct spi_transfer xfer = { - .tx_buf = st->tx, - .rx_buf = st->rx, - .bits_per_word = 8, - .len = 2, - }; - - mutex_lock(&st->buf_lock); - st->tx[0] = LIS3L02DQ_READ_REG(reg_address); - st->tx[1] = 0; - - ret = spi_sync_transfer(st->us, &xfer, 1); - *val = st->rx[1]; - mutex_unlock(&st->buf_lock); - - return ret; -} - -/** - * lis3l02dq_spi_write_reg_8() - write single byte to a register - * @indio_dev: iio_dev for this device - * @reg_address: the address of the register to be written - * @val: the value to write - **/ -int lis3l02dq_spi_write_reg_8(struct iio_dev *indio_dev, - u8 reg_address, - u8 val) -{ - int ret; - struct lis3l02dq_state *st = iio_priv(indio_dev); - - mutex_lock(&st->buf_lock); - st->tx[0] = LIS3L02DQ_WRITE_REG(reg_address); - st->tx[1] = val; - ret = spi_write(st->us, st->tx, 2); - mutex_unlock(&st->buf_lock); - - return ret; -} - -/** - * lisl302dq_spi_write_reg_s16() - write 2 bytes to a pair of registers - * @indio_dev: iio_dev for this device - * @lower_reg_address: the address of the lower of the two registers. - * Second register is assumed to have address one greater. - * @value: value to be written - **/ -static int lis3l02dq_spi_write_reg_s16(struct iio_dev *indio_dev, - u8 lower_reg_address, - s16 value) -{ - int ret; - struct lis3l02dq_state *st = iio_priv(indio_dev); - struct spi_transfer xfers[] = { { - .tx_buf = st->tx, - .bits_per_word = 8, - .len = 2, - .cs_change = 1, - }, { - .tx_buf = st->tx + 2, - .bits_per_word = 8, - .len = 2, - }, - }; - - mutex_lock(&st->buf_lock); - st->tx[0] = LIS3L02DQ_WRITE_REG(lower_reg_address); - st->tx[1] = value & 0xFF; - st->tx[2] = LIS3L02DQ_WRITE_REG(lower_reg_address + 1); - st->tx[3] = (value >> 8) & 0xFF; - - ret = spi_sync_transfer(st->us, xfers, ARRAY_SIZE(xfers)); - mutex_unlock(&st->buf_lock); - - return ret; -} - -static int lis3l02dq_read_reg_s16(struct iio_dev *indio_dev, - u8 lower_reg_address, - int *val) -{ - struct lis3l02dq_state *st = iio_priv(indio_dev); - int ret; - s16 tempval; - struct spi_transfer xfers[] = { { - .tx_buf = st->tx, - .rx_buf = st->rx, - .bits_per_word = 8, - .len = 2, - .cs_change = 1, - }, { - .tx_buf = st->tx + 2, - .rx_buf = st->rx + 2, - .bits_per_word = 8, - .len = 2, - }, - }; - - mutex_lock(&st->buf_lock); - st->tx[0] = LIS3L02DQ_READ_REG(lower_reg_address); - st->tx[1] = 0; - st->tx[2] = LIS3L02DQ_READ_REG(lower_reg_address + 1); - st->tx[3] = 0; - - ret = spi_sync_transfer(st->us, xfers, ARRAY_SIZE(xfers)); - if (ret) { - dev_err(&st->us->dev, "problem when reading 16 bit register"); - goto error_ret; - } - tempval = (s16)(st->rx[1]) | ((s16)(st->rx[3]) << 8); - - *val = tempval; -error_ret: - mutex_unlock(&st->buf_lock); - return ret; -} - -enum lis3l02dq_rm_ind { - LIS3L02DQ_ACCEL, - LIS3L02DQ_GAIN, - LIS3L02DQ_BIAS, -}; - -static u8 lis3l02dq_axis_map[3][3] = { - [LIS3L02DQ_ACCEL] = { LIS3L02DQ_REG_OUT_X_L_ADDR, - LIS3L02DQ_REG_OUT_Y_L_ADDR, - LIS3L02DQ_REG_OUT_Z_L_ADDR }, - [LIS3L02DQ_GAIN] = { LIS3L02DQ_REG_GAIN_X_ADDR, - LIS3L02DQ_REG_GAIN_Y_ADDR, - LIS3L02DQ_REG_GAIN_Z_ADDR }, - [LIS3L02DQ_BIAS] = { LIS3L02DQ_REG_OFFSET_X_ADDR, - LIS3L02DQ_REG_OFFSET_Y_ADDR, - LIS3L02DQ_REG_OFFSET_Z_ADDR } -}; - -static int lis3l02dq_read_thresh(struct iio_dev *indio_dev, - const struct iio_chan_spec *chan, - enum iio_event_type type, - enum iio_event_direction dir, - enum iio_event_info info, - int *val, int *val2) -{ - int ret; - - ret = lis3l02dq_read_reg_s16(indio_dev, LIS3L02DQ_REG_THS_L_ADDR, val); - if (ret) - return ret; - return IIO_VAL_INT; -} - -static int lis3l02dq_write_thresh(struct iio_dev *indio_dev, - const struct iio_chan_spec *chan, - enum iio_event_type type, - enum iio_event_direction dir, - enum iio_event_info info, - int val, int val2) -{ - u16 value = val; - - return lis3l02dq_spi_write_reg_s16(indio_dev, - LIS3L02DQ_REG_THS_L_ADDR, - value); -} - -static int lis3l02dq_write_raw(struct iio_dev *indio_dev, - struct iio_chan_spec const *chan, - int val, - int val2, - long mask) -{ - int ret = -EINVAL, reg; - u8 uval; - s8 sval; - - switch (mask) { - case IIO_CHAN_INFO_CALIBBIAS: - if (val > 255 || val < -256) - return -EINVAL; - sval = val; - reg = lis3l02dq_axis_map[LIS3L02DQ_BIAS][chan->address]; - ret = lis3l02dq_spi_write_reg_8(indio_dev, reg, sval); - break; - case IIO_CHAN_INFO_CALIBSCALE: - if (val & ~0xFF) - return -EINVAL; - uval = val; - reg = lis3l02dq_axis_map[LIS3L02DQ_GAIN][chan->address]; - ret = lis3l02dq_spi_write_reg_8(indio_dev, reg, uval); - break; - } - return ret; -} - -static int lis3l02dq_read_raw(struct iio_dev *indio_dev, - struct iio_chan_spec const *chan, - int *val, - int *val2, - long mask) -{ - u8 utemp; - s8 stemp; - ssize_t ret = 0; - u8 reg; - - switch (mask) { - case IIO_CHAN_INFO_RAW: - /* Take the iio_dev status lock */ - mutex_lock(&indio_dev->mlock); - if (indio_dev->currentmode == INDIO_BUFFER_TRIGGERED) { - ret = -EBUSY; - } else { - reg = lis3l02dq_axis_map - [LIS3L02DQ_ACCEL][chan->address]; - ret = lis3l02dq_read_reg_s16(indio_dev, reg, val); - } - mutex_unlock(&indio_dev->mlock); - if (ret < 0) - goto error_ret; - return IIO_VAL_INT; - case IIO_CHAN_INFO_SCALE: - *val = 0; - *val2 = 9580; - return IIO_VAL_INT_PLUS_MICRO; - case IIO_CHAN_INFO_CALIBSCALE: - reg = lis3l02dq_axis_map[LIS3L02DQ_GAIN][chan->address]; - ret = lis3l02dq_spi_read_reg_8(indio_dev, reg, &utemp); - if (ret) - goto error_ret; - /* to match with what previous code does */ - *val = utemp; - return IIO_VAL_INT; - - case IIO_CHAN_INFO_CALIBBIAS: - reg = lis3l02dq_axis_map[LIS3L02DQ_BIAS][chan->address]; - ret = lis3l02dq_spi_read_reg_8(indio_dev, reg, (u8 *)&stemp); - /* to match with what previous code does */ - *val = stemp; - return IIO_VAL_INT; - } -error_ret: - return ret; -} - -static ssize_t lis3l02dq_read_frequency(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct iio_dev *indio_dev = dev_to_iio_dev(dev); - int ret, len = 0; - s8 t; - - ret = lis3l02dq_spi_read_reg_8(indio_dev, - LIS3L02DQ_REG_CTRL_1_ADDR, - (u8 *)&t); - if (ret) - return ret; - t &= LIS3L02DQ_DEC_MASK; - switch (t) { - case LIS3L02DQ_REG_CTRL_1_DF_128: - len = sprintf(buf, "280\n"); - break; - case LIS3L02DQ_REG_CTRL_1_DF_64: - len = sprintf(buf, "560\n"); - break; - case LIS3L02DQ_REG_CTRL_1_DF_32: - len = sprintf(buf, "1120\n"); - break; - case LIS3L02DQ_REG_CTRL_1_DF_8: - len = sprintf(buf, "4480\n"); - break; - } - return len; -} - -static ssize_t lis3l02dq_write_frequency(struct device *dev, - struct device_attribute *attr, - const char *buf, - size_t len) -{ - struct iio_dev *indio_dev = dev_to_iio_dev(dev); - unsigned long val; - int ret; - u8 t; - - ret = kstrtoul(buf, 10, &val); - if (ret) - return ret; - - mutex_lock(&indio_dev->mlock); - ret = lis3l02dq_spi_read_reg_8(indio_dev, - LIS3L02DQ_REG_CTRL_1_ADDR, - &t); - if (ret) - goto error_ret_mutex; - /* Wipe the bits clean */ - t &= ~LIS3L02DQ_DEC_MASK; - switch (val) { - case 280: - t |= LIS3L02DQ_REG_CTRL_1_DF_128; - break; - case 560: - t |= LIS3L02DQ_REG_CTRL_1_DF_64; - break; - case 1120: - t |= LIS3L02DQ_REG_CTRL_1_DF_32; - break; - case 4480: - t |= LIS3L02DQ_REG_CTRL_1_DF_8; - break; - default: - ret = -EINVAL; - goto error_ret_mutex; - } - - ret = lis3l02dq_spi_write_reg_8(indio_dev, - LIS3L02DQ_REG_CTRL_1_ADDR, - t); - -error_ret_mutex: - mutex_unlock(&indio_dev->mlock); - - return ret ? ret : len; -} - -static int lis3l02dq_initial_setup(struct iio_dev *indio_dev) -{ - struct lis3l02dq_state *st = iio_priv(indio_dev); - int ret; - u8 val, valtest; - - st->us->mode = SPI_MODE_3; - - spi_setup(st->us); - - val = LIS3L02DQ_DEFAULT_CTRL1; - /* Write suitable defaults to ctrl1 */ - ret = lis3l02dq_spi_write_reg_8(indio_dev, - LIS3L02DQ_REG_CTRL_1_ADDR, - val); - if (ret) { - dev_err(&st->us->dev, "problem with setup control register 1"); - goto err_ret; - } - /* Repeat as sometimes doesn't work first time? */ - ret = lis3l02dq_spi_write_reg_8(indio_dev, - LIS3L02DQ_REG_CTRL_1_ADDR, - val); - if (ret) { - dev_err(&st->us->dev, "problem with setup control register 1"); - goto err_ret; - } - - /* - * Read back to check this has worked acts as loose test of correct - * chip - */ - ret = lis3l02dq_spi_read_reg_8(indio_dev, - LIS3L02DQ_REG_CTRL_1_ADDR, - &valtest); - if (ret || (valtest != val)) { - dev_err(&indio_dev->dev, - "device not playing ball %d %d\n", valtest, val); - ret = -EINVAL; - goto err_ret; - } - - val = LIS3L02DQ_DEFAULT_CTRL2; - ret = lis3l02dq_spi_write_reg_8(indio_dev, - LIS3L02DQ_REG_CTRL_2_ADDR, - val); - if (ret) { - dev_err(&st->us->dev, "problem with setup control register 2"); - goto err_ret; - } - - val = LIS3L02DQ_REG_WAKE_UP_CFG_LATCH_SRC; - ret = lis3l02dq_spi_write_reg_8(indio_dev, - LIS3L02DQ_REG_WAKE_UP_CFG_ADDR, - val); - if (ret) - dev_err(&st->us->dev, "problem with interrupt cfg register"); -err_ret: - - return ret; -} - -static IIO_DEV_ATTR_SAMP_FREQ(S_IWUSR | S_IRUGO, - lis3l02dq_read_frequency, - lis3l02dq_write_frequency); - -static IIO_CONST_ATTR_SAMP_FREQ_AVAIL("280 560 1120 4480"); - -static irqreturn_t lis3l02dq_event_handler(int irq, void *private) -{ - struct iio_dev *indio_dev = private; - u8 t; - - s64 timestamp = iio_get_time_ns(indio_dev); - - lis3l02dq_spi_read_reg_8(indio_dev, - LIS3L02DQ_REG_WAKE_UP_SRC_ADDR, - &t); - - if (t & LIS3L02DQ_REG_WAKE_UP_SRC_INTERRUPT_Z_HIGH) - iio_push_event(indio_dev, - IIO_MOD_EVENT_CODE(IIO_ACCEL, - 0, - IIO_MOD_Z, - IIO_EV_TYPE_THRESH, - IIO_EV_DIR_RISING), - timestamp); - - if (t & LIS3L02DQ_REG_WAKE_UP_SRC_INTERRUPT_Z_LOW) - iio_push_event(indio_dev, - IIO_MOD_EVENT_CODE(IIO_ACCEL, - 0, - IIO_MOD_Z, - IIO_EV_TYPE_THRESH, - IIO_EV_DIR_FALLING), - timestamp); - - if (t & LIS3L02DQ_REG_WAKE_UP_SRC_INTERRUPT_Y_HIGH) - iio_push_event(indio_dev, - IIO_MOD_EVENT_CODE(IIO_ACCEL, - 0, - IIO_MOD_Y, - IIO_EV_TYPE_THRESH, - IIO_EV_DIR_RISING), - timestamp); - - if (t & LIS3L02DQ_REG_WAKE_UP_SRC_INTERRUPT_Y_LOW) - iio_push_event(indio_dev, - IIO_MOD_EVENT_CODE(IIO_ACCEL, - 0, - IIO_MOD_Y, - IIO_EV_TYPE_THRESH, - IIO_EV_DIR_FALLING), - timestamp); - - if (t & LIS3L02DQ_REG_WAKE_UP_SRC_INTERRUPT_X_HIGH) - iio_push_event(indio_dev, - IIO_MOD_EVENT_CODE(IIO_ACCEL, - 0, - IIO_MOD_X, - IIO_EV_TYPE_THRESH, - IIO_EV_DIR_RISING), - timestamp); - - if (t & LIS3L02DQ_REG_WAKE_UP_SRC_INTERRUPT_X_LOW) - iio_push_event(indio_dev, - IIO_MOD_EVENT_CODE(IIO_ACCEL, - 0, - IIO_MOD_X, - IIO_EV_TYPE_THRESH, - IIO_EV_DIR_FALLING), - timestamp); - - /* Ack and allow for new interrupts */ - lis3l02dq_spi_read_reg_8(indio_dev, - LIS3L02DQ_REG_WAKE_UP_ACK_ADDR, - &t); - - return IRQ_HANDLED; -} - -static const struct iio_event_spec lis3l02dq_event[] = { - { - .type = IIO_EV_TYPE_THRESH, - .dir = IIO_EV_DIR_RISING, - .mask_separate = BIT(IIO_EV_INFO_ENABLE), - .mask_shared_by_type = BIT(IIO_EV_INFO_VALUE), - }, { - .type = IIO_EV_TYPE_THRESH, - .dir = IIO_EV_DIR_FALLING, - .mask_separate = BIT(IIO_EV_INFO_ENABLE), - .mask_shared_by_type = BIT(IIO_EV_INFO_VALUE), - } -}; - -#define LIS3L02DQ_CHAN(index, mod) \ - { \ - .type = IIO_ACCEL, \ - .modified = 1, \ - .channel2 = mod, \ - .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ - BIT(IIO_CHAN_INFO_CALIBSCALE) | \ - BIT(IIO_CHAN_INFO_CALIBBIAS), \ - .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ - .address = index, \ - .scan_index = index, \ - .scan_type = { \ - .sign = 's', \ - .realbits = 12, \ - .storagebits = 16, \ - }, \ - .event_spec = lis3l02dq_event, \ - .num_event_specs = ARRAY_SIZE(lis3l02dq_event), \ - } - -static const struct iio_chan_spec lis3l02dq_channels[] = { - LIS3L02DQ_CHAN(0, IIO_MOD_X), - LIS3L02DQ_CHAN(1, IIO_MOD_Y), - LIS3L02DQ_CHAN(2, IIO_MOD_Z), - IIO_CHAN_SOFT_TIMESTAMP(3) -}; - -static int lis3l02dq_read_event_config(struct iio_dev *indio_dev, - const struct iio_chan_spec *chan, - enum iio_event_type type, - enum iio_event_direction dir) -{ - u8 val; - int ret; - u8 mask = 1 << (chan->channel2 * 2 + (dir == IIO_EV_DIR_RISING)); - - ret = lis3l02dq_spi_read_reg_8(indio_dev, - LIS3L02DQ_REG_WAKE_UP_CFG_ADDR, - &val); - if (ret < 0) - return ret; - - return !!(val & mask); -} - -int lis3l02dq_disable_all_events(struct iio_dev *indio_dev) -{ - int ret; - u8 control, val; - - ret = lis3l02dq_spi_read_reg_8(indio_dev, - LIS3L02DQ_REG_CTRL_2_ADDR, - &control); - - control &= ~LIS3L02DQ_REG_CTRL_2_ENABLE_INTERRUPT; - ret = lis3l02dq_spi_write_reg_8(indio_dev, - LIS3L02DQ_REG_CTRL_2_ADDR, - control); - if (ret) - goto error_ret; - /* Also for consistency clear the mask */ - ret = lis3l02dq_spi_read_reg_8(indio_dev, - LIS3L02DQ_REG_WAKE_UP_CFG_ADDR, - &val); - if (ret) - goto error_ret; - val &= ~0x3f; - - ret = lis3l02dq_spi_write_reg_8(indio_dev, - LIS3L02DQ_REG_WAKE_UP_CFG_ADDR, - val); - if (ret) - goto error_ret; - - ret = control; -error_ret: - return ret; -} - -static int lis3l02dq_write_event_config(struct iio_dev *indio_dev, - const struct iio_chan_spec *chan, - enum iio_event_type type, - enum iio_event_direction dir, - int state) -{ - int ret = 0; - u8 val, control; - u8 currentlyset; - bool changed = false; - u8 mask = 1 << (chan->channel2 * 2 + (dir == IIO_EV_DIR_RISING)); - - mutex_lock(&indio_dev->mlock); - /* read current control */ - ret = lis3l02dq_spi_read_reg_8(indio_dev, - LIS3L02DQ_REG_CTRL_2_ADDR, - &control); - if (ret) - goto error_ret; - ret = lis3l02dq_spi_read_reg_8(indio_dev, - LIS3L02DQ_REG_WAKE_UP_CFG_ADDR, - &val); - if (ret < 0) - goto error_ret; - currentlyset = val & mask; - - if (!currentlyset && state) { - changed = true; - val |= mask; - } else if (currentlyset && !state) { - changed = true; - val &= ~mask; - } - - if (changed) { - ret = lis3l02dq_spi_write_reg_8(indio_dev, - LIS3L02DQ_REG_WAKE_UP_CFG_ADDR, - val); - if (ret) - goto error_ret; - control = val & 0x3f ? - (control | LIS3L02DQ_REG_CTRL_2_ENABLE_INTERRUPT) : - (control & ~LIS3L02DQ_REG_CTRL_2_ENABLE_INTERRUPT); - ret = lis3l02dq_spi_write_reg_8(indio_dev, - LIS3L02DQ_REG_CTRL_2_ADDR, - control); - if (ret) - goto error_ret; - } - -error_ret: - mutex_unlock(&indio_dev->mlock); - return ret; -} - -static struct attribute *lis3l02dq_attributes[] = { - &iio_dev_attr_sampling_frequency.dev_attr.attr, - &iio_const_attr_sampling_frequency_available.dev_attr.attr, - NULL -}; - -static const struct attribute_group lis3l02dq_attribute_group = { - .attrs = lis3l02dq_attributes, -}; - -static const struct iio_info lis3l02dq_info = { - .read_raw = &lis3l02dq_read_raw, - .write_raw = &lis3l02dq_write_raw, - .read_event_value = &lis3l02dq_read_thresh, - .write_event_value = &lis3l02dq_write_thresh, - .write_event_config = &lis3l02dq_write_event_config, - .read_event_config = &lis3l02dq_read_event_config, - .driver_module = THIS_MODULE, - .attrs = &lis3l02dq_attribute_group, -}; - -static int lis3l02dq_probe(struct spi_device *spi) -{ - int ret; - struct lis3l02dq_state *st; - struct iio_dev *indio_dev; - - indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); - if (!indio_dev) - return -ENOMEM; - st = iio_priv(indio_dev); - /* this is only used for removal purposes */ - spi_set_drvdata(spi, indio_dev); - - st->us = spi; - st->gpio = of_get_gpio(spi->dev.of_node, 0); - mutex_init(&st->buf_lock); - indio_dev->name = spi->dev.driver->name; - indio_dev->dev.parent = &spi->dev; - indio_dev->info = &lis3l02dq_info; - indio_dev->channels = lis3l02dq_channels; - indio_dev->num_channels = ARRAY_SIZE(lis3l02dq_channels); - - indio_dev->modes = INDIO_DIRECT_MODE; - - ret = lis3l02dq_configure_buffer(indio_dev); - if (ret) - return ret; - - if (spi->irq) { - ret = request_threaded_irq(st->us->irq, - &lis3l02dq_th, - &lis3l02dq_event_handler, - IRQF_TRIGGER_RISING, - "lis3l02dq", - indio_dev); - if (ret) - goto error_unreg_buffer_funcs; - - ret = lis3l02dq_probe_trigger(indio_dev); - if (ret) - goto error_free_interrupt; - } - - /* Get the device into a sane initial state */ - ret = lis3l02dq_initial_setup(indio_dev); - if (ret) - goto error_remove_trigger; - - ret = iio_device_register(indio_dev); - if (ret) - goto error_remove_trigger; - - return 0; - -error_remove_trigger: - if (spi->irq) - lis3l02dq_remove_trigger(indio_dev); -error_free_interrupt: - if (spi->irq) - free_irq(st->us->irq, indio_dev); -error_unreg_buffer_funcs: - lis3l02dq_unconfigure_buffer(indio_dev); - return ret; -} - -/* Power down the device */ -static int lis3l02dq_stop_device(struct iio_dev *indio_dev) -{ - int ret; - struct lis3l02dq_state *st = iio_priv(indio_dev); - u8 val = 0; - - mutex_lock(&indio_dev->mlock); - ret = lis3l02dq_spi_write_reg_8(indio_dev, - LIS3L02DQ_REG_CTRL_1_ADDR, - val); - if (ret) { - dev_err(&st->us->dev, "problem with turning device off: ctrl1"); - goto err_ret; - } - - ret = lis3l02dq_spi_write_reg_8(indio_dev, - LIS3L02DQ_REG_CTRL_2_ADDR, - val); - if (ret) - dev_err(&st->us->dev, "problem with turning device off: ctrl2"); -err_ret: - mutex_unlock(&indio_dev->mlock); - return ret; -} - -/* fixme, confirm ordering in this function */ -static int lis3l02dq_remove(struct spi_device *spi) -{ - struct iio_dev *indio_dev = spi_get_drvdata(spi); - struct lis3l02dq_state *st = iio_priv(indio_dev); - - iio_device_unregister(indio_dev); - - lis3l02dq_disable_all_events(indio_dev); - lis3l02dq_stop_device(indio_dev); - - if (spi->irq) - free_irq(st->us->irq, indio_dev); - - lis3l02dq_remove_trigger(indio_dev); - lis3l02dq_unconfigure_buffer(indio_dev); - - return 0; -} - -static struct spi_driver lis3l02dq_driver = { - .driver = { - .name = "lis3l02dq", - }, - .probe = lis3l02dq_probe, - .remove = lis3l02dq_remove, -}; -module_spi_driver(lis3l02dq_driver); - -MODULE_AUTHOR("Jonathan Cameron "); -MODULE_DESCRIPTION("ST LIS3L02DQ Accelerometer SPI driver"); -MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("spi:lis3l02dq"); diff --git a/drivers/staging/iio/accel/lis3l02dq_ring.c b/drivers/staging/iio/accel/lis3l02dq_ring.c deleted file mode 100644 index 50c162e..0000000 --- a/drivers/staging/iio/accel/lis3l02dq_ring.c +++ /dev/null @@ -1,428 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include "lis3l02dq.h" - -/** - * combine_8_to_16() utility function to munge two u8s into u16 - **/ -static inline u16 combine_8_to_16(u8 lower, u8 upper) -{ - u16 _lower = lower; - u16 _upper = upper; - - return _lower | (_upper << 8); -} - -/** - * lis3l02dq_data_rdy_trig_poll() the event handler for the data rdy trig - **/ -irqreturn_t lis3l02dq_data_rdy_trig_poll(int irq, void *private) -{ - struct iio_dev *indio_dev = private; - struct lis3l02dq_state *st = iio_priv(indio_dev); - - if (st->trigger_on) { - iio_trigger_poll(st->trig); - return IRQ_HANDLED; - } - - return IRQ_WAKE_THREAD; -} - -static const u8 read_all_tx_array[] = { - LIS3L02DQ_READ_REG(LIS3L02DQ_REG_OUT_X_L_ADDR), 0, - LIS3L02DQ_READ_REG(LIS3L02DQ_REG_OUT_X_H_ADDR), 0, - LIS3L02DQ_READ_REG(LIS3L02DQ_REG_OUT_Y_L_ADDR), 0, - LIS3L02DQ_READ_REG(LIS3L02DQ_REG_OUT_Y_H_ADDR), 0, - LIS3L02DQ_READ_REG(LIS3L02DQ_REG_OUT_Z_L_ADDR), 0, - LIS3L02DQ_READ_REG(LIS3L02DQ_REG_OUT_Z_H_ADDR), 0, -}; - -/** - * lis3l02dq_read_all() Reads all channels currently selected - * @indio_dev: IIO device state - * @rx_array: (dma capable) receive array, must be at least - * 4*number of channels - **/ -static int lis3l02dq_read_all(struct iio_dev *indio_dev, u8 *rx_array) -{ - struct lis3l02dq_state *st = iio_priv(indio_dev); - struct spi_transfer *xfers; - struct spi_message msg; - int ret, i, j = 0; - - xfers = kcalloc(bitmap_weight(indio_dev->active_scan_mask, - indio_dev->masklength) * 2, - sizeof(*xfers), GFP_KERNEL); - if (!xfers) - return -ENOMEM; - - mutex_lock(&st->buf_lock); - - for (i = 0; i < ARRAY_SIZE(read_all_tx_array) / 4; i++) - if (test_bit(i, indio_dev->active_scan_mask)) { - /* lower byte */ - xfers[j].tx_buf = st->tx + (2 * j); - st->tx[2 * j] = read_all_tx_array[i * 4]; - st->tx[2 * j + 1] = 0; - if (rx_array) - xfers[j].rx_buf = rx_array + (j * 2); - xfers[j].bits_per_word = 8; - xfers[j].len = 2; - xfers[j].cs_change = 1; - j++; - - /* upper byte */ - xfers[j].tx_buf = st->tx + (2 * j); - st->tx[2 * j] = read_all_tx_array[i * 4 + 2]; - st->tx[2 * j + 1] = 0; - if (rx_array) - xfers[j].rx_buf = rx_array + (j * 2); - xfers[j].bits_per_word = 8; - xfers[j].len = 2; - xfers[j].cs_change = 1; - j++; - } - - /* After these are transmitted, the rx_buff should have - * values in alternate bytes - */ - spi_message_init(&msg); - for (j = 0; j < bitmap_weight(indio_dev->active_scan_mask, - indio_dev->masklength) * 2; j++) - spi_message_add_tail(&xfers[j], &msg); - - ret = spi_sync(st->us, &msg); - mutex_unlock(&st->buf_lock); - kfree(xfers); - - return ret; -} - -static int lis3l02dq_get_buffer_element(struct iio_dev *indio_dev, - u8 *buf) -{ - int ret, i; - u8 *rx_array; - s16 *data = (s16 *)buf; - int scan_count = bitmap_weight(indio_dev->active_scan_mask, - indio_dev->masklength); - - rx_array = kcalloc(4, scan_count, GFP_KERNEL); - if (!rx_array) - return -ENOMEM; - ret = lis3l02dq_read_all(indio_dev, rx_array); - if (ret < 0) { - kfree(rx_array); - return ret; - } - for (i = 0; i < scan_count; i++) - data[i] = combine_8_to_16(rx_array[i * 4 + 1], - rx_array[i * 4 + 3]); - kfree(rx_array); - - return i * sizeof(data[0]); -} - -static irqreturn_t lis3l02dq_trigger_handler(int irq, void *p) -{ - struct iio_poll_func *pf = p; - struct iio_dev *indio_dev = pf->indio_dev; - int len = 0; - char *data; - - data = kmalloc(indio_dev->scan_bytes, GFP_KERNEL); - if (!data) - goto done; - - if (!bitmap_empty(indio_dev->active_scan_mask, indio_dev->masklength)) - len = lis3l02dq_get_buffer_element(indio_dev, data); - - iio_push_to_buffers_with_timestamp(indio_dev, data, pf->timestamp); - - kfree(data); -done: - iio_trigger_notify_done(indio_dev->trig); - return IRQ_HANDLED; -} - -/* Caller responsible for locking as necessary. */ -static int -__lis3l02dq_write_data_ready_config(struct iio_dev *indio_dev, bool state) -{ - int ret; - u8 valold; - bool currentlyset; - struct lis3l02dq_state *st = iio_priv(indio_dev); - - /* Get the current event mask register */ - ret = lis3l02dq_spi_read_reg_8(indio_dev, - LIS3L02DQ_REG_CTRL_2_ADDR, - &valold); - if (ret) - goto error_ret; - /* Find out if data ready is already on */ - currentlyset - = valold & LIS3L02DQ_REG_CTRL_2_ENABLE_DATA_READY_GENERATION; - - /* Disable requested */ - if (!state && currentlyset) { - /* Disable the data ready signal */ - valold &= ~LIS3L02DQ_REG_CTRL_2_ENABLE_DATA_READY_GENERATION; - - /* The double write is to overcome a hardware bug? */ - ret = lis3l02dq_spi_write_reg_8(indio_dev, - LIS3L02DQ_REG_CTRL_2_ADDR, - valold); - if (ret) - goto error_ret; - ret = lis3l02dq_spi_write_reg_8(indio_dev, - LIS3L02DQ_REG_CTRL_2_ADDR, - valold); - if (ret) - goto error_ret; - st->trigger_on = false; - /* Enable requested */ - } else if (state && !currentlyset) { - /* If not set, enable requested - * first disable all events - */ - ret = lis3l02dq_disable_all_events(indio_dev); - if (ret < 0) - goto error_ret; - - valold = ret | - LIS3L02DQ_REG_CTRL_2_ENABLE_DATA_READY_GENERATION; - - st->trigger_on = true; - ret = lis3l02dq_spi_write_reg_8(indio_dev, - LIS3L02DQ_REG_CTRL_2_ADDR, - valold); - if (ret) - goto error_ret; - } - - return 0; -error_ret: - return ret; -} - -/** - * lis3l02dq_data_rdy_trigger_set_state() set datardy interrupt state - * - * If disabling the interrupt also does a final read to ensure it is clear. - * This is only important in some cases where the scan enable elements are - * switched before the buffer is reenabled. - **/ -static int lis3l02dq_data_rdy_trigger_set_state(struct iio_trigger *trig, - bool state) -{ - struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig); - int ret = 0; - u8 t; - - __lis3l02dq_write_data_ready_config(indio_dev, state); - if (!state) { - /* - * A possible quirk with the handler is currently worked around - * by ensuring outstanding read events are cleared. - */ - ret = lis3l02dq_read_all(indio_dev, NULL); - } - lis3l02dq_spi_read_reg_8(indio_dev, - LIS3L02DQ_REG_WAKE_UP_SRC_ADDR, - &t); - return ret; -} - -/** - * lis3l02dq_trig_try_reen() try reenabling irq for data rdy trigger - * @trig: the datardy trigger - */ -static int lis3l02dq_trig_try_reen(struct iio_trigger *trig) -{ - struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig); - struct lis3l02dq_state *st = iio_priv(indio_dev); - int i; - - /* If gpio still high (or high again) - * In theory possible we will need to do this several times - */ - for (i = 0; i < 5; i++) - if (gpio_get_value(st->gpio)) - lis3l02dq_read_all(indio_dev, NULL); - else - break; - if (i == 5) - pr_info("Failed to clear the interrupt for lis3l02dq\n"); - - /* irq reenabled so success! */ - return 0; -} - -static const struct iio_trigger_ops lis3l02dq_trigger_ops = { - .owner = THIS_MODULE, - .set_trigger_state = &lis3l02dq_data_rdy_trigger_set_state, - .try_reenable = &lis3l02dq_trig_try_reen, -}; - -int lis3l02dq_probe_trigger(struct iio_dev *indio_dev) -{ - int ret; - struct lis3l02dq_state *st = iio_priv(indio_dev); - - st->trig = iio_trigger_alloc("lis3l02dq-dev%d", indio_dev->id); - if (!st->trig) { - ret = -ENOMEM; - goto error_ret; - } - - st->trig->dev.parent = &st->us->dev; - st->trig->ops = &lis3l02dq_trigger_ops; - iio_trigger_set_drvdata(st->trig, indio_dev); - ret = iio_trigger_register(st->trig); - if (ret) - goto error_free_trig; - - return 0; - -error_free_trig: - iio_trigger_free(st->trig); -error_ret: - return ret; -} - -void lis3l02dq_remove_trigger(struct iio_dev *indio_dev) -{ - struct lis3l02dq_state *st = iio_priv(indio_dev); - - iio_trigger_unregister(st->trig); - iio_trigger_free(st->trig); -} - -void lis3l02dq_unconfigure_buffer(struct iio_dev *indio_dev) -{ - iio_dealloc_pollfunc(indio_dev->pollfunc); - iio_kfifo_free(indio_dev->buffer); -} - -static int lis3l02dq_buffer_postenable(struct iio_dev *indio_dev) -{ - /* Disable unwanted channels otherwise the interrupt will not clear */ - u8 t; - int ret; - bool oneenabled = false; - - ret = lis3l02dq_spi_read_reg_8(indio_dev, - LIS3L02DQ_REG_CTRL_1_ADDR, - &t); - if (ret) - goto error_ret; - - if (test_bit(0, indio_dev->active_scan_mask)) { - t |= LIS3L02DQ_REG_CTRL_1_AXES_X_ENABLE; - oneenabled = true; - } else { - t &= ~LIS3L02DQ_REG_CTRL_1_AXES_X_ENABLE; - } - if (test_bit(1, indio_dev->active_scan_mask)) { - t |= LIS3L02DQ_REG_CTRL_1_AXES_Y_ENABLE; - oneenabled = true; - } else { - t &= ~LIS3L02DQ_REG_CTRL_1_AXES_Y_ENABLE; - } - if (test_bit(2, indio_dev->active_scan_mask)) { - t |= LIS3L02DQ_REG_CTRL_1_AXES_Z_ENABLE; - oneenabled = true; - } else { - t &= ~LIS3L02DQ_REG_CTRL_1_AXES_Z_ENABLE; - } - if (!oneenabled) /* what happens in this case is unknown */ - return -EINVAL; - ret = lis3l02dq_spi_write_reg_8(indio_dev, - LIS3L02DQ_REG_CTRL_1_ADDR, - t); - if (ret) - goto error_ret; - - return iio_triggered_buffer_postenable(indio_dev); -error_ret: - return ret; -} - -/* Turn all channels on again */ -static int lis3l02dq_buffer_predisable(struct iio_dev *indio_dev) -{ - u8 t; - int ret; - - ret = iio_triggered_buffer_predisable(indio_dev); - if (ret) - goto error_ret; - - ret = lis3l02dq_spi_read_reg_8(indio_dev, - LIS3L02DQ_REG_CTRL_1_ADDR, - &t); - if (ret) - goto error_ret; - t |= LIS3L02DQ_REG_CTRL_1_AXES_X_ENABLE | - LIS3L02DQ_REG_CTRL_1_AXES_Y_ENABLE | - LIS3L02DQ_REG_CTRL_1_AXES_Z_ENABLE; - - ret = lis3l02dq_spi_write_reg_8(indio_dev, - LIS3L02DQ_REG_CTRL_1_ADDR, - t); - -error_ret: - return ret; -} - -static const struct iio_buffer_setup_ops lis3l02dq_buffer_setup_ops = { - .postenable = &lis3l02dq_buffer_postenable, - .predisable = &lis3l02dq_buffer_predisable, -}; - -int lis3l02dq_configure_buffer(struct iio_dev *indio_dev) -{ - int ret; - struct iio_buffer *buffer; - - buffer = iio_kfifo_allocate(); - if (!buffer) - return -ENOMEM; - - iio_device_attach_buffer(indio_dev, buffer); - - buffer->scan_timestamp = true; - indio_dev->setup_ops = &lis3l02dq_buffer_setup_ops; - - /* Functions are NULL as we set handler below */ - indio_dev->pollfunc = iio_alloc_pollfunc(&iio_pollfunc_store_time, - &lis3l02dq_trigger_handler, - 0, - indio_dev, - "lis3l02dq_consumer%d", - indio_dev->id); - - if (!indio_dev->pollfunc) { - ret = -ENOMEM; - goto error_iio_sw_rb_free; - } - - indio_dev->modes |= INDIO_BUFFER_TRIGGERED; - return 0; - -error_iio_sw_rb_free: - iio_kfifo_free(indio_dev->buffer); - return ret; -} -- cgit v0.10.2 From e7385de5291e347f5bc85985acdce3a3f5096667 Mon Sep 17 00:00:00 2001 From: Gregor Boirie Date: Mon, 27 Jun 2016 12:38:52 +0200 Subject: iio:st_sensors: align on storagebits boundaries Ensure triggered buffering memory accesses are properly aligned on per channel storagebits boundaries. Signed-off-by: Gregor Boirie Tested-by: Linus Walleij Signed-off-by: Jonathan Cameron diff --git a/drivers/iio/common/st_sensors/st_sensors_buffer.c b/drivers/iio/common/st_sensors/st_sensors_buffer.c index 2371fc8..d06e728 100644 --- a/drivers/iio/common/st_sensors/st_sensors_buffer.c +++ b/drivers/iio/common/st_sensors/st_sensors_buffer.c @@ -24,30 +24,29 @@ static int st_sensors_get_buffer_element(struct iio_dev *indio_dev, u8 *buf) { - int i, len; - int total = 0; + int i; struct st_sensor_data *sdata = iio_priv(indio_dev); unsigned int num_data_channels = sdata->num_data_channels; - for (i = 0; i < num_data_channels; i++) { - unsigned int bytes_to_read; - - if (test_bit(i, indio_dev->active_scan_mask)) { - bytes_to_read = indio_dev->channels[i].scan_type.storagebits >> 3; - len = sdata->tf->read_multiple_byte(&sdata->tb, - sdata->dev, indio_dev->channels[i].address, - bytes_to_read, - buf + total, sdata->multiread_bit); - - if (len < bytes_to_read) - return -EIO; - - /* Advance the buffer pointer */ - total += len; - } + for_each_set_bit(i, indio_dev->active_scan_mask, num_data_channels) { + const struct iio_chan_spec *channel = &indio_dev->channels[i]; + unsigned int bytes_to_read = channel->scan_type.realbits >> 3; + unsigned int storage_bytes = + channel->scan_type.storagebits >> 3; + + buf = PTR_ALIGN(buf, storage_bytes); + if (sdata->tf->read_multiple_byte(&sdata->tb, sdata->dev, + channel->address, + bytes_to_read, buf, + sdata->multiread_bit) < + bytes_to_read) + return -EIO; + + /* Advance the buffer pointer */ + buf += storage_bytes; } - return total; + return 0; } irqreturn_t st_sensors_trigger_handler(int irq, void *p) diff --git a/drivers/iio/common/st_sensors/st_sensors_core.c b/drivers/iio/common/st_sensors/st_sensors_core.c index 26ce325..2d5282e 100644 --- a/drivers/iio/common/st_sensors/st_sensors_core.c +++ b/drivers/iio/common/st_sensors/st_sensors_core.c @@ -490,7 +490,7 @@ static int st_sensors_read_axis_data(struct iio_dev *indio_dev, int err; u8 *outdata; struct st_sensor_data *sdata = iio_priv(indio_dev); - unsigned int byte_for_channel = ch->scan_type.storagebits >> 3; + unsigned int byte_for_channel = ch->scan_type.realbits >> 3; outdata = kmalloc(byte_for_channel, GFP_KERNEL); if (!outdata) -- cgit v0.10.2 From c9d5e5b97e8723e20204b430edde2f3dc5f5c0cf Mon Sep 17 00:00:00 2001 From: Gregor Boirie Date: Mon, 27 Jun 2016 12:38:53 +0200 Subject: iio:st_pressure: align storagebits on power of 2 Sampled pressure data are 24 bits long and should be stored in a 32 bits word. Signed-off-by: Gregor Boirie Tested-by: Linus Walleij Signed-off-by: Jonathan Cameron diff --git a/drivers/iio/pressure/st_pressure_core.c b/drivers/iio/pressure/st_pressure_core.c index 56d8f5e..8fa3d81 100644 --- a/drivers/iio/pressure/st_pressure_core.c +++ b/drivers/iio/pressure/st_pressure_core.c @@ -146,7 +146,7 @@ static const struct iio_chan_spec st_press_1_channels[] = { .scan_type = { .sign = 'u', .realbits = 24, - .storagebits = 24, + .storagebits = 32, .endianness = IIO_LE, }, .info_mask_separate = @@ -218,7 +218,7 @@ static const struct iio_chan_spec st_press_lps22hb_channels[] = { .scan_type = { .sign = 'u', .realbits = 24, - .storagebits = 24, + .storagebits = 32, .endianness = IIO_LE, }, .info_mask_separate = -- cgit v0.10.2 From 19b7b8a89b8d98fdafd80b61160a167deb75888d Mon Sep 17 00:00:00 2001 From: Gregor Boirie Date: Mon, 27 Jun 2016 12:38:54 +0200 Subject: iio:st_pressure: document sampling gains Details scaling factors and offsets applied to raw temperature and pressure samples. Signed-off-by: Gregor Boirie Tested-by: Linus Walleij Signed-off-by: Jonathan Cameron diff --git a/drivers/iio/pressure/st_pressure_core.c b/drivers/iio/pressure/st_pressure_core.c index 8fa3d81..2ab1056 100644 --- a/drivers/iio/pressure/st_pressure_core.c +++ b/drivers/iio/pressure/st_pressure_core.c @@ -28,6 +28,72 @@ #include #include "st_pressure.h" +/* + * About determining pressure scaling factors + * ------------------------------------------ + * + * Datasheets specify typical pressure sensitivity so that pressure is computed + * according to the following equation : + * pressure[mBar] = raw / sensitivity + * where : + * raw the 24 bits long raw sampled pressure + * sensitivity a scaling factor specified by the datasheet in LSB/mBar + * + * IIO ABI expects pressure to be expressed as kPascal, hence pressure should be + * computed according to : + * pressure[kPascal] = pressure[mBar] / 10 + * = raw / (sensitivity * 10) (1) + * + * Finally, st_press_read_raw() returns pressure scaling factor as an + * IIO_VAL_INT_PLUS_NANO with a zero integral part and "gain" as decimal part. + * Therefore, from (1), "gain" becomes : + * gain = 10^9 / (sensitivity * 10) + * = 10^8 / sensitivity + * + * About determining temperature scaling factors and offsets + * --------------------------------------------------------- + * + * Datasheets specify typical temperature sensitivity and offset so that + * temperature is computed according to the following equation : + * temp[Celsius] = offset[Celsius] + (raw / sensitivity) + * where : + * raw the 16 bits long raw sampled temperature + * offset a constant specified by the datasheet in degree Celsius + * (sometimes zero) + * sensitivity a scaling factor specified by the datasheet in LSB/Celsius + * + * IIO ABI expects temperature to be expressed as milli degree Celsius such as + * user space should compute temperature according to : + * temp[mCelsius] = temp[Celsius] * 10^3 + * = (offset[Celsius] + (raw / sensitivity)) * 10^3 + * = ((offset[Celsius] * sensitivity) + raw) * + * (10^3 / sensitivity) (2) + * + * IIO ABI expects user space to apply offset and scaling factors to raw samples + * according to : + * temp[mCelsius] = (OFFSET + raw) * SCALE + * where : + * OFFSET an arbitrary constant exposed by device + * SCALE an arbitrary scaling factor exposed by device + * + * Matching OFFSET and SCALE with members of (2) gives : + * OFFSET = offset[Celsius] * sensitivity (3) + * SCALE = 10^3 / sensitivity (4) + * + * st_press_read_raw() returns temperature scaling factor as an + * IIO_VAL_FRACTIONAL with a 10^3 numerator and "gain2" as denominator. + * Therefore, from (3), "gain2" becomes : + * gain2 = sensitivity + * + * When declared within channel, i.e. for a non zero specified offset, + * st_press_read_raw() will return the latter as an IIO_VAL_FRACTIONAL such as : + * numerator = OFFSET * 10^3 + * denominator = 10^3 + * giving from (4): + * numerator = offset[Celsius] * 10^3 * sensitivity + * = offset[mCelsius] * gain2 + */ + #define MCELSIUS_PER_CELSIUS 1000 /* Default pressure sensitivity */ @@ -48,7 +114,11 @@ #define ST_PRESS_1_OUT_XL_ADDR 0x28 #define ST_TEMP_1_OUT_L_ADDR 0x2b -/* CUSTOM VALUES FOR LPS331AP SENSOR */ +/* + * CUSTOM VALUES FOR LPS331AP SENSOR + * See LPS331AP datasheet: + * http://www2.st.com/resource/en/datasheet/lps331ap.pdf + */ #define ST_PRESS_LPS331AP_WAI_EXP 0xbb #define ST_PRESS_LPS331AP_ODR_ADDR 0x20 #define ST_PRESS_LPS331AP_ODR_MASK 0x70 @@ -71,7 +141,9 @@ #define ST_PRESS_LPS331AP_OD_IRQ_MASK 0x40 #define ST_PRESS_LPS331AP_MULTIREAD_BIT true -/* CUSTOM VALUES FOR LPS001WP SENSOR */ +/* + * CUSTOM VALUES FOR THE OBSOLETE LPS001WP SENSOR + */ /* LPS001WP pressure resolution */ #define ST_PRESS_LPS001WP_LSB_PER_MBAR 16UL @@ -94,7 +166,11 @@ #define ST_PRESS_LPS001WP_OUT_L_ADDR 0x28 #define ST_TEMP_LPS001WP_OUT_L_ADDR 0x2a -/* CUSTOM VALUES FOR LPS25H SENSOR */ +/* + * CUSTOM VALUES FOR LPS25H SENSOR + * See LPS25H datasheet: + * http://www2.st.com/resource/en/datasheet/lps25h.pdf + */ #define ST_PRESS_LPS25H_WAI_EXP 0xbd #define ST_PRESS_LPS25H_ODR_ADDR 0x20 #define ST_PRESS_LPS25H_ODR_MASK 0x70 @@ -117,7 +193,11 @@ #define ST_PRESS_LPS25H_OUT_XL_ADDR 0x28 #define ST_TEMP_LPS25H_OUT_L_ADDR 0x2b -/* CUSTOM VALUES FOR LPS22HB SENSOR */ +/* + * CUSTOM VALUES FOR LPS22HB SENSOR + * See LPS22HB datasheet: + * http://www2.st.com/resource/en/datasheet/lps22hb.pdf + */ #define ST_PRESS_LPS22HB_WAI_EXP 0xb1 #define ST_PRESS_LPS22HB_ODR_ADDR 0x10 #define ST_PRESS_LPS22HB_ODR_MASK 0x70 @@ -413,6 +493,10 @@ static const struct st_sensor_settings st_press_sensors_settings[] = { }, .fs = { .fs_avl = { + /* + * Sensitivity values as defined in table 3 of + * LPS22HB datasheet. + */ [0] = { .num = ST_PRESS_FS_AVL_1260MB, .gain = ST_PRESS_KPASCAL_NANO_SCALE, -- cgit v0.10.2 From b4701fd6922d9ebb4dab7cb015fa7ac8775814bd Mon Sep 17 00:00:00 2001 From: Gregor Boirie Date: Mon, 27 Jun 2016 12:38:55 +0200 Subject: iio:st_pressure: temperature triggered buffering Enable support for triggered buffering of temperature samples. Signed-off-by: Gregor Boirie Tested-by: Linus Walleij Signed-off-by: Jonathan Cameron diff --git a/drivers/iio/pressure/st_pressure_core.c b/drivers/iio/pressure/st_pressure_core.c index 2ab1056..ea8241f 100644 --- a/drivers/iio/pressure/st_pressure_core.c +++ b/drivers/iio/pressure/st_pressure_core.c @@ -105,8 +105,6 @@ #define ST_PRESS_LSB_PER_CELSIUS 480UL #define ST_PRESS_MILLI_CELSIUS_OFFSET 42500UL -#define ST_PRESS_NUMBER_DATA_CHANNELS 1 - /* FULLSCALE */ #define ST_PRESS_FS_AVL_1100MB 1100 #define ST_PRESS_FS_AVL_1260MB 1260 @@ -222,7 +220,7 @@ static const struct iio_chan_spec st_press_1_channels[] = { .type = IIO_PRESSURE, .channel2 = IIO_NO_MOD, .address = ST_PRESS_1_OUT_XL_ADDR, - .scan_index = ST_SENSORS_SCAN_X, + .scan_index = 0, .scan_type = { .sign = 'u', .realbits = 24, @@ -237,7 +235,7 @@ static const struct iio_chan_spec st_press_1_channels[] = { .type = IIO_TEMP, .channel2 = IIO_NO_MOD, .address = ST_TEMP_1_OUT_L_ADDR, - .scan_index = -1, + .scan_index = 1, .scan_type = { .sign = 'u', .realbits = 16, @@ -250,7 +248,7 @@ static const struct iio_chan_spec st_press_1_channels[] = { BIT(IIO_CHAN_INFO_OFFSET), .modified = 0, }, - IIO_CHAN_SOFT_TIMESTAMP(1) + IIO_CHAN_SOFT_TIMESTAMP(2) }; static const struct iio_chan_spec st_press_lps001wp_channels[] = { @@ -258,7 +256,7 @@ static const struct iio_chan_spec st_press_lps001wp_channels[] = { .type = IIO_PRESSURE, .channel2 = IIO_NO_MOD, .address = ST_PRESS_LPS001WP_OUT_L_ADDR, - .scan_index = ST_SENSORS_SCAN_X, + .scan_index = 0, .scan_type = { .sign = 'u', .realbits = 16, @@ -274,7 +272,7 @@ static const struct iio_chan_spec st_press_lps001wp_channels[] = { .type = IIO_TEMP, .channel2 = IIO_NO_MOD, .address = ST_TEMP_LPS001WP_OUT_L_ADDR, - .scan_index = -1, + .scan_index = 1, .scan_type = { .sign = 'u', .realbits = 16, @@ -286,7 +284,7 @@ static const struct iio_chan_spec st_press_lps001wp_channels[] = { BIT(IIO_CHAN_INFO_SCALE), .modified = 0, }, - IIO_CHAN_SOFT_TIMESTAMP(1) + IIO_CHAN_SOFT_TIMESTAMP(2) }; static const struct iio_chan_spec st_press_lps22hb_channels[] = { @@ -642,7 +640,13 @@ int st_press_common_probe(struct iio_dev *indio_dev) if (err < 0) goto st_press_power_off; - press_data->num_data_channels = ST_PRESS_NUMBER_DATA_CHANNELS; + /* + * Skip timestamping channel while declaring available channels to + * common st_sensor layer. Look at st_sensors_get_buffer_element() to + * see how timestamps are explicitly pushed as last samples block + * element. + */ + press_data->num_data_channels = press_data->sensor_settings->num_ch - 1; press_data->multiread_bit = press_data->sensor_settings->multi_read_bit; indio_dev->channels = press_data->sensor_settings->ch; indio_dev->num_channels = press_data->sensor_settings->num_ch; -- cgit v0.10.2 From 05167cdce057910125c535a120d7ba0a4a3617b8 Mon Sep 17 00:00:00 2001 From: Gregor Boirie Date: Mon, 27 Jun 2016 12:38:56 +0200 Subject: iio:st_pressure:lps22hb: open drain support Add support for open drain interrupt line. Signed-off-by: Gregor Boirie Signed-off-by: Jonathan Cameron diff --git a/drivers/iio/pressure/st_pressure_core.c b/drivers/iio/pressure/st_pressure_core.c index ea8241f..70230a1 100644 --- a/drivers/iio/pressure/st_pressure_core.c +++ b/drivers/iio/pressure/st_pressure_core.c @@ -213,6 +213,8 @@ #define ST_PRESS_LPS22HB_DRDY_IRQ_INT2_MASK 0x08 #define ST_PRESS_LPS22HB_IHL_IRQ_ADDR 0x12 #define ST_PRESS_LPS22HB_IHL_IRQ_MASK 0x80 +#define ST_PRESS_LPS22HB_OD_IRQ_ADDR 0x12 +#define ST_PRESS_LPS22HB_OD_IRQ_MASK 0x40 #define ST_PRESS_LPS22HB_MULTIREAD_BIT true static const struct iio_chan_spec st_press_1_channels[] = { @@ -511,6 +513,9 @@ static const struct st_sensor_settings st_press_sensors_settings[] = { .mask_int2 = ST_PRESS_LPS22HB_DRDY_IRQ_INT2_MASK, .addr_ihl = ST_PRESS_LPS22HB_IHL_IRQ_ADDR, .mask_ihl = ST_PRESS_LPS22HB_IHL_IRQ_MASK, + .addr_od = ST_PRESS_LPS22HB_OD_IRQ_ADDR, + .mask_od = ST_PRESS_LPS22HB_OD_IRQ_MASK, + .addr_stat_drdy = ST_SENSORS_DEFAULT_STAT_ADDR, }, .multi_read_bit = ST_PRESS_LPS22HB_MULTIREAD_BIT, }, -- cgit v0.10.2 From 85d79136d3080729b13d1dcd433727223038e830 Mon Sep 17 00:00:00 2001 From: Gregor Boirie Date: Mon, 27 Jun 2016 12:38:57 +0200 Subject: iio:st_pressure:lps22hb: temperature support Implement lps22hb temperature sampling channel. Signed-off-by: Gregor Boirie Tested-by: Linus Walleij Signed-off-by: Jonathan Cameron diff --git a/drivers/iio/pressure/st_pressure_core.c b/drivers/iio/pressure/st_pressure_core.c index 70230a1..274cdec 100644 --- a/drivers/iio/pressure/st_pressure_core.c +++ b/drivers/iio/pressure/st_pressure_core.c @@ -196,6 +196,10 @@ * See LPS22HB datasheet: * http://www2.st.com/resource/en/datasheet/lps22hb.pdf */ + +/* LPS22HB temperature sensitivity */ +#define ST_PRESS_LPS22HB_LSB_PER_CELSIUS 100UL + #define ST_PRESS_LPS22HB_WAI_EXP 0xb1 #define ST_PRESS_LPS22HB_ODR_ADDR 0x10 #define ST_PRESS_LPS22HB_ODR_MASK 0x70 @@ -307,7 +311,22 @@ static const struct iio_chan_spec st_press_lps22hb_channels[] = { .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), .modified = 0, }, - IIO_CHAN_SOFT_TIMESTAMP(1) + { + .type = IIO_TEMP, + .address = ST_TEMP_1_OUT_L_ADDR, + .scan_index = 1, + .scan_type = { + .sign = 's', + .realbits = 16, + .storagebits = 16, + .endianness = IIO_LE, + }, + .info_mask_separate = + BIT(IIO_CHAN_INFO_RAW) | + BIT(IIO_CHAN_INFO_SCALE), + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), + }, + IIO_CHAN_SOFT_TIMESTAMP(2) }; static const struct st_sensor_settings st_press_sensors_settings[] = { @@ -494,12 +513,13 @@ static const struct st_sensor_settings st_press_sensors_settings[] = { .fs = { .fs_avl = { /* - * Sensitivity values as defined in table 3 of - * LPS22HB datasheet. + * Pressure and temperature sensitivity values + * as defined in table 3 of LPS22HB datasheet. */ [0] = { .num = ST_PRESS_FS_AVL_1260MB, .gain = ST_PRESS_KPASCAL_NANO_SCALE, + .gain2 = ST_PRESS_LPS22HB_LSB_PER_CELSIUS, }, }, }, -- cgit v0.10.2 From 060a518eda493aa680a64a1a12089b850f8f9f5c Mon Sep 17 00:00:00 2001 From: Gregor Boirie Date: Mon, 27 Jun 2016 12:38:58 +0200 Subject: iio:st_pressure: clean useless static channel initializers Some static channels are explicitly initialized with default values. Remove them to enhance readability. Signed-off-by: Gregor Boirie Tested-by: Linus Walleij Signed-off-by: Jonathan Cameron diff --git a/drivers/iio/pressure/st_pressure_core.c b/drivers/iio/pressure/st_pressure_core.c index 274cdec..55df9a7 100644 --- a/drivers/iio/pressure/st_pressure_core.c +++ b/drivers/iio/pressure/st_pressure_core.c @@ -224,7 +224,6 @@ static const struct iio_chan_spec st_press_1_channels[] = { { .type = IIO_PRESSURE, - .channel2 = IIO_NO_MOD, .address = ST_PRESS_1_OUT_XL_ADDR, .scan_index = 0, .scan_type = { @@ -235,11 +234,9 @@ static const struct iio_chan_spec st_press_1_channels[] = { }, .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE), - .modified = 0, }, { .type = IIO_TEMP, - .channel2 = IIO_NO_MOD, .address = ST_TEMP_1_OUT_L_ADDR, .scan_index = 1, .scan_type = { @@ -252,7 +249,6 @@ static const struct iio_chan_spec st_press_1_channels[] = { BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE) | BIT(IIO_CHAN_INFO_OFFSET), - .modified = 0, }, IIO_CHAN_SOFT_TIMESTAMP(2) }; @@ -260,7 +256,6 @@ static const struct iio_chan_spec st_press_1_channels[] = { static const struct iio_chan_spec st_press_lps001wp_channels[] = { { .type = IIO_PRESSURE, - .channel2 = IIO_NO_MOD, .address = ST_PRESS_LPS001WP_OUT_L_ADDR, .scan_index = 0, .scan_type = { @@ -272,11 +267,9 @@ static const struct iio_chan_spec st_press_lps001wp_channels[] = { .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE), - .modified = 0, }, { .type = IIO_TEMP, - .channel2 = IIO_NO_MOD, .address = ST_TEMP_LPS001WP_OUT_L_ADDR, .scan_index = 1, .scan_type = { @@ -288,7 +281,6 @@ static const struct iio_chan_spec st_press_lps001wp_channels[] = { .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE), - .modified = 0, }, IIO_CHAN_SOFT_TIMESTAMP(2) }; @@ -296,7 +288,6 @@ static const struct iio_chan_spec st_press_lps001wp_channels[] = { static const struct iio_chan_spec st_press_lps22hb_channels[] = { { .type = IIO_PRESSURE, - .channel2 = IIO_NO_MOD, .address = ST_PRESS_1_OUT_XL_ADDR, .scan_index = 0, .scan_type = { @@ -309,7 +300,6 @@ static const struct iio_chan_spec st_press_lps22hb_channels[] = { BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE), .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), - .modified = 0, }, { .type = IIO_TEMP, -- cgit v0.10.2 From 21d41655f5dde155caa2e5c004ac45bb76291449 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 3 Jul 2016 10:18:03 +0100 Subject: iio: Add iio.git tree to MAINTAINERS The tree has been in the same location for a long time. Putting it in MAINTAINERS makes it easy for those new to, or less familiar with IIO to find the correct tree to base patches on. Mostly basing on staging-next is fine as well unless working on a very active driver. Signed-off-by: Jonathan Cameron diff --git a/MAINTAINERS b/MAINTAINERS index c1e4bf3..345e757 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -5785,6 +5785,7 @@ R: Hartmut Knaack R: Lars-Peter Clausen R: Peter Meerwald-Stadler L: linux-iio@vger.kernel.org +T: git git://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio.git S: Maintained F: Documentation/devicetree/bindings/iio/ F: drivers/iio/ -- cgit v0.10.2 From d5d5e8d55732c7c35c354e45e3b0af2795978a57 Mon Sep 17 00:00:00 2001 From: Haishuang Yan Date: Sat, 2 Jul 2016 15:02:48 +0800 Subject: geneve: fix max_mtu setting For ipv6+udp+geneve encapsulation data, the max_mtu should subtract sizeof(ipv6hdr), instead of sizeof(iphdr). Signed-off-by: Haishuang Yan Signed-off-by: David S. Miller diff --git a/drivers/net/geneve.c b/drivers/net/geneve.c index cc39cef..9b3dc3c 100644 --- a/drivers/net/geneve.c +++ b/drivers/net/geneve.c @@ -1072,12 +1072,17 @@ static netdev_tx_t geneve_xmit(struct sk_buff *skb, struct net_device *dev) static int __geneve_change_mtu(struct net_device *dev, int new_mtu, bool strict) { + struct geneve_dev *geneve = netdev_priv(dev); /* The max_mtu calculation does not take account of GENEVE * options, to avoid excluding potentially valid * configurations. */ - int max_mtu = IP_MAX_MTU - GENEVE_BASE_HLEN - sizeof(struct iphdr) - - dev->hard_header_len; + int max_mtu = IP_MAX_MTU - GENEVE_BASE_HLEN - dev->hard_header_len; + + if (geneve->remote.sa.sa_family == AF_INET6) + max_mtu -= sizeof(struct ipv6hdr); + else + max_mtu -= sizeof(struct iphdr); if (new_mtu < 68) return -EINVAL; -- cgit v0.10.2 From 2492c465ad3ae6860ebfff1c9032865017835e70 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Mon, 4 Jul 2016 19:35:47 -0300 Subject: perf build: Add feature detection for libelf's elf_getshdrstrndx() That appeared after 0.140, and will be used in the SDT code, so, to avoid bisection break on older systems, add a feature detection and provide a stub with a pr_debug() to keep it building. Cc: Ananth N Mavinakayanahalli Cc: Brendan Gregg Cc: Hemant Kumar Cc: Masami Hiramatsu Cc: Namhyung Kim Cc: Peter Zijlstra Link: http://lkml.kernel.org/n/tip-80y0eldgweorqnwha9rvfxjr@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/build/Makefile.feature b/tools/build/Makefile.feature index 57c8f98..3dd529b 100644 --- a/tools/build/Makefile.feature +++ b/tools/build/Makefile.feature @@ -40,6 +40,7 @@ FEATURE_TESTS_BASIC := \ libbfd \ libelf \ libelf-getphdrnum \ + libelf-getshdrstrndx \ libelf-mmap \ libnuma \ numa_num_possible_cpus \ diff --git a/tools/build/feature/Makefile b/tools/build/feature/Makefile index 3d88f09..6747116 100644 --- a/tools/build/feature/Makefile +++ b/tools/build/feature/Makefile @@ -17,6 +17,7 @@ FILES= \ test-cplus-demangle.bin \ test-libelf.bin \ test-libelf-getphdrnum.bin \ + test-libelf-getshdrstrndx.bin \ test-libelf-mmap.bin \ test-libnuma.bin \ test-numa_num_possible_cpus.bin \ @@ -98,6 +99,9 @@ $(OUTPUT)test-libelf-mmap.bin: $(OUTPUT)test-libelf-getphdrnum.bin: $(BUILD) -lelf +$(OUTPUT)test-libelf-getshdrstrndx.bin: + $(BUILD) -lelf + $(OUTPUT)test-libnuma.bin: $(BUILD) -lnuma diff --git a/tools/build/feature/test-all.c b/tools/build/feature/test-all.c index a282e8c..7433cca 100644 --- a/tools/build/feature/test-all.c +++ b/tools/build/feature/test-all.c @@ -49,6 +49,10 @@ # include "test-libelf-getphdrnum.c" #undef main +#define main main_test_libelf_getshdrstrndx +# include "test-libelf-getshdrstrndx.c" +#undef main + #define main main_test_libunwind # include "test-libunwind.c" #undef main @@ -149,6 +153,7 @@ int main(int argc, char *argv[]) main_test_dwarf(); main_test_dwarf_getlocations(); main_test_libelf_getphdrnum(); + main_test_libelf_getshdrstrndx(); main_test_libunwind(); main_test_libaudit(); main_test_libslang(); diff --git a/tools/build/feature/test-libelf-getshdrstrndx.c b/tools/build/feature/test-libelf-getshdrstrndx.c new file mode 100644 index 0000000..f0c3b47 --- /dev/null +++ b/tools/build/feature/test-libelf-getshdrstrndx.c @@ -0,0 +1,8 @@ +#include + +int main(void) +{ + size_t dst; + + return elf_getshdrstrndx(0, &dst); +} diff --git a/tools/perf/config/Makefile b/tools/perf/config/Makefile index bf1a0a0..c7e269a 100644 --- a/tools/perf/config/Makefile +++ b/tools/perf/config/Makefile @@ -309,6 +309,10 @@ ifndef NO_LIBELF CFLAGS += -DHAVE_ELF_GETPHDRNUM_SUPPORT endif + ifeq ($(feature-libelf-getshdrstrndx), 1) + CFLAGS += -DHAVE_ELF_GETSHDRSTRNDX_SUPPORT + endif + ifndef NO_DWARF ifeq ($(origin PERF_HAVE_DWARF_REGS), undefined) msg := $(warning DWARF register mappings have not been defined for architecture $(ARCH), DWARF support disabled); diff --git a/tools/perf/util/symbol-elf.c b/tools/perf/util/symbol-elf.c index 87a297d..b222552c 100644 --- a/tools/perf/util/symbol-elf.c +++ b/tools/perf/util/symbol-elf.c @@ -54,6 +54,14 @@ static int elf_getphdrnum(Elf *elf, size_t *dst) } #endif +#ifndef HAVE_ELF_GETSHDRSTRNDX_SUPPORT +static int elf_getshdrstrndx(Elf *elf __maybe_unused, size_t *dst __maybe_unused) +{ + pr_err("%s: update your libelf to > 0.140, this one lacks elf_getshdrstrndx().\n", __func__); + return -1; +} +#endif + #ifndef NT_GNU_BUILD_ID #define NT_GNU_BUILD_ID 3 #endif -- cgit v0.10.2 From 060fa0c7a3e0bb4f1426ee79dfd38e2a4c80067a Mon Sep 17 00:00:00 2001 From: Hemant Kumar Date: Fri, 1 Jul 2016 17:03:46 +0900 Subject: perf sdt: ELF support for SDT This patch serves the initial support to identify and list SDT events in binaries. When programs containing SDT markers are compiled, gcc with the help of assembler directives identifies them and places them in the section ".note.stapsdt". To find these markers from the binaries, one needs to traverse through this section and parse the relevant details like the name, type and location of the marker. Also, the original location could be skewed due to the effect of prelinking. If that is the case, the locations need to be adjusted. The functions in this patch open a given ELF, find out the SDT section, parse the relevant details, adjust the location (if necessary) and populate them in a list. A typical note entry in ".note.stapsdt" section is as follows : |--nhdr.n_namesz--| ------------------------------------ | nhdr | "stapsdt" | ----- |----------------------------------| | | | | | | nhdr.n_descsize | "provider_name" "note_name" | | | | ----- |----------------------------------| | nhdr | "stapsdt" | |... The above shows an excerpt from the section ".note.stapsdt". 'nhdr' is a structure which has the note name size (n_namesz), note description size (n_desc_sz) and note type (n_type). So, in order to parse the note note info, we need nhdr to tell us where to start from. As can be seen from , the name of the SDT notes given is "stapsdt". But this is not the identifier of the note. After that, we go to description of the note to find out its location, the address of the ".stapsdt.base" section and the semaphore address. Then, we find the provider name and the SDT marker name and then follow the arguments. Signed-off-by: Hemant Kumar Reviewed-by: Masami Hiramatsu Acked-by: Namhyung Kim Cc: Ananth N Mavinakayanahalli Cc: Brendan Gregg Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/146736022628.27797.1201368329092908163.stgit@devbox Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/util/symbol-elf.c b/tools/perf/util/symbol-elf.c index b222552c..6f15b92 100644 --- a/tools/perf/util/symbol-elf.c +++ b/tools/perf/util/symbol-elf.c @@ -1789,6 +1789,258 @@ void kcore_extract__delete(struct kcore_extract *kce) unlink(kce->extract_filename); } +/** + * populate_sdt_note : Parse raw data and identify SDT note + * @elf: elf of the opened file + * @data: raw data of a section with description offset applied + * @len: note description size + * @type: type of the note + * @sdt_notes: List to add the SDT note + * + * Responsible for parsing the @data in section .note.stapsdt in @elf and + * if its an SDT note, it appends to @sdt_notes list. + */ +static int populate_sdt_note(Elf **elf, const char *data, size_t len, + struct list_head *sdt_notes) +{ + const char *provider, *name; + struct sdt_note *tmp = NULL; + GElf_Ehdr ehdr; + GElf_Addr base_off = 0; + GElf_Shdr shdr; + int ret = -EINVAL; + + union { + Elf64_Addr a64[NR_ADDR]; + Elf32_Addr a32[NR_ADDR]; + } buf; + + Elf_Data dst = { + .d_buf = &buf, .d_type = ELF_T_ADDR, .d_version = EV_CURRENT, + .d_size = gelf_fsize((*elf), ELF_T_ADDR, NR_ADDR, EV_CURRENT), + .d_off = 0, .d_align = 0 + }; + Elf_Data src = { + .d_buf = (void *) data, .d_type = ELF_T_ADDR, + .d_version = EV_CURRENT, .d_size = dst.d_size, .d_off = 0, + .d_align = 0 + }; + + tmp = (struct sdt_note *)calloc(1, sizeof(struct sdt_note)); + if (!tmp) { + ret = -ENOMEM; + goto out_err; + } + + INIT_LIST_HEAD(&tmp->note_list); + + if (len < dst.d_size + 3) + goto out_free_note; + + /* Translation from file representation to memory representation */ + if (gelf_xlatetom(*elf, &dst, &src, + elf_getident(*elf, NULL)[EI_DATA]) == NULL) { + pr_err("gelf_xlatetom : %s\n", elf_errmsg(-1)); + goto out_free_note; + } + + /* Populate the fields of sdt_note */ + provider = data + dst.d_size; + + name = (const char *)memchr(provider, '\0', data + len - provider); + if (name++ == NULL) + goto out_free_note; + + tmp->provider = strdup(provider); + if (!tmp->provider) { + ret = -ENOMEM; + goto out_free_note; + } + tmp->name = strdup(name); + if (!tmp->name) { + ret = -ENOMEM; + goto out_free_prov; + } + + if (gelf_getclass(*elf) == ELFCLASS32) { + memcpy(&tmp->addr, &buf, 3 * sizeof(Elf32_Addr)); + tmp->bit32 = true; + } else { + memcpy(&tmp->addr, &buf, 3 * sizeof(Elf64_Addr)); + tmp->bit32 = false; + } + + if (!gelf_getehdr(*elf, &ehdr)) { + pr_debug("%s : cannot get elf header.\n", __func__); + ret = -EBADF; + goto out_free_name; + } + + /* Adjust the prelink effect : + * Find out the .stapsdt.base section. + * This scn will help us to handle prelinking (if present). + * Compare the retrieved file offset of the base section with the + * base address in the description of the SDT note. If its different, + * then accordingly, adjust the note location. + */ + if (elf_section_by_name(*elf, &ehdr, &shdr, SDT_BASE_SCN, NULL)) { + base_off = shdr.sh_offset; + if (base_off) { + if (tmp->bit32) + tmp->addr.a32[0] = tmp->addr.a32[0] + base_off - + tmp->addr.a32[1]; + else + tmp->addr.a64[0] = tmp->addr.a64[0] + base_off - + tmp->addr.a64[1]; + } + } + + list_add_tail(&tmp->note_list, sdt_notes); + return 0; + +out_free_name: + free(tmp->name); +out_free_prov: + free(tmp->provider); +out_free_note: + free(tmp); +out_err: + return ret; +} + +/** + * construct_sdt_notes_list : constructs a list of SDT notes + * @elf : elf to look into + * @sdt_notes : empty list_head + * + * Scans the sections in 'elf' for the section + * .note.stapsdt. It, then calls populate_sdt_note to find + * out the SDT events and populates the 'sdt_notes'. + */ +static int construct_sdt_notes_list(Elf *elf, struct list_head *sdt_notes) +{ + GElf_Ehdr ehdr; + Elf_Scn *scn = NULL; + Elf_Data *data; + GElf_Shdr shdr; + size_t shstrndx, next; + GElf_Nhdr nhdr; + size_t name_off, desc_off, offset; + int ret = 0; + + if (gelf_getehdr(elf, &ehdr) == NULL) { + ret = -EBADF; + goto out_ret; + } + if (elf_getshdrstrndx(elf, &shstrndx) != 0) { + ret = -EBADF; + goto out_ret; + } + + /* Look for the required section */ + scn = elf_section_by_name(elf, &ehdr, &shdr, SDT_NOTE_SCN, NULL); + if (!scn) { + ret = -ENOENT; + goto out_ret; + } + + if ((shdr.sh_type != SHT_NOTE) || (shdr.sh_flags & SHF_ALLOC)) { + ret = -ENOENT; + goto out_ret; + } + + data = elf_getdata(scn, NULL); + + /* Get the SDT notes */ + for (offset = 0; (next = gelf_getnote(data, offset, &nhdr, &name_off, + &desc_off)) > 0; offset = next) { + if (nhdr.n_namesz == sizeof(SDT_NOTE_NAME) && + !memcmp(data->d_buf + name_off, SDT_NOTE_NAME, + sizeof(SDT_NOTE_NAME))) { + /* Check the type of the note */ + if (nhdr.n_type != SDT_NOTE_TYPE) + goto out_ret; + + ret = populate_sdt_note(&elf, ((data->d_buf) + desc_off), + nhdr.n_descsz, sdt_notes); + if (ret < 0) + goto out_ret; + } + } + if (list_empty(sdt_notes)) + ret = -ENOENT; + +out_ret: + return ret; +} + +/** + * get_sdt_note_list : Wrapper to construct a list of sdt notes + * @head : empty list_head + * @target : file to find SDT notes from + * + * This opens the file, initializes + * the ELF and then calls construct_sdt_notes_list. + */ +int get_sdt_note_list(struct list_head *head, const char *target) +{ + Elf *elf; + int fd, ret; + + fd = open(target, O_RDONLY); + if (fd < 0) + return -EBADF; + + elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL); + if (!elf) { + ret = -EBADF; + goto out_close; + } + ret = construct_sdt_notes_list(elf, head); + elf_end(elf); +out_close: + close(fd); + return ret; +} + +/** + * cleanup_sdt_note_list : free the sdt notes' list + * @sdt_notes: sdt notes' list + * + * Free up the SDT notes in @sdt_notes. + * Returns the number of SDT notes free'd. + */ +int cleanup_sdt_note_list(struct list_head *sdt_notes) +{ + struct sdt_note *tmp, *pos; + int nr_free = 0; + + list_for_each_entry_safe(pos, tmp, sdt_notes, note_list) { + list_del(&pos->note_list); + free(pos->name); + free(pos->provider); + free(pos); + nr_free++; + } + return nr_free; +} + +/** + * sdt_notes__get_count: Counts the number of sdt events + * @start: list_head to sdt_notes list + * + * Returns the number of SDT notes in a list + */ +int sdt_notes__get_count(struct list_head *start) +{ + struct sdt_note *sdt_ptr; + int count = 0; + + list_for_each_entry(sdt_ptr, start, note_list) + count++; + return count; +} + void symbol__elf_init(void) { elf_version(EV_CURRENT); diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h index b10d558..699f7cb 100644 --- a/tools/perf/util/symbol.h +++ b/tools/perf/util/symbol.h @@ -342,4 +342,26 @@ void arch__sym_update(struct symbol *s, GElf_Sym *sym); int arch__choose_best_symbol(struct symbol *syma, struct symbol *symb); +/* structure containing an SDT note's info */ +struct sdt_note { + char *name; /* name of the note*/ + char *provider; /* provider name */ + bool bit32; /* whether the location is 32 bits? */ + union { /* location, base and semaphore addrs */ + Elf64_Addr a64[3]; + Elf32_Addr a32[3]; + } addr; + struct list_head note_list; /* SDT notes' list */ +}; + +int get_sdt_note_list(struct list_head *head, const char *target); +int cleanup_sdt_note_list(struct list_head *sdt_notes); +int sdt_notes__get_count(struct list_head *start); + +#define SDT_BASE_SCN ".stapsdt.base" +#define SDT_NOTE_SCN ".note.stapsdt" +#define SDT_NOTE_TYPE 3 +#define SDT_NOTE_NAME "stapsdt" +#define NR_ADDR 3 + #endif /* __PERF_SYMBOL */ -- cgit v0.10.2 From 8d993d96901f55d26e083390aae80fd02cbff7aa Mon Sep 17 00:00:00 2001 From: Masami Hiramatsu Date: Fri, 1 Jul 2016 17:04:01 +0900 Subject: perf probe: Add group name support Allow user to set group name for adding new event. Note that user must ensure that the group name doesn't conflict with existing group name carefully. E.g. Existing group name can conflict with other events. Especially, using the group name reserved for kernel modules can hide kernel embedded events when loading modules. Signed-off-by: Masami Hiramatsu Signed-off-by: Masami Hiramatsu Cc: Ananth N Mavinakayanahalli Cc: Brendan Gregg Cc: Hemant Kumar Cc: Namhyung Kim Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/146736024091.27797.9471545190066268995.stgit@devbox Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/Documentation/perf-probe.txt b/tools/perf/Documentation/perf-probe.txt index 8d09173..7a258e9 100644 --- a/tools/perf/Documentation/perf-probe.txt +++ b/tools/perf/Documentation/perf-probe.txt @@ -143,16 +143,18 @@ PROBE SYNTAX Probe points are defined by following syntax. 1) Define event based on function name - [EVENT=]FUNC[@SRC][:RLN|+OFFS|%return|;PTN] [ARG ...] + [[GROUP:]EVENT=]FUNC[@SRC][:RLN|+OFFS|%return|;PTN] [ARG ...] 2) Define event based on source file with line number - [EVENT=]SRC:ALN [ARG ...] + [[GROUP:]EVENT=]SRC:ALN [ARG ...] 3) Define event based on source file with lazy pattern - [EVENT=]SRC;PTN [ARG ...] + [[GROUP:]EVENT=]SRC;PTN [ARG ...] -'EVENT' specifies the name of new event, if omitted, it will be set the name of the probed function. Currently, event group name is set as 'probe'. +'EVENT' specifies the name of new event, if omitted, it will be set the name of the probed function. You can also specify a group name by 'GROUP', if omitted, set 'probe' is used for kprobe and 'probe_' is used for uprobe. +Note that using existing group name can conflict with other events. Especially, using the group name reserved for kernel modules can hide embedded events in the +modules. 'FUNC' specifies a probed function name, and it may have one of the following options; '+OFFS' is the offset from function entry address in bytes, ':RLN' is the relative-line number from function entry line, and '%return' means that it probes function return. And ';PTN' means lazy matching pattern (see LAZY MATCHING). Note that ';PTN' must be the end of the probe point definition. In addition, '@SRC' specifies a source file which has that function. It is also possible to specify a probe point by the source line number or lazy matching by using 'SRC:ALN' or 'SRC;PTN' syntax, where 'SRC' is the source file path, ':ALN' is the line number and ';PTN' is the lazy matching pattern. 'ARG' specifies the arguments of this probe point, (see PROBE ARGUMENT). diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c index f81b5dd..0201f66 100644 --- a/tools/perf/util/probe-event.c +++ b/tools/perf/util/probe-event.c @@ -1206,10 +1206,8 @@ static int parse_perf_probe_point(char *arg, struct perf_probe_event *pev) bool file_spec = false; /* * - * perf probe [EVENT=]SRC[:LN|;PTN] - * perf probe [EVENT=]FUNC[@SRC][+OFFS|%return|:LN|;PAT] - * - * TODO:Group name support + * perf probe [GRP:][EVENT=]SRC[:LN|;PTN] + * perf probe [GRP:][EVENT=]FUNC[@SRC][+OFFS|%return|:LN|;PAT] */ if (!arg) return -EINVAL; @@ -1218,11 +1216,19 @@ static int parse_perf_probe_point(char *arg, struct perf_probe_event *pev) if (ptr && *ptr == '=') { /* Event name */ *ptr = '\0'; tmp = ptr + 1; - if (strchr(arg, ':')) { - semantic_error("Group name is not supported yet.\n"); - return -ENOTSUP; - } + ptr = strchr(arg, ':'); + if (ptr) { + *ptr = '\0'; + if (!is_c_func_name(arg)) + goto not_fname; + pev->group = strdup(arg); + if (!pev->group) + return -ENOMEM; + arg = ptr + 1; + } else + pev->group = NULL; if (!is_c_func_name(arg)) { +not_fname: semantic_error("%s is bad for event name -it must " "follow C symbol-naming rule.\n", arg); return -EINVAL; @@ -1230,7 +1236,6 @@ static int parse_perf_probe_point(char *arg, struct perf_probe_event *pev) pev->event = strdup(arg); if (pev->event == NULL) return -ENOMEM; - pev->group = NULL; arg = tmp; } -- cgit v0.10.2 From 6430a94ead2a4c8f350441351a735303eb6d1c8a Mon Sep 17 00:00:00 2001 From: Masami Hiramatsu Date: Fri, 1 Jul 2016 17:04:10 +0900 Subject: perf buildid-cache: Scan and import user SDT events to probe cache perf buildid-cache --add scans given binary and add the SDT events to probe cache. "sdt_" prefix is appended for all SDT providers to avoid event-name clash with other pre-defined events. It is possible to use the cached SDT events as other cached events, via perf probe --add "sdt_:=". e.g. ---- # perf buildid-cache --add /lib/libc-2.17.so # perf probe --cache --list | head -n 5 /usr/lib/libc-2.17.so (a6fb821bdf53660eb2c29f778757aef294d3d392): sdt_libc:setjmp=setjmp sdt_libc:longjmp=longjmp sdt_libc:longjmp_target=longjmp_target sdt_libc:memory_heap_new=memory_heap_new # perf probe -x /usr/lib/libc-2.17.so \ -a sdt_libc:memory_heap_new=memory_heap_new Added new event: sdt_libc:memory_heap_new (on memory_heap_new in /usr/lib/libc-2.17.so) You can now use it in all perf tools, such as: perf record -e sdt_libc:memory_heap_new -aR sleep 1 # perf probe -l sdt_libc:memory_heap_new (on new_heap+183 in /usr/lib/libc-2.17.so) ---- Note that SDT event entries in probe-cache file is somewhat different from normal cached events. Normal one starts with "#", but SDTs are starting with "%". Signed-off-by: Masami Hiramatsu Signed-off-by: Masami Hiramatsu Cc: Ananth N Mavinakayanahalli Cc: Brendan Gregg Cc: Hemant Kumar Cc: Namhyung Kim Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/146736025058.27797.13043265488541434502.stgit@devbox Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/Documentation/perf-buildid-cache.txt b/tools/perf/Documentation/perf-buildid-cache.txt index dd07b55..058064d 100644 --- a/tools/perf/Documentation/perf-buildid-cache.txt +++ b/tools/perf/Documentation/perf-buildid-cache.txt @@ -15,6 +15,9 @@ DESCRIPTION This command manages the build-id cache. It can add, remove, update and purge files to/from the cache. In the future it should as well set upper limits for the space used by the cache, etc. +This also scans the target binary for SDT (Statically Defined Tracing) and +record it along with the buildid-cache, which will be used by perf-probe. +For more details, see linkperf:perf-probe[1]. OPTIONS ------- diff --git a/tools/perf/util/build-id.c b/tools/perf/util/build-id.c index 1c49620..e1a1640 100644 --- a/tools/perf/util/build-id.c +++ b/tools/perf/util/build-id.c @@ -17,6 +17,7 @@ #include "tool.h" #include "header.h" #include "vdso.h" +#include "probe-file.h" static bool no_buildid_cache; @@ -532,6 +533,30 @@ int build_id_cache__list_build_ids(const char *pathname, return ret; } +#ifdef HAVE_LIBELF_SUPPORT +static int build_id_cache__add_sdt_cache(const char *sbuild_id, + const char *realname) +{ + struct probe_cache *cache; + int ret; + + cache = probe_cache__new(sbuild_id); + if (!cache) + return -1; + + ret = probe_cache__scan_sdt(cache, realname); + if (ret >= 0) { + pr_debug("Found %d SDTs in %s\n", ret, realname); + if (probe_cache__commit(cache) < 0) + ret = -1; + } + probe_cache__delete(cache); + return ret; +} +#else +#define build_id_cache__add_sdt_cache(sbuild_id, realname) (0) +#endif + int build_id_cache__add_s(const char *sbuild_id, const char *name, bool is_kallsyms, bool is_vdso) { @@ -589,6 +614,11 @@ int build_id_cache__add_s(const char *sbuild_id, const char *name, if (symlink(tmp, linkname) == 0) err = 0; + + /* Update SDT cache : error is just warned */ + if (build_id_cache__add_sdt_cache(sbuild_id, realname) < 0) + pr_debug("Failed to update/scan SDT cache for %s\n", realname); + out_free: if (!is_kallsyms) free(realname); diff --git a/tools/perf/util/probe-file.c b/tools/perf/util/probe-file.c index 6cb6ec0..5b563b2 100644 --- a/tools/perf/util/probe-file.c +++ b/tools/perf/util/probe-file.c @@ -434,12 +434,15 @@ static int probe_cache__load(struct probe_cache *pcache) p = strchr(buf, '\n'); if (p) *p = '\0'; - if (buf[0] == '#') { /* #perf_probe_event */ + /* #perf_probe_event or %sdt_event */ + if (buf[0] == '#' || buf[0] == '%') { entry = probe_cache_entry__new(NULL); if (!entry) { ret = -ENOMEM; goto out; } + if (buf[0] == '%') + entry->sdt = true; entry->spev = strdup(buf + 1); if (entry->spev) ret = parse_perf_probe_command(buf + 1, @@ -621,19 +624,79 @@ out_err: return ret; } +static unsigned long long sdt_note__get_addr(struct sdt_note *note) +{ + return note->bit32 ? (unsigned long long)note->addr.a32[0] + : (unsigned long long)note->addr.a64[0]; +} + +int probe_cache__scan_sdt(struct probe_cache *pcache, const char *pathname) +{ + struct probe_cache_entry *entry = NULL; + struct list_head sdtlist; + struct sdt_note *note; + char *buf; + char sdtgrp[64]; + int ret; + + INIT_LIST_HEAD(&sdtlist); + ret = get_sdt_note_list(&sdtlist, pathname); + if (ret < 0) { + pr_debug("Failed to get sdt note: %d\n", ret); + return ret; + } + list_for_each_entry(note, &sdtlist, note_list) { + ret = snprintf(sdtgrp, 64, "sdt_%s", note->provider); + if (ret < 0) + break; + /* Try to find same-name entry */ + entry = probe_cache__find_by_name(pcache, sdtgrp, note->name); + if (!entry) { + entry = probe_cache_entry__new(NULL); + if (!entry) { + ret = -ENOMEM; + break; + } + entry->sdt = true; + ret = asprintf(&entry->spev, "%s:%s=%s", sdtgrp, + note->name, note->name); + if (ret < 0) + break; + entry->pev.event = strdup(note->name); + entry->pev.group = strdup(sdtgrp); + list_add_tail(&entry->node, &pcache->entries); + } + ret = asprintf(&buf, "p:%s/%s %s:0x%llx", + sdtgrp, note->name, pathname, + sdt_note__get_addr(note)); + if (ret < 0) + break; + strlist__add(entry->tevlist, buf); + free(buf); + entry = NULL; + } + if (entry) { + list_del_init(&entry->node); + probe_cache_entry__delete(entry); + } + cleanup_sdt_note_list(&sdtlist); + return ret; +} + static int probe_cache_entry__write(struct probe_cache_entry *entry, int fd) { struct str_node *snode; struct stat st; struct iovec iov[3]; + const char *prefix = entry->sdt ? "%" : "#"; int ret; /* Save stat for rollback */ ret = fstat(fd, &st); if (ret < 0) return ret; - pr_debug("Writing cache: #%s\n", entry->spev); - iov[0].iov_base = (void *)"#"; iov[0].iov_len = 1; + pr_debug("Writing cache: %s%s\n", prefix, entry->spev); + iov[0].iov_base = (void *)prefix; iov[0].iov_len = 1; iov[1].iov_base = entry->spev; iov[1].iov_len = strlen(entry->spev); iov[2].iov_base = (void *)"\n"; iov[2].iov_len = 1; ret = writev(fd, iov, 3); diff --git a/tools/perf/util/probe-file.h b/tools/perf/util/probe-file.h index 0ed1fc5..ddf5ae2 100644 --- a/tools/perf/util/probe-file.h +++ b/tools/perf/util/probe-file.h @@ -8,6 +8,7 @@ /* Cache of probe definitions */ struct probe_cache_entry { struct list_head node; + bool sdt; struct perf_probe_event pev; char *spev; struct strlist *tevlist; @@ -35,6 +36,7 @@ struct probe_cache *probe_cache__new(const char *target); int probe_cache__add_entry(struct probe_cache *pcache, struct perf_probe_event *pev, struct probe_trace_event *tevs, int ntevs); +int probe_cache__scan_sdt(struct probe_cache *pcache, const char *pathname); int probe_cache__commit(struct probe_cache *pcache); void probe_cache__purge(struct probe_cache *pcache); void probe_cache__delete(struct probe_cache *pcache); -- cgit v0.10.2 From c60da22aca8755b77b7f4d4caf57ada8654db939 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Mon, 4 Jul 2016 14:16:20 +0200 Subject: perf header: Transform nodes string info to struct Storing NUMA info within struct numa_node instead of strings. This way it's usable in future patches. Also it turned out it's slightly less code involved than using strings. Signed-off-by: Jiri Olsa Cc: David Ahern Cc: Namhyung Kim Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1467634583-29147-2-git-send-email-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/util/env.c b/tools/perf/util/env.c index 49a11d9..bb964e8 100644 --- a/tools/perf/util/env.c +++ b/tools/perf/util/env.c @@ -18,10 +18,13 @@ void perf_env__exit(struct perf_env *env) zfree(&env->cmdline_argv); zfree(&env->sibling_cores); zfree(&env->sibling_threads); - zfree(&env->numa_nodes); zfree(&env->pmu_mappings); zfree(&env->cpu); + for (i = 0; i < env->nr_numa_nodes; i++) + cpu_map__put(env->numa_nodes[i].map); + zfree(&env->numa_nodes); + for (i = 0; i < env->caches_cnt; i++) cpu_cache_level__free(&env->caches[i]); zfree(&env->caches); diff --git a/tools/perf/util/env.h b/tools/perf/util/env.h index 56cffb6..b164dfd 100644 --- a/tools/perf/util/env.h +++ b/tools/perf/util/env.h @@ -2,6 +2,7 @@ #define __PERF_ENV_H #include +#include "cpumap.h" struct cpu_topology_map { int socket_id; @@ -18,6 +19,13 @@ struct cpu_cache_level { char *map; }; +struct numa_node { + u32 node; + u64 mem_total; + u64 mem_free; + struct cpu_map *map; +}; + struct perf_env { char *hostname; char *os_release; @@ -40,11 +48,11 @@ struct perf_env { const char **cmdline_argv; char *sibling_cores; char *sibling_threads; - char *numa_nodes; char *pmu_mappings; struct cpu_topology_map *cpu; struct cpu_cache_level *caches; int caches_cnt; + struct numa_node *numa_nodes; }; extern struct perf_env perf_env; diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index c5cd269..8f0db40 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c @@ -1306,42 +1306,19 @@ static void print_total_mem(struct perf_header *ph, int fd __maybe_unused, static void print_numa_topology(struct perf_header *ph, int fd __maybe_unused, FILE *fp) { - u32 nr, c, i; - char *str, *tmp; - uint64_t mem_total, mem_free; - - /* nr nodes */ - nr = ph->env.nr_numa_nodes; - str = ph->env.numa_nodes; - - for (i = 0; i < nr; i++) { - /* node number */ - c = strtoul(str, &tmp, 0); - if (*tmp != ':') - goto error; - - str = tmp + 1; - mem_total = strtoull(str, &tmp, 0); - if (*tmp != ':') - goto error; + int i; + struct numa_node *n; - str = tmp + 1; - mem_free = strtoull(str, &tmp, 0); - if (*tmp != ':') - goto error; + for (i = 0; i < ph->env.nr_numa_nodes; i++) { + n = &ph->env.numa_nodes[i]; fprintf(fp, "# node%u meminfo : total = %"PRIu64" kB," " free = %"PRIu64" kB\n", - c, mem_total, mem_free); + n->node, n->mem_total, n->mem_free); - str = tmp + 1; - fprintf(fp, "# node%u cpu list : %s\n", c, str); - - str += strlen(str) + 1; + fprintf(fp, "# node%u cpu list : ", n->node); + cpu_map__fprintf(n->map, fp); } - return; -error: - fprintf(fp, "# numa topology : not available\n"); } static void print_cpuid(struct perf_header *ph, int fd __maybe_unused, FILE *fp) @@ -1906,11 +1883,10 @@ static int process_numa_topology(struct perf_file_section *section __maybe_unuse struct perf_header *ph, int fd, void *data __maybe_unused) { + struct numa_node *nodes, *n; ssize_t ret; - u32 nr, node, i; + u32 nr, i; char *str; - uint64_t mem_total, mem_free; - struct strbuf sb; /* nr nodes */ ret = readn(fd, &nr, sizeof(nr)); @@ -1921,47 +1897,47 @@ static int process_numa_topology(struct perf_file_section *section __maybe_unuse nr = bswap_32(nr); ph->env.nr_numa_nodes = nr; - if (strbuf_init(&sb, 256) < 0) - return -1; + nodes = zalloc(sizeof(*nodes) * nr); + if (!nodes) + return -ENOMEM; for (i = 0; i < nr; i++) { + n = &nodes[i]; + /* node number */ - ret = readn(fd, &node, sizeof(node)); - if (ret != sizeof(node)) + ret = readn(fd, &n->node, sizeof(u32)); + if (ret != sizeof(n->node)) goto error; - ret = readn(fd, &mem_total, sizeof(u64)); + ret = readn(fd, &n->mem_total, sizeof(u64)); if (ret != sizeof(u64)) goto error; - ret = readn(fd, &mem_free, sizeof(u64)); + ret = readn(fd, &n->mem_free, sizeof(u64)); if (ret != sizeof(u64)) goto error; if (ph->needs_swap) { - node = bswap_32(node); - mem_total = bswap_64(mem_total); - mem_free = bswap_64(mem_free); + n->node = bswap_32(n->node); + n->mem_total = bswap_64(n->mem_total); + n->mem_free = bswap_64(n->mem_free); } - if (strbuf_addf(&sb, "%u:%"PRIu64":%"PRIu64":", - node, mem_total, mem_free) < 0) - goto error; - str = do_read_string(fd, ph); if (!str) goto error; - /* include a NULL character at the end */ - if (strbuf_add(&sb, str, strlen(str) + 1) < 0) + n->map = cpu_map__new(str); + if (!n->map) goto error; + free(str); } - ph->env.numa_nodes = strbuf_detach(&sb, NULL); + ph->env.numa_nodes = nodes; return 0; error: - strbuf_release(&sb); + free(nodes); return -1; } -- cgit v0.10.2 From 347ca878062d5fb0e16db1fae81b0994f2457efd Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Mon, 4 Jul 2016 14:16:21 +0200 Subject: perf tests: Fix hist accumulation test User's values from .perfconfig could overload the default callchain setup and cause this test to fail. Making sure the test is using default callchain_param values. Signed-off-by: Jiri Olsa Cc: David Ahern Cc: Namhyung Kim Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1467634583-29147-3-git-send-email-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/tests/hists_cumulate.c b/tools/perf/tests/hists_cumulate.c index a9e3db3..9fd54b7 100644 --- a/tools/perf/tests/hists_cumulate.c +++ b/tools/perf/tests/hists_cumulate.c @@ -216,6 +216,8 @@ static int do_test(struct hists *hists, struct result *expected, size_t nr_expec /* check callchain entries */ root = &he->callchain->node.rb_root; + + TEST_ASSERT_VAL("callchains expected", !RB_EMPTY_ROOT(root)); cnode = rb_entry(rb_first(root), struct callchain_node, rb_node); c = 0; @@ -666,6 +668,8 @@ static int test4(struct perf_evsel *evsel, struct machine *machine) perf_evsel__set_sample_bit(evsel, CALLCHAIN); setup_sorting(NULL); + + callchain_param = callchain_param_default; callchain_register_param(&callchain_param); err = add_hist_entries(hists, machine); diff --git a/tools/perf/util/callchain.h b/tools/perf/util/callchain.h index a70f6b5..13e7554 100644 --- a/tools/perf/util/callchain.h +++ b/tools/perf/util/callchain.h @@ -106,6 +106,7 @@ struct callchain_param { }; extern struct callchain_param callchain_param; +extern struct callchain_param callchain_param_default; struct callchain_list { u64 ip; diff --git a/tools/perf/util/util.c b/tools/perf/util/util.c index e08b9a0..5f44a21 100644 --- a/tools/perf/util/util.c +++ b/tools/perf/util/util.c @@ -19,12 +19,19 @@ #include "callchain.h" #include "strlist.h" -struct callchain_param callchain_param = { - .mode = CHAIN_GRAPH_ABS, - .min_percent = 0.5, - .order = ORDER_CALLEE, - .key = CCKEY_FUNCTION, - .value = CCVAL_PERCENT, +#define CALLCHAIN_PARAM_DEFAULT \ + .mode = CHAIN_GRAPH_ABS, \ + .min_percent = 0.5, \ + .order = ORDER_CALLEE, \ + .key = CCKEY_FUNCTION, \ + .value = CCVAL_PERCENT, \ + +struct callchain_param callchain_param = { + CALLCHAIN_PARAM_DEFAULT +}; + +struct callchain_param callchain_param_default = { + CALLCHAIN_PARAM_DEFAULT }; /* -- cgit v0.10.2 From 3dad5424adfb346c871847d467f97dcdca64ea97 Mon Sep 17 00:00:00 2001 From: Vegard Nossum Date: Sun, 3 Jul 2016 10:54:54 +0200 Subject: RDS: fix rds_tcp_init() error path If register_pernet_subsys() fails, we shouldn't try to call unregister_pernet_subsys(). Fixes: 467fa15356 ("RDS-TCP: Support multiple RDS-TCP listen endpoints, one per netns.") Cc: stable@vger.kernel.org Cc: Sowmini Varadhan Cc: David S. Miller Signed-off-by: Vegard Nossum Acked-by: Sowmini Varadhan Acked-by: Santosh Shilimkar Signed-off-by: David S. Miller diff --git a/net/rds/tcp.c b/net/rds/tcp.c index 74ee126..c8a7b4c 100644 --- a/net/rds/tcp.c +++ b/net/rds/tcp.c @@ -616,7 +616,7 @@ static int rds_tcp_init(void) ret = rds_tcp_recv_init(); if (ret) - goto out_slab; + goto out_pernet; ret = rds_trans_register(&rds_tcp_transport); if (ret) @@ -628,8 +628,9 @@ static int rds_tcp_init(void) out_recv: rds_tcp_recv_exit(); -out_slab: +out_pernet: unregister_pernet_subsys(&rds_tcp_net_ops); +out_slab: kmem_cache_destroy(rds_tcp_conn_slab); out: return ret; -- cgit v0.10.2 From c086e7096170390594c425114d98172bc9aceb8a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B8rn=20Mork?= Date: Sun, 3 Jul 2016 22:24:50 +0200 Subject: cdc_ncm: workaround for EM7455 "silent" data interface MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Several Lenovo users have reported problems with their Sierra Wireless EM7455 modem. The driver has loaded successfully and the MBIM management channel has appeared to work, including establishing a connection to the mobile network. But no frames have been received over the data interface. The problem affects all EM7455 and MC7455, and is assumed to affect other modems based on the same Qualcomm chipset and baseband firmware. Testing narrowed the problem down to what seems to be a firmware timing bug during initialization. Adding a short sleep while probing is sufficient to make the problem disappear. Experiments have shown that 1-2 ms is too little to have any effect, while 10-20 ms is enough to reliably succeed. Reported-by: Stefan Armbruster Reported-by: Ralph Plawetzki Reported-by: Andreas Fett Reported-by: Rasmus Lerdorf Reported-by: Samo Ratnik Reported-and-tested-by: Aleksander Morgado Signed-off-by: Bjørn Mork Signed-off-by: David S. Miller diff --git a/drivers/net/usb/cdc_ncm.c b/drivers/net/usb/cdc_ncm.c index 53759c3..877c951 100644 --- a/drivers/net/usb/cdc_ncm.c +++ b/drivers/net/usb/cdc_ncm.c @@ -854,6 +854,13 @@ int cdc_ncm_bind_common(struct usbnet *dev, struct usb_interface *intf, u8 data_ if (cdc_ncm_init(dev)) goto error2; + /* Some firmwares need a pause here or they will silently fail + * to set up the interface properly. This value was decided + * empirically on a Sierra Wireless MC7455 running 02.08.02.00 + * firmware. + */ + usleep_range(10000, 20000); + /* configure data interface */ temp = usb_set_interface(dev->udev, iface_no, data_altsetting); if (temp) { -- cgit v0.10.2 From a2873325ffb21cecca8032673eb698cb4d778dc6 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Mon, 4 Jul 2016 14:16:22 +0200 Subject: perf unwind: Add initialized arg into unwind__prepare_access Adding initialized arg into unwind__prepare_access to get feedback about the initialization state. It's not possible to get it from error code, because we return 0 even in case we don't recognize dso, which is valid. The 'initialized' value is used in following patch to speedup unwind__prepare_access calls logic in fork path. Signed-off-by: Jiri Olsa Cc: David Ahern Cc: He Kuang Cc: Namhyung Kim Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1467634583-29147-4-git-send-email-jolsa@kernel.org [ Remove ; after static inline function signatures, fixes build break ] Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c index f30f956..2439b12 100644 --- a/tools/perf/util/thread.c +++ b/tools/perf/util/thread.c @@ -202,7 +202,7 @@ int thread__insert_map(struct thread *thread, struct map *map) { int ret; - ret = unwind__prepare_access(thread, map); + ret = unwind__prepare_access(thread, map, NULL); if (ret) return ret; diff --git a/tools/perf/util/unwind-libunwind.c b/tools/perf/util/unwind-libunwind.c index 8547119..6d542a4 100644 --- a/tools/perf/util/unwind-libunwind.c +++ b/tools/perf/util/unwind-libunwind.c @@ -14,15 +14,19 @@ static void unwind__register_ops(struct thread *thread, thread->unwind_libunwind_ops = ops; } -int unwind__prepare_access(struct thread *thread, struct map *map) +int unwind__prepare_access(struct thread *thread, struct map *map, + bool *initialized) { const char *arch; enum dso_type dso_type; struct unwind_libunwind_ops *ops = local_unwind_libunwind_ops; + int err; if (thread->addr_space) { pr_debug("unwind: thread map already set, dso=%s\n", map->dso->name); + if (initialized) + *initialized = true; return 0; } @@ -51,7 +55,10 @@ int unwind__prepare_access(struct thread *thread, struct map *map) out_register: unwind__register_ops(thread, ops); - return thread->unwind_libunwind_ops->prepare_access(thread); + err = thread->unwind_libunwind_ops->prepare_access(thread); + if (initialized) + *initialized = err ? false : true; + return err; } void unwind__flush_access(struct thread *thread) diff --git a/tools/perf/util/unwind.h b/tools/perf/util/unwind.h index 84c6d44..61fb1e9 100644 --- a/tools/perf/util/unwind.h +++ b/tools/perf/util/unwind.h @@ -42,12 +42,14 @@ int unwind__get_entries(unwind_entry_cb_t cb, void *arg, #endif int LIBUNWIND__ARCH_REG_ID(int regnum); -int unwind__prepare_access(struct thread *thread, struct map *map); +int unwind__prepare_access(struct thread *thread, struct map *map, + bool *initialized); void unwind__flush_access(struct thread *thread); void unwind__finish_access(struct thread *thread); #else static inline int unwind__prepare_access(struct thread *thread __maybe_unused, - struct map *map __maybe_unused) + struct map *map __maybe_unused, + bool *initialized __maybe_unused) { return 0; } @@ -67,7 +69,8 @@ unwind__get_entries(unwind_entry_cb_t cb __maybe_unused, } static inline int unwind__prepare_access(struct thread *thread __maybe_unused, - struct map *map __maybe_unused) + struct map *map __maybe_unused, + bool *initialized __maybe_unused) { return 0; } -- cgit v0.10.2 From 6c502584438bda63fc1a67606854fb0b300465cd Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Mon, 4 Jul 2016 14:16:23 +0200 Subject: perf unwind: Call unwind__prepare_access for forked thread Currently we call unwind__prepare_access for map event. In case we report fork event the thread inherits its parent's maps and unwind__prepare_access is never called for the thread. This causes unwind__get_entries seeing uninitialized unwind_libunwind_ops and thus returning no callchain. Adding unwind__prepare_access calls for fork even processing. Signed-off-by: Jiri Olsa Cc: David Ahern Cc: He Kuang Cc: Namhyung Kim Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1467634583-29147-5-git-send-email-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c index b19bcd3..b39b12a 100644 --- a/tools/perf/util/map.c +++ b/tools/perf/util/map.c @@ -15,6 +15,7 @@ #include "debug.h" #include "machine.h" #include +#include "unwind.h" static void __maps__insert(struct maps *maps, struct map *map); @@ -744,9 +745,10 @@ int map_groups__fixup_overlappings(struct map_groups *mg, struct map *map, /* * XXX This should not really _copy_ te maps, but refcount them. */ -int map_groups__clone(struct map_groups *mg, +int map_groups__clone(struct thread *thread, struct map_groups *parent, enum map_type type) { + struct map_groups *mg = thread->mg; int err = -ENOMEM; struct map *map; struct maps *maps = &parent->maps[type]; @@ -757,6 +759,11 @@ int map_groups__clone(struct map_groups *mg, struct map *new = map__clone(map); if (new == NULL) goto out_unlock; + + err = unwind__prepare_access(thread, new, NULL); + if (err) + goto out_unlock; + map_groups__insert(mg, new); map__put(new); } diff --git a/tools/perf/util/map.h b/tools/perf/util/map.h index 7309d64..d83396c 100644 --- a/tools/perf/util/map.h +++ b/tools/perf/util/map.h @@ -194,7 +194,7 @@ struct symbol *maps__find_symbol_by_name(struct maps *maps, const char *name, struct map **mapp, symbol_filter_t filter); void map_groups__init(struct map_groups *mg, struct machine *machine); void map_groups__exit(struct map_groups *mg); -int map_groups__clone(struct map_groups *mg, +int map_groups__clone(struct thread *thread, struct map_groups *parent, enum map_type type); size_t map_groups__fprintf(struct map_groups *mg, FILE *fp); diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c index 2439b12..8b10a55 100644 --- a/tools/perf/util/thread.c +++ b/tools/perf/util/thread.c @@ -212,6 +212,39 @@ int thread__insert_map(struct thread *thread, struct map *map) return 0; } +static int __thread__prepare_access(struct thread *thread) +{ + bool initialized = false; + int i, err = 0; + + for (i = 0; i < MAP__NR_TYPES; ++i) { + struct maps *maps = &thread->mg->maps[i]; + struct map *map; + + pthread_rwlock_rdlock(&maps->lock); + + for (map = maps__first(maps); map; map = map__next(map)) { + err = unwind__prepare_access(thread, map, &initialized); + if (err || initialized) + break; + } + + pthread_rwlock_unlock(&maps->lock); + } + + return err; +} + +static int thread__prepare_access(struct thread *thread) +{ + int err = 0; + + if (symbol_conf.use_callchain) + err = __thread__prepare_access(thread); + + return err; +} + static int thread__clone_map_groups(struct thread *thread, struct thread *parent) { @@ -219,7 +252,7 @@ static int thread__clone_map_groups(struct thread *thread, /* This is new thread, we share map groups for process. */ if (thread->pid_ == parent->pid_) - return 0; + return thread__prepare_access(thread); if (thread->mg == parent->mg) { pr_debug("broken map groups on thread %d/%d parent %d/%d\n", @@ -229,7 +262,7 @@ static int thread__clone_map_groups(struct thread *thread, /* But this one is new process, copy maps. */ for (i = 0; i < MAP__NR_TYPES; ++i) - if (map_groups__clone(thread->mg, parent->mg, i) < 0) + if (map_groups__clone(thread, parent->mg, i) < 0) return -ENOMEM; return 0; -- cgit v0.10.2 From 203d1cacaddfc1e320f1e2625502fd1e0de465bd Mon Sep 17 00:00:00 2001 From: Wang Nan Date: Mon, 4 Jul 2016 11:02:42 +0000 Subject: tools lib bpf: Add license header Adding a missing license descriptopn header to files in libbpf, make it LGPL-2.1. Signed-off-by: Wang Nan Cc: Alexei Starovoitov Cc: Daniel Borkmann Cc: Eric Leblond Cc: Zefan Li Cc: pi3orama@163.com Link: http://lkml.kernel.org/r/1467630162-193121-1-git-send-email-wangnan0@huawei.com Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/lib/bpf/bpf.c b/tools/lib/bpf/bpf.c index 1f91cc9..4212ed6 100644 --- a/tools/lib/bpf/bpf.c +++ b/tools/lib/bpf/bpf.c @@ -4,6 +4,19 @@ * Copyright (C) 2013-2015 Alexei Starovoitov * Copyright (C) 2015 Wang Nan * Copyright (C) 2015 Huawei Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License (not later!) + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see */ #include diff --git a/tools/lib/bpf/bpf.h b/tools/lib/bpf/bpf.h index a764655..e8ba540 100644 --- a/tools/lib/bpf/bpf.h +++ b/tools/lib/bpf/bpf.h @@ -4,6 +4,19 @@ * Copyright (C) 2013-2015 Alexei Starovoitov * Copyright (C) 2015 Wang Nan * Copyright (C) 2015 Huawei Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License (not later!) + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see */ #ifndef __BPF_BPF_H #define __BPF_BPF_H diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c index a7cb40a..3dcda9e 100644 --- a/tools/lib/bpf/libbpf.c +++ b/tools/lib/bpf/libbpf.c @@ -4,6 +4,19 @@ * Copyright (C) 2013-2015 Alexei Starovoitov * Copyright (C) 2015 Wang Nan * Copyright (C) 2015 Huawei Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License (not later!) + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see */ #include diff --git a/tools/lib/bpf/libbpf.h b/tools/lib/bpf/libbpf.h index 148df36..f392c5e 100644 --- a/tools/lib/bpf/libbpf.h +++ b/tools/lib/bpf/libbpf.h @@ -4,6 +4,19 @@ * Copyright (C) 2013-2015 Alexei Starovoitov * Copyright (C) 2015 Wang Nan * Copyright (C) 2015 Huawei Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License (not later!) + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see */ #ifndef __BPF_LIBBPF_H #define __BPF_LIBBPF_H -- cgit v0.10.2 From b983d54473344a9ef524a231943478047a779796 Mon Sep 17 00:00:00 2001 From: Chris Phlipot Date: Thu, 30 Jun 2016 22:12:32 -0700 Subject: tools lib api: Respect WERROR=0 for build This enables the workaround for compilers that generate warnings when compiling libapi. Signed-off-by: Chris Phlipot Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1467349955-1135-2-git-send-email-cphlipot0@gmail.com Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/lib/api/Makefile b/tools/lib/api/Makefile index 67ff93e..c7ceea6 100644 --- a/tools/lib/api/Makefile +++ b/tools/lib/api/Makefile @@ -17,7 +17,13 @@ MAKEFLAGS += --no-print-directory LIBFILE = $(OUTPUT)libapi.a CFLAGS := $(EXTRA_WARNINGS) $(EXTRA_CFLAGS) -CFLAGS += -ggdb3 -Wall -Wextra -std=gnu99 -Werror -O6 -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=2 -fPIC +CFLAGS += -ggdb3 -Wall -Wextra -std=gnu99 -O6 -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=2 -fPIC + +# Treat warnings as errors unless directed not to +ifneq ($(WERROR),0) + CFLAGS += -Werror +endif + CFLAGS += -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 CFLAGS += -I$(srctree)/tools/lib/api -- cgit v0.10.2 From fd01d06ae33be63cff7d133e650cd1eb32f1d548 Mon Sep 17 00:00:00 2001 From: Chris Phlipot Date: Thu, 30 Jun 2016 22:12:33 -0700 Subject: tools lib subcmd: Respect WERROR=0 for build this enables the workaround for compilers that generate warnings when compiling libsubcmd. Signed-off-by: Chris Phlipot Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1467349955-1135-3-git-send-email-cphlipot0@gmail.com Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/lib/subcmd/Makefile b/tools/lib/subcmd/Makefile index a810370..ce4b7e5 100644 --- a/tools/lib/subcmd/Makefile +++ b/tools/lib/subcmd/Makefile @@ -19,7 +19,13 @@ MAKEFLAGS += --no-print-directory LIBFILE = $(OUTPUT)libsubcmd.a CFLAGS := $(EXTRA_WARNINGS) $(EXTRA_CFLAGS) -CFLAGS += -ggdb3 -Wall -Wextra -std=gnu99 -Werror -O6 -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=2 -fPIC +CFLAGS += -ggdb3 -Wall -Wextra -std=gnu99 -O6 -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=2 -fPIC + +# Treat warnings as errors unless directed not to +ifneq ($(WERROR),0) + CFLAGS += -Werror +endif + CFLAGS += -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE CFLAGS += -I$(srctree)/tools/include/ -- cgit v0.10.2 From 3d0376113ed9cf92b86885bf5102944b61523f5b Mon Sep 17 00:00:00 2001 From: Chris Phlipot Date: Thu, 30 Jun 2016 22:12:35 -0700 Subject: perf tools: Update android build documentation Update the android build documentation according to recent android build fixes. The instructions for step 1a and step 2 were updated to work with NDK version 11(oldest supported version) and NDK version 12(current version). Signed-off-by: Chris Phlipot Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1467349955-1135-5-git-send-email-cphlipot0@gmail.com Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/Documentation/android.txt b/tools/perf/Documentation/android.txt index 8484c3a..24a5999 100644 --- a/tools/perf/Documentation/android.txt +++ b/tools/perf/Documentation/android.txt @@ -12,14 +12,14 @@ Set the NDK variable to point to the path where you installed the NDK: 2. Set cross-compiling environment variables for NDK toolchain and sysroot. For arm: - export NDK_TOOLCHAIN=${NDK}/toolchains/arm-linux-androideabi-4.6/prebuilt/linux-x86/bin/arm-linux-androideabi- - export NDK_SYSROOT=${NDK}/platforms/android-9/arch-arm + export NDK_TOOLCHAIN=${NDK}/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64/bin/arm-linux-androideabi- + export NDK_SYSROOT=${NDK}/platforms/android-24/arch-arm For x86: - export NDK_TOOLCHAIN=${NDK}/toolchains/x86-4.6/prebuilt/linux-x86/bin/i686-linux-android- - export NDK_SYSROOT=${NDK}/platforms/android-9/arch-x86 + export NDK_TOOLCHAIN=${NDK}/toolchains/x86-4.9/prebuilt/linux-x86_64/bin/i686-linux-android- + export NDK_SYSROOT=${NDK}/platforms/android-24/arch-x86 -This method is not working for Android NDK versions up to Revision 8b. -perf uses some bionic enhancements that are not included in these NDK versions. +This method is only tested for Android NDK versions Revision 11b and later. +perf uses some bionic enhancements that are not included in prior NDK versions. You can use method (b) described below instead. (b). Use the Android source tree @@ -49,9 +49,9 @@ II. Compile perf for Android ------------------------------------------------ You need to run make with the NDK toolchain and sysroot defined above: For arm: - make ARCH=arm CROSS_COMPILE=${NDK_TOOLCHAIN} CFLAGS="--sysroot=${NDK_SYSROOT}" + make WERROR=0 ARCH=arm CROSS_COMPILE=${NDK_TOOLCHAIN} EXTRA_CFLAGS="-pie --sysroot=${NDK_SYSROOT}" For x86: - make ARCH=x86 CROSS_COMPILE=${NDK_TOOLCHAIN} CFLAGS="--sysroot=${NDK_SYSROOT}" + make WERROR=0 ARCH=x86 CROSS_COMPILE=${NDK_TOOLCHAIN} EXTRA_CFLAGS="-pie --sysroot=${NDK_SYSROOT}" III. Install perf ----------------------------------------------- -- cgit v0.10.2 From eacc48ce3accfc9092594794b009a40f91331b0e Mon Sep 17 00:00:00 2001 From: Alison Schofield Date: Mon, 4 Jul 2016 12:19:28 -0700 Subject: hwmon: (jc42) Add I2C_CLASS_HWMON to detection class In 2011, commit 774466add7c ("hwmon: (jc42) Change detection class") changed the detection class of these chips to I2C_CLASS_SPD based on this premise: "makes more sense because these chips always live on memory modules" Today these chips have applications beyond memory modules. Examples are JC42.4 compatible chips such as MCP9804 and MCP9808, but also MCP9805, which is marked as JC42.4 compliant and suggested for use not only for DIMMS, but also as generic temperature sensor. Add I2C_CLASS_HWMON as an additional detection class to allow detection by hwmon class i2c adapters. Signed-off-by: Alison Schofield Cc: Daniel Baluta [groeck: Updated description] Signed-off-by: Guenter Roeck diff --git a/drivers/hwmon/jc42.c b/drivers/hwmon/jc42.c index f67c1bb..d9c4f78 100644 --- a/drivers/hwmon/jc42.c +++ b/drivers/hwmon/jc42.c @@ -542,7 +542,7 @@ static const struct i2c_device_id jc42_id[] = { MODULE_DEVICE_TABLE(i2c, jc42_id); static struct i2c_driver jc42_driver = { - .class = I2C_CLASS_SPD, + .class = I2C_CLASS_SPD | I2C_CLASS_HWMON, .driver = { .name = "jc42", .pm = JC42_DEV_PM_OPS, -- cgit v0.10.2 From f3d082ceabe53177c98bfa4580a294c2844966e8 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Mon, 4 Jul 2016 20:29:40 -0300 Subject: perf tools: Sync copy of syscall_64.tbl with the kernel MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Noticed by the build system, that emitted this warning: Warning: x86_64's syscall_64.tbl differs from kernel This was due to the wiring up of the recently added preadv2 & pwritev2 syscalls to the compat code, which hadn't been done by the patch introducing those syscalls: 4babf2c5efb7 ("x86: wire up preadv2 and pwritev2"). The patch doing the compat wiring was: 482dd2ef1244 ("x86/syscalls: Wire up compat readv2/writev2 syscalls") This just silences the perf build warning, as compat syscalls still can't be supported in 'perf trace´ due to limitations in the raw_syscalls:sys_{enter,exit} tracepoints it relies on. Reported-by: Ingo Molnar Cc: Adrian Hunter Cc: Christoph Hellwig Cc: David Ahern Cc: Jiri Olsa Cc: Milian Wolff Cc: Namhyung Kim Cc: Wang Nan Link: http://lkml.kernel.org/n/tip-4dm8eoy0wslgtwqdhz64ods0@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/arch/x86/entry/syscalls/syscall_64.tbl b/tools/perf/arch/x86/entry/syscalls/syscall_64.tbl index cac6d17..555263e 100644 --- a/tools/perf/arch/x86/entry/syscalls/syscall_64.tbl +++ b/tools/perf/arch/x86/entry/syscalls/syscall_64.tbl @@ -374,3 +374,5 @@ 543 x32 io_setup compat_sys_io_setup 544 x32 io_submit compat_sys_io_submit 545 x32 execveat compat_sys_execveat/ptregs +534 x32 preadv2 compat_sys_preadv2 +535 x32 pwritev2 compat_sys_pwritev2 -- cgit v0.10.2 From a788a4a040e003574b8ad17115706ab1601ec572 Mon Sep 17 00:00:00 2001 From: Christophe Jaillet Date: Mon, 4 Jul 2016 07:46:42 +0200 Subject: fsl/fman: fix error handling This is likely that checking 'fman->fifo_offset' instead of 'fman->cam_offset' is expected here. Signed-off-by: Christophe JAILLET Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/freescale/fman/fman.c b/drivers/net/ethernet/freescale/fman/fman.c index 1de2e1e..f634e769 100644 --- a/drivers/net/ethernet/freescale/fman/fman.c +++ b/drivers/net/ethernet/freescale/fman/fman.c @@ -2036,7 +2036,7 @@ static int fman_init(struct fman *fman) /* allocate MURAM for FIFO according to total size */ fman->fifo_offset = fman_muram_alloc(fman->muram, fman->state->total_fifo_size); - if (IS_ERR_VALUE(fman->cam_offset)) { + if (IS_ERR_VALUE(fman->fifo_offset)) { free_init_resources(fman); dev_err(fman->dev, "%s: MURAM alloc for BMI FIFO failed\n", __func__); -- cgit v0.10.2 From c8e2ca30fdba613c088ab2fd5ac7b9c69b402559 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Mon, 4 Jul 2016 17:16:41 -0700 Subject: Revert "fsl/fman: fix error handling" This reverts commit a788a4a040e003574b8ad17115706ab1601ec572. This patch is wrong, the type returned doesn't fit what the error pointer macros expect. Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/freescale/fman/fman.c b/drivers/net/ethernet/freescale/fman/fman.c index f634e769..1de2e1e 100644 --- a/drivers/net/ethernet/freescale/fman/fman.c +++ b/drivers/net/ethernet/freescale/fman/fman.c @@ -2036,7 +2036,7 @@ static int fman_init(struct fman *fman) /* allocate MURAM for FIFO according to total size */ fman->fifo_offset = fman_muram_alloc(fman->muram, fman->state->total_fifo_size); - if (IS_ERR_VALUE(fman->fifo_offset)) { + if (IS_ERR_VALUE(fman->cam_offset)) { free_init_resources(fman); dev_err(fman->dev, "%s: MURAM alloc for BMI FIFO failed\n", __func__); -- cgit v0.10.2 From 7831b4ff0d926e0deeaabef9db8800ed069a2757 Mon Sep 17 00:00:00 2001 From: Ursula Braun Date: Mon, 4 Jul 2016 14:07:16 +0200 Subject: qeth: delete napi struct when removing a qeth device A qeth_card contains a napi_struct linked to the net_device during device probing. This struct must be deleted when removing the qeth device, otherwise Panic on oops can occur when qeth devices are repeatedly removed and added. Fixes: a1c3ed4c9ca ("qeth: NAPI support for l2 and l3 discipline") Cc: stable@vger.kernel.org # v2.6.37+ Signed-off-by: Ursula Braun Tested-by: Alexander Klein Signed-off-by: David S. Miller diff --git a/drivers/s390/net/qeth_l2_main.c b/drivers/s390/net/qeth_l2_main.c index 80b1979..df036b8 100644 --- a/drivers/s390/net/qeth_l2_main.c +++ b/drivers/s390/net/qeth_l2_main.c @@ -1051,6 +1051,7 @@ static void qeth_l2_remove_device(struct ccwgroup_device *cgdev) qeth_l2_set_offline(cgdev); if (card->dev) { + netif_napi_del(&card->napi); unregister_netdev(card->dev); card->dev = NULL; } diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c index ac54433..709b523 100644 --- a/drivers/s390/net/qeth_l3_main.c +++ b/drivers/s390/net/qeth_l3_main.c @@ -3226,6 +3226,7 @@ static void qeth_l3_remove_device(struct ccwgroup_device *cgdev) qeth_l3_set_offline(cgdev); if (card->dev) { + netif_napi_del(&card->napi); unregister_netdev(card->dev); card->dev = NULL; } -- cgit v0.10.2 From 3b8e64f6f8e2d437b15572f445b1932a45f9be6a Mon Sep 17 00:00:00 2001 From: Peter Chen Date: Tue, 5 Jul 2016 10:04:53 +0800 Subject: gpu: drm: sun4i_drv: add missing of_node_put after calling of_parse_phandle of_node_put needs to be called when the device node which is got from of_parse_phandle has finished using. Cc: Maxime Ripard Cc: Chen-Yu Tsai Signed-off-by: Peter Chen Signed-off-by: Maxime Ripard diff --git a/drivers/gpu/drm/sun4i/sun4i_drv.c b/drivers/gpu/drm/sun4i/sun4i_drv.c index cbe4a25..937394c 100644 --- a/drivers/gpu/drm/sun4i/sun4i_drv.c +++ b/drivers/gpu/drm/sun4i/sun4i_drv.c @@ -310,6 +310,7 @@ static int sun4i_drv_probe(struct platform_device *pdev) count += sun4i_drv_add_endpoints(&pdev->dev, &match, pipeline); + of_node_put(pipeline); DRM_DEBUG_DRIVER("Queued %d outputs on pipeline %d\n", count, i); -- cgit v0.10.2 From 9cd25743765cfe851aed8d655a62d60156aed293 Mon Sep 17 00:00:00 2001 From: Torsten Hilbrich Date: Tue, 5 Jul 2016 10:40:22 +0200 Subject: ALSA: hda/realtek: Add Lenovo L460 to docking unit fixup This solves the issue that a headphone is not working on the docking unit. Signed-off-by: Torsten Hilbrich Cc: Signed-off-by: Takashi Iwai diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 900bfbc..5fac786 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -5651,6 +5651,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x17aa, 0x504a, "ThinkPad X260", ALC292_FIXUP_TPT440_DOCK), SND_PCI_QUIRK(0x17aa, 0x504b, "Thinkpad", ALC293_FIXUP_LENOVO_SPK_NOISE), SND_PCI_QUIRK(0x17aa, 0x5050, "Thinkpad T560p", ALC292_FIXUP_TPT460), + SND_PCI_QUIRK(0x17aa, 0x5051, "Thinkpad L460", ALC292_FIXUP_TPT460), SND_PCI_QUIRK(0x17aa, 0x5053, "Thinkpad T460", ALC292_FIXUP_TPT460), SND_PCI_QUIRK(0x17aa, 0x5109, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), SND_PCI_QUIRK(0x17aa, 0x3bf8, "Quanta FL1", ALC269_FIXUP_PCM_44K), -- cgit v0.10.2 From 10c78f5854d361ded4736c1831948e0a5f67b932 Mon Sep 17 00:00:00 2001 From: Sven Eckelmann Date: Sat, 2 Jul 2016 09:52:13 +0200 Subject: batman-adv: Avoid nullptr dereference in bla after vlan_insert_tag vlan_insert_tag can return NULL on errors. The bridge loop avoidance code therefore has to check the return value of vlan_insert_tag for NULL before it can safely operate on this pointer. Fixes: 23721387c409 ("batman-adv: add basic bridge loop avoidance code") Signed-off-by: Sven Eckelmann Signed-off-by: Marek Lindner Signed-off-by: Simon Wunderlich diff --git a/net/batman-adv/bridge_loop_avoidance.c b/net/batman-adv/bridge_loop_avoidance.c index 748a9ea..7129780 100644 --- a/net/batman-adv/bridge_loop_avoidance.c +++ b/net/batman-adv/bridge_loop_avoidance.c @@ -418,9 +418,12 @@ static void batadv_bla_send_claim(struct batadv_priv *bat_priv, u8 *mac, break; } - if (vid & BATADV_VLAN_HAS_TAG) + if (vid & BATADV_VLAN_HAS_TAG) { skb = vlan_insert_tag(skb, htons(ETH_P_8021Q), vid & VLAN_VID_MASK); + if (!skb) + goto out; + } skb_reset_mac_header(skb); skb->protocol = eth_type_trans(skb, soft_iface); -- cgit v0.10.2 From 60154a1e0495ffb8343a95cefe1e874634572fa8 Mon Sep 17 00:00:00 2001 From: Sven Eckelmann Date: Sat, 2 Jul 2016 09:52:14 +0200 Subject: batman-adv: Avoid nullptr dereference in dat after vlan_insert_tag vlan_insert_tag can return NULL on errors. The distributed arp table code therefore has to check the return value of vlan_insert_tag for NULL before it can safely operate on this pointer. Fixes: be1db4f6615b ("batman-adv: make the Distributed ARP Table vlan aware") Signed-off-by: Sven Eckelmann Signed-off-by: Marek Lindner Signed-off-by: Simon Wunderlich diff --git a/net/batman-adv/distributed-arp-table.c b/net/batman-adv/distributed-arp-table.c index 278800a..aee3b39 100644 --- a/net/batman-adv/distributed-arp-table.c +++ b/net/batman-adv/distributed-arp-table.c @@ -1009,9 +1009,12 @@ bool batadv_dat_snoop_outgoing_arp_request(struct batadv_priv *bat_priv, if (!skb_new) goto out; - if (vid & BATADV_VLAN_HAS_TAG) + if (vid & BATADV_VLAN_HAS_TAG) { skb_new = vlan_insert_tag(skb_new, htons(ETH_P_8021Q), vid & VLAN_VID_MASK); + if (!skb_new) + goto out; + } skb_reset_mac_header(skb_new); skb_new->protocol = eth_type_trans(skb_new, @@ -1089,9 +1092,12 @@ bool batadv_dat_snoop_incoming_arp_request(struct batadv_priv *bat_priv, */ skb_reset_mac_header(skb_new); - if (vid & BATADV_VLAN_HAS_TAG) + if (vid & BATADV_VLAN_HAS_TAG) { skb_new = vlan_insert_tag(skb_new, htons(ETH_P_8021Q), vid & VLAN_VID_MASK); + if (!skb_new) + goto out; + } /* To preserve backwards compatibility, the node has choose the outgoing * format based on the incoming request packet type. The assumption is -- cgit v0.10.2 From 33fbb1f3db87ce53da925b3e034b4dd446d483f8 Mon Sep 17 00:00:00 2001 From: Sven Eckelmann Date: Thu, 30 Jun 2016 20:10:46 +0200 Subject: batman-adv: Fix orig_node_vlan leak on orig_node_release batadv_orig_node_new uses batadv_orig_node_vlan_new to allocate a new batadv_orig_node_vlan and add it to batadv_orig_node::vlan_list. References to this list have also to be cleaned when the batadv_orig_node is removed. Fixes: 7ea7b4a14275 ("batman-adv: make the TT CRC logic VLAN specific") Signed-off-by: Sven Eckelmann Signed-off-by: Marek Lindner Signed-off-by: Simon Wunderlich diff --git a/net/batman-adv/originator.c b/net/batman-adv/originator.c index 7f51bc2..fe2fcda 100644 --- a/net/batman-adv/originator.c +++ b/net/batman-adv/originator.c @@ -765,6 +765,7 @@ static void batadv_orig_node_release(struct kref *ref) struct batadv_neigh_node *neigh_node; struct batadv_orig_node *orig_node; struct batadv_orig_ifinfo *orig_ifinfo; + struct batadv_orig_node_vlan *vlan; orig_node = container_of(ref, struct batadv_orig_node, refcount); @@ -784,6 +785,13 @@ static void batadv_orig_node_release(struct kref *ref) } spin_unlock_bh(&orig_node->neigh_list_lock); + spin_lock_bh(&orig_node->vlan_list_lock); + hlist_for_each_entry_safe(vlan, node_tmp, &orig_node->vlan_list, list) { + hlist_del_rcu(&vlan->list); + batadv_orig_node_vlan_put(vlan); + } + spin_unlock_bh(&orig_node->vlan_list_lock); + /* Free nc_nodes */ batadv_nc_purge_orig(orig_node->bat_priv, orig_node, NULL); -- cgit v0.10.2 From 3db0decf1185357d6ab2256d0dede1ca9efda03d Mon Sep 17 00:00:00 2001 From: Sven Eckelmann Date: Fri, 1 Jul 2016 15:49:43 +0200 Subject: batman-adv: Fix non-atomic bla_claim::backbone_gw access The pointer batadv_bla_claim::backbone_gw can be changed at any time. Therefore, access to it must be protected to ensure that two function accessing the same backbone_gw are actually accessing the same. This is especially important when the crc_lock is used or when the backbone_gw of a claim is exchanged. Not doing so leads to invalid memory access and/or reference leaks. Fixes: 23721387c409 ("batman-adv: add basic bridge loop avoidance code") Fixes: 5a1dd8a4773d ("batman-adv: lock crc access in bridge loop avoidance") Signed-off-by: Sven Eckelmann Signed-off-by: Marek Lindner Signed-off-by: Simon Wunderlich diff --git a/net/batman-adv/bridge_loop_avoidance.c b/net/batman-adv/bridge_loop_avoidance.c index 7129780..825a5cd 100644 --- a/net/batman-adv/bridge_loop_avoidance.c +++ b/net/batman-adv/bridge_loop_avoidance.c @@ -177,10 +177,21 @@ static void batadv_backbone_gw_put(struct batadv_bla_backbone_gw *backbone_gw) static void batadv_claim_release(struct kref *ref) { struct batadv_bla_claim *claim; + struct batadv_bla_backbone_gw *old_backbone_gw; claim = container_of(ref, struct batadv_bla_claim, refcount); - batadv_backbone_gw_put(claim->backbone_gw); + spin_lock_bh(&claim->backbone_lock); + old_backbone_gw = claim->backbone_gw; + claim->backbone_gw = NULL; + spin_unlock_bh(&claim->backbone_lock); + + spin_lock_bh(&old_backbone_gw->crc_lock); + old_backbone_gw->crc ^= crc16(0, claim->addr, ETH_ALEN); + spin_unlock_bh(&old_backbone_gw->crc_lock); + + batadv_backbone_gw_put(old_backbone_gw); + kfree_rcu(claim, rcu); } @@ -677,8 +688,10 @@ static void batadv_bla_add_claim(struct batadv_priv *bat_priv, const u8 *mac, const unsigned short vid, struct batadv_bla_backbone_gw *backbone_gw) { + struct batadv_bla_backbone_gw *old_backbone_gw; struct batadv_bla_claim *claim; struct batadv_bla_claim search_claim; + bool remove_crc = false; int hash_added; ether_addr_copy(search_claim.addr, mac); @@ -692,8 +705,10 @@ static void batadv_bla_add_claim(struct batadv_priv *bat_priv, return; ether_addr_copy(claim->addr, mac); + spin_lock_init(&claim->backbone_lock); claim->vid = vid; claim->lasttime = jiffies; + kref_get(&backbone_gw->refcount); claim->backbone_gw = backbone_gw; kref_init(&claim->refcount); @@ -721,15 +736,26 @@ static void batadv_bla_add_claim(struct batadv_priv *bat_priv, "bla_add_claim(): changing ownership for %pM, vid %d\n", mac, BATADV_PRINT_VID(vid)); - spin_lock_bh(&claim->backbone_gw->crc_lock); - claim->backbone_gw->crc ^= crc16(0, claim->addr, ETH_ALEN); - spin_unlock_bh(&claim->backbone_gw->crc_lock); - batadv_backbone_gw_put(claim->backbone_gw); + remove_crc = true; } - /* set (new) backbone gw */ + + /* replace backbone_gw atomically and adjust reference counters */ + spin_lock_bh(&claim->backbone_lock); + old_backbone_gw = claim->backbone_gw; kref_get(&backbone_gw->refcount); claim->backbone_gw = backbone_gw; + spin_unlock_bh(&claim->backbone_lock); + + if (remove_crc) { + /* remove claim address from old backbone_gw */ + spin_lock_bh(&old_backbone_gw->crc_lock); + old_backbone_gw->crc ^= crc16(0, claim->addr, ETH_ALEN); + spin_unlock_bh(&old_backbone_gw->crc_lock); + } + batadv_backbone_gw_put(old_backbone_gw); + + /* add claim address to new backbone_gw */ spin_lock_bh(&backbone_gw->crc_lock); backbone_gw->crc ^= crc16(0, claim->addr, ETH_ALEN); spin_unlock_bh(&backbone_gw->crc_lock); @@ -740,6 +766,26 @@ claim_free_ref: } /** + * batadv_bla_claim_get_backbone_gw - Get valid reference for backbone_gw of + * claim + * @claim: claim whose backbone_gw should be returned + * + * Return: valid reference to claim::backbone_gw + */ +static struct batadv_bla_backbone_gw * +batadv_bla_claim_get_backbone_gw(struct batadv_bla_claim *claim) +{ + struct batadv_bla_backbone_gw *backbone_gw; + + spin_lock_bh(&claim->backbone_lock); + backbone_gw = claim->backbone_gw; + kref_get(&backbone_gw->refcount); + spin_unlock_bh(&claim->backbone_lock); + + return backbone_gw; +} + +/** * batadv_bla_del_claim - delete a claim from the claim hash * @bat_priv: the bat priv with all the soft interface information * @mac: mac address of the claim to be removed @@ -763,10 +809,6 @@ static void batadv_bla_del_claim(struct batadv_priv *bat_priv, batadv_choose_claim, claim); batadv_claim_put(claim); /* reference from the hash is gone */ - spin_lock_bh(&claim->backbone_gw->crc_lock); - claim->backbone_gw->crc ^= crc16(0, claim->addr, ETH_ALEN); - spin_unlock_bh(&claim->backbone_gw->crc_lock); - /* don't need the reference from hash_find() anymore */ batadv_claim_put(claim); } @@ -1219,6 +1261,7 @@ static void batadv_bla_purge_claims(struct batadv_priv *bat_priv, struct batadv_hard_iface *primary_if, int now) { + struct batadv_bla_backbone_gw *backbone_gw; struct batadv_bla_claim *claim; struct hlist_head *head; struct batadv_hashtable *hash; @@ -1233,14 +1276,17 @@ static void batadv_bla_purge_claims(struct batadv_priv *bat_priv, rcu_read_lock(); hlist_for_each_entry_rcu(claim, head, hash_entry) { + backbone_gw = batadv_bla_claim_get_backbone_gw(claim); if (now) goto purge_now; - if (!batadv_compare_eth(claim->backbone_gw->orig, + + if (!batadv_compare_eth(backbone_gw->orig, primary_if->net_dev->dev_addr)) - continue; + goto skip; + if (!batadv_has_timed_out(claim->lasttime, BATADV_BLA_CLAIM_TIMEOUT)) - continue; + goto skip; batadv_dbg(BATADV_DBG_BLA, bat_priv, "bla_purge_claims(): %pM, vid %d, time out\n", @@ -1248,8 +1294,10 @@ static void batadv_bla_purge_claims(struct batadv_priv *bat_priv, purge_now: batadv_handle_unclaim(bat_priv, primary_if, - claim->backbone_gw->orig, + backbone_gw->orig, claim->addr, claim->vid); +skip: + batadv_backbone_gw_put(backbone_gw); } rcu_read_unlock(); } @@ -1760,9 +1808,11 @@ batadv_bla_loopdetect_check(struct batadv_priv *bat_priv, struct sk_buff *skb, bool batadv_bla_rx(struct batadv_priv *bat_priv, struct sk_buff *skb, unsigned short vid, bool is_bcast) { + struct batadv_bla_backbone_gw *backbone_gw; struct ethhdr *ethhdr; struct batadv_bla_claim search_claim, *claim = NULL; struct batadv_hard_iface *primary_if; + bool own_claim; bool ret; ethhdr = eth_hdr(skb); @@ -1797,8 +1847,12 @@ bool batadv_bla_rx(struct batadv_priv *bat_priv, struct sk_buff *skb, } /* if it is our own claim ... */ - if (batadv_compare_eth(claim->backbone_gw->orig, - primary_if->net_dev->dev_addr)) { + backbone_gw = batadv_bla_claim_get_backbone_gw(claim); + own_claim = batadv_compare_eth(backbone_gw->orig, + primary_if->net_dev->dev_addr); + batadv_backbone_gw_put(backbone_gw); + + if (own_claim) { /* ... allow it in any case */ claim->lasttime = jiffies; goto allow; @@ -1862,7 +1916,9 @@ bool batadv_bla_tx(struct batadv_priv *bat_priv, struct sk_buff *skb, { struct ethhdr *ethhdr; struct batadv_bla_claim search_claim, *claim = NULL; + struct batadv_bla_backbone_gw *backbone_gw; struct batadv_hard_iface *primary_if; + bool client_roamed; bool ret = false; primary_if = batadv_primary_if_get_selected(bat_priv); @@ -1892,8 +1948,12 @@ bool batadv_bla_tx(struct batadv_priv *bat_priv, struct sk_buff *skb, goto allow; /* check if we are responsible. */ - if (batadv_compare_eth(claim->backbone_gw->orig, - primary_if->net_dev->dev_addr)) { + backbone_gw = batadv_bla_claim_get_backbone_gw(claim); + client_roamed = batadv_compare_eth(backbone_gw->orig, + primary_if->net_dev->dev_addr); + batadv_backbone_gw_put(backbone_gw); + + if (client_roamed) { /* if yes, the client has roamed and we have * to unclaim it. */ @@ -1941,6 +2001,7 @@ int batadv_bla_claim_table_seq_print_text(struct seq_file *seq, void *offset) struct net_device *net_dev = (struct net_device *)seq->private; struct batadv_priv *bat_priv = netdev_priv(net_dev); struct batadv_hashtable *hash = bat_priv->bla.claim_hash; + struct batadv_bla_backbone_gw *backbone_gw; struct batadv_bla_claim *claim; struct batadv_hard_iface *primary_if; struct hlist_head *head; @@ -1965,17 +2026,21 @@ int batadv_bla_claim_table_seq_print_text(struct seq_file *seq, void *offset) rcu_read_lock(); hlist_for_each_entry_rcu(claim, head, hash_entry) { - is_own = batadv_compare_eth(claim->backbone_gw->orig, + backbone_gw = batadv_bla_claim_get_backbone_gw(claim); + + is_own = batadv_compare_eth(backbone_gw->orig, primary_addr); - spin_lock_bh(&claim->backbone_gw->crc_lock); - backbone_crc = claim->backbone_gw->crc; - spin_unlock_bh(&claim->backbone_gw->crc_lock); + spin_lock_bh(&backbone_gw->crc_lock); + backbone_crc = backbone_gw->crc; + spin_unlock_bh(&backbone_gw->crc_lock); seq_printf(seq, " * %pM on %5d by %pM [%c] (%#.4x)\n", claim->addr, BATADV_PRINT_VID(claim->vid), - claim->backbone_gw->orig, + backbone_gw->orig, (is_own ? 'x' : ' '), backbone_crc); + + batadv_backbone_gw_put(backbone_gw); } rcu_read_unlock(); } diff --git a/net/batman-adv/types.h b/net/batman-adv/types.h index ba846b0..0051222 100644 --- a/net/batman-adv/types.h +++ b/net/batman-adv/types.h @@ -1042,6 +1042,7 @@ struct batadv_bla_backbone_gw { * @addr: mac address of claimed non-mesh client * @vid: vlan id this client was detected on * @backbone_gw: pointer to backbone gw claiming this client + * @backbone_lock: lock protecting backbone_gw pointer * @lasttime: last time we heard of claim (locals only) * @hash_entry: hlist node for batadv_priv_bla::claim_hash * @refcount: number of contexts the object is used @@ -1051,6 +1052,7 @@ struct batadv_bla_claim { u8 addr[ETH_ALEN]; unsigned short vid; struct batadv_bla_backbone_gw *backbone_gw; + spinlock_t backbone_lock; /* protects backbone_gw */ unsigned long lasttime; struct hlist_node hash_entry; struct rcu_head rcu; -- cgit v0.10.2 From 15c2ed753cd9e3e746472deab8151337a5b6da56 Mon Sep 17 00:00:00 2001 From: Sven Eckelmann Date: Thu, 30 Jun 2016 20:11:34 +0200 Subject: batman-adv: Fix reference leak in batadv_find_router The replacement of last_bonding_candidate in batadv_orig_node has to be an atomic operation. Otherwise it is possible that the reference counter of a batadv_orig_ifinfo is reduced which was no longer the last_bonding_candidate when the new candidate is added. This can either lead to an invalid memory access or to reference leaks which make it impossible to an interface which was added to batman-adv. Fixes: f3b3d9018975 ("batman-adv: add bonding again") Signed-off-by: Sven Eckelmann Signed-off-by: Marek Lindner Signed-off-by: Simon Wunderlich diff --git a/net/batman-adv/routing.c b/net/batman-adv/routing.c index 6c2901a..bfac086 100644 --- a/net/batman-adv/routing.c +++ b/net/batman-adv/routing.c @@ -456,6 +456,29 @@ static int batadv_check_unicast_packet(struct batadv_priv *bat_priv, } /** + * batadv_last_bonding_replace - Replace last_bonding_candidate of orig_node + * @orig_node: originator node whose bonding candidates should be replaced + * @new_candidate: new bonding candidate or NULL + */ +static void +batadv_last_bonding_replace(struct batadv_orig_node *orig_node, + struct batadv_orig_ifinfo *new_candidate) +{ + struct batadv_orig_ifinfo *old_candidate; + + spin_lock_bh(&orig_node->neigh_list_lock); + old_candidate = orig_node->last_bonding_candidate; + + if (new_candidate) + kref_get(&new_candidate->refcount); + orig_node->last_bonding_candidate = new_candidate; + spin_unlock_bh(&orig_node->neigh_list_lock); + + if (old_candidate) + batadv_orig_ifinfo_put(old_candidate); +} + +/** * batadv_find_router - find a suitable router for this originator * @bat_priv: the bat priv with all the soft interface information * @orig_node: the destination node @@ -562,10 +585,6 @@ next: } rcu_read_unlock(); - /* last_bonding_candidate is reset below, remove the old reference. */ - if (orig_node->last_bonding_candidate) - batadv_orig_ifinfo_put(orig_node->last_bonding_candidate); - /* After finding candidates, handle the three cases: * 1) there is a next candidate, use that * 2) there is no next candidate, use the first of the list @@ -574,21 +593,28 @@ next: if (next_candidate) { batadv_neigh_node_put(router); - /* remove references to first candidate, we don't need it. */ - if (first_candidate) { - batadv_neigh_node_put(first_candidate_router); - batadv_orig_ifinfo_put(first_candidate); - } + kref_get(&next_candidate_router->refcount); router = next_candidate_router; - orig_node->last_bonding_candidate = next_candidate; + batadv_last_bonding_replace(orig_node, next_candidate); } else if (first_candidate) { batadv_neigh_node_put(router); - /* refcounting has already been done in the loop above. */ + kref_get(&first_candidate_router->refcount); router = first_candidate_router; - orig_node->last_bonding_candidate = first_candidate; + batadv_last_bonding_replace(orig_node, first_candidate); } else { - orig_node->last_bonding_candidate = NULL; + batadv_last_bonding_replace(orig_node, NULL); + } + + /* cleanup of candidates */ + if (first_candidate) { + batadv_neigh_node_put(first_candidate_router); + batadv_orig_ifinfo_put(first_candidate); + } + + if (next_candidate) { + batadv_neigh_node_put(next_candidate_router); + batadv_orig_ifinfo_put(next_candidate); } return router; diff --git a/net/batman-adv/types.h b/net/batman-adv/types.h index 0051222..74d865a 100644 --- a/net/batman-adv/types.h +++ b/net/batman-adv/types.h @@ -330,7 +330,9 @@ struct batadv_orig_node { DECLARE_BITMAP(bcast_bits, BATADV_TQ_LOCAL_WINDOW_SIZE); u32 last_bcast_seqno; struct hlist_head neigh_list; - /* neigh_list_lock protects: neigh_list and router */ + /* neigh_list_lock protects: neigh_list, ifinfo_list, + * last_bonding_candidate and router + */ spinlock_t neigh_list_lock; struct hlist_node hash_entry; struct batadv_priv *bat_priv; -- cgit v0.10.2 From cbef1e102003edb236c6b2319ab269ccef963731 Mon Sep 17 00:00:00 2001 From: Sven Eckelmann Date: Thu, 30 Jun 2016 21:41:13 +0200 Subject: batman-adv: Free last_bonding_candidate on release of orig_node The orig_ifinfo reference counter for last_bonding_candidate in batadv_orig_node has to be reduced when an originator node is released. Otherwise the orig_ifinfo is leaked and the reference counter the netdevice is not reduced correctly. Fixes: f3b3d9018975 ("batman-adv: add bonding again") Signed-off-by: Sven Eckelmann Signed-off-by: Marek Lindner Signed-off-by: Simon Wunderlich diff --git a/net/batman-adv/originator.c b/net/batman-adv/originator.c index fe2fcda..ab8c4f9 100644 --- a/net/batman-adv/originator.c +++ b/net/batman-adv/originator.c @@ -766,6 +766,7 @@ static void batadv_orig_node_release(struct kref *ref) struct batadv_orig_node *orig_node; struct batadv_orig_ifinfo *orig_ifinfo; struct batadv_orig_node_vlan *vlan; + struct batadv_orig_ifinfo *last_candidate; orig_node = container_of(ref, struct batadv_orig_node, refcount); @@ -783,8 +784,14 @@ static void batadv_orig_node_release(struct kref *ref) hlist_del_rcu(&orig_ifinfo->list); batadv_orig_ifinfo_put(orig_ifinfo); } + + last_candidate = orig_node->last_bonding_candidate; + orig_node->last_bonding_candidate = NULL; spin_unlock_bh(&orig_node->neigh_list_lock); + if (last_candidate) + batadv_orig_ifinfo_put(last_candidate); + spin_lock_bh(&orig_node->vlan_list_lock); hlist_for_each_entry_safe(vlan, node_tmp, &orig_node->vlan_list, list) { hlist_del_rcu(&vlan->list); -- cgit v0.10.2 From 8ca2cf2c8e0d172824ac305391fb4273dd1e3e5a Mon Sep 17 00:00:00 2001 From: Maxime Coquelin Date: Wed, 22 Jun 2016 15:56:58 +0200 Subject: MAINTAINERS: update STM32 maintainers list I will have less time to work on STM32 platform, so I propose Alexandre as co-maintainer. Alex is working in the STMicroelectronics division in charge of STM32 family, so he will have access to all technical information and hardware. Signed-off-by: Maxime Coquelin Cc: Alexandre Torgue Signed-off-by: Arnd Bergmann diff --git a/MAINTAINERS b/MAINTAINERS index e1b090f..d8b5450 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1724,6 +1724,7 @@ F: drivers/ata/ahci_st.c ARM/STM32 ARCHITECTURE M: Maxime Coquelin +M: Alexandre Torgue L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) S: Maintained T: git git://git.kernel.org/pub/scm/linux/kernel/git/mcoquelin/stm32.git -- cgit v0.10.2 From 3867b228d6aed0e916d8d36119b465cb1946bb32 Mon Sep 17 00:00:00 2001 From: Maxime Coquelin Date: Fri, 1 Jul 2016 15:19:56 +0200 Subject: MAINTAINERS: update STi maintainer list Remove myself as STi maintainer as I will no longer have access to STi platforms, and remove Srini too, who now works on other platforms. Patrice will manage the pull requests. Signed-off-by: Maxime Coquelin Cc: Patrice Chotard Cc: Srinivas Kandagatla Cc: Arnd Bergmann Acked-by: Patrice Chotard Acked-by: Srinivas Kandagatla Signed-off-by: Arnd Bergmann diff --git a/MAINTAINERS b/MAINTAINERS index d8b5450..73fcd7e 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1690,8 +1690,6 @@ S: Maintained F: drivers/edac/altera_edac. ARM/STI ARCHITECTURE -M: Srinivas Kandagatla -M: Maxime Coquelin M: Patrice Chotard L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) L: kernel@stlinux.com -- cgit v0.10.2 From 99ec8a3608330d202448085185cf28389b789b7b Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Tue, 5 Jul 2016 14:25:59 +0100 Subject: irqchip/mips-gic: Map to VPs using HW VPNum When mapping an interrupt to a VP(E) we must use the identifier for the VP that the hardware expects, and this does not always match up with the Linux CPU number. Commit d46812bb0bef ("irqchip: mips-gic: Use HW IDs for VPE_OTHER_ADDR") corrected this for the cases that existed at the time it was written, but commit 2af70a962070 ("irqchip/mips-gic: Add a IPI hierarchy domain") added another case before the former patch was merged. This leads to incorrectly using Linux CPU numbers when mapping interrupts to VPs, which breaks on certain systems such as those with multi-core I6400 CPUs. Fix by adding the appropriate call to mips_cm_vp_id() to retrieve the expected VP identifier. Fixes: d46812bb0bef ("irqchip: mips-gic: Use HW IDs for VPE_OTHER_ADDR") Fixes: 2af70a962070 ("irqchip/mips-gic: Add a IPI hierarchy domain") Signed-off-by: Paul Burton Cc: linux-mips@linux-mips.org Cc: Jason Cooper Cc: Qais Yousef Cc: Ralf Baechle Cc: Marc Zyngier Cc: stable@vger.kernel.org Link: http://lkml.kernel.org/r/20160705132600.27730-1-paul.burton@imgtec.com Signed-off-by: Thomas Gleixner diff --git a/drivers/irqchip/irq-mips-gic.c b/drivers/irqchip/irq-mips-gic.c index 8a4adbeb..69b1b82 100644 --- a/drivers/irqchip/irq-mips-gic.c +++ b/drivers/irqchip/irq-mips-gic.c @@ -718,7 +718,7 @@ static int gic_shared_irq_domain_map(struct irq_domain *d, unsigned int virq, spin_lock_irqsave(&gic_lock, flags); gic_map_to_pin(intr, gic_cpu_pin); - gic_map_to_vpe(intr, vpe); + gic_map_to_vpe(intr, mips_cm_vp_id(vpe)); for (i = 0; i < min(gic_vpes, NR_CPUS); i++) clear_bit(intr, pcpu_masks[i].pcpu_mask); set_bit(intr, pcpu_masks[vpe].pcpu_mask); -- cgit v0.10.2 From 547aefc4db877e65245c3d95fcce703701bf3a0c Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Tue, 5 Jul 2016 14:26:00 +0100 Subject: irqchip/mips-gic: Match IPI IRQ domain by bus token only Commit fbde2d7d8290 ("MIPS: Add generic SMP IPI support") introduced code which calls irq_find_matching_host with a NULL node parameter in order to discover IPI IRQ domains which are not associated with the DT root node's interrupt parent. This suggests that implementations of IPI IRQ domains should effectively ignore the node parameter if it is NULL and search purely based upon the bus token. Commit 2af70a962070 ("irqchip/mips-gic: Add a IPI hierarchy domain") did not do this when implementing the GIC IPI IRQ domain, and on MIPS Boston boards this leads to no IPI domain being discovered and a NULL pointer dereference when attempting to send an IPI: CPU 0 Unable to handle kernel paging request at virtual address 0000000000000040, epc == ffffffff8016e70c, ra == ffffffff8010ff5c Oops[#1]: CPU: 0 PID: 1 Comm: swapper/0 Not tainted 4.7.0-rc6-00223-gad0d1b6 #945 task: a8000000ff066fc0 ti: a8000000ff068000 task.ti: a8000000ff068000 $ 0 : 0000000000000000 0000000000000001 ffffffff80730000 0000000000000003 $ 4 : 0000000000000000 ffffffff8057e5b0 a800000001e3ee00 0000000000000000 $ 8 : 0000000000000000 0000000000000023 0000000000000001 0000000000000001 $12 : 0000000000000000 ffffffff803323d0 0000000000000000 0000000000000000 $16 : 0000000000000000 0000000000000000 0000000000000001 ffffffff801108fc $20 : 0000000000000000 ffffffff8057e5b0 0000000000000001 0000000000000000 $24 : 0000000000000000 ffffffff8012de28 $28 : a8000000ff068000 a8000000ff06fbc0 0000000000000000 ffffffff8010ff5c Hi : ffffffff8014c174 Lo : a800000001e1e140 epc : ffffffff8016e70c __ipi_send_mask+0x24/0x11c ra : ffffffff8010ff5c mips_smp_send_ipi_mask+0x68/0x178 Status: 140084e2 KX SX UX KERNEL EXL Cause : 00800008 (ExcCode 02) BadVA : 0000000000000040 PrId : 0001a920 (MIPS I6400) Process swapper/0 (pid: 1, threadinfo=a8000000ff068000, task=a8000000ff066fc0, tls=0000000000000000) Stack : 0000000000000000 0000000000000000 0000000000000001 ffffffff801108fc 0000000000000000 ffffffff8057e5b0 0000000000000001 ffffffff8010ff5c 0000000000000001 0000000000000020 0000000000000000 0000000000000000 0000000000000000 ffffffff801108fc 0000000000000000 0000000000000001 0000000000000001 0000000000000000 0000000000000000 ffffffff801865e8 a8000000ff0c7500 a8000000ff06fc90 0000000000000001 0000000000000002 ffffffff801108fc ffffffff801868b8 0000000000000000 ffffffff801108fc 0000000000000000 0000000000000003 ffffffff8068c700 0000000000000001 ffffffff80730000 0000000000000001 a8000000ff00a290 ffffffff80110c50 0000000000000003 a800000001e48308 0000000000000003 0000000000000008 ... Call Trace: [] __ipi_send_mask+0x24/0x11c [] mips_smp_send_ipi_mask+0x68/0x178 [] generic_exec_single+0x150/0x170 [] smp_call_function_single+0x108/0x160 [] cps_boot_secondary+0x328/0x394 [] __cpu_up+0x38/0x90 [] bringup_cpu+0x24/0xac [] cpuhp_up_callbacks+0x58/0xdc [] cpu_up+0x118/0x18c [] smp_init+0xbc/0xe8 [] kernel_init_freeable+0xa0/0x228 [] kernel_init+0x10/0xf0 [] ret_from_kernel_thread+0x14/0x1c Fix this by allowing the GIC IPI IRQ domain to match purely based upon the bus token if the node provided is NULL. Fixes: 2af70a962070 ("irqchip/mips-gic: Add a IPI hierarchy domain") Signed-off-by: Paul Burton Cc: linux-mips@linux-mips.org Cc: Jason Cooper Cc: Qais Yousef Cc: Ralf Baechle Cc: Marc Zyngier Cc: stable@vger.kernel.org Link: http://lkml.kernel.org/r/20160705132600.27730-2-paul.burton@imgtec.com Signed-off-by: Thomas Gleixner diff --git a/drivers/irqchip/irq-mips-gic.c b/drivers/irqchip/irq-mips-gic.c index 69b1b82..70ed1d0 100644 --- a/drivers/irqchip/irq-mips-gic.c +++ b/drivers/irqchip/irq-mips-gic.c @@ -959,7 +959,7 @@ int gic_ipi_domain_match(struct irq_domain *d, struct device_node *node, switch (bus_token) { case DOMAIN_BUS_IPI: is_ipi = d->bus_token == bus_token; - return to_of_node(d->fwnode) == node && is_ipi; + return (!node || to_of_node(d->fwnode) == node) && is_ipi; break; default: return 0; -- cgit v0.10.2 From 5130213721d01b6632c255d4295a8102cbb58379 Mon Sep 17 00:00:00 2001 From: Jisheng Zhang Date: Tue, 5 Jul 2016 16:57:51 +0800 Subject: tick/broadcast-hrtimer: Set name of the ce_broadcast_hrtimer This is to avoid the "null" name when we either ~ # cat /sys/devices/system/clockevents/broadcast/current_device (null) or ~ # cat /proc/timer_list ... Tick Device: mode: 1 Broadcast device Clock Event Device: (null) ... Signed-off-by: Jisheng Zhang Cc: linux-arm-kernel@lists.infradead.org Link: http://lkml.kernel.org/r/1467709071-3667-1-git-send-email-jszhang@marvell.com Signed-off-by: Thomas Gleixner diff --git a/kernel/time/tick-broadcast-hrtimer.c b/kernel/time/tick-broadcast-hrtimer.c index 53d7184..690b797 100644 --- a/kernel/time/tick-broadcast-hrtimer.c +++ b/kernel/time/tick-broadcast-hrtimer.c @@ -75,6 +75,7 @@ static int bc_set_next(ktime_t expires, struct clock_event_device *bc) } static struct clock_event_device ce_broadcast_hrtimer = { + .name = "bc_hrtimer", .set_state_shutdown = bc_shutdown, .set_next_ktime = bc_set_next, .features = CLOCK_EVT_FEAT_ONESHOT | -- cgit v0.10.2 From eab09988e47f2b4322faa5ee1430d05714e59000 Mon Sep 17 00:00:00 2001 From: Jon Hunter Date: Tue, 14 Jun 2016 21:26:46 +0100 Subject: i2c: tegra: Correct error path in probe Commit 497fbe24987b ("i2c: tegra: enable multi master mode for tegra210") enables the Tegra I2C 'div_clk' for adapters using the multi-master mode during the device probe. Although the probe error path was updated to disable the clock on probe failure, there is one place after calling tegra_i2c_init() where the clock will not be disabled on failure. Correct the error path so that the 'div_clk' is disabled if calling tegra_i2c_init() fails. Fixes: 497fbe24987b ("i2c: tegra: enable multi master mode for tegra210") Signed-off-by: Jon Hunter Acked-by: Laxman Dewangan Signed-off-by: Wolfram Sang diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c index 445398c3..b126dba 100644 --- a/drivers/i2c/busses/i2c-tegra.c +++ b/drivers/i2c/busses/i2c-tegra.c @@ -912,7 +912,7 @@ static int tegra_i2c_probe(struct platform_device *pdev) ret = tegra_i2c_init(i2c_dev); if (ret) { dev_err(&pdev->dev, "Failed to initialize i2c controller"); - goto unprepare_div_clk; + goto disable_div_clk; } ret = devm_request_irq(&pdev->dev, i2c_dev->irq, -- cgit v0.10.2 From 22ebf00eb56fe77922de8138aa9af9996582c2b3 Mon Sep 17 00:00:00 2001 From: Lukasz Gemborowski Date: Mon, 27 Jun 2016 12:57:47 +0200 Subject: i2c: mux: reg: wrong condition checked for of_address_to_resource return value of_address_to_resource return 0 on successful call but devm_ioremap_resource is called only if it returns non-zero value Signed-off-by: Lukasz Gemborowski Reviewed-by: Alexander Sverdlin Signed-off-by: Wolfram Sang Cc: stable@kernel.org diff --git a/drivers/i2c/muxes/i2c-mux-reg.c b/drivers/i2c/muxes/i2c-mux-reg.c index 26e7c51..c6a90b4 100644 --- a/drivers/i2c/muxes/i2c-mux-reg.c +++ b/drivers/i2c/muxes/i2c-mux-reg.c @@ -145,7 +145,7 @@ static int i2c_mux_reg_probe_dt(struct regmux *mux, mux->data.idle_in_use = true; /* map address from "reg" if exists */ - if (of_address_to_resource(np, 0, &res)) { + if (of_address_to_resource(np, 0, &res) == 0) { mux->data.reg_size = resource_size(&res); mux->data.reg = devm_ioremap_resource(&pdev->dev, &res); if (IS_ERR(mux->data.reg)) -- cgit v0.10.2 From 92c74bceb0dd4b74a6c0b56c2f9a5c93a0860808 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Tue, 5 Jul 2016 08:46:43 +0200 Subject: Revert "gpio: gpiolib-of: Allow compile testing" This reverts commit 1e4a80640338924b9f9fd7a121ac31d08134410a. This creates more problems than it solves right now. Compile testing needs to go in with patches fixing the problems it uncovers. Signed-off-by: Linus Walleij diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index cebcb40..536112f 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -49,7 +49,7 @@ config GPIO_DEVRES config OF_GPIO def_bool y - depends on OF || COMPILE_TEST + depends on OF config GPIO_ACPI def_bool y -- cgit v0.10.2 From 2609af19362d03332b55fc7836e7023bcd6d90bf Mon Sep 17 00:00:00 2001 From: hayeswang Date: Tue, 5 Jul 2016 16:11:46 +0800 Subject: r8152: fix runtime function for RTL8152 The RTL8152 doesn't have U1U2 and U2P3 features, so use different runtime functions for RTL812 and RTL8153 by adding autosuspend_en() to rtl_ops. Signed-off-by: Hayes Wang Signed-off-by: David S. Miller diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c index d7f20a9..0da72d3 100644 --- a/drivers/net/usb/r8152.c +++ b/drivers/net/usb/r8152.c @@ -31,7 +31,7 @@ #define NETNEXT_VERSION "08" /* Information for net */ -#define NET_VERSION "4" +#define NET_VERSION "5" #define DRIVER_VERSION "v1." NETNEXT_VERSION "." NET_VERSION #define DRIVER_AUTHOR "Realtek linux nic maintainers " @@ -624,6 +624,7 @@ struct r8152 { int (*eee_get)(struct r8152 *, struct ethtool_eee *); int (*eee_set)(struct r8152 *, struct ethtool_eee *); bool (*in_nway)(struct r8152 *); + void (*autosuspend_en)(struct r8152 *tp, bool enable); } rtl_ops; int intr_interval; @@ -2408,9 +2409,6 @@ static void rtl_runtime_suspend_enable(struct r8152 *tp, bool enable) if (enable) { u32 ocp_data; - r8153_u1u2en(tp, false); - r8153_u2p3en(tp, false); - __rtl_set_wol(tp, WAKE_ANY); ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CRWECR, CRWECR_CONFIG); @@ -2432,7 +2430,17 @@ static void rtl_runtime_suspend_enable(struct r8152 *tp, bool enable) ocp_write_word(tp, MCU_TYPE_PLA, PLA_CONFIG34, ocp_data); ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CRWECR, CRWECR_NORAML); + } +} +static void rtl8153_runtime_enable(struct r8152 *tp, bool enable) +{ + rtl_runtime_suspend_enable(tp, enable); + + if (enable) { + r8153_u1u2en(tp, false); + r8153_u2p3en(tp, false); + } else { r8153_u2p3en(tp, true); r8153_u1u2en(tp, true); } @@ -3523,7 +3531,7 @@ static int rtl8152_suspend(struct usb_interface *intf, pm_message_t message) napi_disable(&tp->napi); if (test_bit(SELECTIVE_SUSPEND, &tp->flags)) { rtl_stop_rx(tp); - rtl_runtime_suspend_enable(tp, true); + tp->rtl_ops.autosuspend_en(tp, true); } else { cancel_delayed_work_sync(&tp->schedule); tp->rtl_ops.down(tp); @@ -3549,7 +3557,7 @@ static int rtl8152_resume(struct usb_interface *intf) if (netif_running(tp->netdev) && tp->netdev->flags & IFF_UP) { if (test_bit(SELECTIVE_SUSPEND, &tp->flags)) { - rtl_runtime_suspend_enable(tp, false); + tp->rtl_ops.autosuspend_en(tp, false); clear_bit(SELECTIVE_SUSPEND, &tp->flags); napi_disable(&tp->napi); set_bit(WORK_ENABLE, &tp->flags); @@ -3568,7 +3576,7 @@ static int rtl8152_resume(struct usb_interface *intf) usb_submit_urb(tp->intr_urb, GFP_KERNEL); } else if (test_bit(SELECTIVE_SUSPEND, &tp->flags)) { if (tp->netdev->flags & IFF_UP) - rtl_runtime_suspend_enable(tp, false); + tp->rtl_ops.autosuspend_en(tp, false); clear_bit(SELECTIVE_SUSPEND, &tp->flags); } @@ -4148,6 +4156,7 @@ static int rtl_ops_init(struct r8152 *tp) ops->eee_get = r8152_get_eee; ops->eee_set = r8152_set_eee; ops->in_nway = rtl8152_in_nway; + ops->autosuspend_en = rtl_runtime_suspend_enable; break; case RTL_VER_03: @@ -4163,6 +4172,7 @@ static int rtl_ops_init(struct r8152 *tp) ops->eee_get = r8153_get_eee; ops->eee_set = r8153_set_eee; ops->in_nway = rtl8153_in_nway; + ops->autosuspend_en = rtl8153_runtime_enable; break; default: -- cgit v0.10.2 From a30b016808e214c6864ad579ef867b3fe0a314f8 Mon Sep 17 00:00:00 2001 From: Aviv Heller Date: Tue, 5 Jul 2016 12:09:47 +0300 Subject: bonding: fix enslavement slave link notifications Currently, link notifications are not sent by bond_set_slave_link_state() upon enslavement if the slave is enslaved when up. This happens because slave->link default init value is 0, which is the same as BOND_LINK_UP, resulting in bond_set_slave_link_state() ignoring this transition. This patch sets the default value of slave->link to BOND_LINK_NOCHANGE, assuring it will count as a state transition and thus trigger notification logic. Signed-off-by: Aviv Heller Reviewed-by: Jiri Pirko Signed-off-by: Saeed Mahameed Signed-off-by: David S. Miller diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 941ec99..a2afa3b 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -1584,6 +1584,7 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) } /* check for initial state */ + new_slave->link = BOND_LINK_NOCHANGE; if (bond->params.miimon) { if (bond_check_dev_link(bond, slave_dev, 0) == BMSR_LSTATUS) { if (bond->params.updelay) { -- cgit v0.10.2 From eae033c1b86721ec54511607fc26bfb94a0e004b Mon Sep 17 00:00:00 2001 From: Or Gerlitz Date: Tue, 5 Jul 2016 12:17:12 +0300 Subject: net/mlx5: Avoid setting unused var when modifying vport node GUID GCC complains on unused-but-set-variable, clean this up. Fixes: 23898c763f4a ('net/mlx5: E-Switch, Modify node guid on vf set MAC') Signed-off-by: Or Gerlitz Acked-by: Saeed Mahameed Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/mellanox/mlx5/core/vport.c b/drivers/net/ethernet/mellanox/mlx5/core/vport.c index daf44cd..91846df 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/vport.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/vport.c @@ -513,7 +513,6 @@ int mlx5_modify_nic_vport_node_guid(struct mlx5_core_dev *mdev, { int inlen = MLX5_ST_SZ_BYTES(modify_nic_vport_context_in); void *nic_vport_context; - u8 *guid; void *in; int err; @@ -535,8 +534,6 @@ int mlx5_modify_nic_vport_node_guid(struct mlx5_core_dev *mdev, nic_vport_context = MLX5_ADDR_OF(modify_nic_vport_context_in, in, nic_vport_context); - guid = MLX5_ADDR_OF(nic_vport_context, nic_vport_context, - node_guid); MLX5_SET64(nic_vport_context, nic_vport_context, node_guid, node_guid); err = mlx5_modify_nic_vport_context(mdev, in, inlen); -- cgit v0.10.2 From f5d6516120ee5c777fb7b1ba9d39031881ad511b Mon Sep 17 00:00:00 2001 From: Ganesh Goudar Date: Tue, 5 Jul 2016 18:07:24 +0530 Subject: cxgb4: update latest firmware version supported Change t4fw_version.h to update latest firmware version number Signed-off-by: Ganesh Goudar Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4fw_version.h b/drivers/net/ethernet/chelsio/cxgb4/t4fw_version.h index c4b262c..2accab3 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4fw_version.h +++ b/drivers/net/ethernet/chelsio/cxgb4/t4fw_version.h @@ -36,8 +36,8 @@ #define __T4FW_VERSION_H__ #define T4FW_VERSION_MAJOR 0x01 -#define T4FW_VERSION_MINOR 0x0E -#define T4FW_VERSION_MICRO 0x04 +#define T4FW_VERSION_MINOR 0x0F +#define T4FW_VERSION_MICRO 0x25 #define T4FW_VERSION_BUILD 0x00 #define T4FW_MIN_VERSION_MAJOR 0x01 @@ -45,8 +45,8 @@ #define T4FW_MIN_VERSION_MICRO 0x00 #define T5FW_VERSION_MAJOR 0x01 -#define T5FW_VERSION_MINOR 0x0E -#define T5FW_VERSION_MICRO 0x04 +#define T5FW_VERSION_MINOR 0x0F +#define T5FW_VERSION_MICRO 0x25 #define T5FW_VERSION_BUILD 0x00 #define T5FW_MIN_VERSION_MAJOR 0x00 @@ -54,8 +54,8 @@ #define T5FW_MIN_VERSION_MICRO 0x00 #define T6FW_VERSION_MAJOR 0x01 -#define T6FW_VERSION_MINOR 0x0E -#define T6FW_VERSION_MICRO 0x04 +#define T6FW_VERSION_MINOR 0x0F +#define T6FW_VERSION_MICRO 0x25 #define T6FW_VERSION_BUILD 0x00 #define T6FW_MIN_VERSION_MAJOR 0x00 -- cgit v0.10.2 From 262e2bfd7d1e1f1ee48b870e5dfabb87c06b975e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bruno=20Pr=C3=83=C2=A9mont?= Date: Thu, 30 Jun 2016 17:00:32 +0200 Subject: qla2xxx: Fix NULL pointer deref in QLA interrupt MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In qla24xx_process_response_queue() rsp->msix->cpuid may trigger NULL pointer dereference when rsp->msix is NULL: [ 5.622457] NULL pointer dereference at 0000000000000050 [ 5.622457] IP: [] qla24xx_process_response_queue+0x44/0x4b0 [ 5.622457] PGD 0 [ 5.622457] Oops: 0000 [#1] SMP [ 5.622457] Modules linked in: [ 5.622457] CPU: 2 PID: 0 Comm: swapper/2 Not tainted 4.6.3-x86_64 #1 [ 5.622457] Hardware name: HP ProLiant DL360 G5, BIOS P58 05/02/2011 [ 5.622457] task: ffff8801a88f3740 ti: ffff8801a8954000 task.ti: ffff8801a8954000 [ 5.622457] RIP: 0010:[] [] qla24xx_process_response_queue+0x44/0x4b0 [ 5.622457] RSP: 0000:ffff8801afb03de8 EFLAGS: 00010002 [ 5.622457] RAX: 0000000000000000 RBX: 0000000000000032 RCX: 00000000ffffffff [ 5.622457] RDX: 0000000000000002 RSI: ffff8801a79bf8c8 RDI: ffff8800c8f7e7c0 [ 5.622457] RBP: ffff8801afb03e68 R08: 0000000000000000 R09: 0000000000000000 [ 5.622457] R10: 00000000ffff8c47 R11: 0000000000000002 R12: ffff8801a79bf8c8 [ 5.622457] R13: ffff8800c8f7e7c0 R14: ffff8800c8f60000 R15: 0000000000018013 [ 5.622457] FS: 0000000000000000(0000) GS:ffff8801afb00000(0000) knlGS:0000000000000000 [ 5.622457] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 5.622457] CR2: 0000000000000050 CR3: 0000000001e07000 CR4: 00000000000006e0 [ 5.622457] Stack: [ 5.622457] ffff8801afb03e30 ffffffff810c0f2d 0000000000000086 0000000000000002 [ 5.622457] ffff8801afb03e28 ffffffff816570e1 ffff8800c8994628 0000000000000002 [ 5.622457] ffff8801afb03e60 ffffffff816772d4 b47c472ad6955e68 0000000000000032 [ 5.622457] Call Trace: [ 5.622457] [ 5.622457] [] ? __wake_up_common+0x4d/0x80 [ 5.622457] [] ? usb_hcd_resume_root_hub+0x51/0x60 [ 5.622457] [] ? uhci_hub_status_data+0x64/0x240 [ 5.622457] [] qla24xx_intr_handler+0xf0/0x2e0 [ 5.622457] [] ? get_next_timer_interrupt+0xce/0x200 [ 5.622457] [] handle_irq_event_percpu+0x64/0x100 [ 5.622457] [] handle_irq_event+0x27/0x50 [ 5.622457] [] handle_edge_irq+0x65/0x140 [ 5.622457] [] handle_irq+0x18/0x30 [ 5.622457] [] do_IRQ+0x46/0xd0 [ 5.622457] [] common_interrupt+0x7f/0x7f [ 5.622457] [ 5.622457] [] ? mwait_idle+0x68/0x80 [ 5.622457] [] arch_cpu_idle+0xa/0x10 [ 5.622457] [] default_idle_call+0x27/0x30 [ 5.622457] [] cpu_startup_entry+0x19b/0x230 [ 5.622457] [] start_secondary+0x136/0x140 [ 5.622457] Code: 00 00 65 48 8b 04 25 28 00 00 00 48 89 45 d0 31 c0 48 8b 47 58 a8 02 0f 84 c5 00 00 00 48 8b 46 50 49 89 f4 65 8b 15 34 bb aa 7e <39> 50 50 74 11 89 50 50 48 8b 46 50 8b 40 50 41 89 86 60 8b 00 [ 5.622457] RIP [] qla24xx_process_response_queue+0x44/0x4b0 [ 5.622457] RSP [ 5.622457] CR2: 0000000000000050 [ 5.622457] ---[ end trace fa2b19c25106d42b ]--- [ 5.622457] Kernel panic - not syncing: Fatal exception in interrupt The affected code was introduced by commit cdb898c52d1dfad4b4800b83a58b3fe5d352edde (qla2xxx: Add irq affinity notification). Only dereference rsp->msix when it has been set so the machine can boot fine. Possibly rsp->msix is unset because: [ 3.479679] qla2xxx [0000:00:00.0]-0005: : QLogic Fibre Channel HBA Driver: 8.07.00.33-k. [ 3.481839] qla2xxx [0000:13:00.0]-001d: : Found an ISP2432 irq 17 iobase 0xffffc90000038000. [ 3.484081] qla2xxx [0000:13:00.0]-0035:0: MSI-X; Unsupported ISP2432 (0x2, 0x3). [ 3.485804] qla2xxx [0000:13:00.0]-0037:0: Falling back-to MSI mode -258. [ 3.890145] scsi host0: qla2xxx [ 3.891956] qla2xxx [0000:13:00.0]-00fb:0: QLogic QLE2460 - PCI-Express Single Channel 4Gb Fibre Channel HBA. [ 3.894207] qla2xxx [0000:13:00.0]-00fc:0: ISP2432: PCIe (2.5GT/s x4) @ 0000:13:00.0 hdma+ host#=0 fw=7.03.00 (9496). [ 5.714774] qla2xxx [0000:13:00.0]-500a:0: LOOP UP detected (4 Gbps). Signed-off-by: Bruno Prémont Acked-by: Quinn Tran CC: # 4.5+ Fixes: cdb898c52d1dfad4b4800b83a58b3fe5d352edde Signed-off-by: James Bottomley diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c index 5649c20..a92a62d 100644 --- a/drivers/scsi/qla2xxx/qla_isr.c +++ b/drivers/scsi/qla2xxx/qla_isr.c @@ -2548,7 +2548,7 @@ void qla24xx_process_response_queue(struct scsi_qla_host *vha, if (!vha->flags.online) return; - if (rsp->msix->cpuid != smp_processor_id()) { + if (rsp->msix && rsp->msix->cpuid != smp_processor_id()) { /* if kernel does not notify qla of IRQ's CPU change, * then set it here. */ -- cgit v0.10.2 From 00699ad8571afd7fb8bc2c61f67c86c2428680ab Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 5 Jul 2016 09:44:53 -0400 Subject: Use the right predicate in ->atomic_open() instances ->atomic_open() can be given an in-lookup dentry *or* a negative one found in dcache. Use d_in_lookup() to tell one from another, rather than d_unhashed(). Signed-off-by: Al Viro diff --git a/fs/9p/vfs_inode.c b/fs/9p/vfs_inode.c index f4645c5..e2e7c74 100644 --- a/fs/9p/vfs_inode.c +++ b/fs/9p/vfs_inode.c @@ -853,7 +853,7 @@ v9fs_vfs_atomic_open(struct inode *dir, struct dentry *dentry, struct p9_fid *fid, *inode_fid; struct dentry *res = NULL; - if (d_unhashed(dentry)) { + if (d_in_lookup(dentry)) { res = v9fs_vfs_lookup(dir, dentry, 0); if (IS_ERR(res)) return PTR_ERR(res); diff --git a/fs/9p/vfs_inode_dotl.c b/fs/9p/vfs_inode_dotl.c index a34702c..1b51eaa 100644 --- a/fs/9p/vfs_inode_dotl.c +++ b/fs/9p/vfs_inode_dotl.c @@ -254,7 +254,7 @@ v9fs_vfs_atomic_open_dotl(struct inode *dir, struct dentry *dentry, struct posix_acl *pacl = NULL, *dacl = NULL; struct dentry *res = NULL; - if (d_unhashed(dentry)) { + if (d_in_lookup(dentry)) { res = v9fs_vfs_lookup(dir, dentry, 0); if (IS_ERR(res)) return PTR_ERR(res); diff --git a/fs/ceph/file.c b/fs/ceph/file.c index ce2f579..0daaf7c 100644 --- a/fs/ceph/file.c +++ b/fs/ceph/file.c @@ -394,7 +394,7 @@ int ceph_atomic_open(struct inode *dir, struct dentry *dentry, if ((flags & O_CREAT) && !req->r_reply_info.head->is_dentry) err = ceph_handle_notrace_create(dir, dentry); - if (d_unhashed(dentry)) { + if (d_in_lookup(dentry)) { dn = ceph_finish_lookup(req, dentry, err); if (IS_ERR(dn)) err = PTR_ERR(dn); diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c index c3eb998..fb0903f 100644 --- a/fs/cifs/dir.c +++ b/fs/cifs/dir.c @@ -445,7 +445,7 @@ cifs_atomic_open(struct inode *inode, struct dentry *direntry, * Check for hashed negative dentry. We have already revalidated * the dentry and it is fine. No need to perform another lookup. */ - if (!d_unhashed(direntry)) + if (!d_in_lookup(direntry)) return -ENOENT; res = cifs_lookup(inode, direntry, 0); diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c index 264f07c..cca7b04 100644 --- a/fs/fuse/dir.c +++ b/fs/fuse/dir.c @@ -480,7 +480,7 @@ static int fuse_atomic_open(struct inode *dir, struct dentry *entry, struct fuse_conn *fc = get_fuse_conn(dir); struct dentry *res = NULL; - if (d_unhashed(entry)) { + if (d_in_lookup(entry)) { res = fuse_lookup(dir, entry, 0); if (IS_ERR(res)) return PTR_ERR(res); diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c index 21dc784..9bad79f 100644 --- a/fs/gfs2/inode.c +++ b/fs/gfs2/inode.c @@ -1189,7 +1189,7 @@ static int gfs2_atomic_open(struct inode *dir, struct dentry *dentry, struct dentry *d; bool excl = !!(flags & O_EXCL); - if (!d_unhashed(dentry)) + if (!d_in_lookup(dentry)) goto skip_lookup; d = __gfs2_lookup(dir, dentry, file, opened); diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index d8015a0..3d5eb5e 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c @@ -1504,7 +1504,7 @@ int nfs_atomic_open(struct inode *dir, struct dentry *dentry, /* NFS only supports OPEN on regular files */ if ((open_flags & O_DIRECTORY)) { - if (!d_unhashed(dentry)) { + if (!d_in_lookup(dentry)) { /* * Hashed negative dentry with O_DIRECTORY: dentry was * revalidated and is fine, no need to perform lookup -- cgit v0.10.2 From c94c09535c4debcc439f55b5b6d9ebe57bd4665a Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 5 Jul 2016 09:49:21 -0400 Subject: nfs_atomic_open(): prevent parallel nfs_lookup() on a negative hashed Signed-off-by: Al Viro diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index 3d5eb5e..19d93d0 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c @@ -1485,11 +1485,13 @@ int nfs_atomic_open(struct inode *dir, struct dentry *dentry, struct file *file, unsigned open_flags, umode_t mode, int *opened) { + DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wq); struct nfs_open_context *ctx; struct dentry *res; struct iattr attr = { .ia_valid = ATTR_OPEN }; struct inode *inode; unsigned int lookup_flags = 0; + bool switched = false; int err; /* Expect a negative dentry */ @@ -1528,6 +1530,17 @@ int nfs_atomic_open(struct inode *dir, struct dentry *dentry, attr.ia_size = 0; } + if (!(open_flags & O_CREAT) && !d_in_lookup(dentry)) { + d_drop(dentry); + switched = true; + dentry = d_alloc_parallel(dentry->d_parent, + &dentry->d_name, &wq); + if (IS_ERR(dentry)) + return PTR_ERR(dentry); + if (unlikely(!d_in_lookup(dentry))) + return finish_no_open(file, dentry); + } + ctx = create_nfs_open_context(dentry, open_flags); err = PTR_ERR(ctx); if (IS_ERR(ctx)) @@ -1563,14 +1576,23 @@ int nfs_atomic_open(struct inode *dir, struct dentry *dentry, trace_nfs_atomic_open_exit(dir, ctx, open_flags, err); put_nfs_open_context(ctx); out: + if (unlikely(switched)) { + d_lookup_done(dentry); + dput(dentry); + } return err; no_open: res = nfs_lookup(dir, dentry, lookup_flags); - err = PTR_ERR(res); + if (switched) { + d_lookup_done(dentry); + if (!res) + res = dentry; + else + dput(dentry); + } if (IS_ERR(res)) - goto out; - + return PTR_ERR(res); return finish_no_open(file, res); } EXPORT_SYMBOL_GPL(nfs_atomic_open); -- cgit v0.10.2 From 1a965d405fc6f6b1e3454baad7001fed91c9c458 Mon Sep 17 00:00:00 2001 From: Bijosh Thykkoottathil Date: Mon, 4 Jul 2016 10:08:53 +0000 Subject: drivers:iio:accel:mma8452: added cleanup provision in case of failure. mma8452_set_freefall_mode can return -ve value in case if i2c_smbus_read_byte_data fails. This function is called from mma8452_probe, and returning -ve value from probe indicates probe failure. Need to call iio_triggered_buffer_cleanup & iio_trigger_cleanup in this case. Signed-off-by: Bijosh Thykkoottathil Acked-by: Martin Kepplinger Signed-off-by: Jonathan Cameron diff --git a/drivers/iio/accel/mma8452.c b/drivers/iio/accel/mma8452.c index c0df283..9ba2f7f 100644 --- a/drivers/iio/accel/mma8452.c +++ b/drivers/iio/accel/mma8452.c @@ -1579,8 +1579,8 @@ static int mma8452_probe(struct i2c_client *client, goto buffer_cleanup; ret = mma8452_set_freefall_mode(data, false); - if (ret) - return ret; + if (ret < 0) + goto buffer_cleanup; return 0; -- cgit v0.10.2 From 0ddfd857130d16b1fb1e45c5ab2321a65738d70b Mon Sep 17 00:00:00 2001 From: Bijosh Thykkoottathil Date: Mon, 4 Jul 2016 11:15:08 +0000 Subject: drivers:iio:accel:mma8452: removed unwanted return statements Removed unwanted return statements from the function mma8452_set_freefall_mode. Signed-off-by: Bijosh Thykkoottathil Acked-by: Martin Kepplinger Signed-off-by: Jonathan Cameron diff --git a/drivers/iio/accel/mma8452.c b/drivers/iio/accel/mma8452.c index 9ba2f7f..d41e1b5 100644 --- a/drivers/iio/accel/mma8452.c +++ b/drivers/iio/accel/mma8452.c @@ -634,11 +634,7 @@ static int mma8452_set_freefall_mode(struct mma8452_data *data, bool state) val |= MMA8452_FF_MT_CFG_OAE; } - val = mma8452_change_config(data, chip->ev_cfg, val); - if (val) - return val; - - return 0; + return mma8452_change_config(data, chip->ev_cfg, val); } static int mma8452_set_hp_filter_frequency(struct mma8452_data *data, -- cgit v0.10.2 From 45209046c47b93fadf26dc59a9da724f387b9cf2 Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Tue, 5 Jul 2016 13:53:12 +0800 Subject: ACPICA: Namespace: Fix namespace/interpreter lock ordering There is a lock order issue in acpi_load_tables(). The namespace lock is held before holding the interpreter lock. With ACPI_MUTEX_DEBUG enabled in the kernel, this is printed to the log during boot: [ 0.885699] ACPI Error: Invalid acquire order: Thread 405884224 owns [ACPI_MTX_Namespace], wants [ACPI_MTX_Interpreter] (20160422/utmutex-263) [ 0.885881] ACPI Error: Could not acquire AML Interpreter mutex (20160422/exutils-95) [ 0.893846] ACPI Error: Mutex [0x0] is not acquired, cannot release (20160422/utmutex-326) [ 0.894019] ACPI Error: Could not release AML Interpreter mutex (20160422/exutils-133) The issue has been introduced by the following commit: Commit: 2f38b1b16d9280689e5cfa47a4c50956bf437f0d ACPICA Commit: bfe03ffcde8ed56a7eae38ea0b188aeb12f9c52e Subject: ACPICA: Namespace: Fix a regression that MLC support triggers dead lock in dynamic table loading Which fixed a deadlock issue for acpi_ns_load_table() in acpi_ex_add_table() but didn't take care of the lock order in acpi_ns_load_table() correctly. Originally (before the above commit), ACPICA used the namespace/interpreter locks in the following 2 key code paths: 1. Table loading: acpi_ns_load_table L(Namespace) acpi_ns_parse_table acpi_ns_one_complete_parse U(Namespace) 2. Object evaluation: acpi_ns_evaluate L(Interpreter) acpi_ps_execute_method U(Interpreter) acpi_ns_load_table L(Namespace) U(Namespace) acpi_ev_initialize_region L(Namespace) U(Namespace) address_space.setup L(Namespace) U(Namespace) address_space.handler L(Namespace) U(Namespace) acpi_os_wait_semaphore acpi_os_acquire_mutex acpi_os_sleep L(Interpreter) U(Interpreter) During runtime, while acpi_ns_evaluate is called, the lock order is always Interpreter -> Namespace. In turn, the problematic commit acquires the locks in the following order: 3. Table loading: acpi_ns_load_table L(Namespace) acpi_ns_parse_table L(Interpreter) acpi_ns_one_complete_parse U(Interpreter) U(Namespace) To fix the lock order issue, move the interpreter lock to acpi_ns_load_table() to ensure the lock order correctness: 4. Table loading: acpi_ns_load_table L(Interpreter) L(Namespace) acpi_ns_parse_table acpi_ns_one_complete_parse U(Namespace) U(Interpreter) However, this doesn't fix the current design issues related to the namespace lock. For example, we can notice that in acpi_ns_evaluate(), outside of acpi_ns_load_table(), the namespace objects may be created by the named object creation control methods. And the creation of the method-owned namespace objects are not locked by the namespace lock. This patch doesn't try to fix such kind of existing issues. Fixes: 2f38b1b16d92 (ACPICA: Namespace: Fix a regression that MLC support triggers dead lock in dynamic table loading) Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/acpica/nsload.c b/drivers/acpi/acpica/nsload.c index b5e2b0a..297f6aa 100644 --- a/drivers/acpi/acpica/nsload.c +++ b/drivers/acpi/acpica/nsload.c @@ -46,6 +46,7 @@ #include "acnamesp.h" #include "acdispat.h" #include "actables.h" +#include "acinterp.h" #define _COMPONENT ACPI_NAMESPACE ACPI_MODULE_NAME("nsload") @@ -78,6 +79,8 @@ acpi_ns_load_table(u32 table_index, struct acpi_namespace_node *node) ACPI_FUNCTION_TRACE(ns_load_table); + acpi_ex_enter_interpreter(); + /* * Parse the table and load the namespace with all named * objects found within. Control methods are NOT parsed @@ -89,7 +92,7 @@ acpi_ns_load_table(u32 table_index, struct acpi_namespace_node *node) */ status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); + goto unlock_interp; } /* If table already loaded into namespace, just return */ @@ -130,6 +133,8 @@ acpi_ns_load_table(u32 table_index, struct acpi_namespace_node *node) unlock: (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); +unlock_interp: + (void)acpi_ex_exit_interpreter(); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); diff --git a/drivers/acpi/acpica/nsparse.c b/drivers/acpi/acpica/nsparse.c index 1783cd7..f631a47 100644 --- a/drivers/acpi/acpica/nsparse.c +++ b/drivers/acpi/acpica/nsparse.c @@ -47,7 +47,6 @@ #include "acparser.h" #include "acdispat.h" #include "actables.h" -#include "acinterp.h" #define _COMPONENT ACPI_NAMESPACE ACPI_MODULE_NAME("nsparse") @@ -171,8 +170,6 @@ acpi_ns_parse_table(u32 table_index, struct acpi_namespace_node *start_node) ACPI_FUNCTION_TRACE(ns_parse_table); - acpi_ex_enter_interpreter(); - /* * AML Parse, pass 1 * @@ -188,7 +185,7 @@ acpi_ns_parse_table(u32 table_index, struct acpi_namespace_node *start_node) status = acpi_ns_one_complete_parse(ACPI_IMODE_LOAD_PASS1, table_index, start_node); if (ACPI_FAILURE(status)) { - goto error_exit; + return_ACPI_STATUS(status); } /* @@ -204,10 +201,8 @@ acpi_ns_parse_table(u32 table_index, struct acpi_namespace_node *start_node) status = acpi_ns_one_complete_parse(ACPI_IMODE_LOAD_PASS2, table_index, start_node); if (ACPI_FAILURE(status)) { - goto error_exit; + return_ACPI_STATUS(status); } -error_exit: - acpi_ex_exit_interpreter(); return_ACPI_STATUS(status); } -- cgit v0.10.2 From 217215041b9285af2193a755b56a8f3ed408bfe2 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Wed, 6 Jul 2016 06:50:36 +1000 Subject: drm/nouveau/disp/sor/gf119: select correct sor when poking training pattern Fixes a regression caused by a stupid thinko from "disp/sor/gf119: both links use the same training register". Signed-off-by: Ben Skeggs Cc: stable@vger.kernel.org diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgf119.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgf119.c index 22706c0..49bd5da 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgf119.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgf119.c @@ -40,7 +40,8 @@ static int gf119_sor_dp_pattern(struct nvkm_output_dp *outp, int pattern) { struct nvkm_device *device = outp->base.disp->engine.subdev.device; - nvkm_mask(device, 0x61c110, 0x0f0f0f0f, 0x01010101 * pattern); + const u32 soff = gf119_sor_soff(outp); + nvkm_mask(device, 0x61c110 + soff, 0x0f0f0f0f, 0x01010101 * pattern); return 0; } -- cgit v0.10.2 From 096cdc6f52225835ff503f987a0d68ef770bb78e Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Tue, 21 Jun 2016 16:58:46 +0300 Subject: platform/chrome: cros_ec_dev - double fetch bug in ioctl We verify "u_cmd.outsize" and "u_cmd.insize" but we need to make sure that those values have not changed between the two copy_from_user() calls. Otherwise it could lead to a buffer overflow. Additionally, cros_ec_cmd_xfer() can set s_cmd->insize to a lower value. We should use the new smaller value so we don't copy too much data to the user. Reported-by: Pengfei Wang Fixes: a841178445bb ('mfd: cros_ec: Use a zero-length array for command data') Signed-off-by: Dan Carpenter Reviewed-by: Kees Cook Tested-by: Gwendal Grignou Cc: # v4.2+ Signed-off-by: Olof Johansson diff --git a/drivers/platform/chrome/cros_ec_dev.c b/drivers/platform/chrome/cros_ec_dev.c index 6d8ee3b..8abd80d 100644 --- a/drivers/platform/chrome/cros_ec_dev.c +++ b/drivers/platform/chrome/cros_ec_dev.c @@ -151,13 +151,19 @@ static long ec_device_ioctl_xcmd(struct cros_ec_dev *ec, void __user *arg) goto exit; } + if (u_cmd.outsize != s_cmd->outsize || + u_cmd.insize != s_cmd->insize) { + ret = -EINVAL; + goto exit; + } + s_cmd->command += ec->cmd_offset; ret = cros_ec_cmd_xfer(ec->ec_dev, s_cmd); /* Only copy data to userland if data was received. */ if (ret < 0) goto exit; - if (copy_to_user(arg, s_cmd, sizeof(*s_cmd) + u_cmd.insize)) + if (copy_to_user(arg, s_cmd, sizeof(*s_cmd) + s_cmd->insize)) ret = -EFAULT; exit: kfree(s_cmd); -- cgit v0.10.2 From 7e3fd813717693597daaa95dee875f4cb2d911ef Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Tue, 5 Jul 2016 19:18:07 +0800 Subject: ACPI / debugger: Fix regression introduced by IS_ERR_VALUE() removal The FIFO unlocking mechanism in acpi_dbg has been broken by the following commit: Commit: 287980e49ffc0f6d911601e7e352a812ed27768e Subject: remove lots of IS_ERR_VALUE abuses It converted !IS_ERR_VALUE(ret) into !ret which was not entirely correct. Fix the regression by taking ret > 0 into account too as appropriate. Fixes: 287980e49ffc (remove lots of IS_ERR_VALUE abuses) Signed-off-by: Lv Zheng [ rjw: Simplifications, changelog & subject massage ] Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/acpi_dbg.c b/drivers/acpi/acpi_dbg.c index 1f41284..dee8692 100644 --- a/drivers/acpi/acpi_dbg.c +++ b/drivers/acpi/acpi_dbg.c @@ -602,7 +602,7 @@ static int acpi_aml_read_user(char __user *buf, int len) crc->tail = (crc->tail + n) & (ACPI_AML_BUF_SIZE - 1); ret = n; out: - acpi_aml_unlock_fifo(ACPI_AML_OUT_USER, !ret); + acpi_aml_unlock_fifo(ACPI_AML_OUT_USER, ret >= 0); return ret; } @@ -672,7 +672,7 @@ static int acpi_aml_write_user(const char __user *buf, int len) crc->head = (crc->head + n) & (ACPI_AML_BUF_SIZE - 1); ret = n; out: - acpi_aml_unlock_fifo(ACPI_AML_IN_USER, !ret); + acpi_aml_unlock_fifo(ACPI_AML_IN_USER, ret >= 0); return n; } -- cgit v0.10.2 From ab58298cf459fcd4f588a401d36abf0bd2215b51 Mon Sep 17 00:00:00 2001 From: Vegard Nossum Date: Tue, 5 Jul 2016 21:12:53 +0200 Subject: net: fix decnet rtnexthop parsing dn_fib_count_nhs() could enter an infinite loop if nhp->rtnh_len == 0 (i.e. if userspace passes a malformed netlink message). Let's use the helpers from net/nexthop.h which take care of all this stuff. We can do exactly the same as e.g. fib_count_nexthops() and fib_get_nhs() from net/ipv4/fib_semantics.c. This fixes the softlockup for me. Cc: Thomas Graf Signed-off-by: Vegard Nossum Signed-off-by: David S. Miller diff --git a/net/decnet/dn_fib.c b/net/decnet/dn_fib.c index df48034..a796fc7 100644 --- a/net/decnet/dn_fib.c +++ b/net/decnet/dn_fib.c @@ -41,6 +41,7 @@ #include #include #include +#include #define RT_MIN_TABLE 1 @@ -150,14 +151,13 @@ static int dn_fib_count_nhs(const struct nlattr *attr) struct rtnexthop *nhp = nla_data(attr); int nhs = 0, nhlen = nla_len(attr); - while(nhlen >= (int)sizeof(struct rtnexthop)) { - if ((nhlen -= nhp->rtnh_len) < 0) - return 0; + while (rtnh_ok(nhp, nhlen)) { nhs++; - nhp = RTNH_NEXT(nhp); + nhp = rtnh_next(nhp, &nhlen); } - return nhs; + /* leftover implies invalid nexthop configuration, discard it */ + return nhlen > 0 ? 0 : nhs; } static int dn_fib_get_nhs(struct dn_fib_info *fi, const struct nlattr *attr, @@ -167,21 +167,24 @@ static int dn_fib_get_nhs(struct dn_fib_info *fi, const struct nlattr *attr, int nhlen = nla_len(attr); change_nexthops(fi) { - int attrlen = nhlen - sizeof(struct rtnexthop); - if (attrlen < 0 || (nhlen -= nhp->rtnh_len) < 0) + int attrlen; + + if (!rtnh_ok(nhp, nhlen)) return -EINVAL; nh->nh_flags = (r->rtm_flags&~0xFF) | nhp->rtnh_flags; nh->nh_oif = nhp->rtnh_ifindex; nh->nh_weight = nhp->rtnh_hops + 1; - if (attrlen) { + attrlen = rtnh_attrlen(nhp); + if (attrlen > 0) { struct nlattr *gw_attr; gw_attr = nla_find((struct nlattr *) (nhp + 1), attrlen, RTA_GATEWAY); nh->nh_gw = gw_attr ? nla_get_le16(gw_attr) : 0; } - nhp = RTNH_NEXT(nhp); + + nhp = rtnh_next(nhp, &nhlen); } endfor_nexthops(fi); return 0; -- cgit v0.10.2 From 903ce4abdf374e3365d93bcb3df56c62008835ba Mon Sep 17 00:00:00 2001 From: Martin KaFai Lau Date: Tue, 5 Jul 2016 12:10:23 -0700 Subject: ipv6: Fix mem leak in rt6i_pcpu It was first reported and reproduced by Petr (thanks!) in https://bugzilla.kernel.org/show_bug.cgi?id=119581 free_percpu(rt->rt6i_pcpu) used to always happen in ip6_dst_destroy(). However, after fixing a deadlock bug in commit 9c7370a166b4 ("ipv6: Fix a potential deadlock when creating pcpu rt"), free_percpu() is not called before setting non_pcpu_rt->rt6i_pcpu to NULL. It is worth to note that rt6i_pcpu is protected by table->tb6_lock. kmemleak somehow did not report it. We nailed it down by observing the pcpu entries in /proc/vmallocinfo (first suggested by Hannes, thanks!). Signed-off-by: Martin KaFai Lau Fixes: 9c7370a166b4 ("ipv6: Fix a potential deadlock when creating pcpu rt") Reported-by: Petr Novopashenniy Tested-by: Petr Novopashenniy Acked-by: Hannes Frederic Sowa Cc: Hannes Frederic Sowa Cc: Petr Novopashenniy Signed-off-by: David S. Miller diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c index 1bcef23..771be1f 100644 --- a/net/ipv6/ip6_fib.c +++ b/net/ipv6/ip6_fib.c @@ -177,6 +177,7 @@ static void rt6_free_pcpu(struct rt6_info *non_pcpu_rt) } } + free_percpu(non_pcpu_rt->rt6i_pcpu); non_pcpu_rt->rt6i_pcpu = NULL; } -- cgit v0.10.2 From 175a20c16fdb7700fcac63f1eeb2caa7e1dddd2d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Thu, 23 Jun 2016 18:06:49 +0300 Subject: x86/perf/intel/rapl: Fix module name collision with powercap intel-rapl MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since commit 4b6e2571bf00 the rapl perf module calls itself intel-rapl. That name was already in use by the rapl powercap driver, which now fails to load if the perf module is loaded. Fix the problem by renaming the perf module to intel-rapl-perf, so that both modules can coexist. Fixes: 4b6e2571bf00 ("x86/perf/intel/rapl: Make the Intel RAPL PMU driver modular") Signed-off-by: Ville Syrjälä Cc: Vince Weaver Cc: Alexander Shishkin Cc: Kan Liang Cc: Stephane Eranian Cc: Arnaldo Carvalho de Melo Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Jiri Olsa Link: http://lkml.kernel.org/r/1466694409-3620-1-git-send-email-ville.syrjala@linux.intel.com Signed-off-by: Thomas Gleixner diff --git a/arch/x86/events/intel/Makefile b/arch/x86/events/intel/Makefile index 3660b2c..06c2baa 100644 --- a/arch/x86/events/intel/Makefile +++ b/arch/x86/events/intel/Makefile @@ -1,8 +1,8 @@ obj-$(CONFIG_CPU_SUP_INTEL) += core.o bts.o cqm.o obj-$(CONFIG_CPU_SUP_INTEL) += ds.o knc.o obj-$(CONFIG_CPU_SUP_INTEL) += lbr.o p4.o p6.o pt.o -obj-$(CONFIG_PERF_EVENTS_INTEL_RAPL) += intel-rapl.o -intel-rapl-objs := rapl.o +obj-$(CONFIG_PERF_EVENTS_INTEL_RAPL) += intel-rapl-perf.o +intel-rapl-perf-objs := rapl.o obj-$(CONFIG_PERF_EVENTS_INTEL_UNCORE) += intel-uncore.o intel-uncore-objs := uncore.o uncore_nhmex.o uncore_snb.o uncore_snbep.o obj-$(CONFIG_PERF_EVENTS_INTEL_CSTATE) += intel-cstate.o -- cgit v0.10.2 From 6e8ef842223b90a33efd570128bb566a9ae6f5ad Mon Sep 17 00:00:00 2001 From: Purushottam Kushwaha Date: Tue, 5 Jul 2016 13:44:51 +0530 Subject: nl80211: Move ACL parsing later to avoid a possible memory leak No support for pbss results in a memory leak for the acl_data (if parse_acl_data succeeds). Fix this by moving the ACL parsing later. Cc: stable@vger.kernel.org Fixes: 34d505193bd10 ("cfg80211: basic support for PBSS network type") Signed-off-by: Purushottam Kushwaha Signed-off-by: Johannes Berg diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index d759901..7d72283 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -3487,16 +3487,16 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info) params.smps_mode = NL80211_SMPS_OFF; } + params.pbss = nla_get_flag(info->attrs[NL80211_ATTR_PBSS]); + if (params.pbss && !rdev->wiphy.bands[NL80211_BAND_60GHZ]) + return -EOPNOTSUPP; + if (info->attrs[NL80211_ATTR_ACL_POLICY]) { params.acl = parse_acl_data(&rdev->wiphy, info); if (IS_ERR(params.acl)) return PTR_ERR(params.acl); } - params.pbss = nla_get_flag(info->attrs[NL80211_ATTR_PBSS]); - if (params.pbss && !rdev->wiphy.bands[NL80211_BAND_60GHZ]) - return -EOPNOTSUPP; - wdev_lock(wdev); err = rdev_start_ap(rdev, dev, ¶ms); if (!err) { -- cgit v0.10.2 From b79efd345361667f7d81da765b8d61f631209c3d Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Wed, 6 Jul 2016 13:18:44 +0200 Subject: MAINTAINERS: Remove Jiang Liu from irq domains Jiang is not longer working for Intel and we have no new mail address. Avoid that people cc him. Signed-off-by: Thomas Gleixner diff --git a/MAINTAINERS b/MAINTAINERS index 1209323..6ec72cf 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -6235,7 +6235,6 @@ F: Documentation/devicetree/bindings/interrupt-controller/ F: drivers/irqchip/ IRQ DOMAINS (IRQ NUMBER MAPPING LIBRARY) -M: Jiang Liu M: Marc Zyngier S: Maintained T: git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git irq/core -- cgit v0.10.2 From 16a910a6722b7a8680409e634c7c0dac073c01e4 Mon Sep 17 00:00:00 2001 From: Gregory Greenman Date: Tue, 5 Jul 2016 15:23:10 +0300 Subject: cfg80211: handle failed skb allocation Handle the case when dev_alloc_skb returns NULL. Cc: stable@vger.kernel.org Fixes: 2b67f944f88c2 ("cfg80211: reuse existing page fragments in A-MSDU rx") Signed-off-by: Gregory Greenman Signed-off-by: Luca Coelho Signed-off-by: Johannes Berg diff --git a/net/wireless/util.c b/net/wireless/util.c index 2443ee3..b7d1592 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c @@ -721,6 +721,8 @@ __ieee80211_amsdu_copy(struct sk_buff *skb, unsigned int hlen, * alignment since sizeof(struct ethhdr) is 14. */ frame = dev_alloc_skb(hlen + sizeof(struct ethhdr) + 2 + cur_len); + if (!frame) + return NULL; skb_reserve(frame, hlen + sizeof(struct ethhdr) + 2); skb_copy_bits(skb, offset, skb_put(frame, cur_len), cur_len); -- cgit v0.10.2 From 88d02a2ba6c52350f9a73ff1b01a5be839c3ca17 Mon Sep 17 00:00:00 2001 From: David Daney Date: Thu, 16 Jun 2016 15:50:31 -0700 Subject: MIPS: Fix page table corruption on THP permission changes. When the core THP code is modifying the permissions of a huge page it calls pmd_modify(), which unfortunately was clearing the _PAGE_HUGE bit of the page table entry. The result can be kernel messages like: mm/memory.c:397: bad pmd 000000040080004d. mm/memory.c:397: bad pmd 00000003ff00004d. mm/memory.c:397: bad pmd 000000040100004d. or: ------------[ cut here ]------------ WARNING: at mm/mmap.c:3200 exit_mmap+0x150/0x158() Modules linked in: ipv6 at24 octeon3_ethernet octeon_srio_nexus m25p80 CPU: 12 PID: 1295 Comm: pmderr Not tainted 3.10.87-rt80-Cavium-Octeon #4 Stack : 0000000040808000 0000000014009ce1 0000000000400004 ffffffff81076ba0 0000000000000000 0000000000000000 ffffffff85110000 0000000000000119 0000000000000004 0000000000000000 0000000000000119 43617669756d2d4f 0000000000000000 ffffffff850fda40 ffffffff85110000 0000000000000000 0000000000000000 0000000000000009 ffffffff809207a0 0000000000000c80 ffffffff80f1bf20 0000000000000001 000000ffeca36828 0000000000000001 0000000000000000 0000000000000001 000000ffeca7e700 ffffffff80886924 80000003fd7a0000 80000003fd7a39b0 80000003fdea8000 ffffffff80885780 80000003fdea8000 ffffffff80f12218 000000000000000c 000000000000050f 0000000000000000 ffffffff80865c4c 0000000000000000 0000000000000000 ... Call Trace: [] show_stack+0x6c/0xf8 [] warn_slowpath_common+0x78/0xa8 [] exit_mmap+0x150/0x158 [] mmput+0x5c/0x110 [] do_exit+0x230/0xa68 [] do_group_exit+0x54/0x1d0 [] __wake_up_parent+0x0/0x18 ---[ end trace c7b38293191c57dc ]--- BUG: Bad rss-counter state mm:80000003fa168000 idx:1 val:1536 Fix by not clearing _PAGE_HUGE bit. Signed-off-by: David Daney Tested-by: Aaro Koskinen Cc: stable@vger.kernel.org Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/13687/ Signed-off-by: Ralf Baechle diff --git a/arch/mips/include/asm/pgtable.h b/arch/mips/include/asm/pgtable.h index f538167..7d44e88 100644 --- a/arch/mips/include/asm/pgtable.h +++ b/arch/mips/include/asm/pgtable.h @@ -633,7 +633,7 @@ static inline struct page *pmd_page(pmd_t pmd) static inline pmd_t pmd_modify(pmd_t pmd, pgprot_t newprot) { - pmd_val(pmd) = (pmd_val(pmd) & _PAGE_CHG_MASK) | + pmd_val(pmd) = (pmd_val(pmd) & (_PAGE_CHG_MASK | _PAGE_HUGE)) | (pgprot_val(newprot) & ~_PAGE_CHG_MASK); return pmd; } -- cgit v0.10.2 From d1fe176ca51fa3cb35f70c1d876d9a090e9befce Mon Sep 17 00:00:00 2001 From: Sven Eckelmann Date: Sun, 12 Jun 2016 10:43:19 +0200 Subject: batman-adv: Fix speedy join in gateway client mode Speedy join only works when the received packet is either broadcast or an 4addr unicast packet. Thus packets converted from broadcast to unicast via the gateway handling code have to be converted to 4addr packets to allow the receiving gateway server to add the sender address as temporary entry to the translation table. Not doing it will make the batman-adv gateway server drop the DHCP response in many situations because it doesn't yet have the TT entry for the destination of the DHCP response. Fixes: 371351731e9c ("batman-adv: change interface_rx to get orig node") Signed-off-by: Sven Eckelmann Acked-by: Antonio Quartulli Signed-off-by: Marek Lindner Signed-off-by: Simon Wunderlich diff --git a/net/batman-adv/send.c b/net/batman-adv/send.c index f2f1256..0103976 100644 --- a/net/batman-adv/send.c +++ b/net/batman-adv/send.c @@ -424,8 +424,8 @@ int batadv_send_skb_via_gw(struct batadv_priv *bat_priv, struct sk_buff *skb, struct batadv_orig_node *orig_node; orig_node = batadv_gw_get_selected_orig(bat_priv); - return batadv_send_skb_unicast(bat_priv, skb, BATADV_UNICAST, 0, - orig_node, vid); + return batadv_send_skb_unicast(bat_priv, skb, BATADV_UNICAST_4ADDR, + BATADV_P_DATA, orig_node, vid); } void batadv_schedule_bat_ogm(struct batadv_hard_iface *hard_iface) -- cgit v0.10.2 From 522e5cb76d0663c88f96b6a8301451c8efa37207 Mon Sep 17 00:00:00 2001 From: Joerg Roedel Date: Fri, 1 Jul 2016 16:42:55 +0200 Subject: iommu/amd: Fix unity mapping initialization race There is a race condition in the AMD IOMMU init code that causes requested unity mappings to be blocked by the IOMMU for a short period of time. This results on boot failures and IO_PAGE_FAULTs on some machines. Fix this by making sure the unity mappings are installed before all other DMA is blocked. Fixes: aafd8ba0ca74 ('iommu/amd: Implement add_device and remove_device') Cc: stable@vger.kernel.org # v4.2+ Signed-off-by: Joerg Roedel diff --git a/drivers/iommu/amd_iommu_init.c b/drivers/iommu/amd_iommu_init.c index d091def..59741ea 100644 --- a/drivers/iommu/amd_iommu_init.c +++ b/drivers/iommu/amd_iommu_init.c @@ -1568,13 +1568,23 @@ static int __init amd_iommu_init_pci(void) break; } + /* + * Order is important here to make sure any unity map requirements are + * fulfilled. The unity mappings are created and written to the device + * table during the amd_iommu_init_api() call. + * + * After that we call init_device_table_dma() to make sure any + * uninitialized DTE will block DMA, and in the end we flush the caches + * of all IOMMUs to make sure the changes to the device table are + * active. + */ + ret = amd_iommu_init_api(); + init_device_table_dma(); for_each_iommu(iommu) iommu_flush_all_caches(iommu); - ret = amd_iommu_init_api(); - if (!ret) print_iommu_info(); -- cgit v0.10.2 From 095d28c62f9a05edc186e1b2b02bc44585402bdd Mon Sep 17 00:00:00 2001 From: Huang Rui Date: Wed, 6 Jul 2016 09:31:35 +0800 Subject: drm/amd/powerplay: fix incorrect voltage table value for polaris10 Signed-off-by: Huang Rui Reviewed-by: Alex Deucher Signed-off-by: Alex Deucher diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/polaris10_hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/polaris10_hwmgr.c index ec2a7ad..5785dc2 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/polaris10_hwmgr.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/polaris10_hwmgr.c @@ -733,7 +733,7 @@ static int polaris10_populate_smc_mvdd_table(struct pp_hwmgr *hwmgr, table->Smio[level] |= data->mvdd_voltage_table.entries[level].smio_low; } - table->SmioMask2 = data->vddci_voltage_table.mask_low; + table->SmioMask2 = data->mvdd_voltage_table.mask_low; table->MvddLevelCount = (uint32_t) PP_HOST_TO_SMC_UL(count); } -- cgit v0.10.2 From 1dfefee8939b07dd65a35bb78f6a06df85578301 Mon Sep 17 00:00:00 2001 From: Huang Rui Date: Wed, 6 Jul 2016 09:32:24 +0800 Subject: drm/amd/powerplay: fix incorrect voltage table value for tonga Signed-off-by: Huang Rui Reviewed-by: Alex Deucher Signed-off-by: Alex Deucher Cc: stable@vger.kernel.org diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/tonga_hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/tonga_hwmgr.c index 233eb7f..5d0f655 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/tonga_hwmgr.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/tonga_hwmgr.c @@ -1302,7 +1302,7 @@ static int tonga_populate_smc_mvdd_table(struct pp_hwmgr *hwmgr, table->Smio[count] |= data->mvdd_voltage_table.entries[count].smio_low; } - table->SmioMask2 = data->vddci_voltage_table.mask_low; + table->SmioMask2 = data->mvdd_voltage_table.mask_low; CONVERT_FROM_HOST_TO_SMC_UL(table->MvddLevelCount); } -- cgit v0.10.2 From 4b2427605e5325eafb5cfc2698f517db68e41075 Mon Sep 17 00:00:00 2001 From: Rex Zhu Date: Tue, 5 Jul 2016 13:11:47 +0800 Subject: drm/amd/powerplay: incorrectly use of the function return value MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit '0' means true. Signed-off-by: Rex Zhu Reviewed-by: Michel Dänzer Signed-off-by: Alex Deucher Cc: stable@vger.kernel.org diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/tonga_processpptables.c b/drivers/gpu/drm/amd/powerplay/hwmgr/tonga_processpptables.c index 671fdb4..dccc859 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/tonga_processpptables.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/tonga_processpptables.c @@ -302,7 +302,7 @@ static int init_dpm_2_parameters( (((unsigned long)powerplay_table) + le16_to_cpu(powerplay_table->usPPMTableOffset)); if (0 != powerplay_table->usPPMTableOffset) { - if (1 == get_platform_power_management_table(hwmgr, atom_ppm_table)) { + if (get_platform_power_management_table(hwmgr, atom_ppm_table) == 0) { phm_cap_set(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_EnablePlatformPowerManagement); } -- cgit v0.10.2 From e5eb37170b3cbbf948c6aeaccece818a59e76a6c Mon Sep 17 00:00:00 2001 From: Rex Zhu Date: Wed, 29 Jun 2016 16:37:35 +0800 Subject: drm/amd/powerplay: fix bug that get wrong polaris evv voltage. value is 32 bits for polaris, not 16. Signed-off-by: Rex Zhu Reviewed-by: Ken Wang Signed-off-by: Alex Deucher diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/polaris10_hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/polaris10_hwmgr.c index 5785dc2..b8209ca 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/polaris10_hwmgr.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/polaris10_hwmgr.c @@ -2685,7 +2685,7 @@ static int polaris10_get_evv_voltages(struct pp_hwmgr *hwmgr) { struct polaris10_hwmgr *data = (struct polaris10_hwmgr *)(hwmgr->backend); uint16_t vv_id; - uint16_t vddc = 0; + uint32_t vddc = 0; uint16_t i, j; uint32_t sclk = 0; struct phm_ppt_v1_information *table_info = @@ -2716,8 +2716,9 @@ static int polaris10_get_evv_voltages(struct pp_hwmgr *hwmgr) continue); - /* need to make sure vddc is less than 2v or else, it could burn the ASIC. */ - PP_ASSERT_WITH_CODE((vddc < 2000 && vddc != 0), + /* need to make sure vddc is less than 2v or else, it could burn the ASIC. + * real voltage level in unit of 0.01mv */ + PP_ASSERT_WITH_CODE((vddc < 200000 && vddc != 0), "Invalid VDDC value", result = -EINVAL;); /* the voltage should not be zero nor equal to leakage ID */ diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/ppatomctrl.c b/drivers/gpu/drm/amd/powerplay/hwmgr/ppatomctrl.c index bf4e18f..90b35c5 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/ppatomctrl.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/ppatomctrl.c @@ -1256,7 +1256,7 @@ int atomctrl_set_ac_timing_ai(struct pp_hwmgr *hwmgr, uint32_t memory_clock, } int atomctrl_get_voltage_evv_on_sclk_ai(struct pp_hwmgr *hwmgr, uint8_t voltage_type, - uint32_t sclk, uint16_t virtual_voltage_Id, uint16_t *voltage) + uint32_t sclk, uint16_t virtual_voltage_Id, uint32_t *voltage) { int result; @@ -1274,7 +1274,7 @@ int atomctrl_get_voltage_evv_on_sclk_ai(struct pp_hwmgr *hwmgr, uint8_t voltage_ if (0 != result) return result; - *voltage = get_voltage_info_param_space.usVoltageLevel; + *voltage = ((GET_EVV_VOLTAGE_INFO_OUTPUT_PARAMETER_V1_3 *)(&get_voltage_info_param_space))->ulVoltageLevel; return result; } diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/ppatomctrl.h b/drivers/gpu/drm/amd/powerplay/hwmgr/ppatomctrl.h index 248c5db..1e35a96 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/ppatomctrl.h +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/ppatomctrl.h @@ -305,7 +305,7 @@ extern int atomctrl_get_engine_pll_dividers_ai(struct pp_hwmgr *hwmgr, uint32_t extern int atomctrl_set_ac_timing_ai(struct pp_hwmgr *hwmgr, uint32_t memory_clock, uint8_t level); extern int atomctrl_get_voltage_evv_on_sclk_ai(struct pp_hwmgr *hwmgr, uint8_t voltage_type, - uint32_t sclk, uint16_t virtual_voltage_Id, uint16_t *voltage); + uint32_t sclk, uint16_t virtual_voltage_Id, uint32_t *voltage); extern int atomctrl_get_smc_sclk_range_table(struct pp_hwmgr *hwmgr, struct pp_atom_ctrl_sclk_range_table *table); extern int atomctrl_get_avfs_information(struct pp_hwmgr *hwmgr, struct pp_atom_ctrl__avfs_parameters *param); -- cgit v0.10.2 From ab6bad05c886cf0ef0c86bd1f665cdbe8e5e75e7 Mon Sep 17 00:00:00 2001 From: Rex Zhu Date: Tue, 28 Jun 2016 16:55:52 -0400 Subject: drm/amd/powerplay: Update CKS on/ CKS off voltage offset calculation. As get the right evv voltage, update them to latest coefficients to align with BB. agd: squash in Slava's 32 bit build fix Signed-off-by: Rex Zhu Reviewed-by: Alex Deucher Signed-off-by: Alex Deucher diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/polaris10_hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/polaris10_hwmgr.c index b8209ca..91e25f9 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/polaris10_hwmgr.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/polaris10_hwmgr.c @@ -98,7 +98,6 @@ #define PCIE_BUS_CLK 10000 #define TCLK (PCIE_BUS_CLK / 10) -#define CEILING_UCHAR(double) ((double-(uint8_t)(double)) > 0 ? (uint8_t)(double+1) : (uint8_t)(double)) static const uint16_t polaris10_clock_stretcher_lookup_table[2][4] = { {600, 1050, 3, 0}, {600, 1050, 6, 1} }; @@ -1807,27 +1806,25 @@ static int polaris10_populate_clock_stretcher_data_table(struct pp_hwmgr *hwmgr) ro = efuse * (max -min)/255 + min; - /* Populate Sclk_CKS_masterEn0_7 and Sclk_voltageOffset - * there is a little difference in calculating - * volt_with_cks with windows */ + /* Populate Sclk_CKS_masterEn0_7 and Sclk_voltageOffset */ for (i = 0; i < sclk_table->count; i++) { data->smc_state_table.Sclk_CKS_masterEn0_7 |= sclk_table->entries[i].cks_enable << i; if (hwmgr->chip_id == CHIP_POLARIS10) { - volt_without_cks = (uint32_t)((2753594000 + (sclk_table->entries[i].clk/100) * 136418 -(ro - 70) * 1000000) / \ + volt_without_cks = (uint32_t)((2753594000U + (sclk_table->entries[i].clk/100) * 136418 -(ro - 70) * 1000000) / \ (2424180 - (sclk_table->entries[i].clk/100) * 1132925/1000)); - volt_with_cks = (uint32_t)((279720200 + sclk_table->entries[i].clk * 3232 - (ro - 65) * 100000000) / \ - (252248000 - sclk_table->entries[i].clk/100 * 115764)); + volt_with_cks = (uint32_t)((2797202000U + sclk_table->entries[i].clk/100 * 3232 - (ro - 65) * 1000000) / \ + (2522480 - sclk_table->entries[i].clk/100 * 115764/100)); } else { - volt_without_cks = (uint32_t)((2416794800 + (sclk_table->entries[i].clk/100) * 1476925/10 -(ro - 50) * 1000000) / \ - (2625416 - (sclk_table->entries[i].clk/100) * 12586807/10000)); - volt_with_cks = (uint32_t)((2999656000 + sclk_table->entries[i].clk * 392803/100 - (ro - 44) * 1000000) / \ - (3422454 - sclk_table->entries[i].clk/100 * 18886376/10000)); + volt_without_cks = (uint32_t)((2416794800U + (sclk_table->entries[i].clk/100) * 1476925/10 -(ro - 50) * 1000000) / \ + (2625416 - (sclk_table->entries[i].clk/100) * (12586807/10000))); + volt_with_cks = (uint32_t)((2999656000U - sclk_table->entries[i].clk/100 * 392803 - (ro - 44) * 1000000) / \ + (3422454 - sclk_table->entries[i].clk/100 * (18886376/10000))); } if (volt_without_cks >= volt_with_cks) - volt_offset = (uint8_t)CEILING_UCHAR((volt_without_cks - volt_with_cks + - sclk_table->entries[i].cks_voffset) * 100 / 625); + volt_offset = (uint8_t)(((volt_without_cks - volt_with_cks + + sclk_table->entries[i].cks_voffset) * 100 + 624) / 625); data->smc_state_table.Sclk_voltageOffset[i] = volt_offset; } -- cgit v0.10.2 From 076501ff6ba265a473689c112eda9f1f34f620b5 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Wed, 6 Jul 2016 16:06:53 -0700 Subject: init/Kconfig: keep Expert users menu together The "expert" menu was broken (split) such that all entries in it after KALLSYMS were displayed in the "General setup" area instead of in the "Expert users" area. Fix this by adding one kconfig dependency. Yes, the Expert users menu is fragile. Problems like this have happened several times in the past. I will attempt to isolate the Expert users menu if there is interest in that. Fixes: 4d5d5664c900 ("x86: kallsyms: disable absolute percpu symbols on !SMP") Signed-off-by: Randy Dunlap Cc: Ard Biesheuvel Cc: stable@vger.kernel.org # 4.6 Signed-off-by: Linus Torvalds diff --git a/init/Kconfig b/init/Kconfig index f755a60..c02d897 100644 --- a/init/Kconfig +++ b/init/Kconfig @@ -1458,6 +1458,7 @@ config KALLSYMS_ALL config KALLSYMS_ABSOLUTE_PERCPU bool + depends on KALLSYMS default X86_64 && SMP config KALLSYMS_BASE_RELATIVE -- cgit v0.10.2 From 5eb495349f5ec3b134f7341a2450392fc86d99d0 Mon Sep 17 00:00:00 2001 From: Lucas Stach Date: Thu, 30 Jun 2016 17:32:08 +0200 Subject: ARM: tegra: beaver: Allow SD card voltage to be changed This allows to switch the card signal voltage level to 1.8 V, which is needed for any ultra high speed modes to work. Signed-off-by: Lucas Stach Acked-by: Jon Hunter Signed-off-by: Thierry Reding Signed-off-by: Olof Johansson diff --git a/arch/arm/boot/dts/tegra30-beaver.dts b/arch/arm/boot/dts/tegra30-beaver.dts index 1eca3b2..b6da15d 100644 --- a/arch/arm/boot/dts/tegra30-beaver.dts +++ b/arch/arm/boot/dts/tegra30-beaver.dts @@ -1843,7 +1843,7 @@ ldo5_reg: ldo5 { regulator-name = "vddio_sdmmc,avdd_vdac"; - regulator-min-microvolt = <3300000>; + regulator-min-microvolt = <1800000>; regulator-max-microvolt = <3300000>; regulator-always-on; }; @@ -1914,6 +1914,7 @@ sdhci@78000000 { status = "okay"; + vqmmc-supply = <&ldo5_reg>; cd-gpios = <&gpio TEGRA_GPIO(I, 5) GPIO_ACTIVE_LOW>; wp-gpios = <&gpio TEGRA_GPIO(T, 3) GPIO_ACTIVE_HIGH>; power-gpios = <&gpio TEGRA_GPIO(D, 7) GPIO_ACTIVE_HIGH>; -- cgit v0.10.2 From 2c81a6477081966fe80b8c6daa68459bca896774 Mon Sep 17 00:00:00 2001 From: Mark Rutland Date: Tue, 14 Jun 2016 16:10:41 +0100 Subject: perf/core: Fix pmu::filter_match for SW-led groups The following commit: 66eb579e66ec ("perf: allow for PMU-specific event filtering") added the pmu::filter_match() callback. This was intended to avoid HW constraints on events from resulting in extremely pessimistic scheduling. However, pmu::filter_match() is only called for the leader of each event group. When the leader is a SW event, we do not filter the groups, and may fail at pmu::add() time, and when this happens we'll give up on scheduling any event groups later in the list until they are rotated ahead of the failing group. This can result in extremely sub-optimal event scheduling behaviour, e.g. if running the following on a big.LITTLE platform: $ taskset -c 0 ./perf stat \ -e 'a57{context-switches,armv8_cortex_a57/config=0x11/}' \ -e 'a53{context-switches,armv8_cortex_a53/config=0x11/}' \ ls context-switches (0.00%) armv8_cortex_a57/config=0x11/ (0.00%) 24 context-switches (37.36%) 57589154 armv8_cortex_a53/config=0x11/ (37.36%) Here the 'a53' event group was always eligible to be scheduled, but the 'a57' group never eligible to be scheduled, as the task was always affine to a Cortex-A53 CPU. The SW (group leader) event in the 'a57' group was eligible, but the HW event failed at pmu::add() time, resulting in ctx_flexible_sched_in giving up on scheduling further groups with HW events. One way of avoiding this is to check pmu::filter_match() on siblings as well as the group leader. If any of these fail their pmu::filter_match() call, we must skip the entire group before attempting to add any events. Signed-off-by: Mark Rutland Signed-off-by: Peter Zijlstra (Intel) Cc: Alexander Shishkin Cc: Arnaldo Carvalho de Melo Cc: Arnaldo Carvalho de Melo Cc: Jiri Olsa Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: Will Deacon Fixes: 66eb579e66ec ("perf: allow for PMU-specific event filtering") Link: http://lkml.kernel.org/r/1465917041-15339-1-git-send-email-mark.rutland@arm.com [ Small readability edits. ] Signed-off-by: Ingo Molnar diff --git a/kernel/events/core.c b/kernel/events/core.c index 85cd418..43d43a2d 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c @@ -1678,12 +1678,33 @@ static bool is_orphaned_event(struct perf_event *event) return event->state == PERF_EVENT_STATE_DEAD; } -static inline int pmu_filter_match(struct perf_event *event) +static inline int __pmu_filter_match(struct perf_event *event) { struct pmu *pmu = event->pmu; return pmu->filter_match ? pmu->filter_match(event) : 1; } +/* + * Check whether we should attempt to schedule an event group based on + * PMU-specific filtering. An event group can consist of HW and SW events, + * potentially with a SW leader, so we must check all the filters, to + * determine whether a group is schedulable: + */ +static inline int pmu_filter_match(struct perf_event *event) +{ + struct perf_event *child; + + if (!__pmu_filter_match(event)) + return 0; + + list_for_each_entry(child, &event->sibling_list, group_entry) { + if (!__pmu_filter_match(child)) + return 0; + } + + return 1; +} + static inline int event_filter_match(struct perf_event *event) { -- cgit v0.10.2 From aefbc4d04c7b09cb6775a32cea7986c62e489ee2 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Thu, 30 Jun 2016 11:49:08 +0200 Subject: perf/x86/intel: Fix rdlbr_to() MSR reading typo It helps to actually read the right MSR.. Signed-off-by: Peter Zijlstra (Intel) Cc: Alexander Shishkin Cc: Arnaldo Carvalho de Melo Cc: Jiri Olsa Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Thomas Gleixner Cc: Vince Weaver Cc: linux-kernel@vger.kernel.org Fixes: d4cf1949f968 ("perf/x86/intel: Add {rd,wr}lbr_{to,from} wrappers") Signed-off-by: Ingo Molnar diff --git a/arch/x86/events/intel/lbr.c b/arch/x86/events/intel/lbr.c index cc4555a..707d358 100644 --- a/arch/x86/events/intel/lbr.c +++ b/arch/x86/events/intel/lbr.c @@ -323,7 +323,7 @@ static inline u64 rdlbr_to(unsigned int idx) { u64 val; - rdmsrl(x86_pmu.lbr_from + idx, val); + rdmsrl(x86_pmu.lbr_to + idx, val); return val; } -- cgit v0.10.2 From 46866b59dfbe9bf99bb1323ce1f3fd2073a81aa3 Mon Sep 17 00:00:00 2001 From: Kan Liang Date: Wed, 29 Jun 2016 07:01:51 -0700 Subject: perf/x86/intel/uncore: Add support for the Intel Skylake client uncore PMU This patch adds full support for Intel SKL client uncore PMU: - Add support for SKL client CPU uncore PMU, which is similar to the BDW client PMU driver. (There are some differences in CBOX numbering and uncore control MSR.) - Add new support for SkyLake Mobile uncore PMUs, for both CPU and PCI uncore functionality. Signed-off-by: Kan Liang Signed-off-by: Peter Zijlstra (Intel) Cc: Alexander Shishkin Cc: Arnaldo Carvalho de Melo Cc: Jiri Olsa Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Thomas Gleixner Cc: Vince Weaver Link: http://lkml.kernel.org/r/1467208912-8179-1-git-send-email-kan.liang@intel.com Signed-off-by: Ingo Molnar diff --git a/arch/x86/events/intel/uncore.c b/arch/x86/events/intel/uncore.c index dc965d2..59b4974 100644 --- a/arch/x86/events/intel/uncore.c +++ b/arch/x86/events/intel/uncore.c @@ -1379,6 +1379,7 @@ static const struct intel_uncore_init_fun knl_uncore_init __initconst = { }; static const struct intel_uncore_init_fun skl_uncore_init __initconst = { + .cpu_init = skl_uncore_cpu_init, .pci_init = skl_uncore_pci_init, }; @@ -1403,6 +1404,7 @@ static const struct x86_cpu_id intel_uncore_match[] __initconst = { X86_UNCORE_MODEL_MATCH(INTEL_FAM6_BROADWELL_XEON_D, bdx_uncore_init), X86_UNCORE_MODEL_MATCH(INTEL_FAM6_XEON_PHI_KNL, knl_uncore_init), X86_UNCORE_MODEL_MATCH(INTEL_FAM6_SKYLAKE_DESKTOP,skl_uncore_init), + X86_UNCORE_MODEL_MATCH(INTEL_FAM6_SKYLAKE_MOBILE, skl_uncore_init), {}, }; diff --git a/arch/x86/events/intel/uncore.h b/arch/x86/events/intel/uncore.h index 66c3a36..d6063e4 100644 --- a/arch/x86/events/intel/uncore.h +++ b/arch/x86/events/intel/uncore.h @@ -364,6 +364,7 @@ int bdw_uncore_pci_init(void); int skl_uncore_pci_init(void); void snb_uncore_cpu_init(void); void nhm_uncore_cpu_init(void); +void skl_uncore_cpu_init(void); int snb_pci2phy_map_init(int devid); /* perf_event_intel_uncore_snbep.c */ diff --git a/arch/x86/events/intel/uncore_snb.c b/arch/x86/events/intel/uncore_snb.c index 96531d2..97a69db 100644 --- a/arch/x86/events/intel/uncore_snb.c +++ b/arch/x86/events/intel/uncore_snb.c @@ -1,4 +1,4 @@ -/* Nehalem/SandBridge/Haswell uncore support */ +/* Nehalem/SandBridge/Haswell/Broadwell/Skylake uncore support */ #include "uncore.h" /* Uncore IMC PCI IDs */ @@ -9,6 +9,7 @@ #define PCI_DEVICE_ID_INTEL_HSW_U_IMC 0x0a04 #define PCI_DEVICE_ID_INTEL_BDW_IMC 0x1604 #define PCI_DEVICE_ID_INTEL_SKL_IMC 0x191f +#define PCI_DEVICE_ID_INTEL_SKL_U_IMC 0x190c /* SNB event control */ #define SNB_UNC_CTL_EV_SEL_MASK 0x000000ff @@ -64,6 +65,10 @@ #define NHM_UNC_PERFEVTSEL0 0x3c0 #define NHM_UNC_UNCORE_PMC0 0x3b0 +/* SKL uncore global control */ +#define SKL_UNC_PERF_GLOBAL_CTL 0xe01 +#define SKL_UNC_GLOBAL_CTL_CORE_ALL ((1 << 5) - 1) + DEFINE_UNCORE_FORMAT_ATTR(event, event, "config:0-7"); DEFINE_UNCORE_FORMAT_ATTR(umask, umask, "config:8-15"); DEFINE_UNCORE_FORMAT_ATTR(edge, edge, "config:18"); @@ -179,6 +184,60 @@ void snb_uncore_cpu_init(void) snb_uncore_cbox.num_boxes = boot_cpu_data.x86_max_cores; } +static void skl_uncore_msr_init_box(struct intel_uncore_box *box) +{ + if (box->pmu->pmu_idx == 0) { + wrmsrl(SKL_UNC_PERF_GLOBAL_CTL, + SNB_UNC_GLOBAL_CTL_EN | SKL_UNC_GLOBAL_CTL_CORE_ALL); + } +} + +static void skl_uncore_msr_exit_box(struct intel_uncore_box *box) +{ + if (box->pmu->pmu_idx == 0) + wrmsrl(SKL_UNC_PERF_GLOBAL_CTL, 0); +} + +static struct intel_uncore_ops skl_uncore_msr_ops = { + .init_box = skl_uncore_msr_init_box, + .exit_box = skl_uncore_msr_exit_box, + .disable_event = snb_uncore_msr_disable_event, + .enable_event = snb_uncore_msr_enable_event, + .read_counter = uncore_msr_read_counter, +}; + +static struct intel_uncore_type skl_uncore_cbox = { + .name = "cbox", + .num_counters = 4, + .num_boxes = 5, + .perf_ctr_bits = 44, + .fixed_ctr_bits = 48, + .perf_ctr = SNB_UNC_CBO_0_PER_CTR0, + .event_ctl = SNB_UNC_CBO_0_PERFEVTSEL0, + .fixed_ctr = SNB_UNC_FIXED_CTR, + .fixed_ctl = SNB_UNC_FIXED_CTR_CTRL, + .single_fixed = 1, + .event_mask = SNB_UNC_RAW_EVENT_MASK, + .msr_offset = SNB_UNC_CBO_MSR_OFFSET, + .ops = &skl_uncore_msr_ops, + .format_group = &snb_uncore_format_group, + .event_descs = snb_uncore_events, +}; + +static struct intel_uncore_type *skl_msr_uncores[] = { + &skl_uncore_cbox, + &snb_uncore_arb, + NULL, +}; + +void skl_uncore_cpu_init(void) +{ + uncore_msr_uncores = skl_msr_uncores; + if (skl_uncore_cbox.num_boxes > boot_cpu_data.x86_max_cores) + skl_uncore_cbox.num_boxes = boot_cpu_data.x86_max_cores; + snb_uncore_arb.ops = &skl_uncore_msr_ops; +} + enum { SNB_PCI_UNCORE_IMC, }; @@ -544,6 +603,11 @@ static const struct pci_device_id skl_uncore_pci_ids[] = { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_SKL_IMC), .driver_data = UNCORE_PCI_DEV_DATA(SNB_PCI_UNCORE_IMC, 0), }, + { /* IMC */ + PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_SKL_U_IMC), + .driver_data = UNCORE_PCI_DEV_DATA(SNB_PCI_UNCORE_IMC, 0), + }, + { /* end: all zeroes */ }, }; @@ -587,6 +651,7 @@ static const struct imc_uncore_pci_dev desktop_imc_pci_ids[] = { IMC_DEV(HSW_U_IMC, &hsw_uncore_pci_driver), /* 4th Gen Core ULT Mobile Processor */ IMC_DEV(BDW_IMC, &bdw_uncore_pci_driver), /* 5th Gen Core U */ IMC_DEV(SKL_IMC, &skl_uncore_pci_driver), /* 6th Gen Core */ + IMC_DEV(SKL_U_IMC, &skl_uncore_pci_driver), /* 6th Gen Core U */ { /* end marker */ } }; -- cgit v0.10.2 From 885885f6b88d22f81e67ee6a61561e480b27d27a Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Fri, 17 Jun 2016 17:19:40 +0000 Subject: locking/static_keys: Fix non static symbol Sparse warning Fix the following sparse warnings: kernel/jump_label.c:473:23: warning: symbol 'jump_label_module_nb' was not declared. Should it be static? Signed-off-by: Wei Yongjun Signed-off-by: Peter Zijlstra (Intel) Cc: Andrew Morton Cc: Linus Torvalds Cc: Paul E. McKenney Cc: Peter Zijlstra Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/1466183980-8903-1-git-send-email-weiyj_lk@163.com Signed-off-by: Ingo Molnar diff --git a/kernel/jump_label.c b/kernel/jump_label.c index 05254ee..ac4ab95 100644 --- a/kernel/jump_label.c +++ b/kernel/jump_label.c @@ -422,7 +422,7 @@ jump_label_module_notify(struct notifier_block *self, unsigned long val, return notifier_from_errno(ret); } -struct notifier_block jump_label_module_nb = { +static struct notifier_block jump_label_module_nb = { .notifier_call = jump_label_module_notify, .priority = 1, /* higher than tracepoints */ }; -- cgit v0.10.2 From 03e3c2b7edbe1e8758196b2c7843333eb328063d Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Mon, 27 Jun 2016 18:43:54 +0100 Subject: locking/barriers, arch/arm64: Implement LDXR+WFE based smp_cond_load_acquire() smp_cond_load_acquire() is used to spin on a variable until some expression involving that variable becomes true. On arm64, we can build this using the LDXR and WFE instructions, since clearing of the exclusive monitor as a result of the variable being changed by another CPU generates an event, which will wake us up out of WFE. This patch implements smp_cond_load_acquire() using LDXR and WFE, which themselves are contained in an internal __cmpwait() function. Signed-off-by: Will Deacon Signed-off-by: Peter Zijlstra (Intel) Cc: Andrew Morton Cc: Linus Torvalds Cc: Paul E. McKenney Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: catalin.marinas@arm.com Cc: linux-arm-kernel@lists.infradead.org Link: http://lkml.kernel.org/r/1467049434-30451-1-git-send-email-will.deacon@arm.com Signed-off-by: Ingo Molnar diff --git a/arch/arm64/include/asm/barrier.h b/arch/arm64/include/asm/barrier.h index dae5c49..4eea7f6 100644 --- a/arch/arm64/include/asm/barrier.h +++ b/arch/arm64/include/asm/barrier.h @@ -91,6 +91,19 @@ do { \ __u.__val; \ }) +#define smp_cond_load_acquire(ptr, cond_expr) \ +({ \ + typeof(ptr) __PTR = (ptr); \ + typeof(*ptr) VAL; \ + for (;;) { \ + VAL = smp_load_acquire(__PTR); \ + if (cond_expr) \ + break; \ + __cmpwait_relaxed(__PTR, VAL); \ + } \ + VAL; \ +}) + #include #endif /* __ASSEMBLY__ */ diff --git a/arch/arm64/include/asm/cmpxchg.h b/arch/arm64/include/asm/cmpxchg.h index 510c7b4..bd86a79 100644 --- a/arch/arm64/include/asm/cmpxchg.h +++ b/arch/arm64/include/asm/cmpxchg.h @@ -224,4 +224,55 @@ __CMPXCHG_GEN(_mb) __ret; \ }) +#define __CMPWAIT_CASE(w, sz, name) \ +static inline void __cmpwait_case_##name(volatile void *ptr, \ + unsigned long val) \ +{ \ + unsigned long tmp; \ + \ + asm volatile( \ + " ldxr" #sz "\t%" #w "[tmp], %[v]\n" \ + " eor %" #w "[tmp], %" #w "[tmp], %" #w "[val]\n" \ + " cbnz %" #w "[tmp], 1f\n" \ + " wfe\n" \ + "1:" \ + : [tmp] "=&r" (tmp), [v] "+Q" (*(unsigned long *)ptr) \ + : [val] "r" (val)); \ +} + +__CMPWAIT_CASE(w, b, 1); +__CMPWAIT_CASE(w, h, 2); +__CMPWAIT_CASE(w, , 4); +__CMPWAIT_CASE( , , 8); + +#undef __CMPWAIT_CASE + +#define __CMPWAIT_GEN(sfx) \ +static inline void __cmpwait##sfx(volatile void *ptr, \ + unsigned long val, \ + int size) \ +{ \ + switch (size) { \ + case 1: \ + return __cmpwait_case##sfx##_1(ptr, (u8)val); \ + case 2: \ + return __cmpwait_case##sfx##_2(ptr, (u16)val); \ + case 4: \ + return __cmpwait_case##sfx##_4(ptr, val); \ + case 8: \ + return __cmpwait_case##sfx##_8(ptr, val); \ + default: \ + BUILD_BUG(); \ + } \ + \ + unreachable(); \ +} + +__CMPWAIT_GEN() + +#undef __CMPWAIT_GEN + +#define __cmpwait_relaxed(ptr, val) \ + __cmpwait((ptr), (unsigned long)(val), sizeof(*(ptr))) + #endif /* __ASM_CMPXCHG_H */ -- cgit v0.10.2 From f06628638cf6e75f179742b6c1b35076965b9fdd Mon Sep 17 00:00:00 2001 From: Davidlohr Bueso Date: Tue, 28 Jun 2016 14:56:51 -0700 Subject: locking/atomic: Introduce inc/dec variants for the atomic_fetch_$op() API With the inclusion of atomic FETCH-OP variants, many places in the kernel can make use of atomic_fetch_$op() to avoid the callers that need to compute the value/state _before_ the operation. Peter Zijlstra laid out the machinery but we are still missing the simpler dec,inc() calls (which future patches will make use of). This patch only deals with the generic code, as at least right now no arch actually implement them -- which is similar to what the OP-RETURN primitives currently do. Signed-off-by: Davidlohr Bueso Signed-off-by: Peter Zijlstra (Intel) Cc: Andrew Morton Cc: James.Bottomley@HansenPartnership.com Cc: Linus Torvalds Cc: Paul E. McKenney Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: awalls@md.metrocast.net Cc: bp@alien8.de Cc: cw00.choi@samsung.com Cc: davem@davemloft.net Cc: dledford@redhat.com Cc: dougthompson@xmission.com Cc: gregkh@linuxfoundation.org Cc: hans.verkuil@cisco.com Cc: heiko.carstens@de.ibm.com Cc: jikos@kernel.org Cc: kys@microsoft.com Cc: mchehab@osg.samsung.com Cc: pfg@sgi.com Cc: schwidefsky@de.ibm.com Cc: sean.hefty@intel.com Cc: sumit.semwal@linaro.org Link: http://lkml.kernel.org/r/20160628215651.GA20048@linux-80c1.suse Signed-off-by: Ingo Molnar diff --git a/include/asm-generic/atomic-long.h b/include/asm-generic/atomic-long.h index 2d0d3cf..288cc9e 100644 --- a/include/asm-generic/atomic-long.h +++ b/include/asm-generic/atomic-long.h @@ -146,6 +146,28 @@ ATOMIC_LONG_FETCH_OP(xor, _relaxed) ATOMIC_LONG_FETCH_OP(xor, _acquire) ATOMIC_LONG_FETCH_OP(xor, _release) +#undef ATOMIC_LONG_FETCH_OP + +#define ATOMIC_LONG_FETCH_INC_DEC_OP(op, mo) \ +static inline long \ +atomic_long_fetch_##op##mo(atomic_long_t *l) \ +{ \ + ATOMIC_LONG_PFX(_t) *v = (ATOMIC_LONG_PFX(_t) *)l; \ + \ + return (long)ATOMIC_LONG_PFX(_fetch_##op##mo)(v); \ +} + +ATOMIC_LONG_FETCH_INC_DEC_OP(inc,) +ATOMIC_LONG_FETCH_INC_DEC_OP(inc, _relaxed) +ATOMIC_LONG_FETCH_INC_DEC_OP(inc, _acquire) +ATOMIC_LONG_FETCH_INC_DEC_OP(inc, _release) +ATOMIC_LONG_FETCH_INC_DEC_OP(dec,) +ATOMIC_LONG_FETCH_INC_DEC_OP(dec, _relaxed) +ATOMIC_LONG_FETCH_INC_DEC_OP(dec, _acquire) +ATOMIC_LONG_FETCH_INC_DEC_OP(dec, _release) + +#undef ATOMIC_LONG_FETCH_INC_DEC_OP + #define ATOMIC_LONG_OP(op) \ static __always_inline void \ atomic_long_##op(long i, atomic_long_t *l) \ diff --git a/include/linux/atomic.h b/include/linux/atomic.h index 12d910d..e71835b 100644 --- a/include/linux/atomic.h +++ b/include/linux/atomic.h @@ -188,6 +188,38 @@ #endif #endif /* atomic_fetch_add_relaxed */ +/* atomic_fetch_inc_relaxed */ +#ifndef atomic_fetch_inc_relaxed + +#ifndef atomic_fetch_inc +#define atomic_fetch_inc(v) atomic_fetch_add(1, (v)) +#define atomic_fetch_inc_relaxed(v) atomic_fetch_add_relaxed(1, (v)) +#define atomic_fetch_inc_acquire(v) atomic_fetch_add_acquire(1, (v)) +#define atomic_fetch_inc_release(v) atomic_fetch_add_release(1, (v)) +#else /* atomic_fetch_inc */ +#define atomic_fetch_inc_relaxed atomic_fetch_inc +#define atomic_fetch_inc_acquire atomic_fetch_inc +#define atomic_fetch_inc_release atomic_fetch_inc +#endif /* atomic_fetch_inc */ + +#else /* atomic_fetch_inc_relaxed */ + +#ifndef atomic_fetch_inc_acquire +#define atomic_fetch_inc_acquire(...) \ + __atomic_op_acquire(atomic_fetch_inc, __VA_ARGS__) +#endif + +#ifndef atomic_fetch_inc_release +#define atomic_fetch_inc_release(...) \ + __atomic_op_release(atomic_fetch_inc, __VA_ARGS__) +#endif + +#ifndef atomic_fetch_inc +#define atomic_fetch_inc(...) \ + __atomic_op_fence(atomic_fetch_inc, __VA_ARGS__) +#endif +#endif /* atomic_fetch_inc_relaxed */ + /* atomic_fetch_sub_relaxed */ #ifndef atomic_fetch_sub_relaxed #define atomic_fetch_sub_relaxed atomic_fetch_sub @@ -212,6 +244,38 @@ #endif #endif /* atomic_fetch_sub_relaxed */ +/* atomic_fetch_dec_relaxed */ +#ifndef atomic_fetch_dec_relaxed + +#ifndef atomic_fetch_dec +#define atomic_fetch_dec(v) atomic_fetch_sub(1, (v)) +#define atomic_fetch_dec_relaxed(v) atomic_fetch_sub_relaxed(1, (v)) +#define atomic_fetch_dec_acquire(v) atomic_fetch_sub_acquire(1, (v)) +#define atomic_fetch_dec_release(v) atomic_fetch_sub_release(1, (v)) +#else /* atomic_fetch_dec */ +#define atomic_fetch_dec_relaxed atomic_fetch_dec +#define atomic_fetch_dec_acquire atomic_fetch_dec +#define atomic_fetch_dec_release atomic_fetch_dec +#endif /* atomic_fetch_dec */ + +#else /* atomic_fetch_dec_relaxed */ + +#ifndef atomic_fetch_dec_acquire +#define atomic_fetch_dec_acquire(...) \ + __atomic_op_acquire(atomic_fetch_dec, __VA_ARGS__) +#endif + +#ifndef atomic_fetch_dec_release +#define atomic_fetch_dec_release(...) \ + __atomic_op_release(atomic_fetch_dec, __VA_ARGS__) +#endif + +#ifndef atomic_fetch_dec +#define atomic_fetch_dec(...) \ + __atomic_op_fence(atomic_fetch_dec, __VA_ARGS__) +#endif +#endif /* atomic_fetch_dec_relaxed */ + /* atomic_fetch_or_relaxed */ #ifndef atomic_fetch_or_relaxed #define atomic_fetch_or_relaxed atomic_fetch_or @@ -697,6 +761,38 @@ static inline int atomic_dec_if_positive(atomic_t *v) #endif #endif /* atomic64_fetch_add_relaxed */ +/* atomic64_fetch_inc_relaxed */ +#ifndef atomic64_fetch_inc_relaxed + +#ifndef atomic64_fetch_inc +#define atomic64_fetch_inc(v) atomic64_fetch_add(1, (v)) +#define atomic64_fetch_inc_relaxed(v) atomic64_fetch_add_relaxed(1, (v)) +#define atomic64_fetch_inc_acquire(v) atomic64_fetch_add_acquire(1, (v)) +#define atomic64_fetch_inc_release(v) atomic64_fetch_add_release(1, (v)) +#else /* atomic64_fetch_inc */ +#define atomic64_fetch_inc_relaxed atomic64_fetch_inc +#define atomic64_fetch_inc_acquire atomic64_fetch_inc +#define atomic64_fetch_inc_release atomic64_fetch_inc +#endif /* atomic64_fetch_inc */ + +#else /* atomic64_fetch_inc_relaxed */ + +#ifndef atomic64_fetch_inc_acquire +#define atomic64_fetch_inc_acquire(...) \ + __atomic_op_acquire(atomic64_fetch_inc, __VA_ARGS__) +#endif + +#ifndef atomic64_fetch_inc_release +#define atomic64_fetch_inc_release(...) \ + __atomic_op_release(atomic64_fetch_inc, __VA_ARGS__) +#endif + +#ifndef atomic64_fetch_inc +#define atomic64_fetch_inc(...) \ + __atomic_op_fence(atomic64_fetch_inc, __VA_ARGS__) +#endif +#endif /* atomic64_fetch_inc_relaxed */ + /* atomic64_fetch_sub_relaxed */ #ifndef atomic64_fetch_sub_relaxed #define atomic64_fetch_sub_relaxed atomic64_fetch_sub @@ -721,6 +817,38 @@ static inline int atomic_dec_if_positive(atomic_t *v) #endif #endif /* atomic64_fetch_sub_relaxed */ +/* atomic64_fetch_dec_relaxed */ +#ifndef atomic64_fetch_dec_relaxed + +#ifndef atomic64_fetch_dec +#define atomic64_fetch_dec(v) atomic64_fetch_sub(1, (v)) +#define atomic64_fetch_dec_relaxed(v) atomic64_fetch_sub_relaxed(1, (v)) +#define atomic64_fetch_dec_acquire(v) atomic64_fetch_sub_acquire(1, (v)) +#define atomic64_fetch_dec_release(v) atomic64_fetch_sub_release(1, (v)) +#else /* atomic64_fetch_dec */ +#define atomic64_fetch_dec_relaxed atomic64_fetch_dec +#define atomic64_fetch_dec_acquire atomic64_fetch_dec +#define atomic64_fetch_dec_release atomic64_fetch_dec +#endif /* atomic64_fetch_dec */ + +#else /* atomic64_fetch_dec_relaxed */ + +#ifndef atomic64_fetch_dec_acquire +#define atomic64_fetch_dec_acquire(...) \ + __atomic_op_acquire(atomic64_fetch_dec, __VA_ARGS__) +#endif + +#ifndef atomic64_fetch_dec_release +#define atomic64_fetch_dec_release(...) \ + __atomic_op_release(atomic64_fetch_dec, __VA_ARGS__) +#endif + +#ifndef atomic64_fetch_dec +#define atomic64_fetch_dec(...) \ + __atomic_op_fence(atomic64_fetch_dec, __VA_ARGS__) +#endif +#endif /* atomic64_fetch_dec_relaxed */ + /* atomic64_fetch_or_relaxed */ #ifndef atomic64_fetch_or_relaxed #define atomic64_fetch_or_relaxed atomic64_fetch_or -- cgit v0.10.2 From 34c720a915857f168b98ab03f97b33784286e4ad Mon Sep 17 00:00:00 2001 From: Christophe Jaillet Date: Wed, 6 Jul 2016 07:35:23 +0200 Subject: clocksource/drivers/cadence_ttc: fix a return value in case of error MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit IS_ERR and PTR_ERR should use the same variable, clk_ce in this case. Fixes: 4de1eb07c47f (Convert init function to return error) Signed-off-by: Christophe JAILLET Acked-by: Sören Brinkmann diff --git a/drivers/clocksource/cadence_ttc_timer.c b/drivers/clocksource/cadence_ttc_timer.c index 388a77b..fbfbdec 100644 --- a/drivers/clocksource/cadence_ttc_timer.c +++ b/drivers/clocksource/cadence_ttc_timer.c @@ -523,7 +523,7 @@ static int __init ttc_timer_init(struct device_node *timer) clk_ce = of_clk_get(timer, clksel); if (IS_ERR(clk_ce)) { pr_err("ERROR: timer input clock not found\n"); - return PTR_ERR(clk_cs); + return PTR_ERR(clk_ce); } ret = ttc_setup_clocksource(clk_cs, timer_baseaddr, timer_width); -- cgit v0.10.2 From e675447bda51c1ea72d1ac9132ce3bed974f1da3 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Mon, 4 Jul 2016 09:50:15 +0000 Subject: timers: Make 'pinned' a timer property We want to move the timer migration logic from a 'push' to a 'pull' model. Under the current 'push' model pinned timers are handled via a runtime API variant: mod_timer_pinned(). The 'pull' model requires us to store the pinned attribute of a timer in the timer_list structure itself, as a new TIMER_PINNED bit in timer->flags. This flag must be set at initialization time and the timer APIs recognize the flag. This patch: - Implements the new flag and associated new-style initialization methods - makes mod_timer() recognize new-style pinned timers, - and adds some migration helper facility to allow step by step conversion of old-style to new-style pinned timers. Signed-off-by: Thomas Gleixner Reviewed-by: Frederic Weisbecker Cc: Arjan van de Ven Cc: Chris Mason Cc: Eric Dumazet Cc: George Spelvin Cc: Josh Triplett Cc: Len Brown Cc: Linus Torvalds Cc: Paul E. McKenney Cc: Peter Zijlstra Cc: Rik van Riel Cc: rt@linutronix.de Link: http://lkml.kernel.org/r/20160704094341.049338558@linutronix.de Signed-off-by: Ingo Molnar diff --git a/include/linux/timer.h b/include/linux/timer.h index 20ac746..046d6cf 100644 --- a/include/linux/timer.h +++ b/include/linux/timer.h @@ -62,7 +62,8 @@ struct timer_list { #define TIMER_MIGRATING 0x00080000 #define TIMER_BASEMASK (TIMER_CPUMASK | TIMER_MIGRATING) #define TIMER_DEFERRABLE 0x00100000 -#define TIMER_IRQSAFE 0x00200000 +#define TIMER_PINNED 0x00200000 +#define TIMER_IRQSAFE 0x00400000 #define __TIMER_INITIALIZER(_function, _expires, _data, _flags) { \ .entry = { .next = TIMER_ENTRY_STATIC }, \ @@ -78,9 +79,15 @@ struct timer_list { #define TIMER_INITIALIZER(_function, _expires, _data) \ __TIMER_INITIALIZER((_function), (_expires), (_data), 0) +#define TIMER_PINNED_INITIALIZER(_function, _expires, _data) \ + __TIMER_INITIALIZER((_function), (_expires), (_data), TIMER_PINNED) + #define TIMER_DEFERRED_INITIALIZER(_function, _expires, _data) \ __TIMER_INITIALIZER((_function), (_expires), (_data), TIMER_DEFERRABLE) +#define TIMER_PINNED_DEFERRED_INITIALIZER(_function, _expires, _data) \ + __TIMER_INITIALIZER((_function), (_expires), (_data), TIMER_DEFERRABLE | TIMER_PINNED) + #define DEFINE_TIMER(_name, _function, _expires, _data) \ struct timer_list _name = \ TIMER_INITIALIZER(_function, _expires, _data) @@ -124,8 +131,12 @@ static inline void init_timer_on_stack_key(struct timer_list *timer, #define init_timer(timer) \ __init_timer((timer), 0) +#define init_timer_pinned(timer) \ + __init_timer((timer), TIMER_PINNED) #define init_timer_deferrable(timer) \ __init_timer((timer), TIMER_DEFERRABLE) +#define init_timer_pinned_deferrable(timer) \ + __init_timer((timer), TIMER_DEFERRABLE | TIMER_PINNED) #define init_timer_on_stack(timer) \ __init_timer_on_stack((timer), 0) @@ -145,12 +156,20 @@ static inline void init_timer_on_stack_key(struct timer_list *timer, #define setup_timer(timer, fn, data) \ __setup_timer((timer), (fn), (data), 0) +#define setup_pinned_timer(timer, fn, data) \ + __setup_timer((timer), (fn), (data), TIMER_PINNED) #define setup_deferrable_timer(timer, fn, data) \ __setup_timer((timer), (fn), (data), TIMER_DEFERRABLE) +#define setup_pinned_deferrable_timer(timer, fn, data) \ + __setup_timer((timer), (fn), (data), TIMER_DEFERRABLE | TIMER_PINNED) #define setup_timer_on_stack(timer, fn, data) \ __setup_timer_on_stack((timer), (fn), (data), 0) +#define setup_pinned_timer_on_stack(timer, fn, data) \ + __setup_timer_on_stack((timer), (fn), (data), TIMER_PINNED) #define setup_deferrable_timer_on_stack(timer, fn, data) \ __setup_timer_on_stack((timer), (fn), (data), TIMER_DEFERRABLE) +#define setup_pinned_deferrable_timer_on_stack(timer, fn, data) \ + __setup_timer_on_stack((timer), (fn), (data), TIMER_DEFERRABLE | TIMER_PINNED) /** * timer_pending - is a timer pending? @@ -175,8 +194,8 @@ extern int mod_timer_pinned(struct timer_list *timer, unsigned long expires); extern void set_timer_slack(struct timer_list *time, int slack_hz); -#define TIMER_NOT_PINNED 0 -#define TIMER_PINNED 1 +#define MOD_TIMER_NOT_PINNED 0 +#define MOD_TIMER_PINNED 1 /* * The jiffies value which is added to now, when there is no timer * in the timer wheel: diff --git a/kernel/time/timer.c b/kernel/time/timer.c index 3a95f97..693f6d1 100644 --- a/kernel/time/timer.c +++ b/kernel/time/timer.c @@ -782,7 +782,7 @@ __mod_timer(struct timer_list *timer, unsigned long expires, debug_activate(timer, expires); - new_base = get_target_base(base, pinned); + new_base = get_target_base(base, pinned || timer->flags & TIMER_PINNED); if (base != new_base) { /* @@ -825,7 +825,7 @@ out_unlock: */ int mod_timer_pending(struct timer_list *timer, unsigned long expires) { - return __mod_timer(timer, expires, true, TIMER_NOT_PINNED); + return __mod_timer(timer, expires, true, MOD_TIMER_NOT_PINNED); } EXPORT_SYMBOL(mod_timer_pending); @@ -900,7 +900,7 @@ int mod_timer(struct timer_list *timer, unsigned long expires) if (timer_pending(timer) && timer->expires == expires) return 1; - return __mod_timer(timer, expires, false, TIMER_NOT_PINNED); + return __mod_timer(timer, expires, false, MOD_TIMER_NOT_PINNED); } EXPORT_SYMBOL(mod_timer); @@ -928,7 +928,7 @@ int mod_timer_pinned(struct timer_list *timer, unsigned long expires) if (timer->expires == expires && timer_pending(timer)) return 1; - return __mod_timer(timer, expires, false, TIMER_PINNED); + return __mod_timer(timer, expires, false, MOD_TIMER_PINNED); } EXPORT_SYMBOL(mod_timer_pinned); @@ -1512,7 +1512,7 @@ signed long __sched schedule_timeout(signed long timeout) expire = timeout + jiffies; setup_timer_on_stack(&timer, process_timeout, (unsigned long)current); - __mod_timer(&timer, expire, false, TIMER_NOT_PINNED); + __mod_timer(&timer, expire, false, MOD_TIMER_NOT_PINNED); schedule(); del_singleshot_timer_sync(&timer); -- cgit v0.10.2 From 920a4a70c55058a9997f2e35bf41503acf87c301 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Mon, 4 Jul 2016 09:50:16 +0000 Subject: timers, x86/apic/uv: Initialize the UV heartbeat timer as pinned Pinned timers must carry the pinned attribute in the timer structure itself, so convert the code to the new API. No functional change. Signed-off-by: Thomas Gleixner Reviewed-by: Frederic Weisbecker Cc: Arjan van de Ven Cc: Chris Mason Cc: Eric Dumazet Cc: George Spelvin Cc: Josh Triplett Cc: Len Brown Cc: Linus Torvalds Cc: Paul E. McKenney Cc: Peter Zijlstra Cc: Rik van Riel Cc: rt@linutronix.de Link: http://lkml.kernel.org/r/20160704094341.133837204@linutronix.de Signed-off-by: Ingo Molnar diff --git a/arch/x86/kernel/apic/x2apic_uv_x.c b/arch/x86/kernel/apic/x2apic_uv_x.c index 2900315..7a50519 100644 --- a/arch/x86/kernel/apic/x2apic_uv_x.c +++ b/arch/x86/kernel/apic/x2apic_uv_x.c @@ -919,7 +919,7 @@ static void uv_heartbeat(unsigned long ignored) uv_set_scir_bits(bits); /* enable next timer period */ - mod_timer_pinned(timer, jiffies + SCIR_CPU_HB_INTERVAL); + mod_timer(timer, jiffies + SCIR_CPU_HB_INTERVAL); } static void uv_heartbeat_enable(int cpu) @@ -928,7 +928,7 @@ static void uv_heartbeat_enable(int cpu) struct timer_list *timer = &uv_cpu_scir_info(cpu)->timer; uv_set_cpu_scir_bits(cpu, SCIR_CPU_HEARTBEAT|SCIR_CPU_ACTIVITY); - setup_timer(timer, uv_heartbeat, cpu); + setup_pinned_timer(timer, uv_heartbeat, cpu); timer->expires = jiffies + SCIR_CPU_HB_INTERVAL; add_timer_on(timer, cpu); uv_cpu_scir_info(cpu)->enabled = 1; -- cgit v0.10.2 From f9c287ba3861714a1959accf14e815c44291bec4 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Mon, 4 Jul 2016 09:50:17 +0000 Subject: timers, x86/mce: Initialize MCE restart timer as pinned Pinned timers must carry the pinned attribute in the timer structure itself, so convert the code to the new API. No functional change. Signed-off-by: Thomas Gleixner Reviewed-by: Frederic Weisbecker Cc: Arjan van de Ven Cc: Chris Mason Cc: Eric Dumazet Cc: George Spelvin Cc: Josh Triplett Cc: Len Brown Cc: Linus Torvalds Cc: Paul E. McKenney Cc: Peter Zijlstra Cc: Rik van Riel Cc: rt@linutronix.de Link: http://lkml.kernel.org/r/20160704094341.215783439@linutronix.de Signed-off-by: Ingo Molnar diff --git a/arch/x86/kernel/cpu/mcheck/mce.c b/arch/x86/kernel/cpu/mcheck/mce.c index 92e5e37..b80a636 100644 --- a/arch/x86/kernel/cpu/mcheck/mce.c +++ b/arch/x86/kernel/cpu/mcheck/mce.c @@ -1309,7 +1309,7 @@ static void __restart_timer(struct timer_list *t, unsigned long interval) if (timer_pending(t)) { if (time_before(when, t->expires)) - mod_timer_pinned(t, when); + mod_timer(t, when); } else { t->expires = round_jiffies(when); add_timer_on(t, smp_processor_id()); @@ -1735,7 +1735,7 @@ static void __mcheck_cpu_init_timer(void) struct timer_list *t = this_cpu_ptr(&mce_timer); unsigned int cpu = smp_processor_id(); - setup_timer(t, mce_timer_fn, cpu); + setup_pinned_timer(t, mce_timer_fn, cpu); mce_start_timer(cpu, t); } -- cgit v0.10.2 From 7bc54b652f13119f64e87dd96bb792efbfc5a786 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Mon, 4 Jul 2016 09:50:18 +0000 Subject: timers, cpufreq/powernv: Initialize the gpstate timer as pinned Pinned timers must carry the pinned attribute in the timer structure itself, so convert the code to the new API. No functional change. Signed-off-by: Thomas Gleixner Reviewed-by: Frederic Weisbecker Cc: Arjan van de Ven Cc: Chris Mason Cc: Eric Dumazet Cc: George Spelvin Cc: Josh Triplett Cc: Len Brown Cc: Linus Torvalds Cc: Paul E. McKenney Cc: Peter Zijlstra Cc: Rik van Riel Cc: rt@linutronix.de Link: http://lkml.kernel.org/r/20160704094341.297014487@linutronix.de Signed-off-by: Ingo Molnar diff --git a/drivers/cpufreq/powernv-cpufreq.c b/drivers/cpufreq/powernv-cpufreq.c index 54c4536..6bd715b 100644 --- a/drivers/cpufreq/powernv-cpufreq.c +++ b/drivers/cpufreq/powernv-cpufreq.c @@ -530,8 +530,7 @@ static inline void queue_gpstate_timer(struct global_pstate_info *gpstates) else timer_interval = GPSTATE_TIMER_INTERVAL; - mod_timer_pinned(&gpstates->timer, jiffies + - msecs_to_jiffies(timer_interval)); + mod_timer(&gpstates->timer, jiffies + msecs_to_jiffies(timer_interval)); } /** @@ -699,7 +698,7 @@ static int powernv_cpufreq_cpu_init(struct cpufreq_policy *policy) policy->driver_data = gpstates; /* initialize timer */ - init_timer_deferrable(&gpstates->timer); + init_timer_pinned_deferrable(&gpstates->timer); gpstates->timer.data = (unsigned long)policy; gpstates->timer.function = gpstate_timer_handler; gpstates->timer.expires = jiffies + -- cgit v0.10.2 From 25df57605edbe92b6f4215226bd40e1a465ef6b4 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Mon, 4 Jul 2016 09:50:19 +0000 Subject: timers, driver/net/ethernet/tile: Initialize the egress timer as pinned Pinned timers must carry the pinned attribute in the timer structure itself, so convert the code to the new API. No functional change. Signed-off-by: Thomas Gleixner Reviewed-by: Frederic Weisbecker Cc: Arjan van de Ven Cc: Chris Mason Cc: Eric Dumazet Cc: George Spelvin Cc: Josh Triplett Cc: Len Brown Cc: Linus Torvalds Cc: Paul E. McKenney Cc: Peter Zijlstra Cc: Rik van Riel Cc: rt@linutronix.de Link: http://lkml.kernel.org/r/20160704094341.376394205@linutronix.de Signed-off-by: Ingo Molnar diff --git a/drivers/net/ethernet/tile/tilepro.c b/drivers/net/ethernet/tile/tilepro.c index 922a443..4ef605a 100644 --- a/drivers/net/ethernet/tile/tilepro.c +++ b/drivers/net/ethernet/tile/tilepro.c @@ -588,7 +588,7 @@ static bool tile_net_lepp_free_comps(struct net_device *dev, bool all) static void tile_net_schedule_egress_timer(struct tile_net_cpu *info) { if (!info->egress_timer_scheduled) { - mod_timer_pinned(&info->egress_timer, jiffies + 1); + mod_timer(&info->egress_timer, jiffies + 1); info->egress_timer_scheduled = true; } } @@ -1004,7 +1004,7 @@ static void tile_net_register(void *dev_ptr) BUG(); /* Initialize the egress timer. */ - init_timer(&info->egress_timer); + init_timer_pinned(&info->egress_timer); info->egress_timer.data = (long)info; info->egress_timer.function = tile_net_handle_egress_timer; -- cgit v0.10.2 From 01bab536b1fe982fcba8144e2ee11ac889a22f0e Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Mon, 4 Jul 2016 09:50:21 +0000 Subject: timers, drivers/tty/metag_da: Initialize the poll timer as pinned Pinned timers must carry the pinned attribute in the timer structure itself, so convert the code to the new API. No functional change. Signed-off-by: Thomas Gleixner Reviewed-by: Frederic Weisbecker Cc: Arjan van de Ven Cc: Chris Mason Cc: Eric Dumazet Cc: George Spelvin Cc: Josh Triplett Cc: Len Brown Cc: Linus Torvalds Cc: Paul E. McKenney Cc: Peter Zijlstra Cc: Rik van Riel Cc: rt@linutronix.de Link: http://lkml.kernel.org/r/20160704094341.456452642@linutronix.de Signed-off-by: Ingo Molnar diff --git a/drivers/tty/metag_da.c b/drivers/tty/metag_da.c index 9325262..25ccef2 100644 --- a/drivers/tty/metag_da.c +++ b/drivers/tty/metag_da.c @@ -323,12 +323,12 @@ static void dashtty_timer(unsigned long ignored) if (channel >= 0) fetch_data(channel); - mod_timer_pinned(&poll_timer, jiffies + DA_TTY_POLL); + mod_timer(&poll_timer, jiffies + DA_TTY_POLL); } static void add_poll_timer(struct timer_list *poll_timer) { - setup_timer(poll_timer, dashtty_timer, 0); + setup_pinned_timer(poll_timer, dashtty_timer, 0); poll_timer->expires = jiffies + DA_TTY_POLL; /* -- cgit v0.10.2 From 853f90d49bbabcf4e01c615402c1bea1871d7646 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Mon, 4 Jul 2016 09:50:22 +0000 Subject: timers, drivers/tty/mips_ejtag: Initialize the poll timer as pinned Pinned timers must carry the pinned attribute in the timer structure itself, so convert the code to the new API. No functional change. Signed-off-by: Thomas Gleixner Reviewed-by: Frederic Weisbecker Cc: Arjan van de Ven Cc: Chris Mason Cc: Eric Dumazet Cc: George Spelvin Cc: Josh Triplett Cc: Len Brown Cc: Linus Torvalds Cc: Paul E. McKenney Cc: Peter Zijlstra Cc: Rik van Riel Cc: rt@linutronix.de Link: http://lkml.kernel.org/r/20160704094341.537448301@linutronix.de Signed-off-by: Ingo Molnar diff --git a/drivers/tty/mips_ejtag_fdc.c b/drivers/tty/mips_ejtag_fdc.c index a119176..234123b 100644 --- a/drivers/tty/mips_ejtag_fdc.c +++ b/drivers/tty/mips_ejtag_fdc.c @@ -689,7 +689,7 @@ static void mips_ejtag_fdc_tty_timer(unsigned long opaque) mips_ejtag_fdc_handle(priv); if (!priv->removing) - mod_timer_pinned(&priv->poll_timer, jiffies + FDC_TTY_POLL); + mod_timer(&priv->poll_timer, jiffies + FDC_TTY_POLL); } /* TTY Port operations */ @@ -1002,7 +1002,7 @@ static int mips_ejtag_fdc_tty_probe(struct mips_cdmm_device *dev) raw_spin_unlock_irq(&priv->lock); } else { /* If we didn't get an usable IRQ, poll instead */ - setup_timer(&priv->poll_timer, mips_ejtag_fdc_tty_timer, + setup_pinned_timer(&priv->poll_timer, mips_ejtag_fdc_tty_timer, (unsigned long)priv); priv->poll_timer.expires = jiffies + FDC_TTY_POLL; /* -- cgit v0.10.2 From f3438bc7813c439a06104ba074301c8bdd64ac8b Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Mon, 4 Jul 2016 09:50:23 +0000 Subject: timers, net/ipv4/inet: Initialize connection request timers as pinned Pinned timers must carry the pinned attribute in the timer structure itself, so convert the code to the new API. No functional change. Signed-off-by: Thomas Gleixner Reviewed-by: Frederic Weisbecker Cc: Arjan van de Ven Cc: Chris Mason Cc: Eric Dumazet Cc: George Spelvin Cc: Josh Triplett Cc: Len Brown Cc: Linus Torvalds Cc: Paul E. McKenney Cc: Peter Zijlstra Cc: Rik van Riel Cc: rt@linutronix.de Link: http://lkml.kernel.org/r/20160704094341.617891430@linutronix.de Signed-off-by: Ingo Molnar diff --git a/net/ipv4/inet_connection_sock.c b/net/ipv4/inet_connection_sock.c index fa8c398..61a9dee 100644 --- a/net/ipv4/inet_connection_sock.c +++ b/net/ipv4/inet_connection_sock.c @@ -603,7 +603,7 @@ static void reqsk_timer_handler(unsigned long data) if (req->num_timeout++ == 0) atomic_dec(&queue->young); timeo = min(TCP_TIMEOUT_INIT << req->num_timeout, TCP_RTO_MAX); - mod_timer_pinned(&req->rsk_timer, jiffies + timeo); + mod_timer(&req->rsk_timer, jiffies + timeo); return; } drop: @@ -617,8 +617,9 @@ static void reqsk_queue_hash_req(struct request_sock *req, req->num_timeout = 0; req->sk = NULL; - setup_timer(&req->rsk_timer, reqsk_timer_handler, (unsigned long)req); - mod_timer_pinned(&req->rsk_timer, jiffies + timeout); + setup_pinned_timer(&req->rsk_timer, reqsk_timer_handler, + (unsigned long)req); + mod_timer(&req->rsk_timer, jiffies + timeout); inet_ehash_insert(req_to_sk(req), NULL); /* before letting lookups find us, make sure all req fields diff --git a/net/ipv4/inet_timewait_sock.c b/net/ipv4/inet_timewait_sock.c index 2065816..ddcd56c 100644 --- a/net/ipv4/inet_timewait_sock.c +++ b/net/ipv4/inet_timewait_sock.c @@ -188,7 +188,8 @@ struct inet_timewait_sock *inet_twsk_alloc(const struct sock *sk, tw->tw_prot = sk->sk_prot_creator; atomic64_set(&tw->tw_cookie, atomic64_read(&sk->sk_cookie)); twsk_net_set(tw, sock_net(sk)); - setup_timer(&tw->tw_timer, tw_timer_handler, (unsigned long)tw); + setup_pinned_timer(&tw->tw_timer, tw_timer_handler, + (unsigned long)tw); /* * Because we use RCU lookups, we should not set tw_refcnt * to a non null value before everything is setup for this @@ -248,7 +249,7 @@ void __inet_twsk_schedule(struct inet_timewait_sock *tw, int timeo, bool rearm) tw->tw_kill = timeo <= 4*HZ; if (!rearm) { - BUG_ON(mod_timer_pinned(&tw->tw_timer, jiffies + timeo)); + BUG_ON(mod_timer(&tw->tw_timer, jiffies + timeo)); atomic_inc(&tw->tw_dr->tw_count); } else { mod_timer_pending(&tw->tw_timer, jiffies + timeo); -- cgit v0.10.2 From 177ec0a0a531695210b277d734b2f92ee5796303 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Mon, 4 Jul 2016 09:50:24 +0000 Subject: timers: Remove the deprecated mod_timer_pinned() API We switched all users to initialize the timers as pinned and call mod_timer(). Remove the now unused timer API function. Signed-off-by: Thomas Gleixner Reviewed-by: Frederic Weisbecker Cc: Arjan van de Ven Cc: Chris Mason Cc: Eric Dumazet Cc: George Spelvin Cc: Josh Triplett Cc: Len Brown Cc: Linus Torvalds Cc: Paul E. McKenney Cc: Peter Zijlstra Cc: Rik van Riel Cc: rt@linutronix.de Link: http://lkml.kernel.org/r/20160704094341.706205231@linutronix.de Signed-off-by: Ingo Molnar diff --git a/include/linux/timer.h b/include/linux/timer.h index 046d6cf..a8f6c70 100644 --- a/include/linux/timer.h +++ b/include/linux/timer.h @@ -190,12 +190,9 @@ extern void add_timer_on(struct timer_list *timer, int cpu); extern int del_timer(struct timer_list * timer); extern int mod_timer(struct timer_list *timer, unsigned long expires); extern int mod_timer_pending(struct timer_list *timer, unsigned long expires); -extern int mod_timer_pinned(struct timer_list *timer, unsigned long expires); extern void set_timer_slack(struct timer_list *time, int slack_hz); -#define MOD_TIMER_NOT_PINNED 0 -#define MOD_TIMER_PINNED 1 /* * The jiffies value which is added to now, when there is no timer * in the timer wheel: diff --git a/kernel/time/timer.c b/kernel/time/timer.c index 693f6d1..ba49c1c 100644 --- a/kernel/time/timer.c +++ b/kernel/time/timer.c @@ -764,8 +764,7 @@ static struct tvec_base *lock_timer_base(struct timer_list *timer, } static inline int -__mod_timer(struct timer_list *timer, unsigned long expires, - bool pending_only, int pinned) +__mod_timer(struct timer_list *timer, unsigned long expires, bool pending_only) { struct tvec_base *base, *new_base; unsigned long flags; @@ -782,7 +781,7 @@ __mod_timer(struct timer_list *timer, unsigned long expires, debug_activate(timer, expires); - new_base = get_target_base(base, pinned || timer->flags & TIMER_PINNED); + new_base = get_target_base(base, timer->flags & TIMER_PINNED); if (base != new_base) { /* @@ -825,7 +824,7 @@ out_unlock: */ int mod_timer_pending(struct timer_list *timer, unsigned long expires) { - return __mod_timer(timer, expires, true, MOD_TIMER_NOT_PINNED); + return __mod_timer(timer, expires, true); } EXPORT_SYMBOL(mod_timer_pending); @@ -900,39 +899,11 @@ int mod_timer(struct timer_list *timer, unsigned long expires) if (timer_pending(timer) && timer->expires == expires) return 1; - return __mod_timer(timer, expires, false, MOD_TIMER_NOT_PINNED); + return __mod_timer(timer, expires, false); } EXPORT_SYMBOL(mod_timer); /** - * mod_timer_pinned - modify a timer's timeout - * @timer: the timer to be modified - * @expires: new timeout in jiffies - * - * mod_timer_pinned() is a way to update the expire field of an - * active timer (if the timer is inactive it will be activated) - * and to ensure that the timer is scheduled on the current CPU. - * - * Note that this does not prevent the timer from being migrated - * when the current CPU goes offline. If this is a problem for - * you, use CPU-hotplug notifiers to handle it correctly, for - * example, cancelling the timer when the corresponding CPU goes - * offline. - * - * mod_timer_pinned(timer, expires) is equivalent to: - * - * del_timer(timer); timer->expires = expires; add_timer(timer); - */ -int mod_timer_pinned(struct timer_list *timer, unsigned long expires) -{ - if (timer->expires == expires && timer_pending(timer)) - return 1; - - return __mod_timer(timer, expires, false, MOD_TIMER_PINNED); -} -EXPORT_SYMBOL(mod_timer_pinned); - -/** * add_timer - start a timer * @timer: the timer to be added * @@ -1512,7 +1483,7 @@ signed long __sched schedule_timeout(signed long timeout) expire = timeout + jiffies; setup_timer_on_stack(&timer, process_timeout, (unsigned long)current); - __mod_timer(&timer, expire, false, MOD_TIMER_NOT_PINNED); + __mod_timer(&timer, expire, false); schedule(); del_singleshot_timer_sync(&timer); -- cgit v0.10.2 From 2b1ecc3d1a6b10f8fbac7f83d80db30b5a2c2791 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Mon, 4 Jul 2016 09:50:25 +0000 Subject: signals: Use hrtimer for sigtimedwait() We've converted most timeout related syscalls to hrtimers, but sigtimedwait() did not get this treatment. Convert it so we get a reasonable accuracy and remove the user space exposure to the timer wheel properties. Signed-off-by: Thomas Gleixner Reviewed-by: Frederic Weisbecker Cc: Al Viro Cc: Arjan van de Ven Cc: Chris Mason Cc: Cyril Hrubis Cc: George Spelvin Cc: Josh Triplett Cc: Len Brown Cc: Linus Torvalds Cc: Paul McKenney Cc: Peter Zijlstra Cc: Rik van Riel Cc: rt@linutronix.de Link: http://lkml.kernel.org/r/20160704094341.787164909@linutronix.de Signed-off-by: Ingo Molnar diff --git a/kernel/signal.c b/kernel/signal.c index 96e9bc4..af21afc 100644 --- a/kernel/signal.c +++ b/kernel/signal.c @@ -2751,23 +2751,18 @@ int copy_siginfo_to_user(siginfo_t __user *to, const siginfo_t *from) * @ts: upper bound on process time suspension */ int do_sigtimedwait(const sigset_t *which, siginfo_t *info, - const struct timespec *ts) + const struct timespec *ts) { + ktime_t *to = NULL, timeout = { .tv64 = KTIME_MAX }; struct task_struct *tsk = current; - long timeout = MAX_SCHEDULE_TIMEOUT; sigset_t mask = *which; - int sig; + int sig, ret = 0; if (ts) { if (!timespec_valid(ts)) return -EINVAL; - timeout = timespec_to_jiffies(ts); - /* - * We can be close to the next tick, add another one - * to ensure we will wait at least the time asked for. - */ - if (ts->tv_sec || ts->tv_nsec) - timeout++; + timeout = timespec_to_ktime(*ts); + to = &timeout; } /* @@ -2778,7 +2773,7 @@ int do_sigtimedwait(const sigset_t *which, siginfo_t *info, spin_lock_irq(&tsk->sighand->siglock); sig = dequeue_signal(tsk, &mask, info); - if (!sig && timeout) { + if (!sig && timeout.tv64) { /* * None ready, temporarily unblock those we're interested * while we are sleeping in so that we'll be awakened when @@ -2790,8 +2785,9 @@ int do_sigtimedwait(const sigset_t *which, siginfo_t *info, recalc_sigpending(); spin_unlock_irq(&tsk->sighand->siglock); - timeout = freezable_schedule_timeout_interruptible(timeout); - + __set_current_state(TASK_INTERRUPTIBLE); + ret = freezable_schedule_hrtimeout_range(to, tsk->timer_slack_ns, + HRTIMER_MODE_REL); spin_lock_irq(&tsk->sighand->siglock); __set_task_blocked(tsk, &tsk->real_blocked); sigemptyset(&tsk->real_blocked); @@ -2801,7 +2797,7 @@ int do_sigtimedwait(const sigset_t *which, siginfo_t *info, if (sig) return sig; - return timeout ? -EINTR : -EAGAIN; + return ret ? -EINTR : -EAGAIN; } /** -- cgit v0.10.2 From 15dba1e37b5cfd7fab9bc84e0f05f35c918f4eef Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Mon, 4 Jul 2016 09:50:27 +0000 Subject: hlist: Add hlist_is_singular_node() helper Required to figure out whether the entry is the only one in the hlist. Signed-off-by: Thomas Gleixner Reviewed-by: Frederic Weisbecker Cc: Arjan van de Ven Cc: Chris Mason Cc: Eric Dumazet Cc: George Spelvin Cc: Josh Triplett Cc: Len Brown Cc: Linus Torvalds Cc: Paul E. McKenney Cc: Peter Zijlstra Cc: Rik van Riel Cc: rt@linutronix.de Link: http://lkml.kernel.org/r/20160704094341.867631372@linutronix.de Signed-off-by: Ingo Molnar diff --git a/include/linux/list.h b/include/linux/list.h index 5356f4d..5183138 100644 --- a/include/linux/list.h +++ b/include/linux/list.h @@ -679,6 +679,16 @@ static inline bool hlist_fake(struct hlist_node *h) } /* + * Check whether the node is the only node of the head without + * accessing head: + */ +static inline bool +hlist_is_singular_node(struct hlist_node *n, struct hlist_head *h) +{ + return !n->next && n->pprev == &h->first; +} + +/* * Move a list from one list head to another. Fixup the pprev * reference of the first entry if it exists. */ -- cgit v0.10.2 From 494af3ed7848de08640d98ee5aff57a45c137c3c Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Mon, 4 Jul 2016 09:50:28 +0000 Subject: timers: Give a few structs and members proper names Some of the names in the internal implementation of the timer code are not longer correct and others are simply too long to type. Clean it up before we switch the wheel implementation over to the new scheme. No functional change. Signed-off-by: Thomas Gleixner Reviewed-by: Frederic Weisbecker Cc: Arjan van de Ven Cc: Chris Mason Cc: Eric Dumazet Cc: George Spelvin Cc: Josh Triplett Cc: Len Brown Cc: Linus Torvalds Cc: Paul E. McKenney Cc: Peter Zijlstra Cc: Rik van Riel Cc: rt@linutronix.de Link: http://lkml.kernel.org/r/20160704094341.948752516@linutronix.de Signed-off-by: Ingo Molnar diff --git a/kernel/time/timer.c b/kernel/time/timer.c index ba49c1c..f259a3e 100644 --- a/kernel/time/timer.c +++ b/kernel/time/timer.c @@ -77,10 +77,10 @@ struct tvec_root { struct hlist_head vec[TVR_SIZE]; }; -struct tvec_base { +struct timer_base { spinlock_t lock; struct timer_list *running_timer; - unsigned long timer_jiffies; + unsigned long clk; unsigned long next_timer; unsigned long active_timers; unsigned long all_timers; @@ -95,7 +95,7 @@ struct tvec_base { } ____cacheline_aligned; -static DEFINE_PER_CPU(struct tvec_base, tvec_bases); +static DEFINE_PER_CPU(struct timer_base, timer_bases); #if defined(CONFIG_SMP) && defined(CONFIG_NO_HZ_COMMON) unsigned int sysctl_timer_migration = 1; @@ -106,15 +106,15 @@ void timers_update_migration(bool update_nohz) unsigned int cpu; /* Avoid the loop, if nothing to update */ - if (this_cpu_read(tvec_bases.migration_enabled) == on) + if (this_cpu_read(timer_bases.migration_enabled) == on) return; for_each_possible_cpu(cpu) { - per_cpu(tvec_bases.migration_enabled, cpu) = on; + per_cpu(timer_bases.migration_enabled, cpu) = on; per_cpu(hrtimer_bases.migration_enabled, cpu) = on; if (!update_nohz) continue; - per_cpu(tvec_bases.nohz_active, cpu) = true; + per_cpu(timer_bases.nohz_active, cpu) = true; per_cpu(hrtimer_bases.nohz_active, cpu) = true; } } @@ -134,18 +134,18 @@ int timer_migration_handler(struct ctl_table *table, int write, return ret; } -static inline struct tvec_base *get_target_base(struct tvec_base *base, +static inline struct timer_base *get_target_base(struct timer_base *base, int pinned) { if (pinned || !base->migration_enabled) - return this_cpu_ptr(&tvec_bases); - return per_cpu_ptr(&tvec_bases, get_nohz_timer_target()); + return this_cpu_ptr(&timer_bases); + return per_cpu_ptr(&timer_bases, get_nohz_timer_target()); } #else -static inline struct tvec_base *get_target_base(struct tvec_base *base, +static inline struct timer_base *get_target_base(struct timer_base *base, int pinned) { - return this_cpu_ptr(&tvec_bases); + return this_cpu_ptr(&timer_bases); } #endif @@ -371,10 +371,10 @@ void set_timer_slack(struct timer_list *timer, int slack_hz) EXPORT_SYMBOL_GPL(set_timer_slack); static void -__internal_add_timer(struct tvec_base *base, struct timer_list *timer) +__internal_add_timer(struct timer_base *base, struct timer_list *timer) { unsigned long expires = timer->expires; - unsigned long idx = expires - base->timer_jiffies; + unsigned long idx = expires - base->clk; struct hlist_head *vec; if (idx < TVR_SIZE) { @@ -394,7 +394,7 @@ __internal_add_timer(struct tvec_base *base, struct timer_list *timer) * Can happen if you add a timer with expires == jiffies, * or you set a timer to go off in the past */ - vec = base->tv1.vec + (base->timer_jiffies & TVR_MASK); + vec = base->tv1.vec + (base->clk & TVR_MASK); } else { int i; /* If the timeout is larger than MAX_TVAL (on 64-bit @@ -403,7 +403,7 @@ __internal_add_timer(struct tvec_base *base, struct timer_list *timer) */ if (idx > MAX_TVAL) { idx = MAX_TVAL; - expires = idx + base->timer_jiffies; + expires = idx + base->clk; } i = (expires >> (TVR_BITS + 3 * TVN_BITS)) & TVN_MASK; vec = base->tv5.vec + i; @@ -412,11 +412,11 @@ __internal_add_timer(struct tvec_base *base, struct timer_list *timer) hlist_add_head(&timer->entry, vec); } -static void internal_add_timer(struct tvec_base *base, struct timer_list *timer) +static void internal_add_timer(struct timer_base *base, struct timer_list *timer) { /* Advance base->jiffies, if the base is empty */ if (!base->all_timers++) - base->timer_jiffies = jiffies; + base->clk = jiffies; __internal_add_timer(base, timer); /* @@ -707,7 +707,7 @@ static inline void detach_timer(struct timer_list *timer, bool clear_pending) } static inline void -detach_expired_timer(struct timer_list *timer, struct tvec_base *base) +detach_expired_timer(struct timer_list *timer, struct timer_base *base) { detach_timer(timer, true); if (!(timer->flags & TIMER_DEFERRABLE)) @@ -715,7 +715,7 @@ detach_expired_timer(struct timer_list *timer, struct tvec_base *base) base->all_timers--; } -static int detach_if_pending(struct timer_list *timer, struct tvec_base *base, +static int detach_if_pending(struct timer_list *timer, struct timer_base *base, bool clear_pending) { if (!timer_pending(timer)) @@ -725,16 +725,16 @@ static int detach_if_pending(struct timer_list *timer, struct tvec_base *base, if (!(timer->flags & TIMER_DEFERRABLE)) { base->active_timers--; if (timer->expires == base->next_timer) - base->next_timer = base->timer_jiffies; + base->next_timer = base->clk; } /* If this was the last timer, advance base->jiffies */ if (!--base->all_timers) - base->timer_jiffies = jiffies; + base->clk = jiffies; return 1; } /* - * We are using hashed locking: holding per_cpu(tvec_bases).lock + * We are using hashed locking: holding per_cpu(timer_bases).lock * means that all timers which are tied to this base via timer->base are * locked, and the base itself is locked too. * @@ -744,16 +744,16 @@ static int detach_if_pending(struct timer_list *timer, struct tvec_base *base, * When the timer's base is locked and removed from the list, the * TIMER_MIGRATING flag is set, FIXME */ -static struct tvec_base *lock_timer_base(struct timer_list *timer, +static struct timer_base *lock_timer_base(struct timer_list *timer, unsigned long *flags) __acquires(timer->base->lock) { for (;;) { u32 tf = timer->flags; - struct tvec_base *base; + struct timer_base *base; if (!(tf & TIMER_MIGRATING)) { - base = per_cpu_ptr(&tvec_bases, tf & TIMER_CPUMASK); + base = per_cpu_ptr(&timer_bases, tf & TIMER_CPUMASK); spin_lock_irqsave(&base->lock, *flags); if (timer->flags == tf) return base; @@ -766,7 +766,7 @@ static struct tvec_base *lock_timer_base(struct timer_list *timer, static inline int __mod_timer(struct timer_list *timer, unsigned long expires, bool pending_only) { - struct tvec_base *base, *new_base; + struct timer_base *base, *new_base; unsigned long flags; int ret = 0; @@ -933,8 +933,8 @@ EXPORT_SYMBOL(add_timer); */ void add_timer_on(struct timer_list *timer, int cpu) { - struct tvec_base *new_base = per_cpu_ptr(&tvec_bases, cpu); - struct tvec_base *base; + struct timer_base *new_base = per_cpu_ptr(&timer_bases, cpu); + struct timer_base *base; unsigned long flags; timer_stats_timer_set_start_info(timer); @@ -975,7 +975,7 @@ EXPORT_SYMBOL_GPL(add_timer_on); */ int del_timer(struct timer_list *timer) { - struct tvec_base *base; + struct timer_base *base; unsigned long flags; int ret = 0; @@ -1001,7 +1001,7 @@ EXPORT_SYMBOL(del_timer); */ int try_to_del_timer_sync(struct timer_list *timer) { - struct tvec_base *base; + struct timer_base *base; unsigned long flags; int ret = -1; @@ -1085,7 +1085,7 @@ int del_timer_sync(struct timer_list *timer) EXPORT_SYMBOL(del_timer_sync); #endif -static int cascade(struct tvec_base *base, struct tvec *tv, int index) +static int cascade(struct timer_base *base, struct tvec *tv, int index) { /* cascade all the timers from tv up one level */ struct timer_list *timer; @@ -1149,7 +1149,7 @@ static void call_timer_fn(struct timer_list *timer, void (*fn)(unsigned long), } } -#define INDEX(N) ((base->timer_jiffies >> (TVR_BITS + (N) * TVN_BITS)) & TVN_MASK) +#define INDEX(N) ((base->clk >> (TVR_BITS + (N) * TVN_BITS)) & TVN_MASK) /** * __run_timers - run all expired timers (if any) on this CPU. @@ -1158,23 +1158,23 @@ static void call_timer_fn(struct timer_list *timer, void (*fn)(unsigned long), * This function cascades all vectors and executes all expired timer * vectors. */ -static inline void __run_timers(struct tvec_base *base) +static inline void __run_timers(struct timer_base *base) { struct timer_list *timer; spin_lock_irq(&base->lock); - while (time_after_eq(jiffies, base->timer_jiffies)) { + while (time_after_eq(jiffies, base->clk)) { struct hlist_head work_list; struct hlist_head *head = &work_list; int index; if (!base->all_timers) { - base->timer_jiffies = jiffies; + base->clk = jiffies; break; } - index = base->timer_jiffies & TVR_MASK; + index = base->clk & TVR_MASK; /* * Cascade timers: @@ -1184,7 +1184,7 @@ static inline void __run_timers(struct tvec_base *base) (!cascade(base, &base->tv3, INDEX(1))) && !cascade(base, &base->tv4, INDEX(2))) cascade(base, &base->tv5, INDEX(3)); - ++base->timer_jiffies; + ++base->clk; hlist_move_list(base->tv1.vec + index, head); while (!hlist_empty(head)) { void (*fn)(unsigned long); @@ -1222,16 +1222,16 @@ static inline void __run_timers(struct tvec_base *base) * is used on S/390 to stop all activity when a CPU is idle. * This function needs to be called with interrupts disabled. */ -static unsigned long __next_timer_interrupt(struct tvec_base *base) +static unsigned long __next_timer_interrupt(struct timer_base *base) { - unsigned long timer_jiffies = base->timer_jiffies; - unsigned long expires = timer_jiffies + NEXT_TIMER_MAX_DELTA; + unsigned long clk = base->clk; + unsigned long expires = clk + NEXT_TIMER_MAX_DELTA; int index, slot, array, found = 0; struct timer_list *nte; struct tvec *varray[4]; /* Look for timer events in tv1. */ - index = slot = timer_jiffies & TVR_MASK; + index = slot = clk & TVR_MASK; do { hlist_for_each_entry(nte, base->tv1.vec + slot, entry) { if (nte->flags & TIMER_DEFERRABLE) @@ -1250,8 +1250,8 @@ static unsigned long __next_timer_interrupt(struct tvec_base *base) cascade: /* Calculate the next cascade event */ if (index) - timer_jiffies += TVR_SIZE - index; - timer_jiffies >>= TVR_BITS; + clk += TVR_SIZE - index; + clk >>= TVR_BITS; /* Check tv2-tv5. */ varray[0] = &base->tv2; @@ -1262,7 +1262,7 @@ cascade: for (array = 0; array < 4; array++) { struct tvec *varp = varray[array]; - index = slot = timer_jiffies & TVN_MASK; + index = slot = clk & TVN_MASK; do { hlist_for_each_entry(nte, varp->vec + slot, entry) { if (nte->flags & TIMER_DEFERRABLE) @@ -1286,8 +1286,8 @@ cascade: } while (slot != index); if (index) - timer_jiffies += TVN_SIZE - index; - timer_jiffies >>= TVN_BITS; + clk += TVN_SIZE - index; + clk >>= TVN_BITS; } return expires; } @@ -1335,7 +1335,7 @@ static u64 cmp_next_hrtimer_event(u64 basem, u64 expires) */ u64 get_next_timer_interrupt(unsigned long basej, u64 basem) { - struct tvec_base *base = this_cpu_ptr(&tvec_bases); + struct timer_base *base = this_cpu_ptr(&timer_bases); u64 expires = KTIME_MAX; unsigned long nextevt; @@ -1348,7 +1348,7 @@ u64 get_next_timer_interrupt(unsigned long basej, u64 basem) spin_lock(&base->lock); if (base->active_timers) { - if (time_before_eq(base->next_timer, base->timer_jiffies)) + if (time_before_eq(base->next_timer, base->clk)) base->next_timer = __next_timer_interrupt(base); nextevt = base->next_timer; if (time_before_eq(nextevt, basej)) @@ -1387,9 +1387,9 @@ void update_process_times(int user_tick) */ static void run_timer_softirq(struct softirq_action *h) { - struct tvec_base *base = this_cpu_ptr(&tvec_bases); + struct timer_base *base = this_cpu_ptr(&timer_bases); - if (time_after_eq(jiffies, base->timer_jiffies)) + if (time_after_eq(jiffies, base->clk)) __run_timers(base); } @@ -1534,7 +1534,7 @@ signed long __sched schedule_timeout_idle(signed long timeout) EXPORT_SYMBOL(schedule_timeout_idle); #ifdef CONFIG_HOTPLUG_CPU -static void migrate_timer_list(struct tvec_base *new_base, struct hlist_head *head) +static void migrate_timer_list(struct timer_base *new_base, struct hlist_head *head) { struct timer_list *timer; int cpu = new_base->cpu; @@ -1550,13 +1550,13 @@ static void migrate_timer_list(struct tvec_base *new_base, struct hlist_head *he static void migrate_timers(int cpu) { - struct tvec_base *old_base; - struct tvec_base *new_base; + struct timer_base *old_base; + struct timer_base *new_base; int i; BUG_ON(cpu_online(cpu)); - old_base = per_cpu_ptr(&tvec_bases, cpu); - new_base = get_cpu_ptr(&tvec_bases); + old_base = per_cpu_ptr(&timer_bases, cpu); + new_base = get_cpu_ptr(&timer_bases); /* * The caller is globally serialized and nobody else * takes two locks at once, deadlock is not possible. @@ -1580,7 +1580,7 @@ static void migrate_timers(int cpu) spin_unlock(&old_base->lock); spin_unlock_irq(&new_base->lock); - put_cpu_ptr(&tvec_bases); + put_cpu_ptr(&timer_bases); } static int timer_cpu_notify(struct notifier_block *self, @@ -1608,13 +1608,13 @@ static inline void timer_register_cpu_notifier(void) { } static void __init init_timer_cpu(int cpu) { - struct tvec_base *base = per_cpu_ptr(&tvec_bases, cpu); + struct timer_base *base = per_cpu_ptr(&timer_bases, cpu); base->cpu = cpu; spin_lock_init(&base->lock); - base->timer_jiffies = jiffies; - base->next_timer = base->timer_jiffies; + base->clk = jiffies; + base->next_timer = base->clk; } static void __init init_timer_cpus(void) -- cgit v0.10.2 From b0d6e2dcb284f1f4dcb4b92760f49eeaf5fc0bc7 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Mon, 4 Jul 2016 09:50:29 +0000 Subject: timers: Reduce the CPU index space to 256k We want to store the array index in the flags space. 256k CPUs should be enough for a while. Signed-off-by: Thomas Gleixner Reviewed-by: Frederic Weisbecker Cc: Arjan van de Ven Cc: Chris Mason Cc: George Spelvin Cc: Josh Triplett Cc: Len Brown Cc: Linus Torvalds Cc: Paul McKenney Cc: Peter Zijlstra Cc: Rik van Riel Cc: rt@linutronix.de Link: http://lkml.kernel.org/r/20160704094342.030144293@linutronix.de Signed-off-by: Ingo Molnar diff --git a/include/linux/timer.h b/include/linux/timer.h index a8f6c70..989f33d 100644 --- a/include/linux/timer.h +++ b/include/linux/timer.h @@ -58,12 +58,12 @@ struct timer_list { * workqueue locking issues. It's not meant for executing random crap * with interrupts disabled. Abuse is monitored! */ -#define TIMER_CPUMASK 0x0007FFFF -#define TIMER_MIGRATING 0x00080000 +#define TIMER_CPUMASK 0x0003FFFF +#define TIMER_MIGRATING 0x00040000 #define TIMER_BASEMASK (TIMER_CPUMASK | TIMER_MIGRATING) -#define TIMER_DEFERRABLE 0x00100000 -#define TIMER_PINNED 0x00200000 -#define TIMER_IRQSAFE 0x00400000 +#define TIMER_DEFERRABLE 0x00080000 +#define TIMER_PINNED 0x00100000 +#define TIMER_IRQSAFE 0x00200000 #define __TIMER_INITIALIZER(_function, _expires, _data, _flags) { \ .entry = { .next = TIMER_ENTRY_STATIC }, \ -- cgit v0.10.2 From 500462a9de657f86edaa102f8ab6bff7f7e43fc2 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Mon, 4 Jul 2016 09:50:30 +0000 Subject: timers: Switch to a non-cascading wheel The current timer wheel has some drawbacks: 1) Cascading: Cascading can be an unbound operation and is completely pointless in most cases because the vast majority of the timer wheel timers are canceled or rearmed before expiration. (They are used as timeout safeguards, not as real timers to measure time.) 2) No fast lookup of the next expiring timer: In NOHZ scenarios the first timer soft interrupt after a long NOHZ period must fast forward the base time to the current value of jiffies. As we have no way to find the next expiring timer fast, the code loops linearly and increments the base time one by one and checks for expired timers in each step. This causes unbound overhead spikes exactly in the moment when we should wake up as fast as possible. After a thorough analysis of real world data gathered on laptops, workstations, webservers and other machines (thanks Chris!) I came to the conclusion that the current 'classic' timer wheel implementation can be modified to address the above issues. The vast majority of timer wheel timers is canceled or rearmed before expiry. Most of them are timeouts for networking and other I/O tasks. The nature of timeouts is to catch the exception from normal operation (TCP ack timed out, disk does not respond, etc.). For these kinds of timeouts the accuracy of the timeout is not really a concern. Timeouts are very often approximate worst-case values and in case the timeout fires, we already waited for a long time and performance is down the drain already. The few timers which actually expire can be split into two categories: 1) Short expiry times which expect halfways accurate expiry 2) Long term expiry times are inaccurate today already due to the batching which is done for NOHZ automatically and also via the set_timer_slack() API. So for long term expiry timers we can avoid the cascading property and just leave them in the less granular outer wheels until expiry or cancelation. Timers which are armed with a timeout larger than the wheel capacity are no longer cascaded. We expire them with the longest possible timeout (6+ days). We have not observed such timeouts in our data collection, but at least we handle them, applying the rule of the least surprise. To avoid extending the wheel levels for HZ=1000 so we can accomodate the longest observed timeouts (5 days in the network conntrack code) we reduce the first level granularity on HZ=1000 to 4ms, which effectively is the same as the HZ=250 behaviour. From our data analysis there is nothing which relies on that 1ms granularity and as a side effect we get better batching and timer locality for the networking code as well. Contrary to the classic wheel the granularity of the next wheel is not the capacity of the first wheel. The granularities of the wheels are in the currently chosen setting 8 times the granularity of the previous wheel. So for HZ=250 we end up with the following granularity levels: Level Offset Granularity Range 0 0 4 ms 0 ms - 252 ms 1 64 32 ms 256 ms - 2044 ms (256ms - ~2s) 2 128 256 ms 2048 ms - 16380 ms (~2s - ~16s) 3 192 2048 ms (~2s) 16384 ms - 131068 ms (~16s - ~2m) 4 256 16384 ms (~16s) 131072 ms - 1048572 ms (~2m - ~17m) 5 320 131072 ms (~2m) 1048576 ms - 8388604 ms (~17m - ~2h) 6 384 1048576 ms (~17m) 8388608 ms - 67108863 ms (~2h - ~18h) 7 448 8388608 ms (~2h) 67108864 ms - 536870911 ms (~18h - ~6d) That's a worst case inaccuracy of 12.5% for the timers which are queued at the beginning of a level. So the new wheel concept addresses the old issues: 1) Cascading is avoided completely 2) By keeping the timers in the bucket until expiry/cancelation we can track the buckets which have timers enqueued in a bucket bitmap and therefore can look up the next expiring timer very fast and O(1). A further benefit of the concept is that the slack calculation which is done on every timer start is no longer necessary because the granularity levels provide natural batching already. Our extensive testing with various loads did not show any performance degradation vs. the current wheel implementation. This patch does not address the 'fast lookup' issue as we wanted to make sure that there is no regression introduced by the wheel redesign. The optimizations are in follow up patches. This patch contains fixes from Anna-Maria Gleixner and Richard Cochran. Signed-off-by: Thomas Gleixner Cc: Arjan van de Ven Cc: Chris Mason Cc: Eric Dumazet Cc: Frederic Weisbecker Cc: George Spelvin Cc: Josh Triplett Cc: Len Brown Cc: Linus Torvalds Cc: Paul E. McKenney Cc: Peter Zijlstra Cc: Rik van Riel Cc: rt@linutronix.de Link: http://lkml.kernel.org/r/20160704094342.108621834@linutronix.de Signed-off-by: Ingo Molnar diff --git a/include/linux/timer.h b/include/linux/timer.h index 989f33d..5869ab9 100644 --- a/include/linux/timer.h +++ b/include/linux/timer.h @@ -64,6 +64,8 @@ struct timer_list { #define TIMER_DEFERRABLE 0x00080000 #define TIMER_PINNED 0x00100000 #define TIMER_IRQSAFE 0x00200000 +#define TIMER_ARRAYSHIFT 22 +#define TIMER_ARRAYMASK 0xFFC00000 #define __TIMER_INITIALIZER(_function, _expires, _data, _flags) { \ .entry = { .next = TIMER_ENTRY_STATIC }, \ diff --git a/kernel/time/timer.c b/kernel/time/timer.c index f259a3e..86e95b7 100644 --- a/kernel/time/timer.c +++ b/kernel/time/timer.c @@ -59,43 +59,151 @@ __visible u64 jiffies_64 __cacheline_aligned_in_smp = INITIAL_JIFFIES; EXPORT_SYMBOL(jiffies_64); /* - * per-CPU timer vector definitions: + * The timer wheel has LVL_DEPTH array levels. Each level provides an array of + * LVL_SIZE buckets. Each level is driven by its own clock and therefor each + * level has a different granularity. + * + * The level granularity is: LVL_CLK_DIV ^ lvl + * The level clock frequency is: HZ / (LVL_CLK_DIV ^ level) + * + * The array level of a newly armed timer depends on the relative expiry + * time. The farther the expiry time is away the higher the array level and + * therefor the granularity becomes. + * + * Contrary to the original timer wheel implementation, which aims for 'exact' + * expiry of the timers, this implementation removes the need for recascading + * the timers into the lower array levels. The previous 'classic' timer wheel + * implementation of the kernel already violated the 'exact' expiry by adding + * slack to the expiry time to provide batched expiration. The granularity + * levels provide implicit batching. + * + * This is an optimization of the original timer wheel implementation for the + * majority of the timer wheel use cases: timeouts. The vast majority of + * timeout timers (networking, disk I/O ...) are canceled before expiry. If + * the timeout expires it indicates that normal operation is disturbed, so it + * does not matter much whether the timeout comes with a slight delay. + * + * The only exception to this are networking timers with a small expiry + * time. They rely on the granularity. Those fit into the first wheel level, + * which has HZ granularity. + * + * We don't have cascading anymore. timers with a expiry time above the + * capacity of the last wheel level are force expired at the maximum timeout + * value of the last wheel level. From data sampling we know that the maximum + * value observed is 5 days (network connection tracking), so this should not + * be an issue. + * + * The currently chosen array constants values are a good compromise between + * array size and granularity. + * + * This results in the following granularity and range levels: + * + * HZ 1000 steps + * Level Offset Granularity Range + * 0 0 1 ms 0 ms - 63 ms + * 1 64 8 ms 64 ms - 511 ms + * 2 128 64 ms 512 ms - 4095 ms (512ms - ~4s) + * 3 192 512 ms 4096 ms - 32767 ms (~4s - ~32s) + * 4 256 4096 ms (~4s) 32768 ms - 262143 ms (~32s - ~4m) + * 5 320 32768 ms (~32s) 262144 ms - 2097151 ms (~4m - ~34m) + * 6 384 262144 ms (~4m) 2097152 ms - 16777215 ms (~34m - ~4h) + * 7 448 2097152 ms (~34m) 16777216 ms - 134217727 ms (~4h - ~1d) + * 8 512 16777216 ms (~4h) 134217728 ms - 1073741822 ms (~1d - ~12d) + * + * HZ 300 + * Level Offset Granularity Range + * 0 0 3 ms 0 ms - 210 ms + * 1 64 26 ms 213 ms - 1703 ms (213ms - ~1s) + * 2 128 213 ms 1706 ms - 13650 ms (~1s - ~13s) + * 3 192 1706 ms (~1s) 13653 ms - 109223 ms (~13s - ~1m) + * 4 256 13653 ms (~13s) 109226 ms - 873810 ms (~1m - ~14m) + * 5 320 109226 ms (~1m) 873813 ms - 6990503 ms (~14m - ~1h) + * 6 384 873813 ms (~14m) 6990506 ms - 55924050 ms (~1h - ~15h) + * 7 448 6990506 ms (~1h) 55924053 ms - 447392423 ms (~15h - ~5d) + * 8 512 55924053 ms (~15h) 447392426 ms - 3579139406 ms (~5d - ~41d) + * + * HZ 250 + * Level Offset Granularity Range + * 0 0 4 ms 0 ms - 255 ms + * 1 64 32 ms 256 ms - 2047 ms (256ms - ~2s) + * 2 128 256 ms 2048 ms - 16383 ms (~2s - ~16s) + * 3 192 2048 ms (~2s) 16384 ms - 131071 ms (~16s - ~2m) + * 4 256 16384 ms (~16s) 131072 ms - 1048575 ms (~2m - ~17m) + * 5 320 131072 ms (~2m) 1048576 ms - 8388607 ms (~17m - ~2h) + * 6 384 1048576 ms (~17m) 8388608 ms - 67108863 ms (~2h - ~18h) + * 7 448 8388608 ms (~2h) 67108864 ms - 536870911 ms (~18h - ~6d) + * 8 512 67108864 ms (~18h) 536870912 ms - 4294967288 ms (~6d - ~49d) + * + * HZ 100 + * Level Offset Granularity Range + * 0 0 10 ms 0 ms - 630 ms + * 1 64 80 ms 640 ms - 5110 ms (640ms - ~5s) + * 2 128 640 ms 5120 ms - 40950 ms (~5s - ~40s) + * 3 192 5120 ms (~5s) 40960 ms - 327670 ms (~40s - ~5m) + * 4 256 40960 ms (~40s) 327680 ms - 2621430 ms (~5m - ~43m) + * 5 320 327680 ms (~5m) 2621440 ms - 20971510 ms (~43m - ~5h) + * 6 384 2621440 ms (~43m) 20971520 ms - 167772150 ms (~5h - ~1d) + * 7 448 20971520 ms (~5h) 167772160 ms - 1342177270 ms (~1d - ~15d) */ -#define TVN_BITS (CONFIG_BASE_SMALL ? 4 : 6) -#define TVR_BITS (CONFIG_BASE_SMALL ? 6 : 8) -#define TVN_SIZE (1 << TVN_BITS) -#define TVR_SIZE (1 << TVR_BITS) -#define TVN_MASK (TVN_SIZE - 1) -#define TVR_MASK (TVR_SIZE - 1) -#define MAX_TVAL ((unsigned long)((1ULL << (TVR_BITS + 4*TVN_BITS)) - 1)) - -struct tvec { - struct hlist_head vec[TVN_SIZE]; -}; -struct tvec_root { - struct hlist_head vec[TVR_SIZE]; -}; +/* Clock divisor for the next level */ +#define LVL_CLK_SHIFT 3 +#define LVL_CLK_DIV (1UL << LVL_CLK_SHIFT) +#define LVL_CLK_MASK (LVL_CLK_DIV - 1) +#define LVL_SHIFT(n) ((n) * LVL_CLK_SHIFT) +#define LVL_GRAN(n) (1UL << LVL_SHIFT(n)) + +/* + * The time start value for each level to select the bucket at enqueue + * time. + */ +#define LVL_START(n) ((LVL_SIZE - 1) << (((n) - 1) * LVL_CLK_SHIFT)) + +/* Size of each clock level */ +#define LVL_BITS 6 +#define LVL_SIZE (1UL << LVL_BITS) +#define LVL_MASK (LVL_SIZE - 1) +#define LVL_OFFS(n) ((n) * LVL_SIZE) + +/* Level depth */ +#if HZ > 100 +# define LVL_DEPTH 9 +# else +# define LVL_DEPTH 8 +#endif + +/* The cutoff (max. capacity of the wheel) */ +#define WHEEL_TIMEOUT_CUTOFF (LVL_START(LVL_DEPTH)) +#define WHEEL_TIMEOUT_MAX (WHEEL_TIMEOUT_CUTOFF - LVL_GRAN(LVL_DEPTH - 1)) + +/* + * The resulting wheel size. If NOHZ is configured we allocate two + * wheels so we have a separate storage for the deferrable timers. + */ +#define WHEEL_SIZE (LVL_SIZE * LVL_DEPTH) + +#ifdef CONFIG_NO_HZ_COMMON +# define NR_BASES 2 +# define BASE_STD 0 +# define BASE_DEF 1 +#else +# define NR_BASES 1 +# define BASE_STD 0 +# define BASE_DEF 0 +#endif struct timer_base { - spinlock_t lock; - struct timer_list *running_timer; - unsigned long clk; - unsigned long next_timer; - unsigned long active_timers; - unsigned long all_timers; - int cpu; - bool migration_enabled; - bool nohz_active; - struct tvec_root tv1; - struct tvec tv2; - struct tvec tv3; - struct tvec tv4; - struct tvec tv5; + spinlock_t lock; + struct timer_list *running_timer; + unsigned long clk; + unsigned int cpu; + bool migration_enabled; + bool nohz_active; + DECLARE_BITMAP(pending_map, WHEEL_SIZE); + struct hlist_head vectors[WHEEL_SIZE]; } ____cacheline_aligned; - -static DEFINE_PER_CPU(struct timer_base, timer_bases); +static DEFINE_PER_CPU(struct timer_base, timer_bases[NR_BASES]); #if defined(CONFIG_SMP) && defined(CONFIG_NO_HZ_COMMON) unsigned int sysctl_timer_migration = 1; @@ -106,15 +214,17 @@ void timers_update_migration(bool update_nohz) unsigned int cpu; /* Avoid the loop, if nothing to update */ - if (this_cpu_read(timer_bases.migration_enabled) == on) + if (this_cpu_read(timer_bases[BASE_STD].migration_enabled) == on) return; for_each_possible_cpu(cpu) { - per_cpu(timer_bases.migration_enabled, cpu) = on; + per_cpu(timer_bases[BASE_STD].migration_enabled, cpu) = on; + per_cpu(timer_bases[BASE_DEF].migration_enabled, cpu) = on; per_cpu(hrtimer_bases.migration_enabled, cpu) = on; if (!update_nohz) continue; - per_cpu(timer_bases.nohz_active, cpu) = true; + per_cpu(timer_bases[BASE_STD].nohz_active, cpu) = true; + per_cpu(timer_bases[BASE_DEF].nohz_active, cpu) = true; per_cpu(hrtimer_bases.nohz_active, cpu) = true; } } @@ -133,20 +243,6 @@ int timer_migration_handler(struct ctl_table *table, int write, mutex_unlock(&mutex); return ret; } - -static inline struct timer_base *get_target_base(struct timer_base *base, - int pinned) -{ - if (pinned || !base->migration_enabled) - return this_cpu_ptr(&timer_bases); - return per_cpu_ptr(&timer_bases, get_nohz_timer_target()); -} -#else -static inline struct timer_base *get_target_base(struct timer_base *base, - int pinned) -{ - return this_cpu_ptr(&timer_bases); -} #endif static unsigned long round_jiffies_common(unsigned long j, int cpu, @@ -370,78 +466,91 @@ void set_timer_slack(struct timer_list *timer, int slack_hz) } EXPORT_SYMBOL_GPL(set_timer_slack); +static inline unsigned int timer_get_idx(struct timer_list *timer) +{ + return (timer->flags & TIMER_ARRAYMASK) >> TIMER_ARRAYSHIFT; +} + +static inline void timer_set_idx(struct timer_list *timer, unsigned int idx) +{ + timer->flags = (timer->flags & ~TIMER_ARRAYMASK) | + idx << TIMER_ARRAYSHIFT; +} + +/* + * Helper function to calculate the array index for a given expiry + * time. + */ +static inline unsigned calc_index(unsigned expires, unsigned lvl) +{ + expires = (expires + LVL_GRAN(lvl)) >> LVL_SHIFT(lvl); + return LVL_OFFS(lvl) + (expires & LVL_MASK); +} + static void __internal_add_timer(struct timer_base *base, struct timer_list *timer) { unsigned long expires = timer->expires; - unsigned long idx = expires - base->clk; + unsigned long delta = expires - base->clk; struct hlist_head *vec; - - if (idx < TVR_SIZE) { - int i = expires & TVR_MASK; - vec = base->tv1.vec + i; - } else if (idx < 1 << (TVR_BITS + TVN_BITS)) { - int i = (expires >> TVR_BITS) & TVN_MASK; - vec = base->tv2.vec + i; - } else if (idx < 1 << (TVR_BITS + 2 * TVN_BITS)) { - int i = (expires >> (TVR_BITS + TVN_BITS)) & TVN_MASK; - vec = base->tv3.vec + i; - } else if (idx < 1 << (TVR_BITS + 3 * TVN_BITS)) { - int i = (expires >> (TVR_BITS + 2 * TVN_BITS)) & TVN_MASK; - vec = base->tv4.vec + i; - } else if ((signed long) idx < 0) { - /* - * Can happen if you add a timer with expires == jiffies, - * or you set a timer to go off in the past - */ - vec = base->tv1.vec + (base->clk & TVR_MASK); + unsigned int idx; + + if (delta < LVL_START(1)) { + idx = calc_index(expires, 0); + } else if (delta < LVL_START(2)) { + idx = calc_index(expires, 1); + } else if (delta < LVL_START(3)) { + idx = calc_index(expires, 2); + } else if (delta < LVL_START(4)) { + idx = calc_index(expires, 3); + } else if (delta < LVL_START(5)) { + idx = calc_index(expires, 4); + } else if (delta < LVL_START(6)) { + idx = calc_index(expires, 5); + } else if (delta < LVL_START(7)) { + idx = calc_index(expires, 6); + } else if (LVL_DEPTH > 8 && delta < LVL_START(8)) { + idx = calc_index(expires, 7); + } else if ((long) delta < 0) { + idx = base->clk & LVL_MASK; } else { - int i; - /* If the timeout is larger than MAX_TVAL (on 64-bit - * architectures or with CONFIG_BASE_SMALL=1) then we - * use the maximum timeout. + /* + * Force expire obscene large timeouts to expire at the + * capacity limit of the wheel. */ - if (idx > MAX_TVAL) { - idx = MAX_TVAL; - expires = idx + base->clk; - } - i = (expires >> (TVR_BITS + 3 * TVN_BITS)) & TVN_MASK; - vec = base->tv5.vec + i; - } + if (expires >= WHEEL_TIMEOUT_CUTOFF) + expires = WHEEL_TIMEOUT_MAX; + idx = calc_index(expires, LVL_DEPTH - 1); + } + /* + * Enqueue the timer into the array bucket, mark it pending in + * the bitmap and store the index in the timer flags. + */ + vec = base->vectors + idx; hlist_add_head(&timer->entry, vec); + __set_bit(idx, base->pending_map); + timer_set_idx(timer, idx); } static void internal_add_timer(struct timer_base *base, struct timer_list *timer) { - /* Advance base->jiffies, if the base is empty */ - if (!base->all_timers++) - base->clk = jiffies; - __internal_add_timer(base, timer); - /* - * Update base->active_timers and base->next_timer - */ - if (!(timer->flags & TIMER_DEFERRABLE)) { - if (!base->active_timers++ || - time_before(timer->expires, base->next_timer)) - base->next_timer = timer->expires; - } /* * Check whether the other CPU is in dynticks mode and needs - * to be triggered to reevaluate the timer wheel. - * We are protected against the other CPU fiddling - * with the timer by holding the timer base lock. This also - * makes sure that a CPU on the way to stop its tick can not - * evaluate the timer wheel. + * to be triggered to reevaluate the timer wheel. We are + * protected against the other CPU fiddling with the timer by + * holding the timer base lock. This also makes sure that a + * CPU on the way to stop its tick can not evaluate the timer + * wheel. * * Spare the IPI for deferrable timers on idle targets though. * The next busy ticks will take care of it. Except full dynticks * require special care against races with idle_cpu(), lets deal * with that later. */ - if (base->nohz_active) { + if (IS_ENABLED(CONFIG_NO_HZ_COMMON) && base->nohz_active) { if (!(timer->flags & TIMER_DEFERRABLE) || tick_nohz_full_cpu(base->cpu)) wake_up_nohz_cpu(base->cpu); @@ -706,54 +815,87 @@ static inline void detach_timer(struct timer_list *timer, bool clear_pending) entry->next = LIST_POISON2; } -static inline void -detach_expired_timer(struct timer_list *timer, struct timer_base *base) -{ - detach_timer(timer, true); - if (!(timer->flags & TIMER_DEFERRABLE)) - base->active_timers--; - base->all_timers--; -} - static int detach_if_pending(struct timer_list *timer, struct timer_base *base, bool clear_pending) { + unsigned idx = timer_get_idx(timer); + if (!timer_pending(timer)) return 0; + if (hlist_is_singular_node(&timer->entry, base->vectors + idx)) + __clear_bit(idx, base->pending_map); + detach_timer(timer, clear_pending); - if (!(timer->flags & TIMER_DEFERRABLE)) { - base->active_timers--; - if (timer->expires == base->next_timer) - base->next_timer = base->clk; - } - /* If this was the last timer, advance base->jiffies */ - if (!--base->all_timers) - base->clk = jiffies; return 1; } +static inline struct timer_base *get_timer_cpu_base(u32 tflags, u32 cpu) +{ + struct timer_base *base = per_cpu_ptr(&timer_bases[BASE_STD], cpu); + + /* + * If the timer is deferrable and nohz is active then we need to use + * the deferrable base. + */ + if (IS_ENABLED(CONFIG_NO_HZ_COMMON) && base->nohz_active && + (tflags & TIMER_DEFERRABLE)) + base = per_cpu_ptr(&timer_bases[BASE_DEF], cpu); + return base; +} + +static inline struct timer_base *get_timer_this_cpu_base(u32 tflags) +{ + struct timer_base *base = this_cpu_ptr(&timer_bases[BASE_STD]); + + /* + * If the timer is deferrable and nohz is active then we need to use + * the deferrable base. + */ + if (IS_ENABLED(CONFIG_NO_HZ_COMMON) && base->nohz_active && + (tflags & TIMER_DEFERRABLE)) + base = this_cpu_ptr(&timer_bases[BASE_DEF]); + return base; +} + +static inline struct timer_base *get_timer_base(u32 tflags) +{ + return get_timer_cpu_base(tflags, tflags & TIMER_CPUMASK); +} + +static inline struct timer_base *get_target_base(struct timer_base *base, + unsigned tflags) +{ +#if defined(CONFIG_NO_HZ_COMMON) && defined(CONFIG_SMP) + if ((tflags & TIMER_PINNED) || !base->migration_enabled) + return get_timer_this_cpu_base(tflags); + return get_timer_cpu_base(tflags, get_nohz_timer_target()); +#else + return get_timer_this_cpu_base(tflags); +#endif +} + /* - * We are using hashed locking: holding per_cpu(timer_bases).lock - * means that all timers which are tied to this base via timer->base are - * locked, and the base itself is locked too. + * We are using hashed locking: Holding per_cpu(timer_bases[x]).lock means + * that all timers which are tied to this base are locked, and the base itself + * is locked too. * * So __run_timers/migrate_timers can safely modify all timers which could - * be found on ->tvX lists. + * be found in the base->vectors array. * - * When the timer's base is locked and removed from the list, the - * TIMER_MIGRATING flag is set, FIXME + * When a timer is migrating then the TIMER_MIGRATING flag is set and we need + * to wait until the migration is done. */ static struct timer_base *lock_timer_base(struct timer_list *timer, - unsigned long *flags) + unsigned long *flags) __acquires(timer->base->lock) { for (;;) { - u32 tf = timer->flags; struct timer_base *base; + u32 tf = timer->flags; if (!(tf & TIMER_MIGRATING)) { - base = per_cpu_ptr(&timer_bases, tf & TIMER_CPUMASK); + base = get_timer_base(tf); spin_lock_irqsave(&base->lock, *flags); if (timer->flags == tf) return base; @@ -770,6 +912,27 @@ __mod_timer(struct timer_list *timer, unsigned long expires, bool pending_only) unsigned long flags; int ret = 0; + /* + * TODO: Calculate the array bucket of the timer right here w/o + * holding the base lock. This allows to check not only + * timer->expires == expires below, but also whether the timer + * ends up in the same bucket. If we really need to requeue + * the timer then we check whether base->clk have + * advanced between here and locking the timer base. If + * jiffies advanced we have to recalc the array bucket with the + * lock held. + */ + + /* + * This is a common optimization triggered by the + * networking code - if the timer is re-modified + * to be the same thing then just return: + */ + if (timer_pending(timer)) { + if (timer->expires == expires) + return 1; + } + timer_stats_timer_set_start_info(timer); BUG_ON(!timer->function); @@ -781,15 +944,15 @@ __mod_timer(struct timer_list *timer, unsigned long expires, bool pending_only) debug_activate(timer, expires); - new_base = get_target_base(base, timer->flags & TIMER_PINNED); + new_base = get_target_base(base, timer->flags); if (base != new_base) { /* - * We are trying to schedule the timer on the local CPU. + * We are trying to schedule the timer on the new base. * However we can't change timer's base while it is running, * otherwise del_timer_sync() can't detect that the timer's - * handler yet has not finished. This also guarantees that - * the timer is serialized wrt itself. + * handler yet has not finished. This also guarantees that the + * timer is serialized wrt itself. */ if (likely(base->running_timer != timer)) { /* See the comment in lock_timer_base() */ @@ -828,45 +991,6 @@ int mod_timer_pending(struct timer_list *timer, unsigned long expires) } EXPORT_SYMBOL(mod_timer_pending); -/* - * Decide where to put the timer while taking the slack into account - * - * Algorithm: - * 1) calculate the maximum (absolute) time - * 2) calculate the highest bit where the expires and new max are different - * 3) use this bit to make a mask - * 4) use the bitmask to round down the maximum time, so that all last - * bits are zeros - */ -static inline -unsigned long apply_slack(struct timer_list *timer, unsigned long expires) -{ - unsigned long expires_limit, mask; - int bit; - - if (timer->slack >= 0) { - expires_limit = expires + timer->slack; - } else { - long delta = expires - jiffies; - - if (delta < 256) - return expires; - - expires_limit = expires + delta / 256; - } - mask = expires ^ expires_limit; - if (mask == 0) - return expires; - - bit = __fls(mask); - - mask = (1UL << bit) - 1; - - expires_limit = expires_limit & ~(mask); - - return expires_limit; -} - /** * mod_timer - modify a timer's timeout * @timer: the timer to be modified @@ -889,16 +1013,6 @@ unsigned long apply_slack(struct timer_list *timer, unsigned long expires) */ int mod_timer(struct timer_list *timer, unsigned long expires) { - expires = apply_slack(timer, expires); - - /* - * This is a common optimization triggered by the - * networking code - if the timer is re-modified - * to be the same thing then just return: - */ - if (timer_pending(timer) && timer->expires == expires) - return 1; - return __mod_timer(timer, expires, false); } EXPORT_SYMBOL(mod_timer); @@ -933,13 +1047,14 @@ EXPORT_SYMBOL(add_timer); */ void add_timer_on(struct timer_list *timer, int cpu) { - struct timer_base *new_base = per_cpu_ptr(&timer_bases, cpu); - struct timer_base *base; + struct timer_base *new_base, *base; unsigned long flags; timer_stats_timer_set_start_info(timer); BUG_ON(timer_pending(timer) || !timer->function); + new_base = get_timer_cpu_base(timer->flags, cpu); + /* * If @timer was on a different CPU, it should be migrated with the * old base locked to prevent other operations proceeding with the @@ -1085,27 +1200,6 @@ int del_timer_sync(struct timer_list *timer) EXPORT_SYMBOL(del_timer_sync); #endif -static int cascade(struct timer_base *base, struct tvec *tv, int index) -{ - /* cascade all the timers from tv up one level */ - struct timer_list *timer; - struct hlist_node *tmp; - struct hlist_head tv_list; - - hlist_move_list(tv->vec + index, &tv_list); - - /* - * We are removing _all_ timers from the list, so we - * don't have to detach them individually. - */ - hlist_for_each_entry_safe(timer, tmp, &tv_list, entry) { - /* No accounting, while moving them */ - __internal_add_timer(base, timer); - } - - return index; -} - static void call_timer_fn(struct timer_list *timer, void (*fn)(unsigned long), unsigned long data) { @@ -1149,68 +1243,80 @@ static void call_timer_fn(struct timer_list *timer, void (*fn)(unsigned long), } } -#define INDEX(N) ((base->clk >> (TVR_BITS + (N) * TVN_BITS)) & TVN_MASK) +static void expire_timers(struct timer_base *base, struct hlist_head *head) +{ + while (!hlist_empty(head)) { + struct timer_list *timer; + void (*fn)(unsigned long); + unsigned long data; + + timer = hlist_entry(head->first, struct timer_list, entry); + timer_stats_account_timer(timer); + + base->running_timer = timer; + detach_timer(timer, true); + + fn = timer->function; + data = timer->data; + + if (timer->flags & TIMER_IRQSAFE) { + spin_unlock(&base->lock); + call_timer_fn(timer, fn, data); + spin_lock(&base->lock); + } else { + spin_unlock_irq(&base->lock); + call_timer_fn(timer, fn, data); + spin_lock_irq(&base->lock); + } + } +} + +static int collect_expired_timers(struct timer_base *base, + struct hlist_head *heads) +{ + unsigned long clk = base->clk; + struct hlist_head *vec; + int i, levels = 0; + unsigned int idx; + + for (i = 0; i < LVL_DEPTH; i++) { + idx = (clk & LVL_MASK) + i * LVL_SIZE; + + if (__test_and_clear_bit(idx, base->pending_map)) { + vec = base->vectors + idx; + hlist_move_list(vec, heads++); + levels++; + } + /* Is it time to look at the next level? */ + if (clk & LVL_CLK_MASK) + break; + /* Shift clock for the next level granularity */ + clk >>= LVL_CLK_SHIFT; + } + return levels; +} /** * __run_timers - run all expired timers (if any) on this CPU. * @base: the timer vector to be processed. - * - * This function cascades all vectors and executes all expired timer - * vectors. */ static inline void __run_timers(struct timer_base *base) { - struct timer_list *timer; + struct hlist_head heads[LVL_DEPTH]; + int levels; + + if (!time_after_eq(jiffies, base->clk)) + return; spin_lock_irq(&base->lock); while (time_after_eq(jiffies, base->clk)) { - struct hlist_head work_list; - struct hlist_head *head = &work_list; - int index; - if (!base->all_timers) { - base->clk = jiffies; - break; - } - - index = base->clk & TVR_MASK; + levels = collect_expired_timers(base, heads); + base->clk++; - /* - * Cascade timers: - */ - if (!index && - (!cascade(base, &base->tv2, INDEX(0))) && - (!cascade(base, &base->tv3, INDEX(1))) && - !cascade(base, &base->tv4, INDEX(2))) - cascade(base, &base->tv5, INDEX(3)); - ++base->clk; - hlist_move_list(base->tv1.vec + index, head); - while (!hlist_empty(head)) { - void (*fn)(unsigned long); - unsigned long data; - bool irqsafe; - - timer = hlist_entry(head->first, struct timer_list, entry); - fn = timer->function; - data = timer->data; - irqsafe = timer->flags & TIMER_IRQSAFE; - - timer_stats_account_timer(timer); - - base->running_timer = timer; - detach_expired_timer(timer, base); - - if (irqsafe) { - spin_unlock(&base->lock); - call_timer_fn(timer, fn, data); - spin_lock(&base->lock); - } else { - spin_unlock_irq(&base->lock); - call_timer_fn(timer, fn, data); - spin_lock_irq(&base->lock); - } - } + while (levels--) + expire_timers(base, heads + levels); } base->running_timer = NULL; spin_unlock_irq(&base->lock); @@ -1218,78 +1324,87 @@ static inline void __run_timers(struct timer_base *base) #ifdef CONFIG_NO_HZ_COMMON /* - * Find out when the next timer event is due to happen. This - * is used on S/390 to stop all activity when a CPU is idle. - * This function needs to be called with interrupts disabled. + * Find the next pending bucket of a level. Search from @offset + @clk upwards + * and if nothing there, search from start of the level (@offset) up to + * @offset + clk. + */ +static int next_pending_bucket(struct timer_base *base, unsigned offset, + unsigned clk) +{ + unsigned pos, start = offset + clk; + unsigned end = offset + LVL_SIZE; + + pos = find_next_bit(base->pending_map, end, start); + if (pos < end) + return pos - start; + + pos = find_next_bit(base->pending_map, start, offset); + return pos < start ? pos + LVL_SIZE - start : -1; +} + +/* + * Search the first expiring timer in the various clock levels. */ static unsigned long __next_timer_interrupt(struct timer_base *base) { - unsigned long clk = base->clk; - unsigned long expires = clk + NEXT_TIMER_MAX_DELTA; - int index, slot, array, found = 0; - struct timer_list *nte; - struct tvec *varray[4]; - - /* Look for timer events in tv1. */ - index = slot = clk & TVR_MASK; - do { - hlist_for_each_entry(nte, base->tv1.vec + slot, entry) { - if (nte->flags & TIMER_DEFERRABLE) - continue; - - found = 1; - expires = nte->expires; - /* Look at the cascade bucket(s)? */ - if (!index || slot < index) - goto cascade; - return expires; + unsigned long clk, next, adj; + unsigned lvl, offset = 0; + + spin_lock(&base->lock); + next = base->clk + NEXT_TIMER_MAX_DELTA; + clk = base->clk; + for (lvl = 0; lvl < LVL_DEPTH; lvl++, offset += LVL_SIZE) { + int pos = next_pending_bucket(base, offset, clk & LVL_MASK); + + if (pos >= 0) { + unsigned long tmp = clk + (unsigned long) pos; + + tmp <<= LVL_SHIFT(lvl); + if (time_before(tmp, next)) + next = tmp; } - slot = (slot + 1) & TVR_MASK; - } while (slot != index); - -cascade: - /* Calculate the next cascade event */ - if (index) - clk += TVR_SIZE - index; - clk >>= TVR_BITS; - - /* Check tv2-tv5. */ - varray[0] = &base->tv2; - varray[1] = &base->tv3; - varray[2] = &base->tv4; - varray[3] = &base->tv5; - - for (array = 0; array < 4; array++) { - struct tvec *varp = varray[array]; - - index = slot = clk & TVN_MASK; - do { - hlist_for_each_entry(nte, varp->vec + slot, entry) { - if (nte->flags & TIMER_DEFERRABLE) - continue; - - found = 1; - if (time_before(nte->expires, expires)) - expires = nte->expires; - } - /* - * Do we still search for the first timer or are - * we looking up the cascade buckets ? - */ - if (found) { - /* Look at the cascade bucket(s)? */ - if (!index || slot < index) - break; - return expires; - } - slot = (slot + 1) & TVN_MASK; - } while (slot != index); - - if (index) - clk += TVN_SIZE - index; - clk >>= TVN_BITS; + /* + * Clock for the next level. If the current level clock lower + * bits are zero, we look at the next level as is. If not we + * need to advance it by one because that's going to be the + * next expiring bucket in that level. base->clk is the next + * expiring jiffie. So in case of: + * + * LVL5 LVL4 LVL3 LVL2 LVL1 LVL0 + * 0 0 0 0 0 0 + * + * we have to look at all levels @index 0. With + * + * LVL5 LVL4 LVL3 LVL2 LVL1 LVL0 + * 0 0 0 0 0 2 + * + * LVL0 has the next expiring bucket @index 2. The upper + * levels have the next expiring bucket @index 1. + * + * In case that the propagation wraps the next level the same + * rules apply: + * + * LVL5 LVL4 LVL3 LVL2 LVL1 LVL0 + * 0 0 0 0 F 2 + * + * So after looking at LVL0 we get: + * + * LVL5 LVL4 LVL3 LVL2 LVL1 + * 0 0 0 1 0 + * + * So no propagation from LVL1 to LVL2 because that happened + * with the add already, but then we need to propagate further + * from LVL2 to LVL3. + * + * So the simple check whether the lower bits of the current + * level are 0 or not is sufficient for all cases. + */ + adj = clk & LVL_CLK_MASK ? 1 : 0; + clk >>= LVL_CLK_SHIFT; + clk += adj; } - return expires; + spin_unlock(&base->lock); + return next; } /* @@ -1335,7 +1450,7 @@ static u64 cmp_next_hrtimer_event(u64 basem, u64 expires) */ u64 get_next_timer_interrupt(unsigned long basej, u64 basem) { - struct timer_base *base = this_cpu_ptr(&timer_bases); + struct timer_base *base = this_cpu_ptr(&timer_bases[BASE_STD]); u64 expires = KTIME_MAX; unsigned long nextevt; @@ -1346,17 +1461,11 @@ u64 get_next_timer_interrupt(unsigned long basej, u64 basem) if (cpu_is_offline(smp_processor_id())) return expires; - spin_lock(&base->lock); - if (base->active_timers) { - if (time_before_eq(base->next_timer, base->clk)) - base->next_timer = __next_timer_interrupt(base); - nextevt = base->next_timer; - if (time_before_eq(nextevt, basej)) - expires = basem; - else - expires = basem + (nextevt - basej) * TICK_NSEC; - } - spin_unlock(&base->lock); + nextevt = __next_timer_interrupt(base); + if (time_before_eq(nextevt, basej)) + expires = basem; + else + expires = basem + (nextevt - basej) * TICK_NSEC; return cmp_next_hrtimer_event(basem, expires); } @@ -1387,10 +1496,11 @@ void update_process_times(int user_tick) */ static void run_timer_softirq(struct softirq_action *h) { - struct timer_base *base = this_cpu_ptr(&timer_bases); + struct timer_base *base = this_cpu_ptr(&timer_bases[BASE_STD]); - if (time_after_eq(jiffies, base->clk)) - __run_timers(base); + __run_timers(base); + if (IS_ENABLED(CONFIG_NO_HZ_COMMON) && base->nohz_active) + __run_timers(this_cpu_ptr(&timer_bases[BASE_DEF])); } /* @@ -1541,7 +1651,6 @@ static void migrate_timer_list(struct timer_base *new_base, struct hlist_head *h while (!hlist_empty(head)) { timer = hlist_entry(head->first, struct timer_list, entry); - /* We ignore the accounting on the dying cpu */ detach_timer(timer, false); timer->flags = (timer->flags & ~TIMER_BASEMASK) | cpu; internal_add_timer(new_base, timer); @@ -1552,35 +1661,29 @@ static void migrate_timers(int cpu) { struct timer_base *old_base; struct timer_base *new_base; - int i; + int b, i; BUG_ON(cpu_online(cpu)); - old_base = per_cpu_ptr(&timer_bases, cpu); - new_base = get_cpu_ptr(&timer_bases); - /* - * The caller is globally serialized and nobody else - * takes two locks at once, deadlock is not possible. - */ - spin_lock_irq(&new_base->lock); - spin_lock_nested(&old_base->lock, SINGLE_DEPTH_NESTING); - - BUG_ON(old_base->running_timer); - - for (i = 0; i < TVR_SIZE; i++) - migrate_timer_list(new_base, old_base->tv1.vec + i); - for (i = 0; i < TVN_SIZE; i++) { - migrate_timer_list(new_base, old_base->tv2.vec + i); - migrate_timer_list(new_base, old_base->tv3.vec + i); - migrate_timer_list(new_base, old_base->tv4.vec + i); - migrate_timer_list(new_base, old_base->tv5.vec + i); - } - old_base->active_timers = 0; - old_base->all_timers = 0; + for (b = 0; b < NR_BASES; b++) { + old_base = per_cpu_ptr(&timer_bases[b], cpu); + new_base = get_cpu_ptr(&timer_bases[b]); + /* + * The caller is globally serialized and nobody else + * takes two locks at once, deadlock is not possible. + */ + spin_lock_irq(&new_base->lock); + spin_lock_nested(&old_base->lock, SINGLE_DEPTH_NESTING); + + BUG_ON(old_base->running_timer); + + for (i = 0; i < WHEEL_SIZE; i++) + migrate_timer_list(new_base, old_base->vectors + i); - spin_unlock(&old_base->lock); - spin_unlock_irq(&new_base->lock); - put_cpu_ptr(&timer_bases); + spin_unlock(&old_base->lock); + spin_unlock_irq(&new_base->lock); + put_cpu_ptr(&timer_bases); + } } static int timer_cpu_notify(struct notifier_block *self, @@ -1608,13 +1711,15 @@ static inline void timer_register_cpu_notifier(void) { } static void __init init_timer_cpu(int cpu) { - struct timer_base *base = per_cpu_ptr(&timer_bases, cpu); - - base->cpu = cpu; - spin_lock_init(&base->lock); + struct timer_base *base; + int i; - base->clk = jiffies; - base->next_timer = base->clk; + for (i = 0; i < NR_BASES; i++) { + base = per_cpu_ptr(&timer_bases[i], cpu); + base->cpu = cpu; + spin_lock_init(&base->lock); + base->clk = jiffies; + } } static void __init init_timer_cpus(void) -- cgit v0.10.2 From 53bf837b78d155b8e1110b3c25b4d0d6391b8ff3 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Mon, 4 Jul 2016 09:50:31 +0000 Subject: timers: Remove set_timer_slack() leftovers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We now have implicit batching in the timer wheel. The slack API is no longer used, so remove it. Signed-off-by: Thomas Gleixner Cc: Alan Stern Cc: Andrew F. Davis Cc: Arjan van de Ven Cc: Chris Mason Cc: David S. Miller Cc: David Woodhouse Cc: Dmitry Eremin-Solenikov Cc: Eric Dumazet Cc: Frederic Weisbecker Cc: George Spelvin Cc: Greg Kroah-Hartman Cc: Jaehoon Chung Cc: Jens Axboe Cc: John Stultz Cc: Josh Triplett Cc: Len Brown Cc: Linus Torvalds Cc: Mathias Nyman Cc: Pali Rohár Cc: Paul E. McKenney Cc: Peter Zijlstra Cc: Rik van Riel Cc: Sebastian Reichel Cc: Ulf Hansson Cc: linux-block@vger.kernel.org Cc: linux-kernel@vger.kernel.org Cc: linux-mmc@vger.kernel.org Cc: linux-pm@vger.kernel.org Cc: linux-usb@vger.kernel.org Cc: netdev@vger.kernel.org Cc: rt@linutronix.de Link: http://lkml.kernel.org/r/20160704094342.189813118@linutronix.de Signed-off-by: Ingo Molnar diff --git a/block/genhd.c b/block/genhd.c index 9f42526..f06d7f3 100644 --- a/block/genhd.c +++ b/block/genhd.c @@ -1523,12 +1523,7 @@ static void __disk_unblock_events(struct gendisk *disk, bool check_now) if (--ev->block) goto out_unlock; - /* - * Not exactly a latency critical operation, set poll timer - * slack to 25% and kick event check. - */ intv = disk_events_poll_jiffies(disk); - set_timer_slack(&ev->dwork.timer, intv / 4); if (check_now) queue_delayed_work(system_freezable_power_efficient_wq, &ev->dwork, 0); diff --git a/drivers/mmc/host/jz4740_mmc.c b/drivers/mmc/host/jz4740_mmc.c index 03ddf0e..684087d 100644 --- a/drivers/mmc/host/jz4740_mmc.c +++ b/drivers/mmc/host/jz4740_mmc.c @@ -1068,8 +1068,6 @@ static int jz4740_mmc_probe(struct platform_device* pdev) jz4740_mmc_clock_disable(host); setup_timer(&host->timeout_timer, jz4740_mmc_timeout, (unsigned long)host); - /* It is not important when it times out, it just needs to timeout. */ - set_timer_slack(&host->timeout_timer, HZ); host->use_dma = true; if (host->use_dma && jz4740_mmc_acquire_dma_channels(host) != 0) diff --git a/drivers/power/bq27xxx_battery.c b/drivers/power/bq27xxx_battery.c index 45f6ebf..e90b3f3 100644 --- a/drivers/power/bq27xxx_battery.c +++ b/drivers/power/bq27xxx_battery.c @@ -735,11 +735,8 @@ static void bq27xxx_battery_poll(struct work_struct *work) bq27xxx_battery_update(di); - if (poll_interval > 0) { - /* The timer does not have to be accurate. */ - set_timer_slack(&di->work.timer, poll_interval * HZ / 4); + if (poll_interval > 0) schedule_delayed_work(&di->work, poll_interval * HZ); - } } /* diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c index 0449235..1700908 100644 --- a/drivers/usb/host/ohci-hcd.c +++ b/drivers/usb/host/ohci-hcd.c @@ -500,7 +500,6 @@ static int ohci_init (struct ohci_hcd *ohci) setup_timer(&ohci->io_watchdog, io_watchdog_func, (unsigned long) ohci); - set_timer_slack(&ohci->io_watchdog, msecs_to_jiffies(20)); ohci->hcca = dma_alloc_coherent (hcd->self.controller, sizeof(*ohci->hcca), &ohci->hcca_dma, GFP_KERNEL); diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index f2f9518..a986fe7 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -490,8 +490,6 @@ static void compliance_mode_recovery_timer_init(struct xhci_hcd *xhci) xhci->comp_mode_recovery_timer.expires = jiffies + msecs_to_jiffies(COMP_MODE_RCVRY_MSECS); - set_timer_slack(&xhci->comp_mode_recovery_timer, - msecs_to_jiffies(COMP_MODE_RCVRY_MSECS)); add_timer(&xhci->comp_mode_recovery_timer); xhci_dbg_trace(xhci, trace_xhci_dbg_quirks, "Compliance mode recovery timer initialized"); diff --git a/include/linux/timer.h b/include/linux/timer.h index 5869ab9..4419506 100644 --- a/include/linux/timer.h +++ b/include/linux/timer.h @@ -19,7 +19,6 @@ struct timer_list { void (*function)(unsigned long); unsigned long data; u32 flags; - int slack; #ifdef CONFIG_TIMER_STATS int start_pid; @@ -73,7 +72,6 @@ struct timer_list { .expires = (_expires), \ .data = (_data), \ .flags = (_flags), \ - .slack = -1, \ __TIMER_LOCKDEP_MAP_INITIALIZER( \ __FILE__ ":" __stringify(__LINE__)) \ } @@ -193,8 +191,6 @@ extern int del_timer(struct timer_list * timer); extern int mod_timer(struct timer_list *timer, unsigned long expires); extern int mod_timer_pending(struct timer_list *timer, unsigned long expires); -extern void set_timer_slack(struct timer_list *time, int slack_hz); - /* * The jiffies value which is added to now, when there is no timer * in the timer wheel: diff --git a/kernel/time/timer.c b/kernel/time/timer.c index 86e95b7..a83e23d 100644 --- a/kernel/time/timer.c +++ b/kernel/time/timer.c @@ -447,24 +447,6 @@ unsigned long round_jiffies_up_relative(unsigned long j) } EXPORT_SYMBOL_GPL(round_jiffies_up_relative); -/** - * set_timer_slack - set the allowed slack for a timer - * @timer: the timer to be modified - * @slack_hz: the amount of time (in jiffies) allowed for rounding - * - * Set the amount of time, in jiffies, that a certain timer has - * in terms of slack. By setting this value, the timer subsystem - * will schedule the actual timer somewhere between - * the time mod_timer() asks for, and that time plus the slack. - * - * By setting the slack to -1, a percentage of the delay is used - * instead. - */ -void set_timer_slack(struct timer_list *timer, int slack_hz) -{ - timer->slack = slack_hz; -} -EXPORT_SYMBOL_GPL(set_timer_slack); static inline unsigned int timer_get_idx(struct timer_list *timer) { @@ -775,7 +757,6 @@ static void do_init_timer(struct timer_list *timer, unsigned int flags, { timer->entry.pprev = NULL; timer->flags = flags | raw_smp_processor_id(); - timer->slack = -1; #ifdef CONFIG_TIMER_STATS timer->start_site = NULL; timer->start_pid = -1; diff --git a/lib/random32.c b/lib/random32.c index 510d1ce..69ed593 100644 --- a/lib/random32.c +++ b/lib/random32.c @@ -233,7 +233,6 @@ static void __prandom_timer(unsigned long dontcare) static void __init __prandom_start_seed_timer(void) { - set_timer_slack(&seed_timer, HZ); seed_timer.expires = jiffies + msecs_to_jiffies(40 * MSEC_PER_SEC); add_timer(&seed_timer); } -- cgit v0.10.2 From 73420fea80c6c376d91a69defe64013baa0d7e95 Mon Sep 17 00:00:00 2001 From: Anna-Maria Gleixner Date: Mon, 4 Jul 2016 09:50:33 +0000 Subject: timers: Move __run_timers() function Move __run_timers() below __next_timer_interrupt() and next_pending_bucket() in preparation for __run_timers() NOHZ optimization. No functional change. Signed-off-by: Anna-Maria Gleixner Signed-off-by: Thomas Gleixner Cc: Arjan van de Ven Cc: Chris Mason Cc: Eric Dumazet Cc: Frederic Weisbecker Cc: George Spelvin Cc: Josh Triplett Cc: Len Brown Cc: Linus Torvalds Cc: Paul E. McKenney Cc: Peter Zijlstra Cc: Rik van Riel Cc: rt@linutronix.de Link: http://lkml.kernel.org/r/20160704094342.271872665@linutronix.de Signed-off-by: Ingo Molnar diff --git a/kernel/time/timer.c b/kernel/time/timer.c index a83e23d..c16c48d 100644 --- a/kernel/time/timer.c +++ b/kernel/time/timer.c @@ -1277,32 +1277,6 @@ static int collect_expired_timers(struct timer_base *base, return levels; } -/** - * __run_timers - run all expired timers (if any) on this CPU. - * @base: the timer vector to be processed. - */ -static inline void __run_timers(struct timer_base *base) -{ - struct hlist_head heads[LVL_DEPTH]; - int levels; - - if (!time_after_eq(jiffies, base->clk)) - return; - - spin_lock_irq(&base->lock); - - while (time_after_eq(jiffies, base->clk)) { - - levels = collect_expired_timers(base, heads); - base->clk++; - - while (levels--) - expire_timers(base, heads + levels); - } - base->running_timer = NULL; - spin_unlock_irq(&base->lock); -} - #ifdef CONFIG_NO_HZ_COMMON /* * Find the next pending bucket of a level. Search from @offset + @clk upwards @@ -1472,6 +1446,32 @@ void update_process_times(int user_tick) run_posix_cpu_timers(p); } +/** + * __run_timers - run all expired timers (if any) on this CPU. + * @base: the timer vector to be processed. + */ +static inline void __run_timers(struct timer_base *base) +{ + struct hlist_head heads[LVL_DEPTH]; + int levels; + + if (!time_after_eq(jiffies, base->clk)) + return; + + spin_lock_irq(&base->lock); + + while (time_after_eq(jiffies, base->clk)) { + + levels = collect_expired_timers(base, heads); + base->clk++; + + while (levels--) + expire_timers(base, heads + levels); + } + base->running_timer = NULL; + spin_unlock_irq(&base->lock); +} + /* * This function runs timers and the timer-tq in bottom half context. */ -- cgit v0.10.2 From 236968383cf5cd48835ff0d8a265e299e220d140 Mon Sep 17 00:00:00 2001 From: Anna-Maria Gleixner Date: Mon, 4 Jul 2016 09:50:34 +0000 Subject: timers: Optimize collect_expired_timers() for NOHZ After a NOHZ idle sleep the timer wheel must be forwarded to current jiffies. There might be expired timers so the current code loops and checks the expired buckets for timers. This can take quite some time for long NOHZ idle periods. The pending bitmask in the timer base allows us to do a quick search for the next expiring timer and therefore a fast forward of the base time which prevents pointless long lasting loops. For a 3 seconds idle sleep this reduces the catchup time from ~1ms to 5us. Signed-off-by: Anna-Maria Gleixner Signed-off-by: Thomas Gleixner Cc: Arjan van de Ven Cc: Chris Mason Cc: Eric Dumazet Cc: Frederic Weisbecker Cc: George Spelvin Cc: Josh Triplett Cc: Len Brown Cc: Linus Torvalds Cc: Paul E. McKenney Cc: Peter Zijlstra Cc: Rik van Riel Cc: rt@linutronix.de Link: http://lkml.kernel.org/r/20160704094342.351296290@linutronix.de Signed-off-by: Ingo Molnar diff --git a/kernel/time/timer.c b/kernel/time/timer.c index c16c48d..658051c 100644 --- a/kernel/time/timer.c +++ b/kernel/time/timer.c @@ -1252,8 +1252,8 @@ static void expire_timers(struct timer_base *base, struct hlist_head *head) } } -static int collect_expired_timers(struct timer_base *base, - struct hlist_head *heads) +static int __collect_expired_timers(struct timer_base *base, + struct hlist_head *heads) { unsigned long clk = base->clk; struct hlist_head *vec; @@ -1279,9 +1279,9 @@ static int collect_expired_timers(struct timer_base *base, #ifdef CONFIG_NO_HZ_COMMON /* - * Find the next pending bucket of a level. Search from @offset + @clk upwards - * and if nothing there, search from start of the level (@offset) up to - * @offset + clk. + * Find the next pending bucket of a level. Search from level start (@offset) + * + @clk upwards and if nothing there, search from start of the level + * (@offset) up to @offset + clk. */ static int next_pending_bucket(struct timer_base *base, unsigned offset, unsigned clk) @@ -1298,14 +1298,14 @@ static int next_pending_bucket(struct timer_base *base, unsigned offset, } /* - * Search the first expiring timer in the various clock levels. + * Search the first expiring timer in the various clock levels. Caller must + * hold base->lock. */ static unsigned long __next_timer_interrupt(struct timer_base *base) { unsigned long clk, next, adj; unsigned lvl, offset = 0; - spin_lock(&base->lock); next = base->clk + NEXT_TIMER_MAX_DELTA; clk = base->clk; for (lvl = 0; lvl < LVL_DEPTH; lvl++, offset += LVL_SIZE) { @@ -1358,7 +1358,6 @@ static unsigned long __next_timer_interrupt(struct timer_base *base) clk >>= LVL_CLK_SHIFT; clk += adj; } - spin_unlock(&base->lock); return next; } @@ -1416,7 +1415,10 @@ u64 get_next_timer_interrupt(unsigned long basej, u64 basem) if (cpu_is_offline(smp_processor_id())) return expires; + spin_lock(&base->lock); nextevt = __next_timer_interrupt(base); + spin_unlock(&base->lock); + if (time_before_eq(nextevt, basej)) expires = basem; else @@ -1424,6 +1426,37 @@ u64 get_next_timer_interrupt(unsigned long basej, u64 basem) return cmp_next_hrtimer_event(basem, expires); } + +static int collect_expired_timers(struct timer_base *base, + struct hlist_head *heads) +{ + /* + * NOHZ optimization. After a long idle sleep we need to forward the + * base to current jiffies. Avoid a loop by searching the bitfield for + * the next expiring timer. + */ + if ((long)(jiffies - base->clk) > 2) { + unsigned long next = __next_timer_interrupt(base); + + /* + * If the next timer is ahead of time forward to current + * jiffies, otherwise forward to the next expiry time. + */ + if (time_after(next, jiffies)) { + /* The call site will increment clock! */ + base->clk = jiffies - 1; + return 0; + } + base->clk = next; + } + return __collect_expired_timers(base, heads); +} +#else +static inline int collect_expired_timers(struct timer_base *base, + struct hlist_head *heads) +{ + return __collect_expired_timers(base, heads); +} #endif /* -- cgit v0.10.2 From ff00673292bd42a3688b33de47252a6a3c3f424c Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Mon, 4 Jul 2016 09:50:35 +0000 Subject: timers/nohz: Remove pointless tick_nohz_kick_tick() function This was a failed attempt to optimize the timer expiry in idle, which was disabled and never revisited. Remove the cruft. Signed-off-by: Thomas Gleixner Cc: Arjan van de Ven Cc: Chris Mason Cc: Eric Dumazet Cc: Frederic Weisbecker Cc: George Spelvin Cc: Josh Triplett Cc: Len Brown Cc: Linus Torvalds Cc: Paul E. McKenney Cc: Peter Zijlstra Cc: Rik van Riel Cc: rt@linutronix.de Link: http://lkml.kernel.org/r/20160704094342.431073782@linutronix.de Signed-off-by: Ingo Molnar diff --git a/kernel/time/tick-sched.c b/kernel/time/tick-sched.c index 536ada8..69abc7b 100644 --- a/kernel/time/tick-sched.c +++ b/kernel/time/tick-sched.c @@ -1092,35 +1092,6 @@ static void tick_nohz_switch_to_nohz(void) tick_nohz_activate(ts, NOHZ_MODE_LOWRES); } -/* - * When NOHZ is enabled and the tick is stopped, we need to kick the - * tick timer from irq_enter() so that the jiffies update is kept - * alive during long running softirqs. That's ugly as hell, but - * correctness is key even if we need to fix the offending softirq in - * the first place. - * - * Note, this is different to tick_nohz_restart. We just kick the - * timer and do not touch the other magic bits which need to be done - * when idle is left. - */ -static void tick_nohz_kick_tick(struct tick_sched *ts, ktime_t now) -{ -#if 0 - /* Switch back to 2.6.27 behaviour */ - ktime_t delta; - - /* - * Do not touch the tick device, when the next expiry is either - * already reached or less/equal than the tick period. - */ - delta = ktime_sub(hrtimer_get_expires(&ts->sched_timer), now); - if (delta.tv64 <= tick_period.tv64) - return; - - tick_nohz_restart(ts, now); -#endif -} - static inline void tick_nohz_irq_enter(void) { struct tick_sched *ts = this_cpu_ptr(&tick_cpu_sched); @@ -1131,10 +1102,8 @@ static inline void tick_nohz_irq_enter(void) now = ktime_get(); if (ts->idle_active) tick_nohz_stop_idle(ts, now); - if (ts->tick_stopped) { + if (ts->tick_stopped) tick_nohz_update_jiffies(now); - tick_nohz_kick_tick(ts, now); - } } #else -- cgit v0.10.2 From a683f390b93f4d1292f849fc48d28e322046120f Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Mon, 4 Jul 2016 09:50:36 +0000 Subject: timers: Forward the wheel clock whenever possible The wheel clock is stale when a CPU goes into a long idle sleep. This has the side effect that timers which are queued end up in the outer wheel levels. That results in coarser granularity. To solve this, we keep track of the idle state and forward the wheel clock whenever possible. Signed-off-by: Thomas Gleixner Cc: Arjan van de Ven Cc: Chris Mason Cc: Eric Dumazet Cc: Frederic Weisbecker Cc: George Spelvin Cc: Josh Triplett Cc: Len Brown Cc: Linus Torvalds Cc: Paul E. McKenney Cc: Peter Zijlstra Cc: Rik van Riel Cc: rt@linutronix.de Link: http://lkml.kernel.org/r/20160704094342.512039360@linutronix.de Signed-off-by: Ingo Molnar diff --git a/kernel/time/tick-internal.h b/kernel/time/tick-internal.h index 966a5a6..f738251 100644 --- a/kernel/time/tick-internal.h +++ b/kernel/time/tick-internal.h @@ -164,3 +164,4 @@ static inline void timers_update_migration(bool update_nohz) { } DECLARE_PER_CPU(struct hrtimer_cpu_base, hrtimer_bases); extern u64 get_next_timer_interrupt(unsigned long basej, u64 basem); +void timer_clear_idle(void); diff --git a/kernel/time/tick-sched.c b/kernel/time/tick-sched.c index 69abc7b..5d81f9a 100644 --- a/kernel/time/tick-sched.c +++ b/kernel/time/tick-sched.c @@ -700,6 +700,12 @@ static ktime_t tick_nohz_stop_sched_tick(struct tick_sched *ts, delta = next_tick - basemono; if (delta <= (u64)TICK_NSEC) { tick.tv64 = 0; + + /* + * Tell the timer code that the base is not idle, i.e. undo + * the effect of get_next_timer_interrupt(): + */ + timer_clear_idle(); /* * We've not stopped the tick yet, and there's a timer in the * next period, so no point in stopping it either, bail. @@ -809,6 +815,12 @@ static void tick_nohz_restart_sched_tick(struct tick_sched *ts, ktime_t now) tick_do_update_jiffies64(now); cpu_load_update_nohz_stop(); + /* + * Clear the timer idle flag, so we avoid IPIs on remote queueing and + * the clock forward checks in the enqueue path: + */ + timer_clear_idle(); + calc_load_exit_idle(); touch_softlockup_watchdog_sched(); /* diff --git a/kernel/time/timer.c b/kernel/time/timer.c index 658051c..9339d71 100644 --- a/kernel/time/timer.c +++ b/kernel/time/timer.c @@ -196,9 +196,11 @@ struct timer_base { spinlock_t lock; struct timer_list *running_timer; unsigned long clk; + unsigned long next_expiry; unsigned int cpu; bool migration_enabled; bool nohz_active; + bool is_idle; DECLARE_BITMAP(pending_map, WHEEL_SIZE); struct hlist_head vectors[WHEEL_SIZE]; } ____cacheline_aligned; @@ -519,24 +521,37 @@ static void internal_add_timer(struct timer_base *base, struct timer_list *timer { __internal_add_timer(base, timer); + if (!IS_ENABLED(CONFIG_NO_HZ_COMMON) || !base->nohz_active) + return; + /* - * Check whether the other CPU is in dynticks mode and needs - * to be triggered to reevaluate the timer wheel. We are - * protected against the other CPU fiddling with the timer by - * holding the timer base lock. This also makes sure that a - * CPU on the way to stop its tick can not evaluate the timer - * wheel. - * - * Spare the IPI for deferrable timers on idle targets though. - * The next busy ticks will take care of it. Except full dynticks - * require special care against races with idle_cpu(), lets deal - * with that later. + * TODO: This wants some optimizing similar to the code below, but we + * will do that when we switch from push to pull for deferrable timers. */ - if (IS_ENABLED(CONFIG_NO_HZ_COMMON) && base->nohz_active) { - if (!(timer->flags & TIMER_DEFERRABLE) || - tick_nohz_full_cpu(base->cpu)) + if (timer->flags & TIMER_DEFERRABLE) { + if (tick_nohz_full_cpu(base->cpu)) wake_up_nohz_cpu(base->cpu); + return; } + + /* + * We might have to IPI the remote CPU if the base is idle and the + * timer is not deferrable. If the other CPU is on the way to idle + * then it can't set base->is_idle as we hold the base lock: + */ + if (!base->is_idle) + return; + + /* Check whether this is the new first expiring timer: */ + if (time_after_eq(timer->expires, base->next_expiry)) + return; + + /* + * Set the next expiry time and kick the CPU so it can reevaluate the + * wheel: + */ + base->next_expiry = timer->expires; + wake_up_nohz_cpu(base->cpu); } #ifdef CONFIG_TIMER_STATS @@ -844,10 +859,11 @@ static inline struct timer_base *get_timer_base(u32 tflags) return get_timer_cpu_base(tflags, tflags & TIMER_CPUMASK); } -static inline struct timer_base *get_target_base(struct timer_base *base, - unsigned tflags) +#ifdef CONFIG_NO_HZ_COMMON +static inline struct timer_base * +__get_target_base(struct timer_base *base, unsigned tflags) { -#if defined(CONFIG_NO_HZ_COMMON) && defined(CONFIG_SMP) +#ifdef CONFIG_SMP if ((tflags & TIMER_PINNED) || !base->migration_enabled) return get_timer_this_cpu_base(tflags); return get_timer_cpu_base(tflags, get_nohz_timer_target()); @@ -856,6 +872,43 @@ static inline struct timer_base *get_target_base(struct timer_base *base, #endif } +static inline void forward_timer_base(struct timer_base *base) +{ + /* + * We only forward the base when it's idle and we have a delta between + * base clock and jiffies. + */ + if (!base->is_idle || (long) (jiffies - base->clk) < 2) + return; + + /* + * If the next expiry value is > jiffies, then we fast forward to + * jiffies otherwise we forward to the next expiry value. + */ + if (time_after(base->next_expiry, jiffies)) + base->clk = jiffies; + else + base->clk = base->next_expiry; +} +#else +static inline struct timer_base * +__get_target_base(struct timer_base *base, unsigned tflags) +{ + return get_timer_this_cpu_base(tflags); +} + +static inline void forward_timer_base(struct timer_base *base) { } +#endif + +static inline struct timer_base * +get_target_base(struct timer_base *base, unsigned tflags) +{ + struct timer_base *target = __get_target_base(base, tflags); + + forward_timer_base(target); + return target; +} + /* * We are using hashed locking: Holding per_cpu(timer_bases[x]).lock means * that all timers which are tied to this base are locked, and the base itself @@ -1417,16 +1470,49 @@ u64 get_next_timer_interrupt(unsigned long basej, u64 basem) spin_lock(&base->lock); nextevt = __next_timer_interrupt(base); - spin_unlock(&base->lock); + base->next_expiry = nextevt; + /* + * We have a fresh next event. Check whether we can forward the base: + */ + if (time_after(nextevt, jiffies)) + base->clk = jiffies; + else if (time_after(nextevt, base->clk)) + base->clk = nextevt; - if (time_before_eq(nextevt, basej)) + if (time_before_eq(nextevt, basej)) { expires = basem; - else + base->is_idle = false; + } else { expires = basem + (nextevt - basej) * TICK_NSEC; + /* + * If we expect to sleep more than a tick, mark the base idle: + */ + if ((expires - basem) > TICK_NSEC) + base->is_idle = true; + } + spin_unlock(&base->lock); return cmp_next_hrtimer_event(basem, expires); } +/** + * timer_clear_idle - Clear the idle state of the timer base + * + * Called with interrupts disabled + */ +void timer_clear_idle(void) +{ + struct timer_base *base = this_cpu_ptr(&timer_bases[BASE_STD]); + + /* + * We do this unlocked. The worst outcome is a remote enqueue sending + * a pointless IPI, but taking the lock would just make the window for + * sending the IPI a few instructions smaller for the cost of taking + * the lock in the exit from idle path. + */ + base->is_idle = false; +} + static int collect_expired_timers(struct timer_base *base, struct hlist_head *heads) { @@ -1440,7 +1526,7 @@ static int collect_expired_timers(struct timer_base *base, /* * If the next timer is ahead of time forward to current - * jiffies, otherwise forward to the next expiry time. + * jiffies, otherwise forward to the next expiry time: */ if (time_after(next, jiffies)) { /* The call site will increment clock! */ -- cgit v0.10.2 From 4e85876a9d2a977b4a07389da8c07edf76d10825 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Mon, 4 Jul 2016 09:50:37 +0000 Subject: timers: Only wake softirq if necessary With the wheel forwading in place and with the HZ=1000 4ms folding we can avoid running the softirq at all. Signed-off-by: Thomas Gleixner Cc: Arjan van de Ven Cc: Chris Mason Cc: Frederic Weisbecker Cc: George Spelvin Cc: Josh Triplett Cc: Len Brown Cc: Linus Torvalds Cc: Paul McKenney Cc: Peter Zijlstra Cc: Rik van Riel Cc: rt@linutronix.de Link: http://lkml.kernel.org/r/20160704094342.607650550@linutronix.de Signed-off-by: Ingo Molnar diff --git a/kernel/time/timer.c b/kernel/time/timer.c index 9339d71..8d830f1 100644 --- a/kernel/time/timer.c +++ b/kernel/time/timer.c @@ -1608,7 +1608,18 @@ static void run_timer_softirq(struct softirq_action *h) */ void run_local_timers(void) { + struct timer_base *base = this_cpu_ptr(&timer_bases[BASE_STD]); + hrtimer_run_queues(); + /* Raise the softirq only if required. */ + if (time_before(jiffies, base->clk)) { + if (!IS_ENABLED(CONFIG_NO_HZ_COMMON) || !base->nohz_active) + return; + /* CPU is awake, so check the deferrable base. */ + base++; + if (time_before(jiffies, base->clk)) + return; + } raise_softirq(TIMER_SOFTIRQ); } -- cgit v0.10.2 From ffdf047728f8f93df896b58049c7513856027141 Mon Sep 17 00:00:00 2001 From: Anna-Maria Gleixner Date: Mon, 4 Jul 2016 09:50:39 +0000 Subject: timers: Split out index calculation For further optimizations we need to seperate index calculation from queueing. No functional change. Signed-off-by: Anna-Maria Gleixner Signed-off-by: Thomas Gleixner Cc: Arjan van de Ven Cc: Chris Mason Cc: Eric Dumazet Cc: Frederic Weisbecker Cc: George Spelvin Cc: Josh Triplett Cc: Len Brown Cc: Linus Torvalds Cc: Paul E. McKenney Cc: Peter Zijlstra Cc: Rik van Riel Cc: rt@linutronix.de Link: http://lkml.kernel.org/r/20160704094342.691159619@linutronix.de Signed-off-by: Ingo Molnar diff --git a/kernel/time/timer.c b/kernel/time/timer.c index 8d830f1..8d7c23e 100644 --- a/kernel/time/timer.c +++ b/kernel/time/timer.c @@ -471,12 +471,9 @@ static inline unsigned calc_index(unsigned expires, unsigned lvl) return LVL_OFFS(lvl) + (expires & LVL_MASK); } -static void -__internal_add_timer(struct timer_base *base, struct timer_list *timer) +static int calc_wheel_index(unsigned long expires, unsigned long clk) { - unsigned long expires = timer->expires; - unsigned long delta = expires - base->clk; - struct hlist_head *vec; + unsigned long delta = expires - clk; unsigned int idx; if (delta < LVL_START(1)) { @@ -496,7 +493,7 @@ __internal_add_timer(struct timer_base *base, struct timer_list *timer) } else if (LVL_DEPTH > 8 && delta < LVL_START(8)) { idx = calc_index(expires, 7); } else if ((long) delta < 0) { - idx = base->clk & LVL_MASK; + idx = clk & LVL_MASK; } else { /* * Force expire obscene large timeouts to expire at the @@ -507,20 +504,33 @@ __internal_add_timer(struct timer_base *base, struct timer_list *timer) idx = calc_index(expires, LVL_DEPTH - 1); } - /* - * Enqueue the timer into the array bucket, mark it pending in - * the bitmap and store the index in the timer flags. - */ - vec = base->vectors + idx; - hlist_add_head(&timer->entry, vec); + return idx; +} + +/* + * Enqueue the timer into the hash bucket, mark it pending in + * the bitmap and store the index in the timer flags. + */ +static void enqueue_timer(struct timer_base *base, struct timer_list *timer, + unsigned int idx) +{ + hlist_add_head(&timer->entry, base->vectors + idx); __set_bit(idx, base->pending_map); timer_set_idx(timer, idx); } -static void internal_add_timer(struct timer_base *base, struct timer_list *timer) +static void +__internal_add_timer(struct timer_base *base, struct timer_list *timer) { - __internal_add_timer(base, timer); + unsigned int idx; + + idx = calc_wheel_index(timer->expires, base->clk); + enqueue_timer(base, timer, idx); +} +static void +trigger_dyntick_cpu(struct timer_base *base, struct timer_list *timer) +{ if (!IS_ENABLED(CONFIG_NO_HZ_COMMON) || !base->nohz_active) return; @@ -551,7 +561,14 @@ static void internal_add_timer(struct timer_base *base, struct timer_list *timer * wheel: */ base->next_expiry = timer->expires; - wake_up_nohz_cpu(base->cpu); + wake_up_nohz_cpu(base->cpu); +} + +static void +internal_add_timer(struct timer_base *base, struct timer_list *timer) +{ + __internal_add_timer(base, timer); + trigger_dyntick_cpu(base, timer); } #ifdef CONFIG_TIMER_STATS -- cgit v0.10.2 From f00c0afdfa625165a609513bc74164d56752ec3e Mon Sep 17 00:00:00 2001 From: Anna-Maria Gleixner Date: Mon, 4 Jul 2016 09:50:40 +0000 Subject: timers: Implement optimization for same expiry time in mod_timer() The existing optimization for same expiry time in mod_timer() checks whether the timer expiry time is the same as the new requested expiry time. In the old timer wheel implementation this does not take the slack batching into account, neither does the new implementation evaluate whether the new expiry time will requeue the timer to the same bucket. To optimize that, we can calculate the resulting bucket and check if the new expiry time is different from the current expiry time. This calculation happens outside the base lock held region. If the resulting bucket is the same we can avoid taking the base lock and requeueing the timer. If the timer needs to be requeued then we have to check under the base lock whether the base time has changed between the lockless calculation and taking the lock. If it has changed we need to recalculate under the lock. This optimization takes effect for timers which are enqueued into the less granular wheel levels (1 and above). With a simple test case the functionality has been verified: Before After Match: 5.5% 86.6% Requeue: 94.5% 13.4% Recalc: <0.01% In the non optimized case the timer is requeued in 94.5% of the cases. With the index optimization in place the requeue rate drops to 13.4%. The case where the lockless index calculation has to be redone is less than 0.01%. With a real world test case (networking) we observed the following changes: Before After Match: 97.8% 99.7% Requeue: 2.2% 0.3% Recalc: <0.001% That means two percent fewer lock/requeue/unlock operations done in one of the hot path use cases of timers. Signed-off-by: Anna-Maria Gleixner Signed-off-by: Thomas Gleixner Cc: Arjan van de Ven Cc: Chris Mason Cc: Eric Dumazet Cc: Frederic Weisbecker Cc: George Spelvin Cc: Josh Triplett Cc: Len Brown Cc: Linus Torvalds Cc: Paul E. McKenney Cc: Peter Zijlstra Cc: Rik van Riel Cc: rt@linutronix.de Link: http://lkml.kernel.org/r/20160704094342.778527749@linutronix.de Signed-off-by: Ingo Molnar diff --git a/kernel/time/timer.c b/kernel/time/timer.c index 8d7c23e..8f29abe 100644 --- a/kernel/time/timer.c +++ b/kernel/time/timer.c @@ -960,28 +960,36 @@ static inline int __mod_timer(struct timer_list *timer, unsigned long expires, bool pending_only) { struct timer_base *base, *new_base; - unsigned long flags; + unsigned int idx = UINT_MAX; + unsigned long clk = 0, flags; int ret = 0; /* - * TODO: Calculate the array bucket of the timer right here w/o - * holding the base lock. This allows to check not only - * timer->expires == expires below, but also whether the timer - * ends up in the same bucket. If we really need to requeue - * the timer then we check whether base->clk have - * advanced between here and locking the timer base. If - * jiffies advanced we have to recalc the array bucket with the - * lock held. - */ - - /* - * This is a common optimization triggered by the - * networking code - if the timer is re-modified - * to be the same thing then just return: + * This is a common optimization triggered by the networking code - if + * the timer is re-modified to have the same timeout or ends up in the + * same array bucket then just return: */ if (timer_pending(timer)) { if (timer->expires == expires) return 1; + /* + * Take the current timer_jiffies of base, but without holding + * the lock! + */ + base = get_timer_base(timer->flags); + clk = base->clk; + + idx = calc_wheel_index(expires, clk); + + /* + * Retrieve and compare the array index of the pending + * timer. If it matches set the expiry to the new value so a + * subsequent call will exit in the expires check above. + */ + if (idx == timer_get_idx(timer)) { + timer->expires = expires; + return 1; + } } timer_stats_timer_set_start_info(timer); @@ -1018,7 +1026,18 @@ __mod_timer(struct timer_list *timer, unsigned long expires, bool pending_only) } timer->expires = expires; - internal_add_timer(base, timer); + /* + * If 'idx' was calculated above and the base time did not advance + * between calculating 'idx' and taking the lock, only enqueue_timer() + * and trigger_dyntick_cpu() is required. Otherwise we need to + * (re)calculate the wheel index via internal_add_timer(). + */ + if (idx != UINT_MAX && clk == base->clk) { + enqueue_timer(base, timer, idx); + trigger_dyntick_cpu(base, timer); + } else { + internal_add_timer(base, timer); + } out_unlock: spin_unlock_irqrestore(&base->lock, flags); -- cgit v0.10.2 From 0beef634b86a1350c31da5fcc2992f0d7c8a622b Mon Sep 17 00:00:00 2001 From: Jan Beulich Date: Thu, 7 Jul 2016 01:23:57 -0600 Subject: xenbus: don't BUG() on user mode induced condition Inability to locate a user mode specified transaction ID should not lead to a kernel crash. For other than XS_TRANSACTION_START also don't issue anything to xenbus if the specified ID doesn't match that of any active transaction. Signed-off-by: Jan Beulich Cc: Signed-off-by: David Vrabel diff --git a/drivers/xen/xenbus/xenbus_dev_frontend.c b/drivers/xen/xenbus/xenbus_dev_frontend.c index cacf30d..7487971 100644 --- a/drivers/xen/xenbus/xenbus_dev_frontend.c +++ b/drivers/xen/xenbus/xenbus_dev_frontend.c @@ -316,11 +316,18 @@ static int xenbus_write_transaction(unsigned msg_type, rc = -ENOMEM; goto out; } + } else { + list_for_each_entry(trans, &u->transactions, list) + if (trans->handle.id == u->u.msg.tx_id) + break; + if (&trans->list == &u->transactions) + return -ESRCH; } reply = xenbus_dev_request_and_reply(&u->u.msg); if (IS_ERR(reply)) { - kfree(trans); + if (msg_type == XS_TRANSACTION_START) + kfree(trans); rc = PTR_ERR(reply); goto out; } @@ -333,12 +340,7 @@ static int xenbus_write_transaction(unsigned msg_type, list_add(&trans->list, &u->transactions); } } else if (u->u.msg.type == XS_TRANSACTION_END) { - list_for_each_entry(trans, &u->transactions, list) - if (trans->handle.id == u->u.msg.tx_id) - break; - BUG_ON(&trans->list == &u->transactions); list_del(&trans->list); - kfree(trans); } -- cgit v0.10.2 From 54b880caf15034644b564e378abf67b7f9eaf4dc Mon Sep 17 00:00:00 2001 From: James Hogan Date: Fri, 24 Jun 2016 23:42:23 +0100 Subject: kbuild, x86: Track generated headers with generated-y Track generated header files which aren't already in genhdr-y, alongside generic-y wrappers in the */include/generated/[uapi/]asm/ directories. Currently only x86 generates extra headers in these directories, for the purposes of enumerating system calls for different ABIs, and xen hypercalls. This will allow the asm-generic wrapper handling code to remove stale wrappers when files are removed from generic-y, without also removing these headers which are generated separately. Reported-by: kbuild test robot Signed-off-by: James Hogan Acked-by: Arnd Bergmann Cc: Jonathan Corbet Cc: linux-kbuild@vger.kernel.org Cc: linux-doc@vger.kernel.org Cc: Michal Marek Link: http://lkml.kernel.org/r/1466808144-23209-2-git-send-email-james.hogan@imgtec.com Signed-off-by: Thomas Gleixner diff --git a/Documentation/kbuild/makefiles.txt b/Documentation/kbuild/makefiles.txt index 13f888a..385a5ef 100644 --- a/Documentation/kbuild/makefiles.txt +++ b/Documentation/kbuild/makefiles.txt @@ -47,6 +47,7 @@ This document describes the Linux kernel Makefiles. --- 7.2 genhdr-y --- 7.3 destination-y --- 7.4 generic-y + --- 7.5 generated-y === 8 Kbuild Variables === 9 Makefile language @@ -1319,6 +1320,19 @@ See subsequent chapter for the syntax of the Kbuild file. Example: termios.h #include + --- 7.5 generated-y + + If an architecture generates other header files alongside generic-y + wrappers, and not included in genhdr-y, then generated-y specifies + them. + + This prevents them being treated as stale asm-generic wrappers and + removed. + + Example: + #arch/x86/include/asm/Kbuild + generated-y += syscalls_32.h + === 8 Kbuild Variables The top Makefile exports the following variables: diff --git a/arch/x86/include/asm/Kbuild b/arch/x86/include/asm/Kbuild index aeac434..2cfed17 100644 --- a/arch/x86/include/asm/Kbuild +++ b/arch/x86/include/asm/Kbuild @@ -1,5 +1,11 @@ +generated-y += syscalls_32.h +generated-y += syscalls_64.h +generated-y += unistd_32_ia32.h +generated-y += unistd_64_x32.h +generated-y += xen-hypercalls.h + genhdr-y += unistd_32.h genhdr-y += unistd_64.h genhdr-y += unistd_x32.h -- cgit v0.10.2 From cda2c65f981d0c29805fd01ffce441c650ffe6cf Mon Sep 17 00:00:00 2001 From: James Hogan Date: Fri, 24 Jun 2016 23:42:24 +0100 Subject: kbuild: Remove stale asm-generic wrappers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When a header file is removed from generic-y (often accompanied by the addition of an arch specific header), the generated wrapper file will persist, and in some cases may still take precedence over the new arch header. For example commit f1fe2d21f4e1 ("MIPS: Add definitions for extended context") removed ucontext.h from generic-y in arch/mips/include/asm/, and added an arch/mips/include/uapi/asm/ucontext.h. The continued use of the wrapper when reusing a dirty build tree resulted in build failures in arch/mips/kernel/signal.c: arch/mips/kernel/signal.c: In function ‘sc_to_extcontext’: arch/mips/kernel/signal.c:142:12: error: ‘struct ucontext’ has no member named ‘uc_extcontext’ return &uc->uc_extcontext; ^ Fix by detecting and removing wrapper headers in generated header directories that do not correspond to a filename in generic-y, genhdr-y, or the newly introduced generated-y. Reported-by: Jacek Anaszewski Reported-by: Hauke Mehrtens Reported-by: Heinrich Schuchardt Signed-off-by: James Hogan Acked-by: Arnd Bergmann Acked-by: Florian Fainelli Cc: linux-arch@vger.kernel.org Cc: linux-mips@linux-mips.org Cc: Paul Burton Cc: linux-kbuild@vger.kernel.org Cc: Ralf Baechle Cc: Michal Marek Link: http://lkml.kernel.org/r/1466808144-23209-3-git-send-email-james.hogan@imgtec.com Signed-off-by: Thomas Gleixner diff --git a/scripts/Makefile.asm-generic b/scripts/Makefile.asm-generic index 045e0098..e4d017d5 100644 --- a/scripts/Makefile.asm-generic +++ b/scripts/Makefile.asm-generic @@ -13,11 +13,26 @@ include scripts/Kbuild.include # Create output directory if not already present _dummy := $(shell [ -d $(obj) ] || mkdir -p $(obj)) +# Stale wrappers when the corresponding files are removed from generic-y +# need removing. +generated-y := $(generic-y) $(genhdr-y) $(generated-y) +all-files := $(patsubst %, $(obj)/%, $(generated-y)) +old-headers := $(wildcard $(obj)/*.h) +unwanted := $(filter-out $(all-files),$(old-headers)) + quiet_cmd_wrap = WRAP $@ cmd_wrap = echo "\#include " >$@ -all: $(patsubst %, $(obj)/%, $(generic-y)) +quiet_cmd_remove = REMOVE $(unwanted) +cmd_remove = rm -f $(unwanted) + +all: $(patsubst %, $(obj)/%, $(generic-y)) FORCE + $(if $(unwanted),$(call cmd,remove),) @: $(obj)/%.h: $(call cmd,wrap) + +PHONY += FORCE +.PHONY: $(PHONY) +FORCE: ; -- cgit v0.10.2 From e19a6ee2460bdd0d0055a6029383422773f9999a Mon Sep 17 00:00:00 2001 From: James Morse Date: Mon, 20 Jun 2016 18:28:01 +0100 Subject: arm64: kernel: Save and restore UAO and addr_limit on exception entry If we take an exception while at EL1, the exception handler inherits the original context's addr_limit and PSTATE.UAO values. To be consistent always reset addr_limit and PSTATE.UAO on (re-)entry to EL1. This prevents accidental re-use of the original context's addr_limit. Based on a similar patch for arm from Russell King. Cc: # 4.6- Acked-by: Will Deacon Reviewed-by: Mark Rutland Signed-off-by: James Morse Signed-off-by: Will Deacon diff --git a/arch/arm64/include/asm/ptrace.h b/arch/arm64/include/asm/ptrace.h index a307eb6..7f94755 100644 --- a/arch/arm64/include/asm/ptrace.h +++ b/arch/arm64/include/asm/ptrace.h @@ -117,6 +117,8 @@ struct pt_regs { }; u64 orig_x0; u64 syscallno; + u64 orig_addr_limit; + u64 unused; // maintain 16 byte alignment }; #define arch_has_single_step() (1) diff --git a/arch/arm64/kernel/asm-offsets.c b/arch/arm64/kernel/asm-offsets.c index f8e5d47..2f4ba77 100644 --- a/arch/arm64/kernel/asm-offsets.c +++ b/arch/arm64/kernel/asm-offsets.c @@ -60,6 +60,7 @@ int main(void) DEFINE(S_PC, offsetof(struct pt_regs, pc)); DEFINE(S_ORIG_X0, offsetof(struct pt_regs, orig_x0)); DEFINE(S_SYSCALLNO, offsetof(struct pt_regs, syscallno)); + DEFINE(S_ORIG_ADDR_LIMIT, offsetof(struct pt_regs, orig_addr_limit)); DEFINE(S_FRAME_SIZE, sizeof(struct pt_regs)); BLANK(); DEFINE(MM_CONTEXT_ID, offsetof(struct mm_struct, context.id.counter)); diff --git a/arch/arm64/kernel/entry.S b/arch/arm64/kernel/entry.S index 12e8d2b..6c3b734 100644 --- a/arch/arm64/kernel/entry.S +++ b/arch/arm64/kernel/entry.S @@ -28,6 +28,7 @@ #include #include #include +#include #include #include @@ -97,7 +98,14 @@ mov x29, xzr // fp pointed to user-space .else add x21, sp, #S_FRAME_SIZE - .endif + get_thread_info tsk + /* Save the task's original addr_limit and set USER_DS (TASK_SIZE_64) */ + ldr x20, [tsk, #TI_ADDR_LIMIT] + str x20, [sp, #S_ORIG_ADDR_LIMIT] + mov x20, #TASK_SIZE_64 + str x20, [tsk, #TI_ADDR_LIMIT] + ALTERNATIVE(nop, SET_PSTATE_UAO(0), ARM64_HAS_UAO, CONFIG_ARM64_UAO) + .endif /* \el == 0 */ mrs x22, elr_el1 mrs x23, spsr_el1 stp lr, x21, [sp, #S_LR] @@ -128,6 +136,14 @@ .endm .macro kernel_exit, el + .if \el != 0 + /* Restore the task's original addr_limit. */ + ldr x20, [sp, #S_ORIG_ADDR_LIMIT] + str x20, [tsk, #TI_ADDR_LIMIT] + + /* No need to restore UAO, it will be restored from SPSR_EL1 */ + .endif + ldp x21, x22, [sp, #S_PC] // load ELR, SPSR .if \el == 0 ct_user_enter @@ -406,7 +422,6 @@ el1_irq: bl trace_hardirqs_off #endif - get_thread_info tsk irq_handler #ifdef CONFIG_PREEMPT diff --git a/arch/arm64/mm/fault.c b/arch/arm64/mm/fault.c index 013e2cb..b1166d1 100644 --- a/arch/arm64/mm/fault.c +++ b/arch/arm64/mm/fault.c @@ -280,7 +280,8 @@ static int __kprobes do_page_fault(unsigned long addr, unsigned int esr, } if (permission_fault(esr) && (addr < USER_DS)) { - if (get_fs() == KERNEL_DS) + /* regs->orig_addr_limit may be 0 if we entered from EL0 */ + if (regs->orig_addr_limit == KERNEL_DS) die("Accessing user space memory with fs=KERNEL_DS", regs, esr); if (!search_exception_tables(regs->pc)) -- cgit v0.10.2 From 47c459beabe969c6751e2ea8d1f85c5fa1652d6c Mon Sep 17 00:00:00 2001 From: Ganapatrao Kulkarni Date: Thu, 7 Jul 2016 10:18:17 +0530 Subject: arm64: Enable workaround for Cavium erratum 27456 on thunderx-81xx Cavium erratum 27456 commit 104a0c02e8b1 ("arm64: Add workaround for Cavium erratum 27456") is applicable for thunderx-81xx pass1.0 SoC as well. Adding code to enable to 81xx. Signed-off-by: Ganapatrao Kulkarni Reviewed-by: Andrew Pinski Signed-off-by: Will Deacon diff --git a/arch/arm64/include/asm/cputype.h b/arch/arm64/include/asm/cputype.h index 87e1985..9d9fd4b 100644 --- a/arch/arm64/include/asm/cputype.h +++ b/arch/arm64/include/asm/cputype.h @@ -80,12 +80,14 @@ #define APM_CPU_PART_POTENZA 0x000 #define CAVIUM_CPU_PART_THUNDERX 0x0A1 +#define CAVIUM_CPU_PART_THUNDERX_81XX 0x0A2 #define BRCM_CPU_PART_VULCAN 0x516 #define MIDR_CORTEX_A53 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A53) #define MIDR_CORTEX_A57 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A57) #define MIDR_THUNDERX MIDR_CPU_MODEL(ARM_CPU_IMP_CAVIUM, CAVIUM_CPU_PART_THUNDERX) +#define MIDR_THUNDERX_81XX MIDR_CPU_MODEL(ARM_CPU_IMP_CAVIUM, CAVIUM_CPU_PART_THUNDERX_81XX) #ifndef __ASSEMBLY__ diff --git a/arch/arm64/kernel/cpu_errata.c b/arch/arm64/kernel/cpu_errata.c index d427894..af716b6 100644 --- a/arch/arm64/kernel/cpu_errata.c +++ b/arch/arm64/kernel/cpu_errata.c @@ -98,6 +98,12 @@ const struct arm64_cpu_capabilities arm64_errata[] = { MIDR_RANGE(MIDR_THUNDERX, 0x00, (1 << MIDR_VARIANT_SHIFT) | 1), }, + { + /* Cavium ThunderX, T81 pass 1.0 */ + .desc = "Cavium erratum 27456", + .capability = ARM64_WORKAROUND_CAVIUM_27456, + MIDR_RANGE(MIDR_THUNDERX_81XX, 0x00, 0x00), + }, #endif { } -- cgit v0.10.2 From 6c3521400c345fa2575a6f5b212c215db38c5d93 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Thu, 23 Jun 2016 22:01:26 -0700 Subject: lkdtm: add usercopy test for blocking kernel text The upcoming HARDENED_USERCOPY checks will also block access to the kernel text, so provide a test for this as well. Signed-off-by: Kees Cook diff --git a/drivers/misc/lkdtm_core.c b/drivers/misc/lkdtm_core.c index a595a6f..c915961 100644 --- a/drivers/misc/lkdtm_core.c +++ b/drivers/misc/lkdtm_core.c @@ -120,6 +120,7 @@ enum ctype { CT_USERCOPY_STACK_FRAME_TO, CT_USERCOPY_STACK_FRAME_FROM, CT_USERCOPY_STACK_BEYOND, + CT_USERCOPY_KERNEL, }; static char* cp_name[] = { @@ -171,6 +172,7 @@ static char* cp_type[] = { "USERCOPY_STACK_FRAME_TO", "USERCOPY_STACK_FRAME_FROM", "USERCOPY_STACK_BEYOND", + "USERCOPY_KERNEL", }; static struct jprobe lkdtm; @@ -495,6 +497,35 @@ free_user: vm_munmap(user_addr, PAGE_SIZE); } +static void do_usercopy_kernel(void) +{ + unsigned long user_addr; + + user_addr = vm_mmap(NULL, 0, PAGE_SIZE, + PROT_READ | PROT_WRITE | PROT_EXEC, + MAP_ANONYMOUS | MAP_PRIVATE, 0); + if (user_addr >= TASK_SIZE) { + pr_warn("Failed to allocate user memory\n"); + return; + } + + pr_info("attempting good copy_to_user from kernel rodata\n"); + if (copy_to_user((void __user *)user_addr, test_text, + sizeof(test_text))) { + pr_warn("copy_to_user failed unexpectedly?!\n"); + goto free_user; + } + + pr_info("attempting bad copy_to_user from kernel text\n"); + if (copy_to_user((void __user *)user_addr, vm_mmap, PAGE_SIZE)) { + pr_warn("copy_to_user failed, but lacked Oops\n"); + goto free_user; + } + +free_user: + vm_munmap(user_addr, PAGE_SIZE); +} + static void do_usercopy_heap_size(bool to_user) { unsigned long user_addr; @@ -957,6 +988,9 @@ static void lkdtm_do_action(enum ctype which) case CT_USERCOPY_STACK_BEYOND: do_usercopy_stack(true, false); break; + case CT_USERCOPY_KERNEL: + do_usercopy_kernel(); + break; case CT_NONE: default: break; -- cgit v0.10.2 From 0edca7b5afb4b0909eecd2ede9a6736ef7cafc42 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Sun, 26 Jun 2016 08:51:14 -0700 Subject: lkdtm: drop "alloc_size" parameter There is no good reason to have the alloc_size parameter currently. The compiler-tricking value used to exercise the stack can just use a stack address instead. Similarly hard-code cache_size. Signed-off-by: Kees Cook diff --git a/drivers/misc/lkdtm_core.c b/drivers/misc/lkdtm_core.c index c915961..1454d58 100644 --- a/drivers/misc/lkdtm_core.c +++ b/drivers/misc/lkdtm_core.c @@ -184,8 +184,6 @@ static char* cpoint_name; static char* cpoint_type; static int cpoint_count = DEFAULT_COUNT; static int recur_count = REC_NUM_DEFAULT; -static int alloc_size = 1024; -static size_t cache_size; static enum cname cpoint = CN_INVALID; static enum ctype cptype = CT_NONE; @@ -194,6 +192,8 @@ static DEFINE_SPINLOCK(count_lock); static DEFINE_SPINLOCK(lock_me_up); static u8 data_area[EXEC_SIZE]; + +static size_t cache_size = 1024; static struct kmem_cache *bad_cache; static const unsigned char test_text[] = "This is a test.\n"; @@ -210,9 +210,6 @@ MODULE_PARM_DESC(cpoint_type, " Crash Point Type, action to be taken on "\ module_param(cpoint_count, int, 0644); MODULE_PARM_DESC(cpoint_count, " Crash Point Count, number of times the "\ "crash point is to be hit to trigger action"); -module_param(alloc_size, int, 0644); -MODULE_PARM_DESC(alloc_size, " Size of allocation for user copy tests "\ - "(from 1 to PAGE_SIZE)"); static unsigned int jp_do_irq(unsigned int irq) { @@ -441,7 +438,7 @@ static noinline void do_usercopy_stack(bool to_user, bool bad_frame) /* This is a pointer to outside our current stack frame. */ if (bad_frame) { - bad_stack = do_usercopy_stack_callee(alloc_size); + bad_stack = do_usercopy_stack_callee((uintptr_t)bad_stack); } else { /* Put start address just inside stack. */ bad_stack = task_stack_page(current) + THREAD_SIZE; @@ -530,7 +527,7 @@ static void do_usercopy_heap_size(bool to_user) { unsigned long user_addr; unsigned char *one, *two; - size_t size = clamp_t(int, alloc_size, 1, PAGE_SIZE); + size_t size = 1024; one = kmalloc(size, GFP_KERNEL); two = kmalloc(size, GFP_KERNEL); @@ -564,8 +561,7 @@ static void do_usercopy_heap_size(bool to_user) } } else { pr_info("attempting good copy_from_user of correct size\n"); - if (copy_from_user(one, (void __user *)user_addr, - size)) { + if (copy_from_user(one, (void __user *)user_addr, size)) { pr_warn("copy_from_user failed unexpectedly?!\n"); goto free_user; } @@ -1284,7 +1280,6 @@ static int __init lkdtm_module_init(void) ro_after_init |= 0xAA; /* Prepare cache that lacks SLAB_USERCOPY flag. */ - cache_size = clamp_t(int, alloc_size, 1, PAGE_SIZE); bad_cache = kmem_cache_create("lkdtm-no-usercopy", cache_size, 0, 0, NULL); -- cgit v0.10.2 From a3dff71c1c88fc184a1ae5e425ba621d547d16ec Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Sun, 26 Jun 2016 08:46:23 -0700 Subject: lkdtm: split usercopy tests to separate file This splits the USERCOPY_* tests into the new lkdtm_usercopy.c file to help separate things better for readability. Signed-off-by: Kees Cook diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index 7d45ed4..e6b2778 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -60,6 +60,7 @@ obj-$(CONFIG_PANEL) += panel.o lkdtm-$(CONFIG_LKDTM) += lkdtm_core.o lkdtm-$(CONFIG_LKDTM) += lkdtm_rodata_objcopy.o +lkdtm-$(CONFIG_LKDTM) += lkdtm_usercopy.o OBJCOPYFLAGS := OBJCOPYFLAGS_lkdtm_rodata_objcopy.o := \ diff --git a/drivers/misc/lkdtm.h b/drivers/misc/lkdtm.h index 9531fa3..ef290a2 100644 --- a/drivers/misc/lkdtm.h +++ b/drivers/misc/lkdtm.h @@ -1,6 +1,19 @@ #ifndef __LKDTM_H #define __LKDTM_H +/* lkdtm_rodata.c */ void lkdtm_rodata_do_nothing(void); +/* lkdtm_usercopy.c */ +void __init lkdtm_usercopy_init(void); +void __exit lkdtm_usercopy_exit(void); +void lkdtm_USERCOPY_HEAP_SIZE_TO(void); +void lkdtm_USERCOPY_HEAP_SIZE_FROM(void); +void lkdtm_USERCOPY_HEAP_FLAG_TO(void); +void lkdtm_USERCOPY_HEAP_FLAG_FROM(void); +void lkdtm_USERCOPY_STACK_FRAME_TO(void); +void lkdtm_USERCOPY_STACK_FRAME_FROM(void); +void lkdtm_USERCOPY_STACK_BEYOND(void); +void lkdtm_USERCOPY_KERNEL(void); + #endif diff --git a/drivers/misc/lkdtm_core.c b/drivers/misc/lkdtm_core.c index 1454d58..7437692 100644 --- a/drivers/misc/lkdtm_core.c +++ b/drivers/misc/lkdtm_core.c @@ -193,10 +193,6 @@ static DEFINE_SPINLOCK(lock_me_up); static u8 data_area[EXEC_SIZE]; -static size_t cache_size = 1024; -static struct kmem_cache *bad_cache; - -static const unsigned char test_text[] = "This is a test.\n"; static const unsigned long rodata = 0xAA55AA55; static unsigned long ro_after_init __ro_after_init = 0x55AA5500; @@ -403,255 +399,6 @@ static void execute_user_location(void *dst) func(); } -/* - * Instead of adding -Wno-return-local-addr, just pass the stack address - * through a function to obfuscate it from the compiler. - */ -static noinline unsigned char *trick_compiler(unsigned char *stack) -{ - return stack + 0; -} - -static noinline unsigned char *do_usercopy_stack_callee(int value) -{ - unsigned char buf[32]; - int i; - - /* Exercise stack to avoid everything living in registers. */ - for (i = 0; i < sizeof(buf); i++) { - buf[i] = value & 0xff; - } - - return trick_compiler(buf); -} - -static noinline void do_usercopy_stack(bool to_user, bool bad_frame) -{ - unsigned long user_addr; - unsigned char good_stack[32]; - unsigned char *bad_stack; - int i; - - /* Exercise stack to avoid everything living in registers. */ - for (i = 0; i < sizeof(good_stack); i++) - good_stack[i] = test_text[i % sizeof(test_text)]; - - /* This is a pointer to outside our current stack frame. */ - if (bad_frame) { - bad_stack = do_usercopy_stack_callee((uintptr_t)bad_stack); - } else { - /* Put start address just inside stack. */ - bad_stack = task_stack_page(current) + THREAD_SIZE; - bad_stack -= sizeof(unsigned long); - } - - user_addr = vm_mmap(NULL, 0, PAGE_SIZE, - PROT_READ | PROT_WRITE | PROT_EXEC, - MAP_ANONYMOUS | MAP_PRIVATE, 0); - if (user_addr >= TASK_SIZE) { - pr_warn("Failed to allocate user memory\n"); - return; - } - - if (to_user) { - pr_info("attempting good copy_to_user of local stack\n"); - if (copy_to_user((void __user *)user_addr, good_stack, - sizeof(good_stack))) { - pr_warn("copy_to_user failed unexpectedly?!\n"); - goto free_user; - } - - pr_info("attempting bad copy_to_user of distant stack\n"); - if (copy_to_user((void __user *)user_addr, bad_stack, - sizeof(good_stack))) { - pr_warn("copy_to_user failed, but lacked Oops\n"); - goto free_user; - } - } else { - /* - * There isn't a safe way to not be protected by usercopy - * if we're going to write to another thread's stack. - */ - if (!bad_frame) - goto free_user; - - pr_info("attempting good copy_from_user of local stack\n"); - if (copy_from_user(good_stack, (void __user *)user_addr, - sizeof(good_stack))) { - pr_warn("copy_from_user failed unexpectedly?!\n"); - goto free_user; - } - - pr_info("attempting bad copy_from_user of distant stack\n"); - if (copy_from_user(bad_stack, (void __user *)user_addr, - sizeof(good_stack))) { - pr_warn("copy_from_user failed, but lacked Oops\n"); - goto free_user; - } - } - -free_user: - vm_munmap(user_addr, PAGE_SIZE); -} - -static void do_usercopy_kernel(void) -{ - unsigned long user_addr; - - user_addr = vm_mmap(NULL, 0, PAGE_SIZE, - PROT_READ | PROT_WRITE | PROT_EXEC, - MAP_ANONYMOUS | MAP_PRIVATE, 0); - if (user_addr >= TASK_SIZE) { - pr_warn("Failed to allocate user memory\n"); - return; - } - - pr_info("attempting good copy_to_user from kernel rodata\n"); - if (copy_to_user((void __user *)user_addr, test_text, - sizeof(test_text))) { - pr_warn("copy_to_user failed unexpectedly?!\n"); - goto free_user; - } - - pr_info("attempting bad copy_to_user from kernel text\n"); - if (copy_to_user((void __user *)user_addr, vm_mmap, PAGE_SIZE)) { - pr_warn("copy_to_user failed, but lacked Oops\n"); - goto free_user; - } - -free_user: - vm_munmap(user_addr, PAGE_SIZE); -} - -static void do_usercopy_heap_size(bool to_user) -{ - unsigned long user_addr; - unsigned char *one, *two; - size_t size = 1024; - - one = kmalloc(size, GFP_KERNEL); - two = kmalloc(size, GFP_KERNEL); - if (!one || !two) { - pr_warn("Failed to allocate kernel memory\n"); - goto free_kernel; - } - - user_addr = vm_mmap(NULL, 0, PAGE_SIZE, - PROT_READ | PROT_WRITE | PROT_EXEC, - MAP_ANONYMOUS | MAP_PRIVATE, 0); - if (user_addr >= TASK_SIZE) { - pr_warn("Failed to allocate user memory\n"); - goto free_kernel; - } - - memset(one, 'A', size); - memset(two, 'B', size); - - if (to_user) { - pr_info("attempting good copy_to_user of correct size\n"); - if (copy_to_user((void __user *)user_addr, one, size)) { - pr_warn("copy_to_user failed unexpectedly?!\n"); - goto free_user; - } - - pr_info("attempting bad copy_to_user of too large size\n"); - if (copy_to_user((void __user *)user_addr, one, 2 * size)) { - pr_warn("copy_to_user failed, but lacked Oops\n"); - goto free_user; - } - } else { - pr_info("attempting good copy_from_user of correct size\n"); - if (copy_from_user(one, (void __user *)user_addr, size)) { - pr_warn("copy_from_user failed unexpectedly?!\n"); - goto free_user; - } - - pr_info("attempting bad copy_from_user of too large size\n"); - if (copy_from_user(one, (void __user *)user_addr, 2 * size)) { - pr_warn("copy_from_user failed, but lacked Oops\n"); - goto free_user; - } - } - -free_user: - vm_munmap(user_addr, PAGE_SIZE); -free_kernel: - kfree(one); - kfree(two); -} - -static void do_usercopy_heap_flag(bool to_user) -{ - unsigned long user_addr; - unsigned char *good_buf = NULL; - unsigned char *bad_buf = NULL; - - /* Make sure cache was prepared. */ - if (!bad_cache) { - pr_warn("Failed to allocate kernel cache\n"); - return; - } - - /* - * Allocate one buffer from each cache (kmalloc will have the - * SLAB_USERCOPY flag already, but "bad_cache" won't). - */ - good_buf = kmalloc(cache_size, GFP_KERNEL); - bad_buf = kmem_cache_alloc(bad_cache, GFP_KERNEL); - if (!good_buf || !bad_buf) { - pr_warn("Failed to allocate buffers from caches\n"); - goto free_alloc; - } - - /* Allocate user memory we'll poke at. */ - user_addr = vm_mmap(NULL, 0, PAGE_SIZE, - PROT_READ | PROT_WRITE | PROT_EXEC, - MAP_ANONYMOUS | MAP_PRIVATE, 0); - if (user_addr >= TASK_SIZE) { - pr_warn("Failed to allocate user memory\n"); - goto free_alloc; - } - - memset(good_buf, 'A', cache_size); - memset(bad_buf, 'B', cache_size); - - if (to_user) { - pr_info("attempting good copy_to_user with SLAB_USERCOPY\n"); - if (copy_to_user((void __user *)user_addr, good_buf, - cache_size)) { - pr_warn("copy_to_user failed unexpectedly?!\n"); - goto free_user; - } - - pr_info("attempting bad copy_to_user w/o SLAB_USERCOPY\n"); - if (copy_to_user((void __user *)user_addr, bad_buf, - cache_size)) { - pr_warn("copy_to_user failed, but lacked Oops\n"); - goto free_user; - } - } else { - pr_info("attempting good copy_from_user with SLAB_USERCOPY\n"); - if (copy_from_user(good_buf, (void __user *)user_addr, - cache_size)) { - pr_warn("copy_from_user failed unexpectedly?!\n"); - goto free_user; - } - - pr_info("attempting bad copy_from_user w/o SLAB_USERCOPY\n"); - if (copy_from_user(bad_buf, (void __user *)user_addr, - cache_size)) { - pr_warn("copy_from_user failed, but lacked Oops\n"); - goto free_user; - } - } - -free_user: - vm_munmap(user_addr, PAGE_SIZE); -free_alloc: - if (bad_buf) - kmem_cache_free(bad_cache, bad_buf); - kfree(good_buf); -} static void lkdtm_do_action(enum ctype which) { @@ -964,28 +711,28 @@ static void lkdtm_do_action(enum ctype which) return; } case CT_USERCOPY_HEAP_SIZE_TO: - do_usercopy_heap_size(true); + lkdtm_USERCOPY_HEAP_SIZE_TO(); break; case CT_USERCOPY_HEAP_SIZE_FROM: - do_usercopy_heap_size(false); + lkdtm_USERCOPY_HEAP_SIZE_FROM(); break; case CT_USERCOPY_HEAP_FLAG_TO: - do_usercopy_heap_flag(true); + lkdtm_USERCOPY_HEAP_FLAG_TO(); break; case CT_USERCOPY_HEAP_FLAG_FROM: - do_usercopy_heap_flag(false); + lkdtm_USERCOPY_HEAP_FLAG_FROM(); break; case CT_USERCOPY_STACK_FRAME_TO: - do_usercopy_stack(true, true); + lkdtm_USERCOPY_STACK_FRAME_TO(); break; case CT_USERCOPY_STACK_FRAME_FROM: - do_usercopy_stack(false, true); + lkdtm_USERCOPY_STACK_FRAME_FROM(); break; case CT_USERCOPY_STACK_BEYOND: - do_usercopy_stack(true, false); + lkdtm_USERCOPY_STACK_BEYOND(); break; case CT_USERCOPY_KERNEL: - do_usercopy_kernel(); + lkdtm_USERCOPY_KERNEL(); break; case CT_NONE: default: @@ -1276,13 +1023,12 @@ static int __init lkdtm_module_init(void) int n_debugfs_entries = 1; /* Assume only the direct entry */ int i; + /* Handle test-specific initialization. */ + lkdtm_usercopy_init(); + /* Make sure we can write to __ro_after_init values during __init */ ro_after_init |= 0xAA; - /* Prepare cache that lacks SLAB_USERCOPY flag. */ - bad_cache = kmem_cache_create("lkdtm-no-usercopy", cache_size, 0, - 0, NULL); - /* Register debugfs interface */ lkdtm_debugfs_root = debugfs_create_dir("provoke-crash", NULL); if (!lkdtm_debugfs_root) { @@ -1334,7 +1080,8 @@ static void __exit lkdtm_module_exit(void) { debugfs_remove_recursive(lkdtm_debugfs_root); - kmem_cache_destroy(bad_cache); + /* Handle test-specific clean-up. */ + lkdtm_usercopy_exit(); unregister_jprobe(&lkdtm); pr_info("Crash point unregistered\n"); diff --git a/drivers/misc/lkdtm_usercopy.c b/drivers/misc/lkdtm_usercopy.c new file mode 100644 index 0000000..9c748e8 --- /dev/null +++ b/drivers/misc/lkdtm_usercopy.c @@ -0,0 +1,315 @@ +/* + * This is for all the tests related to copy_to_user() and copy_from_user() + * hardening. + */ +#define pr_fmt(fmt) "lkdtm: " fmt + +#include +#include +#include +#include +#include +#include + +static size_t cache_size = 1024; +static struct kmem_cache *bad_cache; + +static const unsigned char test_text[] = "This is a test.\n"; + +/* + * Instead of adding -Wno-return-local-addr, just pass the stack address + * through a function to obfuscate it from the compiler. + */ +static noinline unsigned char *trick_compiler(unsigned char *stack) +{ + return stack + 0; +} + +static noinline unsigned char *do_usercopy_stack_callee(int value) +{ + unsigned char buf[32]; + int i; + + /* Exercise stack to avoid everything living in registers. */ + for (i = 0; i < sizeof(buf); i++) { + buf[i] = value & 0xff; + } + + return trick_compiler(buf); +} + +static noinline void do_usercopy_stack(bool to_user, bool bad_frame) +{ + unsigned long user_addr; + unsigned char good_stack[32]; + unsigned char *bad_stack; + int i; + + /* Exercise stack to avoid everything living in registers. */ + for (i = 0; i < sizeof(good_stack); i++) + good_stack[i] = test_text[i % sizeof(test_text)]; + + /* This is a pointer to outside our current stack frame. */ + if (bad_frame) { + bad_stack = do_usercopy_stack_callee((uintptr_t)bad_stack); + } else { + /* Put start address just inside stack. */ + bad_stack = task_stack_page(current) + THREAD_SIZE; + bad_stack -= sizeof(unsigned long); + } + + user_addr = vm_mmap(NULL, 0, PAGE_SIZE, + PROT_READ | PROT_WRITE | PROT_EXEC, + MAP_ANONYMOUS | MAP_PRIVATE, 0); + if (user_addr >= TASK_SIZE) { + pr_warn("Failed to allocate user memory\n"); + return; + } + + if (to_user) { + pr_info("attempting good copy_to_user of local stack\n"); + if (copy_to_user((void __user *)user_addr, good_stack, + sizeof(good_stack))) { + pr_warn("copy_to_user failed unexpectedly?!\n"); + goto free_user; + } + + pr_info("attempting bad copy_to_user of distant stack\n"); + if (copy_to_user((void __user *)user_addr, bad_stack, + sizeof(good_stack))) { + pr_warn("copy_to_user failed, but lacked Oops\n"); + goto free_user; + } + } else { + /* + * There isn't a safe way to not be protected by usercopy + * if we're going to write to another thread's stack. + */ + if (!bad_frame) + goto free_user; + + pr_info("attempting good copy_from_user of local stack\n"); + if (copy_from_user(good_stack, (void __user *)user_addr, + sizeof(good_stack))) { + pr_warn("copy_from_user failed unexpectedly?!\n"); + goto free_user; + } + + pr_info("attempting bad copy_from_user of distant stack\n"); + if (copy_from_user(bad_stack, (void __user *)user_addr, + sizeof(good_stack))) { + pr_warn("copy_from_user failed, but lacked Oops\n"); + goto free_user; + } + } + +free_user: + vm_munmap(user_addr, PAGE_SIZE); +} + +static void do_usercopy_heap_size(bool to_user) +{ + unsigned long user_addr; + unsigned char *one, *two; + const size_t size = 1024; + + one = kmalloc(size, GFP_KERNEL); + two = kmalloc(size, GFP_KERNEL); + if (!one || !two) { + pr_warn("Failed to allocate kernel memory\n"); + goto free_kernel; + } + + user_addr = vm_mmap(NULL, 0, PAGE_SIZE, + PROT_READ | PROT_WRITE | PROT_EXEC, + MAP_ANONYMOUS | MAP_PRIVATE, 0); + if (user_addr >= TASK_SIZE) { + pr_warn("Failed to allocate user memory\n"); + goto free_kernel; + } + + memset(one, 'A', size); + memset(two, 'B', size); + + if (to_user) { + pr_info("attempting good copy_to_user of correct size\n"); + if (copy_to_user((void __user *)user_addr, one, size)) { + pr_warn("copy_to_user failed unexpectedly?!\n"); + goto free_user; + } + + pr_info("attempting bad copy_to_user of too large size\n"); + if (copy_to_user((void __user *)user_addr, one, 2 * size)) { + pr_warn("copy_to_user failed, but lacked Oops\n"); + goto free_user; + } + } else { + pr_info("attempting good copy_from_user of correct size\n"); + if (copy_from_user(one, (void __user *)user_addr, size)) { + pr_warn("copy_from_user failed unexpectedly?!\n"); + goto free_user; + } + + pr_info("attempting bad copy_from_user of too large size\n"); + if (copy_from_user(one, (void __user *)user_addr, 2 * size)) { + pr_warn("copy_from_user failed, but lacked Oops\n"); + goto free_user; + } + } + +free_user: + vm_munmap(user_addr, PAGE_SIZE); +free_kernel: + kfree(one); + kfree(two); +} + +static void do_usercopy_heap_flag(bool to_user) +{ + unsigned long user_addr; + unsigned char *good_buf = NULL; + unsigned char *bad_buf = NULL; + + /* Make sure cache was prepared. */ + if (!bad_cache) { + pr_warn("Failed to allocate kernel cache\n"); + return; + } + + /* + * Allocate one buffer from each cache (kmalloc will have the + * SLAB_USERCOPY flag already, but "bad_cache" won't). + */ + good_buf = kmalloc(cache_size, GFP_KERNEL); + bad_buf = kmem_cache_alloc(bad_cache, GFP_KERNEL); + if (!good_buf || !bad_buf) { + pr_warn("Failed to allocate buffers from caches\n"); + goto free_alloc; + } + + /* Allocate user memory we'll poke at. */ + user_addr = vm_mmap(NULL, 0, PAGE_SIZE, + PROT_READ | PROT_WRITE | PROT_EXEC, + MAP_ANONYMOUS | MAP_PRIVATE, 0); + if (user_addr >= TASK_SIZE) { + pr_warn("Failed to allocate user memory\n"); + goto free_alloc; + } + + memset(good_buf, 'A', cache_size); + memset(bad_buf, 'B', cache_size); + + if (to_user) { + pr_info("attempting good copy_to_user with SLAB_USERCOPY\n"); + if (copy_to_user((void __user *)user_addr, good_buf, + cache_size)) { + pr_warn("copy_to_user failed unexpectedly?!\n"); + goto free_user; + } + + pr_info("attempting bad copy_to_user w/o SLAB_USERCOPY\n"); + if (copy_to_user((void __user *)user_addr, bad_buf, + cache_size)) { + pr_warn("copy_to_user failed, but lacked Oops\n"); + goto free_user; + } + } else { + pr_info("attempting good copy_from_user with SLAB_USERCOPY\n"); + if (copy_from_user(good_buf, (void __user *)user_addr, + cache_size)) { + pr_warn("copy_from_user failed unexpectedly?!\n"); + goto free_user; + } + + pr_info("attempting bad copy_from_user w/o SLAB_USERCOPY\n"); + if (copy_from_user(bad_buf, (void __user *)user_addr, + cache_size)) { + pr_warn("copy_from_user failed, but lacked Oops\n"); + goto free_user; + } + } + +free_user: + vm_munmap(user_addr, PAGE_SIZE); +free_alloc: + if (bad_buf) + kmem_cache_free(bad_cache, bad_buf); + kfree(good_buf); +} + +/* Callable tests. */ +void lkdtm_USERCOPY_HEAP_SIZE_TO(void) +{ + do_usercopy_heap_size(true); +} + +void lkdtm_USERCOPY_HEAP_SIZE_FROM(void) +{ + do_usercopy_heap_size(false); +} + +void lkdtm_USERCOPY_HEAP_FLAG_TO(void) +{ + do_usercopy_heap_flag(true); +} + +void lkdtm_USERCOPY_HEAP_FLAG_FROM(void) +{ + do_usercopy_heap_flag(false); +} + +void lkdtm_USERCOPY_STACK_FRAME_TO(void) +{ + do_usercopy_stack(true, true); +} + +void lkdtm_USERCOPY_STACK_FRAME_FROM(void) +{ + do_usercopy_stack(false, true); +} + +void lkdtm_USERCOPY_STACK_BEYOND(void) +{ + do_usercopy_stack(true, false); +} + +void lkdtm_USERCOPY_KERNEL(void) +{ + unsigned long user_addr; + + user_addr = vm_mmap(NULL, 0, PAGE_SIZE, + PROT_READ | PROT_WRITE | PROT_EXEC, + MAP_ANONYMOUS | MAP_PRIVATE, 0); + if (user_addr >= TASK_SIZE) { + pr_warn("Failed to allocate user memory\n"); + return; + } + + pr_info("attempting good copy_to_user from kernel rodata\n"); + if (copy_to_user((void __user *)user_addr, test_text, + sizeof(test_text))) { + pr_warn("copy_to_user failed unexpectedly?!\n"); + goto free_user; + } + + pr_info("attempting bad copy_to_user from kernel text\n"); + if (copy_to_user((void __user *)user_addr, vm_mmap, PAGE_SIZE)) { + pr_warn("copy_to_user failed, but lacked Oops\n"); + goto free_user; + } + +free_user: + vm_munmap(user_addr, PAGE_SIZE); +} + +void __init lkdtm_usercopy_init(void) +{ + /* Prepare cache that lacks SLAB_USERCOPY flag. */ + bad_cache = kmem_cache_create("lkdtm-no-usercopy", cache_size, 0, + 0, NULL); +} + +void __exit lkdtm_usercopy_exit(void) +{ + kmem_cache_destroy(bad_cache); +} -- cgit v0.10.2 From 0d9eb29b13f0e326c4e19b85d3a4ac46e335e6d2 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Sun, 26 Jun 2016 15:12:31 -0700 Subject: lkdtm: split memory permissions tests to separate file This splits the EXEC_*, WRITE_* and related tests into the new lkdtm_perms.c file to help separate things better for readability. Signed-off-by: Kees Cook diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index e6b2778..9f6e95b 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -59,6 +59,7 @@ obj-$(CONFIG_CXL_BASE) += cxl/ obj-$(CONFIG_PANEL) += panel.o lkdtm-$(CONFIG_LKDTM) += lkdtm_core.o +lkdtm-$(CONFIG_LKDTM) += lkdtm_perms.o lkdtm-$(CONFIG_LKDTM) += lkdtm_rodata_objcopy.o lkdtm-$(CONFIG_LKDTM) += lkdtm_usercopy.o diff --git a/drivers/misc/lkdtm.h b/drivers/misc/lkdtm.h index ef290a2..40f681c 100644 --- a/drivers/misc/lkdtm.h +++ b/drivers/misc/lkdtm.h @@ -1,6 +1,19 @@ #ifndef __LKDTM_H #define __LKDTM_H +/* lkdtm_perms.c */ +void __init lkdtm_perms_init(void); +void lkdtm_WRITE_RO(void); +void lkdtm_WRITE_RO_AFTER_INIT(void); +void lkdtm_WRITE_KERN(void); +void lkdtm_EXEC_DATA(void); +void lkdtm_EXEC_STACK(void); +void lkdtm_EXEC_KMALLOC(void); +void lkdtm_EXEC_VMALLOC(void); +void lkdtm_EXEC_RODATA(void); +void lkdtm_EXEC_USERSPACE(void); +void lkdtm_ACCESS_USERSPACE(void); + /* lkdtm_rodata.c */ void lkdtm_rodata_do_nothing(void); @@ -16,4 +29,5 @@ void lkdtm_USERCOPY_STACK_FRAME_FROM(void); void lkdtm_USERCOPY_STACK_BEYOND(void); void lkdtm_USERCOPY_KERNEL(void); + #endif diff --git a/drivers/misc/lkdtm_core.c b/drivers/misc/lkdtm_core.c index 7437692..0b3e377 100644 --- a/drivers/misc/lkdtm_core.c +++ b/drivers/misc/lkdtm_core.c @@ -44,9 +44,6 @@ #include #include #include -#include -#include -#include #ifdef CONFIG_IDE #include @@ -67,7 +64,6 @@ #define REC_NUM_DEFAULT ((THREAD_SIZE / REC_STACK_SIZE) * 2) #define DEFAULT_COUNT 10 -#define EXEC_SIZE 64 enum cname { CN_INVALID, @@ -191,11 +187,6 @@ static int count = DEFAULT_COUNT; static DEFINE_SPINLOCK(count_lock); static DEFINE_SPINLOCK(lock_me_up); -static u8 data_area[EXEC_SIZE]; - -static const unsigned long rodata = 0xAA55AA55; -static unsigned long ro_after_init __ro_after_init = 0x55AA5500; - module_param(recur_count, int, 0644); MODULE_PARM_DESC(recur_count, " Recursion level for the stack overflow test"); module_param(cpoint_name, charp, 0444); @@ -348,18 +339,6 @@ static int recursive_loop(int remaining) return recursive_loop(remaining - 1); } -static void do_nothing(void) -{ - return; -} - -/* Must immediately follow do_nothing for size calculuations to work out. */ -static void do_overwritten(void) -{ - pr_info("do_overwritten wasn't overwritten!\n"); - return; -} - static noinline void corrupt_stack(void) { /* Use default char array length that triggers stack protection. */ @@ -368,38 +347,6 @@ static noinline void corrupt_stack(void) memset((void *)data, 0, 64); } -static noinline void execute_location(void *dst, bool write) -{ - void (*func)(void) = dst; - - pr_info("attempting ok execution at %p\n", do_nothing); - do_nothing(); - - if (write) { - memcpy(dst, do_nothing, EXEC_SIZE); - flush_icache_range((unsigned long)dst, - (unsigned long)dst + EXEC_SIZE); - } - pr_info("attempting bad execution at %p\n", func); - func(); -} - -static void execute_user_location(void *dst) -{ - /* Intentionally crossing kernel/user memory boundary. */ - void (*func)(void) = dst; - - pr_info("attempting ok execution at %p\n", do_nothing); - do_nothing(); - - if (copy_to_user((void __user *)dst, do_nothing, EXEC_SIZE)) - return; - flush_icache_range((unsigned long)dst, (unsigned long)dst + EXEC_SIZE); - pr_info("attempting bad execution at %p\n", func); - func(); -} - - static void lkdtm_do_action(enum ctype which) { switch (which) { @@ -577,116 +524,35 @@ static void lkdtm_do_action(enum ctype which) schedule(); break; case CT_EXEC_DATA: - execute_location(data_area, true); + lkdtm_EXEC_DATA(); break; - case CT_EXEC_STACK: { - u8 stack_area[EXEC_SIZE]; - execute_location(stack_area, true); + case CT_EXEC_STACK: + lkdtm_EXEC_STACK(); break; - } - case CT_EXEC_KMALLOC: { - u32 *kmalloc_area = kmalloc(EXEC_SIZE, GFP_KERNEL); - execute_location(kmalloc_area, true); - kfree(kmalloc_area); + case CT_EXEC_KMALLOC: + lkdtm_EXEC_KMALLOC(); break; - } - case CT_EXEC_VMALLOC: { - u32 *vmalloc_area = vmalloc(EXEC_SIZE); - execute_location(vmalloc_area, true); - vfree(vmalloc_area); + case CT_EXEC_VMALLOC: + lkdtm_EXEC_VMALLOC(); break; - } case CT_EXEC_RODATA: - execute_location(lkdtm_rodata_do_nothing, false); + lkdtm_EXEC_RODATA(); break; - case CT_EXEC_USERSPACE: { - unsigned long user_addr; - - user_addr = vm_mmap(NULL, 0, PAGE_SIZE, - PROT_READ | PROT_WRITE | PROT_EXEC, - MAP_ANONYMOUS | MAP_PRIVATE, 0); - if (user_addr >= TASK_SIZE) { - pr_warn("Failed to allocate user memory\n"); - return; - } - execute_user_location((void *)user_addr); - vm_munmap(user_addr, PAGE_SIZE); + case CT_EXEC_USERSPACE: + lkdtm_EXEC_USERSPACE(); break; - } - case CT_ACCESS_USERSPACE: { - unsigned long user_addr, tmp = 0; - unsigned long *ptr; - - user_addr = vm_mmap(NULL, 0, PAGE_SIZE, - PROT_READ | PROT_WRITE | PROT_EXEC, - MAP_ANONYMOUS | MAP_PRIVATE, 0); - if (user_addr >= TASK_SIZE) { - pr_warn("Failed to allocate user memory\n"); - return; - } - - if (copy_to_user((void __user *)user_addr, &tmp, sizeof(tmp))) { - pr_warn("copy_to_user failed\n"); - vm_munmap(user_addr, PAGE_SIZE); - return; - } - - ptr = (unsigned long *)user_addr; - - pr_info("attempting bad read at %p\n", ptr); - tmp = *ptr; - tmp += 0xc0dec0de; - - pr_info("attempting bad write at %p\n", ptr); - *ptr = tmp; - - vm_munmap(user_addr, PAGE_SIZE); - + case CT_ACCESS_USERSPACE: + lkdtm_ACCESS_USERSPACE(); break; - } - case CT_WRITE_RO: { - /* Explicitly cast away "const" for the test. */ - unsigned long *ptr = (unsigned long *)&rodata; - - pr_info("attempting bad rodata write at %p\n", ptr); - *ptr ^= 0xabcd1234; - + case CT_WRITE_RO: + lkdtm_WRITE_RO(); break; - } - case CT_WRITE_RO_AFTER_INIT: { - unsigned long *ptr = &ro_after_init; - - /* - * Verify we were written to during init. Since an Oops - * is considered a "success", a failure is to just skip the - * real test. - */ - if ((*ptr & 0xAA) != 0xAA) { - pr_info("%p was NOT written during init!?\n", ptr); - break; - } - - pr_info("attempting bad ro_after_init write at %p\n", ptr); - *ptr ^= 0xabcd1234; - + case CT_WRITE_RO_AFTER_INIT: + lkdtm_WRITE_RO_AFTER_INIT(); break; - } - case CT_WRITE_KERN: { - size_t size; - unsigned char *ptr; - - size = (unsigned long)do_overwritten - - (unsigned long)do_nothing; - ptr = (unsigned char *)do_overwritten; - - pr_info("attempting bad %zu byte write at %p\n", size, ptr); - memcpy(ptr, (unsigned char *)do_nothing, size); - flush_icache_range((unsigned long)ptr, - (unsigned long)(ptr + size)); - - do_overwritten(); + case CT_WRITE_KERN: + lkdtm_WRITE_KERN(); break; - } case CT_ATOMIC_UNDERFLOW: { atomic_t under = ATOMIC_INIT(INT_MIN); @@ -1024,11 +890,9 @@ static int __init lkdtm_module_init(void) int i; /* Handle test-specific initialization. */ + lkdtm_perms_init(); lkdtm_usercopy_init(); - /* Make sure we can write to __ro_after_init values during __init */ - ro_after_init |= 0xAA; - /* Register debugfs interface */ lkdtm_debugfs_root = debugfs_create_dir("provoke-crash", NULL); if (!lkdtm_debugfs_root) { diff --git a/drivers/misc/lkdtm_perms.c b/drivers/misc/lkdtm_perms.c new file mode 100644 index 0000000..8201006 --- /dev/null +++ b/drivers/misc/lkdtm_perms.c @@ -0,0 +1,203 @@ +/* + * This is for all the tests related to validating kernel memory + * permissions: non-executable regions, non-writable regions, and + * even non-readable regions. + */ +#define pr_fmt(fmt) "lkdtm: " fmt + +#include +#include +#include +#include +#include +#include + +#include "lkdtm.h" + +/* Whether or not to fill the target memory area with do_nothing(). */ +#define CODE_WRITE true +#define CODE_AS_IS false + +/* How many bytes to copy to be sure we've copied enough of do_nothing(). */ +#define EXEC_SIZE 64 + +/* This is non-const, so it will end up in the .data section. */ +static u8 data_area[EXEC_SIZE]; + +/* This is cost, so it will end up in the .rodata section. */ +static const unsigned long rodata = 0xAA55AA55; + +/* This is marked __ro_after_init, so it should ultimately be .rodata. */ +static unsigned long ro_after_init __ro_after_init = 0x55AA5500; + +/* + * This just returns to the caller. It is designed to be copied into + * non-executable memory regions. + */ +static void do_nothing(void) +{ + return; +} + +/* Must immediately follow do_nothing for size calculuations to work out. */ +static void do_overwritten(void) +{ + pr_info("do_overwritten wasn't overwritten!\n"); + return; +} + +static noinline void execute_location(void *dst, bool write) +{ + void (*func)(void) = dst; + + pr_info("attempting ok execution at %p\n", do_nothing); + do_nothing(); + + if (write == CODE_WRITE) { + memcpy(dst, do_nothing, EXEC_SIZE); + flush_icache_range((unsigned long)dst, + (unsigned long)dst + EXEC_SIZE); + } + pr_info("attempting bad execution at %p\n", func); + func(); +} + +static void execute_user_location(void *dst) +{ + /* Intentionally crossing kernel/user memory boundary. */ + void (*func)(void) = dst; + + pr_info("attempting ok execution at %p\n", do_nothing); + do_nothing(); + + if (copy_to_user((void __user *)dst, do_nothing, EXEC_SIZE)) + return; + flush_icache_range((unsigned long)dst, (unsigned long)dst + EXEC_SIZE); + pr_info("attempting bad execution at %p\n", func); + func(); +} + +void lkdtm_WRITE_RO(void) +{ + /* Explicitly cast away "const" for the test. */ + unsigned long *ptr = (unsigned long *)&rodata; + + pr_info("attempting bad rodata write at %p\n", ptr); + *ptr ^= 0xabcd1234; +} + +void lkdtm_WRITE_RO_AFTER_INIT(void) +{ + unsigned long *ptr = &ro_after_init; + + /* + * Verify we were written to during init. Since an Oops + * is considered a "success", a failure is to just skip the + * real test. + */ + if ((*ptr & 0xAA) != 0xAA) { + pr_info("%p was NOT written during init!?\n", ptr); + return; + } + + pr_info("attempting bad ro_after_init write at %p\n", ptr); + *ptr ^= 0xabcd1234; +} + +void lkdtm_WRITE_KERN(void) +{ + size_t size; + unsigned char *ptr; + + size = (unsigned long)do_overwritten - (unsigned long)do_nothing; + ptr = (unsigned char *)do_overwritten; + + pr_info("attempting bad %zu byte write at %p\n", size, ptr); + memcpy(ptr, (unsigned char *)do_nothing, size); + flush_icache_range((unsigned long)ptr, (unsigned long)(ptr + size)); + + do_overwritten(); +} + +void lkdtm_EXEC_DATA(void) +{ + execute_location(data_area, CODE_WRITE); +} + +void lkdtm_EXEC_STACK(void) +{ + u8 stack_area[EXEC_SIZE]; + execute_location(stack_area, CODE_WRITE); +} + +void lkdtm_EXEC_KMALLOC(void) +{ + u32 *kmalloc_area = kmalloc(EXEC_SIZE, GFP_KERNEL); + execute_location(kmalloc_area, CODE_WRITE); + kfree(kmalloc_area); +} + +void lkdtm_EXEC_VMALLOC(void) +{ + u32 *vmalloc_area = vmalloc(EXEC_SIZE); + execute_location(vmalloc_area, CODE_WRITE); + vfree(vmalloc_area); +} + +void lkdtm_EXEC_RODATA(void) +{ + execute_location(lkdtm_rodata_do_nothing, CODE_AS_IS); +} + +void lkdtm_EXEC_USERSPACE(void) +{ + unsigned long user_addr; + + user_addr = vm_mmap(NULL, 0, PAGE_SIZE, + PROT_READ | PROT_WRITE | PROT_EXEC, + MAP_ANONYMOUS | MAP_PRIVATE, 0); + if (user_addr >= TASK_SIZE) { + pr_warn("Failed to allocate user memory\n"); + return; + } + execute_user_location((void *)user_addr); + vm_munmap(user_addr, PAGE_SIZE); +} + +void lkdtm_ACCESS_USERSPACE(void) +{ + unsigned long user_addr, tmp = 0; + unsigned long *ptr; + + user_addr = vm_mmap(NULL, 0, PAGE_SIZE, + PROT_READ | PROT_WRITE | PROT_EXEC, + MAP_ANONYMOUS | MAP_PRIVATE, 0); + if (user_addr >= TASK_SIZE) { + pr_warn("Failed to allocate user memory\n"); + return; + } + + if (copy_to_user((void __user *)user_addr, &tmp, sizeof(tmp))) { + pr_warn("copy_to_user failed\n"); + vm_munmap(user_addr, PAGE_SIZE); + return; + } + + ptr = (unsigned long *)user_addr; + + pr_info("attempting bad read at %p\n", ptr); + tmp = *ptr; + tmp += 0xc0dec0de; + + pr_info("attempting bad write at %p\n", ptr); + *ptr = tmp; + + vm_munmap(user_addr, PAGE_SIZE); +} + +void __init lkdtm_perms_init(void) +{ + /* Make sure we can write to __ro_after_init values during __init */ + ro_after_init |= 0xAA; + +} -- cgit v0.10.2 From ffc514f3fcac4aa76735ada55228c814153943e6 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Sun, 26 Jun 2016 21:45:23 -0700 Subject: lkdtm: split heap corruption tests to separate file This splits the *_AFTER_FREE and related tests into the new lkdtm_heap.c file to help separate things better for readability. Signed-off-by: Kees Cook diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index 9f6e95b..d66f657 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -59,6 +59,7 @@ obj-$(CONFIG_CXL_BASE) += cxl/ obj-$(CONFIG_PANEL) += panel.o lkdtm-$(CONFIG_LKDTM) += lkdtm_core.o +lkdtm-$(CONFIG_LKDTM) += lkdtm_heap.o lkdtm-$(CONFIG_LKDTM) += lkdtm_perms.o lkdtm-$(CONFIG_LKDTM) += lkdtm_rodata_objcopy.o lkdtm-$(CONFIG_LKDTM) += lkdtm_usercopy.o diff --git a/drivers/misc/lkdtm.h b/drivers/misc/lkdtm.h index 40f681c..9397360 100644 --- a/drivers/misc/lkdtm.h +++ b/drivers/misc/lkdtm.h @@ -1,6 +1,13 @@ #ifndef __LKDTM_H #define __LKDTM_H +/* lkdtm_heap.c */ +void lkdtm_OVERWRITE_ALLOCATION(void); +void lkdtm_WRITE_AFTER_FREE(void); +void lkdtm_READ_AFTER_FREE(void); +void lkdtm_WRITE_BUDDY_AFTER_FREE(void); +void lkdtm_READ_BUDDY_AFTER_FREE(void); + /* lkdtm_perms.c */ void __init lkdtm_perms_init(void); void lkdtm_WRITE_RO(void); diff --git a/drivers/misc/lkdtm_core.c b/drivers/misc/lkdtm_core.c index 0b3e377..1c5056c 100644 --- a/drivers/misc/lkdtm_core.c +++ b/drivers/misc/lkdtm_core.c @@ -384,125 +384,21 @@ static void lkdtm_do_action(enum ctype which) *p = val; break; } - case CT_OVERWRITE_ALLOCATION: { - size_t len = 1020; - u32 *data = kmalloc(len, GFP_KERNEL); - - data[1024 / sizeof(u32)] = 0x12345678; - kfree(data); + case CT_OVERWRITE_ALLOCATION: + lkdtm_OVERWRITE_ALLOCATION(); break; - } - case CT_WRITE_AFTER_FREE: { - int *base, *again; - size_t len = 1024; - /* - * The slub allocator uses the first word to store the free - * pointer in some configurations. Use the middle of the - * allocation to avoid running into the freelist - */ - size_t offset = (len / sizeof(*base)) / 2; - - base = kmalloc(len, GFP_KERNEL); - pr_info("Allocated memory %p-%p\n", base, &base[offset * 2]); - pr_info("Attempting bad write to freed memory at %p\n", - &base[offset]); - kfree(base); - base[offset] = 0x0abcdef0; - /* Attempt to notice the overwrite. */ - again = kmalloc(len, GFP_KERNEL); - kfree(again); - if (again != base) - pr_info("Hmm, didn't get the same memory range.\n"); - + case CT_WRITE_AFTER_FREE: + lkdtm_WRITE_AFTER_FREE(); break; - } - case CT_READ_AFTER_FREE: { - int *base, *val, saw; - size_t len = 1024; - /* - * The slub allocator uses the first word to store the free - * pointer in some configurations. Use the middle of the - * allocation to avoid running into the freelist - */ - size_t offset = (len / sizeof(*base)) / 2; - - base = kmalloc(len, GFP_KERNEL); - if (!base) - break; - - val = kmalloc(len, GFP_KERNEL); - if (!val) { - kfree(base); - break; - } - - *val = 0x12345678; - base[offset] = *val; - pr_info("Value in memory before free: %x\n", base[offset]); - - kfree(base); - - pr_info("Attempting bad read from freed memory\n"); - saw = base[offset]; - if (saw != *val) { - /* Good! Poisoning happened, so declare a win. */ - pr_info("Memory correctly poisoned (%x)\n", saw); - BUG(); - } - pr_info("Memory was not poisoned\n"); - - kfree(val); + case CT_READ_AFTER_FREE: + lkdtm_READ_AFTER_FREE(); break; - } - case CT_WRITE_BUDDY_AFTER_FREE: { - unsigned long p = __get_free_page(GFP_KERNEL); - if (!p) - break; - pr_info("Writing to the buddy page before free\n"); - memset((void *)p, 0x3, PAGE_SIZE); - free_page(p); - schedule(); - pr_info("Attempting bad write to the buddy page after free\n"); - memset((void *)p, 0x78, PAGE_SIZE); - /* Attempt to notice the overwrite. */ - p = __get_free_page(GFP_KERNEL); - free_page(p); - schedule(); - + case CT_WRITE_BUDDY_AFTER_FREE: + lkdtm_WRITE_BUDDY_AFTER_FREE(); break; - } - case CT_READ_BUDDY_AFTER_FREE: { - unsigned long p = __get_free_page(GFP_KERNEL); - int saw, *val; - int *base; - - if (!p) - break; - - val = kmalloc(1024, GFP_KERNEL); - if (!val) { - free_page(p); - break; - } - - base = (int *)p; - - *val = 0x12345678; - base[0] = *val; - pr_info("Value in memory before free: %x\n", base[0]); - free_page(p); - pr_info("Attempting to read from freed memory\n"); - saw = base[0]; - if (saw != *val) { - /* Good! Poisoning happened, so declare a win. */ - pr_info("Memory correctly poisoned (%x)\n", saw); - BUG(); - } - pr_info("Buddy page was not poisoned\n"); - - kfree(val); + case CT_READ_BUDDY_AFTER_FREE: + lkdtm_READ_BUDDY_AFTER_FREE(); break; - } case CT_SOFTLOCKUP: preempt_disable(); for (;;) diff --git a/drivers/misc/lkdtm_heap.c b/drivers/misc/lkdtm_heap.c new file mode 100644 index 0000000..12f50e8 --- /dev/null +++ b/drivers/misc/lkdtm_heap.c @@ -0,0 +1,146 @@ +/* + * This is for all the tests relating directly to heap memory, including + * page allocation and slab allocations. + */ +#define pr_fmt(fmt) "lkdtm: " fmt + +#include +#include + +#include "lkdtm.h" + +/* + * This tries to stay within the next largest power-of-2 kmalloc cache + * to avoid actually overwriting anything important if it's not detected + * correctly. + */ +void lkdtm_OVERWRITE_ALLOCATION(void) +{ + size_t len = 1020; + u32 *data = kmalloc(len, GFP_KERNEL); + + data[1024 / sizeof(u32)] = 0x12345678; + kfree(data); +} + +void lkdtm_WRITE_AFTER_FREE(void) +{ + int *base, *again; + size_t len = 1024; + /* + * The slub allocator uses the first word to store the free + * pointer in some configurations. Use the middle of the + * allocation to avoid running into the freelist + */ + size_t offset = (len / sizeof(*base)) / 2; + + base = kmalloc(len, GFP_KERNEL); + pr_info("Allocated memory %p-%p\n", base, &base[offset * 2]); + pr_info("Attempting bad write to freed memory at %p\n", + &base[offset]); + kfree(base); + base[offset] = 0x0abcdef0; + /* Attempt to notice the overwrite. */ + again = kmalloc(len, GFP_KERNEL); + kfree(again); + if (again != base) + pr_info("Hmm, didn't get the same memory range.\n"); +} + +void lkdtm_READ_AFTER_FREE(void) +{ + int *base, *val, saw; + size_t len = 1024; + /* + * The slub allocator uses the first word to store the free + * pointer in some configurations. Use the middle of the + * allocation to avoid running into the freelist + */ + size_t offset = (len / sizeof(*base)) / 2; + + base = kmalloc(len, GFP_KERNEL); + if (!base) { + pr_info("Unable to allocate base memory.\n"); + return; + } + + val = kmalloc(len, GFP_KERNEL); + if (!val) { + pr_info("Unable to allocate val memory.\n"); + kfree(base); + return; + } + + *val = 0x12345678; + base[offset] = *val; + pr_info("Value in memory before free: %x\n", base[offset]); + + kfree(base); + + pr_info("Attempting bad read from freed memory\n"); + saw = base[offset]; + if (saw != *val) { + /* Good! Poisoning happened, so declare a win. */ + pr_info("Memory correctly poisoned (%x)\n", saw); + BUG(); + } + pr_info("Memory was not poisoned\n"); + + kfree(val); +} + +void lkdtm_WRITE_BUDDY_AFTER_FREE(void) +{ + unsigned long p = __get_free_page(GFP_KERNEL); + if (!p) { + pr_info("Unable to allocate free page\n"); + return; + } + + pr_info("Writing to the buddy page before free\n"); + memset((void *)p, 0x3, PAGE_SIZE); + free_page(p); + schedule(); + pr_info("Attempting bad write to the buddy page after free\n"); + memset((void *)p, 0x78, PAGE_SIZE); + /* Attempt to notice the overwrite. */ + p = __get_free_page(GFP_KERNEL); + free_page(p); + schedule(); +} + +void lkdtm_READ_BUDDY_AFTER_FREE(void) +{ + unsigned long p = __get_free_page(GFP_KERNEL); + int saw, *val; + int *base; + + if (!p) { + pr_info("Unable to allocate free page\n"); + return; + } + + val = kmalloc(1024, GFP_KERNEL); + if (!val) { + pr_info("Unable to allocate val memory.\n"); + free_page(p); + return; + } + + base = (int *)p; + + *val = 0x12345678; + base[0] = *val; + pr_info("Value in memory before free: %x\n", base[0]); + free_page(p); + pr_info("Attempting to read from freed memory\n"); + saw = base[0]; + if (saw != *val) { + /* Good! Poisoning happened, so declare a win. */ + pr_info("Memory correctly poisoned (%x)\n", saw); + BUG(); + } + pr_info("Buddy page was not poisoned\n"); + + kfree(val); +} -- cgit v0.10.2 From 00f496c416122e7f5a572a4511cf87c7240ba761 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Sun, 26 Jun 2016 22:17:25 -0700 Subject: lkdtm: split remaining logic bug tests to separate file This splits all the remaining tests from lkdtm_core.c into the new lkdtm_bugs.c file to help separate things better for readability. Signed-off-by: Kees Cook diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index d66f657..4387ccb 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -59,6 +59,7 @@ obj-$(CONFIG_CXL_BASE) += cxl/ obj-$(CONFIG_PANEL) += panel.o lkdtm-$(CONFIG_LKDTM) += lkdtm_core.o +lkdtm-$(CONFIG_LKDTM) += lkdtm_bugs.o lkdtm-$(CONFIG_LKDTM) += lkdtm_heap.o lkdtm-$(CONFIG_LKDTM) += lkdtm_perms.o lkdtm-$(CONFIG_LKDTM) += lkdtm_rodata_objcopy.o diff --git a/drivers/misc/lkdtm.h b/drivers/misc/lkdtm.h index 9397360..d70a417 100644 --- a/drivers/misc/lkdtm.h +++ b/drivers/misc/lkdtm.h @@ -1,6 +1,23 @@ #ifndef __LKDTM_H #define __LKDTM_H +/* lkdtm_bugs.c */ +void __init lkdtm_bugs_init(int *recur_param); +void lkdtm_PANIC(void); +void lkdtm_BUG(void); +void lkdtm_WARNING(void); +void lkdtm_EXCEPTION(void); +void lkdtm_LOOP(void); +void lkdtm_OVERFLOW(void); +void lkdtm_CORRUPT_STACK(void); +void lkdtm_UNALIGNED_LOAD_STORE_WRITE(void); +void lkdtm_SOFTLOCKUP(void); +void lkdtm_HARDLOCKUP(void); +void lkdtm_SPINLOCKUP(void); +void lkdtm_HUNG_TASK(void); +void lkdtm_ATOMIC_UNDERFLOW(void); +void lkdtm_ATOMIC_OVERFLOW(void); + /* lkdtm_heap.c */ void lkdtm_OVERWRITE_ALLOCATION(void); void lkdtm_WRITE_AFTER_FREE(void); diff --git a/drivers/misc/lkdtm_bugs.c b/drivers/misc/lkdtm_bugs.c new file mode 100644 index 0000000..e87071f --- /dev/null +++ b/drivers/misc/lkdtm_bugs.c @@ -0,0 +1,152 @@ +/* + * This is for all the tests related to logic bugs (e.g. bad dereferences, + * bad alignment, bad loops, bad locking, bad scheduling, deep stacks, and + * lockups) along with other things that don't fit well into existing LKDTM + * test source files. + */ +#define pr_fmt(fmt) "lkdtm: " fmt + +#include +#include + +#include "lkdtm.h" + +/* + * Make sure our attempts to over run the kernel stack doesn't trigger + * a compiler warning when CONFIG_FRAME_WARN is set. Then make sure we + * recurse past the end of THREAD_SIZE by default. + */ +#if defined(CONFIG_FRAME_WARN) && (CONFIG_FRAME_WARN > 0) +#define REC_STACK_SIZE (CONFIG_FRAME_WARN / 2) +#else +#define REC_STACK_SIZE (THREAD_SIZE / 8) +#endif +#define REC_NUM_DEFAULT ((THREAD_SIZE / REC_STACK_SIZE) * 2) + +static int recur_count = REC_NUM_DEFAULT; + +static DEFINE_SPINLOCK(lock_me_up); + +static int recursive_loop(int remaining) +{ + char buf[REC_STACK_SIZE]; + + /* Make sure compiler does not optimize this away. */ + memset(buf, (remaining & 0xff) | 0x1, REC_STACK_SIZE); + if (!remaining) + return 0; + else + return recursive_loop(remaining - 1); +} + +/* If the depth is negative, use the default, otherwise keep parameter. */ +void __init lkdtm_bugs_init(int *recur_param) +{ + if (*recur_param < 0) + *recur_param = recur_count; + else + recur_count = *recur_param; +} + +void lkdtm_PANIC(void) +{ + panic("dumptest"); +} + +void lkdtm_BUG(void) +{ + BUG(); +} + +void lkdtm_WARNING(void) +{ + WARN_ON(1); +} + +void lkdtm_EXCEPTION(void) +{ + *((int *) 0) = 0; +} + +void lkdtm_LOOP(void) +{ + for (;;) + ; +} + +void lkdtm_OVERFLOW(void) +{ + (void) recursive_loop(recur_count); +} + +noinline void lkdtm_CORRUPT_STACK(void) +{ + /* Use default char array length that triggers stack protection. */ + char data[8]; + + memset((void *)data, 0, 64); +} + +void lkdtm_UNALIGNED_LOAD_STORE_WRITE(void) +{ + static u8 data[5] __attribute__((aligned(4))) = {1, 2, 3, 4, 5}; + u32 *p; + u32 val = 0x12345678; + + p = (u32 *)(data + 1); + if (*p == 0) + val = 0x87654321; + *p = val; +} + +void lkdtm_SOFTLOCKUP(void) +{ + preempt_disable(); + for (;;) + cpu_relax(); +} + +void lkdtm_HARDLOCKUP(void) +{ + local_irq_disable(); + for (;;) + cpu_relax(); +} + +void lkdtm_SPINLOCKUP(void) +{ + /* Must be called twice to trigger. */ + spin_lock(&lock_me_up); + /* Let sparse know we intended to exit holding the lock. */ + __release(&lock_me_up); +} + +void lkdtm_HUNG_TASK(void) +{ + set_current_state(TASK_UNINTERRUPTIBLE); + schedule(); +} + +void lkdtm_ATOMIC_UNDERFLOW(void) +{ + atomic_t under = ATOMIC_INIT(INT_MIN); + + pr_info("attempting good atomic increment\n"); + atomic_inc(&under); + atomic_dec(&under); + + pr_info("attempting bad atomic underflow\n"); + atomic_dec(&under); +} + +void lkdtm_ATOMIC_OVERFLOW(void) +{ + atomic_t over = ATOMIC_INIT(INT_MAX); + + pr_info("attempting good atomic decrement\n"); + atomic_dec(&over); + atomic_inc(&over); + + pr_info("attempting bad atomic overflow\n"); + atomic_inc(&over); +} diff --git a/drivers/misc/lkdtm_core.c b/drivers/misc/lkdtm_core.c index 1c5056c..e0f1013 100644 --- a/drivers/misc/lkdtm_core.c +++ b/drivers/misc/lkdtm_core.c @@ -51,20 +51,11 @@ #include "lkdtm.h" -/* - * Make sure our attempts to over run the kernel stack doesn't trigger - * a compiler warning when CONFIG_FRAME_WARN is set. Then make sure we - * recurse past the end of THREAD_SIZE by default. - */ -#if defined(CONFIG_FRAME_WARN) && (CONFIG_FRAME_WARN > 0) -#define REC_STACK_SIZE (CONFIG_FRAME_WARN / 2) -#else -#define REC_STACK_SIZE (THREAD_SIZE / 8) -#endif -#define REC_NUM_DEFAULT ((THREAD_SIZE / REC_STACK_SIZE) * 2) - #define DEFAULT_COUNT 10 +static int count = DEFAULT_COUNT; +static DEFINE_SPINLOCK(count_lock); + enum cname { CN_INVALID, CN_INT_HARDWARE_ENTRY, @@ -179,13 +170,10 @@ static void lkdtm_handler(void); static char* cpoint_name; static char* cpoint_type; static int cpoint_count = DEFAULT_COUNT; -static int recur_count = REC_NUM_DEFAULT; +static int recur_count = -1; static enum cname cpoint = CN_INVALID; static enum ctype cptype = CT_NONE; -static int count = DEFAULT_COUNT; -static DEFINE_SPINLOCK(count_lock); -static DEFINE_SPINLOCK(lock_me_up); module_param(recur_count, int, 0644); MODULE_PARM_DESC(recur_count, " Recursion level for the stack overflow test"); @@ -327,63 +315,33 @@ static int lkdtm_parse_commandline(void) return -EINVAL; } -static int recursive_loop(int remaining) -{ - char buf[REC_STACK_SIZE]; - - /* Make sure compiler does not optimize this away. */ - memset(buf, (remaining & 0xff) | 0x1, REC_STACK_SIZE); - if (!remaining) - return 0; - else - return recursive_loop(remaining - 1); -} - -static noinline void corrupt_stack(void) -{ - /* Use default char array length that triggers stack protection. */ - char data[8]; - - memset((void *)data, 0, 64); -} - static void lkdtm_do_action(enum ctype which) { switch (which) { case CT_PANIC: - panic("dumptest"); + lkdtm_PANIC(); break; case CT_BUG: - BUG(); + lkdtm_BUG(); break; case CT_WARNING: - WARN_ON(1); + lkdtm_WARNING(); break; case CT_EXCEPTION: - *((int *) 0) = 0; + lkdtm_EXCEPTION(); break; case CT_LOOP: - for (;;) - ; + lkdtm_LOOP(); break; case CT_OVERFLOW: - (void) recursive_loop(recur_count); + lkdtm_OVERFLOW(); break; case CT_CORRUPT_STACK: - corrupt_stack(); - break; - case CT_UNALIGNED_LOAD_STORE_WRITE: { - static u8 data[5] __attribute__((aligned(4))) = {1, 2, - 3, 4, 5}; - u32 *p; - u32 val = 0x12345678; - - p = (u32 *)(data + 1); - if (*p == 0) - val = 0x87654321; - *p = val; - break; - } + lkdtm_CORRUPT_STACK(); + break; + case CT_UNALIGNED_LOAD_STORE_WRITE: + lkdtm_UNALIGNED_LOAD_STORE_WRITE(); + break; case CT_OVERWRITE_ALLOCATION: lkdtm_OVERWRITE_ALLOCATION(); break; @@ -400,24 +358,16 @@ static void lkdtm_do_action(enum ctype which) lkdtm_READ_BUDDY_AFTER_FREE(); break; case CT_SOFTLOCKUP: - preempt_disable(); - for (;;) - cpu_relax(); + lkdtm_SOFTLOCKUP(); break; case CT_HARDLOCKUP: - local_irq_disable(); - for (;;) - cpu_relax(); + lkdtm_HARDLOCKUP(); break; case CT_SPINLOCKUP: - /* Must be called twice to trigger. */ - spin_lock(&lock_me_up); - /* Let sparse know we intended to exit holding the lock. */ - __release(&lock_me_up); + lkdtm_SPINLOCKUP(); break; case CT_HUNG_TASK: - set_current_state(TASK_UNINTERRUPTIBLE); - schedule(); + lkdtm_HUNG_TASK(); break; case CT_EXEC_DATA: lkdtm_EXEC_DATA(); @@ -449,29 +399,12 @@ static void lkdtm_do_action(enum ctype which) case CT_WRITE_KERN: lkdtm_WRITE_KERN(); break; - case CT_ATOMIC_UNDERFLOW: { - atomic_t under = ATOMIC_INIT(INT_MIN); - - pr_info("attempting good atomic increment\n"); - atomic_inc(&under); - atomic_dec(&under); - - pr_info("attempting bad atomic underflow\n"); - atomic_dec(&under); + case CT_ATOMIC_UNDERFLOW: + lkdtm_ATOMIC_UNDERFLOW(); + break; + case CT_ATOMIC_OVERFLOW: + lkdtm_ATOMIC_OVERFLOW(); break; - } - case CT_ATOMIC_OVERFLOW: { - atomic_t over = ATOMIC_INIT(INT_MAX); - - pr_info("attempting good atomic decrement\n"); - atomic_dec(&over); - atomic_inc(&over); - - pr_info("attempting bad atomic overflow\n"); - atomic_inc(&over); - - return; - } case CT_USERCOPY_HEAP_SIZE_TO: lkdtm_USERCOPY_HEAP_SIZE_TO(); break; @@ -786,6 +719,7 @@ static int __init lkdtm_module_init(void) int i; /* Handle test-specific initialization. */ + lkdtm_bugs_init(&recur_count); lkdtm_perms_init(); lkdtm_usercopy_init(); -- cgit v0.10.2 From 329d416ca0ecc38c2be2515897d0e0e8780af1ce Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Sun, 26 Jun 2016 22:26:11 -0700 Subject: lkdtm: remove intentional off-by-one array access There wasn't a good reason for keeping the enum and the names out of sync by 1 position just to avoid "NONE" and "INVALID" from being in the string lists. Signed-off-by: Kees Cook diff --git a/drivers/misc/lkdtm_core.c b/drivers/misc/lkdtm_core.c index e0f1013..4f9d2f3 100644 --- a/drivers/misc/lkdtm_core.c +++ b/drivers/misc/lkdtm_core.c @@ -111,6 +111,7 @@ enum ctype { }; static char* cp_name[] = { + "INVALID", "INT_HARDWARE_ENTRY", "INT_HW_IRQ_EN", "INT_TASKLET_ENTRY", @@ -123,6 +124,7 @@ static char* cp_name[] = { }; static char* cp_type[] = { + "NONE", "PANIC", "BUG", "WARNING", @@ -257,7 +259,7 @@ static enum ctype parse_cp_type(const char *what, size_t count) for (i = 0; i < ARRAY_SIZE(cp_type); i++) { if (!strcmp(what, cp_type[i])) - return i + 1; + return i; } return CT_NONE; @@ -266,9 +268,9 @@ static enum ctype parse_cp_type(const char *what, size_t count) static const char *cp_type_to_str(enum ctype type) { if (type == CT_NONE || type < 0 || type > ARRAY_SIZE(cp_type)) - return "None"; + return "NONE"; - return cp_type[type - 1]; + return cp_type[type]; } static const char *cp_name_to_str(enum cname name) @@ -276,7 +278,7 @@ static const char *cp_name_to_str(enum cname name) if (name == CN_INVALID || name < 0 || name > ARRAY_SIZE(cp_name)) return "INVALID"; - return cp_name[name - 1]; + return cp_name[name]; } @@ -304,9 +306,13 @@ static int lkdtm_parse_commandline(void) if (cptype == CT_NONE) return -EINVAL; + /* Refuse INVALID as a selectable crashpoint name. */ + if (!strcmp(cpoint_name, "INVALID")) + return -EINVAL; + for (i = 0; i < ARRAY_SIZE(cp_name); i++) { if (!strcmp(cpoint_name, cp_name[i])) { - cpoint = i + 1; + cpoint = i; return 0; } } -- cgit v0.10.2 From 76a10e2b3a9dc3e6a290681aa126776c0ad304ad Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Sun, 26 Jun 2016 22:40:13 -0700 Subject: lkdtm: rename "count" to "crash_count" The "count" variable name was not easy to understand, since it was regularly obscured by local variables of the same name, and it's purpose wasn't clear. This renames it (and its lock) to "crash_count", which is more readable. Signed-off-by: Kees Cook diff --git a/drivers/misc/lkdtm_core.c b/drivers/misc/lkdtm_core.c index 4f9d2f3..fa7335e 100644 --- a/drivers/misc/lkdtm_core.c +++ b/drivers/misc/lkdtm_core.c @@ -51,11 +51,6 @@ #include "lkdtm.h" -#define DEFAULT_COUNT 10 - -static int count = DEFAULT_COUNT; -static DEFINE_SPINLOCK(count_lock); - enum cname { CN_INVALID, CN_INT_HARDWARE_ENTRY, @@ -169,10 +164,13 @@ static struct jprobe lkdtm; static int lkdtm_parse_commandline(void); static void lkdtm_handler(void); +#define DEFAULT_COUNT 10 static char* cpoint_name; static char* cpoint_type; static int cpoint_count = DEFAULT_COUNT; static int recur_count = -1; +static int crash_count = DEFAULT_COUNT; +static DEFINE_SPINLOCK(crash_count_lock); static enum cname cpoint = CN_INVALID; static enum ctype cptype = CT_NONE; @@ -290,9 +288,9 @@ static int lkdtm_parse_commandline(void) if (cpoint_count < 1 || recur_count < 1) return -EINVAL; - spin_lock_irqsave(&count_lock, flags); - count = cpoint_count; - spin_unlock_irqrestore(&count_lock, flags); + spin_lock_irqsave(&crash_count_lock, flags); + crash_count = cpoint_count; + spin_unlock_irqrestore(&crash_count_lock, flags); /* No special parameters */ if (!cpoint_type && !cpoint_name) @@ -447,16 +445,16 @@ static void lkdtm_handler(void) unsigned long flags; bool do_it = false; - spin_lock_irqsave(&count_lock, flags); - count--; + spin_lock_irqsave(&crash_count_lock, flags); + crash_count--; pr_info("Crash point %s of type %s hit, trigger in %d rounds\n", - cp_name_to_str(cpoint), cp_type_to_str(cptype), count); + cp_name_to_str(cpoint), cp_type_to_str(cptype), crash_count); - if (count == 0) { + if (crash_count == 0) { do_it = true; - count = cpoint_count; + crash_count = cpoint_count; } - spin_unlock_irqrestore(&count_lock, flags); + spin_unlock_irqrestore(&crash_count_lock, flags); if (do_it) lkdtm_do_action(cptype); -- cgit v0.10.2 From 38f95fe296f93274395330e62fd0561271e4718d Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Wed, 29 Jun 2016 08:02:32 -0700 Subject: lkdtm: rename globals for clarity The global variables used to track the active crashpoint and crashtype are hard to distinguish from local variable names, so add a "lkdtm_" prefix to them (or in the case of "lkdtm", add a "_jprobe" suffix). Signed-off-by: Kees Cook diff --git a/drivers/misc/lkdtm_core.c b/drivers/misc/lkdtm_core.c index fa7335e..31b22f3 100644 --- a/drivers/misc/lkdtm_core.c +++ b/drivers/misc/lkdtm_core.c @@ -159,7 +159,7 @@ static char* cp_type[] = { "USERCOPY_KERNEL", }; -static struct jprobe lkdtm; +static struct jprobe lkdtm_jprobe; static int lkdtm_parse_commandline(void); static void lkdtm_handler(void); @@ -172,8 +172,8 @@ static int recur_count = -1; static int crash_count = DEFAULT_COUNT; static DEFINE_SPINLOCK(crash_count_lock); -static enum cname cpoint = CN_INVALID; -static enum ctype cptype = CT_NONE; +static enum cname lkdtm_crashpoint = CN_INVALID; +static enum ctype lkdtm_crashtype = CT_NONE; module_param(recur_count, int, 0644); MODULE_PARM_DESC(recur_count, " Recursion level for the stack overflow test"); @@ -300,8 +300,8 @@ static int lkdtm_parse_commandline(void) if (!cpoint_type || !cpoint_name) return -EINVAL; - cptype = parse_cp_type(cpoint_type, strlen(cpoint_type)); - if (cptype == CT_NONE) + lkdtm_crashtype = parse_cp_type(cpoint_type, strlen(cpoint_type)); + if (lkdtm_crashtype == CT_NONE) return -EINVAL; /* Refuse INVALID as a selectable crashpoint name. */ @@ -310,7 +310,7 @@ static int lkdtm_parse_commandline(void) for (i = 0; i < ARRAY_SIZE(cp_name); i++) { if (!strcmp(cpoint_name, cp_name[i])) { - cpoint = i; + lkdtm_crashpoint = i; return 0; } } @@ -448,7 +448,8 @@ static void lkdtm_handler(void) spin_lock_irqsave(&crash_count_lock, flags); crash_count--; pr_info("Crash point %s of type %s hit, trigger in %d rounds\n", - cp_name_to_str(cpoint), cp_type_to_str(cptype), crash_count); + cp_name_to_str(lkdtm_crashpoint), + cp_type_to_str(lkdtm_crashtype), crash_count); if (crash_count == 0) { do_it = true; @@ -457,53 +458,53 @@ static void lkdtm_handler(void) spin_unlock_irqrestore(&crash_count_lock, flags); if (do_it) - lkdtm_do_action(cptype); + lkdtm_do_action(lkdtm_crashtype); } static int lkdtm_register_cpoint(enum cname which) { int ret; - cpoint = CN_INVALID; - if (lkdtm.entry != NULL) - unregister_jprobe(&lkdtm); + lkdtm_crashpoint = CN_INVALID; + if (lkdtm_jprobe.entry != NULL) + unregister_jprobe(&lkdtm_jprobe); switch (which) { case CN_DIRECT: - lkdtm_do_action(cptype); + lkdtm_do_action(lkdtm_crashtype); return 0; case CN_INT_HARDWARE_ENTRY: - lkdtm.kp.symbol_name = "do_IRQ"; - lkdtm.entry = (kprobe_opcode_t*) jp_do_irq; + lkdtm_jprobe.kp.symbol_name = "do_IRQ"; + lkdtm_jprobe.entry = (kprobe_opcode_t*) jp_do_irq; break; case CN_INT_HW_IRQ_EN: - lkdtm.kp.symbol_name = "handle_IRQ_event"; - lkdtm.entry = (kprobe_opcode_t*) jp_handle_irq_event; + lkdtm_jprobe.kp.symbol_name = "handle_IRQ_event"; + lkdtm_jprobe.entry = (kprobe_opcode_t*) jp_handle_irq_event; break; case CN_INT_TASKLET_ENTRY: - lkdtm.kp.symbol_name = "tasklet_action"; - lkdtm.entry = (kprobe_opcode_t*) jp_tasklet_action; + lkdtm_jprobe.kp.symbol_name = "tasklet_action"; + lkdtm_jprobe.entry = (kprobe_opcode_t*) jp_tasklet_action; break; case CN_FS_DEVRW: - lkdtm.kp.symbol_name = "ll_rw_block"; - lkdtm.entry = (kprobe_opcode_t*) jp_ll_rw_block; + lkdtm_jprobe.kp.symbol_name = "ll_rw_block"; + lkdtm_jprobe.entry = (kprobe_opcode_t*) jp_ll_rw_block; break; case CN_MEM_SWAPOUT: - lkdtm.kp.symbol_name = "shrink_inactive_list"; - lkdtm.entry = (kprobe_opcode_t*) jp_shrink_inactive_list; + lkdtm_jprobe.kp.symbol_name = "shrink_inactive_list"; + lkdtm_jprobe.entry = (kprobe_opcode_t*) jp_shrink_inactive_list; break; case CN_TIMERADD: - lkdtm.kp.symbol_name = "hrtimer_start"; - lkdtm.entry = (kprobe_opcode_t*) jp_hrtimer_start; + lkdtm_jprobe.kp.symbol_name = "hrtimer_start"; + lkdtm_jprobe.entry = (kprobe_opcode_t*) jp_hrtimer_start; break; case CN_SCSI_DISPATCH_CMD: - lkdtm.kp.symbol_name = "scsi_dispatch_cmd"; - lkdtm.entry = (kprobe_opcode_t*) jp_scsi_dispatch_cmd; + lkdtm_jprobe.kp.symbol_name = "scsi_dispatch_cmd"; + lkdtm_jprobe.entry = (kprobe_opcode_t*) jp_scsi_dispatch_cmd; break; case CN_IDE_CORE_CP: #ifdef CONFIG_IDE - lkdtm.kp.symbol_name = "generic_ide_ioctl"; - lkdtm.entry = (kprobe_opcode_t*) jp_generic_ide_ioctl; + lkdtm_jprobe.kp.symbol_name = "generic_ide_ioctl"; + lkdtm_jprobe.entry = (kprobe_opcode_t*) jp_generic_ide_ioctl; #else pr_info("Crash point not available\n"); return -EINVAL; @@ -514,10 +515,10 @@ static int lkdtm_register_cpoint(enum cname which) return -EINVAL; } - cpoint = which; - if ((ret = register_jprobe(&lkdtm)) < 0) { + lkdtm_crashpoint = which; + if ((ret = register_jprobe(&lkdtm_jprobe)) < 0) { pr_info("Couldn't register jprobe\n"); - cpoint = CN_INVALID; + lkdtm_crashpoint = CN_INVALID; } return ret; @@ -543,10 +544,10 @@ static ssize_t do_register_entry(enum cname which, struct file *f, buf[count] = '\0'; strim(buf); - cptype = parse_cp_type(buf, count); + lkdtm_crashtype = parse_cp_type(buf, count); free_page((unsigned long) buf); - if (cptype == CT_NONE) + if (lkdtm_crashtype == CT_NONE) return -EINVAL; err = lkdtm_register_cpoint(which); @@ -755,10 +756,10 @@ static int __init lkdtm_module_init(void) goto out_err; } - if (cpoint != CN_INVALID && cptype != CT_NONE) { - ret = lkdtm_register_cpoint(cpoint); + if (lkdtm_crashpoint != CN_INVALID && lkdtm_crashtype != CT_NONE) { + ret = lkdtm_register_cpoint(lkdtm_crashpoint); if (ret < 0) { - pr_info("Invalid crash point %d\n", cpoint); + pr_info("Invalid crash point %d\n", lkdtm_crashpoint); goto out_err; } pr_info("Crash point %s of type %s registered\n", @@ -781,7 +782,7 @@ static void __exit lkdtm_module_exit(void) /* Handle test-specific clean-up. */ lkdtm_usercopy_exit(); - unregister_jprobe(&lkdtm); + unregister_jprobe(&lkdtm_jprobe); pr_info("Crash point unregistered\n"); } -- cgit v0.10.2 From d87c978830674f388d910c2691069a4d2219f382 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Wed, 29 Jun 2016 08:07:11 -0700 Subject: lkdtm: reorganize module paramaters This reorganizes module parameters and global variables in the source so they're grouped together with comments. Also moves early function declarations to the top of the file. Signed-off-by: Kees Cook diff --git a/drivers/misc/lkdtm_core.c b/drivers/misc/lkdtm_core.c index 31b22f3..ff28bd0 100644 --- a/drivers/misc/lkdtm_core.c +++ b/drivers/misc/lkdtm_core.c @@ -51,6 +51,11 @@ #include "lkdtm.h" +#define DEFAULT_COUNT 10 + +static int lkdtm_parse_commandline(void); +static void lkdtm_handler(void); + enum cname { CN_INVALID, CN_INT_HARDWARE_ENTRY, @@ -159,29 +164,30 @@ static char* cp_type[] = { "USERCOPY_KERNEL", }; +/* Global jprobe entry and crashtype. */ static struct jprobe lkdtm_jprobe; +static enum cname lkdtm_crashpoint = CN_INVALID; +static enum ctype lkdtm_crashtype = CT_NONE; -static int lkdtm_parse_commandline(void); -static void lkdtm_handler(void); - -#define DEFAULT_COUNT 10 -static char* cpoint_name; -static char* cpoint_type; -static int cpoint_count = DEFAULT_COUNT; -static int recur_count = -1; +/* Global crash counter and spinlock. */ static int crash_count = DEFAULT_COUNT; static DEFINE_SPINLOCK(crash_count_lock); -static enum cname lkdtm_crashpoint = CN_INVALID; -static enum ctype lkdtm_crashtype = CT_NONE; - +/* Module parameters */ +static int recur_count = -1; module_param(recur_count, int, 0644); MODULE_PARM_DESC(recur_count, " Recursion level for the stack overflow test"); + +static char* cpoint_name; module_param(cpoint_name, charp, 0444); MODULE_PARM_DESC(cpoint_name, " Crash Point, where kernel is to be crashed"); + +static char* cpoint_type; module_param(cpoint_type, charp, 0444); MODULE_PARM_DESC(cpoint_type, " Crash Point Type, action to be taken on "\ "hitting the crash point"); + +static int cpoint_count = DEFAULT_COUNT; module_param(cpoint_count, int, 0644); MODULE_PARM_DESC(cpoint_count, " Crash Point Count, number of times the "\ "crash point is to be hit to trigger action"); -- cgit v0.10.2 From f2c6edc1ed0674b196080cfc3f66bc130e4d7c18 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Wed, 29 Jun 2016 08:10:36 -0700 Subject: lkdtm: move jprobe entry points to start of source In preparation of referencing the jprobe entry points in a structure, this moves them to the start of the source since they operate mostly separately from everything else. Signed-off-by: Kees Cook diff --git a/drivers/misc/lkdtm_core.c b/drivers/misc/lkdtm_core.c index ff28bd0..8b90220 100644 --- a/drivers/misc/lkdtm_core.c +++ b/drivers/misc/lkdtm_core.c @@ -56,6 +56,71 @@ static int lkdtm_parse_commandline(void); static void lkdtm_handler(void); +/* jprobe entry point handlers. */ +static unsigned int jp_do_irq(unsigned int irq) +{ + lkdtm_handler(); + jprobe_return(); + return 0; +} + +static irqreturn_t jp_handle_irq_event(unsigned int irq, + struct irqaction *action) +{ + lkdtm_handler(); + jprobe_return(); + return 0; +} + +static void jp_tasklet_action(struct softirq_action *a) +{ + lkdtm_handler(); + jprobe_return(); +} + +static void jp_ll_rw_block(int rw, int nr, struct buffer_head *bhs[]) +{ + lkdtm_handler(); + jprobe_return(); +} + +struct scan_control; + +static unsigned long jp_shrink_inactive_list(unsigned long max_scan, + struct zone *zone, + struct scan_control *sc) +{ + lkdtm_handler(); + jprobe_return(); + return 0; +} + +static int jp_hrtimer_start(struct hrtimer *timer, ktime_t tim, + const enum hrtimer_mode mode) +{ + lkdtm_handler(); + jprobe_return(); + return 0; +} + +static int jp_scsi_dispatch_cmd(struct scsi_cmnd *cmd) +{ + lkdtm_handler(); + jprobe_return(); + return 0; +} + +#ifdef CONFIG_IDE +static int jp_generic_ide_ioctl(ide_drive_t *drive, struct file *file, + struct block_device *bdev, unsigned int cmd, + unsigned long arg) +{ + lkdtm_handler(); + jprobe_return(); + return 0; +} +#endif + enum cname { CN_INVALID, CN_INT_HARDWARE_ENTRY, @@ -192,70 +257,6 @@ module_param(cpoint_count, int, 0644); MODULE_PARM_DESC(cpoint_count, " Crash Point Count, number of times the "\ "crash point is to be hit to trigger action"); -static unsigned int jp_do_irq(unsigned int irq) -{ - lkdtm_handler(); - jprobe_return(); - return 0; -} - -static irqreturn_t jp_handle_irq_event(unsigned int irq, - struct irqaction *action) -{ - lkdtm_handler(); - jprobe_return(); - return 0; -} - -static void jp_tasklet_action(struct softirq_action *a) -{ - lkdtm_handler(); - jprobe_return(); -} - -static void jp_ll_rw_block(int rw, int nr, struct buffer_head *bhs[]) -{ - lkdtm_handler(); - jprobe_return(); -} - -struct scan_control; - -static unsigned long jp_shrink_inactive_list(unsigned long max_scan, - struct zone *zone, - struct scan_control *sc) -{ - lkdtm_handler(); - jprobe_return(); - return 0; -} - -static int jp_hrtimer_start(struct hrtimer *timer, ktime_t tim, - const enum hrtimer_mode mode) -{ - lkdtm_handler(); - jprobe_return(); - return 0; -} - -static int jp_scsi_dispatch_cmd(struct scsi_cmnd *cmd) -{ - lkdtm_handler(); - jprobe_return(); - return 0; -} - -#ifdef CONFIG_IDE -static int jp_generic_ide_ioctl(ide_drive_t *drive, struct file *file, - struct block_device *bdev, unsigned int cmd, - unsigned long arg) -{ - lkdtm_handler(); - jprobe_return(); - return 0; -} -#endif - /* Return the crashpoint number or NONE if the name is invalid */ static enum ctype parse_cp_type(const char *what, size_t count) { -- cgit v0.10.2 From c479e3fd88703c4b1049d7102a3fa8c6b3affef5 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Wed, 29 Jun 2016 08:18:27 -0700 Subject: lkdtm: use struct arrays instead of enums This removes the use of enums in favor of much more readable and compact structure arrays. This requires changing all the enum passing to pointers instead, but the results are much cleaner. Signed-off-by: Kees Cook diff --git a/drivers/misc/lkdtm_core.c b/drivers/misc/lkdtm_core.c index 8b90220..de29a33 100644 --- a/drivers/misc/lkdtm_core.c +++ b/drivers/misc/lkdtm_core.c @@ -53,8 +53,16 @@ #define DEFAULT_COUNT 10 -static int lkdtm_parse_commandline(void); static void lkdtm_handler(void); +static int lkdtm_debugfs_open(struct inode *inode, struct file *file); +static ssize_t lkdtm_debugfs_read(struct file *f, char __user *user_buf, + size_t count, loff_t *off); +static ssize_t direct_entry(struct file *f, const char __user *user_buf, + size_t count, loff_t *off); +static ssize_t lkdtm_debugfs_entry(struct file *f, + const char __user *user_buf, + size_t count, loff_t *off); + /* jprobe entry point handlers. */ static unsigned int jp_do_irq(unsigned int irq) @@ -121,118 +129,114 @@ static int jp_generic_ide_ioctl(ide_drive_t *drive, struct file *file, } #endif -enum cname { - CN_INVALID, - CN_INT_HARDWARE_ENTRY, - CN_INT_HW_IRQ_EN, - CN_INT_TASKLET_ENTRY, - CN_FS_DEVRW, - CN_MEM_SWAPOUT, - CN_TIMERADD, - CN_SCSI_DISPATCH_CMD, - CN_IDE_CORE_CP, - CN_DIRECT, + +/* Crash points */ +struct crashpoint { + const char *name; + const struct file_operations fops; + struct jprobe jprobe; }; -enum ctype { - CT_NONE, - CT_PANIC, - CT_BUG, - CT_WARNING, - CT_EXCEPTION, - CT_LOOP, - CT_OVERFLOW, - CT_CORRUPT_STACK, - CT_UNALIGNED_LOAD_STORE_WRITE, - CT_OVERWRITE_ALLOCATION, - CT_WRITE_AFTER_FREE, - CT_READ_AFTER_FREE, - CT_WRITE_BUDDY_AFTER_FREE, - CT_READ_BUDDY_AFTER_FREE, - CT_SOFTLOCKUP, - CT_HARDLOCKUP, - CT_SPINLOCKUP, - CT_HUNG_TASK, - CT_EXEC_DATA, - CT_EXEC_STACK, - CT_EXEC_KMALLOC, - CT_EXEC_VMALLOC, - CT_EXEC_RODATA, - CT_EXEC_USERSPACE, - CT_ACCESS_USERSPACE, - CT_WRITE_RO, - CT_WRITE_RO_AFTER_INIT, - CT_WRITE_KERN, - CT_ATOMIC_UNDERFLOW, - CT_ATOMIC_OVERFLOW, - CT_USERCOPY_HEAP_SIZE_TO, - CT_USERCOPY_HEAP_SIZE_FROM, - CT_USERCOPY_HEAP_FLAG_TO, - CT_USERCOPY_HEAP_FLAG_FROM, - CT_USERCOPY_STACK_FRAME_TO, - CT_USERCOPY_STACK_FRAME_FROM, - CT_USERCOPY_STACK_BEYOND, - CT_USERCOPY_KERNEL, +#define CRASHPOINT(_name, _write, _symbol, _entry) \ + { \ + .name = _name, \ + .fops = { \ + .read = lkdtm_debugfs_read, \ + .llseek = generic_file_llseek, \ + .open = lkdtm_debugfs_open, \ + .write = _write, \ + }, \ + .jprobe = { \ + .kp.symbol_name = _symbol, \ + .entry = (kprobe_opcode_t *)_entry, \ + }, \ + } + +/* Define the possible places where we can trigger a crash point. */ +struct crashpoint crashpoints[] = { + CRASHPOINT("DIRECT", direct_entry, + NULL, NULL), +#ifdef CONFIG_KPROBES + CRASHPOINT("INT_HARDWARE_ENTRY", lkdtm_debugfs_entry, + "do_IRQ", jp_do_irq), + CRASHPOINT("INT_HW_IRQ_EN", lkdtm_debugfs_entry, + "handle_IRQ_event", jp_handle_irq_event), + CRASHPOINT("INT_TASKLET_ENTRY", lkdtm_debugfs_entry, + "tasklet_action", jp_tasklet_action), + CRASHPOINT("FS_DEVRW", lkdtm_debugfs_entry, + "ll_rw_block", jp_ll_rw_block), + CRASHPOINT("MEM_SWAPOUT", lkdtm_debugfs_entry, + "shrink_inactive_list", jp_shrink_inactive_list), + CRASHPOINT("TIMERADD", lkdtm_debugfs_entry, + "hrtimer_start", jp_hrtimer_start), + CRASHPOINT("SCSI_DISPATCH_CMD", lkdtm_debugfs_entry, + "scsi_dispatch_cmd", jp_scsi_dispatch_cmd), +# ifdef CONFIG_IDE + CRASHPOINT("IDE_CORE_CP", lkdtm_debugfs_entry, + "generic_ide_ioctl", jp_generic_ide_ioctl), +# endif +#endif }; -static char* cp_name[] = { - "INVALID", - "INT_HARDWARE_ENTRY", - "INT_HW_IRQ_EN", - "INT_TASKLET_ENTRY", - "FS_DEVRW", - "MEM_SWAPOUT", - "TIMERADD", - "SCSI_DISPATCH_CMD", - "IDE_CORE_CP", - "DIRECT", + +/* Crash types. */ +struct crashtype { + const char *name; + void (*func)(void); }; -static char* cp_type[] = { - "NONE", - "PANIC", - "BUG", - "WARNING", - "EXCEPTION", - "LOOP", - "OVERFLOW", - "CORRUPT_STACK", - "UNALIGNED_LOAD_STORE_WRITE", - "OVERWRITE_ALLOCATION", - "WRITE_AFTER_FREE", - "READ_AFTER_FREE", - "WRITE_BUDDY_AFTER_FREE", - "READ_BUDDY_AFTER_FREE", - "SOFTLOCKUP", - "HARDLOCKUP", - "SPINLOCKUP", - "HUNG_TASK", - "EXEC_DATA", - "EXEC_STACK", - "EXEC_KMALLOC", - "EXEC_VMALLOC", - "EXEC_RODATA", - "EXEC_USERSPACE", - "ACCESS_USERSPACE", - "WRITE_RO", - "WRITE_RO_AFTER_INIT", - "WRITE_KERN", - "ATOMIC_UNDERFLOW", - "ATOMIC_OVERFLOW", - "USERCOPY_HEAP_SIZE_TO", - "USERCOPY_HEAP_SIZE_FROM", - "USERCOPY_HEAP_FLAG_TO", - "USERCOPY_HEAP_FLAG_FROM", - "USERCOPY_STACK_FRAME_TO", - "USERCOPY_STACK_FRAME_FROM", - "USERCOPY_STACK_BEYOND", - "USERCOPY_KERNEL", +#define CRASHTYPE(_name) \ + { \ + .name = __stringify(_name), \ + .func = lkdtm_ ## _name, \ + } + +/* Define the possible types of crashes that can be triggered. */ +struct crashtype crashtypes[] = { + CRASHTYPE(PANIC), + CRASHTYPE(BUG), + CRASHTYPE(WARNING), + CRASHTYPE(EXCEPTION), + CRASHTYPE(LOOP), + CRASHTYPE(OVERFLOW), + CRASHTYPE(CORRUPT_STACK), + CRASHTYPE(UNALIGNED_LOAD_STORE_WRITE), + CRASHTYPE(OVERWRITE_ALLOCATION), + CRASHTYPE(WRITE_AFTER_FREE), + CRASHTYPE(READ_AFTER_FREE), + CRASHTYPE(WRITE_BUDDY_AFTER_FREE), + CRASHTYPE(READ_BUDDY_AFTER_FREE), + CRASHTYPE(SOFTLOCKUP), + CRASHTYPE(HARDLOCKUP), + CRASHTYPE(SPINLOCKUP), + CRASHTYPE(HUNG_TASK), + CRASHTYPE(EXEC_DATA), + CRASHTYPE(EXEC_STACK), + CRASHTYPE(EXEC_KMALLOC), + CRASHTYPE(EXEC_VMALLOC), + CRASHTYPE(EXEC_RODATA), + CRASHTYPE(EXEC_USERSPACE), + CRASHTYPE(ACCESS_USERSPACE), + CRASHTYPE(WRITE_RO), + CRASHTYPE(WRITE_RO_AFTER_INIT), + CRASHTYPE(WRITE_KERN), + CRASHTYPE(ATOMIC_UNDERFLOW), + CRASHTYPE(ATOMIC_OVERFLOW), + CRASHTYPE(USERCOPY_HEAP_SIZE_TO), + CRASHTYPE(USERCOPY_HEAP_SIZE_FROM), + CRASHTYPE(USERCOPY_HEAP_FLAG_TO), + CRASHTYPE(USERCOPY_HEAP_FLAG_FROM), + CRASHTYPE(USERCOPY_STACK_FRAME_TO), + CRASHTYPE(USERCOPY_STACK_FRAME_FROM), + CRASHTYPE(USERCOPY_STACK_BEYOND), + CRASHTYPE(USERCOPY_KERNEL), }; + /* Global jprobe entry and crashtype. */ -static struct jprobe lkdtm_jprobe; -static enum cname lkdtm_crashpoint = CN_INVALID; -static enum ctype lkdtm_crashtype = CT_NONE; +static struct jprobe *lkdtm_jprobe; +struct crashpoint *lkdtm_crashpoint; +struct crashtype *lkdtm_crashtype; /* Global crash counter and spinlock. */ static int crash_count = DEFAULT_COUNT; @@ -257,206 +261,42 @@ module_param(cpoint_count, int, 0644); MODULE_PARM_DESC(cpoint_count, " Crash Point Count, number of times the "\ "crash point is to be hit to trigger action"); -/* Return the crashpoint number or NONE if the name is invalid */ -static enum ctype parse_cp_type(const char *what, size_t count) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(cp_type); i++) { - if (!strcmp(what, cp_type[i])) - return i; - } - - return CT_NONE; -} - -static const char *cp_type_to_str(enum ctype type) -{ - if (type == CT_NONE || type < 0 || type > ARRAY_SIZE(cp_type)) - return "NONE"; - - return cp_type[type]; -} - -static const char *cp_name_to_str(enum cname name) -{ - if (name == CN_INVALID || name < 0 || name > ARRAY_SIZE(cp_name)) - return "INVALID"; - - return cp_name[name]; -} - -static int lkdtm_parse_commandline(void) +/* Return the crashtype number or NULL if the name is invalid */ +static struct crashtype *find_crashtype(const char *name) { int i; - unsigned long flags; - - if (cpoint_count < 1 || recur_count < 1) - return -EINVAL; - - spin_lock_irqsave(&crash_count_lock, flags); - crash_count = cpoint_count; - spin_unlock_irqrestore(&crash_count_lock, flags); - /* No special parameters */ - if (!cpoint_type && !cpoint_name) - return 0; - - /* Neither or both of these need to be set */ - if (!cpoint_type || !cpoint_name) - return -EINVAL; - - lkdtm_crashtype = parse_cp_type(cpoint_type, strlen(cpoint_type)); - if (lkdtm_crashtype == CT_NONE) - return -EINVAL; - - /* Refuse INVALID as a selectable crashpoint name. */ - if (!strcmp(cpoint_name, "INVALID")) - return -EINVAL; - - for (i = 0; i < ARRAY_SIZE(cp_name); i++) { - if (!strcmp(cpoint_name, cp_name[i])) { - lkdtm_crashpoint = i; - return 0; - } + for (i = 0; i < ARRAY_SIZE(crashtypes); i++) { + if (!strcmp(name, crashtypes[i].name)) + return &crashtypes[i]; } - /* Could not find a valid crash point */ - return -EINVAL; + return NULL; } -static void lkdtm_do_action(enum ctype which) +/* + * This is forced noinline just so it distinctly shows up in the stackdump + * which makes validation of expected lkdtm crashes easier. + */ +static noinline void lkdtm_do_action(struct crashtype *crashtype) { - switch (which) { - case CT_PANIC: - lkdtm_PANIC(); - break; - case CT_BUG: - lkdtm_BUG(); - break; - case CT_WARNING: - lkdtm_WARNING(); - break; - case CT_EXCEPTION: - lkdtm_EXCEPTION(); - break; - case CT_LOOP: - lkdtm_LOOP(); - break; - case CT_OVERFLOW: - lkdtm_OVERFLOW(); - break; - case CT_CORRUPT_STACK: - lkdtm_CORRUPT_STACK(); - break; - case CT_UNALIGNED_LOAD_STORE_WRITE: - lkdtm_UNALIGNED_LOAD_STORE_WRITE(); - break; - case CT_OVERWRITE_ALLOCATION: - lkdtm_OVERWRITE_ALLOCATION(); - break; - case CT_WRITE_AFTER_FREE: - lkdtm_WRITE_AFTER_FREE(); - break; - case CT_READ_AFTER_FREE: - lkdtm_READ_AFTER_FREE(); - break; - case CT_WRITE_BUDDY_AFTER_FREE: - lkdtm_WRITE_BUDDY_AFTER_FREE(); - break; - case CT_READ_BUDDY_AFTER_FREE: - lkdtm_READ_BUDDY_AFTER_FREE(); - break; - case CT_SOFTLOCKUP: - lkdtm_SOFTLOCKUP(); - break; - case CT_HARDLOCKUP: - lkdtm_HARDLOCKUP(); - break; - case CT_SPINLOCKUP: - lkdtm_SPINLOCKUP(); - break; - case CT_HUNG_TASK: - lkdtm_HUNG_TASK(); - break; - case CT_EXEC_DATA: - lkdtm_EXEC_DATA(); - break; - case CT_EXEC_STACK: - lkdtm_EXEC_STACK(); - break; - case CT_EXEC_KMALLOC: - lkdtm_EXEC_KMALLOC(); - break; - case CT_EXEC_VMALLOC: - lkdtm_EXEC_VMALLOC(); - break; - case CT_EXEC_RODATA: - lkdtm_EXEC_RODATA(); - break; - case CT_EXEC_USERSPACE: - lkdtm_EXEC_USERSPACE(); - break; - case CT_ACCESS_USERSPACE: - lkdtm_ACCESS_USERSPACE(); - break; - case CT_WRITE_RO: - lkdtm_WRITE_RO(); - break; - case CT_WRITE_RO_AFTER_INIT: - lkdtm_WRITE_RO_AFTER_INIT(); - break; - case CT_WRITE_KERN: - lkdtm_WRITE_KERN(); - break; - case CT_ATOMIC_UNDERFLOW: - lkdtm_ATOMIC_UNDERFLOW(); - break; - case CT_ATOMIC_OVERFLOW: - lkdtm_ATOMIC_OVERFLOW(); - break; - case CT_USERCOPY_HEAP_SIZE_TO: - lkdtm_USERCOPY_HEAP_SIZE_TO(); - break; - case CT_USERCOPY_HEAP_SIZE_FROM: - lkdtm_USERCOPY_HEAP_SIZE_FROM(); - break; - case CT_USERCOPY_HEAP_FLAG_TO: - lkdtm_USERCOPY_HEAP_FLAG_TO(); - break; - case CT_USERCOPY_HEAP_FLAG_FROM: - lkdtm_USERCOPY_HEAP_FLAG_FROM(); - break; - case CT_USERCOPY_STACK_FRAME_TO: - lkdtm_USERCOPY_STACK_FRAME_TO(); - break; - case CT_USERCOPY_STACK_FRAME_FROM: - lkdtm_USERCOPY_STACK_FRAME_FROM(); - break; - case CT_USERCOPY_STACK_BEYOND: - lkdtm_USERCOPY_STACK_BEYOND(); - break; - case CT_USERCOPY_KERNEL: - lkdtm_USERCOPY_KERNEL(); - break; - case CT_NONE: - default: - break; - } - + BUG_ON(!crashtype || !crashtype->func); + crashtype->func(); } +/* Called by jprobe entry points. */ static void lkdtm_handler(void) { unsigned long flags; bool do_it = false; + BUG_ON(!lkdtm_crashpoint || !lkdtm_crashtype); + spin_lock_irqsave(&crash_count_lock, flags); crash_count--; pr_info("Crash point %s of type %s hit, trigger in %d rounds\n", - cp_name_to_str(lkdtm_crashpoint), - cp_type_to_str(lkdtm_crashtype), crash_count); + lkdtm_crashpoint->name, lkdtm_crashtype->name, crash_count); if (crash_count == 0) { do_it = true; @@ -468,72 +308,41 @@ static void lkdtm_handler(void) lkdtm_do_action(lkdtm_crashtype); } -static int lkdtm_register_cpoint(enum cname which) +static int lkdtm_register_cpoint(struct crashpoint *crashpoint, + struct crashtype *crashtype) { int ret; - lkdtm_crashpoint = CN_INVALID; - if (lkdtm_jprobe.entry != NULL) - unregister_jprobe(&lkdtm_jprobe); - - switch (which) { - case CN_DIRECT: - lkdtm_do_action(lkdtm_crashtype); + /* If this doesn't have a symbol, just call immediately. */ + if (!crashpoint->jprobe.kp.symbol_name) { + lkdtm_do_action(crashtype); return 0; - case CN_INT_HARDWARE_ENTRY: - lkdtm_jprobe.kp.symbol_name = "do_IRQ"; - lkdtm_jprobe.entry = (kprobe_opcode_t*) jp_do_irq; - break; - case CN_INT_HW_IRQ_EN: - lkdtm_jprobe.kp.symbol_name = "handle_IRQ_event"; - lkdtm_jprobe.entry = (kprobe_opcode_t*) jp_handle_irq_event; - break; - case CN_INT_TASKLET_ENTRY: - lkdtm_jprobe.kp.symbol_name = "tasklet_action"; - lkdtm_jprobe.entry = (kprobe_opcode_t*) jp_tasklet_action; - break; - case CN_FS_DEVRW: - lkdtm_jprobe.kp.symbol_name = "ll_rw_block"; - lkdtm_jprobe.entry = (kprobe_opcode_t*) jp_ll_rw_block; - break; - case CN_MEM_SWAPOUT: - lkdtm_jprobe.kp.symbol_name = "shrink_inactive_list"; - lkdtm_jprobe.entry = (kprobe_opcode_t*) jp_shrink_inactive_list; - break; - case CN_TIMERADD: - lkdtm_jprobe.kp.symbol_name = "hrtimer_start"; - lkdtm_jprobe.entry = (kprobe_opcode_t*) jp_hrtimer_start; - break; - case CN_SCSI_DISPATCH_CMD: - lkdtm_jprobe.kp.symbol_name = "scsi_dispatch_cmd"; - lkdtm_jprobe.entry = (kprobe_opcode_t*) jp_scsi_dispatch_cmd; - break; - case CN_IDE_CORE_CP: -#ifdef CONFIG_IDE - lkdtm_jprobe.kp.symbol_name = "generic_ide_ioctl"; - lkdtm_jprobe.entry = (kprobe_opcode_t*) jp_generic_ide_ioctl; -#else - pr_info("Crash point not available\n"); - return -EINVAL; -#endif - break; - default: - pr_info("Invalid Crash Point\n"); - return -EINVAL; } - lkdtm_crashpoint = which; - if ((ret = register_jprobe(&lkdtm_jprobe)) < 0) { - pr_info("Couldn't register jprobe\n"); - lkdtm_crashpoint = CN_INVALID; + if (lkdtm_jprobe != NULL) + unregister_jprobe(lkdtm_jprobe); + + lkdtm_crashpoint = crashpoint; + lkdtm_crashtype = crashtype; + lkdtm_jprobe = &crashpoint->jprobe; + ret = register_jprobe(lkdtm_jprobe); + if (ret < 0) { + pr_info("Couldn't register jprobe %s\n", + crashpoint->jprobe.kp.symbol_name); + lkdtm_jprobe = NULL; + lkdtm_crashpoint = NULL; + lkdtm_crashtype = NULL; } return ret; } -static ssize_t do_register_entry(enum cname which, struct file *f, - const char __user *user_buf, size_t count, loff_t *off) +static ssize_t lkdtm_debugfs_entry(struct file *f, + const char __user *user_buf, + size_t count, loff_t *off) { + struct crashpoint *crashpoint = file_inode(f)->i_private; + struct crashtype *crashtype = NULL; char *buf; int err; @@ -551,13 +360,13 @@ static ssize_t do_register_entry(enum cname which, struct file *f, buf[count] = '\0'; strim(buf); - lkdtm_crashtype = parse_cp_type(buf, count); - free_page((unsigned long) buf); + crashtype = find_crashtype(buf); + free_page((unsigned long)buf); - if (lkdtm_crashtype == CT_NONE) + if (!crashtype) return -EINVAL; - err = lkdtm_register_cpoint(which); + err = lkdtm_register_cpoint(crashpoint, crashtype); if (err < 0) return err; @@ -578,8 +387,10 @@ static ssize_t lkdtm_debugfs_read(struct file *f, char __user *user_buf, return -ENOMEM; n = snprintf(buf, PAGE_SIZE, "Available crash types:\n"); - for (i = 0; i < ARRAY_SIZE(cp_type); i++) - n += snprintf(buf + n, PAGE_SIZE - n, "%s\n", cp_type[i]); + for (i = 0; i < ARRAY_SIZE(crashtypes); i++) { + n += snprintf(buf + n, PAGE_SIZE - n, "%s\n", + crashtypes[i].name); + } buf[n] = '\0'; out = simple_read_from_buffer(user_buf, count, off, @@ -594,60 +405,11 @@ static int lkdtm_debugfs_open(struct inode *inode, struct file *file) return 0; } - -static ssize_t int_hardware_entry(struct file *f, const char __user *buf, - size_t count, loff_t *off) -{ - return do_register_entry(CN_INT_HARDWARE_ENTRY, f, buf, count, off); -} - -static ssize_t int_hw_irq_en(struct file *f, const char __user *buf, - size_t count, loff_t *off) -{ - return do_register_entry(CN_INT_HW_IRQ_EN, f, buf, count, off); -} - -static ssize_t int_tasklet_entry(struct file *f, const char __user *buf, - size_t count, loff_t *off) -{ - return do_register_entry(CN_INT_TASKLET_ENTRY, f, buf, count, off); -} - -static ssize_t fs_devrw_entry(struct file *f, const char __user *buf, - size_t count, loff_t *off) -{ - return do_register_entry(CN_FS_DEVRW, f, buf, count, off); -} - -static ssize_t mem_swapout_entry(struct file *f, const char __user *buf, - size_t count, loff_t *off) -{ - return do_register_entry(CN_MEM_SWAPOUT, f, buf, count, off); -} - -static ssize_t timeradd_entry(struct file *f, const char __user *buf, - size_t count, loff_t *off) -{ - return do_register_entry(CN_TIMERADD, f, buf, count, off); -} - -static ssize_t scsi_dispatch_cmd_entry(struct file *f, - const char __user *buf, size_t count, loff_t *off) -{ - return do_register_entry(CN_SCSI_DISPATCH_CMD, f, buf, count, off); -} - -static ssize_t ide_core_cp_entry(struct file *f, const char __user *buf, - size_t count, loff_t *off) -{ - return do_register_entry(CN_IDE_CORE_CP, f, buf, count, off); -} - /* Special entry to just crash directly. Available without KPROBEs */ static ssize_t direct_entry(struct file *f, const char __user *user_buf, size_t count, loff_t *off) { - enum ctype type; + struct crashtype *crashtype; char *buf; if (count >= PAGE_SIZE) @@ -666,70 +428,57 @@ static ssize_t direct_entry(struct file *f, const char __user *user_buf, buf[count] = '\0'; strim(buf); - type = parse_cp_type(buf, count); + crashtype = find_crashtype(buf); free_page((unsigned long) buf); - if (type == CT_NONE) + if (!crashtype) return -EINVAL; - pr_info("Performing direct entry %s\n", cp_type_to_str(type)); - lkdtm_do_action(type); + pr_info("Performing direct entry %s\n", crashtype->name); + lkdtm_do_action(crashtype); *off += count; return count; } -struct crash_entry { - const char *name; - const struct file_operations fops; -}; - -static const struct crash_entry crash_entries[] = { - {"DIRECT", {.read = lkdtm_debugfs_read, - .llseek = generic_file_llseek, - .open = lkdtm_debugfs_open, - .write = direct_entry} }, - {"INT_HARDWARE_ENTRY", {.read = lkdtm_debugfs_read, - .llseek = generic_file_llseek, - .open = lkdtm_debugfs_open, - .write = int_hardware_entry} }, - {"INT_HW_IRQ_EN", {.read = lkdtm_debugfs_read, - .llseek = generic_file_llseek, - .open = lkdtm_debugfs_open, - .write = int_hw_irq_en} }, - {"INT_TASKLET_ENTRY", {.read = lkdtm_debugfs_read, - .llseek = generic_file_llseek, - .open = lkdtm_debugfs_open, - .write = int_tasklet_entry} }, - {"FS_DEVRW", {.read = lkdtm_debugfs_read, - .llseek = generic_file_llseek, - .open = lkdtm_debugfs_open, - .write = fs_devrw_entry} }, - {"MEM_SWAPOUT", {.read = lkdtm_debugfs_read, - .llseek = generic_file_llseek, - .open = lkdtm_debugfs_open, - .write = mem_swapout_entry} }, - {"TIMERADD", {.read = lkdtm_debugfs_read, - .llseek = generic_file_llseek, - .open = lkdtm_debugfs_open, - .write = timeradd_entry} }, - {"SCSI_DISPATCH_CMD", {.read = lkdtm_debugfs_read, - .llseek = generic_file_llseek, - .open = lkdtm_debugfs_open, - .write = scsi_dispatch_cmd_entry} }, - {"IDE_CORE_CP", {.read = lkdtm_debugfs_read, - .llseek = generic_file_llseek, - .open = lkdtm_debugfs_open, - .write = ide_core_cp_entry} }, -}; - static struct dentry *lkdtm_debugfs_root; static int __init lkdtm_module_init(void) { + struct crashpoint *crashpoint = NULL; + struct crashtype *crashtype = NULL; int ret = -EINVAL; - int n_debugfs_entries = 1; /* Assume only the direct entry */ int i; + /* Neither or both of these need to be set */ + if ((cpoint_type || cpoint_name) && !(cpoint_type && cpoint_name)) { + pr_err("Need both cpoint_type and cpoint_name or neither\n"); + return -EINVAL; + } + + if (cpoint_type) { + crashtype = find_crashtype(cpoint_type); + if (!crashtype) { + pr_err("Unknown crashtype '%s'\n", cpoint_type); + return -EINVAL; + } + } + + if (cpoint_name) { + for (i = 0; i < ARRAY_SIZE(crashpoints); i++) { + if (!strcmp(cpoint_name, crashpoints[i].name)) + crashpoint = &crashpoints[i]; + } + + /* Refuse unknown crashpoints. */ + if (!crashpoint) { + pr_err("Invalid crashpoint %s\n", cpoint_name); + return -EINVAL; + } + } + + /* Set crash count. */ + crash_count = cpoint_count; + /* Handle test-specific initialization. */ lkdtm_bugs_init(&recur_count); lkdtm_perms_init(); @@ -742,35 +491,28 @@ static int __init lkdtm_module_init(void) return -ENODEV; } -#ifdef CONFIG_KPROBES - n_debugfs_entries = ARRAY_SIZE(crash_entries); -#endif - - for (i = 0; i < n_debugfs_entries; i++) { - const struct crash_entry *cur = &crash_entries[i]; + /* Install debugfs trigger files. */ + for (i = 0; i < ARRAY_SIZE(crashpoints); i++) { + struct crashpoint *cur = &crashpoints[i]; struct dentry *de; de = debugfs_create_file(cur->name, 0644, lkdtm_debugfs_root, - NULL, &cur->fops); + cur, &cur->fops); if (de == NULL) { - pr_err("could not create %s\n", cur->name); + pr_err("could not create crashpoint %s\n", cur->name); goto out_err; } } - if (lkdtm_parse_commandline() == -EINVAL) { - pr_info("Invalid command\n"); - goto out_err; - } - - if (lkdtm_crashpoint != CN_INVALID && lkdtm_crashtype != CT_NONE) { - ret = lkdtm_register_cpoint(lkdtm_crashpoint); + /* Install crashpoint if one was selected. */ + if (crashpoint) { + ret = lkdtm_register_cpoint(crashpoint, crashtype); if (ret < 0) { - pr_info("Invalid crash point %d\n", lkdtm_crashpoint); + pr_info("Invalid crashpoint %s\n", crashpoint->name); goto out_err; } pr_info("Crash point %s of type %s registered\n", - cpoint_name, cpoint_type); + crashpoint->name, cpoint_type); } else { pr_info("No crash points registered, enable through debugfs\n"); } @@ -789,7 +531,7 @@ static void __exit lkdtm_module_exit(void) /* Handle test-specific clean-up. */ lkdtm_usercopy_exit(); - unregister_jprobe(&lkdtm_jprobe); + unregister_jprobe(lkdtm_jprobe); pr_info("Crash point unregistered\n"); } @@ -797,4 +539,4 @@ module_init(lkdtm_module_init); module_exit(lkdtm_module_exit); MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("Kprobe module for testing crash dumps"); +MODULE_DESCRIPTION("Kernel crash testing module"); -- cgit v0.10.2 From 3777ed688fba82d0bd43f9fc1ebbc6abe788576d Mon Sep 17 00:00:00 2001 From: Quentin Armitage Date: Thu, 16 Jun 2016 08:00:14 +0100 Subject: ipvs: fix bind to link-local mcast IPv6 address in backup When using HEAD from https://git.kernel.org/cgit/utils/kernel/ipvsadm/ipvsadm.git/, the command: ipvsadm --start-daemon backup --mcast-interface eth0.60 \ --mcast-group ff02::1:81 fails with the error message: Argument list too long whereas both: ipvsadm --start-daemon master --mcast-interface eth0.60 \ --mcast-group ff02::1:81 and: ipvsadm --start-daemon backup --mcast-interface eth0.60 \ --mcast-group 224.0.0.81 are successful. The error message "Argument list too long" isn't helpful. The error occurs because an IPv6 address is given in backup mode. The error is in make_receive_sock() in net/netfilter/ipvs/ip_vs_sync.c, since it fails to set the interface on the address or the socket before calling inet6_bind() (via sock->ops->bind), where the test 'if (!sk->sk_bound_dev_if)' failed. Setting sock->sk->sk_bound_dev_if on the socket before calling inet6_bind() resolves the issue. Fixes: d33288172e72 ("ipvs: add more mcast parameters for the sync daemon") Signed-off-by: Quentin Armitage Acked-by: Julian Anastasov Signed-off-by: Simon Horman diff --git a/net/netfilter/ipvs/ip_vs_sync.c b/net/netfilter/ipvs/ip_vs_sync.c index 803001a..1b07578 100644 --- a/net/netfilter/ipvs/ip_vs_sync.c +++ b/net/netfilter/ipvs/ip_vs_sync.c @@ -1545,7 +1545,8 @@ error: /* * Set up receiving multicast socket over UDP */ -static struct socket *make_receive_sock(struct netns_ipvs *ipvs, int id) +static struct socket *make_receive_sock(struct netns_ipvs *ipvs, int id, + int ifindex) { /* multicast addr */ union ipvs_sockaddr mcast_addr; @@ -1566,6 +1567,7 @@ static struct socket *make_receive_sock(struct netns_ipvs *ipvs, int id) set_sock_size(sock->sk, 0, result); get_mcast_sockaddr(&mcast_addr, &salen, &ipvs->bcfg, id); + sock->sk->sk_bound_dev_if = ifindex; result = sock->ops->bind(sock, (struct sockaddr *)&mcast_addr, salen); if (result < 0) { pr_err("Error binding to the multicast addr\n"); @@ -1868,7 +1870,7 @@ int start_sync_thread(struct netns_ipvs *ipvs, struct ipvs_sync_daemon_cfg *c, if (state == IP_VS_STATE_MASTER) sock = make_send_sock(ipvs, id); else - sock = make_receive_sock(ipvs, id); + sock = make_receive_sock(ipvs, id, dev->ifindex); if (IS_ERR(sock)) { result = PTR_ERR(sock); goto outtinfo; -- cgit v0.10.2 From 78c4e172412de5d0456dc00d2b34050aa0b683b5 Mon Sep 17 00:00:00 2001 From: Jeff Mahoney Date: Tue, 5 Jul 2016 17:32:29 -0400 Subject: Revert "ecryptfs: forbid opening files without mmap handler" This reverts commit 2f36db71009304b3f0b95afacd8eba1f9f046b87. It fixed a local root exploit but also introduced a dependency on the lower file system implementing an mmap operation just to open a file, which is a bit of a heavy hammer. The right fix is to have mmap depend on the existence of the mmap handler instead. Signed-off-by: Jeff Mahoney Cc: stable@vger.kernel.org Signed-off-by: Tyler Hicks diff --git a/fs/ecryptfs/kthread.c b/fs/ecryptfs/kthread.c index e818f5a..866bb18 100644 --- a/fs/ecryptfs/kthread.c +++ b/fs/ecryptfs/kthread.c @@ -25,7 +25,6 @@ #include #include #include -#include #include "ecryptfs_kernel.h" struct ecryptfs_open_req { @@ -148,7 +147,7 @@ int ecryptfs_privileged_open(struct file **lower_file, flags |= IS_RDONLY(d_inode(lower_dentry)) ? O_RDONLY : O_RDWR; (*lower_file) = dentry_open(&req.path, flags, cred); if (!IS_ERR(*lower_file)) - goto have_file; + goto out; if ((flags & O_ACCMODE) == O_RDONLY) { rc = PTR_ERR((*lower_file)); goto out; @@ -166,16 +165,8 @@ int ecryptfs_privileged_open(struct file **lower_file, mutex_unlock(&ecryptfs_kthread_ctl.mux); wake_up(&ecryptfs_kthread_ctl.wait); wait_for_completion(&req.done); - if (IS_ERR(*lower_file)) { + if (IS_ERR(*lower_file)) rc = PTR_ERR(*lower_file); - goto out; - } -have_file: - if ((*lower_file)->f_op->mmap == NULL) { - fput(*lower_file); - *lower_file = NULL; - rc = -EMEDIUMTYPE; - } out: return rc; } -- cgit v0.10.2 From 30a46a4647fd1df9cf52e43bf467f0d9265096ca Mon Sep 17 00:00:00 2001 From: Vegard Nossum Date: Thu, 7 Jul 2016 13:41:11 -0700 Subject: apparmor: fix oops, validate buffer size in apparmor_setprocattr() When proc_pid_attr_write() was changed to use memdup_user apparmor's (interface violating) assumption that the setprocattr buffer was always a single page was violated. The size test is not strictly speaking needed as proc_pid_attr_write() will reject anything larger, but for the sake of robustness we can keep it in. SMACK and SELinux look safe to me, but somebody else should probably have a look just in case. Based on original patch from Vegard Nossum modified for the case that apparmor provides null termination. Fixes: bb646cdb12e75d82258c2f2e7746d5952d3e321a Reported-by: Vegard Nossum Cc: Al Viro Cc: John Johansen Cc: Paul Moore Cc: Stephen Smalley Cc: Eric Paris Cc: Casey Schaufler Cc: stable@kernel.org Signed-off-by: John Johansen Reviewed-by: Tyler Hicks Signed-off-by: James Morris diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c index 2660fbc..7798e16 100644 --- a/security/apparmor/lsm.c +++ b/security/apparmor/lsm.c @@ -500,34 +500,34 @@ static int apparmor_setprocattr(struct task_struct *task, char *name, { struct common_audit_data sa; struct apparmor_audit_data aad = {0,}; - char *command, *args = value; + char *command, *largs = NULL, *args = value; size_t arg_size; int error; if (size == 0) return -EINVAL; - /* args points to a PAGE_SIZE buffer, AppArmor requires that - * the buffer must be null terminated or have size <= PAGE_SIZE -1 - * so that AppArmor can null terminate them - */ - if (args[size - 1] != '\0') { - if (size == PAGE_SIZE) - return -EINVAL; - args[size] = '\0'; - } - /* task can only write its own attributes */ if (current != task) return -EACCES; - args = value; + /* AppArmor requires that the buffer must be null terminated atm */ + if (args[size - 1] != '\0') { + /* null terminate */ + largs = args = kmalloc(size + 1, GFP_KERNEL); + if (!args) + return -ENOMEM; + memcpy(args, value, size); + args[size] = '\0'; + } + + error = -EINVAL; args = strim(args); command = strsep(&args, " "); if (!args) - return -EINVAL; + goto out; args = skip_spaces(args); if (!*args) - return -EINVAL; + goto out; arg_size = size - (args - (char *) value); if (strcmp(name, "current") == 0) { @@ -553,10 +553,12 @@ static int apparmor_setprocattr(struct task_struct *task, char *name, goto fail; } else /* only support the "current" and "exec" process attributes */ - return -EINVAL; + goto fail; if (!error) error = size; +out: + kfree(largs); return error; fail: @@ -565,9 +567,9 @@ fail: aad.profile = aa_current_profile(); aad.op = OP_SETPROCATTR; aad.info = name; - aad.error = -EINVAL; + aad.error = error = -EINVAL; aa_audit_msg(AUDIT_APPARMOR_DENIED, &sa, NULL); - return -EINVAL; + goto out; } static int apparmor_task_setrlimit(struct task_struct *task, -- cgit v0.10.2 From 8a132099f080d7384bb6ab4cc168f76cb4b47d08 Mon Sep 17 00:00:00 2001 From: Hui Wang Date: Fri, 8 Jul 2016 14:26:57 +0800 Subject: ALSA: hda/realtek - add new pin definition in alc225 pin quirk table We have some Dell laptops which can't detect headset mic, the machines use the codec ALC225, they have some new pin configuration values, after adding them in the alc225 pin quirk table, they work well. Cc: Signed-off-by: Hui Wang Signed-off-by: Takashi Iwai diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 5fac786..abcb5a6 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -5738,7 +5738,6 @@ static const struct hda_model_fixup alc269_fixup_models[] = { {} }; #define ALC225_STANDARD_PINS \ - {0x12, 0xb7a60130}, \ {0x21, 0x04211020} #define ALC256_STANDARD_PINS \ @@ -5763,10 +5762,24 @@ static const struct hda_model_fixup alc269_fixup_models[] = { static const struct snd_hda_pin_quirk alc269_pin_fixup_tbl[] = { SND_HDA_PIN_QUIRK(0x10ec0225, 0x1028, "Dell", ALC225_FIXUP_DELL1_MIC_NO_PRESENCE, ALC225_STANDARD_PINS, + {0x12, 0xb7a60130}, {0x14, 0x901701a0}), SND_HDA_PIN_QUIRK(0x10ec0225, 0x1028, "Dell", ALC225_FIXUP_DELL1_MIC_NO_PRESENCE, ALC225_STANDARD_PINS, + {0x12, 0xb7a60130}, {0x14, 0x901701b0}), + SND_HDA_PIN_QUIRK(0x10ec0225, 0x1028, "Dell", ALC225_FIXUP_DELL1_MIC_NO_PRESENCE, + ALC225_STANDARD_PINS, + {0x12, 0xb7a60150}, + {0x14, 0x901701a0}), + SND_HDA_PIN_QUIRK(0x10ec0225, 0x1028, "Dell", ALC225_FIXUP_DELL1_MIC_NO_PRESENCE, + ALC225_STANDARD_PINS, + {0x12, 0xb7a60150}, + {0x14, 0x901701b0}), + SND_HDA_PIN_QUIRK(0x10ec0225, 0x1028, "Dell", ALC225_FIXUP_DELL1_MIC_NO_PRESENCE, + ALC225_STANDARD_PINS, + {0x12, 0xb7a60130}, + {0x1b, 0x90170110}), SND_HDA_PIN_QUIRK(0x10ec0255, 0x1028, "Dell", ALC255_FIXUP_DELL2_MIC_NO_PRESENCE, {0x14, 0x90170110}, {0x21, 0x02211020}), -- cgit v0.10.2 From f388cdcdd160687c6650833f286b9c89c50960ff Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 8 Jul 2016 08:05:19 +0200 Subject: ALSA: ctl: Stop notification after disconnection snd_ctl_remove() has a notification for the removal event. It's superfluous when done during the device got disconnected. Although the notification itself is mostly harmless, it may potentially be harmful, and should be suppressed. Actually some components PCM may free ctl elements during the disconnect or free callbacks, thus it's no theoretical issue. This patch adds the check of card->shutdown flag for avoiding unnecessary notifications after (or during) the disconnect. Cc: Signed-off-by: Takashi Iwai diff --git a/sound/core/control.c b/sound/core/control.c index a85d455..b4fe9b0 100644 --- a/sound/core/control.c +++ b/sound/core/control.c @@ -160,6 +160,8 @@ void snd_ctl_notify(struct snd_card *card, unsigned int mask, if (snd_BUG_ON(!card || !id)) return; + if (card->shutdown) + return; read_lock(&card->ctl_files_rwlock); #if IS_ENABLED(CONFIG_SND_MIXER_OSS) card->mixer_oss_change_count++; -- cgit v0.10.2 From a8ff48cb70835f48de5703052760312019afea55 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 8 Jul 2016 08:23:43 +0200 Subject: ALSA: pcm: Free chmap at PCM free callback, too The chmap ctls assigned to PCM streams are freed in the PCM disconnect callback. However, since the disconnect callback isn't called when the card gets freed before registering, the chmap ctls may still be left assigned. They are eventually freed together with other ctls, but it may cause an Oops at pcm_chmap_ctl_private_free(), as the function refers to the assigned PCM stream, while the PCM objects have been already freed beforehand. The fix is to free the chmap ctls also at PCM free callback, not only at PCM disconnect. Reported-by: Laxminath Kasam Cc: Signed-off-by: Takashi Iwai diff --git a/sound/core/pcm.c b/sound/core/pcm.c index 308c9ec..8e980aa 100644 --- a/sound/core/pcm.c +++ b/sound/core/pcm.c @@ -849,6 +849,14 @@ int snd_pcm_new_internal(struct snd_card *card, const char *id, int device, } EXPORT_SYMBOL(snd_pcm_new_internal); +static void free_chmap(struct snd_pcm_str *pstr) +{ + if (pstr->chmap_kctl) { + snd_ctl_remove(pstr->pcm->card, pstr->chmap_kctl); + pstr->chmap_kctl = NULL; + } +} + static void snd_pcm_free_stream(struct snd_pcm_str * pstr) { struct snd_pcm_substream *substream, *substream_next; @@ -871,6 +879,7 @@ static void snd_pcm_free_stream(struct snd_pcm_str * pstr) kfree(setup); } #endif + free_chmap(pstr); if (pstr->substream_count) put_device(&pstr->dev); } @@ -1135,10 +1144,7 @@ static int snd_pcm_dev_disconnect(struct snd_device *device) for (cidx = 0; cidx < 2; cidx++) { if (!pcm->internal) snd_unregister_device(&pcm->streams[cidx].dev); - if (pcm->streams[cidx].chmap_kctl) { - snd_ctl_remove(pcm->card, pcm->streams[cidx].chmap_kctl); - pcm->streams[cidx].chmap_kctl = NULL; - } + free_chmap(&pcm->streams[cidx]); } mutex_unlock(&pcm->open_mutex); mutex_unlock(®ister_mutex); -- cgit v0.10.2 From e99a0745bdf8a5f7e3126a686846af4aeb852cc9 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 5 Jul 2016 23:09:07 +0300 Subject: x86/pci, x86/platform/intel_mid_pci: Remove duplicate power off code Intel MID platforms (Moorestown, Medfield, Clovertrail, Merrifield) are sharing the code in the intel_mid_pci.c module. There is no need to power off specific Moorestown devices after the following commit: 5823d0893ec2 ("x86/platform/intel-mid: Add Power Management Unit driver") ... because the condition in mrfld_power_off_dev() is true for any platform from the above list. Remove duplicate power off certain devices on Intel Moorestown and rename the affected functions to show that they are applied to any of Intel MID platforms. Signed-off-by: Andy Shevchenko Cc: Bjorn Helgaas Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/1467749348-100518-1-git-send-email-andriy.shevchenko@linux.intel.com Signed-off-by: Ingo Molnar diff --git a/arch/x86/pci/intel_mid_pci.c b/arch/x86/pci/intel_mid_pci.c index a971043..5413d6a 100644 --- a/arch/x86/pci/intel_mid_pci.c +++ b/arch/x86/pci/intel_mid_pci.c @@ -316,7 +316,7 @@ static void pci_d3delay_fixup(struct pci_dev *dev) } DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_ANY_ID, pci_d3delay_fixup); -static void mid_power_off_dev(struct pci_dev *dev) +static void mid_power_off_one_device(struct pci_dev *dev) { u16 pmcsr; @@ -330,12 +330,7 @@ static void mid_power_off_dev(struct pci_dev *dev) pci_set_power_state(dev, PCI_D3hot); } -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x0801, mid_power_off_dev); -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x0809, mid_power_off_dev); -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x080C, mid_power_off_dev); -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x0815, mid_power_off_dev); - -static void mrfld_power_off_dev(struct pci_dev *dev) +static void mid_power_off_devices(struct pci_dev *dev) { int id; @@ -350,10 +345,10 @@ static void mrfld_power_off_dev(struct pci_dev *dev) * This sets only PMCSR bits. The actual power off will happen in * arch/x86/platform/intel-mid/pwr.c. */ - mid_power_off_dev(dev); + mid_power_off_one_device(dev); } -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_ANY_ID, mrfld_power_off_dev); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_ANY_ID, mid_power_off_devices); /* * Langwell devices reside at fixed offsets, don't try to move them. -- cgit v0.10.2 From ca22312dc840065206285626829ceed8bb4df88c Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 5 Jul 2016 23:09:08 +0300 Subject: x86/platform/intel-mid: Extend PWRMU to support Penwell Intel Penwell is one of the first SoCs in Intel MID series. It has slightly older version of PWRMU IP, though it is compatible with one found on Intel Tangier. Since we are not using (yet) any advanced stuff in the driver we may safely re-use what it's done for Intel Tangier for now. Extend PWRMU driver to support Intel Penwell by adding PCI ID and re-using existing ->set_initial_state() function. Signed-off-by: Andy Shevchenko Cc: Bjorn Helgaas Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/1467749348-100518-2-git-send-email-andriy.shevchenko@linux.intel.com Signed-off-by: Ingo Molnar diff --git a/arch/x86/platform/intel-mid/pwr.c b/arch/x86/platform/intel-mid/pwr.c index 59faf05..5bc90dd 100644 --- a/arch/x86/platform/intel-mid/pwr.c +++ b/arch/x86/platform/intel-mid/pwr.c @@ -75,6 +75,7 @@ #define LSS_PWS_BITS 2 /* power state width */ /* Supported device IDs */ +#define PCI_DEVICE_ID_PENWELL 0x0828 #define PCI_DEVICE_ID_TANGIER 0x11a1 struct mid_pwr_dev { @@ -354,7 +355,7 @@ static int mid_pwr_probe(struct pci_dev *pdev, const struct pci_device_id *id) return 0; } -static int tng_set_initial_state(struct mid_pwr *pwr) +static int mid_set_initial_state(struct mid_pwr *pwr) { unsigned int i, j; int ret; @@ -397,12 +398,13 @@ static int tng_set_initial_state(struct mid_pwr *pwr) return 0; } -static const struct mid_pwr_device_info tng_info = { - .set_initial_state = tng_set_initial_state, +static const struct mid_pwr_device_info mid_info = { + .set_initial_state = mid_set_initial_state, }; static const struct pci_device_id mid_pwr_pci_ids[] = { - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_TANGIER), (kernel_ulong_t)&tng_info }, + { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_PENWELL), (kernel_ulong_t)&mid_info }, + { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_TANGIER), (kernel_ulong_t)&mid_info }, {} }; MODULE_DEVICE_TABLE(pci, mid_pwr_pci_ids); -- cgit v0.10.2 From e81e11bc71573709352a5275e175a4b2ee1325e5 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 5 Jul 2016 03:14:50 +0300 Subject: x86/platform/intel-mid: Enable spidev on Intel Edison boards Intel Edison board provides one of the SPI bus for user's connected devices. Append platform data to get spidev enumerated over it. Signed-off-by: Andy Shevchenko Cc: Dan O'Donovan Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/1467677690-90007-1-git-send-email-andriy.shevchenko@linux.intel.com Signed-off-by: Ingo Molnar diff --git a/arch/x86/platform/intel-mid/device_libs/Makefile b/arch/x86/platform/intel-mid/device_libs/Makefile index 79e97ed..fc135bf 100644 --- a/arch/x86/platform/intel-mid/device_libs/Makefile +++ b/arch/x86/platform/intel-mid/device_libs/Makefile @@ -10,6 +10,8 @@ obj-$(subst m,y,$(CONFIG_MFD_INTEL_MSIC)) += platform_msic_battery.o obj-$(subst m,y,$(CONFIG_INTEL_MID_POWER_BUTTON)) += platform_msic_power_btn.o obj-$(subst m,y,$(CONFIG_GPIO_INTEL_PMIC)) += platform_pmic_gpio.o obj-$(subst m,y,$(CONFIG_INTEL_MFLD_THERMAL)) += platform_msic_thermal.o +# SPI Devices +obj-$(subst m,y,$(CONFIG_SPI_SPIDEV)) += platform_spidev.o # I2C Devices obj-$(subst m,y,$(CONFIG_SENSORS_EMC1403)) += platform_emc1403.o obj-$(subst m,y,$(CONFIG_SENSORS_LIS3LV02D)) += platform_lis331.o diff --git a/arch/x86/platform/intel-mid/device_libs/platform_spidev.c b/arch/x86/platform/intel-mid/device_libs/platform_spidev.c new file mode 100644 index 0000000..30c601b --- /dev/null +++ b/arch/x86/platform/intel-mid/device_libs/platform_spidev.c @@ -0,0 +1,50 @@ +/* + * spidev platform data initilization file + * + * (C) Copyright 2014, 2016 Intel Corporation + * Authors: Andy Shevchenko + * Dan O'Donovan + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; version 2 + * of the License. + */ + +#include +#include +#include +#include + +#include + +#define MRFLD_SPI_DEFAULT_DMA_BURST 8 +#define MRFLD_SPI_DEFAULT_TIMEOUT 500 + +/* GPIO pin for spidev chipselect */ +#define MRFLD_SPIDEV_GPIO_CS 111 + +static struct pxa2xx_spi_chip spidev_spi_chip = { + .dma_burst_size = MRFLD_SPI_DEFAULT_DMA_BURST, + .timeout = MRFLD_SPI_DEFAULT_TIMEOUT, + .gpio_cs = MRFLD_SPIDEV_GPIO_CS, +}; + +static void __init *spidev_platform_data(void *info) +{ + struct spi_board_info *spi_info = info; + + spi_info->mode = SPI_MODE_0; + spi_info->controller_data = &spidev_spi_chip; + + return NULL; +} + +static const struct devs_id spidev_dev_id __initconst = { + .name = "spidev", + .type = SFI_DEV_TYPE_SPI, + .delay = 0, + .get_platform_data = &spidev_platform_data, +}; + +sfi_device(spidev_dev_id); -- cgit v0.10.2 From 955d1427a91b18f53e082bd7c19c40ce13b0a0f4 Mon Sep 17 00:00:00 2001 From: Aravind Gopalakrishnan Date: Fri, 8 Jul 2016 11:09:38 +0200 Subject: x86/mce/AMD: Increase size of the bank_map type Change bank_map type from 'char' to 'int' since we now have more than eight banks in a system. Signed-off-by: Aravind Gopalakrishnan Signed-off-by: Yazen Ghannam Signed-off-by: Borislav Petkov Cc: Andy Lutomirski Cc: Aravind Gopalakrishnan Cc: Borislav Petkov Cc: Brian Gerst Cc: Denys Vlasenko Cc: H. Peter Anvin Cc: Josh Poimboeuf Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: Tony Luck Cc: linux-edac Link: http://lkml.kernel.org/r/1467968983-4874-2-git-send-email-bp@alien8.de Signed-off-by: Ingo Molnar diff --git a/arch/x86/kernel/cpu/mcheck/mce_amd.c b/arch/x86/kernel/cpu/mcheck/mce_amd.c index 10b0661..7b7f3be 100644 --- a/arch/x86/kernel/cpu/mcheck/mce_amd.c +++ b/arch/x86/kernel/cpu/mcheck/mce_amd.c @@ -93,7 +93,7 @@ const char * const amd_df_mcablock_names[] = { EXPORT_SYMBOL_GPL(amd_df_mcablock_names); static DEFINE_PER_CPU(struct threshold_bank **, threshold_banks); -static DEFINE_PER_CPU(unsigned char, bank_map); /* see which banks are on */ +static DEFINE_PER_CPU(unsigned int, bank_map); /* see which banks are on */ static void amd_threshold_interrupt(void); static void amd_deferred_error_interrupt(void); -- cgit v0.10.2 From 340e983ab8afd02b59d698dd1365d7773bf136b3 Mon Sep 17 00:00:00 2001 From: Yazen Ghannam Date: Fri, 8 Jul 2016 11:09:39 +0200 Subject: x86/RAS/AMD: Reduce the number of IPIs when prepping error injection We currently use wrmsr_on_cpu() 4 times when prepping for an error injection. This will generate 4 IPIs for each MSR write. We can reduce the number of IPIs to 1 by grouping the MSR writes and executing them serially on the appropriate CPU. Suggested-by: Borislav Petkov Signed-off-by: Yazen Ghannam Signed-off-by: Borislav Petkov Cc: Andy Lutomirski Cc: Aravind Gopalakrishnan Cc: Borislav Petkov Cc: Brian Gerst Cc: Denys Vlasenko Cc: H. Peter Anvin Cc: Josh Poimboeuf Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: Tony Luck Cc: linux-edac Link: http://lkml.kernel.org/r/1467968983-4874-3-git-send-email-bp@alien8.de Signed-off-by: Ingo Molnar diff --git a/arch/x86/ras/mce_amd_inj.c b/arch/x86/ras/mce_amd_inj.c index e69f470..1104515 100644 --- a/arch/x86/ras/mce_amd_inj.c +++ b/arch/x86/ras/mce_amd_inj.c @@ -241,6 +241,31 @@ static void toggle_nb_mca_mst_cpu(u16 nid) __func__, PCI_FUNC(F3->devfn), NBCFG); } +static void prepare_msrs(void *info) +{ + struct mce i_mce = *(struct mce *)info; + u8 b = i_mce.bank; + + wrmsrl(MSR_IA32_MCG_STATUS, i_mce.mcgstatus); + + if (boot_cpu_has(X86_FEATURE_SMCA)) { + if (i_mce.inject_flags == DFR_INT_INJ) { + wrmsrl(MSR_AMD64_SMCA_MCx_DESTAT(b), i_mce.status); + wrmsrl(MSR_AMD64_SMCA_MCx_DEADDR(b), i_mce.addr); + } else { + wrmsrl(MSR_AMD64_SMCA_MCx_STATUS(b), i_mce.status); + wrmsrl(MSR_AMD64_SMCA_MCx_ADDR(b), i_mce.addr); + } + + wrmsrl(MSR_AMD64_SMCA_MCx_MISC(b), i_mce.misc); + } else { + wrmsrl(MSR_IA32_MCx_STATUS(b), i_mce.status); + wrmsrl(MSR_IA32_MCx_ADDR(b), i_mce.addr); + wrmsrl(MSR_IA32_MCx_MISC(b), i_mce.misc); + } + +} + static void do_inject(void) { u64 mcg_status = 0; @@ -287,36 +312,9 @@ static void do_inject(void) toggle_hw_mce_inject(cpu, true); - wrmsr_on_cpu(cpu, MSR_IA32_MCG_STATUS, - (u32)mcg_status, (u32)(mcg_status >> 32)); - - if (boot_cpu_has(X86_FEATURE_SMCA)) { - if (inj_type == DFR_INT_INJ) { - wrmsr_on_cpu(cpu, MSR_AMD64_SMCA_MCx_DESTAT(b), - (u32)i_mce.status, (u32)(i_mce.status >> 32)); - - wrmsr_on_cpu(cpu, MSR_AMD64_SMCA_MCx_DEADDR(b), - (u32)i_mce.addr, (u32)(i_mce.addr >> 32)); - } else { - wrmsr_on_cpu(cpu, MSR_AMD64_SMCA_MCx_STATUS(b), - (u32)i_mce.status, (u32)(i_mce.status >> 32)); - - wrmsr_on_cpu(cpu, MSR_AMD64_SMCA_MCx_ADDR(b), - (u32)i_mce.addr, (u32)(i_mce.addr >> 32)); - } - - wrmsr_on_cpu(cpu, MSR_AMD64_SMCA_MCx_MISC(b), - (u32)i_mce.misc, (u32)(i_mce.misc >> 32)); - } else { - wrmsr_on_cpu(cpu, MSR_IA32_MCx_STATUS(b), - (u32)i_mce.status, (u32)(i_mce.status >> 32)); - - wrmsr_on_cpu(cpu, MSR_IA32_MCx_ADDR(b), - (u32)i_mce.addr, (u32)(i_mce.addr >> 32)); - - wrmsr_on_cpu(cpu, MSR_IA32_MCx_MISC(b), - (u32)i_mce.misc, (u32)(i_mce.misc >> 32)); - } + i_mce.mcgstatus = mcg_status; + i_mce.inject_flags = inj_type; + smp_call_function_single(cpu, prepare_msrs, &i_mce, 0); toggle_hw_mce_inject(cpu, false); -- cgit v0.10.2 From 38c54ccb2ded3e93d8a353baeb7b9e12e1b77e23 Mon Sep 17 00:00:00 2001 From: Borislav Petkov Date: Fri, 8 Jul 2016 11:09:41 +0200 Subject: x86/mce: Fix mce_rdmsrl() warning message The MSR address we're dumping in there should be in hex, otherwise we get funsies like: [ 0.016000] WARNING: CPU: 1 PID: 0 at arch/x86/kernel/cpu/mcheck/mce.c:428 mce_rdmsrl+0xd9/0xe0 [ 0.016000] mce: Unable to read msr -1073733631! ^^^^^^^^^^^ Signed-off-by: Borislav Petkov Cc: Andy Lutomirski Cc: Borislav Petkov Cc: Brian Gerst Cc: Denys Vlasenko Cc: H. Peter Anvin Cc: Josh Poimboeuf Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: Tony Luck Link: http://lkml.kernel.org/r/1467968983-4874-5-git-send-email-bp@alien8.de [ Fixed capitalization of 'MSR'. ] Signed-off-by: Ingo Molnar diff --git a/arch/x86/kernel/cpu/mcheck/mce.c b/arch/x86/kernel/cpu/mcheck/mce.c index 92e5e37..58af630 100644 --- a/arch/x86/kernel/cpu/mcheck/mce.c +++ b/arch/x86/kernel/cpu/mcheck/mce.c @@ -425,7 +425,7 @@ static u64 mce_rdmsrl(u32 msr) } if (rdmsrl_safe(msr, &v)) { - WARN_ONCE(1, "mce: Unable to read msr %d!\n", msr); + WARN_ONCE(1, "mce: Unable to read MSR 0x%x!\n", msr); /* * Return zero in case the access faulted. This should * not happen normally but can happen if the CPU does -- cgit v0.10.2 From ef16dd0c2a523d2e3975bb1bea9f5727e3e7146f Mon Sep 17 00:00:00 2001 From: Andy Lutomirski Date: Tue, 5 Jul 2016 00:31:25 +0200 Subject: x86/dumpstack: Honor supplied @regs arg The comment suggests that show_stack(NULL, NULL) should backtrace the current context, but the code doesn't match the comment. If regs are given, start the "Stack:" hexdump at regs->sp. Signed-off-by: Andy Lutomirski Signed-off-by: Borislav Petkov Cc: Andrew Morton Cc: Andy Lutomirski Cc: Borislav Petkov Cc: Brian Gerst Cc: Denys Vlasenko Cc: Frederic Weisbecker Cc: H. Peter Anvin Cc: Josh Poimboeuf Cc: Kees Cook Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/1467671487-10344-2-git-send-email-bp@alien8.de Link: http://lkml.kernel.org/r/efcd79bf4106d61f1cd258c2caa87f3a0618eeac.1466036668.git.luto@kernel.org Signed-off-by: Ingo Molnar diff --git a/arch/x86/kernel/dumpstack_32.c b/arch/x86/kernel/dumpstack_32.c index fef917e..948d77d 100644 --- a/arch/x86/kernel/dumpstack_32.c +++ b/arch/x86/kernel/dumpstack_32.c @@ -96,7 +96,9 @@ show_stack_log_lvl(struct task_struct *task, struct pt_regs *regs, int i; if (sp == NULL) { - if (task) + if (regs) + sp = (unsigned long *)regs->sp; + else if (task) sp = (unsigned long *)task->thread.sp; else sp = (unsigned long *)&sp; diff --git a/arch/x86/kernel/dumpstack_64.c b/arch/x86/kernel/dumpstack_64.c index d558a8a..a81e1ef 100644 --- a/arch/x86/kernel/dumpstack_64.c +++ b/arch/x86/kernel/dumpstack_64.c @@ -264,7 +264,9 @@ show_stack_log_lvl(struct task_struct *task, struct pt_regs *regs, * back trace for this cpu: */ if (sp == NULL) { - if (task) + if (regs) + sp = (unsigned long *)regs->sp; + else if (task) sp = (unsigned long *)task->thread.sp; else sp = (unsigned long *)&sp; -- cgit v0.10.2 From 069f0cd00df0abfb9252e0dbdc355e40e6ab75fc Mon Sep 17 00:00:00 2001 From: Borislav Petkov Date: Tue, 5 Jul 2016 00:31:26 +0200 Subject: printk: Make the printk*once() variants return a value Have printk*once() return a bool which denotes whether the string was printed or not so that calling code can react accordingly. Signed-off-by: Borislav Petkov Cc: Andrew Morton Cc: Andy Lutomirski Cc: Andy Lutomirski Cc: Borislav Petkov Cc: Brian Gerst Cc: Denys Vlasenko Cc: Frederic Weisbecker Cc: H. Peter Anvin Cc: Josh Poimboeuf Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/1467671487-10344-3-git-send-email-bp@alien8.de Signed-off-by: Ingo Molnar diff --git a/include/linux/printk.h b/include/linux/printk.h index f4da695..f136b22 100644 --- a/include/linux/printk.h +++ b/include/linux/printk.h @@ -108,11 +108,14 @@ struct va_format { * Dummy printk for disabled debugging statements to use whilst maintaining * gcc's format checking. */ -#define no_printk(fmt, ...) \ -do { \ - if (0) \ - printk(fmt, ##__VA_ARGS__); \ -} while (0) +#define no_printk(fmt, ...) \ +({ \ + do { \ + if (0) \ + printk(fmt, ##__VA_ARGS__); \ + } while (0); \ + 0; \ +}) #ifdef CONFIG_EARLY_PRINTK extern asmlinkage __printf(1, 2) @@ -309,20 +312,24 @@ extern asmlinkage void dump_stack(void) __cold; #define printk_once(fmt, ...) \ ({ \ static bool __print_once __read_mostly; \ + bool __ret_print_once = !__print_once; \ \ if (!__print_once) { \ __print_once = true; \ printk(fmt, ##__VA_ARGS__); \ } \ + unlikely(__ret_print_once); \ }) #define printk_deferred_once(fmt, ...) \ ({ \ static bool __print_once __read_mostly; \ + bool __ret_print_once = !__print_once; \ \ if (!__print_once) { \ __print_once = true; \ printk_deferred(fmt, ##__VA_ARGS__); \ } \ + unlikely(__ret_print_once); \ }) #else #define printk_once(fmt, ...) \ -- cgit v0.10.2 From 81c2949f7fdcf8ff681326669afde24962232670 Mon Sep 17 00:00:00 2001 From: Borislav Petkov Date: Tue, 5 Jul 2016 00:31:27 +0200 Subject: x86/dumpstack: Add show_stack_regs() and use it Add a helper to dump supplied pt_regs and use it in the MSR exception handling code to have precise stack traces pointing to the actual function causing the MSR access exception and not the stack frame of the exception handler itself. The new output looks like this: unchecked MSR access error: RDMSR from 0xdeadbeef at rIP: 0xffffffff8102ddb6 (early_init_intel+0x16/0x3a0) 00000000756e6547 ffffffff81c03f68 ffffffff81dd0940 ffffffff81c03f10 ffffffff81d42e65 0000000001000000 ffffffff81c03f58 ffffffff81d3e5a3 0000800000000000 ffffffff81800080 ffffffffffffffff 0000000000000000 Call Trace: [] early_cpu_init+0xe7/0x136 [] setup_arch+0xa5/0x9df [] start_kernel+0x9f/0x43a [] x86_64_start_reservations+0x2f/0x31 [] x86_64_start_kernel+0x168/0x176 Signed-off-by: Borislav Petkov Reviewed-by: Andy Lutomirski Cc: Andrew Morton Cc: Andy Lutomirski Cc: Borislav Petkov Cc: Brian Gerst Cc: Denys Vlasenko Cc: Frederic Weisbecker Cc: H. Peter Anvin Cc: Josh Poimboeuf Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/1467671487-10344-4-git-send-email-bp@alien8.de Signed-off-by: Ingo Molnar diff --git a/arch/x86/include/asm/kdebug.h b/arch/x86/include/asm/kdebug.h index e5f5dc9..1ef9d58 100644 --- a/arch/x86/include/asm/kdebug.h +++ b/arch/x86/include/asm/kdebug.h @@ -26,6 +26,7 @@ extern void die(const char *, struct pt_regs *,long); extern int __must_check __die(const char *, struct pt_regs *, long); extern void show_trace(struct task_struct *t, struct pt_regs *regs, unsigned long *sp, unsigned long bp); +extern void show_stack_regs(struct pt_regs *regs); extern void __show_regs(struct pt_regs *regs, int all); extern unsigned long oops_begin(void); extern void oops_end(unsigned long, struct pt_regs *, int signr); diff --git a/arch/x86/kernel/dumpstack.c b/arch/x86/kernel/dumpstack.c index ef8017c..d66e5ac 100644 --- a/arch/x86/kernel/dumpstack.c +++ b/arch/x86/kernel/dumpstack.c @@ -197,6 +197,11 @@ void show_stack(struct task_struct *task, unsigned long *sp) show_stack_log_lvl(task, NULL, sp, bp, ""); } +void show_stack_regs(struct pt_regs *regs) +{ + show_stack_log_lvl(current, regs, (unsigned long *)regs->sp, regs->bp, ""); +} + static arch_spinlock_t die_lock = __ARCH_SPIN_LOCK_UNLOCKED; static int die_owner = -1; static unsigned int die_nest_count; diff --git a/arch/x86/mm/extable.c b/arch/x86/mm/extable.c index 4bb53b8..fafc771 100644 --- a/arch/x86/mm/extable.c +++ b/arch/x86/mm/extable.c @@ -1,6 +1,7 @@ #include #include #include +#include typedef bool (*ex_handler_t)(const struct exception_table_entry *, struct pt_regs *, int); @@ -46,8 +47,9 @@ EXPORT_SYMBOL(ex_handler_ext); bool ex_handler_rdmsr_unsafe(const struct exception_table_entry *fixup, struct pt_regs *regs, int trapnr) { - WARN_ONCE(1, "unchecked MSR access error: RDMSR from 0x%x\n", - (unsigned int)regs->cx); + if (pr_warn_once("unchecked MSR access error: RDMSR from 0x%x at rIP: 0x%lx (%pF)\n", + (unsigned int)regs->cx, regs->ip, (void *)regs->ip)) + show_stack_regs(regs); /* Pretend that the read succeeded and returned 0. */ regs->ip = ex_fixup_addr(fixup); @@ -60,9 +62,10 @@ EXPORT_SYMBOL(ex_handler_rdmsr_unsafe); bool ex_handler_wrmsr_unsafe(const struct exception_table_entry *fixup, struct pt_regs *regs, int trapnr) { - WARN_ONCE(1, "unchecked MSR access error: WRMSR to 0x%x (tried to write 0x%08x%08x)\n", - (unsigned int)regs->cx, - (unsigned int)regs->dx, (unsigned int)regs->ax); + if (pr_warn_once("unchecked MSR access error: WRMSR to 0x%x (tried to write 0x%08x%08x) at rIP: 0x%lx (%pF)\n", + (unsigned int)regs->cx, (unsigned int)regs->dx, + (unsigned int)regs->ax, regs->ip, (void *)regs->ip)) + show_stack_regs(regs); /* Pretend that the write succeeded. */ regs->ip = ex_fixup_addr(fixup); -- cgit v0.10.2 From 39380b80d72723282f0ea1d1bbf2294eae45013e Mon Sep 17 00:00:00 2001 From: Jiri Kosina Date: Fri, 8 Jul 2016 11:38:28 +0200 Subject: x86/mm/pat, /dev/mem: Remove superfluous error message Currently it's possible for broken (or malicious) userspace to flood a kernel log indefinitely with messages a-la Program dmidecode tried to access /dev/mem between f0000->100000 because range_is_allowed() is case of CONFIG_STRICT_DEVMEM being turned on dumps this information each and every time devmem_is_allowed() fails. Reportedly userspace that is able to trigger contignuous flow of these messages exists. It would be possible to rate limit this message, but that'd have a questionable value; the administrator wouldn't get information about all the failing accessess, so then the information would be both superfluous and incomplete at the same time :) Returning EPERM (which is what is actually happening) is enough indication for userspace what has happened; no need to log this particular error as some sort of special condition. Signed-off-by: Jiri Kosina Cc: Andrew Morton Cc: Andy Lutomirski Cc: Borislav Petkov Cc: Brian Gerst Cc: Denys Vlasenko Cc: H. Peter Anvin Cc: Josh Poimboeuf Cc: Kees Cook Cc: Linus Torvalds Cc: Luis R. Rodriguez Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: Toshi Kani Link: http://lkml.kernel.org/r/alpine.LNX.2.00.1607081137020.24757@cbobk.fhfr.pm Signed-off-by: Ingo Molnar diff --git a/arch/x86/mm/pat.c b/arch/x86/mm/pat.c index fb0604f..db00e3e 100644 --- a/arch/x86/mm/pat.c +++ b/arch/x86/mm/pat.c @@ -755,11 +755,8 @@ static inline int range_is_allowed(unsigned long pfn, unsigned long size) return 1; while (cursor < to) { - if (!devmem_is_allowed(pfn)) { - pr_info("x86/PAT: Program %s tried to access /dev/mem between [mem %#010Lx-%#010Lx], PAT prevents it\n", - current->comm, from, to - 1); + if (!devmem_is_allowed(pfn)) return 0; - } cursor += PAGE_SIZE; pfn++; } diff --git a/drivers/char/mem.c b/drivers/char/mem.c index 71025c2..d633974 100644 --- a/drivers/char/mem.c +++ b/drivers/char/mem.c @@ -66,12 +66,8 @@ static inline int range_is_allowed(unsigned long pfn, unsigned long size) u64 cursor = from; while (cursor < to) { - if (!devmem_is_allowed(pfn)) { - printk(KERN_INFO - "Program %s tried to access /dev/mem between %Lx->%Lx.\n", - current->comm, from, to); + if (!devmem_is_allowed(pfn)) return 0; - } cursor += PAGE_SIZE; pfn++; } -- cgit v0.10.2 From 7469be95a487319514adce2304ad2af3553d2fc9 Mon Sep 17 00:00:00 2001 From: Jan Beulich Date: Thu, 7 Jul 2016 01:32:04 -0600 Subject: xenbus: don't bail early from xenbus_dev_request_and_reply() xenbus_dev_request_and_reply() needs to track whether a transaction is open. For XS_TRANSACTION_START messages it calls transaction_start() and for XS_TRANSACTION_END messages it calls transaction_end(). If sending an XS_TRANSACTION_START message fails or responds with an an error, the transaction is not open and transaction_end() must be called. If sending an XS_TRANSACTION_END message fails, the transaction is still open, but if an error response is returned the transaction is closed. Commit 027bd7e89906 ("xen/xenbus: Avoid synchronous wait on XenBus stalling shutdown/restart") introduced a regression where failed XS_TRANSACTION_START messages were leaving the transaction open. This can cause problems with suspend (and migration) as all transactions must be closed before suspending. It appears that the problematic change was added accidentally, so just remove it. Signed-off-by: Jan Beulich Cc: Konrad Rzeszutek Wilk Cc: Signed-off-by: David Vrabel diff --git a/drivers/xen/xenbus/xenbus_xs.c b/drivers/xen/xenbus/xenbus_xs.c index 374b12a..0bd3d47 100644 --- a/drivers/xen/xenbus/xenbus_xs.c +++ b/drivers/xen/xenbus/xenbus_xs.c @@ -249,9 +249,6 @@ void *xenbus_dev_request_and_reply(struct xsd_sockmsg *msg) mutex_unlock(&xs_state.request_mutex); - if (IS_ERR(ret)) - return ret; - if ((msg->type == XS_TRANSACTION_END) || ((req_msg.type == XS_TRANSACTION_START) && (msg->type == XS_ERROR))) -- cgit v0.10.2 From e5a79475a7ae171fef82608c6e11f51bb85a6745 Mon Sep 17 00:00:00 2001 From: Jan Beulich Date: Thu, 7 Jul 2016 01:32:35 -0600 Subject: xenbus: simplify xenbus_dev_request_and_reply() No need to retain a local copy of the full request message, only the type is really needed. Signed-off-by: Jan Beulich Signed-off-by: David Vrabel diff --git a/drivers/xen/xenbus/xenbus_xs.c b/drivers/xen/xenbus/xenbus_xs.c index 0bd3d47..22f7cd7 100644 --- a/drivers/xen/xenbus/xenbus_xs.c +++ b/drivers/xen/xenbus/xenbus_xs.c @@ -232,10 +232,10 @@ static void transaction_resume(void) void *xenbus_dev_request_and_reply(struct xsd_sockmsg *msg) { void *ret; - struct xsd_sockmsg req_msg = *msg; + enum xsd_sockmsg_type type = msg->type; int err; - if (req_msg.type == XS_TRANSACTION_START) + if (type == XS_TRANSACTION_START) transaction_start(); mutex_lock(&xs_state.request_mutex); @@ -250,8 +250,7 @@ void *xenbus_dev_request_and_reply(struct xsd_sockmsg *msg) mutex_unlock(&xs_state.request_mutex); if ((msg->type == XS_TRANSACTION_END) || - ((req_msg.type == XS_TRANSACTION_START) && - (msg->type == XS_ERROR))) + ((type == XS_TRANSACTION_START) && (msg->type == XS_ERROR))) transaction_end(); return ret; -- cgit v0.10.2 From b059a453b1cf1c8453c2b2ed373d3147d6264ebd Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Tue, 28 Jun 2016 14:35:38 +0300 Subject: x86/vdso: Add mremap hook to vm_special_mapping Add possibility for 32-bit user-space applications to move the vDSO mapping. Previously, when a user-space app called mremap() for the vDSO address, in the syscall return path it would land on the previous address of the vDSOpage, resulting in segmentation violation. Now it lands fine and returns to userspace with a remapped vDSO. This will also fix the context.vdso pointer for 64-bit, which does not affect the user of vDSO after mremap() currently, but this may change in the future. As suggested by Andy, return -EINVAL for mremap() that would split the vDSO image: that operation cannot possibly result in a working system so reject it. Renamed and moved the text_mapping structure declaration inside map_vdso(), as it used only there and now it complements the vvar_mapping variable. There is still a problem for remapping the vDSO in glibc applications: the linker relocates addresses for syscalls on the vDSO page, so you need to relink with the new addresses. Without that the next syscall through glibc may fail: Program received signal SIGSEGV, Segmentation fault. #0 0xf7fd9b80 in __kernel_vsyscall () #1 0xf7ec8238 in _exit () from /usr/lib32/libc.so.6 Signed-off-by: Dmitry Safonov Acked-by: Andy Lutomirski Cc: 0x7f454c46@gmail.com Cc: Borislav Petkov Cc: Brian Gerst Cc: Denys Vlasenko Cc: H. Peter Anvin Cc: Josh Poimboeuf Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: linux-mm@kvack.org Link: http://lkml.kernel.org/r/20160628113539.13606-2-dsafonov@virtuozzo.com Signed-off-by: Ingo Molnar diff --git a/arch/x86/entry/vdso/vma.c b/arch/x86/entry/vdso/vma.c index ab220ac..3329844 100644 --- a/arch/x86/entry/vdso/vma.c +++ b/arch/x86/entry/vdso/vma.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -97,10 +98,40 @@ static int vdso_fault(const struct vm_special_mapping *sm, return 0; } -static const struct vm_special_mapping text_mapping = { - .name = "[vdso]", - .fault = vdso_fault, -}; +static void vdso_fix_landing(const struct vdso_image *image, + struct vm_area_struct *new_vma) +{ +#if defined CONFIG_X86_32 || defined CONFIG_IA32_EMULATION + if (in_ia32_syscall() && image == &vdso_image_32) { + struct pt_regs *regs = current_pt_regs(); + unsigned long vdso_land = image->sym_int80_landing_pad; + unsigned long old_land_addr = vdso_land + + (unsigned long)current->mm->context.vdso; + + /* Fixing userspace landing - look at do_fast_syscall_32 */ + if (regs->ip == old_land_addr) + regs->ip = new_vma->vm_start + vdso_land; + } +#endif +} + +static int vdso_mremap(const struct vm_special_mapping *sm, + struct vm_area_struct *new_vma) +{ + unsigned long new_size = new_vma->vm_end - new_vma->vm_start; + const struct vdso_image *image = current->mm->context.vdso_image; + + if (image->size != new_size) + return -EINVAL; + + if (WARN_ON_ONCE(current->mm != new_vma->vm_mm)) + return -EFAULT; + + vdso_fix_landing(image, new_vma); + current->mm->context.vdso = (void __user *)new_vma->vm_start; + + return 0; +} static int vvar_fault(const struct vm_special_mapping *sm, struct vm_area_struct *vma, struct vm_fault *vmf) @@ -151,6 +182,12 @@ static int map_vdso(const struct vdso_image *image, bool calculate_addr) struct vm_area_struct *vma; unsigned long addr, text_start; int ret = 0; + + static const struct vm_special_mapping vdso_mapping = { + .name = "[vdso]", + .fault = vdso_fault, + .mremap = vdso_mremap, + }; static const struct vm_special_mapping vvar_mapping = { .name = "[vvar]", .fault = vvar_fault, @@ -185,7 +222,7 @@ static int map_vdso(const struct vdso_image *image, bool calculate_addr) image->size, VM_READ|VM_EXEC| VM_MAYREAD|VM_MAYWRITE|VM_MAYEXEC, - &text_mapping); + &vdso_mapping); if (IS_ERR(vma)) { ret = PTR_ERR(vma); diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h index ca3e517..917f2b6 100644 --- a/include/linux/mm_types.h +++ b/include/linux/mm_types.h @@ -594,6 +594,9 @@ struct vm_special_mapping { int (*fault)(const struct vm_special_mapping *sm, struct vm_area_struct *vma, struct vm_fault *vmf); + + int (*mremap)(const struct vm_special_mapping *sm, + struct vm_area_struct *new_vma); }; enum tlb_flush_reason { diff --git a/mm/mmap.c b/mm/mmap.c index de2c176..234edff 100644 --- a/mm/mmap.c +++ b/mm/mmap.c @@ -2943,9 +2943,19 @@ static const char *special_mapping_name(struct vm_area_struct *vma) return ((struct vm_special_mapping *)vma->vm_private_data)->name; } +static int special_mapping_mremap(struct vm_area_struct *new_vma) +{ + struct vm_special_mapping *sm = new_vma->vm_private_data; + + if (sm->mremap) + return sm->mremap(sm, new_vma); + return 0; +} + static const struct vm_operations_struct special_mapping_vmops = { .close = special_mapping_close, .fault = special_mapping_fault, + .mremap = special_mapping_mremap, .name = special_mapping_name, }; -- cgit v0.10.2 From f80fd3a5fff88a9ace7e8cd11d07cf874a63ea9f Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Tue, 28 Jun 2016 14:35:39 +0300 Subject: selftests/x86: Add vDSO mremap() test Should print this on vDSO remapping success (on new kernels): [root@localhost ~]# ./test_mremap_vdso_32 AT_SYSINFO_EHDR is 0xf773f000 [NOTE] Moving vDSO: [f773f000, f7740000] -> [a000000, a001000] [OK] Or print that mremap() for vDSOs is unsupported: [root@localhost ~]# ./test_mremap_vdso_32 AT_SYSINFO_EHDR is 0xf773c000 [NOTE] Moving vDSO: [0xf773c000, 0xf773d000] -> [0xf7737000, 0xf7738000] [FAIL] mremap() of the vDSO does not work on this kernel! Suggested-by: Andy Lutomirski Signed-off-by: Dmitry Safonov Acked-by: Andy Lutomirski Cc: 0x7f454c46@gmail.com Cc: Borislav Petkov Cc: Brian Gerst Cc: Denys Vlasenko Cc: H. Peter Anvin Cc: Josh Poimboeuf Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Shuah Khan Cc: Thomas Gleixner Cc: linux-kselftest@vger.kernel.org Cc: linux-mm@kvack.org Link: http://lkml.kernel.org/r/20160628113539.13606-3-dsafonov@virtuozzo.com Signed-off-by: Ingo Molnar diff --git a/tools/testing/selftests/x86/Makefile b/tools/testing/selftests/x86/Makefile index c73425d..543a6d0 100644 --- a/tools/testing/selftests/x86/Makefile +++ b/tools/testing/selftests/x86/Makefile @@ -4,7 +4,7 @@ include ../lib.mk .PHONY: all all_32 all_64 warn_32bit_failure clean -TARGETS_C_BOTHBITS := single_step_syscall sysret_ss_attrs syscall_nt ptrace_syscall \ +TARGETS_C_BOTHBITS := single_step_syscall sysret_ss_attrs syscall_nt ptrace_syscall test_mremap_vdso \ check_initial_reg_state sigreturn ldt_gdt iopl TARGETS_C_32BIT_ONLY := entry_from_vm86 syscall_arg_fault test_syscall_vdso unwind_vdso \ test_FCMOV test_FCOMI test_FISTTP \ diff --git a/tools/testing/selftests/x86/test_mremap_vdso.c b/tools/testing/selftests/x86/test_mremap_vdso.c new file mode 100644 index 0000000..bf0d687 --- /dev/null +++ b/tools/testing/selftests/x86/test_mremap_vdso.c @@ -0,0 +1,111 @@ +/* + * 32-bit test to check vDSO mremap. + * + * Copyright (c) 2016 Dmitry Safonov + * Suggested-by: Andrew Lutomirski + * + * This program is free software; you can redistribute it and/or modify + * it under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ +/* + * Can be built statically: + * gcc -Os -Wall -static -m32 test_mremap_vdso.c + */ +#define _GNU_SOURCE +#include +#include +#include +#include + +#include +#include +#include +#include + +#define PAGE_SIZE 4096 + +static int try_to_remap(void *vdso_addr, unsigned long size) +{ + void *dest_addr, *new_addr; + + /* Searching for memory location where to remap */ + dest_addr = mmap(0, size, PROT_NONE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); + if (dest_addr == MAP_FAILED) { + printf("[WARN]\tmmap failed (%d): %m\n", errno); + return 0; + } + + printf("[NOTE]\tMoving vDSO: [%p, %#lx] -> [%p, %#lx]\n", + vdso_addr, (unsigned long)vdso_addr + size, + dest_addr, (unsigned long)dest_addr + size); + fflush(stdout); + + new_addr = mremap(vdso_addr, size, size, + MREMAP_FIXED|MREMAP_MAYMOVE, dest_addr); + if ((unsigned long)new_addr == (unsigned long)-1) { + munmap(dest_addr, size); + if (errno == EINVAL) { + printf("[NOTE]\tvDSO partial move failed, will try with bigger size\n"); + return -1; /* Retry with larger */ + } + printf("[FAIL]\tmremap failed (%d): %m\n", errno); + return 1; + } + + return 0; + +} + +int main(int argc, char **argv, char **envp) +{ + pid_t child; + + child = fork(); + if (child == -1) { + printf("[WARN]\tfailed to fork (%d): %m\n", errno); + return 1; + } + + if (child == 0) { + unsigned long vdso_size = PAGE_SIZE; + unsigned long auxval; + int ret = -1; + + auxval = getauxval(AT_SYSINFO_EHDR); + printf("\tAT_SYSINFO_EHDR is %#lx\n", auxval); + if (!auxval || auxval == -ENOENT) { + printf("[WARN]\tgetauxval failed\n"); + return 0; + } + + /* Simpler than parsing ELF header */ + while (ret < 0) { + ret = try_to_remap((void *)auxval, vdso_size); + vdso_size += PAGE_SIZE; + } + + /* Glibc is likely to explode now - exit with raw syscall */ + asm volatile ("int $0x80" : : "a" (__NR_exit), "b" (!!ret)); + } else { + int status; + + if (waitpid(child, &status, 0) != child || + !WIFEXITED(status)) { + printf("[FAIL]\tmremap() of the vDSO does not work on this kernel!\n"); + return 1; + } else if (WEXITSTATUS(status) != 0) { + printf("[FAIL]\tChild failed with %d\n", + WEXITSTATUS(status)); + return 1; + } + printf("[OK]\n"); + } + + return 0; +} -- cgit v0.10.2 From 6daa2ec0b3e3808c55329d12de3c157cf38b17b0 Mon Sep 17 00:00:00 2001 From: Baoquan He Date: Fri, 1 Jul 2016 15:34:40 +0800 Subject: x86/KASLR: Fix boot crash with certain memory configurations Ye Xiaolong reported this boot crash: | | XZ-compressed data is corrupt | | -- System halted | Fix the bug in mem_avoid_overlap() of finding the earliest overlap. Reported-and-tested-by: Ye Xiaolong Signed-off-by: Baoquan He Cc: Kees Cook Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: linux-kernel@vger.kernel.org Signed-off-by: Ingo Molnar diff --git a/arch/x86/boot/compressed/kaslr.c b/arch/x86/boot/compressed/kaslr.c index 749c9e0..010ea16 100644 --- a/arch/x86/boot/compressed/kaslr.c +++ b/arch/x86/boot/compressed/kaslr.c @@ -285,6 +285,7 @@ static bool mem_avoid_overlap(struct mem_vector *img, if (mem_overlaps(img, &mem_avoid[i]) && mem_avoid[i].start < earliest) { *overlap = mem_avoid[i]; + earliest = overlap->start; is_overlapping = true; } } @@ -299,6 +300,7 @@ static bool mem_avoid_overlap(struct mem_vector *img, if (mem_overlaps(img, &avoid) && (avoid.start < earliest)) { *overlap = avoid; + earliest = overlap->start; is_overlapping = true; } -- cgit v0.10.2 From c8607e020014cf11a61601a0005270bad81cabdf Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Wed, 6 Jul 2016 14:53:06 +0200 Subject: netfilter: nft_ct: fix expiration getter We need to compute timeout.expires - jiffies, not the other way around. Add a helper, another patch can then later change more places in conntrack code where we currently open-code this. Will allow us to only change one place later when we remove per-ct timer. Signed-off-by: Florian Westphal Signed-off-by: Pablo Neira Ayuso diff --git a/include/net/netfilter/nf_conntrack.h b/include/net/netfilter/nf_conntrack.h index dd78bea..b6083c3 100644 --- a/include/net/netfilter/nf_conntrack.h +++ b/include/net/netfilter/nf_conntrack.h @@ -284,6 +284,14 @@ static inline bool nf_is_loopback_packet(const struct sk_buff *skb) return skb->dev && skb->skb_iif && skb->dev->flags & IFF_LOOPBACK; } +/* jiffies until ct expires, 0 if already expired */ +static inline unsigned long nf_ct_expires(const struct nf_conn *ct) +{ + long timeout = (long)ct->timeout.expires - (long)jiffies; + + return timeout > 0 ? timeout : 0; +} + struct kernel_param; int nf_conntrack_set_hashsize(const char *val, struct kernel_param *kp); diff --git a/net/netfilter/nft_ct.c b/net/netfilter/nft_ct.c index 137e308..81fbb45 100644 --- a/net/netfilter/nft_ct.c +++ b/net/netfilter/nft_ct.c @@ -54,7 +54,6 @@ static void nft_ct_get_eval(const struct nft_expr *expr, const struct nf_conn_help *help; const struct nf_conntrack_tuple *tuple; const struct nf_conntrack_helper *helper; - long diff; unsigned int state; ct = nf_ct_get(pkt->skb, &ctinfo); @@ -94,10 +93,7 @@ static void nft_ct_get_eval(const struct nft_expr *expr, return; #endif case NFT_CT_EXPIRATION: - diff = (long)jiffies - (long)ct->timeout.expires; - if (diff < 0) - diff = 0; - *dest = jiffies_to_msecs(diff); + *dest = jiffies_to_msecs(nf_ct_expires(ct)); return; case NFT_CT_HELPER: if (ct->master == NULL) -- cgit v0.10.2 From 7fb2b43c3252c9177825a0a49138cd16144b6b5e Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Mon, 27 Jun 2016 12:49:20 +0200 Subject: efi: Reorganize the GUID table to make it easier to read Re-organize the GUID table so that every GUID takes a single line. This makes each line super long, but if you have a large enough terminal (or zoom out of a small terminal) then you can see the structure at a glance - which is more readable than it was the case with the multi-line layout. Acked-by: Matt Fleming Cc: Ard Biesheuvel Cc: Joe Perches Cc: Linus Torvalds Cc: Peter Jones Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: linux-efi@vger.kernel.org Link: http://lkml.kernel.org/r/20160627104920.GA9099@gmail.com Signed-off-by: Ingo Molnar diff --git a/include/linux/efi.h b/include/linux/efi.h index 0174f28..7f80a75 100644 --- a/include/linux/efi.h +++ b/include/linux/efi.h @@ -538,9 +538,11 @@ void efi_native_runtime_setup(void); /* * EFI Configuration Table and GUID definitions * - * These should be formatted roughly like the ones in the UEFI SPEC has - * them. It makes them easier to grep for, and they look the same when - * you're staring at them. Here's the guide: + * These are all defined in a single line to make them easier to + * grep for and to see them at a glance - while still having a + * similar structure to the definitions in the spec. + * + * Here's how they are structured: * * GUID: 12345678-1234-1234-1234-123456789012 * Spec: @@ -548,119 +550,44 @@ void efi_native_runtime_setup(void); * {0x12345678,0x1234,0x1234,\ * {0x12,0x34,0x12,0x34,0x56,0x78,0x90,0x12}} * Here: - * #define SOME_PROTOCOL_GUID \ - * EFI_GUID(0x12345678, 0x1234, 0x1234, \ - * 0x12, 0x34, 0x12, 0x34, 0x56, 0x78, 0x90, 0x12) - * ^ tab ^tab ^ space + * #define SOME_PROTOCOL_GUID EFI_GUID(0x12345678, 0x1234, 0x1234, 0x12, 0x34, 0x12, 0x34, 0x56, 0x78, 0x90, 0x12) + * ^ tabs ^extra space + * + * Note that the 'extra space' separates the values at the same place + * where the UEFI SPEC breaks the line. */ -#define NULL_GUID \ - EFI_GUID(0x00000000, 0x0000, 0x0000, \ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00) - -#define MPS_TABLE_GUID \ - EFI_GUID(0xeb9d2d2f, 0x2d88, 0x11d3, \ - 0x9a, 0x16, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d) - -#define ACPI_TABLE_GUID \ - EFI_GUID(0xeb9d2d30, 0x2d88, 0x11d3, \ - 0x9a, 0x16, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d) - -#define ACPI_20_TABLE_GUID \ - EFI_GUID(0x8868e871, 0xe4f1, 0x11d3, \ - 0xbc, 0x22, 0x00, 0x80, 0xc7, 0x3c, 0x88, 0x81) - -#define SMBIOS_TABLE_GUID \ - EFI_GUID(0xeb9d2d31, 0x2d88, 0x11d3, \ - 0x9a, 0x16, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d) - -#define SMBIOS3_TABLE_GUID \ - EFI_GUID(0xf2fd1544, 0x9794, 0x4a2c, \ - 0x99, 0x2e, 0xe5, 0xbb, 0xcf, 0x20, 0xe3, 0x94) - -#define SAL_SYSTEM_TABLE_GUID \ - EFI_GUID(0xeb9d2d32, 0x2d88, 0x11d3, \ - 0x9a, 0x16, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d) - -#define HCDP_TABLE_GUID \ - EFI_GUID(0xf951938d, 0x620b, 0x42ef, \ - 0x82, 0x79, 0xa8, 0x4b, 0x79, 0x61, 0x78, 0x98) - -#define UGA_IO_PROTOCOL_GUID \ - EFI_GUID(0x61a4d49e, 0x6f68, 0x4f1b, \ - 0xb9, 0x22, 0xa8, 0x6e, 0xed, 0x0b, 0x07, 0xa2) - -#define EFI_GLOBAL_VARIABLE_GUID \ - EFI_GUID(0x8be4df61, 0x93ca, 0x11d2, \ - 0xaa, 0x0d, 0x00, 0xe0, 0x98, 0x03, 0x2b, 0x8c) - -#define UV_SYSTEM_TABLE_GUID \ - EFI_GUID(0x3b13a7d4, 0x633e, 0x11dd, \ - 0x93, 0xec, 0xda, 0x25, 0x56, 0xd8, 0x95, 0x93) - -#define LINUX_EFI_CRASH_GUID \ - EFI_GUID(0xcfc8fc79, 0xbe2e, 0x4ddc, \ - 0x97, 0xf0, 0x9f, 0x98, 0xbf, 0xe2, 0x98, 0xa0) - -#define LOADED_IMAGE_PROTOCOL_GUID \ - EFI_GUID(0x5b1b31a1, 0x9562, 0x11d2, \ - 0x8e, 0x3f, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b) - -#define EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID \ - EFI_GUID(0x9042a9de, 0x23dc, 0x4a38, \ - 0x96, 0xfb, 0x7a, 0xde, 0xd0, 0x80, 0x51, 0x6a) - -#define EFI_UGA_PROTOCOL_GUID \ - EFI_GUID(0x982c298b, 0xf4fa, 0x41cb, \ - 0xb8, 0x38, 0x77, 0xaa, 0x68, 0x8f, 0xb8, 0x39) - -#define EFI_PCI_IO_PROTOCOL_GUID \ - EFI_GUID(0x4cf5b200, 0x68b8, 0x4ca5, \ - 0x9e, 0xec, 0xb2, 0x3e, 0x3f, 0x50, 0x02, 0x9a) - -#define EFI_FILE_INFO_ID \ - EFI_GUID(0x9576e92, 0x6d3f, 0x11d2, \ - 0x8e, 0x39, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b) - -#define EFI_SYSTEM_RESOURCE_TABLE_GUID \ - EFI_GUID(0xb122a263, 0x3661, 0x4f68, \ - 0x99, 0x29, 0x78, 0xf8, 0xb0, 0xd6, 0x21, 0x80) - -#define EFI_FILE_SYSTEM_GUID \ - EFI_GUID(0x964e5b22, 0x6459, 0x11d2, \ - 0x8e, 0x39, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b) - -#define DEVICE_TREE_GUID \ - EFI_GUID(0xb1b621d5, 0xf19c, 0x41a5, \ - 0x83, 0x0b, 0xd9, 0x15, 0x2c, 0x69, 0xaa, 0xe0) - -#define EFI_PROPERTIES_TABLE_GUID \ - EFI_GUID(0x880aaca3, 0x4adc, 0x4a04, \ - 0x90, 0x79, 0xb7, 0x47, 0x34, 0x08, 0x25, 0xe5) - -#define EFI_RNG_PROTOCOL_GUID \ - EFI_GUID(0x3152bca5, 0xeade, 0x433d, \ - 0x86, 0x2e, 0xc0, 0x1c, 0xdc, 0x29, 0x1f, 0x44) - -#define EFI_MEMORY_ATTRIBUTES_TABLE_GUID \ - EFI_GUID(0xdcfa911d, 0x26eb, 0x469f, \ - 0xa2, 0x20, 0x38, 0xb7, 0xdc, 0x46, 0x12, 0x20) - -#define EFI_CONSOLE_OUT_DEVICE_GUID \ - EFI_GUID(0xd3b36f2c, 0xd551, 0x11d4, \ - 0x9a, 0x46, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d) +#define NULL_GUID EFI_GUID(0x00000000, 0x0000, 0x0000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00) +#define MPS_TABLE_GUID EFI_GUID(0xeb9d2d2f, 0x2d88, 0x11d3, 0x9a, 0x16, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d) +#define ACPI_TABLE_GUID EFI_GUID(0xeb9d2d30, 0x2d88, 0x11d3, 0x9a, 0x16, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d) +#define ACPI_20_TABLE_GUID EFI_GUID(0x8868e871, 0xe4f1, 0x11d3, 0xbc, 0x22, 0x00, 0x80, 0xc7, 0x3c, 0x88, 0x81) +#define SMBIOS_TABLE_GUID EFI_GUID(0xeb9d2d31, 0x2d88, 0x11d3, 0x9a, 0x16, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d) +#define SMBIOS3_TABLE_GUID EFI_GUID(0xf2fd1544, 0x9794, 0x4a2c, 0x99, 0x2e, 0xe5, 0xbb, 0xcf, 0x20, 0xe3, 0x94) +#define SAL_SYSTEM_TABLE_GUID EFI_GUID(0xeb9d2d32, 0x2d88, 0x11d3, 0x9a, 0x16, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d) +#define HCDP_TABLE_GUID EFI_GUID(0xf951938d, 0x620b, 0x42ef, 0x82, 0x79, 0xa8, 0x4b, 0x79, 0x61, 0x78, 0x98) +#define UGA_IO_PROTOCOL_GUID EFI_GUID(0x61a4d49e, 0x6f68, 0x4f1b, 0xb9, 0x22, 0xa8, 0x6e, 0xed, 0x0b, 0x07, 0xa2) +#define EFI_GLOBAL_VARIABLE_GUID EFI_GUID(0x8be4df61, 0x93ca, 0x11d2, 0xaa, 0x0d, 0x00, 0xe0, 0x98, 0x03, 0x2b, 0x8c) +#define UV_SYSTEM_TABLE_GUID EFI_GUID(0x3b13a7d4, 0x633e, 0x11dd, 0x93, 0xec, 0xda, 0x25, 0x56, 0xd8, 0x95, 0x93) +#define LINUX_EFI_CRASH_GUID EFI_GUID(0xcfc8fc79, 0xbe2e, 0x4ddc, 0x97, 0xf0, 0x9f, 0x98, 0xbf, 0xe2, 0x98, 0xa0) +#define LOADED_IMAGE_PROTOCOL_GUID EFI_GUID(0x5b1b31a1, 0x9562, 0x11d2, 0x8e, 0x3f, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b) +#define EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID EFI_GUID(0x9042a9de, 0x23dc, 0x4a38, 0x96, 0xfb, 0x7a, 0xde, 0xd0, 0x80, 0x51, 0x6a) +#define EFI_UGA_PROTOCOL_GUID EFI_GUID(0x982c298b, 0xf4fa, 0x41cb, 0xb8, 0x38, 0x77, 0xaa, 0x68, 0x8f, 0xb8, 0x39) +#define EFI_PCI_IO_PROTOCOL_GUID EFI_GUID(0x4cf5b200, 0x68b8, 0x4ca5, 0x9e, 0xec, 0xb2, 0x3e, 0x3f, 0x50, 0x02, 0x9a) +#define EFI_FILE_INFO_ID EFI_GUID(0x09576e92, 0x6d3f, 0x11d2, 0x8e, 0x39, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b) +#define EFI_SYSTEM_RESOURCE_TABLE_GUID EFI_GUID(0xb122a263, 0x3661, 0x4f68, 0x99, 0x29, 0x78, 0xf8, 0xb0, 0xd6, 0x21, 0x80) +#define EFI_FILE_SYSTEM_GUID EFI_GUID(0x964e5b22, 0x6459, 0x11d2, 0x8e, 0x39, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b) +#define DEVICE_TREE_GUID EFI_GUID(0xb1b621d5, 0xf19c, 0x41a5, 0x83, 0x0b, 0xd9, 0x15, 0x2c, 0x69, 0xaa, 0xe0) +#define EFI_PROPERTIES_TABLE_GUID EFI_GUID(0x880aaca3, 0x4adc, 0x4a04, 0x90, 0x79, 0xb7, 0x47, 0x34, 0x08, 0x25, 0xe5) +#define EFI_RNG_PROTOCOL_GUID EFI_GUID(0x3152bca5, 0xeade, 0x433d, 0x86, 0x2e, 0xc0, 0x1c, 0xdc, 0x29, 0x1f, 0x44) +#define EFI_MEMORY_ATTRIBUTES_TABLE_GUID EFI_GUID(0xdcfa911d, 0x26eb, 0x469f, 0xa2, 0x20, 0x38, 0xb7, 0xdc, 0x46, 0x12, 0x20) +#define EFI_CONSOLE_OUT_DEVICE_GUID EFI_GUID(0xd3b36f2c, 0xd551, 0x11d4, 0x9a, 0x46, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d) /* * This GUID is used to pass to the kernel proper the struct screen_info * structure that was populated by the stub based on the GOP protocol instance * associated with ConOut */ -#define LINUX_EFI_ARM_SCREEN_INFO_TABLE_GUID \ - EFI_GUID(0xe03fc20a, 0x85dc, 0x406e, \ - 0xb9, 0xe, 0x4a, 0xb5, 0x02, 0x37, 0x1d, 0x95) - -#define LINUX_EFI_LOADER_ENTRY_GUID \ - EFI_GUID(0x4a67b082, 0x0a4c, 0x41cf, \ - 0xb6, 0xc7, 0x44, 0x0b, 0x29, 0xbb, 0x8c, 0x4f) +#define LINUX_EFI_ARM_SCREEN_INFO_TABLE_GUID EFI_GUID(0xe03fc20a, 0x85dc, 0x406e, 0xb9, 0x0e, 0x4a, 0xb5, 0x02, 0x37, 0x1d, 0x95) +#define LINUX_EFI_LOADER_ENTRY_GUID EFI_GUID(0x4a67b082, 0x0a4c, 0x41cf, 0xb6, 0xc7, 0x44, 0x0b, 0x29, 0xbb, 0x8c, 0x4f) typedef struct { efi_guid_t guid; -- cgit v0.10.2 From 6f2d9d99213514360034c6d52d2c3919290b3504 Mon Sep 17 00:00:00 2001 From: Jan Beulich Date: Fri, 8 Jul 2016 06:15:07 -0600 Subject: xen/acpi: allow xen-acpi-processor driver to load on Xen 4.7 As of Xen 4.7 PV CPUID doesn't expose either of CPUID[1].ECX[7] and CPUID[0x80000007].EDX[7] anymore, causing the driver to fail to load on both Intel and AMD systems. Doing any kind of hardware capability checks in the driver as a prerequisite was wrong anyway: With the hypervisor being in charge, all such checking should be done by it. If ACPI data gets uploaded despite some missing capability, the hypervisor is free to ignore part or all of that data. Ditch the entire check_prereq() function, and do the only valid check (xen_initial_domain()) in the caller in its place. Signed-off-by: Jan Beulich Cc: Signed-off-by: David Vrabel diff --git a/drivers/xen/xen-acpi-processor.c b/drivers/xen/xen-acpi-processor.c index 076970a..4ce10bc 100644 --- a/drivers/xen/xen-acpi-processor.c +++ b/drivers/xen/xen-acpi-processor.c @@ -423,36 +423,7 @@ upload: return 0; } -static int __init check_prereq(void) -{ - struct cpuinfo_x86 *c = &cpu_data(0); - - if (!xen_initial_domain()) - return -ENODEV; - - if (!acpi_gbl_FADT.smi_command) - return -ENODEV; - - if (c->x86_vendor == X86_VENDOR_INTEL) { - if (!cpu_has(c, X86_FEATURE_EST)) - return -ENODEV; - return 0; - } - if (c->x86_vendor == X86_VENDOR_AMD) { - /* Copied from powernow-k8.h, can't include ../cpufreq/powernow - * as we get compile warnings for the static functions. - */ -#define CPUID_FREQ_VOLT_CAPABILITIES 0x80000007 -#define USE_HW_PSTATE 0x00000080 - u32 eax, ebx, ecx, edx; - cpuid(CPUID_FREQ_VOLT_CAPABILITIES, &eax, &ebx, &ecx, &edx); - if ((edx & USE_HW_PSTATE) != USE_HW_PSTATE) - return -ENODEV; - return 0; - } - return -ENODEV; -} /* acpi_perf_data is a pointer to percpu data. */ static struct acpi_processor_performance __percpu *acpi_perf_data; @@ -509,10 +480,10 @@ struct notifier_block xen_acpi_processor_resume_nb = { static int __init xen_acpi_processor_init(void) { unsigned int i; - int rc = check_prereq(); + int rc; - if (rc) - return rc; + if (!xen_initial_domain()) + return -ENODEV; nr_acpi_bits = get_max_acpi_id() + 1; acpi_ids_done = kcalloc(BITS_TO_LONGS(nr_acpi_bits), sizeof(unsigned long), GFP_KERNEL); -- cgit v0.10.2 From 9a7e7b571826c4399aa639af4a670642d96d935c Mon Sep 17 00:00:00 2001 From: Borislav Petkov Date: Fri, 8 Jul 2016 16:01:48 +0200 Subject: x86/asm/entry: Make thunk's restore a local label No need to have it appear in objdump output. No functionality change. Signed-off-by: Borislav Petkov Cc: Andy Lutomirski Cc: Borislav Petkov Cc: Brian Gerst Cc: Denys Vlasenko Cc: H. Peter Anvin Cc: Josh Poimboeuf Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/20160708141016.GH3808@pd.tnic Signed-off-by: Ingo Molnar diff --git a/arch/x86/entry/thunk_64.S b/arch/x86/entry/thunk_64.S index 027aec4..627ecbc 100644 --- a/arch/x86/entry/thunk_64.S +++ b/arch/x86/entry/thunk_64.S @@ -33,7 +33,7 @@ .endif call \func - jmp restore + jmp .L_restore _ASM_NOKPROBE(\name) .endm @@ -54,7 +54,7 @@ #if defined(CONFIG_TRACE_IRQFLAGS) \ || defined(CONFIG_DEBUG_LOCK_ALLOC) \ || defined(CONFIG_PREEMPT) -restore: +.L_restore: popq %r11 popq %r10 popq %r9 @@ -66,5 +66,5 @@ restore: popq %rdi popq %rbp ret - _ASM_NOKPROBE(restore) + _ASM_NOKPROBE(.L_restore) #endif -- cgit v0.10.2 From 58541f7a6458e17ab417321b284f0090f530aa91 Mon Sep 17 00:00:00 2001 From: Sinclair Yeh Date: Thu, 7 Jul 2016 11:01:30 -0700 Subject: drm/vmwgfx: Fix error paths when mapping framebuffer Rather than returning immediately, make sure to unlock the mutexes first. Signed-off-by: Sinclair Yeh Reviewed-by: Charmaine Lee Reported-by: Emil Velikov Cc: diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c b/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c index 66eaa30..d2d9395 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c @@ -589,7 +589,7 @@ static int vmw_fb_set_par(struct fb_info *info) ret = vfb->pin(vfb); if (ret) { DRM_ERROR("Could not pin the fbdev framebuffer.\n"); - return ret; + goto out_unlock; } ret = ttm_bo_kmap(&par->vmw_bo->base, 0, @@ -597,7 +597,7 @@ static int vmw_fb_set_par(struct fb_info *info) if (ret) { vfb->unpin(vfb); DRM_ERROR("Could not map the fbdev framebuffer.\n"); - return ret; + goto out_unlock; } par->bo_ptr = ttm_kmap_obj_virtual(&par->map, &par->bo_iowrite); -- cgit v0.10.2 From d899a7d146a2ed8a7e6c2f61bcd232908bcbaabc Mon Sep 17 00:00:00 2001 From: Thomas Garnier Date: Tue, 21 Jun 2016 17:46:58 -0700 Subject: x86/mm: Refactor KASLR entropy functions Move the KASLR entropy functions into arch/x86/lib to be used in early kernel boot for KASLR memory randomization. Signed-off-by: Thomas Garnier Signed-off-by: Kees Cook Cc: Alexander Kuleshov Cc: Alexander Popov Cc: Andrew Morton Cc: Andy Lutomirski Cc: Aneesh Kumar K.V Cc: Baoquan He Cc: Boris Ostrovsky Cc: Borislav Petkov Cc: Borislav Petkov Cc: Brian Gerst Cc: Christian Borntraeger Cc: Dan Williams Cc: Dave Hansen Cc: Dave Young Cc: Denys Vlasenko Cc: Dmitry Vyukov Cc: H. Peter Anvin Cc: Jan Beulich Cc: Joerg Roedel Cc: Jonathan Corbet Cc: Josh Poimboeuf Cc: Juergen Gross Cc: Kirill A. Shutemov Cc: Linus Torvalds Cc: Lv Zheng Cc: Mark Salter Cc: Martin Schwidefsky Cc: Matt Fleming Cc: Peter Zijlstra Cc: Stephen Smalley Cc: Thomas Gleixner Cc: Toshi Kani Cc: Xiao Guangrong Cc: Yinghai Lu Cc: kernel-hardening@lists.openwall.com Cc: linux-doc@vger.kernel.org Link: http://lkml.kernel.org/r/1466556426-32664-2-git-send-email-keescook@chromium.org Signed-off-by: Ingo Molnar diff --git a/arch/x86/boot/compressed/kaslr.c b/arch/x86/boot/compressed/kaslr.c index 010ea16..a66854d 100644 --- a/arch/x86/boot/compressed/kaslr.c +++ b/arch/x86/boot/compressed/kaslr.c @@ -12,10 +12,6 @@ #include "misc.h" #include "error.h" -#include -#include -#include - #include #include #include @@ -26,26 +22,6 @@ static const char build_str[] = UTS_RELEASE " (" LINUX_COMPILE_BY "@" LINUX_COMPILE_HOST ") (" LINUX_COMPILER ") " UTS_VERSION; -#define I8254_PORT_CONTROL 0x43 -#define I8254_PORT_COUNTER0 0x40 -#define I8254_CMD_READBACK 0xC0 -#define I8254_SELECT_COUNTER0 0x02 -#define I8254_STATUS_NOTREADY 0x40 -static inline u16 i8254(void) -{ - u16 status, timer; - - do { - outb(I8254_PORT_CONTROL, - I8254_CMD_READBACK | I8254_SELECT_COUNTER0); - status = inb(I8254_PORT_COUNTER0); - timer = inb(I8254_PORT_COUNTER0); - timer |= inb(I8254_PORT_COUNTER0) << 8; - } while (status & I8254_STATUS_NOTREADY); - - return timer; -} - static unsigned long rotate_xor(unsigned long hash, const void *area, size_t size) { @@ -62,7 +38,7 @@ static unsigned long rotate_xor(unsigned long hash, const void *area, } /* Attempt to create a simple but unpredictable starting entropy. */ -static unsigned long get_random_boot(void) +static unsigned long get_boot_seed(void) { unsigned long hash = 0; @@ -72,50 +48,8 @@ static unsigned long get_random_boot(void) return hash; } -static unsigned long get_random_long(const char *purpose) -{ -#ifdef CONFIG_X86_64 - const unsigned long mix_const = 0x5d6008cbf3848dd3UL; -#else - const unsigned long mix_const = 0x3f39e593UL; -#endif - unsigned long raw, random = get_random_boot(); - bool use_i8254 = true; - - debug_putstr(purpose); - debug_putstr(" KASLR using"); - - if (has_cpuflag(X86_FEATURE_RDRAND)) { - debug_putstr(" RDRAND"); - if (rdrand_long(&raw)) { - random ^= raw; - use_i8254 = false; - } - } - - if (has_cpuflag(X86_FEATURE_TSC)) { - debug_putstr(" RDTSC"); - raw = rdtsc(); - - random ^= raw; - use_i8254 = false; - } - - if (use_i8254) { - debug_putstr(" i8254"); - random ^= i8254(); - } - - /* Circular multiply for better bit diffusion */ - asm("mul %3" - : "=a" (random), "=d" (raw) - : "a" (random), "rm" (mix_const)); - random += raw; - - debug_putstr("...\n"); - - return random; -} +#define KASLR_COMPRESSED_BOOT +#include "../../lib/kaslr.c" struct mem_vector { unsigned long start; @@ -349,7 +283,7 @@ static unsigned long slots_fetch_random(void) if (slot_max == 0) return 0; - slot = get_random_long("Physical") % slot_max; + slot = kaslr_get_random_long("Physical") % slot_max; for (i = 0; i < slot_area_index; i++) { if (slot >= slot_areas[i].num) { @@ -479,7 +413,7 @@ static unsigned long find_random_virt_addr(unsigned long minimum, slots = (KERNEL_IMAGE_SIZE - minimum - image_size) / CONFIG_PHYSICAL_ALIGN + 1; - random_addr = get_random_long("Virtual") % slots; + random_addr = kaslr_get_random_long("Virtual") % slots; return random_addr * CONFIG_PHYSICAL_ALIGN + minimum; } diff --git a/arch/x86/include/asm/kaslr.h b/arch/x86/include/asm/kaslr.h new file mode 100644 index 0000000..5547438 --- /dev/null +++ b/arch/x86/include/asm/kaslr.h @@ -0,0 +1,6 @@ +#ifndef _ASM_KASLR_H_ +#define _ASM_KASLR_H_ + +unsigned long kaslr_get_random_long(const char *purpose); + +#endif diff --git a/arch/x86/lib/Makefile b/arch/x86/lib/Makefile index 72a5767..cfa6d07 100644 --- a/arch/x86/lib/Makefile +++ b/arch/x86/lib/Makefile @@ -24,6 +24,7 @@ lib-y += usercopy_$(BITS).o usercopy.o getuser.o putuser.o lib-y += memcpy_$(BITS).o lib-$(CONFIG_RWSEM_XCHGADD_ALGORITHM) += rwsem.o lib-$(CONFIG_INSTRUCTION_DECODER) += insn.o inat.o +lib-$(CONFIG_RANDOMIZE_BASE) += kaslr.o obj-y += msr.o msr-reg.o msr-reg-export.o diff --git a/arch/x86/lib/kaslr.c b/arch/x86/lib/kaslr.c new file mode 100644 index 0000000..f7dfeda --- /dev/null +++ b/arch/x86/lib/kaslr.c @@ -0,0 +1,90 @@ +/* + * Entropy functions used on early boot for KASLR base and memory + * randomization. The base randomization is done in the compressed + * kernel and memory randomization is done early when the regular + * kernel starts. This file is included in the compressed kernel and + * normally linked in the regular. + */ +#include +#include +#include +#include +#include + +/* + * When built for the regular kernel, several functions need to be stubbed out + * or changed to their regular kernel equivalent. + */ +#ifndef KASLR_COMPRESSED_BOOT +#include +#include + +#define debug_putstr(v) early_printk(v) +#define has_cpuflag(f) boot_cpu_has(f) +#define get_boot_seed() kaslr_offset() +#endif + +#define I8254_PORT_CONTROL 0x43 +#define I8254_PORT_COUNTER0 0x40 +#define I8254_CMD_READBACK 0xC0 +#define I8254_SELECT_COUNTER0 0x02 +#define I8254_STATUS_NOTREADY 0x40 +static inline u16 i8254(void) +{ + u16 status, timer; + + do { + outb(I8254_PORT_CONTROL, + I8254_CMD_READBACK | I8254_SELECT_COUNTER0); + status = inb(I8254_PORT_COUNTER0); + timer = inb(I8254_PORT_COUNTER0); + timer |= inb(I8254_PORT_COUNTER0) << 8; + } while (status & I8254_STATUS_NOTREADY); + + return timer; +} + +unsigned long kaslr_get_random_long(const char *purpose) +{ +#ifdef CONFIG_X86_64 + const unsigned long mix_const = 0x5d6008cbf3848dd3UL; +#else + const unsigned long mix_const = 0x3f39e593UL; +#endif + unsigned long raw, random = get_boot_seed(); + bool use_i8254 = true; + + debug_putstr(purpose); + debug_putstr(" KASLR using"); + + if (has_cpuflag(X86_FEATURE_RDRAND)) { + debug_putstr(" RDRAND"); + if (rdrand_long(&raw)) { + random ^= raw; + use_i8254 = false; + } + } + + if (has_cpuflag(X86_FEATURE_TSC)) { + debug_putstr(" RDTSC"); + raw = rdtsc(); + + random ^= raw; + use_i8254 = false; + } + + if (use_i8254) { + debug_putstr(" i8254"); + random ^= i8254(); + } + + /* Circular multiply for better bit diffusion */ + asm("mul %3" + : "=a" (random), "=d" (raw) + : "a" (random), "rm" (mix_const)); + random += raw; + + debug_putstr("...\n"); + + return random; +} -- cgit v0.10.2 From 59b3d0206d74a700069e49160e8194b2ca93b703 Mon Sep 17 00:00:00 2001 From: Thomas Garnier Date: Tue, 21 Jun 2016 17:46:59 -0700 Subject: x86/mm: Update physical mapping variable names Change the variable names in kernel_physical_mapping_init() and related functions to correctly reflect physical and virtual memory addresses. Also add comments on each function to describe usage and alignment constraints. Signed-off-by: Thomas Garnier Signed-off-by: Kees Cook Cc: Alexander Kuleshov Cc: Alexander Popov Cc: Andrew Morton Cc: Andy Lutomirski Cc: Aneesh Kumar K.V Cc: Baoquan He Cc: Boris Ostrovsky Cc: Borislav Petkov Cc: Borislav Petkov Cc: Brian Gerst Cc: Christian Borntraeger Cc: Dan Williams Cc: Dave Hansen Cc: Dave Young Cc: Denys Vlasenko Cc: Dmitry Vyukov Cc: H. Peter Anvin Cc: Jan Beulich Cc: Joerg Roedel Cc: Jonathan Corbet Cc: Josh Poimboeuf Cc: Juergen Gross Cc: Kirill A. Shutemov Cc: Linus Torvalds Cc: Lv Zheng Cc: Mark Salter Cc: Martin Schwidefsky Cc: Matt Fleming Cc: Peter Zijlstra Cc: Stephen Smalley Cc: Thomas Gleixner Cc: Toshi Kani Cc: Xiao Guangrong Cc: Yinghai Lu Cc: kernel-hardening@lists.openwall.com Cc: linux-doc@vger.kernel.org Link: http://lkml.kernel.org/r/1466556426-32664-3-git-send-email-keescook@chromium.org Signed-off-by: Ingo Molnar diff --git a/arch/x86/mm/init_64.c b/arch/x86/mm/init_64.c index bce2e5d..6714712 100644 --- a/arch/x86/mm/init_64.c +++ b/arch/x86/mm/init_64.c @@ -328,22 +328,30 @@ void __init cleanup_highmap(void) } } +/* + * Create PTE level page table mapping for physical addresses. + * It returns the last physical address mapped. + */ static unsigned long __meminit -phys_pte_init(pte_t *pte_page, unsigned long addr, unsigned long end, +phys_pte_init(pte_t *pte_page, unsigned long paddr, unsigned long paddr_end, pgprot_t prot) { - unsigned long pages = 0, next; - unsigned long last_map_addr = end; + unsigned long pages = 0, paddr_next; + unsigned long paddr_last = paddr_end; + pte_t *pte; int i; - pte_t *pte = pte_page + pte_index(addr); + pte = pte_page + pte_index(paddr); + i = pte_index(paddr); - for (i = pte_index(addr); i < PTRS_PER_PTE; i++, addr = next, pte++) { - next = (addr & PAGE_MASK) + PAGE_SIZE; - if (addr >= end) { + for (; i < PTRS_PER_PTE; i++, paddr = paddr_next, pte++) { + paddr_next = (paddr & PAGE_MASK) + PAGE_SIZE; + if (paddr >= paddr_end) { if (!after_bootmem && - !e820_any_mapped(addr & PAGE_MASK, next, E820_RAM) && - !e820_any_mapped(addr & PAGE_MASK, next, E820_RESERVED_KERN)) + !e820_any_mapped(paddr & PAGE_MASK, paddr_next, + E820_RAM) && + !e820_any_mapped(paddr & PAGE_MASK, paddr_next, + E820_RESERVED_KERN)) set_pte(pte, __pte(0)); continue; } @@ -361,37 +369,44 @@ phys_pte_init(pte_t *pte_page, unsigned long addr, unsigned long end, } if (0) - printk(" pte=%p addr=%lx pte=%016lx\n", - pte, addr, pfn_pte(addr >> PAGE_SHIFT, PAGE_KERNEL).pte); + pr_info(" pte=%p addr=%lx pte=%016lx\n", pte, paddr, + pfn_pte(paddr >> PAGE_SHIFT, PAGE_KERNEL).pte); pages++; - set_pte(pte, pfn_pte(addr >> PAGE_SHIFT, prot)); - last_map_addr = (addr & PAGE_MASK) + PAGE_SIZE; + set_pte(pte, pfn_pte(paddr >> PAGE_SHIFT, prot)); + paddr_last = (paddr & PAGE_MASK) + PAGE_SIZE; } update_page_count(PG_LEVEL_4K, pages); - return last_map_addr; + return paddr_last; } +/* + * Create PMD level page table mapping for physical addresses. The virtual + * and physical address have to be aligned at this level. + * It returns the last physical address mapped. + */ static unsigned long __meminit -phys_pmd_init(pmd_t *pmd_page, unsigned long address, unsigned long end, +phys_pmd_init(pmd_t *pmd_page, unsigned long paddr, unsigned long paddr_end, unsigned long page_size_mask, pgprot_t prot) { - unsigned long pages = 0, next; - unsigned long last_map_addr = end; + unsigned long pages = 0, paddr_next; + unsigned long paddr_last = paddr_end; - int i = pmd_index(address); + int i = pmd_index(paddr); - for (; i < PTRS_PER_PMD; i++, address = next) { - pmd_t *pmd = pmd_page + pmd_index(address); + for (; i < PTRS_PER_PMD; i++, paddr = paddr_next) { + pmd_t *pmd = pmd_page + pmd_index(paddr); pte_t *pte; pgprot_t new_prot = prot; - next = (address & PMD_MASK) + PMD_SIZE; - if (address >= end) { + paddr_next = (paddr & PMD_MASK) + PMD_SIZE; + if (paddr >= paddr_end) { if (!after_bootmem && - !e820_any_mapped(address & PMD_MASK, next, E820_RAM) && - !e820_any_mapped(address & PMD_MASK, next, E820_RESERVED_KERN)) + !e820_any_mapped(paddr & PMD_MASK, paddr_next, + E820_RAM) && + !e820_any_mapped(paddr & PMD_MASK, paddr_next, + E820_RESERVED_KERN)) set_pmd(pmd, __pmd(0)); continue; } @@ -400,8 +415,8 @@ phys_pmd_init(pmd_t *pmd_page, unsigned long address, unsigned long end, if (!pmd_large(*pmd)) { spin_lock(&init_mm.page_table_lock); pte = (pte_t *)pmd_page_vaddr(*pmd); - last_map_addr = phys_pte_init(pte, address, - end, prot); + paddr_last = phys_pte_init(pte, paddr, + paddr_end, prot); spin_unlock(&init_mm.page_table_lock); continue; } @@ -420,7 +435,7 @@ phys_pmd_init(pmd_t *pmd_page, unsigned long address, unsigned long end, if (page_size_mask & (1 << PG_LEVEL_2M)) { if (!after_bootmem) pages++; - last_map_addr = next; + paddr_last = paddr_next; continue; } new_prot = pte_pgprot(pte_clrhuge(*(pte_t *)pmd)); @@ -430,42 +445,49 @@ phys_pmd_init(pmd_t *pmd_page, unsigned long address, unsigned long end, pages++; spin_lock(&init_mm.page_table_lock); set_pte((pte_t *)pmd, - pfn_pte((address & PMD_MASK) >> PAGE_SHIFT, + pfn_pte((paddr & PMD_MASK) >> PAGE_SHIFT, __pgprot(pgprot_val(prot) | _PAGE_PSE))); spin_unlock(&init_mm.page_table_lock); - last_map_addr = next; + paddr_last = paddr_next; continue; } pte = alloc_low_page(); - last_map_addr = phys_pte_init(pte, address, end, new_prot); + paddr_last = phys_pte_init(pte, paddr, paddr_end, new_prot); spin_lock(&init_mm.page_table_lock); pmd_populate_kernel(&init_mm, pmd, pte); spin_unlock(&init_mm.page_table_lock); } update_page_count(PG_LEVEL_2M, pages); - return last_map_addr; + return paddr_last; } +/* + * Create PUD level page table mapping for physical addresses. The virtual + * and physical address have to be aligned at this level. + * It returns the last physical address mapped. + */ static unsigned long __meminit -phys_pud_init(pud_t *pud_page, unsigned long addr, unsigned long end, - unsigned long page_size_mask) +phys_pud_init(pud_t *pud_page, unsigned long paddr, unsigned long paddr_end, + unsigned long page_size_mask) { - unsigned long pages = 0, next; - unsigned long last_map_addr = end; - int i = pud_index(addr); + unsigned long pages = 0, paddr_next; + unsigned long paddr_last = paddr_end; + int i = pud_index(paddr); - for (; i < PTRS_PER_PUD; i++, addr = next) { - pud_t *pud = pud_page + pud_index(addr); + for (; i < PTRS_PER_PUD; i++, paddr = paddr_next) { + pud_t *pud = pud_page + pud_index(paddr); pmd_t *pmd; pgprot_t prot = PAGE_KERNEL; - next = (addr & PUD_MASK) + PUD_SIZE; - if (addr >= end) { + paddr_next = (paddr & PUD_MASK) + PUD_SIZE; + if (paddr >= paddr_end) { if (!after_bootmem && - !e820_any_mapped(addr & PUD_MASK, next, E820_RAM) && - !e820_any_mapped(addr & PUD_MASK, next, E820_RESERVED_KERN)) + !e820_any_mapped(paddr & PUD_MASK, paddr_next, + E820_RAM) && + !e820_any_mapped(paddr & PUD_MASK, paddr_next, + E820_RESERVED_KERN)) set_pud(pud, __pud(0)); continue; } @@ -473,8 +495,10 @@ phys_pud_init(pud_t *pud_page, unsigned long addr, unsigned long end, if (pud_val(*pud)) { if (!pud_large(*pud)) { pmd = pmd_offset(pud, 0); - last_map_addr = phys_pmd_init(pmd, addr, end, - page_size_mask, prot); + paddr_last = phys_pmd_init(pmd, paddr, + paddr_end, + page_size_mask, + prot); __flush_tlb_all(); continue; } @@ -493,7 +517,7 @@ phys_pud_init(pud_t *pud_page, unsigned long addr, unsigned long end, if (page_size_mask & (1 << PG_LEVEL_1G)) { if (!after_bootmem) pages++; - last_map_addr = next; + paddr_last = paddr_next; continue; } prot = pte_pgprot(pte_clrhuge(*(pte_t *)pud)); @@ -503,16 +527,16 @@ phys_pud_init(pud_t *pud_page, unsigned long addr, unsigned long end, pages++; spin_lock(&init_mm.page_table_lock); set_pte((pte_t *)pud, - pfn_pte((addr & PUD_MASK) >> PAGE_SHIFT, + pfn_pte((paddr & PUD_MASK) >> PAGE_SHIFT, PAGE_KERNEL_LARGE)); spin_unlock(&init_mm.page_table_lock); - last_map_addr = next; + paddr_last = paddr_next; continue; } pmd = alloc_low_page(); - last_map_addr = phys_pmd_init(pmd, addr, end, page_size_mask, - prot); + paddr_last = phys_pmd_init(pmd, paddr, paddr_end, + page_size_mask, prot); spin_lock(&init_mm.page_table_lock); pud_populate(&init_mm, pud, pmd); @@ -522,38 +546,44 @@ phys_pud_init(pud_t *pud_page, unsigned long addr, unsigned long end, update_page_count(PG_LEVEL_1G, pages); - return last_map_addr; + return paddr_last; } +/* + * Create page table mapping for the physical memory for specific physical + * addresses. The virtual and physical addresses have to be aligned on PUD level + * down. It returns the last physical address mapped. + */ unsigned long __meminit -kernel_physical_mapping_init(unsigned long start, - unsigned long end, +kernel_physical_mapping_init(unsigned long paddr_start, + unsigned long paddr_end, unsigned long page_size_mask) { bool pgd_changed = false; - unsigned long next, last_map_addr = end; - unsigned long addr; + unsigned long vaddr, vaddr_start, vaddr_end, vaddr_next, paddr_last; - start = (unsigned long)__va(start); - end = (unsigned long)__va(end); - addr = start; + paddr_last = paddr_end; + vaddr = (unsigned long)__va(paddr_start); + vaddr_end = (unsigned long)__va(paddr_end); + vaddr_start = vaddr; - for (; start < end; start = next) { - pgd_t *pgd = pgd_offset_k(start); + for (; vaddr < vaddr_end; vaddr = vaddr_next) { + pgd_t *pgd = pgd_offset_k(vaddr); pud_t *pud; - next = (start & PGDIR_MASK) + PGDIR_SIZE; + vaddr_next = (vaddr & PGDIR_MASK) + PGDIR_SIZE; if (pgd_val(*pgd)) { pud = (pud_t *)pgd_page_vaddr(*pgd); - last_map_addr = phys_pud_init(pud, __pa(start), - __pa(end), page_size_mask); + paddr_last = phys_pud_init(pud, __pa(vaddr), + __pa(vaddr_end), + page_size_mask); continue; } pud = alloc_low_page(); - last_map_addr = phys_pud_init(pud, __pa(start), __pa(end), - page_size_mask); + paddr_last = phys_pud_init(pud, __pa(vaddr), __pa(vaddr_end), + page_size_mask); spin_lock(&init_mm.page_table_lock); pgd_populate(&init_mm, pgd, pud); @@ -562,11 +592,11 @@ kernel_physical_mapping_init(unsigned long start, } if (pgd_changed) - sync_global_pgds(addr, end - 1, 0); + sync_global_pgds(vaddr_start, vaddr_end - 1, 0); __flush_tlb_all(); - return last_map_addr; + return paddr_last; } #ifndef CONFIG_NUMA -- cgit v0.10.2 From faa379332f3cb3375db1849e27386f8bc9b97da4 Mon Sep 17 00:00:00 2001 From: Thomas Garnier Date: Tue, 21 Jun 2016 17:47:00 -0700 Subject: x86/mm: Add PUD VA support for physical mapping Minor change that allows early boot physical mapping of PUD level virtual addresses. The current implementation expects the virtual address to be PUD aligned. For KASLR memory randomization, we need to be able to randomize the offset used on the PUD table. It has no impact on current usage. Signed-off-by: Thomas Garnier Signed-off-by: Kees Cook Cc: Alexander Kuleshov Cc: Alexander Popov Cc: Andrew Morton Cc: Andy Lutomirski Cc: Aneesh Kumar K.V Cc: Baoquan He Cc: Boris Ostrovsky Cc: Borislav Petkov Cc: Borislav Petkov Cc: Brian Gerst Cc: Christian Borntraeger Cc: Dan Williams Cc: Dave Hansen Cc: Dave Young Cc: Denys Vlasenko Cc: Dmitry Vyukov Cc: H. Peter Anvin Cc: Jan Beulich Cc: Joerg Roedel Cc: Jonathan Corbet Cc: Josh Poimboeuf Cc: Juergen Gross Cc: Kirill A. Shutemov Cc: Linus Torvalds Cc: Lv Zheng Cc: Mark Salter Cc: Martin Schwidefsky Cc: Matt Fleming Cc: Peter Zijlstra Cc: Stephen Smalley Cc: Thomas Gleixner Cc: Toshi Kani Cc: Xiao Guangrong Cc: Yinghai Lu Cc: kernel-hardening@lists.openwall.com Cc: linux-doc@vger.kernel.org Link: http://lkml.kernel.org/r/1466556426-32664-4-git-send-email-keescook@chromium.org Signed-off-by: Ingo Molnar diff --git a/arch/x86/mm/init_64.c b/arch/x86/mm/init_64.c index 6714712..7bf1ddb 100644 --- a/arch/x86/mm/init_64.c +++ b/arch/x86/mm/init_64.c @@ -465,7 +465,8 @@ phys_pmd_init(pmd_t *pmd_page, unsigned long paddr, unsigned long paddr_end, /* * Create PUD level page table mapping for physical addresses. The virtual - * and physical address have to be aligned at this level. + * and physical address do not have to be aligned at this level. KASLR can + * randomize virtual addresses up to this level. * It returns the last physical address mapped. */ static unsigned long __meminit @@ -474,14 +475,18 @@ phys_pud_init(pud_t *pud_page, unsigned long paddr, unsigned long paddr_end, { unsigned long pages = 0, paddr_next; unsigned long paddr_last = paddr_end; - int i = pud_index(paddr); + unsigned long vaddr = (unsigned long)__va(paddr); + int i = pud_index(vaddr); for (; i < PTRS_PER_PUD; i++, paddr = paddr_next) { - pud_t *pud = pud_page + pud_index(paddr); + pud_t *pud; pmd_t *pmd; pgprot_t prot = PAGE_KERNEL; + vaddr = (unsigned long)__va(paddr); + pud = pud_page + pud_index(vaddr); paddr_next = (paddr & PUD_MASK) + PUD_SIZE; + if (paddr >= paddr_end) { if (!after_bootmem && !e820_any_mapped(paddr & PUD_MASK, paddr_next, @@ -551,7 +556,7 @@ phys_pud_init(pud_t *pud_page, unsigned long paddr, unsigned long paddr_end, /* * Create page table mapping for the physical memory for specific physical - * addresses. The virtual and physical addresses have to be aligned on PUD level + * addresses. The virtual and physical addresses have to be aligned on PMD level * down. It returns the last physical address mapped. */ unsigned long __meminit -- cgit v0.10.2 From b234e8a09003af108d3573f0369e25c080676b14 Mon Sep 17 00:00:00 2001 From: Thomas Garnier Date: Tue, 21 Jun 2016 17:47:01 -0700 Subject: x86/mm: Separate variable for trampoline PGD Use a separate global variable to define the trampoline PGD used to start other processors. This change will allow KALSR memory randomization to change the trampoline PGD to be correctly aligned with physical memory. Signed-off-by: Thomas Garnier Signed-off-by: Kees Cook Cc: Alexander Kuleshov Cc: Alexander Popov Cc: Andrew Morton Cc: Andy Lutomirski Cc: Aneesh Kumar K.V Cc: Baoquan He Cc: Boris Ostrovsky Cc: Borislav Petkov Cc: Borislav Petkov Cc: Brian Gerst Cc: Christian Borntraeger Cc: Dan Williams Cc: Dave Hansen Cc: Dave Young Cc: Denys Vlasenko Cc: Dmitry Vyukov Cc: H. Peter Anvin Cc: Jan Beulich Cc: Joerg Roedel Cc: Jonathan Corbet Cc: Josh Poimboeuf Cc: Juergen Gross Cc: Kirill A. Shutemov Cc: Linus Torvalds Cc: Lv Zheng Cc: Mark Salter Cc: Martin Schwidefsky Cc: Matt Fleming Cc: Peter Zijlstra Cc: Stephen Smalley Cc: Thomas Gleixner Cc: Toshi Kani Cc: Xiao Guangrong Cc: Yinghai Lu Cc: kernel-hardening@lists.openwall.com Cc: linux-doc@vger.kernel.org Link: http://lkml.kernel.org/r/1466556426-32664-5-git-send-email-keescook@chromium.org Signed-off-by: Ingo Molnar diff --git a/arch/x86/include/asm/pgtable.h b/arch/x86/include/asm/pgtable.h index 1a27396..d455bef 100644 --- a/arch/x86/include/asm/pgtable.h +++ b/arch/x86/include/asm/pgtable.h @@ -729,6 +729,18 @@ extern int direct_gbpages; void init_mem_mapping(void); void early_alloc_pgt_buf(void); +#ifdef CONFIG_X86_64 +/* Realmode trampoline initialization. */ +extern pgd_t trampoline_pgd_entry; +static inline void __meminit init_trampoline(void) +{ + /* Default trampoline pgd value */ + trampoline_pgd_entry = init_level4_pgt[pgd_index(__PAGE_OFFSET)]; +} +#else +static inline void init_trampoline(void) { } +#endif + /* local pte updates need not use xchg for locking */ static inline pte_t native_local_ptep_get_and_clear(pte_t *ptep) { diff --git a/arch/x86/mm/init.c b/arch/x86/mm/init.c index 372aad2..4252acd 100644 --- a/arch/x86/mm/init.c +++ b/arch/x86/mm/init.c @@ -590,6 +590,9 @@ void __init init_mem_mapping(void) /* the ISA range is always mapped regardless of memory holes */ init_memory_mapping(0, ISA_END_ADDRESS); + /* Init the trampoline, possibly with KASLR memory offset */ + init_trampoline(); + /* * If the allocation is in bottom-up direction, we setup direct mapping * in bottom-up, otherwise we setup direct mapping in top-down. diff --git a/arch/x86/realmode/init.c b/arch/x86/realmode/init.c index 0b7a63d..705e3ff 100644 --- a/arch/x86/realmode/init.c +++ b/arch/x86/realmode/init.c @@ -8,6 +8,9 @@ struct real_mode_header *real_mode_header; u32 *trampoline_cr4_features; +/* Hold the pgd entry used on booting additional CPUs */ +pgd_t trampoline_pgd_entry; + void __init reserve_real_mode(void) { phys_addr_t mem; @@ -84,7 +87,7 @@ void __init setup_real_mode(void) *trampoline_cr4_features = __read_cr4(); trampoline_pgd = (u64 *) __va(real_mode_header->trampoline_pgd); - trampoline_pgd[0] = init_level4_pgt[pgd_index(__PAGE_OFFSET)].pgd; + trampoline_pgd[0] = trampoline_pgd_entry.pgd; trampoline_pgd[511] = init_level4_pgt[511].pgd; #endif } -- cgit v0.10.2 From 0483e1fa6e09d4948272680f691dccb1edb9677f Mon Sep 17 00:00:00 2001 From: Thomas Garnier Date: Tue, 21 Jun 2016 17:47:02 -0700 Subject: x86/mm: Implement ASLR for kernel memory regions Randomizes the virtual address space of kernel memory regions for x86_64. This first patch adds the infrastructure and does not randomize any region. The following patches will randomize the physical memory mapping, vmalloc and vmemmap regions. This security feature mitigates exploits relying on predictable kernel addresses. These addresses can be used to disclose the kernel modules base addresses or corrupt specific structures to elevate privileges bypassing the current implementation of KASLR. This feature can be enabled with the CONFIG_RANDOMIZE_MEMORY option. The order of each memory region is not changed. The feature looks at the available space for the regions based on different configuration options and randomizes the base and space between each. The size of the physical memory mapping is the available physical memory. No performance impact was detected while testing the feature. Entropy is generated using the KASLR early boot functions now shared in the lib directory (originally written by Kees Cook). Randomization is done on PGD & PUD page table levels to increase possible addresses. The physical memory mapping code was adapted to support PUD level virtual addresses. This implementation on the best configuration provides 30,000 possible virtual addresses in average for each memory region. An additional low memory page is used to ensure each CPU can start with a PGD aligned virtual address (for realmode). x86/dump_pagetable was updated to correctly display each region. Updated documentation on x86_64 memory layout accordingly. Performance data, after all patches in the series: Kernbench shows almost no difference (-+ less than 1%): Before: Average Optimal load -j 12 Run (std deviation): Elapsed Time 102.63 (1.2695) User Time 1034.89 (1.18115) System Time 87.056 (0.456416) Percent CPU 1092.9 (13.892) Context Switches 199805 (3455.33) Sleeps 97907.8 (900.636) After: Average Optimal load -j 12 Run (std deviation): Elapsed Time 102.489 (1.10636) User Time 1034.86 (1.36053) System Time 87.764 (0.49345) Percent CPU 1095 (12.7715) Context Switches 199036 (4298.1) Sleeps 97681.6 (1031.11) Hackbench shows 0% difference on average (hackbench 90 repeated 10 times): attemp,before,after 1,0.076,0.069 2,0.072,0.069 3,0.066,0.066 4,0.066,0.068 5,0.066,0.067 6,0.066,0.069 7,0.067,0.066 8,0.063,0.067 9,0.067,0.065 10,0.068,0.071 average,0.0677,0.0677 Signed-off-by: Thomas Garnier Signed-off-by: Kees Cook Cc: Alexander Kuleshov Cc: Alexander Popov Cc: Andrew Morton Cc: Andy Lutomirski Cc: Aneesh Kumar K.V Cc: Baoquan He Cc: Boris Ostrovsky Cc: Borislav Petkov Cc: Borislav Petkov Cc: Brian Gerst Cc: Christian Borntraeger Cc: Dan Williams Cc: Dave Hansen Cc: Dave Young Cc: Denys Vlasenko Cc: Dmitry Vyukov Cc: H. Peter Anvin Cc: Jan Beulich Cc: Joerg Roedel Cc: Jonathan Corbet Cc: Josh Poimboeuf Cc: Juergen Gross Cc: Kirill A. Shutemov Cc: Linus Torvalds Cc: Lv Zheng Cc: Mark Salter Cc: Martin Schwidefsky Cc: Matt Fleming Cc: Peter Zijlstra Cc: Stephen Smalley Cc: Thomas Gleixner Cc: Toshi Kani Cc: Xiao Guangrong Cc: Yinghai Lu Cc: kernel-hardening@lists.openwall.com Cc: linux-doc@vger.kernel.org Link: http://lkml.kernel.org/r/1466556426-32664-6-git-send-email-keescook@chromium.org Signed-off-by: Ingo Molnar diff --git a/Documentation/x86/x86_64/mm.txt b/Documentation/x86/x86_64/mm.txt index 5aa7383..8c7dd59 100644 --- a/Documentation/x86/x86_64/mm.txt +++ b/Documentation/x86/x86_64/mm.txt @@ -39,4 +39,8 @@ memory window (this size is arbitrary, it can be raised later if needed). The mappings are not part of any other kernel PGD and are only available during EFI runtime calls. +Note that if CONFIG_RANDOMIZE_MEMORY is enabled, the direct mapping of all +physical memory, vmalloc/ioremap space and virtual memory map are randomized. +Their order is preserved but their base will be offset early at boot time. + -Andi Kleen, Jul 2004 diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 930fe88..9719b8e 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -1993,6 +1993,23 @@ config PHYSICAL_ALIGN Don't change this unless you know what you are doing. +config RANDOMIZE_MEMORY + bool "Randomize the kernel memory sections" + depends on X86_64 + depends on RANDOMIZE_BASE + default RANDOMIZE_BASE + ---help--- + Randomizes the base virtual address of kernel memory sections + (physical memory mapping, vmalloc & vmemmap). This security feature + makes exploits relying on predictable memory locations less reliable. + + The order of allocations remains unchanged. Entropy is generated in + the same way as RANDOMIZE_BASE. Current implementation in the optimal + configuration have in average 30,000 different possible virtual + addresses for each memory section. + + If unsure, say N. + config HOTPLUG_CPU bool "Support for hot-pluggable CPUs" depends on SMP diff --git a/arch/x86/include/asm/kaslr.h b/arch/x86/include/asm/kaslr.h index 5547438..683c9d7 100644 --- a/arch/x86/include/asm/kaslr.h +++ b/arch/x86/include/asm/kaslr.h @@ -3,4 +3,10 @@ unsigned long kaslr_get_random_long(const char *purpose); +#ifdef CONFIG_RANDOMIZE_MEMORY +void kernel_randomize_memory(void); +#else +static inline void kernel_randomize_memory(void) { } +#endif /* CONFIG_RANDOMIZE_MEMORY */ + #endif diff --git a/arch/x86/include/asm/pgtable.h b/arch/x86/include/asm/pgtable.h index d455bef..5472682 100644 --- a/arch/x86/include/asm/pgtable.h +++ b/arch/x86/include/asm/pgtable.h @@ -732,11 +732,16 @@ void early_alloc_pgt_buf(void); #ifdef CONFIG_X86_64 /* Realmode trampoline initialization. */ extern pgd_t trampoline_pgd_entry; -static inline void __meminit init_trampoline(void) +static inline void __meminit init_trampoline_default(void) { /* Default trampoline pgd value */ trampoline_pgd_entry = init_level4_pgt[pgd_index(__PAGE_OFFSET)]; } +# ifdef CONFIG_RANDOMIZE_MEMORY +void __meminit init_trampoline(void); +# else +# define init_trampoline init_trampoline_default +# endif #else static inline void init_trampoline(void) { } #endif diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c index c4e7b39..a261658 100644 --- a/arch/x86/kernel/setup.c +++ b/arch/x86/kernel/setup.c @@ -113,6 +113,7 @@ #include #include #include +#include /* * max_low_pfn_mapped: highest direct mapped pfn under 4GB @@ -942,6 +943,8 @@ void __init setup_arch(char **cmdline_p) x86_init.oem.arch_setup(); + kernel_randomize_memory(); + iomem_resource.end = (1ULL << boot_cpu_data.x86_phys_bits) - 1; setup_memory_map(); parse_setup_data(); diff --git a/arch/x86/mm/Makefile b/arch/x86/mm/Makefile index 62c0043..96d2b84 100644 --- a/arch/x86/mm/Makefile +++ b/arch/x86/mm/Makefile @@ -37,4 +37,5 @@ obj-$(CONFIG_NUMA_EMU) += numa_emulation.o obj-$(CONFIG_X86_INTEL_MPX) += mpx.o obj-$(CONFIG_X86_INTEL_MEMORY_PROTECTION_KEYS) += pkeys.o +obj-$(CONFIG_RANDOMIZE_MEMORY) += kaslr.o diff --git a/arch/x86/mm/dump_pagetables.c b/arch/x86/mm/dump_pagetables.c index 99bfb19..9a17250 100644 --- a/arch/x86/mm/dump_pagetables.c +++ b/arch/x86/mm/dump_pagetables.c @@ -72,9 +72,9 @@ static struct addr_marker address_markers[] = { { 0, "User Space" }, #ifdef CONFIG_X86_64 { 0x8000000000000000UL, "Kernel Space" }, - { PAGE_OFFSET, "Low Kernel Mapping" }, - { VMALLOC_START, "vmalloc() Area" }, - { VMEMMAP_START, "Vmemmap" }, + { 0/* PAGE_OFFSET */, "Low Kernel Mapping" }, + { 0/* VMALLOC_START */, "vmalloc() Area" }, + { 0/* VMEMMAP_START */, "Vmemmap" }, # ifdef CONFIG_X86_ESPFIX64 { ESPFIX_BASE_ADDR, "ESPfix Area", 16 }, # endif @@ -434,8 +434,16 @@ void ptdump_walk_pgd_level_checkwx(void) static int __init pt_dump_init(void) { + /* + * Various markers are not compile-time constants, so assign them + * here. + */ +#ifdef CONFIG_X86_64 + address_markers[LOW_KERNEL_NR].start_address = PAGE_OFFSET; + address_markers[VMALLOC_START_NR].start_address = VMALLOC_START; + address_markers[VMEMMAP_START_NR].start_address = VMEMMAP_START; +#endif #ifdef CONFIG_X86_32 - /* Not a compile-time constant on x86-32 */ address_markers[VMALLOC_START_NR].start_address = VMALLOC_START; address_markers[VMALLOC_END_NR].start_address = VMALLOC_END; # ifdef CONFIG_HIGHMEM diff --git a/arch/x86/mm/init.c b/arch/x86/mm/init.c index 4252acd..cc82830 100644 --- a/arch/x86/mm/init.c +++ b/arch/x86/mm/init.c @@ -17,6 +17,7 @@ #include #include /* for MAX_DMA_PFN */ #include +#include /* * We need to define the tracepoints somewhere, and tlb.c diff --git a/arch/x86/mm/kaslr.c b/arch/x86/mm/kaslr.c new file mode 100644 index 0000000..d5380a4 --- /dev/null +++ b/arch/x86/mm/kaslr.c @@ -0,0 +1,152 @@ +/* + * This file implements KASLR memory randomization for x86_64. It randomizes + * the virtual address space of kernel memory regions (physical memory + * mapping, vmalloc & vmemmap) for x86_64. This security feature mitigates + * exploits relying on predictable kernel addresses. + * + * Entropy is generated using the KASLR early boot functions now shared in + * the lib directory (originally written by Kees Cook). Randomization is + * done on PGD & PUD page table levels to increase possible addresses. The + * physical memory mapping code was adapted to support PUD level virtual + * addresses. This implementation on the best configuration provides 30,000 + * possible virtual addresses in average for each memory region. An additional + * low memory page is used to ensure each CPU can start with a PGD aligned + * virtual address (for realmode). + * + * The order of each memory region is not changed. The feature looks at + * the available space for the regions based on different configuration + * options and randomizes the base and space between each. The size of the + * physical memory mapping is the available physical memory. + */ + +#include +#include +#include + +#include +#include +#include +#include + +#include "mm_internal.h" + +#define TB_SHIFT 40 + +/* + * Virtual address start and end range for randomization. The end changes base + * on configuration to have the highest amount of space for randomization. + * It increases the possible random position for each randomized region. + * + * You need to add an if/def entry if you introduce a new memory region + * compatible with KASLR. Your entry must be in logical order with memory + * layout. For example, ESPFIX is before EFI because its virtual address is + * before. You also need to add a BUILD_BUG_ON in kernel_randomize_memory to + * ensure that this order is correct and won't be changed. + */ +static const unsigned long vaddr_start; +static const unsigned long vaddr_end; + +/* + * Memory regions randomized by KASLR (except modules that use a separate logic + * earlier during boot). The list is ordered based on virtual addresses. This + * order is kept after randomization. + */ +static __initdata struct kaslr_memory_region { + unsigned long *base; + unsigned long size_tb; +} kaslr_regions[] = { +}; + +/* Get size in bytes used by the memory region */ +static inline unsigned long get_padding(struct kaslr_memory_region *region) +{ + return (region->size_tb << TB_SHIFT); +} + +/* + * Apply no randomization if KASLR was disabled at boot or if KASAN + * is enabled. KASAN shadow mappings rely on regions being PGD aligned. + */ +static inline bool kaslr_memory_enabled(void) +{ + return kaslr_enabled() && !config_enabled(CONFIG_KASAN); +} + +/* Initialize base and padding for each memory region randomized with KASLR */ +void __init kernel_randomize_memory(void) +{ + size_t i; + unsigned long vaddr = vaddr_start; + unsigned long rand; + struct rnd_state rand_state; + unsigned long remain_entropy; + + if (!kaslr_memory_enabled()) + return; + + /* Calculate entropy available between regions */ + remain_entropy = vaddr_end - vaddr_start; + for (i = 0; i < ARRAY_SIZE(kaslr_regions); i++) + remain_entropy -= get_padding(&kaslr_regions[i]); + + prandom_seed_state(&rand_state, kaslr_get_random_long("Memory")); + + for (i = 0; i < ARRAY_SIZE(kaslr_regions); i++) { + unsigned long entropy; + + /* + * Select a random virtual address using the extra entropy + * available. + */ + entropy = remain_entropy / (ARRAY_SIZE(kaslr_regions) - i); + prandom_bytes_state(&rand_state, &rand, sizeof(rand)); + entropy = (rand % (entropy + 1)) & PUD_MASK; + vaddr += entropy; + *kaslr_regions[i].base = vaddr; + + /* + * Jump the region and add a minimum padding based on + * randomization alignment. + */ + vaddr += get_padding(&kaslr_regions[i]); + vaddr = round_up(vaddr + 1, PUD_SIZE); + remain_entropy -= entropy; + } +} + +/* + * Create PGD aligned trampoline table to allow real mode initialization + * of additional CPUs. Consume only 1 low memory page. + */ +void __meminit init_trampoline(void) +{ + unsigned long paddr, paddr_next; + pgd_t *pgd; + pud_t *pud_page, *pud_page_tramp; + int i; + + if (!kaslr_memory_enabled()) { + init_trampoline_default(); + return; + } + + pud_page_tramp = alloc_low_page(); + + paddr = 0; + pgd = pgd_offset_k((unsigned long)__va(paddr)); + pud_page = (pud_t *) pgd_page_vaddr(*pgd); + + for (i = pud_index(paddr); i < PTRS_PER_PUD; i++, paddr = paddr_next) { + pud_t *pud, *pud_tramp; + unsigned long vaddr = (unsigned long)__va(paddr); + + pud_tramp = pud_page_tramp + pud_index(paddr); + pud = pud_page + pud_index(vaddr); + paddr_next = (paddr & PUD_MASK) + PUD_SIZE; + + *pud_tramp = *pud; + } + + set_pgd(&trampoline_pgd_entry, + __pgd(_KERNPG_TABLE | __pa(pud_page_tramp))); +} -- cgit v0.10.2 From 021182e52fe01c1f7b126f97fd6ba048dc4234fd Mon Sep 17 00:00:00 2001 From: Thomas Garnier Date: Tue, 21 Jun 2016 17:47:03 -0700 Subject: x86/mm: Enable KASLR for physical mapping memory regions Add the physical mapping in the list of randomized memory regions. The physical memory mapping holds most allocations from boot and heap allocators. Knowing the base address and physical memory size, an attacker can deduce the PDE virtual address for the vDSO memory page. This attack was demonstrated at CanSecWest 2016, in the following presentation: "Getting Physical: Extreme Abuse of Intel Based Paged Systems": https://github.com/n3k/CansecWest2016_Getting_Physical_Extreme_Abuse_of_Intel_Based_Paging_Systems/blob/master/Presentation/CanSec2016_Presentation.pdf (See second part of the presentation). The exploits used against Linux worked successfully against 4.6+ but fail with KASLR memory enabled: https://github.com/n3k/CansecWest2016_Getting_Physical_Extreme_Abuse_of_Intel_Based_Paging_Systems/tree/master/Demos/Linux/exploits Similar research was done at Google leading to this patch proposal. Variants exists to overwrite /proc or /sys objects ACLs leading to elevation of privileges. These variants were tested against 4.6+. The page offset used by the compressed kernel retains the static value since it is not yet randomized during this boot stage. Signed-off-by: Thomas Garnier Signed-off-by: Kees Cook Cc: Alexander Kuleshov Cc: Alexander Popov Cc: Andrew Morton Cc: Andy Lutomirski Cc: Aneesh Kumar K.V Cc: Baoquan He Cc: Boris Ostrovsky Cc: Borislav Petkov Cc: Borislav Petkov Cc: Brian Gerst Cc: Christian Borntraeger Cc: Dan Williams Cc: Dave Hansen Cc: Dave Young Cc: Denys Vlasenko Cc: Dmitry Vyukov Cc: H. Peter Anvin Cc: Jan Beulich Cc: Joerg Roedel Cc: Jonathan Corbet Cc: Josh Poimboeuf Cc: Juergen Gross Cc: Kirill A. Shutemov Cc: Linus Torvalds Cc: Lv Zheng Cc: Mark Salter Cc: Martin Schwidefsky Cc: Matt Fleming Cc: Peter Zijlstra Cc: Stephen Smalley Cc: Thomas Gleixner Cc: Toshi Kani Cc: Xiao Guangrong Cc: Yinghai Lu Cc: kernel-hardening@lists.openwall.com Cc: linux-doc@vger.kernel.org Link: http://lkml.kernel.org/r/1466556426-32664-7-git-send-email-keescook@chromium.org Signed-off-by: Ingo Molnar diff --git a/arch/x86/boot/compressed/pagetable.c b/arch/x86/boot/compressed/pagetable.c index 6e31a6a..56589d0 100644 --- a/arch/x86/boot/compressed/pagetable.c +++ b/arch/x86/boot/compressed/pagetable.c @@ -20,6 +20,9 @@ /* These actually do the work of building the kernel identity maps. */ #include #include +/* Use the static base for this part of the boot process */ +#undef __PAGE_OFFSET +#define __PAGE_OFFSET __PAGE_OFFSET_BASE #include "../../mm/ident_map.c" /* Used by pgtable.h asm code to force instruction serialization. */ diff --git a/arch/x86/include/asm/kaslr.h b/arch/x86/include/asm/kaslr.h index 683c9d7..62b1b81 100644 --- a/arch/x86/include/asm/kaslr.h +++ b/arch/x86/include/asm/kaslr.h @@ -4,6 +4,8 @@ unsigned long kaslr_get_random_long(const char *purpose); #ifdef CONFIG_RANDOMIZE_MEMORY +extern unsigned long page_offset_base; + void kernel_randomize_memory(void); #else static inline void kernel_randomize_memory(void) { } diff --git a/arch/x86/include/asm/page_64_types.h b/arch/x86/include/asm/page_64_types.h index d5c2f8b..9215e05 100644 --- a/arch/x86/include/asm/page_64_types.h +++ b/arch/x86/include/asm/page_64_types.h @@ -1,6 +1,10 @@ #ifndef _ASM_X86_PAGE_64_DEFS_H #define _ASM_X86_PAGE_64_DEFS_H +#ifndef __ASSEMBLY__ +#include +#endif + #ifdef CONFIG_KASAN #define KASAN_STACK_ORDER 1 #else @@ -32,7 +36,12 @@ * hypervisor to fit. Choosing 16 slots here is arbitrary, but it's * what Xen requires. */ -#define __PAGE_OFFSET _AC(0xffff880000000000, UL) +#define __PAGE_OFFSET_BASE _AC(0xffff880000000000, UL) +#ifdef CONFIG_RANDOMIZE_MEMORY +#define __PAGE_OFFSET page_offset_base +#else +#define __PAGE_OFFSET __PAGE_OFFSET_BASE +#endif /* CONFIG_RANDOMIZE_MEMORY */ #define __START_KERNEL_map _AC(0xffffffff80000000, UL) diff --git a/arch/x86/kernel/head_64.S b/arch/x86/kernel/head_64.S index c7920ba..9f8efc9 100644 --- a/arch/x86/kernel/head_64.S +++ b/arch/x86/kernel/head_64.S @@ -38,7 +38,7 @@ #define pud_index(x) (((x) >> PUD_SHIFT) & (PTRS_PER_PUD-1)) -L4_PAGE_OFFSET = pgd_index(__PAGE_OFFSET) +L4_PAGE_OFFSET = pgd_index(__PAGE_OFFSET_BASE) L4_START_KERNEL = pgd_index(__START_KERNEL_map) L3_START_KERNEL = pud_index(__START_KERNEL_map) diff --git a/arch/x86/mm/kaslr.c b/arch/x86/mm/kaslr.c index d5380a4..609ecf2 100644 --- a/arch/x86/mm/kaslr.c +++ b/arch/x86/mm/kaslr.c @@ -43,8 +43,12 @@ * before. You also need to add a BUILD_BUG_ON in kernel_randomize_memory to * ensure that this order is correct and won't be changed. */ -static const unsigned long vaddr_start; -static const unsigned long vaddr_end; +static const unsigned long vaddr_start = __PAGE_OFFSET_BASE; +static const unsigned long vaddr_end = VMALLOC_START; + +/* Default values */ +unsigned long page_offset_base = __PAGE_OFFSET_BASE; +EXPORT_SYMBOL(page_offset_base); /* * Memory regions randomized by KASLR (except modules that use a separate logic @@ -55,6 +59,7 @@ static __initdata struct kaslr_memory_region { unsigned long *base; unsigned long size_tb; } kaslr_regions[] = { + { &page_offset_base, 64/* Maximum */ }, }; /* Get size in bytes used by the memory region */ @@ -77,13 +82,20 @@ void __init kernel_randomize_memory(void) { size_t i; unsigned long vaddr = vaddr_start; - unsigned long rand; + unsigned long rand, memory_tb; struct rnd_state rand_state; unsigned long remain_entropy; if (!kaslr_memory_enabled()) return; + BUG_ON(kaslr_regions[0].base != &page_offset_base); + memory_tb = ((max_pfn << PAGE_SHIFT) >> TB_SHIFT); + + /* Adapt phyiscal memory region size based on available memory */ + if (memory_tb < kaslr_regions[0].size_tb) + kaslr_regions[0].size_tb = memory_tb; + /* Calculate entropy available between regions */ remain_entropy = vaddr_end - vaddr_start; for (i = 0; i < ARRAY_SIZE(kaslr_regions); i++) -- cgit v0.10.2 From a95ae27c2ee1cba5f4f6b9dea43ffe88252e79b1 Mon Sep 17 00:00:00 2001 From: Thomas Garnier Date: Tue, 21 Jun 2016 17:47:04 -0700 Subject: x86/mm: Enable KASLR for vmalloc memory regions Add vmalloc to the list of randomized memory regions. The vmalloc memory region contains the allocation made through the vmalloc() API. The allocations are done sequentially to prevent fragmentation and each allocation address can easily be deduced especially from boot. Signed-off-by: Thomas Garnier Signed-off-by: Kees Cook Cc: Alexander Kuleshov Cc: Alexander Popov Cc: Andrew Morton Cc: Andy Lutomirski Cc: Aneesh Kumar K.V Cc: Baoquan He Cc: Boris Ostrovsky Cc: Borislav Petkov Cc: Borislav Petkov Cc: Brian Gerst Cc: Christian Borntraeger Cc: Dan Williams Cc: Dave Hansen Cc: Dave Young Cc: Denys Vlasenko Cc: Dmitry Vyukov Cc: H. Peter Anvin Cc: Jan Beulich Cc: Joerg Roedel Cc: Jonathan Corbet Cc: Josh Poimboeuf Cc: Juergen Gross Cc: Kirill A. Shutemov Cc: Linus Torvalds Cc: Lv Zheng Cc: Mark Salter Cc: Martin Schwidefsky Cc: Matt Fleming Cc: Peter Zijlstra Cc: Stephen Smalley Cc: Thomas Gleixner Cc: Toshi Kani Cc: Xiao Guangrong Cc: Yinghai Lu Cc: kernel-hardening@lists.openwall.com Cc: linux-doc@vger.kernel.org Link: http://lkml.kernel.org/r/1466556426-32664-8-git-send-email-keescook@chromium.org Signed-off-by: Ingo Molnar diff --git a/arch/x86/include/asm/kaslr.h b/arch/x86/include/asm/kaslr.h index 62b1b81..2674ee3 100644 --- a/arch/x86/include/asm/kaslr.h +++ b/arch/x86/include/asm/kaslr.h @@ -5,6 +5,7 @@ unsigned long kaslr_get_random_long(const char *purpose); #ifdef CONFIG_RANDOMIZE_MEMORY extern unsigned long page_offset_base; +extern unsigned long vmalloc_base; void kernel_randomize_memory(void); #else diff --git a/arch/x86/include/asm/pgtable_64_types.h b/arch/x86/include/asm/pgtable_64_types.h index e6844df..6fdef9e 100644 --- a/arch/x86/include/asm/pgtable_64_types.h +++ b/arch/x86/include/asm/pgtable_64_types.h @@ -5,6 +5,7 @@ #ifndef __ASSEMBLY__ #include +#include /* * These are used to make use of C type-checking.. @@ -53,10 +54,16 @@ typedef struct { pteval_t pte; } pte_t; #define PGDIR_MASK (~(PGDIR_SIZE - 1)) /* See Documentation/x86/x86_64/mm.txt for a description of the memory map. */ -#define MAXMEM _AC(__AC(1, UL) << MAX_PHYSMEM_BITS, UL) -#define VMALLOC_START _AC(0xffffc90000000000, UL) -#define VMALLOC_END _AC(0xffffe8ffffffffff, UL) -#define VMEMMAP_START _AC(0xffffea0000000000, UL) +#define MAXMEM _AC(__AC(1, UL) << MAX_PHYSMEM_BITS, UL) +#define VMALLOC_SIZE_TB _AC(32, UL) +#define __VMALLOC_BASE _AC(0xffffc90000000000, UL) +#define VMEMMAP_START _AC(0xffffea0000000000, UL) +#ifdef CONFIG_RANDOMIZE_MEMORY +#define VMALLOC_START vmalloc_base +#else +#define VMALLOC_START __VMALLOC_BASE +#endif /* CONFIG_RANDOMIZE_MEMORY */ +#define VMALLOC_END (VMALLOC_START + _AC((VMALLOC_SIZE_TB << 40) - 1, UL)) #define MODULES_VADDR (__START_KERNEL_map + KERNEL_IMAGE_SIZE) #define MODULES_END _AC(0xffffffffff000000, UL) #define MODULES_LEN (MODULES_END - MODULES_VADDR) diff --git a/arch/x86/mm/kaslr.c b/arch/x86/mm/kaslr.c index 609ecf2..c939cfe 100644 --- a/arch/x86/mm/kaslr.c +++ b/arch/x86/mm/kaslr.c @@ -44,11 +44,13 @@ * ensure that this order is correct and won't be changed. */ static const unsigned long vaddr_start = __PAGE_OFFSET_BASE; -static const unsigned long vaddr_end = VMALLOC_START; +static const unsigned long vaddr_end = VMEMMAP_START; /* Default values */ unsigned long page_offset_base = __PAGE_OFFSET_BASE; EXPORT_SYMBOL(page_offset_base); +unsigned long vmalloc_base = __VMALLOC_BASE; +EXPORT_SYMBOL(vmalloc_base); /* * Memory regions randomized by KASLR (except modules that use a separate logic @@ -60,6 +62,7 @@ static __initdata struct kaslr_memory_region { unsigned long size_tb; } kaslr_regions[] = { { &page_offset_base, 64/* Maximum */ }, + { &vmalloc_base, VMALLOC_SIZE_TB }, }; /* Get size in bytes used by the memory region */ -- cgit v0.10.2 From 90397a41779645d3abba5599f6bb538fdcab9339 Mon Sep 17 00:00:00 2001 From: Thomas Garnier Date: Tue, 21 Jun 2016 17:47:06 -0700 Subject: x86/mm: Add memory hotplug support for KASLR memory randomization Add a new option (CONFIG_RANDOMIZE_MEMORY_PHYSICAL_PADDING) to define the padding used for the physical memory mapping section when KASLR memory is enabled. It ensures there is enough virtual address space when CONFIG_MEMORY_HOTPLUG is used. The default value is 10 terabytes. If CONFIG_MEMORY_HOTPLUG is not used, no space is reserved increasing the entropy available. Signed-off-by: Thomas Garnier Signed-off-by: Kees Cook Cc: Alexander Kuleshov Cc: Alexander Popov Cc: Andrew Morton Cc: Andy Lutomirski Cc: Aneesh Kumar K.V Cc: Baoquan He Cc: Boris Ostrovsky Cc: Borislav Petkov Cc: Borislav Petkov Cc: Brian Gerst Cc: Christian Borntraeger Cc: Dan Williams Cc: Dave Hansen Cc: Dave Young Cc: Denys Vlasenko Cc: Dmitry Vyukov Cc: H. Peter Anvin Cc: Jan Beulich Cc: Joerg Roedel Cc: Jonathan Corbet Cc: Josh Poimboeuf Cc: Juergen Gross Cc: Kirill A. Shutemov Cc: Linus Torvalds Cc: Lv Zheng Cc: Mark Salter Cc: Martin Schwidefsky Cc: Matt Fleming Cc: Peter Zijlstra Cc: Stephen Smalley Cc: Thomas Gleixner Cc: Toshi Kani Cc: Xiao Guangrong Cc: Yinghai Lu Cc: kernel-hardening@lists.openwall.com Cc: linux-doc@vger.kernel.org Link: http://lkml.kernel.org/r/1466556426-32664-10-git-send-email-keescook@chromium.org Signed-off-by: Ingo Molnar diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 9719b8e..703413f 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -2010,6 +2010,21 @@ config RANDOMIZE_MEMORY If unsure, say N. +config RANDOMIZE_MEMORY_PHYSICAL_PADDING + hex "Physical memory mapping padding" if EXPERT + depends on RANDOMIZE_MEMORY + default "0xa" if MEMORY_HOTPLUG + default "0x0" + range 0x1 0x40 if MEMORY_HOTPLUG + range 0x0 0x40 + ---help--- + Define the padding in terabytes added to the existing physical + memory size during kernel memory randomization. It is useful + for memory hotplug support but reduces the entropy available for + address randomization. + + If unsure, leave at the default value. + config HOTPLUG_CPU bool "Support for hot-pluggable CPUs" depends on SMP diff --git a/arch/x86/mm/kaslr.c b/arch/x86/mm/kaslr.c index c939cfe..26dccd6 100644 --- a/arch/x86/mm/kaslr.c +++ b/arch/x86/mm/kaslr.c @@ -92,8 +92,13 @@ void __init kernel_randomize_memory(void) if (!kaslr_memory_enabled()) return; + /* + * Update Physical memory mapping to available and + * add padding if needed (especially for memory hotplug support). + */ BUG_ON(kaslr_regions[0].base != &page_offset_base); - memory_tb = ((max_pfn << PAGE_SHIFT) >> TB_SHIFT); + memory_tb = ((max_pfn << PAGE_SHIFT) >> TB_SHIFT) + + CONFIG_RANDOMIZE_MEMORY_PHYSICAL_PADDING; /* Adapt phyiscal memory region size based on available memory */ if (memory_tb < kaslr_regions[0].size_tb) -- cgit v0.10.2 From f0fe970df3838c202ef6c07a4c2b36838ef0a88b Mon Sep 17 00:00:00 2001 From: Jeff Mahoney Date: Tue, 5 Jul 2016 17:32:30 -0400 Subject: ecryptfs: don't allow mmap when the lower fs doesn't support it There are legitimate reasons to disallow mmap on certain files, notably in sysfs or procfs. We shouldn't emulate mmap support on file systems that don't offer support natively. CVE-2016-1583 Signed-off-by: Jeff Mahoney Cc: stable@vger.kernel.org [tyhicks: clean up f_op check by using ecryptfs_file_to_lower()] Signed-off-by: Tyler Hicks diff --git a/fs/ecryptfs/file.c b/fs/ecryptfs/file.c index 53d0141..ca4e837 100644 --- a/fs/ecryptfs/file.c +++ b/fs/ecryptfs/file.c @@ -169,6 +169,19 @@ out: return rc; } +static int ecryptfs_mmap(struct file *file, struct vm_area_struct *vma) +{ + struct file *lower_file = ecryptfs_file_to_lower(file); + /* + * Don't allow mmap on top of file systems that don't support it + * natively. If FILESYSTEM_MAX_STACK_DEPTH > 2 or ecryptfs + * allows recursive mounting, this will need to be extended. + */ + if (!lower_file->f_op->mmap) + return -ENODEV; + return generic_file_mmap(file, vma); +} + /** * ecryptfs_open * @inode: inode specifying file to open @@ -403,7 +416,7 @@ const struct file_operations ecryptfs_main_fops = { #ifdef CONFIG_COMPAT .compat_ioctl = ecryptfs_compat_ioctl, #endif - .mmap = generic_file_mmap, + .mmap = ecryptfs_mmap, .open = ecryptfs_open, .flush = ecryptfs_flush, .release = ecryptfs_release, -- cgit v0.10.2 From fa5b4a509d7bbba5d45c8ea177bddfd0b618876a Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Fri, 8 Jul 2016 09:25:05 +0800 Subject: ACPI / EC: Fix code ordering issue in ec_remove_handlers() There is an order issue in ec_remove_handlers() that acpi_ec_stop() is called before removing the operation region handler. That is incorrect, because the operation region handler removal triggers _REG(DISCONNECT) which may result in new EC transactions to carry out. That existing issue has been triggered by the following commit: Commit: dcf15cbded656a12335bc4151f3f75f10080a375 Subject: ACPI / EC: Fix a boot EC regresion by restoring boot EC which changed the driver to call ec_remove_handlers() after invoking _REG(CONNECT), so the issue has become visible. Fixes: dcf15cbded65 (ACPI / EC: Fix a boot EC regresion by restoring boot EC) Link: https://bugzilla.kernel.org/show_bug.cgi?id=102421 Reported-and-tested-by: Wolfram Sang Reported-by: Nicholas Signed-off-by: Lv Zheng [ rjw: Changelog ] Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index 73c76d6..290d6f5 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c @@ -1331,8 +1331,6 @@ static int ec_install_handlers(struct acpi_ec *ec) static void ec_remove_handlers(struct acpi_ec *ec) { - acpi_ec_stop(ec, false); - if (test_bit(EC_FLAGS_EC_HANDLER_INSTALLED, &ec->flags)) { if (ACPI_FAILURE(acpi_remove_address_space_handler(ec->handle, ACPI_ADR_SPACE_EC, &acpi_ec_space_handler))) @@ -1340,6 +1338,19 @@ static void ec_remove_handlers(struct acpi_ec *ec) clear_bit(EC_FLAGS_EC_HANDLER_INSTALLED, &ec->flags); } + /* + * Stops handling the EC transactions after removing the operation + * region handler. This is required because _REG(DISCONNECT) + * invoked during the removal can result in new EC transactions. + * + * Flushes the EC requests and thus disables the GPE before + * removing the GPE handler. This is required by the current ACPICA + * GPE core. ACPICA GPE core will automatically disable a GPE when + * it is indicated but there is no way to handle it. So the drivers + * must disable the GPEs prior to removing the GPE handlers. + */ + acpi_ec_stop(ec, false); + if (test_bit(EC_FLAGS_GPE_HANDLER_INSTALLED, &ec->flags)) { if (ACPI_FAILURE(acpi_remove_gpe_handler(NULL, ec->gpe, &acpi_ec_gpe_handler))) -- cgit v0.10.2 From 06708f81528725148473c0869d6af5f809c6824b Mon Sep 17 00:00:00 2001 From: Dmitri Epshtein Date: Wed, 6 Jul 2016 04:18:58 +0200 Subject: net: mvneta: set real interrupt per packet for tx_done Commit aebea2ba0f74 ("net: mvneta: fix Tx interrupt delay") intended to set coalescing threshold to a value guaranteeing interrupt generation per each sent packet, so that buffers can be released with no delay. In fact setting threshold to '1' was wrong, because it causes interrupt every two packets. According to the documentation a reason behind it is following - interrupt occurs once sent buffers counter reaches a value, which is higher than one specified in MVNETA_TXQ_SIZE_REG(q). This behavior was confirmed during tests. Also when testing the SoC working as a NAS device, better performance was observed with int-per-packet, as it strongly depends on the fact that all transmitted packets are released immediately. This commit enables NETA controller work in interrupt per sent packet mode by setting coalescing threshold to 0. Signed-off-by: Dmitri Epshtein Signed-off-by: Marcin Wojtas Cc: # v3.10+ Fixes aebea2ba0f74 ("net: mvneta: fix Tx interrupt delay") Acked-by: Willy Tarreau Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/marvell/mvneta.c b/drivers/net/ethernet/marvell/mvneta.c index d5d263b..f92018b 100644 --- a/drivers/net/ethernet/marvell/mvneta.c +++ b/drivers/net/ethernet/marvell/mvneta.c @@ -244,7 +244,7 @@ /* Various constants */ /* Coalescing */ -#define MVNETA_TXDONE_COAL_PKTS 1 +#define MVNETA_TXDONE_COAL_PKTS 0 /* interrupt per packet */ #define MVNETA_RX_COAL_PKTS 32 #define MVNETA_RX_COAL_USEC 100 -- cgit v0.10.2 From 205e1e255c479f3fd77446415706463b282f94e4 Mon Sep 17 00:00:00 2001 From: WANG Cong Date: Tue, 5 Jul 2016 22:12:36 -0700 Subject: ppp: defer netns reference release for ppp channel Matt reported that we have a NULL pointer dereference in ppp_pernet() from ppp_connect_channel(), i.e. pch->chan_net is NULL. This is due to that a parallel ppp_unregister_channel() could happen while we are in ppp_connect_channel(), during which pch->chan_net set to NULL. Since we need a reference to net per channel, it makes sense to sync the refcnt with the life time of the channel, therefore we should release this reference when we destroy it. Fixes: 1f461dcdd296 ("ppp: take reference on channels netns") Reported-by: Matt Bennett Cc: Paul Mackerras Cc: linux-ppp@vger.kernel.org Cc: Guillaume Nault Cc: Cyrill Gorcunov Signed-off-by: Cong Wang Reviewed-by: Cyrill Gorcunov Signed-off-by: David S. Miller diff --git a/drivers/net/ppp/ppp_generic.c b/drivers/net/ppp/ppp_generic.c index 8dedafa..a30ee42 100644 --- a/drivers/net/ppp/ppp_generic.c +++ b/drivers/net/ppp/ppp_generic.c @@ -2601,8 +2601,6 @@ ppp_unregister_channel(struct ppp_channel *chan) spin_lock_bh(&pn->all_channels_lock); list_del(&pch->list); spin_unlock_bh(&pn->all_channels_lock); - put_net(pch->chan_net); - pch->chan_net = NULL; pch->file.dead = 1; wake_up_interruptible(&pch->file.rwait); @@ -3136,6 +3134,9 @@ ppp_disconnect_channel(struct channel *pch) */ static void ppp_destroy_channel(struct channel *pch) { + put_net(pch->chan_net); + pch->chan_net = NULL; + atomic_dec(&channel_count); if (!pch->file.dead) { -- cgit v0.10.2 From 92f7d07d68c1dfcbb80b3259f29dad8efe890803 Mon Sep 17 00:00:00 2001 From: hayeswang Date: Wed, 6 Jul 2016 17:35:59 +0800 Subject: r8152: remove the setting of LAN_WAKE_EN The LAN_WAKE_EN is not used to determine if the device could support WOL. It is used to signal a GPIO pin when a WOL event occurs. The WOL still works even though it is disabled. Signed-off-by: Hayes Wang Signed-off-by: David S. Miller diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c index 0da72d3..419f4ce 100644 --- a/drivers/net/usb/r8152.c +++ b/drivers/net/usb/r8152.c @@ -2296,10 +2296,6 @@ static u32 __rtl_get_wol(struct r8152 *tp) u32 ocp_data; u32 wolopts = 0; - ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_CONFIG5); - if (!(ocp_data & LAN_WAKE_EN)) - return 0; - ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_CONFIG34); if (ocp_data & LINK_ON_WAKE_EN) wolopts |= WAKE_PHY; @@ -2332,15 +2328,13 @@ static void __rtl_set_wol(struct r8152 *tp, u32 wolopts) ocp_write_word(tp, MCU_TYPE_PLA, PLA_CONFIG34, ocp_data); ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_CONFIG5); - ocp_data &= ~(UWF_EN | BWF_EN | MWF_EN | LAN_WAKE_EN); + ocp_data &= ~(UWF_EN | BWF_EN | MWF_EN); if (wolopts & WAKE_UCAST) ocp_data |= UWF_EN; if (wolopts & WAKE_BCAST) ocp_data |= BWF_EN; if (wolopts & WAKE_MCAST) ocp_data |= MWF_EN; - if (wolopts & WAKE_ANY) - ocp_data |= LAN_WAKE_EN; ocp_write_word(tp, MCU_TYPE_PLA, PLA_CONFIG5, ocp_data); ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CRWECR, CRWECR_NORAML); -- cgit v0.10.2 From 9acacc2ac525ef1397af63b15cef7bb77a823c06 Mon Sep 17 00:00:00 2001 From: Zhao Lei Date: Mon, 20 Jun 2016 17:37:18 +0800 Subject: sched/cpuacct: Merge cpuacct_usage_index and cpuacct_stat_index enums These two types have similar function, no need to separate them. Signed-off-by: Zhao Lei Cc: KOSAKI Motohiro Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/436748885270d64363c7dc67167507d486c2057a.1466415271.git.zhaolei@cn.fujitsu.com Signed-off-by: Ingo Molnar diff --git a/kernel/sched/cpuacct.c b/kernel/sched/cpuacct.c index 41f85c4..74241eb 100644 --- a/kernel/sched/cpuacct.c +++ b/kernel/sched/cpuacct.c @@ -25,15 +25,13 @@ enum cpuacct_stat_index { CPUACCT_STAT_NSTATS, }; -enum cpuacct_usage_index { - CPUACCT_USAGE_USER, /* ... user mode */ - CPUACCT_USAGE_SYSTEM, /* ... kernel mode */ - - CPUACCT_USAGE_NRUSAGE, +static const char * const cpuacct_stat_desc[] = { + [CPUACCT_STAT_USER] = "user", + [CPUACCT_STAT_SYSTEM] = "system", }; struct cpuacct_usage { - u64 usages[CPUACCT_USAGE_NRUSAGE]; + u64 usages[CPUACCT_STAT_NSTATS]; }; /* track cpu usage of a group of tasks and its child groups */ @@ -108,16 +106,16 @@ static void cpuacct_css_free(struct cgroup_subsys_state *css) } static u64 cpuacct_cpuusage_read(struct cpuacct *ca, int cpu, - enum cpuacct_usage_index index) + enum cpuacct_stat_index index) { struct cpuacct_usage *cpuusage = per_cpu_ptr(ca->cpuusage, cpu); u64 data; /* - * We allow index == CPUACCT_USAGE_NRUSAGE here to read + * We allow index == CPUACCT_STAT_NSTATS here to read * the sum of suages. */ - BUG_ON(index > CPUACCT_USAGE_NRUSAGE); + BUG_ON(index > CPUACCT_STAT_NSTATS); #ifndef CONFIG_64BIT /* @@ -126,11 +124,11 @@ static u64 cpuacct_cpuusage_read(struct cpuacct *ca, int cpu, raw_spin_lock_irq(&cpu_rq(cpu)->lock); #endif - if (index == CPUACCT_USAGE_NRUSAGE) { + if (index == CPUACCT_STAT_NSTATS) { int i = 0; data = 0; - for (i = 0; i < CPUACCT_USAGE_NRUSAGE; i++) + for (i = 0; i < CPUACCT_STAT_NSTATS; i++) data += cpuusage->usages[i]; } else { data = cpuusage->usages[index]; @@ -155,7 +153,7 @@ static void cpuacct_cpuusage_write(struct cpuacct *ca, int cpu, u64 val) raw_spin_lock_irq(&cpu_rq(cpu)->lock); #endif - for (i = 0; i < CPUACCT_USAGE_NRUSAGE; i++) + for (i = 0; i < CPUACCT_STAT_NSTATS; i++) cpuusage->usages[i] = val; #ifndef CONFIG_64BIT @@ -165,7 +163,7 @@ static void cpuacct_cpuusage_write(struct cpuacct *ca, int cpu, u64 val) /* return total cpu usage (in nanoseconds) of a group */ static u64 __cpuusage_read(struct cgroup_subsys_state *css, - enum cpuacct_usage_index index) + enum cpuacct_stat_index index) { struct cpuacct *ca = css_ca(css); u64 totalcpuusage = 0; @@ -180,18 +178,18 @@ static u64 __cpuusage_read(struct cgroup_subsys_state *css, static u64 cpuusage_user_read(struct cgroup_subsys_state *css, struct cftype *cft) { - return __cpuusage_read(css, CPUACCT_USAGE_USER); + return __cpuusage_read(css, CPUACCT_STAT_USER); } static u64 cpuusage_sys_read(struct cgroup_subsys_state *css, struct cftype *cft) { - return __cpuusage_read(css, CPUACCT_USAGE_SYSTEM); + return __cpuusage_read(css, CPUACCT_STAT_SYSTEM); } static u64 cpuusage_read(struct cgroup_subsys_state *css, struct cftype *cft) { - return __cpuusage_read(css, CPUACCT_USAGE_NRUSAGE); + return __cpuusage_read(css, CPUACCT_STAT_NSTATS); } static int cpuusage_write(struct cgroup_subsys_state *css, struct cftype *cft, @@ -213,7 +211,7 @@ static int cpuusage_write(struct cgroup_subsys_state *css, struct cftype *cft, } static int __cpuacct_percpu_seq_show(struct seq_file *m, - enum cpuacct_usage_index index) + enum cpuacct_stat_index index) { struct cpuacct *ca = css_ca(seq_css(m)); u64 percpu; @@ -229,24 +227,19 @@ static int __cpuacct_percpu_seq_show(struct seq_file *m, static int cpuacct_percpu_user_seq_show(struct seq_file *m, void *V) { - return __cpuacct_percpu_seq_show(m, CPUACCT_USAGE_USER); + return __cpuacct_percpu_seq_show(m, CPUACCT_STAT_USER); } static int cpuacct_percpu_sys_seq_show(struct seq_file *m, void *V) { - return __cpuacct_percpu_seq_show(m, CPUACCT_USAGE_SYSTEM); + return __cpuacct_percpu_seq_show(m, CPUACCT_STAT_SYSTEM); } static int cpuacct_percpu_seq_show(struct seq_file *m, void *V) { - return __cpuacct_percpu_seq_show(m, CPUACCT_USAGE_NRUSAGE); + return __cpuacct_percpu_seq_show(m, CPUACCT_STAT_NSTATS); } -static const char * const cpuacct_stat_desc[] = { - [CPUACCT_STAT_USER] = "user", - [CPUACCT_STAT_SYSTEM] = "system", -}; - static int cpuacct_stats_show(struct seq_file *sf, void *v) { struct cpuacct *ca = css_ca(seq_css(sf)); @@ -316,11 +309,11 @@ static struct cftype files[] = { void cpuacct_charge(struct task_struct *tsk, u64 cputime) { struct cpuacct *ca; - int index = CPUACCT_USAGE_SYSTEM; + int index = CPUACCT_STAT_SYSTEM; struct pt_regs *regs = task_pt_regs(tsk); if (regs && user_mode(regs)) - index = CPUACCT_USAGE_USER; + index = CPUACCT_STAT_USER; rcu_read_lock(); -- cgit v0.10.2 From 8e546bfafb3121ed25c73a0c02311ec58459344a Mon Sep 17 00:00:00 2001 From: Zhao Lei Date: Mon, 20 Jun 2016 17:37:19 +0800 Subject: sched/cpuacct: Use loop to consolidate code in cpuacct_stats_show() In cpuacct_stats_show() we currently we have copies of similar code, for each cpustat(system/user) variant. Use a loop instead to consolidate the code. This will also work better if we extend the CPUACCT_STAT_NSTATS type. Signed-off-by: Zhao Lei Cc: KOSAKI Motohiro Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/b0597d4224655e9f333f1a6224ed9654c7d7d36a.1466415271.git.zhaolei@cn.fujitsu.com Signed-off-by: Ingo Molnar diff --git a/kernel/sched/cpuacct.c b/kernel/sched/cpuacct.c index 74241eb..677cd1a 100644 --- a/kernel/sched/cpuacct.c +++ b/kernel/sched/cpuacct.c @@ -243,27 +243,26 @@ static int cpuacct_percpu_seq_show(struct seq_file *m, void *V) static int cpuacct_stats_show(struct seq_file *sf, void *v) { struct cpuacct *ca = css_ca(seq_css(sf)); + s64 val[CPUACCT_STAT_NSTATS]; int cpu; - s64 val = 0; + int stat; + memset(val, 0, sizeof(val)); for_each_possible_cpu(cpu) { - struct kernel_cpustat *kcpustat = per_cpu_ptr(ca->cpustat, cpu); - val += kcpustat->cpustat[CPUTIME_USER]; - val += kcpustat->cpustat[CPUTIME_NICE]; - } - val = cputime64_to_clock_t(val); - seq_printf(sf, "%s %lld\n", cpuacct_stat_desc[CPUACCT_STAT_USER], val); + u64 *cpustat = per_cpu_ptr(ca->cpustat, cpu)->cpustat; - val = 0; - for_each_possible_cpu(cpu) { - struct kernel_cpustat *kcpustat = per_cpu_ptr(ca->cpustat, cpu); - val += kcpustat->cpustat[CPUTIME_SYSTEM]; - val += kcpustat->cpustat[CPUTIME_IRQ]; - val += kcpustat->cpustat[CPUTIME_SOFTIRQ]; + val[CPUACCT_STAT_USER] += cpustat[CPUTIME_USER]; + val[CPUACCT_STAT_USER] += cpustat[CPUTIME_NICE]; + val[CPUACCT_STAT_SYSTEM] += cpustat[CPUTIME_SYSTEM]; + val[CPUACCT_STAT_SYSTEM] += cpustat[CPUTIME_IRQ]; + val[CPUACCT_STAT_SYSTEM] += cpustat[CPUTIME_SOFTIRQ]; } - val = cputime64_to_clock_t(val); - seq_printf(sf, "%s %lld\n", cpuacct_stat_desc[CPUACCT_STAT_SYSTEM], val); + for (stat = 0; stat < CPUACCT_STAT_NSTATS; stat++) { + seq_printf(sf, "%s %lld\n", + cpuacct_stat_desc[stat], + cputime64_to_clock_t(val[stat])); + } return 0; } -- cgit v0.10.2 From 277a13e4f0d661678a7084bf97ed96a99c7dac21 Mon Sep 17 00:00:00 2001 From: Zhao Lei Date: Mon, 20 Jun 2016 17:37:20 +0800 Subject: sched/cpuacct: Introduce cpuacct.usage_all to show all CPU stats together In current code, we can get cpuacct data from several files, but each file has various limitations. For example: - We can get CPU usage in user and kernel mode via cpuacct.stat, but we can't get detailed data about each CPU. - We can get each CPU's kernel mode usage in cpuacct.usage_percpu_sys, but we can't get user mode usage data at the same time. This patch introduces cpuacct.usage_all, to show all detailed CPU accounting data together: # cat cpuacct.usage_all cpu user system 0 3809760299 5807968992 1 3250329855 454612211 .. Signed-off-by: Zhao Lei Cc: KOSAKI Motohiro Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/7744460969edd7caaf0e903592ee52353ed9bdd6.1466415271.git.zhaolei@cn.fujitsu.com Signed-off-by: Ingo Molnar diff --git a/kernel/sched/cpuacct.c b/kernel/sched/cpuacct.c index 677cd1a..bc0b309c 100644 --- a/kernel/sched/cpuacct.c +++ b/kernel/sched/cpuacct.c @@ -240,6 +240,42 @@ static int cpuacct_percpu_seq_show(struct seq_file *m, void *V) return __cpuacct_percpu_seq_show(m, CPUACCT_STAT_NSTATS); } +static int cpuacct_all_seq_show(struct seq_file *m, void *V) +{ + struct cpuacct *ca = css_ca(seq_css(m)); + int index; + int cpu; + + seq_puts(m, "cpu"); + for (index = 0; index < CPUACCT_STAT_NSTATS; index++) + seq_printf(m, " %s", cpuacct_stat_desc[index]); + seq_puts(m, "\n"); + + for_each_possible_cpu(cpu) { + struct cpuacct_usage *cpuusage = per_cpu_ptr(ca->cpuusage, cpu); + + seq_printf(m, "%d", cpu); + + for (index = 0; index < CPUACCT_STAT_NSTATS; index++) { +#ifndef CONFIG_64BIT + /* + * Take rq->lock to make 64-bit read safe on 32-bit + * platforms. + */ + raw_spin_lock_irq(&cpu_rq(cpu)->lock); +#endif + + seq_printf(m, " %llu", cpuusage->usages[index]); + +#ifndef CONFIG_64BIT + raw_spin_unlock_irq(&cpu_rq(cpu)->lock); +#endif + } + seq_puts(m, "\n"); + } + return 0; +} + static int cpuacct_stats_show(struct seq_file *sf, void *v) { struct cpuacct *ca = css_ca(seq_css(sf)); @@ -294,6 +330,10 @@ static struct cftype files[] = { .seq_show = cpuacct_percpu_sys_seq_show, }, { + .name = "usage_all", + .seq_show = cpuacct_all_seq_show, + }, + { .name = "stat", .seq_show = cpuacct_stats_show, }, -- cgit v0.10.2 From 62d855d3e725f4e4b0d2786f7cad3f0660a03a59 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Sat, 18 Jun 2016 18:51:34 +0300 Subject: x86/platform/intel-mid: Rename mrfl.c to mrfld.c Use mrfld as an abbreviation of Merrifield to be consistent with the rest of the code. In the future we are going to add more files here prefixed with 'mrfld'. Signed-off-by: Andy Shevchenko Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/1466265094-146113-1-git-send-email-andriy.shevchenko@linux.intel.com Signed-off-by: Ingo Molnar diff --git a/arch/x86/platform/intel-mid/Makefile b/arch/x86/platform/intel-mid/Makefile index aebb5b9..fa021df 100644 --- a/arch/x86/platform/intel-mid/Makefile +++ b/arch/x86/platform/intel-mid/Makefile @@ -1,4 +1,4 @@ -obj-$(CONFIG_X86_INTEL_MID) += intel-mid.o intel_mid_vrtc.o mfld.o mrfl.o pwr.o +obj-$(CONFIG_X86_INTEL_MID) += intel-mid.o intel_mid_vrtc.o mfld.o mrfld.o pwr.o # SFI specific code ifdef CONFIG_X86_INTEL_MID diff --git a/arch/x86/platform/intel-mid/mrfl.c b/arch/x86/platform/intel-mid/mrfl.c deleted file mode 100644 index bd1adc6..0000000 --- a/arch/x86/platform/intel-mid/mrfl.c +++ /dev/null @@ -1,100 +0,0 @@ -/* - * mrfl.c: Intel Merrifield platform specific setup code - * - * (C) Copyright 2013 Intel Corporation - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; version 2 - * of the License. - */ - -#include - -#include -#include - -#include "intel_mid_weak_decls.h" - -static unsigned long __init tangier_calibrate_tsc(void) -{ - unsigned long fast_calibrate; - u32 lo, hi, ratio, fsb, bus_freq; - - /* *********************** */ - /* Compute TSC:Ratio * FSB */ - /* *********************** */ - - /* Compute Ratio */ - rdmsr(MSR_PLATFORM_INFO, lo, hi); - pr_debug("IA32 PLATFORM_INFO is 0x%x : %x\n", hi, lo); - - ratio = (lo >> 8) & 0xFF; - pr_debug("ratio is %d\n", ratio); - if (!ratio) { - pr_err("Read a zero ratio, force tsc ratio to 4 ...\n"); - ratio = 4; - } - - /* Compute FSB */ - rdmsr(MSR_FSB_FREQ, lo, hi); - pr_debug("Actual FSB frequency detected by SOC 0x%x : %x\n", - hi, lo); - - bus_freq = lo & 0x7; - pr_debug("bus_freq = 0x%x\n", bus_freq); - - if (bus_freq == 0) - fsb = FSB_FREQ_100SKU; - else if (bus_freq == 1) - fsb = FSB_FREQ_100SKU; - else if (bus_freq == 2) - fsb = FSB_FREQ_133SKU; - else if (bus_freq == 3) - fsb = FSB_FREQ_167SKU; - else if (bus_freq == 4) - fsb = FSB_FREQ_83SKU; - else if (bus_freq == 5) - fsb = FSB_FREQ_400SKU; - else if (bus_freq == 6) - fsb = FSB_FREQ_267SKU; - else if (bus_freq == 7) - fsb = FSB_FREQ_333SKU; - else { - BUG(); - pr_err("Invalid bus_freq! Setting to minimal value!\n"); - fsb = FSB_FREQ_100SKU; - } - - /* TSC = FSB Freq * Resolved HFM Ratio */ - fast_calibrate = ratio * fsb; - pr_debug("calculate tangier tsc %lu KHz\n", fast_calibrate); - - /* ************************************ */ - /* Calculate Local APIC Timer Frequency */ - /* ************************************ */ - lapic_timer_frequency = (fsb * 1000) / HZ; - - pr_debug("Setting lapic_timer_frequency = %d\n", - lapic_timer_frequency); - - /* mark tsc clocksource as reliable */ - set_cpu_cap(&boot_cpu_data, X86_FEATURE_TSC_RELIABLE); - - return fast_calibrate; -} - -static void __init tangier_arch_setup(void) -{ - x86_platform.calibrate_tsc = tangier_calibrate_tsc; -} - -/* tangier arch ops */ -static struct intel_mid_ops tangier_ops = { - .arch_setup = tangier_arch_setup, -}; - -void *get_tangier_ops(void) -{ - return &tangier_ops; -} diff --git a/arch/x86/platform/intel-mid/mrfld.c b/arch/x86/platform/intel-mid/mrfld.c new file mode 100644 index 0000000..59253db --- /dev/null +++ b/arch/x86/platform/intel-mid/mrfld.c @@ -0,0 +1,100 @@ +/* + * Intel Merrifield platform specific setup code + * + * (C) Copyright 2013 Intel Corporation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; version 2 + * of the License. + */ + +#include + +#include +#include + +#include "intel_mid_weak_decls.h" + +static unsigned long __init tangier_calibrate_tsc(void) +{ + unsigned long fast_calibrate; + u32 lo, hi, ratio, fsb, bus_freq; + + /* *********************** */ + /* Compute TSC:Ratio * FSB */ + /* *********************** */ + + /* Compute Ratio */ + rdmsr(MSR_PLATFORM_INFO, lo, hi); + pr_debug("IA32 PLATFORM_INFO is 0x%x : %x\n", hi, lo); + + ratio = (lo >> 8) & 0xFF; + pr_debug("ratio is %d\n", ratio); + if (!ratio) { + pr_err("Read a zero ratio, force tsc ratio to 4 ...\n"); + ratio = 4; + } + + /* Compute FSB */ + rdmsr(MSR_FSB_FREQ, lo, hi); + pr_debug("Actual FSB frequency detected by SOC 0x%x : %x\n", + hi, lo); + + bus_freq = lo & 0x7; + pr_debug("bus_freq = 0x%x\n", bus_freq); + + if (bus_freq == 0) + fsb = FSB_FREQ_100SKU; + else if (bus_freq == 1) + fsb = FSB_FREQ_100SKU; + else if (bus_freq == 2) + fsb = FSB_FREQ_133SKU; + else if (bus_freq == 3) + fsb = FSB_FREQ_167SKU; + else if (bus_freq == 4) + fsb = FSB_FREQ_83SKU; + else if (bus_freq == 5) + fsb = FSB_FREQ_400SKU; + else if (bus_freq == 6) + fsb = FSB_FREQ_267SKU; + else if (bus_freq == 7) + fsb = FSB_FREQ_333SKU; + else { + BUG(); + pr_err("Invalid bus_freq! Setting to minimal value!\n"); + fsb = FSB_FREQ_100SKU; + } + + /* TSC = FSB Freq * Resolved HFM Ratio */ + fast_calibrate = ratio * fsb; + pr_debug("calculate tangier tsc %lu KHz\n", fast_calibrate); + + /* ************************************ */ + /* Calculate Local APIC Timer Frequency */ + /* ************************************ */ + lapic_timer_frequency = (fsb * 1000) / HZ; + + pr_debug("Setting lapic_timer_frequency = %d\n", + lapic_timer_frequency); + + /* mark tsc clocksource as reliable */ + set_cpu_cap(&boot_cpu_data, X86_FEATURE_TSC_RELIABLE); + + return fast_calibrate; +} + +static void __init tangier_arch_setup(void) +{ + x86_platform.calibrate_tsc = tangier_calibrate_tsc; +} + +/* tangier arch ops */ +static struct intel_mid_ops tangier_ops = { + .arch_setup = tangier_arch_setup, +}; + +void *get_tangier_ops(void) +{ + return &tangier_ops; +} -- cgit v0.10.2 From 8709ed4d4b0eab04561c1ec9e6ea50fd1e3897ff Mon Sep 17 00:00:00 2001 From: Dave Hansen Date: Fri, 17 Jun 2016 17:15:03 -0700 Subject: x86/cpu: Fix duplicated X86_BUG(9) macro cpufeatures.h currently defines X86_BUG(9) twice on 32-bit: #define X86_BUG_NULL_SEG X86_BUG(9) /* Nulling a selector preserves the base */ ... #ifdef CONFIG_X86_32 #define X86_BUG_ESPFIX X86_BUG(9) /* "" IRET to 16-bit SS corrupts ESP/RSP high bits */ #endif I think what happened was that this added the X86_BUG_ESPFIX, but in an #ifdef below most of the bugs: 58a5aac53313 x86/entry/32: Introduce and use X86_BUG_ESPFIX instead of paravirt_enabled Then this came along and added X86_BUG_NULL_SEG, but collided with the earlier one that did the bug below the main block defining all the X86_BUG()s. 7a5d67048745 x86/cpu: Probe the behavior of nulling out a segment at boot time Signed-off-by: Dave Hansen Acked-by: Andy Lutomirski Cc: Andy Lutomirski Cc: Borislav Petkov Cc: Brian Gerst Cc: Dave Hansen Cc: Denys Vlasenko Cc: H. Peter Anvin Cc: Josh Poimboeuf Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: stable@vger.kernel.org Link: http://lkml.kernel.org/r/20160618001503.CEE1B141@viggo.jf.intel.com Signed-off-by: Ingo Molnar diff --git a/arch/x86/include/asm/cpufeatures.h b/arch/x86/include/asm/cpufeatures.h index 4a41348..c64b1e9 100644 --- a/arch/x86/include/asm/cpufeatures.h +++ b/arch/x86/include/asm/cpufeatures.h @@ -301,10 +301,6 @@ #define X86_BUG_FXSAVE_LEAK X86_BUG(6) /* FXSAVE leaks FOP/FIP/FOP */ #define X86_BUG_CLFLUSH_MONITOR X86_BUG(7) /* AAI65, CLFLUSH required before MONITOR */ #define X86_BUG_SYSRET_SS_ATTRS X86_BUG(8) /* SYSRET doesn't fix up SS attrs */ -#define X86_BUG_NULL_SEG X86_BUG(9) /* Nulling a selector preserves the base */ -#define X86_BUG_SWAPGS_FENCE X86_BUG(10) /* SWAPGS without input dep on GS */ - - #ifdef CONFIG_X86_32 /* * 64-bit kernels don't use X86_BUG_ESPFIX. Make the define conditional @@ -312,5 +308,7 @@ */ #define X86_BUG_ESPFIX X86_BUG(9) /* "" IRET to 16-bit SS corrupts ESP/RSP high bits */ #endif +#define X86_BUG_NULL_SEG X86_BUG(10) /* Nulling a selector preserves the base */ +#define X86_BUG_SWAPGS_FENCE X86_BUG(11) /* SWAPGS without input dep on GS */ #endif /* _ASM_X86_CPUFEATURES_H */ -- cgit v0.10.2 From 9e37d3e2298e7ca2a9d210532c77a325d07816fe Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Sun, 19 Jun 2016 17:06:48 -0700 Subject: hwmon: (lm75) Handle cleanup with devm_add_action Use devm_add_action() to register the function to restore the original chip configuration. Use devm_hwmon_device_register_with_groups() to register the hwmon device, and drop the remove function as no longer needed. Signed-off-by: Guenter Roeck diff --git a/drivers/hwmon/lm75.c b/drivers/hwmon/lm75.c index 69166ab..0df7455 100644 --- a/drivers/hwmon/lm75.c +++ b/drivers/hwmon/lm75.c @@ -76,7 +76,6 @@ static const u8 LM75_REG_TEMP[3] = { /* Each client has this additional data */ struct lm75_data { struct i2c_client *client; - struct device *hwmon_dev; struct mutex update_lock; u8 orig_conf; u8 resolution; /* In bits, between 9 and 12 */ @@ -185,10 +184,19 @@ static const struct thermal_zone_of_device_ops lm75_of_thermal_ops = { /* device probe and removal */ +static void lm75_remove(void *data) +{ + struct lm75_data *lm75 = data; + struct i2c_client *client = lm75->client; + + i2c_smbus_write_byte_data(client, LM75_REG_CONF, lm75->orig_conf); +} + static int lm75_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct device *dev = &client->dev; + struct device *hwmon_dev; struct lm75_data *data; int status; u8 set_mask, clr_mask; @@ -298,29 +306,22 @@ lm75_probe(struct i2c_client *client, const struct i2c_device_id *id) new |= set_mask; if (status != new) lm75_write_value(client, LM75_REG_CONF, new); - dev_dbg(dev, "Config %02x\n", new); - data->hwmon_dev = hwmon_device_register_with_groups(dev, client->name, - data, lm75_groups); - if (IS_ERR(data->hwmon_dev)) - return PTR_ERR(data->hwmon_dev); + devm_add_action(dev, lm75_remove, data); - devm_thermal_zone_of_sensor_register(data->hwmon_dev, 0, - data->hwmon_dev, - &lm75_of_thermal_ops); + dev_dbg(dev, "Config %02x\n", new); - dev_info(dev, "%s: sensor '%s'\n", - dev_name(data->hwmon_dev), client->name); + hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name, + data, lm75_groups); + if (IS_ERR(hwmon_dev)) + return PTR_ERR(hwmon_dev); - return 0; -} + devm_thermal_zone_of_sensor_register(hwmon_dev, 0, + hwmon_dev, + &lm75_of_thermal_ops); -static int lm75_remove(struct i2c_client *client) -{ - struct lm75_data *data = i2c_get_clientdata(client); + dev_info(dev, "%s: sensor '%s'\n", dev_name(hwmon_dev), client->name); - hwmon_device_unregister(data->hwmon_dev); - lm75_write_value(client, LM75_REG_CONF, data->orig_conf); return 0; } @@ -489,7 +490,6 @@ static struct i2c_driver lm75_driver = { .pm = LM75_DEV_PM_OPS, }, .probe = lm75_probe, - .remove = lm75_remove, .id_table = lm75_ids, .detect = lm75_detect, .address_list = normal_i2c, -- cgit v0.10.2 From 38aefb41b3803873dc366918a2e22f22dca78eac Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Sun, 19 Jun 2016 17:11:13 -0700 Subject: hwmon: (lm75) Drop lm75_read_value and lm75_write_value lm75_read_value and lm75_write_value don't really add any value. Replace with direct smbus access functions. Signed-off-by: Guenter Roeck diff --git a/drivers/hwmon/lm75.c b/drivers/hwmon/lm75.c index 0df7455..7b18cbd 100644 --- a/drivers/hwmon/lm75.c +++ b/drivers/hwmon/lm75.c @@ -89,8 +89,6 @@ struct lm75_data { 2 = hyst */ }; -static int lm75_read_value(struct i2c_client *client, u8 reg); -static int lm75_write_value(struct i2c_client *client, u8 reg, u16 value); static struct lm75_data *lm75_update_device(struct device *dev); @@ -156,7 +154,7 @@ static ssize_t set_temp(struct device *dev, struct device_attribute *da, temp = clamp_val(temp, LM75_TEMP_MIN, LM75_TEMP_MAX); data->temp[nr] = DIV_ROUND_CLOSEST(temp << (resolution - 8), 1000) << (16 - resolution); - lm75_write_value(client, LM75_REG_TEMP[nr], data->temp[nr]); + i2c_smbus_write_word_swapped(client, LM75_REG_TEMP[nr], data->temp[nr]); mutex_unlock(&data->update_lock); return count; } @@ -296,7 +294,7 @@ lm75_probe(struct i2c_client *client, const struct i2c_device_id *id) } /* configure as specified */ - status = lm75_read_value(client, LM75_REG_CONF); + status = i2c_smbus_read_byte_data(client, LM75_REG_CONF); if (status < 0) { dev_dbg(dev, "Can't read config? %d\n", status); return status; @@ -305,7 +303,7 @@ lm75_probe(struct i2c_client *client, const struct i2c_device_id *id) new = status & ~clr_mask; new |= set_mask; if (status != new) - lm75_write_value(client, LM75_REG_CONF, new); + i2c_smbus_write_byte_data(client, LM75_REG_CONF, new); devm_add_action(dev, lm75_remove, data); @@ -450,13 +448,13 @@ static int lm75_suspend(struct device *dev) { int status; struct i2c_client *client = to_i2c_client(dev); - status = lm75_read_value(client, LM75_REG_CONF); + status = i2c_smbus_read_byte_data(client, LM75_REG_CONF); if (status < 0) { dev_dbg(&client->dev, "Can't read config? %d\n", status); return status; } status = status | LM75_SHUTDOWN; - lm75_write_value(client, LM75_REG_CONF, status); + i2c_smbus_write_byte_data(client, LM75_REG_CONF, status); return 0; } @@ -464,13 +462,13 @@ static int lm75_resume(struct device *dev) { int status; struct i2c_client *client = to_i2c_client(dev); - status = lm75_read_value(client, LM75_REG_CONF); + status = i2c_smbus_read_byte_data(client, LM75_REG_CONF); if (status < 0) { dev_dbg(&client->dev, "Can't read config? %d\n", status); return status; } status = status & ~LM75_SHUTDOWN; - lm75_write_value(client, LM75_REG_CONF, status); + i2c_smbus_write_byte_data(client, LM75_REG_CONF, status); return 0; } @@ -497,29 +495,6 @@ static struct i2c_driver lm75_driver = { /*-----------------------------------------------------------------------*/ -/* register access */ - -/* - * All registers are word-sized, except for the configuration register. - * LM75 uses a high-byte first convention, which is exactly opposite to - * the SMBus standard. - */ -static int lm75_read_value(struct i2c_client *client, u8 reg) -{ - if (reg == LM75_REG_CONF) - return i2c_smbus_read_byte_data(client, reg); - else - return i2c_smbus_read_word_swapped(client, reg); -} - -static int lm75_write_value(struct i2c_client *client, u8 reg, u16 value) -{ - if (reg == LM75_REG_CONF) - return i2c_smbus_write_byte_data(client, reg, value); - else - return i2c_smbus_write_word_swapped(client, reg, value); -} - static struct lm75_data *lm75_update_device(struct device *dev) { struct lm75_data *data = dev_get_drvdata(dev); @@ -536,7 +511,8 @@ static struct lm75_data *lm75_update_device(struct device *dev) for (i = 0; i < ARRAY_SIZE(data->temp); i++) { int status; - status = lm75_read_value(client, LM75_REG_TEMP[i]); + status = i2c_smbus_read_word_swapped(client, + LM75_REG_TEMP[i]); if (unlikely(status < 0)) { dev_dbg(dev, "LM75: Failed to read value: reg %d, error %d\n", -- cgit v0.10.2 From 5f7e5e29ab60967a009d307dc4fdecce57efaa9c Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Sun, 19 Jun 2016 17:56:22 -0700 Subject: hwmon: (lm75) Add update_interval attribute Since we know the chip's update interval, let's make it available to the user. Signed-off-by: Guenter Roeck diff --git a/drivers/hwmon/lm75.c b/drivers/hwmon/lm75.c index 7b18cbd..fe83f70 100644 --- a/drivers/hwmon/lm75.c +++ b/drivers/hwmon/lm75.c @@ -159,16 +159,29 @@ static ssize_t set_temp(struct device *dev, struct device_attribute *da, return count; } +static ssize_t show_update_interval(struct device *dev, + struct device_attribute *da, char *buf) +{ + struct lm75_data *data = lm75_update_device(dev); + + if (IS_ERR(data)) + return PTR_ERR(data); + + return sprintf(buf, "%u\n", jiffies_to_msecs(data->sample_time)); +} + static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp, set_temp, 1); static SENSOR_DEVICE_ATTR(temp1_max_hyst, S_IWUSR | S_IRUGO, show_temp, set_temp, 2); static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL, 0); +static DEVICE_ATTR(update_interval, S_IRUGO, show_update_interval, NULL); static struct attribute *lm75_attrs[] = { &sensor_dev_attr_temp1_input.dev_attr.attr, &sensor_dev_attr_temp1_max.dev_attr.attr, &sensor_dev_attr_temp1_max_hyst.dev_attr.attr, + &dev_attr_update_interval.attr, NULL }; -- cgit v0.10.2 From e65365fed87f5385c04124b6e7ab8967ca600b26 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Sun, 19 Jun 2016 17:49:19 -0700 Subject: hwmon: (lm75) Convert to use regmap Convert to use regmap. Leave caching to regmap and drop the register update function. While this can result in additional read operations if the temperature register is read continuously, it avoids re-reading the limit registers and thus overall reduces complexity. Signed-off-by: Guenter Roeck diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index 91f145e..f271353 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -958,6 +958,7 @@ config SENSORS_LM75 tristate "National Semiconductor LM75 and compatibles" depends on I2C depends on THERMAL || !THERMAL_OF + select REGMAP_I2C help If you say yes here you get support for one common type of temperature sensor chip, with models including: diff --git a/drivers/hwmon/lm75.c b/drivers/hwmon/lm75.c index fe83f70..547a9c8 100644 --- a/drivers/hwmon/lm75.c +++ b/drivers/hwmon/lm75.c @@ -26,8 +26,8 @@ #include #include #include -#include #include +#include #include #include "lm75.h" @@ -66,32 +66,21 @@ static const unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4b, 0x4c, /* The LM75 registers */ +#define LM75_REG_TEMP 0x00 #define LM75_REG_CONF 0x01 -static const u8 LM75_REG_TEMP[3] = { - 0x00, /* input */ - 0x03, /* max */ - 0x02, /* hyst */ -}; +#define LM75_REG_HYST 0x02 +#define LM75_REG_MAX 0x03 /* Each client has this additional data */ struct lm75_data { struct i2c_client *client; - struct mutex update_lock; + struct regmap *regmap; u8 orig_conf; u8 resolution; /* In bits, between 9 and 12 */ u8 resolution_limits; - char valid; /* !=0 if registers are valid */ - unsigned long last_updated; /* In jiffies */ - unsigned long sample_time; /* In jiffies */ - s16 temp[3]; /* Register values, - 0 = input - 1 = max - 2 = hyst */ + unsigned int sample_time; /* In ms */ }; -static struct lm75_data *lm75_update_device(struct device *dev); - - /*-----------------------------------------------------------------------*/ static inline long lm75_reg_to_mc(s16 temp, u8 resolution) @@ -103,12 +92,15 @@ static inline long lm75_reg_to_mc(s16 temp, u8 resolution) static int lm75_read_temp(void *dev, int *temp) { - struct lm75_data *data = lm75_update_device(dev); + struct lm75_data *data = dev_get_drvdata(dev); + unsigned int _temp; + int err; - if (IS_ERR(data)) - return PTR_ERR(data); + err = regmap_read(data->regmap, LM75_REG_TEMP, &_temp); + if (err < 0) + return err; - *temp = lm75_reg_to_mc(data->temp[0], data->resolution); + *temp = lm75_reg_to_mc(_temp, data->resolution); return 0; } @@ -117,13 +109,15 @@ static ssize_t show_temp(struct device *dev, struct device_attribute *da, char *buf) { struct sensor_device_attribute *attr = to_sensor_dev_attr(da); - struct lm75_data *data = lm75_update_device(dev); + struct lm75_data *data = dev_get_drvdata(dev); + unsigned int temp = 0; + int err; - if (IS_ERR(data)) - return PTR_ERR(data); + err = regmap_read(data->regmap, attr->index, &temp); + if (err < 0) + return err; - return sprintf(buf, "%ld\n", lm75_reg_to_mc(data->temp[attr->index], - data->resolution)); + return sprintf(buf, "%ld\n", lm75_reg_to_mc(temp, data->resolution)); } static ssize_t set_temp(struct device *dev, struct device_attribute *da, @@ -131,8 +125,6 @@ static ssize_t set_temp(struct device *dev, struct device_attribute *da, { struct sensor_device_attribute *attr = to_sensor_dev_attr(da); struct lm75_data *data = dev_get_drvdata(dev); - struct i2c_client *client = data->client; - int nr = attr->index; long temp; int error; u8 resolution; @@ -150,31 +142,29 @@ static ssize_t set_temp(struct device *dev, struct device_attribute *da, else resolution = data->resolution; - mutex_lock(&data->update_lock); temp = clamp_val(temp, LM75_TEMP_MIN, LM75_TEMP_MAX); - data->temp[nr] = DIV_ROUND_CLOSEST(temp << (resolution - 8), - 1000) << (16 - resolution); - i2c_smbus_write_word_swapped(client, LM75_REG_TEMP[nr], data->temp[nr]); - mutex_unlock(&data->update_lock); + temp = DIV_ROUND_CLOSEST(temp << (resolution - 8), + 1000) << (16 - resolution); + error = regmap_write(data->regmap, attr->index, temp); + if (error < 0) + return error; + return count; } static ssize_t show_update_interval(struct device *dev, struct device_attribute *da, char *buf) { - struct lm75_data *data = lm75_update_device(dev); - - if (IS_ERR(data)) - return PTR_ERR(data); + struct lm75_data *data = dev_get_drvdata(dev); - return sprintf(buf, "%u\n", jiffies_to_msecs(data->sample_time)); + return sprintf(buf, "%u\n", data->sample_time); } static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, - show_temp, set_temp, 1); + show_temp, set_temp, LM75_REG_MAX); static SENSOR_DEVICE_ATTR(temp1_max_hyst, S_IWUSR | S_IRUGO, - show_temp, set_temp, 2); -static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL, 0); + show_temp, set_temp, LM75_REG_HYST); +static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL, LM75_REG_TEMP); static DEVICE_ATTR(update_interval, S_IRUGO, show_update_interval, NULL); static struct attribute *lm75_attrs[] = { @@ -195,6 +185,27 @@ static const struct thermal_zone_of_device_ops lm75_of_thermal_ops = { /* device probe and removal */ +static bool lm75_is_writeable_reg(struct device *dev, unsigned int reg) +{ + return reg != LM75_REG_TEMP; +} + +static bool lm75_is_volatile_reg(struct device *dev, unsigned int reg) +{ + return reg == LM75_REG_TEMP; +} + +static const struct regmap_config lm75_regmap_config = { + .reg_bits = 8, + .val_bits = 16, + .max_register = LM75_REG_MAX, + .writeable_reg = lm75_is_writeable_reg, + .volatile_reg = lm75_is_volatile_reg, + .val_format_endian = REGMAP_ENDIAN_BIG, + .cache_type = REGCACHE_RBTREE, + .use_single_rw = true, +}; + static void lm75_remove(void *data) { struct lm75_data *lm75 = data; @@ -223,8 +234,10 @@ lm75_probe(struct i2c_client *client, const struct i2c_device_id *id) return -ENOMEM; data->client = client; - i2c_set_clientdata(client, data); - mutex_init(&data->update_lock); + + data->regmap = devm_regmap_init_i2c(client, &lm75_regmap_config); + if (IS_ERR(data->regmap)) + return PTR_ERR(data->regmap); /* Set to LM75 resolution (9 bits, 1/2 degree C) and range. * Then tweak to be more precise when appropriate. @@ -236,7 +249,7 @@ lm75_probe(struct i2c_client *client, const struct i2c_device_id *id) case adt75: clr_mask |= 1 << 5; /* not one-shot mode */ data->resolution = 12; - data->sample_time = HZ / 8; + data->sample_time = MSEC_PER_SEC / 8; break; case ds1775: case ds75: @@ -244,35 +257,35 @@ lm75_probe(struct i2c_client *client, const struct i2c_device_id *id) clr_mask |= 3 << 5; set_mask |= 2 << 5; /* 11-bit mode */ data->resolution = 11; - data->sample_time = HZ; + data->sample_time = MSEC_PER_SEC; break; case ds7505: set_mask |= 3 << 5; /* 12-bit mode */ data->resolution = 12; - data->sample_time = HZ / 4; + data->sample_time = MSEC_PER_SEC / 4; break; case g751: case lm75: case lm75a: data->resolution = 9; - data->sample_time = HZ / 2; + data->sample_time = MSEC_PER_SEC / 2; break; case lm75b: data->resolution = 11; - data->sample_time = HZ / 4; + data->sample_time = MSEC_PER_SEC / 4; break; case max6625: data->resolution = 9; - data->sample_time = HZ / 4; + data->sample_time = MSEC_PER_SEC / 4; break; case max6626: data->resolution = 12; data->resolution_limits = 9; - data->sample_time = HZ / 4; + data->sample_time = MSEC_PER_SEC / 4; break; case tcn75: data->resolution = 9; - data->sample_time = HZ / 8; + data->sample_time = MSEC_PER_SEC / 8; break; case mcp980x: data->resolution_limits = 9; @@ -281,14 +294,14 @@ lm75_probe(struct i2c_client *client, const struct i2c_device_id *id) case tmp101: set_mask |= 3 << 5; /* 12-bit mode */ data->resolution = 12; - data->sample_time = HZ; + data->sample_time = MSEC_PER_SEC; clr_mask |= 1 << 7; /* not one-shot mode */ break; case tmp112: set_mask |= 3 << 5; /* 12-bit mode */ clr_mask |= 1 << 7; /* not one-shot mode */ data->resolution = 12; - data->sample_time = HZ / 4; + data->sample_time = MSEC_PER_SEC / 4; break; case tmp105: case tmp175: @@ -297,12 +310,12 @@ lm75_probe(struct i2c_client *client, const struct i2c_device_id *id) set_mask |= 3 << 5; /* 12-bit mode */ clr_mask |= 1 << 7; /* not one-shot mode */ data->resolution = 12; - data->sample_time = HZ / 2; + data->sample_time = MSEC_PER_SEC / 2; break; case tmp75c: clr_mask |= 1 << 5; /* not one-shot mode */ data->resolution = 12; - data->sample_time = HZ / 4; + data->sample_time = MSEC_PER_SEC / 4; break; } @@ -506,45 +519,6 @@ static struct i2c_driver lm75_driver = { .address_list = normal_i2c, }; -/*-----------------------------------------------------------------------*/ - -static struct lm75_data *lm75_update_device(struct device *dev) -{ - struct lm75_data *data = dev_get_drvdata(dev); - struct i2c_client *client = data->client; - struct lm75_data *ret = data; - - mutex_lock(&data->update_lock); - - if (time_after(jiffies, data->last_updated + data->sample_time) - || !data->valid) { - int i; - dev_dbg(&client->dev, "Starting lm75 update\n"); - - for (i = 0; i < ARRAY_SIZE(data->temp); i++) { - int status; - - status = i2c_smbus_read_word_swapped(client, - LM75_REG_TEMP[i]); - if (unlikely(status < 0)) { - dev_dbg(dev, - "LM75: Failed to read value: reg %d, error %d\n", - LM75_REG_TEMP[i], status); - ret = ERR_PTR(status); - data->valid = 0; - goto abort; - } - data->temp[i] = status; - } - data->last_updated = jiffies; - data->valid = 1; - } - -abort: - mutex_unlock(&data->update_lock); - return ret; -} - module_i2c_driver(lm75_driver); MODULE_AUTHOR("Frodo Looijaard "); -- cgit v0.10.2 From 1f17a444b42bd7522016417a871f0485abeffda4 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Mon, 13 Jun 2016 06:19:11 -0700 Subject: hwmon: (lm90) Use devm_add_action for cleanup Use devm_add_action where possible to simplify error handling and cleanup on remove. Signed-off-by: Guenter Roeck diff --git a/drivers/hwmon/lm90.c b/drivers/hwmon/lm90.c index e30a593..4b530ef 100644 --- a/drivers/hwmon/lm90.c +++ b/drivers/hwmon/lm90.c @@ -369,7 +369,6 @@ struct lm90_data { struct device *hwmon_dev; const struct attribute_group *groups[6]; struct mutex update_lock; - struct regulator *regulator; char valid; /* zero until following fields are valid */ unsigned long last_updated; /* in jiffies */ int kind; @@ -1404,8 +1403,11 @@ static int lm90_detect(struct i2c_client *client, return 0; } -static void lm90_restore_conf(struct i2c_client *client, struct lm90_data *data) +static void lm90_restore_conf(void *_data) { + struct lm90_data *data = _data; + struct i2c_client *client = data->client; + /* Restore initial configuration */ i2c_smbus_write_byte_data(client, LM90_REG_W_CONVRATE, data->convrate_orig); @@ -1456,6 +1458,8 @@ static void lm90_init_client(struct i2c_client *client, struct lm90_data *data) config &= 0xBF; /* run */ if (config != data->config_orig) /* Only write if changed */ i2c_smbus_write_byte_data(client, LM90_REG_W_CONFIG1, config); + + devm_add_action(&client->dev, lm90_restore_conf, data); } static bool lm90_is_tripped(struct i2c_client *client, u16 *status) @@ -1506,6 +1510,16 @@ static irqreturn_t lm90_irq_thread(int irq, void *dev_id) return IRQ_NONE; } +static void lm90_remove_pec(void *dev) +{ + device_remove_file(dev, &dev_attr_pec); +} + +static void lm90_regulator_disable(void *regulator) +{ + regulator_disable(regulator); +} + static int lm90_probe(struct i2c_client *client, const struct i2c_device_id *id) { @@ -1526,6 +1540,8 @@ static int lm90_probe(struct i2c_client *client, return err; } + devm_add_action(dev, lm90_regulator_disable, regulator); + data = devm_kzalloc(dev, sizeof(struct lm90_data), GFP_KERNEL); if (!data) return -ENOMEM; @@ -1534,8 +1550,6 @@ static int lm90_probe(struct i2c_client *client, i2c_set_clientdata(client, data); mutex_init(&data->update_lock); - data->regulator = regulator; - /* Set the device type */ data->kind = id->driver_data; if (data->kind == adm1032) { @@ -1577,15 +1591,14 @@ static int lm90_probe(struct i2c_client *client, if (client->flags & I2C_CLIENT_PEC) { err = device_create_file(dev, &dev_attr_pec); if (err) - goto exit_restore; + return err; + devm_add_action(dev, lm90_remove_pec, dev); } data->hwmon_dev = hwmon_device_register_with_groups(dev, client->name, data, data->groups); - if (IS_ERR(data->hwmon_dev)) { - err = PTR_ERR(data->hwmon_dev); - goto exit_remove_pec; - } + if (IS_ERR(data->hwmon_dev)) + return PTR_ERR(data->hwmon_dev); if (client->irq) { dev_dbg(dev, "IRQ: %d\n", client->irq); @@ -1603,12 +1616,6 @@ static int lm90_probe(struct i2c_client *client, exit_unregister: hwmon_device_unregister(data->hwmon_dev); -exit_remove_pec: - device_remove_file(dev, &dev_attr_pec); -exit_restore: - lm90_restore_conf(client, data); - regulator_disable(data->regulator); - return err; } @@ -1617,9 +1624,6 @@ static int lm90_remove(struct i2c_client *client) struct lm90_data *data = i2c_get_clientdata(client); hwmon_device_unregister(data->hwmon_dev); - device_remove_file(&client->dev, &dev_attr_pec); - lm90_restore_conf(client, data); - regulator_disable(data->regulator); return 0; } -- cgit v0.10.2 From 6e5f62b9e3651e619a6baee9e11f6d9c8e4fd657 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Mon, 13 Jun 2016 06:28:03 -0700 Subject: hwmon: (lm90) Use devm_hwmon_device_register_with_groups Since all other cleanup handled with devm_add_action, we can use devm_hwmon_device_register_with_groups() to register the hwmon device, and drop the remove function. Signed-off-by: Guenter Roeck diff --git a/drivers/hwmon/lm90.c b/drivers/hwmon/lm90.c index 4b530ef..9d733cb 100644 --- a/drivers/hwmon/lm90.c +++ b/drivers/hwmon/lm90.c @@ -366,7 +366,6 @@ enum lm90_temp11_reg_index { struct lm90_data { struct i2c_client *client; - struct device *hwmon_dev; const struct attribute_group *groups[6]; struct mutex update_lock; char valid; /* zero until following fields are valid */ @@ -1527,6 +1526,7 @@ static int lm90_probe(struct i2c_client *client, struct i2c_adapter *adapter = to_i2c_adapter(dev->parent); struct lm90_data *data; struct regulator *regulator; + struct device *hwmon_dev; int groups = 0; int err; @@ -1595,10 +1595,10 @@ static int lm90_probe(struct i2c_client *client, devm_add_action(dev, lm90_remove_pec, dev); } - data->hwmon_dev = hwmon_device_register_with_groups(dev, client->name, - data, data->groups); - if (IS_ERR(data->hwmon_dev)) - return PTR_ERR(data->hwmon_dev); + hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name, + data, data->groups); + if (IS_ERR(hwmon_dev)) + return PTR_ERR(hwmon_dev); if (client->irq) { dev_dbg(dev, "IRQ: %d\n", client->irq); @@ -1608,24 +1608,11 @@ static int lm90_probe(struct i2c_client *client, "lm90", client); if (err < 0) { dev_err(dev, "cannot request IRQ %d\n", client->irq); - goto exit_unregister; + return err; } } return 0; - -exit_unregister: - hwmon_device_unregister(data->hwmon_dev); - return err; -} - -static int lm90_remove(struct i2c_client *client) -{ - struct lm90_data *data = i2c_get_clientdata(client); - - hwmon_device_unregister(data->hwmon_dev); - - return 0; } static void lm90_alert(struct i2c_client *client, unsigned int flag) @@ -1659,7 +1646,6 @@ static struct i2c_driver lm90_driver = { .name = "lm90", }, .probe = lm90_probe, - .remove = lm90_remove, .alert = lm90_alert, .id_table = lm90_id, .detect = lm90_detect, -- cgit v0.10.2 From 37ad04d7a9a5c8c066e2e17d960f6563e194e53a Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Mon, 13 Jun 2016 06:57:37 -0700 Subject: hwmon: (lm90) Simplify read functions Return both error code and register value as return code from read functions, and always check for errors. This reduces code size on x86_64 by more than 1k while at the same time improving error resiliency. Signed-off-by: Guenter Roeck diff --git a/drivers/hwmon/lm90.c b/drivers/hwmon/lm90.c index 9d733cb..2a330bd 100644 --- a/drivers/hwmon/lm90.c +++ b/drivers/hwmon/lm90.c @@ -171,7 +171,6 @@ enum chips { lm90, adm1032, lm99, lm86, max6657, max6659, adt7461, max6680, #define SA56004_REG_R_LOCAL_TEMPL 0x22 -#define LM90_DEF_CONVRATE_RVAL 6 /* Def conversion rate register value */ #define LM90_MAX_CONVRATE_MS 16000 /* Maximum conversion rate in ms */ /* TMP451 registers */ @@ -410,7 +409,7 @@ static inline s32 adm1032_write_byte(struct i2c_client *client, u8 value) * because we don't want the address pointer to change between the write * byte and the read byte transactions. */ -static int lm90_read_reg(struct i2c_client *client, u8 reg, u8 *value) +static int lm90_read_reg(struct i2c_client *client, u8 reg) { int err; @@ -421,20 +420,12 @@ static int lm90_read_reg(struct i2c_client *client, u8 reg, u8 *value) } else err = i2c_smbus_read_byte_data(client, reg); - if (err < 0) { - dev_warn(&client->dev, "Register %#02x read failed (%d)\n", - reg, err); - return err; - } - *value = err; - - return 0; + return err; } -static int lm90_read16(struct i2c_client *client, u8 regh, u8 regl, u16 *value) +static int lm90_read16(struct i2c_client *client, u8 regh, u8 regl) { - int err; - u8 oldh, newh, l; + int oldh, newh, l; /* * There is a trick here. We have to read two registers to have the @@ -449,18 +440,21 @@ static int lm90_read16(struct i2c_client *client, u8 regh, u8 regl, u16 *value) * we have to read the low byte again, and now we believe we have a * correct reading. */ - if ((err = lm90_read_reg(client, regh, &oldh)) - || (err = lm90_read_reg(client, regl, &l)) - || (err = lm90_read_reg(client, regh, &newh))) - return err; + oldh = lm90_read_reg(client, regh); + if (oldh < 0) + return oldh; + l = lm90_read_reg(client, regl); + if (l < 0) + return l; + newh = lm90_read_reg(client, regh); + if (newh < 0) + return newh; if (oldh != newh) { - err = lm90_read_reg(client, regl, &l); - if (err) - return err; + l = lm90_read_reg(client, regl); + if (l < 0) + return l; } - *value = (newh << 8) | l; - - return 0; + return (newh << 8) | l; } /* @@ -471,20 +465,23 @@ static int lm90_read16(struct i2c_client *client, u8 regh, u8 regl, u16 *value) * various registers have different meanings as a result of selecting a * non-default remote channel. */ -static inline void lm90_select_remote_channel(struct i2c_client *client, - struct lm90_data *data, - int channel) +static inline int lm90_select_remote_channel(struct i2c_client *client, + struct lm90_data *data, + int channel) { - u8 config; + int config; if (data->kind == max6696) { - lm90_read_reg(client, LM90_REG_R_CONFIG1, &config); + config = lm90_read_reg(client, LM90_REG_R_CONFIG1); + if (config < 0) + return config; config &= ~0x08; if (channel) config |= 0x08; i2c_smbus_write_byte_data(client, LM90_REG_W_CONFIG1, config); } + return 0; } /* @@ -516,104 +513,153 @@ static struct lm90_data *lm90_update_device(struct device *dev) struct lm90_data *data = dev_get_drvdata(dev); struct i2c_client *client = data->client; unsigned long next_update; + int val = 0; mutex_lock(&data->update_lock); next_update = data->last_updated + msecs_to_jiffies(data->update_interval); if (time_after(jiffies, next_update) || !data->valid) { - u8 h, l; - u8 alarms; - dev_dbg(&client->dev, "Updating lm90 data.\n"); - lm90_read_reg(client, LM90_REG_R_LOCAL_LOW, - &data->temp8[LOCAL_LOW]); - lm90_read_reg(client, LM90_REG_R_LOCAL_HIGH, - &data->temp8[LOCAL_HIGH]); - lm90_read_reg(client, LM90_REG_R_LOCAL_CRIT, - &data->temp8[LOCAL_CRIT]); - lm90_read_reg(client, LM90_REG_R_REMOTE_CRIT, - &data->temp8[REMOTE_CRIT]); - lm90_read_reg(client, LM90_REG_R_TCRIT_HYST, &data->temp_hyst); + val = lm90_read_reg(client, LM90_REG_R_LOCAL_LOW); + if (val < 0) + goto error; + data->temp8[LOCAL_LOW] = val; + + val = lm90_read_reg(client, LM90_REG_R_LOCAL_HIGH); + if (val < 0) + goto error; + data->temp8[LOCAL_HIGH] = val; + + val = lm90_read_reg(client, LM90_REG_R_LOCAL_CRIT); + if (val < 0) + goto error; + data->temp8[LOCAL_CRIT] = val; + + val = lm90_read_reg(client, LM90_REG_R_REMOTE_CRIT); + if (val < 0) + goto error; + data->temp8[REMOTE_CRIT] = val; + val = lm90_read_reg(client, LM90_REG_R_TCRIT_HYST); + if (val < 0) + goto error; + data->temp_hyst = val; if (data->reg_local_ext) { - lm90_read16(client, LM90_REG_R_LOCAL_TEMP, - data->reg_local_ext, - &data->temp11[LOCAL_TEMP]); + val = lm90_read16(client, LM90_REG_R_LOCAL_TEMP, + data->reg_local_ext); + if (val < 0) + goto error; + data->temp11[LOCAL_TEMP] = val; } else { - if (lm90_read_reg(client, LM90_REG_R_LOCAL_TEMP, - &h) == 0) - data->temp11[LOCAL_TEMP] = h << 8; + val = lm90_read_reg(client, LM90_REG_R_LOCAL_TEMP); + if (val < 0) + goto error; + data->temp11[LOCAL_TEMP] = val << 8; } - lm90_read16(client, LM90_REG_R_REMOTE_TEMPH, - LM90_REG_R_REMOTE_TEMPL, - &data->temp11[REMOTE_TEMP]); - - if (lm90_read_reg(client, LM90_REG_R_REMOTE_LOWH, &h) == 0) { - data->temp11[REMOTE_LOW] = h << 8; - if ((data->flags & LM90_HAVE_REM_LIMIT_EXT) - && lm90_read_reg(client, LM90_REG_R_REMOTE_LOWL, - &l) == 0) - data->temp11[REMOTE_LOW] |= l; + val = lm90_read16(client, LM90_REG_R_REMOTE_TEMPH, + LM90_REG_R_REMOTE_TEMPL); + if (val < 0) + goto error; + data->temp11[REMOTE_TEMP] = val; + + lm90_read_reg(client, LM90_REG_R_REMOTE_LOWH); + if (val < 0) + goto error; + data->temp11[REMOTE_LOW] = val << 8; + if (data->flags & LM90_HAVE_REM_LIMIT_EXT) { + val = lm90_read_reg(client, LM90_REG_R_REMOTE_LOWL); + if (val < 0) + goto error; + data->temp11[REMOTE_LOW] |= val; } - if (lm90_read_reg(client, LM90_REG_R_REMOTE_HIGHH, &h) == 0) { - data->temp11[REMOTE_HIGH] = h << 8; - if ((data->flags & LM90_HAVE_REM_LIMIT_EXT) - && lm90_read_reg(client, LM90_REG_R_REMOTE_HIGHL, - &l) == 0) - data->temp11[REMOTE_HIGH] |= l; + val = lm90_read_reg(client, LM90_REG_R_REMOTE_HIGHH); + if (val < 0) + goto error; + data->temp11[REMOTE_HIGH] = val << 8; + if (data->flags & LM90_HAVE_REM_LIMIT_EXT) { + val = lm90_read_reg(client, LM90_REG_R_REMOTE_HIGHL); + if (val < 0) + goto error; + data->temp11[REMOTE_HIGH] |= val; } if (data->flags & LM90_HAVE_OFFSET) { - if (lm90_read_reg(client, LM90_REG_R_REMOTE_OFFSH, - &h) == 0 - && lm90_read_reg(client, LM90_REG_R_REMOTE_OFFSL, - &l) == 0) - data->temp11[REMOTE_OFFSET] = (h << 8) | l; + val = lm90_read16(client, LM90_REG_R_REMOTE_OFFSH, + LM90_REG_R_REMOTE_OFFSL); + if (val < 0) + goto error; + data->temp11[REMOTE_OFFSET] = val; } if (data->flags & LM90_HAVE_EMERGENCY) { - lm90_read_reg(client, MAX6659_REG_R_LOCAL_EMERG, - &data->temp8[LOCAL_EMERG]); - lm90_read_reg(client, MAX6659_REG_R_REMOTE_EMERG, - &data->temp8[REMOTE_EMERG]); + val = lm90_read_reg(client, MAX6659_REG_R_LOCAL_EMERG); + if (val < 0) + goto error; + data->temp8[LOCAL_EMERG] = val; + val = lm90_read_reg(client, MAX6659_REG_R_REMOTE_EMERG); + if (val < 0) + goto error; + data->temp8[REMOTE_EMERG] = val; } - lm90_read_reg(client, LM90_REG_R_STATUS, &alarms); - data->alarms = alarms; /* save as 16 bit value */ + val = lm90_read_reg(client, LM90_REG_R_STATUS); + if (val < 0) + goto error; + data->alarms = val; /* lower 8 bit of alarms */ if (data->kind == max6696) { - lm90_select_remote_channel(client, data, 1); - lm90_read_reg(client, LM90_REG_R_REMOTE_CRIT, - &data->temp8[REMOTE2_CRIT]); - lm90_read_reg(client, MAX6659_REG_R_REMOTE_EMERG, - &data->temp8[REMOTE2_EMERG]); - lm90_read16(client, LM90_REG_R_REMOTE_TEMPH, - LM90_REG_R_REMOTE_TEMPL, - &data->temp11[REMOTE2_TEMP]); - if (!lm90_read_reg(client, LM90_REG_R_REMOTE_LOWH, &h)) - data->temp11[REMOTE2_LOW] = h << 8; - if (!lm90_read_reg(client, LM90_REG_R_REMOTE_HIGHH, &h)) - data->temp11[REMOTE2_HIGH] = h << 8; + val = lm90_select_remote_channel(client, data, 1); + if (val < 0) + goto error; + + val = lm90_read_reg(client, LM90_REG_R_REMOTE_CRIT); + if (val < 0) + goto error; + data->temp8[REMOTE2_CRIT] = val; + + val = lm90_read_reg(client, MAX6659_REG_R_REMOTE_EMERG); + if (val < 0) + goto error; + data->temp8[REMOTE2_EMERG] = val; + + val = lm90_read16(client, LM90_REG_R_REMOTE_TEMPH, + LM90_REG_R_REMOTE_TEMPL); + if (val < 0) + goto error; + data->temp11[REMOTE2_TEMP] = val; + + val = lm90_read_reg(client, LM90_REG_R_REMOTE_LOWH); + if (val < 0) + goto error; + data->temp11[REMOTE2_LOW] = val << 8; + + val = lm90_read_reg(client, LM90_REG_R_REMOTE_HIGHH); + if (val < 0) + goto error; + data->temp11[REMOTE2_HIGH] = val << 8; + lm90_select_remote_channel(client, data, 0); - if (!lm90_read_reg(client, MAX6696_REG_R_STATUS2, - &alarms)) - data->alarms |= alarms << 8; + val = lm90_read_reg(client, MAX6696_REG_R_STATUS2); + if (val < 0) + goto error; + data->alarms |= val << 8; } /* * Re-enable ALERT# output if it was originally enabled and * relevant alarms are all clear */ - if ((data->config_orig & 0x80) == 0 - && (data->alarms & data->alert_alarms) == 0) { - u8 config; + if (!(data->config_orig & 0x80) && + !(data->alarms & data->alert_alarms)) { + val = lm90_read_reg(client, LM90_REG_R_CONFIG1); + if (val < 0) + goto error; - lm90_read_reg(client, LM90_REG_R_CONFIG1, &config); - if (config & 0x80) { + if (val & 0x80) { dev_dbg(&client->dev, "Re-enabling ALERT#\n"); i2c_smbus_write_byte_data(client, LM90_REG_W_CONFIG1, - config & ~0x80); + val & ~0x80); } } @@ -621,8 +667,12 @@ static struct lm90_data *lm90_update_device(struct device *dev) data->valid = 1; } +error: mutex_unlock(&data->update_lock); + if (val < 0) + return ERR_PTR(val); + return data; } @@ -764,6 +814,9 @@ static ssize_t show_temp8(struct device *dev, struct device_attribute *devattr, struct lm90_data *data = lm90_update_device(dev); int temp; + if (IS_ERR(data)) + return PTR_ERR(data); + if (data->kind == adt7461 || data->kind == tmp451) temp = temp_from_u8_adt7461(data, data->temp8[attr->index]); else if (data->kind == max6646) @@ -830,6 +883,9 @@ static ssize_t show_temp11(struct device *dev, struct device_attribute *devattr, struct lm90_data *data = lm90_update_device(dev); int temp; + if (IS_ERR(data)) + return PTR_ERR(data); + if (data->kind == adt7461 || data->kind == tmp451) temp = temp_from_u16_adt7461(data, data->temp11[attr->index]); else if (data->kind == max6646) @@ -905,6 +961,9 @@ static ssize_t show_temphyst(struct device *dev, struct lm90_data *data = lm90_update_device(dev); int temp; + if (IS_ERR(data)) + return PTR_ERR(data); + if (data->kind == adt7461 || data->kind == tmp451) temp = temp_from_u8_adt7461(data, data->temp8[attr->index]); else if (data->kind == max6646) @@ -951,6 +1010,10 @@ static ssize_t show_alarms(struct device *dev, struct device_attribute *dummy, char *buf) { struct lm90_data *data = lm90_update_device(dev); + + if (IS_ERR(data)) + return PTR_ERR(data); + return sprintf(buf, "%d\n", data->alarms); } @@ -961,6 +1024,9 @@ static ssize_t show_alarm(struct device *dev, struct device_attribute struct lm90_data *data = lm90_update_device(dev); int bitnr = attr->index; + if (IS_ERR(data)) + return PTR_ERR(data); + return sprintf(buf, "%d\n", (data->alarms >> bitnr) & 1); } @@ -1414,24 +1480,22 @@ static void lm90_restore_conf(void *_data) data->config_orig); } -static void lm90_init_client(struct i2c_client *client, struct lm90_data *data) +static int lm90_init_client(struct i2c_client *client, struct lm90_data *data) { - u8 config, convrate; + int config, convrate; - if (lm90_read_reg(client, LM90_REG_R_CONVRATE, &convrate) < 0) { - dev_warn(&client->dev, "Failed to read convrate register!\n"); - convrate = LM90_DEF_CONVRATE_RVAL; - } + convrate = lm90_read_reg(client, LM90_REG_R_CONVRATE); + if (convrate < 0) + return convrate; data->convrate_orig = convrate; /* * Start the conversions. */ lm90_set_convrate(client, data, 500); /* 500ms; 2Hz conversion rate */ - if (lm90_read_reg(client, LM90_REG_R_CONFIG1, &config) < 0) { - dev_warn(&client->dev, "Initialization failed!\n"); - return; - } + config = lm90_read_reg(client, LM90_REG_R_CONFIG1); + if (config < 0) + return config; data->config_orig = config; /* Check Temperature Range Select */ @@ -1459,17 +1523,24 @@ static void lm90_init_client(struct i2c_client *client, struct lm90_data *data) i2c_smbus_write_byte_data(client, LM90_REG_W_CONFIG1, config); devm_add_action(&client->dev, lm90_restore_conf, data); + + return 0; } static bool lm90_is_tripped(struct i2c_client *client, u16 *status) { struct lm90_data *data = i2c_get_clientdata(client); - u8 st, st2 = 0; + int st, st2 = 0; - lm90_read_reg(client, LM90_REG_R_STATUS, &st); + st = lm90_read_reg(client, LM90_REG_R_STATUS); + if (st < 0) + return false; - if (data->kind == max6696) - lm90_read_reg(client, MAX6696_REG_R_STATUS2, &st2); + if (data->kind == max6696) { + st2 = lm90_read_reg(client, MAX6696_REG_R_STATUS2); + if (st2 < 0) + return false; + } *status = st | (st2 << 8); @@ -1571,7 +1642,11 @@ static int lm90_probe(struct i2c_client *client, data->max_convrate = lm90_params[data->kind].max_convrate; /* Initialize the LM90 chip */ - lm90_init_client(client, data); + err = lm90_init_client(client, data); + if (err < 0) { + dev_err(dev, "Failed to initialize device\n"); + return err; + } /* Register sysfs hooks */ data->groups[groups++] = &lm90_group; @@ -1627,13 +1702,16 @@ static void lm90_alert(struct i2c_client *client, unsigned int flag) */ struct lm90_data *data = i2c_get_clientdata(client); - if ((data->flags & LM90_HAVE_BROKEN_ALERT) - && (alarms & data->alert_alarms)) { - u8 config; + if ((data->flags & LM90_HAVE_BROKEN_ALERT) && + (alarms & data->alert_alarms)) { + int config; + dev_dbg(&client->dev, "Disabling ALERT#\n"); - lm90_read_reg(client, LM90_REG_R_CONFIG1, &config); - i2c_smbus_write_byte_data(client, LM90_REG_W_CONFIG1, - config | 0x80); + config = lm90_read_reg(client, LM90_REG_R_CONFIG1); + if (config >= 0) + i2c_smbus_write_byte_data(client, + LM90_REG_W_CONFIG1, + config | 0x80); } } else { dev_info(&client->dev, "Everything OK\n"); -- cgit v0.10.2 From 10bfef47bd259a800a731a2b459599b14cfb8052 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Mon, 13 Jun 2016 19:26:45 -0700 Subject: hwmon: (lm90) Read limit registers only once Read limit registers only once at startup or after errors to improve driver performance. Signed-off-by: Guenter Roeck diff --git a/drivers/hwmon/lm90.c b/drivers/hwmon/lm90.c index 2a330bd..322a73d 100644 --- a/drivers/hwmon/lm90.c +++ b/drivers/hwmon/lm90.c @@ -508,6 +508,102 @@ static void lm90_set_convrate(struct i2c_client *client, struct lm90_data *data, data->update_interval = DIV_ROUND_CLOSEST(update_interval, 64); } +static int lm90_update_limits(struct device *dev) +{ + struct lm90_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; + int val; + + val = lm90_read_reg(client, LM90_REG_R_LOCAL_CRIT); + if (val < 0) + return val; + data->temp8[LOCAL_CRIT] = val; + + val = lm90_read_reg(client, LM90_REG_R_REMOTE_CRIT); + if (val < 0) + return val; + data->temp8[REMOTE_CRIT] = val; + + val = lm90_read_reg(client, LM90_REG_R_TCRIT_HYST); + if (val < 0) + return val; + data->temp_hyst = val; + + lm90_read_reg(client, LM90_REG_R_REMOTE_LOWH); + if (val < 0) + return val; + data->temp11[REMOTE_LOW] = val << 8; + + if (data->flags & LM90_HAVE_REM_LIMIT_EXT) { + val = lm90_read_reg(client, LM90_REG_R_REMOTE_LOWL); + if (val < 0) + return val; + data->temp11[REMOTE_LOW] |= val; + } + + val = lm90_read_reg(client, LM90_REG_R_REMOTE_HIGHH); + if (val < 0) + return val; + data->temp11[REMOTE_HIGH] = val << 8; + + if (data->flags & LM90_HAVE_REM_LIMIT_EXT) { + val = lm90_read_reg(client, LM90_REG_R_REMOTE_HIGHL); + if (val < 0) + return val; + data->temp11[REMOTE_HIGH] |= val; + } + + if (data->flags & LM90_HAVE_OFFSET) { + val = lm90_read16(client, LM90_REG_R_REMOTE_OFFSH, + LM90_REG_R_REMOTE_OFFSL); + if (val < 0) + return val; + data->temp11[REMOTE_OFFSET] = val; + } + + if (data->flags & LM90_HAVE_EMERGENCY) { + val = lm90_read_reg(client, MAX6659_REG_R_LOCAL_EMERG); + if (val < 0) + return val; + data->temp8[LOCAL_EMERG] = val; + + val = lm90_read_reg(client, MAX6659_REG_R_REMOTE_EMERG); + if (val < 0) + return val; + data->temp8[REMOTE_EMERG] = val; + } + + if (data->kind == max6696) { + val = lm90_select_remote_channel(client, data, 1); + if (val < 0) + return val; + + val = lm90_read_reg(client, LM90_REG_R_REMOTE_CRIT); + if (val < 0) + return val; + data->temp8[REMOTE2_CRIT] = val; + + val = lm90_read_reg(client, MAX6659_REG_R_REMOTE_EMERG); + if (val < 0) + return val; + data->temp8[REMOTE2_EMERG] = val; + + val = lm90_read_reg(client, LM90_REG_R_REMOTE_LOWH); + if (val < 0) + return val; + data->temp11[REMOTE2_LOW] = val << 8; + + val = lm90_read_reg(client, LM90_REG_R_REMOTE_HIGHH); + if (val < 0) + return val; + data->temp11[REMOTE2_HIGH] = val << 8; + + lm90_select_remote_channel(client, data, 0); + } + + return 0; +} + static struct lm90_data *lm90_update_device(struct device *dev) { struct lm90_data *data = dev_get_drvdata(dev); @@ -517,10 +613,19 @@ static struct lm90_data *lm90_update_device(struct device *dev) mutex_lock(&data->update_lock); + if (!data->valid) { + val = lm90_update_limits(dev); + if (val < 0) + goto error; + } + next_update = data->last_updated + msecs_to_jiffies(data->update_interval); if (time_after(jiffies, next_update) || !data->valid) { dev_dbg(&client->dev, "Updating lm90 data.\n"); + + data->valid = 0; + val = lm90_read_reg(client, LM90_REG_R_LOCAL_LOW); if (val < 0) goto error; @@ -531,20 +636,6 @@ static struct lm90_data *lm90_update_device(struct device *dev) goto error; data->temp8[LOCAL_HIGH] = val; - val = lm90_read_reg(client, LM90_REG_R_LOCAL_CRIT); - if (val < 0) - goto error; - data->temp8[LOCAL_CRIT] = val; - - val = lm90_read_reg(client, LM90_REG_R_REMOTE_CRIT); - if (val < 0) - goto error; - data->temp8[REMOTE_CRIT] = val; - val = lm90_read_reg(client, LM90_REG_R_TCRIT_HYST); - if (val < 0) - goto error; - data->temp_hyst = val; - if (data->reg_local_ext) { val = lm90_read16(client, LM90_REG_R_LOCAL_TEMP, data->reg_local_ext); @@ -563,44 +654,6 @@ static struct lm90_data *lm90_update_device(struct device *dev) goto error; data->temp11[REMOTE_TEMP] = val; - lm90_read_reg(client, LM90_REG_R_REMOTE_LOWH); - if (val < 0) - goto error; - data->temp11[REMOTE_LOW] = val << 8; - if (data->flags & LM90_HAVE_REM_LIMIT_EXT) { - val = lm90_read_reg(client, LM90_REG_R_REMOTE_LOWL); - if (val < 0) - goto error; - data->temp11[REMOTE_LOW] |= val; - } - val = lm90_read_reg(client, LM90_REG_R_REMOTE_HIGHH); - if (val < 0) - goto error; - data->temp11[REMOTE_HIGH] = val << 8; - if (data->flags & LM90_HAVE_REM_LIMIT_EXT) { - val = lm90_read_reg(client, LM90_REG_R_REMOTE_HIGHL); - if (val < 0) - goto error; - data->temp11[REMOTE_HIGH] |= val; - } - - if (data->flags & LM90_HAVE_OFFSET) { - val = lm90_read16(client, LM90_REG_R_REMOTE_OFFSH, - LM90_REG_R_REMOTE_OFFSL); - if (val < 0) - goto error; - data->temp11[REMOTE_OFFSET] = val; - } - if (data->flags & LM90_HAVE_EMERGENCY) { - val = lm90_read_reg(client, MAX6659_REG_R_LOCAL_EMERG); - if (val < 0) - goto error; - data->temp8[LOCAL_EMERG] = val; - val = lm90_read_reg(client, MAX6659_REG_R_REMOTE_EMERG); - if (val < 0) - goto error; - data->temp8[REMOTE_EMERG] = val; - } val = lm90_read_reg(client, LM90_REG_R_STATUS); if (val < 0) goto error; @@ -611,32 +664,12 @@ static struct lm90_data *lm90_update_device(struct device *dev) if (val < 0) goto error; - val = lm90_read_reg(client, LM90_REG_R_REMOTE_CRIT); - if (val < 0) - goto error; - data->temp8[REMOTE2_CRIT] = val; - - val = lm90_read_reg(client, MAX6659_REG_R_REMOTE_EMERG); - if (val < 0) - goto error; - data->temp8[REMOTE2_EMERG] = val; - val = lm90_read16(client, LM90_REG_R_REMOTE_TEMPH, LM90_REG_R_REMOTE_TEMPL); if (val < 0) goto error; data->temp11[REMOTE2_TEMP] = val; - val = lm90_read_reg(client, LM90_REG_R_REMOTE_LOWH); - if (val < 0) - goto error; - data->temp11[REMOTE2_LOW] = val << 8; - - val = lm90_read_reg(client, LM90_REG_R_REMOTE_HIGHH); - if (val < 0) - goto error; - data->temp11[REMOTE2_HIGH] = val << 8; - lm90_select_remote_channel(client, data, 0); val = lm90_read_reg(client, MAX6696_REG_R_STATUS2); -- cgit v0.10.2 From 2f83ab77b43807edf695ca9a31673be2197a33b3 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Sat, 18 Jun 2016 15:39:08 -0700 Subject: hwmon: (lm90) Use bool for valid flag Use bool for valid flag and leave it up to the compiler to find an optimal representation. Signed-off-by: Guenter Roeck diff --git a/drivers/hwmon/lm90.c b/drivers/hwmon/lm90.c index 322a73d..c38d6e4 100644 --- a/drivers/hwmon/lm90.c +++ b/drivers/hwmon/lm90.c @@ -367,7 +367,7 @@ struct lm90_data { struct i2c_client *client; const struct attribute_group *groups[6]; struct mutex update_lock; - char valid; /* zero until following fields are valid */ + bool valid; /* true if register values are valid */ unsigned long last_updated; /* in jiffies */ int kind; u32 flags; @@ -624,7 +624,7 @@ static struct lm90_data *lm90_update_device(struct device *dev) if (time_after(jiffies, next_update) || !data->valid) { dev_dbg(&client->dev, "Updating lm90 data.\n"); - data->valid = 0; + data->valid = false; val = lm90_read_reg(client, LM90_REG_R_LOCAL_LOW); if (val < 0) @@ -697,7 +697,7 @@ static struct lm90_data *lm90_update_device(struct device *dev) } data->last_updated = jiffies; - data->valid = 1; + data->valid = true; } error: -- cgit v0.10.2 From 589f707c72426793a0f537592098a5a2a3117dc0 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Sat, 18 Jun 2016 19:58:26 -0700 Subject: hwmon: (lm90) Drop unnecessary else statements checkpatch rightfully complains that else after return is unnecessary. Signed-off-by: Guenter Roeck diff --git a/drivers/hwmon/lm90.c b/drivers/hwmon/lm90.c index c38d6e4..f51e758 100644 --- a/drivers/hwmon/lm90.c +++ b/drivers/hwmon/lm90.c @@ -790,16 +790,14 @@ static inline int temp_from_u8_adt7461(struct lm90_data *data, u8 val) { if (data->flags & LM90_FLAG_ADT7461_EXT) return (val - 64) * 1000; - else - return temp_from_s8(val); + return temp_from_s8(val); } static inline int temp_from_u16_adt7461(struct lm90_data *data, u16 val) { if (data->flags & LM90_FLAG_ADT7461_EXT) return (val - 0x4000) / 64 * 250; - else - return temp_from_s16(val); + return temp_from_s16(val); } static u8 temp_to_u8_adt7461(struct lm90_data *data, long val) @@ -810,13 +808,12 @@ static u8 temp_to_u8_adt7461(struct lm90_data *data, long val) if (val >= 191000) return 0xFF; return (val + 500 + 64000) / 1000; - } else { - if (val <= 0) - return 0; - if (val >= 127000) - return 127; - return (val + 500) / 1000; } + if (val <= 0) + return 0; + if (val >= 127000) + return 127; + return (val + 500) / 1000; } static u16 temp_to_u16_adt7461(struct lm90_data *data, long val) @@ -827,13 +824,12 @@ static u16 temp_to_u16_adt7461(struct lm90_data *data, long val) if (val >= 191750) return 0xFFC0; return (val + 64000 + 125) / 250 * 64; - } else { - if (val <= 0) - return 0; - if (val >= 127750) - return 0x7FC0; - return (val + 125) / 250 * 64; } + if (val <= 0) + return 0; + if (val >= 127750) + return 0x7FC0; + return (val + 125) / 250 * 64; } /* -- cgit v0.10.2 From b8efb894e672bd0080126c68a076ddcacfcbc0ef Mon Sep 17 00:00:00 2001 From: Thomas Falcon Date: Wed, 6 Jul 2016 15:35:15 -0500 Subject: ibmvnic: properly start and stop tx queues Since ibmvnic uses multiple tx queues, start and stop all queues when opening and closing devices. Signed-off-by: Thomas Falcon Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/ibm/ibmvnic.c b/drivers/net/ethernet/ibm/ibmvnic.c index ecdb685..f04830e 100644 --- a/drivers/net/ethernet/ibm/ibmvnic.c +++ b/drivers/net/ethernet/ibm/ibmvnic.c @@ -469,7 +469,8 @@ static int ibmvnic_open(struct net_device *netdev) crq.logical_link_state.link_state = IBMVNIC_LOGICAL_LNK_UP; ibmvnic_send_crq(adapter, &crq); - netif_start_queue(netdev); + netif_tx_start_all_queues(netdev); + return 0; bounce_map_failed: @@ -519,7 +520,7 @@ static int ibmvnic_close(struct net_device *netdev) for (i = 0; i < adapter->req_rx_queues; i++) napi_disable(&adapter->napi[i]); - netif_stop_queue(netdev); + netif_tx_stop_all_queues(netdev); if (adapter->bounce_buffer) { if (!dma_mapping_error(dev, adapter->bounce_buffer_dma)) { -- cgit v0.10.2 From 88eb98a0178219e1d6e9037b71d293f19b89eef2 Mon Sep 17 00:00:00 2001 From: Thomas Falcon Date: Wed, 6 Jul 2016 15:35:16 -0500 Subject: ibmvnic: dispose irq mappings IRQ mappings were not being properly disposed when releasing sub-CRQ's. Signed-off-by: Thomas Falcon Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/ibm/ibmvnic.c b/drivers/net/ethernet/ibm/ibmvnic.c index f04830e..79d2ab3 100644 --- a/drivers/net/ethernet/ibm/ibmvnic.c +++ b/drivers/net/ethernet/ibm/ibmvnic.c @@ -1257,6 +1257,7 @@ static void release_sub_crqs(struct ibmvnic_adapter *adapter) if (adapter->tx_scrq[i]) { free_irq(adapter->tx_scrq[i]->irq, adapter->tx_scrq[i]); + irq_dispose_mapping(adapter->tx_scrq[i]->irq); release_sub_crq_queue(adapter, adapter->tx_scrq[i]); } @@ -1268,6 +1269,7 @@ static void release_sub_crqs(struct ibmvnic_adapter *adapter) if (adapter->rx_scrq[i]) { free_irq(adapter->rx_scrq[i]->irq, adapter->rx_scrq[i]); + irq_dispose_mapping(adapter->rx_scrq[i]->irq); release_sub_crq_queue(adapter, adapter->rx_scrq[i]); } -- cgit v0.10.2 From ea22d51a7831b062978fcf07c3c5ac7ecbb6cbeb Mon Sep 17 00:00:00 2001 From: Thomas Falcon Date: Wed, 6 Jul 2016 15:35:17 -0500 Subject: ibmvnic: simplify and improve driver probe function This patch creates a function that handles sub-CRQ IRQ creation separately from sub-CRQ initialization. Another function is then needed to release sub-CRQ resources prior to sub-CRQ IRQ creation. These additions allow the driver probe function to be simplified, specifically during the VNIC Server login process. A timeout is also included while waiting for completion of the login process in case the VNIC Server is not available or some other error occurs. Signed-off-by: Thomas Falcon Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/ibm/ibmvnic.c b/drivers/net/ethernet/ibm/ibmvnic.c index 79d2ab3..52b0c07 100644 --- a/drivers/net/ethernet/ibm/ibmvnic.c +++ b/drivers/net/ethernet/ibm/ibmvnic.c @@ -89,6 +89,7 @@ MODULE_VERSION(IBMVNIC_DRIVER_VERSION); static int ibmvnic_version = IBMVNIC_INITIAL_VERSION; static int ibmvnic_remove(struct vio_dev *); static void release_sub_crqs(struct ibmvnic_adapter *); +static void release_sub_crqs_no_irqs(struct ibmvnic_adapter *); static int ibmvnic_reset_crq(struct ibmvnic_adapter *); static int ibmvnic_send_crq_init(struct ibmvnic_adapter *); static int ibmvnic_reenable_crq_queue(struct ibmvnic_adapter *); @@ -1213,12 +1214,6 @@ static struct ibmvnic_sub_crq_queue *init_sub_crq_queue(struct ibmvnic_adapter goto reg_failed; } - scrq->irq = irq_create_mapping(NULL, scrq->hw_irq); - if (scrq->irq == NO_IRQ) { - dev_err(dev, "Error mapping irq\n"); - goto map_irq_failed; - } - scrq->adapter = adapter; scrq->size = 4 * PAGE_SIZE / sizeof(*scrq->msgs); scrq->cur = 0; @@ -1231,12 +1226,6 @@ static struct ibmvnic_sub_crq_queue *init_sub_crq_queue(struct ibmvnic_adapter return scrq; -map_irq_failed: - do { - rc = plpar_hcall_norets(H_FREE_SUB_CRQ, - adapter->vdev->unit_address, - scrq->crq_num); - } while (rc == H_BUSY || H_IS_LONG_BUSY(rc)); reg_failed: dma_unmap_single(dev, scrq->msg_token, 4 * PAGE_SIZE, DMA_BIDIRECTIONAL); @@ -1279,6 +1268,29 @@ static void release_sub_crqs(struct ibmvnic_adapter *adapter) adapter->requested_caps = 0; } +static void release_sub_crqs_no_irqs(struct ibmvnic_adapter *adapter) +{ + int i; + + if (adapter->tx_scrq) { + for (i = 0; i < adapter->req_tx_queues; i++) + if (adapter->tx_scrq[i]) + release_sub_crq_queue(adapter, + adapter->tx_scrq[i]); + adapter->tx_scrq = NULL; + } + + if (adapter->rx_scrq) { + for (i = 0; i < adapter->req_rx_queues; i++) + if (adapter->rx_scrq[i]) + release_sub_crq_queue(adapter, + adapter->rx_scrq[i]); + adapter->rx_scrq = NULL; + } + + adapter->requested_caps = 0; +} + static int disable_scrq_irq(struct ibmvnic_adapter *adapter, struct ibmvnic_sub_crq_queue *scrq) { @@ -1398,6 +1410,66 @@ static irqreturn_t ibmvnic_interrupt_rx(int irq, void *instance) return IRQ_HANDLED; } +static int init_sub_crq_irqs(struct ibmvnic_adapter *adapter) +{ + struct device *dev = &adapter->vdev->dev; + struct ibmvnic_sub_crq_queue *scrq; + int i = 0, j = 0; + int rc = 0; + + for (i = 0; i < adapter->req_tx_queues; i++) { + scrq = adapter->tx_scrq[i]; + scrq->irq = irq_create_mapping(NULL, scrq->hw_irq); + + if (scrq->irq == NO_IRQ) { + rc = -EINVAL; + dev_err(dev, "Error mapping irq\n"); + goto req_tx_irq_failed; + } + + rc = request_irq(scrq->irq, ibmvnic_interrupt_tx, + 0, "ibmvnic_tx", scrq); + + if (rc) { + dev_err(dev, "Couldn't register tx irq 0x%x. rc=%d\n", + scrq->irq, rc); + irq_dispose_mapping(scrq->irq); + goto req_rx_irq_failed; + } + } + + for (i = 0; i < adapter->req_rx_queues; i++) { + scrq = adapter->rx_scrq[i]; + scrq->irq = irq_create_mapping(NULL, scrq->hw_irq); + if (scrq->irq == NO_IRQ) { + rc = -EINVAL; + dev_err(dev, "Error mapping irq\n"); + goto req_rx_irq_failed; + } + rc = request_irq(scrq->irq, ibmvnic_interrupt_rx, + 0, "ibmvnic_rx", scrq); + if (rc) { + dev_err(dev, "Couldn't register rx irq 0x%x. rc=%d\n", + scrq->irq, rc); + irq_dispose_mapping(scrq->irq); + goto req_rx_irq_failed; + } + } + return rc; + +req_rx_irq_failed: + for (j = 0; j < i; j++) + free_irq(adapter->rx_scrq[j]->irq, adapter->rx_scrq[j]); + irq_dispose_mapping(adapter->rx_scrq[j]->irq); + i = adapter->req_tx_queues; +req_tx_irq_failed: + for (j = 0; j < i; j++) + free_irq(adapter->tx_scrq[j]->irq, adapter->tx_scrq[j]); + irq_dispose_mapping(adapter->rx_scrq[j]->irq); + release_sub_crqs_no_irqs(adapter); + return rc; +} + static void init_sub_crqs(struct ibmvnic_adapter *adapter, int retry) { struct device *dev = &adapter->vdev->dev; @@ -1406,8 +1478,7 @@ static void init_sub_crqs(struct ibmvnic_adapter *adapter, int retry) union ibmvnic_crq crq; int total_queues; int more = 0; - int i, j; - int rc; + int i; if (!retry) { /* Sub-CRQ entries are 32 byte long */ @@ -1486,13 +1557,6 @@ static void init_sub_crqs(struct ibmvnic_adapter *adapter, int retry) for (i = 0; i < adapter->req_tx_queues; i++) { adapter->tx_scrq[i] = allqueues[i]; adapter->tx_scrq[i]->pool_index = i; - rc = request_irq(adapter->tx_scrq[i]->irq, ibmvnic_interrupt_tx, - 0, "ibmvnic_tx", adapter->tx_scrq[i]); - if (rc) { - dev_err(dev, "Couldn't register tx irq 0x%x. rc=%d\n", - adapter->tx_scrq[i]->irq, rc); - goto req_tx_irq_failed; - } } adapter->rx_scrq = kcalloc(adapter->req_rx_queues, @@ -1503,13 +1567,6 @@ static void init_sub_crqs(struct ibmvnic_adapter *adapter, int retry) for (i = 0; i < adapter->req_rx_queues; i++) { adapter->rx_scrq[i] = allqueues[i + adapter->req_tx_queues]; adapter->rx_scrq[i]->scrq_num = i; - rc = request_irq(adapter->rx_scrq[i]->irq, ibmvnic_interrupt_rx, - 0, "ibmvnic_rx", adapter->rx_scrq[i]); - if (rc) { - dev_err(dev, "Couldn't register rx irq 0x%x. rc=%d\n", - adapter->rx_scrq[i]->irq, rc); - goto req_rx_irq_failed; - } } memset(&crq, 0, sizeof(crq)); @@ -1562,15 +1619,6 @@ static void init_sub_crqs(struct ibmvnic_adapter *adapter, int retry) return; -req_rx_irq_failed: - for (j = 0; j < i; j++) - free_irq(adapter->rx_scrq[j]->irq, adapter->rx_scrq[j]); - i = adapter->req_tx_queues; -req_tx_irq_failed: - for (j = 0; j < i; j++) - free_irq(adapter->tx_scrq[j]->irq, adapter->tx_scrq[j]); - kfree(adapter->rx_scrq); - adapter->rx_scrq = NULL; rx_failed: kfree(adapter->tx_scrq); adapter->tx_scrq = NULL; @@ -2351,9 +2399,9 @@ static void handle_request_cap_rsp(union ibmvnic_crq *crq, *req_value, (long int)be32_to_cpu(crq->request_capability_rsp. number), name); - release_sub_crqs(adapter); + release_sub_crqs_no_irqs(adapter); *req_value = be32_to_cpu(crq->request_capability_rsp.number); - complete(&adapter->init_done); + init_sub_crqs(adapter, 1); return; default: dev_err(dev, "Error %d in request cap rsp\n", @@ -2662,7 +2710,7 @@ static void handle_query_cap_rsp(union ibmvnic_crq *crq, out: if (atomic_read(&adapter->running_cap_queries) == 0) - complete(&adapter->init_done); + init_sub_crqs(adapter, 0); /* We're done querying the capabilities, initialize sub-crqs */ } @@ -3560,6 +3608,7 @@ static const struct file_operations ibmvnic_dump_ops = { static int ibmvnic_probe(struct vio_dev *dev, const struct vio_device_id *id) { + unsigned long timeout = msecs_to_jiffies(30000); struct ibmvnic_adapter *adapter; struct net_device *netdev; unsigned char *mac_addr_p; @@ -3638,30 +3687,26 @@ static int ibmvnic_probe(struct vio_dev *dev, const struct vio_device_id *id) ibmvnic_send_crq_init(adapter); init_completion(&adapter->init_done); - wait_for_completion(&adapter->init_done); + if (!wait_for_completion_timeout(&adapter->init_done, timeout)) + return 0; do { - adapter->renegotiate = false; - - init_sub_crqs(adapter, 0); - reinit_completion(&adapter->init_done); - wait_for_completion(&adapter->init_done); - if (adapter->renegotiate) { - release_sub_crqs(adapter); + adapter->renegotiate = false; + release_sub_crqs_no_irqs(adapter); send_cap_queries(adapter); reinit_completion(&adapter->init_done); - wait_for_completion(&adapter->init_done); + if (!wait_for_completion_timeout(&adapter->init_done, + timeout)) + return 0; } } while (adapter->renegotiate); - /* if init_sub_crqs is partially successful, retry */ - while (!adapter->tx_scrq || !adapter->rx_scrq) { - init_sub_crqs(adapter, 1); - - reinit_completion(&adapter->init_done); - wait_for_completion(&adapter->init_done); + rc = init_sub_crq_irqs(adapter); + if (rc) { + dev_err(&dev->dev, "failed to initialize sub crq irqs\n"); + goto free_debugfs; } netdev->real_num_tx_queues = adapter->req_tx_queues; @@ -3669,12 +3714,14 @@ static int ibmvnic_probe(struct vio_dev *dev, const struct vio_device_id *id) rc = register_netdev(netdev); if (rc) { dev_err(&dev->dev, "failed to register netdev rc=%d\n", rc); - goto free_debugfs; + goto free_sub_crqs; } dev_info(&dev->dev, "ibmvnic registered\n"); return 0; +free_sub_crqs: + release_sub_crqs(adapter); free_debugfs: if (adapter->debugfs_dir && !IS_ERR(adapter->debugfs_dir)) debugfs_remove_recursive(adapter->debugfs_dir); -- cgit v0.10.2 From 65dc689182ec5117896d876cc03405ac51427314 Mon Sep 17 00:00:00 2001 From: Thomas Falcon Date: Wed, 6 Jul 2016 15:35:18 -0500 Subject: ibmvnic: Fix passive VNIC server login process In some cases, if there is no VNIC server available during the driver probe, the driver should wait until it receives an initialization request from the VNIC Server to start the login process. Recent testing has show that this is incorrectly handled in the current driver. The proposed solution handles this initialization request by scheduling a task in the shared workqueue that completes the login process and registers the net device. Signed-off-by: Thomas Falcon Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/ibm/ibmvnic.c b/drivers/net/ethernet/ibm/ibmvnic.c index 52b0c07..88f3c85 100644 --- a/drivers/net/ethernet/ibm/ibmvnic.c +++ b/drivers/net/ethernet/ibm/ibmvnic.c @@ -75,6 +75,7 @@ #include #include #include +#include #include "ibmvnic.h" @@ -3253,8 +3254,8 @@ static void ibmvnic_handle_crq(union ibmvnic_crq *crq, dev_info(dev, "Partner initialized\n"); /* Send back a response */ rc = ibmvnic_send_crq_init_complete(adapter); - if (rc == 0) - send_version_xchg(adapter); + if (!rc) + schedule_work(&adapter->vnic_crq_init); else dev_err(dev, "Can't send initrsp rc=%ld\n", rc); break; @@ -3606,6 +3607,60 @@ static const struct file_operations ibmvnic_dump_ops = { .release = single_release, }; +static void handle_crq_init_rsp(struct work_struct *work) +{ + struct ibmvnic_adapter *adapter = container_of(work, + struct ibmvnic_adapter, + vnic_crq_init); + struct device *dev = &adapter->vdev->dev; + struct net_device *netdev = adapter->netdev; + unsigned long timeout = msecs_to_jiffies(30000); + int rc; + + send_version_xchg(adapter); + reinit_completion(&adapter->init_done); + if (!wait_for_completion_timeout(&adapter->init_done, timeout)) { + dev_err(dev, "Passive init timeout\n"); + goto task_failed; + } + + do { + if (adapter->renegotiate) { + adapter->renegotiate = false; + release_sub_crqs_no_irqs(adapter); + send_cap_queries(adapter); + + reinit_completion(&adapter->init_done); + if (!wait_for_completion_timeout(&adapter->init_done, + timeout)) { + dev_err(dev, "Passive init timeout\n"); + goto task_failed; + } + } + } while (adapter->renegotiate); + rc = init_sub_crq_irqs(adapter); + + if (rc) + goto task_failed; + + netdev->real_num_tx_queues = adapter->req_tx_queues; + + rc = register_netdev(netdev); + if (rc) { + dev_err(dev, + "failed to register netdev rc=%d\n", rc); + goto register_failed; + } + dev_info(dev, "ibmvnic registered\n"); + + return; + +register_failed: + release_sub_crqs(adapter); +task_failed: + dev_err(dev, "Passive initialization was not successful\n"); +} + static int ibmvnic_probe(struct vio_dev *dev, const struct vio_device_id *id) { unsigned long timeout = msecs_to_jiffies(30000); @@ -3645,6 +3700,8 @@ static int ibmvnic_probe(struct vio_dev *dev, const struct vio_device_id *id) netdev->ethtool_ops = &ibmvnic_ethtool_ops; SET_NETDEV_DEV(netdev, &dev->dev); + INIT_WORK(&adapter->vnic_crq_init, handle_crq_init_rsp); + spin_lock_init(&adapter->stats_lock); rc = ibmvnic_init_crq_queue(adapter); diff --git a/drivers/net/ethernet/ibm/ibmvnic.h b/drivers/net/ethernet/ibm/ibmvnic.h index 0b66a50..e82898f 100644 --- a/drivers/net/ethernet/ibm/ibmvnic.h +++ b/drivers/net/ethernet/ibm/ibmvnic.h @@ -1045,4 +1045,6 @@ struct ibmvnic_adapter { u64 opt_rxba_entries_per_subcrq; __be64 tx_rx_desc_req; u8 map_id; + + struct work_struct vnic_crq_init; }; -- cgit v0.10.2 From 95556a883834122c616bbeb942654d745ceb9712 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Fri, 8 Jul 2016 11:03:57 +0200 Subject: dccp: avoid deadlock in dccp_v4_ctl_send_reset In the prep work I did before enabling BH while handling socket backlog, I missed two points in DCCP : 1) dccp_v4_ctl_send_reset() uses bh_lock_sock(), assuming BH were blocked. It is not anymore always true. 2) dccp_v4_route_skb() was using __IP_INC_STATS() instead of IP_INC_STATS() A similar fix was done for TCP, in commit 47dcc20a39d0 ("ipv4: tcp: ip_send_unicast_reply() is not BH safe") Fixes: 7309f8821fd6 ("dccp: do not assume DCCP code is non preemptible") Fixes: 5413d1babe8f ("net: do not block BH while processing socket backlog") Signed-off-by: Eric Dumazet Reported-by: Dmitry Vyukov Signed-off-by: David S. Miller diff --git a/net/dccp/ipv4.c b/net/dccp/ipv4.c index 5c7e413..25dd25b 100644 --- a/net/dccp/ipv4.c +++ b/net/dccp/ipv4.c @@ -462,7 +462,7 @@ static struct dst_entry* dccp_v4_route_skb(struct net *net, struct sock *sk, security_skb_classify_flow(skb, flowi4_to_flowi(&fl4)); rt = ip_route_output_flow(net, &fl4, sk); if (IS_ERR(rt)) { - __IP_INC_STATS(net, IPSTATS_MIB_OUTNOROUTES); + IP_INC_STATS(net, IPSTATS_MIB_OUTNOROUTES); return NULL; } @@ -527,17 +527,19 @@ static void dccp_v4_ctl_send_reset(const struct sock *sk, struct sk_buff *rxskb) rxiph->daddr); skb_dst_set(skb, dst_clone(dst)); + local_bh_disable(); bh_lock_sock(ctl_sk); err = ip_build_and_send_pkt(skb, ctl_sk, rxiph->daddr, rxiph->saddr, NULL); bh_unlock_sock(ctl_sk); if (net_xmit_eval(err) == 0) { - DCCP_INC_STATS(DCCP_MIB_OUTSEGS); - DCCP_INC_STATS(DCCP_MIB_OUTRSTS); + __DCCP_INC_STATS(DCCP_MIB_OUTSEGS); + __DCCP_INC_STATS(DCCP_MIB_OUTRSTS); } + local_bh_enable(); out: - dst_release(dst); + dst_release(dst); } static void dccp_v4_reqsk_destructor(struct request_sock *req) -- cgit v0.10.2 From a11836fa5a67ba56d8338138e37b42384af73e5e Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Sat, 9 Jul 2016 16:45:29 +0300 Subject: x86/platform/intel-mid: Mark regulators explicitly defined Intel MID platforms are using explicitly defined regulators. Let the regulator core know that we do not have any additional regulators left. This lets it substitute unprovided regulators with dummy ones. Without this change when CONFIG_REGULATOR=y the USB driver fails on getting "vbus" regulator and SDHCI can't get "vmmc" and "vqmmc" regulators either. Signed-off-by: Andy Shevchenko Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/1468071929-77383-1-git-send-email-andriy.shevchenko@linux.intel.com Signed-off-by: Ingo Molnar diff --git a/arch/x86/platform/intel-mid/intel-mid.c b/arch/x86/platform/intel-mid/intel-mid.c index 90bb997..abbf49c 100644 --- a/arch/x86/platform/intel-mid/intel-mid.c +++ b/arch/x86/platform/intel-mid/intel-mid.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -144,6 +145,15 @@ static void intel_mid_arch_setup(void) out: if (intel_mid_ops->arch_setup) intel_mid_ops->arch_setup(); + + /* + * Intel MID platforms are using explicitly defined regulators. + * + * Let the regulator core know that we do not have any additional + * regulators left. This lets it substitute unprovided regulators with + * dummy ones: + */ + regulator_has_full_constraints(); } /* MID systems don't have i8042 controller */ -- cgit v0.10.2 From 2e9d1e150abf88cb63e5d34ca286edbb95b4c53d Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 20 Jun 2016 16:58:29 +0200 Subject: x86/entry: Avoid interrupt flag save and restore Thanks to all the work that was done by Andy Lutomirski and others, enter_from_user_mode() and prepare_exit_to_usermode() are now called only with interrupts disabled. Let's provide them a version of user_enter()/user_exit() that skips saving and restoring the interrupt flag. On an AMD-based machine I tested this patch on, with force-enabled context tracking, the speed-up in system calls was 90 clock cycles or 6%, measured with the following simple benchmark: #include #include #include #include unsigned long rdtsc() { unsigned long result; asm volatile("rdtsc; shl $32, %%rdx; mov %%eax, %%eax\n" "or %%rdx, %%rax" : "=a" (result) : : "rdx"); return result; } int main() { unsigned long tsc1, tsc2; int pid = getpid(); int i; tsc1 = rdtsc(); for (i = 0; i < 100000000; i++) kill(pid, SIGWINCH); tsc2 = rdtsc(); printf("%ld\n", tsc2 - tsc1); } Signed-off-by: Paolo Bonzini Reviewed-by: Rik van Riel Reviewed-by: Andy Lutomirski Acked-by: Paolo Bonzini Cc: Borislav Petkov Cc: Brian Gerst Cc: Denys Vlasenko Cc: H. Peter Anvin Cc: Josh Poimboeuf Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: kvm@vger.kernel.org Link: http://lkml.kernel.org/r/1466434712-31440-2-git-send-email-pbonzini@redhat.com Signed-off-by: Ingo Molnar diff --git a/arch/x86/entry/common.c b/arch/x86/entry/common.c index ec138e5..618bc61 100644 --- a/arch/x86/entry/common.c +++ b/arch/x86/entry/common.c @@ -43,7 +43,7 @@ static struct thread_info *pt_regs_to_thread_info(struct pt_regs *regs) __visible void enter_from_user_mode(void) { CT_WARN_ON(ct_state() != CONTEXT_USER); - user_exit(); + user_exit_irqoff(); } #else static inline void enter_from_user_mode(void) {} @@ -274,7 +274,7 @@ __visible inline void prepare_exit_to_usermode(struct pt_regs *regs) ti->status &= ~TS_COMPAT; #endif - user_enter(); + user_enter_irqoff(); } #define SYSCALL_EXIT_WORK_FLAGS \ diff --git a/include/linux/context_tracking.h b/include/linux/context_tracking.h index d259274..d9aef2a 100644 --- a/include/linux/context_tracking.h +++ b/include/linux/context_tracking.h @@ -31,6 +31,19 @@ static inline void user_exit(void) context_tracking_exit(CONTEXT_USER); } +/* Called with interrupts disabled. */ +static inline void user_enter_irqoff(void) +{ + if (context_tracking_is_enabled()) + __context_tracking_enter(CONTEXT_USER); + +} +static inline void user_exit_irqoff(void) +{ + if (context_tracking_is_enabled()) + __context_tracking_exit(CONTEXT_USER); +} + static inline enum ctx_state exception_enter(void) { enum ctx_state prev_ctx; @@ -69,6 +82,8 @@ static inline enum ctx_state ct_state(void) #else static inline void user_enter(void) { } static inline void user_exit(void) { } +static inline void user_enter_irqoff(void) { } +static inline void user_exit_irqoff(void) { } static inline enum ctx_state exception_enter(void) { return 0; } static inline void exception_exit(enum ctx_state prev_ctx) { } static inline enum ctx_state ct_state(void) { return CONTEXT_DISABLED; } -- cgit v0.10.2 From be8a18e2e98e04a5def5887d913b267865562448 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 20 Jun 2016 16:58:30 +0200 Subject: x86/entry: Inline enter_from_user_mode() This matches what is already done for prepare_exit_to_usermode(), and saves about 60 clock cycles (4% speedup) with the benchmark in the previous commit message. Signed-off-by: Paolo Bonzini Reviewed-by: Rik van Riel Reviewed-by: Andy Lutomirski Acked-by: Paolo Bonzini Cc: Borislav Petkov Cc: Brian Gerst Cc: Denys Vlasenko Cc: H. Peter Anvin Cc: Josh Poimboeuf Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: kvm@vger.kernel.org Link: http://lkml.kernel.org/r/1466434712-31440-3-git-send-email-pbonzini@redhat.com Signed-off-by: Ingo Molnar diff --git a/arch/x86/entry/common.c b/arch/x86/entry/common.c index 618bc61..9e1e27d 100644 --- a/arch/x86/entry/common.c +++ b/arch/x86/entry/common.c @@ -40,7 +40,7 @@ static struct thread_info *pt_regs_to_thread_info(struct pt_regs *regs) #ifdef CONFIG_CONTEXT_TRACKING /* Called on entry from user mode with IRQs off. */ -__visible void enter_from_user_mode(void) +__visible inline void enter_from_user_mode(void) { CT_WARN_ON(ct_state() != CONTEXT_USER); user_exit_irqoff(); -- cgit v0.10.2 From 99e9d958726c04cec3e36902d8583fdd8cb5b1bb Mon Sep 17 00:00:00 2001 From: John Kacur Date: Fri, 17 Jun 2016 15:05:15 +0200 Subject: irq/Documentation: Correct result of echnoing 5 to smp_affinity This command: echo 5 > /proc/irq/10/smp_affinity means only the first and third (not fourth) CPUs can handle irqs That is, CPU0 is the first CPU and CPU2 is the third cpu Signed-off-by: John Kacur Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/1466168715-8410-1-git-send-email-jkacur@redhat.com Signed-off-by: Ingo Molnar diff --git a/Documentation/filesystems/proc.txt b/Documentation/filesystems/proc.txt index e8d0075..5b61eea 100644 --- a/Documentation/filesystems/proc.txt +++ b/Documentation/filesystems/proc.txt @@ -725,7 +725,7 @@ IRQ, you can set it by doing: > echo 1 > /proc/irq/10/smp_affinity This means that only the first CPU will handle the IRQ, but you can also echo -5 which means that only the first and fourth CPU can handle the IRQ. +5 which means that only the first and third CPU can handle the IRQ. The contents of each smp_affinity file is the same by default: -- cgit v0.10.2 From fc5f3ac24720012909c224a63ca3217f4759967d Mon Sep 17 00:00:00 2001 From: Len Brown Date: Fri, 17 Jun 2016 01:22:43 -0400 Subject: Revert "x86/tsc: Add missing Cherrytrail frequency to the table" This reverts commit: e2724e9d9692 ("x86/tsc: Add missing Cherrytrail frequency to the table") ... as it is incomplete, and is replaced by a more complete patch later in this series. Signed-off-by: Len Brown Reviewed-by: Thomas Gleixner Cc: Linus Torvalds Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/2199d0e959f7f71a18827268b5d060f8d3831639.1466138954.git.len.brown@intel.com Signed-off-by: Ingo Molnar diff --git a/arch/x86/kernel/tsc_msr.c b/arch/x86/kernel/tsc_msr.c index 9911a06..6aa0f4d 100644 --- a/arch/x86/kernel/tsc_msr.c +++ b/arch/x86/kernel/tsc_msr.c @@ -23,7 +23,6 @@ #include /* CPU reference clock frequency: in KHz */ -#define FREQ_80 80000 #define FREQ_83 83200 #define FREQ_100 99840 #define FREQ_133 133200 @@ -57,8 +56,6 @@ static struct freq_desc freq_desc_tables[] = { { 6, 0x37, 1, { FREQ_83, FREQ_100, FREQ_133, FREQ_166, 0, 0, 0, 0 } }, /* ANN */ { 6, 0x5a, 1, { FREQ_83, FREQ_100, FREQ_133, FREQ_100, 0, 0, 0, 0 } }, - /* AIRMONT */ - { 6, 0x4c, 1, { FREQ_83, FREQ_100, FREQ_133, FREQ_166, FREQ_80, 0, 0, 0 } }, }; static int match_cpu(u8 family, u8 model) -- cgit v0.10.2 From ba8268330dc18d309a39175ea4d2c5d86c2cef09 Mon Sep 17 00:00:00 2001 From: Len Brown Date: Fri, 17 Jun 2016 01:22:44 -0400 Subject: x86/tsc_msr: Identify Intel-specific code try_msr_calibrate_tsc() is currently Intel-specific, and should not execute on any other vendor's parts. Signed-off-by: Len Brown Reviewed-by: Thomas Gleixner Cc: Linus Torvalds Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1fe23c052826bdcfeb3d45045aa02246078cb5a7.1466138954.git.len.brown@intel.com Signed-off-by: Ingo Molnar diff --git a/arch/x86/kernel/tsc_msr.c b/arch/x86/kernel/tsc_msr.c index 6aa0f4d..4ec5e56 100644 --- a/arch/x86/kernel/tsc_msr.c +++ b/arch/x86/kernel/tsc_msr.c @@ -86,6 +86,9 @@ unsigned long try_msr_calibrate_tsc(void) unsigned long res; int cpu_index; + if (boot_cpu_data.x86_vendor != X86_VENDOR_INTEL) + return 0; + cpu_index = match_cpu(boot_cpu_data.x86, boot_cpu_data.x86_model); if (cpu_index < 0) return 0; -- cgit v0.10.2 From 14bb4e34860af48ef1ea0f52b11611ce4db987fe Mon Sep 17 00:00:00 2001 From: Len Brown Date: Fri, 17 Jun 2016 01:22:45 -0400 Subject: x86/tsc_msr: Remove debugging messages Debugging messages are not necessary after all of the possible hardware failures that never occur. Instead, this code can simply return 0. This code also doesn't need to print in the success case. tsc_init() already prints the TSC frequency, and apic=debug is available if anybody really is interested in printing the LAPIC frequency. Signed-off-by: Len Brown Reviewed-by: Thomas Gleixner Cc: Linus Torvalds Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/cf03279a125b95dfa9b8d3d5b4a66de09cd04050.1466138954.git.len.brown@intel.com Signed-off-by: Ingo Molnar diff --git a/arch/x86/kernel/tsc_msr.c b/arch/x86/kernel/tsc_msr.c index 4ec5e56..f7ba44b 100644 --- a/arch/x86/kernel/tsc_msr.c +++ b/arch/x86/kernel/tsc_msr.c @@ -76,9 +76,10 @@ static int match_cpu(u8 family, u8 model) (freq_desc_tables[cpu_index].freqs[freq_id]) /* - * Do MSR calibration only for known/supported CPUs. + * MSR-based CPU/TSC frequency discovery for certain CPUs. * - * Returns the calibration value or 0 if MSR calibration failed. + * Set global "lapic_timer_frequency" to bus_clock_cycles/jiffy + * Return processor base frequency in KHz, or 0 on failure. */ unsigned long try_msr_calibrate_tsc(void) { @@ -100,31 +101,17 @@ unsigned long try_msr_calibrate_tsc(void) rdmsr(MSR_IA32_PERF_STATUS, lo, hi); ratio = (hi >> 8) & 0x1f; } - pr_info("Maximum core-clock to bus-clock ratio: 0x%x\n", ratio); - - if (!ratio) - goto fail; /* Get FSB FREQ ID */ rdmsr(MSR_FSB_FREQ, lo, hi); freq_id = lo & 0x7; freq = id_to_freq(cpu_index, freq_id); - pr_info("Resolved frequency ID: %u, frequency: %u KHz\n", - freq_id, freq); - if (!freq) - goto fail; /* TSC frequency = maximum resolved freq * maximum resolved bus ratio */ res = freq * ratio; - pr_info("TSC runs at %lu KHz\n", res); #ifdef CONFIG_X86_LOCAL_APIC lapic_timer_frequency = (freq * 1000) / HZ; - pr_info("lapic_timer_frequency = %d\n", lapic_timer_frequency); #endif return res; - -fail: - pr_warn("Fast TSC calibration using MSR failed\n"); - return 0; } -- cgit v0.10.2 From 9e0cae9f6227f946fb0076b6a68c88156137f618 Mon Sep 17 00:00:00 2001 From: Len Brown Date: Fri, 17 Jun 2016 01:22:46 -0400 Subject: x86/tsc_msr: Update comments, expand definitions Syntax only, no functional change. Signed-off-by: Len Brown Reviewed-by: Thomas Gleixner Cc: Linus Torvalds Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/8653a2dba21fef122fc7b29eafb750e2004d3976.1466138954.git.len.brown@intel.com Signed-off-by: Ingo Molnar diff --git a/arch/x86/kernel/tsc_msr.c b/arch/x86/kernel/tsc_msr.c index f7ba44b..4110f72 100644 --- a/arch/x86/kernel/tsc_msr.c +++ b/arch/x86/kernel/tsc_msr.c @@ -1,14 +1,5 @@ /* - * tsc_msr.c - MSR based TSC calibration on Intel Atom SoC platforms. - * - * TSC in Intel Atom SoC runs at a constant rate which can be figured - * by this formula: - * * - * See Intel 64 and IA-32 System Programming Guid section 16.12 and 30.11.5 - * for details. - * Especially some Intel Atom SoCs don't have PIT(i8254) or HPET, so MSR - * based calibration is the only option. - * + * tsc_msr.c - TSC frequency enumeration via MSR * * Copyright (C) 2013 Intel Corporation * Author: Bin Gao @@ -22,17 +13,10 @@ #include #include -/* CPU reference clock frequency: in KHz */ -#define FREQ_83 83200 -#define FREQ_100 99840 -#define FREQ_133 133200 -#define FREQ_166 166400 - #define MAX_NUM_FREQS 8 /* - * According to Intel 64 and IA-32 System Programming Guide, - * if MSR_PERF_STAT[31] is set, the maximum resolved bus ratio can be + * If MSR_PERF_STAT[31] is set, the maximum resolved bus ratio can be * read in MSR_PLATFORM_ID[12:8], otherwise in MSR_PERF_STAT[44:40]. * Unfortunately some Intel Atom SoCs aren't quite compliant to this, * so we need manually differentiate SoC families. This is what the @@ -47,15 +31,15 @@ struct freq_desc { static struct freq_desc freq_desc_tables[] = { /* PNW */ - { 6, 0x27, 0, { 0, 0, 0, 0, 0, FREQ_100, 0, FREQ_83 } }, + { 6, 0x27, 0, { 0, 0, 0, 0, 0, 99840, 0, 83200 } }, /* CLV+ */ - { 6, 0x35, 0, { 0, FREQ_133, 0, 0, 0, FREQ_100, 0, FREQ_83 } }, - /* TNG */ - { 6, 0x4a, 1, { 0, FREQ_100, FREQ_133, 0, 0, 0, 0, 0 } }, - /* VLV2 */ - { 6, 0x37, 1, { FREQ_83, FREQ_100, FREQ_133, FREQ_166, 0, 0, 0, 0 } }, - /* ANN */ - { 6, 0x5a, 1, { FREQ_83, FREQ_100, FREQ_133, FREQ_100, 0, 0, 0, 0 } }, + { 6, 0x35, 0, { 0, 133200, 0, 0, 0, 99840, 0, 83200 } }, + /* TNG - Intel Atom processor Z3400 series */ + { 6, 0x4a, 1, { 0, 99840, 133200, 0, 0, 0, 0, 0 } }, + /* VLV2 - Intel Atom processor E3000, Z3600, Z3700 series */ + { 6, 0x37, 1, { 83200, 99840, 133200, 166400, 0, 0, 0, 0 } }, + /* ANN - Intel Atom processor Z3500 series */ + { 6, 0x5a, 1, { 83200, 99840, 133200, 99840, 0, 0, 0, 0 } }, }; static int match_cpu(u8 family, u8 model) -- cgit v0.10.2 From 05680e7fa8a4e700e031a5e72cd8c18265f0031a Mon Sep 17 00:00:00 2001 From: Len Brown Date: Fri, 17 Jun 2016 01:22:47 -0400 Subject: x86/tsc_msr: Correct Silvermont reference clock values Atom processors use a 19.2 MHz crystal oscillator. Early processors generate 100 MHz via 19.2 MHz * 26 / 5 = 99.84 MHz. Later preocessor generate 100 MHz via 19.2 MHz * 125 / 24 = 100 MHz. Update the Silvermont-based tables accordingly, matching the Software Developers Manual. Also, correct a 166 MHz entry that should have been 116 MHz, and add a missing 80 MHz entry. Reported-by: Stephane Gasparini Signed-off-by: Len Brown Reviewed-by: Thomas Gleixner Cc: Linus Torvalds Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/5d7561655dfb066ff10801b423405bae4d1cfbe2.1466138954.git.len.brown@intel.com Signed-off-by: Ingo Molnar diff --git a/arch/x86/kernel/tsc_msr.c b/arch/x86/kernel/tsc_msr.c index 4110f72..20487e2 100644 --- a/arch/x86/kernel/tsc_msr.c +++ b/arch/x86/kernel/tsc_msr.c @@ -35,11 +35,11 @@ static struct freq_desc freq_desc_tables[] = { /* CLV+ */ { 6, 0x35, 0, { 0, 133200, 0, 0, 0, 99840, 0, 83200 } }, /* TNG - Intel Atom processor Z3400 series */ - { 6, 0x4a, 1, { 0, 99840, 133200, 0, 0, 0, 0, 0 } }, + { 6, 0x4a, 1, { 0, 100000, 133300, 0, 0, 0, 0, 0 } }, /* VLV2 - Intel Atom processor E3000, Z3600, Z3700 series */ - { 6, 0x37, 1, { 83200, 99840, 133200, 166400, 0, 0, 0, 0 } }, + { 6, 0x37, 1, { 83300, 100000, 133300, 116700, 80000, 0, 0, 0 } }, /* ANN - Intel Atom processor Z3500 series */ - { 6, 0x5a, 1, { 83200, 99840, 133200, 99840, 0, 0, 0, 0 } }, + { 6, 0x5a, 1, { 83300, 100000, 133300, 100000, 0, 0, 0, 0 } }, }; static int match_cpu(u8 family, u8 model) -- cgit v0.10.2 From 6fcb41cdaee5056c96de88ee095bddd27a7697de Mon Sep 17 00:00:00 2001 From: Len Brown Date: Fri, 17 Jun 2016 01:22:48 -0400 Subject: x86/tsc_msr: Add Airmont reference clock values per the Intel 64 and IA-32 Architecture Software Developer's Manual... Add the reference clock for Intel Atom Processors Based on the Airmont Microarchitecture. Reported-by: Stephane Gasparini Signed-off-by: Len Brown Reviewed-by: Thomas Gleixner Cc: Linus Torvalds Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/abc6a0f4b18281410da1a3f26e2819d8e03e144f.1466138954.git.len.brown@intel.com Signed-off-by: Ingo Molnar diff --git a/arch/x86/kernel/tsc_msr.c b/arch/x86/kernel/tsc_msr.c index 20487e2..65b3d8cb 100644 --- a/arch/x86/kernel/tsc_msr.c +++ b/arch/x86/kernel/tsc_msr.c @@ -13,7 +13,7 @@ #include #include -#define MAX_NUM_FREQS 8 +#define MAX_NUM_FREQS 9 /* * If MSR_PERF_STAT[31] is set, the maximum resolved bus ratio can be @@ -40,6 +40,9 @@ static struct freq_desc freq_desc_tables[] = { { 6, 0x37, 1, { 83300, 100000, 133300, 116700, 80000, 0, 0, 0 } }, /* ANN - Intel Atom processor Z3500 series */ { 6, 0x5a, 1, { 83300, 100000, 133300, 100000, 0, 0, 0, 0 } }, + /* AMT - Intel Atom processor X7-Z8000 and X5-Z8000 series */ + { 6, 0x4c, 1, { 83300, 100000, 133300, 116700, + 80000, 93300, 90000, 88900, 87500 } }, }; static int match_cpu(u8 family, u8 model) -- cgit v0.10.2 From 03482e08a87d24e5c8c23e6981c482e832cf3bdc Mon Sep 17 00:00:00 2001 From: Yu-cheng Yu Date: Fri, 17 Jun 2016 13:07:15 -0700 Subject: x86/fpu/xstate: Align xstate components according to CPUID CPUID function 0x0d, sub function (i, i > 1) returns in ecx[1] the alignment requirement of component 'i' when the compacted format is used. If ecx[1] is 0, component 'i' is located immediately following the preceding component. If ecx[1] is 1, component 'i' is located on the next 64-byte boundary following the preceding component. Signed-off-by: Yu-cheng Yu Reviewed-by: Dave Hansen Cc: Andy Lutomirski Cc: Borislav Petkov Cc: Brian Gerst Cc: Dave Hansen Cc: Denys Vlasenko Cc: Fenghua Yu Cc: H. Peter Anvin Cc: Josh Poimboeuf Cc: Linus Torvalds Cc: Oleg Nesterov Cc: Peter Zijlstra Cc: Quentin Casasnovas Cc: Ravi V. Shankar Cc: Sai Praneeth Prakhya Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/331e2bef1a0a7a584f06adde095b6bbfbe166472.1466179491.git.yu-cheng.yu@intel.com Signed-off-by: Ingo Molnar diff --git a/arch/x86/kernel/fpu/xstate.c b/arch/x86/kernel/fpu/xstate.c index 0b01f00..7963029 100644 --- a/arch/x86/kernel/fpu/xstate.c +++ b/arch/x86/kernel/fpu/xstate.c @@ -270,6 +270,33 @@ static void __init print_xstate_features(void) } /* + * This check is important because it is easy to get XSTATE_* + * confused with XSTATE_BIT_*. + */ +#define CHECK_XFEATURE(nr) do { \ + WARN_ON(nr < FIRST_EXTENDED_XFEATURE); \ + WARN_ON(nr >= XFEATURE_MAX); \ +} while (0) + +/* + * We could cache this like xstate_size[], but we only use + * it here, so it would be a waste of space. + */ +static int xfeature_is_aligned(int xfeature_nr) +{ + u32 eax, ebx, ecx, edx; + + CHECK_XFEATURE(xfeature_nr); + cpuid_count(XSTATE_CPUID, xfeature_nr, &eax, &ebx, &ecx, &edx); + /* + * The value returned by ECX[1] indicates the alignment + * of state component 'i' when the compacted format + * of the extended region of an XSAVE area is used: + */ + return !!(ecx & 2); +} + +/* * This function sets up offsets and sizes of all extended states in * xsave area. This supports both standard format and compacted format * of the xsave aread. @@ -306,10 +333,14 @@ static void __init setup_xstate_comp(void) else xstate_comp_sizes[i] = 0; - if (i > FIRST_EXTENDED_XFEATURE) + if (i > FIRST_EXTENDED_XFEATURE) { xstate_comp_offsets[i] = xstate_comp_offsets[i-1] + xstate_comp_sizes[i-1]; + if (xfeature_is_aligned(i)) + xstate_comp_offsets[i] = + ALIGN(xstate_comp_offsets[i], 64); + } } } @@ -366,33 +397,6 @@ static int xfeature_is_user(int xfeature_nr) } */ -/* - * This check is important because it is easy to get XSTATE_* - * confused with XSTATE_BIT_*. - */ -#define CHECK_XFEATURE(nr) do { \ - WARN_ON(nr < FIRST_EXTENDED_XFEATURE); \ - WARN_ON(nr >= XFEATURE_MAX); \ -} while (0) - -/* - * We could cache this like xstate_size[], but we only use - * it here, so it would be a waste of space. - */ -static int xfeature_is_aligned(int xfeature_nr) -{ - u32 eax, ebx, ecx, edx; - - CHECK_XFEATURE(xfeature_nr); - cpuid_count(XSTATE_CPUID, xfeature_nr, &eax, &ebx, &ecx, &edx); - /* - * The value returned by ECX[1] indicates the alignment - * of state component i when the compacted format - * of the extended region of an XSAVE area is used - */ - return !!(ecx & 2); -} - static int xfeature_uncompacted_offset(int xfeature_nr) { u32 eax, ebx, ecx, edx; -- cgit v0.10.2 From 1499ce2dd45afddea2e84f9f920890cf88384c4e Mon Sep 17 00:00:00 2001 From: Yu-cheng Yu Date: Fri, 17 Jun 2016 13:07:16 -0700 Subject: x86/fpu/xstate: Fix supervisor xstate component offset CPUID function 0x0d, sub function (i, i > 1) returns in ebx the offset of xstate component i. Zero is returned for a supervisor state. A supervisor state can only be saved by XSAVES and XSAVES uses a compacted format. There is no fixed offset for a supervisor state. This patch checks and makes sure a supervisor state offset is not recorded or mis-used. This has no effect in practice as we currently use no supervisor states, but it would be good to fix. Signed-off-by: Yu-cheng Yu Reviewed-by: Dave Hansen Cc: Andy Lutomirski Cc: Borislav Petkov Cc: Brian Gerst Cc: Dave Hansen Cc: Denys Vlasenko Cc: Fenghua Yu Cc: H. Peter Anvin Cc: Josh Poimboeuf Cc: Linus Torvalds Cc: Oleg Nesterov Cc: Peter Zijlstra Cc: Quentin Casasnovas Cc: Ravi V. Shankar Cc: Sai Praneeth Prakhya Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/81b29e40d35d4cec9f2511a856fe769f34935a3f.1466179491.git.yu-cheng.yu@intel.com Signed-off-by: Ingo Molnar diff --git a/arch/x86/include/asm/fpu/types.h b/arch/x86/include/asm/fpu/types.h index 36b90bb..12dd648 100644 --- a/arch/x86/include/asm/fpu/types.h +++ b/arch/x86/include/asm/fpu/types.h @@ -122,6 +122,7 @@ enum xfeature { #define XFEATURE_MASK_OPMASK (1 << XFEATURE_OPMASK) #define XFEATURE_MASK_ZMM_Hi256 (1 << XFEATURE_ZMM_Hi256) #define XFEATURE_MASK_Hi16_ZMM (1 << XFEATURE_Hi16_ZMM) +#define XFEATURE_MASK_PT (1 << XFEATURE_PT_UNIMPLEMENTED_SO_FAR) #define XFEATURE_MASK_PKRU (1 << XFEATURE_PKRU) #define XFEATURE_MASK_FPSSE (XFEATURE_MASK_FP | XFEATURE_MASK_SSE) diff --git a/arch/x86/include/asm/fpu/xstate.h b/arch/x86/include/asm/fpu/xstate.h index d812cf3..92f376c 100644 --- a/arch/x86/include/asm/fpu/xstate.h +++ b/arch/x86/include/asm/fpu/xstate.h @@ -18,6 +18,9 @@ #define XSAVE_YMM_SIZE 256 #define XSAVE_YMM_OFFSET (XSAVE_HDR_SIZE + XSAVE_HDR_OFFSET) +/* Supervisor features */ +#define XFEATURE_MASK_SUPERVISOR (XFEATURE_MASK_PT) + /* Supported features which support lazy state saving */ #define XFEATURE_MASK_LAZY (XFEATURE_MASK_FP | \ XFEATURE_MASK_SSE | \ diff --git a/arch/x86/kernel/fpu/xstate.c b/arch/x86/kernel/fpu/xstate.c index 7963029..02786fb 100644 --- a/arch/x86/kernel/fpu/xstate.c +++ b/arch/x86/kernel/fpu/xstate.c @@ -112,6 +112,27 @@ int cpu_has_xfeatures(u64 xfeatures_needed, const char **feature_name) } EXPORT_SYMBOL_GPL(cpu_has_xfeatures); +static int xfeature_is_supervisor(int xfeature_nr) +{ + /* + * We currently do not support supervisor states, but if + * we did, we could find out like this. + * + * SDM says: If state component 'i' is a user state component, + * ECX[0] return 0; if state component i is a supervisor + * state component, ECX[0] returns 1. + */ + u32 eax, ebx, ecx, edx; + + cpuid_count(XSTATE_CPUID, xfeature_nr, &eax, &ebx, &ecx, &edx); + return !!(ecx & 1); +} + +static int xfeature_is_user(int xfeature_nr) +{ + return !xfeature_is_supervisor(xfeature_nr); +} + /* * When executing XSAVEOPT (or other optimized XSAVE instructions), if * a processor implementation detects that an FPU state component is still @@ -230,7 +251,14 @@ static void __init setup_xstate_features(void) continue; cpuid_count(XSTATE_CPUID, i, &eax, &ebx, &ecx, &edx); - xstate_offsets[i] = ebx; + + /* + * If an xfeature is supervisor state, the offset + * in EBX is invalid. We leave it to -1. + */ + if (xfeature_is_user(i)) + xstate_offsets[i] = ebx; + xstate_sizes[i] = eax; /* * In our xstate size checks, we assume that the @@ -375,32 +403,20 @@ static void __init setup_init_fpu_buf(void) copy_xregs_to_kernel_booting(&init_fpstate.xsave); } -static int xfeature_is_supervisor(int xfeature_nr) -{ - /* - * We currently do not support supervisor states, but if - * we did, we could find out like this. - * - * SDM says: If state component i is a user state component, - * ECX[0] return 0; if state component i is a supervisor - * state component, ECX[0] returns 1. - u32 eax, ebx, ecx, edx; - cpuid_count(XSTATE_CPUID, xfeature_nr, &eax, &ebx, &ecx, &edx; - return !!(ecx & 1); - */ - return 0; -} -/* -static int xfeature_is_user(int xfeature_nr) -{ - return !xfeature_is_supervisor(xfeature_nr); -} -*/ - static int xfeature_uncompacted_offset(int xfeature_nr) { u32 eax, ebx, ecx, edx; + /* + * Only XSAVES supports supervisor states and it uses compacted + * format. Checking a supervisor state's uncompacted offset is + * an error. + */ + if (XFEATURE_MASK_SUPERVISOR & (1 << xfeature_nr)) { + WARN_ONCE(1, "No fixed offset for xstate %d\n", xfeature_nr); + return -1; + } + CHECK_XFEATURE(xfeature_nr); cpuid_count(XSTATE_CPUID, xfeature_nr, &eax, &ebx, &ecx, &edx); return ebx; -- cgit v0.10.2 From 91c3dba7dbc199191272f4a9863f86ea3bfd679f Mon Sep 17 00:00:00 2001 From: Yu-cheng Yu Date: Fri, 17 Jun 2016 13:07:17 -0700 Subject: x86/fpu/xstate: Fix PTRACE frames for XSAVES XSAVES uses compacted format and is a kernel instruction. The kernel should use standard-format, non-supervisor state data for PTRACE. Signed-off-by: Yu-cheng Yu [ Edited away artificial linebreaks. ] Reviewed-by: Dave Hansen Cc: Andy Lutomirski Cc: Borislav Petkov Cc: Brian Gerst Cc: Dave Hansen Cc: Denys Vlasenko Cc: Fenghua Yu Cc: H. Peter Anvin Cc: Josh Poimboeuf Cc: Linus Torvalds Cc: Oleg Nesterov Cc: Peter Zijlstra Cc: Quentin Casasnovas Cc: Ravi V. Shankar Cc: Sai Praneeth Prakhya Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/de3d80949001305fe389799973b675cab055c457.1466179491.git.yu-cheng.yu@intel.com [ Made various readability edits. ] Signed-off-by: Ingo Molnar diff --git a/arch/x86/include/asm/fpu/xstate.h b/arch/x86/include/asm/fpu/xstate.h index 92f376c..ae55a43 100644 --- a/arch/x86/include/asm/fpu/xstate.h +++ b/arch/x86/include/asm/fpu/xstate.h @@ -51,5 +51,8 @@ void fpu__xstate_clear_all_cpu_caps(void); void *get_xsave_addr(struct xregs_state *xsave, int xstate); const void *get_xsave_field_ptr(int xstate_field); int using_compacted_format(void); - +int copyout_from_xsaves(unsigned int pos, unsigned int count, void *kbuf, + void __user *ubuf, struct xregs_state *xsave); +int copyin_to_xsaves(const void *kbuf, const void __user *ubuf, + struct xregs_state *xsave); #endif diff --git a/arch/x86/kernel/fpu/regset.c b/arch/x86/kernel/fpu/regset.c index 81422df..c114b13 100644 --- a/arch/x86/kernel/fpu/regset.c +++ b/arch/x86/kernel/fpu/regset.c @@ -4,6 +4,7 @@ #include #include #include +#include /* * The xstateregs_active() routine is the same as the regset_fpregs_active() routine, @@ -85,21 +86,26 @@ int xstateregs_get(struct task_struct *target, const struct user_regset *regset, if (!boot_cpu_has(X86_FEATURE_XSAVE)) return -ENODEV; - fpu__activate_fpstate_read(fpu); - xsave = &fpu->state.xsave; - /* - * Copy the 48bytes defined by the software first into the xstate - * memory layout in the thread struct, so that we can copy the entire - * xstateregs to the user using one user_regset_copyout(). - */ - memcpy(&xsave->i387.sw_reserved, - xstate_fx_sw_bytes, sizeof(xstate_fx_sw_bytes)); - /* - * Copy the xstate memory layout. - */ - ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, xsave, 0, -1); + fpu__activate_fpstate_read(fpu); + + if (using_compacted_format()) { + ret = copyout_from_xsaves(pos, count, kbuf, ubuf, xsave); + } else { + fpstate_sanitize_xstate(fpu); + /* + * Copy the 48 bytes defined by the software into the xsave + * area in the thread struct, so that we can copy the whole + * area to user using one user_regset_copyout(). + */ + memcpy(&xsave->i387.sw_reserved, xstate_fx_sw_bytes, sizeof(xstate_fx_sw_bytes)); + + /* + * Copy the xstate memory layout. + */ + ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, xsave, 0, -1); + } return ret; } @@ -114,11 +120,27 @@ int xstateregs_set(struct task_struct *target, const struct user_regset *regset, if (!boot_cpu_has(X86_FEATURE_XSAVE)) return -ENODEV; - fpu__activate_fpstate_write(fpu); + /* + * A whole standard-format XSAVE buffer is needed: + */ + if ((pos != 0) || (count < fpu_user_xstate_size)) + return -EFAULT; xsave = &fpu->state.xsave; - ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, xsave, 0, -1); + fpu__activate_fpstate_write(fpu); + + if (boot_cpu_has(X86_FEATURE_XSAVES)) + ret = copyin_to_xsaves(kbuf, ubuf, xsave); + else + ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, xsave, 0, -1); + + /* + * In case of failure, mark all states as init: + */ + if (ret) + fpstate_init(&fpu->state); + /* * mxcsr reserved bits must be masked to zero for security reasons. */ diff --git a/arch/x86/kernel/fpu/xstate.c b/arch/x86/kernel/fpu/xstate.c index 02786fb..56c0e70 100644 --- a/arch/x86/kernel/fpu/xstate.c +++ b/arch/x86/kernel/fpu/xstate.c @@ -11,6 +11,7 @@ #include #include #include +#include #include @@ -697,7 +698,12 @@ void __init fpu__init_system_xstate(void) return; } - update_regset_xstate_info(fpu_kernel_xstate_size, xfeatures_mask); + /* + * Update info used for ptrace frames; use standard-format size and no + * supervisor xstates: + */ + update_regset_xstate_info(fpu_user_xstate_size, xfeatures_mask & ~XFEATURE_MASK_SUPERVISOR); + fpu__init_prepare_fx_sw_frame(); setup_init_fpu_buf(); setup_xstate_comp(); @@ -925,16 +931,16 @@ int arch_set_user_pkey_access(struct task_struct *tsk, int pkey, if (!boot_cpu_has(X86_FEATURE_OSPKE)) return -EINVAL; - /* Set the bits we need in PKRU */ + /* Set the bits we need in PKRU: */ if (init_val & PKEY_DISABLE_ACCESS) new_pkru_bits |= PKRU_AD_BIT; if (init_val & PKEY_DISABLE_WRITE) new_pkru_bits |= PKRU_WD_BIT; - /* Shift the bits in to the correct place in PKRU for pkey. */ + /* Shift the bits in to the correct place in PKRU for pkey: */ new_pkru_bits <<= pkey_shift; - /* Locate old copy of the state in the xsave buffer */ + /* Locate old copy of the state in the xsave buffer: */ old_pkru_state = get_xsave_addr(xsave, XFEATURE_MASK_PKRU); /* @@ -947,9 +953,10 @@ int arch_set_user_pkey_access(struct task_struct *tsk, int pkey, else new_pkru_state.pkru = old_pkru_state->pkru; - /* mask off any old bits in place */ + /* Mask off any old bits in place: */ new_pkru_state.pkru &= ~((PKRU_AD_BIT|PKRU_WD_BIT) << pkey_shift); - /* Set the newly-requested bits */ + + /* Set the newly-requested bits: */ new_pkru_state.pkru |= new_pkru_bits; /* @@ -963,8 +970,168 @@ int arch_set_user_pkey_access(struct task_struct *tsk, int pkey, */ new_pkru_state.pad = 0; - fpu__xfeature_set_state(XFEATURE_MASK_PKRU, &new_pkru_state, - sizeof(new_pkru_state)); + fpu__xfeature_set_state(XFEATURE_MASK_PKRU, &new_pkru_state, sizeof(new_pkru_state)); + + return 0; +} + +/* + * This is similar to user_regset_copyout(), but will not add offset to + * the source data pointer or increment pos, count, kbuf, and ubuf. + */ +static inline int xstate_copyout(unsigned int pos, unsigned int count, + void *kbuf, void __user *ubuf, + const void *data, const int start_pos, + const int end_pos) +{ + if ((count == 0) || (pos < start_pos)) + return 0; + + if (end_pos < 0 || pos < end_pos) { + unsigned int copy = (end_pos < 0 ? count : min(count, end_pos - pos)); + + if (kbuf) { + memcpy(kbuf + pos, data, copy); + } else { + if (__copy_to_user(ubuf + pos, data, copy)) + return -EFAULT; + } + } + return 0; +} + +/* + * Convert from kernel XSAVES compacted format to standard format and copy + * to a ptrace buffer. It supports partial copy but pos always starts from + * zero. This is called from xstateregs_get() and there we check the CPU + * has XSAVES. + */ +int copyout_from_xsaves(unsigned int pos, unsigned int count, void *kbuf, + void __user *ubuf, struct xregs_state *xsave) +{ + unsigned int offset, size; + int ret, i; + struct xstate_header header; + + /* + * Currently copy_regset_to_user() starts from pos 0: + */ + if (unlikely(pos != 0)) + return -EFAULT; + + /* + * The destination is a ptrace buffer; we put in only user xstates: + */ + memset(&header, 0, sizeof(header)); + header.xfeatures = xsave->header.xfeatures; + header.xfeatures &= ~XFEATURE_MASK_SUPERVISOR; + + /* + * Copy xregs_state->header: + */ + offset = offsetof(struct xregs_state, header); + size = sizeof(header); + + ret = xstate_copyout(offset, size, kbuf, ubuf, &header, 0, count); + + if (ret) + return ret; + + for (i = 0; i < XFEATURE_MAX; i++) { + /* + * Copy only in-use xstates: + */ + if ((header.xfeatures >> i) & 1) { + void *src = __raw_xsave_addr(xsave, 1 << i); + + offset = xstate_offsets[i]; + size = xstate_sizes[i]; + + ret = xstate_copyout(offset, size, kbuf, ubuf, src, 0, count); + + if (ret) + return ret; + + if (offset + size >= count) + break; + } + + } + + /* + * Fill xsave->i387.sw_reserved value for ptrace frame: + */ + offset = offsetof(struct fxregs_state, sw_reserved); + size = sizeof(xstate_fx_sw_bytes); + + ret = xstate_copyout(offset, size, kbuf, ubuf, xstate_fx_sw_bytes, 0, count); + + if (ret) + return ret; + + return 0; +} + +/* + * Convert from a ptrace standard-format buffer to kernel XSAVES format + * and copy to the target thread. This is called from xstateregs_set() and + * there we check the CPU has XSAVES and a whole standard-sized buffer + * exists. + */ +int copyin_to_xsaves(const void *kbuf, const void __user *ubuf, + struct xregs_state *xsave) +{ + unsigned int offset, size; + int i; + u64 xfeatures; + u64 allowed_features; + + offset = offsetof(struct xregs_state, header); + size = sizeof(xfeatures); + + if (kbuf) { + memcpy(&xfeatures, kbuf + offset, size); + } else { + if (__copy_from_user(&xfeatures, ubuf + offset, size)) + return -EFAULT; + } + + /* + * Reject if the user sets any disabled or supervisor features: + */ + allowed_features = xfeatures_mask & ~XFEATURE_MASK_SUPERVISOR; + + if (xfeatures & ~allowed_features) + return -EINVAL; + + for (i = 0; i < XFEATURE_MAX; i++) { + u64 mask = ((u64)1 << i); + + if (xfeatures & mask) { + void *dst = __raw_xsave_addr(xsave, 1 << i); + + offset = xstate_offsets[i]; + size = xstate_sizes[i]; + + if (kbuf) { + memcpy(dst, kbuf + offset, size); + } else { + if (__copy_from_user(dst, ubuf + offset, size)) + return -EFAULT; + } + } + } + + /* + * The state that came in from userspace was user-state only. + * Mask all the user states out of 'xfeatures': + */ + xsave->header.xfeatures &= XFEATURE_MASK_SUPERVISOR; + + /* + * Add back in the features that came in from userspace: + */ + xsave->header.xfeatures |= xfeatures; return 0; } -- cgit v0.10.2 From 996952e0148026ac0e512db5cad26e14f4267e8b Mon Sep 17 00:00:00 2001 From: Yu-cheng Yu Date: Fri, 17 Jun 2016 13:07:18 -0700 Subject: x86/fpu/xstate: Fix XSTATE component offset print out Component offset print out was incorrect for XSAVES. Correct it and move to a separate function. Signed-off-by: Yu-cheng Yu Reviewed-by: Dave Hansen Cc: Andy Lutomirski Cc: Borislav Petkov Cc: Brian Gerst Cc: Dave Hansen Cc: Denys Vlasenko Cc: Fenghua Yu Cc: H. Peter Anvin Cc: Josh Poimboeuf Cc: Linus Torvalds Cc: Oleg Nesterov Cc: Peter Zijlstra Cc: Quentin Casasnovas Cc: Ravi V. Shankar Cc: Sai Praneeth Prakhya Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/86602a8ac400626c6eca7125c3e15934866fc38e.1466179491.git.yu-cheng.yu@intel.com Signed-off-by: Ingo Molnar diff --git a/arch/x86/kernel/fpu/xstate.c b/arch/x86/kernel/fpu/xstate.c index 56c0e70..09bac97 100644 --- a/arch/x86/kernel/fpu/xstate.c +++ b/arch/x86/kernel/fpu/xstate.c @@ -269,8 +269,6 @@ static void __init setup_xstate_features(void) WARN_ONCE(last_good_offset > xstate_offsets[i], "x86/fpu: misordered xstate at %d\n", last_good_offset); last_good_offset = xstate_offsets[i]; - - printk(KERN_INFO "x86/fpu: xstate_offset[%d]: %4d, xstate_sizes[%d]: %4d\n", i, ebx, i, eax); } } @@ -374,6 +372,21 @@ static void __init setup_xstate_comp(void) } /* + * Print out xstate component offsets and sizes + */ +static void __init print_xstate_offset_size(void) +{ + int i; + + for (i = FIRST_EXTENDED_XFEATURE; i < XFEATURE_MAX; i++) { + if (!xfeature_enabled(i)) + continue; + pr_info("x86/fpu: xstate_offset[%d]: %4d, xstate_sizes[%d]: %4d\n", + i, xstate_comp_offsets[i], i, xstate_sizes[i]); + } +} + +/* * setup the xstate image representing the init state */ static void __init setup_init_fpu_buf(void) @@ -707,6 +720,7 @@ void __init fpu__init_system_xstate(void) fpu__init_prepare_fx_sw_frame(); setup_init_fpu_buf(); setup_xstate_comp(); + print_xstate_offset_size(); pr_info("x86/fpu: Enabled xstate features 0x%llx, context size is %d bytes, using '%s' format.\n", xfeatures_mask, -- cgit v0.10.2 From ac73b27aea4eacdd7555f664d5fc6e1d4d1c8bf6 Mon Sep 17 00:00:00 2001 From: Yu-cheng Yu Date: Fri, 17 Jun 2016 13:07:19 -0700 Subject: x86/fpu/xstate: Fix xstate_offsets, xstate_sizes for non-extended xstates The arrays xstate_offsets[] and xstate_sizes[] record XSAVE standard- format offsets and sizes. Values for non-extended state components fpu and xmm's were not initialized or used. Ptrace format conversion needs them. Fix it. Signed-off-by: Yu-cheng Yu Reviewed-by: Dave Hansen Cc: Andy Lutomirski Cc: Borislav Petkov Cc: Brian Gerst Cc: Dave Hansen Cc: Denys Vlasenko Cc: Fenghua Yu Cc: H. Peter Anvin Cc: Josh Poimboeuf Cc: Linus Torvalds Cc: Oleg Nesterov Cc: Peter Zijlstra Cc: Quentin Casasnovas Cc: Ravi V. Shankar Cc: Sai Praneeth Prakhya Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/cf3ea36cf30e2a99e37da6483e65446d018ff0a7.1466179491.git.yu-cheng.yu@intel.com Signed-off-by: Ingo Molnar diff --git a/arch/x86/kernel/fpu/xstate.c b/arch/x86/kernel/fpu/xstate.c index 09bac97..f8d1aff 100644 --- a/arch/x86/kernel/fpu/xstate.c +++ b/arch/x86/kernel/fpu/xstate.c @@ -246,6 +246,15 @@ static void __init setup_xstate_features(void) /* start at the beginnning of the "extended state" */ unsigned int last_good_offset = offsetof(struct xregs_state, extended_state_area); + /* + * The FP xstates and SSE xstates are legacy states. They are always + * in the fixed offsets in the xsave area in either compacted form + * or standard form. + */ + xstate_offsets[0] = 0; + xstate_sizes[0] = offsetof(struct fxregs_state, xmm_space); + xstate_offsets[1] = xstate_sizes[0]; + xstate_sizes[1] = FIELD_SIZEOF(struct fxregs_state, xmm_space); for (i = FIRST_EXTENDED_XFEATURE; i < XFEATURE_MAX; i++) { if (!xfeature_enabled(i)) -- cgit v0.10.2 From 0ea5ad869c85ac604f3e022bf2c5bef54838433b Mon Sep 17 00:00:00 2001 From: Josh Poimboeuf Date: Wed, 15 Jun 2016 15:45:58 -0500 Subject: objtool: Fix STACK_FRAME_NON_STANDARD macro checking for function symbols Mathieu Desnoyers reported that the STACK_FRAME_NON_STANDARD macro wasn't working with the lttng_filter_interpret_bytecode() function in the lttng-modules code. Usually the relocation created by STACK_FRAME_NON_STANDARD creates a reference to a section symbol like this: Offset Type Value Addend Name 000000000000000000 X86_64_64 000000000000000000 +3136 .text But in this case it created a reference to a function symbol: Offset Type Value Addend Name 000000000000000000 X86_64_64 0x00000000000003a0 +0 lttng_filter_interpret_bytecode To be honest I have no idea what causes gcc to decide to do one over the other. But both are valid ELF, so add support for the function symbol. Reported-by: Mathieu Desnoyers Signed-off-by: Josh Poimboeuf Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: lttng-dev@lists.lttng.org Link: http://lkml.kernel.org/r/9cee42843bc6d94e990a152e4e0319cfdf6756ef.1466023450.git.jpoimboe@redhat.com Signed-off-by: Ingo Molnar diff --git a/tools/objtool/builtin-check.c b/tools/objtool/builtin-check.c index e8a1e69..25d8031 100644 --- a/tools/objtool/builtin-check.c +++ b/tools/objtool/builtin-check.c @@ -122,10 +122,14 @@ static bool ignore_func(struct objtool_file *file, struct symbol *func) /* check for STACK_FRAME_NON_STANDARD */ if (file->whitelist && file->whitelist->rela) - list_for_each_entry(rela, &file->whitelist->rela->rela_list, list) - if (rela->sym->sec == func->sec && + list_for_each_entry(rela, &file->whitelist->rela->rela_list, list) { + if (rela->sym->type == STT_SECTION && + rela->sym->sec == func->sec && rela->addend == func->offset) return true; + if (rela->sym->type == STT_FUNC && rela->sym == func) + return true; + } /* check if it has a context switching instruction */ func_for_each_insn(file, func, insn) -- cgit v0.10.2 From 4ff5308744f5858e4e49e56a0445e2f8b73e47e0 Mon Sep 17 00:00:00 2001 From: Thomas Garnier Date: Wed, 15 Jun 2016 12:05:45 -0700 Subject: x86/mm: Do not reference phys addr beyond kernel The new physical address randomized KASLR implementation can cause the kernel to be aligned close to the end of physical memory. In this case, _brk_end aligned to PMD will go beyond what is expected safe and hit the assert in __phys_addr_symbol(): VIRTUAL_BUG_ON(y >= KERNEL_IMAGE_SIZE); Instead, perform an inclusive range check to avoid incorrectly triggering the assert: kernel BUG at arch/x86/mm/physaddr.c:38! invalid opcode: 0000 [#1] SMP ... RIP: 0010:[] __phys_addr_symbol+0x41/0x50 ... Call Trace: [] cpa_process_alias+0xa9/0x210 [] ? do_raw_spin_unlock+0xc1/0x100 [] __change_page_attr_set_clr+0x8cf/0xbd0 [] ? vm_unmap_aliases+0x7d/0x210 [] change_page_attr_set_clr+0x18c/0x4e0 [] set_memory_4k+0x2c/0x40 [] check_bugs+0x28/0x2a [] start_kernel+0x49d/0x4b9 [] ? early_idt_handler_array+0x120/0x120 [] x86_64_start_reservations+0x29/0x2b [] x86_64_start_kernel+0x143/0x152 Signed-off-by: Thomas Garnier Signed-off-by: Kees Cook Cc: Andy Lutomirski Cc: Borislav Petkov Cc: Borislav Petkov Cc: Brian Gerst Cc: Chris Wilson Cc: Christian Borntraeger Cc: Denys Vlasenko Cc: Dexuan Cui Cc: H. Peter Anvin Cc: Josh Poimboeuf Cc: Linus Torvalds Cc: Matt Fleming Cc: Peter Zijlstra Cc: Sai Praneeth Cc: Thomas Gleixner Cc: Toshi Kani Link: http://lkml.kernel.org/r/20160615190545.GA26071@www.outflux.net Signed-off-by: Ingo Molnar diff --git a/arch/x86/mm/pageattr.c b/arch/x86/mm/pageattr.c index 7a1f7bb..379b511 100644 --- a/arch/x86/mm/pageattr.c +++ b/arch/x86/mm/pageattr.c @@ -101,7 +101,8 @@ static inline unsigned long highmap_start_pfn(void) static inline unsigned long highmap_end_pfn(void) { - return __pa_symbol(roundup(_brk_end, PMD_SIZE)) >> PAGE_SHIFT; + /* Do not reference physical address outside the kernel. */ + return __pa_symbol(roundup(_brk_end, PMD_SIZE) - 1) >> PAGE_SHIFT; } #endif @@ -112,6 +113,12 @@ within(unsigned long addr, unsigned long start, unsigned long end) return addr >= start && addr < end; } +static inline int +within_inclusive(unsigned long addr, unsigned long start, unsigned long end) +{ + return addr >= start && addr <= end; +} + /* * Flushing functions */ @@ -1316,7 +1323,8 @@ static int cpa_process_alias(struct cpa_data *cpa) * to touch the high mapped kernel as well: */ if (!within(vaddr, (unsigned long)_text, _brk_end) && - within(cpa->pfn, highmap_start_pfn(), highmap_end_pfn())) { + within_inclusive(cpa->pfn, highmap_start_pfn(), + highmap_end_pfn())) { unsigned long temp_cpa_vaddr = (cpa->pfn << PAGE_SHIFT) + __START_KERNEL_map - phys_base; alias_cpa = *cpa; -- cgit v0.10.2 From 06a3fcc44d98d6b05afeeae2fbb32938dc3233c7 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 15 Jun 2016 15:04:20 +0300 Subject: x86/platform/intel-mid: Make vertical indentation consistent The vertical indentation is kinda chaotic in intel-mid.h. Let's be consistent with it. Suggested-by: Ingo Molnar Signed-off-by: Andy Shevchenko Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/1465992260-29897-1-git-send-email-andriy.shevchenko@linux.intel.com Signed-off-by: Ingo Molnar diff --git a/arch/x86/include/asm/intel-mid.h b/arch/x86/include/asm/intel-mid.h index 38498a4..59013a2 100644 --- a/arch/x86/include/asm/intel-mid.h +++ b/arch/x86/include/asm/intel-mid.h @@ -42,11 +42,11 @@ struct devs_id { void *(*get_platform_data)(void *info); /* Custom handler for devices */ void (*device_handler)(struct sfi_device_table_entry *pentry, - struct devs_id *dev); + struct devs_id *dev); }; -#define sfi_device(i) \ - static const struct devs_id *const __intel_mid_sfi_##i##_dev __used \ +#define sfi_device(i) \ + static const struct devs_id *const __intel_mid_sfi_##i##_dev __used \ __attribute__((__section__(".x86_intel_mid_dev.init"))) = &i /* @@ -68,7 +68,7 @@ extern enum intel_mid_cpu_type __intel_mid_cpu_chip; /** * struct intel_mid_ops - Interface between intel-mid & sub archs * @arch_setup: arch_setup function to re-initialize platform - * structures (x86_init, x86_platform_init) + * structures (x86_init, x86_platform_init) * * This structure can be extended if any new interface is required * between intel-mid & its sub arch files. @@ -78,20 +78,20 @@ struct intel_mid_ops { }; /* Helper API's for INTEL_MID_OPS_INIT */ -#define DECLARE_INTEL_MID_OPS_INIT(cpuname, cpuid) \ - [cpuid] = get_##cpuname##_ops +#define DECLARE_INTEL_MID_OPS_INIT(cpuname, cpuid) \ + [cpuid] = get_##cpuname##_ops /* Maximum number of CPU ops */ -#define MAX_CPU_OPS(a) (sizeof(a)/sizeof(void *)) +#define MAX_CPU_OPS(a) (sizeof(a)/sizeof(void *)) /* * For every new cpu addition, a weak get__ops() function needs be * declared in arch/x86/platform/intel_mid/intel_mid_weak_decls.h. */ -#define INTEL_MID_OPS_INIT {\ - DECLARE_INTEL_MID_OPS_INIT(penwell, INTEL_MID_CPU_CHIP_PENWELL), \ - DECLARE_INTEL_MID_OPS_INIT(cloverview, INTEL_MID_CPU_CHIP_CLOVERVIEW), \ - DECLARE_INTEL_MID_OPS_INIT(tangier, INTEL_MID_CPU_CHIP_TANGIER) \ +#define INTEL_MID_OPS_INIT { \ + DECLARE_INTEL_MID_OPS_INIT(penwell, INTEL_MID_CPU_CHIP_PENWELL), \ + DECLARE_INTEL_MID_OPS_INIT(cloverview, INTEL_MID_CPU_CHIP_CLOVERVIEW), \ + DECLARE_INTEL_MID_OPS_INIT(tangier, INTEL_MID_CPU_CHIP_TANGIER) \ }; #ifdef CONFIG_X86_INTEL_MID @@ -108,8 +108,8 @@ static inline bool intel_mid_has_msic(void) #else /* !CONFIG_X86_INTEL_MID */ -#define intel_mid_identify_cpu() (0) -#define intel_mid_has_msic() (0) +#define intel_mid_identify_cpu() 0 +#define intel_mid_has_msic() 0 #endif /* !CONFIG_X86_INTEL_MID */ @@ -125,35 +125,38 @@ extern enum intel_mid_timer_options intel_mid_timer_options; * Penwell uses spread spectrum clock, so the freq number is not exactly * the same as reported by MSR based on SDM. */ -#define FSB_FREQ_83SKU 83200 -#define FSB_FREQ_100SKU 99840 -#define FSB_FREQ_133SKU 133000 +#define FSB_FREQ_83SKU 83200 +#define FSB_FREQ_100SKU 99840 +#define FSB_FREQ_133SKU 133000 -#define FSB_FREQ_167SKU 167000 -#define FSB_FREQ_200SKU 200000 -#define FSB_FREQ_267SKU 267000 -#define FSB_FREQ_333SKU 333000 -#define FSB_FREQ_400SKU 400000 +#define FSB_FREQ_167SKU 167000 +#define FSB_FREQ_200SKU 200000 +#define FSB_FREQ_267SKU 267000 +#define FSB_FREQ_333SKU 333000 +#define FSB_FREQ_400SKU 400000 /* Bus Select SoC Fuse value */ -#define BSEL_SOC_FUSE_MASK 0x7 -#define BSEL_SOC_FUSE_001 0x1 /* FSB 133MHz */ -#define BSEL_SOC_FUSE_101 0x5 /* FSB 100MHz */ -#define BSEL_SOC_FUSE_111 0x7 /* FSB 83MHz */ +#define BSEL_SOC_FUSE_MASK 0x7 +/* FSB 133MHz */ +#define BSEL_SOC_FUSE_001 0x1 +/* FSB 100MHz */ +#define BSEL_SOC_FUSE_101 0x5 +/* FSB 83MHz */ +#define BSEL_SOC_FUSE_111 0x7 -#define SFI_MTMR_MAX_NUM 8 -#define SFI_MRTC_MAX 8 +#define SFI_MTMR_MAX_NUM 8 +#define SFI_MRTC_MAX 8 extern void intel_scu_devices_create(void); extern void intel_scu_devices_destroy(void); /* VRTC timer */ -#define MRST_VRTC_MAP_SZ (1024) -/*#define MRST_VRTC_PGOFFSET (0xc00) */ +#define MRST_VRTC_MAP_SZ 1024 +/* #define MRST_VRTC_PGOFFSET 0xc00 */ extern void intel_mid_rtc_init(void); -/* the offset for the mapping of global gpio pin to irq */ -#define INTEL_MID_IRQ_OFFSET 0x100 +/* The offset for the mapping of global gpio pin to irq */ +#define INTEL_MID_IRQ_OFFSET 0x100 #endif /* _ASM_X86_INTEL_MID_H */ -- cgit v0.10.2 From eb019503569c8c701f1e9c70e848d99c6680839b Mon Sep 17 00:00:00 2001 From: Vegard Nossum Date: Sun, 10 Jul 2016 19:14:01 +0200 Subject: perf/x86: Fix bogus kernel printk, again This showed up as "6Failed to access..." here. Signed-off-by: Vegard Nossum Cc: Alexander Shishkin Cc: Arnaldo Carvalho de Melo Cc: Chen Yucong Cc: Jiri Olsa Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Fixes: 1b74dde7c47c ("x86/cpu: Convert printk(KERN_ ...) to pr_(...)") Link: http://lkml.kernel.org/r/1468170841-17045-1-git-send-email-vegard.nossum@oracle.com Signed-off-by: Ingo Molnar diff --git a/arch/x86/events/core.c b/arch/x86/events/core.c index 26ced53..91eac39 100644 --- a/arch/x86/events/core.c +++ b/arch/x86/events/core.c @@ -263,7 +263,7 @@ static bool check_hw_exists(void) msr_fail: pr_cont("Broken PMU hardware detected, using software events only.\n"); - pr_info("%sFailed to access perfctr msr (MSR %x is %Lx)\n", + printk("%sFailed to access perfctr msr (MSR %x is %Lx)\n", boot_cpu_has(X86_FEATURE_HYPERVISOR) ? KERN_INFO : KERN_ERR, reg, val_new); -- cgit v0.10.2 From 447d29d1d3aed839e74c2401ef63387780ac51ed Mon Sep 17 00:00:00 2001 From: Lukas Wunner Date: Sun, 12 Jun 2016 12:31:53 +0200 Subject: x86/quirks: Apply nvidia_bugs quirk only on root bus Since the following commit: 8659c406ade3 ("x86: only scan the root bus in early PCI quirks") ... early quirks are only applied to devices on the root bus. The motivation was to prevent application of the nvidia_bugs quirk on secondary buses. We're about to reintroduce scanning of secondary buses for a quirk to reset the Broadcom 4331 wireless card on 2011/2012 Macs. To prevent regressions, open code the requirement to apply nvidia_bugs only on the root bus. Signed-off-by: Lukas Wunner Cc: Andy Lutomirski Cc: Bjorn Helgaas Cc: Borislav Petkov Cc: Brian Gerst Cc: Denys Vlasenko Cc: H. Peter Anvin Cc: Josh Poimboeuf Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: Yinghai Lu Link: http://lkml.kernel.org/r/4d5477c1d76b2f0387a780f2142bbcdd9fee869b.1465690253.git.lukas@wunner.de Signed-off-by: Ingo Molnar diff --git a/arch/x86/kernel/early-quirks.c b/arch/x86/kernel/early-quirks.c index bca14c8..256976f 100644 --- a/arch/x86/kernel/early-quirks.c +++ b/arch/x86/kernel/early-quirks.c @@ -76,6 +76,13 @@ static void __init nvidia_bugs(int num, int slot, int func) #ifdef CONFIG_ACPI #ifdef CONFIG_X86_IO_APIC /* + * Only applies to Nvidia root ports (bus 0) and not to + * Nvidia graphics cards with PCI ports on secondary buses. + */ + if (num) + return; + + /* * All timer overrides on Nvidia are * wrong unless HPET is enabled. * Unfortunately that's not true on many Asus boards. -- cgit v0.10.2 From 850c321027c2e31d0afc71588974719a4b565550 Mon Sep 17 00:00:00 2001 From: Lukas Wunner Date: Sun, 12 Jun 2016 12:31:53 +0200 Subject: x86/quirks: Reintroduce scanning of secondary buses We used to scan secondary buses until the following commit that was applied in 2009: 8659c406ade3 ("x86: only scan the root bus in early PCI quirks") which commit constrained early quirks to the root bus only. Its motivation was to prevent application of the nvidia_bugs quirk on secondary buses. We're about to add a quirk to reset the Broadcom 4331 wireless card on 2011/2012 Macs, which is located on a secondary bus behind a PCIe root port. To facilitate that, reintroduce scanning of secondary buses. The commit message of 8659c406ade3 notes that scanning only the root bus "saves quite some unnecessary scanning work". The algorithm used prior to 8659c406ade3 was particularly time consuming because it scanned buses 0 to 31 brute force. To avoid lengthening boot time, employ a recursive strategy which only scans buses that are actually reachable from the root bus. Yinghai Lu pointed out that the secondary bus number read from a bridge's config space may be invalid, in particular a value of 0 would cause an infinite loop. The PCI core goes beyond that and recurses to a child bus only if its bus number is greater than the parent bus number (see pci_scan_bridge()). Since the root bus is numbered 0, this implies that secondary buses may not be 0. Do the same on early scanning. If this algorithm is found to significantly impact boot time or cause infinite loops on broken hardware, it would be possible to limit its recursion depth: The Broadcom 4331 quirk applies at depth 1, all others at depth 0, so the bus need not be scanned deeper than that for now. An alternative approach would be to revert to scanning only the root bus, and apply the Broadcom 4331 quirk to the root ports 8086:1c12, 8086:1e12 and 8086:1e16. Apple always positioned the card behind either of these three ports. The quirk would then check presence of the card in slot 0 below the root port and do its deed. Signed-off-by: Lukas Wunner Cc: Andy Lutomirski Cc: Bjorn Helgaas Cc: Borislav Petkov Cc: Brian Gerst Cc: Denys Vlasenko Cc: H. Peter Anvin Cc: Josh Poimboeuf Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: Yinghai Lu Cc: linux-pci@vger.kernel.org Link: http://lkml.kernel.org/r/f0daa70dac1a9b2483abdb31887173eb6ab77bdf.1465690253.git.lukas@wunner.de Signed-off-by: Ingo Molnar diff --git a/arch/x86/kernel/early-quirks.c b/arch/x86/kernel/early-quirks.c index 256976f..ea60c05 100644 --- a/arch/x86/kernel/early-quirks.c +++ b/arch/x86/kernel/early-quirks.c @@ -610,12 +610,6 @@ struct chipset { void (*f)(int num, int slot, int func); }; -/* - * Only works for devices on the root bus. If you add any devices - * not on bus 0 readd another loop level in early_quirks(). But - * be careful because at least the Nvidia quirk here relies on - * only matching on bus 0. - */ static struct chipset early_qrk[] __initdata = { { PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID, PCI_CLASS_BRIDGE_PCI, PCI_ANY_ID, QFLAG_APPLY_ONCE, nvidia_bugs }, @@ -648,6 +642,8 @@ static struct chipset early_qrk[] __initdata = { {} }; +static void __init early_pci_scan_bus(int bus); + /** * check_dev_quirk - apply early quirks to a given PCI device * @num: bus number @@ -656,7 +652,7 @@ static struct chipset early_qrk[] __initdata = { * * Check the vendor & device ID against the early quirks table. * - * If the device is single function, let early_quirks() know so we don't + * If the device is single function, let early_pci_scan_bus() know so we don't * poke at this device again. */ static int __init check_dev_quirk(int num, int slot, int func) @@ -665,6 +661,7 @@ static int __init check_dev_quirk(int num, int slot, int func) u16 vendor; u16 device; u8 type; + u8 sec; int i; class = read_pci_config_16(num, slot, func, PCI_CLASS_DEVICE); @@ -692,25 +689,36 @@ static int __init check_dev_quirk(int num, int slot, int func) type = read_pci_config_byte(num, slot, func, PCI_HEADER_TYPE); + + if ((type & 0x7f) == PCI_HEADER_TYPE_BRIDGE) { + sec = read_pci_config_byte(num, slot, func, PCI_SECONDARY_BUS); + if (sec > num) + early_pci_scan_bus(sec); + } + if (!(type & 0x80)) return -1; return 0; } -void __init early_quirks(void) +static void __init early_pci_scan_bus(int bus) { int slot, func; - if (!early_pci_allowed()) - return; - /* Poor man's PCI discovery */ - /* Only scan the root bus */ for (slot = 0; slot < 32; slot++) for (func = 0; func < 8; func++) { /* Only probe function 0 on single fn devices */ - if (check_dev_quirk(0, slot, func)) + if (check_dev_quirk(bus, slot, func)) break; } } + +void __init early_quirks(void) +{ + if (!early_pci_allowed()) + return; + + early_pci_scan_bus(0); +} -- cgit v0.10.2 From abb2bafd295fe962bbadc329dbfb2146457283ac Mon Sep 17 00:00:00 2001 From: Lukas Wunner Date: Sun, 12 Jun 2016 12:31:53 +0200 Subject: x86/quirks: Add early quirk to reset Apple AirPort card MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The EFI firmware on Macs contains a full-fledged network stack for downloading OS X images from osrecovery.apple.com. Unfortunately on Macs introduced 2011 and 2012, EFI brings up the Broadcom 4331 wireless card on every boot and leaves it enabled even after ExitBootServices has been called. The card continues to assert its IRQ line, causing spurious interrupts if the IRQ is shared. It also corrupts memory by DMAing received packets, allowing for remote code execution over the air. This only stops when a driver is loaded for the wireless card, which may be never if the driver is not installed or blacklisted. The issue seems to be constrained to the Broadcom 4331. Chris Milsted has verified that the newer Broadcom 4360 built into the MacBookPro11,3 (2013/2014) does not exhibit this behaviour. The chances that Apple will ever supply a firmware fix for the older machines appear to be zero. The solution is to reset the card on boot by writing to a reset bit in its mmio space. This must be done as an early quirk and not as a plain vanilla PCI quirk to successfully combat memory corruption by DMAed packets: Matthew Garrett found out in 2012 that the packets are written to EfiBootServicesData memory (http://mjg59.dreamwidth.org/11235.html). This type of memory is made available to the page allocator by efi_free_boot_services(). Plain vanilla PCI quirks run much later, in subsys initcall level. In-between a time window would be open for memory corruption. Random crashes occurring in this time window and attributed to DMAed packets have indeed been observed in the wild by Chris Bainbridge. When Matthew Garrett analyzed the memory corruption issue in 2012, he sought to fix it with a grub quirk which transitions the card to D3hot: http://git.savannah.gnu.org/cgit/grub.git/commit/?id=9d34bb85da56 This approach does not help users with other bootloaders and while it may prevent DMAed packets, it does not cure the spurious interrupts emanating from the card. Unfortunately the card's mmio space is inaccessible in D3hot, so to reset it, we have to undo the effect of Matthew's grub patch and transition the card back to D0. Note that the quirk takes a few shortcuts to reduce the amount of code: The size of BAR 0 and the location of the PM capability is identical on all affected machines and therefore hardcoded. Only the address of BAR 0 differs between models. Also, it is assumed that the BCMA core currently mapped is the 802.11 core. The EFI driver seems to always take care of this. Michael Büsch, Bjorn Helgaas and Matt Fleming contributed feedback towards finding the best solution to this problem. The following should be a comprehensive list of affected models: iMac13,1 2012 21.5" [Root Port 00:1c.3 = 8086:1e16] iMac13,2 2012 27" [Root Port 00:1c.3 = 8086:1e16] Macmini5,1 2011 i5 2.3 GHz [Root Port 00:1c.1 = 8086:1c12] Macmini5,2 2011 i5 2.5 GHz [Root Port 00:1c.1 = 8086:1c12] Macmini5,3 2011 i7 2.0 GHz [Root Port 00:1c.1 = 8086:1c12] Macmini6,1 2012 i5 2.5 GHz [Root Port 00:1c.1 = 8086:1e12] Macmini6,2 2012 i7 2.3 GHz [Root Port 00:1c.1 = 8086:1e12] MacBookPro8,1 2011 13" [Root Port 00:1c.1 = 8086:1c12] MacBookPro8,2 2011 15" [Root Port 00:1c.1 = 8086:1c12] MacBookPro8,3 2011 17" [Root Port 00:1c.1 = 8086:1c12] MacBookPro9,1 2012 15" [Root Port 00:1c.1 = 8086:1e12] MacBookPro9,2 2012 13" [Root Port 00:1c.1 = 8086:1e12] MacBookPro10,1 2012 15" [Root Port 00:1c.1 = 8086:1e12] MacBookPro10,2 2012 13" [Root Port 00:1c.1 = 8086:1e12] For posterity, spurious interrupts caused by the Broadcom 4331 wireless card resulted in splats like this (stacktrace omitted): irq 17: nobody cared (try booting with the "irqpoll" option) handlers: [] pcie_isr [] sdhci_irq [sdhci] threaded [] sdhci_thread_irq [sdhci] [] azx_interrupt [snd_hda_codec] Disabling IRQ #17 Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=79301 Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=111781 Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=728916 Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=895951#c16 Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1009819 Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1098621 Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1149632#c5 Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1279130 Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1332732 Tested-by: Konstantin Simanov # [MacBookPro8,1] Tested-by: Lukas Wunner # [MacBookPro9,1] Tested-by: Bryan Paradis # [MacBookPro9,2] Tested-by: Andrew Worsley # [MacBookPro10,1] Tested-by: Chris Bainbridge # [MacBookPro10,2] Signed-off-by: Lukas Wunner Acked-by: Rafał Miłecki Acked-by: Matt Fleming Cc: Andy Lutomirski Cc: Bjorn Helgaas Cc: Borislav Petkov Cc: Brian Gerst Cc: Chris Milsted Cc: Denys Vlasenko Cc: H. Peter Anvin Cc: Josh Poimboeuf Cc: Linus Torvalds Cc: Matthew Garrett Cc: Michael Buesch Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: Yinghai Lu Cc: b43-dev@lists.infradead.org Cc: linux-pci@vger.kernel.org Cc: linux-wireless@vger.kernel.org Cc: stable@vger.kernel.org Cc: stable@vger.kernel.org # 123456789abc: x86/quirks: Apply nvidia_bugs quirk only on root bus Cc: stable@vger.kernel.org # 123456789abc: x86/quirks: Reintroduce scanning of secondary buses Link: http://lkml.kernel.org/r/48d0972ac82a53d460e5fce77a07b2560db95203.1465690253.git.lukas@wunner.de [ Did minor readability edits. ] Signed-off-by: Ingo Molnar diff --git a/arch/x86/kernel/early-quirks.c b/arch/x86/kernel/early-quirks.c index ea60c05..57b7137 100644 --- a/arch/x86/kernel/early-quirks.c +++ b/arch/x86/kernel/early-quirks.c @@ -11,7 +11,11 @@ #include #include +#include +#include #include +#include +#include #include #include #include @@ -21,6 +25,9 @@ #include #include #include +#include + +#define dev_err(msg) pr_err("pci 0000:%02x:%02x.%d: %s", bus, slot, func, msg) static void __init fix_hypertransport_config(int num, int slot, int func) { @@ -597,6 +604,61 @@ static void __init force_disable_hpet(int num, int slot, int func) #endif } +#define BCM4331_MMIO_SIZE 16384 +#define BCM4331_PM_CAP 0x40 +#define bcma_aread32(reg) ioread32(mmio + 1 * BCMA_CORE_SIZE + reg) +#define bcma_awrite32(reg, val) iowrite32(val, mmio + 1 * BCMA_CORE_SIZE + reg) + +static void __init apple_airport_reset(int bus, int slot, int func) +{ + void __iomem *mmio; + u16 pmcsr; + u64 addr; + int i; + + if (!dmi_match(DMI_SYS_VENDOR, "Apple Inc.")) + return; + + /* Card may have been put into PCI_D3hot by grub quirk */ + pmcsr = read_pci_config_16(bus, slot, func, BCM4331_PM_CAP + PCI_PM_CTRL); + + if ((pmcsr & PCI_PM_CTRL_STATE_MASK) != PCI_D0) { + pmcsr &= ~PCI_PM_CTRL_STATE_MASK; + write_pci_config_16(bus, slot, func, BCM4331_PM_CAP + PCI_PM_CTRL, pmcsr); + mdelay(10); + + pmcsr = read_pci_config_16(bus, slot, func, BCM4331_PM_CAP + PCI_PM_CTRL); + if ((pmcsr & PCI_PM_CTRL_STATE_MASK) != PCI_D0) { + dev_err("Cannot power up Apple AirPort card\n"); + return; + } + } + + addr = read_pci_config(bus, slot, func, PCI_BASE_ADDRESS_0); + addr |= (u64)read_pci_config(bus, slot, func, PCI_BASE_ADDRESS_1) << 32; + addr &= PCI_BASE_ADDRESS_MEM_MASK; + + mmio = early_ioremap(addr, BCM4331_MMIO_SIZE); + if (!mmio) { + dev_err("Cannot iomap Apple AirPort card\n"); + return; + } + + pr_info("Resetting Apple AirPort card (left enabled by EFI)\n"); + + for (i = 0; bcma_aread32(BCMA_RESET_ST) && i < 30; i++) + udelay(10); + + bcma_awrite32(BCMA_RESET_CTL, BCMA_RESET_CTL_RESET); + bcma_aread32(BCMA_RESET_CTL); + udelay(1); + + bcma_awrite32(BCMA_RESET_CTL, 0); + bcma_aread32(BCMA_RESET_CTL); + udelay(10); + + early_iounmap(mmio, BCM4331_MMIO_SIZE); +} #define QFLAG_APPLY_ONCE 0x1 #define QFLAG_APPLIED 0x2 @@ -639,6 +701,8 @@ static struct chipset early_qrk[] __initdata = { */ { PCI_VENDOR_ID_INTEL, 0x0f00, PCI_CLASS_BRIDGE_HOST, PCI_ANY_ID, 0, force_disable_hpet}, + { PCI_VENDOR_ID_BROADCOM, 0x4331, + PCI_CLASS_NETWORK_OTHER, PCI_ANY_ID, 0, apple_airport_reset}, {} }; diff --git a/drivers/bcma/bcma_private.h b/drivers/bcma/bcma_private.h index eda0909..f642c42 100644 --- a/drivers/bcma/bcma_private.h +++ b/drivers/bcma/bcma_private.h @@ -8,8 +8,6 @@ #include #include -#define BCMA_CORE_SIZE 0x1000 - #define bcma_err(bus, fmt, ...) \ pr_err("bus%d: " fmt, (bus)->num, ##__VA_ARGS__) #define bcma_warn(bus, fmt, ...) \ diff --git a/include/linux/bcma/bcma.h b/include/linux/bcma/bcma.h index e6b41f4..3db25df 100644 --- a/include/linux/bcma/bcma.h +++ b/include/linux/bcma/bcma.h @@ -159,6 +159,7 @@ struct bcma_host_ops { #define BCMA_CORE_DEFAULT 0xFFF #define BCMA_MAX_NR_CORES 16 +#define BCMA_CORE_SIZE 0x1000 /* Chip IDs of PCIe devices */ #define BCMA_CHIP_ID_BCM4313 0x4313 -- cgit v0.10.2 From 748c7201e622d1c24abb4f85072d2e74d12f295f Mon Sep 17 00:00:00 2001 From: Daniel Bristot de Oliveira Date: Fri, 3 Jun 2016 17:10:18 -0300 Subject: sched/core: Panic on scheduling while atomic bugs if kernel.panic_on_warn is set Currently, a schedule while atomic error prints the stack trace to the kernel log and the system continue running. Although it is possible to collect the kernel log messages and analyze it, often more information are needed. Furthermore, keep the system running is not always the best choice. For example, when the preempt count underflows the system will not stop to complain about scheduling while atomic, so the kernel log can wrap around overwriting the first stack trace, tuning the analysis even more challenging. This patch uses the kernel.panic_on_warn sysctl to help out on these more complex situations. When kernel.panic_on_warn is set to 1, the kernel will panic() in the schedule while atomic detection. The default value of the sysctl is 0, maintaining the current behavior. Signed-off-by: Daniel Bristot de Oliveira Reviewed-by: Luis Claudio R. Goncalves Cc: Christian Borntraeger Cc: Linus Torvalds Cc: Luis Claudio R. Goncalves Cc: Peter Zijlstra Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/e8f7b80f353aa22c63bd8557208163989af8493d.1464983675.git.bristot@redhat.com Signed-off-by: Ingo Molnar diff --git a/kernel/sched/core.c b/kernel/sched/core.c index 28da50a..4e9617a 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c @@ -3168,6 +3168,9 @@ static noinline void __schedule_bug(struct task_struct *prev) pr_cont("\n"); } #endif + if (panic_on_warn) + panic("scheduling while atomic\n"); + dump_stack(); add_taint(TAINT_WARN, LOCKDEP_STILL_OK); } -- cgit v0.10.2 From 44530d588e142a96cf0cd345a7cb8911c4f88720 Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Sun, 10 Jul 2016 20:58:36 +0200 Subject: Revert "perf/x86/intel, watchdog: Switch NMI watchdog to ref cycles on x86" This reverts commit 2c95afc1e83d93fac3be6923465e1753c2c53b0a. Stephane reported the following regression: > Since Andi added: > > commit 2c95afc1e83d93fac3be6923465e1753c2c53b0a > Author: Andi Kleen > Date: Thu Jun 9 06:14:38 2016 -0700 > > perf/x86/intel, watchdog: Switch NMI watchdog to ref cycles on x86 > > $ perf stat -e ref-cycles ls > .... > > fails systematically because the ref-cycles is now used by the > watchdog and given this is a system-wide pinned event, it monopolizes > the fixed counter 2 which is the only counter able to measure this event. Since the next merge window is near, fix the regression for now by reverting the commit. Reported-by: Stephane Eranian Cc: Andi Kleen Cc: Peter Zijlstra Cc: Arnaldo Carvalho de Melo Cc: Jiri Olsa Cc: Vince Weaver Cc: Alexander Shishkin Cc: Linus Torvalds Cc: Thomas Gleixner Cc: linux-kernel@vger.kernel.org Signed-off-by: Ingo Molnar diff --git a/arch/x86/kernel/apic/hw_nmi.c b/arch/x86/kernel/apic/hw_nmi.c index 016f426..7788ce6 100644 --- a/arch/x86/kernel/apic/hw_nmi.c +++ b/arch/x86/kernel/apic/hw_nmi.c @@ -18,16 +18,8 @@ #include #include #include -#include #ifdef CONFIG_HARDLOCKUP_DETECTOR -int hw_nmi_get_event(void) -{ - if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL) - return PERF_COUNT_HW_REF_CPU_CYCLES; - return PERF_COUNT_HW_CPU_CYCLES; -} - u64 hw_nmi_get_sample_period(int watchdog_thresh) { return (u64)(cpu_khz) * 1000 * watchdog_thresh; diff --git a/include/linux/nmi.h b/include/linux/nmi.h index 79858af..4630eea 100644 --- a/include/linux/nmi.h +++ b/include/linux/nmi.h @@ -66,7 +66,6 @@ static inline bool trigger_allbutself_cpu_backtrace(void) #ifdef CONFIG_LOCKUP_DETECTOR u64 hw_nmi_get_sample_period(int watchdog_thresh); -int hw_nmi_get_event(void); extern int nmi_watchdog_enabled; extern int soft_watchdog_enabled; extern int watchdog_user_enabled; diff --git a/kernel/watchdog.c b/kernel/watchdog.c index 8dd30fcd..9acb29f 100644 --- a/kernel/watchdog.c +++ b/kernel/watchdog.c @@ -315,12 +315,6 @@ static int is_softlockup(unsigned long touch_ts) #ifdef CONFIG_HARDLOCKUP_DETECTOR -/* Can be overriden by architecture */ -__weak int hw_nmi_get_event(void) -{ - return PERF_COUNT_HW_CPU_CYCLES; -} - static struct perf_event_attr wd_hw_attr = { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_CPU_CYCLES, @@ -610,7 +604,6 @@ static int watchdog_nmi_enable(unsigned int cpu) wd_attr = &wd_hw_attr; wd_attr->sample_period = hw_nmi_get_sample_period(watchdog_thresh); - wd_attr->config = hw_nmi_get_event(); /* Try to register using hardware perf events */ event = perf_event_create_kernel_counter(wd_attr, cpu, NULL, watchdog_overflow_callback, NULL); -- cgit v0.10.2 From 7f556567036cb7f89aabe2f0954b08566b4efb53 Mon Sep 17 00:00:00 2001 From: Hugh Dickins Date: Sun, 10 Jul 2016 16:46:32 -0700 Subject: tmpfs: fix regression hang in fallocate undo The well-spotted fallocate undo fix is good in most cases, but not when fallocate failed on the very first page. index 0 then passes lend -1 to shmem_undo_range(), and that has two bad effects: (a) that it will undo every fallocation throughout the file, unrestricted by the current range; but more importantly (b) it can cause the undo to hang, because lend -1 is treated as truncation, which makes it keep on retrying until every page has gone, but those already fully instantiated will never go away. Big thank you to xfstests generic/269 which demonstrates this. Fixes: b9b4bb26af01 ("tmpfs: don't undo fallocate past its last page") Cc: stable@vger.kernel.org Signed-off-by: Hugh Dickins Signed-off-by: Linus Torvalds diff --git a/mm/shmem.c b/mm/shmem.c index 24463b6..171dee7 100644 --- a/mm/shmem.c +++ b/mm/shmem.c @@ -2225,9 +2225,11 @@ static long shmem_fallocate(struct file *file, int mode, loff_t offset, error = shmem_getpage(inode, index, &page, SGP_FALLOC); if (error) { /* Remove the !PageUptodate pages we added */ - shmem_undo_range(inode, - (loff_t)start << PAGE_SHIFT, - ((loff_t)index << PAGE_SHIFT) - 1, true); + if (index > start) { + shmem_undo_range(inode, + (loff_t)start << PAGE_SHIFT, + ((loff_t)index << PAGE_SHIFT) - 1, true); + } goto undone; } -- cgit v0.10.2 From 92d21ac74a9e3c09b0b01c764e530657e4c85c49 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Sun, 10 Jul 2016 20:24:59 -0700 Subject: Linux 4.7-rc7 diff --git a/Makefile b/Makefile index 0d50489..81b2262 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ VERSION = 4 PATCHLEVEL = 7 SUBLEVEL = 0 -EXTRAVERSION = -rc6 +EXTRAVERSION = -rc7 NAME = Psychotic Stoned Sheep # *DOCUMENTATION* -- cgit v0.10.2 From e8807e4470e6b4230b24c537d7179a945f0f7c40 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Sun, 10 Jul 2016 23:34:01 +0200 Subject: Revert "ACPICA: Namespace: Fix namespace/interpreter lock ordering" Revert commit 45209046c47b (ACPICA: Namespace: Fix namespace/interpreter lock ordering) that renders Dell Precision 5510 with the latest (1.2.10) BIOS applied unable to boot. Fixes: 45209046c47b (ACPICA: Namespace: Fix namespace/interpreter lock ordering) Link: https://bugzilla.kernel.org/show_bug.cgi?id=121701 Reported-by: Greg White Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/acpica/nsload.c b/drivers/acpi/acpica/nsload.c index 297f6aa..b5e2b0a 100644 --- a/drivers/acpi/acpica/nsload.c +++ b/drivers/acpi/acpica/nsload.c @@ -46,7 +46,6 @@ #include "acnamesp.h" #include "acdispat.h" #include "actables.h" -#include "acinterp.h" #define _COMPONENT ACPI_NAMESPACE ACPI_MODULE_NAME("nsload") @@ -79,8 +78,6 @@ acpi_ns_load_table(u32 table_index, struct acpi_namespace_node *node) ACPI_FUNCTION_TRACE(ns_load_table); - acpi_ex_enter_interpreter(); - /* * Parse the table and load the namespace with all named * objects found within. Control methods are NOT parsed @@ -92,7 +89,7 @@ acpi_ns_load_table(u32 table_index, struct acpi_namespace_node *node) */ status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); if (ACPI_FAILURE(status)) { - goto unlock_interp; + return_ACPI_STATUS(status); } /* If table already loaded into namespace, just return */ @@ -133,8 +130,6 @@ acpi_ns_load_table(u32 table_index, struct acpi_namespace_node *node) unlock: (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); -unlock_interp: - (void)acpi_ex_exit_interpreter(); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); diff --git a/drivers/acpi/acpica/nsparse.c b/drivers/acpi/acpica/nsparse.c index f631a47..1783cd7 100644 --- a/drivers/acpi/acpica/nsparse.c +++ b/drivers/acpi/acpica/nsparse.c @@ -47,6 +47,7 @@ #include "acparser.h" #include "acdispat.h" #include "actables.h" +#include "acinterp.h" #define _COMPONENT ACPI_NAMESPACE ACPI_MODULE_NAME("nsparse") @@ -170,6 +171,8 @@ acpi_ns_parse_table(u32 table_index, struct acpi_namespace_node *start_node) ACPI_FUNCTION_TRACE(ns_parse_table); + acpi_ex_enter_interpreter(); + /* * AML Parse, pass 1 * @@ -185,7 +188,7 @@ acpi_ns_parse_table(u32 table_index, struct acpi_namespace_node *start_node) status = acpi_ns_one_complete_parse(ACPI_IMODE_LOAD_PASS1, table_index, start_node); if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); + goto error_exit; } /* @@ -201,8 +204,10 @@ acpi_ns_parse_table(u32 table_index, struct acpi_namespace_node *start_node) status = acpi_ns_one_complete_parse(ACPI_IMODE_LOAD_PASS2, table_index, start_node); if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); + goto error_exit; } +error_exit: + acpi_ex_exit_interpreter(); return_ACPI_STATUS(status); } -- cgit v0.10.2 From ffd8d61845c90cea87bc3efa58ddff1b14dea8f2 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Mon, 11 Jul 2016 16:18:18 +0200 Subject: Revert "ACPICA: Namespace: Fix deadlock triggered by MLC support in dynamic table loading" Revert commit 2f38b1b16d92 (ACPICA: Namespace: Fix deadlock triggered by MLC support in dynamic table loading) that attempted to fix a deadlock issue introduced by a previous commit, but it led to a lock ordering inconsistency that caused further problems to appear. Fixes: 2f38b1b16d92 (ACPICA: Namespace: Fix deadlock triggered by MLC support in dynamic table loading) Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/acpica/exconfig.c b/drivers/acpi/acpica/exconfig.c index 21932d6..a1d177d 100644 --- a/drivers/acpi/acpica/exconfig.c +++ b/drivers/acpi/acpica/exconfig.c @@ -108,9 +108,7 @@ acpi_ex_add_table(u32 table_index, /* Add the table to the namespace */ - acpi_ex_exit_interpreter(); status = acpi_ns_load_table(table_index, parent_node); - acpi_ex_enter_interpreter(); if (ACPI_FAILURE(status)) { acpi_ut_remove_reference(obj_desc); *ddb_handle = NULL; diff --git a/drivers/acpi/acpica/nsparse.c b/drivers/acpi/acpica/nsparse.c index 1783cd7..f631a47 100644 --- a/drivers/acpi/acpica/nsparse.c +++ b/drivers/acpi/acpica/nsparse.c @@ -47,7 +47,6 @@ #include "acparser.h" #include "acdispat.h" #include "actables.h" -#include "acinterp.h" #define _COMPONENT ACPI_NAMESPACE ACPI_MODULE_NAME("nsparse") @@ -171,8 +170,6 @@ acpi_ns_parse_table(u32 table_index, struct acpi_namespace_node *start_node) ACPI_FUNCTION_TRACE(ns_parse_table); - acpi_ex_enter_interpreter(); - /* * AML Parse, pass 1 * @@ -188,7 +185,7 @@ acpi_ns_parse_table(u32 table_index, struct acpi_namespace_node *start_node) status = acpi_ns_one_complete_parse(ACPI_IMODE_LOAD_PASS1, table_index, start_node); if (ACPI_FAILURE(status)) { - goto error_exit; + return_ACPI_STATUS(status); } /* @@ -204,10 +201,8 @@ acpi_ns_parse_table(u32 table_index, struct acpi_namespace_node *start_node) status = acpi_ns_one_complete_parse(ACPI_IMODE_LOAD_PASS2, table_index, start_node); if (ACPI_FAILURE(status)) { - goto error_exit; + return_ACPI_STATUS(status); } -error_exit: - acpi_ex_exit_interpreter(); return_ACPI_STATUS(status); } -- cgit v0.10.2 From 00c611def8748a0a1cf1d31842e49b42dfdb3de1 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Mon, 11 Jul 2016 16:21:08 +0200 Subject: Revert "ACPI 2.0 / AML: Improve module level execution by moving the If/Else/While execution to per-table basis" Revert commit 3d4b7ae96d81 (ACPI 2.0 / AML: Improve module level execution by moving the If/Else/While execution to per-table basis) that enabled the execution of module-level AML after loading each table (rather than after all AML tables have been loaded), but overlooked locking issues resulting from that change. Fixes: 3d4b7ae96d81 (ACPI 2.0 / AML: Improve module level execution by moving the If/Else/While execution to per-table basis) Reported-by: Mika Westerberg Signed-off-by: Rafael J. Wysocki diff --git a/include/acpi/acpixf.h b/include/acpi/acpixf.h index 4e4c214..1ff3a76 100644 --- a/include/acpi/acpixf.h +++ b/include/acpi/acpixf.h @@ -192,7 +192,7 @@ ACPI_INIT_GLOBAL(u8, acpi_gbl_do_not_use_xsdt, FALSE); /* * Optionally support group module level code. */ -ACPI_INIT_GLOBAL(u8, acpi_gbl_group_module_level_code, FALSE); +ACPI_INIT_GLOBAL(u8, acpi_gbl_group_module_level_code, TRUE); /* * Optionally use 32-bit FADT addresses if and when there is a conflict -- cgit v0.10.2 From 1fc2b67b43d5001b92b3a002b988884ad0137e99 Mon Sep 17 00:00:00 2001 From: Yu-cheng Yu Date: Mon, 11 Jul 2016 09:18:54 -0700 Subject: x86/fpu/xstate: Fix __fpu_restore_sig() for XSAVES When the kernel is using XSAVES compacted format, we cannot do __copy_from_user() from a signal frame, which has standard-format data. Fix it by using copyin_to_xsaves(), which converts between formats and filters out all supervisor states that we do not allow userspace to write. Signed-off-by: Yu-cheng Yu Signed-off-by: Fenghua Yu Reviewed-by: Dave Hansen Cc: H. Peter Anvin Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Ravi V Shankar Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/1468253937-40008-2-git-send-email-fenghua.yu@intel.com Signed-off-by: Ingo Molnar diff --git a/arch/x86/kernel/fpu/signal.c b/arch/x86/kernel/fpu/signal.c index 8aa96cb..9e231d8 100644 --- a/arch/x86/kernel/fpu/signal.c +++ b/arch/x86/kernel/fpu/signal.c @@ -323,8 +323,15 @@ static int __fpu__restore_sig(void __user *buf, void __user *buf_fx, int size) */ fpu__drop(fpu); - if (__copy_from_user(&fpu->state.xsave, buf_fx, state_size) || - __copy_from_user(&env, buf, sizeof(env))) { + if (using_compacted_format()) { + err = copyin_to_xsaves(NULL, buf_fx, + &fpu->state.xsave); + } else { + err = __copy_from_user(&fpu->state.xsave, + buf_fx, state_size); + } + + if (err || __copy_from_user(&env, buf, sizeof(env))) { fpstate_init(&fpu->state); trace_x86_fpu_init_state(fpu); err = -1; -- cgit v0.10.2 From 5060b91513b866f774da15dfd82157864c4b1683 Mon Sep 17 00:00:00 2001 From: Yu-cheng Yu Date: Mon, 11 Jul 2016 09:18:55 -0700 Subject: x86/fpu/xstate: Return NULL for disabled xstate component address It is an error to request a disabled XSAVE/XSAVES component address. For that case, make __raw_xsave_addr() return a NULL and issue a warning. Signed-off-by: Yu-cheng Yu Signed-off-by: Fenghua Yu Reviewed-by: Dave Hansen Cc: H. Peter Anvin Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Ravi V Shankar Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/1468253937-40008-3-git-send-email-fenghua.yu@intel.com Signed-off-by: Ingo Molnar diff --git a/arch/x86/kernel/fpu/xstate.c b/arch/x86/kernel/fpu/xstate.c index f8d1aff..4fb8dd7 100644 --- a/arch/x86/kernel/fpu/xstate.c +++ b/arch/x86/kernel/fpu/xstate.c @@ -760,6 +760,11 @@ void *__raw_xsave_addr(struct xregs_state *xsave, int xstate_feature_mask) { int feature_nr = fls64(xstate_feature_mask) - 1; + if (!xfeature_enabled(feature_nr)) { + WARN_ON_FPU(1); + return NULL; + } + return (void *)xsave + xstate_comp_offsets[feature_nr]; } /* -- cgit v0.10.2 From 35ac2d7ba787eb4b7418a5a6f5919c25e10a780a Mon Sep 17 00:00:00 2001 From: Yu-cheng Yu Date: Mon, 11 Jul 2016 09:18:56 -0700 Subject: x86/fpu/xstate: Fix fpstate_init() for XRSTORS In XSAVES mode if fpstate_init() is used to initialize a task's extended state area, xsave.header.xcomp_bv[63] must be set. Otherwise, when the task is scheduled, a warning is triggered from copy_kernel_to_xregs(). One such test case is: setting an invalid extended state through PTRACE. When xstateregs_set() rejects the syscall and re-initializes the task's extended state area. This triggers the warning mentioned above. Signed-off-by: Yu-cheng Yu Signed-off-by: Fenghua Yu Reviewed-by: Dave Hansen Cc: H. Peter Anvin Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Ravi V Shankar Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/1468253937-40008-4-git-send-email-fenghua.yu@intel.com Signed-off-by: Ingo Molnar diff --git a/arch/x86/include/asm/fpu/types.h b/arch/x86/include/asm/fpu/types.h index 12dd648..48df486 100644 --- a/arch/x86/include/asm/fpu/types.h +++ b/arch/x86/include/asm/fpu/types.h @@ -232,6 +232,12 @@ struct xstate_header { } __attribute__((packed)); /* + * xstate_header.xcomp_bv[63] indicates that the extended_state_area + * is in compacted format. + */ +#define XCOMP_BV_COMPACTED_FORMAT ((u64)1 << 63) + +/* * This is our most modern FPU state format, as saved by the XSAVE * and restored by the XRSTOR instructions. * diff --git a/arch/x86/kernel/fpu/core.c b/arch/x86/kernel/fpu/core.c index c759bd0..3fc03a0 100644 --- a/arch/x86/kernel/fpu/core.c +++ b/arch/x86/kernel/fpu/core.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include @@ -229,6 +230,13 @@ void fpstate_init(union fpregs_state *state) memset(state, 0, fpu_kernel_xstate_size); + /* + * XRSTORS requires that this bit is set in xcomp_bv, or + * it will #GP. Make sure it is replaced after the memset(). + */ + if (static_cpu_has(X86_FEATURE_XSAVES)) + state->xsave.header.xcomp_bv = XCOMP_BV_COMPACTED_FORMAT; + if (static_cpu_has(X86_FEATURE_FXSR)) fpstate_init_fxstate(&state->fxsave); else -- cgit v0.10.2 From b8be15d588060a03569ac85dc4a0247460988f5b Mon Sep 17 00:00:00 2001 From: Yu-cheng Yu Date: Mon, 11 Jul 2016 09:18:57 -0700 Subject: x86/fpu/xstate: Re-enable XSAVES We did not handle XSAVES instructions correctly. There were issues in converting between standard and compacted format when interfacing with user-space. These issues have been corrected. Add a WARN_ONCE() to make it clear that XSAVES supervisor states are not yet implemented. Signed-off-by: Yu-cheng Yu Signed-off-by: Fenghua Yu Reviewed-by: Dave Hansen Cc: H. Peter Anvin Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Ravi V Shankar Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/1468253937-40008-5-git-send-email-fenghua.yu@intel.com Signed-off-by: Ingo Molnar diff --git a/arch/x86/kernel/fpu/init.c b/arch/x86/kernel/fpu/init.c index 60f3839..93982ae 100644 --- a/arch/x86/kernel/fpu/init.c +++ b/arch/x86/kernel/fpu/init.c @@ -230,21 +230,6 @@ static void __init fpu__init_system_xstate_size_legacy(void) } fpu_user_xstate_size = fpu_kernel_xstate_size; - - /* - * Quirk: we don't yet handle the XSAVES* instructions - * correctly, as we don't correctly convert between - * standard and compacted format when interfacing - * with user-space - so disable it for now. - * - * The difference is small: with recent CPUs the - * compacted format is only marginally smaller than - * the standard FPU state format. - * - * ( This is easy to backport while we are fixing - * XSAVES* support. ) - */ - setup_clear_cpu_cap(X86_FEATURE_XSAVES); } /* diff --git a/arch/x86/kernel/fpu/xstate.c b/arch/x86/kernel/fpu/xstate.c index 4fb8dd7..3169bca 100644 --- a/arch/x86/kernel/fpu/xstate.c +++ b/arch/x86/kernel/fpu/xstate.c @@ -221,6 +221,15 @@ void fpu__init_cpu_xstate(void) { if (!boot_cpu_has(X86_FEATURE_XSAVE) || !xfeatures_mask) return; + /* + * Make it clear that XSAVES supervisor states are not yet + * implemented should anyone expect it to work by changing + * bits in XFEATURE_MASK_* macros and XCR0. + */ + WARN_ONCE((xfeatures_mask & XFEATURE_MASK_SUPERVISOR), + "x86/fpu: XSAVES supervisor states are not yet implemented.\n"); + + xfeatures_mask &= ~XFEATURE_MASK_SUPERVISOR; cr4_set_bits(X86_CR4_OSXSAVE); xsetbv(XCR_XFEATURE_ENABLED_MASK, xfeatures_mask); -- cgit v0.10.2 From 2c13ce8f6b2f6fd9ba2f9261b1939fc0f62d1307 Mon Sep 17 00:00:00 2001 From: Alexey Dobriyan Date: Fri, 8 Jul 2016 01:39:11 +0300 Subject: posix_cpu_timer: Exit early when process has been reaped Variable "now" seems to be genuinely used unintialized if branch if (CPUCLOCK_PERTHREAD(timer->it_clock)) { is not taken and branch if (unlikely(sighand == NULL)) { is taken. In this case the process has been reaped and the timer is marked as disarmed anyway. So none of the postprocessing of the sample is required. Return right away. Signed-off-by: Alexey Dobriyan Cc: stable@vger.kernel.org Link: http://lkml.kernel.org/r/20160707223911.GA26483@p183.telecom.by Signed-off-by: Thomas Gleixner diff --git a/kernel/time/posix-cpu-timers.c b/kernel/time/posix-cpu-timers.c index 1cafba8..39008d7 100644 --- a/kernel/time/posix-cpu-timers.c +++ b/kernel/time/posix-cpu-timers.c @@ -777,6 +777,7 @@ static void posix_cpu_timer_get(struct k_itimer *timer, struct itimerspec *itp) timer->it.cpu.expires = 0; sample_to_timespec(timer->it_clock, timer->it.cpu.expires, &itp->it_value); + return; } else { cpu_timer_sample_group(timer->it_clock, p, &now); unlock_task_sighand(p, &flags); -- cgit v0.10.2 From a1b7b1a57b9919a0abb6c93fca04ac9cf840c992 Mon Sep 17 00:00:00 2001 From: Alexander Popov Date: Sun, 3 Jul 2016 03:24:08 +0300 Subject: irqdomain: Fix irq_domain_alloc_irqs_recursive() error handling If an irq_domain is auto-recursive and irq_domain_alloc_irqs_recursive() for its parent has returned an error, then do return and avoid calling irq_domain_free_irqs_recursive() uselessly, because: - if domain->ops->alloc() had failed for an auto-recursive irq_domain, then irq_domain_free_irqs_recursive() had already been called; - if domain->ops->alloc() had failed for a not auto-recursive irq_domain, then there is nothing to free at all. Signed-off-by: Alexander Popov Acked-by: Marc Zyngier Link: http://lkml.kernel.org/r/1467505448-2850-1-git-send-email-alex.popov@linux.com Signed-off-by: Thomas Gleixner diff --git a/kernel/irq/irqdomain.c b/kernel/irq/irqdomain.c index a828537..4752b43 100644 --- a/kernel/irq/irqdomain.c +++ b/kernel/irq/irqdomain.c @@ -1192,8 +1192,10 @@ int irq_domain_alloc_irqs_recursive(struct irq_domain *domain, if (recursive) ret = irq_domain_alloc_irqs_recursive(parent, irq_base, nr_irqs, arg); - if (ret >= 0) - ret = domain->ops->alloc(domain, irq_base, nr_irqs, arg); + if (ret < 0) + return ret; + + ret = domain->ops->alloc(domain, irq_base, nr_irqs, arg); if (ret < 0 && recursive) irq_domain_free_irqs_recursive(parent, irq_base, nr_irqs); -- cgit v0.10.2 From 6d4e56ce977864b0fcd28c61555060e6010aa89b Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Mon, 11 Jul 2016 09:10:06 -0400 Subject: posix_acl: de-union a_refcount and a_rcu Currently the two are unioned together, but I don't think that's safe. It looks like get_cached_acl could race with the last put in posix_acl_release. get_cached_acl calls atomic_inc_not_zero on a_refcount, but that field could have already been clobbered by call_rcu, and may no longer be zero. Fix this by de-unioning the two fields. Fixes: b8a7a3a66747 (posix_acl: Inode acl caching fixes) Signed-off-by: Jeff Layton Signed-off-by: Al Viro diff --git a/include/linux/posix_acl.h b/include/linux/posix_acl.h index 5b5a80c..c818772 100644 --- a/include/linux/posix_acl.h +++ b/include/linux/posix_acl.h @@ -43,10 +43,8 @@ struct posix_acl_entry { }; struct posix_acl { - union { - atomic_t a_refcount; - struct rcu_head a_rcu; - }; + atomic_t a_refcount; + struct rcu_head a_rcu; unsigned int a_count; struct posix_acl_entry a_entries[0]; }; -- cgit v0.10.2 From ab58d8cc870ef3f0771c197700441936898d1f1d Mon Sep 17 00:00:00 2001 From: Peter Wu Date: Mon, 11 Jul 2016 19:51:06 +0200 Subject: ALSA: hda - fix use-after-free after module unload register_vga_switcheroo() sets the PM ops from the hda structure which is freed later in azx_free. Make sure that these ops are cleared. Caught by KASAN, initially noticed due to a general protection fault. Fixes: 246efa4a072f ("snd/hda: add runtime suspend/resume on optimus support (v4)") Signed-off-by: Peter Wu Cc: Signed-off-by: Takashi Iwai diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index e320c44..7c9b06b 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -1218,8 +1218,10 @@ static int azx_free(struct azx *chip) if (use_vga_switcheroo(hda)) { if (chip->disabled && hda->probe_continued) snd_hda_unlock_devices(&chip->bus); - if (hda->vga_switcheroo_registered) + if (hda->vga_switcheroo_registered) { vga_switcheroo_unregister_client(chip->pci); + vga_switcheroo_fini_domain_pm_ops(chip->card->dev); + } } if (bus->chip_init) { -- cgit v0.10.2 From 02c0cd2dcf7fdc47d054b855b148ea8b82dbb7eb Mon Sep 17 00:00:00 2001 From: Len Brown Date: Fri, 17 Jun 2016 01:22:50 -0400 Subject: x86/tsc_msr: Remove irqoff around MSR-based TSC enumeration Remove the irqoff/irqon around MSR-based TSC enumeration, as it is not necessary. Also rename: try_msr_calibrate_tsc() to cpu_khz_from_msr(), as that better describes what the routine does. Signed-off-by: Len Brown Reviewed-by: Thomas Gleixner Cc: Linus Torvalds Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/a6b5c3ecd3b068175d2309599ab28163fc34215e.1466138954.git.len.brown@intel.com Signed-off-by: Ingo Molnar diff --git a/arch/x86/include/asm/tsc.h b/arch/x86/include/asm/tsc.h index 7428697..db1f779 100644 --- a/arch/x86/include/asm/tsc.h +++ b/arch/x86/include/asm/tsc.h @@ -52,7 +52,6 @@ extern int notsc_setup(char *); extern void tsc_save_sched_clock_state(void); extern void tsc_restore_sched_clock_state(void); -/* MSR based TSC calibration for Intel Atom SoC platforms */ -unsigned long try_msr_calibrate_tsc(void); +unsigned long cpu_khz_from_msr(void); #endif /* _ASM_X86_TSC_H */ diff --git a/arch/x86/kernel/tsc.c b/arch/x86/kernel/tsc.c index 38ba6de..35a3976 100644 --- a/arch/x86/kernel/tsc.c +++ b/arch/x86/kernel/tsc.c @@ -674,10 +674,7 @@ unsigned long native_calibrate_tsc(void) unsigned long flags, latch, ms, fast_calibrate; int hpet = is_hpet_enabled(), i, loopmin; - /* Calibrate TSC using MSR for Intel Atom SoCs */ - local_irq_save(flags); - fast_calibrate = try_msr_calibrate_tsc(); - local_irq_restore(flags); + fast_calibrate = cpu_khz_from_msr(); if (fast_calibrate) return fast_calibrate; diff --git a/arch/x86/kernel/tsc_msr.c b/arch/x86/kernel/tsc_msr.c index 65b3d8cb..0fe720d 100644 --- a/arch/x86/kernel/tsc_msr.c +++ b/arch/x86/kernel/tsc_msr.c @@ -68,7 +68,7 @@ static int match_cpu(u8 family, u8 model) * Set global "lapic_timer_frequency" to bus_clock_cycles/jiffy * Return processor base frequency in KHz, or 0 on failure. */ -unsigned long try_msr_calibrate_tsc(void) +unsigned long cpu_khz_from_msr(void) { u32 lo, hi, ratio, freq_id, freq; unsigned long res; -- cgit v0.10.2 From aa297292d708e89773b3b2cdcaf33f01bfa095d8 Mon Sep 17 00:00:00 2001 From: Len Brown Date: Fri, 17 Jun 2016 01:22:51 -0400 Subject: x86/tsc: Enumerate SKL cpu_khz and tsc_khz via CPUID Skylake CPU base-frequency and TSC frequency may differ by up to 2%. Enumerate CPU and TSC frequencies separately, allowing cpu_khz and tsc_khz to differ. The existing CPU frequency calibration mechanism is unchanged. However, CPUID extensions are preferred, when available. CPUID.0x16 is preferred over MSR and timer calibration for CPU frequency discovery. CPUID.0x15 takes precedence over CPU-frequency for TSC frequency discovery. Signed-off-by: Len Brown Reviewed-by: Thomas Gleixner Cc: Linus Torvalds Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/b27ec289fd005833b27d694d9c2dbb716c5cdff7.1466138954.git.len.brown@intel.com Signed-off-by: Ingo Molnar diff --git a/arch/x86/include/asm/tsc.h b/arch/x86/include/asm/tsc.h index db1f779..a30591e 100644 --- a/arch/x86/include/asm/tsc.h +++ b/arch/x86/include/asm/tsc.h @@ -36,6 +36,7 @@ extern void mark_tsc_unstable(char *reason); extern int unsynchronized_tsc(void); extern int check_tsc_unstable(void); extern int check_tsc_disabled(void); +extern unsigned long native_calibrate_cpu(void); extern unsigned long native_calibrate_tsc(void); extern unsigned long long native_sched_clock_from_tsc(u64 tsc); diff --git a/arch/x86/include/asm/x86_init.h b/arch/x86/include/asm/x86_init.h index 4dcdf74..08a08a8 100644 --- a/arch/x86/include/asm/x86_init.h +++ b/arch/x86/include/asm/x86_init.h @@ -181,7 +181,8 @@ struct x86_legacy_features { /** * struct x86_platform_ops - platform specific runtime functions - * @calibrate_tsc: calibrate TSC + * @calibrate_cpu: calibrate CPU + * @calibrate_tsc: calibrate TSC, if different from CPU * @get_wallclock: get time from HW clock like RTC etc. * @set_wallclock: set time back to HW clock * @is_untracked_pat_range exclude from PAT logic @@ -200,6 +201,7 @@ struct x86_legacy_features { * semantics. */ struct x86_platform_ops { + unsigned long (*calibrate_cpu)(void); unsigned long (*calibrate_tsc)(void); void (*get_wallclock)(struct timespec *ts); int (*set_wallclock)(const struct timespec *ts); diff --git a/arch/x86/kernel/tsc.c b/arch/x86/kernel/tsc.c index 35a3976..e1496b7 100644 --- a/arch/x86/kernel/tsc.c +++ b/arch/x86/kernel/tsc.c @@ -239,7 +239,7 @@ static inline unsigned long long cycles_2_ns(unsigned long long cyc) return ns; } -static void set_cyc2ns_scale(unsigned long cpu_khz, int cpu) +static void set_cyc2ns_scale(unsigned long khz, int cpu) { unsigned long long tsc_now, ns_now; struct cyc2ns_data *data; @@ -248,7 +248,7 @@ static void set_cyc2ns_scale(unsigned long cpu_khz, int cpu) local_irq_save(flags); sched_clock_idle_sleep_event(); - if (!cpu_khz) + if (!khz) goto done; data = cyc2ns_write_begin(cpu); @@ -261,7 +261,7 @@ static void set_cyc2ns_scale(unsigned long cpu_khz, int cpu) * time function is continuous; see the comment near struct * cyc2ns_data. */ - clocks_calc_mult_shift(&data->cyc2ns_mul, &data->cyc2ns_shift, cpu_khz, + clocks_calc_mult_shift(&data->cyc2ns_mul, &data->cyc2ns_shift, khz, NSEC_PER_MSEC, 0); /* @@ -665,15 +665,72 @@ success: } /** - * native_calibrate_tsc - calibrate the tsc on boot + * native_calibrate_tsc + * Determine TSC frequency via CPUID, else return 0. */ unsigned long native_calibrate_tsc(void) { + unsigned int eax_denominator, ebx_numerator, ecx_hz, edx; + unsigned int crystal_khz; + + if (boot_cpu_data.x86_vendor != X86_VENDOR_INTEL) + return 0; + + if (boot_cpu_data.cpuid_level < 0x15) + return 0; + + eax_denominator = ebx_numerator = ecx_hz = edx = 0; + + /* CPUID 15H TSC/Crystal ratio, plus optionally Crystal Hz */ + cpuid(0x15, &eax_denominator, &ebx_numerator, &ecx_hz, &edx); + + if (ebx_numerator == 0 || eax_denominator == 0) + return 0; + + crystal_khz = ecx_hz / 1000; + + if (crystal_khz == 0) { + switch (boot_cpu_data.x86_model) { + case 0x4E: /* SKL */ + case 0x5E: /* SKL */ + crystal_khz = 24000; /* 24 MHz */ + } + } + + return crystal_khz * ebx_numerator / eax_denominator; +} + +static unsigned long cpu_khz_from_cpuid(void) +{ + unsigned int eax_base_mhz, ebx_max_mhz, ecx_bus_mhz, edx; + + if (boot_cpu_data.x86_vendor != X86_VENDOR_INTEL) + return 0; + + if (boot_cpu_data.cpuid_level < 0x16) + return 0; + + eax_base_mhz = ebx_max_mhz = ecx_bus_mhz = edx = 0; + + cpuid(0x16, &eax_base_mhz, &ebx_max_mhz, &ecx_bus_mhz, &edx); + + return eax_base_mhz * 1000; +} + +/** + * native_calibrate_cpu - calibrate the cpu on boot + */ +unsigned long native_calibrate_cpu(void) +{ u64 tsc1, tsc2, delta, ref1, ref2; unsigned long tsc_pit_min = ULONG_MAX, tsc_ref_min = ULONG_MAX; unsigned long flags, latch, ms, fast_calibrate; int hpet = is_hpet_enabled(), i, loopmin; + fast_calibrate = cpu_khz_from_cpuid(); + if (fast_calibrate) + return fast_calibrate; + fast_calibrate = cpu_khz_from_msr(); if (fast_calibrate) return fast_calibrate; @@ -834,8 +891,10 @@ int recalibrate_cpu_khz(void) if (!boot_cpu_has(X86_FEATURE_TSC)) return -ENODEV; + cpu_khz = x86_platform.calibrate_cpu(); tsc_khz = x86_platform.calibrate_tsc(); - cpu_khz = tsc_khz; + if (tsc_khz == 0) + tsc_khz = cpu_khz; cpu_data(0).loops_per_jiffy = cpufreq_scale(cpu_data(0).loops_per_jiffy, cpu_khz_old, cpu_khz); @@ -1241,8 +1300,10 @@ void __init tsc_init(void) return; } + cpu_khz = x86_platform.calibrate_cpu(); tsc_khz = x86_platform.calibrate_tsc(); - cpu_khz = tsc_khz; + if (tsc_khz == 0) + tsc_khz = cpu_khz; if (!tsc_khz) { mark_tsc_unstable("could not calculate TSC khz"); @@ -1262,7 +1323,7 @@ void __init tsc_init(void) */ for_each_possible_cpu(cpu) { cyc2ns_init(cpu); - set_cyc2ns_scale(cpu_khz, cpu); + set_cyc2ns_scale(tsc_khz, cpu); } if (tsc_disabled > 0) diff --git a/arch/x86/kernel/x86_init.c b/arch/x86/kernel/x86_init.c index dad5fe9..58b4592 100644 --- a/arch/x86/kernel/x86_init.c +++ b/arch/x86/kernel/x86_init.c @@ -92,6 +92,7 @@ static void default_nmi_init(void) { }; static int default_i8042_detect(void) { return 1; }; struct x86_platform_ops x86_platform = { + .calibrate_cpu = native_calibrate_cpu, .calibrate_tsc = native_calibrate_tsc, .get_wallclock = mach_get_cmos_time, .set_wallclock = mach_set_rtc_mmss, -- cgit v0.10.2 From ff4c86635ee12461fd3bd911d7d5253394da8f9d Mon Sep 17 00:00:00 2001 From: Len Brown Date: Fri, 17 Jun 2016 01:22:52 -0400 Subject: x86/tsc: Enumerate BXT tsc_khz via CPUID Hard code the BXT crystal clock (aka ART - Always Running Timer) to 19.200 MHz, and use CPUID leaf 0x15 to determine the BXT TSC frequency. Use tsc_khz to sanity check BXT cpu_khz, which can be erroneous in some configurations. (I simplified the original patch from Bin Gao.) Original-From: Bin Gao Signed-off-by: Len Brown Reviewed-by: Thomas Gleixner Cc: Linus Torvalds Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/bf4e7c175acd6d09719c47c319b10ff1f0627ff8.1466138954.git.len.brown@intel.com Signed-off-by: Ingo Molnar diff --git a/arch/x86/kernel/tsc.c b/arch/x86/kernel/tsc.c index e1496b7..2a952fc 100644 --- a/arch/x86/kernel/tsc.c +++ b/arch/x86/kernel/tsc.c @@ -693,7 +693,11 @@ unsigned long native_calibrate_tsc(void) switch (boot_cpu_data.x86_model) { case 0x4E: /* SKL */ case 0x5E: /* SKL */ - crystal_khz = 24000; /* 24 MHz */ + crystal_khz = 24000; /* 24.0 MHz */ + break; + case 0x5C: /* BXT */ + crystal_khz = 19200; /* 19.2 MHz */ + break; } } @@ -895,6 +899,8 @@ int recalibrate_cpu_khz(void) tsc_khz = x86_platform.calibrate_tsc(); if (tsc_khz == 0) tsc_khz = cpu_khz; + else if (abs(cpu_khz - tsc_khz) * 10 > tsc_khz) + cpu_khz = tsc_khz; cpu_data(0).loops_per_jiffy = cpufreq_scale(cpu_data(0).loops_per_jiffy, cpu_khz_old, cpu_khz); @@ -1302,8 +1308,16 @@ void __init tsc_init(void) cpu_khz = x86_platform.calibrate_cpu(); tsc_khz = x86_platform.calibrate_tsc(); + + /* + * Trust non-zero tsc_khz as authorative, + * and use it to sanity check cpu_khz, + * which will be off if system timer is off. + */ if (tsc_khz == 0) tsc_khz = cpu_khz; + else if (abs(cpu_khz - tsc_khz) * 10 > tsc_khz) + cpu_khz = tsc_khz; if (!tsc_khz) { mark_tsc_unstable("could not calculate TSC khz"); -- cgit v0.10.2 From f3ea3119ad75dde0ba3e8da4653dbd5a189688e5 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Fri, 8 Jul 2016 16:42:48 +0100 Subject: bnxt_en: initialize rc to zero to avoid returning garbage rc is not initialized so it can contain garbage if it is not set by the call to bnxt_read_sfp_module_eeprom_info. Ensure garbage is not returned by initializing rc to 0. Signed-off-by: Colin Ian King Acked-by: Michael Chan Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c index a38cb04..1b0ae4a 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c @@ -1591,7 +1591,7 @@ static int bnxt_get_module_eeprom(struct net_device *dev, { struct bnxt *bp = netdev_priv(dev); u16 start = eeprom->offset, length = eeprom->len; - int rc; + int rc = 0; memset(data, 0, eeprom->len); -- cgit v0.10.2 From a612769774a30e4fc143c4cb6395c12573415660 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Kube=C4=8Dek?= Date: Fri, 8 Jul 2016 17:52:33 +0200 Subject: udp: prevent bugcheck if filter truncates packet too much If socket filter truncates an udp packet below the length of UDP header in udpv6_queue_rcv_skb() or udp_queue_rcv_skb(), it will trigger a BUG_ON in skb_pull_rcsum(). This BUG_ON (and therefore a system crash if kernel is configured that way) can be easily enforced by an unprivileged user which was reported as CVE-2016-6162. For a reproducer, see http://seclists.org/oss-sec/2016/q3/8 Fixes: e6afc8ace6dd ("udp: remove headers from UDP packets before queueing") Reported-by: Marco Grassi Signed-off-by: Michal Kubecek Acked-by: Eric Dumazet Acked-by: Willem de Bruijn Signed-off-by: David S. Miller diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index ca5e8ea..4aed8fc 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -1583,6 +1583,8 @@ int udp_queue_rcv_skb(struct sock *sk, struct sk_buff *skb) if (sk_filter(sk, skb)) goto drop; + if (unlikely(skb->len < sizeof(struct udphdr))) + goto drop; udp_csum_pull_header(skb); if (sk_rcvqueues_full(sk, sk->sk_rcvbuf)) { diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index 005dc82..acc09705 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c @@ -620,6 +620,8 @@ int udpv6_queue_rcv_skb(struct sock *sk, struct sk_buff *skb) if (sk_filter(sk, skb)) goto drop; + if (unlikely(skb->len < sizeof(struct udphdr))) + goto drop; udp_csum_pull_header(skb); if (sk_rcvqueues_full(sk, sk->sk_rcvbuf)) { -- cgit v0.10.2 From 75ff39ccc1bd5d3c455b6822ab09e533c551f758 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Sun, 10 Jul 2016 10:04:02 +0200 Subject: tcp: make challenge acks less predictable Yue Cao claims that current host rate limiting of challenge ACKS (RFC 5961) could leak enough information to allow a patient attacker to hijack TCP sessions. He will soon provide details in an academic paper. This patch increases the default limit from 100 to 1000, and adds some randomization so that the attacker can no longer hijack sessions without spending a considerable amount of probes. Based on initial analysis and patch from Linus. Note that we also have per socket rate limiting, so it is tempting to remove the host limit in the future. v2: randomize the count of challenge acks per second, not the period. Fixes: 282f23c6ee34 ("tcp: implement RFC 5961 3.2") Reported-by: Yue Cao Signed-off-by: Eric Dumazet Suggested-by: Linus Torvalds Cc: Yuchung Cheng Cc: Neal Cardwell Acked-by: Neal Cardwell Acked-by: Yuchung Cheng Signed-off-by: David S. Miller diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index d6c8f4cd0..91868bb 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -87,7 +87,7 @@ int sysctl_tcp_adv_win_scale __read_mostly = 1; EXPORT_SYMBOL(sysctl_tcp_adv_win_scale); /* rfc5961 challenge ack rate limiting */ -int sysctl_tcp_challenge_ack_limit = 100; +int sysctl_tcp_challenge_ack_limit = 1000; int sysctl_tcp_stdurg __read_mostly; int sysctl_tcp_rfc1337 __read_mostly; @@ -3458,7 +3458,7 @@ static void tcp_send_challenge_ack(struct sock *sk, const struct sk_buff *skb) static u32 challenge_timestamp; static unsigned int challenge_count; struct tcp_sock *tp = tcp_sk(sk); - u32 now; + u32 count, now; /* First check our per-socket dupack rate limit. */ if (tcp_oow_rate_limited(sock_net(sk), skb, @@ -3466,13 +3466,18 @@ static void tcp_send_challenge_ack(struct sock *sk, const struct sk_buff *skb) &tp->last_oow_ack_time)) return; - /* Then check the check host-wide RFC 5961 rate limit. */ + /* Then check host-wide RFC 5961 rate limit. */ now = jiffies / HZ; if (now != challenge_timestamp) { + u32 half = (sysctl_tcp_challenge_ack_limit + 1) >> 1; + challenge_timestamp = now; - challenge_count = 0; + WRITE_ONCE(challenge_count, half + + prandom_u32_max(sysctl_tcp_challenge_ack_limit)); } - if (++challenge_count <= sysctl_tcp_challenge_ack_limit) { + count = READ_ONCE(challenge_count); + if (count > 0) { + WRITE_ONCE(challenge_count, count - 1); NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPCHALLENGEACK); tcp_send_ack(sk); } -- cgit v0.10.2 From 80610229ef7b26615dbb6cb6e873709a60bacc9f Mon Sep 17 00:00:00 2001 From: Julian Anastasov Date: Sun, 10 Jul 2016 21:11:55 +0300 Subject: ipv4: reject RTNH_F_DEAD and RTNH_F_LINKDOWN from user space Vegard Nossum is reporting for a crash in fib_dump_info when nh_dev = NULL and fib_nhs == 1: Pid: 50, comm: netlink.exe Not tainted 4.7.0-rc5+ RIP: 0033:[<00000000602b3d18>] RSP: 0000000062623890 EFLAGS: 00010202 RAX: 0000000000000000 RBX: 000000006261b800 RCX: 0000000000000000 RDX: 0000000000000000 RSI: 0000000000000024 RDI: 000000006245ba00 RBP: 00000000626238f0 R08: 000000000000029c R09: 0000000000000000 R10: 0000000062468038 R11: 000000006245ba00 R12: 000000006245ba00 R13: 00000000625f96c0 R14: 00000000601e16f0 R15: 0000000000000000 Kernel panic - not syncing: Kernel mode fault at addr 0x2e0, ip 0x602b3d18 CPU: 0 PID: 50 Comm: netlink.exe Not tainted 4.7.0-rc5+ #581 Stack: 626238f0 960226a02 00000400 000000fe 62623910 600afca7 62623970 62623a48 62468038 00000018 00000000 00000000 Call Trace: [<602b3e93>] rtmsg_fib+0xd3/0x190 [<602b6680>] fib_table_insert+0x260/0x500 [<602b0e5d>] inet_rtm_newroute+0x4d/0x60 [<60250def>] rtnetlink_rcv_msg+0x8f/0x270 [<60267079>] netlink_rcv_skb+0xc9/0xe0 [<60250d4b>] rtnetlink_rcv+0x3b/0x50 [<60265400>] netlink_unicast+0x1a0/0x2c0 [<60265e47>] netlink_sendmsg+0x3f7/0x470 [<6021dc9a>] sock_sendmsg+0x3a/0x90 [<6021e0d0>] ___sys_sendmsg+0x300/0x360 [<6021fa64>] __sys_sendmsg+0x54/0xa0 [<6021fac0>] SyS_sendmsg+0x10/0x20 [<6001ea68>] handle_syscall+0x88/0x90 [<600295fd>] userspace+0x3fd/0x500 [<6001ac55>] fork_handler+0x85/0x90 $ addr2line -e vmlinux -i 0x602b3d18 include/linux/inetdevice.h:222 net/ipv4/fib_semantics.c:1264 Problem happens when RTNH_F_LINKDOWN is provided from user space when creating routes that do not use the flag, catched with netlink fuzzer. Currently, the kernel allows user space to set both flags to nh_flags and fib_flags but this is not intentional, the assumption was that they are not set. Fix this by rejecting both flags with EINVAL. Reported-by: Vegard Nossum Fixes: 0eeb075fad73 ("net: ipv4 sysctl option to ignore routes when nexthop link is down") Signed-off-by: Julian Anastasov Cc: Andy Gospodarek Cc: Dinesh Dutt Cc: Scott Feldman Reviewed-by: Andy Gospodarek Signed-off-by: David S. Miller diff --git a/net/ipv4/fib_semantics.c b/net/ipv4/fib_semantics.c index d09173b..539fa26 100644 --- a/net/ipv4/fib_semantics.c +++ b/net/ipv4/fib_semantics.c @@ -479,6 +479,9 @@ static int fib_get_nhs(struct fib_info *fi, struct rtnexthop *rtnh, if (!rtnh_ok(rtnh, remaining)) return -EINVAL; + if (rtnh->rtnh_flags & (RTNH_F_DEAD | RTNH_F_LINKDOWN)) + return -EINVAL; + nexthop_nh->nh_flags = (cfg->fc_flags & ~0xFF) | rtnh->rtnh_flags; nexthop_nh->nh_oif = rtnh->rtnh_ifindex; @@ -1003,6 +1006,9 @@ struct fib_info *fib_create_info(struct fib_config *cfg) if (fib_props[cfg->fc_type].scope > cfg->fc_scope) goto err_inval; + if (cfg->fc_flags & (RTNH_F_DEAD | RTNH_F_LINKDOWN)) + goto err_inval; + #ifdef CONFIG_IP_ROUTE_MULTIPATH if (cfg->fc_mp) { nhs = fib_count_nexthops(cfg->fc_mp, cfg->fc_mp_len); -- cgit v0.10.2 From 779f1edec664a7b32b71f7b4702e085a08d60592 Mon Sep 17 00:00:00 2001 From: Soheil Hassas Yeganeh Date: Mon, 11 Jul 2016 16:51:26 -0400 Subject: sock: ignore SCM_RIGHTS and SCM_CREDENTIALS in __sock_cmsg_send Sergei Trofimovich reported that pulse audio sends SCM_CREDENTIALS as a control message to TCP. Since __sock_cmsg_send does not support SCM_RIGHTS and SCM_CREDENTIALS, it returns an error and hence breaks pulse audio over TCP. SCM_RIGHTS and SCM_CREDENTIALS are sent on the SOL_SOCKET layer but they semantically belong to SOL_UNIX. Since all cmsg-processing functions including sock_cmsg_send ignore control messages of other layers, it is best to ignore SCM_RIGHTS and SCM_CREDENTIALS for consistency (and also for fixing pulse audio over TCP). Fixes: c14ac9451c34 ("sock: enable timestamping using control messages") Signed-off-by: Soheil Hassas Yeganeh Reported-by: Sergei Trofimovich Tested-by: Sergei Trofimovich Cc: Eric Dumazet Cc: Willem de Bruijn Signed-off-by: David S. Miller diff --git a/net/core/sock.c b/net/core/sock.c index 08bf97e..b7f1263 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -1938,6 +1938,10 @@ int __sock_cmsg_send(struct sock *sk, struct msghdr *msg, struct cmsghdr *cmsg, sockc->tsflags &= ~SOF_TIMESTAMPING_TX_RECORD_MASK; sockc->tsflags |= tsflags; break; + /* SCM_RIGHTS and SCM_CREDENTIALS are semantically in SOL_UNIX. */ + case SCM_RIGHTS: + case SCM_CREDENTIALS: + break; default: return -EINVAL; } -- cgit v0.10.2 From 34ee32c9a5696247be405bb0c21f3d1fc6cb5729 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Mon, 11 Jul 2016 19:58:04 -0500 Subject: r8152: Add support for setting pass through MAC address on RTL8153-AD The RTL8153-AD supports a persistent system specific MAC address. This means a device plugged into two different systems with host side support will show different (but persistent) MAC addresses. This information for the system's persistent MAC address is burned in when the system HW is built and available under \_SB.AMAC in the DSDT at runtime. This technology is currently implemented in the Dell TB15 and WD15 Type-C docks. More information is available here: http://www.dell.com/support/article/us/en/04/SLN301147 Signed-off-by: Mario Limonciello Signed-off-by: David S. Miller diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c index 419f4ce..63f4018 100644 --- a/drivers/net/usb/r8152.c +++ b/drivers/net/usb/r8152.c @@ -26,6 +26,7 @@ #include #include #include +#include /* Information for net-next */ #define NETNEXT_VERSION "08" @@ -460,6 +461,11 @@ /* SRAM_IMPEDANCE */ #define RX_DRIVING_MASK 0x6000 +/* MAC PASSTHRU */ +#define AD_MASK 0xfee0 +#define EFUSE 0xcfdb +#define PASS_THRU_MASK 0x1 + enum rtl_register_content { _1000bps = 0x10, _100bps = 0x08, @@ -1036,6 +1042,65 @@ out1: return ret; } +/* Devices containing RTL8153-AD can support a persistent + * host system provided MAC address. + * Examples of this are Dell TB15 and Dell WD15 docks + */ +static int vendor_mac_passthru_addr_read(struct r8152 *tp, struct sockaddr *sa) +{ + acpi_status status; + struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; + union acpi_object *obj; + int ret = -EINVAL; + u32 ocp_data; + unsigned char buf[6]; + + /* test for -AD variant of RTL8153 */ + ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_MISC_0); + if ((ocp_data & AD_MASK) != 0x1000) + return -ENODEV; + + /* test for MAC address pass-through bit */ + ocp_data = ocp_read_byte(tp, MCU_TYPE_USB, EFUSE); + if ((ocp_data & PASS_THRU_MASK) != 1) + return -ENODEV; + + /* returns _AUXMAC_#AABBCCDDEEFF# */ + status = acpi_evaluate_object(NULL, "\\_SB.AMAC", NULL, &buffer); + obj = (union acpi_object *)buffer.pointer; + if (!ACPI_SUCCESS(status)) + return -ENODEV; + if (obj->type != ACPI_TYPE_BUFFER || obj->string.length != 0x17) { + netif_warn(tp, probe, tp->netdev, + "Invalid buffer when reading pass-thru MAC addr: " + "(%d, %d)\n", + obj->type, obj->string.length); + goto amacout; + } + if (strncmp(obj->string.pointer, "_AUXMAC_#", 9) != 0 || + strncmp(obj->string.pointer + 0x15, "#", 1) != 0) { + netif_warn(tp, probe, tp->netdev, + "Invalid header when reading pass-thru MAC addr\n"); + goto amacout; + } + ret = hex2bin(buf, obj->string.pointer + 9, 6); + if (!(ret == 0 && is_valid_ether_addr(buf))) { + netif_warn(tp, probe, tp->netdev, + "Invalid MAC when reading pass-thru MAC addr: " + "%d, %pM\n", ret, buf); + ret = -EINVAL; + goto amacout; + } + memcpy(sa->sa_data, buf, 6); + ether_addr_copy(tp->netdev->dev_addr, sa->sa_data); + netif_info(tp, probe, tp->netdev, + "Using pass-thru MAC addr %pM\n", sa->sa_data); + +amacout: + kfree(obj); + return ret; +} + static int set_ethernet_addr(struct r8152 *tp) { struct net_device *dev = tp->netdev; @@ -1044,8 +1109,15 @@ static int set_ethernet_addr(struct r8152 *tp) if (tp->version == RTL_VER_01) ret = pla_ocp_read(tp, PLA_IDR, 8, sa.sa_data); - else - ret = pla_ocp_read(tp, PLA_BACKUP, 8, sa.sa_data); + else { + /* if this is not an RTL8153-AD, no eFuse mac pass thru set, + * or system doesn't provide valid _SB.AMAC this will be + * be expected to non-zero + */ + ret = vendor_mac_passthru_addr_read(tp, &sa); + if (ret < 0) + ret = pla_ocp_read(tp, PLA_BACKUP, 8, sa.sa_data); + } if (ret < 0) { netif_err(tp, probe, dev, "Get ether addr fail\n"); -- cgit v0.10.2 From 0a269a6bb3f86abb218b8632f13c4ecd9b6b92af Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Tue, 5 Jul 2016 08:56:03 +0200 Subject: perf hists: Introduce hist_entry__init function Move the 'struct hist_entry' initialization code to a separate function. It'll be useful and more clear for the following patches that introduce allocation callbacks. Releasing the hist_entry object in hist_entry__new function (where it's allocated) rather than in hist_entry__init. Signed-off-by: Jiri Olsa Cc: David Ahern Cc: Namhyung Kim Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1467701765-26194-2-git-send-email-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c index e1fcc8d..04f3b52 100644 --- a/tools/perf/util/hist.c +++ b/tools/perf/util/hist.c @@ -352,86 +352,93 @@ void hists__delete_entries(struct hists *hists) * histogram, sorted on item, collects periods */ -static struct hist_entry *hist_entry__new(struct hist_entry *template, - bool sample_self) -{ - size_t callchain_size = 0; - struct hist_entry *he; +static int hist_entry__init(struct hist_entry *he, + struct hist_entry *template, + bool sample_self) +{ + *he = *template; + + if (symbol_conf.cumulate_callchain) { + he->stat_acc = malloc(sizeof(he->stat)); + if (he->stat_acc == NULL) + return -ENOMEM; + memcpy(he->stat_acc, &he->stat, sizeof(he->stat)); + if (!sample_self) + memset(&he->stat, 0, sizeof(he->stat)); + } - if (symbol_conf.use_callchain) - callchain_size = sizeof(struct callchain_root); + map__get(he->ms.map); - he = zalloc(sizeof(*he) + callchain_size); + if (he->branch_info) { + /* + * This branch info is (a part of) allocated from + * sample__resolve_bstack() and will be freed after + * adding new entries. So we need to save a copy. + */ + he->branch_info = malloc(sizeof(*he->branch_info)); + if (he->branch_info == NULL) { + map__zput(he->ms.map); + free(he->stat_acc); + return -ENOMEM; + } - if (he != NULL) { - *he = *template; + memcpy(he->branch_info, template->branch_info, + sizeof(*he->branch_info)); - if (symbol_conf.cumulate_callchain) { - he->stat_acc = malloc(sizeof(he->stat)); - if (he->stat_acc == NULL) { - free(he); - return NULL; - } - memcpy(he->stat_acc, &he->stat, sizeof(he->stat)); - if (!sample_self) - memset(&he->stat, 0, sizeof(he->stat)); - } + map__get(he->branch_info->from.map); + map__get(he->branch_info->to.map); + } - map__get(he->ms.map); + if (he->mem_info) { + map__get(he->mem_info->iaddr.map); + map__get(he->mem_info->daddr.map); + } - if (he->branch_info) { - /* - * This branch info is (a part of) allocated from - * sample__resolve_bstack() and will be freed after - * adding new entries. So we need to save a copy. - */ - he->branch_info = malloc(sizeof(*he->branch_info)); - if (he->branch_info == NULL) { - map__zput(he->ms.map); - free(he->stat_acc); - free(he); - return NULL; - } + if (symbol_conf.use_callchain) + callchain_init(he->callchain); - memcpy(he->branch_info, template->branch_info, - sizeof(*he->branch_info)); + if (he->raw_data) { + he->raw_data = memdup(he->raw_data, he->raw_size); - map__get(he->branch_info->from.map); - map__get(he->branch_info->to.map); + if (he->raw_data == NULL) { + map__put(he->ms.map); + if (he->branch_info) { + map__put(he->branch_info->from.map); + map__put(he->branch_info->to.map); + free(he->branch_info); + } + if (he->mem_info) { + map__put(he->mem_info->iaddr.map); + map__put(he->mem_info->daddr.map); + } + free(he->stat_acc); + return -ENOMEM; } + } + INIT_LIST_HEAD(&he->pairs.node); + thread__get(he->thread); - if (he->mem_info) { - map__get(he->mem_info->iaddr.map); - map__get(he->mem_info->daddr.map); - } + if (!symbol_conf.report_hierarchy) + he->leaf = true; - if (symbol_conf.use_callchain) - callchain_init(he->callchain); + return 0; +} - if (he->raw_data) { - he->raw_data = memdup(he->raw_data, he->raw_size); +static struct hist_entry *hist_entry__new(struct hist_entry *template, + bool sample_self) +{ + size_t callchain_size = 0; + struct hist_entry *he; + int err = 0; - if (he->raw_data == NULL) { - map__put(he->ms.map); - if (he->branch_info) { - map__put(he->branch_info->from.map); - map__put(he->branch_info->to.map); - free(he->branch_info); - } - if (he->mem_info) { - map__put(he->mem_info->iaddr.map); - map__put(he->mem_info->daddr.map); - } - free(he->stat_acc); - free(he); - return NULL; - } - } - INIT_LIST_HEAD(&he->pairs.node); - thread__get(he->thread); + if (symbol_conf.use_callchain) + callchain_size = sizeof(struct callchain_root); - if (!symbol_conf.report_hierarchy) - he->leaf = true; + he = zalloc(sizeof(*he) + callchain_size); + if (he) { + err = hist_entry__init(he, template, sample_self); + if (err) + zfree(&he); } return he; -- cgit v0.10.2 From f542e7670e48bc9d0aed351c1fd2ae0b65cc6f68 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Tue, 5 Jul 2016 08:56:04 +0200 Subject: perf hists: Introduce hist_entry_ops Introducing allocation callbacks, that allows to extend current hist_entry object into objects with special needs without polluting the current hist_entry object. Signed-off-by: Jiri Olsa Cc: David Ahern Cc: Namhyung Kim Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1467701765-26194-3-git-send-email-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c index 04f3b52..355b760 100644 --- a/tools/perf/util/hist.c +++ b/tools/perf/util/hist.c @@ -424,21 +424,42 @@ static int hist_entry__init(struct hist_entry *he, return 0; } +static void *hist_entry__zalloc(size_t size) +{ + return zalloc(size + sizeof(struct hist_entry)); +} + +static void hist_entry__free(void *ptr) +{ + free(ptr); +} + +static struct hist_entry_ops default_ops = { + .new = hist_entry__zalloc, + .free = hist_entry__free, +}; + static struct hist_entry *hist_entry__new(struct hist_entry *template, bool sample_self) { + struct hist_entry_ops *ops = template->ops; size_t callchain_size = 0; struct hist_entry *he; int err = 0; + if (!ops) + ops = template->ops = &default_ops; + if (symbol_conf.use_callchain) callchain_size = sizeof(struct callchain_root); - he = zalloc(sizeof(*he) + callchain_size); + he = ops->new(callchain_size); if (he) { err = hist_entry__init(he, template, sample_self); - if (err) - zfree(&he); + if (err) { + ops->free(he); + he = NULL; + } } return he; @@ -1050,6 +1071,8 @@ hist_entry__collapse(struct hist_entry *left, struct hist_entry *right) void hist_entry__delete(struct hist_entry *he) { + struct hist_entry_ops *ops = he->ops; + thread__zput(he->thread); map__zput(he->ms.map); @@ -1074,7 +1097,7 @@ void hist_entry__delete(struct hist_entry *he) free_callchain(he->callchain); free(he->trace_output); free(he->raw_data); - free(he); + ops->free(he); } /* diff --git a/tools/perf/util/sort.h b/tools/perf/util/sort.h index ebb59ca..7ca37ea 100644 --- a/tools/perf/util/sort.h +++ b/tools/perf/util/sort.h @@ -67,6 +67,11 @@ struct hist_entry_diff { }; }; +struct hist_entry_ops { + void *(*new)(size_t size); + void (*free)(void *ptr); +}; + /** * struct hist_entry - histogram entry * @@ -125,6 +130,7 @@ struct hist_entry { void *trace_output; struct perf_hpp_list *hpp_list; struct hist_entry *parent_he; + struct hist_entry_ops *ops; union { /* this is for hierarchical entry structure */ struct { -- cgit v0.10.2 From a5051979f533afc65112cc42a20f25db08bf2272 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Tue, 5 Jul 2016 08:56:05 +0200 Subject: perf hists: Introduce hists__add_entry_ops function Introducing hists__add_entry_ops function to allow using the allocation callbacks externally. Signed-off-by: Jiri Olsa Cc: David Ahern Cc: Namhyung Kim Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1467701765-26194-4-git-send-email-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c index 355b760..a18d142 100644 --- a/tools/perf/util/hist.c +++ b/tools/perf/util/hist.c @@ -559,13 +559,15 @@ out: return he; } -struct hist_entry *hists__add_entry(struct hists *hists, - struct addr_location *al, - struct symbol *sym_parent, - struct branch_info *bi, - struct mem_info *mi, - struct perf_sample *sample, - bool sample_self) +static struct hist_entry* +__hists__add_entry(struct hists *hists, + struct addr_location *al, + struct symbol *sym_parent, + struct branch_info *bi, + struct mem_info *mi, + struct perf_sample *sample, + bool sample_self, + struct hist_entry_ops *ops) { struct hist_entry entry = { .thread = al->thread, @@ -592,11 +594,37 @@ struct hist_entry *hists__add_entry(struct hists *hists, .transaction = sample->transaction, .raw_data = sample->raw_data, .raw_size = sample->raw_size, + .ops = ops, }; return hists__findnew_entry(hists, &entry, al, sample_self); } +struct hist_entry *hists__add_entry(struct hists *hists, + struct addr_location *al, + struct symbol *sym_parent, + struct branch_info *bi, + struct mem_info *mi, + struct perf_sample *sample, + bool sample_self) +{ + return __hists__add_entry(hists, al, sym_parent, bi, mi, + sample, sample_self, NULL); +} + +struct hist_entry *hists__add_entry_ops(struct hists *hists, + struct hist_entry_ops *ops, + struct addr_location *al, + struct symbol *sym_parent, + struct branch_info *bi, + struct mem_info *mi, + struct perf_sample *sample, + bool sample_self) +{ + return __hists__add_entry(hists, al, sym_parent, bi, mi, + sample, sample_self, ops); +} + static int iter_next_nop_entry(struct hist_entry_iter *iter __maybe_unused, struct addr_location *al __maybe_unused) diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h index 0a03e08..49aa4fa 100644 --- a/tools/perf/util/hist.h +++ b/tools/perf/util/hist.h @@ -10,6 +10,7 @@ #include "ui/progress.h" struct hist_entry; +struct hist_entry_ops; struct addr_location; struct symbol; @@ -127,6 +128,16 @@ struct hist_entry *hists__add_entry(struct hists *hists, struct mem_info *mi, struct perf_sample *sample, bool sample_self); + +struct hist_entry *hists__add_entry_ops(struct hists *hists, + struct hist_entry_ops *ops, + struct addr_location *al, + struct symbol *sym_parent, + struct branch_info *bi, + struct mem_info *mi, + struct perf_sample *sample, + bool sample_self); + int hist_entry_iter__add(struct hist_entry_iter *iter, struct addr_location *al, int max_stack_depth, void *arg); -- cgit v0.10.2 From c09615f29c70d4155986f55097a99ad8f2036ca1 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 5 Jul 2016 11:05:24 -0300 Subject: perf ui stdio: Add way to setup the color output mode selection In --stdio we turn off color output when the output is not a tty, which is not always desirable, for instance, in: perf annotate | more the 'more' tool is perfectly capable of processing the escape sequences for colored output. Allow using the existing logic for .perfconfig's "color.ui" to be used from the command line by providing a stdio__config_color() helper, that will be used by annotate and report in follow up patches. Cc: Adrian Hunter Cc: David Ahern Cc: Jiri Olsa Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Wang Nan Link: http://lkml.kernel.org/n/tip-1u4wjdbcc41dxndsb4klpa9y@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/ui/setup.c b/tools/perf/ui/setup.c index ba51fa8..1f6b099 100644 --- a/tools/perf/ui/setup.c +++ b/tools/perf/ui/setup.c @@ -60,6 +60,13 @@ static inline int setup_gtk_browser(void) { return -1; } static inline void exit_gtk_browser(bool wait_for_ok __maybe_unused) {} #endif +int stdio__config_color(const struct option *opt __maybe_unused, + const char *mode, int unset __maybe_unused) +{ + perf_use_color_default = perf_config_colorbool("color.ui", mode, -1); + return 0; +} + void setup_browser(bool fallback_to_pager) { if (use_browser < 2 && (!isatty(1) || dump_trace)) diff --git a/tools/perf/ui/ui.h b/tools/perf/ui/ui.h index ab88383..4b6fb6c 100644 --- a/tools/perf/ui/ui.h +++ b/tools/perf/ui/ui.h @@ -26,4 +26,8 @@ static inline void ui__exit(bool wait_for_ok __maybe_unused) {} void ui__refresh_dimensions(bool force); +struct option; + +int stdio__config_color(const struct option *opt, const char *mode, int unset); + #endif /* _PERF_UI_H_ */ -- cgit v0.10.2 From 53fe4ba1da92892f5a76fdc51b699eeb6b808a3a Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 5 Jul 2016 11:08:17 -0300 Subject: perf annotate: Introduce --stdio-color to setup the color output mode selection 'perf annotate --stdio' will colorize entries with most hits and possibly some other aspects of its output, but those colors gets suppressed if we redirect the output to a non-tty, allow keeping the colors by adding a new option, --stdio-color, now this use case will also output escape sequences for colors: $ perf annotate --stdio-color | more Based-on-a-patch-by: Peter Zijlstra Cc: Adrian Hunter Cc: David Ahern Cc: Jiri Olsa Cc: Namhyung Kim Cc: Wang Nan Link: http://lkml.kernel.org/n/tip-sjrnixani5pg6qez640gaxhf@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/Documentation/perf-annotate.txt b/tools/perf/Documentation/perf-annotate.txt index 778f54d..8ffbd27 100644 --- a/tools/perf/Documentation/perf-annotate.txt +++ b/tools/perf/Documentation/perf-annotate.txt @@ -61,6 +61,13 @@ OPTIONS --stdio:: Use the stdio interface. +--stdio-color:: + 'always', 'never' or 'auto', allowing configuring color output + via the command line, in addition to via "color.ui" .perfconfig. + Use '--stdio-color always' to generate color even when redirecting + to a pipe or file. Using just '--stdio-color' is equivalent to + using 'always'. + --tui:: Use the TUI interface. Use of --tui requires a tty, if one is not present, as when piping to other commands, the stdio interface is used. This interfaces starts by centering on the line with more diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c index b15e768..9c1034d 100644 --- a/tools/perf/builtin-annotate.c +++ b/tools/perf/builtin-annotate.c @@ -339,6 +339,9 @@ int cmd_annotate(int argc, const char **argv, const char *prefix __maybe_unused) "Show event group information together"), OPT_BOOLEAN(0, "show-total-period", &symbol_conf.show_total_period, "Show a column with the sum of periods"), + OPT_CALLBACK_DEFAULT(0, "stdio-color", NULL, "mode", + "'always' (default), 'never' or 'auto' only applicable to --stdio mode", + stdio__config_color, "always"), OPT_END() }; int ret = hists__init(); -- cgit v0.10.2 From 175b968b81ba3bef0b39618714eb23d6675a935c Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 5 Jul 2016 11:14:38 -0300 Subject: perf report: Introduce --stdio-color to setup the color output mode selection 'perf report --stdio' will colorize entries with most hits and possibly some other aspects of its output, but those colors gets suppressed if we redirect the output to a non-tty, allow keeping the colors by adding a new option, --stdio-color, now this use case will also output escape sequences for colors: $ perf annotate --stdio-color | more Cc: Adrian Hunter Cc: David Ahern Cc: Jiri Olsa Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Wang Nan Link: http://lkml.kernel.org/n/tip-3iuawqjldu4i8gziot7e3d5n@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/Documentation/perf-report.txt b/tools/perf/Documentation/perf-report.txt index 9cbddc2..2d17462 100644 --- a/tools/perf/Documentation/perf-report.txt +++ b/tools/perf/Documentation/perf-report.txt @@ -265,6 +265,13 @@ OPTIONS --stdio:: Use the stdio interface. +--stdio-color:: + 'always', 'never' or 'auto', allowing configuring color output + via the command line, in addition to via "color.ui" .perfconfig. + Use '--stdio-color always' to generate color even when redirecting + to a pipe or file. Using just '--stdio-color' is equivalent to + using 'always'. + --tui:: Use the TUI interface, that is integrated with annotate and allows zooming into DSOs or threads, among other features. Use of --tui requires a tty, if one is not present, as when piping to other diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index f6cb35798..949e5a1 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c @@ -817,6 +817,9 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused) "Show raw trace event output (do not use print fmt or plugins)"), OPT_BOOLEAN(0, "hierarchy", &symbol_conf.report_hierarchy, "Show entries in a hierarchy"), + OPT_CALLBACK_DEFAULT(0, "stdio-color", NULL, "mode", + "'always' (default), 'never' or 'auto' only applicable to --stdio mode", + stdio__config_color, "always"), OPT_END() }; struct perf_data_file file = { -- cgit v0.10.2 From 0e91e6bfd3514fe30925891ec5f468b7d2c11d56 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 5 Jul 2016 14:42:31 -0300 Subject: perf trace beauty msg_flags: Remove MSG_TRYHARD It is the same as MSG_DONTROUTE and is only defined together with _GNU_SOURCE. Cc: Adrian Hunter Cc: David Ahern Cc: Jiri Olsa Cc: Namhyung Kim Cc: Wang Nan Link: http://lkml.kernel.org/n/tip-q4vbov6jl0e0152y01kv2htw@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/trace/beauty/msg_flags.c b/tools/perf/trace/beauty/msg_flags.c index 07fa8a0..1106c89 100644 --- a/tools/perf/trace/beauty/msg_flags.c +++ b/tools/perf/trace/beauty/msg_flags.c @@ -33,7 +33,6 @@ static size_t syscall_arg__scnprintf_msg_flags(char *bf, size_t size, P_MSG_FLAG(OOB); P_MSG_FLAG(PEEK); P_MSG_FLAG(DONTROUTE); - P_MSG_FLAG(TRYHARD); P_MSG_FLAG(CTRUNC); P_MSG_FLAG(PROBE); P_MSG_FLAG(TRUNC); -- cgit v0.10.2 From f8e018704cdf2a741477b8fd8ee0a313caf87f72 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 5 Jul 2016 14:43:27 -0300 Subject: perf trace beauty flock: Add missing fcntl.h include Those beautifiers need to make sure they include what they reference, as changes in builtin-trace.c may end up removing needed stuff, like when undefining _GNU_SOURCE. Cc: Adrian Hunter Cc: David Ahern Cc: Jiri Olsa Cc: Namhyung Kim Cc: Wang Nan Link: http://lkml.kernel.org/n/tip-2etqhfmgv5jcnfwnkbwadns2@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/trace/beauty/flock.c b/tools/perf/trace/beauty/flock.c index 021bb48..34b6348 100644 --- a/tools/perf/trace/beauty/flock.c +++ b/tools/perf/trace/beauty/flock.c @@ -1,3 +1,4 @@ +#include static size_t syscall_arg__scnprintf_flock(char *bf, size_t size, struct syscall_arg *arg) -- cgit v0.10.2 From 9d4a94cabcffd1f069666ddf9ad3cdc25565eec6 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 5 Jul 2016 14:43:27 -0300 Subject: perf trace beauty open_flags: Add missing headers Those beautifiers need to make sure they include what they reference, as changes in builtin-trace.c may end up removing needed stuff, like when undefining _GNU_SOURCE. Cc: Adrian Hunter Cc: David Ahern Cc: Jiri Olsa Cc: Namhyung Kim Cc: Wang Nan Link: http://lkml.kernel.org/n/tip-a9cz8za6lqutfapn5e7uum09@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/trace/beauty/open_flags.c b/tools/perf/trace/beauty/open_flags.c index 0f3679e..9c3a4cb 100644 --- a/tools/perf/trace/beauty/open_flags.c +++ b/tools/perf/trace/beauty/open_flags.c @@ -1,3 +1,6 @@ +#include +#include +#include static size_t syscall_arg__scnprintf_open_flags(char *bf, size_t size, struct syscall_arg *arg) -- cgit v0.10.2 From 256763b01741ec74bbecb3021baee229727935e6 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 5 Jul 2016 14:43:27 -0300 Subject: perf trace beauty mmap: Add more conditional defines Don't handle some flags only if they have its defines in headers at time of building, define what is missing. Cc: Adrian Hunter Cc: David Ahern Cc: Jiri Olsa Cc: Namhyung Kim Cc: Wang Nan Link: http://lkml.kernel.org/n/tip-czbmxb01xzcl3h2qxuzoqkj5@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/trace/beauty/mmap.c b/tools/perf/trace/beauty/mmap.c index 3444a4d..d0a3a8e 100644 --- a/tools/perf/trace/beauty/mmap.c +++ b/tools/perf/trace/beauty/mmap.c @@ -1,5 +1,9 @@ #include +#ifndef PROT_SEM +#define PROT_SEM 0x8 +#endif + static size_t syscall_arg__scnprintf_mmap_prot(char *bf, size_t size, struct syscall_arg *arg) { @@ -16,9 +20,7 @@ static size_t syscall_arg__scnprintf_mmap_prot(char *bf, size_t size, P_MMAP_PROT(EXEC); P_MMAP_PROT(READ); P_MMAP_PROT(WRITE); -#ifdef PROT_SEM P_MMAP_PROT(SEM); -#endif P_MMAP_PROT(GROWSDOWN); P_MMAP_PROT(GROWSUP); #undef P_MMAP_PROT @@ -31,10 +33,31 @@ static size_t syscall_arg__scnprintf_mmap_prot(char *bf, size_t size, #define SCA_MMAP_PROT syscall_arg__scnprintf_mmap_prot +#ifndef MAP_FIXED +#define MAP_FIXED 0x10 +#endif + +#ifndef MAP_ANONYMOUS +#define MAP_ANONYMOUS 0x20 +#endif + +#ifndef MAP_32BIT +#define MAP_32BIT 0x40 +#endif + #ifndef MAP_STACK -# define MAP_STACK 0x20000 +#define MAP_STACK 0x20000 #endif +#ifndef MAP_HUGETLB +#define MAP_HUGETLB 0x40000 +#endif + +#ifndef MAP_UNINITIALIZED +#define MAP_UNINITIALIZED 0x4000000 +#endif + + static size_t syscall_arg__scnprintf_mmap_flags(char *bf, size_t size, struct syscall_arg *arg) { @@ -48,26 +71,20 @@ static size_t syscall_arg__scnprintf_mmap_flags(char *bf, size_t size, P_MMAP_FLAG(SHARED); P_MMAP_FLAG(PRIVATE); -#ifdef MAP_32BIT P_MMAP_FLAG(32BIT); -#endif P_MMAP_FLAG(ANONYMOUS); P_MMAP_FLAG(DENYWRITE); P_MMAP_FLAG(EXECUTABLE); P_MMAP_FLAG(FILE); P_MMAP_FLAG(FIXED); P_MMAP_FLAG(GROWSDOWN); -#ifdef MAP_HUGETLB P_MMAP_FLAG(HUGETLB); -#endif P_MMAP_FLAG(LOCKED); P_MMAP_FLAG(NONBLOCK); P_MMAP_FLAG(NORESERVE); P_MMAP_FLAG(POPULATE); P_MMAP_FLAG(STACK); -#ifdef MAP_UNINITIALIZED P_MMAP_FLAG(UNINITIALIZED); -#endif #undef P_MMAP_FLAG if (flags) @@ -78,6 +95,13 @@ static size_t syscall_arg__scnprintf_mmap_flags(char *bf, size_t size, #define SCA_MMAP_FLAGS syscall_arg__scnprintf_mmap_flags +#ifndef MREMAP_MAYMOVE +#define MREMAP_MAYMOVE 1 +#endif +#ifndef MREMAP_FIXED +#define MREMAP_FIXED 2 +#endif + static size_t syscall_arg__scnprintf_mremap_flags(char *bf, size_t size, struct syscall_arg *arg) { @@ -90,9 +114,7 @@ static size_t syscall_arg__scnprintf_mremap_flags(char *bf, size_t size, } P_MREMAP_FLAG(MAYMOVE); -#ifdef MREMAP_FIXED P_MREMAP_FLAG(FIXED); -#endif #undef P_MREMAP_FLAG if (flags) @@ -107,6 +129,10 @@ static size_t syscall_arg__scnprintf_mremap_flags(char *bf, size_t size, #define MADV_HWPOISON 100 #endif +#ifndef MADV_SOFT_OFFLINE +#define MADV_SOFT_OFFLINE 101 +#endif + #ifndef MADV_MERGEABLE #define MADV_MERGEABLE 12 #endif @@ -115,6 +141,23 @@ static size_t syscall_arg__scnprintf_mremap_flags(char *bf, size_t size, #define MADV_UNMERGEABLE 13 #endif +#ifndef MADV_HUGEPAGE +#define MADV_HUGEPAGE 14 +#endif + +#ifndef MADV_NOHUGEPAGE +#define MADV_NOHUGEPAGE 15 +#endif + +#ifndef MADV_DONTDUMP +#define MADV_DONTDUMP 16 +#endif + +#ifndef MADV_DODUMP +#define MADV_DODUMP 17 +#endif + + static size_t syscall_arg__scnprintf_madvise_behavior(char *bf, size_t size, struct syscall_arg *arg) { @@ -131,24 +174,14 @@ static size_t syscall_arg__scnprintf_madvise_behavior(char *bf, size_t size, P_MADV_BHV(DONTFORK); P_MADV_BHV(DOFORK); P_MADV_BHV(HWPOISON); -#ifdef MADV_SOFT_OFFLINE P_MADV_BHV(SOFT_OFFLINE); -#endif P_MADV_BHV(MERGEABLE); P_MADV_BHV(UNMERGEABLE); -#ifdef MADV_HUGEPAGE P_MADV_BHV(HUGEPAGE); -#endif -#ifdef MADV_NOHUGEPAGE P_MADV_BHV(NOHUGEPAGE); -#endif -#ifdef MADV_DONTDUMP P_MADV_BHV(DONTDUMP); -#endif -#ifdef MADV_DODUMP P_MADV_BHV(DODUMP); -#endif -#undef P_MADV_PHV +#undef P_MADV_BHV default: break; } -- cgit v0.10.2 From 4c7c224ac4a4735288bc9e5377e43844aa2c9393 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 5 Jul 2016 14:43:27 -0300 Subject: perf trace beauty flock: Add more conditional defines Don't handle some flags only if they have its defines in headers at time of building, define what is missing. Cc: Adrian Hunter Cc: David Ahern Cc: Jiri Olsa Cc: Namhyung Kim Cc: Wang Nan Link: http://lkml.kernel.org/n/tip-pgoxanv1y6hfcnryxawzuskl@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/trace/beauty/flock.c b/tools/perf/trace/beauty/flock.c index 34b6348..7461370 100644 --- a/tools/perf/trace/beauty/flock.c +++ b/tools/perf/trace/beauty/flock.c @@ -1,5 +1,21 @@ #include +#ifndef LOCK_MAND +#define LOCK_MAND 32 +#endif + +#ifndef LOCK_READ +#define LOCK_READ 64 +#endif + +#ifndef LOCK_WRITE +#define LOCK_WRITE 128 +#endif + +#ifndef LOCK_RW +#define LOCK_RW 192 +#endif + static size_t syscall_arg__scnprintf_flock(char *bf, size_t size, struct syscall_arg *arg) { -- cgit v0.10.2 From ffe3a28a8b90879c21acf7a1a8f5277785b05ff6 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 5 Jul 2016 14:43:27 -0300 Subject: perf trace beauty open_flags: Add more conditional defines Don't handle some flags only if they have its defines in headers at time of building, define what is missing. Cc: Adrian Hunter Cc: David Ahern Cc: Jiri Olsa Cc: Namhyung Kim Cc: Wang Nan Link: http://lkml.kernel.org/n/tip-wgjxeidwpowrvqgrxr080k6u@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/trace/beauty/open_flags.c b/tools/perf/trace/beauty/open_flags.c index 9c3a4cb..f55a459 100644 --- a/tools/perf/trace/beauty/open_flags.c +++ b/tools/perf/trace/beauty/open_flags.c @@ -2,6 +2,18 @@ #include #include +#ifndef O_DIRECT +#define O_DIRECT 00040000 +#endif + +#ifndef O_DIRECTORY +#define O_DIRECTORY 00200000 +#endif + +#ifndef O_NOATIME +#define O_NOATIME 01000000 +#endif + static size_t syscall_arg__scnprintf_open_flags(char *bf, size_t size, struct syscall_arg *arg) { -- cgit v0.10.2 From 2d18ac4ba7454a4260473e68be7e485ae71e7948 Mon Sep 17 00:00:00 2001 From: Jon Paul Maloy Date: Mon, 11 Jul 2016 16:08:35 -0400 Subject: tipc: extend broadcast link initialization criteria At first contact between two nodes, an endpoint might sometimes have time to send out a LINK_PROTOCOL/STATE packet before it has received the broadcast initialization packet from the peer, i.e., before it has received a valid broadcast packet number to add to the 'bc_ack' field of the protocol message. This means that the peer endpoint will receive a protocol packet with an invalid broadcast acknowledge value of 0. Under unlucky circumstances this may lead to the original, already received acknowledge value being overwritten, so that the whole broadcast link goes stale after a while. We fix this by delaying the setting of the link field 'bc_peer_is_up' until we know that the peer really has received our own broadcast initialization message. The latter is always sent out as the first unicast message on a link, and always with seqeunce number 1. Because of this, we only need to look for a non-zero unicast acknowledge value in the arriving STATE messages, and once that is confirmed we know we are safe and can set the mentioned field. Before this moment, we must ignore all broadcast acknowledges from the peer. Acked-by: Ying Xue Signed-off-by: Jon Maloy Signed-off-by: David S. Miller diff --git a/net/tipc/link.c b/net/tipc/link.c index 67b6ab9..6483dc4 100644 --- a/net/tipc/link.c +++ b/net/tipc/link.c @@ -1559,7 +1559,12 @@ void tipc_link_bc_sync_rcv(struct tipc_link *l, struct tipc_msg *hdr, if (!msg_peer_node_is_up(hdr)) return; - l->bc_peer_is_up = true; + /* Open when peer ackowledges our bcast init msg (pkt #1) */ + if (msg_ack(hdr)) + l->bc_peer_is_up = true; + + if (!l->bc_peer_is_up) + return; /* Ignore if peers_snd_nxt goes beyond receive window */ if (more(peers_snd_nxt, l->rcv_nxt + l->window)) -- cgit v0.10.2 From a71eb720355c28eaeb2de0c4d960247c69bb2c6f Mon Sep 17 00:00:00 2001 From: Jon Paul Maloy Date: Mon, 11 Jul 2016 16:08:36 -0400 Subject: tipc: ensure correct broadcast send buffer release when peer is lost After a new receiver peer has been added to the broadcast transmission link, we allow immediate transmission of new broadcast packets, trusting that the new peer will not accept the packets until it has received the previously sent unicast broadcast initialiation message. In the same way, the sender must not accept any acknowledges until it has itself received the broadcast initialization from the peer, as well as confirmation of the reception of its own initialization message. Furthermore, when a receiver peer goes down, the sender has to produce the missing acknowledges from the lost peer locally, in order ensure correct release of the buffers that were expected to be acknowledged by the said peer. In a highly stressed system we have observed that contact with a peer may come up and be lost before the above mentioned broadcast initial- ization and confirmation have been received. This leads to the locally produced acknowledges being rejected, and the non-acknowledged buffers to linger in the broadcast link transmission queue until it fills up and the link goes into permanent congestion. In this commit, we remedy this by temporarily setting the corresponding broadcast receive link state to ESTABLISHED and the 'bc_peer_is_up' state to true before we issue the local acknowledges. This ensures that those acknowledges will always be accepted. The mentioned state values are restored immediately afterwards when the link is reset. Acked-by: Ying Xue Signed-off-by: Jon Maloy Signed-off-by: David S. Miller diff --git a/net/tipc/link.c b/net/tipc/link.c index 6483dc4..7d89f87 100644 --- a/net/tipc/link.c +++ b/net/tipc/link.c @@ -349,6 +349,8 @@ void tipc_link_remove_bc_peer(struct tipc_link *snd_l, u16 ack = snd_l->snd_nxt - 1; snd_l->ackers--; + rcv_l->bc_peer_is_up = true; + rcv_l->state = LINK_ESTABLISHED; tipc_link_bc_ack_rcv(rcv_l, ack, xmitq); tipc_link_reset(rcv_l); rcv_l->state = LINK_RESET; -- cgit v0.10.2 From 1fc07f3e1541cc49cc159beb3fdefc5013570eda Mon Sep 17 00:00:00 2001 From: Jon Paul Maloy Date: Mon, 11 Jul 2016 16:08:37 -0400 Subject: tipc: reset all unicast links when broadcast send link fails In test situations with many nodes and a heavily stressed system we have observed that the transmission broadcast link may fail due to an excessive number of retransmissions of the same packet. In such situations we need to reset all unicast links to all peers, in order to reset and re-synchronize the broadcast link. In this commit, we add a new function tipc_bearer_reset_all() to be used in such situations. The function scans across all bearers and resets all their pertaining links. Acked-by: Ying Xue Signed-off-by: Jon Maloy Signed-off-by: David S. Miller diff --git a/net/tipc/bearer.c b/net/tipc/bearer.c index bf8f05c..a597708 100644 --- a/net/tipc/bearer.c +++ b/net/tipc/bearer.c @@ -330,6 +330,21 @@ static int tipc_reset_bearer(struct net *net, struct tipc_bearer *b) return 0; } +/* tipc_bearer_reset_all - reset all links on all bearers + */ +void tipc_bearer_reset_all(struct net *net) +{ + struct tipc_net *tn = tipc_net(net); + struct tipc_bearer *b; + int i; + + for (i = 0; i < MAX_BEARERS; i++) { + b = rcu_dereference_rtnl(tn->bearer_list[i]); + if (b) + tipc_reset_bearer(net, b); + } +} + /** * bearer_disable * diff --git a/net/tipc/bearer.h b/net/tipc/bearer.h index f686e41..60e49c3 100644 --- a/net/tipc/bearer.h +++ b/net/tipc/bearer.h @@ -198,6 +198,7 @@ void tipc_bearer_add_dest(struct net *net, u32 bearer_id, u32 dest); void tipc_bearer_remove_dest(struct net *net, u32 bearer_id, u32 dest); struct tipc_bearer *tipc_bearer_find(struct net *net, const char *name); struct tipc_media *tipc_media_find(const char *name); +void tipc_bearer_reset_all(struct net *net); int tipc_bearer_setup(void); void tipc_bearer_cleanup(void); void tipc_bearer_stop(struct net *net); diff --git a/net/tipc/node.c b/net/tipc/node.c index e01e2c71..23d4761 100644 --- a/net/tipc/node.c +++ b/net/tipc/node.c @@ -1297,10 +1297,6 @@ static void tipc_node_bc_rcv(struct net *net, struct sk_buff *skb, int bearer_id rc = tipc_bcast_rcv(net, be->link, skb); - /* Broadcast link reset may happen at reassembly failure */ - if (rc & TIPC_LINK_DOWN_EVT) - tipc_node_reset_links(n); - /* Broadcast ACKs are sent on a unicast link */ if (rc & TIPC_LINK_SND_BC_ACK) { tipc_node_read_lock(n); @@ -1320,6 +1316,17 @@ static void tipc_node_bc_rcv(struct net *net, struct sk_buff *skb, int bearer_id spin_unlock_bh(&be->inputq2.lock); tipc_sk_mcast_rcv(net, &be->arrvq, &be->inputq2); } + + if (rc & TIPC_LINK_DOWN_EVT) { + /* Reception reassembly failure => reset all links to peer */ + if (!tipc_link_is_up(be->link)) + tipc_node_reset_links(n); + + /* Retransmission failure => reset all links to all peers */ + if (!tipc_link_is_up(tipc_bc_sndlink(net))) + tipc_bearer_reset_all(net); + } + tipc_node_put(n); } -- cgit v0.10.2 From d716fb03f76411fc7e138692e33b749cada5c094 Mon Sep 17 00:00:00 2001 From: Awais Belal Date: Tue, 12 Jul 2016 15:21:28 +0500 Subject: ALSA: hda: add AMD Stoney PCI ID with proper driver caps This allows the device to correctly show up as ATI HDMI rather than a generic one and allows the driver to use the available caps. Signed-off-by: Awais Belal Cc: Signed-off-by: Takashi Iwai diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 7c9b06b..6f8ea13 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -2269,6 +2269,8 @@ static const struct pci_device_id azx_ids[] = { .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS }, { PCI_DEVICE(0x1002, 0x157a), .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS }, + { PCI_DEVICE(0x1002, 0x15b3), + .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS }, { PCI_DEVICE(0x1002, 0x793b), .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI }, { PCI_DEVICE(0x1002, 0x7919), -- cgit v0.10.2 From 590b52e10d410e1439ae86be9fe19d75fdab628b Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Mon, 11 Jul 2016 17:28:54 +0200 Subject: netfilter: conntrack: skip clash resolution if nat is in place The clash resolution is not easy to apply if the NAT table is registered. Even if no NAT rules are installed, the nul-binding ensures that a unique tuple is used, thus, the packet that loses race gets a different source port number, as described by: http://marc.info/?l=netfilter-devel&m=146818011604484&w=2 Clash resolution with NAT is also problematic if addresses/port range ports are used since the conntrack that wins race may describe a different mangling that we may have earlier applied to the packet via nf_nat_setup_info(). Fixes: 71d8c47fc653 ("netfilter: conntrack: introduce clash resolution on insertion race") Signed-off-by: Pablo Neira Ayuso Tested-by: Marc Dionne diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c index 62c42e9..9f530ad 100644 --- a/net/netfilter/nf_conntrack_core.c +++ b/net/netfilter/nf_conntrack_core.c @@ -646,6 +646,7 @@ static int nf_ct_resolve_clash(struct net *net, struct sk_buff *skb, l4proto = __nf_ct_l4proto_find(nf_ct_l3num(ct), nf_ct_protonum(ct)); if (l4proto->allow_clash && + !nfct_nat(ct) && !nf_ct_is_dying(ct) && atomic_inc_not_zero(&ct->ct_general.use)) { nf_ct_acct_merge(ct, ctinfo, (struct nf_conn *)skb->nfct); -- cgit v0.10.2 From 896ce45da2c2f4abc508d443fdecde7de0b3fa7e Mon Sep 17 00:00:00 2001 From: Mike Marciniszyn Date: Fri, 1 Jul 2016 15:57:02 -0700 Subject: IB/hfi1: Correct issues with sc5 computation There are several computatations of the sc in the ud receive routine. Besides the code duplication, all are wrong when the sc is greater than 15. In that case the code incorrectly or's a 1 into the computed sc instead of 1 shifted left by 4. Fix precomputed sc5 by using an already implemented routine hdr2sc() and deleting flawed duplicated code. Cc: Stable # 4.6+ Reviewed-by: Dennis Dalessandro Signed-off-by: Mike Marciniszyn Signed-off-by: Dennis Dalessandro Signed-off-by: Doug Ledford diff --git a/drivers/infiniband/hw/hfi1/ud.c b/drivers/infiniband/hw/hfi1/ud.c index 1e503ad..be91f6f 100644 --- a/drivers/infiniband/hw/hfi1/ud.c +++ b/drivers/infiniband/hw/hfi1/ud.c @@ -678,8 +678,7 @@ void hfi1_ud_rcv(struct hfi1_packet *packet) u32 tlen = packet->tlen; struct rvt_qp *qp = packet->qp; bool has_grh = rcv_flags & HFI1_HAS_GRH; - bool sc4_bit = has_sc4_bit(packet); - u8 sc; + u8 sc5 = hdr2sc((struct hfi1_message_header *)hdr, packet->rhf); u32 bth1; int is_mcast; struct ib_grh *grh = NULL; @@ -697,10 +696,8 @@ void hfi1_ud_rcv(struct hfi1_packet *packet) */ struct hfi1_pportdata *ppd = ppd_from_ibp(ibp); u32 lqpn = be32_to_cpu(ohdr->bth[1]) & RVT_QPN_MASK; - u8 sl, sc5; + u8 sl; - sc5 = (be16_to_cpu(hdr->lrh[0]) >> 12) & 0xf; - sc5 |= sc4_bit; sl = ibp->sc_to_sl[sc5]; process_becn(ppd, sl, 0, lqpn, 0, IB_CC_SVCTYPE_UD); @@ -717,10 +714,6 @@ void hfi1_ud_rcv(struct hfi1_packet *packet) if (!is_mcast && (opcode != IB_OPCODE_CNP) && bth1 & HFI1_FECN_SMASK) { u16 slid = be16_to_cpu(hdr->lrh[3]); - u8 sc5; - - sc5 = (be16_to_cpu(hdr->lrh[0]) >> 12) & 0xf; - sc5 |= sc4_bit; return_cnp(ibp, qp, src_qp, pkey, dlid, slid, sc5, grh); } @@ -745,10 +738,6 @@ void hfi1_ud_rcv(struct hfi1_packet *packet) if (qp->ibqp.qp_num > 1) { struct hfi1_pportdata *ppd = ppd_from_ibp(ibp); u16 slid; - u8 sc5; - - sc5 = (be16_to_cpu(hdr->lrh[0]) >> 12) & 0xf; - sc5 |= sc4_bit; slid = be16_to_cpu(hdr->lrh[3]); if (unlikely(rcv_pkey_check(ppd, pkey, sc5, slid))) { @@ -790,10 +779,6 @@ void hfi1_ud_rcv(struct hfi1_packet *packet) /* Received on QP0, and so by definition, this is an SMP */ struct opa_smp *smp = (struct opa_smp *)data; u16 slid = be16_to_cpu(hdr->lrh[3]); - u8 sc5; - - sc5 = (be16_to_cpu(hdr->lrh[0]) >> 12) & 0xf; - sc5 |= sc4_bit; if (opa_smp_check(ibp, pkey, sc5, qp, slid, smp)) goto drop; @@ -890,9 +875,7 @@ void hfi1_ud_rcv(struct hfi1_packet *packet) } wc.slid = be16_to_cpu(hdr->lrh[3]); - sc = (be16_to_cpu(hdr->lrh[0]) >> 12) & 0xf; - sc |= sc4_bit; - wc.sl = ibp->sc_to_sl[sc]; + wc.sl = ibp->sc_to_sl[sc5]; /* * Save the LMC lower bits if the destination LID is a unicast LID. -- cgit v0.10.2 From 98f179a5eaf77eaac49df3d0c217c6eaaba8c0db Mon Sep 17 00:00:00 2001 From: Tadeusz Struk Date: Wed, 6 Jul 2016 17:14:47 -0400 Subject: IB/hfi1: Fix sleep inside atomic issue in init_asic_data The critical section should protect only the list traversal and dd->asic_data modification, not the memory allocation. The fix pulls the allocation out of the critical section. Reviewed-by: Dennis Dalessandro Reviewed-by: Sebastian Sanchez Reviewed-by: Dean Luick Signed-off-by: Tadeusz Struk Signed-off-by: Dennis Dalessandro Signed-off-by: Mike Marciniszyn Signed-off-by: Doug Ledford diff --git a/drivers/infiniband/hw/hfi1/chip.c b/drivers/infiniband/hw/hfi1/chip.c index f5de851..dad4d0e 100644 --- a/drivers/infiniband/hw/hfi1/chip.c +++ b/drivers/infiniband/hw/hfi1/chip.c @@ -14113,8 +14113,14 @@ static int init_asic_data(struct hfi1_devdata *dd) { unsigned long flags; struct hfi1_devdata *tmp, *peer = NULL; + struct hfi1_asic_data *asic_data; int ret = 0; + /* pre-allocate the asic structure in case we are the first device */ + asic_data = kzalloc(sizeof(*dd->asic_data), GFP_KERNEL); + if (!asic_data) + return -ENOMEM; + spin_lock_irqsave(&hfi1_devs_lock, flags); /* Find our peer device */ list_for_each_entry(tmp, &hfi1_dev_list, list) { @@ -14126,18 +14132,14 @@ static int init_asic_data(struct hfi1_devdata *dd) } if (peer) { + /* use already allocated structure */ dd->asic_data = peer->asic_data; + kfree(asic_data); } else { - dd->asic_data = kzalloc(sizeof(*dd->asic_data), GFP_KERNEL); - if (!dd->asic_data) { - ret = -ENOMEM; - goto done; - } + dd->asic_data = asic_data; mutex_init(&dd->asic_data->asic_resource_mutex); } dd->asic_data->dds[dd->hfi1_id] = dd; /* self back-pointer */ - -done: spin_unlock_irqrestore(&hfi1_devs_lock, flags); return ret; } -- cgit v0.10.2 From c5a81d11d756bfa2b7215463b5908006871bd4fa Mon Sep 17 00:00:00 2001 From: Christoph Lameter Date: Fri, 8 Jul 2016 10:27:42 -0500 Subject: IB core: Add port_xmit_wait counter Add the missing port_xmit_wait counter. This counter is displayed through some tools like perfquery but is not available via sysfs. For the PORT_PMA_ATTR macro the _counter field is set to zero allowing us to specify the offset directly like with PORT_PMA_ATTR_EXT See also the earlier work in 2008 by Vladimir Skolovsky https://www.mail-archive.com/general@lists.openfabrics.org/msg20313.html Signed-off-by: Vladimir Sokolvsky Signed-off-by: Christoph Lameter Signed-off-by: Doug Ledford diff --git a/drivers/infiniband/core/sysfs.c b/drivers/infiniband/core/sysfs.c index a5793c8..60df4f8 100644 --- a/drivers/infiniband/core/sysfs.c +++ b/drivers/infiniband/core/sysfs.c @@ -530,6 +530,7 @@ static PORT_PMA_ATTR(port_xmit_data , 12, 32, 192); static PORT_PMA_ATTR(port_rcv_data , 13, 32, 224); static PORT_PMA_ATTR(port_xmit_packets , 14, 32, 256); static PORT_PMA_ATTR(port_rcv_packets , 15, 32, 288); +static PORT_PMA_ATTR(port_xmit_wait , 0, 32, 320); /* * Counters added by extended set @@ -560,6 +561,7 @@ static struct attribute *pma_attrs[] = { &port_pma_attr_port_rcv_data.attr.attr, &port_pma_attr_port_xmit_packets.attr.attr, &port_pma_attr_port_rcv_packets.attr.attr, + &port_pma_attr_port_xmit_wait.attr.attr, NULL }; @@ -579,6 +581,7 @@ static struct attribute *pma_attrs_ext[] = { &port_pma_attr_ext_port_xmit_data.attr.attr, &port_pma_attr_ext_port_rcv_data.attr.attr, &port_pma_attr_ext_port_xmit_packets.attr.attr, + &port_pma_attr_port_xmit_wait.attr.attr, &port_pma_attr_ext_port_rcv_packets.attr.attr, &port_pma_attr_ext_unicast_rcv_packets.attr.attr, &port_pma_attr_ext_unicast_xmit_packets.attr.attr, @@ -604,6 +607,7 @@ static struct attribute *pma_attrs_noietf[] = { &port_pma_attr_ext_port_rcv_data.attr.attr, &port_pma_attr_ext_port_xmit_packets.attr.attr, &port_pma_attr_ext_port_rcv_packets.attr.attr, + &port_pma_attr_port_xmit_wait.attr.attr, NULL }; -- cgit v0.10.2 From b0548cff99ba927730d4f0c306b98cb6b6aa7cf7 Mon Sep 17 00:00:00 2001 From: Nicolas Iooss Date: Sat, 25 Jun 2016 17:55:07 +0200 Subject: i40iw: do not print unitialized variables in error message i40iw_create_cqp() printed the contents of variables maj_err and min_err in an error message before they could be initialized (by calling dev->cqp_ops->cqp_create). Signed-off-by: Nicolas Iooss Signed-off-by: Doug Ledford diff --git a/drivers/infiniband/hw/i40iw/i40iw_main.c b/drivers/infiniband/hw/i40iw/i40iw_main.c index c963cad..6e90813 100644 --- a/drivers/infiniband/hw/i40iw/i40iw_main.c +++ b/drivers/infiniband/hw/i40iw/i40iw_main.c @@ -600,8 +600,7 @@ static enum i40iw_status_code i40iw_create_cqp(struct i40iw_device *iwdev) cqp_init_info.scratch_array = cqp->scratch_array; status = dev->cqp_ops->cqp_init(dev->cqp, &cqp_init_info); if (status) { - i40iw_pr_err("cqp init status %d maj_err %d min_err %d\n", - status, maj_err, min_err); + i40iw_pr_err("cqp init status %d\n", status); goto exit; } status = dev->cqp_ops->cqp_create(dev->cqp, true, &maj_err, &min_err); -- cgit v0.10.2 From 8e0e7aedadb877d91a6e66611464165c969bc0a9 Mon Sep 17 00:00:00 2001 From: Shiraz Saleem Date: Mon, 27 Jun 2016 16:52:14 -0500 Subject: i40iw: Enable remote access rights for stag allocation Fix to enable remote access rights when allocating stag. Fixes: b7aee855d3b9 ("RDMA/i40iw: Add base memory management extensions") Signed-off-by: Shiraz Saleem Signed-off-by: Doug Ledford diff --git a/drivers/infiniband/hw/i40iw/i40iw_verbs.c b/drivers/infiniband/hw/i40iw/i40iw_verbs.c index 33959ed..283b64c 100644 --- a/drivers/infiniband/hw/i40iw/i40iw_verbs.c +++ b/drivers/infiniband/hw/i40iw/i40iw_verbs.c @@ -1474,6 +1474,7 @@ static int i40iw_hw_alloc_stag(struct i40iw_device *iwdev, struct i40iw_mr *iwmr info->stag_idx = iwmr->stag >> I40IW_CQPSQ_STAG_IDX_SHIFT; info->pd_id = iwpd->sc_pd.pd_id; info->total_len = iwmr->length; + info->remote_access = true; cqp_info->cqp_cmd = OP_ALLOC_STAG; cqp_info->post_sq = 1; cqp_info->in.u.alloc_stag.dev = &iwdev->sc_dev; -- cgit v0.10.2 From 1d661bf5327a2c059ec967f850e89362e637f4e6 Mon Sep 17 00:00:00 2001 From: Anna-Maria Gleixner Date: Tue, 12 Jul 2016 16:40:09 +0200 Subject: clocksource/drivers/time-armada-370-xp: Fix return value check The failure check of armada_370_xp_timer_setup() in armada_370_xp_timer_common_init() is negated. This leads to an error message and exit in case of a successful initialization. Remove the stray '!'. Fixes: 12549e27c63c ("clocksource/drivers/time-armada-370-xp: Convert init function to return error") Signed-off-by: Anna-Maria Gleixner Cc: Daniel Lezcano Link: http://lkml.kernel.org/r/alpine.DEB.2.11.1607121731020.1344@hypnos.tec.linutronix.de Signed-off-by: Thomas Gleixner diff --git a/drivers/clocksource/time-armada-370-xp.c b/drivers/clocksource/time-armada-370-xp.c index a4e5923..20ec066 100644 --- a/drivers/clocksource/time-armada-370-xp.c +++ b/drivers/clocksource/time-armada-370-xp.c @@ -342,7 +342,7 @@ static int __init armada_370_xp_timer_common_init(struct device_node *np) } res = armada_370_xp_timer_setup(this_cpu_ptr(armada_370_xp_evt)); - if (!res) { + if (res) { pr_err("Failed to setup timer"); return res; } -- cgit v0.10.2 From 44f52122a22004de9c3bae288bbc6dff3624fe9c Mon Sep 17 00:00:00 2001 From: Bob Peterson Date: Wed, 6 Jul 2016 10:36:43 -0500 Subject: GFS2: Check rs_free with rd_rsspin protection For the last process to close a file opened for write, function gfs2_rsqa_delete was deleting the file's inode's block reservation out of the rgrp reservations tree. Then it was checking to make sure rs_free was 0, but it was performing the check outside the protection of rd_rsspin spin_lock. The rd_rsspin spin_lock protection is needed to prevent a race between the process freeing the reservation and another who is allocating a new set of blocks inside the same rgrp for the same inode, thus changing its value. Signed-off-by: Bob Peterson diff --git a/fs/gfs2/rgrp.c b/fs/gfs2/rgrp.c index fba38ca..86ccc015 100644 --- a/fs/gfs2/rgrp.c +++ b/fs/gfs2/rgrp.c @@ -658,6 +658,7 @@ void gfs2_rs_deltree(struct gfs2_blkreserv *rs) if (rgd) { spin_lock(&rgd->rd_rsspin); __rs_deltree(rs); + BUG_ON(rs->rs_free); spin_unlock(&rgd->rd_rsspin); } } @@ -671,10 +672,8 @@ void gfs2_rs_deltree(struct gfs2_blkreserv *rs) void gfs2_rsqa_delete(struct gfs2_inode *ip, atomic_t *wcount) { down_write(&ip->i_rw_mutex); - if ((wcount == NULL) || (atomic_read(wcount) <= 1)) { + if ((wcount == NULL) || (atomic_read(wcount) <= 1)) gfs2_rs_deltree(&ip->i_res); - BUG_ON(ip->i_res.rs_free); - } up_write(&ip->i_rw_mutex); gfs2_qa_delete(ip, wcount); } -- cgit v0.10.2 From c8b5f2c96d1bf6cefcbe12f67dce0b892fe20512 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Wed, 6 Jul 2016 11:56:20 -0300 Subject: tools: Introduce str_error_r() The tools so far have been using the strerror_r() GNU variant, that returns a string, be it the buffer passed or something else. But that, besides being tricky in cases where we expect that the function using strerror_r() returns the error formatted in a provided buffer (we have to check if it returned something else and copy that instead), breaks the build on systems not using glibc, like Alpine Linux, where musl libc is used. So, introduce yet another wrapper, str_error_r(), that has the GNU interface, but uses the portable XSI variant of strerror_r(), so that users rest asured that the provided buffer is used and it is what is returned. Cc: Adrian Hunter Cc: David Ahern Cc: Jiri Olsa Cc: Namhyung Kim Cc: Wang Nan Link: http://lkml.kernel.org/n/tip-d4t42fnf48ytlk8rjxs822tf@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/include/linux/string.h b/tools/include/linux/string.h index e26223f..b466d02 100644 --- a/tools/include/linux/string.h +++ b/tools/include/linux/string.h @@ -12,4 +12,6 @@ int strtobool(const char *s, bool *res); extern size_t strlcpy(char *dest, const char *src, size_t size); #endif +char *str_error_r(int errnum, char *buf, size_t buflen); + #endif /* _LINUX_STRING_H_ */ diff --git a/tools/lib/str_error_r.c b/tools/lib/str_error_r.c new file mode 100644 index 0000000..503ae07 --- /dev/null +++ b/tools/lib/str_error_r.c @@ -0,0 +1,26 @@ +#undef _GNU_SOURCE +#include +#include +#include + +/* + * The tools so far have been using the strerror_r() GNU variant, that returns + * a string, be it the buffer passed or something else. + * + * But that, besides being tricky in cases where we expect that the function + * using strerror_r() returns the error formatted in a provided buffer (we have + * to check if it returned something else and copy that instead), breaks the + * build on systems not using glibc, like Alpine Linux, where musl libc is + * used. + * + * So, introduce yet another wrapper, str_error_r(), that has the GNU + * interface, but uses the portable XSI variant of strerror_r(), so that users + * rest asured that the provided buffer is used and it is what is returned. + */ +char *str_error_r(int errnum, char *buf, size_t buflen) +{ + int err = strerror_r(errnum, buf, buflen); + if (err) + snprintf(buf, buflen, "INTERNAL ERROR: strerror_r(%d, %p, %zd)=%d", errnum, buf, buflen, err); + return buf; +} diff --git a/tools/perf/MANIFEST b/tools/perf/MANIFEST index 8c8c6b9..f18e781 100644 --- a/tools/perf/MANIFEST +++ b/tools/perf/MANIFEST @@ -29,6 +29,7 @@ tools/lib/symbol/kallsyms.c tools/lib/symbol/kallsyms.h tools/lib/find_bit.c tools/lib/bitmap.c +tools/lib/str_error_r.c tools/include/asm/atomic.h tools/include/asm/barrier.h tools/include/asm/bug.h diff --git a/tools/perf/arch/x86/tests/rdpmc.c b/tools/perf/arch/x86/tests/rdpmc.c index 72193f19..a32d72e 100644 --- a/tools/perf/arch/x86/tests/rdpmc.c +++ b/tools/perf/arch/x86/tests/rdpmc.c @@ -111,14 +111,14 @@ static int __test__rdpmc(void) if (fd < 0) { pr_err("Error: sys_perf_event_open() syscall returned " "with %d (%s)\n", fd, - strerror_r(errno, sbuf, sizeof(sbuf))); + str_error_r(errno, sbuf, sizeof(sbuf))); return -1; } addr = mmap(NULL, page_size, PROT_READ, MAP_SHARED, fd, 0); if (addr == (void *)(-1)) { pr_err("Error: mmap() syscall returned with (%s)\n", - strerror_r(errno, sbuf, sizeof(sbuf))); + str_error_r(errno, sbuf, sizeof(sbuf))); goto out_close; } diff --git a/tools/perf/builtin-buildid-cache.c b/tools/perf/builtin-buildid-cache.c index 76a4d03..30e2b2c 100644 --- a/tools/perf/builtin-buildid-cache.c +++ b/tools/perf/builtin-buildid-cache.c @@ -351,7 +351,7 @@ int cmd_buildid_cache(int argc, const char **argv, continue; } pr_warning("Couldn't add %s: %s\n", - pos->s, strerror_r(errno, sbuf, sizeof(sbuf))); + pos->s, str_error_r(errno, sbuf, sizeof(sbuf))); } strlist__delete(list); @@ -369,7 +369,7 @@ int cmd_buildid_cache(int argc, const char **argv, continue; } pr_warning("Couldn't remove %s: %s\n", - pos->s, strerror_r(errno, sbuf, sizeof(sbuf))); + pos->s, str_error_r(errno, sbuf, sizeof(sbuf))); } strlist__delete(list); @@ -387,7 +387,7 @@ int cmd_buildid_cache(int argc, const char **argv, continue; } pr_warning("Couldn't remove %s: %s\n", - pos->s, strerror_r(errno, sbuf, sizeof(sbuf))); + pos->s, str_error_r(errno, sbuf, sizeof(sbuf))); } strlist__delete(list); @@ -408,7 +408,7 @@ int cmd_buildid_cache(int argc, const char **argv, continue; } pr_warning("Couldn't update %s: %s\n", - pos->s, strerror_r(errno, sbuf, sizeof(sbuf))); + pos->s, str_error_r(errno, sbuf, sizeof(sbuf))); } strlist__delete(list); diff --git a/tools/perf/builtin-help.c b/tools/perf/builtin-help.c index 268ab73..3bdb2c7 100644 --- a/tools/perf/builtin-help.c +++ b/tools/perf/builtin-help.c @@ -117,7 +117,7 @@ static void exec_woman_emacs(const char *path, const char *page) free(man_page); } warning("failed to exec '%s': %s", path, - strerror_r(errno, sbuf, sizeof(sbuf))); + str_error_r(errno, sbuf, sizeof(sbuf))); } } @@ -150,7 +150,7 @@ static void exec_man_konqueror(const char *path, const char *page) free(man_page); } warning("failed to exec '%s': %s", path, - strerror_r(errno, sbuf, sizeof(sbuf))); + str_error_r(errno, sbuf, sizeof(sbuf))); } } @@ -162,7 +162,7 @@ static void exec_man_man(const char *path, const char *page) path = "man"; execlp(path, "man", page, NULL); warning("failed to exec '%s': %s", path, - strerror_r(errno, sbuf, sizeof(sbuf))); + str_error_r(errno, sbuf, sizeof(sbuf))); } static void exec_man_cmd(const char *cmd, const char *page) @@ -175,7 +175,7 @@ static void exec_man_cmd(const char *cmd, const char *page) free(shell_cmd); } warning("failed to exec '%s': %s", cmd, - strerror_r(errno, sbuf, sizeof(sbuf))); + str_error_r(errno, sbuf, sizeof(sbuf))); } static void add_man_viewer(const char *name) diff --git a/tools/perf/builtin-kvm.c b/tools/perf/builtin-kvm.c index f4efef9..5e2127e 100644 --- a/tools/perf/builtin-kvm.c +++ b/tools/perf/builtin-kvm.c @@ -1018,13 +1018,13 @@ static int kvm_live_open_events(struct perf_kvm_stat *kvm) err = perf_evlist__open(evlist); if (err < 0) { printf("Couldn't create the events: %s\n", - strerror_r(errno, sbuf, sizeof(sbuf))); + str_error_r(errno, sbuf, sizeof(sbuf))); goto out; } if (perf_evlist__mmap(evlist, kvm->opts.mmap_pages, false) < 0) { ui__error("Failed to mmap the events: %s\n", - strerror_r(errno, sbuf, sizeof(sbuf))); + str_error_r(errno, sbuf, sizeof(sbuf))); perf_evlist__close(evlist); goto out; } diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c index a1a5cd1..c6d890a 100644 --- a/tools/perf/builtin-probe.c +++ b/tools/perf/builtin-probe.c @@ -308,7 +308,7 @@ static void pr_err_with_code(const char *msg, int err) pr_err("%s", msg); pr_debug(" Reason: %s (Code: %d)", - strerror_r(-err, sbuf, sizeof(sbuf)), err); + str_error_r(-err, sbuf, sizeof(sbuf)), err); pr_err("\n"); } diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index b2b3b60..d9f5cc3 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -361,7 +361,7 @@ static int record__mmap_evlist(struct record *rec, return -errno; } else { pr_err("failed to mmap with %d (%s)\n", errno, - strerror_r(errno, msg, sizeof(msg))); + str_error_r(errno, msg, sizeof(msg))); if (errno) return -errno; else @@ -407,7 +407,7 @@ try_again: if (perf_evlist__apply_filters(evlist, &pos)) { error("failed to set filter \"%s\" on event %s with %d (%s)\n", pos->filter, perf_evsel__name(pos), errno, - strerror_r(errno, msg, sizeof(msg))); + str_error_r(errno, msg, sizeof(msg))); rc = -1; goto out; } @@ -1003,7 +1003,7 @@ static int __cmd_record(struct record *rec, int argc, const char **argv) if (forks && workload_exec_errno) { char msg[STRERR_BUFSIZE]; - const char *emsg = strerror_r(workload_exec_errno, msg, sizeof(msg)); + const char *emsg = str_error_r(workload_exec_errno, msg, sizeof(msg)); pr_err("Workload failed: %s\n", emsg); err = -1; goto out_child; diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c index afa0576..0dfe8df 100644 --- a/tools/perf/builtin-sched.c +++ b/tools/perf/builtin-sched.c @@ -494,7 +494,7 @@ force_again: } pr_err("Error: sys_perf_event_open() syscall returned " "with %d (%s)\n%s", fd, - strerror_r(errno, sbuf, sizeof(sbuf)), info); + str_error_r(errno, sbuf, sizeof(sbuf)), info); exit(EXIT_FAILURE); } return fd; diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index c367a43..8c5a3bf 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c @@ -596,7 +596,7 @@ try_again: if (perf_evlist__apply_filters(evsel_list, &counter)) { error("failed to set filter \"%s\" on event %s with %d (%s)\n", counter->filter, perf_evsel__name(counter), errno, - strerror_r(errno, msg, sizeof(msg))); + str_error_r(errno, msg, sizeof(msg))); return -1; } @@ -637,7 +637,7 @@ try_again: wait(&status); if (workload_exec_errno) { - const char *emsg = strerror_r(workload_exec_errno, msg, sizeof(msg)); + const char *emsg = str_error_r(workload_exec_errno, msg, sizeof(msg)); pr_err("Workload failed: %s\n", emsg); return -1; } diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 07fc792..bd10868 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -907,7 +907,7 @@ try_again: if (perf_evlist__mmap(evlist, opts->mmap_pages, false) < 0) { ui__error("Failed to mmap with %d (%s)\n", - errno, strerror_r(errno, msg, sizeof(msg))); + errno, str_error_r(errno, msg, sizeof(msg))); goto out_err; } @@ -1028,7 +1028,7 @@ out_delete: out_err_cpu_topo: { char errbuf[BUFSIZ]; - const char *err = strerror_r(-ret, errbuf, sizeof(errbuf)); + const char *err = str_error_r(-ret, errbuf, sizeof(errbuf)); ui__error("Could not read the CPU topology map: %s\n", err); goto out_delete; @@ -1295,7 +1295,7 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused) if (perf_evlist__create_maps(top.evlist, target) < 0) { ui__error("Couldn't create thread/CPU maps: %s\n", - errno == ENOENT ? "No such process" : strerror_r(errno, errbuf, sizeof(errbuf))); + errno == ENOENT ? "No such process" : str_error_r(errno, errbuf, sizeof(errbuf))); goto out_delete_evlist; } diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c index cf90de8..e7e0b6e 100644 --- a/tools/perf/builtin-trace.c +++ b/tools/perf/builtin-trace.c @@ -1601,7 +1601,7 @@ signed_print: fprintf(trace->output, ") = %ld", ret); } else if (ret < 0 && (sc->fmt->errmsg || sc->fmt->errpid)) { char bf[STRERR_BUFSIZE]; - const char *emsg = strerror_r(-ret, bf, sizeof(bf)), + const char *emsg = str_error_r(-ret, bf, sizeof(bf)), *e = audit_errno_to_name(-ret); fprintf(trace->output, ") = -1 %s %s", e, emsg); @@ -2402,7 +2402,7 @@ out_error_apply_filters: fprintf(trace->output, "Failed to set filter \"%s\" on event %s with %d (%s)\n", evsel->filter, perf_evsel__name(evsel), errno, - strerror_r(errno, errbuf, sizeof(errbuf))); + str_error_r(errno, errbuf, sizeof(errbuf))); goto out_delete_evlist; } out_error_mem: diff --git a/tools/perf/perf.c b/tools/perf/perf.c index 8f21922..f7d7dbb 100644 --- a/tools/perf/perf.c +++ b/tools/perf/perf.c @@ -374,7 +374,7 @@ static int run_builtin(struct cmd_struct *p, int argc, const char **argv) /* Check for ENOSPC and EIO errors.. */ if (fflush(stdout)) { fprintf(stderr, "write failure on standard output: %s", - strerror_r(errno, sbuf, sizeof(sbuf))); + str_error_r(errno, sbuf, sizeof(sbuf))); goto out; } if (ferror(stdout)) { @@ -383,7 +383,7 @@ static int run_builtin(struct cmd_struct *p, int argc, const char **argv) } if (fclose(stdout)) { fprintf(stderr, "close failed on standard output: %s", - strerror_r(errno, sbuf, sizeof(sbuf))); + str_error_r(errno, sbuf, sizeof(sbuf))); goto out; } status = 0; @@ -615,7 +615,7 @@ int main(int argc, const char **argv) } fprintf(stderr, "Failed to run command '%s': %s\n", - cmd, strerror_r(errno, sbuf, sizeof(sbuf))); + cmd, str_error_r(errno, sbuf, sizeof(sbuf))); out: return 1; } diff --git a/tools/perf/tests/backward-ring-buffer.c b/tools/perf/tests/backward-ring-buffer.c index e70313f..f20ea4c 100644 --- a/tools/perf/tests/backward-ring-buffer.c +++ b/tools/perf/tests/backward-ring-buffer.c @@ -60,7 +60,7 @@ static int do_test(struct perf_evlist *evlist, int mmap_pages, err = perf_evlist__mmap(evlist, mmap_pages, true); if (err < 0) { pr_debug("perf_evlist__mmap: %s\n", - strerror_r(errno, sbuf, sizeof(sbuf))); + str_error_r(errno, sbuf, sizeof(sbuf))); return TEST_FAIL; } @@ -124,7 +124,7 @@ int test__backward_ring_buffer(int subtest __maybe_unused) err = perf_evlist__open(evlist); if (err < 0) { pr_debug("perf_evlist__open: %s\n", - strerror_r(errno, sbuf, sizeof(sbuf))); + str_error_r(errno, sbuf, sizeof(sbuf))); goto out_delete_evlist; } diff --git a/tools/perf/tests/bpf.c b/tools/perf/tests/bpf.c index f31eed3..da0d87613 100644 --- a/tools/perf/tests/bpf.c +++ b/tools/perf/tests/bpf.c @@ -143,14 +143,14 @@ static int do_test(struct bpf_object *obj, int (*func)(void), err = perf_evlist__open(evlist); if (err < 0) { pr_debug("perf_evlist__open: %s\n", - strerror_r(errno, sbuf, sizeof(sbuf))); + str_error_r(errno, sbuf, sizeof(sbuf))); goto out_delete_evlist; } err = perf_evlist__mmap(evlist, opts.mmap_pages, false); if (err < 0) { pr_debug("perf_evlist__mmap: %s\n", - strerror_r(errno, sbuf, sizeof(sbuf))); + str_error_r(errno, sbuf, sizeof(sbuf))); goto out_delete_evlist; } diff --git a/tools/perf/tests/builtin-test.c b/tools/perf/tests/builtin-test.c index 07c14e9..c23cbf7 100644 --- a/tools/perf/tests/builtin-test.c +++ b/tools/perf/tests/builtin-test.c @@ -258,7 +258,7 @@ static int run_test(struct test *test, int subtest) if (child < 0) { pr_err("failed to fork test: %s\n", - strerror_r(errno, sbuf, sizeof(sbuf))); + str_error_r(errno, sbuf, sizeof(sbuf))); return -1; } diff --git a/tools/perf/tests/event-times.c b/tools/perf/tests/event-times.c index 9f5698a..19ef77b 100644 --- a/tools/perf/tests/event-times.c +++ b/tools/perf/tests/event-times.c @@ -37,7 +37,7 @@ static int attach__enable_on_exec(struct perf_evlist *evlist) err = perf_evlist__open(evlist); if (err < 0) { pr_debug("perf_evlist__open: %s\n", - strerror_r(errno, sbuf, sizeof(sbuf))); + str_error_r(errno, sbuf, sizeof(sbuf))); return err; } diff --git a/tools/perf/tests/mmap-basic.c b/tools/perf/tests/mmap-basic.c index aea33f5..5c9b931 100644 --- a/tools/perf/tests/mmap-basic.c +++ b/tools/perf/tests/mmap-basic.c @@ -49,7 +49,7 @@ int test__basic_mmap(int subtest __maybe_unused) sched_setaffinity(0, sizeof(cpu_set), &cpu_set); if (sched_setaffinity(0, sizeof(cpu_set), &cpu_set) < 0) { pr_debug("sched_setaffinity() failed on CPU %d: %s ", - cpus->map[0], strerror_r(errno, sbuf, sizeof(sbuf))); + cpus->map[0], str_error_r(errno, sbuf, sizeof(sbuf))); goto out_free_cpus; } @@ -79,7 +79,7 @@ int test__basic_mmap(int subtest __maybe_unused) if (perf_evsel__open(evsels[i], cpus, threads) < 0) { pr_debug("failed to open counter: %s, " "tweak /proc/sys/kernel/perf_event_paranoid?\n", - strerror_r(errno, sbuf, sizeof(sbuf))); + str_error_r(errno, sbuf, sizeof(sbuf))); goto out_delete_evlist; } @@ -89,7 +89,7 @@ int test__basic_mmap(int subtest __maybe_unused) if (perf_evlist__mmap(evlist, 128, true) < 0) { pr_debug("failed to mmap events: %d (%s)\n", errno, - strerror_r(errno, sbuf, sizeof(sbuf))); + str_error_r(errno, sbuf, sizeof(sbuf))); goto out_delete_evlist; } diff --git a/tools/perf/tests/openat-syscall-all-cpus.c b/tools/perf/tests/openat-syscall-all-cpus.c index ad1cb63..265abb1 100644 --- a/tools/perf/tests/openat-syscall-all-cpus.c +++ b/tools/perf/tests/openat-syscall-all-cpus.c @@ -41,7 +41,7 @@ int test__openat_syscall_event_on_all_cpus(int subtest __maybe_unused) if (perf_evsel__open(evsel, cpus, threads) < 0) { pr_debug("failed to open counter: %s, " "tweak /proc/sys/kernel/perf_event_paranoid?\n", - strerror_r(errno, sbuf, sizeof(sbuf))); + str_error_r(errno, sbuf, sizeof(sbuf))); goto out_evsel_delete; } @@ -62,7 +62,7 @@ int test__openat_syscall_event_on_all_cpus(int subtest __maybe_unused) if (sched_setaffinity(0, sizeof(cpu_set), &cpu_set) < 0) { pr_debug("sched_setaffinity() failed on CPU %d: %s ", cpus->map[cpu], - strerror_r(errno, sbuf, sizeof(sbuf))); + str_error_r(errno, sbuf, sizeof(sbuf))); goto out_close_fd; } for (i = 0; i < ncalls; ++i) { diff --git a/tools/perf/tests/openat-syscall-tp-fields.c b/tools/perf/tests/openat-syscall-tp-fields.c index 4344fe4..942dbf4 100644 --- a/tools/perf/tests/openat-syscall-tp-fields.c +++ b/tools/perf/tests/openat-syscall-tp-fields.c @@ -51,14 +51,14 @@ int test__syscall_openat_tp_fields(int subtest __maybe_unused) err = perf_evlist__open(evlist); if (err < 0) { pr_debug("perf_evlist__open: %s\n", - strerror_r(errno, sbuf, sizeof(sbuf))); + str_error_r(errno, sbuf, sizeof(sbuf))); goto out_delete_evlist; } err = perf_evlist__mmap(evlist, UINT_MAX, false); if (err < 0) { pr_debug("perf_evlist__mmap: %s\n", - strerror_r(errno, sbuf, sizeof(sbuf))); + str_error_r(errno, sbuf, sizeof(sbuf))); goto out_delete_evlist; } diff --git a/tools/perf/tests/openat-syscall.c b/tools/perf/tests/openat-syscall.c index 1184f9b..d741412 100644 --- a/tools/perf/tests/openat-syscall.c +++ b/tools/perf/tests/openat-syscall.c @@ -29,7 +29,7 @@ int test__openat_syscall_event(int subtest __maybe_unused) if (perf_evsel__open_per_thread(evsel, threads) < 0) { pr_debug("failed to open counter: %s, " "tweak /proc/sys/kernel/perf_event_paranoid?\n", - strerror_r(errno, sbuf, sizeof(sbuf))); + str_error_r(errno, sbuf, sizeof(sbuf))); goto out_evsel_delete; } diff --git a/tools/perf/tests/perf-record.c b/tools/perf/tests/perf-record.c index b836ee6a..3eb67a9 100644 --- a/tools/perf/tests/perf-record.c +++ b/tools/perf/tests/perf-record.c @@ -104,7 +104,7 @@ int test__PERF_RECORD(int subtest __maybe_unused) err = sched__get_first_possible_cpu(evlist->workload.pid, &cpu_mask); if (err < 0) { pr_debug("sched__get_first_possible_cpu: %s\n", - strerror_r(errno, sbuf, sizeof(sbuf))); + str_error_r(errno, sbuf, sizeof(sbuf))); goto out_delete_evlist; } @@ -115,7 +115,7 @@ int test__PERF_RECORD(int subtest __maybe_unused) */ if (sched_setaffinity(evlist->workload.pid, cpu_mask_size, &cpu_mask) < 0) { pr_debug("sched_setaffinity: %s\n", - strerror_r(errno, sbuf, sizeof(sbuf))); + str_error_r(errno, sbuf, sizeof(sbuf))); goto out_delete_evlist; } @@ -126,7 +126,7 @@ int test__PERF_RECORD(int subtest __maybe_unused) err = perf_evlist__open(evlist); if (err < 0) { pr_debug("perf_evlist__open: %s\n", - strerror_r(errno, sbuf, sizeof(sbuf))); + str_error_r(errno, sbuf, sizeof(sbuf))); goto out_delete_evlist; } @@ -138,7 +138,7 @@ int test__PERF_RECORD(int subtest __maybe_unused) err = perf_evlist__mmap(evlist, opts.mmap_pages, false); if (err < 0) { pr_debug("perf_evlist__mmap: %s\n", - strerror_r(errno, sbuf, sizeof(sbuf))); + str_error_r(errno, sbuf, sizeof(sbuf))); goto out_delete_evlist; } diff --git a/tools/perf/tests/sw-clock.c b/tools/perf/tests/sw-clock.c index 36e8ce1..4c9fd04 100644 --- a/tools/perf/tests/sw-clock.c +++ b/tools/perf/tests/sw-clock.c @@ -70,7 +70,7 @@ static int __test__sw_clock_freq(enum perf_sw_ids clock_id) err = -errno; pr_debug("Couldn't open evlist: %s\nHint: check %s, using %" PRIu64 " in this test.\n", - strerror_r(errno, sbuf, sizeof(sbuf)), + str_error_r(errno, sbuf, sizeof(sbuf)), knob, (u64)attr.sample_freq); goto out_delete_evlist; } @@ -78,7 +78,7 @@ static int __test__sw_clock_freq(enum perf_sw_ids clock_id) err = perf_evlist__mmap(evlist, 128, true); if (err < 0) { pr_debug("failed to mmap event: %d (%s)\n", errno, - strerror_r(errno, sbuf, sizeof(sbuf))); + str_error_r(errno, sbuf, sizeof(sbuf))); goto out_delete_evlist; } diff --git a/tools/perf/tests/task-exit.c b/tools/perf/tests/task-exit.c index 2dfff7a..01a5ba2 100644 --- a/tools/perf/tests/task-exit.c +++ b/tools/perf/tests/task-exit.c @@ -91,13 +91,13 @@ int test__task_exit(int subtest __maybe_unused) err = perf_evlist__open(evlist); if (err < 0) { pr_debug("Couldn't open the evlist: %s\n", - strerror_r(-err, sbuf, sizeof(sbuf))); + str_error_r(-err, sbuf, sizeof(sbuf))); goto out_delete_evlist; } if (perf_evlist__mmap(evlist, 128, true) < 0) { pr_debug("failed to mmap events: %d (%s)\n", errno, - strerror_r(errno, sbuf, sizeof(sbuf))); + str_error_r(errno, sbuf, sizeof(sbuf))); goto out_delete_evlist; } diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c index e08b8f7..13d4143 100644 --- a/tools/perf/ui/browsers/hists.c +++ b/tools/perf/ui/browsers/hists.c @@ -2029,7 +2029,7 @@ static int hist_browser__dump(struct hist_browser *browser) fp = fopen(filename, "w"); if (fp == NULL) { char bf[64]; - const char *err = strerror_r(errno, bf, sizeof(bf)); + const char *err = str_error_r(errno, bf, sizeof(bf)); ui_helpline__fpush("Couldn't write to %s: %s", filename, err); return -1; } diff --git a/tools/perf/util/Build b/tools/perf/util/Build index fced833..a6a8053 100644 --- a/tools/perf/util/Build +++ b/tools/perf/util/Build @@ -70,6 +70,7 @@ libperf-y += stat.o libperf-y += stat-shadow.o libperf-y += record.o libperf-y += srcline.o +libperf-y += str_error_r.o libperf-y += data.o libperf-y += tsc.o libperf-y += cloexec.o @@ -173,6 +174,10 @@ $(OUTPUT)util/libstring.o: ../lib/string.c FORCE $(call rule_mkdir) $(call if_changed_dep,cc_o_c) +$(OUTPUT)util/str_error_r.o: ../lib/str_error_r.c FORCE + $(call rule_mkdir) + $(call if_changed_dep,cc_o_c) + $(OUTPUT)util/hweight.o: ../lib/hweight.c FORCE $(call rule_mkdir) $(call if_changed_dep,cc_o_c) diff --git a/tools/perf/util/bpf-loader.c b/tools/perf/util/bpf-loader.c index dcc8845..8445e89 100644 --- a/tools/perf/util/bpf-loader.c +++ b/tools/perf/util/bpf-loader.c @@ -1589,7 +1589,7 @@ bpf_loader_strerror(int err, char *buf, size_t size) snprintf(buf, size, "Unknown bpf loader error %d", err); else snprintf(buf, size, "%s", - strerror_r(err, sbuf, sizeof(sbuf))); + str_error_r(err, sbuf, sizeof(sbuf))); buf[size - 1] = '\0'; return -1; diff --git a/tools/perf/util/cloexec.c b/tools/perf/util/cloexec.c index 2babdda..fde772d 100644 --- a/tools/perf/util/cloexec.c +++ b/tools/perf/util/cloexec.c @@ -58,7 +58,7 @@ static int perf_flag_probe(void) WARN_ONCE(err != EINVAL && err != EBUSY, "perf_event_open(..., PERF_FLAG_FD_CLOEXEC) failed with unexpected error %d (%s)\n", - err, strerror_r(err, sbuf, sizeof(sbuf))); + err, str_error_r(err, sbuf, sizeof(sbuf))); /* not supported, confirm error related to PERF_FLAG_FD_CLOEXEC */ while (1) { @@ -76,7 +76,7 @@ static int perf_flag_probe(void) if (WARN_ONCE(fd < 0 && err != EBUSY, "perf_event_open(..., 0) failed unexpectedly with error %d (%s)\n", - err, strerror_r(err, sbuf, sizeof(sbuf)))) + err, str_error_r(err, sbuf, sizeof(sbuf)))) return -1; return 0; diff --git a/tools/perf/util/data.c b/tools/perf/util/data.c index be835161..60bfc9c 100644 --- a/tools/perf/util/data.c +++ b/tools/perf/util/data.c @@ -57,7 +57,7 @@ static int open_file_read(struct perf_data_file *file) int err = errno; pr_err("failed to open %s: %s", file->path, - strerror_r(err, sbuf, sizeof(sbuf))); + str_error_r(err, sbuf, sizeof(sbuf))); if (err == ENOENT && !strcmp(file->path, "perf.data")) pr_err(" (try 'perf record' first)"); pr_err("\n"); @@ -99,7 +99,7 @@ static int open_file_write(struct perf_data_file *file) if (fd < 0) pr_err("failed to open %s : %s\n", file->path, - strerror_r(errno, sbuf, sizeof(sbuf))); + str_error_r(errno, sbuf, sizeof(sbuf))); return fd; } diff --git a/tools/perf/util/debug.h b/tools/perf/util/debug.h index 14bafda..d242adc 100644 --- a/tools/perf/util/debug.h +++ b/tools/perf/util/debug.h @@ -38,7 +38,7 @@ extern int debug_data_convert; #define pr_oe_time(t, fmt, ...) pr_time_N(1, debug_ordered_events, t, pr_fmt(fmt), ##__VA_ARGS__) #define pr_oe_time2(t, fmt, ...) pr_time_N(2, debug_ordered_events, t, pr_fmt(fmt), ##__VA_ARGS__) -#define STRERR_BUFSIZE 128 /* For the buffer size of strerror_r */ +#define STRERR_BUFSIZE 128 /* For the buffer size of str_error_r */ int dump_printf(const char *fmt, ...) __attribute__((format(printf, 1, 2))); void trace_event(union perf_event *event); diff --git a/tools/perf/util/dso.c b/tools/perf/util/dso.c index e1de6cc..774f6ec 100644 --- a/tools/perf/util/dso.c +++ b/tools/perf/util/dso.c @@ -335,7 +335,7 @@ static int do_open(char *name) return fd; pr_debug("dso open failed: %s\n", - strerror_r(errno, sbuf, sizeof(sbuf))); + str_error_r(errno, sbuf, sizeof(sbuf))); if (!dso__data_open_cnt || errno != EMFILE) break; @@ -786,7 +786,7 @@ static int data_file_size(struct dso *dso, struct machine *machine) if (fstat(dso->data.fd, &st) < 0) { ret = -errno; pr_err("dso cache fstat failed: %s\n", - strerror_r(errno, sbuf, sizeof(sbuf))); + str_error_r(errno, sbuf, sizeof(sbuf))); dso->data.status = DSO_DATA_STATUS_ERROR; goto out; } @@ -1366,7 +1366,7 @@ int dso__strerror_load(struct dso *dso, char *buf, size_t buflen) BUG_ON(buflen == 0); if (errnum >= 0) { - const char *err = strerror_r(errnum, buf, buflen); + const char *err = str_error_r(errnum, buf, buflen); if (err != buf) scnprintf(buf, buflen, "%s", err); diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index 1135077..f2d478d 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c @@ -1790,7 +1790,7 @@ int perf_evlist__strerror_open(struct perf_evlist *evlist, int err, char *buf, size_t size) { int printed, value; - char sbuf[STRERR_BUFSIZE], *emsg = strerror_r(err, sbuf, sizeof(sbuf)); + char sbuf[STRERR_BUFSIZE], *emsg = str_error_r(err, sbuf, sizeof(sbuf)); switch (err) { case EACCES: @@ -1842,7 +1842,7 @@ out_default: int perf_evlist__strerror_mmap(struct perf_evlist *evlist, int err, char *buf, size_t size) { - char sbuf[STRERR_BUFSIZE], *emsg = strerror_r(err, sbuf, sizeof(sbuf)); + char sbuf[STRERR_BUFSIZE], *emsg = str_error_r(err, sbuf, sizeof(sbuf)); int pages_attempted = evlist->mmap_len / 1024, pages_max_per_user, printed = 0; switch (err) { diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index 0fea724..d8c2298 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c @@ -2419,7 +2419,7 @@ int perf_evsel__open_strerror(struct perf_evsel *evsel, struct target *target, "The sys_perf_event_open() syscall returned with %d (%s) for event (%s).\n" "/bin/dmesg may provide additional information.\n" "No CONFIG_PERF_EVENTS=y kernel support configured?", - err, strerror_r(err, sbuf, sizeof(sbuf)), + err, str_error_r(err, sbuf, sizeof(sbuf)), perf_evsel__name(evsel)); } diff --git a/tools/perf/util/llvm-utils.c b/tools/perf/util/llvm-utils.c index 40b6f72..282c30f 100644 --- a/tools/perf/util/llvm-utils.c +++ b/tools/perf/util/llvm-utils.c @@ -106,7 +106,7 @@ read_from_pipe(const char *cmd, void **p_buf, size_t *p_read_sz) file = popen(cmd, "r"); if (!file) { pr_err("ERROR: unable to popen cmd: %s\n", - strerror_r(errno, serr, sizeof(serr))); + str_error_r(errno, serr, sizeof(serr))); return -EINVAL; } @@ -140,7 +140,7 @@ read_from_pipe(const char *cmd, void **p_buf, size_t *p_read_sz) if (ferror(file)) { pr_err("ERROR: error occurred when reading from pipe: %s\n", - strerror_r(errno, serr, sizeof(serr))); + str_error_r(errno, serr, sizeof(serr))); err = -EIO; goto errout; } @@ -382,7 +382,7 @@ int llvm__compile_bpf(const char *path, void **p_obj_buf, if (path[0] != '-' && realpath(path, abspath) == NULL) { err = errno; pr_err("ERROR: problems with path %s: %s\n", - path, strerror_r(err, serr, sizeof(serr))); + path, str_error_r(err, serr, sizeof(serr))); return -err; } @@ -410,7 +410,7 @@ int llvm__compile_bpf(const char *path, void **p_obj_buf, if (nr_cpus_avail <= 0) { pr_err( "WARNING:\tunable to get available CPUs in this system: %s\n" -" \tUse 128 instead.\n", strerror_r(errno, serr, sizeof(serr))); +" \tUse 128 instead.\n", str_error_r(errno, serr, sizeof(serr))); nr_cpus_avail = 128; } snprintf(nr_cpus_avail_str, sizeof(nr_cpus_avail_str), "%d", diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c index 0201f66..2b222a7 100644 --- a/tools/perf/util/probe-event.c +++ b/tools/perf/util/probe-event.c @@ -468,7 +468,7 @@ static struct debuginfo *open_debuginfo(const char *module, bool silent) err = kernel_get_module_dso(module, &dso); if (err < 0) { if (!dso || dso->load_errno == 0) { - if (!strerror_r(-err, reason, STRERR_BUFSIZE)) + if (!str_error_r(-err, reason, STRERR_BUFSIZE)) strcpy(reason, "(unknown)"); } else dso__strerror_load(dso, reason, STRERR_BUFSIZE); @@ -806,7 +806,7 @@ static int __show_one_line(FILE *fp, int l, bool skip, bool show_num) error: if (ferror(fp)) { pr_warning("File read error: %s\n", - strerror_r(errno, sbuf, sizeof(sbuf))); + str_error_r(errno, sbuf, sizeof(sbuf))); return -1; } return 0; @@ -886,7 +886,7 @@ static int __show_line_range(struct line_range *lr, const char *module, fp = fopen(lr->path, "r"); if (fp == NULL) { pr_warning("Failed to open %s: %s\n", lr->path, - strerror_r(errno, sbuf, sizeof(sbuf))); + str_error_r(errno, sbuf, sizeof(sbuf))); return -errno; } /* Skip to starting line number */ diff --git a/tools/perf/util/probe-file.c b/tools/perf/util/probe-file.c index 5b563b2..98398b5 100644 --- a/tools/perf/util/probe-file.c +++ b/tools/perf/util/probe-file.c @@ -50,7 +50,7 @@ static void print_open_warning(int err, bool uprobe) else pr_warning("Failed to open %cprobe_events: %s\n", uprobe ? 'u' : 'k', - strerror_r(-err, sbuf, sizeof(sbuf))); + str_error_r(-err, sbuf, sizeof(sbuf))); } static void print_both_open_warning(int kerr, int uerr) @@ -64,9 +64,9 @@ static void print_both_open_warning(int kerr, int uerr) else { char sbuf[STRERR_BUFSIZE]; pr_warning("Failed to open kprobe events: %s.\n", - strerror_r(-kerr, sbuf, sizeof(sbuf))); + str_error_r(-kerr, sbuf, sizeof(sbuf))); pr_warning("Failed to open uprobe events: %s.\n", - strerror_r(-uerr, sbuf, sizeof(sbuf))); + str_error_r(-uerr, sbuf, sizeof(sbuf))); } } @@ -224,7 +224,7 @@ int probe_file__add_event(int fd, struct probe_trace_event *tev) if (write(fd, buf, strlen(buf)) < (int)strlen(buf)) { ret = -errno; pr_warning("Failed to write event: %s\n", - strerror_r(errno, sbuf, sizeof(sbuf))); + str_error_r(errno, sbuf, sizeof(sbuf))); } } free(buf); @@ -262,7 +262,7 @@ static int __del_trace_probe_event(int fd, struct str_node *ent) return 0; error: pr_warning("Failed to delete event: %s\n", - strerror_r(-ret, buf, sizeof(buf))); + str_error_r(-ret, buf, sizeof(buf))); return ret; } diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c index 1259839..f2d9ff0 100644 --- a/tools/perf/util/probe-finder.c +++ b/tools/perf/util/probe-finder.c @@ -381,7 +381,7 @@ formatted: if (ret >= 16) ret = -E2BIG; pr_warning("Failed to convert variable type: %s\n", - strerror_r(-ret, sbuf, sizeof(sbuf))); + str_error_r(-ret, sbuf, sizeof(sbuf))); return ret; } tvar->type = strdup(buf); @@ -809,7 +809,7 @@ static int find_lazy_match_lines(struct intlist *list, fp = fopen(fname, "r"); if (!fp) { pr_warning("Failed to open %s: %s\n", fname, - strerror_r(errno, sbuf, sizeof(sbuf))); + str_error_r(errno, sbuf, sizeof(sbuf))); return -errno; } diff --git a/tools/perf/util/python-ext-sources b/tools/perf/util/python-ext-sources index 36c6862..49210b7 100644 --- a/tools/perf/util/python-ext-sources +++ b/tools/perf/util/python-ext-sources @@ -13,6 +13,7 @@ util/cpumap.c ../lib/bitmap.c ../lib/find_bit.c ../lib/hweight.c +../lib/str_error_r.c util/thread_map.c util/util.c util/xyarray.c diff --git a/tools/perf/util/target.c b/tools/perf/util/target.c index a53603b..5898af4 100644 --- a/tools/perf/util/target.c +++ b/tools/perf/util/target.c @@ -121,7 +121,7 @@ int target__strerror(struct target *target, int errnum, BUG_ON(buflen == 0); if (errnum >= 0) { - const char *err = strerror_r(errnum, buf, buflen); + const char *err = str_error_r(errnum, buf, buflen); if (err != buf) scnprintf(buf, buflen, "%s", err); diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h index 1e8c316..2370cfb 100644 --- a/tools/perf/util/util.h +++ b/tools/perf/util/util.h @@ -360,4 +360,5 @@ typedef void (*print_binary_t)(enum binary_printer_ops, void print_binary(unsigned char *data, size_t len, size_t bytes_per_line, print_binary_t printer, void *extra); + #endif /* GIT_COMPAT_UTIL_H */ -- cgit v0.10.2 From 8a15858904c803450b6763d09f53d9a1dc7ab1c3 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Wed, 6 Jul 2016 12:14:56 -0300 Subject: perf bench: Add missing pthread.h include for CPU_*() macros Cc: David Ahern Cc: Davidlohr Bueso Cc: Hitoshi Mitake Cc: Jiri Olsa Cc: Namhyung Kim Cc: Wang Nan Link: http://lkml.kernel.org/n/tip-48qbfv7tqs8n8ey74lbyfjtq@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/bench/futex-hash.c b/tools/perf/bench/futex-hash.c index 0999ac5..8fc1782 100644 --- a/tools/perf/bench/futex-hash.c +++ b/tools/perf/bench/futex-hash.c @@ -8,8 +8,10 @@ * many threads and futexes as possible. */ +/* For the CLR_() macros */ +#include + #include "../perf.h" -#include "../util/util.h" #include "../util/stat.h" #include #include "../util/header.h" @@ -17,9 +19,7 @@ #include "futex.h" #include -#include #include -#include static unsigned int nthreads = 0; static unsigned int nsecs = 10; diff --git a/tools/perf/bench/futex-lock-pi.c b/tools/perf/bench/futex-lock-pi.c index 6952db6..be95506 100644 --- a/tools/perf/bench/futex-lock-pi.c +++ b/tools/perf/bench/futex-lock-pi.c @@ -2,6 +2,9 @@ * Copyright (C) 2015 Davidlohr Bueso. */ +/* For the CLR_() macros */ +#include + #include "../perf.h" #include "../util/util.h" #include "../util/stat.h" @@ -13,7 +16,6 @@ #include #include #include -#include struct worker { int tid; diff --git a/tools/perf/bench/futex-requeue.c b/tools/perf/bench/futex-requeue.c index 7182386..7d9712c 100644 --- a/tools/perf/bench/futex-requeue.c +++ b/tools/perf/bench/futex-requeue.c @@ -8,6 +8,9 @@ * requeues without waking up any tasks -- thus mimicking a regular futex_wait. */ +/* For the CLR_() macros */ +#include + #include "../perf.h" #include "../util/util.h" #include "../util/stat.h" @@ -19,7 +22,6 @@ #include #include #include -#include static u_int32_t futex1 = 0, futex2 = 0; diff --git a/tools/perf/bench/futex-wake-parallel.c b/tools/perf/bench/futex-wake-parallel.c index 91aaf2a..aca1228 100644 --- a/tools/perf/bench/futex-wake-parallel.c +++ b/tools/perf/bench/futex-wake-parallel.c @@ -7,6 +7,9 @@ * it can be used to measure futex_wake() changes. */ +/* For the CLR_() macros */ +#include + #include "../perf.h" #include "../util/util.h" #include "../util/stat.h" @@ -18,7 +21,6 @@ #include #include #include -#include struct thread_data { pthread_t worker; diff --git a/tools/perf/bench/futex-wake.c b/tools/perf/bench/futex-wake.c index f416bd7..877e680 100644 --- a/tools/perf/bench/futex-wake.c +++ b/tools/perf/bench/futex-wake.c @@ -8,6 +8,9 @@ * one or more tasks, and thus the waitqueue is never empty. */ +/* For the CLR_() macros */ +#include + #include "../perf.h" #include "../util/util.h" #include "../util/stat.h" @@ -19,7 +22,6 @@ #include #include #include -#include /* all threads will block on the same futex */ static u_int32_t futex1 = 0; diff --git a/tools/perf/bench/numa.c b/tools/perf/bench/numa.c index 7500d95..f7f5300 100644 --- a/tools/perf/bench/numa.c +++ b/tools/perf/bench/numa.c @@ -4,6 +4,9 @@ * numa: Simulate NUMA-sensitive workload and measure their NUMA performance */ +/* For the CLR_() macros */ +#include + #include "../perf.h" #include "../builtin.h" #include "../util/util.h" @@ -21,7 +24,6 @@ #include #include #include -#include #include #include #include -- cgit v0.10.2 From 1fbe7df819d9958f139b87014a2f0d5b34da76d5 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Wed, 6 Jul 2016 12:19:19 -0300 Subject: perf tests: Add missing pthread.h include for CPU_*() macros Cc: David Ahern Cc: Jiri Olsa Cc: Namhyung Kim Cc: Wang Nan Link: http://lkml.kernel.org/n/tip-dfcynqzvecsu55zmpxub9jgv@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/tests/mmap-basic.c b/tools/perf/tests/mmap-basic.c index 5c9b931..634bce9 100644 --- a/tools/perf/tests/mmap-basic.c +++ b/tools/perf/tests/mmap-basic.c @@ -1,3 +1,6 @@ +/* For the CLR_() macros */ +#include + #include "evlist.h" #include "evsel.h" #include "thread_map.h" diff --git a/tools/perf/tests/openat-syscall-all-cpus.c b/tools/perf/tests/openat-syscall-all-cpus.c index 265abb1..c8d9592 100644 --- a/tools/perf/tests/openat-syscall-all-cpus.c +++ b/tools/perf/tests/openat-syscall-all-cpus.c @@ -1,3 +1,6 @@ +/* For the CPU_* macros */ +#include + #include #include #include "evsel.h" diff --git a/tools/perf/tests/perf-record.c b/tools/perf/tests/perf-record.c index 3eb67a9..8f2e1de 100644 --- a/tools/perf/tests/perf-record.c +++ b/tools/perf/tests/perf-record.c @@ -1,3 +1,6 @@ +/* For the CLR_() macros */ +#include + #include #include "evlist.h" #include "evsel.h" -- cgit v0.10.2 From 48e1f91ad2cadcb5689a2a3b6ed141d45009b45e Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 5 Jul 2016 14:43:27 -0300 Subject: perf trace: Add conditional define for AT_FDCWD This one was only defined if _GNU_SOURCE was set in older glibc versions, check that and provide the define in such cases. Cc: Adrian Hunter Cc: David Ahern Cc: Jiri Olsa Cc: Namhyung Kim Cc: Wang Nan Link: http://lkml.kernel.org/n/tip-ilsgsysr6s3mru7rf2befnu5@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c index e7e0b6e..570a78c 100644 --- a/tools/perf/builtin-trace.c +++ b/tools/perf/builtin-trace.c @@ -334,6 +334,10 @@ static size_t syscall_arg__scnprintf_fd(char *bf, size_t size, #define SCA_FD syscall_arg__scnprintf_fd +#ifndef AT_FDCWD +#define AT_FDCWD -100 +#endif + static size_t syscall_arg__scnprintf_fd_at(char *bf, size_t size, struct syscall_arg *arg) { -- cgit v0.10.2 From ab6526b2ca2c2c3b383a24b2a0c68c5a8f71b820 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 5 Jul 2016 14:43:27 -0300 Subject: perf tests openat-syscall-tp-fields: Add some conditional defines These were only defined if _GNU_SOURCE was set in older glibc versions, check that and provide the defines in such cases. Cc: Adrian Hunter Cc: David Ahern Cc: Jiri Olsa Cc: Namhyung Kim Cc: Wang Nan Link: http://lkml.kernel.org/n/tip-b8esouhpg4tk6vi4n3d7ipch@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/tests/openat-syscall-tp-fields.c b/tools/perf/tests/openat-syscall-tp-fields.c index 942dbf4..f52239f 100644 --- a/tools/perf/tests/openat-syscall-tp-fields.c +++ b/tools/perf/tests/openat-syscall-tp-fields.c @@ -6,6 +6,13 @@ #include "tests.h" #include "debug.h" +#ifndef O_DIRECTORY +#define O_DIRECTORY 00200000 +#endif +#ifndef AT_FDCWD +#define AT_FDCWD -100 +#endif + int test__syscall_openat_tp_fields(int subtest __maybe_unused) { struct record_opts opts = { -- cgit v0.10.2 From 9c304f6c715f1849bb5b0d450a600dc731a80bda Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 7 Jul 2016 11:01:46 -0300 Subject: perf bench: Disentangle headers We should try avoiding that perf.h header, it includes way too much stuff, making it difficult to use things like setting _GNU_SOURCE only on a small set of headers. Cc: Adrian Hunter Cc: David Ahern Cc: Davidlohr Bueso Cc: Hitoshi Mitake Cc: Jiri Olsa Cc: Namhyung Kim Cc: Wang Nan Link: http://lkml.kernel.org/n/tip-lb6eg9w1kzrwhv0gm3ho0h54@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/bench/futex-hash.c b/tools/perf/bench/futex-hash.c index 8fc1782..caa9726 100644 --- a/tools/perf/bench/futex-hash.c +++ b/tools/perf/bench/futex-hash.c @@ -11,10 +11,14 @@ /* For the CLR_() macros */ #include -#include "../perf.h" +#include +#include +#include +#include +#include + #include "../util/stat.h" #include -#include "../util/header.h" #include "bench.h" #include "futex.h" diff --git a/tools/perf/bench/futex-lock-pi.c b/tools/perf/bench/futex-lock-pi.c index be95506..e2ba0d6 100644 --- a/tools/perf/bench/futex-lock-pi.c +++ b/tools/perf/bench/futex-lock-pi.c @@ -5,11 +5,11 @@ /* For the CLR_() macros */ #include -#include "../perf.h" -#include "../util/util.h" +#include #include "../util/stat.h" #include -#include "../util/header.h" +#include +#include #include "bench.h" #include "futex.h" diff --git a/tools/perf/bench/futex-requeue.c b/tools/perf/bench/futex-requeue.c index 7d9712c..7eceb05 100644 --- a/tools/perf/bench/futex-requeue.c +++ b/tools/perf/bench/futex-requeue.c @@ -11,11 +11,11 @@ /* For the CLR_() macros */ #include -#include "../perf.h" -#include "../util/util.h" +#include #include "../util/stat.h" #include -#include "../util/header.h" +#include +#include #include "bench.h" #include "futex.h" diff --git a/tools/perf/bench/futex-wake-parallel.c b/tools/perf/bench/futex-wake-parallel.c index aca1228..8143b54 100644 --- a/tools/perf/bench/futex-wake-parallel.c +++ b/tools/perf/bench/futex-wake-parallel.c @@ -10,11 +10,11 @@ /* For the CLR_() macros */ #include -#include "../perf.h" -#include "../util/util.h" +#include #include "../util/stat.h" #include -#include "../util/header.h" +#include +#include #include "bench.h" #include "futex.h" diff --git a/tools/perf/bench/futex-wake.c b/tools/perf/bench/futex-wake.c index 877e680..e978d56 100644 --- a/tools/perf/bench/futex-wake.c +++ b/tools/perf/bench/futex-wake.c @@ -11,11 +11,11 @@ /* For the CLR_() macros */ #include -#include "../perf.h" -#include "../util/util.h" +#include #include "../util/stat.h" #include -#include "../util/header.h" +#include +#include #include "bench.h" #include "futex.h" -- cgit v0.10.2 From cec07f53c398f22576df77052c4777dc13f14962 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 7 Jul 2016 18:28:43 -0300 Subject: perf tools: Move syscall number fallbacks from perf-sys.h to tools/arch/x86/include/asm/ And remove the empty tools/arch/x86/include/asm/unistd_{32,64}.h files introduced by eae7a755ee81 ("perf tools, x86: Build perf on older user-space as well"). This way we get closer to mirroring the kernel for cases where __NR_ can't be found for some include path/_GNU_SOURCE/whatever scenario. Cc: Adrian Hunter Cc: David Ahern Cc: Jiri Olsa Cc: Namhyung Kim Cc: Wang Nan Link: http://lkml.kernel.org/n/tip-kpj6m3mbjw82kg6krk2z529e@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/arch/x86/include/asm/unistd_32.h b/tools/arch/x86/include/asm/unistd_32.h new file mode 100644 index 0000000..cf33ab0 --- /dev/null +++ b/tools/arch/x86/include/asm/unistd_32.h @@ -0,0 +1,9 @@ +#ifndef __NR_perf_event_open +# define __NR_perf_event_open 336 +#endif +#ifndef __NR_futex +# define __NR_futex 240 +#endif +#ifndef __NR_gettid +# define __NR_gettid 224 +#endif diff --git a/tools/arch/x86/include/asm/unistd_64.h b/tools/arch/x86/include/asm/unistd_64.h new file mode 100644 index 0000000..2c98356 --- /dev/null +++ b/tools/arch/x86/include/asm/unistd_64.h @@ -0,0 +1,9 @@ +#ifndef __NR_perf_event_open +# define __NR_perf_event_open 298 +#endif +#ifndef __NR_futex +# define __NR_futex 202 +#endif +#ifndef __NR_gettid +# define __NR_gettid 186 +#endif diff --git a/tools/perf/config/Makefile b/tools/perf/config/Makefile index c7e269a..7d2ea69 100644 --- a/tools/perf/config/Makefile +++ b/tools/perf/config/Makefile @@ -209,6 +209,7 @@ CFLAGS += -I$(src-perf)/arch/$(ARCH)/include CFLAGS += -I$(srctree)/tools/include/ CFLAGS += -I$(srctree)/arch/$(ARCH)/include/uapi CFLAGS += -I$(srctree)/arch/$(ARCH)/include +CFLAGS += -I$(srctree)/tools/arch/$(ARCH)/include CFLAGS += -I$(srctree)/include/uapi CFLAGS += -I$(srctree)/include diff --git a/tools/perf/perf-sys.h b/tools/perf/perf-sys.h index 83a25ce..5cee8a3 100644 --- a/tools/perf/perf-sys.h +++ b/tools/perf/perf-sys.h @@ -11,29 +11,11 @@ #if defined(__i386__) #define cpu_relax() asm volatile("rep; nop" ::: "memory"); #define CPUINFO_PROC {"model name"} -#ifndef __NR_perf_event_open -# define __NR_perf_event_open 336 -#endif -#ifndef __NR_futex -# define __NR_futex 240 -#endif -#ifndef __NR_gettid -# define __NR_gettid 224 -#endif #endif #if defined(__x86_64__) #define cpu_relax() asm volatile("rep; nop" ::: "memory"); #define CPUINFO_PROC {"model name"} -#ifndef __NR_perf_event_open -# define __NR_perf_event_open 298 -#endif -#ifndef __NR_futex -# define __NR_futex 202 -#endif -#ifndef __NR_gettid -# define __NR_gettid 186 -#endif #endif #ifdef __powerpc__ diff --git a/tools/perf/util/include/asm/unistd_32.h b/tools/perf/util/include/asm/unistd_32.h deleted file mode 100644 index 8b13789..0000000 --- a/tools/perf/util/include/asm/unistd_32.h +++ /dev/null @@ -1 +0,0 @@ - diff --git a/tools/perf/util/include/asm/unistd_64.h b/tools/perf/util/include/asm/unistd_64.h deleted file mode 100644 index 8b13789..0000000 --- a/tools/perf/util/include/asm/unistd_64.h +++ /dev/null @@ -1 +0,0 @@ - -- cgit v0.10.2 From 7ed0958ae877c0c470b5ff4c26e7ad9f676ef3ed Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 7 Jul 2016 11:06:58 -0300 Subject: perf strbuf: Add missing headers We were only indirectly and by luck getting types, etc needed for this file, fix it. Cc: Adrian Hunter Cc: David Ahern Cc: Jiri Olsa Cc: Namhyung Kim Cc: Wang Nan Link: http://lkml.kernel.org/n/tip-gr8ejvzm7ojk6zwpeplyx9zu@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/util/strbuf.c b/tools/perf/util/strbuf.c index f95f682..81759390 100644 --- a/tools/perf/util/strbuf.c +++ b/tools/perf/util/strbuf.c @@ -1,5 +1,5 @@ #include "debug.h" -#include "cache.h" +#include "util.h" #include int prefixcmp(const char *str, const char *prefix) diff --git a/tools/perf/util/strbuf.h b/tools/perf/util/strbuf.h index 54b4092..b268a66 100644 --- a/tools/perf/util/strbuf.h +++ b/tools/perf/util/strbuf.h @@ -40,6 +40,9 @@ #include #include +#include +#include +#include extern char strbuf_slopbuf[]; struct strbuf { -- cgit v0.10.2 From 380a71a22b5a3270fbcc57ef45b6108941a6852c Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 7 Jul 2016 11:17:38 -0300 Subject: perf quote: Disentangle headers No need to include stdio.h from quote.h, also forward declare strbuf. Cc: Adrian Hunter Cc: David Ahern Cc: Jiri Olsa Cc: Namhyung Kim Cc: Wang Nan Link: http://lkml.kernel.org/n/tip-k3kbcxhctpxvz6ckve3kv6c1@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/util/quote.c b/tools/perf/util/quote.c index c6d4ee2..639d1da 100644 --- a/tools/perf/util/quote.c +++ b/tools/perf/util/quote.c @@ -1,5 +1,7 @@ -#include "cache.h" +#include +#include "strbuf.h" #include "quote.h" +#include "util.h" /* Help to copy the thing properly quoted for the shell safety. * any single quote is replaced with '\'', any exclamation point diff --git a/tools/perf/util/quote.h b/tools/perf/util/quote.h index e1ec191..055ca45 100644 --- a/tools/perf/util/quote.h +++ b/tools/perf/util/quote.h @@ -2,7 +2,6 @@ #define __PERF_QUOTE_H #include -#include /* Help to copy the thing properly quoted for the shell safety. * any single quote is replaced with '\'', any exclamation point @@ -24,6 +23,8 @@ * sq_quote() in a real application. */ +struct strbuf; + int sq_quote_argv(struct strbuf *, const char **argv, size_t maxlen); #endif /* __PERF_QUOTE_H */ -- cgit v0.10.2 From 3ac55b1df0a7c5fb92890b23a620165b82f45c8a Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 7 Jul 2016 11:32:29 -0300 Subject: perf tests cpumap: Add missing headers It was getting all sort of needed stuff by sheer luck, via indirect includes, fix it. Cc: Adrian Hunter Cc: David Ahern Cc: Jiri Olsa Cc: Namhyung Kim Cc: Wang Nan Link: http://lkml.kernel.org/n/tip-tvjgo39t8k0ye6dntv3knran@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/tests/cpumap.c b/tools/perf/tests/cpumap.c index c9ec5f8..f168a85 100644 --- a/tools/perf/tests/cpumap.c +++ b/tools/perf/tests/cpumap.c @@ -1,5 +1,12 @@ #include "tests.h" +#include #include "cpumap.h" +#include "event.h" +#include +#include +#include "debug.h" + +struct machine; static int process_event_mask(struct perf_tool *tool __maybe_unused, union perf_event *event, -- cgit v0.10.2 From 16b91d5ed4d81483001822ade3c9ea8d50628b0b Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 7 Jul 2016 11:35:04 -0300 Subject: perf test fdarray: Add missing poll.h header It uses poll() but was getting the needed header by chance, do it explicitely. Cc: Adrian Hunter Cc: David Ahern Cc: Jiri Olsa Cc: Namhyung Kim Cc: Wang Nan Link: http://lkml.kernel.org/n/tip-76b3c5imnl6p69j4lqewzu9l@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/tests/fdarray.c b/tools/perf/tests/fdarray.c index 59dbd05..a2b5ff9 100644 --- a/tools/perf/tests/fdarray.c +++ b/tools/perf/tests/fdarray.c @@ -1,4 +1,5 @@ #include +#include #include "util/debug.h" #include "tests/tests.h" -- cgit v0.10.2 From 10ca87fde70d9e7b25e576c491823915c80fa9f6 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 7 Jul 2016 11:35:50 -0300 Subject: perf tests x86 rdpmc: Add missing headers Another case of a file using definitions and getting them by chance, from indirect header inclusion, fix it. Cc: Adrian Hunter Cc: David Ahern Cc: Jiri Olsa Cc: Namhyung Kim Cc: Wang Nan Link: http://lkml.kernel.org/n/tip-o3l1vi4gw2w6xyc6z4ig938s@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/arch/x86/tests/rdpmc.c b/tools/perf/arch/x86/tests/rdpmc.c index a32d72e..500cf96 100644 --- a/tools/perf/arch/x86/tests/rdpmc.c +++ b/tools/perf/arch/x86/tests/rdpmc.c @@ -1,12 +1,16 @@ +#include #include #include #include #include +#include +#include #include #include "perf.h" #include "debug.h" #include "tests/tests.h" #include "cloexec.h" +#include "util.h" #include "arch-tests.h" static u64 rdpmc(unsigned int counter) -- cgit v0.10.2 From 16b7c9bda52a593fb3a7e3a9848d7596777a73f5 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 7 Jul 2016 11:37:08 -0300 Subject: perf tools: Add missing header to color.c It uses isatty(), so needs unistd.h, include it. Cc: Adrian Hunter Cc: David Ahern Cc: Jiri Olsa Cc: Namhyung Kim Cc: Wang Nan Link: http://lkml.kernel.org/n/tip-ivwuz8f68tb3sdcpguo9wmvx@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/util/color.c b/tools/perf/util/color.c index 1210ba5..47a34b5 100644 --- a/tools/perf/util/color.c +++ b/tools/perf/util/color.c @@ -3,6 +3,7 @@ #include "config.h" #include "color.h" #include +#include int perf_use_color_default = -1; -- cgit v0.10.2 From 175729fc2c5144e9eee06b3483c5c9798f7062a5 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 7 Jul 2016 11:38:09 -0300 Subject: perf tools: Remove needless includes from cache.h The cache.h header doesn't use any of the definitions in some of the headers it includes, ditch them and fix the fallout, where files were getting stuff they needed just because they were including it, sometimes not using what it really exports at all. Cc: Adrian Hunter Cc: David Ahern Cc: Jiri Olsa Cc: Namhyung Kim Cc: Wang Nan Link: http://lkml.kernel.org/n/tip-l6r2bmj8h1g3e01wr981on0n@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/arch/common.c b/tools/perf/arch/common.c index ee69668..886dd2a 100644 --- a/tools/perf/arch/common.c +++ b/tools/perf/arch/common.c @@ -1,6 +1,7 @@ #include #include #include "common.h" +#include "../util/util.h" #include "../util/debug.h" const char *const arm_triplets[] = { diff --git a/tools/perf/tests/llvm.c b/tools/perf/tests/llvm.c index cff564f..b798a4b 100644 --- a/tools/perf/tests/llvm.c +++ b/tools/perf/tests/llvm.c @@ -5,6 +5,7 @@ #include "llvm.h" #include "tests.h" #include "debug.h" +#include "util.h" #ifdef HAVE_LIBBPF_SUPPORT static int test__bpf_parsing(void *obj_buf, size_t obj_buf_sz) diff --git a/tools/perf/ui/gtk/util.c b/tools/perf/ui/gtk/util.c index 52e7fc4..00b9192 100644 --- a/tools/perf/ui/gtk/util.c +++ b/tools/perf/ui/gtk/util.c @@ -1,4 +1,5 @@ #include "../util.h" +#include "../../util/util.h" #include "../../util/debug.h" #include "gtk.h" diff --git a/tools/perf/ui/helpline.c b/tools/perf/ui/helpline.c index 700fb3c..5b74a7e 100644 --- a/tools/perf/ui/helpline.c +++ b/tools/perf/ui/helpline.c @@ -5,6 +5,7 @@ #include "../debug.h" #include "helpline.h" #include "ui.h" +#include "../util.h" char ui_helpline__current[512]; diff --git a/tools/perf/ui/tui/setup.c b/tools/perf/ui/tui/setup.c index 7dfeba0..4ea2ba8 100644 --- a/tools/perf/ui/tui/setup.c +++ b/tools/perf/ui/tui/setup.c @@ -1,3 +1,4 @@ +#include #include #include #ifdef HAVE_BACKTRACE_SUPPORT @@ -6,6 +7,7 @@ #include "../../util/cache.h" #include "../../util/debug.h" +#include "../../util/util.h" #include "../browser.h" #include "../helpline.h" #include "../ui.h" diff --git a/tools/perf/util/alias.c b/tools/perf/util/alias.c index 6c80f83..6455471 100644 --- a/tools/perf/util/alias.c +++ b/tools/perf/util/alias.c @@ -1,4 +1,5 @@ #include "cache.h" +#include "util.h" #include "config.h" static const char *alias_key; diff --git a/tools/perf/util/cache.h b/tools/perf/util/cache.h index 9f90e36..512c0c8 100644 --- a/tools/perf/util/cache.h +++ b/tools/perf/util/cache.h @@ -1,11 +1,8 @@ #ifndef __PERF_CACHE_H #define __PERF_CACHE_H -#include -#include "util.h" #include "strbuf.h" #include -#include "../perf.h" #include "../ui/ui.h" #include diff --git a/tools/perf/util/levenshtein.c b/tools/perf/util/levenshtein.c index e521d15..f616e4f 100644 --- a/tools/perf/util/levenshtein.c +++ b/tools/perf/util/levenshtein.c @@ -1,5 +1,7 @@ -#include "cache.h" #include "levenshtein.h" +#include +#include +#include /* * This function implements the Damerau-Levenshtein algorithm to diff --git a/tools/perf/util/llvm-utils.c b/tools/perf/util/llvm-utils.c index 282c30f..bf7216b 100644 --- a/tools/perf/util/llvm-utils.c +++ b/tools/perf/util/llvm-utils.c @@ -3,12 +3,14 @@ * Copyright (C) 2015, Huawei Inc. */ +#include #include #include #include #include "debug.h" #include "llvm-utils.h" #include "config.h" +#include "util.h" #define CLANG_BPF_CMD_DEFAULT_TEMPLATE \ "$CLANG_EXEC -D__KERNEL__ -D__NR_CPUS__=$NR_CPUS "\ diff --git a/tools/perf/util/path.c b/tools/perf/util/path.c index cff8bf0..7c7630b 100644 --- a/tools/perf/util/path.c +++ b/tools/perf/util/path.c @@ -11,6 +11,8 @@ * which is what it's designed for. */ #include "cache.h" +#include "util.h" +#include static char bad_path[] = "/bad-path/"; /* diff --git a/tools/perf/util/target.c b/tools/perf/util/target.c index 5898af4..8cdcf46 100644 --- a/tools/perf/util/target.c +++ b/tools/perf/util/target.c @@ -7,6 +7,7 @@ */ #include "target.h" +#include "util.h" #include "debug.h" #include -- cgit v0.10.2 From 5496bc0c0d255f2a8a3a4c36087eb3b72ff63ea0 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 7 Jul 2016 11:51:47 -0300 Subject: perf evsel: Uninline the is_function_event method So that we don't have to carry a string.h header in evsel.h Cc: Adrian Hunter Cc: David Ahern Cc: Jiri Olsa Cc: Namhyung Kim Cc: Wang Nan Link: http://lkml.kernel.org/n/tip-2lwpm2aytdvvgo626zuat6et@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index d8c2298..ba0f59f 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c @@ -200,6 +200,24 @@ void perf_evsel__set_sample_id(struct perf_evsel *evsel, evsel->attr.read_format |= PERF_FORMAT_ID; } +/** + * perf_evsel__is_function_event - Return whether given evsel is a function + * trace event + * + * @evsel - evsel selector to be tested + * + * Return %true if event is function trace event + */ +bool perf_evsel__is_function_event(struct perf_evsel *evsel) +{ +#define FUNCTION_EVENT "ftrace:function" + + return evsel->name && + !strncmp(FUNCTION_EVENT, evsel->name, sizeof(FUNCTION_EVENT)); + +#undef FUNCTION_EVENT +} + void perf_evsel__init(struct perf_evsel *evsel, struct perf_event_attr *attr, int idx) { diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h index 86fed7a..d73391e 100644 --- a/tools/perf/util/evsel.h +++ b/tools/perf/util/evsel.h @@ -355,23 +355,7 @@ static inline bool perf_evsel__is_group_event(struct perf_evsel *evsel) return perf_evsel__is_group_leader(evsel) && evsel->nr_members > 1; } -/** - * perf_evsel__is_function_event - Return whether given evsel is a function - * trace event - * - * @evsel - evsel selector to be tested - * - * Return %true if event is function trace event - */ -static inline bool perf_evsel__is_function_event(struct perf_evsel *evsel) -{ -#define FUNCTION_EVENT "ftrace:function" - - return evsel->name && - !strncmp(FUNCTION_EVENT, evsel->name, sizeof(FUNCTION_EVENT)); - -#undef FUNCTION_EVENT -} +bool perf_evsel__is_function_event(struct perf_evsel *evsel); static inline bool perf_evsel__is_bpf_output(struct perf_evsel *evsel) { -- cgit v0.10.2 From d0761e37fe3fed7810ed8d6e130b79359f0c3e13 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 7 Jul 2016 15:42:33 -0300 Subject: perf tools: Uninline scnprintf() and vscnprint() They were in tools/include/linux/kernel.h, requiring that it in turn included stdio.h, which is way too heavy. Cc: Adrian Hunter Cc: David Ahern Cc: Jiri Olsa Cc: Josh Poimboeuf Cc: Namhyung Kim Cc: Wang Nan Link: http://lkml.kernel.org/n/tip-855h8olnkot9v0dajuee1lo3@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/include/linux/kernel.h b/tools/include/linux/kernel.h index 76df535..28607db 100644 --- a/tools/include/linux/kernel.h +++ b/tools/include/linux/kernel.h @@ -2,8 +2,7 @@ #define __TOOLS_LINUX_KERNEL_H #include -#include -#include +#include #include #define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d)) @@ -70,29 +69,8 @@ #define cpu_to_le64(x) (x) #define cpu_to_le32(x) (x) -static inline int -vscnprintf(char *buf, size_t size, const char *fmt, va_list args) -{ - int i; - ssize_t ssize = size; - - i = vsnprintf(buf, size, fmt, args); - - return (i >= ssize) ? (ssize - 1) : i; -} - -static inline int scnprintf(char * buf, size_t size, const char * fmt, ...) -{ - va_list args; - ssize_t ssize = size; - int i; - - va_start(args, fmt); - i = vsnprintf(buf, size, fmt, args); - va_end(args); - - return (i >= ssize) ? (ssize - 1) : i; -} +int vscnprintf(char *buf, size_t size, const char *fmt, va_list args); +int scnprintf(char * buf, size_t size, const char * fmt, ...); /* * This looks more complex than it should be. But we need to diff --git a/tools/lib/vsprintf.c b/tools/lib/vsprintf.c new file mode 100644 index 0000000..45f9a06 --- /dev/null +++ b/tools/lib/vsprintf.c @@ -0,0 +1,24 @@ +#include +#include +#include + +int vscnprintf(char *buf, size_t size, const char *fmt, va_list args) +{ + int i = vsnprintf(buf, size, fmt, args); + ssize_t ssize = size; + + return (i >= ssize) ? (ssize - 1) : i; +} + +int scnprintf(char * buf, size_t size, const char * fmt, ...) +{ + ssize_t ssize = size; + va_list args; + int i; + + va_start(args, fmt); + i = vsnprintf(buf, size, fmt, args); + va_end(args); + + return (i >= ssize) ? (ssize - 1) : i; +} diff --git a/tools/objtool/builtin-check.c b/tools/objtool/builtin-check.c index e8a1e69..92d84b2 100644 --- a/tools/objtool/builtin-check.c +++ b/tools/objtool/builtin-check.c @@ -26,6 +26,7 @@ */ #include +#include #include #include "builtin.h" diff --git a/tools/perf/MANIFEST b/tools/perf/MANIFEST index f18e781..2bd8c31 100644 --- a/tools/perf/MANIFEST +++ b/tools/perf/MANIFEST @@ -30,6 +30,7 @@ tools/lib/symbol/kallsyms.h tools/lib/find_bit.c tools/lib/bitmap.c tools/lib/str_error_r.c +tools/lib/vsprintf.c tools/include/asm/atomic.h tools/include/asm/barrier.h tools/include/asm/bug.h diff --git a/tools/perf/util/Build b/tools/perf/util/Build index a6a8053..eda68f5 100644 --- a/tools/perf/util/Build +++ b/tools/perf/util/Build @@ -85,6 +85,7 @@ libperf-y += parse-regs-options.o libperf-y += term.o libperf-y += help-unknown-cmd.o libperf-y += mem-events.o +libperf-y += vsprintf.o libperf-$(CONFIG_LIBBPF) += bpf-loader.o libperf-$(CONFIG_BPF_PROLOGUE) += bpf-prologue.o @@ -181,3 +182,7 @@ $(OUTPUT)util/str_error_r.o: ../lib/str_error_r.c FORCE $(OUTPUT)util/hweight.o: ../lib/hweight.c FORCE $(call rule_mkdir) $(call if_changed_dep,cc_o_c) + +$(OUTPUT)util/vsprintf.o: ../lib/vsprintf.c FORCE + $(call rule_mkdir) + $(call if_changed_dep,cc_o_c) diff --git a/tools/perf/util/color.c b/tools/perf/util/color.c index 47a34b5..dbbf89b 100644 --- a/tools/perf/util/color.c +++ b/tools/perf/util/color.c @@ -1,6 +1,8 @@ #include #include "cache.h" #include "config.h" +#include +#include #include "color.h" #include #include diff --git a/tools/perf/util/dso.h b/tools/perf/util/dso.h index a571f24..ecc4bbd 100644 --- a/tools/perf/util/dso.h +++ b/tools/perf/util/dso.h @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include diff --git a/tools/perf/util/help-unknown-cmd.c b/tools/perf/util/help-unknown-cmd.c index 776e285..2821f8d 100644 --- a/tools/perf/util/help-unknown-cmd.c +++ b/tools/perf/util/help-unknown-cmd.c @@ -1,5 +1,6 @@ #include "cache.h" #include "config.h" +#include #include #include "../builtin.h" #include "levenshtein.h" diff --git a/tools/perf/util/python-ext-sources b/tools/perf/util/python-ext-sources index 49210b7..5065ec9 100644 --- a/tools/perf/util/python-ext-sources +++ b/tools/perf/util/python-ext-sources @@ -14,6 +14,7 @@ util/cpumap.c ../lib/find_bit.c ../lib/hweight.c ../lib/str_error_r.c +../lib/vsprintf.c util/thread_map.c util/util.c util/xyarray.c -- cgit v0.10.2 From c3cec9e68f12d0046f991378391172958b5315d9 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 8 Jul 2016 15:21:37 -0300 Subject: tools lib traceevent: Use str_error_r() To make it portable to non-glibc systems, that follow the XSI variant instead of the GNU specific one that gets in place when _GNU_SOURCE is defined. Cc: Adrian Hunter Cc: David Ahern Cc: Jiri Olsa Cc: Namhyung Kim Cc: Steven Rostedt Cc: Wang Nan Link: http://lkml.kernel.org/n/tip-c1gn8x978qfop65m510wy43o@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/lib/traceevent/event-parse.c b/tools/lib/traceevent/event-parse.c index a8b6357..3a7bd17 100644 --- a/tools/lib/traceevent/event-parse.c +++ b/tools/lib/traceevent/event-parse.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include "event-parse.h" @@ -6131,12 +6132,7 @@ int pevent_strerror(struct pevent *pevent __maybe_unused, const char *msg; if (errnum >= 0) { - msg = strerror_r(errnum, buf, buflen); - if (msg != buf) { - size_t len = strlen(msg); - memcpy(buf, msg, min(buflen - 1, len)); - *(buf + min(buflen - 1, len)) = '\0'; - } + str_error_r(errnum, buf, buflen); return 0; } -- cgit v0.10.2 From b31e3e3316a78e4a2cf23be8e0d47e5e5a025bde Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 8 Jul 2016 15:26:50 -0300 Subject: tools lib api fs: Use str_error_r() To make it portable to non-glibc systems, that follow the XSI variant instead of the GNU specific one that gets in place when _GNU_SOURCE is defined. Cc: Adrian Hunter Cc: David Ahern Cc: Jiri Olsa Cc: Namhyung Kim Cc: Steven Rostedt Cc: Wang Nan Link: http://lkml.kernel.org/n/tip-mixgnh3iyajuqogn2opsocdy@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/lib/api/Makefile b/tools/lib/api/Makefile index c7ceea6..0a6fda9 100644 --- a/tools/lib/api/Makefile +++ b/tools/lib/api/Makefile @@ -26,6 +26,7 @@ endif CFLAGS += -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 CFLAGS += -I$(srctree)/tools/lib/api +CFLAGS += -I$(srctree)/tools/include RM = rm -f diff --git a/tools/lib/api/fs/tracing_path.c b/tools/lib/api/fs/tracing_path.c index a26bb5e..251b7c3 100644 --- a/tools/lib/api/fs/tracing_path.c +++ b/tools/lib/api/fs/tracing_path.c @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include "fs.h" @@ -118,7 +119,7 @@ static int strerror_open(int err, char *buf, size_t size, const char *filename) } break; default: - snprintf(buf, size, "%s", strerror_r(err, sbuf, sizeof(sbuf))); + snprintf(buf, size, "%s", str_error_r(err, sbuf, sizeof(sbuf))); break; } -- cgit v0.10.2 From 61a6445e463a3152590352d8634131955f531c6e Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 8 Jul 2016 15:38:51 -0300 Subject: tools lib: Guard the strlcpy() header with __GLIBC__ Better to whitelist it for libraries that require it (glibc) than blacklist it with the ones that don't (uclibc, musl libc, etc). Cc: Adrian Hunter Cc: Alexey Brodkin Cc: David Ahern Cc: Jiri Olsa Cc: Namhyung Kim Cc: Vineet Gupta Cc: Wang Nan Link: http://lkml.kernel.org/n/tip-52ih0m63a2n63tanpy6yj682@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/include/linux/string.h b/tools/include/linux/string.h index b466d02..b968794 100644 --- a/tools/include/linux/string.h +++ b/tools/include/linux/string.h @@ -8,7 +8,7 @@ void *memdup(const void *src, size_t len); int strtobool(const char *s, bool *res); -#ifndef __UCLIBC__ +#ifdef __GLIBC__ extern size_t strlcpy(char *dest, const char *src, size_t size); #endif -- cgit v0.10.2 From 07eebccbca2c21f32b5142f1a55b3b6818c54116 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 8 Jul 2016 15:26:50 -0300 Subject: tools lib subcmd: Use str_error_r() To make it portable to non-glibc systems, that follow the XSI variant instead of the GNU specific one that gets in place when _GNU_SOURCE is defined. Cc: Adrian Hunter Cc: David Ahern Cc: Jiri Olsa Cc: Josh Poimboeuf Cc: Namhyung Kim Cc: Steven Rostedt Cc: Wang Nan Link: http://lkml.kernel.org/n/tip-bozcszy93tpgw9ad6qm3dhpx@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/lib/subcmd/run-command.c b/tools/lib/subcmd/run-command.c index f4f6c9e..911f839 100644 --- a/tools/lib/subcmd/run-command.c +++ b/tools/lib/subcmd/run-command.c @@ -3,6 +3,7 @@ #include #include #include +#include #include #include #include "subcmd-util.h" @@ -109,7 +110,7 @@ int start_command(struct child_process *cmd) if (cmd->dir && chdir(cmd->dir)) die("exec %s: cd to %s failed (%s)", cmd->argv[0], - cmd->dir, strerror_r(errno, sbuf, sizeof(sbuf))); + cmd->dir, str_error_r(errno, sbuf, sizeof(sbuf))); if (cmd->env) { for (; *cmd->env; cmd->env++) { if (strchr(*cmd->env, '=')) @@ -173,7 +174,7 @@ static int wait_or_whine(pid_t pid) if (errno == EINTR) continue; fprintf(stderr, " Error: waitpid failed (%s)", - strerror_r(errno, sbuf, sizeof(sbuf))); + str_error_r(errno, sbuf, sizeof(sbuf))); return -ERR_RUN_COMMAND_WAITPID; } if (waiting != pid) diff --git a/tools/objtool/Build b/tools/objtool/Build index 0e89258..2457916 100644 --- a/tools/objtool/Build +++ b/tools/objtool/Build @@ -5,9 +5,14 @@ objtool-y += special.o objtool-y += objtool.o objtool-y += libstring.o +objtool-y += str_error_r.o CFLAGS += -I$(srctree)/tools/lib $(OUTPUT)libstring.o: ../lib/string.c FORCE $(call rule_mkdir) $(call if_changed_dep,cc_o_c) + +$(OUTPUT)str_error_r.o: ../lib/str_error_r.c FORCE + $(call rule_mkdir) + $(call if_changed_dep,cc_o_c) -- cgit v0.10.2 From 86695f59c952031e5596f286773d76268f3e3aad Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Mon, 11 Jul 2016 10:05:52 -0300 Subject: perf bench futex: Add missing compiler.h header Since these files use __maybe_unused, and that is defined in linux/compiler.h, include it. Cc: Adrian Hunter Cc: David Ahern Cc: Davidlohr Bueso Cc: Hitoshi Mitake Cc: Jiri Olsa Cc: Namhyung Kim Cc: Wang Nan Link: http://lkml.kernel.org/n/tip-1llbf59ut6xon6ti88jm0n9j@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/bench/futex-hash.c b/tools/perf/bench/futex-hash.c index caa9726..8024cd5 100644 --- a/tools/perf/bench/futex-hash.c +++ b/tools/perf/bench/futex-hash.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include diff --git a/tools/perf/bench/futex-lock-pi.c b/tools/perf/bench/futex-lock-pi.c index e2ba0d6..936d89d 100644 --- a/tools/perf/bench/futex-lock-pi.c +++ b/tools/perf/bench/futex-lock-pi.c @@ -8,6 +8,7 @@ #include #include "../util/stat.h" #include +#include #include #include #include "bench.h" diff --git a/tools/perf/bench/futex-requeue.c b/tools/perf/bench/futex-requeue.c index 7eceb05..f96e22e 100644 --- a/tools/perf/bench/futex-requeue.c +++ b/tools/perf/bench/futex-requeue.c @@ -14,6 +14,7 @@ #include #include "../util/stat.h" #include +#include #include #include #include "bench.h" diff --git a/tools/perf/bench/futex-wake-parallel.c b/tools/perf/bench/futex-wake-parallel.c index 8143b54..4a2ecd7 100644 --- a/tools/perf/bench/futex-wake-parallel.c +++ b/tools/perf/bench/futex-wake-parallel.c @@ -13,6 +13,7 @@ #include #include "../util/stat.h" #include +#include #include #include #include "bench.h" diff --git a/tools/perf/bench/futex-wake.c b/tools/perf/bench/futex-wake.c index e978d56..87d8f4f 100644 --- a/tools/perf/bench/futex-wake.c +++ b/tools/perf/bench/futex-wake.c @@ -14,6 +14,7 @@ #include #include "../util/stat.h" #include +#include #include #include #include "bench.h" -- cgit v0.10.2 From e083a21fcac9311ca425e600a15332f4792c56cc Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Mon, 11 Jul 2016 10:14:08 -0300 Subject: perf tools: event.h needs asm/perf_regs.h As it uses PERF_REGS_MAX, fix it. Cc: Adrian Hunter Cc: David Ahern Cc: Jiri Olsa Cc: Namhyung Kim Cc: Wang Nan Link: http://lkml.kernel.org/n/tip-2t232w0kcqu97xod8t2at2h0@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h index 8d363d5..b32464b 100644 --- a/tools/perf/util/event.h +++ b/tools/perf/util/event.h @@ -8,6 +8,7 @@ #include "map.h" #include "build-id.h" #include "perf_regs.h" +#include struct mmap_event { struct perf_event_header header; -- cgit v0.10.2 From c4b6014e8bb0c8d47fe5c71ebc604f31091e5d3f Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Mon, 11 Jul 2016 10:28:48 -0300 Subject: tools: Add copy of perf_event.h to tools/include/linux/ We shouldn't use headers from the kernel sources directly, instead we should use the system's headers or in cases where that isn't possible, like with perf_event.h, where the introduction of kernel features such as perf_event_attr.{write_backwards,sample_max_stack} and PERF_EVENT_IOC_PAUSE_OUTPUT take some time to become available in /usr/include/linux/perf_event.h we need a copy. Do it and check for source code drift, emitting a warning when changes are detected. Cc: Adrian Hunter Cc: David Ahern Cc: Jiri Olsa Cc: Namhyung Kim Cc: Wang Nan Link: http://lkml.kernel.org/n/tip-v6aks5un3s5pehory6f42nrl@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/include/uapi/linux/perf_event.h b/tools/include/uapi/linux/perf_event.h new file mode 100644 index 0000000..c66a485 --- /dev/null +++ b/tools/include/uapi/linux/perf_event.h @@ -0,0 +1,983 @@ +/* + * Performance events: + * + * Copyright (C) 2008-2009, Thomas Gleixner + * Copyright (C) 2008-2011, Red Hat, Inc., Ingo Molnar + * Copyright (C) 2008-2011, Red Hat, Inc., Peter Zijlstra + * + * Data type definitions, declarations, prototypes. + * + * Started by: Thomas Gleixner and Ingo Molnar + * + * For licencing details see kernel-base/COPYING + */ +#ifndef _UAPI_LINUX_PERF_EVENT_H +#define _UAPI_LINUX_PERF_EVENT_H + +#include +#include +#include + +/* + * User-space ABI bits: + */ + +/* + * attr.type + */ +enum perf_type_id { + PERF_TYPE_HARDWARE = 0, + PERF_TYPE_SOFTWARE = 1, + PERF_TYPE_TRACEPOINT = 2, + PERF_TYPE_HW_CACHE = 3, + PERF_TYPE_RAW = 4, + PERF_TYPE_BREAKPOINT = 5, + + PERF_TYPE_MAX, /* non-ABI */ +}; + +/* + * Generalized performance event event_id types, used by the + * attr.event_id parameter of the sys_perf_event_open() + * syscall: + */ +enum perf_hw_id { + /* + * Common hardware events, generalized by the kernel: + */ + PERF_COUNT_HW_CPU_CYCLES = 0, + PERF_COUNT_HW_INSTRUCTIONS = 1, + PERF_COUNT_HW_CACHE_REFERENCES = 2, + PERF_COUNT_HW_CACHE_MISSES = 3, + PERF_COUNT_HW_BRANCH_INSTRUCTIONS = 4, + PERF_COUNT_HW_BRANCH_MISSES = 5, + PERF_COUNT_HW_BUS_CYCLES = 6, + PERF_COUNT_HW_STALLED_CYCLES_FRONTEND = 7, + PERF_COUNT_HW_STALLED_CYCLES_BACKEND = 8, + PERF_COUNT_HW_REF_CPU_CYCLES = 9, + + PERF_COUNT_HW_MAX, /* non-ABI */ +}; + +/* + * Generalized hardware cache events: + * + * { L1-D, L1-I, LLC, ITLB, DTLB, BPU, NODE } x + * { read, write, prefetch } x + * { accesses, misses } + */ +enum perf_hw_cache_id { + PERF_COUNT_HW_CACHE_L1D = 0, + PERF_COUNT_HW_CACHE_L1I = 1, + PERF_COUNT_HW_CACHE_LL = 2, + PERF_COUNT_HW_CACHE_DTLB = 3, + PERF_COUNT_HW_CACHE_ITLB = 4, + PERF_COUNT_HW_CACHE_BPU = 5, + PERF_COUNT_HW_CACHE_NODE = 6, + + PERF_COUNT_HW_CACHE_MAX, /* non-ABI */ +}; + +enum perf_hw_cache_op_id { + PERF_COUNT_HW_CACHE_OP_READ = 0, + PERF_COUNT_HW_CACHE_OP_WRITE = 1, + PERF_COUNT_HW_CACHE_OP_PREFETCH = 2, + + PERF_COUNT_HW_CACHE_OP_MAX, /* non-ABI */ +}; + +enum perf_hw_cache_op_result_id { + PERF_COUNT_HW_CACHE_RESULT_ACCESS = 0, + PERF_COUNT_HW_CACHE_RESULT_MISS = 1, + + PERF_COUNT_HW_CACHE_RESULT_MAX, /* non-ABI */ +}; + +/* + * Special "software" events provided by the kernel, even if the hardware + * does not support performance events. These events measure various + * physical and sw events of the kernel (and allow the profiling of them as + * well): + */ +enum perf_sw_ids { + PERF_COUNT_SW_CPU_CLOCK = 0, + PERF_COUNT_SW_TASK_CLOCK = 1, + PERF_COUNT_SW_PAGE_FAULTS = 2, + PERF_COUNT_SW_CONTEXT_SWITCHES = 3, + PERF_COUNT_SW_CPU_MIGRATIONS = 4, + PERF_COUNT_SW_PAGE_FAULTS_MIN = 5, + PERF_COUNT_SW_PAGE_FAULTS_MAJ = 6, + PERF_COUNT_SW_ALIGNMENT_FAULTS = 7, + PERF_COUNT_SW_EMULATION_FAULTS = 8, + PERF_COUNT_SW_DUMMY = 9, + PERF_COUNT_SW_BPF_OUTPUT = 10, + + PERF_COUNT_SW_MAX, /* non-ABI */ +}; + +/* + * Bits that can be set in attr.sample_type to request information + * in the overflow packets. + */ +enum perf_event_sample_format { + PERF_SAMPLE_IP = 1U << 0, + PERF_SAMPLE_TID = 1U << 1, + PERF_SAMPLE_TIME = 1U << 2, + PERF_SAMPLE_ADDR = 1U << 3, + PERF_SAMPLE_READ = 1U << 4, + PERF_SAMPLE_CALLCHAIN = 1U << 5, + PERF_SAMPLE_ID = 1U << 6, + PERF_SAMPLE_CPU = 1U << 7, + PERF_SAMPLE_PERIOD = 1U << 8, + PERF_SAMPLE_STREAM_ID = 1U << 9, + PERF_SAMPLE_RAW = 1U << 10, + PERF_SAMPLE_BRANCH_STACK = 1U << 11, + PERF_SAMPLE_REGS_USER = 1U << 12, + PERF_SAMPLE_STACK_USER = 1U << 13, + PERF_SAMPLE_WEIGHT = 1U << 14, + PERF_SAMPLE_DATA_SRC = 1U << 15, + PERF_SAMPLE_IDENTIFIER = 1U << 16, + PERF_SAMPLE_TRANSACTION = 1U << 17, + PERF_SAMPLE_REGS_INTR = 1U << 18, + + PERF_SAMPLE_MAX = 1U << 19, /* non-ABI */ +}; + +/* + * values to program into branch_sample_type when PERF_SAMPLE_BRANCH is set + * + * If the user does not pass priv level information via branch_sample_type, + * the kernel uses the event's priv level. Branch and event priv levels do + * not have to match. Branch priv level is checked for permissions. + * + * The branch types can be combined, however BRANCH_ANY covers all types + * of branches and therefore it supersedes all the other types. + */ +enum perf_branch_sample_type_shift { + PERF_SAMPLE_BRANCH_USER_SHIFT = 0, /* user branches */ + PERF_SAMPLE_BRANCH_KERNEL_SHIFT = 1, /* kernel branches */ + PERF_SAMPLE_BRANCH_HV_SHIFT = 2, /* hypervisor branches */ + + PERF_SAMPLE_BRANCH_ANY_SHIFT = 3, /* any branch types */ + PERF_SAMPLE_BRANCH_ANY_CALL_SHIFT = 4, /* any call branch */ + PERF_SAMPLE_BRANCH_ANY_RETURN_SHIFT = 5, /* any return branch */ + PERF_SAMPLE_BRANCH_IND_CALL_SHIFT = 6, /* indirect calls */ + PERF_SAMPLE_BRANCH_ABORT_TX_SHIFT = 7, /* transaction aborts */ + PERF_SAMPLE_BRANCH_IN_TX_SHIFT = 8, /* in transaction */ + PERF_SAMPLE_BRANCH_NO_TX_SHIFT = 9, /* not in transaction */ + PERF_SAMPLE_BRANCH_COND_SHIFT = 10, /* conditional branches */ + + PERF_SAMPLE_BRANCH_CALL_STACK_SHIFT = 11, /* call/ret stack */ + PERF_SAMPLE_BRANCH_IND_JUMP_SHIFT = 12, /* indirect jumps */ + PERF_SAMPLE_BRANCH_CALL_SHIFT = 13, /* direct call */ + + PERF_SAMPLE_BRANCH_NO_FLAGS_SHIFT = 14, /* no flags */ + PERF_SAMPLE_BRANCH_NO_CYCLES_SHIFT = 15, /* no cycles */ + + PERF_SAMPLE_BRANCH_MAX_SHIFT /* non-ABI */ +}; + +enum perf_branch_sample_type { + PERF_SAMPLE_BRANCH_USER = 1U << PERF_SAMPLE_BRANCH_USER_SHIFT, + PERF_SAMPLE_BRANCH_KERNEL = 1U << PERF_SAMPLE_BRANCH_KERNEL_SHIFT, + PERF_SAMPLE_BRANCH_HV = 1U << PERF_SAMPLE_BRANCH_HV_SHIFT, + + PERF_SAMPLE_BRANCH_ANY = 1U << PERF_SAMPLE_BRANCH_ANY_SHIFT, + PERF_SAMPLE_BRANCH_ANY_CALL = 1U << PERF_SAMPLE_BRANCH_ANY_CALL_SHIFT, + PERF_SAMPLE_BRANCH_ANY_RETURN = 1U << PERF_SAMPLE_BRANCH_ANY_RETURN_SHIFT, + PERF_SAMPLE_BRANCH_IND_CALL = 1U << PERF_SAMPLE_BRANCH_IND_CALL_SHIFT, + PERF_SAMPLE_BRANCH_ABORT_TX = 1U << PERF_SAMPLE_BRANCH_ABORT_TX_SHIFT, + PERF_SAMPLE_BRANCH_IN_TX = 1U << PERF_SAMPLE_BRANCH_IN_TX_SHIFT, + PERF_SAMPLE_BRANCH_NO_TX = 1U << PERF_SAMPLE_BRANCH_NO_TX_SHIFT, + PERF_SAMPLE_BRANCH_COND = 1U << PERF_SAMPLE_BRANCH_COND_SHIFT, + + PERF_SAMPLE_BRANCH_CALL_STACK = 1U << PERF_SAMPLE_BRANCH_CALL_STACK_SHIFT, + PERF_SAMPLE_BRANCH_IND_JUMP = 1U << PERF_SAMPLE_BRANCH_IND_JUMP_SHIFT, + PERF_SAMPLE_BRANCH_CALL = 1U << PERF_SAMPLE_BRANCH_CALL_SHIFT, + + PERF_SAMPLE_BRANCH_NO_FLAGS = 1U << PERF_SAMPLE_BRANCH_NO_FLAGS_SHIFT, + PERF_SAMPLE_BRANCH_NO_CYCLES = 1U << PERF_SAMPLE_BRANCH_NO_CYCLES_SHIFT, + + PERF_SAMPLE_BRANCH_MAX = 1U << PERF_SAMPLE_BRANCH_MAX_SHIFT, +}; + +#define PERF_SAMPLE_BRANCH_PLM_ALL \ + (PERF_SAMPLE_BRANCH_USER|\ + PERF_SAMPLE_BRANCH_KERNEL|\ + PERF_SAMPLE_BRANCH_HV) + +/* + * Values to determine ABI of the registers dump. + */ +enum perf_sample_regs_abi { + PERF_SAMPLE_REGS_ABI_NONE = 0, + PERF_SAMPLE_REGS_ABI_32 = 1, + PERF_SAMPLE_REGS_ABI_64 = 2, +}; + +/* + * Values for the memory transaction event qualifier, mostly for + * abort events. Multiple bits can be set. + */ +enum { + PERF_TXN_ELISION = (1 << 0), /* From elision */ + PERF_TXN_TRANSACTION = (1 << 1), /* From transaction */ + PERF_TXN_SYNC = (1 << 2), /* Instruction is related */ + PERF_TXN_ASYNC = (1 << 3), /* Instruction not related */ + PERF_TXN_RETRY = (1 << 4), /* Retry possible */ + PERF_TXN_CONFLICT = (1 << 5), /* Conflict abort */ + PERF_TXN_CAPACITY_WRITE = (1 << 6), /* Capacity write abort */ + PERF_TXN_CAPACITY_READ = (1 << 7), /* Capacity read abort */ + + PERF_TXN_MAX = (1 << 8), /* non-ABI */ + + /* bits 32..63 are reserved for the abort code */ + + PERF_TXN_ABORT_MASK = (0xffffffffULL << 32), + PERF_TXN_ABORT_SHIFT = 32, +}; + +/* + * The format of the data returned by read() on a perf event fd, + * as specified by attr.read_format: + * + * struct read_format { + * { u64 value; + * { u64 time_enabled; } && PERF_FORMAT_TOTAL_TIME_ENABLED + * { u64 time_running; } && PERF_FORMAT_TOTAL_TIME_RUNNING + * { u64 id; } && PERF_FORMAT_ID + * } && !PERF_FORMAT_GROUP + * + * { u64 nr; + * { u64 time_enabled; } && PERF_FORMAT_TOTAL_TIME_ENABLED + * { u64 time_running; } && PERF_FORMAT_TOTAL_TIME_RUNNING + * { u64 value; + * { u64 id; } && PERF_FORMAT_ID + * } cntr[nr]; + * } && PERF_FORMAT_GROUP + * }; + */ +enum perf_event_read_format { + PERF_FORMAT_TOTAL_TIME_ENABLED = 1U << 0, + PERF_FORMAT_TOTAL_TIME_RUNNING = 1U << 1, + PERF_FORMAT_ID = 1U << 2, + PERF_FORMAT_GROUP = 1U << 3, + + PERF_FORMAT_MAX = 1U << 4, /* non-ABI */ +}; + +#define PERF_ATTR_SIZE_VER0 64 /* sizeof first published struct */ +#define PERF_ATTR_SIZE_VER1 72 /* add: config2 */ +#define PERF_ATTR_SIZE_VER2 80 /* add: branch_sample_type */ +#define PERF_ATTR_SIZE_VER3 96 /* add: sample_regs_user */ + /* add: sample_stack_user */ +#define PERF_ATTR_SIZE_VER4 104 /* add: sample_regs_intr */ +#define PERF_ATTR_SIZE_VER5 112 /* add: aux_watermark */ + +/* + * Hardware event_id to monitor via a performance monitoring event: + * + * @sample_max_stack: Max number of frame pointers in a callchain, + * should be < /proc/sys/kernel/perf_event_max_stack + */ +struct perf_event_attr { + + /* + * Major type: hardware/software/tracepoint/etc. + */ + __u32 type; + + /* + * Size of the attr structure, for fwd/bwd compat. + */ + __u32 size; + + /* + * Type specific configuration information. + */ + __u64 config; + + union { + __u64 sample_period; + __u64 sample_freq; + }; + + __u64 sample_type; + __u64 read_format; + + __u64 disabled : 1, /* off by default */ + inherit : 1, /* children inherit it */ + pinned : 1, /* must always be on PMU */ + exclusive : 1, /* only group on PMU */ + exclude_user : 1, /* don't count user */ + exclude_kernel : 1, /* ditto kernel */ + exclude_hv : 1, /* ditto hypervisor */ + exclude_idle : 1, /* don't count when idle */ + mmap : 1, /* include mmap data */ + comm : 1, /* include comm data */ + freq : 1, /* use freq, not period */ + inherit_stat : 1, /* per task counts */ + enable_on_exec : 1, /* next exec enables */ + task : 1, /* trace fork/exit */ + watermark : 1, /* wakeup_watermark */ + /* + * precise_ip: + * + * 0 - SAMPLE_IP can have arbitrary skid + * 1 - SAMPLE_IP must have constant skid + * 2 - SAMPLE_IP requested to have 0 skid + * 3 - SAMPLE_IP must have 0 skid + * + * See also PERF_RECORD_MISC_EXACT_IP + */ + precise_ip : 2, /* skid constraint */ + mmap_data : 1, /* non-exec mmap data */ + sample_id_all : 1, /* sample_type all events */ + + exclude_host : 1, /* don't count in host */ + exclude_guest : 1, /* don't count in guest */ + + exclude_callchain_kernel : 1, /* exclude kernel callchains */ + exclude_callchain_user : 1, /* exclude user callchains */ + mmap2 : 1, /* include mmap with inode data */ + comm_exec : 1, /* flag comm events that are due to an exec */ + use_clockid : 1, /* use @clockid for time fields */ + context_switch : 1, /* context switch data */ + write_backward : 1, /* Write ring buffer from end to beginning */ + __reserved_1 : 36; + + union { + __u32 wakeup_events; /* wakeup every n events */ + __u32 wakeup_watermark; /* bytes before wakeup */ + }; + + __u32 bp_type; + union { + __u64 bp_addr; + __u64 config1; /* extension of config */ + }; + union { + __u64 bp_len; + __u64 config2; /* extension of config1 */ + }; + __u64 branch_sample_type; /* enum perf_branch_sample_type */ + + /* + * Defines set of user regs to dump on samples. + * See asm/perf_regs.h for details. + */ + __u64 sample_regs_user; + + /* + * Defines size of the user stack to dump on samples. + */ + __u32 sample_stack_user; + + __s32 clockid; + /* + * Defines set of regs to dump for each sample + * state captured on: + * - precise = 0: PMU interrupt + * - precise > 0: sampled instruction + * + * See asm/perf_regs.h for details. + */ + __u64 sample_regs_intr; + + /* + * Wakeup watermark for AUX area + */ + __u32 aux_watermark; + __u16 sample_max_stack; + __u16 __reserved_2; /* align to __u64 */ +}; + +#define perf_flags(attr) (*(&(attr)->read_format + 1)) + +/* + * Ioctls that can be done on a perf event fd: + */ +#define PERF_EVENT_IOC_ENABLE _IO ('$', 0) +#define PERF_EVENT_IOC_DISABLE _IO ('$', 1) +#define PERF_EVENT_IOC_REFRESH _IO ('$', 2) +#define PERF_EVENT_IOC_RESET _IO ('$', 3) +#define PERF_EVENT_IOC_PERIOD _IOW('$', 4, __u64) +#define PERF_EVENT_IOC_SET_OUTPUT _IO ('$', 5) +#define PERF_EVENT_IOC_SET_FILTER _IOW('$', 6, char *) +#define PERF_EVENT_IOC_ID _IOR('$', 7, __u64 *) +#define PERF_EVENT_IOC_SET_BPF _IOW('$', 8, __u32) +#define PERF_EVENT_IOC_PAUSE_OUTPUT _IOW('$', 9, __u32) + +enum perf_event_ioc_flags { + PERF_IOC_FLAG_GROUP = 1U << 0, +}; + +/* + * Structure of the page that can be mapped via mmap + */ +struct perf_event_mmap_page { + __u32 version; /* version number of this structure */ + __u32 compat_version; /* lowest version this is compat with */ + + /* + * Bits needed to read the hw events in user-space. + * + * u32 seq, time_mult, time_shift, index, width; + * u64 count, enabled, running; + * u64 cyc, time_offset; + * s64 pmc = 0; + * + * do { + * seq = pc->lock; + * barrier() + * + * enabled = pc->time_enabled; + * running = pc->time_running; + * + * if (pc->cap_usr_time && enabled != running) { + * cyc = rdtsc(); + * time_offset = pc->time_offset; + * time_mult = pc->time_mult; + * time_shift = pc->time_shift; + * } + * + * index = pc->index; + * count = pc->offset; + * if (pc->cap_user_rdpmc && index) { + * width = pc->pmc_width; + * pmc = rdpmc(index - 1); + * } + * + * barrier(); + * } while (pc->lock != seq); + * + * NOTE: for obvious reason this only works on self-monitoring + * processes. + */ + __u32 lock; /* seqlock for synchronization */ + __u32 index; /* hardware event identifier */ + __s64 offset; /* add to hardware event value */ + __u64 time_enabled; /* time event active */ + __u64 time_running; /* time event on cpu */ + union { + __u64 capabilities; + struct { + __u64 cap_bit0 : 1, /* Always 0, deprecated, see commit 860f085b74e9 */ + cap_bit0_is_deprecated : 1, /* Always 1, signals that bit 0 is zero */ + + cap_user_rdpmc : 1, /* The RDPMC instruction can be used to read counts */ + cap_user_time : 1, /* The time_* fields are used */ + cap_user_time_zero : 1, /* The time_zero field is used */ + cap_____res : 59; + }; + }; + + /* + * If cap_user_rdpmc this field provides the bit-width of the value + * read using the rdpmc() or equivalent instruction. This can be used + * to sign extend the result like: + * + * pmc <<= 64 - width; + * pmc >>= 64 - width; // signed shift right + * count += pmc; + */ + __u16 pmc_width; + + /* + * If cap_usr_time the below fields can be used to compute the time + * delta since time_enabled (in ns) using rdtsc or similar. + * + * u64 quot, rem; + * u64 delta; + * + * quot = (cyc >> time_shift); + * rem = cyc & (((u64)1 << time_shift) - 1); + * delta = time_offset + quot * time_mult + + * ((rem * time_mult) >> time_shift); + * + * Where time_offset,time_mult,time_shift and cyc are read in the + * seqcount loop described above. This delta can then be added to + * enabled and possible running (if index), improving the scaling: + * + * enabled += delta; + * if (index) + * running += delta; + * + * quot = count / running; + * rem = count % running; + * count = quot * enabled + (rem * enabled) / running; + */ + __u16 time_shift; + __u32 time_mult; + __u64 time_offset; + /* + * If cap_usr_time_zero, the hardware clock (e.g. TSC) can be calculated + * from sample timestamps. + * + * time = timestamp - time_zero; + * quot = time / time_mult; + * rem = time % time_mult; + * cyc = (quot << time_shift) + (rem << time_shift) / time_mult; + * + * And vice versa: + * + * quot = cyc >> time_shift; + * rem = cyc & (((u64)1 << time_shift) - 1); + * timestamp = time_zero + quot * time_mult + + * ((rem * time_mult) >> time_shift); + */ + __u64 time_zero; + __u32 size; /* Header size up to __reserved[] fields. */ + + /* + * Hole for extension of the self monitor capabilities + */ + + __u8 __reserved[118*8+4]; /* align to 1k. */ + + /* + * Control data for the mmap() data buffer. + * + * User-space reading the @data_head value should issue an smp_rmb(), + * after reading this value. + * + * When the mapping is PROT_WRITE the @data_tail value should be + * written by userspace to reflect the last read data, after issueing + * an smp_mb() to separate the data read from the ->data_tail store. + * In this case the kernel will not over-write unread data. + * + * See perf_output_put_handle() for the data ordering. + * + * data_{offset,size} indicate the location and size of the perf record + * buffer within the mmapped area. + */ + __u64 data_head; /* head in the data section */ + __u64 data_tail; /* user-space written tail */ + __u64 data_offset; /* where the buffer starts */ + __u64 data_size; /* data buffer size */ + + /* + * AUX area is defined by aux_{offset,size} fields that should be set + * by the userspace, so that + * + * aux_offset >= data_offset + data_size + * + * prior to mmap()ing it. Size of the mmap()ed area should be aux_size. + * + * Ring buffer pointers aux_{head,tail} have the same semantics as + * data_{head,tail} and same ordering rules apply. + */ + __u64 aux_head; + __u64 aux_tail; + __u64 aux_offset; + __u64 aux_size; +}; + +#define PERF_RECORD_MISC_CPUMODE_MASK (7 << 0) +#define PERF_RECORD_MISC_CPUMODE_UNKNOWN (0 << 0) +#define PERF_RECORD_MISC_KERNEL (1 << 0) +#define PERF_RECORD_MISC_USER (2 << 0) +#define PERF_RECORD_MISC_HYPERVISOR (3 << 0) +#define PERF_RECORD_MISC_GUEST_KERNEL (4 << 0) +#define PERF_RECORD_MISC_GUEST_USER (5 << 0) + +/* + * Indicates that /proc/PID/maps parsing are truncated by time out. + */ +#define PERF_RECORD_MISC_PROC_MAP_PARSE_TIMEOUT (1 << 12) +/* + * PERF_RECORD_MISC_MMAP_DATA and PERF_RECORD_MISC_COMM_EXEC are used on + * different events so can reuse the same bit position. + * Ditto PERF_RECORD_MISC_SWITCH_OUT. + */ +#define PERF_RECORD_MISC_MMAP_DATA (1 << 13) +#define PERF_RECORD_MISC_COMM_EXEC (1 << 13) +#define PERF_RECORD_MISC_SWITCH_OUT (1 << 13) +/* + * Indicates that the content of PERF_SAMPLE_IP points to + * the actual instruction that triggered the event. See also + * perf_event_attr::precise_ip. + */ +#define PERF_RECORD_MISC_EXACT_IP (1 << 14) +/* + * Reserve the last bit to indicate some extended misc field + */ +#define PERF_RECORD_MISC_EXT_RESERVED (1 << 15) + +struct perf_event_header { + __u32 type; + __u16 misc; + __u16 size; +}; + +enum perf_event_type { + + /* + * If perf_event_attr.sample_id_all is set then all event types will + * have the sample_type selected fields related to where/when + * (identity) an event took place (TID, TIME, ID, STREAM_ID, CPU, + * IDENTIFIER) described in PERF_RECORD_SAMPLE below, it will be stashed + * just after the perf_event_header and the fields already present for + * the existing fields, i.e. at the end of the payload. That way a newer + * perf.data file will be supported by older perf tools, with these new + * optional fields being ignored. + * + * struct sample_id { + * { u32 pid, tid; } && PERF_SAMPLE_TID + * { u64 time; } && PERF_SAMPLE_TIME + * { u64 id; } && PERF_SAMPLE_ID + * { u64 stream_id;} && PERF_SAMPLE_STREAM_ID + * { u32 cpu, res; } && PERF_SAMPLE_CPU + * { u64 id; } && PERF_SAMPLE_IDENTIFIER + * } && perf_event_attr::sample_id_all + * + * Note that PERF_SAMPLE_IDENTIFIER duplicates PERF_SAMPLE_ID. The + * advantage of PERF_SAMPLE_IDENTIFIER is that its position is fixed + * relative to header.size. + */ + + /* + * The MMAP events record the PROT_EXEC mappings so that we can + * correlate userspace IPs to code. They have the following structure: + * + * struct { + * struct perf_event_header header; + * + * u32 pid, tid; + * u64 addr; + * u64 len; + * u64 pgoff; + * char filename[]; + * struct sample_id sample_id; + * }; + */ + PERF_RECORD_MMAP = 1, + + /* + * struct { + * struct perf_event_header header; + * u64 id; + * u64 lost; + * struct sample_id sample_id; + * }; + */ + PERF_RECORD_LOST = 2, + + /* + * struct { + * struct perf_event_header header; + * + * u32 pid, tid; + * char comm[]; + * struct sample_id sample_id; + * }; + */ + PERF_RECORD_COMM = 3, + + /* + * struct { + * struct perf_event_header header; + * u32 pid, ppid; + * u32 tid, ptid; + * u64 time; + * struct sample_id sample_id; + * }; + */ + PERF_RECORD_EXIT = 4, + + /* + * struct { + * struct perf_event_header header; + * u64 time; + * u64 id; + * u64 stream_id; + * struct sample_id sample_id; + * }; + */ + PERF_RECORD_THROTTLE = 5, + PERF_RECORD_UNTHROTTLE = 6, + + /* + * struct { + * struct perf_event_header header; + * u32 pid, ppid; + * u32 tid, ptid; + * u64 time; + * struct sample_id sample_id; + * }; + */ + PERF_RECORD_FORK = 7, + + /* + * struct { + * struct perf_event_header header; + * u32 pid, tid; + * + * struct read_format values; + * struct sample_id sample_id; + * }; + */ + PERF_RECORD_READ = 8, + + /* + * struct { + * struct perf_event_header header; + * + * # + * # Note that PERF_SAMPLE_IDENTIFIER duplicates PERF_SAMPLE_ID. + * # The advantage of PERF_SAMPLE_IDENTIFIER is that its position + * # is fixed relative to header. + * # + * + * { u64 id; } && PERF_SAMPLE_IDENTIFIER + * { u64 ip; } && PERF_SAMPLE_IP + * { u32 pid, tid; } && PERF_SAMPLE_TID + * { u64 time; } && PERF_SAMPLE_TIME + * { u64 addr; } && PERF_SAMPLE_ADDR + * { u64 id; } && PERF_SAMPLE_ID + * { u64 stream_id;} && PERF_SAMPLE_STREAM_ID + * { u32 cpu, res; } && PERF_SAMPLE_CPU + * { u64 period; } && PERF_SAMPLE_PERIOD + * + * { struct read_format values; } && PERF_SAMPLE_READ + * + * { u64 nr, + * u64 ips[nr]; } && PERF_SAMPLE_CALLCHAIN + * + * # + * # The RAW record below is opaque data wrt the ABI + * # + * # That is, the ABI doesn't make any promises wrt to + * # the stability of its content, it may vary depending + * # on event, hardware, kernel version and phase of + * # the moon. + * # + * # In other words, PERF_SAMPLE_RAW contents are not an ABI. + * # + * + * { u32 size; + * char data[size];}&& PERF_SAMPLE_RAW + * + * { u64 nr; + * { u64 from, to, flags } lbr[nr];} && PERF_SAMPLE_BRANCH_STACK + * + * { u64 abi; # enum perf_sample_regs_abi + * u64 regs[weight(mask)]; } && PERF_SAMPLE_REGS_USER + * + * { u64 size; + * char data[size]; + * u64 dyn_size; } && PERF_SAMPLE_STACK_USER + * + * { u64 weight; } && PERF_SAMPLE_WEIGHT + * { u64 data_src; } && PERF_SAMPLE_DATA_SRC + * { u64 transaction; } && PERF_SAMPLE_TRANSACTION + * { u64 abi; # enum perf_sample_regs_abi + * u64 regs[weight(mask)]; } && PERF_SAMPLE_REGS_INTR + * }; + */ + PERF_RECORD_SAMPLE = 9, + + /* + * The MMAP2 records are an augmented version of MMAP, they add + * maj, min, ino numbers to be used to uniquely identify each mapping + * + * struct { + * struct perf_event_header header; + * + * u32 pid, tid; + * u64 addr; + * u64 len; + * u64 pgoff; + * u32 maj; + * u32 min; + * u64 ino; + * u64 ino_generation; + * u32 prot, flags; + * char filename[]; + * struct sample_id sample_id; + * }; + */ + PERF_RECORD_MMAP2 = 10, + + /* + * Records that new data landed in the AUX buffer part. + * + * struct { + * struct perf_event_header header; + * + * u64 aux_offset; + * u64 aux_size; + * u64 flags; + * struct sample_id sample_id; + * }; + */ + PERF_RECORD_AUX = 11, + + /* + * Indicates that instruction trace has started + * + * struct { + * struct perf_event_header header; + * u32 pid; + * u32 tid; + * }; + */ + PERF_RECORD_ITRACE_START = 12, + + /* + * Records the dropped/lost sample number. + * + * struct { + * struct perf_event_header header; + * + * u64 lost; + * struct sample_id sample_id; + * }; + */ + PERF_RECORD_LOST_SAMPLES = 13, + + /* + * Records a context switch in or out (flagged by + * PERF_RECORD_MISC_SWITCH_OUT). See also + * PERF_RECORD_SWITCH_CPU_WIDE. + * + * struct { + * struct perf_event_header header; + * struct sample_id sample_id; + * }; + */ + PERF_RECORD_SWITCH = 14, + + /* + * CPU-wide version of PERF_RECORD_SWITCH with next_prev_pid and + * next_prev_tid that are the next (switching out) or previous + * (switching in) pid/tid. + * + * struct { + * struct perf_event_header header; + * u32 next_prev_pid; + * u32 next_prev_tid; + * struct sample_id sample_id; + * }; + */ + PERF_RECORD_SWITCH_CPU_WIDE = 15, + + PERF_RECORD_MAX, /* non-ABI */ +}; + +#define PERF_MAX_STACK_DEPTH 127 +#define PERF_MAX_CONTEXTS_PER_STACK 8 + +enum perf_callchain_context { + PERF_CONTEXT_HV = (__u64)-32, + PERF_CONTEXT_KERNEL = (__u64)-128, + PERF_CONTEXT_USER = (__u64)-512, + + PERF_CONTEXT_GUEST = (__u64)-2048, + PERF_CONTEXT_GUEST_KERNEL = (__u64)-2176, + PERF_CONTEXT_GUEST_USER = (__u64)-2560, + + PERF_CONTEXT_MAX = (__u64)-4095, +}; + +/** + * PERF_RECORD_AUX::flags bits + */ +#define PERF_AUX_FLAG_TRUNCATED 0x01 /* record was truncated to fit */ +#define PERF_AUX_FLAG_OVERWRITE 0x02 /* snapshot from overwrite mode */ + +#define PERF_FLAG_FD_NO_GROUP (1UL << 0) +#define PERF_FLAG_FD_OUTPUT (1UL << 1) +#define PERF_FLAG_PID_CGROUP (1UL << 2) /* pid=cgroup id, per-cpu mode only */ +#define PERF_FLAG_FD_CLOEXEC (1UL << 3) /* O_CLOEXEC */ + +union perf_mem_data_src { + __u64 val; + struct { + __u64 mem_op:5, /* type of opcode */ + mem_lvl:14, /* memory hierarchy level */ + mem_snoop:5, /* snoop mode */ + mem_lock:2, /* lock instr */ + mem_dtlb:7, /* tlb access */ + mem_rsvd:31; + }; +}; + +/* type of opcode (load/store/prefetch,code) */ +#define PERF_MEM_OP_NA 0x01 /* not available */ +#define PERF_MEM_OP_LOAD 0x02 /* load instruction */ +#define PERF_MEM_OP_STORE 0x04 /* store instruction */ +#define PERF_MEM_OP_PFETCH 0x08 /* prefetch */ +#define PERF_MEM_OP_EXEC 0x10 /* code (execution) */ +#define PERF_MEM_OP_SHIFT 0 + +/* memory hierarchy (memory level, hit or miss) */ +#define PERF_MEM_LVL_NA 0x01 /* not available */ +#define PERF_MEM_LVL_HIT 0x02 /* hit level */ +#define PERF_MEM_LVL_MISS 0x04 /* miss level */ +#define PERF_MEM_LVL_L1 0x08 /* L1 */ +#define PERF_MEM_LVL_LFB 0x10 /* Line Fill Buffer */ +#define PERF_MEM_LVL_L2 0x20 /* L2 */ +#define PERF_MEM_LVL_L3 0x40 /* L3 */ +#define PERF_MEM_LVL_LOC_RAM 0x80 /* Local DRAM */ +#define PERF_MEM_LVL_REM_RAM1 0x100 /* Remote DRAM (1 hop) */ +#define PERF_MEM_LVL_REM_RAM2 0x200 /* Remote DRAM (2 hops) */ +#define PERF_MEM_LVL_REM_CCE1 0x400 /* Remote Cache (1 hop) */ +#define PERF_MEM_LVL_REM_CCE2 0x800 /* Remote Cache (2 hops) */ +#define PERF_MEM_LVL_IO 0x1000 /* I/O memory */ +#define PERF_MEM_LVL_UNC 0x2000 /* Uncached memory */ +#define PERF_MEM_LVL_SHIFT 5 + +/* snoop mode */ +#define PERF_MEM_SNOOP_NA 0x01 /* not available */ +#define PERF_MEM_SNOOP_NONE 0x02 /* no snoop */ +#define PERF_MEM_SNOOP_HIT 0x04 /* snoop hit */ +#define PERF_MEM_SNOOP_MISS 0x08 /* snoop miss */ +#define PERF_MEM_SNOOP_HITM 0x10 /* snoop hit modified */ +#define PERF_MEM_SNOOP_SHIFT 19 + +/* locked instruction */ +#define PERF_MEM_LOCK_NA 0x01 /* not available */ +#define PERF_MEM_LOCK_LOCKED 0x02 /* locked transaction */ +#define PERF_MEM_LOCK_SHIFT 24 + +/* TLB access */ +#define PERF_MEM_TLB_NA 0x01 /* not available */ +#define PERF_MEM_TLB_HIT 0x02 /* hit level */ +#define PERF_MEM_TLB_MISS 0x04 /* miss level */ +#define PERF_MEM_TLB_L1 0x08 /* L1 */ +#define PERF_MEM_TLB_L2 0x10 /* L2 */ +#define PERF_MEM_TLB_WK 0x20 /* Hardware Walker*/ +#define PERF_MEM_TLB_OS 0x40 /* OS fault handler */ +#define PERF_MEM_TLB_SHIFT 26 + +#define PERF_MEM_S(a, s) \ + (((__u64)PERF_MEM_##a##_##s) << PERF_MEM_##a##_SHIFT) + +/* + * single taken branch record layout: + * + * from: source instruction (may not always be a branch insn) + * to: branch target + * mispred: branch target was mispredicted + * predicted: branch target was predicted + * + * support for mispred, predicted is optional. In case it + * is not supported mispred = predicted = 0. + * + * in_tx: running in a hardware transaction + * abort: aborting a hardware transaction + * cycles: cycles from last branch (or 0 if not supported) + */ +struct perf_branch_entry { + __u64 from; + __u64 to; + __u64 mispred:1, /* target mispredicted */ + predicted:1,/* target predicted */ + in_tx:1, /* in transaction */ + abort:1, /* transaction abort */ + cycles:16, /* cycle count to last branch */ + reserved:44; +}; + +#endif /* _UAPI_LINUX_PERF_EVENT_H */ diff --git a/tools/perf/MANIFEST b/tools/perf/MANIFEST index 2bd8c31..0b1ebf3 100644 --- a/tools/perf/MANIFEST +++ b/tools/perf/MANIFEST @@ -54,6 +54,7 @@ tools/include/linux/hash.h tools/include/linux/kernel.h tools/include/linux/list.h tools/include/linux/log2.h +tools/include/uapi/linux/perf_event.h tools/include/linux/poison.h tools/include/linux/rbtree.h tools/include/linux/rbtree_augmented.h @@ -66,7 +67,6 @@ include/asm-generic/bitops/const_hweight.h include/asm-generic/bitops/fls64.h include/asm-generic/bitops/__fls.h include/asm-generic/bitops/fls.h -include/linux/perf_event.h include/linux/list.h include/linux/hash.h include/linux/stringify.h @@ -79,7 +79,6 @@ arch/*/lib/memset*.S arch/*/include/asm/*features.h include/linux/poison.h include/linux/hw_breakpoint.h -include/uapi/linux/perf_event.h include/uapi/linux/bpf.h include/uapi/linux/bpf_common.h include/uapi/linux/const.h diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf index d0a2cb1..5e5f8cb 100644 --- a/tools/perf/Makefile.perf +++ b/tools/perf/Makefile.perf @@ -345,6 +345,9 @@ export srctree OUTPUT RM CC LD AR CFLAGS V BISON FLEX AWK include $(srctree)/tools/build/Makefile.include $(PERF_IN): prepare FORCE + @(test -f ../../include/uapi/linux/perf_event.h && ( \ + (diff -B ../include/uapi/linux/perf_event.h ../../include/uapi/linux/perf_event.h >/dev/null) \ + || echo "Warning: tools/include/uapi/linux/perf_event.h differs from kernel" >&2 )) || true $(Q)$(MAKE) $(build)=perf $(OUTPUT)perf: $(PERFLIBS) $(PERF_IN) $(LIBTRACEEVENT_DYNAMIC_LIST) diff --git a/tools/perf/config/Makefile b/tools/perf/config/Makefile index 7d2ea69..bbb2210 100644 --- a/tools/perf/config/Makefile +++ b/tools/perf/config/Makefile @@ -206,6 +206,7 @@ endif CFLAGS += -I$(src-perf)/util/include CFLAGS += -I$(src-perf)/arch/$(ARCH)/include +CFLAGS += -I$(srctree)/tools/include/uapi CFLAGS += -I$(srctree)/tools/include/ CFLAGS += -I$(srctree)/arch/$(ARCH)/include/uapi CFLAGS += -I$(srctree)/arch/$(ARCH)/include -- cgit v0.10.2 From 7d7d1bf1d1dabe435ef50efb051724b8664749cb Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Mon, 11 Jul 2016 12:36:41 -0300 Subject: perf bench: Copy kernel files needed to build mem{cpy,set} x86_64 benchmarks We can't access kernel files directly from tools/, so copy the required bits, and make sure that we detect when the original files, in the kernel, gets modified. Cc: Adrian Hunter Cc: David Ahern Cc: Jiri Olsa Cc: Namhyung Kim Cc: Wang Nan Link: http://lkml.kernel.org/n/tip-z7e76274ch5j4nugv048qacb@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/arch/x86/include/asm/cpufeatures.h b/tools/arch/x86/include/asm/cpufeatures.h new file mode 100644 index 0000000..4a41348 --- /dev/null +++ b/tools/arch/x86/include/asm/cpufeatures.h @@ -0,0 +1,316 @@ +#ifndef _ASM_X86_CPUFEATURES_H +#define _ASM_X86_CPUFEATURES_H + +#ifndef _ASM_X86_REQUIRED_FEATURES_H +#include +#endif + +#ifndef _ASM_X86_DISABLED_FEATURES_H +#include +#endif + +/* + * Defines x86 CPU feature bits + */ +#define NCAPINTS 18 /* N 32-bit words worth of info */ +#define NBUGINTS 1 /* N 32-bit bug flags */ + +/* + * Note: If the comment begins with a quoted string, that string is used + * in /proc/cpuinfo instead of the macro name. If the string is "", + * this feature bit is not displayed in /proc/cpuinfo at all. + */ + +/* Intel-defined CPU features, CPUID level 0x00000001 (edx), word 0 */ +#define X86_FEATURE_FPU ( 0*32+ 0) /* Onboard FPU */ +#define X86_FEATURE_VME ( 0*32+ 1) /* Virtual Mode Extensions */ +#define X86_FEATURE_DE ( 0*32+ 2) /* Debugging Extensions */ +#define X86_FEATURE_PSE ( 0*32+ 3) /* Page Size Extensions */ +#define X86_FEATURE_TSC ( 0*32+ 4) /* Time Stamp Counter */ +#define X86_FEATURE_MSR ( 0*32+ 5) /* Model-Specific Registers */ +#define X86_FEATURE_PAE ( 0*32+ 6) /* Physical Address Extensions */ +#define X86_FEATURE_MCE ( 0*32+ 7) /* Machine Check Exception */ +#define X86_FEATURE_CX8 ( 0*32+ 8) /* CMPXCHG8 instruction */ +#define X86_FEATURE_APIC ( 0*32+ 9) /* Onboard APIC */ +#define X86_FEATURE_SEP ( 0*32+11) /* SYSENTER/SYSEXIT */ +#define X86_FEATURE_MTRR ( 0*32+12) /* Memory Type Range Registers */ +#define X86_FEATURE_PGE ( 0*32+13) /* Page Global Enable */ +#define X86_FEATURE_MCA ( 0*32+14) /* Machine Check Architecture */ +#define X86_FEATURE_CMOV ( 0*32+15) /* CMOV instructions */ + /* (plus FCMOVcc, FCOMI with FPU) */ +#define X86_FEATURE_PAT ( 0*32+16) /* Page Attribute Table */ +#define X86_FEATURE_PSE36 ( 0*32+17) /* 36-bit PSEs */ +#define X86_FEATURE_PN ( 0*32+18) /* Processor serial number */ +#define X86_FEATURE_CLFLUSH ( 0*32+19) /* CLFLUSH instruction */ +#define X86_FEATURE_DS ( 0*32+21) /* "dts" Debug Store */ +#define X86_FEATURE_ACPI ( 0*32+22) /* ACPI via MSR */ +#define X86_FEATURE_MMX ( 0*32+23) /* Multimedia Extensions */ +#define X86_FEATURE_FXSR ( 0*32+24) /* FXSAVE/FXRSTOR, CR4.OSFXSR */ +#define X86_FEATURE_XMM ( 0*32+25) /* "sse" */ +#define X86_FEATURE_XMM2 ( 0*32+26) /* "sse2" */ +#define X86_FEATURE_SELFSNOOP ( 0*32+27) /* "ss" CPU self snoop */ +#define X86_FEATURE_HT ( 0*32+28) /* Hyper-Threading */ +#define X86_FEATURE_ACC ( 0*32+29) /* "tm" Automatic clock control */ +#define X86_FEATURE_IA64 ( 0*32+30) /* IA-64 processor */ +#define X86_FEATURE_PBE ( 0*32+31) /* Pending Break Enable */ + +/* AMD-defined CPU features, CPUID level 0x80000001, word 1 */ +/* Don't duplicate feature flags which are redundant with Intel! */ +#define X86_FEATURE_SYSCALL ( 1*32+11) /* SYSCALL/SYSRET */ +#define X86_FEATURE_MP ( 1*32+19) /* MP Capable. */ +#define X86_FEATURE_NX ( 1*32+20) /* Execute Disable */ +#define X86_FEATURE_MMXEXT ( 1*32+22) /* AMD MMX extensions */ +#define X86_FEATURE_FXSR_OPT ( 1*32+25) /* FXSAVE/FXRSTOR optimizations */ +#define X86_FEATURE_GBPAGES ( 1*32+26) /* "pdpe1gb" GB pages */ +#define X86_FEATURE_RDTSCP ( 1*32+27) /* RDTSCP */ +#define X86_FEATURE_LM ( 1*32+29) /* Long Mode (x86-64) */ +#define X86_FEATURE_3DNOWEXT ( 1*32+30) /* AMD 3DNow! extensions */ +#define X86_FEATURE_3DNOW ( 1*32+31) /* 3DNow! */ + +/* Transmeta-defined CPU features, CPUID level 0x80860001, word 2 */ +#define X86_FEATURE_RECOVERY ( 2*32+ 0) /* CPU in recovery mode */ +#define X86_FEATURE_LONGRUN ( 2*32+ 1) /* Longrun power control */ +#define X86_FEATURE_LRTI ( 2*32+ 3) /* LongRun table interface */ + +/* Other features, Linux-defined mapping, word 3 */ +/* This range is used for feature bits which conflict or are synthesized */ +#define X86_FEATURE_CXMMX ( 3*32+ 0) /* Cyrix MMX extensions */ +#define X86_FEATURE_K6_MTRR ( 3*32+ 1) /* AMD K6 nonstandard MTRRs */ +#define X86_FEATURE_CYRIX_ARR ( 3*32+ 2) /* Cyrix ARRs (= MTRRs) */ +#define X86_FEATURE_CENTAUR_MCR ( 3*32+ 3) /* Centaur MCRs (= MTRRs) */ +/* cpu types for specific tunings: */ +#define X86_FEATURE_K8 ( 3*32+ 4) /* "" Opteron, Athlon64 */ +#define X86_FEATURE_K7 ( 3*32+ 5) /* "" Athlon */ +#define X86_FEATURE_P3 ( 3*32+ 6) /* "" P3 */ +#define X86_FEATURE_P4 ( 3*32+ 7) /* "" P4 */ +#define X86_FEATURE_CONSTANT_TSC ( 3*32+ 8) /* TSC ticks at a constant rate */ +#define X86_FEATURE_UP ( 3*32+ 9) /* smp kernel running on up */ +#define X86_FEATURE_ART ( 3*32+10) /* Platform has always running timer (ART) */ +#define X86_FEATURE_ARCH_PERFMON ( 3*32+11) /* Intel Architectural PerfMon */ +#define X86_FEATURE_PEBS ( 3*32+12) /* Precise-Event Based Sampling */ +#define X86_FEATURE_BTS ( 3*32+13) /* Branch Trace Store */ +#define X86_FEATURE_SYSCALL32 ( 3*32+14) /* "" syscall in ia32 userspace */ +#define X86_FEATURE_SYSENTER32 ( 3*32+15) /* "" sysenter in ia32 userspace */ +#define X86_FEATURE_REP_GOOD ( 3*32+16) /* rep microcode works well */ +#define X86_FEATURE_MFENCE_RDTSC ( 3*32+17) /* "" Mfence synchronizes RDTSC */ +#define X86_FEATURE_LFENCE_RDTSC ( 3*32+18) /* "" Lfence synchronizes RDTSC */ +#define X86_FEATURE_ACC_POWER ( 3*32+19) /* AMD Accumulated Power Mechanism */ +#define X86_FEATURE_NOPL ( 3*32+20) /* The NOPL (0F 1F) instructions */ +#define X86_FEATURE_ALWAYS ( 3*32+21) /* "" Always-present feature */ +#define X86_FEATURE_XTOPOLOGY ( 3*32+22) /* cpu topology enum extensions */ +#define X86_FEATURE_TSC_RELIABLE ( 3*32+23) /* TSC is known to be reliable */ +#define X86_FEATURE_NONSTOP_TSC ( 3*32+24) /* TSC does not stop in C states */ +/* free, was #define X86_FEATURE_CLFLUSH_MONITOR ( 3*32+25) * "" clflush reqd with monitor */ +#define X86_FEATURE_EXTD_APICID ( 3*32+26) /* has extended APICID (8 bits) */ +#define X86_FEATURE_AMD_DCM ( 3*32+27) /* multi-node processor */ +#define X86_FEATURE_APERFMPERF ( 3*32+28) /* APERFMPERF */ +#define X86_FEATURE_EAGER_FPU ( 3*32+29) /* "eagerfpu" Non lazy FPU restore */ +#define X86_FEATURE_NONSTOP_TSC_S3 ( 3*32+30) /* TSC doesn't stop in S3 state */ +#define X86_FEATURE_MCE_RECOVERY ( 3*32+31) /* cpu has recoverable machine checks */ + +/* Intel-defined CPU features, CPUID level 0x00000001 (ecx), word 4 */ +#define X86_FEATURE_XMM3 ( 4*32+ 0) /* "pni" SSE-3 */ +#define X86_FEATURE_PCLMULQDQ ( 4*32+ 1) /* PCLMULQDQ instruction */ +#define X86_FEATURE_DTES64 ( 4*32+ 2) /* 64-bit Debug Store */ +#define X86_FEATURE_MWAIT ( 4*32+ 3) /* "monitor" Monitor/Mwait support */ +#define X86_FEATURE_DSCPL ( 4*32+ 4) /* "ds_cpl" CPL Qual. Debug Store */ +#define X86_FEATURE_VMX ( 4*32+ 5) /* Hardware virtualization */ +#define X86_FEATURE_SMX ( 4*32+ 6) /* Safer mode */ +#define X86_FEATURE_EST ( 4*32+ 7) /* Enhanced SpeedStep */ +#define X86_FEATURE_TM2 ( 4*32+ 8) /* Thermal Monitor 2 */ +#define X86_FEATURE_SSSE3 ( 4*32+ 9) /* Supplemental SSE-3 */ +#define X86_FEATURE_CID ( 4*32+10) /* Context ID */ +#define X86_FEATURE_SDBG ( 4*32+11) /* Silicon Debug */ +#define X86_FEATURE_FMA ( 4*32+12) /* Fused multiply-add */ +#define X86_FEATURE_CX16 ( 4*32+13) /* CMPXCHG16B */ +#define X86_FEATURE_XTPR ( 4*32+14) /* Send Task Priority Messages */ +#define X86_FEATURE_PDCM ( 4*32+15) /* Performance Capabilities */ +#define X86_FEATURE_PCID ( 4*32+17) /* Process Context Identifiers */ +#define X86_FEATURE_DCA ( 4*32+18) /* Direct Cache Access */ +#define X86_FEATURE_XMM4_1 ( 4*32+19) /* "sse4_1" SSE-4.1 */ +#define X86_FEATURE_XMM4_2 ( 4*32+20) /* "sse4_2" SSE-4.2 */ +#define X86_FEATURE_X2APIC ( 4*32+21) /* x2APIC */ +#define X86_FEATURE_MOVBE ( 4*32+22) /* MOVBE instruction */ +#define X86_FEATURE_POPCNT ( 4*32+23) /* POPCNT instruction */ +#define X86_FEATURE_TSC_DEADLINE_TIMER ( 4*32+24) /* Tsc deadline timer */ +#define X86_FEATURE_AES ( 4*32+25) /* AES instructions */ +#define X86_FEATURE_XSAVE ( 4*32+26) /* XSAVE/XRSTOR/XSETBV/XGETBV */ +#define X86_FEATURE_OSXSAVE ( 4*32+27) /* "" XSAVE enabled in the OS */ +#define X86_FEATURE_AVX ( 4*32+28) /* Advanced Vector Extensions */ +#define X86_FEATURE_F16C ( 4*32+29) /* 16-bit fp conversions */ +#define X86_FEATURE_RDRAND ( 4*32+30) /* The RDRAND instruction */ +#define X86_FEATURE_HYPERVISOR ( 4*32+31) /* Running on a hypervisor */ + +/* VIA/Cyrix/Centaur-defined CPU features, CPUID level 0xC0000001, word 5 */ +#define X86_FEATURE_XSTORE ( 5*32+ 2) /* "rng" RNG present (xstore) */ +#define X86_FEATURE_XSTORE_EN ( 5*32+ 3) /* "rng_en" RNG enabled */ +#define X86_FEATURE_XCRYPT ( 5*32+ 6) /* "ace" on-CPU crypto (xcrypt) */ +#define X86_FEATURE_XCRYPT_EN ( 5*32+ 7) /* "ace_en" on-CPU crypto enabled */ +#define X86_FEATURE_ACE2 ( 5*32+ 8) /* Advanced Cryptography Engine v2 */ +#define X86_FEATURE_ACE2_EN ( 5*32+ 9) /* ACE v2 enabled */ +#define X86_FEATURE_PHE ( 5*32+10) /* PadLock Hash Engine */ +#define X86_FEATURE_PHE_EN ( 5*32+11) /* PHE enabled */ +#define X86_FEATURE_PMM ( 5*32+12) /* PadLock Montgomery Multiplier */ +#define X86_FEATURE_PMM_EN ( 5*32+13) /* PMM enabled */ + +/* More extended AMD flags: CPUID level 0x80000001, ecx, word 6 */ +#define X86_FEATURE_LAHF_LM ( 6*32+ 0) /* LAHF/SAHF in long mode */ +#define X86_FEATURE_CMP_LEGACY ( 6*32+ 1) /* If yes HyperThreading not valid */ +#define X86_FEATURE_SVM ( 6*32+ 2) /* Secure virtual machine */ +#define X86_FEATURE_EXTAPIC ( 6*32+ 3) /* Extended APIC space */ +#define X86_FEATURE_CR8_LEGACY ( 6*32+ 4) /* CR8 in 32-bit mode */ +#define X86_FEATURE_ABM ( 6*32+ 5) /* Advanced bit manipulation */ +#define X86_FEATURE_SSE4A ( 6*32+ 6) /* SSE-4A */ +#define X86_FEATURE_MISALIGNSSE ( 6*32+ 7) /* Misaligned SSE mode */ +#define X86_FEATURE_3DNOWPREFETCH ( 6*32+ 8) /* 3DNow prefetch instructions */ +#define X86_FEATURE_OSVW ( 6*32+ 9) /* OS Visible Workaround */ +#define X86_FEATURE_IBS ( 6*32+10) /* Instruction Based Sampling */ +#define X86_FEATURE_XOP ( 6*32+11) /* extended AVX instructions */ +#define X86_FEATURE_SKINIT ( 6*32+12) /* SKINIT/STGI instructions */ +#define X86_FEATURE_WDT ( 6*32+13) /* Watchdog timer */ +#define X86_FEATURE_LWP ( 6*32+15) /* Light Weight Profiling */ +#define X86_FEATURE_FMA4 ( 6*32+16) /* 4 operands MAC instructions */ +#define X86_FEATURE_TCE ( 6*32+17) /* translation cache extension */ +#define X86_FEATURE_NODEID_MSR ( 6*32+19) /* NodeId MSR */ +#define X86_FEATURE_TBM ( 6*32+21) /* trailing bit manipulations */ +#define X86_FEATURE_TOPOEXT ( 6*32+22) /* topology extensions CPUID leafs */ +#define X86_FEATURE_PERFCTR_CORE ( 6*32+23) /* core performance counter extensions */ +#define X86_FEATURE_PERFCTR_NB ( 6*32+24) /* NB performance counter extensions */ +#define X86_FEATURE_BPEXT (6*32+26) /* data breakpoint extension */ +#define X86_FEATURE_PTSC ( 6*32+27) /* performance time-stamp counter */ +#define X86_FEATURE_PERFCTR_L2 ( 6*32+28) /* L2 performance counter extensions */ +#define X86_FEATURE_MWAITX ( 6*32+29) /* MWAIT extension (MONITORX/MWAITX) */ + +/* + * Auxiliary flags: Linux defined - For features scattered in various + * CPUID levels like 0x6, 0xA etc, word 7. + * + * Reuse free bits when adding new feature flags! + */ + +#define X86_FEATURE_CPB ( 7*32+ 2) /* AMD Core Performance Boost */ +#define X86_FEATURE_EPB ( 7*32+ 3) /* IA32_ENERGY_PERF_BIAS support */ + +#define X86_FEATURE_HW_PSTATE ( 7*32+ 8) /* AMD HW-PState */ +#define X86_FEATURE_PROC_FEEDBACK ( 7*32+ 9) /* AMD ProcFeedbackInterface */ + +#define X86_FEATURE_INTEL_PT ( 7*32+15) /* Intel Processor Trace */ + +/* Virtualization flags: Linux defined, word 8 */ +#define X86_FEATURE_TPR_SHADOW ( 8*32+ 0) /* Intel TPR Shadow */ +#define X86_FEATURE_VNMI ( 8*32+ 1) /* Intel Virtual NMI */ +#define X86_FEATURE_FLEXPRIORITY ( 8*32+ 2) /* Intel FlexPriority */ +#define X86_FEATURE_EPT ( 8*32+ 3) /* Intel Extended Page Table */ +#define X86_FEATURE_VPID ( 8*32+ 4) /* Intel Virtual Processor ID */ + +#define X86_FEATURE_VMMCALL ( 8*32+15) /* Prefer vmmcall to vmcall */ +#define X86_FEATURE_XENPV ( 8*32+16) /* "" Xen paravirtual guest */ + + +/* Intel-defined CPU features, CPUID level 0x00000007:0 (ebx), word 9 */ +#define X86_FEATURE_FSGSBASE ( 9*32+ 0) /* {RD/WR}{FS/GS}BASE instructions*/ +#define X86_FEATURE_TSC_ADJUST ( 9*32+ 1) /* TSC adjustment MSR 0x3b */ +#define X86_FEATURE_BMI1 ( 9*32+ 3) /* 1st group bit manipulation extensions */ +#define X86_FEATURE_HLE ( 9*32+ 4) /* Hardware Lock Elision */ +#define X86_FEATURE_AVX2 ( 9*32+ 5) /* AVX2 instructions */ +#define X86_FEATURE_SMEP ( 9*32+ 7) /* Supervisor Mode Execution Protection */ +#define X86_FEATURE_BMI2 ( 9*32+ 8) /* 2nd group bit manipulation extensions */ +#define X86_FEATURE_ERMS ( 9*32+ 9) /* Enhanced REP MOVSB/STOSB */ +#define X86_FEATURE_INVPCID ( 9*32+10) /* Invalidate Processor Context ID */ +#define X86_FEATURE_RTM ( 9*32+11) /* Restricted Transactional Memory */ +#define X86_FEATURE_CQM ( 9*32+12) /* Cache QoS Monitoring */ +#define X86_FEATURE_MPX ( 9*32+14) /* Memory Protection Extension */ +#define X86_FEATURE_AVX512F ( 9*32+16) /* AVX-512 Foundation */ +#define X86_FEATURE_AVX512DQ ( 9*32+17) /* AVX-512 DQ (Double/Quad granular) Instructions */ +#define X86_FEATURE_RDSEED ( 9*32+18) /* The RDSEED instruction */ +#define X86_FEATURE_ADX ( 9*32+19) /* The ADCX and ADOX instructions */ +#define X86_FEATURE_SMAP ( 9*32+20) /* Supervisor Mode Access Prevention */ +#define X86_FEATURE_PCOMMIT ( 9*32+22) /* PCOMMIT instruction */ +#define X86_FEATURE_CLFLUSHOPT ( 9*32+23) /* CLFLUSHOPT instruction */ +#define X86_FEATURE_CLWB ( 9*32+24) /* CLWB instruction */ +#define X86_FEATURE_AVX512PF ( 9*32+26) /* AVX-512 Prefetch */ +#define X86_FEATURE_AVX512ER ( 9*32+27) /* AVX-512 Exponential and Reciprocal */ +#define X86_FEATURE_AVX512CD ( 9*32+28) /* AVX-512 Conflict Detection */ +#define X86_FEATURE_SHA_NI ( 9*32+29) /* SHA1/SHA256 Instruction Extensions */ +#define X86_FEATURE_AVX512BW ( 9*32+30) /* AVX-512 BW (Byte/Word granular) Instructions */ +#define X86_FEATURE_AVX512VL ( 9*32+31) /* AVX-512 VL (128/256 Vector Length) Extensions */ + +/* Extended state features, CPUID level 0x0000000d:1 (eax), word 10 */ +#define X86_FEATURE_XSAVEOPT (10*32+ 0) /* XSAVEOPT */ +#define X86_FEATURE_XSAVEC (10*32+ 1) /* XSAVEC */ +#define X86_FEATURE_XGETBV1 (10*32+ 2) /* XGETBV with ECX = 1 */ +#define X86_FEATURE_XSAVES (10*32+ 3) /* XSAVES/XRSTORS */ + +/* Intel-defined CPU QoS Sub-leaf, CPUID level 0x0000000F:0 (edx), word 11 */ +#define X86_FEATURE_CQM_LLC (11*32+ 1) /* LLC QoS if 1 */ + +/* Intel-defined CPU QoS Sub-leaf, CPUID level 0x0000000F:1 (edx), word 12 */ +#define X86_FEATURE_CQM_OCCUP_LLC (12*32+ 0) /* LLC occupancy monitoring if 1 */ +#define X86_FEATURE_CQM_MBM_TOTAL (12*32+ 1) /* LLC Total MBM monitoring */ +#define X86_FEATURE_CQM_MBM_LOCAL (12*32+ 2) /* LLC Local MBM monitoring */ + +/* AMD-defined CPU features, CPUID level 0x80000008 (ebx), word 13 */ +#define X86_FEATURE_CLZERO (13*32+0) /* CLZERO instruction */ +#define X86_FEATURE_IRPERF (13*32+1) /* Instructions Retired Count */ + +/* Thermal and Power Management Leaf, CPUID level 0x00000006 (eax), word 14 */ +#define X86_FEATURE_DTHERM (14*32+ 0) /* Digital Thermal Sensor */ +#define X86_FEATURE_IDA (14*32+ 1) /* Intel Dynamic Acceleration */ +#define X86_FEATURE_ARAT (14*32+ 2) /* Always Running APIC Timer */ +#define X86_FEATURE_PLN (14*32+ 4) /* Intel Power Limit Notification */ +#define X86_FEATURE_PTS (14*32+ 6) /* Intel Package Thermal Status */ +#define X86_FEATURE_HWP (14*32+ 7) /* Intel Hardware P-states */ +#define X86_FEATURE_HWP_NOTIFY (14*32+ 8) /* HWP Notification */ +#define X86_FEATURE_HWP_ACT_WINDOW (14*32+ 9) /* HWP Activity Window */ +#define X86_FEATURE_HWP_EPP (14*32+10) /* HWP Energy Perf. Preference */ +#define X86_FEATURE_HWP_PKG_REQ (14*32+11) /* HWP Package Level Request */ + +/* AMD SVM Feature Identification, CPUID level 0x8000000a (edx), word 15 */ +#define X86_FEATURE_NPT (15*32+ 0) /* Nested Page Table support */ +#define X86_FEATURE_LBRV (15*32+ 1) /* LBR Virtualization support */ +#define X86_FEATURE_SVML (15*32+ 2) /* "svm_lock" SVM locking MSR */ +#define X86_FEATURE_NRIPS (15*32+ 3) /* "nrip_save" SVM next_rip save */ +#define X86_FEATURE_TSCRATEMSR (15*32+ 4) /* "tsc_scale" TSC scaling support */ +#define X86_FEATURE_VMCBCLEAN (15*32+ 5) /* "vmcb_clean" VMCB clean bits support */ +#define X86_FEATURE_FLUSHBYASID (15*32+ 6) /* flush-by-ASID support */ +#define X86_FEATURE_DECODEASSISTS (15*32+ 7) /* Decode Assists support */ +#define X86_FEATURE_PAUSEFILTER (15*32+10) /* filtered pause intercept */ +#define X86_FEATURE_PFTHRESHOLD (15*32+12) /* pause filter threshold */ +#define X86_FEATURE_AVIC (15*32+13) /* Virtual Interrupt Controller */ + +/* Intel-defined CPU features, CPUID level 0x00000007:0 (ecx), word 16 */ +#define X86_FEATURE_PKU (16*32+ 3) /* Protection Keys for Userspace */ +#define X86_FEATURE_OSPKE (16*32+ 4) /* OS Protection Keys Enable */ + +/* AMD-defined CPU features, CPUID level 0x80000007 (ebx), word 17 */ +#define X86_FEATURE_OVERFLOW_RECOV (17*32+0) /* MCA overflow recovery support */ +#define X86_FEATURE_SUCCOR (17*32+1) /* Uncorrectable error containment and recovery */ +#define X86_FEATURE_SMCA (17*32+3) /* Scalable MCA */ + +/* + * BUG word(s) + */ +#define X86_BUG(x) (NCAPINTS*32 + (x)) + +#define X86_BUG_F00F X86_BUG(0) /* Intel F00F */ +#define X86_BUG_FDIV X86_BUG(1) /* FPU FDIV */ +#define X86_BUG_COMA X86_BUG(2) /* Cyrix 6x86 coma */ +#define X86_BUG_AMD_TLB_MMATCH X86_BUG(3) /* "tlb_mmatch" AMD Erratum 383 */ +#define X86_BUG_AMD_APIC_C1E X86_BUG(4) /* "apic_c1e" AMD Erratum 400 */ +#define X86_BUG_11AP X86_BUG(5) /* Bad local APIC aka 11AP */ +#define X86_BUG_FXSAVE_LEAK X86_BUG(6) /* FXSAVE leaks FOP/FIP/FOP */ +#define X86_BUG_CLFLUSH_MONITOR X86_BUG(7) /* AAI65, CLFLUSH required before MONITOR */ +#define X86_BUG_SYSRET_SS_ATTRS X86_BUG(8) /* SYSRET doesn't fix up SS attrs */ +#define X86_BUG_NULL_SEG X86_BUG(9) /* Nulling a selector preserves the base */ +#define X86_BUG_SWAPGS_FENCE X86_BUG(10) /* SWAPGS without input dep on GS */ + + +#ifdef CONFIG_X86_32 +/* + * 64-bit kernels don't use X86_BUG_ESPFIX. Make the define conditional + * to avoid confusion. + */ +#define X86_BUG_ESPFIX X86_BUG(9) /* "" IRET to 16-bit SS corrupts ESP/RSP high bits */ +#endif + +#endif /* _ASM_X86_CPUFEATURES_H */ diff --git a/tools/arch/x86/include/asm/disabled-features.h b/tools/arch/x86/include/asm/disabled-features.h new file mode 100644 index 0000000..911e935 --- /dev/null +++ b/tools/arch/x86/include/asm/disabled-features.h @@ -0,0 +1,60 @@ +#ifndef _ASM_X86_DISABLED_FEATURES_H +#define _ASM_X86_DISABLED_FEATURES_H + +/* These features, although they might be available in a CPU + * will not be used because the compile options to support + * them are not present. + * + * This code allows them to be checked and disabled at + * compile time without an explicit #ifdef. Use + * cpu_feature_enabled(). + */ + +#ifdef CONFIG_X86_INTEL_MPX +# define DISABLE_MPX 0 +#else +# define DISABLE_MPX (1<<(X86_FEATURE_MPX & 31)) +#endif + +#ifdef CONFIG_X86_64 +# define DISABLE_VME (1<<(X86_FEATURE_VME & 31)) +# define DISABLE_K6_MTRR (1<<(X86_FEATURE_K6_MTRR & 31)) +# define DISABLE_CYRIX_ARR (1<<(X86_FEATURE_CYRIX_ARR & 31)) +# define DISABLE_CENTAUR_MCR (1<<(X86_FEATURE_CENTAUR_MCR & 31)) +#else +# define DISABLE_VME 0 +# define DISABLE_K6_MTRR 0 +# define DISABLE_CYRIX_ARR 0 +# define DISABLE_CENTAUR_MCR 0 +#endif /* CONFIG_X86_64 */ + +#ifdef CONFIG_X86_INTEL_MEMORY_PROTECTION_KEYS +# define DISABLE_PKU 0 +# define DISABLE_OSPKE 0 +#else +# define DISABLE_PKU (1<<(X86_FEATURE_PKU & 31)) +# define DISABLE_OSPKE (1<<(X86_FEATURE_OSPKE & 31)) +#endif /* CONFIG_X86_INTEL_MEMORY_PROTECTION_KEYS */ + +/* + * Make sure to add features to the correct mask + */ +#define DISABLED_MASK0 (DISABLE_VME) +#define DISABLED_MASK1 0 +#define DISABLED_MASK2 0 +#define DISABLED_MASK3 (DISABLE_CYRIX_ARR|DISABLE_CENTAUR_MCR|DISABLE_K6_MTRR) +#define DISABLED_MASK4 0 +#define DISABLED_MASK5 0 +#define DISABLED_MASK6 0 +#define DISABLED_MASK7 0 +#define DISABLED_MASK8 0 +#define DISABLED_MASK9 (DISABLE_MPX) +#define DISABLED_MASK10 0 +#define DISABLED_MASK11 0 +#define DISABLED_MASK12 0 +#define DISABLED_MASK13 0 +#define DISABLED_MASK14 0 +#define DISABLED_MASK15 0 +#define DISABLED_MASK16 (DISABLE_PKU|DISABLE_OSPKE) + +#endif /* _ASM_X86_DISABLED_FEATURES_H */ diff --git a/tools/arch/x86/include/asm/required-features.h b/tools/arch/x86/include/asm/required-features.h new file mode 100644 index 0000000..4916144 --- /dev/null +++ b/tools/arch/x86/include/asm/required-features.h @@ -0,0 +1,103 @@ +#ifndef _ASM_X86_REQUIRED_FEATURES_H +#define _ASM_X86_REQUIRED_FEATURES_H + +/* Define minimum CPUID feature set for kernel These bits are checked + really early to actually display a visible error message before the + kernel dies. Make sure to assign features to the proper mask! + + Some requirements that are not in CPUID yet are also in the + CONFIG_X86_MINIMUM_CPU_FAMILY which is checked too. + + The real information is in arch/x86/Kconfig.cpu, this just converts + the CONFIGs into a bitmask */ + +#ifndef CONFIG_MATH_EMULATION +# define NEED_FPU (1<<(X86_FEATURE_FPU & 31)) +#else +# define NEED_FPU 0 +#endif + +#if defined(CONFIG_X86_PAE) || defined(CONFIG_X86_64) +# define NEED_PAE (1<<(X86_FEATURE_PAE & 31)) +#else +# define NEED_PAE 0 +#endif + +#ifdef CONFIG_X86_CMPXCHG64 +# define NEED_CX8 (1<<(X86_FEATURE_CX8 & 31)) +#else +# define NEED_CX8 0 +#endif + +#if defined(CONFIG_X86_CMOV) || defined(CONFIG_X86_64) +# define NEED_CMOV (1<<(X86_FEATURE_CMOV & 31)) +#else +# define NEED_CMOV 0 +#endif + +#ifdef CONFIG_X86_USE_3DNOW +# define NEED_3DNOW (1<<(X86_FEATURE_3DNOW & 31)) +#else +# define NEED_3DNOW 0 +#endif + +#if defined(CONFIG_X86_P6_NOP) || defined(CONFIG_X86_64) +# define NEED_NOPL (1<<(X86_FEATURE_NOPL & 31)) +#else +# define NEED_NOPL 0 +#endif + +#ifdef CONFIG_MATOM +# define NEED_MOVBE (1<<(X86_FEATURE_MOVBE & 31)) +#else +# define NEED_MOVBE 0 +#endif + +#ifdef CONFIG_X86_64 +#ifdef CONFIG_PARAVIRT +/* Paravirtualized systems may not have PSE or PGE available */ +#define NEED_PSE 0 +#define NEED_PGE 0 +#else +#define NEED_PSE (1<<(X86_FEATURE_PSE) & 31) +#define NEED_PGE (1<<(X86_FEATURE_PGE) & 31) +#endif +#define NEED_MSR (1<<(X86_FEATURE_MSR & 31)) +#define NEED_FXSR (1<<(X86_FEATURE_FXSR & 31)) +#define NEED_XMM (1<<(X86_FEATURE_XMM & 31)) +#define NEED_XMM2 (1<<(X86_FEATURE_XMM2 & 31)) +#define NEED_LM (1<<(X86_FEATURE_LM & 31)) +#else +#define NEED_PSE 0 +#define NEED_MSR 0 +#define NEED_PGE 0 +#define NEED_FXSR 0 +#define NEED_XMM 0 +#define NEED_XMM2 0 +#define NEED_LM 0 +#endif + +#define REQUIRED_MASK0 (NEED_FPU|NEED_PSE|NEED_MSR|NEED_PAE|\ + NEED_CX8|NEED_PGE|NEED_FXSR|NEED_CMOV|\ + NEED_XMM|NEED_XMM2) +#define SSE_MASK (NEED_XMM|NEED_XMM2) + +#define REQUIRED_MASK1 (NEED_LM|NEED_3DNOW) + +#define REQUIRED_MASK2 0 +#define REQUIRED_MASK3 (NEED_NOPL) +#define REQUIRED_MASK4 (NEED_MOVBE) +#define REQUIRED_MASK5 0 +#define REQUIRED_MASK6 0 +#define REQUIRED_MASK7 0 +#define REQUIRED_MASK8 0 +#define REQUIRED_MASK9 0 +#define REQUIRED_MASK10 0 +#define REQUIRED_MASK11 0 +#define REQUIRED_MASK12 0 +#define REQUIRED_MASK13 0 +#define REQUIRED_MASK14 0 +#define REQUIRED_MASK15 0 +#define REQUIRED_MASK16 0 + +#endif /* _ASM_X86_REQUIRED_FEATURES_H */ diff --git a/tools/arch/x86/lib/memcpy_64.S b/tools/arch/x86/lib/memcpy_64.S new file mode 100644 index 0000000..2ec0b0abb --- /dev/null +++ b/tools/arch/x86/lib/memcpy_64.S @@ -0,0 +1,297 @@ +/* Copyright 2002 Andi Kleen */ + +#include +#include +#include +#include + +/* + * We build a jump to memcpy_orig by default which gets NOPped out on + * the majority of x86 CPUs which set REP_GOOD. In addition, CPUs which + * have the enhanced REP MOVSB/STOSB feature (ERMS), change those NOPs + * to a jmp to memcpy_erms which does the REP; MOVSB mem copy. + */ + +.weak memcpy + +/* + * memcpy - Copy a memory block. + * + * Input: + * rdi destination + * rsi source + * rdx count + * + * Output: + * rax original destination + */ +ENTRY(__memcpy) +ENTRY(memcpy) + ALTERNATIVE_2 "jmp memcpy_orig", "", X86_FEATURE_REP_GOOD, \ + "jmp memcpy_erms", X86_FEATURE_ERMS + + movq %rdi, %rax + movq %rdx, %rcx + shrq $3, %rcx + andl $7, %edx + rep movsq + movl %edx, %ecx + rep movsb + ret +ENDPROC(memcpy) +ENDPROC(__memcpy) + +/* + * memcpy_erms() - enhanced fast string memcpy. This is faster and + * simpler than memcpy. Use memcpy_erms when possible. + */ +ENTRY(memcpy_erms) + movq %rdi, %rax + movq %rdx, %rcx + rep movsb + ret +ENDPROC(memcpy_erms) + +ENTRY(memcpy_orig) + movq %rdi, %rax + + cmpq $0x20, %rdx + jb .Lhandle_tail + + /* + * We check whether memory false dependence could occur, + * then jump to corresponding copy mode. + */ + cmp %dil, %sil + jl .Lcopy_backward + subq $0x20, %rdx +.Lcopy_forward_loop: + subq $0x20, %rdx + + /* + * Move in blocks of 4x8 bytes: + */ + movq 0*8(%rsi), %r8 + movq 1*8(%rsi), %r9 + movq 2*8(%rsi), %r10 + movq 3*8(%rsi), %r11 + leaq 4*8(%rsi), %rsi + + movq %r8, 0*8(%rdi) + movq %r9, 1*8(%rdi) + movq %r10, 2*8(%rdi) + movq %r11, 3*8(%rdi) + leaq 4*8(%rdi), %rdi + jae .Lcopy_forward_loop + addl $0x20, %edx + jmp .Lhandle_tail + +.Lcopy_backward: + /* + * Calculate copy position to tail. + */ + addq %rdx, %rsi + addq %rdx, %rdi + subq $0x20, %rdx + /* + * At most 3 ALU operations in one cycle, + * so append NOPS in the same 16 bytes trunk. + */ + .p2align 4 +.Lcopy_backward_loop: + subq $0x20, %rdx + movq -1*8(%rsi), %r8 + movq -2*8(%rsi), %r9 + movq -3*8(%rsi), %r10 + movq -4*8(%rsi), %r11 + leaq -4*8(%rsi), %rsi + movq %r8, -1*8(%rdi) + movq %r9, -2*8(%rdi) + movq %r10, -3*8(%rdi) + movq %r11, -4*8(%rdi) + leaq -4*8(%rdi), %rdi + jae .Lcopy_backward_loop + + /* + * Calculate copy position to head. + */ + addl $0x20, %edx + subq %rdx, %rsi + subq %rdx, %rdi +.Lhandle_tail: + cmpl $16, %edx + jb .Lless_16bytes + + /* + * Move data from 16 bytes to 31 bytes. + */ + movq 0*8(%rsi), %r8 + movq 1*8(%rsi), %r9 + movq -2*8(%rsi, %rdx), %r10 + movq -1*8(%rsi, %rdx), %r11 + movq %r8, 0*8(%rdi) + movq %r9, 1*8(%rdi) + movq %r10, -2*8(%rdi, %rdx) + movq %r11, -1*8(%rdi, %rdx) + retq + .p2align 4 +.Lless_16bytes: + cmpl $8, %edx + jb .Lless_8bytes + /* + * Move data from 8 bytes to 15 bytes. + */ + movq 0*8(%rsi), %r8 + movq -1*8(%rsi, %rdx), %r9 + movq %r8, 0*8(%rdi) + movq %r9, -1*8(%rdi, %rdx) + retq + .p2align 4 +.Lless_8bytes: + cmpl $4, %edx + jb .Lless_3bytes + + /* + * Move data from 4 bytes to 7 bytes. + */ + movl (%rsi), %ecx + movl -4(%rsi, %rdx), %r8d + movl %ecx, (%rdi) + movl %r8d, -4(%rdi, %rdx) + retq + .p2align 4 +.Lless_3bytes: + subl $1, %edx + jb .Lend + /* + * Move data from 1 bytes to 3 bytes. + */ + movzbl (%rsi), %ecx + jz .Lstore_1byte + movzbq 1(%rsi), %r8 + movzbq (%rsi, %rdx), %r9 + movb %r8b, 1(%rdi) + movb %r9b, (%rdi, %rdx) +.Lstore_1byte: + movb %cl, (%rdi) + +.Lend: + retq +ENDPROC(memcpy_orig) + +#ifndef CONFIG_UML +/* + * memcpy_mcsafe - memory copy with machine check exception handling + * Note that we only catch machine checks when reading the source addresses. + * Writes to target are posted and don't generate machine checks. + */ +ENTRY(memcpy_mcsafe) + cmpl $8, %edx + /* Less than 8 bytes? Go to byte copy loop */ + jb .L_no_whole_words + + /* Check for bad alignment of source */ + testl $7, %esi + /* Already aligned */ + jz .L_8byte_aligned + + /* Copy one byte at a time until source is 8-byte aligned */ + movl %esi, %ecx + andl $7, %ecx + subl $8, %ecx + negl %ecx + subl %ecx, %edx +.L_copy_leading_bytes: + movb (%rsi), %al + movb %al, (%rdi) + incq %rsi + incq %rdi + decl %ecx + jnz .L_copy_leading_bytes + +.L_8byte_aligned: + /* Figure out how many whole cache lines (64-bytes) to copy */ + movl %edx, %ecx + andl $63, %edx + shrl $6, %ecx + jz .L_no_whole_cache_lines + + /* Loop copying whole cache lines */ +.L_cache_w0: movq (%rsi), %r8 +.L_cache_w1: movq 1*8(%rsi), %r9 +.L_cache_w2: movq 2*8(%rsi), %r10 +.L_cache_w3: movq 3*8(%rsi), %r11 + movq %r8, (%rdi) + movq %r9, 1*8(%rdi) + movq %r10, 2*8(%rdi) + movq %r11, 3*8(%rdi) +.L_cache_w4: movq 4*8(%rsi), %r8 +.L_cache_w5: movq 5*8(%rsi), %r9 +.L_cache_w6: movq 6*8(%rsi), %r10 +.L_cache_w7: movq 7*8(%rsi), %r11 + movq %r8, 4*8(%rdi) + movq %r9, 5*8(%rdi) + movq %r10, 6*8(%rdi) + movq %r11, 7*8(%rdi) + leaq 64(%rsi), %rsi + leaq 64(%rdi), %rdi + decl %ecx + jnz .L_cache_w0 + + /* Are there any trailing 8-byte words? */ +.L_no_whole_cache_lines: + movl %edx, %ecx + andl $7, %edx + shrl $3, %ecx + jz .L_no_whole_words + + /* Copy trailing words */ +.L_copy_trailing_words: + movq (%rsi), %r8 + mov %r8, (%rdi) + leaq 8(%rsi), %rsi + leaq 8(%rdi), %rdi + decl %ecx + jnz .L_copy_trailing_words + + /* Any trailing bytes? */ +.L_no_whole_words: + andl %edx, %edx + jz .L_done_memcpy_trap + + /* Copy trailing bytes */ + movl %edx, %ecx +.L_copy_trailing_bytes: + movb (%rsi), %al + movb %al, (%rdi) + incq %rsi + incq %rdi + decl %ecx + jnz .L_copy_trailing_bytes + + /* Copy successful. Return zero */ +.L_done_memcpy_trap: + xorq %rax, %rax + ret +ENDPROC(memcpy_mcsafe) + + .section .fixup, "ax" + /* Return -EFAULT for any failure */ +.L_memcpy_mcsafe_fail: + mov $-EFAULT, %rax + ret + + .previous + + _ASM_EXTABLE_FAULT(.L_copy_leading_bytes, .L_memcpy_mcsafe_fail) + _ASM_EXTABLE_FAULT(.L_cache_w0, .L_memcpy_mcsafe_fail) + _ASM_EXTABLE_FAULT(.L_cache_w1, .L_memcpy_mcsafe_fail) + _ASM_EXTABLE_FAULT(.L_cache_w3, .L_memcpy_mcsafe_fail) + _ASM_EXTABLE_FAULT(.L_cache_w3, .L_memcpy_mcsafe_fail) + _ASM_EXTABLE_FAULT(.L_cache_w4, .L_memcpy_mcsafe_fail) + _ASM_EXTABLE_FAULT(.L_cache_w5, .L_memcpy_mcsafe_fail) + _ASM_EXTABLE_FAULT(.L_cache_w6, .L_memcpy_mcsafe_fail) + _ASM_EXTABLE_FAULT(.L_cache_w7, .L_memcpy_mcsafe_fail) + _ASM_EXTABLE_FAULT(.L_copy_trailing_words, .L_memcpy_mcsafe_fail) + _ASM_EXTABLE_FAULT(.L_copy_trailing_bytes, .L_memcpy_mcsafe_fail) +#endif diff --git a/tools/arch/x86/lib/memset_64.S b/tools/arch/x86/lib/memset_64.S new file mode 100644 index 0000000..e1229ec --- /dev/null +++ b/tools/arch/x86/lib/memset_64.S @@ -0,0 +1,138 @@ +/* Copyright 2002 Andi Kleen, SuSE Labs */ + +#include +#include +#include + +.weak memset + +/* + * ISO C memset - set a memory block to a byte value. This function uses fast + * string to get better performance than the original function. The code is + * simpler and shorter than the original function as well. + * + * rdi destination + * rsi value (char) + * rdx count (bytes) + * + * rax original destination + */ +ENTRY(memset) +ENTRY(__memset) + /* + * Some CPUs support enhanced REP MOVSB/STOSB feature. It is recommended + * to use it when possible. If not available, use fast string instructions. + * + * Otherwise, use original memset function. + */ + ALTERNATIVE_2 "jmp memset_orig", "", X86_FEATURE_REP_GOOD, \ + "jmp memset_erms", X86_FEATURE_ERMS + + movq %rdi,%r9 + movq %rdx,%rcx + andl $7,%edx + shrq $3,%rcx + /* expand byte value */ + movzbl %sil,%esi + movabs $0x0101010101010101,%rax + imulq %rsi,%rax + rep stosq + movl %edx,%ecx + rep stosb + movq %r9,%rax + ret +ENDPROC(memset) +ENDPROC(__memset) + +/* + * ISO C memset - set a memory block to a byte value. This function uses + * enhanced rep stosb to override the fast string function. + * The code is simpler and shorter than the fast string function as well. + * + * rdi destination + * rsi value (char) + * rdx count (bytes) + * + * rax original destination + */ +ENTRY(memset_erms) + movq %rdi,%r9 + movb %sil,%al + movq %rdx,%rcx + rep stosb + movq %r9,%rax + ret +ENDPROC(memset_erms) + +ENTRY(memset_orig) + movq %rdi,%r10 + + /* expand byte value */ + movzbl %sil,%ecx + movabs $0x0101010101010101,%rax + imulq %rcx,%rax + + /* align dst */ + movl %edi,%r9d + andl $7,%r9d + jnz .Lbad_alignment +.Lafter_bad_alignment: + + movq %rdx,%rcx + shrq $6,%rcx + jz .Lhandle_tail + + .p2align 4 +.Lloop_64: + decq %rcx + movq %rax,(%rdi) + movq %rax,8(%rdi) + movq %rax,16(%rdi) + movq %rax,24(%rdi) + movq %rax,32(%rdi) + movq %rax,40(%rdi) + movq %rax,48(%rdi) + movq %rax,56(%rdi) + leaq 64(%rdi),%rdi + jnz .Lloop_64 + + /* Handle tail in loops. The loops should be faster than hard + to predict jump tables. */ + .p2align 4 +.Lhandle_tail: + movl %edx,%ecx + andl $63&(~7),%ecx + jz .Lhandle_7 + shrl $3,%ecx + .p2align 4 +.Lloop_8: + decl %ecx + movq %rax,(%rdi) + leaq 8(%rdi),%rdi + jnz .Lloop_8 + +.Lhandle_7: + andl $7,%edx + jz .Lende + .p2align 4 +.Lloop_1: + decl %edx + movb %al,(%rdi) + leaq 1(%rdi),%rdi + jnz .Lloop_1 + +.Lende: + movq %r10,%rax + ret + +.Lbad_alignment: + cmpq $7,%rdx + jbe .Lhandle_7 + movq %rax,(%rdi) /* unaligned store */ + movq $8,%r8 + subq %r9,%r8 + addq %r8,%rdi + subq %r8,%rdx + jmp .Lafter_bad_alignment +.Lfinal: +ENDPROC(memset_orig) diff --git a/tools/include/asm/alternative-asm.h b/tools/include/asm/alternative-asm.h new file mode 100644 index 0000000..2a4d1bf --- /dev/null +++ b/tools/include/asm/alternative-asm.h @@ -0,0 +1,9 @@ +#ifndef _TOOLS_ASM_ALTERNATIVE_ASM_H +#define _TOOLS_ASM_ALTERNATIVE_ASM_H + +/* Just disable it so we can build arch/x86/lib/memcpy_64.S for perf bench: */ + +#define altinstruction_entry # +#define ALTERNATIVE_2 # + +#endif diff --git a/tools/perf/MANIFEST b/tools/perf/MANIFEST index 0b1ebf3..cf85d1c 100644 --- a/tools/perf/MANIFEST +++ b/tools/perf/MANIFEST @@ -12,6 +12,11 @@ tools/arch/sparc/include/asm/barrier_32.h tools/arch/sparc/include/asm/barrier_64.h tools/arch/tile/include/asm/barrier.h tools/arch/x86/include/asm/barrier.h +tools/arch/x86/include/asm/cpufeatures.h +tools/arch/x86/include/asm/disabled-features.h +tools/arch/x86/include/asm/required-features.h +tools/arch/x86/lib/memcpy_64.S +tools/arch/x86/lib/memset_64.S tools/arch/xtensa/include/asm/barrier.h tools/scripts tools/build @@ -31,6 +36,7 @@ tools/lib/find_bit.c tools/lib/bitmap.c tools/lib/str_error_r.c tools/lib/vsprintf.c +tools/include/asm/alternative-asm.h tools/include/asm/atomic.h tools/include/asm/barrier.h tools/include/asm/bug.h @@ -74,9 +80,6 @@ include/linux/swab.h arch/*/include/asm/unistd*.h arch/*/include/uapi/asm/unistd*.h arch/*/include/uapi/asm/perf_regs.h -arch/*/lib/memcpy*.S -arch/*/lib/memset*.S -arch/*/include/asm/*features.h include/linux/poison.h include/linux/hw_breakpoint.h include/uapi/linux/bpf.h diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf index 5e5f8cb..809735c 100644 --- a/tools/perf/Makefile.perf +++ b/tools/perf/Makefile.perf @@ -348,6 +348,21 @@ $(PERF_IN): prepare FORCE @(test -f ../../include/uapi/linux/perf_event.h && ( \ (diff -B ../include/uapi/linux/perf_event.h ../../include/uapi/linux/perf_event.h >/dev/null) \ || echo "Warning: tools/include/uapi/linux/perf_event.h differs from kernel" >&2 )) || true + @(test -f ../../arch/x86/include/asm/disabled-features.h && ( \ + (diff -B ../arch/x86/include/asm/disabled-features.h ../../arch/x86/include/asm/disabled-features.h >/dev/null) \ + || echo "Warning: tools/arch/x86/include/asm/disabled-features.h differs from kernel" >&2 )) || true + @(test -f ../../arch/x86/include/asm/required-features.h && ( \ + (diff -B ../arch/x86/include/asm/required-features.h ../../arch/x86/include/asm/required-features.h >/dev/null) \ + || echo "Warning: tools/arch/x86/include/asm/required-features.h differs from kernel" >&2 )) || true + @(test -f ../../arch/x86/include/asm/cpufeatures.h && ( \ + (diff -B ../arch/x86/include/asm/cpufeatures.h ../../arch/x86/include/asm/cpufeatures.h >/dev/null) \ + || echo "Warning: tools/arch/x86/include/asm/cpufeatures.h differs from kernel" >&2 )) || true + @(test -f ../../arch/x86/lib/memcpy_64.S && ( \ + (diff -B ../arch/x86/lib/memcpy_64.S ../../arch/x86/lib/memcpy_64.S >/dev/null) \ + || echo "Warning: tools/arch/x86/lib/memcpy_64.S differs from kernel" >&2 )) || true + @(test -f ../../arch/x86/lib/memset_64.S && ( \ + (diff -B ../arch/x86/lib/memset_64.S ../../arch/x86/lib/memset_64.S >/dev/null) \ + || echo "Warning: tools/arch/x86/lib/memset_64.S differs from kernel" >&2 )) || true $(Q)$(MAKE) $(build)=perf $(OUTPUT)perf: $(PERFLIBS) $(PERF_IN) $(LIBTRACEEVENT_DYNAMIC_LIST) diff --git a/tools/perf/bench/mem-memcpy-x86-64-asm.S b/tools/perf/bench/mem-memcpy-x86-64-asm.S index 5c3cce0..f700369 100644 --- a/tools/perf/bench/mem-memcpy-x86-64-asm.S +++ b/tools/perf/bench/mem-memcpy-x86-64-asm.S @@ -6,7 +6,7 @@ #define globl p2align 4; .globl #define _ASM_EXTABLE_FAULT(x, y) -#include "../../../arch/x86/lib/memcpy_64.S" +#include "../../arch/x86/lib/memcpy_64.S" /* * We need to provide note.GNU-stack section, saying that we want * NOT executable stack. Otherwise the final linking will assume that diff --git a/tools/perf/bench/mem-memset-x86-64-asm.S b/tools/perf/bench/mem-memset-x86-64-asm.S index de27878..58407aa 100644 --- a/tools/perf/bench/mem-memset-x86-64-asm.S +++ b/tools/perf/bench/mem-memset-x86-64-asm.S @@ -1,7 +1,7 @@ #define memset MEMSET /* don't hide glibc's memset() */ #define altinstr_replacement text #define globl p2align 4; .globl -#include "../../../arch/x86/lib/memset_64.S" +#include "../../arch/x86/lib/memset_64.S" /* * We need to provide note.GNU-stack section, saying that we want diff --git a/tools/perf/util/include/asm/alternative-asm.h b/tools/perf/util/include/asm/alternative-asm.h deleted file mode 100644 index 3a3a0f1..0000000 --- a/tools/perf/util/include/asm/alternative-asm.h +++ /dev/null @@ -1,9 +0,0 @@ -#ifndef _PERF_ASM_ALTERNATIVE_ASM_H -#define _PERF_ASM_ALTERNATIVE_ASM_H - -/* Just disable it so we can build arch/x86/lib/memcpy_64.S for perf bench: */ - -#define altinstruction_entry # -#define ALTERNATIVE_2 # - -#endif -- cgit v0.10.2 From 971e827bffef781dd089a402fe602ff20c1f1819 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Mon, 11 Jul 2016 16:38:05 -0300 Subject: tools lib bpf: Copy bpf.h and bpf_common.h from the kernel To allow the build to complete on older systems, where those files are either not uptodate, lacking some recent additions or not present at all. And check if the copy drifts from the kernel, as in this synthetic test: BUILD: Doing 'make -j4' parallel build Warning: tools/include/linux/bpf.h differs from kernel Warning: tools/include/linux/bpf_common.h differs from kernel Cc: Adrian Hunter Cc: David Ahern Cc: Jiri Olsa Cc: Namhyung Kim Cc: Wang Nan Link: http://lkml.kernel.org/n/tip-5plvi2gq4x469dcyybiu226q@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h new file mode 100644 index 0000000..406459b --- /dev/null +++ b/tools/include/uapi/linux/bpf.h @@ -0,0 +1,389 @@ +/* Copyright (c) 2011-2014 PLUMgrid, http://plumgrid.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of version 2 of the GNU General Public + * License as published by the Free Software Foundation. + */ +#ifndef _UAPI__LINUX_BPF_H__ +#define _UAPI__LINUX_BPF_H__ + +#include +#include + +/* Extended instruction set based on top of classic BPF */ + +/* instruction classes */ +#define BPF_ALU64 0x07 /* alu mode in double word width */ + +/* ld/ldx fields */ +#define BPF_DW 0x18 /* double word */ +#define BPF_XADD 0xc0 /* exclusive add */ + +/* alu/jmp fields */ +#define BPF_MOV 0xb0 /* mov reg to reg */ +#define BPF_ARSH 0xc0 /* sign extending arithmetic shift right */ + +/* change endianness of a register */ +#define BPF_END 0xd0 /* flags for endianness conversion: */ +#define BPF_TO_LE 0x00 /* convert to little-endian */ +#define BPF_TO_BE 0x08 /* convert to big-endian */ +#define BPF_FROM_LE BPF_TO_LE +#define BPF_FROM_BE BPF_TO_BE + +#define BPF_JNE 0x50 /* jump != */ +#define BPF_JSGT 0x60 /* SGT is signed '>', GT in x86 */ +#define BPF_JSGE 0x70 /* SGE is signed '>=', GE in x86 */ +#define BPF_CALL 0x80 /* function call */ +#define BPF_EXIT 0x90 /* function return */ + +/* Register numbers */ +enum { + BPF_REG_0 = 0, + BPF_REG_1, + BPF_REG_2, + BPF_REG_3, + BPF_REG_4, + BPF_REG_5, + BPF_REG_6, + BPF_REG_7, + BPF_REG_8, + BPF_REG_9, + BPF_REG_10, + __MAX_BPF_REG, +}; + +/* BPF has 10 general purpose 64-bit registers and stack frame. */ +#define MAX_BPF_REG __MAX_BPF_REG + +struct bpf_insn { + __u8 code; /* opcode */ + __u8 dst_reg:4; /* dest register */ + __u8 src_reg:4; /* source register */ + __s16 off; /* signed offset */ + __s32 imm; /* signed immediate constant */ +}; + +/* BPF syscall commands, see bpf(2) man-page for details. */ +enum bpf_cmd { + BPF_MAP_CREATE, + BPF_MAP_LOOKUP_ELEM, + BPF_MAP_UPDATE_ELEM, + BPF_MAP_DELETE_ELEM, + BPF_MAP_GET_NEXT_KEY, + BPF_PROG_LOAD, + BPF_OBJ_PIN, + BPF_OBJ_GET, +}; + +enum bpf_map_type { + BPF_MAP_TYPE_UNSPEC, + BPF_MAP_TYPE_HASH, + BPF_MAP_TYPE_ARRAY, + BPF_MAP_TYPE_PROG_ARRAY, + BPF_MAP_TYPE_PERF_EVENT_ARRAY, + BPF_MAP_TYPE_PERCPU_HASH, + BPF_MAP_TYPE_PERCPU_ARRAY, + BPF_MAP_TYPE_STACK_TRACE, +}; + +enum bpf_prog_type { + BPF_PROG_TYPE_UNSPEC, + BPF_PROG_TYPE_SOCKET_FILTER, + BPF_PROG_TYPE_KPROBE, + BPF_PROG_TYPE_SCHED_CLS, + BPF_PROG_TYPE_SCHED_ACT, + BPF_PROG_TYPE_TRACEPOINT, +}; + +#define BPF_PSEUDO_MAP_FD 1 + +/* flags for BPF_MAP_UPDATE_ELEM command */ +#define BPF_ANY 0 /* create new element or update existing */ +#define BPF_NOEXIST 1 /* create new element if it didn't exist */ +#define BPF_EXIST 2 /* update existing element */ + +#define BPF_F_NO_PREALLOC (1U << 0) + +union bpf_attr { + struct { /* anonymous struct used by BPF_MAP_CREATE command */ + __u32 map_type; /* one of enum bpf_map_type */ + __u32 key_size; /* size of key in bytes */ + __u32 value_size; /* size of value in bytes */ + __u32 max_entries; /* max number of entries in a map */ + __u32 map_flags; /* prealloc or not */ + }; + + struct { /* anonymous struct used by BPF_MAP_*_ELEM commands */ + __u32 map_fd; + __aligned_u64 key; + union { + __aligned_u64 value; + __aligned_u64 next_key; + }; + __u64 flags; + }; + + struct { /* anonymous struct used by BPF_PROG_LOAD command */ + __u32 prog_type; /* one of enum bpf_prog_type */ + __u32 insn_cnt; + __aligned_u64 insns; + __aligned_u64 license; + __u32 log_level; /* verbosity level of verifier */ + __u32 log_size; /* size of user buffer */ + __aligned_u64 log_buf; /* user supplied buffer */ + __u32 kern_version; /* checked when prog_type=kprobe */ + }; + + struct { /* anonymous struct used by BPF_OBJ_* commands */ + __aligned_u64 pathname; + __u32 bpf_fd; + }; +} __attribute__((aligned(8))); + +/* integer value in 'imm' field of BPF_CALL instruction selects which helper + * function eBPF program intends to call + */ +enum bpf_func_id { + BPF_FUNC_unspec, + BPF_FUNC_map_lookup_elem, /* void *map_lookup_elem(&map, &key) */ + BPF_FUNC_map_update_elem, /* int map_update_elem(&map, &key, &value, flags) */ + BPF_FUNC_map_delete_elem, /* int map_delete_elem(&map, &key) */ + BPF_FUNC_probe_read, /* int bpf_probe_read(void *dst, int size, void *src) */ + BPF_FUNC_ktime_get_ns, /* u64 bpf_ktime_get_ns(void) */ + BPF_FUNC_trace_printk, /* int bpf_trace_printk(const char *fmt, int fmt_size, ...) */ + BPF_FUNC_get_prandom_u32, /* u32 prandom_u32(void) */ + BPF_FUNC_get_smp_processor_id, /* u32 raw_smp_processor_id(void) */ + + /** + * skb_store_bytes(skb, offset, from, len, flags) - store bytes into packet + * @skb: pointer to skb + * @offset: offset within packet from skb->mac_header + * @from: pointer where to copy bytes from + * @len: number of bytes to store into packet + * @flags: bit 0 - if true, recompute skb->csum + * other bits - reserved + * Return: 0 on success + */ + BPF_FUNC_skb_store_bytes, + + /** + * l3_csum_replace(skb, offset, from, to, flags) - recompute IP checksum + * @skb: pointer to skb + * @offset: offset within packet where IP checksum is located + * @from: old value of header field + * @to: new value of header field + * @flags: bits 0-3 - size of header field + * other bits - reserved + * Return: 0 on success + */ + BPF_FUNC_l3_csum_replace, + + /** + * l4_csum_replace(skb, offset, from, to, flags) - recompute TCP/UDP checksum + * @skb: pointer to skb + * @offset: offset within packet where TCP/UDP checksum is located + * @from: old value of header field + * @to: new value of header field + * @flags: bits 0-3 - size of header field + * bit 4 - is pseudo header + * other bits - reserved + * Return: 0 on success + */ + BPF_FUNC_l4_csum_replace, + + /** + * bpf_tail_call(ctx, prog_array_map, index) - jump into another BPF program + * @ctx: context pointer passed to next program + * @prog_array_map: pointer to map which type is BPF_MAP_TYPE_PROG_ARRAY + * @index: index inside array that selects specific program to run + * Return: 0 on success + */ + BPF_FUNC_tail_call, + + /** + * bpf_clone_redirect(skb, ifindex, flags) - redirect to another netdev + * @skb: pointer to skb + * @ifindex: ifindex of the net device + * @flags: bit 0 - if set, redirect to ingress instead of egress + * other bits - reserved + * Return: 0 on success + */ + BPF_FUNC_clone_redirect, + + /** + * u64 bpf_get_current_pid_tgid(void) + * Return: current->tgid << 32 | current->pid + */ + BPF_FUNC_get_current_pid_tgid, + + /** + * u64 bpf_get_current_uid_gid(void) + * Return: current_gid << 32 | current_uid + */ + BPF_FUNC_get_current_uid_gid, + + /** + * bpf_get_current_comm(char *buf, int size_of_buf) + * stores current->comm into buf + * Return: 0 on success + */ + BPF_FUNC_get_current_comm, + + /** + * bpf_get_cgroup_classid(skb) - retrieve a proc's classid + * @skb: pointer to skb + * Return: classid if != 0 + */ + BPF_FUNC_get_cgroup_classid, + BPF_FUNC_skb_vlan_push, /* bpf_skb_vlan_push(skb, vlan_proto, vlan_tci) */ + BPF_FUNC_skb_vlan_pop, /* bpf_skb_vlan_pop(skb) */ + + /** + * bpf_skb_[gs]et_tunnel_key(skb, key, size, flags) + * retrieve or populate tunnel metadata + * @skb: pointer to skb + * @key: pointer to 'struct bpf_tunnel_key' + * @size: size of 'struct bpf_tunnel_key' + * @flags: room for future extensions + * Retrun: 0 on success + */ + BPF_FUNC_skb_get_tunnel_key, + BPF_FUNC_skb_set_tunnel_key, + BPF_FUNC_perf_event_read, /* u64 bpf_perf_event_read(&map, index) */ + /** + * bpf_redirect(ifindex, flags) - redirect to another netdev + * @ifindex: ifindex of the net device + * @flags: bit 0 - if set, redirect to ingress instead of egress + * other bits - reserved + * Return: TC_ACT_REDIRECT + */ + BPF_FUNC_redirect, + + /** + * bpf_get_route_realm(skb) - retrieve a dst's tclassid + * @skb: pointer to skb + * Return: realm if != 0 + */ + BPF_FUNC_get_route_realm, + + /** + * bpf_perf_event_output(ctx, map, index, data, size) - output perf raw sample + * @ctx: struct pt_regs* + * @map: pointer to perf_event_array map + * @index: index of event in the map + * @data: data on stack to be output as raw data + * @size: size of data + * Return: 0 on success + */ + BPF_FUNC_perf_event_output, + BPF_FUNC_skb_load_bytes, + + /** + * bpf_get_stackid(ctx, map, flags) - walk user or kernel stack and return id + * @ctx: struct pt_regs* + * @map: pointer to stack_trace map + * @flags: bits 0-7 - numer of stack frames to skip + * bit 8 - collect user stack instead of kernel + * bit 9 - compare stacks by hash only + * bit 10 - if two different stacks hash into the same stackid + * discard old + * other bits - reserved + * Return: >= 0 stackid on success or negative error + */ + BPF_FUNC_get_stackid, + + /** + * bpf_csum_diff(from, from_size, to, to_size, seed) - calculate csum diff + * @from: raw from buffer + * @from_size: length of from buffer + * @to: raw to buffer + * @to_size: length of to buffer + * @seed: optional seed + * Return: csum result + */ + BPF_FUNC_csum_diff, + + /** + * bpf_skb_[gs]et_tunnel_opt(skb, opt, size) + * retrieve or populate tunnel options metadata + * @skb: pointer to skb + * @opt: pointer to raw tunnel option data + * @size: size of @opt + * Return: 0 on success for set, option size for get + */ + BPF_FUNC_skb_get_tunnel_opt, + BPF_FUNC_skb_set_tunnel_opt, + __BPF_FUNC_MAX_ID, +}; + +/* All flags used by eBPF helper functions, placed here. */ + +/* BPF_FUNC_skb_store_bytes flags. */ +#define BPF_F_RECOMPUTE_CSUM (1ULL << 0) +#define BPF_F_INVALIDATE_HASH (1ULL << 1) + +/* BPF_FUNC_l3_csum_replace and BPF_FUNC_l4_csum_replace flags. + * First 4 bits are for passing the header field size. + */ +#define BPF_F_HDR_FIELD_MASK 0xfULL + +/* BPF_FUNC_l4_csum_replace flags. */ +#define BPF_F_PSEUDO_HDR (1ULL << 4) +#define BPF_F_MARK_MANGLED_0 (1ULL << 5) + +/* BPF_FUNC_clone_redirect and BPF_FUNC_redirect flags. */ +#define BPF_F_INGRESS (1ULL << 0) + +/* BPF_FUNC_skb_set_tunnel_key and BPF_FUNC_skb_get_tunnel_key flags. */ +#define BPF_F_TUNINFO_IPV6 (1ULL << 0) + +/* BPF_FUNC_get_stackid flags. */ +#define BPF_F_SKIP_FIELD_MASK 0xffULL +#define BPF_F_USER_STACK (1ULL << 8) +#define BPF_F_FAST_STACK_CMP (1ULL << 9) +#define BPF_F_REUSE_STACKID (1ULL << 10) + +/* BPF_FUNC_skb_set_tunnel_key flags. */ +#define BPF_F_ZERO_CSUM_TX (1ULL << 1) +#define BPF_F_DONT_FRAGMENT (1ULL << 2) + +/* BPF_FUNC_perf_event_output flags. */ +#define BPF_F_INDEX_MASK 0xffffffffULL +#define BPF_F_CURRENT_CPU BPF_F_INDEX_MASK + +/* user accessible mirror of in-kernel sk_buff. + * new fields can only be added to the end of this structure + */ +struct __sk_buff { + __u32 len; + __u32 pkt_type; + __u32 mark; + __u32 queue_mapping; + __u32 protocol; + __u32 vlan_present; + __u32 vlan_tci; + __u32 vlan_proto; + __u32 priority; + __u32 ingress_ifindex; + __u32 ifindex; + __u32 tc_index; + __u32 cb[5]; + __u32 hash; + __u32 tc_classid; + __u32 data; + __u32 data_end; +}; + +struct bpf_tunnel_key { + __u32 tunnel_id; + union { + __u32 remote_ipv4; + __u32 remote_ipv6[4]; + }; + __u8 tunnel_tos; + __u8 tunnel_ttl; + __u16 tunnel_ext; + __u32 tunnel_label; +}; + +#endif /* _UAPI__LINUX_BPF_H__ */ diff --git a/tools/include/uapi/linux/bpf_common.h b/tools/include/uapi/linux/bpf_common.h new file mode 100644 index 0000000..a5c220e --- /dev/null +++ b/tools/include/uapi/linux/bpf_common.h @@ -0,0 +1,55 @@ +#ifndef _UAPI__LINUX_BPF_COMMON_H__ +#define _UAPI__LINUX_BPF_COMMON_H__ + +/* Instruction classes */ +#define BPF_CLASS(code) ((code) & 0x07) +#define BPF_LD 0x00 +#define BPF_LDX 0x01 +#define BPF_ST 0x02 +#define BPF_STX 0x03 +#define BPF_ALU 0x04 +#define BPF_JMP 0x05 +#define BPF_RET 0x06 +#define BPF_MISC 0x07 + +/* ld/ldx fields */ +#define BPF_SIZE(code) ((code) & 0x18) +#define BPF_W 0x00 +#define BPF_H 0x08 +#define BPF_B 0x10 +#define BPF_MODE(code) ((code) & 0xe0) +#define BPF_IMM 0x00 +#define BPF_ABS 0x20 +#define BPF_IND 0x40 +#define BPF_MEM 0x60 +#define BPF_LEN 0x80 +#define BPF_MSH 0xa0 + +/* alu/jmp fields */ +#define BPF_OP(code) ((code) & 0xf0) +#define BPF_ADD 0x00 +#define BPF_SUB 0x10 +#define BPF_MUL 0x20 +#define BPF_DIV 0x30 +#define BPF_OR 0x40 +#define BPF_AND 0x50 +#define BPF_LSH 0x60 +#define BPF_RSH 0x70 +#define BPF_NEG 0x80 +#define BPF_MOD 0x90 +#define BPF_XOR 0xa0 + +#define BPF_JA 0x00 +#define BPF_JEQ 0x10 +#define BPF_JGT 0x20 +#define BPF_JGE 0x30 +#define BPF_JSET 0x40 +#define BPF_SRC(code) ((code) & 0x08) +#define BPF_K 0x00 +#define BPF_X 0x08 + +#ifndef BPF_MAXINSNS +#define BPF_MAXINSNS 4096 +#endif + +#endif /* _UAPI__LINUX_BPF_COMMON_H__ */ diff --git a/tools/lib/bpf/Makefile b/tools/lib/bpf/Makefile index fc1bc75..62d89d5 100644 --- a/tools/lib/bpf/Makefile +++ b/tools/lib/bpf/Makefile @@ -68,7 +68,7 @@ FEATURE_USER = .libbpf FEATURE_TESTS = libelf libelf-getphdrnum libelf-mmap bpf FEATURE_DISPLAY = libelf bpf -INCLUDES = -I. -I$(srctree)/tools/include -I$(srctree)/arch/$(ARCH)/include/uapi -I$(srctree)/include/uapi +INCLUDES = -I. -I$(srctree)/tools/include -I$(srctree)/tools/arch/$(ARCH)/include/uapi -I$(srctree)/tools/include/uapi FEATURE_CHECK_CFLAGS-bpf = $(INCLUDES) check_feat := 1 @@ -154,6 +154,12 @@ all: fixdep $(VERSION_FILES) all_cmd all_cmd: $(CMD_TARGETS) $(BPF_IN): force elfdep bpfdep + @(test -f ../../../include/uapi/linux/bpf.h -a -f ../../../include/uapi/linux/bpf.h && ( \ + (diff -B ../../include/uapi/linux/bpf.h ../../../include/uapi/linux/bpf.h >/dev/null) || \ + echo "Warning: tools/include/uapi/linux/bpf.h differs from kernel" >&2 )) || true + @(test -f ../../../include/uapi/linux/bpf_common.h -a -f ../../../include/uapi/linux/bpf_common.h && ( \ + (diff -B ../../include/uapi/linux/bpf_common.h ../../../include/uapi/linux/bpf_common.h >/dev/null) || \ + echo "Warning: tools/include/uapi/linux/bpf_common.h differs from kernel" >&2 )) || true $(Q)$(MAKE) $(build)=libbpf $(OUTPUT)libbpf.so: $(BPF_IN) diff --git a/tools/perf/MANIFEST b/tools/perf/MANIFEST index cf85d1c..a300cbb 100644 --- a/tools/perf/MANIFEST +++ b/tools/perf/MANIFEST @@ -23,7 +23,6 @@ tools/build tools/arch/x86/include/asm/atomic.h tools/arch/x86/include/asm/rmwcc.h tools/lib/traceevent -tools/lib/bpf tools/lib/api tools/lib/bpf tools/lib/subcmd @@ -60,6 +59,8 @@ tools/include/linux/hash.h tools/include/linux/kernel.h tools/include/linux/list.h tools/include/linux/log2.h +tools/include/uapi/linux/bpf.h +tools/include/uapi/linux/bpf_common.h tools/include/uapi/linux/perf_event.h tools/include/linux/poison.h tools/include/linux/rbtree.h @@ -82,8 +83,6 @@ arch/*/include/uapi/asm/unistd*.h arch/*/include/uapi/asm/perf_regs.h include/linux/poison.h include/linux/hw_breakpoint.h -include/uapi/linux/bpf.h -include/uapi/linux/bpf_common.h include/uapi/linux/const.h include/uapi/linux/swab.h include/uapi/linux/hw_breakpoint.h diff --git a/tools/perf/config/Makefile b/tools/perf/config/Makefile index bbb2210..d629e5f 100644 --- a/tools/perf/config/Makefile +++ b/tools/perf/config/Makefile @@ -115,7 +115,7 @@ endif FEATURE_CHECK_CFLAGS-libbabeltrace := $(LIBBABELTRACE_CFLAGS) FEATURE_CHECK_LDFLAGS-libbabeltrace := $(LIBBABELTRACE_LDFLAGS) -lbabeltrace-ctf -FEATURE_CHECK_CFLAGS-bpf = -I. -I$(srctree)/tools/include -I$(srctree)/arch/$(ARCH)/include/uapi -I$(srctree)/include/uapi +FEATURE_CHECK_CFLAGS-bpf = -I. -I$(srctree)/tools/include -I$(srctree)/tools/arch/$(ARCH)/include/uapi -I$(srctree)/tools/include/uapi # include ARCH specific config -include $(src-perf)/arch/$(ARCH)/Makefile @@ -210,7 +210,8 @@ CFLAGS += -I$(srctree)/tools/include/uapi CFLAGS += -I$(srctree)/tools/include/ CFLAGS += -I$(srctree)/arch/$(ARCH)/include/uapi CFLAGS += -I$(srctree)/arch/$(ARCH)/include -CFLAGS += -I$(srctree)/tools/arch/$(ARCH)/include +CFLAGS += -I$(srctree)/tools/arch/$(ARCH)/include/uapi +CFLAGS += -I$(srctree)/tools/arch/$(ARCH)/ CFLAGS += -I$(srctree)/include/uapi CFLAGS += -I$(srctree)/include -- cgit v0.10.2 From 12f020338a2ca5db99db40b3cf8e4df88744c541 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Mon, 11 Jul 2016 21:16:52 -0300 Subject: tools: Copy uapi/asm/perf_regs.h from the kernel To allow the build to complete on older systems, where those files are either not uptodate, lacking some recent additions or not present at all. And check if the copy drifts from the kernel. Cc: Adrian Hunter Cc: David Ahern Cc: Jiri Olsa Cc: Namhyung Kim Cc: Wang Nan Link: http://lkml.kernel.org/n/tip-sxf7rpow2blsno5f7t6n0sqz@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/arch/arm/include/uapi/asm/perf_regs.h b/tools/arch/arm/include/uapi/asm/perf_regs.h new file mode 100644 index 0000000..ce59448 --- /dev/null +++ b/tools/arch/arm/include/uapi/asm/perf_regs.h @@ -0,0 +1,23 @@ +#ifndef _ASM_ARM_PERF_REGS_H +#define _ASM_ARM_PERF_REGS_H + +enum perf_event_arm_regs { + PERF_REG_ARM_R0, + PERF_REG_ARM_R1, + PERF_REG_ARM_R2, + PERF_REG_ARM_R3, + PERF_REG_ARM_R4, + PERF_REG_ARM_R5, + PERF_REG_ARM_R6, + PERF_REG_ARM_R7, + PERF_REG_ARM_R8, + PERF_REG_ARM_R9, + PERF_REG_ARM_R10, + PERF_REG_ARM_FP, + PERF_REG_ARM_IP, + PERF_REG_ARM_SP, + PERF_REG_ARM_LR, + PERF_REG_ARM_PC, + PERF_REG_ARM_MAX, +}; +#endif /* _ASM_ARM_PERF_REGS_H */ diff --git a/tools/arch/arm64/include/uapi/asm/perf_regs.h b/tools/arch/arm64/include/uapi/asm/perf_regs.h new file mode 100644 index 0000000..172b831 --- /dev/null +++ b/tools/arch/arm64/include/uapi/asm/perf_regs.h @@ -0,0 +1,40 @@ +#ifndef _ASM_ARM64_PERF_REGS_H +#define _ASM_ARM64_PERF_REGS_H + +enum perf_event_arm_regs { + PERF_REG_ARM64_X0, + PERF_REG_ARM64_X1, + PERF_REG_ARM64_X2, + PERF_REG_ARM64_X3, + PERF_REG_ARM64_X4, + PERF_REG_ARM64_X5, + PERF_REG_ARM64_X6, + PERF_REG_ARM64_X7, + PERF_REG_ARM64_X8, + PERF_REG_ARM64_X9, + PERF_REG_ARM64_X10, + PERF_REG_ARM64_X11, + PERF_REG_ARM64_X12, + PERF_REG_ARM64_X13, + PERF_REG_ARM64_X14, + PERF_REG_ARM64_X15, + PERF_REG_ARM64_X16, + PERF_REG_ARM64_X17, + PERF_REG_ARM64_X18, + PERF_REG_ARM64_X19, + PERF_REG_ARM64_X20, + PERF_REG_ARM64_X21, + PERF_REG_ARM64_X22, + PERF_REG_ARM64_X23, + PERF_REG_ARM64_X24, + PERF_REG_ARM64_X25, + PERF_REG_ARM64_X26, + PERF_REG_ARM64_X27, + PERF_REG_ARM64_X28, + PERF_REG_ARM64_X29, + PERF_REG_ARM64_LR, + PERF_REG_ARM64_SP, + PERF_REG_ARM64_PC, + PERF_REG_ARM64_MAX, +}; +#endif /* _ASM_ARM64_PERF_REGS_H */ diff --git a/tools/arch/powerpc/include/uapi/asm/perf_regs.h b/tools/arch/powerpc/include/uapi/asm/perf_regs.h new file mode 100644 index 0000000..6a93209 --- /dev/null +++ b/tools/arch/powerpc/include/uapi/asm/perf_regs.h @@ -0,0 +1,50 @@ +#ifndef _UAPI_ASM_POWERPC_PERF_REGS_H +#define _UAPI_ASM_POWERPC_PERF_REGS_H + +enum perf_event_powerpc_regs { + PERF_REG_POWERPC_R0, + PERF_REG_POWERPC_R1, + PERF_REG_POWERPC_R2, + PERF_REG_POWERPC_R3, + PERF_REG_POWERPC_R4, + PERF_REG_POWERPC_R5, + PERF_REG_POWERPC_R6, + PERF_REG_POWERPC_R7, + PERF_REG_POWERPC_R8, + PERF_REG_POWERPC_R9, + PERF_REG_POWERPC_R10, + PERF_REG_POWERPC_R11, + PERF_REG_POWERPC_R12, + PERF_REG_POWERPC_R13, + PERF_REG_POWERPC_R14, + PERF_REG_POWERPC_R15, + PERF_REG_POWERPC_R16, + PERF_REG_POWERPC_R17, + PERF_REG_POWERPC_R18, + PERF_REG_POWERPC_R19, + PERF_REG_POWERPC_R20, + PERF_REG_POWERPC_R21, + PERF_REG_POWERPC_R22, + PERF_REG_POWERPC_R23, + PERF_REG_POWERPC_R24, + PERF_REG_POWERPC_R25, + PERF_REG_POWERPC_R26, + PERF_REG_POWERPC_R27, + PERF_REG_POWERPC_R28, + PERF_REG_POWERPC_R29, + PERF_REG_POWERPC_R30, + PERF_REG_POWERPC_R31, + PERF_REG_POWERPC_NIP, + PERF_REG_POWERPC_MSR, + PERF_REG_POWERPC_ORIG_R3, + PERF_REG_POWERPC_CTR, + PERF_REG_POWERPC_LINK, + PERF_REG_POWERPC_XER, + PERF_REG_POWERPC_CCR, + PERF_REG_POWERPC_SOFTE, + PERF_REG_POWERPC_TRAP, + PERF_REG_POWERPC_DAR, + PERF_REG_POWERPC_DSISR, + PERF_REG_POWERPC_MAX, +}; +#endif /* _UAPI_ASM_POWERPC_PERF_REGS_H */ diff --git a/tools/arch/x86/include/uapi/asm/perf_regs.h b/tools/arch/x86/include/uapi/asm/perf_regs.h new file mode 100644 index 0000000..3f2207b --- /dev/null +++ b/tools/arch/x86/include/uapi/asm/perf_regs.h @@ -0,0 +1,33 @@ +#ifndef _ASM_X86_PERF_REGS_H +#define _ASM_X86_PERF_REGS_H + +enum perf_event_x86_regs { + PERF_REG_X86_AX, + PERF_REG_X86_BX, + PERF_REG_X86_CX, + PERF_REG_X86_DX, + PERF_REG_X86_SI, + PERF_REG_X86_DI, + PERF_REG_X86_BP, + PERF_REG_X86_SP, + PERF_REG_X86_IP, + PERF_REG_X86_FLAGS, + PERF_REG_X86_CS, + PERF_REG_X86_SS, + PERF_REG_X86_DS, + PERF_REG_X86_ES, + PERF_REG_X86_FS, + PERF_REG_X86_GS, + PERF_REG_X86_R8, + PERF_REG_X86_R9, + PERF_REG_X86_R10, + PERF_REG_X86_R11, + PERF_REG_X86_R12, + PERF_REG_X86_R13, + PERF_REG_X86_R14, + PERF_REG_X86_R15, + + PERF_REG_X86_32_MAX = PERF_REG_X86_GS + 1, + PERF_REG_X86_64_MAX = PERF_REG_X86_R15 + 1, +}; +#endif /* _ASM_X86_PERF_REGS_H */ diff --git a/tools/perf/MANIFEST b/tools/perf/MANIFEST index a300cbb..d15c052 100644 --- a/tools/perf/MANIFEST +++ b/tools/perf/MANIFEST @@ -80,7 +80,7 @@ include/linux/stringify.h include/linux/swab.h arch/*/include/asm/unistd*.h arch/*/include/uapi/asm/unistd*.h -arch/*/include/uapi/asm/perf_regs.h +tools/arch/*/include/uapi/asm/perf_regs.h include/linux/poison.h include/linux/hw_breakpoint.h include/uapi/linux/const.h diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf index 809735c..34b91ba 100644 --- a/tools/perf/Makefile.perf +++ b/tools/perf/Makefile.perf @@ -363,6 +363,18 @@ $(PERF_IN): prepare FORCE @(test -f ../../arch/x86/lib/memset_64.S && ( \ (diff -B ../arch/x86/lib/memset_64.S ../../arch/x86/lib/memset_64.S >/dev/null) \ || echo "Warning: tools/arch/x86/lib/memset_64.S differs from kernel" >&2 )) || true + @(test -f ../../arch/arm/include/uapi/asm/perf_regs.h && ( \ + (diff -B ../arch/arm/include/uapi/asm/perf_regs.h ../../arch/arm/include/uapi/asm/perf_regs.h >/dev/null) \ + || echo "Warning: tools/arch/arm/include/uapi/asm/perf_regs.h differs from kernel" >&2 )) || true + @(test -f ../../arch/arm64/include/uapi/asm/perf_regs.h && ( \ + (diff -B ../arch/arm64/include/uapi/asm/perf_regs.h ../../arch/arm64/include/uapi/asm/perf_regs.h >/dev/null) \ + || echo "Warning: tools/arch/arm64/include/uapi/asm/perf_regs.h differs from kernel" >&2 )) || true + @(test -f ../../arch/powerpc/include/uapi/asm/perf_regs.h && ( \ + (diff -B ../arch/powerpc/include/uapi/asm/perf_regs.h ../../arch/powerpc/include/uapi/asm/perf_regs.h >/dev/null) \ + || echo "Warning: tools/arch/powerpc/include/uapi/asm/perf_regs.h differs from kernel" >&2 )) || true + @(test -f ../../arch/x86/include/uapi/asm/perf_regs.h && ( \ + (diff -B ../arch/x86/include/uapi/asm/perf_regs.h ../../arch/x86/include/uapi/asm/perf_regs.h >/dev/null) \ + || echo "Warning: tools/arch/x86/include/uapi/asm/perf_regs.h differs from kernel" >&2 )) || true $(Q)$(MAKE) $(build)=perf $(OUTPUT)perf: $(PERFLIBS) $(PERF_IN) $(LIBTRACEEVENT_DYNAMIC_LIST) diff --git a/tools/perf/config/Makefile b/tools/perf/config/Makefile index d629e5f..49a2130 100644 --- a/tools/perf/config/Makefile +++ b/tools/perf/config/Makefile @@ -208,9 +208,10 @@ CFLAGS += -I$(src-perf)/util/include CFLAGS += -I$(src-perf)/arch/$(ARCH)/include CFLAGS += -I$(srctree)/tools/include/uapi CFLAGS += -I$(srctree)/tools/include/ +CFLAGS += -I$(srctree)/tools/arch/$(ARCH)/include/uapi +CFLAGS += -I$(srctree)/tools/arch/$(ARCH)/include/ CFLAGS += -I$(srctree)/arch/$(ARCH)/include/uapi CFLAGS += -I$(srctree)/arch/$(ARCH)/include -CFLAGS += -I$(srctree)/tools/arch/$(ARCH)/include/uapi CFLAGS += -I$(srctree)/tools/arch/$(ARCH)/ CFLAGS += -I$(srctree)/include/uapi CFLAGS += -I$(srctree)/include -- cgit v0.10.2 From 4ffde492461d5c2111bf64366b633e554b4aa925 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Mon, 11 Jul 2016 23:22:30 -0300 Subject: perf test bpf: Use epoll_wait() instead of epoll_pwait() The prototype for epoll_wait() is available in older distros, so use it instead of epoll_pwait() (removing the last NULL arg, the sigmask, makes it the same thing anyway) to avoid breaking the build. Cc: Adrian Hunter Cc: David Ahern Cc: Jiri Olsa Cc: Namhyung Kim Cc: Wang Nan Link: http://lkml.kernel.org/n/tip-pwiwizloxt0jujy8em80qut3@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/tests/bpf-script-example.c b/tools/perf/tests/bpf-script-example.c index 0ec9c2c..e53bc91 100644 --- a/tools/perf/tests/bpf-script-example.c +++ b/tools/perf/tests/bpf-script-example.c @@ -31,8 +31,8 @@ struct bpf_map_def SEC("maps") flip_table = { .max_entries = 1, }; -SEC("func=sys_epoll_pwait") -int bpf_func__sys_epoll_pwait(void *ctx) +SEC("func=sys_epoll_wait") +int bpf_func__sys_epoll_wait(void *ctx) { int ind =0; int *flag = bpf_map_lookup_elem(&flip_table, &ind); diff --git a/tools/perf/tests/bpf.c b/tools/perf/tests/bpf.c index da0d87613..fc54064 100644 --- a/tools/perf/tests/bpf.c +++ b/tools/perf/tests/bpf.c @@ -13,13 +13,13 @@ #ifdef HAVE_LIBBPF_SUPPORT -static int epoll_pwait_loop(void) +static int epoll_wait_loop(void) { int i; /* Should fail NR_ITERS times */ for (i = 0; i < NR_ITERS; i++) - epoll_pwait(-(i + 1), NULL, 0, 0, NULL); + epoll_wait(-(i + 1), NULL, 0, 0); return 0; } @@ -61,7 +61,7 @@ static struct { "[basic_bpf_test]", "fix 'perf test LLVM' first", "load bpf object failed", - &epoll_pwait_loop, + &epoll_wait_loop, (NR_ITERS + 1) / 2, }, #ifdef HAVE_BPF_PROLOGUE -- cgit v0.10.2 From 4998a1224686d74ab7f7789787f7f7f904c75dfc Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Mon, 11 Jul 2016 23:37:18 -0300 Subject: tools: Copy uapi/linux/hw_breakpoint.h from the kernel To allow the build to complete on older systems, where those files are either not uptodate, lacking some recent additions or not present at all. And check if the copy drifts from the kernel. Cc: Adrian Hunter Cc: David Ahern Cc: Jiri Olsa Cc: Namhyung Kim Cc: Wang Nan Link: http://lkml.kernel.org/n/tip-3jz31pz4nw526uko5da9e7o3@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/include/uapi/linux/hw_breakpoint.h b/tools/include/uapi/linux/hw_breakpoint.h new file mode 100644 index 0000000..b04000a --- /dev/null +++ b/tools/include/uapi/linux/hw_breakpoint.h @@ -0,0 +1,30 @@ +#ifndef _UAPI_LINUX_HW_BREAKPOINT_H +#define _UAPI_LINUX_HW_BREAKPOINT_H + +enum { + HW_BREAKPOINT_LEN_1 = 1, + HW_BREAKPOINT_LEN_2 = 2, + HW_BREAKPOINT_LEN_4 = 4, + HW_BREAKPOINT_LEN_8 = 8, +}; + +enum { + HW_BREAKPOINT_EMPTY = 0, + HW_BREAKPOINT_R = 1, + HW_BREAKPOINT_W = 2, + HW_BREAKPOINT_RW = HW_BREAKPOINT_R | HW_BREAKPOINT_W, + HW_BREAKPOINT_X = 4, + HW_BREAKPOINT_INVALID = HW_BREAKPOINT_RW | HW_BREAKPOINT_X, +}; + +enum bp_type_idx { + TYPE_INST = 0, +#ifdef CONFIG_HAVE_MIXED_BREAKPOINTS_REGS + TYPE_DATA = 0, +#else + TYPE_DATA = 1, +#endif + TYPE_MAX +}; + +#endif /* _UAPI_LINUX_HW_BREAKPOINT_H */ diff --git a/tools/perf/MANIFEST b/tools/perf/MANIFEST index d15c052..a4aefae 100644 --- a/tools/perf/MANIFEST +++ b/tools/perf/MANIFEST @@ -61,6 +61,7 @@ tools/include/linux/list.h tools/include/linux/log2.h tools/include/uapi/linux/bpf.h tools/include/uapi/linux/bpf_common.h +tools/include/uapi/linux/hw_breakpoint.h tools/include/uapi/linux/perf_event.h tools/include/linux/poison.h tools/include/linux/rbtree.h @@ -82,10 +83,8 @@ arch/*/include/asm/unistd*.h arch/*/include/uapi/asm/unistd*.h tools/arch/*/include/uapi/asm/perf_regs.h include/linux/poison.h -include/linux/hw_breakpoint.h include/uapi/linux/const.h include/uapi/linux/swab.h -include/uapi/linux/hw_breakpoint.h arch/x86/include/asm/svm.h arch/x86/include/asm/vmx.h arch/x86/include/asm/kvm_host.h diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf index 34b91ba..0d07672 100644 --- a/tools/perf/Makefile.perf +++ b/tools/perf/Makefile.perf @@ -348,6 +348,9 @@ $(PERF_IN): prepare FORCE @(test -f ../../include/uapi/linux/perf_event.h && ( \ (diff -B ../include/uapi/linux/perf_event.h ../../include/uapi/linux/perf_event.h >/dev/null) \ || echo "Warning: tools/include/uapi/linux/perf_event.h differs from kernel" >&2 )) || true + @(test -f ../../include/uapi/linux/hw_breakpoint.h && ( \ + (diff -B ../include/uapi/linux/hw_breakpoint.h ../../include/uapi/linux/hw_breakpoint.h >/dev/null) \ + || echo "Warning: tools/include/uapi/linux/hw_breakpoint.h differs from kernel" >&2 )) || true @(test -f ../../arch/x86/include/asm/disabled-features.h && ( \ (diff -B ../arch/x86/include/asm/disabled-features.h ../../arch/x86/include/asm/disabled-features.h >/dev/null) \ || echo "Warning: tools/arch/x86/include/asm/disabled-features.h differs from kernel" >&2 )) || true -- cgit v0.10.2 From c7007e983682b31d91e9ad7c3e85c49ffcc3651f Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 12 Jul 2016 10:29:31 -0300 Subject: perf tools: Introduce weak alternative to sched_getcpu() Which is just a wrapper for sys_getcpu and is not present in at least musl libc. Cc: Adrian Hunter Cc: David Ahern Cc: Jiri Olsa Cc: Namhyung Kim Cc: Wang Nan Link: http://lkml.kernel.org/n/tip-kblef7svmhr0g93kkx78envg@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/arch/x86/include/asm/unistd_32.h b/tools/arch/x86/include/asm/unistd_32.h index cf33ab0..88b3f8c 100644 --- a/tools/arch/x86/include/asm/unistd_32.h +++ b/tools/arch/x86/include/asm/unistd_32.h @@ -7,3 +7,6 @@ #ifndef __NR_gettid # define __NR_gettid 224 #endif +#ifndef __NR_getcpu +# define __NR_getcpu 318 +#endif diff --git a/tools/arch/x86/include/asm/unistd_64.h b/tools/arch/x86/include/asm/unistd_64.h index 2c98356..fbdb70e 100644 --- a/tools/arch/x86/include/asm/unistd_64.h +++ b/tools/arch/x86/include/asm/unistd_64.h @@ -7,3 +7,6 @@ #ifndef __NR_gettid # define __NR_gettid 186 #endif +#ifndef __NR_getcpu +# define __NR_getcpu 309 +#endif diff --git a/tools/perf/util/cloexec.c b/tools/perf/util/cloexec.c index fde772d..f0dcd0e 100644 --- a/tools/perf/util/cloexec.c +++ b/tools/perf/util/cloexec.c @@ -4,18 +4,24 @@ #include "cloexec.h" #include "asm/bug.h" #include "debug.h" +#include +#include +#include static unsigned long flag = PERF_FLAG_FD_CLOEXEC; -#ifdef __GLIBC_PREREQ -#if !__GLIBC_PREREQ(2, 6) int __weak sched_getcpu(void) { +#ifdef __NR_getcpu + unsigned cpu; + int err = syscall(__NR_getcpu, &cpu, NULL, NULL); + if (!err) + return cpu; +#else errno = ENOSYS; +#endif return -1; } -#endif -#endif static int perf_flag_probe(void) { diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h index 2370cfb..d8d41ef 100644 --- a/tools/perf/util/util.h +++ b/tools/perf/util/util.h @@ -361,4 +361,8 @@ void print_binary(unsigned char *data, size_t len, size_t bytes_per_line, print_binary_t printer, void *extra); +#ifndef __GLIBC__ +extern int sched_getcpu(void); +#endif + #endif /* GIT_COMPAT_UTIL_H */ -- cgit v0.10.2 From a395b35d339174bc42bb22ef729a1ef67639bbb3 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 12 Jul 2016 10:30:39 -0300 Subject: perf tools: Remove unneeded magic.h include from util.h Not used anymore, IIRC it was for useless PROC_FS_MAGIC procfs checks, but those are long gone. Cc: Adrian Hunter Cc: David Ahern Cc: Jiri Olsa Cc: Namhyung Kim Cc: Steven Rostedt Cc: Wang Nan Link: http://lkml.kernel.org/n/tip-v027did3kvj0vz7bofgzkw29@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h index d8d41ef..6178cab 100644 --- a/tools/perf/util/util.h +++ b/tools/perf/util/util.h @@ -72,7 +72,6 @@ #include #include #include -#include #include #include #include -- cgit v0.10.2 From e3e1d7e077688c81ee3326d1bf04550549b8a004 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 12 Jul 2016 10:44:40 -0300 Subject: perf trace: Remove unused sys/ptrace.h include Cc: Adrian Hunter Cc: David Ahern Cc: Jiri Olsa Cc: Namhyung Kim Cc: Wang Nan Link: http://lkml.kernel.org/n/tip-ogtjqc0hxm961djgiwboe2q7@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c index 570a78c..b8c6766 100644 --- a/tools/perf/builtin-trace.c +++ b/tools/perf/builtin-trace.c @@ -43,7 +43,6 @@ #include #include #include -#include #include #include -- cgit v0.10.2 From f2d3adf46d5763e7154e303e972c891999a4da43 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 12 Jul 2016 10:54:45 -0300 Subject: kvm arm/arm64: Remove trailing whitespace from headers Noticed while making a copy of these files to tools/ where those kernel files were being directly accessed, which we're not allowing anymore to avoid that changes in the kernel side break tooling. Cc: Christoffer Dall Cc: Eric Auger Cc: Marc Zyngier Cc: Adrian Hunter Cc: David Ahern Cc: Jiri Olsa Cc: Namhyung Kim Cc: Wang Nan Link: http://lkml.kernel.org/n/tip-82thftcdhj2j5wt6ir4vuyhk@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo diff --git a/arch/arm/include/uapi/asm/kvm.h b/arch/arm/include/uapi/asm/kvm.h index df3f60c..a2b3eb3 100644 --- a/arch/arm/include/uapi/asm/kvm.h +++ b/arch/arm/include/uapi/asm/kvm.h @@ -139,8 +139,8 @@ struct kvm_arch_memory_slot { #define ARM_CP15_REG64(...) __ARM_CP15_REG64(__VA_ARGS__) #define KVM_REG_ARM_TIMER_CTL ARM_CP15_REG32(0, 14, 3, 1) -#define KVM_REG_ARM_TIMER_CNT ARM_CP15_REG64(1, 14) -#define KVM_REG_ARM_TIMER_CVAL ARM_CP15_REG64(3, 14) +#define KVM_REG_ARM_TIMER_CNT ARM_CP15_REG64(1, 14) +#define KVM_REG_ARM_TIMER_CVAL ARM_CP15_REG64(3, 14) /* Normal registers are mapped as coprocessor 16. */ #define KVM_REG_ARM_CORE (0x0010 << KVM_REG_ARM_COPROC_SHIFT) -- cgit v0.10.2 From dd7bd1093622621a910cbb6a77c7addeb20c9984 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 12 Jul 2016 10:57:25 -0300 Subject: tools: Copy the header files needed by perf tools Those kernel files were being directly accessed, which we're not allowing anymore to avoid that changes in the kernel side break tooling. Warn if these copies drift from the original files. Cc: Adrian Hunter Cc: Alexander Yarygin Cc: Christoffer Dall Cc: David Ahern Cc: Eric Auger Cc: Hemant Kumar Cc: Jiri Olsa Cc: Marc Zyngier Cc: Namhyung Kim Cc: Naveen N. Rao Cc: Srikar Dronamraju Cc: Wang Nan Cc: Yunlong Song Link: http://lkml.kernel.org/n/tip-mnopguymhnwzjhw3mowllvsy@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/arch/arm/include/uapi/asm/kvm.h b/tools/arch/arm/include/uapi/asm/kvm.h new file mode 100644 index 0000000..a2b3eb3 --- /dev/null +++ b/tools/arch/arm/include/uapi/asm/kvm.h @@ -0,0 +1,224 @@ +/* + * Copyright (C) 2012 - Virtual Open Systems and Columbia University + * Author: Christoffer Dall + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License, version 2, as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef __ARM_KVM_H__ +#define __ARM_KVM_H__ + +#include +#include +#include + +#define __KVM_HAVE_GUEST_DEBUG +#define __KVM_HAVE_IRQ_LINE +#define __KVM_HAVE_READONLY_MEM + +#define KVM_REG_SIZE(id) \ + (1U << (((id) & KVM_REG_SIZE_MASK) >> KVM_REG_SIZE_SHIFT)) + +/* Valid for svc_regs, abt_regs, und_regs, irq_regs in struct kvm_regs */ +#define KVM_ARM_SVC_sp svc_regs[0] +#define KVM_ARM_SVC_lr svc_regs[1] +#define KVM_ARM_SVC_spsr svc_regs[2] +#define KVM_ARM_ABT_sp abt_regs[0] +#define KVM_ARM_ABT_lr abt_regs[1] +#define KVM_ARM_ABT_spsr abt_regs[2] +#define KVM_ARM_UND_sp und_regs[0] +#define KVM_ARM_UND_lr und_regs[1] +#define KVM_ARM_UND_spsr und_regs[2] +#define KVM_ARM_IRQ_sp irq_regs[0] +#define KVM_ARM_IRQ_lr irq_regs[1] +#define KVM_ARM_IRQ_spsr irq_regs[2] + +/* Valid only for fiq_regs in struct kvm_regs */ +#define KVM_ARM_FIQ_r8 fiq_regs[0] +#define KVM_ARM_FIQ_r9 fiq_regs[1] +#define KVM_ARM_FIQ_r10 fiq_regs[2] +#define KVM_ARM_FIQ_fp fiq_regs[3] +#define KVM_ARM_FIQ_ip fiq_regs[4] +#define KVM_ARM_FIQ_sp fiq_regs[5] +#define KVM_ARM_FIQ_lr fiq_regs[6] +#define KVM_ARM_FIQ_spsr fiq_regs[7] + +struct kvm_regs { + struct pt_regs usr_regs; /* R0_usr - R14_usr, PC, CPSR */ + unsigned long svc_regs[3]; /* SP_svc, LR_svc, SPSR_svc */ + unsigned long abt_regs[3]; /* SP_abt, LR_abt, SPSR_abt */ + unsigned long und_regs[3]; /* SP_und, LR_und, SPSR_und */ + unsigned long irq_regs[3]; /* SP_irq, LR_irq, SPSR_irq */ + unsigned long fiq_regs[8]; /* R8_fiq - R14_fiq, SPSR_fiq */ +}; + +/* Supported Processor Types */ +#define KVM_ARM_TARGET_CORTEX_A15 0 +#define KVM_ARM_TARGET_CORTEX_A7 1 +#define KVM_ARM_NUM_TARGETS 2 + +/* KVM_ARM_SET_DEVICE_ADDR ioctl id encoding */ +#define KVM_ARM_DEVICE_TYPE_SHIFT 0 +#define KVM_ARM_DEVICE_TYPE_MASK (0xffff << KVM_ARM_DEVICE_TYPE_SHIFT) +#define KVM_ARM_DEVICE_ID_SHIFT 16 +#define KVM_ARM_DEVICE_ID_MASK (0xffff << KVM_ARM_DEVICE_ID_SHIFT) + +/* Supported device IDs */ +#define KVM_ARM_DEVICE_VGIC_V2 0 + +/* Supported VGIC address types */ +#define KVM_VGIC_V2_ADDR_TYPE_DIST 0 +#define KVM_VGIC_V2_ADDR_TYPE_CPU 1 + +#define KVM_VGIC_V2_DIST_SIZE 0x1000 +#define KVM_VGIC_V2_CPU_SIZE 0x2000 + +#define KVM_ARM_VCPU_POWER_OFF 0 /* CPU is started in OFF state */ +#define KVM_ARM_VCPU_PSCI_0_2 1 /* CPU uses PSCI v0.2 */ + +struct kvm_vcpu_init { + __u32 target; + __u32 features[7]; +}; + +struct kvm_sregs { +}; + +struct kvm_fpu { +}; + +struct kvm_guest_debug_arch { +}; + +struct kvm_debug_exit_arch { +}; + +struct kvm_sync_regs { +}; + +struct kvm_arch_memory_slot { +}; + +/* If you need to interpret the index values, here is the key: */ +#define KVM_REG_ARM_COPROC_MASK 0x000000000FFF0000 +#define KVM_REG_ARM_COPROC_SHIFT 16 +#define KVM_REG_ARM_32_OPC2_MASK 0x0000000000000007 +#define KVM_REG_ARM_32_OPC2_SHIFT 0 +#define KVM_REG_ARM_OPC1_MASK 0x0000000000000078 +#define KVM_REG_ARM_OPC1_SHIFT 3 +#define KVM_REG_ARM_CRM_MASK 0x0000000000000780 +#define KVM_REG_ARM_CRM_SHIFT 7 +#define KVM_REG_ARM_32_CRN_MASK 0x0000000000007800 +#define KVM_REG_ARM_32_CRN_SHIFT 11 + +#define ARM_CP15_REG_SHIFT_MASK(x,n) \ + (((x) << KVM_REG_ARM_ ## n ## _SHIFT) & KVM_REG_ARM_ ## n ## _MASK) + +#define __ARM_CP15_REG(op1,crn,crm,op2) \ + (KVM_REG_ARM | (15 << KVM_REG_ARM_COPROC_SHIFT) | \ + ARM_CP15_REG_SHIFT_MASK(op1, OPC1) | \ + ARM_CP15_REG_SHIFT_MASK(crn, 32_CRN) | \ + ARM_CP15_REG_SHIFT_MASK(crm, CRM) | \ + ARM_CP15_REG_SHIFT_MASK(op2, 32_OPC2)) + +#define ARM_CP15_REG32(...) (__ARM_CP15_REG(__VA_ARGS__) | KVM_REG_SIZE_U32) + +#define __ARM_CP15_REG64(op1,crm) \ + (__ARM_CP15_REG(op1, 0, crm, 0) | KVM_REG_SIZE_U64) +#define ARM_CP15_REG64(...) __ARM_CP15_REG64(__VA_ARGS__) + +#define KVM_REG_ARM_TIMER_CTL ARM_CP15_REG32(0, 14, 3, 1) +#define KVM_REG_ARM_TIMER_CNT ARM_CP15_REG64(1, 14) +#define KVM_REG_ARM_TIMER_CVAL ARM_CP15_REG64(3, 14) + +/* Normal registers are mapped as coprocessor 16. */ +#define KVM_REG_ARM_CORE (0x0010 << KVM_REG_ARM_COPROC_SHIFT) +#define KVM_REG_ARM_CORE_REG(name) (offsetof(struct kvm_regs, name) / 4) + +/* Some registers need more space to represent values. */ +#define KVM_REG_ARM_DEMUX (0x0011 << KVM_REG_ARM_COPROC_SHIFT) +#define KVM_REG_ARM_DEMUX_ID_MASK 0x000000000000FF00 +#define KVM_REG_ARM_DEMUX_ID_SHIFT 8 +#define KVM_REG_ARM_DEMUX_ID_CCSIDR (0x00 << KVM_REG_ARM_DEMUX_ID_SHIFT) +#define KVM_REG_ARM_DEMUX_VAL_MASK 0x00000000000000FF +#define KVM_REG_ARM_DEMUX_VAL_SHIFT 0 + +/* VFP registers: we could overload CP10 like ARM does, but that's ugly. */ +#define KVM_REG_ARM_VFP (0x0012 << KVM_REG_ARM_COPROC_SHIFT) +#define KVM_REG_ARM_VFP_MASK 0x000000000000FFFF +#define KVM_REG_ARM_VFP_BASE_REG 0x0 +#define KVM_REG_ARM_VFP_FPSID 0x1000 +#define KVM_REG_ARM_VFP_FPSCR 0x1001 +#define KVM_REG_ARM_VFP_MVFR1 0x1006 +#define KVM_REG_ARM_VFP_MVFR0 0x1007 +#define KVM_REG_ARM_VFP_FPEXC 0x1008 +#define KVM_REG_ARM_VFP_FPINST 0x1009 +#define KVM_REG_ARM_VFP_FPINST2 0x100A + +/* Device Control API: ARM VGIC */ +#define KVM_DEV_ARM_VGIC_GRP_ADDR 0 +#define KVM_DEV_ARM_VGIC_GRP_DIST_REGS 1 +#define KVM_DEV_ARM_VGIC_GRP_CPU_REGS 2 +#define KVM_DEV_ARM_VGIC_CPUID_SHIFT 32 +#define KVM_DEV_ARM_VGIC_CPUID_MASK (0xffULL << KVM_DEV_ARM_VGIC_CPUID_SHIFT) +#define KVM_DEV_ARM_VGIC_OFFSET_SHIFT 0 +#define KVM_DEV_ARM_VGIC_OFFSET_MASK (0xffffffffULL << KVM_DEV_ARM_VGIC_OFFSET_SHIFT) +#define KVM_DEV_ARM_VGIC_GRP_NR_IRQS 3 +#define KVM_DEV_ARM_VGIC_GRP_CTRL 4 +#define KVM_DEV_ARM_VGIC_CTRL_INIT 0 + +/* KVM_IRQ_LINE irq field index values */ +#define KVM_ARM_IRQ_TYPE_SHIFT 24 +#define KVM_ARM_IRQ_TYPE_MASK 0xff +#define KVM_ARM_IRQ_VCPU_SHIFT 16 +#define KVM_ARM_IRQ_VCPU_MASK 0xff +#define KVM_ARM_IRQ_NUM_SHIFT 0 +#define KVM_ARM_IRQ_NUM_MASK 0xffff + +/* irq_type field */ +#define KVM_ARM_IRQ_TYPE_CPU 0 +#define KVM_ARM_IRQ_TYPE_SPI 1 +#define KVM_ARM_IRQ_TYPE_PPI 2 + +/* out-of-kernel GIC cpu interrupt injection irq_number field */ +#define KVM_ARM_IRQ_CPU_IRQ 0 +#define KVM_ARM_IRQ_CPU_FIQ 1 + +/* + * This used to hold the highest supported SPI, but it is now obsolete + * and only here to provide source code level compatibility with older + * userland. The highest SPI number can be set via KVM_DEV_ARM_VGIC_GRP_NR_IRQS. + */ +#ifndef __KERNEL__ +#define KVM_ARM_IRQ_GIC_MAX 127 +#endif + +/* One single KVM irqchip, ie. the VGIC */ +#define KVM_NR_IRQCHIPS 1 + +/* PSCI interface */ +#define KVM_PSCI_FN_BASE 0x95c1ba5e +#define KVM_PSCI_FN(n) (KVM_PSCI_FN_BASE + (n)) + +#define KVM_PSCI_FN_CPU_SUSPEND KVM_PSCI_FN(0) +#define KVM_PSCI_FN_CPU_OFF KVM_PSCI_FN(1) +#define KVM_PSCI_FN_CPU_ON KVM_PSCI_FN(2) +#define KVM_PSCI_FN_MIGRATE KVM_PSCI_FN(3) + +#define KVM_PSCI_RET_SUCCESS PSCI_RET_SUCCESS +#define KVM_PSCI_RET_NI PSCI_RET_NOT_SUPPORTED +#define KVM_PSCI_RET_INVAL PSCI_RET_INVALID_PARAMS +#define KVM_PSCI_RET_DENIED PSCI_RET_DENIED + +#endif /* __ARM_KVM_H__ */ diff --git a/tools/arch/arm64/include/uapi/asm/kvm.h b/tools/arch/arm64/include/uapi/asm/kvm.h new file mode 100644 index 0000000..f209ea1 --- /dev/null +++ b/tools/arch/arm64/include/uapi/asm/kvm.h @@ -0,0 +1,258 @@ +/* + * Copyright (C) 2012,2013 - ARM Ltd + * Author: Marc Zyngier + * + * Derived from arch/arm/include/uapi/asm/kvm.h: + * Copyright (C) 2012 - Virtual Open Systems and Columbia University + * Author: Christoffer Dall + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef __ARM_KVM_H__ +#define __ARM_KVM_H__ + +#define KVM_SPSR_EL1 0 +#define KVM_SPSR_SVC KVM_SPSR_EL1 +#define KVM_SPSR_ABT 1 +#define KVM_SPSR_UND 2 +#define KVM_SPSR_IRQ 3 +#define KVM_SPSR_FIQ 4 +#define KVM_NR_SPSR 5 + +#ifndef __ASSEMBLY__ +#include +#include +#include + +#define __KVM_HAVE_GUEST_DEBUG +#define __KVM_HAVE_IRQ_LINE +#define __KVM_HAVE_READONLY_MEM + +#define KVM_REG_SIZE(id) \ + (1U << (((id) & KVM_REG_SIZE_MASK) >> KVM_REG_SIZE_SHIFT)) + +struct kvm_regs { + struct user_pt_regs regs; /* sp = sp_el0 */ + + __u64 sp_el1; + __u64 elr_el1; + + __u64 spsr[KVM_NR_SPSR]; + + struct user_fpsimd_state fp_regs; +}; + +/* + * Supported CPU Targets - Adding a new target type is not recommended, + * unless there are some special registers not supported by the + * genericv8 syreg table. + */ +#define KVM_ARM_TARGET_AEM_V8 0 +#define KVM_ARM_TARGET_FOUNDATION_V8 1 +#define KVM_ARM_TARGET_CORTEX_A57 2 +#define KVM_ARM_TARGET_XGENE_POTENZA 3 +#define KVM_ARM_TARGET_CORTEX_A53 4 +/* Generic ARM v8 target */ +#define KVM_ARM_TARGET_GENERIC_V8 5 + +#define KVM_ARM_NUM_TARGETS 6 + +/* KVM_ARM_SET_DEVICE_ADDR ioctl id encoding */ +#define KVM_ARM_DEVICE_TYPE_SHIFT 0 +#define KVM_ARM_DEVICE_TYPE_MASK (0xffff << KVM_ARM_DEVICE_TYPE_SHIFT) +#define KVM_ARM_DEVICE_ID_SHIFT 16 +#define KVM_ARM_DEVICE_ID_MASK (0xffff << KVM_ARM_DEVICE_ID_SHIFT) + +/* Supported device IDs */ +#define KVM_ARM_DEVICE_VGIC_V2 0 + +/* Supported VGIC address types */ +#define KVM_VGIC_V2_ADDR_TYPE_DIST 0 +#define KVM_VGIC_V2_ADDR_TYPE_CPU 1 + +#define KVM_VGIC_V2_DIST_SIZE 0x1000 +#define KVM_VGIC_V2_CPU_SIZE 0x2000 + +/* Supported VGICv3 address types */ +#define KVM_VGIC_V3_ADDR_TYPE_DIST 2 +#define KVM_VGIC_V3_ADDR_TYPE_REDIST 3 + +#define KVM_VGIC_V3_DIST_SIZE SZ_64K +#define KVM_VGIC_V3_REDIST_SIZE (2 * SZ_64K) + +#define KVM_ARM_VCPU_POWER_OFF 0 /* CPU is started in OFF state */ +#define KVM_ARM_VCPU_EL1_32BIT 1 /* CPU running a 32bit VM */ +#define KVM_ARM_VCPU_PSCI_0_2 2 /* CPU uses PSCI v0.2 */ +#define KVM_ARM_VCPU_PMU_V3 3 /* Support guest PMUv3 */ + +struct kvm_vcpu_init { + __u32 target; + __u32 features[7]; +}; + +struct kvm_sregs { +}; + +struct kvm_fpu { +}; + +/* + * See v8 ARM ARM D7.3: Debug Registers + * + * The architectural limit is 16 debug registers of each type although + * in practice there are usually less (see ID_AA64DFR0_EL1). + * + * Although the control registers are architecturally defined as 32 + * bits wide we use a 64 bit structure here to keep parity with + * KVM_GET/SET_ONE_REG behaviour which treats all system registers as + * 64 bit values. It also allows for the possibility of the + * architecture expanding the control registers without having to + * change the userspace ABI. + */ +#define KVM_ARM_MAX_DBG_REGS 16 +struct kvm_guest_debug_arch { + __u64 dbg_bcr[KVM_ARM_MAX_DBG_REGS]; + __u64 dbg_bvr[KVM_ARM_MAX_DBG_REGS]; + __u64 dbg_wcr[KVM_ARM_MAX_DBG_REGS]; + __u64 dbg_wvr[KVM_ARM_MAX_DBG_REGS]; +}; + +struct kvm_debug_exit_arch { + __u32 hsr; + __u64 far; /* used for watchpoints */ +}; + +/* + * Architecture specific defines for kvm_guest_debug->control + */ + +#define KVM_GUESTDBG_USE_SW_BP (1 << 16) +#define KVM_GUESTDBG_USE_HW (1 << 17) + +struct kvm_sync_regs { +}; + +struct kvm_arch_memory_slot { +}; + +/* If you need to interpret the index values, here is the key: */ +#define KVM_REG_ARM_COPROC_MASK 0x000000000FFF0000 +#define KVM_REG_ARM_COPROC_SHIFT 16 + +/* Normal registers are mapped as coprocessor 16. */ +#define KVM_REG_ARM_CORE (0x0010 << KVM_REG_ARM_COPROC_SHIFT) +#define KVM_REG_ARM_CORE_REG(name) (offsetof(struct kvm_regs, name) / sizeof(__u32)) + +/* Some registers need more space to represent values. */ +#define KVM_REG_ARM_DEMUX (0x0011 << KVM_REG_ARM_COPROC_SHIFT) +#define KVM_REG_ARM_DEMUX_ID_MASK 0x000000000000FF00 +#define KVM_REG_ARM_DEMUX_ID_SHIFT 8 +#define KVM_REG_ARM_DEMUX_ID_CCSIDR (0x00 << KVM_REG_ARM_DEMUX_ID_SHIFT) +#define KVM_REG_ARM_DEMUX_VAL_MASK 0x00000000000000FF +#define KVM_REG_ARM_DEMUX_VAL_SHIFT 0 + +/* AArch64 system registers */ +#define KVM_REG_ARM64_SYSREG (0x0013 << KVM_REG_ARM_COPROC_SHIFT) +#define KVM_REG_ARM64_SYSREG_OP0_MASK 0x000000000000c000 +#define KVM_REG_ARM64_SYSREG_OP0_SHIFT 14 +#define KVM_REG_ARM64_SYSREG_OP1_MASK 0x0000000000003800 +#define KVM_REG_ARM64_SYSREG_OP1_SHIFT 11 +#define KVM_REG_ARM64_SYSREG_CRN_MASK 0x0000000000000780 +#define KVM_REG_ARM64_SYSREG_CRN_SHIFT 7 +#define KVM_REG_ARM64_SYSREG_CRM_MASK 0x0000000000000078 +#define KVM_REG_ARM64_SYSREG_CRM_SHIFT 3 +#define KVM_REG_ARM64_SYSREG_OP2_MASK 0x0000000000000007 +#define KVM_REG_ARM64_SYSREG_OP2_SHIFT 0 + +#define ARM64_SYS_REG_SHIFT_MASK(x,n) \ + (((x) << KVM_REG_ARM64_SYSREG_ ## n ## _SHIFT) & \ + KVM_REG_ARM64_SYSREG_ ## n ## _MASK) + +#define __ARM64_SYS_REG(op0,op1,crn,crm,op2) \ + (KVM_REG_ARM64 | KVM_REG_ARM64_SYSREG | \ + ARM64_SYS_REG_SHIFT_MASK(op0, OP0) | \ + ARM64_SYS_REG_SHIFT_MASK(op1, OP1) | \ + ARM64_SYS_REG_SHIFT_MASK(crn, CRN) | \ + ARM64_SYS_REG_SHIFT_MASK(crm, CRM) | \ + ARM64_SYS_REG_SHIFT_MASK(op2, OP2)) + +#define ARM64_SYS_REG(...) (__ARM64_SYS_REG(__VA_ARGS__) | KVM_REG_SIZE_U64) + +#define KVM_REG_ARM_TIMER_CTL ARM64_SYS_REG(3, 3, 14, 3, 1) +#define KVM_REG_ARM_TIMER_CNT ARM64_SYS_REG(3, 3, 14, 3, 2) +#define KVM_REG_ARM_TIMER_CVAL ARM64_SYS_REG(3, 3, 14, 0, 2) + +/* Device Control API: ARM VGIC */ +#define KVM_DEV_ARM_VGIC_GRP_ADDR 0 +#define KVM_DEV_ARM_VGIC_GRP_DIST_REGS 1 +#define KVM_DEV_ARM_VGIC_GRP_CPU_REGS 2 +#define KVM_DEV_ARM_VGIC_CPUID_SHIFT 32 +#define KVM_DEV_ARM_VGIC_CPUID_MASK (0xffULL << KVM_DEV_ARM_VGIC_CPUID_SHIFT) +#define KVM_DEV_ARM_VGIC_OFFSET_SHIFT 0 +#define KVM_DEV_ARM_VGIC_OFFSET_MASK (0xffffffffULL << KVM_DEV_ARM_VGIC_OFFSET_SHIFT) +#define KVM_DEV_ARM_VGIC_GRP_NR_IRQS 3 +#define KVM_DEV_ARM_VGIC_GRP_CTRL 4 +#define KVM_DEV_ARM_VGIC_CTRL_INIT 0 + +/* Device Control API on vcpu fd */ +#define KVM_ARM_VCPU_PMU_V3_CTRL 0 +#define KVM_ARM_VCPU_PMU_V3_IRQ 0 +#define KVM_ARM_VCPU_PMU_V3_INIT 1 + +/* KVM_IRQ_LINE irq field index values */ +#define KVM_ARM_IRQ_TYPE_SHIFT 24 +#define KVM_ARM_IRQ_TYPE_MASK 0xff +#define KVM_ARM_IRQ_VCPU_SHIFT 16 +#define KVM_ARM_IRQ_VCPU_MASK 0xff +#define KVM_ARM_IRQ_NUM_SHIFT 0 +#define KVM_ARM_IRQ_NUM_MASK 0xffff + +/* irq_type field */ +#define KVM_ARM_IRQ_TYPE_CPU 0 +#define KVM_ARM_IRQ_TYPE_SPI 1 +#define KVM_ARM_IRQ_TYPE_PPI 2 + +/* out-of-kernel GIC cpu interrupt injection irq_number field */ +#define KVM_ARM_IRQ_CPU_IRQ 0 +#define KVM_ARM_IRQ_CPU_FIQ 1 + +/* + * This used to hold the highest supported SPI, but it is now obsolete + * and only here to provide source code level compatibility with older + * userland. The highest SPI number can be set via KVM_DEV_ARM_VGIC_GRP_NR_IRQS. + */ +#ifndef __KERNEL__ +#define KVM_ARM_IRQ_GIC_MAX 127 +#endif + +/* One single KVM irqchip, ie. the VGIC */ +#define KVM_NR_IRQCHIPS 1 + +/* PSCI interface */ +#define KVM_PSCI_FN_BASE 0x95c1ba5e +#define KVM_PSCI_FN(n) (KVM_PSCI_FN_BASE + (n)) + +#define KVM_PSCI_FN_CPU_SUSPEND KVM_PSCI_FN(0) +#define KVM_PSCI_FN_CPU_OFF KVM_PSCI_FN(1) +#define KVM_PSCI_FN_CPU_ON KVM_PSCI_FN(2) +#define KVM_PSCI_FN_MIGRATE KVM_PSCI_FN(3) + +#define KVM_PSCI_RET_SUCCESS PSCI_RET_SUCCESS +#define KVM_PSCI_RET_NI PSCI_RET_NOT_SUPPORTED +#define KVM_PSCI_RET_INVAL PSCI_RET_INVALID_PARAMS +#define KVM_PSCI_RET_DENIED PSCI_RET_DENIED + +#endif + +#endif /* __ARM_KVM_H__ */ diff --git a/tools/arch/mips/include/uapi/asm/kvm.h b/tools/arch/mips/include/uapi/asm/kvm.h new file mode 100644 index 0000000..6985eb5 --- /dev/null +++ b/tools/arch/mips/include/uapi/asm/kvm.h @@ -0,0 +1,208 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 2012 MIPS Technologies, Inc. All rights reserved. + * Copyright (C) 2013 Cavium, Inc. + * Authors: Sanjay Lal + */ + +#ifndef __LINUX_KVM_MIPS_H +#define __LINUX_KVM_MIPS_H + +#include + +/* + * KVM MIPS specific structures and definitions. + * + * Some parts derived from the x86 version of this file. + */ + +/* + * for KVM_GET_REGS and KVM_SET_REGS + * + * If Config[AT] is zero (32-bit CPU), the register contents are + * stored in the lower 32-bits of the struct kvm_regs fields and sign + * extended to 64-bits. + */ +struct kvm_regs { + /* out (KVM_GET_REGS) / in (KVM_SET_REGS) */ + __u64 gpr[32]; + __u64 hi; + __u64 lo; + __u64 pc; +}; + +/* + * for KVM_GET_FPU and KVM_SET_FPU + */ +struct kvm_fpu { +}; + + +/* + * For MIPS, we use KVM_SET_ONE_REG and KVM_GET_ONE_REG to access various + * registers. The id field is broken down as follows: + * + * bits[63..52] - As per linux/kvm.h + * bits[51..32] - Must be zero. + * bits[31..16] - Register set. + * + * Register set = 0: GP registers from kvm_regs (see definitions below). + * + * Register set = 1: CP0 registers. + * bits[15..8] - Must be zero. + * bits[7..3] - Register 'rd' index. + * bits[2..0] - Register 'sel' index. + * + * Register set = 2: KVM specific registers (see definitions below). + * + * Register set = 3: FPU / MSA registers (see definitions below). + * + * Other sets registers may be added in the future. Each set would + * have its own identifier in bits[31..16]. + */ + +#define KVM_REG_MIPS_GP (KVM_REG_MIPS | 0x0000000000000000ULL) +#define KVM_REG_MIPS_CP0 (KVM_REG_MIPS | 0x0000000000010000ULL) +#define KVM_REG_MIPS_KVM (KVM_REG_MIPS | 0x0000000000020000ULL) +#define KVM_REG_MIPS_FPU (KVM_REG_MIPS | 0x0000000000030000ULL) + + +/* + * KVM_REG_MIPS_GP - General purpose registers from kvm_regs. + */ + +#define KVM_REG_MIPS_R0 (KVM_REG_MIPS_GP | KVM_REG_SIZE_U64 | 0) +#define KVM_REG_MIPS_R1 (KVM_REG_MIPS_GP | KVM_REG_SIZE_U64 | 1) +#define KVM_REG_MIPS_R2 (KVM_REG_MIPS_GP | KVM_REG_SIZE_U64 | 2) +#define KVM_REG_MIPS_R3 (KVM_REG_MIPS_GP | KVM_REG_SIZE_U64 | 3) +#define KVM_REG_MIPS_R4 (KVM_REG_MIPS_GP | KVM_REG_SIZE_U64 | 4) +#define KVM_REG_MIPS_R5 (KVM_REG_MIPS_GP | KVM_REG_SIZE_U64 | 5) +#define KVM_REG_MIPS_R6 (KVM_REG_MIPS_GP | KVM_REG_SIZE_U64 | 6) +#define KVM_REG_MIPS_R7 (KVM_REG_MIPS_GP | KVM_REG_SIZE_U64 | 7) +#define KVM_REG_MIPS_R8 (KVM_REG_MIPS_GP | KVM_REG_SIZE_U64 | 8) +#define KVM_REG_MIPS_R9 (KVM_REG_MIPS_GP | KVM_REG_SIZE_U64 | 9) +#define KVM_REG_MIPS_R10 (KVM_REG_MIPS_GP | KVM_REG_SIZE_U64 | 10) +#define KVM_REG_MIPS_R11 (KVM_REG_MIPS_GP | KVM_REG_SIZE_U64 | 11) +#define KVM_REG_MIPS_R12 (KVM_REG_MIPS_GP | KVM_REG_SIZE_U64 | 12) +#define KVM_REG_MIPS_R13 (KVM_REG_MIPS_GP | KVM_REG_SIZE_U64 | 13) +#define KVM_REG_MIPS_R14 (KVM_REG_MIPS_GP | KVM_REG_SIZE_U64 | 14) +#define KVM_REG_MIPS_R15 (KVM_REG_MIPS_GP | KVM_REG_SIZE_U64 | 15) +#define KVM_REG_MIPS_R16 (KVM_REG_MIPS_GP | KVM_REG_SIZE_U64 | 16) +#define KVM_REG_MIPS_R17 (KVM_REG_MIPS_GP | KVM_REG_SIZE_U64 | 17) +#define KVM_REG_MIPS_R18 (KVM_REG_MIPS_GP | KVM_REG_SIZE_U64 | 18) +#define KVM_REG_MIPS_R19 (KVM_REG_MIPS_GP | KVM_REG_SIZE_U64 | 19) +#define KVM_REG_MIPS_R20 (KVM_REG_MIPS_GP | KVM_REG_SIZE_U64 | 20) +#define KVM_REG_MIPS_R21 (KVM_REG_MIPS_GP | KVM_REG_SIZE_U64 | 21) +#define KVM_REG_MIPS_R22 (KVM_REG_MIPS_GP | KVM_REG_SIZE_U64 | 22) +#define KVM_REG_MIPS_R23 (KVM_REG_MIPS_GP | KVM_REG_SIZE_U64 | 23) +#define KVM_REG_MIPS_R24 (KVM_REG_MIPS_GP | KVM_REG_SIZE_U64 | 24) +#define KVM_REG_MIPS_R25 (KVM_REG_MIPS_GP | KVM_REG_SIZE_U64 | 25) +#define KVM_REG_MIPS_R26 (KVM_REG_MIPS_GP | KVM_REG_SIZE_U64 | 26) +#define KVM_REG_MIPS_R27 (KVM_REG_MIPS_GP | KVM_REG_SIZE_U64 | 27) +#define KVM_REG_MIPS_R28 (KVM_REG_MIPS_GP | KVM_REG_SIZE_U64 | 28) +#define KVM_REG_MIPS_R29 (KVM_REG_MIPS_GP | KVM_REG_SIZE_U64 | 29) +#define KVM_REG_MIPS_R30 (KVM_REG_MIPS_GP | KVM_REG_SIZE_U64 | 30) +#define KVM_REG_MIPS_R31 (KVM_REG_MIPS_GP | KVM_REG_SIZE_U64 | 31) + +#define KVM_REG_MIPS_HI (KVM_REG_MIPS_GP | KVM_REG_SIZE_U64 | 32) +#define KVM_REG_MIPS_LO (KVM_REG_MIPS_GP | KVM_REG_SIZE_U64 | 33) +#define KVM_REG_MIPS_PC (KVM_REG_MIPS_GP | KVM_REG_SIZE_U64 | 34) + + +/* + * KVM_REG_MIPS_KVM - KVM specific control registers. + */ + +/* + * CP0_Count control + * DC: Set 0: Master disable CP0_Count and set COUNT_RESUME to now + * Set 1: Master re-enable CP0_Count with unchanged bias, handling timer + * interrupts since COUNT_RESUME + * This can be used to freeze the timer to get a consistent snapshot of + * the CP0_Count and timer interrupt pending state, while also resuming + * safely without losing time or guest timer interrupts. + * Other: Reserved, do not change. + */ +#define KVM_REG_MIPS_COUNT_CTL (KVM_REG_MIPS_KVM | KVM_REG_SIZE_U64 | 0) +#define KVM_REG_MIPS_COUNT_CTL_DC 0x00000001 + +/* + * CP0_Count resume monotonic nanoseconds + * The monotonic nanosecond time of the last set of COUNT_CTL.DC (master + * disable). Any reads and writes of Count related registers while + * COUNT_CTL.DC=1 will appear to occur at this time. When COUNT_CTL.DC is + * cleared again (master enable) any timer interrupts since this time will be + * emulated. + * Modifications to times in the future are rejected. + */ +#define KVM_REG_MIPS_COUNT_RESUME (KVM_REG_MIPS_KVM | KVM_REG_SIZE_U64 | 1) +/* + * CP0_Count rate in Hz + * Specifies the rate of the CP0_Count timer in Hz. Modifications occur without + * discontinuities in CP0_Count. + */ +#define KVM_REG_MIPS_COUNT_HZ (KVM_REG_MIPS_KVM | KVM_REG_SIZE_U64 | 2) + + +/* + * KVM_REG_MIPS_FPU - Floating Point and MIPS SIMD Architecture (MSA) registers. + * + * bits[15..8] - Register subset (see definitions below). + * bits[7..5] - Must be zero. + * bits[4..0] - Register number within register subset. + */ + +#define KVM_REG_MIPS_FPR (KVM_REG_MIPS_FPU | 0x0000000000000000ULL) +#define KVM_REG_MIPS_FCR (KVM_REG_MIPS_FPU | 0x0000000000000100ULL) +#define KVM_REG_MIPS_MSACR (KVM_REG_MIPS_FPU | 0x0000000000000200ULL) + +/* + * KVM_REG_MIPS_FPR - Floating point / Vector registers. + */ +#define KVM_REG_MIPS_FPR_32(n) (KVM_REG_MIPS_FPR | KVM_REG_SIZE_U32 | (n)) +#define KVM_REG_MIPS_FPR_64(n) (KVM_REG_MIPS_FPR | KVM_REG_SIZE_U64 | (n)) +#define KVM_REG_MIPS_VEC_128(n) (KVM_REG_MIPS_FPR | KVM_REG_SIZE_U128 | (n)) + +/* + * KVM_REG_MIPS_FCR - Floating point control registers. + */ +#define KVM_REG_MIPS_FCR_IR (KVM_REG_MIPS_FCR | KVM_REG_SIZE_U32 | 0) +#define KVM_REG_MIPS_FCR_CSR (KVM_REG_MIPS_FCR | KVM_REG_SIZE_U32 | 31) + +/* + * KVM_REG_MIPS_MSACR - MIPS SIMD Architecture (MSA) control registers. + */ +#define KVM_REG_MIPS_MSA_IR (KVM_REG_MIPS_MSACR | KVM_REG_SIZE_U32 | 0) +#define KVM_REG_MIPS_MSA_CSR (KVM_REG_MIPS_MSACR | KVM_REG_SIZE_U32 | 1) + + +/* + * KVM MIPS specific structures and definitions + * + */ +struct kvm_debug_exit_arch { + __u64 epc; +}; + +/* for KVM_SET_GUEST_DEBUG */ +struct kvm_guest_debug_arch { +}; + +/* definition of registers in kvm_run */ +struct kvm_sync_regs { +}; + +/* dummy definition */ +struct kvm_sregs { +}; + +struct kvm_mips_interrupt { + /* in */ + __u32 cpu; + __u32 irq; +}; + +#endif /* __LINUX_KVM_MIPS_H */ diff --git a/tools/arch/powerpc/include/uapi/asm/kvm.h b/tools/arch/powerpc/include/uapi/asm/kvm.h new file mode 100644 index 0000000..c93cf35 --- /dev/null +++ b/tools/arch/powerpc/include/uapi/asm/kvm.h @@ -0,0 +1,612 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License, version 2, as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Copyright IBM Corp. 2007 + * + * Authors: Hollis Blanchard + */ + +#ifndef __LINUX_KVM_POWERPC_H +#define __LINUX_KVM_POWERPC_H + +#include + +/* Select powerpc specific features in */ +#define __KVM_HAVE_SPAPR_TCE +#define __KVM_HAVE_PPC_SMT +#define __KVM_HAVE_IRQCHIP +#define __KVM_HAVE_IRQ_LINE +#define __KVM_HAVE_GUEST_DEBUG + +struct kvm_regs { + __u64 pc; + __u64 cr; + __u64 ctr; + __u64 lr; + __u64 xer; + __u64 msr; + __u64 srr0; + __u64 srr1; + __u64 pid; + + __u64 sprg0; + __u64 sprg1; + __u64 sprg2; + __u64 sprg3; + __u64 sprg4; + __u64 sprg5; + __u64 sprg6; + __u64 sprg7; + + __u64 gpr[32]; +}; + +#define KVM_SREGS_E_IMPL_NONE 0 +#define KVM_SREGS_E_IMPL_FSL 1 + +#define KVM_SREGS_E_FSL_PIDn (1 << 0) /* PID1/PID2 */ + +/* + * Feature bits indicate which sections of the sregs struct are valid, + * both in KVM_GET_SREGS and KVM_SET_SREGS. On KVM_SET_SREGS, registers + * corresponding to unset feature bits will not be modified. This allows + * restoring a checkpoint made without that feature, while keeping the + * default values of the new registers. + * + * KVM_SREGS_E_BASE contains: + * CSRR0/1 (refers to SRR2/3 on 40x) + * ESR + * DEAR + * MCSR + * TSR + * TCR + * DEC + * TB + * VRSAVE (USPRG0) + */ +#define KVM_SREGS_E_BASE (1 << 0) + +/* + * KVM_SREGS_E_ARCH206 contains: + * + * PIR + * MCSRR0/1 + * DECAR + * IVPR + */ +#define KVM_SREGS_E_ARCH206 (1 << 1) + +/* + * Contains EPCR, plus the upper half of 64-bit registers + * that are 32-bit on 32-bit implementations. + */ +#define KVM_SREGS_E_64 (1 << 2) + +#define KVM_SREGS_E_SPRG8 (1 << 3) +#define KVM_SREGS_E_MCIVPR (1 << 4) + +/* + * IVORs are used -- contains IVOR0-15, plus additional IVORs + * in combination with an appropriate feature bit. + */ +#define KVM_SREGS_E_IVOR (1 << 5) + +/* + * Contains MAS0-4, MAS6-7, TLBnCFG, MMUCFG. + * Also TLBnPS if MMUCFG[MAVN] = 1. + */ +#define KVM_SREGS_E_ARCH206_MMU (1 << 6) + +/* DBSR, DBCR, IAC, DAC, DVC */ +#define KVM_SREGS_E_DEBUG (1 << 7) + +/* Enhanced debug -- DSRR0/1, SPRG9 */ +#define KVM_SREGS_E_ED (1 << 8) + +/* Embedded Floating Point (SPE) -- IVOR32-34 if KVM_SREGS_E_IVOR */ +#define KVM_SREGS_E_SPE (1 << 9) + +/* + * DEPRECATED! USE ONE_REG FOR THIS ONE! + * External Proxy (EXP) -- EPR + */ +#define KVM_SREGS_EXP (1 << 10) + +/* External PID (E.PD) -- EPSC/EPLC */ +#define KVM_SREGS_E_PD (1 << 11) + +/* Processor Control (E.PC) -- IVOR36-37 if KVM_SREGS_E_IVOR */ +#define KVM_SREGS_E_PC (1 << 12) + +/* Page table (E.PT) -- EPTCFG */ +#define KVM_SREGS_E_PT (1 << 13) + +/* Embedded Performance Monitor (E.PM) -- IVOR35 if KVM_SREGS_E_IVOR */ +#define KVM_SREGS_E_PM (1 << 14) + +/* + * Special updates: + * + * Some registers may change even while a vcpu is not running. + * To avoid losing these changes, by default these registers are + * not updated by KVM_SET_SREGS. To force an update, set the bit + * in u.e.update_special corresponding to the register to be updated. + * + * The update_special field is zero on return from KVM_GET_SREGS. + * + * When restoring a checkpoint, the caller can set update_special + * to 0xffffffff to ensure that everything is restored, even new features + * that the caller doesn't know about. + */ +#define KVM_SREGS_E_UPDATE_MCSR (1 << 0) +#define KVM_SREGS_E_UPDATE_TSR (1 << 1) +#define KVM_SREGS_E_UPDATE_DEC (1 << 2) +#define KVM_SREGS_E_UPDATE_DBSR (1 << 3) + +/* + * In KVM_SET_SREGS, reserved/pad fields must be left untouched from a + * previous KVM_GET_REGS. + * + * Unless otherwise indicated, setting any register with KVM_SET_SREGS + * directly sets its value. It does not trigger any special semantics such + * as write-one-to-clear. Calling KVM_SET_SREGS on an unmodified struct + * just received from KVM_GET_SREGS is always a no-op. + */ +struct kvm_sregs { + __u32 pvr; + union { + struct { + __u64 sdr1; + struct { + struct { + __u64 slbe; + __u64 slbv; + } slb[64]; + } ppc64; + struct { + __u32 sr[16]; + __u64 ibat[8]; + __u64 dbat[8]; + } ppc32; + } s; + struct { + union { + struct { /* KVM_SREGS_E_IMPL_FSL */ + __u32 features; /* KVM_SREGS_E_FSL_ */ + __u32 svr; + __u64 mcar; + __u32 hid0; + + /* KVM_SREGS_E_FSL_PIDn */ + __u32 pid1, pid2; + } fsl; + __u8 pad[256]; + } impl; + + __u32 features; /* KVM_SREGS_E_ */ + __u32 impl_id; /* KVM_SREGS_E_IMPL_ */ + __u32 update_special; /* KVM_SREGS_E_UPDATE_ */ + __u32 pir; /* read-only */ + __u64 sprg8; + __u64 sprg9; /* E.ED */ + __u64 csrr0; + __u64 dsrr0; /* E.ED */ + __u64 mcsrr0; + __u32 csrr1; + __u32 dsrr1; /* E.ED */ + __u32 mcsrr1; + __u32 esr; + __u64 dear; + __u64 ivpr; + __u64 mcivpr; + __u64 mcsr; /* KVM_SREGS_E_UPDATE_MCSR */ + + __u32 tsr; /* KVM_SREGS_E_UPDATE_TSR */ + __u32 tcr; + __u32 decar; + __u32 dec; /* KVM_SREGS_E_UPDATE_DEC */ + + /* + * Userspace can read TB directly, but the + * value reported here is consistent with "dec". + * + * Read-only. + */ + __u64 tb; + + __u32 dbsr; /* KVM_SREGS_E_UPDATE_DBSR */ + __u32 dbcr[3]; + /* + * iac/dac registers are 64bit wide, while this API + * interface provides only lower 32 bits on 64 bit + * processors. ONE_REG interface is added for 64bit + * iac/dac registers. + */ + __u32 iac[4]; + __u32 dac[2]; + __u32 dvc[2]; + __u8 num_iac; /* read-only */ + __u8 num_dac; /* read-only */ + __u8 num_dvc; /* read-only */ + __u8 pad; + + __u32 epr; /* EXP */ + __u32 vrsave; /* a.k.a. USPRG0 */ + __u32 epcr; /* KVM_SREGS_E_64 */ + + __u32 mas0; + __u32 mas1; + __u64 mas2; + __u64 mas7_3; + __u32 mas4; + __u32 mas6; + + __u32 ivor_low[16]; /* IVOR0-15 */ + __u32 ivor_high[18]; /* IVOR32+, plus room to expand */ + + __u32 mmucfg; /* read-only */ + __u32 eptcfg; /* E.PT, read-only */ + __u32 tlbcfg[4];/* read-only */ + __u32 tlbps[4]; /* read-only */ + + __u32 eplc, epsc; /* E.PD */ + } e; + __u8 pad[1020]; + } u; +}; + +struct kvm_fpu { + __u64 fpr[32]; +}; + +/* + * Defines for h/w breakpoint, watchpoint (read, write or both) and + * software breakpoint. + * These are used as "type" in KVM_SET_GUEST_DEBUG ioctl and "status" + * for KVM_DEBUG_EXIT. + */ +#define KVMPPC_DEBUG_NONE 0x0 +#define KVMPPC_DEBUG_BREAKPOINT (1UL << 1) +#define KVMPPC_DEBUG_WATCH_WRITE (1UL << 2) +#define KVMPPC_DEBUG_WATCH_READ (1UL << 3) +struct kvm_debug_exit_arch { + __u64 address; + /* + * exiting to userspace because of h/w breakpoint, watchpoint + * (read, write or both) and software breakpoint. + */ + __u32 status; + __u32 reserved; +}; + +/* for KVM_SET_GUEST_DEBUG */ +struct kvm_guest_debug_arch { + struct { + /* H/W breakpoint/watchpoint address */ + __u64 addr; + /* + * Type denotes h/w breakpoint, read watchpoint, write + * watchpoint or watchpoint (both read and write). + */ + __u32 type; + __u32 reserved; + } bp[16]; +}; + +/* Debug related defines */ +/* + * kvm_guest_debug->control is a 32 bit field. The lower 16 bits are generic + * and upper 16 bits are architecture specific. Architecture specific defines + * that ioctl is for setting hardware breakpoint or software breakpoint. + */ +#define KVM_GUESTDBG_USE_SW_BP 0x00010000 +#define KVM_GUESTDBG_USE_HW_BP 0x00020000 + +/* definition of registers in kvm_run */ +struct kvm_sync_regs { +}; + +#define KVM_INTERRUPT_SET -1U +#define KVM_INTERRUPT_UNSET -2U +#define KVM_INTERRUPT_SET_LEVEL -3U + +#define KVM_CPU_440 1 +#define KVM_CPU_E500V2 2 +#define KVM_CPU_3S_32 3 +#define KVM_CPU_3S_64 4 +#define KVM_CPU_E500MC 5 + +/* for KVM_CAP_SPAPR_TCE */ +struct kvm_create_spapr_tce { + __u64 liobn; + __u32 window_size; +}; + +/* for KVM_CAP_SPAPR_TCE_64 */ +struct kvm_create_spapr_tce_64 { + __u64 liobn; + __u32 page_shift; + __u32 flags; + __u64 offset; /* in pages */ + __u64 size; /* in pages */ +}; + +/* for KVM_ALLOCATE_RMA */ +struct kvm_allocate_rma { + __u64 rma_size; +}; + +/* for KVM_CAP_PPC_RTAS */ +struct kvm_rtas_token_args { + char name[120]; + __u64 token; /* Use a token of 0 to undefine a mapping */ +}; + +struct kvm_book3e_206_tlb_entry { + __u32 mas8; + __u32 mas1; + __u64 mas2; + __u64 mas7_3; +}; + +struct kvm_book3e_206_tlb_params { + /* + * For mmu types KVM_MMU_FSL_BOOKE_NOHV and KVM_MMU_FSL_BOOKE_HV: + * + * - The number of ways of TLB0 must be a power of two between 2 and + * 16. + * - TLB1 must be fully associative. + * - The size of TLB0 must be a multiple of the number of ways, and + * the number of sets must be a power of two. + * - The size of TLB1 may not exceed 64 entries. + * - TLB0 supports 4 KiB pages. + * - The page sizes supported by TLB1 are as indicated by + * TLB1CFG (if MMUCFG[MAVN] = 0) or TLB1PS (if MMUCFG[MAVN] = 1) + * as returned by KVM_GET_SREGS. + * - TLB2 and TLB3 are reserved, and their entries in tlb_sizes[] + * and tlb_ways[] must be zero. + * + * tlb_ways[n] = tlb_sizes[n] means the array is fully associative. + * + * KVM will adjust TLBnCFG based on the sizes configured here, + * though arrays greater than 2048 entries will have TLBnCFG[NENTRY] + * set to zero. + */ + __u32 tlb_sizes[4]; + __u32 tlb_ways[4]; + __u32 reserved[8]; +}; + +/* For KVM_PPC_GET_HTAB_FD */ +struct kvm_get_htab_fd { + __u64 flags; + __u64 start_index; + __u64 reserved[2]; +}; + +/* Values for kvm_get_htab_fd.flags */ +#define KVM_GET_HTAB_BOLTED_ONLY ((__u64)0x1) +#define KVM_GET_HTAB_WRITE ((__u64)0x2) + +/* + * Data read on the file descriptor is formatted as a series of + * records, each consisting of a header followed by a series of + * `n_valid' HPTEs (16 bytes each), which are all valid. Following + * those valid HPTEs there are `n_invalid' invalid HPTEs, which + * are not represented explicitly in the stream. The same format + * is used for writing. + */ +struct kvm_get_htab_header { + __u32 index; + __u16 n_valid; + __u16 n_invalid; +}; + +/* Per-vcpu XICS interrupt controller state */ +#define KVM_REG_PPC_ICP_STATE (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x8c) + +#define KVM_REG_PPC_ICP_CPPR_SHIFT 56 /* current proc priority */ +#define KVM_REG_PPC_ICP_CPPR_MASK 0xff +#define KVM_REG_PPC_ICP_XISR_SHIFT 32 /* interrupt status field */ +#define KVM_REG_PPC_ICP_XISR_MASK 0xffffff +#define KVM_REG_PPC_ICP_MFRR_SHIFT 24 /* pending IPI priority */ +#define KVM_REG_PPC_ICP_MFRR_MASK 0xff +#define KVM_REG_PPC_ICP_PPRI_SHIFT 16 /* pending irq priority */ +#define KVM_REG_PPC_ICP_PPRI_MASK 0xff + +/* Device control API: PPC-specific devices */ +#define KVM_DEV_MPIC_GRP_MISC 1 +#define KVM_DEV_MPIC_BASE_ADDR 0 /* 64-bit */ + +#define KVM_DEV_MPIC_GRP_REGISTER 2 /* 32-bit */ +#define KVM_DEV_MPIC_GRP_IRQ_ACTIVE 3 /* 32-bit */ + +/* One-Reg API: PPC-specific registers */ +#define KVM_REG_PPC_HIOR (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x1) +#define KVM_REG_PPC_IAC1 (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x2) +#define KVM_REG_PPC_IAC2 (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x3) +#define KVM_REG_PPC_IAC3 (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x4) +#define KVM_REG_PPC_IAC4 (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x5) +#define KVM_REG_PPC_DAC1 (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x6) +#define KVM_REG_PPC_DAC2 (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x7) +#define KVM_REG_PPC_DABR (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x8) +#define KVM_REG_PPC_DSCR (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x9) +#define KVM_REG_PPC_PURR (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0xa) +#define KVM_REG_PPC_SPURR (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0xb) +#define KVM_REG_PPC_DAR (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0xc) +#define KVM_REG_PPC_DSISR (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0xd) +#define KVM_REG_PPC_AMR (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0xe) +#define KVM_REG_PPC_UAMOR (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0xf) + +#define KVM_REG_PPC_MMCR0 (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x10) +#define KVM_REG_PPC_MMCR1 (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x11) +#define KVM_REG_PPC_MMCRA (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x12) +#define KVM_REG_PPC_MMCR2 (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x13) +#define KVM_REG_PPC_MMCRS (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x14) +#define KVM_REG_PPC_SIAR (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x15) +#define KVM_REG_PPC_SDAR (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x16) +#define KVM_REG_PPC_SIER (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x17) + +#define KVM_REG_PPC_PMC1 (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x18) +#define KVM_REG_PPC_PMC2 (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x19) +#define KVM_REG_PPC_PMC3 (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x1a) +#define KVM_REG_PPC_PMC4 (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x1b) +#define KVM_REG_PPC_PMC5 (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x1c) +#define KVM_REG_PPC_PMC6 (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x1d) +#define KVM_REG_PPC_PMC7 (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x1e) +#define KVM_REG_PPC_PMC8 (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x1f) + +/* 32 floating-point registers */ +#define KVM_REG_PPC_FPR0 (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x20) +#define KVM_REG_PPC_FPR(n) (KVM_REG_PPC_FPR0 + (n)) +#define KVM_REG_PPC_FPR31 (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x3f) + +/* 32 VMX/Altivec vector registers */ +#define KVM_REG_PPC_VR0 (KVM_REG_PPC | KVM_REG_SIZE_U128 | 0x40) +#define KVM_REG_PPC_VR(n) (KVM_REG_PPC_VR0 + (n)) +#define KVM_REG_PPC_VR31 (KVM_REG_PPC | KVM_REG_SIZE_U128 | 0x5f) + +/* 32 double-width FP registers for VSX */ +/* High-order halves overlap with FP regs */ +#define KVM_REG_PPC_VSR0 (KVM_REG_PPC | KVM_REG_SIZE_U128 | 0x60) +#define KVM_REG_PPC_VSR(n) (KVM_REG_PPC_VSR0 + (n)) +#define KVM_REG_PPC_VSR31 (KVM_REG_PPC | KVM_REG_SIZE_U128 | 0x7f) + +/* FP and vector status/control registers */ +#define KVM_REG_PPC_FPSCR (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x80) +/* + * VSCR register is documented as a 32-bit register in the ISA, but it can + * only be accesses via a vector register. Expose VSCR as a 32-bit register + * even though the kernel represents it as a 128-bit vector. + */ +#define KVM_REG_PPC_VSCR (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x81) + +/* Virtual processor areas */ +/* For SLB & DTL, address in high (first) half, length in low half */ +#define KVM_REG_PPC_VPA_ADDR (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x82) +#define KVM_REG_PPC_VPA_SLB (KVM_REG_PPC | KVM_REG_SIZE_U128 | 0x83) +#define KVM_REG_PPC_VPA_DTL (KVM_REG_PPC | KVM_REG_SIZE_U128 | 0x84) + +#define KVM_REG_PPC_EPCR (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x85) +#define KVM_REG_PPC_EPR (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x86) + +/* Timer Status Register OR/CLEAR interface */ +#define KVM_REG_PPC_OR_TSR (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x87) +#define KVM_REG_PPC_CLEAR_TSR (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x88) +#define KVM_REG_PPC_TCR (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x89) +#define KVM_REG_PPC_TSR (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x8a) + +/* Debugging: Special instruction for software breakpoint */ +#define KVM_REG_PPC_DEBUG_INST (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x8b) + +/* MMU registers */ +#define KVM_REG_PPC_MAS0 (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x8c) +#define KVM_REG_PPC_MAS1 (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x8d) +#define KVM_REG_PPC_MAS2 (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x8e) +#define KVM_REG_PPC_MAS7_3 (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x8f) +#define KVM_REG_PPC_MAS4 (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x90) +#define KVM_REG_PPC_MAS6 (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x91) +#define KVM_REG_PPC_MMUCFG (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x92) +/* + * TLBnCFG fields TLBnCFG_N_ENTRY and TLBnCFG_ASSOC can be changed only using + * KVM_CAP_SW_TLB ioctl + */ +#define KVM_REG_PPC_TLB0CFG (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x93) +#define KVM_REG_PPC_TLB1CFG (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x94) +#define KVM_REG_PPC_TLB2CFG (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x95) +#define KVM_REG_PPC_TLB3CFG (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x96) +#define KVM_REG_PPC_TLB0PS (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x97) +#define KVM_REG_PPC_TLB1PS (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x98) +#define KVM_REG_PPC_TLB2PS (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x99) +#define KVM_REG_PPC_TLB3PS (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x9a) +#define KVM_REG_PPC_EPTCFG (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x9b) + +/* Timebase offset */ +#define KVM_REG_PPC_TB_OFFSET (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x9c) + +/* POWER8 registers */ +#define KVM_REG_PPC_SPMC1 (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x9d) +#define KVM_REG_PPC_SPMC2 (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x9e) +#define KVM_REG_PPC_IAMR (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x9f) +#define KVM_REG_PPC_TFHAR (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0xa0) +#define KVM_REG_PPC_TFIAR (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0xa1) +#define KVM_REG_PPC_TEXASR (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0xa2) +#define KVM_REG_PPC_FSCR (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0xa3) +#define KVM_REG_PPC_PSPB (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0xa4) +#define KVM_REG_PPC_EBBHR (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0xa5) +#define KVM_REG_PPC_EBBRR (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0xa6) +#define KVM_REG_PPC_BESCR (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0xa7) +#define KVM_REG_PPC_TAR (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0xa8) +#define KVM_REG_PPC_DPDES (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0xa9) +#define KVM_REG_PPC_DAWR (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0xaa) +#define KVM_REG_PPC_DAWRX (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0xab) +#define KVM_REG_PPC_CIABR (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0xac) +#define KVM_REG_PPC_IC (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0xad) +#define KVM_REG_PPC_VTB (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0xae) +#define KVM_REG_PPC_CSIGR (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0xaf) +#define KVM_REG_PPC_TACR (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0xb0) +#define KVM_REG_PPC_TCSCR (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0xb1) +#define KVM_REG_PPC_PID (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0xb2) +#define KVM_REG_PPC_ACOP (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0xb3) + +#define KVM_REG_PPC_VRSAVE (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0xb4) +#define KVM_REG_PPC_LPCR (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0xb5) +#define KVM_REG_PPC_LPCR_64 (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0xb5) +#define KVM_REG_PPC_PPR (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0xb6) + +/* Architecture compatibility level */ +#define KVM_REG_PPC_ARCH_COMPAT (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0xb7) + +#define KVM_REG_PPC_DABRX (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0xb8) +#define KVM_REG_PPC_WORT (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0xb9) +#define KVM_REG_PPC_SPRG9 (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0xba) +#define KVM_REG_PPC_DBSR (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0xbb) + +/* Transactional Memory checkpointed state: + * This is all GPRs, all VSX regs and a subset of SPRs + */ +#define KVM_REG_PPC_TM (KVM_REG_PPC | 0x80000000) +/* TM GPRs */ +#define KVM_REG_PPC_TM_GPR0 (KVM_REG_PPC_TM | KVM_REG_SIZE_U64 | 0) +#define KVM_REG_PPC_TM_GPR(n) (KVM_REG_PPC_TM_GPR0 + (n)) +#define KVM_REG_PPC_TM_GPR31 (KVM_REG_PPC_TM | KVM_REG_SIZE_U64 | 0x1f) +/* TM VSX */ +#define KVM_REG_PPC_TM_VSR0 (KVM_REG_PPC_TM | KVM_REG_SIZE_U128 | 0x20) +#define KVM_REG_PPC_TM_VSR(n) (KVM_REG_PPC_TM_VSR0 + (n)) +#define KVM_REG_PPC_TM_VSR63 (KVM_REG_PPC_TM | KVM_REG_SIZE_U128 | 0x5f) +/* TM SPRS */ +#define KVM_REG_PPC_TM_CR (KVM_REG_PPC_TM | KVM_REG_SIZE_U64 | 0x60) +#define KVM_REG_PPC_TM_LR (KVM_REG_PPC_TM | KVM_REG_SIZE_U64 | 0x61) +#define KVM_REG_PPC_TM_CTR (KVM_REG_PPC_TM | KVM_REG_SIZE_U64 | 0x62) +#define KVM_REG_PPC_TM_FPSCR (KVM_REG_PPC_TM | KVM_REG_SIZE_U64 | 0x63) +#define KVM_REG_PPC_TM_AMR (KVM_REG_PPC_TM | KVM_REG_SIZE_U64 | 0x64) +#define KVM_REG_PPC_TM_PPR (KVM_REG_PPC_TM | KVM_REG_SIZE_U64 | 0x65) +#define KVM_REG_PPC_TM_VRSAVE (KVM_REG_PPC_TM | KVM_REG_SIZE_U64 | 0x66) +#define KVM_REG_PPC_TM_VSCR (KVM_REG_PPC_TM | KVM_REG_SIZE_U32 | 0x67) +#define KVM_REG_PPC_TM_DSCR (KVM_REG_PPC_TM | KVM_REG_SIZE_U64 | 0x68) +#define KVM_REG_PPC_TM_TAR (KVM_REG_PPC_TM | KVM_REG_SIZE_U64 | 0x69) + +/* PPC64 eXternal Interrupt Controller Specification */ +#define KVM_DEV_XICS_GRP_SOURCES 1 /* 64-bit source attributes */ + +/* Layout of 64-bit source attribute values */ +#define KVM_XICS_DESTINATION_SHIFT 0 +#define KVM_XICS_DESTINATION_MASK 0xffffffffULL +#define KVM_XICS_PRIORITY_SHIFT 32 +#define KVM_XICS_PRIORITY_MASK 0xff +#define KVM_XICS_LEVEL_SENSITIVE (1ULL << 40) +#define KVM_XICS_MASKED (1ULL << 41) +#define KVM_XICS_PENDING (1ULL << 42) + +#endif /* __LINUX_KVM_POWERPC_H */ diff --git a/tools/arch/s390/include/uapi/asm/kvm.h b/tools/arch/s390/include/uapi/asm/kvm.h new file mode 100644 index 0000000..3b8e99e --- /dev/null +++ b/tools/arch/s390/include/uapi/asm/kvm.h @@ -0,0 +1,192 @@ +#ifndef __LINUX_KVM_S390_H +#define __LINUX_KVM_S390_H +/* + * KVM s390 specific structures and definitions + * + * Copyright IBM Corp. 2008 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License (version 2 only) + * as published by the Free Software Foundation. + * + * Author(s): Carsten Otte + * Christian Borntraeger + */ +#include + +#define __KVM_S390 +#define __KVM_HAVE_GUEST_DEBUG + +/* Device control API: s390-specific devices */ +#define KVM_DEV_FLIC_GET_ALL_IRQS 1 +#define KVM_DEV_FLIC_ENQUEUE 2 +#define KVM_DEV_FLIC_CLEAR_IRQS 3 +#define KVM_DEV_FLIC_APF_ENABLE 4 +#define KVM_DEV_FLIC_APF_DISABLE_WAIT 5 +#define KVM_DEV_FLIC_ADAPTER_REGISTER 6 +#define KVM_DEV_FLIC_ADAPTER_MODIFY 7 +#define KVM_DEV_FLIC_CLEAR_IO_IRQ 8 +/* + * We can have up to 4*64k pending subchannels + 8 adapter interrupts, + * as well as up to ASYNC_PF_PER_VCPU*KVM_MAX_VCPUS pfault done interrupts. + * There are also sclp and machine checks. This gives us + * sizeof(kvm_s390_irq)*(4*65536+8+64*64+1+1) = 72 * 266250 = 19170000 + * Lets round up to 8192 pages. + */ +#define KVM_S390_MAX_FLOAT_IRQS 266250 +#define KVM_S390_FLIC_MAX_BUFFER 0x2000000 + +struct kvm_s390_io_adapter { + __u32 id; + __u8 isc; + __u8 maskable; + __u8 swap; + __u8 pad; +}; + +#define KVM_S390_IO_ADAPTER_MASK 1 +#define KVM_S390_IO_ADAPTER_MAP 2 +#define KVM_S390_IO_ADAPTER_UNMAP 3 + +struct kvm_s390_io_adapter_req { + __u32 id; + __u8 type; + __u8 mask; + __u16 pad0; + __u64 addr; +}; + +/* kvm attr_group on vm fd */ +#define KVM_S390_VM_MEM_CTRL 0 +#define KVM_S390_VM_TOD 1 +#define KVM_S390_VM_CRYPTO 2 +#define KVM_S390_VM_CPU_MODEL 3 + +/* kvm attributes for mem_ctrl */ +#define KVM_S390_VM_MEM_ENABLE_CMMA 0 +#define KVM_S390_VM_MEM_CLR_CMMA 1 +#define KVM_S390_VM_MEM_LIMIT_SIZE 2 + +#define KVM_S390_NO_MEM_LIMIT U64_MAX + +/* kvm attributes for KVM_S390_VM_TOD */ +#define KVM_S390_VM_TOD_LOW 0 +#define KVM_S390_VM_TOD_HIGH 1 + +/* kvm attributes for KVM_S390_VM_CPU_MODEL */ +/* processor related attributes are r/w */ +#define KVM_S390_VM_CPU_PROCESSOR 0 +struct kvm_s390_vm_cpu_processor { + __u64 cpuid; + __u16 ibc; + __u8 pad[6]; + __u64 fac_list[256]; +}; + +/* machine related attributes are r/o */ +#define KVM_S390_VM_CPU_MACHINE 1 +struct kvm_s390_vm_cpu_machine { + __u64 cpuid; + __u32 ibc; + __u8 pad[4]; + __u64 fac_mask[256]; + __u64 fac_list[256]; +}; + +/* kvm attributes for crypto */ +#define KVM_S390_VM_CRYPTO_ENABLE_AES_KW 0 +#define KVM_S390_VM_CRYPTO_ENABLE_DEA_KW 1 +#define KVM_S390_VM_CRYPTO_DISABLE_AES_KW 2 +#define KVM_S390_VM_CRYPTO_DISABLE_DEA_KW 3 + +/* for KVM_GET_REGS and KVM_SET_REGS */ +struct kvm_regs { + /* general purpose regs for s390 */ + __u64 gprs[16]; +}; + +/* for KVM_GET_SREGS and KVM_SET_SREGS */ +struct kvm_sregs { + __u32 acrs[16]; + __u64 crs[16]; +}; + +/* for KVM_GET_FPU and KVM_SET_FPU */ +struct kvm_fpu { + __u32 fpc; + __u64 fprs[16]; +}; + +#define KVM_GUESTDBG_USE_HW_BP 0x00010000 + +#define KVM_HW_BP 1 +#define KVM_HW_WP_WRITE 2 +#define KVM_SINGLESTEP 4 + +struct kvm_debug_exit_arch { + __u64 addr; + __u8 type; + __u8 pad[7]; /* Should be set to 0 */ +}; + +struct kvm_hw_breakpoint { + __u64 addr; + __u64 phys_addr; + __u64 len; + __u8 type; + __u8 pad[7]; /* Should be set to 0 */ +}; + +/* for KVM_SET_GUEST_DEBUG */ +struct kvm_guest_debug_arch { + __u32 nr_hw_bp; + __u32 pad; /* Should be set to 0 */ + struct kvm_hw_breakpoint __user *hw_bp; +}; + +/* for KVM_SYNC_PFAULT and KVM_REG_S390_PFTOKEN */ +#define KVM_S390_PFAULT_TOKEN_INVALID 0xffffffffffffffffULL + +#define KVM_SYNC_PREFIX (1UL << 0) +#define KVM_SYNC_GPRS (1UL << 1) +#define KVM_SYNC_ACRS (1UL << 2) +#define KVM_SYNC_CRS (1UL << 3) +#define KVM_SYNC_ARCH0 (1UL << 4) +#define KVM_SYNC_PFAULT (1UL << 5) +#define KVM_SYNC_VRS (1UL << 6) +#define KVM_SYNC_RICCB (1UL << 7) +#define KVM_SYNC_FPRS (1UL << 8) +/* definition of registers in kvm_run */ +struct kvm_sync_regs { + __u64 prefix; /* prefix register */ + __u64 gprs[16]; /* general purpose registers */ + __u32 acrs[16]; /* access registers */ + __u64 crs[16]; /* control registers */ + __u64 todpr; /* tod programmable register [ARCH0] */ + __u64 cputm; /* cpu timer [ARCH0] */ + __u64 ckc; /* clock comparator [ARCH0] */ + __u64 pp; /* program parameter [ARCH0] */ + __u64 gbea; /* guest breaking-event address [ARCH0] */ + __u64 pft; /* pfault token [PFAULT] */ + __u64 pfs; /* pfault select [PFAULT] */ + __u64 pfc; /* pfault compare [PFAULT] */ + union { + __u64 vrs[32][2]; /* vector registers (KVM_SYNC_VRS) */ + __u64 fprs[16]; /* fp registers (KVM_SYNC_FPRS) */ + }; + __u8 reserved[512]; /* for future vector expansion */ + __u32 fpc; /* valid on KVM_SYNC_VRS or KVM_SYNC_FPRS */ + __u8 padding[52]; /* riccb needs to be 64byte aligned */ + __u8 riccb[64]; /* runtime instrumentation controls block */ +}; + +#define KVM_REG_S390_TODPR (KVM_REG_S390 | KVM_REG_SIZE_U32 | 0x1) +#define KVM_REG_S390_EPOCHDIFF (KVM_REG_S390 | KVM_REG_SIZE_U64 | 0x2) +#define KVM_REG_S390_CPU_TIMER (KVM_REG_S390 | KVM_REG_SIZE_U64 | 0x3) +#define KVM_REG_S390_CLOCK_COMP (KVM_REG_S390 | KVM_REG_SIZE_U64 | 0x4) +#define KVM_REG_S390_PFTOKEN (KVM_REG_S390 | KVM_REG_SIZE_U64 | 0x5) +#define KVM_REG_S390_PFCOMPARE (KVM_REG_S390 | KVM_REG_SIZE_U64 | 0x6) +#define KVM_REG_S390_PFSELECT (KVM_REG_S390 | KVM_REG_SIZE_U64 | 0x7) +#define KVM_REG_S390_PP (KVM_REG_S390 | KVM_REG_SIZE_U64 | 0x8) +#define KVM_REG_S390_GBEA (KVM_REG_S390 | KVM_REG_SIZE_U64 | 0x9) +#endif diff --git a/tools/arch/s390/include/uapi/asm/kvm_perf.h b/tools/arch/s390/include/uapi/asm/kvm_perf.h new file mode 100644 index 0000000..3972827 --- /dev/null +++ b/tools/arch/s390/include/uapi/asm/kvm_perf.h @@ -0,0 +1,25 @@ +/* + * Definitions for perf-kvm on s390 + * + * Copyright 2014 IBM Corp. + * Author(s): Alexander Yarygin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License (version 2 only) + * as published by the Free Software Foundation. + */ + +#ifndef __LINUX_KVM_PERF_S390_H +#define __LINUX_KVM_PERF_S390_H + +#include + +#define DECODE_STR_LEN 40 + +#define VCPU_ID "id" + +#define KVM_ENTRY_TRACE "kvm:kvm_s390_sie_enter" +#define KVM_EXIT_TRACE "kvm:kvm_s390_sie_exit" +#define KVM_EXIT_REASON "icptcode" + +#endif diff --git a/tools/arch/s390/include/uapi/asm/sie.h b/tools/arch/s390/include/uapi/asm/sie.h new file mode 100644 index 0000000..8fb5d4a --- /dev/null +++ b/tools/arch/s390/include/uapi/asm/sie.h @@ -0,0 +1,250 @@ +#ifndef _UAPI_ASM_S390_SIE_H +#define _UAPI_ASM_S390_SIE_H + +#define diagnose_codes \ + { 0x10, "DIAG (0x10) release pages" }, \ + { 0x44, "DIAG (0x44) time slice end" }, \ + { 0x9c, "DIAG (0x9c) time slice end directed" }, \ + { 0x204, "DIAG (0x204) logical-cpu utilization" }, \ + { 0x258, "DIAG (0x258) page-reference services" }, \ + { 0x288, "DIAG (0x288) watchdog functions" }, \ + { 0x308, "DIAG (0x308) ipl functions" }, \ + { 0x500, "DIAG (0x500) KVM virtio functions" }, \ + { 0x501, "DIAG (0x501) KVM breakpoint" } + +#define sigp_order_codes \ + { 0x01, "SIGP sense" }, \ + { 0x02, "SIGP external call" }, \ + { 0x03, "SIGP emergency signal" }, \ + { 0x04, "SIGP start" }, \ + { 0x05, "SIGP stop" }, \ + { 0x06, "SIGP restart" }, \ + { 0x09, "SIGP stop and store status" }, \ + { 0x0b, "SIGP initial cpu reset" }, \ + { 0x0c, "SIGP cpu reset" }, \ + { 0x0d, "SIGP set prefix" }, \ + { 0x0e, "SIGP store status at address" }, \ + { 0x12, "SIGP set architecture" }, \ + { 0x13, "SIGP conditional emergency signal" }, \ + { 0x15, "SIGP sense running" }, \ + { 0x16, "SIGP set multithreading"}, \ + { 0x17, "SIGP store additional status ait address"} + +#define icpt_prog_codes \ + { 0x0001, "Prog Operation" }, \ + { 0x0002, "Prog Privileged Operation" }, \ + { 0x0003, "Prog Execute" }, \ + { 0x0004, "Prog Protection" }, \ + { 0x0005, "Prog Addressing" }, \ + { 0x0006, "Prog Specification" }, \ + { 0x0007, "Prog Data" }, \ + { 0x0008, "Prog Fixedpoint overflow" }, \ + { 0x0009, "Prog Fixedpoint divide" }, \ + { 0x000A, "Prog Decimal overflow" }, \ + { 0x000B, "Prog Decimal divide" }, \ + { 0x000C, "Prog HFP exponent overflow" }, \ + { 0x000D, "Prog HFP exponent underflow" }, \ + { 0x000E, "Prog HFP significance" }, \ + { 0x000F, "Prog HFP divide" }, \ + { 0x0010, "Prog Segment translation" }, \ + { 0x0011, "Prog Page translation" }, \ + { 0x0012, "Prog Translation specification" }, \ + { 0x0013, "Prog Special operation" }, \ + { 0x0015, "Prog Operand" }, \ + { 0x0016, "Prog Trace table" }, \ + { 0x0017, "Prog ASNtranslation specification" }, \ + { 0x001C, "Prog Spaceswitch event" }, \ + { 0x001D, "Prog HFP square root" }, \ + { 0x001F, "Prog PCtranslation specification" }, \ + { 0x0020, "Prog AFX translation" }, \ + { 0x0021, "Prog ASX translation" }, \ + { 0x0022, "Prog LX translation" }, \ + { 0x0023, "Prog EX translation" }, \ + { 0x0024, "Prog Primary authority" }, \ + { 0x0025, "Prog Secondary authority" }, \ + { 0x0026, "Prog LFXtranslation exception" }, \ + { 0x0027, "Prog LSXtranslation exception" }, \ + { 0x0028, "Prog ALET specification" }, \ + { 0x0029, "Prog ALEN translation" }, \ + { 0x002A, "Prog ALE sequence" }, \ + { 0x002B, "Prog ASTE validity" }, \ + { 0x002C, "Prog ASTE sequence" }, \ + { 0x002D, "Prog Extended authority" }, \ + { 0x002E, "Prog LSTE sequence" }, \ + { 0x002F, "Prog ASTE instance" }, \ + { 0x0030, "Prog Stack full" }, \ + { 0x0031, "Prog Stack empty" }, \ + { 0x0032, "Prog Stack specification" }, \ + { 0x0033, "Prog Stack type" }, \ + { 0x0034, "Prog Stack operation" }, \ + { 0x0039, "Prog Region first translation" }, \ + { 0x003A, "Prog Region second translation" }, \ + { 0x003B, "Prog Region third translation" }, \ + { 0x0040, "Prog Monitor event" }, \ + { 0x0080, "Prog PER event" }, \ + { 0x0119, "Prog Crypto operation" } + +#define exit_code_ipa0(ipa0, opcode, mnemonic) \ + { (ipa0 << 8 | opcode), #ipa0 " " mnemonic } +#define exit_code(opcode, mnemonic) \ + { opcode, mnemonic } + +#define icpt_insn_codes \ + exit_code_ipa0(0x01, 0x01, "PR"), \ + exit_code_ipa0(0x01, 0x04, "PTFF"), \ + exit_code_ipa0(0x01, 0x07, "SCKPF"), \ + exit_code_ipa0(0xAA, 0x00, "RINEXT"), \ + exit_code_ipa0(0xAA, 0x01, "RION"), \ + exit_code_ipa0(0xAA, 0x02, "TRIC"), \ + exit_code_ipa0(0xAA, 0x03, "RIOFF"), \ + exit_code_ipa0(0xAA, 0x04, "RIEMIT"), \ + exit_code_ipa0(0xB2, 0x02, "STIDP"), \ + exit_code_ipa0(0xB2, 0x04, "SCK"), \ + exit_code_ipa0(0xB2, 0x05, "STCK"), \ + exit_code_ipa0(0xB2, 0x06, "SCKC"), \ + exit_code_ipa0(0xB2, 0x07, "STCKC"), \ + exit_code_ipa0(0xB2, 0x08, "SPT"), \ + exit_code_ipa0(0xB2, 0x09, "STPT"), \ + exit_code_ipa0(0xB2, 0x0d, "PTLB"), \ + exit_code_ipa0(0xB2, 0x10, "SPX"), \ + exit_code_ipa0(0xB2, 0x11, "STPX"), \ + exit_code_ipa0(0xB2, 0x12, "STAP"), \ + exit_code_ipa0(0xB2, 0x14, "SIE"), \ + exit_code_ipa0(0xB2, 0x16, "SETR"), \ + exit_code_ipa0(0xB2, 0x17, "STETR"), \ + exit_code_ipa0(0xB2, 0x18, "PC"), \ + exit_code_ipa0(0xB2, 0x20, "SERVC"), \ + exit_code_ipa0(0xB2, 0x21, "IPTE"), \ + exit_code_ipa0(0xB2, 0x28, "PT"), \ + exit_code_ipa0(0xB2, 0x29, "ISKE"), \ + exit_code_ipa0(0xB2, 0x2a, "RRBE"), \ + exit_code_ipa0(0xB2, 0x2b, "SSKE"), \ + exit_code_ipa0(0xB2, 0x2c, "TB"), \ + exit_code_ipa0(0xB2, 0x2e, "PGIN"), \ + exit_code_ipa0(0xB2, 0x2f, "PGOUT"), \ + exit_code_ipa0(0xB2, 0x30, "CSCH"), \ + exit_code_ipa0(0xB2, 0x31, "HSCH"), \ + exit_code_ipa0(0xB2, 0x32, "MSCH"), \ + exit_code_ipa0(0xB2, 0x33, "SSCH"), \ + exit_code_ipa0(0xB2, 0x34, "STSCH"), \ + exit_code_ipa0(0xB2, 0x35, "TSCH"), \ + exit_code_ipa0(0xB2, 0x36, "TPI"), \ + exit_code_ipa0(0xB2, 0x37, "SAL"), \ + exit_code_ipa0(0xB2, 0x38, "RSCH"), \ + exit_code_ipa0(0xB2, 0x39, "STCRW"), \ + exit_code_ipa0(0xB2, 0x3a, "STCPS"), \ + exit_code_ipa0(0xB2, 0x3b, "RCHP"), \ + exit_code_ipa0(0xB2, 0x3c, "SCHM"), \ + exit_code_ipa0(0xB2, 0x40, "BAKR"), \ + exit_code_ipa0(0xB2, 0x48, "PALB"), \ + exit_code_ipa0(0xB2, 0x4c, "TAR"), \ + exit_code_ipa0(0xB2, 0x50, "CSP"), \ + exit_code_ipa0(0xB2, 0x54, "MVPG"), \ + exit_code_ipa0(0xB2, 0x58, "BSG"), \ + exit_code_ipa0(0xB2, 0x5a, "BSA"), \ + exit_code_ipa0(0xB2, 0x5f, "CHSC"), \ + exit_code_ipa0(0xB2, 0x74, "SIGA"), \ + exit_code_ipa0(0xB2, 0x76, "XSCH"), \ + exit_code_ipa0(0xB2, 0x78, "STCKE"), \ + exit_code_ipa0(0xB2, 0x7c, "STCKF"), \ + exit_code_ipa0(0xB2, 0x7d, "STSI"), \ + exit_code_ipa0(0xB2, 0xb0, "STFLE"), \ + exit_code_ipa0(0xB2, 0xb1, "STFL"), \ + exit_code_ipa0(0xB2, 0xb2, "LPSWE"), \ + exit_code_ipa0(0xB2, 0xf8, "TEND"), \ + exit_code_ipa0(0xB2, 0xfc, "TABORT"), \ + exit_code_ipa0(0xB9, 0x1e, "KMAC"), \ + exit_code_ipa0(0xB9, 0x28, "PCKMO"), \ + exit_code_ipa0(0xB9, 0x2a, "KMF"), \ + exit_code_ipa0(0xB9, 0x2b, "KMO"), \ + exit_code_ipa0(0xB9, 0x2d, "KMCTR"), \ + exit_code_ipa0(0xB9, 0x2e, "KM"), \ + exit_code_ipa0(0xB9, 0x2f, "KMC"), \ + exit_code_ipa0(0xB9, 0x3e, "KIMD"), \ + exit_code_ipa0(0xB9, 0x3f, "KLMD"), \ + exit_code_ipa0(0xB9, 0x8a, "CSPG"), \ + exit_code_ipa0(0xB9, 0x8d, "EPSW"), \ + exit_code_ipa0(0xB9, 0x8e, "IDTE"), \ + exit_code_ipa0(0xB9, 0x8f, "CRDTE"), \ + exit_code_ipa0(0xB9, 0x9c, "EQBS"), \ + exit_code_ipa0(0xB9, 0xa2, "PTF"), \ + exit_code_ipa0(0xB9, 0xab, "ESSA"), \ + exit_code_ipa0(0xB9, 0xae, "RRBM"), \ + exit_code_ipa0(0xB9, 0xaf, "PFMF"), \ + exit_code_ipa0(0xE3, 0x03, "LRAG"), \ + exit_code_ipa0(0xE3, 0x13, "LRAY"), \ + exit_code_ipa0(0xE3, 0x25, "NTSTG"), \ + exit_code_ipa0(0xE5, 0x00, "LASP"), \ + exit_code_ipa0(0xE5, 0x01, "TPROT"), \ + exit_code_ipa0(0xE5, 0x60, "TBEGIN"), \ + exit_code_ipa0(0xE5, 0x61, "TBEGINC"), \ + exit_code_ipa0(0xEB, 0x25, "STCTG"), \ + exit_code_ipa0(0xEB, 0x2f, "LCTLG"), \ + exit_code_ipa0(0xEB, 0x60, "LRIC"), \ + exit_code_ipa0(0xEB, 0x61, "STRIC"), \ + exit_code_ipa0(0xEB, 0x62, "MRIC"), \ + exit_code_ipa0(0xEB, 0x8a, "SQBS"), \ + exit_code_ipa0(0xC8, 0x01, "ECTG"), \ + exit_code(0x0a, "SVC"), \ + exit_code(0x80, "SSM"), \ + exit_code(0x82, "LPSW"), \ + exit_code(0x83, "DIAG"), \ + exit_code(0xae, "SIGP"), \ + exit_code(0xac, "STNSM"), \ + exit_code(0xad, "STOSM"), \ + exit_code(0xb1, "LRA"), \ + exit_code(0xb6, "STCTL"), \ + exit_code(0xb7, "LCTL"), \ + exit_code(0xee, "PLO") + +#define sie_intercept_code \ + { 0x00, "Host interruption" }, \ + { 0x04, "Instruction" }, \ + { 0x08, "Program interruption" }, \ + { 0x0c, "Instruction and program interruption" }, \ + { 0x10, "External request" }, \ + { 0x14, "External interruption" }, \ + { 0x18, "I/O request" }, \ + { 0x1c, "Wait state" }, \ + { 0x20, "Validity" }, \ + { 0x28, "Stop request" }, \ + { 0x2c, "Operation exception" }, \ + { 0x38, "Partial-execution" }, \ + { 0x3c, "I/O interruption" }, \ + { 0x40, "I/O instruction" }, \ + { 0x48, "Timing subset" } + +/* + * This is the simple interceptable instructions decoder. + * + * It will be used as userspace interface and it can be used in places + * that does not allow to use general decoder functions, + * such as trace events declarations. + * + * Some userspace tools may want to parse this code + * and would be confused by switch(), if() and other statements, + * but they can understand conditional operator. + */ +#define INSN_DECODE_IPA0(ipa0, insn, rshift, mask) \ + (insn >> 56) == (ipa0) ? \ + ((ipa0 << 8) | ((insn >> rshift) & mask)) : + +#define INSN_DECODE(insn) (insn >> 56) + +/* + * The macro icpt_insn_decoder() takes an intercepted instruction + * and returns a key, which can be used to find a mnemonic name + * of the instruction in the icpt_insn_codes table. + */ +#define icpt_insn_decoder(insn) ( \ + INSN_DECODE_IPA0(0x01, insn, 48, 0xff) \ + INSN_DECODE_IPA0(0xaa, insn, 48, 0x0f) \ + INSN_DECODE_IPA0(0xb2, insn, 48, 0xff) \ + INSN_DECODE_IPA0(0xb9, insn, 48, 0xff) \ + INSN_DECODE_IPA0(0xe3, insn, 48, 0xff) \ + INSN_DECODE_IPA0(0xe5, insn, 48, 0xff) \ + INSN_DECODE_IPA0(0xeb, insn, 16, 0xff) \ + INSN_DECODE_IPA0(0xc8, insn, 48, 0x0f) \ + INSN_DECODE(insn)) + +#endif /* _UAPI_ASM_S390_SIE_H */ diff --git a/tools/arch/x86/include/uapi/asm/kvm.h b/tools/arch/x86/include/uapi/asm/kvm.h new file mode 100644 index 0000000..739c0c5 --- /dev/null +++ b/tools/arch/x86/include/uapi/asm/kvm.h @@ -0,0 +1,360 @@ +#ifndef _ASM_X86_KVM_H +#define _ASM_X86_KVM_H + +/* + * KVM x86 specific structures and definitions + * + */ + +#include +#include + +#define DE_VECTOR 0 +#define DB_VECTOR 1 +#define BP_VECTOR 3 +#define OF_VECTOR 4 +#define BR_VECTOR 5 +#define UD_VECTOR 6 +#define NM_VECTOR 7 +#define DF_VECTOR 8 +#define TS_VECTOR 10 +#define NP_VECTOR 11 +#define SS_VECTOR 12 +#define GP_VECTOR 13 +#define PF_VECTOR 14 +#define MF_VECTOR 16 +#define AC_VECTOR 17 +#define MC_VECTOR 18 +#define XM_VECTOR 19 +#define VE_VECTOR 20 + +/* Select x86 specific features in */ +#define __KVM_HAVE_PIT +#define __KVM_HAVE_IOAPIC +#define __KVM_HAVE_IRQ_LINE +#define __KVM_HAVE_MSI +#define __KVM_HAVE_USER_NMI +#define __KVM_HAVE_GUEST_DEBUG +#define __KVM_HAVE_MSIX +#define __KVM_HAVE_MCE +#define __KVM_HAVE_PIT_STATE2 +#define __KVM_HAVE_XEN_HVM +#define __KVM_HAVE_VCPU_EVENTS +#define __KVM_HAVE_DEBUGREGS +#define __KVM_HAVE_XSAVE +#define __KVM_HAVE_XCRS +#define __KVM_HAVE_READONLY_MEM + +/* Architectural interrupt line count. */ +#define KVM_NR_INTERRUPTS 256 + +struct kvm_memory_alias { + __u32 slot; /* this has a different namespace than memory slots */ + __u32 flags; + __u64 guest_phys_addr; + __u64 memory_size; + __u64 target_phys_addr; +}; + +/* for KVM_GET_IRQCHIP and KVM_SET_IRQCHIP */ +struct kvm_pic_state { + __u8 last_irr; /* edge detection */ + __u8 irr; /* interrupt request register */ + __u8 imr; /* interrupt mask register */ + __u8 isr; /* interrupt service register */ + __u8 priority_add; /* highest irq priority */ + __u8 irq_base; + __u8 read_reg_select; + __u8 poll; + __u8 special_mask; + __u8 init_state; + __u8 auto_eoi; + __u8 rotate_on_auto_eoi; + __u8 special_fully_nested_mode; + __u8 init4; /* true if 4 byte init */ + __u8 elcr; /* PIIX edge/trigger selection */ + __u8 elcr_mask; +}; + +#define KVM_IOAPIC_NUM_PINS 24 +struct kvm_ioapic_state { + __u64 base_address; + __u32 ioregsel; + __u32 id; + __u32 irr; + __u32 pad; + union { + __u64 bits; + struct { + __u8 vector; + __u8 delivery_mode:3; + __u8 dest_mode:1; + __u8 delivery_status:1; + __u8 polarity:1; + __u8 remote_irr:1; + __u8 trig_mode:1; + __u8 mask:1; + __u8 reserve:7; + __u8 reserved[4]; + __u8 dest_id; + } fields; + } redirtbl[KVM_IOAPIC_NUM_PINS]; +}; + +#define KVM_IRQCHIP_PIC_MASTER 0 +#define KVM_IRQCHIP_PIC_SLAVE 1 +#define KVM_IRQCHIP_IOAPIC 2 +#define KVM_NR_IRQCHIPS 3 + +#define KVM_RUN_X86_SMM (1 << 0) + +/* for KVM_GET_REGS and KVM_SET_REGS */ +struct kvm_regs { + /* out (KVM_GET_REGS) / in (KVM_SET_REGS) */ + __u64 rax, rbx, rcx, rdx; + __u64 rsi, rdi, rsp, rbp; + __u64 r8, r9, r10, r11; + __u64 r12, r13, r14, r15; + __u64 rip, rflags; +}; + +/* for KVM_GET_LAPIC and KVM_SET_LAPIC */ +#define KVM_APIC_REG_SIZE 0x400 +struct kvm_lapic_state { + char regs[KVM_APIC_REG_SIZE]; +}; + +struct kvm_segment { + __u64 base; + __u32 limit; + __u16 selector; + __u8 type; + __u8 present, dpl, db, s, l, g, avl; + __u8 unusable; + __u8 padding; +}; + +struct kvm_dtable { + __u64 base; + __u16 limit; + __u16 padding[3]; +}; + + +/* for KVM_GET_SREGS and KVM_SET_SREGS */ +struct kvm_sregs { + /* out (KVM_GET_SREGS) / in (KVM_SET_SREGS) */ + struct kvm_segment cs, ds, es, fs, gs, ss; + struct kvm_segment tr, ldt; + struct kvm_dtable gdt, idt; + __u64 cr0, cr2, cr3, cr4, cr8; + __u64 efer; + __u64 apic_base; + __u64 interrupt_bitmap[(KVM_NR_INTERRUPTS + 63) / 64]; +}; + +/* for KVM_GET_FPU and KVM_SET_FPU */ +struct kvm_fpu { + __u8 fpr[8][16]; + __u16 fcw; + __u16 fsw; + __u8 ftwx; /* in fxsave format */ + __u8 pad1; + __u16 last_opcode; + __u64 last_ip; + __u64 last_dp; + __u8 xmm[16][16]; + __u32 mxcsr; + __u32 pad2; +}; + +struct kvm_msr_entry { + __u32 index; + __u32 reserved; + __u64 data; +}; + +/* for KVM_GET_MSRS and KVM_SET_MSRS */ +struct kvm_msrs { + __u32 nmsrs; /* number of msrs in entries */ + __u32 pad; + + struct kvm_msr_entry entries[0]; +}; + +/* for KVM_GET_MSR_INDEX_LIST */ +struct kvm_msr_list { + __u32 nmsrs; /* number of msrs in entries */ + __u32 indices[0]; +}; + + +struct kvm_cpuid_entry { + __u32 function; + __u32 eax; + __u32 ebx; + __u32 ecx; + __u32 edx; + __u32 padding; +}; + +/* for KVM_SET_CPUID */ +struct kvm_cpuid { + __u32 nent; + __u32 padding; + struct kvm_cpuid_entry entries[0]; +}; + +struct kvm_cpuid_entry2 { + __u32 function; + __u32 index; + __u32 flags; + __u32 eax; + __u32 ebx; + __u32 ecx; + __u32 edx; + __u32 padding[3]; +}; + +#define KVM_CPUID_FLAG_SIGNIFCANT_INDEX (1 << 0) +#define KVM_CPUID_FLAG_STATEFUL_FUNC (1 << 1) +#define KVM_CPUID_FLAG_STATE_READ_NEXT (1 << 2) + +/* for KVM_SET_CPUID2 */ +struct kvm_cpuid2 { + __u32 nent; + __u32 padding; + struct kvm_cpuid_entry2 entries[0]; +}; + +/* for KVM_GET_PIT and KVM_SET_PIT */ +struct kvm_pit_channel_state { + __u32 count; /* can be 65536 */ + __u16 latched_count; + __u8 count_latched; + __u8 status_latched; + __u8 status; + __u8 read_state; + __u8 write_state; + __u8 write_latch; + __u8 rw_mode; + __u8 mode; + __u8 bcd; + __u8 gate; + __s64 count_load_time; +}; + +struct kvm_debug_exit_arch { + __u32 exception; + __u32 pad; + __u64 pc; + __u64 dr6; + __u64 dr7; +}; + +#define KVM_GUESTDBG_USE_SW_BP 0x00010000 +#define KVM_GUESTDBG_USE_HW_BP 0x00020000 +#define KVM_GUESTDBG_INJECT_DB 0x00040000 +#define KVM_GUESTDBG_INJECT_BP 0x00080000 + +/* for KVM_SET_GUEST_DEBUG */ +struct kvm_guest_debug_arch { + __u64 debugreg[8]; +}; + +struct kvm_pit_state { + struct kvm_pit_channel_state channels[3]; +}; + +#define KVM_PIT_FLAGS_HPET_LEGACY 0x00000001 + +struct kvm_pit_state2 { + struct kvm_pit_channel_state channels[3]; + __u32 flags; + __u32 reserved[9]; +}; + +struct kvm_reinject_control { + __u8 pit_reinject; + __u8 reserved[31]; +}; + +/* When set in flags, include corresponding fields on KVM_SET_VCPU_EVENTS */ +#define KVM_VCPUEVENT_VALID_NMI_PENDING 0x00000001 +#define KVM_VCPUEVENT_VALID_SIPI_VECTOR 0x00000002 +#define KVM_VCPUEVENT_VALID_SHADOW 0x00000004 +#define KVM_VCPUEVENT_VALID_SMM 0x00000008 + +/* Interrupt shadow states */ +#define KVM_X86_SHADOW_INT_MOV_SS 0x01 +#define KVM_X86_SHADOW_INT_STI 0x02 + +/* for KVM_GET/SET_VCPU_EVENTS */ +struct kvm_vcpu_events { + struct { + __u8 injected; + __u8 nr; + __u8 has_error_code; + __u8 pad; + __u32 error_code; + } exception; + struct { + __u8 injected; + __u8 nr; + __u8 soft; + __u8 shadow; + } interrupt; + struct { + __u8 injected; + __u8 pending; + __u8 masked; + __u8 pad; + } nmi; + __u32 sipi_vector; + __u32 flags; + struct { + __u8 smm; + __u8 pending; + __u8 smm_inside_nmi; + __u8 latched_init; + } smi; + __u32 reserved[9]; +}; + +/* for KVM_GET/SET_DEBUGREGS */ +struct kvm_debugregs { + __u64 db[4]; + __u64 dr6; + __u64 dr7; + __u64 flags; + __u64 reserved[9]; +}; + +/* for KVM_CAP_XSAVE */ +struct kvm_xsave { + __u32 region[1024]; +}; + +#define KVM_MAX_XCRS 16 + +struct kvm_xcr { + __u32 xcr; + __u32 reserved; + __u64 value; +}; + +struct kvm_xcrs { + __u32 nr_xcrs; + __u32 flags; + struct kvm_xcr xcrs[KVM_MAX_XCRS]; + __u64 padding[16]; +}; + +/* definition of registers in kvm_run */ +struct kvm_sync_regs { +}; + +#define KVM_X86_QUIRK_LINT0_REENABLED (1 << 0) +#define KVM_X86_QUIRK_CD_NW_CLEARED (1 << 1) + +#endif /* _ASM_X86_KVM_H */ diff --git a/tools/arch/x86/include/uapi/asm/kvm_perf.h b/tools/arch/x86/include/uapi/asm/kvm_perf.h new file mode 100644 index 0000000..3bb964f --- /dev/null +++ b/tools/arch/x86/include/uapi/asm/kvm_perf.h @@ -0,0 +1,16 @@ +#ifndef _ASM_X86_KVM_PERF_H +#define _ASM_X86_KVM_PERF_H + +#include +#include +#include + +#define DECODE_STR_LEN 20 + +#define VCPU_ID "vcpu_id" + +#define KVM_ENTRY_TRACE "kvm:kvm_entry" +#define KVM_EXIT_TRACE "kvm:kvm_exit" +#define KVM_EXIT_REASON "exit_reason" + +#endif /* _ASM_X86_KVM_PERF_H */ diff --git a/tools/arch/x86/include/uapi/asm/svm.h b/tools/arch/x86/include/uapi/asm/svm.h new file mode 100644 index 0000000..3725e14 --- /dev/null +++ b/tools/arch/x86/include/uapi/asm/svm.h @@ -0,0 +1,178 @@ +#ifndef _UAPI__SVM_H +#define _UAPI__SVM_H + +#define SVM_EXIT_READ_CR0 0x000 +#define SVM_EXIT_READ_CR2 0x002 +#define SVM_EXIT_READ_CR3 0x003 +#define SVM_EXIT_READ_CR4 0x004 +#define SVM_EXIT_READ_CR8 0x008 +#define SVM_EXIT_WRITE_CR0 0x010 +#define SVM_EXIT_WRITE_CR2 0x012 +#define SVM_EXIT_WRITE_CR3 0x013 +#define SVM_EXIT_WRITE_CR4 0x014 +#define SVM_EXIT_WRITE_CR8 0x018 +#define SVM_EXIT_READ_DR0 0x020 +#define SVM_EXIT_READ_DR1 0x021 +#define SVM_EXIT_READ_DR2 0x022 +#define SVM_EXIT_READ_DR3 0x023 +#define SVM_EXIT_READ_DR4 0x024 +#define SVM_EXIT_READ_DR5 0x025 +#define SVM_EXIT_READ_DR6 0x026 +#define SVM_EXIT_READ_DR7 0x027 +#define SVM_EXIT_WRITE_DR0 0x030 +#define SVM_EXIT_WRITE_DR1 0x031 +#define SVM_EXIT_WRITE_DR2 0x032 +#define SVM_EXIT_WRITE_DR3 0x033 +#define SVM_EXIT_WRITE_DR4 0x034 +#define SVM_EXIT_WRITE_DR5 0x035 +#define SVM_EXIT_WRITE_DR6 0x036 +#define SVM_EXIT_WRITE_DR7 0x037 +#define SVM_EXIT_EXCP_BASE 0x040 +#define SVM_EXIT_INTR 0x060 +#define SVM_EXIT_NMI 0x061 +#define SVM_EXIT_SMI 0x062 +#define SVM_EXIT_INIT 0x063 +#define SVM_EXIT_VINTR 0x064 +#define SVM_EXIT_CR0_SEL_WRITE 0x065 +#define SVM_EXIT_IDTR_READ 0x066 +#define SVM_EXIT_GDTR_READ 0x067 +#define SVM_EXIT_LDTR_READ 0x068 +#define SVM_EXIT_TR_READ 0x069 +#define SVM_EXIT_IDTR_WRITE 0x06a +#define SVM_EXIT_GDTR_WRITE 0x06b +#define SVM_EXIT_LDTR_WRITE 0x06c +#define SVM_EXIT_TR_WRITE 0x06d +#define SVM_EXIT_RDTSC 0x06e +#define SVM_EXIT_RDPMC 0x06f +#define SVM_EXIT_PUSHF 0x070 +#define SVM_EXIT_POPF 0x071 +#define SVM_EXIT_CPUID 0x072 +#define SVM_EXIT_RSM 0x073 +#define SVM_EXIT_IRET 0x074 +#define SVM_EXIT_SWINT 0x075 +#define SVM_EXIT_INVD 0x076 +#define SVM_EXIT_PAUSE 0x077 +#define SVM_EXIT_HLT 0x078 +#define SVM_EXIT_INVLPG 0x079 +#define SVM_EXIT_INVLPGA 0x07a +#define SVM_EXIT_IOIO 0x07b +#define SVM_EXIT_MSR 0x07c +#define SVM_EXIT_TASK_SWITCH 0x07d +#define SVM_EXIT_FERR_FREEZE 0x07e +#define SVM_EXIT_SHUTDOWN 0x07f +#define SVM_EXIT_VMRUN 0x080 +#define SVM_EXIT_VMMCALL 0x081 +#define SVM_EXIT_VMLOAD 0x082 +#define SVM_EXIT_VMSAVE 0x083 +#define SVM_EXIT_STGI 0x084 +#define SVM_EXIT_CLGI 0x085 +#define SVM_EXIT_SKINIT 0x086 +#define SVM_EXIT_RDTSCP 0x087 +#define SVM_EXIT_ICEBP 0x088 +#define SVM_EXIT_WBINVD 0x089 +#define SVM_EXIT_MONITOR 0x08a +#define SVM_EXIT_MWAIT 0x08b +#define SVM_EXIT_MWAIT_COND 0x08c +#define SVM_EXIT_XSETBV 0x08d +#define SVM_EXIT_NPF 0x400 +#define SVM_EXIT_AVIC_INCOMPLETE_IPI 0x401 +#define SVM_EXIT_AVIC_UNACCELERATED_ACCESS 0x402 + +#define SVM_EXIT_ERR -1 + +#define SVM_EXIT_REASONS \ + { SVM_EXIT_READ_CR0, "read_cr0" }, \ + { SVM_EXIT_READ_CR2, "read_cr2" }, \ + { SVM_EXIT_READ_CR3, "read_cr3" }, \ + { SVM_EXIT_READ_CR4, "read_cr4" }, \ + { SVM_EXIT_READ_CR8, "read_cr8" }, \ + { SVM_EXIT_WRITE_CR0, "write_cr0" }, \ + { SVM_EXIT_WRITE_CR2, "write_cr2" }, \ + { SVM_EXIT_WRITE_CR3, "write_cr3" }, \ + { SVM_EXIT_WRITE_CR4, "write_cr4" }, \ + { SVM_EXIT_WRITE_CR8, "write_cr8" }, \ + { SVM_EXIT_READ_DR0, "read_dr0" }, \ + { SVM_EXIT_READ_DR1, "read_dr1" }, \ + { SVM_EXIT_READ_DR2, "read_dr2" }, \ + { SVM_EXIT_READ_DR3, "read_dr3" }, \ + { SVM_EXIT_READ_DR4, "read_dr4" }, \ + { SVM_EXIT_READ_DR5, "read_dr5" }, \ + { SVM_EXIT_READ_DR6, "read_dr6" }, \ + { SVM_EXIT_READ_DR7, "read_dr7" }, \ + { SVM_EXIT_WRITE_DR0, "write_dr0" }, \ + { SVM_EXIT_WRITE_DR1, "write_dr1" }, \ + { SVM_EXIT_WRITE_DR2, "write_dr2" }, \ + { SVM_EXIT_WRITE_DR3, "write_dr3" }, \ + { SVM_EXIT_WRITE_DR4, "write_dr4" }, \ + { SVM_EXIT_WRITE_DR5, "write_dr5" }, \ + { SVM_EXIT_WRITE_DR6, "write_dr6" }, \ + { SVM_EXIT_WRITE_DR7, "write_dr7" }, \ + { SVM_EXIT_EXCP_BASE + DE_VECTOR, "DE excp" }, \ + { SVM_EXIT_EXCP_BASE + DB_VECTOR, "DB excp" }, \ + { SVM_EXIT_EXCP_BASE + BP_VECTOR, "BP excp" }, \ + { SVM_EXIT_EXCP_BASE + OF_VECTOR, "OF excp" }, \ + { SVM_EXIT_EXCP_BASE + BR_VECTOR, "BR excp" }, \ + { SVM_EXIT_EXCP_BASE + UD_VECTOR, "UD excp" }, \ + { SVM_EXIT_EXCP_BASE + NM_VECTOR, "NM excp" }, \ + { SVM_EXIT_EXCP_BASE + DF_VECTOR, "DF excp" }, \ + { SVM_EXIT_EXCP_BASE + TS_VECTOR, "TS excp" }, \ + { SVM_EXIT_EXCP_BASE + NP_VECTOR, "NP excp" }, \ + { SVM_EXIT_EXCP_BASE + SS_VECTOR, "SS excp" }, \ + { SVM_EXIT_EXCP_BASE + GP_VECTOR, "GP excp" }, \ + { SVM_EXIT_EXCP_BASE + PF_VECTOR, "PF excp" }, \ + { SVM_EXIT_EXCP_BASE + MF_VECTOR, "MF excp" }, \ + { SVM_EXIT_EXCP_BASE + AC_VECTOR, "AC excp" }, \ + { SVM_EXIT_EXCP_BASE + MC_VECTOR, "MC excp" }, \ + { SVM_EXIT_EXCP_BASE + XM_VECTOR, "XF excp" }, \ + { SVM_EXIT_INTR, "interrupt" }, \ + { SVM_EXIT_NMI, "nmi" }, \ + { SVM_EXIT_SMI, "smi" }, \ + { SVM_EXIT_INIT, "init" }, \ + { SVM_EXIT_VINTR, "vintr" }, \ + { SVM_EXIT_CR0_SEL_WRITE, "cr0_sel_write" }, \ + { SVM_EXIT_IDTR_READ, "read_idtr" }, \ + { SVM_EXIT_GDTR_READ, "read_gdtr" }, \ + { SVM_EXIT_LDTR_READ, "read_ldtr" }, \ + { SVM_EXIT_TR_READ, "read_rt" }, \ + { SVM_EXIT_IDTR_WRITE, "write_idtr" }, \ + { SVM_EXIT_GDTR_WRITE, "write_gdtr" }, \ + { SVM_EXIT_LDTR_WRITE, "write_ldtr" }, \ + { SVM_EXIT_TR_WRITE, "write_rt" }, \ + { SVM_EXIT_RDTSC, "rdtsc" }, \ + { SVM_EXIT_RDPMC, "rdpmc" }, \ + { SVM_EXIT_PUSHF, "pushf" }, \ + { SVM_EXIT_POPF, "popf" }, \ + { SVM_EXIT_CPUID, "cpuid" }, \ + { SVM_EXIT_RSM, "rsm" }, \ + { SVM_EXIT_IRET, "iret" }, \ + { SVM_EXIT_SWINT, "swint" }, \ + { SVM_EXIT_INVD, "invd" }, \ + { SVM_EXIT_PAUSE, "pause" }, \ + { SVM_EXIT_HLT, "hlt" }, \ + { SVM_EXIT_INVLPG, "invlpg" }, \ + { SVM_EXIT_INVLPGA, "invlpga" }, \ + { SVM_EXIT_IOIO, "io" }, \ + { SVM_EXIT_MSR, "msr" }, \ + { SVM_EXIT_TASK_SWITCH, "task_switch" }, \ + { SVM_EXIT_FERR_FREEZE, "ferr_freeze" }, \ + { SVM_EXIT_SHUTDOWN, "shutdown" }, \ + { SVM_EXIT_VMRUN, "vmrun" }, \ + { SVM_EXIT_VMMCALL, "hypercall" }, \ + { SVM_EXIT_VMLOAD, "vmload" }, \ + { SVM_EXIT_VMSAVE, "vmsave" }, \ + { SVM_EXIT_STGI, "stgi" }, \ + { SVM_EXIT_CLGI, "clgi" }, \ + { SVM_EXIT_SKINIT, "skinit" }, \ + { SVM_EXIT_RDTSCP, "rdtscp" }, \ + { SVM_EXIT_ICEBP, "icebp" }, \ + { SVM_EXIT_WBINVD, "wbinvd" }, \ + { SVM_EXIT_MONITOR, "monitor" }, \ + { SVM_EXIT_MWAIT, "mwait" }, \ + { SVM_EXIT_XSETBV, "xsetbv" }, \ + { SVM_EXIT_NPF, "npf" }, \ + { SVM_EXIT_AVIC_INCOMPLETE_IPI, "avic_incomplete_ipi" }, \ + { SVM_EXIT_AVIC_UNACCELERATED_ACCESS, "avic_unaccelerated_access" }, \ + { SVM_EXIT_ERR, "invalid_guest_state" } + + +#endif /* _UAPI__SVM_H */ diff --git a/tools/arch/x86/include/uapi/asm/vmx.h b/tools/arch/x86/include/uapi/asm/vmx.h new file mode 100644 index 0000000..5b15d94 --- /dev/null +++ b/tools/arch/x86/include/uapi/asm/vmx.h @@ -0,0 +1,136 @@ +/* + * vmx.h: VMX Architecture related definitions + * Copyright (c) 2004, Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple + * Place - Suite 330, Boston, MA 02111-1307 USA. + * + * A few random additions are: + * Copyright (C) 2006 Qumranet + * Avi Kivity + * Yaniv Kamay + * + */ +#ifndef _UAPIVMX_H +#define _UAPIVMX_H + + +#define VMX_EXIT_REASONS_FAILED_VMENTRY 0x80000000 + +#define EXIT_REASON_EXCEPTION_NMI 0 +#define EXIT_REASON_EXTERNAL_INTERRUPT 1 +#define EXIT_REASON_TRIPLE_FAULT 2 + +#define EXIT_REASON_PENDING_INTERRUPT 7 +#define EXIT_REASON_NMI_WINDOW 8 +#define EXIT_REASON_TASK_SWITCH 9 +#define EXIT_REASON_CPUID 10 +#define EXIT_REASON_HLT 12 +#define EXIT_REASON_INVD 13 +#define EXIT_REASON_INVLPG 14 +#define EXIT_REASON_RDPMC 15 +#define EXIT_REASON_RDTSC 16 +#define EXIT_REASON_VMCALL 18 +#define EXIT_REASON_VMCLEAR 19 +#define EXIT_REASON_VMLAUNCH 20 +#define EXIT_REASON_VMPTRLD 21 +#define EXIT_REASON_VMPTRST 22 +#define EXIT_REASON_VMREAD 23 +#define EXIT_REASON_VMRESUME 24 +#define EXIT_REASON_VMWRITE 25 +#define EXIT_REASON_VMOFF 26 +#define EXIT_REASON_VMON 27 +#define EXIT_REASON_CR_ACCESS 28 +#define EXIT_REASON_DR_ACCESS 29 +#define EXIT_REASON_IO_INSTRUCTION 30 +#define EXIT_REASON_MSR_READ 31 +#define EXIT_REASON_MSR_WRITE 32 +#define EXIT_REASON_INVALID_STATE 33 +#define EXIT_REASON_MSR_LOAD_FAIL 34 +#define EXIT_REASON_MWAIT_INSTRUCTION 36 +#define EXIT_REASON_MONITOR_TRAP_FLAG 37 +#define EXIT_REASON_MONITOR_INSTRUCTION 39 +#define EXIT_REASON_PAUSE_INSTRUCTION 40 +#define EXIT_REASON_MCE_DURING_VMENTRY 41 +#define EXIT_REASON_TPR_BELOW_THRESHOLD 43 +#define EXIT_REASON_APIC_ACCESS 44 +#define EXIT_REASON_EOI_INDUCED 45 +#define EXIT_REASON_EPT_VIOLATION 48 +#define EXIT_REASON_EPT_MISCONFIG 49 +#define EXIT_REASON_INVEPT 50 +#define EXIT_REASON_RDTSCP 51 +#define EXIT_REASON_PREEMPTION_TIMER 52 +#define EXIT_REASON_INVVPID 53 +#define EXIT_REASON_WBINVD 54 +#define EXIT_REASON_XSETBV 55 +#define EXIT_REASON_APIC_WRITE 56 +#define EXIT_REASON_INVPCID 58 +#define EXIT_REASON_PML_FULL 62 +#define EXIT_REASON_XSAVES 63 +#define EXIT_REASON_XRSTORS 64 +#define EXIT_REASON_PCOMMIT 65 + +#define VMX_EXIT_REASONS \ + { EXIT_REASON_EXCEPTION_NMI, "EXCEPTION_NMI" }, \ + { EXIT_REASON_EXTERNAL_INTERRUPT, "EXTERNAL_INTERRUPT" }, \ + { EXIT_REASON_TRIPLE_FAULT, "TRIPLE_FAULT" }, \ + { EXIT_REASON_PENDING_INTERRUPT, "PENDING_INTERRUPT" }, \ + { EXIT_REASON_NMI_WINDOW, "NMI_WINDOW" }, \ + { EXIT_REASON_TASK_SWITCH, "TASK_SWITCH" }, \ + { EXIT_REASON_CPUID, "CPUID" }, \ + { EXIT_REASON_HLT, "HLT" }, \ + { EXIT_REASON_INVLPG, "INVLPG" }, \ + { EXIT_REASON_RDPMC, "RDPMC" }, \ + { EXIT_REASON_RDTSC, "RDTSC" }, \ + { EXIT_REASON_VMCALL, "VMCALL" }, \ + { EXIT_REASON_VMCLEAR, "VMCLEAR" }, \ + { EXIT_REASON_VMLAUNCH, "VMLAUNCH" }, \ + { EXIT_REASON_VMPTRLD, "VMPTRLD" }, \ + { EXIT_REASON_VMPTRST, "VMPTRST" }, \ + { EXIT_REASON_VMREAD, "VMREAD" }, \ + { EXIT_REASON_VMRESUME, "VMRESUME" }, \ + { EXIT_REASON_VMWRITE, "VMWRITE" }, \ + { EXIT_REASON_VMOFF, "VMOFF" }, \ + { EXIT_REASON_VMON, "VMON" }, \ + { EXIT_REASON_CR_ACCESS, "CR_ACCESS" }, \ + { EXIT_REASON_DR_ACCESS, "DR_ACCESS" }, \ + { EXIT_REASON_IO_INSTRUCTION, "IO_INSTRUCTION" }, \ + { EXIT_REASON_MSR_READ, "MSR_READ" }, \ + { EXIT_REASON_MSR_WRITE, "MSR_WRITE" }, \ + { EXIT_REASON_MWAIT_INSTRUCTION, "MWAIT_INSTRUCTION" }, \ + { EXIT_REASON_MONITOR_TRAP_FLAG, "MONITOR_TRAP_FLAG" }, \ + { EXIT_REASON_MONITOR_INSTRUCTION, "MONITOR_INSTRUCTION" }, \ + { EXIT_REASON_PAUSE_INSTRUCTION, "PAUSE_INSTRUCTION" }, \ + { EXIT_REASON_MCE_DURING_VMENTRY, "MCE_DURING_VMENTRY" }, \ + { EXIT_REASON_TPR_BELOW_THRESHOLD, "TPR_BELOW_THRESHOLD" }, \ + { EXIT_REASON_APIC_ACCESS, "APIC_ACCESS" }, \ + { EXIT_REASON_EPT_VIOLATION, "EPT_VIOLATION" }, \ + { EXIT_REASON_EPT_MISCONFIG, "EPT_MISCONFIG" }, \ + { EXIT_REASON_INVEPT, "INVEPT" }, \ + { EXIT_REASON_PREEMPTION_TIMER, "PREEMPTION_TIMER" }, \ + { EXIT_REASON_WBINVD, "WBINVD" }, \ + { EXIT_REASON_APIC_WRITE, "APIC_WRITE" }, \ + { EXIT_REASON_EOI_INDUCED, "EOI_INDUCED" }, \ + { EXIT_REASON_INVALID_STATE, "INVALID_STATE" }, \ + { EXIT_REASON_MSR_LOAD_FAIL, "MSR_LOAD_FAIL" }, \ + { EXIT_REASON_INVD, "INVD" }, \ + { EXIT_REASON_INVVPID, "INVVPID" }, \ + { EXIT_REASON_INVPCID, "INVPCID" }, \ + { EXIT_REASON_XSAVES, "XSAVES" }, \ + { EXIT_REASON_XRSTORS, "XRSTORS" }, \ + { EXIT_REASON_PCOMMIT, "PCOMMIT" } + +#define VMX_ABORT_SAVE_GUEST_MSR_FAIL 1 +#define VMX_ABORT_LOAD_HOST_MSR_FAIL 4 + +#endif /* _UAPIVMX_H */ diff --git a/tools/perf/MANIFEST b/tools/perf/MANIFEST index a4aefae..db7cfb4 100644 --- a/tools/perf/MANIFEST +++ b/tools/perf/MANIFEST @@ -15,8 +15,14 @@ tools/arch/x86/include/asm/barrier.h tools/arch/x86/include/asm/cpufeatures.h tools/arch/x86/include/asm/disabled-features.h tools/arch/x86/include/asm/required-features.h +tools/arch/x86/include/uapi/asm/svm.h +tools/arch/x86/include/uapi/asm/vmx.h +tools/arch/x86/include/uapi/asm/kvm.h +tools/arch/x86/include/uapi/asm/kvm_perf.h tools/arch/x86/lib/memcpy_64.S tools/arch/x86/lib/memset_64.S +tools/arch/s390/include/uapi/asm/kvm_perf.h +tools/arch/s390/include/uapi/asm/sie.h tools/arch/xtensa/include/asm/barrier.h tools/scripts tools/build @@ -85,12 +91,3 @@ tools/arch/*/include/uapi/asm/perf_regs.h include/linux/poison.h include/uapi/linux/const.h include/uapi/linux/swab.h -arch/x86/include/asm/svm.h -arch/x86/include/asm/vmx.h -arch/x86/include/asm/kvm_host.h -arch/x86/include/uapi/asm/svm.h -arch/x86/include/uapi/asm/vmx.h -arch/x86/include/uapi/asm/kvm.h -arch/x86/include/uapi/asm/kvm_perf.h -arch/s390/include/uapi/asm/sie.h -arch/s390/include/uapi/asm/kvm_perf.h diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf index 0d07672..feb2c66 100644 --- a/tools/perf/Makefile.perf +++ b/tools/perf/Makefile.perf @@ -378,6 +378,36 @@ $(PERF_IN): prepare FORCE @(test -f ../../arch/x86/include/uapi/asm/perf_regs.h && ( \ (diff -B ../arch/x86/include/uapi/asm/perf_regs.h ../../arch/x86/include/uapi/asm/perf_regs.h >/dev/null) \ || echo "Warning: tools/arch/x86/include/uapi/asm/perf_regs.h differs from kernel" >&2 )) || true + @(test -f ../../arch/x86/include/uapi/asm/kvm.h && ( \ + (diff -B ../arch/x86/include/uapi/asm/kvm.h ../../arch/x86/include/uapi/asm/kvm.h >/dev/null) \ + || echo "Warning: tools/arch/x86/include/uapi/asm/kvm.h differs from kernel" >&2 )) || true + @(test -f ../../arch/x86/include/uapi/asm/kvm_perf.h && ( \ + (diff -B ../arch/x86/include/uapi/asm/kvm_perf.h ../../arch/x86/include/uapi/asm/kvm_perf.h >/dev/null) \ + || echo "Warning: tools/arch/x86/include/uapi/asm/kvm_perf.h differs from kernel" >&2 )) || true + @(test -f ../../arch/x86/include/uapi/asm/svm.h && ( \ + (diff -B ../arch/x86/include/uapi/asm/svm.h ../../arch/x86/include/uapi/asm/svm.h >/dev/null) \ + || echo "Warning: tools/arch/x86/include/uapi/asm/svm.h differs from kernel" >&2 )) || true + @(test -f ../../arch/x86/include/uapi/asm/vmx.h && ( \ + (diff -B ../arch/x86/include/uapi/asm/vmx.h ../../arch/x86/include/uapi/asm/vmx.h >/dev/null) \ + || echo "Warning: tools/arch/x86/include/uapi/asm/vmx.h differs from kernel" >&2 )) || true + @(test -f ../../arch/powerpc/include/uapi/asm/kvm.h && ( \ + (diff -B ../arch/powerpc/include/uapi/asm/kvm.h ../../arch/powerpc/include/uapi/asm/kvm.h >/dev/null) \ + || echo "Warning: tools/arch/powerpc/include/uapi/asm/kvm.h differs from kernel" >&2 )) || true + @(test -f ../../arch/s390/include/uapi/asm/kvm.h && ( \ + (diff -B ../arch/s390/include/uapi/asm/kvm.h ../../arch/s390/include/uapi/asm/kvm.h >/dev/null) \ + || echo "Warning: tools/arch/s390/include/uapi/asm/kvm.h differs from kernel" >&2 )) || true + @(test -f ../../arch/s390/include/uapi/asm/kvm_perf.h && ( \ + (diff -B ../arch/s390/include/uapi/asm/kvm_perf.h ../../arch/s390/include/uapi/asm/kvm_perf.h >/dev/null) \ + || echo "Warning: tools/arch/s390/include/uapi/asm/kvm_perf.h differs from kernel" >&2 )) || true + @(test -f ../../arch/s390/include/uapi/asm/sie.h && ( \ + (diff -B ../arch/s390/include/uapi/asm/sie.h ../../arch/s390/include/uapi/asm/sie.h >/dev/null) \ + || echo "Warning: tools/arch/s390/include/uapi/asm/sie.h differs from kernel" >&2 )) || true + @(test -f ../../arch/arm/include/uapi/asm/kvm.h && ( \ + (diff -B ../arch/arm/include/uapi/asm/kvm.h ../../arch/arm/include/uapi/asm/kvm.h >/dev/null) \ + || echo "Warning: tools/arch/arm/include/uapi/asm/kvm.h differs from kernel" >&2 )) || true + @(test -f ../../arch/arm64/include/uapi/asm/kvm.h && ( \ + (diff -B ../arch/arm64/include/uapi/asm/kvm.h ../../arch/arm64/include/uapi/asm/kvm.h >/dev/null) \ + || echo "Warning: tools/arch/arm64/include/uapi/asm/kvm.h differs from kernel" >&2 )) || true $(Q)$(MAKE) $(build)=perf $(OUTPUT)perf: $(PERFLIBS) $(PERF_IN) $(LIBTRACEEVENT_DYNAMIC_LIST) -- cgit v0.10.2 From 9a3dc28bb015fc730f7ffc49b7b0abf830b56b61 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 12 Jul 2016 11:01:17 -0300 Subject: perf tools: Fallback to reading sysfs to get cacheline size On systems where sysconf(_SC_LEVEL1_DCACHE_LINESIZE) is not available, such as musl LIBC and Android's bionic libc. Cc: Adrian Hunter Cc: Chris Phlipot Cc: David Ahern Cc: Jiri Olsa Cc: Namhyung Kim Cc: Wang Nan Link: http://lkml.kernel.org/n/tip-772obxzby758g7m2wmzcejxz@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/perf.c b/tools/perf/perf.c index f7d7dbb..4b2ff02 100644 --- a/tools/perf/perf.c +++ b/tools/perf/perf.c @@ -497,6 +497,16 @@ void pthread__unblock_sigwinch(void) pthread_sigmask(SIG_UNBLOCK, &set, NULL); } +#ifdef _SC_LEVEL1_DCACHE_LINESIZE +#define cache_line_size(cacheline_sizep) *cacheline_sizep = sysconf(_SC_LEVEL1_DCACHE_LINESIZE) +#else +static void cache_line_size(int *cacheline_sizep) +{ + if (sysfs__read_int("devices/system/cpu/cpu0/cache/index0/coherency_line_size", cacheline_sizep)) + perror("cannot determine cache line size"); +} +#endif + int main(int argc, const char **argv) { const char *cmd; @@ -509,7 +519,7 @@ int main(int argc, const char **argv) /* The page_size is placed in util object. */ page_size = sysconf(_SC_PAGE_SIZE); - cacheline_size = sysconf(_SC_LEVEL1_DCACHE_LINESIZE); + cache_line_size(&cacheline_size); if (sysctl__read_int("kernel/perf_event_max_stack", &value) == 0) sysctl_perf_event_max_stack = value; -- cgit v0.10.2 From e53e6bb8eba683ec1f18947410f39ab77efb098b Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 12 Jul 2016 11:02:37 -0300 Subject: perf trace beauty futex_op: Add missing defines for older systems Cc: Adrian Hunter Cc: David Ahern Cc: Jiri Olsa Cc: Namhyung Kim Cc: Wang Nan Link: http://lkml.kernel.org/n/tip-6qkuhv2mrcxmpy5sasc3c9tf@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/trace/beauty/futex_op.c b/tools/perf/trace/beauty/futex_op.c index e247621..bfd3359 100644 --- a/tools/perf/trace/beauty/futex_op.c +++ b/tools/perf/trace/beauty/futex_op.c @@ -1,5 +1,21 @@ #include +#ifndef FUTEX_WAIT_BITSET +#define FUTEX_WAIT_BITSET 9 +#endif +#ifndef FUTEX_WAKE_BITSET +#define FUTEX_WAKE_BITSET 10 +#endif +#ifndef FUTEX_WAIT_REQUEUE_PI +#define FUTEX_WAIT_REQUEUE_PI 11 +#endif +#ifndef FUTEX_CMP_REQUEUE_PI +#define FUTEX_CMP_REQUEUE_PI 12 +#endif +#ifndef FUTEX_CLOCK_REALTIME +#define FUTEX_CLOCK_REALTIME 256 +#endif + static size_t syscall_arg__scnprintf_futex_op(char *bf, size_t size, struct syscall_arg *arg) { enum syscall_futex_args { -- cgit v0.10.2 From 6e6fec966dcd9eb47952b39def2dee975f3502ff Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 12 Jul 2016 11:03:20 -0300 Subject: perf trace beauty seccomp: Remove seccomp.h include All we need from it is already conditionally defined, and this header file is not present in older systems, so ditch it. Cc: Adrian Hunter Cc: David Ahern Cc: Jiri Olsa Cc: Namhyung Kim Cc: Wang Nan Link: http://lkml.kernel.org/n/tip-3jxpz9gwahk4e7ltqtnr1rjg@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/trace/beauty/seccomp.c b/tools/perf/trace/beauty/seccomp.c index 213c5a7..356441b 100644 --- a/tools/perf/trace/beauty/seccomp.c +++ b/tools/perf/trace/beauty/seccomp.c @@ -1,5 +1,3 @@ -#include - #ifndef SECCOMP_SET_MODE_STRICT #define SECCOMP_SET_MODE_STRICT 0 #endif -- cgit v0.10.2 From cc31078cf13f67c489ad6a5c48dea657f5f88d11 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 12 Jul 2016 11:04:13 -0300 Subject: perf symbols: Provide a GElf_Nhdr typedef This one can be safely defined to be Elf64_Nhdr, as it is in elfutils's libelf, but not on musl libc, as both Elf64_Nhdr and Elf32_Nhdr have the same layout. Cc: Adrian Hunter Cc: David Ahern Cc: Jiri Olsa Cc: Namhyung Kim Cc: Wang Nan Link: http://lkml.kernel.org/n/tip-w8z8614l03lc8bip4ijbywbt@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/util/symbol-elf.c b/tools/perf/util/symbol-elf.c index 6f15b92..79a6a19 100644 --- a/tools/perf/util/symbol-elf.c +++ b/tools/perf/util/symbol-elf.c @@ -16,6 +16,7 @@ #define EM_AARCH64 183 /* ARM 64 bit */ #endif +typedef Elf64_Nhdr GElf_Nhdr; #ifdef HAVE_CPLUS_DEMANGLE_SUPPORT extern char *cplus_demangle(const char *, int); -- cgit v0.10.2 From 39f54862a935e14a448cbd68d6a6bef68d026dbe Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 12 Jul 2016 11:05:26 -0300 Subject: perf script python: Silence -Werror=maybe-uninitialized on gcc 5.3.0 Sounds like a compiler bug, but to silence it, initialize those variables to NULL. Noticed on: Target: x86_64-alpine-linux-musl Configured with: /home/buildozer/aports/main/gcc/src/gcc-5.3.0/configure --prefix=/usr --mandir=/usr/share/man --infodir=/usr/share/info --build=x86_64-alpine-linux-musl --host=x86_64-alpine-linux-musl --target=x86_64-alpine-linux-musl --with-pkgversion='Alpine 5.3.0' --enable-checking=release --disable-fixed-point --disable-libstdcxx-pch --disable-multilib --disable-nls --disable-werror --disable-symvers --enable-__cxa_atexit --enable-esp --enable-cloog-backend --enable-languages=c,c++,objc,java,fortran,ada --disable-libssp --disable-libmudflap --disable-libsanitizer --enable-shared --enable-threads --enable-tls --with-system-zlib Thread model: posix gcc version 5.3.0 (Alpine 5.3.0) Cc: Adrian Hunter Cc: David Ahern Cc: Jiri Olsa Cc: Namhyung Kim Cc: Wang Nan Link: http://lkml.kernel.org/n/tip-zyvsjvbl45o7hzcuz78wu2xi@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c index ff13470..6ac6b7a 100644 --- a/tools/perf/util/scripting-engines/trace-event-python.c +++ b/tools/perf/util/scripting-engines/trace-event-python.c @@ -273,7 +273,7 @@ static PyObject *get_field_numeric_entry(struct event_format *event, struct format_field *field, void *data) { bool is_array = field->flags & FIELD_IS_ARRAY; - PyObject *obj, *list = NULL; + PyObject *obj = NULL, *list = NULL; unsigned long long val; unsigned int item_size, n_items, i; @@ -392,7 +392,7 @@ static void python_process_tracepoint(struct perf_sample *sample, struct addr_location *al) { struct event_format *event = evsel->tp_format; - PyObject *handler, *context, *t, *obj, *callchain; + PyObject *handler, *context, *t, *obj = NULL, *callchain; PyObject *dict = NULL; static char handler_name[256]; struct format_field *field; -- cgit v0.10.2 From bb9707077b4ee5f77bc9939b057ff8a0d410296f Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 12 Jul 2016 11:12:18 -0300 Subject: tools: Copy the bitsperlong.h files from the kernel We use it in bitops/__ffs.h and bitops/atomic.h, that we also got from the kernel, but were getting it from either newer systems that carry it in /usr/include, or from the kernel sources, that we decided not to touch from tools/ code. Fix it. Cc: Adrian Hunter Cc: David Ahern Cc: Jiri Olsa Cc: Namhyung Kim Cc: Wang Nan Link: http://lkml.kernel.org/n/tip-lwqvgbuitjmrdpjmjp6zqnyx@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/arch/alpha/include/uapi/asm/bitsperlong.h b/tools/arch/alpha/include/uapi/asm/bitsperlong.h new file mode 100644 index 0000000..ad57f78 --- /dev/null +++ b/tools/arch/alpha/include/uapi/asm/bitsperlong.h @@ -0,0 +1,8 @@ +#ifndef __ASM_ALPHA_BITSPERLONG_H +#define __ASM_ALPHA_BITSPERLONG_H + +#define __BITS_PER_LONG 64 + +#include + +#endif /* __ASM_ALPHA_BITSPERLONG_H */ diff --git a/tools/arch/arm64/include/uapi/asm/bitsperlong.h b/tools/arch/arm64/include/uapi/asm/bitsperlong.h new file mode 100644 index 0000000..fce9c29 --- /dev/null +++ b/tools/arch/arm64/include/uapi/asm/bitsperlong.h @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2012 ARM Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#ifndef __ASM_BITSPERLONG_H +#define __ASM_BITSPERLONG_H + +#define __BITS_PER_LONG 64 + +#include + +#endif /* __ASM_BITSPERLONG_H */ diff --git a/tools/arch/frv/include/uapi/asm/bitsperlong.h b/tools/arch/frv/include/uapi/asm/bitsperlong.h new file mode 100644 index 0000000..6dc0bb0 --- /dev/null +++ b/tools/arch/frv/include/uapi/asm/bitsperlong.h @@ -0,0 +1 @@ +#include diff --git a/tools/arch/h8300/include/asm/bitsperlong.h b/tools/arch/h8300/include/asm/bitsperlong.h new file mode 100644 index 0000000..e140e46 --- /dev/null +++ b/tools/arch/h8300/include/asm/bitsperlong.h @@ -0,0 +1,14 @@ +#ifndef __ASM_H8300_BITS_PER_LONG +#define __ASM_H8300_BITS_PER_LONG + +#include + +#if !defined(__ASSEMBLY__) +/* h8300-unknown-linux required long */ +#define __kernel_size_t __kernel_size_t +typedef unsigned long __kernel_size_t; +typedef long __kernel_ssize_t; +typedef long __kernel_ptrdiff_t; +#endif + +#endif /* __ASM_H8300_BITS_PER_LONG */ diff --git a/tools/arch/hexagon/include/uapi/asm/bitsperlong.h b/tools/arch/hexagon/include/uapi/asm/bitsperlong.h new file mode 100644 index 0000000..4a65815 --- /dev/null +++ b/tools/arch/hexagon/include/uapi/asm/bitsperlong.h @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2010-2011, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#ifndef __ASM_HEXAGON_BITSPERLONG_H +#define __ASM_HEXAGON_BITSPERLONG_H + +#define __BITS_PER_LONG 32 + +#include + +#endif diff --git a/tools/arch/ia64/include/uapi/asm/bitsperlong.h b/tools/arch/ia64/include/uapi/asm/bitsperlong.h new file mode 100644 index 0000000..ec4db3c --- /dev/null +++ b/tools/arch/ia64/include/uapi/asm/bitsperlong.h @@ -0,0 +1,8 @@ +#ifndef __ASM_IA64_BITSPERLONG_H +#define __ASM_IA64_BITSPERLONG_H + +#define __BITS_PER_LONG 64 + +#include + +#endif /* __ASM_IA64_BITSPERLONG_H */ diff --git a/tools/arch/m32r/include/uapi/asm/bitsperlong.h b/tools/arch/m32r/include/uapi/asm/bitsperlong.h new file mode 100644 index 0000000..6dc0bb0 --- /dev/null +++ b/tools/arch/m32r/include/uapi/asm/bitsperlong.h @@ -0,0 +1 @@ +#include diff --git a/tools/arch/microblaze/include/uapi/asm/bitsperlong.h b/tools/arch/microblaze/include/uapi/asm/bitsperlong.h new file mode 100644 index 0000000..6dc0bb0 --- /dev/null +++ b/tools/arch/microblaze/include/uapi/asm/bitsperlong.h @@ -0,0 +1 @@ +#include diff --git a/tools/arch/mips/include/uapi/asm/bitsperlong.h b/tools/arch/mips/include/uapi/asm/bitsperlong.h new file mode 100644 index 0000000..3e4c10a --- /dev/null +++ b/tools/arch/mips/include/uapi/asm/bitsperlong.h @@ -0,0 +1,8 @@ +#ifndef __ASM_MIPS_BITSPERLONG_H +#define __ASM_MIPS_BITSPERLONG_H + +#define __BITS_PER_LONG _MIPS_SZLONG + +#include + +#endif /* __ASM_MIPS_BITSPERLONG_H */ diff --git a/tools/arch/mn10300/include/uapi/asm/bitsperlong.h b/tools/arch/mn10300/include/uapi/asm/bitsperlong.h new file mode 100644 index 0000000..6dc0bb0 --- /dev/null +++ b/tools/arch/mn10300/include/uapi/asm/bitsperlong.h @@ -0,0 +1 @@ +#include diff --git a/tools/arch/parisc/include/uapi/asm/bitsperlong.h b/tools/arch/parisc/include/uapi/asm/bitsperlong.h new file mode 100644 index 0000000..e0a23c7 --- /dev/null +++ b/tools/arch/parisc/include/uapi/asm/bitsperlong.h @@ -0,0 +1,14 @@ +#ifndef __ASM_PARISC_BITSPERLONG_H +#define __ASM_PARISC_BITSPERLONG_H + +#if defined(__LP64__) +#define __BITS_PER_LONG 64 +#define SHIFT_PER_LONG 6 +#else +#define __BITS_PER_LONG 32 +#define SHIFT_PER_LONG 5 +#endif + +#include + +#endif /* __ASM_PARISC_BITSPERLONG_H */ diff --git a/tools/arch/powerpc/include/uapi/asm/bitsperlong.h b/tools/arch/powerpc/include/uapi/asm/bitsperlong.h new file mode 100644 index 0000000..5f16590 --- /dev/null +++ b/tools/arch/powerpc/include/uapi/asm/bitsperlong.h @@ -0,0 +1,12 @@ +#ifndef __ASM_POWERPC_BITSPERLONG_H +#define __ASM_POWERPC_BITSPERLONG_H + +#if defined(__powerpc64__) +# define __BITS_PER_LONG 64 +#else +# define __BITS_PER_LONG 32 +#endif + +#include + +#endif /* __ASM_POWERPC_BITSPERLONG_H */ diff --git a/tools/arch/s390/include/uapi/asm/bitsperlong.h b/tools/arch/s390/include/uapi/asm/bitsperlong.h new file mode 100644 index 0000000..e351ea2 --- /dev/null +++ b/tools/arch/s390/include/uapi/asm/bitsperlong.h @@ -0,0 +1,12 @@ +#ifndef __ASM_S390_BITSPERLONG_H +#define __ASM_S390_BITSPERLONG_H + +#ifndef __s390x__ +#define __BITS_PER_LONG 32 +#else +#define __BITS_PER_LONG 64 +#endif + +#include + +#endif /* __ASM_S390_BITSPERLONG_H */ diff --git a/tools/arch/score/include/uapi/asm/bitsperlong.h b/tools/arch/score/include/uapi/asm/bitsperlong.h new file mode 100644 index 0000000..86ff337 --- /dev/null +++ b/tools/arch/score/include/uapi/asm/bitsperlong.h @@ -0,0 +1,6 @@ +#ifndef _ASM_SCORE_BITSPERLONG_H +#define _ASM_SCORE_BITSPERLONG_H + +#include + +#endif /* _ASM_SCORE_BITSPERLONG_H */ diff --git a/tools/arch/sparc/include/uapi/asm/bitsperlong.h b/tools/arch/sparc/include/uapi/asm/bitsperlong.h new file mode 100644 index 0000000..b62dd90 --- /dev/null +++ b/tools/arch/sparc/include/uapi/asm/bitsperlong.h @@ -0,0 +1,12 @@ +#ifndef __ASM_ALPHA_BITSPERLONG_H +#define __ASM_ALPHA_BITSPERLONG_H + +#if defined(__sparc__) && defined(__arch64__) +#define __BITS_PER_LONG 64 +#else +#define __BITS_PER_LONG 32 +#endif + +#include + +#endif /* __ASM_ALPHA_BITSPERLONG_H */ diff --git a/tools/arch/tile/include/uapi/asm/bitsperlong.h b/tools/arch/tile/include/uapi/asm/bitsperlong.h new file mode 100644 index 0000000..58c771f --- /dev/null +++ b/tools/arch/tile/include/uapi/asm/bitsperlong.h @@ -0,0 +1,26 @@ +/* + * Copyright 2010 Tilera Corporation. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, version 2. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or + * NON INFRINGEMENT. See the GNU General Public License for + * more details. + */ + +#ifndef _ASM_TILE_BITSPERLONG_H +#define _ASM_TILE_BITSPERLONG_H + +#ifdef __LP64__ +# define __BITS_PER_LONG 64 +#else +# define __BITS_PER_LONG 32 +#endif + +#include + +#endif /* _ASM_TILE_BITSPERLONG_H */ diff --git a/tools/arch/x86/include/uapi/asm/bitsperlong.h b/tools/arch/x86/include/uapi/asm/bitsperlong.h new file mode 100644 index 0000000..6e23c54 --- /dev/null +++ b/tools/arch/x86/include/uapi/asm/bitsperlong.h @@ -0,0 +1,12 @@ +#ifndef __ASM_X86_BITSPERLONG_H +#define __ASM_X86_BITSPERLONG_H + +#if defined(__x86_64__) && !defined(__ILP32__) +# define __BITS_PER_LONG 64 +#else +# define __BITS_PER_LONG 32 +#endif + +#include + +#endif /* __ASM_X86_BITSPERLONG_H */ diff --git a/tools/include/asm-generic/bitops/__ffs.h b/tools/include/asm-generic/bitops/__ffs.h index c941750..b3accfd 100644 --- a/tools/include/asm-generic/bitops/__ffs.h +++ b/tools/include/asm-generic/bitops/__ffs.h @@ -2,6 +2,7 @@ #define _TOOLS_LINUX_ASM_GENERIC_BITOPS___FFS_H_ #include +#include /** * __ffs - find first bit in word. diff --git a/tools/include/asm-generic/bitops/atomic.h b/tools/include/asm-generic/bitops/atomic.h index 4bccd7c3..18663f5 100644 --- a/tools/include/asm-generic/bitops/atomic.h +++ b/tools/include/asm-generic/bitops/atomic.h @@ -2,6 +2,7 @@ #define _TOOLS_LINUX_ASM_GENERIC_BITOPS_ATOMIC_H_ #include +#include static inline void set_bit(int nr, unsigned long *addr) { diff --git a/tools/include/asm-generic/bitsperlong.h b/tools/include/asm-generic/bitsperlong.h new file mode 100644 index 0000000..d1d70aa1 --- /dev/null +++ b/tools/include/asm-generic/bitsperlong.h @@ -0,0 +1,25 @@ +#ifndef __ASM_GENERIC_BITS_PER_LONG +#define __ASM_GENERIC_BITS_PER_LONG + +#include + + +#ifdef CONFIG_64BIT +#define BITS_PER_LONG 64 +#else +#define BITS_PER_LONG 32 +#endif /* CONFIG_64BIT */ + +/* + * FIXME: The check currently breaks x86-64 build, so it's + * temporarily disabled. Please fix x86-64 and reenable + */ +#if 0 && BITS_PER_LONG != __BITS_PER_LONG +#error Inconsistent word size. Check asm/bitsperlong.h +#endif + +#ifndef BITS_PER_LONG_LONG +#define BITS_PER_LONG_LONG 64 +#endif + +#endif /* __ASM_GENERIC_BITS_PER_LONG */ diff --git a/tools/include/uapi/asm-generic/bitsperlong.h b/tools/include/uapi/asm-generic/bitsperlong.h new file mode 100644 index 0000000..23e6c41 --- /dev/null +++ b/tools/include/uapi/asm-generic/bitsperlong.h @@ -0,0 +1,15 @@ +#ifndef _UAPI__ASM_GENERIC_BITS_PER_LONG +#define _UAPI__ASM_GENERIC_BITS_PER_LONG + +/* + * There seems to be no way of detecting this automatically from user + * space, so 64 bit architectures should override this in their + * bitsperlong.h. In particular, an architecture that supports + * both 32 and 64 bit user space must not rely on CONFIG_64BIT + * to decide it, but rather check a compiler provided macro. + */ +#ifndef __BITS_PER_LONG +#define __BITS_PER_LONG 32 +#endif + +#endif /* _UAPI__ASM_GENERIC_BITS_PER_LONG */ -- cgit v0.10.2 From 1d4489d0ec141fe77eb79ce9bf9179d0342cb809 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 12 Jul 2016 11:31:39 -0300 Subject: perf tools: Add the tools/ stringify copy to the MANIFEST So that we don't end up using the kernel one when building out of tree, via a detached tarball. Cc: Adrian Hunter Cc: David Ahern Cc: Jiri Olsa Cc: Namhyung Kim Cc: Wang Nan Fixes: 737ef7d32cb4 ("tools include: Copy linux/stringify.h from the kernel") Link: http://lkml.kernel.org/n/tip-t8yn1d7y0magk889ymc8jlai@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/MANIFEST b/tools/perf/MANIFEST index db7cfb4..923eda2 100644 --- a/tools/perf/MANIFEST +++ b/tools/perf/MANIFEST @@ -73,6 +73,7 @@ tools/include/linux/poison.h tools/include/linux/rbtree.h tools/include/linux/rbtree_augmented.h tools/include/linux/string.h +tools/include/linux/stringify.h tools/include/linux/types.h tools/include/linux/err.h tools/include/linux/bitmap.h @@ -83,7 +84,6 @@ include/asm-generic/bitops/__fls.h include/asm-generic/bitops/fls.h include/linux/list.h include/linux/hash.h -include/linux/stringify.h include/linux/swab.h arch/*/include/asm/unistd*.h arch/*/include/uapi/asm/unistd*.h -- cgit v0.10.2 From 3c7752f7ab6d591d07f0851321d6ab1ace46e6fb Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Mon, 11 Jul 2016 23:39:58 -0300 Subject: perf tools: Don't add kernel directories to the header search path We've decided not to access kernel source files because changes there could break the tooling side, this is one more step in that direction. Cc: Adrian Hunter Cc: David Ahern Cc: Jiri Olsa Cc: Namhyung Kim Cc: Wang Nan Link: http://lkml.kernel.org/n/tip-ar0hupkxl45h5hk09l2rprj3@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/config/Makefile b/tools/perf/config/Makefile index 49a2130..97d4714 100644 --- a/tools/perf/config/Makefile +++ b/tools/perf/config/Makefile @@ -210,11 +210,7 @@ CFLAGS += -I$(srctree)/tools/include/uapi CFLAGS += -I$(srctree)/tools/include/ CFLAGS += -I$(srctree)/tools/arch/$(ARCH)/include/uapi CFLAGS += -I$(srctree)/tools/arch/$(ARCH)/include/ -CFLAGS += -I$(srctree)/arch/$(ARCH)/include/uapi -CFLAGS += -I$(srctree)/arch/$(ARCH)/include CFLAGS += -I$(srctree)/tools/arch/$(ARCH)/ -CFLAGS += -I$(srctree)/include/uapi -CFLAGS += -I$(srctree)/include # $(obj-perf) for generated common-cmds.h # $(obj-perf)/util for generated bison/flex headers -- cgit v0.10.2 From c8a3f7de76717a994c208e137156c077b1e93092 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 12 Jul 2016 12:16:35 -0300 Subject: perf intel-pt-decoder: Avoid checking code drift on busibox's diff That doesn't have -I to match lines. Cc: Adrian Hunter Cc: David Ahern Cc: Jiri Olsa Cc: Namhyung Kim Cc: Wang Nan Link: http://lkml.kernel.org/n/tip-7nz9hnbk7a9p91ou927ye5yh@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/util/intel-pt-decoder/Build b/tools/perf/util/intel-pt-decoder/Build index 0611d61..9b742ea 100644 --- a/tools/perf/util/intel-pt-decoder/Build +++ b/tools/perf/util/intel-pt-decoder/Build @@ -7,8 +7,11 @@ $(OUTPUT)util/intel-pt-decoder/inat-tables.c: $(inat_tables_script) $(inat_table $(call rule_mkdir) @$(call echo-cmd,gen)$(AWK) -f $(inat_tables_script) $(inat_tables_maps) > $@ || rm -f $@ +# Busybox's diff doesn't have -I, avoid warning in the case + $(OUTPUT)util/intel-pt-decoder/intel-pt-insn-decoder.o: util/intel-pt-decoder/intel-pt-insn-decoder.c util/intel-pt-decoder/inat.c $(OUTPUT)util/intel-pt-decoder/inat-tables.c - @(test -d ../../kernel -a -d ../../tools -a -d ../perf && (( \ + @(diff -I 2>&1 | grep -q 'option requires an argument' && \ + test -d ../../kernel -a -d ../../tools -a -d ../perf && (( \ diff -B -I'^#include' util/intel-pt-decoder/insn.c ../../arch/x86/lib/insn.c >/dev/null && \ diff -B -I'^#include' util/intel-pt-decoder/inat.c ../../arch/x86/lib/inat.c >/dev/null && \ diff -B util/intel-pt-decoder/x86-opcode-map.txt ../../arch/x86/lib/x86-opcode-map.txt >/dev/null && \ -- cgit v0.10.2 From 1c1a3a4729aae712c55e001e151ef008d030d4a7 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 12 Jul 2016 12:19:09 -0300 Subject: perf tools: Add feature detection for gelf_getnote() That is not present on some libelf implementations, such as the one used in Alpine Linux: libelf-0.8.13. This ends up disabling the SDT code, that relies on this function. One alternative would be to provide an weak fallback implementation or the open coded variant used by the buildid sysfs notes reading code. Cc: Adrian Hunter Cc: Ananth N Mavinakayanahalli Cc: Brendan Gregg Cc: David Ahern Cc: Hemant Kumar Cc: Jiri Olsa Cc: Masami Hiramatsu Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Wang Nan Link: http://lkml.kernel.org/n/tip-82lh22ybedy9b9lych8xj12g@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/build/Makefile.feature b/tools/build/Makefile.feature index 3dd529b..fe12bee 100644 --- a/tools/build/Makefile.feature +++ b/tools/build/Makefile.feature @@ -40,6 +40,7 @@ FEATURE_TESTS_BASIC := \ libbfd \ libelf \ libelf-getphdrnum \ + libelf-gelf_getnote \ libelf-getshdrstrndx \ libelf-mmap \ libnuma \ diff --git a/tools/build/feature/Makefile b/tools/build/feature/Makefile index 6747116..d6017c1 100644 --- a/tools/build/feature/Makefile +++ b/tools/build/feature/Makefile @@ -17,6 +17,7 @@ FILES= \ test-cplus-demangle.bin \ test-libelf.bin \ test-libelf-getphdrnum.bin \ + test-libelf-gelf_getnote.bin \ test-libelf-getshdrstrndx.bin \ test-libelf-mmap.bin \ test-libnuma.bin \ @@ -99,6 +100,9 @@ $(OUTPUT)test-libelf-mmap.bin: $(OUTPUT)test-libelf-getphdrnum.bin: $(BUILD) -lelf +$(OUTPUT)test-libelf-gelf_getnote.bin: + $(BUILD) -lelf + $(OUTPUT)test-libelf-getshdrstrndx.bin: $(BUILD) -lelf diff --git a/tools/build/feature/test-all.c b/tools/build/feature/test-all.c index 7433cca..843aed0 100644 --- a/tools/build/feature/test-all.c +++ b/tools/build/feature/test-all.c @@ -49,6 +49,10 @@ # include "test-libelf-getphdrnum.c" #undef main +#define main main_test_libelf_gelf_getnote +# include "test-libelf-gelf_getnote.c" +#undef main + #define main main_test_libelf_getshdrstrndx # include "test-libelf-getshdrstrndx.c" #undef main @@ -153,6 +157,7 @@ int main(int argc, char *argv[]) main_test_dwarf(); main_test_dwarf_getlocations(); main_test_libelf_getphdrnum(); + main_test_libelf_gelf_getnote(); main_test_libelf_getshdrstrndx(); main_test_libunwind(); main_test_libaudit(); diff --git a/tools/build/feature/test-libelf-gelf_getnote.c b/tools/build/feature/test-libelf-gelf_getnote.c new file mode 100644 index 0000000..d78cf4d --- /dev/null +++ b/tools/build/feature/test-libelf-gelf_getnote.c @@ -0,0 +1,7 @@ +#include +#include + +int main(void) +{ + return gelf_getnote(NULL, 0, NULL, NULL, NULL); +} diff --git a/tools/perf/config/Makefile b/tools/perf/config/Makefile index 97d4714..5ac4280 100644 --- a/tools/perf/config/Makefile +++ b/tools/perf/config/Makefile @@ -309,6 +309,12 @@ ifndef NO_LIBELF CFLAGS += -DHAVE_ELF_GETPHDRNUM_SUPPORT endif + ifeq ($(feature-libelf-gelf_getnote), 1) + CFLAGS += -DHAVE_GELF_GETNOTE_SUPPORT + else + msg := $(warning gelf_getnote() not found on libelf, SDT support disabled); + endif + ifeq ($(feature-libelf-getshdrstrndx), 1) CFLAGS += -DHAVE_ELF_GETSHDRSTRNDX_SUPPORT endif diff --git a/tools/perf/util/build-id.c b/tools/perf/util/build-id.c index e1a1640..1e504e4 100644 --- a/tools/perf/util/build-id.c +++ b/tools/perf/util/build-id.c @@ -533,7 +533,7 @@ int build_id_cache__list_build_ids(const char *pathname, return ret; } -#ifdef HAVE_LIBELF_SUPPORT +#if defined(HAVE_LIBELF_SUPPORT) && defined(HAVE_GELF_GETNOTE_SUPPORT) static int build_id_cache__add_sdt_cache(const char *sbuild_id, const char *realname) { diff --git a/tools/perf/util/probe-file.c b/tools/perf/util/probe-file.c index 98398b5..e705a74 100644 --- a/tools/perf/util/probe-file.c +++ b/tools/perf/util/probe-file.c @@ -624,6 +624,7 @@ out_err: return ret; } +#ifdef HAVE_GELF_GETNOTE_SUPPORT static unsigned long long sdt_note__get_addr(struct sdt_note *note) { return note->bit32 ? (unsigned long long)note->addr.a32[0] @@ -682,6 +683,7 @@ int probe_cache__scan_sdt(struct probe_cache *pcache, const char *pathname) cleanup_sdt_note_list(&sdtlist); return ret; } +#endif static int probe_cache_entry__write(struct probe_cache_entry *entry, int fd) { diff --git a/tools/perf/util/symbol-elf.c b/tools/perf/util/symbol-elf.c index 79a6a19..cebf98e 100644 --- a/tools/perf/util/symbol-elf.c +++ b/tools/perf/util/symbol-elf.c @@ -1790,6 +1790,7 @@ void kcore_extract__delete(struct kcore_extract *kce) unlink(kce->extract_filename); } +#ifdef HAVE_GELF_GETNOTE_SUPPORT /** * populate_sdt_note : Parse raw data and identify SDT note * @elf: elf of the opened file @@ -2041,6 +2042,7 @@ int sdt_notes__get_count(struct list_head *start) count++; return count; } +#endif void symbol__elf_init(void) { -- cgit v0.10.2 From cae15db74999edb96dd9f5bbd4d55849391dd92b Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sat, 9 Jul 2016 00:20:00 -0700 Subject: perf symbols: Add Rust demangling Rust demangling is another step after bfd demangling. Add a diagnosis to identify mangled Rust symbols based on the hash that the Rust mangler appends as the last path component, as well as other characteristics. Add a demangler to reconstruct the original symbol. Committer notes: How I tested it: Enabled COPR on Fedora 24 and then installed the 'rust-binary' package, with it: $ cat src/main.rs fn main() { println!("Hello, world!"); } $ cat Cargo.toml [package] name = "hello_world" version = "0.0.1" authors = [ "Arnaldo Carvalho de Melo " ] $ perf record cargo bench Compiling hello_world v0.0.1 (file:///home/acme/projects/hello_world) Running target/release/hello_world-d4b9dab4b2a47d75 running 0 tests test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured [ perf record: Woken up 1 times to write data ] [ perf record: Captured and wrote 0.096 MB perf.data (1457 samples) ] $ Before this patch: $ perf report --stdio --dsos librbml-e8edd0fd.so # dso: librbml-e8edd0fd.so # # Total Lost Samples: 0 # # Samples: 1K of event 'cycles:u' # Event count (approx.): 979599126 # # Overhead Command Symbol # ........ ....... ............................................................................................................. # 1.78% rustc [.] rbml::reader::maybe_get_doc::hb9d387df6024b15b 1.50% rustc [.] _$LT$reader..DocsIterator$LT$$u27$a$GT$$u20$as$u20$std..iter..Iterator$GT$::next::hd9af9e60d79a35c8 1.20% rustc [.] rbml::reader::doc_at::hc88107fba445af31 0.46% rustc [.] _$LT$reader..TaggedDocsIterator$LT$$u27$a$GT$$u20$as$u20$std..iter..Iterator$GT$::next::h0cb40e696e4bb489 0.35% rustc [.] rbml::reader::Decoder::_next_int::h66eef7825a398bc3 0.29% rustc [.] rbml::reader::Decoder::_next_sub::h8e5266005580b836 0.15% rustc [.] rbml::reader::get_doc::h094521c645459139 0.14% rustc [.] _$LT$reader..Decoder$LT$$u27$doc$GT$$u20$as$u20$serialize..Decoder$GT$::read_u32::h0acea2fff9669327 0.07% rustc [.] rbml::reader::Decoder::next_doc::h6714d469c9dfaf91 0.07% rustc [.] _ZN4rbml6reader10doc_as_u6417h930b740aa94f1d3aE@plt 0.06% rustc [.] _fini $ After: $ perf report --stdio --dsos librbml-e8edd0fd.so # dso: librbml-e8edd0fd.so # # Total Lost Samples: 0 # # Samples: 1K of event 'cycles:u' # Event count (approx.): 979599126 # # Overhead Command Symbol # ........ ....... ................................................................. # 1.78% rustc [.] rbml::reader::maybe_get_doc 1.50% rustc [.] as std::iter::Iterator>::next 1.20% rustc [.] rbml::reader::doc_at 0.46% rustc [.] as std::iter::Iterator>::next 0.35% rustc [.] rbml::reader::Decoder::_next_int 0.29% rustc [.] rbml::reader::Decoder::_next_sub 0.15% rustc [.] rbml::reader::get_doc 0.14% rustc [.] as serialize::Decoder>::read_u32 0.07% rustc [.] rbml::reader::Decoder::next_doc 0.07% rustc [.] _ZN4rbml6reader10doc_as_u6417h930b740aa94f1d3aE@plt 0.06% rustc [.] _fini $ Signed-off-by: David Tolnay Tested-by: Arnaldo Carvalho de Melo Cc: Alexander Shishkin Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/5780B7FA.3030602@gmail.com Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/util/Build b/tools/perf/util/Build index eda68f5..2fa7d8b 100644 --- a/tools/perf/util/Build +++ b/tools/perf/util/Build @@ -113,6 +113,7 @@ libperf-y += scripting-engines/ libperf-$(CONFIG_ZLIB) += zlib.o libperf-$(CONFIG_LZMA) += lzma.o libperf-y += demangle-java.o +libperf-y += demangle-rust.o ifdef CONFIG_JITDUMP libperf-$(CONFIG_LIBELF) += jitdump.o diff --git a/tools/perf/util/demangle-rust.c b/tools/perf/util/demangle-rust.c new file mode 100644 index 0000000..f9dafa8 --- /dev/null +++ b/tools/perf/util/demangle-rust.c @@ -0,0 +1,269 @@ +#include +#include "util.h" +#include "debug.h" + +#include "demangle-rust.h" + +/* + * Mangled Rust symbols look like this: + * + * _$LT$std..sys..fd..FileDesc$u20$as$u20$core..ops..Drop$GT$::drop::hc68340e1baa4987a + * + * The original symbol is: + * + * ::drop + * + * The last component of the path is a 64-bit hash in lowercase hex, prefixed + * with "h". Rust does not have a global namespace between crates, an illusion + * which Rust maintains by using the hash to distinguish things that would + * otherwise have the same symbol. + * + * Any path component not starting with a XID_Start character is prefixed with + * "_". + * + * The following escape sequences are used: + * + * "," => $C$ + * "@" => $SP$ + * "*" => $BP$ + * "&" => $RF$ + * "<" => $LT$ + * ">" => $GT$ + * "(" => $LP$ + * ")" => $RP$ + * " " => $u20$ + * "'" => $u27$ + * "[" => $u5b$ + * "]" => $u5d$ + * "~" => $u7e$ + * + * A double ".." means "::" and a single "." means "-". + * + * The only characters allowed in the mangled symbol are a-zA-Z0-9 and _.:$ + */ + +static const char *hash_prefix = "::h"; +static const size_t hash_prefix_len = 3; +static const size_t hash_len = 16; + +static bool is_prefixed_hash(const char *start); +static bool looks_like_rust(const char *sym, size_t len); +static bool unescape(const char **in, char **out, const char *seq, char value); + +/* + * INPUT: + * sym: symbol that has been through BFD-demangling + * + * This function looks for the following indicators: + * + * 1. The hash must consist of "h" followed by 16 lowercase hex digits. + * + * 2. As a sanity check, the hash must use between 5 and 15 of the 16 possible + * hex digits. This is true of 99.9998% of hashes so once in your life you + * may see a false negative. The point is to notice path components that + * could be Rust hashes but are probably not, like "haaaaaaaaaaaaaaaa". In + * this case a false positive (non-Rust symbol has an important path + * component removed because it looks like a Rust hash) is worse than a + * false negative (the rare Rust symbol is not demangled) so this sets the + * balance in favor of false negatives. + * + * 3. There must be no characters other than a-zA-Z0-9 and _.:$ + * + * 4. There must be no unrecognized $-sign sequences. + * + * 5. There must be no sequence of three or more dots in a row ("..."). + */ +bool +rust_is_mangled(const char *sym) +{ + size_t len, len_without_hash; + + if (!sym) + return false; + + len = strlen(sym); + if (len <= hash_prefix_len + hash_len) + /* Not long enough to contain "::h" + hash + something else */ + return false; + + len_without_hash = len - (hash_prefix_len + hash_len); + if (!is_prefixed_hash(sym + len_without_hash)) + return false; + + return looks_like_rust(sym, len_without_hash); +} + +/* + * A hash is the prefix "::h" followed by 16 lowercase hex digits. The hex + * digits must comprise between 5 and 15 (inclusive) distinct digits. + */ +static bool is_prefixed_hash(const char *str) +{ + const char *end; + bool seen[16]; + size_t i; + int count; + + if (strncmp(str, hash_prefix, hash_prefix_len)) + return false; + str += hash_prefix_len; + + memset(seen, false, sizeof(seen)); + for (end = str + hash_len; str < end; str++) + if (*str >= '0' && *str <= '9') + seen[*str - '0'] = true; + else if (*str >= 'a' && *str <= 'f') + seen[*str - 'a' + 10] = true; + else + return false; + + /* Count how many distinct digits seen */ + count = 0; + for (i = 0; i < 16; i++) + if (seen[i]) + count++; + + return count >= 5 && count <= 15; +} + +static bool looks_like_rust(const char *str, size_t len) +{ + const char *end = str + len; + + while (str < end) + switch (*str) { + case '$': + if (!strncmp(str, "$C$", 3)) + str += 3; + else if (!strncmp(str, "$SP$", 4) + || !strncmp(str, "$BP$", 4) + || !strncmp(str, "$RF$", 4) + || !strncmp(str, "$LT$", 4) + || !strncmp(str, "$GT$", 4) + || !strncmp(str, "$LP$", 4) + || !strncmp(str, "$RP$", 4)) + str += 4; + else if (!strncmp(str, "$u20$", 5) + || !strncmp(str, "$u27$", 5) + || !strncmp(str, "$u5b$", 5) + || !strncmp(str, "$u5d$", 5) + || !strncmp(str, "$u7e$", 5)) + str += 5; + else + return false; + break; + case '.': + /* Do not allow three or more consecutive dots */ + if (!strncmp(str, "...", 3)) + return false; + /* Fall through */ + case 'a' ... 'z': + case 'A' ... 'Z': + case '0' ... '9': + case '_': + case ':': + str++; + break; + default: + return false; + } + + return true; +} + +/* + * INPUT: + * sym: symbol for which rust_is_mangled(sym) returns true + * + * The input is demangled in-place because the mangled name is always longer + * than the demangled one. + */ +void +rust_demangle_sym(char *sym) +{ + const char *in; + char *out; + const char *end; + + if (!sym) + return; + + in = sym; + out = sym; + end = sym + strlen(sym) - (hash_prefix_len + hash_len); + + while (in < end) + switch (*in) { + case '$': + if (!(unescape(&in, &out, "$C$", ',') + || unescape(&in, &out, "$SP$", '@') + || unescape(&in, &out, "$BP$", '*') + || unescape(&in, &out, "$RF$", '&') + || unescape(&in, &out, "$LT$", '<') + || unescape(&in, &out, "$GT$", '>') + || unescape(&in, &out, "$LP$", '(') + || unescape(&in, &out, "$RP$", ')') + || unescape(&in, &out, "$u20$", ' ') + || unescape(&in, &out, "$u27$", '\'') + || unescape(&in, &out, "$u5b$", '[') + || unescape(&in, &out, "$u5d$", ']') + || unescape(&in, &out, "$u7e$", '~'))) { + pr_err("demangle-rust: unexpected escape sequence"); + goto done; + } + break; + case '_': + /* + * If this is the start of a path component and the next + * character is an escape sequence, ignore the + * underscore. The mangler inserts an underscore to make + * sure the path component begins with a XID_Start + * character. + */ + if ((in == sym || in[-1] == ':') && in[1] == '$') + in++; + else + *out++ = *in++; + break; + case '.': + if (in[1] == '.') { + /* ".." becomes "::" */ + *out++ = ':'; + *out++ = ':'; + in += 2; + } else { + /* "." becomes "-" */ + *out++ = '-'; + in++; + } + break; + case 'a' ... 'z': + case 'A' ... 'Z': + case '0' ... '9': + case ':': + *out++ = *in++; + break; + default: + pr_err("demangle-rust: unexpected character '%c' in symbol\n", + *in); + goto done; + } + +done: + *out = '\0'; +} + +static bool unescape(const char **in, char **out, const char *seq, char value) +{ + size_t len = strlen(seq); + + if (strncmp(*in, seq, len)) + return false; + + **out = value; + + *in += len; + *out += 1; + + return true; +} diff --git a/tools/perf/util/demangle-rust.h b/tools/perf/util/demangle-rust.h new file mode 100644 index 0000000..7b41ead --- /dev/null +++ b/tools/perf/util/demangle-rust.h @@ -0,0 +1,7 @@ +#ifndef __PERF_DEMANGLE_RUST +#define __PERF_DEMANGLE_RUST 1 + +bool rust_is_mangled(const char *str); +void rust_demangle_sym(char *str); + +#endif /* __PERF_DEMANGLE_RUST */ diff --git a/tools/perf/util/symbol-elf.c b/tools/perf/util/symbol-elf.c index cebf98e..a34321e 100644 --- a/tools/perf/util/symbol-elf.c +++ b/tools/perf/util/symbol-elf.c @@ -7,6 +7,7 @@ #include "symbol.h" #include "demangle-java.h" +#include "demangle-rust.h" #include "machine.h" #include "vdso.h" #include @@ -1081,6 +1082,13 @@ new_symbol: demangled = bfd_demangle(NULL, elf_name, demangle_flags); if (demangled == NULL) demangled = java_demangle_sym(elf_name, JAVA_DEMANGLE_NORET); + else if (rust_is_mangled(demangled)) + /* + * Input to Rust demangling is the BFD-demangled + * name which it Rust-demangles in place. + */ + rust_demangle_sym(demangled); + if (demangled != NULL) elf_name = demangled; } -- cgit v0.10.2 From 7cb5c5acaba9fa0b90ca11275f19131d3eca35c2 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Sun, 10 Jul 2016 13:07:53 +0200 Subject: perf evlist: Make event2evsel public It will be used outside of evlist.c object in folowing patches. Signed-off-by: Jiri Olsa Cc: David Ahern Cc: Namhyung Kim Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1468148882-10362-2-git-send-email-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index f2d478d..862e69c 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c @@ -651,8 +651,8 @@ static int perf_evlist__event2id(struct perf_evlist *evlist, return 0; } -static struct perf_evsel *perf_evlist__event2evsel(struct perf_evlist *evlist, - union perf_event *event) +struct perf_evsel *perf_evlist__event2evsel(struct perf_evlist *evlist, + union perf_event *event) { struct perf_evsel *first = perf_evlist__first(evlist); struct hlist_head *head; diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h index 872912b..afd0877 100644 --- a/tools/perf/util/evlist.h +++ b/tools/perf/util/evlist.h @@ -323,4 +323,7 @@ void perf_event_attr__set_max_precise_ip(struct perf_event_attr *attr); struct perf_evsel * perf_evlist__find_evsel_by_str(struct perf_evlist *evlist, const char *str); + +struct perf_evsel *perf_evlist__event2evsel(struct perf_evlist *evlist, + union perf_event *event); #endif /* __PERF_EVLIST_H */ -- cgit v0.10.2 From 71fe1052af98fc5b615c067425aeb6fe39a0368c Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Sun, 10 Jul 2016 13:07:54 +0200 Subject: perf tools: Introduce trace_event__tp_format_id() To get struct event_format object from tracepoint ID. It will be used in following patches. Signed-off-by: Jiri Olsa Cc: David Ahern Cc: Namhyung Kim Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1468148882-10362-3-git-send-email-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/util/trace-event.c b/tools/perf/util/trace-event.c index 8ae051e..c330780 100644 --- a/tools/perf/util/trace-event.c +++ b/tools/perf/util/trace-event.c @@ -105,3 +105,11 @@ trace_event__tp_format(const char *sys, const char *name) return tp_format(sys, name); } + +struct event_format *trace_event__tp_format_id(int id) +{ + if (!tevent_initialized && trace_event__init2()) + return ERR_PTR(-ENOMEM); + + return pevent_find_event(tevent.pevent, id); +} diff --git a/tools/perf/util/trace-event.h b/tools/perf/util/trace-event.h index bce5b1d..b0af9c8 100644 --- a/tools/perf/util/trace-event.h +++ b/tools/perf/util/trace-event.h @@ -23,6 +23,8 @@ int trace_event__register_resolver(struct machine *machine, struct event_format* trace_event__tp_format(const char *sys, const char *name); +struct event_format *trace_event__tp_format_id(int id); + int bigendian(void); void event_format__fprintf(struct event_format *event, -- cgit v0.10.2 From ad4e3c04587c01c2e2b00c0e6a414dbededa6c55 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Sun, 10 Jul 2016 13:07:55 +0200 Subject: perf python: Init perf_event_attr::size in perf.evsel constructor Currently 0 is passed as perf_event_attr::size, which could block usage of new features. Signed-off-by: Jiri Olsa Cc: David Ahern Cc: Namhyung Kim Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1468148882-10362-4-git-send-email-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/util/python.c b/tools/perf/util/python.c index 65c6c73..d0c1267 100644 --- a/tools/perf/util/python.c +++ b/tools/perf/util/python.c @@ -653,6 +653,7 @@ static int pyrf_evsel__init(struct pyrf_evsel *pevsel, attr.precise_ip = precise_ip; attr.mmap_data = mmap_data; attr.sample_id_all = sample_id_all; + attr.size = sizeof(attr); perf_evsel__init(&pevsel->evsel, &attr, idx); return 0; -- cgit v0.10.2 From e8968e654191390a1300f0847250353a1c9da30d Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Sun, 10 Jul 2016 13:07:56 +0200 Subject: perf python: Fix pyrf_evlist__read_on_cpu event consuming We can't consume the event before parsing it. Under heavy load we could get caught by kernel writer overwriting the event we're trying to parse. Signed-off-by: Jiri Olsa Cc: David Ahern Cc: Namhyung Kim Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1468148882-10362-5-git-send-email-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/util/python.c b/tools/perf/util/python.c index d0c1267..c68ef03 100644 --- a/tools/perf/util/python.c +++ b/tools/perf/util/python.c @@ -865,12 +865,14 @@ static PyObject *pyrf_evlist__read_on_cpu(struct pyrf_evlist *pevlist, PyObject *pyevent = pyrf_event__new(event); struct pyrf_event *pevent = (struct pyrf_event *)pyevent; - perf_evlist__mmap_consume(evlist, cpu); - if (pyevent == NULL) return PyErr_NoMemory(); err = perf_evlist__parse_sample(evlist, event, &pevent->sample); + + /* Consume the even only after we parsed it out. */ + perf_evlist__mmap_consume(evlist, cpu); + if (err) return PyErr_Format(PyExc_OSError, "perf: can't parse sample, err=%d", err); -- cgit v0.10.2 From 85e37de3a993b9e407398f792b996acad27f4cdc Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Sun, 10 Jul 2016 13:07:57 +0200 Subject: perf python: Put perf.event objects into dictionary Make perf.event object parts of the perf module dictionary so we can address them by name. The following objects/names are added: mmap_event lost_event comm_event task_event throttle_event task_event read_event sample_event switch_event We can now use it in python script like: ... event = evlist.read_on_cpu(cpu) ... if not isinstance(event, perf.sample_event): Signed-off-by: Jiri Olsa Cc: David Ahern Cc: Namhyung Kim Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1468148882-10362-6-git-send-email-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/util/python.c b/tools/perf/util/python.c index c68ef03..fc277e4 100644 --- a/tools/perf/util/python.c +++ b/tools/perf/util/python.c @@ -1103,6 +1103,33 @@ PyMODINIT_FUNC initperf(void) Py_INCREF(&pyrf_evsel__type); PyModule_AddObject(module, "evsel", (PyObject*)&pyrf_evsel__type); + Py_INCREF(&pyrf_mmap_event__type); + PyModule_AddObject(module, "mmap_event", (PyObject *)&pyrf_mmap_event__type); + + Py_INCREF(&pyrf_lost_event__type); + PyModule_AddObject(module, "lost_event", (PyObject *)&pyrf_lost_event__type); + + Py_INCREF(&pyrf_comm_event__type); + PyModule_AddObject(module, "comm_event", (PyObject *)&pyrf_comm_event__type); + + Py_INCREF(&pyrf_task_event__type); + PyModule_AddObject(module, "task_event", (PyObject *)&pyrf_task_event__type); + + Py_INCREF(&pyrf_throttle_event__type); + PyModule_AddObject(module, "throttle_event", (PyObject *)&pyrf_throttle_event__type); + + Py_INCREF(&pyrf_task_event__type); + PyModule_AddObject(module, "task_event", (PyObject *)&pyrf_task_event__type); + + Py_INCREF(&pyrf_read_event__type); + PyModule_AddObject(module, "read_event", (PyObject *)&pyrf_read_event__type); + + Py_INCREF(&pyrf_sample_event__type); + PyModule_AddObject(module, "sample_event", (PyObject *)&pyrf_sample_event__type); + + Py_INCREF(&pyrf_context_switch_event__type); + PyModule_AddObject(module, "switch_event", (PyObject *)&pyrf_context_switch_event__type); + Py_INCREF(&pyrf_thread_map__type); PyModule_AddObject(module, "thread_map", (PyObject*)&pyrf_thread_map__type); -- cgit v0.10.2 From 1075fbb22f095c857930190e30fd3ae422d424b6 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Sun, 10 Jul 2016 13:07:58 +0200 Subject: perf python: Add perf.tracepoint method To get id of the tracepoint from subsystem and name strings. The interface is: id = perf.tracepoint(sys, name) In case of error -1 is returned. It will be used to get python tracepoint event's config value for tracepoint event. Signed-off-by: Jiri Olsa Cc: David Ahern Cc: Namhyung Kim Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1468148882-10362-7-git-send-email-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/util/python.c b/tools/perf/util/python.c index fc277e4..45fdd4a 100644 --- a/tools/perf/util/python.c +++ b/tools/perf/util/python.c @@ -2,6 +2,7 @@ #include #include #include +#include #include "evlist.h" #include "evsel.h" #include "event.h" @@ -1076,7 +1077,32 @@ static struct { { .name = NULL, }, }; +static PyObject *pyrf__tracepoint(struct pyrf_evsel *pevsel, + PyObject *args, PyObject *kwargs) +{ + struct event_format *tp_format; + static char *kwlist[] = { "sys", "name", NULL }; + char *sys = NULL; + char *name = NULL; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|ss", kwlist, + &sys, &name)) + return NULL; + + tp_format = trace_event__tp_format(sys, name); + if (IS_ERR(tp_format)) + return PyInt_FromLong(-1); + + return PyInt_FromLong(tp_format->id); +} + static PyMethodDef perf__methods[] = { + { + .ml_name = "tracepoint", + .ml_meth = (PyCFunction) pyrf__tracepoint, + .ml_flags = METH_VARARGS | METH_KEYWORDS, + .ml_doc = PyDoc_STR("Get tracepoint config.") + }, { .ml_name = NULL, } }; -- cgit v0.10.2 From 377f698db12150a1cf79987dca1d3990fa14a1f8 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Sun, 10 Jul 2016 13:07:59 +0200 Subject: perf python: Add struct evsel into struct pyrf_event To be able to find out event configuration info during sample parsing. Signed-off-by: Jiri Olsa Cc: David Ahern Cc: Namhyung Kim Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1468148882-10362-8-git-send-email-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/util/python.c b/tools/perf/util/python.c index 45fdd4a..dc7adaa 100644 --- a/tools/perf/util/python.c +++ b/tools/perf/util/python.c @@ -48,6 +48,7 @@ PyMODINIT_FUNC initperf(void); struct pyrf_event { PyObject_HEAD + struct perf_evsel *evsel; struct perf_sample sample; union perf_event event; }; @@ -865,11 +866,18 @@ static PyObject *pyrf_evlist__read_on_cpu(struct pyrf_evlist *pevlist, if (event != NULL) { PyObject *pyevent = pyrf_event__new(event); struct pyrf_event *pevent = (struct pyrf_event *)pyevent; + struct perf_evsel *evsel; if (pyevent == NULL) return PyErr_NoMemory(); - err = perf_evlist__parse_sample(evlist, event, &pevent->sample); + evsel = perf_evlist__event2evsel(evlist, event); + if (!evsel) + return Py_None; + + pevent->evsel = evsel; + + err = perf_evsel__parse_sample(evsel, event, &pevent->sample); /* Consume the even only after we parsed it out. */ perf_evlist__mmap_consume(evlist, cpu); -- cgit v0.10.2 From bae57e3825a3dded15f61cd20c6757d60ad6c712 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Sun, 10 Jul 2016 13:08:00 +0200 Subject: perf python: Add support to resolve tracepoint fields Adding tp_getattro callback for sample event. It resolves tracepoint fields in runtime. It's now possible to access tracepoint fields in normal fashion like hardcoded ones (see the example in the next patch). Reported-and-Tested-by: Jiri Pirko Signed-off-by: Jiri Olsa Cc: David Ahern Cc: Namhyung Kim Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1468148882-10362-9-git-send-email-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/util/python.c b/tools/perf/util/python.c index dc7adaa..d32f970 100644 --- a/tools/perf/util/python.c +++ b/tools/perf/util/python.c @@ -290,6 +290,97 @@ static PyObject *pyrf_sample_event__repr(struct pyrf_event *pevent) return ret; } +static bool is_tracepoint(struct pyrf_event *pevent) +{ + return pevent->evsel->attr.type == PERF_TYPE_TRACEPOINT; +} + +static int is_printable_array(char *p, unsigned int len) +{ + unsigned int i; + + for (i = 0; i < len; i++) { + if (!isprint(p[i]) && !isspace(p[i])) + return 0; + } + + return 1; +} + +static PyObject* +tracepoint_field(struct pyrf_event *pe, struct format_field *field) +{ + struct pevent *pevent = field->event->pevent; + void *data = pe->sample.raw_data; + PyObject *ret = NULL; + unsigned long long val; + unsigned int offset, len; + + if (field->flags & FIELD_IS_ARRAY) { + offset = field->offset; + len = field->size; + if (field->flags & FIELD_IS_DYNAMIC) { + val = pevent_read_number(pevent, data + offset, len); + offset = val; + len = offset >> 16; + offset &= 0xffff; + } + if (field->flags & FIELD_IS_STRING && + is_printable_array(data + offset, len)) { + ret = PyString_FromString((char *)data + offset); + } else { + ret = PyByteArray_FromStringAndSize((const char *) data + offset, len); + field->flags &= ~FIELD_IS_STRING; + } + } else { + val = pevent_read_number(pevent, data + field->offset, + field->size); + if (field->flags & FIELD_IS_POINTER) + ret = PyLong_FromUnsignedLong((unsigned long) val); + else if (field->flags & FIELD_IS_SIGNED) + ret = PyLong_FromLong((long) val); + else + ret = PyLong_FromUnsignedLong((unsigned long) val); + } + + return ret; +} + +static PyObject* +get_tracepoint_field(struct pyrf_event *pevent, PyObject *attr_name) +{ + const char *str = PyString_AsString(PyObject_Str(attr_name)); + struct perf_evsel *evsel = pevent->evsel; + struct format_field *field; + + if (!evsel->tp_format) { + struct event_format *tp_format; + + tp_format = trace_event__tp_format_id(evsel->attr.config); + if (!tp_format) + return NULL; + + evsel->tp_format = tp_format; + } + + field = pevent_find_any_field(evsel->tp_format, str); + if (!field) + return NULL; + + return tracepoint_field(pevent, field); +} + +static PyObject* +pyrf_sample_event__getattro(struct pyrf_event *pevent, PyObject *attr_name) +{ + PyObject *obj = NULL; + + if (is_tracepoint(pevent)) + obj = get_tracepoint_field(pevent, attr_name); + + return obj ?: PyObject_GenericGetAttr((PyObject *) pevent, attr_name); +} + static PyTypeObject pyrf_sample_event__type = { PyVarObject_HEAD_INIT(NULL, 0) .tp_name = "perf.sample_event", @@ -298,6 +389,7 @@ static PyTypeObject pyrf_sample_event__type = { .tp_doc = pyrf_sample_event__doc, .tp_members = pyrf_sample_event__members, .tp_repr = (reprfunc)pyrf_sample_event__repr, + .tp_getattro = (getattrofunc) pyrf_sample_event__getattro, }; static char pyrf_context_switch_event__doc[] = PyDoc_STR("perf context_switch event object."); -- cgit v0.10.2 From 9881d7df9dddef24e34949a4510245e156746c21 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Sun, 10 Jul 2016 13:08:01 +0200 Subject: perf python: Add tracepoint example To show how to enable a tracepoint and access its fields. Committer note: Testing it: # ls -l /tmp/build/perf/python/perf.so -rwxrwxr-x. 1 acme acme 1563256 Jul 12 16:19 /tmp/build/perf/python/perf.so # export PYTHONPATH=/tmp/build/perf/python/ # tools/perf/python/tracepoint.py 2> /dev/null | head -200 | tail -10 time 76345337296548 prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=0x0 ==> next_comm=tracepoint.py- next_pid=18479 next_prio=120 time 76345338520479 prev_comm=gnome-shelln-b prev_pid=2186 prev_prio=120 prev_state=0x1 ==> next_comm=swapper/1 next_pid=0 next_prio=120 time 76345337309942 prev_comm=tracepoint.py- prev_pid=18479 prev_prio=120 prev_state=0x1 ==> next_comm=swapper/0 next_pid=0 next_prio=120 time 76345337312302 prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=0x0 ==> next_comm=tracepoint.py- next_pid=18479 next_prio=120 time 76345337324927 prev_comm=tracepoint.py- prev_pid=18479 prev_prio=120 prev_state=0x1 ==> next_comm=swapper/0 next_pid=0 next_prio=120 time 76345337327115 prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=0x0 ==> next_comm=tracepoint.py- next_pid=18479 next_prio=120 time 76345338621750 prev_comm=swapper/2 prev_pid=0 prev_prio=120 prev_state=0x0 ==> next_comm=rcuos/2 next_pid=29 next_prio=120 time 76345338607922 prev_comm=swapper/3 prev_pid=0 prev_prio=120 prev_state=0x0 ==> next_comm=rcu_sched next_pid=7 next_prio=120 time 76345337338817 prev_comm=tracepoint.py- prev_pid=18479 prev_prio=120 prev_state=0x1 ==> next_comm=swapper/0 next_pid=0 next_prio=120 time 76345338627156 prev_comm=swapper/1 prev_pid=0 prev_prio=120 prev_state=0x0 ==> next_comm=head-terminal- next_pid=18480 next_prio=120 # # strip /tmp/build/perf/python/perf.so # ls -l /tmp/build/perf/python/perf.so -rwxrwxr-x. 1 acme acme 319616 Jul 12 16:25 /tmp/build/perf/python/perf.so Reported-and-Tested-by: Jiri Pirko Signed-off-by: Jiri Olsa Tested-by: Arnaldo Carvalho de Melo Cc: David Ahern Cc: Namhyung Kim Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1468148882-10362-10-git-send-email-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/python/tracepoint.py b/tools/perf/python/tracepoint.py new file mode 100755 index 0000000..eb4dbed --- /dev/null +++ b/tools/perf/python/tracepoint.py @@ -0,0 +1,47 @@ +#! /usr/bin/python +# -*- python -*- +# -*- coding: utf-8 -*- + +import perf + +class tracepoint(perf.evsel): + def __init__(self, sys, name): + config = perf.tracepoint(sys, name) + perf.evsel.__init__(self, + type = perf.TYPE_TRACEPOINT, + config = config, + freq = 0, sample_period = 1, wakeup_events = 1, + sample_type = perf.SAMPLE_PERIOD | perf.SAMPLE_TID | perf.SAMPLE_CPU | perf.SAMPLE_RAW | perf.SAMPLE_TIME) + +def main(): + tp = tracepoint("sched", "sched_switch") + cpus = perf.cpu_map() + threads = perf.thread_map(-1) + + evlist = perf.evlist(cpus, threads) + evlist.add(tp) + evlist.open() + evlist.mmap() + + while True: + evlist.poll(timeout = -1) + for cpu in cpus: + event = evlist.read_on_cpu(cpu) + if not event: + continue + + if not isinstance(event, perf.sample_event): + continue + + print "time %u prev_comm=%s prev_pid=%d prev_prio=%d prev_state=0x%x ==> next_comm=%s next_pid=%d next_prio=%d" % ( + event.sample_time, + event.prev_comm, + event.prev_pid, + event.prev_prio, + event.prev_state, + event.next_comm, + event.next_pid, + event.next_prio) + +if __name__ == '__main__': + main() -- cgit v0.10.2 From 6d248fbda59c51ef5f2e90e11551d9e17aeb226f Mon Sep 17 00:00:00 2001 From: Steven Rostedt Date: Tue, 12 Jul 2016 09:33:06 -0400 Subject: tools lib traceevent: Add filter on task CPU id Add a 'CPU' special field to allow the filter in trace-cmd report to filter on the task's CPU. By adding a special field 'CPU' (all caps) the user can now filter out tasks based on which CPU they are on. This is useful when filtering out (or in) a bunch of threads. -F 'CPU == 0' Signed-off-by: Steven Rostedt Cc: Andrew Morton Cc: Namhyung Kim Link: http://lkml.kernel.org/r/20160712093306.5b058103@gandalf.local.home Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/lib/traceevent/parse-filter.c b/tools/lib/traceevent/parse-filter.c index 88cccea..7c214ce 100644 --- a/tools/lib/traceevent/parse-filter.c +++ b/tools/lib/traceevent/parse-filter.c @@ -28,11 +28,16 @@ #include "event-utils.h" #define COMM "COMM" +#define CPU "CPU" static struct format_field comm = { .name = "COMM", }; +static struct format_field cpu = { + .name = "CPU", +}; + struct event_list { struct event_list *next; struct event_format *event; @@ -382,14 +387,17 @@ create_arg_item(struct event_format *event, const char *token, /* Consider this a field */ field = pevent_find_any_field(event, token); if (!field) { - if (strcmp(token, COMM) != 0) { + /* If token is 'COMM' or 'CPU' then it is special */ + if (strcmp(token, COMM) == 0) { + field = &comm; + } else if (strcmp(token, CPU) == 0) { + field = &cpu; + } else { /* not a field, Make it false */ arg->type = FILTER_ARG_BOOLEAN; arg->boolean.value = FILTER_FALSE; break; } - /* If token is 'COMM' then it is special */ - field = &comm; } arg->type = FILTER_ARG_FIELD; arg->field.field = field; @@ -1718,6 +1726,10 @@ get_value(struct event_format *event, return (unsigned long)name; } + /* Handle our dummy "cpu" field */ + if (field == &cpu) + return record->cpu; + pevent_read_number_field(field, record->data, &val); if (!(field->flags & FIELD_IS_SIGNED)) -- cgit v0.10.2 From 136ab0d0e10f29bdac3ee04bd0e9661073e15c80 Mon Sep 17 00:00:00 2001 From: Noam Camus Date: Tue, 12 Jul 2016 16:01:11 +0300 Subject: net: nps_enet: Fix PCS reset During commit b54b8c2d6e3c ("net: ezchip: adapt driver to little endian architecture") adapting to little endian architecture, zeroing of controller was left out. Signed-off-by: Elad Kanfi Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/ezchip/nps_enet.c b/drivers/net/ethernet/ezchip/nps_enet.c index 06f0317..9b7a3f5 100644 --- a/drivers/net/ethernet/ezchip/nps_enet.c +++ b/drivers/net/ethernet/ezchip/nps_enet.c @@ -285,6 +285,7 @@ static void nps_enet_hw_reset(struct net_device *ndev) ge_rst_value |= NPS_ENET_ENABLE << RST_GMAC_0_SHIFT; nps_enet_reg_set(priv, NPS_ENET_REG_GE_RST, ge_rst_value); usleep_range(10, 20); + ge_rst_value = 0; nps_enet_reg_set(priv, NPS_ENET_REG_GE_RST, ge_rst_value); /* Tx fifo reset sequence */ -- cgit v0.10.2 From 3d8f7a89a1979be7f631cf06e02f882adf144885 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Sun, 19 Jun 2016 20:34:57 -0700 Subject: hwmon: (tmp102) Improve handling of initial read delay If the chip was in shutdown mode when the driver was loaded, the first conversion is ready no more than 35 milli-seconds after the chip was taken out of shutdown. The driver delay was so far set to 333 ms (HZ / 3), which is much higher than the maximum time needed by the chip. Reduce the time to 35 milli-seconds. Introduce a 'valid' flag to ensure that sensor data is actually read even if requested less than 333 ms after the driver was loaded. Acked-by: Nishanth Menon Signed-off-by: Guenter Roeck diff --git a/drivers/hwmon/tmp102.c b/drivers/hwmon/tmp102.c index 5bdf262..fd4a451 100644 --- a/drivers/hwmon/tmp102.c +++ b/drivers/hwmon/tmp102.c @@ -13,6 +13,7 @@ * GNU General Public License for more details. */ +#include #include #include #include @@ -46,13 +47,16 @@ #define TMP102_TLOW_REG 0x02 #define TMP102_THIGH_REG 0x03 +#define CONVERSION_TIME_MS 35 /* in milli-seconds */ + struct tmp102 { struct i2c_client *client; struct mutex lock; u16 config_orig; unsigned long last_update; + unsigned long ready_time; + bool valid; int temp[3]; - bool first_time; }; /* convert left adjusted 13-bit TMP102 register value to milliCelsius */ @@ -73,13 +77,14 @@ static const u8 tmp102_reg[] = { TMP102_THIGH_REG, }; -static struct tmp102 *tmp102_update_device(struct device *dev) +static void tmp102_update_device(struct device *dev) { struct tmp102 *tmp102 = dev_get_drvdata(dev); struct i2c_client *client = tmp102->client; mutex_lock(&tmp102->lock); - if (time_after(jiffies, tmp102->last_update + HZ / 3)) { + if (!tmp102->valid || + time_after(jiffies, tmp102->last_update + HZ / 3)) { int i; for (i = 0; i < ARRAY_SIZE(tmp102->temp); ++i) { int status = i2c_smbus_read_word_swapped(client, @@ -88,22 +93,22 @@ static struct tmp102 *tmp102_update_device(struct device *dev) tmp102->temp[i] = tmp102_reg_to_mC(status); } tmp102->last_update = jiffies; - tmp102->first_time = false; + tmp102->valid = true; } mutex_unlock(&tmp102->lock); - return tmp102; } static int tmp102_read_temp(void *dev, int *temp) { - struct tmp102 *tmp102 = tmp102_update_device(dev); + struct tmp102 *tmp102 = dev_get_drvdata(dev); - /* Is it too early even to return a conversion? */ - if (tmp102->first_time) { + if (time_before(jiffies, tmp102->ready_time)) { dev_dbg(dev, "%s: Conversion not ready yet..\n", __func__); return -EAGAIN; } + tmp102_update_device(dev); + *temp = tmp102->temp[0]; return 0; @@ -114,12 +119,13 @@ static ssize_t tmp102_show_temp(struct device *dev, char *buf) { struct sensor_device_attribute *sda = to_sensor_dev_attr(attr); - struct tmp102 *tmp102 = tmp102_update_device(dev); + struct tmp102 *tmp102 = dev_get_drvdata(dev); - /* Is it too early even to return a read? */ - if (tmp102->first_time) + if (time_before(jiffies, tmp102->ready_time)) return -EAGAIN; + tmp102_update_device(dev); + return sprintf(buf, "%d\n", tmp102->temp[sda->index]); } @@ -224,11 +230,18 @@ static int tmp102_probe(struct i2c_client *client, dev_err(dev, "config settings did not stick\n"); return -ENODEV; } - tmp102->last_update = jiffies; - /* Mark that we are not ready with data until conversion is complete */ - tmp102->first_time = true; + mutex_init(&tmp102->lock); + tmp102->ready_time = jiffies; + if (tmp102->config_orig & TMP102_CONF_SD) { + /* + * Mark that we are not ready with data until the first + * conversion is complete + */ + tmp102->ready_time += msecs_to_jiffies(CONVERSION_TIME_MS); + } + hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name, tmp102, tmp102_groups); @@ -261,12 +274,15 @@ static int tmp102_suspend(struct device *dev) static int tmp102_resume(struct device *dev) { struct i2c_client *client = to_i2c_client(dev); + struct tmp102 *tmp102 = i2c_get_clientdata(client); int config; config = i2c_smbus_read_word_swapped(client, TMP102_CONF_REG); if (config < 0) return config; + tmp102->ready_time = jiffies + msecs_to_jiffies(CONVERSION_TIME_MS); + config &= ~TMP102_CONF_SD; return i2c_smbus_write_word_swapped(client, TMP102_CONF_REG, config); } -- cgit v0.10.2 From a9f92ccf334f7e15124193b1d7b89b7e6e6624e2 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Wed, 22 Jun 2016 10:01:57 -0700 Subject: hwmon: (tmp102) Rework chip configuration So far the chip was forced into polarity 0, even if it was preconfigured differently. Do not touch the polarity when configuring the chip. Also, the configuration register was read beack to check if the configuration 'sticks'. Ultimately, that is similar to checking if the chip is a tmp102 in the first place. Checking if a write into the configuration register was successful is really not the way to do it, and quite risky if the chip is not a tmp102, so drop that check. Instead, verify if the configuration register has unexpected bits set before writing into it. Acked-by: Nishanth Menon Signed-off-by: Guenter Roeck diff --git a/drivers/hwmon/tmp102.c b/drivers/hwmon/tmp102.c index fd4a451..82a8a29 100644 --- a/drivers/hwmon/tmp102.c +++ b/drivers/hwmon/tmp102.c @@ -47,6 +47,17 @@ #define TMP102_TLOW_REG 0x02 #define TMP102_THIGH_REG 0x03 +#define TMP102_CONFREG_MASK (TMP102_CONF_SD | TMP102_CONF_TM | \ + TMP102_CONF_POL | TMP102_CONF_F0 | \ + TMP102_CONF_F1 | TMP102_CONF_OS | \ + TMP102_CONF_EM | TMP102_CONF_AL | \ + TMP102_CONF_CR0 | TMP102_CONF_CR1) + +#define TMP102_CONFIG_CLEAR (TMP102_CONF_SD | TMP102_CONF_OS | \ + TMP102_CONF_CR0) +#define TMP102_CONFIG_SET (TMP102_CONF_TM | TMP102_CONF_EM | \ + TMP102_CONF_CR1) + #define CONVERSION_TIME_MS 35 /* in milli-seconds */ struct tmp102 { @@ -167,9 +178,6 @@ static struct attribute *tmp102_attrs[] = { }; ATTRIBUTE_GROUPS(tmp102); -#define TMP102_CONFIG (TMP102_CONF_TM | TMP102_CONF_EM | TMP102_CONF_CR1) -#define TMP102_CONFIG_RD_ONLY (TMP102_CONF_R0 | TMP102_CONF_R1 | TMP102_CONF_AL) - static const struct thermal_zone_of_device_ops tmp102_of_thermal_ops = { .get_temp = tmp102_read_temp, }; @@ -210,26 +218,25 @@ static int tmp102_probe(struct i2c_client *client, dev_err(dev, "error reading config register\n"); return status; } + + if ((status & ~TMP102_CONFREG_MASK) != + (TMP102_CONF_R0 | TMP102_CONF_R1)) { + dev_err(dev, "unexpected config register value\n"); + return -ENODEV; + } + tmp102->config_orig = status; devm_add_action(dev, tmp102_restore_config, tmp102); - status = i2c_smbus_write_word_swapped(client, TMP102_CONF_REG, - TMP102_CONFIG); + status &= ~TMP102_CONFIG_CLEAR; + status |= TMP102_CONFIG_SET; + + status = i2c_smbus_write_word_swapped(client, TMP102_CONF_REG, status); if (status < 0) { dev_err(dev, "error writing config register\n"); return status; } - status = i2c_smbus_read_word_swapped(client, TMP102_CONF_REG); - if (status < 0) { - dev_err(dev, "error reading config register\n"); - return status; - } - status &= ~TMP102_CONFIG_RD_ONLY; - if (status != TMP102_CONFIG) { - dev_err(dev, "config settings did not stick\n"); - return -ENODEV; - } mutex_init(&tmp102->lock); -- cgit v0.10.2 From 28a340db9043f11dfd092c1b8ea4043f59cc0ca1 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Mon, 20 Jun 2016 09:55:46 -0700 Subject: hwmon: (tmp102) Convert to use regmap, and drop local cache By converting the driver to regmap, we can use regmap to cache non-volatile registers. Stop caching the temperature register; while potentially reading it more often can result in reading it more often than necessary, this is offset by the gain due to not re-reading the limit registers. A positive side effect of this change is that limit registers can now be read and updated before the first temperature conversion is complete. Acked-by: Nishanth Menon Signed-off-by: Guenter Roeck diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index f271353..e72cd3d 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -1561,6 +1561,7 @@ config SENSORS_TMP102 tristate "Texas Instruments TMP102" depends on I2C depends on THERMAL || !THERMAL_OF + select REGMAP_I2C help If you say yes here you get support for Texas Instruments TMP102 sensor chips. diff --git a/drivers/hwmon/tmp102.c b/drivers/hwmon/tmp102.c index 82a8a29..a942a25 100644 --- a/drivers/hwmon/tmp102.c +++ b/drivers/hwmon/tmp102.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include @@ -61,13 +62,9 @@ #define CONVERSION_TIME_MS 35 /* in milli-seconds */ struct tmp102 { - struct i2c_client *client; - struct mutex lock; + struct regmap *regmap; u16 config_orig; - unsigned long last_update; unsigned long ready_time; - bool valid; - int temp[3]; }; /* convert left adjusted 13-bit TMP102 register value to milliCelsius */ @@ -82,45 +79,22 @@ static inline u16 tmp102_mC_to_reg(int val) return (val * 128) / 1000; } -static const u8 tmp102_reg[] = { - TMP102_TEMP_REG, - TMP102_TLOW_REG, - TMP102_THIGH_REG, -}; - -static void tmp102_update_device(struct device *dev) -{ - struct tmp102 *tmp102 = dev_get_drvdata(dev); - struct i2c_client *client = tmp102->client; - - mutex_lock(&tmp102->lock); - if (!tmp102->valid || - time_after(jiffies, tmp102->last_update + HZ / 3)) { - int i; - for (i = 0; i < ARRAY_SIZE(tmp102->temp); ++i) { - int status = i2c_smbus_read_word_swapped(client, - tmp102_reg[i]); - if (status > -1) - tmp102->temp[i] = tmp102_reg_to_mC(status); - } - tmp102->last_update = jiffies; - tmp102->valid = true; - } - mutex_unlock(&tmp102->lock); -} - static int tmp102_read_temp(void *dev, int *temp) { struct tmp102 *tmp102 = dev_get_drvdata(dev); + unsigned int reg; + int ret; if (time_before(jiffies, tmp102->ready_time)) { dev_dbg(dev, "%s: Conversion not ready yet..\n", __func__); return -EAGAIN; } - tmp102_update_device(dev); + ret = regmap_read(tmp102->regmap, TMP102_TEMP_REG, ®); + if (ret < 0) + return ret; - *temp = tmp102->temp[0]; + *temp = tmp102_reg_to_mC(reg); return 0; } @@ -131,13 +105,19 @@ static ssize_t tmp102_show_temp(struct device *dev, { struct sensor_device_attribute *sda = to_sensor_dev_attr(attr); struct tmp102 *tmp102 = dev_get_drvdata(dev); + int regaddr = sda->index; + unsigned int reg; + int err; - if (time_before(jiffies, tmp102->ready_time)) + if (regaddr == TMP102_TEMP_REG && + time_before(jiffies, tmp102->ready_time)) return -EAGAIN; - tmp102_update_device(dev); + err = regmap_read(tmp102->regmap, regaddr, ®); + if (err < 0) + return err; - return sprintf(buf, "%d\n", tmp102->temp[sda->index]); + return sprintf(buf, "%d\n", tmp102_reg_to_mC(reg)); } static ssize_t tmp102_set_temp(struct device *dev, @@ -146,29 +126,26 @@ static ssize_t tmp102_set_temp(struct device *dev, { struct sensor_device_attribute *sda = to_sensor_dev_attr(attr); struct tmp102 *tmp102 = dev_get_drvdata(dev); - struct i2c_client *client = tmp102->client; + int reg = sda->index; long val; - int status; + int err; if (kstrtol(buf, 10, &val) < 0) return -EINVAL; val = clamp_val(val, -256000, 255000); - mutex_lock(&tmp102->lock); - tmp102->temp[sda->index] = val; - status = i2c_smbus_write_word_swapped(client, tmp102_reg[sda->index], - tmp102_mC_to_reg(val)); - mutex_unlock(&tmp102->lock); - return status ? : count; + err = regmap_write(tmp102->regmap, reg, tmp102_mC_to_reg(val)); + return err ? : count; } -static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, tmp102_show_temp, NULL , 0); +static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, tmp102_show_temp, NULL, + TMP102_TEMP_REG); static SENSOR_DEVICE_ATTR(temp1_max_hyst, S_IWUSR | S_IRUGO, tmp102_show_temp, - tmp102_set_temp, 1); + tmp102_set_temp, TMP102_TLOW_REG); static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, tmp102_show_temp, - tmp102_set_temp, 2); + tmp102_set_temp, TMP102_THIGH_REG); static struct attribute *tmp102_attrs[] = { &sensor_dev_attr_temp1_input.dev_attr.attr, @@ -185,19 +162,39 @@ static const struct thermal_zone_of_device_ops tmp102_of_thermal_ops = { static void tmp102_restore_config(void *data) { struct tmp102 *tmp102 = data; - struct i2c_client *client = tmp102->client; - i2c_smbus_write_word_swapped(client, TMP102_CONF_REG, - tmp102->config_orig); + regmap_write(tmp102->regmap, TMP102_CONF_REG, tmp102->config_orig); +} + +static bool tmp102_is_writeable_reg(struct device *dev, unsigned int reg) +{ + return reg != TMP102_TEMP_REG; } +static bool tmp102_is_volatile_reg(struct device *dev, unsigned int reg) +{ + return reg == TMP102_TEMP_REG; +} + +static const struct regmap_config tmp102_regmap_config = { + .reg_bits = 8, + .val_bits = 16, + .max_register = TMP102_THIGH_REG, + .writeable_reg = tmp102_is_writeable_reg, + .volatile_reg = tmp102_is_volatile_reg, + .val_format_endian = REGMAP_ENDIAN_BIG, + .cache_type = REGCACHE_RBTREE, + .use_single_rw = true, +}; + static int tmp102_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct device *dev = &client->dev; struct device *hwmon_dev; struct tmp102 *tmp102; - int status; + unsigned int regval; + int err; if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WORD_DATA)) { @@ -211,35 +208,36 @@ static int tmp102_probe(struct i2c_client *client, return -ENOMEM; i2c_set_clientdata(client, tmp102); - tmp102->client = client; - status = i2c_smbus_read_word_swapped(client, TMP102_CONF_REG); - if (status < 0) { + tmp102->regmap = devm_regmap_init_i2c(client, &tmp102_regmap_config); + if (IS_ERR(tmp102->regmap)) + return PTR_ERR(tmp102->regmap); + + err = regmap_read(tmp102->regmap, TMP102_CONF_REG, ®val); + if (err < 0) { dev_err(dev, "error reading config register\n"); - return status; + return err; } - if ((status & ~TMP102_CONFREG_MASK) != + if ((regval & ~TMP102_CONFREG_MASK) != (TMP102_CONF_R0 | TMP102_CONF_R1)) { dev_err(dev, "unexpected config register value\n"); return -ENODEV; } - tmp102->config_orig = status; + tmp102->config_orig = regval; devm_add_action(dev, tmp102_restore_config, tmp102); - status &= ~TMP102_CONFIG_CLEAR; - status |= TMP102_CONFIG_SET; + regval &= ~TMP102_CONFIG_CLEAR; + regval |= TMP102_CONFIG_SET; - status = i2c_smbus_write_word_swapped(client, TMP102_CONF_REG, status); - if (status < 0) { + err = regmap_write(tmp102->regmap, TMP102_CONF_REG, regval); + if (err < 0) { dev_err(dev, "error writing config register\n"); - return status; + return err; } - mutex_init(&tmp102->lock); - tmp102->ready_time = jiffies; if (tmp102->config_orig & TMP102_CONF_SD) { /* @@ -268,30 +266,24 @@ static int tmp102_probe(struct i2c_client *client, static int tmp102_suspend(struct device *dev) { struct i2c_client *client = to_i2c_client(dev); - int config; - - config = i2c_smbus_read_word_swapped(client, TMP102_CONF_REG); - if (config < 0) - return config; + struct tmp102 *tmp102 = i2c_get_clientdata(client); - config |= TMP102_CONF_SD; - return i2c_smbus_write_word_swapped(client, TMP102_CONF_REG, config); + return regmap_update_bits(tmp102->regmap, TMP102_CONF_REG, + TMP102_CONF_SD, TMP102_CONF_SD); } static int tmp102_resume(struct device *dev) { struct i2c_client *client = to_i2c_client(dev); struct tmp102 *tmp102 = i2c_get_clientdata(client); - int config; + int err; - config = i2c_smbus_read_word_swapped(client, TMP102_CONF_REG); - if (config < 0) - return config; + err = regmap_update_bits(tmp102->regmap, TMP102_CONF_REG, + TMP102_CONF_SD, 0); tmp102->ready_time = jiffies + msecs_to_jiffies(CONVERSION_TIME_MS); - config &= ~TMP102_CONF_SD; - return i2c_smbus_write_word_swapped(client, TMP102_CONF_REG, config); + return err; } #endif /* CONFIG_PM */ -- cgit v0.10.2 From e066f89d0608236a72d8e9e13cef05005e8d1aea Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Sat, 2 Jul 2016 09:02:43 -0700 Subject: dt/bindings: Add bindings for JC-42.4 compatible temperature sensors Provide generic bindings for all Jedec JC-42.4 compatible temperature sensor chips. Acked-by: Rob Herring Signed-off-by: Guenter Roeck diff --git a/Documentation/devicetree/bindings/hwmon/jc42.txt b/Documentation/devicetree/bindings/hwmon/jc42.txt new file mode 100644 index 0000000..07a2504 --- /dev/null +++ b/Documentation/devicetree/bindings/hwmon/jc42.txt @@ -0,0 +1,42 @@ +Properties for Jedec JC-42.4 compatible temperature sensors + +Required properties: +- compatible: May include a device-specific string consisting of the + manufacturer and the name of the chip. A list of supported + chip names follows. + Must include "jedec,jc-42.4-temp" for any Jedec JC-42.4 + compatible temperature sensor. + + Supported chip names: + adi,adt7408 + atmel,at30ts00 + atmel,at30tse004 + onnn,cat6095 + onnn,cat34ts02 + maxim,max6604 + microchip,mcp9804 + microchip,mcp9805 + microchip,mcp9808 + microchip,mcp98243 + microchip,mcp98244 + microchip,mcp9843 + nxp,se97 + nxp,se98 + st,stts2002 + st,stts2004 + st,stts3000 + st,stts424 + st,stts424e + idt,tse2002 + idt,tse2004 + idt,ts3000 + idt,ts3001 + +- reg: I2C address + +Example: + +temp-sensor@1a { + compatible = "jedec,jc-42.4-temp"; + reg = <0x1a>; +}; -- cgit v0.10.2 From 803deccec2513379ff0873a386d955af6f43d005 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Sat, 2 Jul 2016 09:05:48 -0700 Subject: hwmon: (jc42) Add support for generic JC-42.4 devicetree binding With this change, JC-42.4 compatible temperature sensors can be configured in devicetree by providing a generic "jedec,jc-42.4-temp" binding. Signed-off-by: Guenter Roeck diff --git a/drivers/hwmon/jc42.c b/drivers/hwmon/jc42.c index d9c4f78..9d5f85f 100644 --- a/drivers/hwmon/jc42.c +++ b/drivers/hwmon/jc42.c @@ -31,6 +31,7 @@ #include #include #include +#include /* Addresses to scan */ static const unsigned short normal_i2c[] = { @@ -541,11 +542,20 @@ static const struct i2c_device_id jc42_id[] = { }; MODULE_DEVICE_TABLE(i2c, jc42_id); +#ifdef CONFIG_OF +static const struct of_device_id jc42_of_ids[] = { + { .compatible = "jedec,jc-42.4-temp", }, + { } +}; +MODULE_DEVICE_TABLE(of, jc42_of_ids); +#endif + static struct i2c_driver jc42_driver = { .class = I2C_CLASS_SPD | I2C_CLASS_HWMON, .driver = { .name = "jc42", .pm = JC42_DEV_PM_OPS, + .of_match_table = of_match_ptr(jc42_of_ids), }, .probe = jc42_probe, .remove = jc42_remove, -- cgit v0.10.2 From 386512d18b268c6182903239f9f3390f03ce4c7b Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Tue, 12 Jul 2016 16:04:35 -0700 Subject: net: ethoc: Fix early error paths In case any operation fails before we can successfully go the point where we would register a MDIO bus, we would be going to an error label which involves unregistering then freeing this yet to be created MDIO bus. Update all error paths to go to label free which is the only one valid until either the clock is enabled, or the MDIO bus is allocated and registered. This fixes kernel oops observed while trying to dereference the MDIO bus structure which is not yet allocated. Fixes: a1702857724f ("net: Add support for the OpenCores 10/100 Mbps Ethernet MAC.") Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/ethoc.c b/drivers/net/ethernet/ethoc.c index 4edb98c..06ae14a 100644 --- a/drivers/net/ethernet/ethoc.c +++ b/drivers/net/ethernet/ethoc.c @@ -1086,7 +1086,7 @@ static int ethoc_probe(struct platform_device *pdev) if (!priv->iobase) { dev_err(&pdev->dev, "cannot remap I/O memory space\n"); ret = -ENXIO; - goto error; + goto free; } if (netdev->mem_end) { @@ -1095,7 +1095,7 @@ static int ethoc_probe(struct platform_device *pdev) if (!priv->membase) { dev_err(&pdev->dev, "cannot remap memory space\n"); ret = -ENXIO; - goto error; + goto free; } } else { /* Allocate buffer memory */ @@ -1106,7 +1106,7 @@ static int ethoc_probe(struct platform_device *pdev) dev_err(&pdev->dev, "cannot allocate %dB buffer\n", buffer_size); ret = -ENOMEM; - goto error; + goto free; } netdev->mem_end = netdev->mem_start + buffer_size; priv->dma_alloc = buffer_size; @@ -1120,7 +1120,7 @@ static int ethoc_probe(struct platform_device *pdev) 128, (netdev->mem_end - netdev->mem_start + 1) / ETHOC_BUFSIZ); if (num_bd < 4) { ret = -ENODEV; - goto error; + goto free; } priv->num_bd = num_bd; /* num_tx must be a power of two */ @@ -1133,7 +1133,7 @@ static int ethoc_probe(struct platform_device *pdev) priv->vma = devm_kzalloc(&pdev->dev, num_bd*sizeof(void *), GFP_KERNEL); if (!priv->vma) { ret = -ENOMEM; - goto error; + goto free; } /* Allow the platform setup code to pass in a MAC address. */ -- cgit v0.10.2 From ee6c21b9c11ad96318160f9a504a3fac2114ddca Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Tue, 12 Jul 2016 16:04:36 -0700 Subject: net: ethoc: Correctly pad short packets Even though the hardware can be doing zero padding, we want the SKB to be going out on the wire with the appropriate size. This fixes packet truncations observed with e.g: ARP packets. Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/ethoc.c b/drivers/net/ethernet/ethoc.c index 06ae14a..4466a11 100644 --- a/drivers/net/ethernet/ethoc.c +++ b/drivers/net/ethernet/ethoc.c @@ -860,6 +860,11 @@ static netdev_tx_t ethoc_start_xmit(struct sk_buff *skb, struct net_device *dev) unsigned int entry; void *dest; + if (skb_put_padto(skb, ETHOC_ZLEN)) { + dev->stats.tx_errors++; + goto out_no_free; + } + if (unlikely(skb->len > ETHOC_BUFSIZ)) { dev->stats.tx_errors++; goto out; @@ -894,6 +899,7 @@ static netdev_tx_t ethoc_start_xmit(struct sk_buff *skb, struct net_device *dev) skb_tx_timestamp(skb); out: dev_kfree_skb(skb); +out_no_free: return NETDEV_TX_OK; } -- cgit v0.10.2 From 707a605b5a1732e548f4ff51ccf0199a14d95f0f Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 12 Jul 2016 14:04:22 +0300 Subject: x86/pci: Use MRFLD abbreviation for Merrifield Everywhere in the kernel the MRFLD is used as abbreviation of Intel Merrifield. Do the same in intel_mid_pci.c module. Signed-off-by: Andy Shevchenko Cc: Bjorn Helgaas Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/1468321462-136016-1-git-send-email-andriy.shevchenko@linux.intel.com Signed-off-by: Ingo Molnar diff --git a/arch/x86/pci/intel_mid_pci.c b/arch/x86/pci/intel_mid_pci.c index 5413d6a..5a18aed 100644 --- a/arch/x86/pci/intel_mid_pci.c +++ b/arch/x86/pci/intel_mid_pci.c @@ -36,8 +36,8 @@ #define PCIE_CAP_OFFSET 0x100 /* Quirks for the listed devices */ -#define PCI_DEVICE_ID_INTEL_MRFL_MMC 0x1190 -#define PCI_DEVICE_ID_INTEL_MRFL_HSU 0x1191 +#define PCI_DEVICE_ID_INTEL_MRFLD_MMC 0x1190 +#define PCI_DEVICE_ID_INTEL_MRFLD_HSU 0x1191 /* Fixed BAR fields */ #define PCIE_VNDR_CAP_ID_FIXED_BAR 0x00 /* Fixed BAR (TBD) */ @@ -229,7 +229,7 @@ static int intel_mid_pci_irq_enable(struct pci_dev *dev) * Skip HS UART common registers device since it has * IRQ0 assigned and not used by the kernel. */ - if (dev->device == PCI_DEVICE_ID_INTEL_MRFL_HSU) + if (dev->device == PCI_DEVICE_ID_INTEL_MRFLD_HSU) return -EBUSY; /* * TNG has IRQ0 assigned to eMMC controller. But there @@ -238,7 +238,7 @@ static int intel_mid_pci_irq_enable(struct pci_dev *dev) * eMMC gets it. The rest of devices still could be * enabled without interrupt line being allocated. */ - if (dev->device != PCI_DEVICE_ID_INTEL_MRFL_MMC) + if (dev->device != PCI_DEVICE_ID_INTEL_MRFLD_MMC) return 0; } break; -- cgit v0.10.2 From 05f310e26fe9d97fec0ce1752edc16bf1ea55a2d Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 12 Jul 2016 14:16:32 +0300 Subject: x86/sfi: Enable enumeration of SD devices SFI specification v0.8.2 defines type of devices which are connected to SD bus. In particularly WiFi dongle is a such. Add a callback to enumerate the devices connected to SD bus. Signed-off-by: Andy Shevchenko Cc: Bjorn Helgaas Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/1468322192-62080-1-git-send-email-andriy.shevchenko@linux.intel.com Signed-off-by: Ingo Molnar diff --git a/arch/x86/include/asm/intel-mid.h b/arch/x86/include/asm/intel-mid.h index 59013a2..9d6b097 100644 --- a/arch/x86/include/asm/intel-mid.h +++ b/arch/x86/include/asm/intel-mid.h @@ -49,6 +49,21 @@ struct devs_id { static const struct devs_id *const __intel_mid_sfi_##i##_dev __used \ __attribute__((__section__(".x86_intel_mid_dev.init"))) = &i +/** +* struct mid_sd_board_info - template for SD device creation +* @name: identifies the driver +* @bus_num: board-specific identifier for a given SD controller +* @max_clk: the maximum frequency device supports +* @platform_data: the particular data stored there is driver-specific +*/ +struct mid_sd_board_info { + char name[SFI_NAME_LEN]; + int bus_num; + unsigned short addr; + u32 max_clk; + void *platform_data; +}; + /* * Medfield is the follow-up of Moorestown, it combines two chip solution into * one. Other than that it also added always-on and constant tsc and lapic diff --git a/arch/x86/platform/intel-mid/sfi.c b/arch/x86/platform/intel-mid/sfi.c index 5ee360a..1555672 100644 --- a/arch/x86/platform/intel-mid/sfi.c +++ b/arch/x86/platform/intel-mid/sfi.c @@ -407,6 +407,32 @@ static void __init sfi_handle_i2c_dev(struct sfi_device_table_entry *pentry, i2c_register_board_info(pentry->host_num, &i2c_info, 1); } +static void __init sfi_handle_sd_dev(struct sfi_device_table_entry *pentry, + struct devs_id *dev) +{ + struct mid_sd_board_info sd_info; + void *pdata; + + memset(&sd_info, 0, sizeof(sd_info)); + strncpy(sd_info.name, pentry->name, SFI_NAME_LEN); + sd_info.bus_num = pentry->host_num; + sd_info.max_clk = pentry->max_freq; + sd_info.addr = pentry->addr; + pr_debug("SD bus = %d, name = %16.16s, max_clk = %d, addr = 0x%x\n", + sd_info.bus_num, + sd_info.name, + sd_info.max_clk, + sd_info.addr); + pdata = intel_mid_sfi_get_pdata(dev, &sd_info); + if (IS_ERR(pdata)) + return; + + /* Nothing we can do with this for now */ + sd_info.platform_data = pdata; + + pr_debug("Successfully registered %16.16s", sd_info.name); +} + extern struct devs_id *const __x86_intel_mid_dev_start[], *const __x86_intel_mid_dev_end[]; @@ -490,6 +516,9 @@ static int __init sfi_parse_devs(struct sfi_table_header *table) case SFI_DEV_TYPE_I2C: sfi_handle_i2c_dev(pentry, dev); break; + case SFI_DEV_TYPE_SD: + sfi_handle_sd_dev(pentry, dev); + break; case SFI_DEV_TYPE_UART: case SFI_DEV_TYPE_HSI: default: diff --git a/include/linux/sfi.h b/include/linux/sfi.h index d9b436f..e0e1597 100644 --- a/include/linux/sfi.h +++ b/include/linux/sfi.h @@ -156,6 +156,7 @@ struct sfi_device_table_entry { #define SFI_DEV_TYPE_UART 2 #define SFI_DEV_TYPE_HSI 3 #define SFI_DEV_TYPE_IPC 4 +#define SFI_DEV_TYPE_SD 5 u8 host_num; /* attached to host 0, 1...*/ u16 addr; -- cgit v0.10.2 From a7c734140aa36413944eef0f8c660e0e2256357d Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Tue, 12 Jul 2016 21:59:23 +0200 Subject: cpu/hotplug: Keep enough storage space if SMP=n to avoid array out of bounds scribble Xiaolong Ye reported lock debug warnings triggered by the following commit: 8de4a0066106 ("perf/x86: Convert the core to the hotplug state machine") The bug is the following: the cpuhp_bp_states[] array is cut short when CONFIG_SMP=n, but the dynamically registered callbacks are stored nevertheless and happily scribble outside of the array bounds... We need to store them in case that the state is unregistered so we can invoke the teardown function. That's independent of CONFIG_SMP. Make sure the array is large enough. Reported-by: kernel test robot Signed-off-by: Thomas Gleixner Cc: Adam Borowski Cc: Alexander Shishkin Cc: Anna-Maria Gleixner Cc: Arnaldo Carvalho de Melo Cc: Arnaldo Carvalho de Melo Cc: Borislav Petkov Cc: Jiri Olsa Cc: Kan Liang Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Sebastian Andrzej Siewior Cc: Stephane Eranian Cc: Vince Weaver Cc: lkp@01.org Cc: stable@vger.kernel.org Cc: tipbuild@zytor.com Fixes: cff7d378d3fd "cpu/hotplug: Convert to a state machine for the control processor" Link: http://lkml.kernel.org/r/alpine.DEB.2.11.1607122144560.4083@nanos Signed-off-by: Ingo Molnar diff --git a/kernel/cpu.c b/kernel/cpu.c index d948e44..7b61887 100644 --- a/kernel/cpu.c +++ b/kernel/cpu.c @@ -1201,6 +1201,8 @@ static struct cpuhp_step cpuhp_bp_states[] = { .teardown = takedown_cpu, .cant_stop = true, }, +#else + [CPUHP_BRINGUP_CPU] = { }, #endif }; -- cgit v0.10.2 From 7b39cafb7aa68ef8e32a9f51fbe737d96084ca74 Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Wed, 13 Jul 2016 09:37:43 +0200 Subject: tools: Work around BITS_PER_LONG related build failure in objtool The objtool build fails with the recent changes to the bits-per-long headers: tools/include/linux/bitops.h:12:0: error: "BITS_PER_LONG" redefined [-Werror] Which got introduced by: bb9707077b4e tools: Copy the bitsperlong.h files from the kernel Work it around for the time being. Cc: Arnaldo Carvalho de Melo Cc: Josh Poimboeuf Cc: linux-kernel@vger.kernel.org Signed-off-by: Ingo Molnar diff --git a/tools/include/linux/bitops.h b/tools/include/linux/bitops.h index 5ad9ee1..49c929a 100644 --- a/tools/include/linux/bitops.h +++ b/tools/include/linux/bitops.h @@ -9,7 +9,9 @@ #define __WORDSIZE (__SIZEOF_LONG__ * 8) #endif -#define BITS_PER_LONG __WORDSIZE +#ifndef BITS_PER_LONG +# define BITS_PER_LONG __WORDSIZE +#endif #define BIT_MASK(nr) (1UL << ((nr) % BITS_PER_LONG)) #define BIT_WORD(nr) ((nr) / BITS_PER_LONG) -- cgit v0.10.2 From 00839ee3b299303c6a5e26a0a2485427a3afcbbf Mon Sep 17 00:00:00 2001 From: Dave Hansen Date: Thu, 7 Jul 2016 17:19:11 -0700 Subject: x86/mm: Move swap offset/type up in PTE to work around erratum This erratum can result in Accessed/Dirty getting set by the hardware when we do not expect them to be (on !Present PTEs). Instead of trying to fix them up after this happens, we just allow the bits to get set and try to ignore them. We do this by shifting the layout of the bits we use for swap offset/type in our 64-bit PTEs. It looks like this: bitnrs: | ... | 11| 10| 9|8|7|6|5| 4| 3|2|1|0| names: | ... |SW3|SW2|SW1|G|L|D|A|CD|WT|U|W|P| before: | OFFSET (9-63) |0|X|X| TYPE(1-5) |0| after: | OFFSET (14-63) | TYPE (9-13) |0|X|X|X| X| X|X|X|0| Note that D was already a don't care (X) even before. We just move TYPE up and turn its old spot (which could be hit by the A bit) into all don't cares. We take 5 bits away from the offset, but that still leaves us with 50 bits which lets us index into a 62-bit swapfile (4 EiB). I think that's probably fine for the moment. We could theoretically reclaim 5 of the bits (1, 2, 3, 4, 7) but it doesn't gain us anything. Signed-off-by: Dave Hansen Cc: Andrew Morton Cc: Andy Lutomirski Cc: Borislav Petkov Cc: Brian Gerst Cc: Dave Hansen Cc: Denys Vlasenko Cc: H. Peter Anvin Cc: Josh Poimboeuf Cc: Linus Torvalds Cc: Luis R. Rodriguez Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: Toshi Kani Cc: dave.hansen@intel.com Cc: linux-mm@kvack.org Cc: mhocko@suse.com Link: http://lkml.kernel.org/r/20160708001911.9A3FD2B6@viggo.jf.intel.com Signed-off-by: Ingo Molnar diff --git a/arch/x86/include/asm/pgtable_64.h b/arch/x86/include/asm/pgtable_64.h index 2ee7811..7e8ec7a 100644 --- a/arch/x86/include/asm/pgtable_64.h +++ b/arch/x86/include/asm/pgtable_64.h @@ -140,18 +140,32 @@ static inline int pgd_large(pgd_t pgd) { return 0; } #define pte_offset_map(dir, address) pte_offset_kernel((dir), (address)) #define pte_unmap(pte) ((void)(pte))/* NOP */ -/* Encode and de-code a swap entry */ +/* + * Encode and de-code a swap entry + * + * | ... | 11| 10| 9|8|7|6|5| 4| 3|2|1|0| <- bit number + * | ... |SW3|SW2|SW1|G|L|D|A|CD|WT|U|W|P| <- bit names + * | OFFSET (14->63) | TYPE (10-13) |0|X|X|X| X| X|X|X|0| <- swp entry + * + * G (8) is aliased and used as a PROT_NONE indicator for + * !present ptes. We need to start storing swap entries above + * there. We also need to avoid using A and D because of an + * erratum where they can be incorrectly set by hardware on + * non-present PTEs. + */ +#define SWP_TYPE_FIRST_BIT (_PAGE_BIT_PROTNONE + 1) #define SWP_TYPE_BITS 5 -#define SWP_OFFSET_SHIFT (_PAGE_BIT_PROTNONE + 1) +/* Place the offset above the type: */ +#define SWP_OFFSET_FIRST_BIT (SWP_TYPE_FIRST_BIT + SWP_TYPE_BITS + 1) #define MAX_SWAPFILES_CHECK() BUILD_BUG_ON(MAX_SWAPFILES_SHIFT > SWP_TYPE_BITS) -#define __swp_type(x) (((x).val >> (_PAGE_BIT_PRESENT + 1)) \ +#define __swp_type(x) (((x).val >> (SWP_TYPE_FIRST_BIT)) \ & ((1U << SWP_TYPE_BITS) - 1)) -#define __swp_offset(x) ((x).val >> SWP_OFFSET_SHIFT) +#define __swp_offset(x) ((x).val >> SWP_OFFSET_FIRST_BIT) #define __swp_entry(type, offset) ((swp_entry_t) { \ - ((type) << (_PAGE_BIT_PRESENT + 1)) \ - | ((offset) << SWP_OFFSET_SHIFT) }) + ((type) << (SWP_TYPE_FIRST_BIT)) \ + | ((offset) << SWP_OFFSET_FIRST_BIT) }) #define __pte_to_swp_entry(pte) ((swp_entry_t) { pte_val((pte)) }) #define __swp_entry_to_pte(x) ((pte_t) { .pte = (x).val }) -- cgit v0.10.2 From 97e3c602ccbdd7db54e92fe05675c664c052a466 Mon Sep 17 00:00:00 2001 From: Dave Hansen Date: Thu, 7 Jul 2016 17:19:12 -0700 Subject: x86/mm: Ignore A/D bits in pte/pmd/pud_none() The erratum we are fixing here can lead to stray setting of the A and D bits. That means that a pte that we cleared might suddenly have A/D set. So, stop considering those bits when determining if a pte is pte_none(). The same goes for the other pmd_none() and pud_none(). pgd_none() can be skipped because it is not affected; we do not use PGD entries for anything other than pagetables on affected configurations. This adds a tiny amount of overhead to all pte_none() checks. I doubt we'll be able to measure it anywhere. Signed-off-by: Dave Hansen Cc: Andrew Morton Cc: Andy Lutomirski Cc: Borislav Petkov Cc: Brian Gerst Cc: Dave Hansen Cc: Denys Vlasenko Cc: H. Peter Anvin Cc: Josh Poimboeuf Cc: Linus Torvalds Cc: Luis R. Rodriguez Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: Toshi Kani Cc: dave.hansen@intel.com Cc: linux-mm@kvack.org Cc: mhocko@suse.com Link: http://lkml.kernel.org/r/20160708001912.5216F89C@viggo.jf.intel.com Signed-off-by: Ingo Molnar diff --git a/arch/x86/include/asm/pgtable.h b/arch/x86/include/asm/pgtable.h index 1a27396..2815d26 100644 --- a/arch/x86/include/asm/pgtable.h +++ b/arch/x86/include/asm/pgtable.h @@ -480,7 +480,7 @@ pte_t *populate_extra_pte(unsigned long vaddr); static inline int pte_none(pte_t pte) { - return !pte.pte; + return !(pte.pte & ~(_PAGE_KNL_ERRATUM_MASK)); } #define __HAVE_ARCH_PTE_SAME @@ -552,7 +552,8 @@ static inline int pmd_none(pmd_t pmd) { /* Only check low word on 32-bit platforms, since it might be out of sync with upper half. */ - return (unsigned long)native_pmd_val(pmd) == 0; + unsigned long val = native_pmd_val(pmd); + return (val & ~_PAGE_KNL_ERRATUM_MASK) == 0; } static inline unsigned long pmd_page_vaddr(pmd_t pmd) @@ -616,7 +617,7 @@ static inline unsigned long pages_to_mb(unsigned long npg) #if CONFIG_PGTABLE_LEVELS > 2 static inline int pud_none(pud_t pud) { - return native_pud_val(pud) == 0; + return (native_pud_val(pud) & ~(_PAGE_KNL_ERRATUM_MASK)) == 0; } static inline int pud_present(pud_t pud) @@ -694,6 +695,12 @@ static inline int pgd_bad(pgd_t pgd) static inline int pgd_none(pgd_t pgd) { + /* + * There is no need to do a workaround for the KNL stray + * A/D bit erratum here. PGDs only point to page tables + * except on 32-bit non-PAE which is not supported on + * KNL. + */ return !native_pgd_val(pgd); } #endif /* CONFIG_PGTABLE_LEVELS > 3 */ diff --git a/arch/x86/include/asm/pgtable_types.h b/arch/x86/include/asm/pgtable_types.h index 7b5efe2..d14d0a5 100644 --- a/arch/x86/include/asm/pgtable_types.h +++ b/arch/x86/include/asm/pgtable_types.h @@ -70,6 +70,12 @@ _PAGE_PKEY_BIT2 | \ _PAGE_PKEY_BIT3) +#if defined(CONFIG_X86_64) || defined(CONFIG_X86_PAE) +#define _PAGE_KNL_ERRATUM_MASK (_PAGE_DIRTY | _PAGE_ACCESSED) +#else +#define _PAGE_KNL_ERRATUM_MASK 0 +#endif + #ifdef CONFIG_KMEMCHECK #define _PAGE_HIDDEN (_AT(pteval_t, 1) << _PAGE_BIT_HIDDEN) #else -- cgit v0.10.2 From e4a84be6f05eab4778732d799f63b3cd15427885 Mon Sep 17 00:00:00 2001 From: Dave Hansen Date: Thu, 7 Jul 2016 17:19:14 -0700 Subject: x86/mm: Disallow running with 32-bit PTEs to work around erratum The Intel(R) Xeon Phi(TM) Processor x200 Family (codename: Knights Landing) has an erratum where a processor thread setting the Accessed or Dirty bits may not do so atomically against its checks for the Present bit. This may cause a thread (which is about to page fault) to set A and/or D, even though the Present bit had already been atomically cleared. These bits are truly "stray". In the case of the Dirty bit, the thread associated with the stray set was *not* allowed to write to the page. This means that we do not have to launder the bit(s); we can simply ignore them. If the PTE is used for storing a swap index or a NUMA migration index, the A bit could be misinterpreted as part of the swap type. The stray bits being set cause a software-cleared PTE to be interpreted as a swap entry. In some cases (like when the swap index ends up being for a non-existent swapfile), the kernel detects the stray value and WARN()s about it, but there is no guarantee that the kernel can always detect it. When we have 64-bit PTEs (64-bit mode or 32-bit PAE), we were able to move the swap PTE format around to avoid these troublesome bits. But, 32-bit non-PAE is tight on bits. So, disallow it from running on this hardware. I can't imagine anyone wanting to run 32-bit non-highmem kernels on this hardware, but disallowing them from running entirely is surely the safe thing to do. Signed-off-by: Dave Hansen Cc: Andrew Morton Cc: Andy Lutomirski Cc: Borislav Petkov Cc: Brian Gerst Cc: Dave Hansen Cc: Denys Vlasenko Cc: H. Peter Anvin Cc: Josh Poimboeuf Cc: Linus Torvalds Cc: Luis R. Rodriguez Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: Toshi Kani Cc: dave.hansen@intel.com Cc: linux-mm@kvack.org Cc: mhocko@suse.com Link: http://lkml.kernel.org/r/20160708001914.D0B50110@viggo.jf.intel.com Signed-off-by: Ingo Molnar diff --git a/arch/x86/boot/boot.h b/arch/x86/boot/boot.h index 9011a88..a5ce666 100644 --- a/arch/x86/boot/boot.h +++ b/arch/x86/boot/boot.h @@ -294,6 +294,7 @@ static inline int cmdline_find_option_bool(const char *option) /* cpu.c, cpucheck.c */ int check_cpu(int *cpu_level_ptr, int *req_level_ptr, u32 **err_flags_ptr); +int check_knl_erratum(void); int validate_cpu(void); /* early_serial_console.c */ diff --git a/arch/x86/boot/cpu.c b/arch/x86/boot/cpu.c index 29207f6..26240dd 100644 --- a/arch/x86/boot/cpu.c +++ b/arch/x86/boot/cpu.c @@ -93,6 +93,8 @@ int validate_cpu(void) show_cap_strs(err_flags); putchar('\n'); return -1; + } else if (check_knl_erratum()) { + return -1; } else { return 0; } diff --git a/arch/x86/boot/cpucheck.c b/arch/x86/boot/cpucheck.c index 1fd7d57..4ad7d70 100644 --- a/arch/x86/boot/cpucheck.c +++ b/arch/x86/boot/cpucheck.c @@ -24,6 +24,7 @@ # include "boot.h" #endif #include +#include #include #include #include @@ -175,6 +176,8 @@ int check_cpu(int *cpu_level_ptr, int *req_level_ptr, u32 **err_flags_ptr) puts("WARNING: PAE disabled. Use parameter 'forcepae' to enable at your own risk!\n"); } } + if (!err) + err = check_knl_erratum(); if (err_flags_ptr) *err_flags_ptr = err ? err_flags : NULL; @@ -185,3 +188,33 @@ int check_cpu(int *cpu_level_ptr, int *req_level_ptr, u32 **err_flags_ptr) return (cpu.level < req_level || err) ? -1 : 0; } + +int check_knl_erratum(void) +{ + /* + * First check for the affected model/family: + */ + if (!is_intel() || + cpu.family != 6 || + cpu.model != INTEL_FAM6_XEON_PHI_KNL) + return 0; + + /* + * This erratum affects the Accessed/Dirty bits, and can + * cause stray bits to be set in !Present PTEs. We have + * enough bits in our 64-bit PTEs (which we have on real + * 64-bit mode or PAE) to avoid using these troublesome + * bits. But, we do not have enough space in our 32-bit + * PTEs. So, refuse to run on 32-bit non-PAE kernels. + */ + if (IS_ENABLED(CONFIG_X86_64) || IS_ENABLED(CONFIG_X86_PAE)) + return 0; + + puts("This 32-bit kernel can not run on this Xeon Phi x200\n" + "processor due to a processor erratum. Use a 64-bit\n" + "kernel, or enable PAE in this 32-bit kernel.\n\n"); + + return -1; +} + + diff --git a/arch/x86/boot/cpuflags.c b/arch/x86/boot/cpuflags.c index 431fa5f..6687ab9 100644 --- a/arch/x86/boot/cpuflags.c +++ b/arch/x86/boot/cpuflags.c @@ -102,6 +102,7 @@ void get_cpuflags(void) cpuid(0x1, &tfms, &ignored, &cpu.flags[4], &cpu.flags[0]); cpu.level = (tfms >> 8) & 15; + cpu.family = cpu.level; cpu.model = (tfms >> 4) & 15; if (cpu.level >= 6) cpu.model += ((tfms >> 16) & 0xf) << 4; diff --git a/arch/x86/boot/cpuflags.h b/arch/x86/boot/cpuflags.h index 4cb404f..15ad56a 100644 --- a/arch/x86/boot/cpuflags.h +++ b/arch/x86/boot/cpuflags.h @@ -6,6 +6,7 @@ struct cpu_features { int level; /* Family, or 64 for x86-64 */ + int family; /* Family, always */ int model; u32 flags[NCAPINTS]; }; -- cgit v0.10.2 From dcb32d9913b7ed527b135a7e221f8d14b67bb952 Mon Sep 17 00:00:00 2001 From: Dave Hansen Date: Thu, 7 Jul 2016 17:19:15 -0700 Subject: x86/mm: Use pte_none() to test for empty PTE The page table manipulation code seems to have grown a couple of sites that are looking for empty PTEs. Just in case one of these entries got a stray bit set, use pte_none() instead of checking for a zero pte_val(). The use pte_same() makes me a bit nervous. If we were doing a pte_same() check against two cleared entries and one of them had a stray bit set, it might fail the pte_same() check. But, I don't think we ever _do_ pte_same() for cleared entries. It is almost entirely used for checking for races in fault-in paths. Signed-off-by: Dave Hansen Cc: Andrew Morton Cc: Andy Lutomirski Cc: Borislav Petkov Cc: Brian Gerst Cc: Dave Hansen Cc: Denys Vlasenko Cc: H. Peter Anvin Cc: Josh Poimboeuf Cc: Linus Torvalds Cc: Luis R. Rodriguez Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: Toshi Kani Cc: dave.hansen@intel.com Cc: linux-mm@kvack.org Cc: mhocko@suse.com Link: http://lkml.kernel.org/r/20160708001915.813703D9@viggo.jf.intel.com Signed-off-by: Ingo Molnar diff --git a/arch/x86/mm/init_64.c b/arch/x86/mm/init_64.c index bce2e5d..bb88fbc 100644 --- a/arch/x86/mm/init_64.c +++ b/arch/x86/mm/init_64.c @@ -354,7 +354,7 @@ phys_pte_init(pte_t *pte_page, unsigned long addr, unsigned long end, * pagetable pages as RO. So assume someone who pre-setup * these mappings are more intelligent. */ - if (pte_val(*pte)) { + if (!pte_none(*pte)) { if (!after_bootmem) pages++; continue; @@ -396,7 +396,7 @@ phys_pmd_init(pmd_t *pmd_page, unsigned long address, unsigned long end, continue; } - if (pmd_val(*pmd)) { + if (!pmd_none(*pmd)) { if (!pmd_large(*pmd)) { spin_lock(&init_mm.page_table_lock); pte = (pte_t *)pmd_page_vaddr(*pmd); @@ -470,7 +470,7 @@ phys_pud_init(pud_t *pud_page, unsigned long addr, unsigned long end, continue; } - if (pud_val(*pud)) { + if (!pud_none(*pud)) { if (!pud_large(*pud)) { pmd = pmd_offset(pud, 0); last_map_addr = phys_pmd_init(pmd, addr, end, @@ -673,7 +673,7 @@ static void __meminit free_pte_table(pte_t *pte_start, pmd_t *pmd) for (i = 0; i < PTRS_PER_PTE; i++) { pte = pte_start + i; - if (pte_val(*pte)) + if (!pte_none(*pte)) return; } @@ -691,7 +691,7 @@ static void __meminit free_pmd_table(pmd_t *pmd_start, pud_t *pud) for (i = 0; i < PTRS_PER_PMD; i++) { pmd = pmd_start + i; - if (pmd_val(*pmd)) + if (!pmd_none(*pmd)) return; } @@ -710,7 +710,7 @@ static bool __meminit free_pud_table(pud_t *pud_start, pgd_t *pgd) for (i = 0; i < PTRS_PER_PUD; i++) { pud = pud_start + i; - if (pud_val(*pud)) + if (!pud_none(*pud)) return false; } diff --git a/arch/x86/mm/pageattr.c b/arch/x86/mm/pageattr.c index 7a1f7bb..7514215 100644 --- a/arch/x86/mm/pageattr.c +++ b/arch/x86/mm/pageattr.c @@ -1185,7 +1185,7 @@ repeat: return __cpa_process_fault(cpa, address, primary); old_pte = *kpte; - if (!pte_val(old_pte)) + if (pte_none(old_pte)) return __cpa_process_fault(cpa, address, primary); if (level == PG_LEVEL_4K) { diff --git a/arch/x86/mm/pgtable_32.c b/arch/x86/mm/pgtable_32.c index 75cc097..e67ae0e6 100644 --- a/arch/x86/mm/pgtable_32.c +++ b/arch/x86/mm/pgtable_32.c @@ -47,7 +47,7 @@ void set_pte_vaddr(unsigned long vaddr, pte_t pteval) return; } pte = pte_offset_kernel(pmd, vaddr); - if (pte_val(pteval)) + if (!pte_none(pteval)) set_pte_at(&init_mm, vaddr, pte, pteval); else pte_clear(&init_mm, vaddr, pte); -- cgit v0.10.2 From d60585c5766e9620d5d83e2b25dc042c7bdada2c Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Tue, 12 Jul 2016 18:33:56 +0200 Subject: sched/core: Correct off by one bug in load migration calculation The move of calc_load_migrate() from CPU_DEAD to CPU_DYING did not take into account that the function is now called from a thread running on the outgoing CPU. As a result a cpu unplug leakes a load of 1 into the global load accounting mechanism. Fix it by adjusting for the currently running thread which calls calc_load_migrate(). Reported-by: Anton Blanchard Signed-off-by: Thomas Gleixner Acked-by: Peter Zijlstra Cc: Linus Torvalds Cc: Michael Ellerman Cc: Vaidyanathan Srinivasan Cc: rt@linutronix.de Cc: shreyas@linux.vnet.ibm.com Fixes: e9cd8fa4fcfd: ("sched/migration: Move calc_load_migrate() into CPU_DYING") Link: http://lkml.kernel.org/r/alpine.DEB.2.11.1607121744350.4083@nanos Signed-off-by: Ingo Molnar diff --git a/kernel/sched/core.c b/kernel/sched/core.c index 51d7105..97ee9ac 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c @@ -5394,13 +5394,15 @@ void idle_task_exit(void) /* * Since this CPU is going 'away' for a while, fold any nr_active delta * we might have. Assumes we're called after migrate_tasks() so that the - * nr_active count is stable. + * nr_active count is stable. We need to take the teardown thread which + * is calling this into account, so we hand in adjust = 1 to the load + * calculation. * * Also see the comment "Global load-average calculations". */ static void calc_load_migrate(struct rq *rq) { - long delta = calc_load_fold_active(rq); + long delta = calc_load_fold_active(rq, 1); if (delta) atomic_long_add(delta, &calc_load_tasks); } diff --git a/kernel/sched/loadavg.c b/kernel/sched/loadavg.c index b0b93fd..a2d6eb7 100644 --- a/kernel/sched/loadavg.c +++ b/kernel/sched/loadavg.c @@ -78,11 +78,11 @@ void get_avenrun(unsigned long *loads, unsigned long offset, int shift) loads[2] = (avenrun[2] + offset) << shift; } -long calc_load_fold_active(struct rq *this_rq) +long calc_load_fold_active(struct rq *this_rq, long adjust) { long nr_active, delta = 0; - nr_active = this_rq->nr_running; + nr_active = this_rq->nr_running - adjust; nr_active += (long)this_rq->nr_uninterruptible; if (nr_active != this_rq->calc_load_active) { @@ -188,7 +188,7 @@ void calc_load_enter_idle(void) * We're going into NOHZ mode, if there's any pending delta, fold it * into the pending idle delta. */ - delta = calc_load_fold_active(this_rq); + delta = calc_load_fold_active(this_rq, 0); if (delta) { int idx = calc_load_write_idx(); @@ -389,7 +389,7 @@ void calc_global_load_tick(struct rq *this_rq) if (time_before(jiffies, this_rq->calc_load_update)) return; - delta = calc_load_fold_active(this_rq); + delta = calc_load_fold_active(this_rq, 0); if (delta) atomic_long_add(delta, &calc_load_tasks); diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h index 7cbeb92..898c0d2 100644 --- a/kernel/sched/sched.h +++ b/kernel/sched/sched.h @@ -28,7 +28,7 @@ extern unsigned long calc_load_update; extern atomic_long_t calc_load_tasks; extern void calc_global_load_tick(struct rq *this_rq); -extern long calc_load_fold_active(struct rq *this_rq); +extern long calc_load_fold_active(struct rq *this_rq, long adjust); #ifdef CONFIG_SMP extern void cpu_load_update_active(struct rq *this_rq); -- cgit v0.10.2 From 2a00f026a15d161b47ba3d3417d0fec5193468c3 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Wed, 13 Jul 2016 15:04:04 -0300 Subject: tools: Fix up BITS_PER_LONG setting It was set based on CONFIG_64BIT, that is available only when using Kconfig, which we're working towards but not to the point of having this CONFIG variable set, so synthesize it from available compiler defined defines, __SIZEOF_LONG__ or, lacking that, __WORDSIZE. Cc: Adrian Hunter Cc: David Ahern Cc: Jiri Olsa Cc: Namhyung Kim Cc: Wang Nan Link: http://lkml.kernel.org/n/tip-og5fmkr17856lhupacihwxvb@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/include/asm-generic/bitsperlong.h b/tools/include/asm-generic/bitsperlong.h index d1d70aa1..cfd661c 100644 --- a/tools/include/asm-generic/bitsperlong.h +++ b/tools/include/asm-generic/bitsperlong.h @@ -3,6 +3,24 @@ #include +/* + * In the kernel, where this file comes from, we can rely on CONFIG_64BIT, + * here we have to make amends with what the various compilers provides us + * to figure out if we're on a 64-bit machine... + */ +#ifdef __SIZEOF_LONG__ +# if __SIZEOF_LONG__ == 8 +# define CONFIG_64BIT +# endif +#else +# ifdef __WORDSIZE +# if __WORDSIZE == 64 +# define CONFIG_64BIT +# endif +# else +# error Failed to determine BITS_PER_LONG value +# endif +#endif #ifdef CONFIG_64BIT #define BITS_PER_LONG 64 @@ -10,11 +28,7 @@ #define BITS_PER_LONG 32 #endif /* CONFIG_64BIT */ -/* - * FIXME: The check currently breaks x86-64 build, so it's - * temporarily disabled. Please fix x86-64 and reenable - */ -#if 0 && BITS_PER_LONG != __BITS_PER_LONG +#if BITS_PER_LONG != __BITS_PER_LONG #error Inconsistent word size. Check asm/bitsperlong.h #endif -- cgit v0.10.2 From 2c1ccc993707ecb0830ef0aebb7c8061f7704aa3 Mon Sep 17 00:00:00 2001 From: Daniel Jurgens Date: Wed, 13 Jul 2016 00:06:59 +0300 Subject: net/mlx5e: Fix TX Timeout to detect queues stuck on BQL Change netif_tx_queue_stopped to netif_xmit_stopped. This will show when queues are stopped due to byte queue limits. Fixes: 3947ca185999 ('net/mlx5e: Implement ndo_tx_timeout callback') Signed-off-by: Daniel Jurgens Signed-off-by: Saeed Mahameed Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c index 7a0dca2..0cebc7e 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c @@ -2656,7 +2656,7 @@ static void mlx5e_tx_timeout(struct net_device *dev) for (i = 0; i < priv->params.num_channels * priv->params.num_tc; i++) { struct mlx5e_sq *sq = priv->txq_to_sq_map[i]; - if (!netif_tx_queue_stopped(netdev_get_tx_queue(dev, i))) + if (!netif_xmit_stopped(netdev_get_tx_queue(dev, i))) continue; sched_work = true; set_bit(MLX5E_SQ_STATE_TX_TIMEOUT, &sq->state); -- cgit v0.10.2 From c3b7c5c9504348e0c22fa47629c419d82c963bc2 Mon Sep 17 00:00:00 2001 From: Mohamad Haj Yahia Date: Wed, 13 Jul 2016 00:07:00 +0300 Subject: net/mlx5e: start/stop all tx queues upon open/close netdev Start all tx queues (including inactive ones) when opening the netdev. Stop all tx queues (including inactive ones) when closing the netdev. This is a workaround for the tx timeout watchdog false alarm issue in which the netdev watchdog is polling all the tx queues which may include inactive queues and thus once lowering the real tx queues number (ethtool -L) it will generate tx timeout watchdog false alarms. Fixes: 3947ca185999 ('net/mlx5e: Implement ndo_tx_timeout callback') Signed-off-by: Mohamad Haj Yahia Signed-off-by: Saeed Mahameed Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c index 0cebc7e..5a4d88c 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c @@ -1348,6 +1348,11 @@ static int mlx5e_open_channels(struct mlx5e_priv *priv) goto err_close_channels; } + /* FIXME: This is a W/A for tx timeout watch dog false alarm when + * polling for inactive tx queues. + */ + netif_tx_start_all_queues(priv->netdev); + kfree(cparam); return 0; @@ -1367,6 +1372,12 @@ static void mlx5e_close_channels(struct mlx5e_priv *priv) { int i; + /* FIXME: This is a W/A only for tx timeout watch dog false alarm when + * polling for inactive tx queues. + */ + netif_tx_stop_all_queues(priv->netdev); + netif_tx_disable(priv->netdev); + for (i = 0; i < priv->params.num_channels; i++) mlx5e_close_channel(priv->channel[i]); -- cgit v0.10.2 From 774bec3fddcccb0b36f319c6d6e8148dc5e8c937 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Wed, 13 Jul 2016 15:28:51 -0300 Subject: objtool: Add fallback from ELF_C_READ_MMAP to ELF_C_READ Not all libelf implementations have this "Please, ELF_C_READ, but use mmap if possible" elf_begin() cmd, so provide a fallback to plain old ELF_C_READ. Case in point: Alpine Linux 3.4. Cc: Adrian Hunter Cc: David Ahern Cc: Jiri Olsa Cc: Josh Poimboeuf Cc: Namhyung Kim Cc: Wang Nan Link: http://lkml.kernel.org/n/tip-1fctuknrawgoi5xqon4mu9dv@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/objtool/elf.c b/tools/objtool/elf.c index e11f6b6..0d7983a 100644 --- a/tools/objtool/elf.c +++ b/tools/objtool/elf.c @@ -30,6 +30,13 @@ #include "elf.h" #include "warn.h" +/* + * Fallback for systems without this "read, mmaping if possible" cmd. + */ +#ifndef ELF_C_READ_MMAP +#define ELF_C_READ_MMAP ELF_C_READ +#endif + struct section *find_section_by_name(struct elf *elf, const char *name) { struct section *sec; -- cgit v0.10.2 From f4979fcea7fd36d8e2f556abef86f80e0d5af1ba Mon Sep 17 00:00:00 2001 From: Willem de Bruijn Date: Tue, 12 Jul 2016 18:18:56 -0400 Subject: rose: limit sk_filter trim to payload Sockets can have a filter program attached that drops or trims incoming packets based on the filter program return value. Rose requires data packets to have at least ROSE_MIN_LEN bytes. It verifies this on arrival in rose_route_frame and unconditionally pulls the bytes in rose_recvmsg. The filter can trim packets to below this value in-between, causing pull to fail, leaving the partial header at the time of skb_copy_datagram_msg. Place a lower bound on the size to which sk_filter may trim packets by introducing sk_filter_trim_cap and call this for rose packets. Signed-off-by: Willem de Bruijn Acked-by: Daniel Borkmann Signed-off-by: David S. Miller diff --git a/include/linux/filter.h b/include/linux/filter.h index 6fc31ef..8f74f3d 100644 --- a/include/linux/filter.h +++ b/include/linux/filter.h @@ -467,7 +467,11 @@ static inline void bpf_prog_unlock_ro(struct bpf_prog *fp) } #endif /* CONFIG_DEBUG_SET_MODULE_RONX */ -int sk_filter(struct sock *sk, struct sk_buff *skb); +int sk_filter_trim_cap(struct sock *sk, struct sk_buff *skb, unsigned int cap); +static inline int sk_filter(struct sock *sk, struct sk_buff *skb) +{ + return sk_filter_trim_cap(sk, skb, 1); +} struct bpf_prog *bpf_prog_select_runtime(struct bpf_prog *fp, int *err); void bpf_prog_free(struct bpf_prog *fp); diff --git a/net/core/filter.c b/net/core/filter.c index c4b330c..e759d90 100644 --- a/net/core/filter.c +++ b/net/core/filter.c @@ -53,9 +53,10 @@ #include /** - * sk_filter - run a packet through a socket filter + * sk_filter_trim_cap - run a packet through a socket filter * @sk: sock associated with &sk_buff * @skb: buffer to filter + * @cap: limit on how short the eBPF program may trim the packet * * Run the eBPF program and then cut skb->data to correct size returned by * the program. If pkt_len is 0 we toss packet. If skb->len is smaller @@ -64,7 +65,7 @@ * be accepted or -EPERM if the packet should be tossed. * */ -int sk_filter(struct sock *sk, struct sk_buff *skb) +int sk_filter_trim_cap(struct sock *sk, struct sk_buff *skb, unsigned int cap) { int err; struct sk_filter *filter; @@ -85,14 +86,13 @@ int sk_filter(struct sock *sk, struct sk_buff *skb) filter = rcu_dereference(sk->sk_filter); if (filter) { unsigned int pkt_len = bpf_prog_run_save_cb(filter->prog, skb); - - err = pkt_len ? pskb_trim(skb, pkt_len) : -EPERM; + err = pkt_len ? pskb_trim(skb, max(cap, pkt_len)) : -EPERM; } rcu_read_unlock(); return err; } -EXPORT_SYMBOL(sk_filter); +EXPORT_SYMBOL(sk_filter_trim_cap); static u64 __skb_get_pay_offset(u64 ctx, u64 a, u64 x, u64 r4, u64 r5) { diff --git a/net/rose/rose_in.c b/net/rose/rose_in.c index 79c4abc..0a63947 100644 --- a/net/rose/rose_in.c +++ b/net/rose/rose_in.c @@ -164,7 +164,8 @@ static int rose_state3_machine(struct sock *sk, struct sk_buff *skb, int framety rose_frames_acked(sk, nr); if (ns == rose->vr) { rose_start_idletimer(sk); - if (sock_queue_rcv_skb(sk, skb) == 0) { + if (sk_filter_trim_cap(sk, skb, ROSE_MIN_LEN) == 0 && + __sock_queue_rcv_skb(sk, skb) == 0) { rose->vr = (rose->vr + 1) % ROSE_MODULUS; queued = 1; } else { -- cgit v0.10.2 From 4f0c40d94461cfd23893a17335b2ab78ecb333c8 Mon Sep 17 00:00:00 2001 From: Willem de Bruijn Date: Tue, 12 Jul 2016 18:18:57 -0400 Subject: dccp: limit sk_filter trim to payload Dccp verifies packet integrity, including length, at initial rcv in dccp_invalid_packet, later pulls headers in dccp_enqueue_skb. A call to sk_filter in-between can cause __skb_pull to wrap skb->len. skb_copy_datagram_msg interprets this as a negative value, so (correctly) fails with EFAULT. The negative length is reported in ioctl SIOCINQ or possibly in a DCCP_WARN in dccp_close. Introduce an sk_receive_skb variant that caps how small a filter program can trim packets, and call this in dccp with the header length. Excessively trimmed packets are now processed normally and queued for reception as 0B payloads. Fixes: 7c657876b63c ("[DCCP]: Initial implementation") Signed-off-by: Willem de Bruijn Acked-by: Daniel Borkmann Signed-off-by: David S. Miller diff --git a/include/net/sock.h b/include/net/sock.h index 649d2a8..ff5be7e 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -1576,7 +1576,13 @@ static inline void sock_put(struct sock *sk) */ void sock_gen_put(struct sock *sk); -int sk_receive_skb(struct sock *sk, struct sk_buff *skb, const int nested); +int __sk_receive_skb(struct sock *sk, struct sk_buff *skb, const int nested, + unsigned int trim_cap); +static inline int sk_receive_skb(struct sock *sk, struct sk_buff *skb, + const int nested) +{ + return __sk_receive_skb(sk, skb, nested, 1); +} static inline void sk_tx_queue_set(struct sock *sk, int tx_queue) { diff --git a/net/core/sock.c b/net/core/sock.c index b7f1263..25dab8b 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -452,11 +452,12 @@ int sock_queue_rcv_skb(struct sock *sk, struct sk_buff *skb) } EXPORT_SYMBOL(sock_queue_rcv_skb); -int sk_receive_skb(struct sock *sk, struct sk_buff *skb, const int nested) +int __sk_receive_skb(struct sock *sk, struct sk_buff *skb, + const int nested, unsigned int trim_cap) { int rc = NET_RX_SUCCESS; - if (sk_filter(sk, skb)) + if (sk_filter_trim_cap(sk, skb, trim_cap)) goto discard_and_relse; skb->dev = NULL; @@ -492,7 +493,7 @@ discard_and_relse: kfree_skb(skb); goto out; } -EXPORT_SYMBOL(sk_receive_skb); +EXPORT_SYMBOL(__sk_receive_skb); struct dst_entry *__sk_dst_check(struct sock *sk, u32 cookie) { diff --git a/net/dccp/ipv4.c b/net/dccp/ipv4.c index 25dd25b..345a3ae 100644 --- a/net/dccp/ipv4.c +++ b/net/dccp/ipv4.c @@ -868,7 +868,7 @@ lookup: goto discard_and_relse; nf_reset(skb); - return sk_receive_skb(sk, skb, 1); + return __sk_receive_skb(sk, skb, 1, dh->dccph_doff * 4); no_dccp_socket: if (!xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb)) diff --git a/net/dccp/ipv6.c b/net/dccp/ipv6.c index d176f4e..3ff137d9 100644 --- a/net/dccp/ipv6.c +++ b/net/dccp/ipv6.c @@ -732,7 +732,7 @@ lookup: if (!xfrm6_policy_check(sk, XFRM_POLICY_IN, skb)) goto discard_and_relse; - return sk_receive_skb(sk, skb, 1) ? -1 : 0; + return __sk_receive_skb(sk, skb, 1, dh->dccph_doff * 4) ? -1 : 0; no_dccp_socket: if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb)) -- cgit v0.10.2 From 1a4bf28573c82b4cbeb4e8d3326b24a93ed64c8e Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Wed, 13 Jul 2016 15:33:54 -0300 Subject: objtool: Avoid checking code drift on busybox's diff That doesn't have -I to match lines. Cc: Adrian Hunter Cc: David Ahern Cc: Jiri Olsa Cc: Josh Poimboeuf Cc: Namhyung Kim Cc: Wang Nan Link: http://lkml.kernel.org/n/tip-1zqv1h6okt70e2huokkdtf1u@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/objtool/Makefile b/tools/objtool/Makefile index f094f3c..9a3110c 100644 --- a/tools/objtool/Makefile +++ b/tools/objtool/Makefile @@ -41,8 +41,11 @@ include $(srctree)/tools/build/Makefile.include $(OBJTOOL_IN): fixdep FORCE @$(MAKE) $(build)=objtool +# Busybox's diff doesn't have -I, avoid warning in that case +# $(OBJTOOL): $(LIBSUBCMD) $(OBJTOOL_IN) - @(test -d ../../kernel -a -d ../../tools -a -d ../objtool && (( \ + @(diff -I 2>&1 | grep -q 'option requires an argument' && \ + test -d ../../kernel -a -d ../../tools -a -d ../objtool && (( \ diff -I'^#include' arch/x86/insn/insn.c ../../arch/x86/lib/insn.c >/dev/null && \ diff -I'^#include' arch/x86/insn/inat.c ../../arch/x86/lib/inat.c >/dev/null && \ diff arch/x86/insn/x86-opcode-map.txt ../../arch/x86/lib/x86-opcode-map.txt >/dev/null && \ -- cgit v0.10.2 From 5f44e4c810bf3ace5a97a84554d4eeccbb563ca5 Mon Sep 17 00:00:00 2001 From: Wang Nan Date: Wed, 13 Jul 2016 10:44:01 +0000 Subject: tools lib bpf: New API to adjust type of a BPF program Add 4 new APIs to adjust and query the type of a BPF program. Load program according to type set by caller. Default is set to BPF_PROG_TYPE_KPROBE. Signed-off-by: Wang Nan Cc: Alexei Starovoitov Cc: Jiri Olsa Cc: Zefan Li Cc: pi3orama@163.com Link: http://lkml.kernel.org/r/1468406646-21642-2-git-send-email-wangnan0@huawei.com Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c index 3dcda9e..4751936 100644 --- a/tools/lib/bpf/libbpf.c +++ b/tools/lib/bpf/libbpf.c @@ -158,6 +158,7 @@ struct bpf_program { char *section_name; struct bpf_insn *insns; size_t insns_cnt; + enum bpf_prog_type type; struct { int insn_idx; @@ -299,6 +300,7 @@ bpf_program__init(void *data, size_t size, char *name, int idx, prog->idx = idx; prog->instances.fds = NULL; prog->instances.nr = -1; + prog->type = BPF_PROG_TYPE_KPROBE; return 0; errout: @@ -894,8 +896,8 @@ static int bpf_object__collect_reloc(struct bpf_object *obj) } static int -load_program(struct bpf_insn *insns, int insns_cnt, - char *license, u32 kern_version, int *pfd) +load_program(enum bpf_prog_type type, struct bpf_insn *insns, + int insns_cnt, char *license, u32 kern_version, int *pfd) { int ret; char *log_buf; @@ -907,9 +909,8 @@ load_program(struct bpf_insn *insns, int insns_cnt, if (!log_buf) pr_warning("Alloc log buffer for bpf loader error, continue without log\n"); - ret = bpf_load_program(BPF_PROG_TYPE_KPROBE, insns, - insns_cnt, license, kern_version, - log_buf, BPF_LOG_BUF_SIZE); + ret = bpf_load_program(type, insns, insns_cnt, license, + kern_version, log_buf, BPF_LOG_BUF_SIZE); if (ret >= 0) { *pfd = ret; @@ -968,7 +969,7 @@ bpf_program__load(struct bpf_program *prog, pr_warning("Program '%s' is inconsistent: nr(%d) != 1\n", prog->section_name, prog->instances.nr); } - err = load_program(prog->insns, prog->insns_cnt, + err = load_program(prog->type, prog->insns, prog->insns_cnt, license, kern_version, &fd); if (!err) prog->instances.fds[0] = fd; @@ -997,7 +998,7 @@ bpf_program__load(struct bpf_program *prog, continue; } - err = load_program(result.new_insn_ptr, + err = load_program(prog->type, result.new_insn_ptr, result.new_insn_cnt, license, kern_version, &fd); @@ -1316,6 +1317,44 @@ int bpf_program__nth_fd(struct bpf_program *prog, int n) return fd; } +static void bpf_program__set_type(struct bpf_program *prog, + enum bpf_prog_type type) +{ + prog->type = type; +} + +int bpf_program__set_tracepoint(struct bpf_program *prog) +{ + if (!prog) + return -EINVAL; + bpf_program__set_type(prog, BPF_PROG_TYPE_TRACEPOINT); + return 0; +} + +int bpf_program__set_kprobe(struct bpf_program *prog) +{ + if (!prog) + return -EINVAL; + bpf_program__set_type(prog, BPF_PROG_TYPE_KPROBE); + return 0; +} + +static bool bpf_program__is_type(struct bpf_program *prog, + enum bpf_prog_type type) +{ + return prog ? (prog->type == type) : false; +} + +bool bpf_program__is_tracepoint(struct bpf_program *prog) +{ + return bpf_program__is_type(prog, BPF_PROG_TYPE_TRACEPOINT); +} + +bool bpf_program__is_kprobe(struct bpf_program *prog) +{ + return bpf_program__is_type(prog, BPF_PROG_TYPE_KPROBE); +} + int bpf_map__fd(struct bpf_map *map) { return map ? map->fd : -EINVAL; diff --git a/tools/lib/bpf/libbpf.h b/tools/lib/bpf/libbpf.h index f392c5e..eb2a4c4 100644 --- a/tools/lib/bpf/libbpf.h +++ b/tools/lib/bpf/libbpf.h @@ -165,6 +165,15 @@ int bpf_program__set_prep(struct bpf_program *prog, int nr_instance, int bpf_program__nth_fd(struct bpf_program *prog, int n); /* + * Adjust type of bpf program. Default is kprobe. + */ +int bpf_program__set_tracepoint(struct bpf_program *prog); +int bpf_program__set_kprobe(struct bpf_program *prog); + +bool bpf_program__is_tracepoint(struct bpf_program *prog); +bool bpf_program__is_kprobe(struct bpf_program *prog); + +/* * We don't need __attribute__((packed)) now since it is * unnecessary for 'bpf_map_def' because they are all aligned. * In addition, using it will trigger -Wpacked warning message, -- cgit v0.10.2 From 705fa2190dfb3d02f83adcd1abdb4e7dc3434597 Mon Sep 17 00:00:00 2001 From: Wang Nan Date: Wed, 13 Jul 2016 10:44:02 +0000 Subject: tools lib bpf: Report error when kernel doesn't support program type Now libbpf support tracepoint program type. Report meaningful error when kernel version is less than 4.7. Signed-off-by: Wang Nan Cc: Alexei Starovoitov Cc: Jiri Olsa Cc: Zefan Li Cc: pi3orama@163.com Link: http://lkml.kernel.org/r/1468406646-21642-3-git-send-email-wangnan0@huawei.com Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c index 4751936..32e6b6b 100644 --- a/tools/lib/bpf/libbpf.c +++ b/tools/lib/bpf/libbpf.c @@ -90,6 +90,7 @@ static const char *libbpf_strerror_table[NR_ERRNO] = { [ERRCODE_OFFSET(VERIFY)] = "Kernel verifier blocks program loading", [ERRCODE_OFFSET(PROG2BIG)] = "Program too big", [ERRCODE_OFFSET(KVER)] = "Incorrect kernel version", + [ERRCODE_OFFSET(PROGTYPE)] = "Kernel doesn't support this program type", }; int libbpf_strerror(int err, char *buf, size_t size) @@ -926,15 +927,27 @@ load_program(enum bpf_prog_type type, struct bpf_insn *insns, pr_warning("-- BEGIN DUMP LOG ---\n"); pr_warning("\n%s\n", log_buf); pr_warning("-- END LOG --\n"); + } else if (insns_cnt >= BPF_MAXINSNS) { + pr_warning("Program too large (%d insns), at most %d insns\n", + insns_cnt, BPF_MAXINSNS); + ret = -LIBBPF_ERRNO__PROG2BIG; } else { - if (insns_cnt >= BPF_MAXINSNS) { - pr_warning("Program too large (%d insns), at most %d insns\n", - insns_cnt, BPF_MAXINSNS); - ret = -LIBBPF_ERRNO__PROG2BIG; - } else if (log_buf) { - pr_warning("log buffer is empty\n"); - ret = -LIBBPF_ERRNO__KVER; + /* Wrong program type? */ + if (type != BPF_PROG_TYPE_KPROBE) { + int fd; + + fd = bpf_load_program(BPF_PROG_TYPE_KPROBE, insns, + insns_cnt, license, kern_version, + NULL, 0); + if (fd >= 0) { + close(fd); + ret = -LIBBPF_ERRNO__PROGTYPE; + goto out; + } } + + if (log_buf) + ret = -LIBBPF_ERRNO__KVER; } out: diff --git a/tools/lib/bpf/libbpf.h b/tools/lib/bpf/libbpf.h index eb2a4c4..dd7a513 100644 --- a/tools/lib/bpf/libbpf.h +++ b/tools/lib/bpf/libbpf.h @@ -39,6 +39,7 @@ enum libbpf_errno { LIBBPF_ERRNO__VERIFY, /* Kernel verifier blocks program loading */ LIBBPF_ERRNO__PROG2BIG, /* Program too big */ LIBBPF_ERRNO__KVER, /* Incorrect kernel version */ + LIBBPF_ERRNO__PROGTYPE, /* Kernel doesn't support this program type */ __LIBBPF_ERRNO__END, }; -- cgit v0.10.2 From 8c619d6a333f98087816e64c62f0f2389e19ab4a Mon Sep 17 00:00:00 2001 From: Wang Nan Date: Wed, 13 Jul 2016 10:44:03 +0000 Subject: perf event parser: Add const qualifier to evt_name and sys_name Add missing 'const' qualifiers so following commits are able to create tracepoints using const strings. Signed-off-by: Wang Nan Cc: Alexei Starovoitov Cc: Jiri Olsa Cc: Zefan Li Cc: pi3orama@163.com Link: http://lkml.kernel.org/r/1468406646-21642-4-git-send-email-wangnan0@huawei.com Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index ebd87b7..d866824 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -436,7 +436,7 @@ int parse_events_add_cache(struct list_head *list, int *idx, } static void tracepoint_error(struct parse_events_error *e, int err, - char *sys, char *name) + const char *sys, const char *name) { char help[BUFSIZ]; @@ -466,7 +466,7 @@ static void tracepoint_error(struct parse_events_error *e, int err, } static int add_tracepoint(struct list_head *list, int *idx, - char *sys_name, char *evt_name, + const char *sys_name, const char *evt_name, struct parse_events_error *err, struct list_head *head_config) { @@ -491,7 +491,7 @@ static int add_tracepoint(struct list_head *list, int *idx, } static int add_tracepoint_multi_event(struct list_head *list, int *idx, - char *sys_name, char *evt_name, + const char *sys_name, const char *evt_name, struct parse_events_error *err, struct list_head *head_config) { @@ -533,7 +533,7 @@ static int add_tracepoint_multi_event(struct list_head *list, int *idx, } static int add_tracepoint_event(struct list_head *list, int *idx, - char *sys_name, char *evt_name, + const char *sys_name, const char *evt_name, struct parse_events_error *err, struct list_head *head_config) { @@ -545,7 +545,7 @@ static int add_tracepoint_event(struct list_head *list, int *idx, } static int add_tracepoint_multi_sys(struct list_head *list, int *idx, - char *sys_name, char *evt_name, + const char *sys_name, const char *evt_name, struct parse_events_error *err, struct list_head *head_config) { @@ -1126,7 +1126,7 @@ do { \ } int parse_events_add_tracepoint(struct list_head *list, int *idx, - char *sys, char *event, + const char *sys, const char *event, struct parse_events_error *err, struct list_head *head_config) { diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h index 46c05cc..0bd664d 100644 --- a/tools/perf/util/parse-events.h +++ b/tools/perf/util/parse-events.h @@ -134,7 +134,7 @@ int parse_events__modifier_event(struct list_head *list, char *str, bool add); int parse_events__modifier_group(struct list_head *list, char *event_mod); int parse_events_name(struct list_head *list, char *name); int parse_events_add_tracepoint(struct list_head *list, int *idx, - char *sys, char *event, + const char *sys, const char *event, struct parse_events_error *error, struct list_head *head_config); int parse_events_load_bpf(struct parse_events_evlist *data, -- cgit v0.10.2 From cd102d70fe957b060b9df6bc4f54684de3fe00cd Mon Sep 17 00:00:00 2001 From: Wang Nan Date: Wed, 13 Jul 2016 10:44:04 +0000 Subject: perf bpf: Rename bpf__foreach_tev() to bpf__foreach_event() Following commit will allow BPF script attach to tracepoints. bpf__foreach_tev() will iterate over all events, not only kprobes. Rename it to bpf__foreach_event(). Since only group and event are used by caller, there's no need to pass full 'struct probe_trace_event' to bpf_prog_iter_callback_t. Pass only these two strings. After this patch bpf_prog_iter_callback_t natually support tracepoints. Signed-off-by: Wang Nan Cc: Alexei Starovoitov Cc: Jiri Olsa Cc: Zefan Li Cc: pi3orama@163.com Link: http://lkml.kernel.org/r/1468406646-21642-5-git-send-email-wangnan0@huawei.com Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/util/bpf-loader.c b/tools/perf/util/bpf-loader.c index 8445e89..f227014 100644 --- a/tools/perf/util/bpf-loader.c +++ b/tools/perf/util/bpf-loader.c @@ -693,9 +693,9 @@ int bpf__load(struct bpf_object *obj) return 0; } -int bpf__foreach_tev(struct bpf_object *obj, - bpf_prog_iter_callback_t func, - void *arg) +int bpf__foreach_event(struct bpf_object *obj, + bpf_prog_iter_callback_t func, + void *arg) { struct bpf_program *prog; int err; @@ -728,7 +728,7 @@ int bpf__foreach_tev(struct bpf_object *obj, return fd; } - err = (*func)(tev, fd, arg); + err = (*func)(tev->group, tev->event, fd, arg); if (err) { pr_debug("bpf: call back failed, stop iterate\n"); return err; diff --git a/tools/perf/util/bpf-loader.h b/tools/perf/util/bpf-loader.h index 941e172..f2b737b 100644 --- a/tools/perf/util/bpf-loader.h +++ b/tools/perf/util/bpf-loader.h @@ -46,7 +46,7 @@ struct bpf_object; struct parse_events_term; #define PERF_BPF_PROBE_GROUP "perf_bpf_probe" -typedef int (*bpf_prog_iter_callback_t)(struct probe_trace_event *tev, +typedef int (*bpf_prog_iter_callback_t)(const char *group, const char *event, int fd, void *arg); #ifdef HAVE_LIBBPF_SUPPORT @@ -67,8 +67,8 @@ int bpf__strerror_probe(struct bpf_object *obj, int err, int bpf__load(struct bpf_object *obj); int bpf__strerror_load(struct bpf_object *obj, int err, char *buf, size_t size); -int bpf__foreach_tev(struct bpf_object *obj, - bpf_prog_iter_callback_t func, void *arg); +int bpf__foreach_event(struct bpf_object *obj, + bpf_prog_iter_callback_t func, void *arg); int bpf__config_obj(struct bpf_object *obj, struct parse_events_term *term, struct perf_evlist *evlist, int *error_pos); @@ -107,9 +107,9 @@ static inline int bpf__unprobe(struct bpf_object *obj __maybe_unused) { return 0 static inline int bpf__load(struct bpf_object *obj __maybe_unused) { return 0; } static inline int -bpf__foreach_tev(struct bpf_object *obj __maybe_unused, - bpf_prog_iter_callback_t func __maybe_unused, - void *arg __maybe_unused) +bpf__foreach_event(struct bpf_object *obj __maybe_unused, + bpf_prog_iter_callback_t func __maybe_unused, + void *arg __maybe_unused) { return 0; } diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index d866824..6b4fff3 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -584,7 +584,7 @@ struct __add_bpf_event_param { struct list_head *head_config; }; -static int add_bpf_event(struct probe_trace_event *tev, int fd, +static int add_bpf_event(const char *group, const char *event, int fd, void *_param) { LIST_HEAD(new_evsels); @@ -595,27 +595,27 @@ static int add_bpf_event(struct probe_trace_event *tev, int fd, int err; pr_debug("add bpf event %s:%s and attach bpf program %d\n", - tev->group, tev->event, fd); + group, event, fd); - err = parse_events_add_tracepoint(&new_evsels, &evlist->idx, tev->group, - tev->event, evlist->error, + err = parse_events_add_tracepoint(&new_evsels, &evlist->idx, group, + event, evlist->error, param->head_config); if (err) { struct perf_evsel *evsel, *tmp; pr_debug("Failed to add BPF event %s:%s\n", - tev->group, tev->event); + group, event); list_for_each_entry_safe(evsel, tmp, &new_evsels, node) { list_del(&evsel->node); perf_evsel__delete(evsel); } return err; } - pr_debug("adding %s:%s\n", tev->group, tev->event); + pr_debug("adding %s:%s\n", group, event); list_for_each_entry(pos, &new_evsels, node) { pr_debug("adding %s:%s to %p\n", - tev->group, tev->event, pos); + group, event, pos); pos->bpf_fd = fd; } list_splice(&new_evsels, list); @@ -661,7 +661,7 @@ int parse_events_load_bpf_obj(struct parse_events_evlist *data, goto errout; } - err = bpf__foreach_tev(obj, add_bpf_event, ¶m); + err = bpf__foreach_event(obj, add_bpf_event, ¶m); if (err) { snprintf(errbuf, sizeof(errbuf), "Attach events in BPF object failed"); -- cgit v0.10.2 From b4ee6d415e731b9d8a51451da0ebe33450c355d2 Mon Sep 17 00:00:00 2001 From: Wang Nan Date: Wed, 13 Jul 2016 10:44:05 +0000 Subject: perf bpf: Support BPF program attach to tracepoints To support 98b5c2c65c29 ("perf, bpf: allow bpf programs attach to tracepoints"), this patch allows BPF scripts to select tracepoints in their section name. Example: # cat test_tracepoint.c /*********************************************/ #include #define SEC(NAME) __attribute__((section(NAME), used)) SEC("raw_syscalls:sys_enter") int func(void *ctx) { /* * /sys/kernel/debug/tracing/events/raw_syscalls/sys_enter/format: * ... * field:long id; offset:8; size:8; signed:1; * ... * ctx + 8 select 'id' */ u64 id = *((u64 *)(ctx + 8)); if (id == 1) return 1; return 0; } SEC("_write=sys_write") int _write(void *ctx) { return 1; } char _license[] SEC("license") = "GPL"; int _version SEC("version") = LINUX_VERSION_CODE; /*********************************************/ # perf record -e ./test_tracepoint.c dd if=/dev/zero of=/dev/null count=5 5+0 records in 5+0 records out 2560 bytes (2.6 kB) copied, 6.2281e-05 s, 41.1 MB/s [ perf record: Woken up 1 times to write data ] # perf script dd 13436 [005] 1596.490869: raw_syscalls:sys_enter: NR 1 (1, 178d000, 200, 7ffe82470d60, ffffffffffffe020, fffff dd 13436 [005] 1596.490871: perf_bpf_probe:_write: (ffffffff812351e0) dd 13436 [005] 1596.490873: raw_syscalls:sys_enter: NR 1 (1, 178d000, 200, ffffffffffffe000, ffffffffffffe020, f dd 13436 [005] 1596.490874: perf_bpf_probe:_write: (ffffffff812351e0) dd 13436 [005] 1596.490876: raw_syscalls:sys_enter: NR 1 (1, 178d000, 200, ffffffffffffe000, ffffffffffffe020, f dd 13436 [005] 1596.490876: perf_bpf_probe:_write: (ffffffff812351e0) dd 13436 [005] 1596.490878: raw_syscalls:sys_enter: NR 1 (1, 178d000, 200, ffffffffffffe000, ffffffffffffe020, f dd 13436 [005] 1596.490879: perf_bpf_probe:_write: (ffffffff812351e0) dd 13436 [005] 1596.490881: raw_syscalls:sys_enter: NR 1 (1, 178d000, 200, ffffffffffffe000, ffffffffffffe020, f dd 13436 [005] 1596.490882: perf_bpf_probe:_write: (ffffffff812351e0) dd 13436 [005] 1596.490900: raw_syscalls:sys_enter: NR 1 (2, 7ffe8246e640, 1f, 40acb8, 7f44bac74700, 7f44baa4fba dd 13436 [005] 1596.490901: perf_bpf_probe:_write: (ffffffff812351e0) dd 13436 [005] 1596.490917: raw_syscalls:sys_enter: NR 1 (2, 7ffe8246e640, 1a, fffffffa, 7f44bac74700, 7f44baa4f dd 13436 [005] 1596.490918: perf_bpf_probe:_write: (ffffffff812351e0) dd 13436 [005] 1596.490932: raw_syscalls:sys_enter: NR 1 (2, 7ffe8246e640, 1a, fffffff9, 7f44bac74700, 7f44baa4f dd 13436 [005] 1596.490933: perf_bpf_probe:_write: (ffffffff812351e0) Committer note: Further testing: # trace --no-sys --event /home/acme/bpf/tracepoint.c cat /etc/passwd > /dev/null 0.000 raw_syscalls:sys_enter:NR 1 (1, 7f0490504000, c48, 7f0490503010, ffffffffffffffff, 0)) 0.006 perf_bpf_probe:_write:(ffffffff81241bc0)) # Signed-off-by: Wang Nan Tested-by: Arnaldo Carvalho de Melo Cc: Alexei Starovoitov Cc: Jiri Olsa Cc: Zefan Li Cc: pi3orama@163.com Link: http://lkml.kernel.org/r/1468406646-21642-6-git-send-email-wangnan0@huawei.com Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/util/bpf-loader.c b/tools/perf/util/bpf-loader.c index f227014..1f12e4e 100644 --- a/tools/perf/util/bpf-loader.c +++ b/tools/perf/util/bpf-loader.c @@ -37,6 +37,9 @@ DEFINE_PRINT_FN(info, 1) DEFINE_PRINT_FN(debug, 1) struct bpf_prog_priv { + bool is_tp; + char *sys_name; + char *evt_name; struct perf_probe_event pev; bool need_prologue; struct bpf_insn *insns_buf; @@ -118,6 +121,8 @@ clear_prog_priv(struct bpf_program *prog __maybe_unused, cleanup_perf_probe_events(&priv->pev, 1); zfree(&priv->insns_buf); zfree(&priv->type_mapping); + zfree(&priv->sys_name); + zfree(&priv->evt_name); free(priv); } @@ -269,7 +274,8 @@ nextline: } static int -parse_prog_config(const char *config_str, struct perf_probe_event *pev) +parse_prog_config(const char *config_str, const char **p_main_str, + bool *is_tp, struct perf_probe_event *pev) { int err; const char *main_str = parse_prog_config_kvpair(config_str, pev); @@ -277,6 +283,22 @@ parse_prog_config(const char *config_str, struct perf_probe_event *pev) if (IS_ERR(main_str)) return PTR_ERR(main_str); + *p_main_str = main_str; + if (!strchr(main_str, '=')) { + /* Is a tracepoint event? */ + const char *s = strchr(main_str, ':'); + + if (!s) { + pr_debug("bpf: '%s' is not a valid tracepoint\n", + config_str); + return -BPF_LOADER_ERRNO__CONFIG; + } + + *is_tp = true; + return 0; + } + + *is_tp = false; err = parse_perf_probe_command(main_str, pev); if (err < 0) { pr_debug("bpf: '%s' is not a valid config string\n", @@ -292,7 +314,8 @@ config_bpf_program(struct bpf_program *prog) { struct perf_probe_event *pev = NULL; struct bpf_prog_priv *priv = NULL; - const char *config_str; + const char *config_str, *main_str; + bool is_tp = false; int err; /* Initialize per-program probing setting */ @@ -313,10 +336,19 @@ config_bpf_program(struct bpf_program *prog) pev = &priv->pev; pr_debug("bpf: config program '%s'\n", config_str); - err = parse_prog_config(config_str, pev); + err = parse_prog_config(config_str, &main_str, &is_tp, pev); if (err) goto errout; + if (is_tp) { + char *s = strchr(main_str, ':'); + + priv->is_tp = true; + priv->sys_name = strndup(main_str, s - main_str); + priv->evt_name = strdup(s + 1); + goto set_priv; + } + if (pev->group && strcmp(pev->group, PERF_BPF_PROBE_GROUP)) { pr_debug("bpf: '%s': group for event is set and not '%s'.\n", config_str, PERF_BPF_PROBE_GROUP); @@ -339,6 +371,7 @@ config_bpf_program(struct bpf_program *prog) } pr_debug("bpf: config '%s' is ok\n", config_str); +set_priv: err = bpf_program__set_priv(prog, priv, clear_prog_priv); if (err) { pr_debug("Failed to set priv for program '%s'\n", config_str); @@ -387,7 +420,7 @@ preproc_gen_prologue(struct bpf_program *prog, int n, size_t prologue_cnt = 0; int i, err; - if (IS_ERR(priv) || !priv) + if (IS_ERR(priv) || !priv || priv->is_tp) goto errout; pev = &priv->pev; @@ -544,6 +577,11 @@ static int hook_load_preprocessor(struct bpf_program *prog) return -BPF_LOADER_ERRNO__INTERNAL; } + if (priv->is_tp) { + priv->need_prologue = false; + return 0; + } + pev = &priv->pev; for (i = 0; i < pev->ntevs; i++) { struct probe_trace_event *tev = &pev->tevs[i]; @@ -610,6 +648,13 @@ int bpf__probe(struct bpf_object *obj) err = PTR_ERR(priv); goto out; } + + if (priv->is_tp) { + bpf_program__set_tracepoint(prog); + continue; + } + + bpf_program__set_kprobe(prog); pev = &priv->pev; err = convert_perf_probe_events(pev, 1); @@ -650,7 +695,7 @@ int bpf__unprobe(struct bpf_object *obj) struct bpf_prog_priv *priv = bpf_program__priv(prog); int i; - if (IS_ERR(priv) || !priv) + if (IS_ERR(priv) || !priv || priv->is_tp) continue; for (i = 0; i < priv->pev.ntevs; i++) { @@ -711,6 +756,16 @@ int bpf__foreach_event(struct bpf_object *obj, return -BPF_LOADER_ERRNO__INTERNAL; } + if (priv->is_tp) { + fd = bpf_program__fd(prog); + err = (*func)(priv->sys_name, priv->evt_name, fd, arg); + if (err) { + pr_debug("bpf: tracepoint call back failed, stop iterate\n"); + return err; + } + continue; + } + pev = &priv->pev; for (i = 0; i < pev->ntevs; i++) { tev = &pev->tevs[i]; -- cgit v0.10.2 From f6eb0518f325ef0d6557fbef5c7ebe48a81e74db Mon Sep 17 00:00:00 2001 From: Masami Hiramatsu Date: Tue, 12 Jul 2016 19:04:34 +0900 Subject: perf probe: Fix to show correct error message for $vars and $params Fix to show correct error messages for $vars and $params because those special variables requires debug information to find the real variables or function parameters. E.g. without this fix; ---- # perf probe -x /lib64/libc-2.23.so getaddrinfo \$params Failed to write event: Invalid argument Please upgrade your kernel to at least 3.14 to have access to feature $params Error: Failed to add events. ---- Perf ends up with an error, but the message is not correct. With this fix, perf shows correct error message as below. ---- # perf probe -x /lib64/libc-2.23.so getaddrinfo \$params The /usr/lib64/libc-2.23.so file has no debug information. Rebuild with -g, or install an appropriate debuginfo package. Error: Failed to add events. ---- Reported-and-Tested-by: Arnaldo Carvalho de Melo Signed-off-by: Masami Hiramatsu Cc: Ananth N Mavinakayanahalli Cc: Brendan Gregg Cc: Hemant Kumar Cc: Namhyung Kim Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/146831787438.17065.6152436996780110699.stgit@devbox Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c index 2b222a7..fef9768 100644 --- a/tools/perf/util/probe-event.c +++ b/tools/perf/util/probe-event.c @@ -1547,7 +1547,9 @@ bool perf_probe_event_need_dwarf(struct perf_probe_event *pev) return true; for (i = 0; i < pev->nargs; i++) - if (is_c_varname(pev->args[i].var)) + if (is_c_varname(pev->args[i].var) || + !strcmp(pev->args[i].var, "$params") || + !strcmp(pev->args[i].var, "$vars")) return true; return false; -- cgit v0.10.2 From 36a009fe07bdecd201335f982babb8af34b603e2 Mon Sep 17 00:00:00 2001 From: Masami Hiramatsu Date: Tue, 12 Jul 2016 19:04:43 +0900 Subject: perf probe: Accept %sdt and %cached event name To improve usability, support %[PROVIDER:]SDTEVENT format to add new probes on SDT and cached events. e.g. ---- # perf probe -x /lib/libc-2.17.so %lll_lock_wait_private Added new event: sdt_libc:lll_lock_wait_private (on %lll_lock_wait_private in /usr/lib/libc-2.17.so) You can now use it in all perf tools, such as: perf record -e sdt_libc:lll_lock_wait_private -aR sleep 1 # perf probe -l | more sdt_libc:lll_lock_wait_private (on __lll_lock_wait_private+21 in /usr/lib/libc-2.17.so) ---- Note that this is not only for SDT events, but also normal events with event-name. e.g. define "myevent" on cache (-n doesn't add the real probe) ---- # perf probe -x ./perf --cache -n --add 'myevent=dso__load $params' ---- Reuse the "myevent" from cache as below. ---- # perf probe -x ./perf %myevent ---- Signed-off-by: Masami Hiramatsu Signed-off-by: Masami Hiramatsu Tested-by: Arnaldo Carvalho de Melo Cc: Ananth N Mavinakayanahalli Cc: Brendan Gregg Cc: Hemant Kumar Cc: Namhyung Kim Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/146831788372.17065.3645054540325909346.stgit@devbox Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/Documentation/perf-probe.txt b/tools/perf/Documentation/perf-probe.txt index 7a258e9..39e3870 100644 --- a/tools/perf/Documentation/perf-probe.txt +++ b/tools/perf/Documentation/perf-probe.txt @@ -151,6 +151,8 @@ Probe points are defined by following syntax. 3) Define event based on source file with lazy pattern [[GROUP:]EVENT=]SRC;PTN [ARG ...] + 4) Pre-defined SDT events or cached event with name + %[PROVIDER:]SDTEVENT 'EVENT' specifies the name of new event, if omitted, it will be set the name of the probed function. You can also specify a group name by 'GROUP', if omitted, set 'probe' is used for kprobe and 'probe_' is used for uprobe. Note that using existing group name can conflict with other events. Especially, using the group name reserved for kernel modules can hide embedded events in the @@ -158,6 +160,11 @@ modules. 'FUNC' specifies a probed function name, and it may have one of the following options; '+OFFS' is the offset from function entry address in bytes, ':RLN' is the relative-line number from function entry line, and '%return' means that it probes function return. And ';PTN' means lazy matching pattern (see LAZY MATCHING). Note that ';PTN' must be the end of the probe point definition. In addition, '@SRC' specifies a source file which has that function. It is also possible to specify a probe point by the source line number or lazy matching by using 'SRC:ALN' or 'SRC;PTN' syntax, where 'SRC' is the source file path, ':ALN' is the line number and ';PTN' is the lazy matching pattern. 'ARG' specifies the arguments of this probe point, (see PROBE ARGUMENT). +'SDTEVENT' and 'PROVIDER' is the pre-defined event name which is defined by user SDT (Statically Defined Tracing) or the pre-cached probes with event name. +Note that before using the SDT event, the target binary (on which SDT events are defined) must be scanned by linkperf:perf-buildid-cache[1] to make SDT events as cached events. + +For details of the SDT, see below. +https://sourceware.org/gdb/onlinedocs/gdb/Static-Probe-Points.html PROBE ARGUMENT -------------- @@ -237,4 +244,4 @@ Add probes at malloc() function on libc SEE ALSO -------- -linkperf:perf-trace[1], linkperf:perf-record[1] +linkperf:perf-trace[1], linkperf:perf-record[1], linkperf:perf-buildid-cache[1] diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c index fef9768..85f25d4 100644 --- a/tools/perf/util/probe-event.c +++ b/tools/perf/util/probe-event.c @@ -1197,6 +1197,34 @@ err: return err; } +static int parse_perf_probe_event_name(char **arg, struct perf_probe_event *pev) +{ + char *ptr; + + ptr = strchr(*arg, ':'); + if (ptr) { + *ptr = '\0'; + if (!is_c_func_name(*arg)) + goto ng_name; + pev->group = strdup(*arg); + if (!pev->group) + return -ENOMEM; + *arg = ptr + 1; + } else + pev->group = NULL; + if (!is_c_func_name(*arg)) { +ng_name: + semantic_error("%s is bad for event name -it must " + "follow C symbol-naming rule.\n", *arg); + return -EINVAL; + } + pev->event = strdup(*arg); + if (pev->event == NULL) + return -ENOMEM; + + return 0; +} + /* Parse probepoint definition. */ static int parse_perf_probe_point(char *arg, struct perf_probe_event *pev) { @@ -1204,38 +1232,43 @@ static int parse_perf_probe_point(char *arg, struct perf_probe_event *pev) char *ptr, *tmp; char c, nc = 0; bool file_spec = false; + int ret; + /* * * perf probe [GRP:][EVENT=]SRC[:LN|;PTN] * perf probe [GRP:][EVENT=]FUNC[@SRC][+OFFS|%return|:LN|;PAT] + * perf probe %[GRP:]SDT_EVENT */ if (!arg) return -EINVAL; + if (arg[0] == '%') { + pev->sdt = true; + arg++; + } + ptr = strpbrk(arg, ";=@+%"); - if (ptr && *ptr == '=') { /* Event name */ - *ptr = '\0'; - tmp = ptr + 1; - ptr = strchr(arg, ':'); + if (pev->sdt) { if (ptr) { - *ptr = '\0'; - if (!is_c_func_name(arg)) - goto not_fname; - pev->group = strdup(arg); - if (!pev->group) - return -ENOMEM; - arg = ptr + 1; - } else - pev->group = NULL; - if (!is_c_func_name(arg)) { -not_fname: - semantic_error("%s is bad for event name -it must " - "follow C symbol-naming rule.\n", arg); + semantic_error("%s must contain only an SDT event name.\n", arg); return -EINVAL; } - pev->event = strdup(arg); - if (pev->event == NULL) - return -ENOMEM; + ret = parse_perf_probe_event_name(&arg, pev); + if (ret == 0) { + if (asprintf(&pev->point.function, "%%%s", pev->event) < 0) + ret = -errno; + } + return ret; + } + + if (ptr && *ptr == '=') { /* Event name */ + *ptr = '\0'; + tmp = ptr + 1; + ret = parse_perf_probe_event_name(&arg, pev); + if (ret < 0) + return ret; + arg = tmp; } @@ -2876,7 +2909,8 @@ static int find_probe_trace_events_from_cache(struct perf_probe_event *pev, entry = probe_cache__find(cache, pev); if (!entry) { - ret = 0; + /* SDT must be in the cache */ + ret = pev->sdt ? -ENOENT : 0; goto out; } @@ -2915,7 +2949,7 @@ static int convert_to_probe_trace_events(struct perf_probe_event *pev, { int ret; - if (!pev->group) { + if (!pev->group && !pev->sdt) { /* Set group name if not given */ if (!pev->uprobes) { pev->group = strdup(PERFPROBE_GROUP); @@ -2934,8 +2968,8 @@ static int convert_to_probe_trace_events(struct perf_probe_event *pev, /* At first, we need to lookup cache entry */ ret = find_probe_trace_events_from_cache(pev, tevs); - if (ret > 0) - return ret; /* Found in probe cache */ + if (ret > 0 || pev->sdt) /* SDT can be found only in the cache */ + return ret == 0 ? -ENOENT : ret; /* Found in probe cache */ if (arch__prefers_symtab() && !perf_probe_event_need_dwarf(pev)) { ret = find_probe_trace_events_from_map(pev, tevs); diff --git a/tools/perf/util/probe-event.h b/tools/perf/util/probe-event.h index 432b690..e18ea9f 100644 --- a/tools/perf/util/probe-event.h +++ b/tools/perf/util/probe-event.h @@ -85,6 +85,7 @@ struct perf_probe_event { char *group; /* Group name */ struct perf_probe_point point; /* Probe point */ int nargs; /* Number of arguments */ + bool sdt; /* SDT/cached event flag */ bool uprobes; /* Uprobe event flag */ char *target; /* Target binary */ struct perf_probe_arg *args; /* Arguments */ diff --git a/tools/perf/util/probe-file.c b/tools/perf/util/probe-file.c index e705a74..fc16b17 100644 --- a/tools/perf/util/probe-file.c +++ b/tools/perf/util/probe-file.c @@ -547,6 +547,15 @@ probe_cache__find(struct probe_cache *pcache, struct perf_probe_event *pev) return NULL; list_for_each_entry(entry, &pcache->entries, node) { + if (pev->sdt) { + if (entry->pev.event && + streql(entry->pev.event, pev->event) && + (!pev->group || + streql(entry->pev.group, pev->group))) + goto found; + + continue; + } /* Hit if same event name or same command-string */ if ((pev->event && (streql(entry->pev.group, pev->group) && -- cgit v0.10.2 From c3492a3a4e58117f18d96125e67b0bed7c4231e1 Mon Sep 17 00:00:00 2001 From: Masami Hiramatsu Date: Tue, 12 Jul 2016 19:04:54 +0900 Subject: perf probe: Make --list show only available cached events Make "perf probe --cache --list" show only available cached events by checking build-id validity. E.g. without this patch: ---- $ ./perf probe --cache --add oldevent=cmd_probe $ make #(to update ./perf) $ ./perf probe --cache --add newevent=cmd_probe $ ./perf probe --cache --list /home/mhiramat/ksrc/linux/tools/perf/perf (061e90539bac69 probe_perf:newevent=cmd_probe /home/mhiramat/ksrc/linux/tools/perf/perf (c2e44d614e33e1 probe_perf:oldevent=cmd_probe ---- It shows both of old and new events but user can not use old one. With this; ---- $ ./perf probe --cache -l /home/mhiramat/ksrc/linux/tools/perf/perf (061e90539bac69 probe_perf:newevent=cmd_probe ---- This shows only new events which are on the existing binary. Signed-off-by: Masami Hiramatsu Signed-off-by: Masami Hiramatsu Cc: Ananth N Mavinakayanahalli Cc: Brendan Gregg Cc: Hemant Kumar Cc: Namhyung Kim Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/146831789417.17065.17896487479879669610.stgit@devbox Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c index c6d890a..ee5b421 100644 --- a/tools/perf/builtin-probe.c +++ b/tools/perf/builtin-probe.c @@ -370,7 +370,7 @@ static int del_perf_probe_caches(struct strfilter *filter) struct str_node *nd; int ret; - bidlist = build_id_cache__list_all(); + bidlist = build_id_cache__list_all(false); if (!bidlist) { ret = -errno; pr_debug("Failed to get buildids: %d\n", ret); diff --git a/tools/perf/util/build-id.c b/tools/perf/util/build-id.c index 1e504e4..36b4279 100644 --- a/tools/perf/util/build-id.c +++ b/tools/perf/util/build-id.c @@ -206,6 +206,31 @@ out: return ret; } +/* Check if the given build_id cache is valid on current running system */ +static bool build_id_cache__valid_id(char *sbuild_id) +{ + char real_sbuild_id[SBUILD_ID_SIZE] = ""; + char *pathname; + int ret = 0; + bool result = false; + + pathname = build_id_cache__origname(sbuild_id); + if (!pathname) + return false; + + if (!strcmp(pathname, DSO__NAME_KALLSYMS)) + ret = sysfs__sprintf_build_id("/", real_sbuild_id); + else if (pathname[0] == '/') + ret = filename__sprintf_build_id(pathname, real_sbuild_id); + else + ret = -EINVAL; /* Should we support other special DSO cache? */ + if (ret >= 0) + result = (strcmp(sbuild_id, real_sbuild_id) == 0); + free(pathname); + + return result; +} + static const char *build_id_cache__basename(bool is_kallsyms, bool is_vdso) { return is_kallsyms ? "kallsyms" : (is_vdso ? "vdso" : "elf"); @@ -433,13 +458,17 @@ static bool lsdir_bid_tail_filter(const char *name __maybe_unused, return (i == SBUILD_ID_SIZE - 3) && (d->d_name[i] == '\0'); } -struct strlist *build_id_cache__list_all(void) +struct strlist *build_id_cache__list_all(bool validonly) { struct strlist *toplist, *linklist = NULL, *bidlist; struct str_node *nd, *nd2; char *topdir, *linkdir = NULL; char sbuild_id[SBUILD_ID_SIZE]; + /* for filename__ functions */ + if (validonly) + symbol__init(NULL); + /* Open the top-level directory */ if (asprintf(&topdir, "%s/.build-id/", buildid_dir) < 0) return NULL; @@ -470,6 +499,8 @@ struct strlist *build_id_cache__list_all(void) if (snprintf(sbuild_id, SBUILD_ID_SIZE, "%s%s", nd->s, nd2->s) != SBUILD_ID_SIZE - 1) goto err_out; + if (validonly && !build_id_cache__valid_id(sbuild_id)) + continue; if (strlist__add(bidlist, sbuild_id) < 0) goto err_out; } diff --git a/tools/perf/util/build-id.h b/tools/perf/util/build-id.h index b742e27..64e740f 100644 --- a/tools/perf/util/build-id.h +++ b/tools/perf/util/build-id.h @@ -34,7 +34,7 @@ char *build_id_cache__origname(const char *sbuild_id); char *build_id_cache__linkname(const char *sbuild_id, char *bf, size_t size); char *build_id_cache__cachedir(const char *sbuild_id, const char *name, bool is_kallsyms, bool is_vdso); -struct strlist *build_id_cache__list_all(void); +struct strlist *build_id_cache__list_all(bool validonly); int build_id_cache__list_build_ids(const char *pathname, struct strlist **result); bool build_id_cache__cached(const char *sbuild_id); diff --git a/tools/perf/util/probe-file.c b/tools/perf/util/probe-file.c index fc16b17..a5059dc 100644 --- a/tools/perf/util/probe-file.c +++ b/tools/perf/util/probe-file.c @@ -808,7 +808,7 @@ int probe_cache__show_all_caches(struct strfilter *filter) pr_debug("list cache with filter: %s\n", buf); free(buf); - bidlist = build_id_cache__list_all(); + bidlist = build_id_cache__list_all(true); if (!bidlist) { pr_debug("Failed to get buildids: %d\n", errno); return -EINVAL; -- cgit v0.10.2 From 05bf2c8a2a819132b4a8f35d4315ff22e8e84a20 Mon Sep 17 00:00:00 2001 From: Masami Hiramatsu Date: Tue, 12 Jul 2016 19:05:04 +0900 Subject: perf probe-cache: Add for_each_probe_cache_entry() wrapper Add for_each_probe_cache_entry() wrapper macro for hiding list in probe_cache. Signed-off-by: Masami Hiramatsu Cc: Ananth N Mavinakayanahalli Cc: Brendan Gregg Cc: Hemant Kumar Cc: Namhyung Kim Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/146831790386.17065.15082256697569419710.stgit@devbox Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/util/probe-file.c b/tools/perf/util/probe-file.c index a5059dc..abfb05c 100644 --- a/tools/perf/util/probe-file.c +++ b/tools/perf/util/probe-file.c @@ -546,7 +546,7 @@ probe_cache__find(struct probe_cache *pcache, struct perf_probe_event *pev) if (!cmd) return NULL; - list_for_each_entry(entry, &pcache->entries, node) { + for_each_probe_cache_entry(entry, pcache) { if (pev->sdt) { if (entry->pev.event && streql(entry->pev.event, pev->event) && @@ -576,7 +576,7 @@ probe_cache__find_by_name(struct probe_cache *pcache, { struct probe_cache_entry *entry = NULL; - list_for_each_entry(entry, &pcache->entries, node) { + for_each_probe_cache_entry(entry, pcache) { /* Hit if same event name or same command-string */ if (streql(entry->pev.group, group) && streql(entry->pev.event, event)) @@ -748,7 +748,7 @@ int probe_cache__commit(struct probe_cache *pcache) if (ret < 0) goto out; - list_for_each_entry(entry, &pcache->entries, node) { + for_each_probe_cache_entry(entry, pcache) { ret = probe_cache_entry__write(entry, pcache->fd); pr_debug("Cache committed: %d\n", ret); if (ret < 0) @@ -790,7 +790,7 @@ static int probe_cache__show_entries(struct probe_cache *pcache, { struct probe_cache_entry *entry; - list_for_each_entry(entry, &pcache->entries, node) { + for_each_probe_cache_entry(entry, pcache) { if (probe_cache_entry__compare(entry, filter)) printf("%s\n", entry->spev); } diff --git a/tools/perf/util/probe-file.h b/tools/perf/util/probe-file.h index ddf5ae2..d513b34 100644 --- a/tools/perf/util/probe-file.h +++ b/tools/perf/util/probe-file.h @@ -21,6 +21,8 @@ struct probe_cache { #define PF_FL_UPROBE 1 #define PF_FL_RW 2 +#define for_each_probe_cache_entry(entry, pcache) \ + list_for_each_entry(entry, &pcache->entries, node) int probe_file__open(int flag); int probe_file__open_both(int *kfd, int *ufd, int flag); -- cgit v0.10.2 From 42bba263eb58800b6239a0cb35ac17fd29379277 Mon Sep 17 00:00:00 2001 From: Masami Hiramatsu Date: Tue, 12 Jul 2016 19:05:18 +0900 Subject: perf probe: Allow wildcard for cached events Allo glob wildcard for reusing cached/SDT events. E.g. # perf probe -x /usr/lib64/libc-2.20.so -a %sdt_libc:\* This example adds probes for all SDT in libc. Note that the SDTs must have been scanned by perf buildid-cache. Committer note: Using it to check what of those SDT probes would take place when doing a cargo run (rust): # trace --no-sys --event sdt_libc:* cargo run 0.000 sdt_libc:setjmp:(7f326b69c4d1)) 28.423 sdt_libc:setjmp:(7f4b0a5364d1)) 29.000 sdt_libc:setjmp:(7f4b0a5364d1)) 88.597 sdt_libc:setjmp:(7fc01fd414d1)) 89.220 sdt_libc:setjmp:(7fc01fd414d1)) 95.501 sdt_libc:setjmp:(7f326b69c4d1)) Running `target/debug/hello_world` 97.110 sdt_libc:setjmp:(7f95e09234d1)) Hello, world! # Signed-off-by: Masami Hiramatsu Tested-by: Arnaldo Carvalho de Melo Cc: Ananth N Mavinakayanahalli Cc: Brendan Gregg Cc: Hemant Kumar Cc: Namhyung Kim Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/146831791813.17065.17846564230840594888.stgit@devbox Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c index 85f25d4..7b96e68 100644 --- a/tools/perf/util/probe-event.c +++ b/tools/perf/util/probe-event.c @@ -1204,7 +1204,7 @@ static int parse_perf_probe_event_name(char **arg, struct perf_probe_event *pev) ptr = strchr(*arg, ':'); if (ptr) { *ptr = '\0'; - if (!is_c_func_name(*arg)) + if (!pev->sdt && !is_c_func_name(*arg)) goto ng_name; pev->group = strdup(*arg); if (!pev->group) @@ -1212,7 +1212,7 @@ static int parse_perf_probe_event_name(char **arg, struct perf_probe_event *pev) *arg = ptr + 1; } else pev->group = NULL; - if (!is_c_func_name(*arg)) { + if (!pev->sdt && !is_c_func_name(*arg)) { ng_name: semantic_error("%s is bad for event name -it must " "follow C symbol-naming rule.\n", *arg); @@ -1644,6 +1644,7 @@ int parse_probe_trace_command(const char *cmd, struct probe_trace_event *tev) ret = -ENOMEM; goto out; } + tev->uprobes = (tp->module[0] == '/'); p++; } else p = argv[1]; @@ -2518,7 +2519,7 @@ static int probe_trace_event__set_name(struct probe_trace_event *tev, int ret; /* If probe_event or trace_event already have the name, reuse it */ - if (pev->event) + if (pev->event && !pev->sdt) event = pev->event; else if (tev->event) event = tev->event; @@ -2531,7 +2532,7 @@ static int probe_trace_event__set_name(struct probe_trace_event *tev, else event = tev->point.realname; } - if (pev->group) + if (pev->group && !pev->sdt) group = pev->group; else if (tev->group) group = tev->group; @@ -2894,6 +2895,100 @@ errout: bool __weak arch__prefers_symtab(void) { return false; } +/* Concatinate two arrays */ +static void *memcat(void *a, size_t sz_a, void *b, size_t sz_b) +{ + void *ret; + + ret = malloc(sz_a + sz_b); + if (ret) { + memcpy(ret, a, sz_a); + memcpy(ret + sz_a, b, sz_b); + } + return ret; +} + +static int +concat_probe_trace_events(struct probe_trace_event **tevs, int *ntevs, + struct probe_trace_event **tevs2, int ntevs2) +{ + struct probe_trace_event *new_tevs; + int ret = 0; + + if (ntevs == 0) { + *tevs = *tevs2; + *ntevs = ntevs2; + *tevs2 = NULL; + return 0; + } + + if (*ntevs + ntevs2 > probe_conf.max_probes) + ret = -E2BIG; + else { + /* Concatinate the array of probe_trace_event */ + new_tevs = memcat(*tevs, (*ntevs) * sizeof(**tevs), + *tevs2, ntevs2 * sizeof(**tevs2)); + if (!new_tevs) + ret = -ENOMEM; + else { + free(*tevs); + *tevs = new_tevs; + *ntevs += ntevs2; + } + } + if (ret < 0) + clear_probe_trace_events(*tevs2, ntevs2); + zfree(tevs2); + + return ret; +} + +/* + * Try to find probe_trace_event from given probe caches. Return the number + * of cached events found, if an error occurs return the error. + */ +static int find_cached_events(struct perf_probe_event *pev, + struct probe_trace_event **tevs, + const char *target) +{ + struct probe_cache *cache; + struct probe_cache_entry *entry; + struct probe_trace_event *tmp_tevs = NULL; + int ntevs = 0; + int ret = 0; + + cache = probe_cache__new(target); + /* Return 0 ("not found") if the target has no probe cache. */ + if (!cache) + return 0; + + for_each_probe_cache_entry(entry, cache) { + /* Skip the cache entry which has no name */ + if (!entry->pev.event || !entry->pev.group) + continue; + if ((!pev->group || strglobmatch(entry->pev.group, pev->group)) && + strglobmatch(entry->pev.event, pev->event)) { + ret = probe_cache_entry__get_event(entry, &tmp_tevs); + if (ret > 0) + ret = concat_probe_trace_events(tevs, &ntevs, + &tmp_tevs, ret); + if (ret < 0) + break; + } + } + probe_cache__delete(cache); + if (ret < 0) { + clear_probe_trace_events(*tevs, ntevs); + zfree(tevs); + } else { + ret = ntevs; + if (ntevs > 0 && target && target[0] == '/') + pev->uprobes = true; + } + + return ret; +} + static int find_probe_trace_events_from_cache(struct perf_probe_event *pev, struct probe_trace_event **tevs) { @@ -2903,6 +2998,10 @@ static int find_probe_trace_events_from_cache(struct perf_probe_event *pev, struct str_node *node; int ret, i; + if (pev->sdt) + /* For SDT/cached events, we use special search functions */ + return find_cached_events(pev, tevs, pev->target); + cache = probe_cache__new(pev->target); if (!cache) return 0; diff --git a/tools/perf/util/probe-file.c b/tools/perf/util/probe-file.c index abfb05c..9aed9c3 100644 --- a/tools/perf/util/probe-file.c +++ b/tools/perf/util/probe-file.c @@ -362,13 +362,38 @@ probe_cache_entry__new(struct perf_probe_event *pev) return entry; } -/* For the kernel probe caches, pass target = NULL */ +int probe_cache_entry__get_event(struct probe_cache_entry *entry, + struct probe_trace_event **tevs) +{ + struct probe_trace_event *tev; + struct str_node *node; + int ret, i; + + ret = strlist__nr_entries(entry->tevlist); + if (ret > probe_conf.max_probes) + return -E2BIG; + + *tevs = zalloc(ret * sizeof(*tev)); + if (!*tevs) + return -ENOMEM; + + i = 0; + strlist__for_each_entry(node, entry->tevlist) { + tev = &(*tevs)[i++]; + ret = parse_probe_trace_command(node->s, tev); + if (ret < 0) + break; + } + return i; +} + +/* For the kernel probe caches, pass target = NULL or DSO__NAME_KALLSYMS */ static int probe_cache__open(struct probe_cache *pcache, const char *target) { char cpath[PATH_MAX]; char sbuildid[SBUILD_ID_SIZE]; char *dir_name = NULL; - bool is_kallsyms = !target; + bool is_kallsyms = false; int ret, fd; if (target && build_id_cache__cached(target)) { @@ -378,12 +403,13 @@ static int probe_cache__open(struct probe_cache *pcache, const char *target) goto found; } - if (target) - ret = filename__sprintf_build_id(target, sbuildid); - else { + if (!target || !strcmp(target, DSO__NAME_KALLSYMS)) { target = DSO__NAME_KALLSYMS; + is_kallsyms = true; ret = sysfs__sprintf_build_id("/", sbuildid); - } + } else + ret = filename__sprintf_build_id(target, sbuildid); + if (ret < 0) { pr_debug("Failed to get build-id from %s.\n", target); return ret; diff --git a/tools/perf/util/probe-file.h b/tools/perf/util/probe-file.h index d513b34..cafbe1d 100644 --- a/tools/perf/util/probe-file.h +++ b/tools/perf/util/probe-file.h @@ -34,6 +34,9 @@ int probe_file__get_events(int fd, struct strfilter *filter, struct strlist *plist); int probe_file__del_strlist(int fd, struct strlist *namelist); +int probe_cache_entry__get_event(struct probe_cache_entry *entry, + struct probe_trace_event **tevs); + struct probe_cache *probe_cache__new(const char *target); int probe_cache__add_entry(struct probe_cache *pcache, struct perf_probe_event *pev, -- cgit v0.10.2 From 1de7b8bf728fd8d51b0cc644003d0694c6e0feef Mon Sep 17 00:00:00 2001 From: Masami Hiramatsu Date: Tue, 12 Jul 2016 19:05:28 +0900 Subject: perf probe: Search SDT/cached event from all probe caches Search SDT/cached event from all probe caches if user doesn't pass any binary. With this, we don't have to specify target binary for SDT and named cached events (which start with %). E.g. without this, a target binary must be passed with -x. # perf probe -x /usr/lib64/libc-2.20.so -a %sdt_libc:\* With this change, we don't need it anymore. # perf probe -a %sdt_libc:\* Signed-off-by: Masami Hiramatsu Cc: Ananth N Mavinakayanahalli Cc: Brendan Gregg Cc: Hemant Kumar Cc: Namhyung Kim Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/146831792812.17065.2353705982669445313.stgit@devbox Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c index 7b96e68..c63e3b8 100644 --- a/tools/perf/util/probe-event.c +++ b/tools/perf/util/probe-event.c @@ -2557,41 +2557,60 @@ static int probe_trace_event__set_name(struct probe_trace_event *tev, return 0; } -static int __add_probe_trace_events(struct perf_probe_event *pev, - struct probe_trace_event *tevs, - int ntevs, bool allow_suffix) +static int __open_probe_file_and_namelist(bool uprobe, + struct strlist **namelist) { - int i, fd, ret; - struct probe_trace_event *tev = NULL; - struct probe_cache *cache = NULL; - struct strlist *namelist; + int fd; - fd = probe_file__open(PF_FL_RW | (pev->uprobes ? PF_FL_UPROBE : 0)); + fd = probe_file__open(PF_FL_RW | (uprobe ? PF_FL_UPROBE : 0)); if (fd < 0) return fd; /* Get current event names */ - namelist = probe_file__get_namelist(fd); - if (!namelist) { + *namelist = probe_file__get_namelist(fd); + if (!(*namelist)) { pr_debug("Failed to get current event list.\n"); - ret = -ENOMEM; - goto close_out; + close(fd); + return -ENOMEM; } + return fd; +} + +static int __add_probe_trace_events(struct perf_probe_event *pev, + struct probe_trace_event *tevs, + int ntevs, bool allow_suffix) +{ + int i, fd[2] = {-1, -1}, up, ret; + struct probe_trace_event *tev = NULL; + struct probe_cache *cache = NULL; + struct strlist *namelist[2] = {NULL, NULL}; + + up = pev->uprobes ? 1 : 0; + fd[up] = __open_probe_file_and_namelist(up, &namelist[up]); + if (fd[up] < 0) + return fd[up]; ret = 0; for (i = 0; i < ntevs; i++) { tev = &tevs[i]; + up = tev->uprobes ? 1 : 0; + if (fd[up] == -1) { /* Open the kprobe/uprobe_events */ + fd[up] = __open_probe_file_and_namelist(up, + &namelist[up]); + if (fd[up] < 0) + goto close_out; + } /* Skip if the symbol is out of .text or blacklisted */ if (!tev->point.symbol && !pev->uprobes) continue; /* Set new name for tev (and update namelist) */ - ret = probe_trace_event__set_name(tev, pev, namelist, + ret = probe_trace_event__set_name(tev, pev, namelist[up], allow_suffix); if (ret < 0) break; - ret = probe_file__add_event(fd, tev); + ret = probe_file__add_event(fd[up], tev); if (ret < 0) break; @@ -2614,9 +2633,12 @@ static int __add_probe_trace_events(struct perf_probe_event *pev, probe_cache__delete(cache); } - strlist__delete(namelist); close_out: - close(fd); + for (up = 0; up < 2; up++) { + strlist__delete(namelist[up]); + if (fd[up] >= 0) + close(fd[up]); + } return ret; } @@ -2989,6 +3011,48 @@ static int find_cached_events(struct perf_probe_event *pev, return ret; } +/* Try to find probe_trace_event from all probe caches */ +static int find_cached_events_all(struct perf_probe_event *pev, + struct probe_trace_event **tevs) +{ + struct probe_trace_event *tmp_tevs = NULL; + struct strlist *bidlist; + struct str_node *nd; + char *pathname; + int ntevs = 0; + int ret; + + /* Get the buildid list of all valid caches */ + bidlist = build_id_cache__list_all(true); + if (!bidlist) { + ret = -errno; + pr_debug("Failed to get buildids: %d\n", ret); + return ret; + } + + ret = 0; + strlist__for_each_entry(nd, bidlist) { + pathname = build_id_cache__origname(nd->s); + ret = find_cached_events(pev, &tmp_tevs, pathname); + /* In the case of cnt == 0, we just skip it */ + if (ret > 0) + ret = concat_probe_trace_events(tevs, &ntevs, + &tmp_tevs, ret); + free(pathname); + if (ret < 0) + break; + } + strlist__delete(bidlist); + + if (ret < 0) { + clear_probe_trace_events(*tevs, ntevs); + zfree(tevs); + } else + ret = ntevs; + + return ret; +} + static int find_probe_trace_events_from_cache(struct perf_probe_event *pev, struct probe_trace_event **tevs) { @@ -2998,10 +3062,13 @@ static int find_probe_trace_events_from_cache(struct perf_probe_event *pev, struct str_node *node; int ret, i; - if (pev->sdt) + if (pev->sdt) { /* For SDT/cached events, we use special search functions */ - return find_cached_events(pev, tevs, pev->target); - + if (!pev->target) + return find_cached_events_all(pev, tevs); + else + return find_cached_events(pev, tevs, pev->target); + } cache = probe_cache__new(pev->target); if (!cache) return 0; -- cgit v0.10.2 From 40218daea1db1f95f1f10e58ebd43b8adf1c6c61 Mon Sep 17 00:00:00 2001 From: Masami Hiramatsu Date: Fri, 24 Jun 2016 18:06:46 +0900 Subject: perf list: Show SDT and pre-cached events Show SDT and pre-cached events by perf-list with "sdt". This also shows the binary and build-id where the events are placed only when there are same name events on different binaries. e.g.: # perf list sdt List of pre-defined events (to be used in -e): sdt_libc:lll_futex_wake [SDT event] sdt_libc:lll_lock_wait_private [SDT event] sdt_libc:longjmp [SDT event] sdt_libc:longjmp_target [SDT event] ... sdt_libstdcxx:rethrow@/usr/bin/gcc(0cc207fc4b27) [SDT event] sdt_libstdcxx:rethrow@/usr/lib64/libstdc++.so.6.0.20(91c7a88fdf49) sdt_libstdcxx:throw@/usr/bin/gcc(0cc207fc4b27) [SDT event] sdt_libstdcxx:throw@/usr/lib64/libstdc++.so.6.0.20(91c7a88fdf49) The binary path and build-id are shown in below format; :@() Signed-off-by: Masami Hiramatsu Signed-off-by: Masami Hiramatsu Tested-by: Arnaldo Carvalho de Melo Cc: Ananth N Mavinakayanahalli Cc: Brendan Gregg Cc: Hemant Kumar Cc: Namhyung Kim Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/20160624090646.25421.44225.stgit@devbox Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/builtin-list.c b/tools/perf/builtin-list.c index 5e22db4..88ee419 100644 --- a/tools/perf/builtin-list.c +++ b/tools/perf/builtin-list.c @@ -25,7 +25,7 @@ int cmd_list(int argc, const char **argv, const char *prefix __maybe_unused) OPT_END() }; const char * const list_usage[] = { - "perf list [hw|sw|cache|tracepoint|pmu|event_glob]", + "perf list [hw|sw|cache|tracepoint|pmu|sdt|event_glob]", NULL }; @@ -62,6 +62,8 @@ int cmd_list(int argc, const char **argv, const char *prefix __maybe_unused) print_hwcache_events(NULL, raw_dump); else if (strcmp(argv[i], "pmu") == 0) print_pmu_events(NULL, raw_dump); + else if (strcmp(argv[i], "sdt") == 0) + print_sdt_events(NULL, NULL, raw_dump); else if ((sep = strchr(argv[i], ':')) != NULL) { int sep_idx; @@ -76,6 +78,7 @@ int cmd_list(int argc, const char **argv, const char *prefix __maybe_unused) s[sep_idx] = '\0'; print_tracepoint_events(s, s + sep_idx + 1, raw_dump); + print_sdt_events(s, s + sep_idx + 1, raw_dump); free(s); } else { if (asprintf(&s, "*%s*", argv[i]) < 0) { @@ -89,6 +92,7 @@ int cmd_list(int argc, const char **argv, const char *prefix __maybe_unused) print_hwcache_events(s, raw_dump); print_pmu_events(s, raw_dump); print_tracepoint_events(NULL, s, raw_dump); + print_sdt_events(NULL, s, raw_dump); free(s); } } diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index 6b4fff3..375af0e 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -20,6 +20,7 @@ #include "pmu.h" #include "thread_map.h" #include "cpumap.h" +#include "probe-file.h" #include "asm/bug.h" #define MAX_NAME_LEN 100 @@ -1984,6 +1985,85 @@ static bool is_event_supported(u8 type, unsigned config) return ret; } +void print_sdt_events(const char *subsys_glob, const char *event_glob, + bool name_only) +{ + struct probe_cache *pcache; + struct probe_cache_entry *ent; + struct strlist *bidlist, *sdtlist; + struct strlist_config cfg = {.dont_dupstr = true}; + struct str_node *nd, *nd2; + char *buf, *path, *ptr = NULL; + bool show_detail = false; + int ret; + + sdtlist = strlist__new(NULL, &cfg); + if (!sdtlist) { + pr_debug("Failed to allocate new strlist for SDT\n"); + return; + } + bidlist = build_id_cache__list_all(true); + if (!bidlist) { + pr_debug("Failed to get buildids: %d\n", errno); + return; + } + strlist__for_each_entry(nd, bidlist) { + pcache = probe_cache__new(nd->s); + if (!pcache) + continue; + list_for_each_entry(ent, &pcache->entries, node) { + if (!ent->sdt) + continue; + if (subsys_glob && + !strglobmatch(ent->pev.group, subsys_glob)) + continue; + if (event_glob && + !strglobmatch(ent->pev.event, event_glob)) + continue; + ret = asprintf(&buf, "%s:%s@%s", ent->pev.group, + ent->pev.event, nd->s); + if (ret > 0) + strlist__add(sdtlist, buf); + } + probe_cache__delete(pcache); + } + strlist__delete(bidlist); + + strlist__for_each_entry(nd, sdtlist) { + buf = strchr(nd->s, '@'); + if (buf) + *(buf++) = '\0'; + if (name_only) { + printf("%s ", nd->s); + continue; + } + nd2 = strlist__next(nd); + if (nd2) { + ptr = strchr(nd2->s, '@'); + if (ptr) + *ptr = '\0'; + if (strcmp(nd->s, nd2->s) == 0) + show_detail = true; + } + if (show_detail) { + path = build_id_cache__origname(buf); + ret = asprintf(&buf, "%s@%s(%.12s)", nd->s, path, buf); + if (ret > 0) { + printf(" %-50s [%s]\n", buf, "SDT event"); + free(buf); + } + } else + printf(" %-50s [%s]\n", nd->s, "SDT event"); + if (nd2) { + if (strcmp(nd->s, nd2->s) != 0) + show_detail = false; + if (ptr) + *ptr = '@'; + } + } + strlist__delete(sdtlist); +} + int print_hwcache_events(const char *event_glob, bool name_only) { unsigned int type, op, i, evt_i = 0, evt_num = 0; @@ -2166,6 +2246,8 @@ void print_events(const char *event_glob, bool name_only) } print_tracepoint_events(NULL, NULL, name_only); + + print_sdt_events(NULL, NULL, name_only); } int parse_events__is_hardcoded_term(struct parse_events_term *term) diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h index 0bd664d..b4aa7eb 100644 --- a/tools/perf/util/parse-events.h +++ b/tools/perf/util/parse-events.h @@ -183,6 +183,8 @@ void print_symbol_events(const char *event_glob, unsigned type, void print_tracepoint_events(const char *subsys_glob, const char *event_glob, bool name_only); int print_hwcache_events(const char *event_glob, bool name_only); +void print_sdt_events(const char *subsys_glob, const char *event_glob, + bool name_only); int is_valid_tracepoint(const char *event_string); int valid_event_mount(const char *eventfs); diff --git a/tools/perf/util/probe-file.h b/tools/perf/util/probe-file.h index cafbe1d..9577b5c 100644 --- a/tools/perf/util/probe-file.h +++ b/tools/perf/util/probe-file.h @@ -24,6 +24,8 @@ struct probe_cache { #define for_each_probe_cache_entry(entry, pcache) \ list_for_each_entry(entry, &pcache->entries, node) +/* probe-file.c depends on libelf */ +#ifdef HAVE_LIBELF_SUPPORT int probe_file__open(int flag); int probe_file__open_both(int *kfd, int *ufd, int flag); struct strlist *probe_file__get_namelist(int fd); @@ -52,4 +54,11 @@ struct probe_cache_entry *probe_cache__find(struct probe_cache *pcache, struct probe_cache_entry *probe_cache__find_by_name(struct probe_cache *pcache, const char *group, const char *event); int probe_cache__show_all_caches(struct strfilter *filter); +#else /* ! HAVE_LIBELF_SUPPORT */ +static inline struct probe_cache *probe_cache__new(const char *tgt __maybe_unused) +{ + return NULL; +} +#define probe_cache__delete(pcache) do {} while (0) +#endif #endif -- cgit v0.10.2 From a598180aa1279bac4d24dfc85cd2d78553c4210d Mon Sep 17 00:00:00 2001 From: Masami Hiramatsu Date: Tue, 12 Jul 2016 19:05:37 +0900 Subject: perf probe: Support @BUILDID or @FILE suffix for SDT events Support @BUILDID or @FILE suffix for SDT events. This allows perf to add probes on SDTs/pre-cached events on given FILE or the file which has given BUILDID (also, this complements BUILDID.) For example, both gcc and libstdc++ has same SDTs as below. If you would like to add a probe on sdt_libstdcxx:catch on gcc, you can do as below. ---- # perf list sdt | tail -n 6 sdt_libstdcxx:catch@/usr/bin/gcc(0cc207fc4b27) [SDT event] sdt_libstdcxx:catch@/usr/lib64/libstdc++.so.6.0.20(91c7a88fdf49) sdt_libstdcxx:rethrow@/usr/bin/gcc(0cc207fc4b27) [SDT event] sdt_libstdcxx:rethrow@/usr/lib64/libstdc++.so.6.0.20(91c7a88fdf49) sdt_libstdcxx:throw@/usr/bin/gcc(0cc207fc4b27) [SDT event] sdt_libstdcxx:throw@/usr/lib64/libstdc++.so.6.0.20(91c7a88fdf49) # perf probe -a %sdt_libstdcxx:catch@0cc Added new event: sdt_libstdcxx:catch (on %catch in /usr/bin/gcc) You can now use it in all perf tools, such as: perf record -e sdt_libstdcxx:catch -aR sleep 1 ---- Committer note: Doing the full sequence of steps to get the results above: With a clean build-id cache: [root@jouet ~]# rm -rf ~/.debug/ [root@jouet ~]# perf list sdt List of pre-defined events (to be used in -e): [root@jouet ~]# No events whatsoever, then, we can add all events in gcc to the build-id cache, doing a --add + --dry-run: [root@jouet ~]# perf probe --dry-run --cache -x /usr/bin/gcc --add %sdt_libstdcxx:\* Added new events: sdt_libstdcxx:throw (on %* in /usr/bin/gcc) sdt_libstdcxx:rethrow (on %* in /usr/bin/gcc) sdt_libstdcxx:catch (on %* in /usr/bin/gcc) You can now use it in all perf tools, such as: perf record -e sdt_libstdcxx:catch -aR sleep 1 [root@jouet ~]# It really didn't add any events, it just cached them: [root@jouet ~]# perf probe -l [root@jouet ~]# We can see that it was cached as: [root@jouet ~]# ls -la ~/.debug/usr/bin/gcc/9a0730e2bcc6d2a2003d21ac46807e8ee6bcb7c2/ total 976 drwxr-xr-x. 2 root root 4096 Jul 13 21:47 . drwxr-xr-x. 3 root root 4096 Jul 13 21:47 .. -rwxr-xr-x. 4 root root 985912 Jun 22 18:52 elf -rw-r--r--. 1 root root 303 Jul 13 21:47 probes [root@jouet ~]# file ~/.debug/usr/bin/gcc/9a0730e2bcc6d2a2003d21ac46807e8ee6bcb7c2/elf /root/.debug/usr/bin/gcc/9a0730e2bcc6d2a2003d21ac46807e8ee6bcb7c2/elf: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=9a0730e2bcc6d2a2003d21ac46807e8ee6bcb7c2, stripped [root@jouet ~]# cat ~/.debug/usr/bin/gcc/9a0730e2bcc6d2a2003d21ac46807e8ee6bcb7c2/probes %sdt_libstdcxx:throw=throw p:sdt_libstdcxx/throw /usr/bin/gcc:0x71ffd %sdt_libstdcxx:rethrow=rethrow p:sdt_libstdcxx/rethrow /usr/bin/gcc:0x720b8 %sdt_libstdcxx:catch=catch p:sdt_libstdcxx/catch /usr/bin/gcc:0x7307f %sdt_libgcc:unwind=unwind p:sdt_libgcc/unwind /usr/bin/gcc:0x7eec0 #sdt_libstdcxx:*=%* [root@jouet ~]# Ok, now we can use 'perf probe' to refer to those cached entries as: Humm, nope, doing as above we end up with: [root@jouet ~]# perf probe -a %sdt_libstdcxx:catch Semantic error :* is bad for event name -it must follow C symbol-naming rule. Error: Failed to add events. [root@jouet ~]# But it worked at some point, lets try not using --dry-run: Resetting everything: # rm -rf ~/.debug/ # perf probe -d *:* # perf probe -l # perf list sdt List of pre-defined events (to be used in -e): # Ok, now it cached everything, even things we haven't asked it to (sdt_libgcc:unwind): [root@jouet ~]# perf probe -x /usr/bin/gcc --add %sdt_libstdcxx:\* Added new events: sdt_libstdcxx:throw (on %* in /usr/bin/gcc) sdt_libstdcxx:rethrow (on %* in /usr/bin/gcc) sdt_libstdcxx:catch (on %* in /usr/bin/gcc) You can now use it in all perf tools, such as: perf record -e sdt_libstdcxx:catch -aR sleep 1 [root@jouet ~]# perf list sdt List of pre-defined events (to be used in -e): sdt_libgcc:unwind [SDT event] sdt_libstdcxx:catch [SDT event] sdt_libstdcxx:rethrow [SDT event] sdt_libstdcxx:throw [SDT event] [root@jouet ~]# And we have the events in place: [root@jouet ~]# perf probe -l sdt_libstdcxx:catch (on execute_cfa_program+1551@../../../libgcc/unwind-dw2.c in /usr/bin/gcc) sdt_libstdcxx:rethrow (on d_print_subexpr+280@libsupc++/cp-demangle.c in /usr/bin/gcc) sdt_libstdcxx:throw (on d_print_subexpr+93@libsupc++/cp-demangle.c in /usr/bin/gcc) [root@jouet ~]# And trying to use them at least has 'perf trace --event sdt*:*' working. Then, if we try to add the ones in libstdc++: [root@jouet ~]# perf probe -x /usr/lib64/libstdc++.so.6 -a %sdt_libstdcxx:\* Error: event "catch" already exists. Hint: Remove existing event by 'perf probe -d' or force duplicates by 'perf probe -f' or set 'force=yes' in BPF source. Error: Failed to add events. [root@jouet ~]# Doesn't work, dups, but at least this served to, unbeknownst to the user, add the SDT probes in /usr/lib64/libstdc++.so.6! [root@jouet ~]# perf list sdt List of pre-defined events (to be used in -e): sdt_libgcc:unwind [SDT event] sdt_libstdcxx:catch@/usr/bin/gcc(9a0730e2bcc6) [SDT event] sdt_libstdcxx:catch@/usr/lib64/libstdc++.so.6.0.22(ef2b7066559a) [SDT event] sdt_libstdcxx:rethrow@/usr/bin/gcc(9a0730e2bcc6) [SDT event] sdt_libstdcxx:rethrow@/usr/lib64/libstdc++.so.6.0.22(ef2b7066559a) [SDT event] sdt_libstdcxx:throw@/usr/bin/gcc(9a0730e2bcc6) [SDT event] sdt_libstdcxx:throw@/usr/lib64/libstdc++.so.6.0.22(ef2b7066559a) [SDT event] [root@jouet ~]# Now we should be able to get to the original cset comment, if we remove all SDTs events in place, not from the cache, from the kernel, where it was set up as: [root@jouet ~]# ls -la /sys/kernel/debug/tracing/events/sdt_libstdcxx/ total 0 drwxr-xr-x. 5 root root 0 Jul 13 22:00 . drwxr-xr-x. 80 root root 0 Jul 13 21:56 .. drwxr-xr-x. 2 root root 0 Jul 13 22:00 catch -rw-r--r--. 1 root root 0 Jul 13 22:00 enable -rw-r--r--. 1 root root 0 Jul 13 22:00 filter drwxr-xr-x. 2 root root 0 Jul 13 22:00 rethrow drwxr-xr-x. 2 root root 0 Jul 13 22:00 throw [root@jouet ~]# [root@jouet ~]# head -2 /sys/kernel/debug/tracing/events/sdt_libstdcxx/throw/format name: throw ID: 2059 [root@jouet ~]# Now to remove it: [root@jouet ~]# perf probe -d sdt_libstdc*:* Removed event: sdt_libstdcxx:catch Removed event: sdt_libstdcxx:rethrow Removed event: sdt_libstdcxx:throw [root@jouet ~]# Which caused: [root@jouet ~]# ls -la /sys/kernel/debug/tracing/events/sdt_libstdcxx/ ls: cannot access '/sys/kernel/debug/tracing/events/sdt_libstdcxx/': No such file or directory [root@jouet ~]# Ok, now we can do: [root@jouet ~]# perf list sdt_libstdcxx:catch List of pre-defined events (to be used in -e): sdt_libstdcxx:catch@/usr/bin/gcc(9a0730e2bcc6) [SDT event] sdt_libstdcxx:catch@/usr/lib64/libstdc++.so.6.0.22(ef2b7066559a) [SDT event] [root@jouet ~]# So, these are not really 'pre-defined events', i.e. we can't use them with 'perf record --event': [root@jouet ~]# perf record --event sdt_libstdcxx:catch* event syntax error: 'sdt_libstdcxx:catch*' \___ unknown tracepoint Error: File /sys/kernel/debug/tracing/events/sdt_libstdcxx/catch* not found. Hint: Perhaps this kernel misses some CONFIG_ setting to enable this feature?. [root@jouet ~]# To have it really pre-defined we must use perf probe to get its definition from the cache and set it up in the kernel, creating the tracepoint to _then_ use it with 'perf record --event': [root@jouet ~]# perf probe -a sdt_libstdcxx:catch Semantic error :There is non-digit char in line number. Oops, there is another gotcha here, we need that pesky '%' character: [root@jouet ~]# perf probe -a %sdt_libstdcxx:catch Added new events: sdt_libstdcxx:catch (on %catch in /usr/bin/gcc) sdt_libstdcxx:catch_1 (on %catch in /usr/lib64/libstdc++.so.6.0.22) You can now use it in all perf tools, such as: perf record -e sdt_libstdcxx:catch_1 -aR sleep 1 [root@jouet ~]# But then we added _two_ events, one with the name we expected, the other one with a _ added, when doing the analysis we need to pay attention to who maps to who. And here is where we get to the point of this patch, which is to be able to disambiguate those definitions for 'catch' in the build-id cache, but first we need remove those events we just added: [root@jouet ~]# perf probe -d %sdt_libstdcxx:catch Oops, that didn't remove anything, we need to _remove_ that % char in this case: [root@jouet ~]# perf probe -d sdt_libstdcxx:catch Removed event: sdt_libstdcxx:catch And we need to remove the other event added, i.e. I forgot to add a * at the end: [root@jouet ~]# perf probe -d sdt_libstdcxx:catch* Removed event: sdt_libstdcxx:catch_1 [root@jouet ~]# Ok, disambiguating it using what is in this patch: [root@jouet ~]# perf list sdt_libstdcxx:catch List of pre-defined events (to be used in -e): sdt_libstdcxx:catch@/usr/bin/gcc(9a0730e2bcc6) [SDT event] sdt_libstdcxx:catch@/usr/lib64/libstdc++.so.6.0.22(ef2b7066559a) [SDT event] [root@jouet ~]# [root@jouet ~]# perf probe -a %sdt_libstdcxx:catch@9a07 Added new event: sdt_libstdcxx:catch (on %catch in /usr/bin/gcc) You can now use it in all perf tools, such as: perf record -e sdt_libstdcxx:catch -aR sleep 1 [root@jouet ~]# perf probe -l sdt_libstdcxx:catch (on execute_cfa_program+1551@../../../libgcc/unwind-dw2.c in /usr/bin/gcc) [root@jouet ~]# Yeah, it works! But we need to try and simplify this :-) Update: Some aspects of this simplification take place in the following patches. Signed-off-by: Masami Hiramatsu Tested-by: Arnaldo Carvalho de Melo Cc: Ananth N Mavinakayanahalli Cc: Brendan Gregg Cc: Hemant Kumar Cc: Namhyung Kim Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/146831793746.17065.13065062753978236612.stgit@devbox Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/util/build-id.c b/tools/perf/util/build-id.c index 36b4279..5651f3c 100644 --- a/tools/perf/util/build-id.c +++ b/tools/perf/util/build-id.c @@ -523,6 +523,49 @@ err_out: goto out_free; } +static bool str_is_build_id(const char *maybe_sbuild_id, size_t len) +{ + size_t i; + + for (i = 0; i < len; i++) { + if (!isxdigit(maybe_sbuild_id[i])) + return false; + } + return true; +} + +/* Return the valid complete build-id */ +char *build_id_cache__complement(const char *incomplete_sbuild_id) +{ + struct strlist *bidlist; + struct str_node *nd, *cand = NULL; + char *sbuild_id = NULL; + size_t len = strlen(incomplete_sbuild_id); + + if (len >= SBUILD_ID_SIZE || + !str_is_build_id(incomplete_sbuild_id, len)) + return NULL; + + bidlist = build_id_cache__list_all(true); + if (!bidlist) + return NULL; + + strlist__for_each_entry(nd, bidlist) { + if (strncmp(nd->s, incomplete_sbuild_id, len) != 0) + continue; + if (cand) { /* Error: There are more than 2 candidates. */ + cand = NULL; + break; + } + cand = nd; + } + if (cand) + sbuild_id = strdup(cand->s); + strlist__delete(bidlist); + + return sbuild_id; +} + char *build_id_cache__cachedir(const char *sbuild_id, const char *name, bool is_kallsyms, bool is_vdso) { diff --git a/tools/perf/util/build-id.h b/tools/perf/util/build-id.h index 64e740f..d279906 100644 --- a/tools/perf/util/build-id.h +++ b/tools/perf/util/build-id.h @@ -35,6 +35,7 @@ char *build_id_cache__linkname(const char *sbuild_id, char *bf, size_t size); char *build_id_cache__cachedir(const char *sbuild_id, const char *name, bool is_kallsyms, bool is_vdso); struct strlist *build_id_cache__list_all(bool validonly); +char *build_id_cache__complement(const char *incomplete_sbuild_id); int build_id_cache__list_build_ids(const char *pathname, struct strlist **result); bool build_id_cache__cached(const char *sbuild_id); diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c index c63e3b8..f12081e 100644 --- a/tools/perf/util/probe-event.c +++ b/tools/perf/util/probe-event.c @@ -1251,8 +1251,21 @@ static int parse_perf_probe_point(char *arg, struct perf_probe_event *pev) ptr = strpbrk(arg, ";=@+%"); if (pev->sdt) { if (ptr) { - semantic_error("%s must contain only an SDT event name.\n", arg); - return -EINVAL; + if (*ptr != '@') { + semantic_error("%s must be an SDT name.\n", + arg); + return -EINVAL; + } + /* This must be a target file name or build id */ + tmp = build_id_cache__complement(ptr + 1); + if (tmp) { + pev->target = build_id_cache__origname(tmp); + free(tmp); + } else + pev->target = strdup(ptr + 1); + if (!pev->target) + return -ENOMEM; + *ptr = '\0'; } ret = parse_perf_probe_event_name(&arg, pev); if (ret == 0) { -- cgit v0.10.2 From 7e9fca51fbf8430e27fb6b29299eda575e3f00cf Mon Sep 17 00:00:00 2001 From: Masami Hiramatsu Date: Tue, 12 Jul 2016 19:05:46 +0900 Subject: perf probe: Support a special SDT probe format Support a special SDT probe format which can omit the '%' prefix only if the SDT group name starts with "sdt_". So, for example both of "%sdt_libc:setjump" and "sdt_libc:setjump" are acceptable for perf probe --add. E.g. without this: # perf probe -a sdt_libc:setjmp Semantic error :There is non-digit char in line number. ... With this: # perf probe -a sdt_libc:setjmp Added new event: sdt_libc:setjmp (on %setjmp in /usr/lib64/libc-2.20.so) You can now use it in all perf tools, such as: perf record -e sdt_libc:setjmp -aR sleep 1 Suggested-by: Brendan Gregg Signed-off-by: Masami Hiramatsu Tested-by: Arnaldo Carvalho de Melo Cc: Ananth N Mavinakayanahalli Cc: Brendan Gregg Cc: Hemant Kumar Cc: Namhyung Kim Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/146831794674.17065.13359473252168740430.stgit@devbox Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/Documentation/perf-probe.txt b/tools/perf/Documentation/perf-probe.txt index 39e3870..736da44 100644 --- a/tools/perf/Documentation/perf-probe.txt +++ b/tools/perf/Documentation/perf-probe.txt @@ -152,7 +152,9 @@ Probe points are defined by following syntax. [[GROUP:]EVENT=]SRC;PTN [ARG ...] 4) Pre-defined SDT events or cached event with name - %[PROVIDER:]SDTEVENT + %[sdt_PROVIDER:]SDTEVENT + or, + sdt_PROVIDER:SDTEVENT 'EVENT' specifies the name of new event, if omitted, it will be set the name of the probed function. You can also specify a group name by 'GROUP', if omitted, set 'probe' is used for kprobe and 'probe_' is used for uprobe. Note that using existing group name can conflict with other events. Especially, using the group name reserved for kernel modules can hide embedded events in the diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c index f12081e..d4f8835 100644 --- a/tools/perf/util/probe-event.c +++ b/tools/perf/util/probe-event.c @@ -1243,9 +1243,17 @@ static int parse_perf_probe_point(char *arg, struct perf_probe_event *pev) if (!arg) return -EINVAL; - if (arg[0] == '%') { + /* + * If the probe point starts with '%', + * or starts with "sdt_" and has a ':' but no '=', + * then it should be a SDT/cached probe point. + */ + if (arg[0] == '%' || + (!strncmp(arg, "sdt_", 4) && + !!strchr(arg, ':') && !strchr(arg, '='))) { pev->sdt = true; - arg++; + if (arg[0] == '%') + arg++; } ptr = strpbrk(arg, ";=@+%"); -- cgit v0.10.2 From e26e63be64a108c1fd12020b93b5b447ffe0532b Mon Sep 17 00:00:00 2001 From: Masami Hiramatsu Date: Tue, 12 Jul 2016 19:05:56 +0900 Subject: perf build: Add sdt feature detection This checks whether sys/sdt.h is available or not, which is required for DTRACE_PROBE(). We can disable this feature by passing NO_SDT=1 when building. This flag will be used for SDT test case and further SDT events in perftools. Signed-off-by: Masami Hiramatsu Cc: Ananth N Mavinakayanahalli Cc: Brendan Gregg Cc: Hemant Kumar Cc: Namhyung Kim Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/146831795615.17065.17513820540591053933.stgit@devbox Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/build/Makefile.feature b/tools/build/Makefile.feature index fe12bee..a120c6b 100644 --- a/tools/build/Makefile.feature +++ b/tools/build/Makefile.feature @@ -62,7 +62,8 @@ FEATURE_TESTS_BASIC := \ zlib \ lzma \ get_cpuid \ - bpf + bpf \ + sdt # FEATURE_TESTS_BASIC + FEATURE_TESTS_EXTRA is the complete list # of all feature tests diff --git a/tools/build/feature/Makefile b/tools/build/feature/Makefile index d6017c1..a0b29a3 100644 --- a/tools/build/feature/Makefile +++ b/tools/build/feature/Makefile @@ -45,7 +45,8 @@ FILES= \ test-zlib.bin \ test-lzma.bin \ test-bpf.bin \ - test-get_cpuid.bin + test-get_cpuid.bin \ + test-sdt.bin FILES := $(addprefix $(OUTPUT),$(FILES)) @@ -213,6 +214,9 @@ $(OUTPUT)test-get_cpuid.bin: $(OUTPUT)test-bpf.bin: $(BUILD) +$(OUTPUT)test-sdt.bin: + $(BUILD) + -include $(OUTPUT)*.d ############################### diff --git a/tools/build/feature/test-all.c b/tools/build/feature/test-all.c index 843aed0..699e436 100644 --- a/tools/build/feature/test-all.c +++ b/tools/build/feature/test-all.c @@ -145,6 +145,10 @@ # include "test-libcrypto.c" #undef main +#define main main_test_sdt +# include "test-sdt.c" +#undef main + int main(int argc, char *argv[]) { main_test_libpython(); @@ -178,6 +182,7 @@ int main(int argc, char *argv[]) main_test_get_cpuid(); main_test_bpf(); main_test_libcrypto(); + main_test_sdt(); return 0; } diff --git a/tools/build/feature/test-sdt.c b/tools/build/feature/test-sdt.c new file mode 100644 index 0000000..e4531a6 --- /dev/null +++ b/tools/build/feature/test-sdt.c @@ -0,0 +1,7 @@ +#include + +int main(void) +{ + DTRACE_PROBE(provider, name); + return 0; +} diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf index feb2c66..a129fbc 100644 --- a/tools/perf/Makefile.perf +++ b/tools/perf/Makefile.perf @@ -81,6 +81,9 @@ include ../scripts/utilities.mak # # Define NO_LIBBPF if you do not want BPF support # +# Define NO_SDT if you do not want to define SDT event in perf tools, +# note that it doesn't disable SDT scanning support. +# # Define FEATURES_DUMP to provide features detection dump file # and bypass the feature detection diff --git a/tools/perf/config/Makefile b/tools/perf/config/Makefile index 5ac4280..24803c5 100644 --- a/tools/perf/config/Makefile +++ b/tools/perf/config/Makefile @@ -355,6 +355,16 @@ ifndef NO_LIBELF endif # NO_LIBBPF endif # NO_LIBELF +ifndef NO_SDT + ifneq ($(feature-sdt), 1) + msg := $(warning No sys/sdt.h found, no SDT events are defined, please install systemtap-sdt-devel or systemtap-sdt-dev); + NO_SDT := 1; + else + CFLAGS += -DHAVE_SDT_EVENT + $(call detected,CONFIG_SDT_EVENT) + endif +endif + ifdef PERF_HAVE_JITDUMP ifndef NO_DWARF $(call detected,CONFIG_JITDUMP) diff --git a/tools/perf/tests/make b/tools/perf/tests/make index 51966d9..143f4d5 100644 --- a/tools/perf/tests/make +++ b/tools/perf/tests/make @@ -82,6 +82,7 @@ make_no_auxtrace := NO_AUXTRACE=1 make_no_libbpf := NO_LIBBPF=1 make_no_libcrypto := NO_LIBCRYPTO=1 make_with_babeltrace:= LIBBABELTRACE=1 +make_no_sdt := NO_SDT=1 make_tags := tags make_cscope := cscope make_help := help @@ -105,7 +106,7 @@ make_minimal := NO_LIBPERL=1 NO_LIBPYTHON=1 NO_NEWT=1 NO_GTK2=1 make_minimal += NO_DEMANGLE=1 NO_LIBELF=1 NO_LIBUNWIND=1 NO_BACKTRACE=1 make_minimal += NO_LIBNUMA=1 NO_LIBAUDIT=1 NO_LIBBIONIC=1 make_minimal += NO_LIBDW_DWARF_UNWIND=1 NO_AUXTRACE=1 NO_LIBBPF=1 -make_minimal += NO_LIBCRYPTO=1 +make_minimal += NO_LIBCRYPTO=1 NO_SDT=1 # $(run) contains all available tests run := make_pure -- cgit v0.10.2 From 8e5dc848356ecf6ea8d27d641c4d7ad8d42fe92b Mon Sep 17 00:00:00 2001 From: Masami Hiramatsu Date: Tue, 12 Jul 2016 19:06:05 +0900 Subject: perf test: Add a test case for SDT event Add a basic test case for SDT event support. This test scans an SDT event in perftools and check whether the SDT event is correctly stored into the buildid cache. Here is an example: ---- $ perf test sdt -v 47: Test SDT event probing : --- start --- test child forked, pid 20732 Found 72 SDTs in /home/mhiramat/ksrc/linux/tools/perf/perf Writing cache: %sdt_perf:test_target=test_target Cache committed: 0 symbol:test_target file:(null) line:0 offset:0 return:0 lazy:(null) test child finished with 0 ---- end ---- Test SDT event probing: Ok ---- Signed-off-by: Masami Hiramatsu Tested-by: Arnaldo Carvalho de Melo Cc: Ananth N Mavinakayanahalli Cc: Brendan Gregg Cc: Hemant Kumar Cc: Namhyung Kim Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/146831796546.17065.1502584370844087537.stgit@devbox Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/tests/Build b/tools/perf/tests/Build index 66a2898..4158422 100644 --- a/tools/perf/tests/Build +++ b/tools/perf/tests/Build @@ -39,6 +39,7 @@ perf-y += stat.o perf-y += event_update.o perf-y += event-times.o perf-y += backward-ring-buffer.o +perf-y += sdt.o $(OUTPUT)tests/llvm-src-base.c: tests/bpf-script-example.c tests/Build $(call rule_mkdir) diff --git a/tools/perf/tests/builtin-test.c b/tools/perf/tests/builtin-test.c index c23cbf7..4dd2d05 100644 --- a/tools/perf/tests/builtin-test.c +++ b/tools/perf/tests/builtin-test.c @@ -218,6 +218,10 @@ static struct test generic_tests[] = { .func = test__cpu_map_print, }, { + .desc = "Test SDT event probing", + .func = test__sdt_event, + }, + { .func = NULL, }, }; diff --git a/tools/perf/tests/sdt.c b/tools/perf/tests/sdt.c new file mode 100644 index 0000000..f59d210 --- /dev/null +++ b/tools/perf/tests/sdt.c @@ -0,0 +1,115 @@ +#include +#include +#include +#include +#include +#include "tests.h" +#include "debug.h" +#include "probe-file.h" +#include "build-id.h" + +/* To test SDT event, we need libelf support to scan elf binary */ +#if defined(HAVE_SDT_EVENT) && defined(HAVE_LIBELF_SUPPORT) + +#include + +static int target_function(void) +{ + DTRACE_PROBE(perf, test_target); + return TEST_OK; +} + +/* Copied from builtin-buildid-cache.c */ +static int build_id_cache__add_file(const char *filename) +{ + char sbuild_id[SBUILD_ID_SIZE]; + u8 build_id[BUILD_ID_SIZE]; + int err; + + err = filename__read_build_id(filename, &build_id, sizeof(build_id)); + if (err < 0) { + pr_debug("Failed to read build id of %s\n", filename); + return err; + } + + build_id__sprintf(build_id, sizeof(build_id), sbuild_id); + err = build_id_cache__add_s(sbuild_id, filename, false, false); + if (err < 0) + pr_debug("Failed to add build id cache of %s\n", filename); + return err; +} + +static char *get_self_path(void) +{ + char *buf = calloc(PATH_MAX, sizeof(char)); + + if (buf && readlink("/proc/self/exe", buf, PATH_MAX) < 0) { + pr_debug("Failed to get correct path of perf\n"); + free(buf); + return NULL; + } + return buf; +} + +static int search_cached_probe(const char *target, + const char *group, const char *event) +{ + struct probe_cache *cache = probe_cache__new(target); + int ret = 0; + + if (!cache) { + pr_debug("Failed to open probe cache of %s\n", target); + return -EINVAL; + } + + if (!probe_cache__find_by_name(cache, group, event)) { + pr_debug("Failed to find %s:%s in the cache\n", group, event); + ret = -ENOENT; + } + probe_cache__delete(cache); + + return ret; +} + +int test__sdt_event(int subtests __maybe_unused) +{ + int ret = TEST_FAIL; + char __tempdir[] = "./test-buildid-XXXXXX"; + char *tempdir = NULL, *myself = get_self_path(); + + if (myself == NULL || mkdtemp(__tempdir) == NULL) { + pr_debug("Failed to make a tempdir for build-id cache\n"); + goto error; + } + /* Note that buildid_dir must be an absolute path */ + tempdir = realpath(__tempdir, NULL); + + /* At first, scan itself */ + set_buildid_dir(tempdir); + if (build_id_cache__add_file(myself) < 0) + goto error_rmdir; + + /* Open a cache and make sure the SDT is stored */ + if (search_cached_probe(myself, "sdt_perf", "test_target") < 0) + goto error_rmdir; + + /* TBD: probing on the SDT event and collect logs */ + + /* Call the target and get an event */ + ret = target_function(); + +error_rmdir: + /* Cleanup temporary buildid dir */ + rm_rf(tempdir); +error: + free(tempdir); + free(myself); + return ret; +} +#else +int test__sdt_event(int subtests __maybe_unused) +{ + pr_debug("Skip SDT event test because SDT support is not compiled\n"); + return TEST_SKIP; +} +#endif diff --git a/tools/perf/tests/tests.h b/tools/perf/tests/tests.h index 52f9695..a0288f8 100644 --- a/tools/perf/tests/tests.h +++ b/tools/perf/tests/tests.h @@ -88,6 +88,7 @@ int test__event_update(int subtest); int test__event_times(int subtest); int test__backward_ring_buffer(int subtest); int test__cpu_map_print(int subtest); +int test__sdt_event(int subtest); #if defined(__arm__) || defined(__aarch64__) #ifdef HAVE_DWARF_UNWIND_SUPPORT -- cgit v0.10.2 From 25b1f9acc452209ae0fcc8c1332be852b5c52f53 Mon Sep 17 00:00:00 2001 From: Joseph Salisbury Date: Wed, 6 Jul 2016 21:18:51 -0400 Subject: usb: quirks: Add no-lpm quirk for Elan BugLink: http://bugs.launchpad.net/bugs/1498667 As reported in BugLink, this device has an issue with Linux Power Management so adding a quirk. This quirk was reccomended by Alan Stern: http://lkml.iu.edu/hypermail/linux/kernel/1606.2/05590.html Signed-off-by: Joseph Salisbury Cc: stable Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c index 944a6dc..d2e50a2 100644 --- a/drivers/usb/core/quirks.c +++ b/drivers/usb/core/quirks.c @@ -128,6 +128,9 @@ static const struct usb_device_id usb_quirk_list[] = { { USB_DEVICE(0x04f3, 0x016f), .driver_info = USB_QUIRK_DEVICE_QUALIFIER }, + { USB_DEVICE(0x04f3, 0x0381), .driver_info = + USB_QUIRK_NO_LPM }, + { USB_DEVICE(0x04f3, 0x21b8), .driver_info = USB_QUIRK_DEVICE_QUALIFIER }, -- cgit v0.10.2 From 077e2642fbe2274e1b7b9d7c71da6cd3f69f21fd Mon Sep 17 00:00:00 2001 From: Fengguang Wu Date: Tue, 12 Jul 2016 15:05:49 +0800 Subject: chardev: add missing line break in pr_warn To fix super long dmesg error lines like CHRDEV "dummy_stm.0" major number 224 goes below the dynamic allocation rangeCHRDEV "dummy_stm.1" major number 223 goes below the dynamic allocation rangeswapper: page allocation failure: order:8, mode:0x26040c0(GFP_KERNEL|__GFP_COMP|__GFP_NOTRACK) After fix, it should look like CHRDEV "dummy_stm.0" major number 224 goes below the dynamic allocation range CHRDEV "dummy_stm.1" major number 223 goes below the dynamic allocation range swapper: page allocation failure: order:8, mode:0x26040c0(GFP_KERNEL|__GFP_COMP|__GFP_NOTRACK) Reported-by: Philip Li Signed-off-by: Fengguang Wu Signed-off-by: Greg Kroah-Hartman diff --git a/fs/char_dev.c b/fs/char_dev.c index 687471d..6edd825 100644 --- a/fs/char_dev.c +++ b/fs/char_dev.c @@ -92,7 +92,7 @@ __register_chrdev_region(unsigned int major, unsigned int baseminor, } if (i < CHRDEV_MAJOR_DYN_END) - pr_warn("CHRDEV \"%s\" major number %d goes below the dynamic allocation range", + pr_warn("CHRDEV \"%s\" major number %d goes below the dynamic allocation range\n", name, i); if (i == 0) { -- cgit v0.10.2 From 241903641111803807c90016866d88d7ef8c9347 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 13 Jul 2016 13:11:19 +0300 Subject: dsp56k: prevent a harmless underflow There is a mistake here where we don't allow "len" to be zero but we allow negative lengths. It's basically harmless in this case, but the underflow makes my static checker complain. Signed-off-by: Dan Carpenter Reviewed-by: Arnd Bergmann Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/char/dsp56k.c b/drivers/char/dsp56k.c index 8bf70e8..50aa9ba 100644 --- a/drivers/char/dsp56k.c +++ b/drivers/char/dsp56k.c @@ -325,7 +325,7 @@ static long dsp56k_ioctl(struct file *file, unsigned int cmd, if(get_user(bin, &binary->bin) < 0) return -EFAULT; - if (len == 0) { + if (len <= 0) { return -EINVAL; /* nothing to upload?!? */ } if (len > DSP56K_MAX_BINARY_LENGTH) { -- cgit v0.10.2 From 57430218317e5b280a80582a139b26029c25de6c Mon Sep 17 00:00:00 2001 From: Rik van Riel Date: Wed, 13 Jul 2016 16:50:01 +0200 Subject: sched/cputime: Count actually elapsed irq & softirq time Currently, if there was any irq or softirq time during 'ticks' jiffies, the entire period will be accounted as irq or softirq time. This is inaccurate if only a subset of the time was actually spent handling irqs, and could conceivably mis-count all of the ticks during a period as irq time, when there was some irq and some softirq time. This can actually happen when irqtime_account_process_tick is called from account_idle_ticks, which can pass a larger number of ticks down all at once. Fix this by changing irqtime_account_hi_update(), irqtime_account_si_update(), and steal_account_process_ticks() to work with cputime_t time units, and return the amount of time spent in each mode. Rename steal_account_process_ticks() to steal_account_process_time(), to reflect that time is now accounted in cputime_t, instead of ticks. Additionally, have irqtime_account_process_tick() take into account how much time was spent in each of steal, irq, and softirq time. The latter could help improve the accuracy of cputime accounting when returning from idle on a NO_HZ_IDLE CPU. Properly accounting how much time was spent in hardirq and softirq time will also allow the NO_HZ_FULL code to re-use these same functions for hardirq and softirq accounting. Signed-off-by: Rik van Riel [ Make nsecs_to_cputime64() actually return cputime64_t. ] Signed-off-by: Frederic Weisbecker Cc: Linus Torvalds Cc: Mike Galbraith Cc: Paolo Bonzini Cc: Peter Zijlstra Cc: Radim Krcmar Cc: Thomas Gleixner Cc: Wanpeng Li Link: http://lkml.kernel.org/r/1468421405-20056-2-git-send-email-fweisbec@gmail.com Signed-off-by: Ingo Molnar diff --git a/include/asm-generic/cputime_nsecs.h b/include/asm-generic/cputime_nsecs.h index 0f1c6f3..a84e28e 100644 --- a/include/asm-generic/cputime_nsecs.h +++ b/include/asm-generic/cputime_nsecs.h @@ -50,6 +50,8 @@ typedef u64 __nocast cputime64_t; (__force u64)(__ct) #define nsecs_to_cputime(__nsecs) \ (__force cputime_t)(__nsecs) +#define nsecs_to_cputime64(__nsecs) \ + (__force cputime64_t)(__nsecs) /* diff --git a/kernel/sched/cputime.c b/kernel/sched/cputime.c index 3d60e5d..db82ae1 100644 --- a/kernel/sched/cputime.c +++ b/kernel/sched/cputime.c @@ -79,40 +79,50 @@ void irqtime_account_irq(struct task_struct *curr) } EXPORT_SYMBOL_GPL(irqtime_account_irq); -static int irqtime_account_hi_update(void) +static cputime_t irqtime_account_hi_update(cputime_t maxtime) { u64 *cpustat = kcpustat_this_cpu->cpustat; unsigned long flags; - u64 latest_ns; - int ret = 0; + cputime_t irq_cputime; local_irq_save(flags); - latest_ns = this_cpu_read(cpu_hardirq_time); - if (nsecs_to_cputime64(latest_ns) > cpustat[CPUTIME_IRQ]) - ret = 1; + irq_cputime = nsecs_to_cputime64(this_cpu_read(cpu_hardirq_time)) - + cpustat[CPUTIME_IRQ]; + irq_cputime = min(irq_cputime, maxtime); + cpustat[CPUTIME_IRQ] += irq_cputime; local_irq_restore(flags); - return ret; + return irq_cputime; } -static int irqtime_account_si_update(void) +static cputime_t irqtime_account_si_update(cputime_t maxtime) { u64 *cpustat = kcpustat_this_cpu->cpustat; unsigned long flags; - u64 latest_ns; - int ret = 0; + cputime_t softirq_cputime; local_irq_save(flags); - latest_ns = this_cpu_read(cpu_softirq_time); - if (nsecs_to_cputime64(latest_ns) > cpustat[CPUTIME_SOFTIRQ]) - ret = 1; + softirq_cputime = nsecs_to_cputime64(this_cpu_read(cpu_softirq_time)) - + cpustat[CPUTIME_SOFTIRQ]; + softirq_cputime = min(softirq_cputime, maxtime); + cpustat[CPUTIME_SOFTIRQ] += softirq_cputime; local_irq_restore(flags); - return ret; + return softirq_cputime; } #else /* CONFIG_IRQ_TIME_ACCOUNTING */ #define sched_clock_irqtime (0) +static cputime_t irqtime_account_hi_update(cputime_t dummy) +{ + return 0; +} + +static cputime_t irqtime_account_si_update(cputime_t dummy) +{ + return 0; +} + #endif /* !CONFIG_IRQ_TIME_ACCOUNTING */ static inline void task_group_account_field(struct task_struct *p, int index, @@ -257,32 +267,45 @@ void account_idle_time(cputime_t cputime) cpustat[CPUTIME_IDLE] += (__force u64) cputime; } -static __always_inline unsigned long steal_account_process_tick(unsigned long max_jiffies) +static __always_inline cputime_t steal_account_process_time(cputime_t maxtime) { #ifdef CONFIG_PARAVIRT if (static_key_false(¶virt_steal_enabled)) { + cputime_t steal_cputime; u64 steal; - unsigned long steal_jiffies; steal = paravirt_steal_clock(smp_processor_id()); steal -= this_rq()->prev_steal_time; - /* - * steal is in nsecs but our caller is expecting steal - * time in jiffies. Lets cast the result to jiffies - * granularity and account the rest on the next rounds. - */ - steal_jiffies = min(nsecs_to_jiffies(steal), max_jiffies); - this_rq()->prev_steal_time += jiffies_to_nsecs(steal_jiffies); + steal_cputime = min(nsecs_to_cputime(steal), maxtime); + account_steal_time(steal_cputime); + this_rq()->prev_steal_time += cputime_to_nsecs(steal_cputime); - account_steal_time(jiffies_to_cputime(steal_jiffies)); - return steal_jiffies; + return steal_cputime; } #endif return 0; } /* + * Account how much elapsed time was spent in steal, irq, or softirq time. + */ +static inline cputime_t account_other_time(cputime_t max) +{ + cputime_t accounted; + + accounted = steal_account_process_time(max); + + if (accounted < max) + accounted += irqtime_account_hi_update(max - accounted); + + if (accounted < max) + accounted += irqtime_account_si_update(max - accounted); + + return accounted; +} + +/* * Accumulate raw cputime values of dead tasks (sig->[us]time) and live * tasks (sum on group iteration) belonging to @tsk's group. */ @@ -342,21 +365,23 @@ void thread_group_cputime(struct task_struct *tsk, struct task_cputime *times) static void irqtime_account_process_tick(struct task_struct *p, int user_tick, struct rq *rq, int ticks) { - cputime_t scaled = cputime_to_scaled(cputime_one_jiffy); - u64 cputime = (__force u64) cputime_one_jiffy; - u64 *cpustat = kcpustat_this_cpu->cpustat; + u64 cputime = (__force u64) cputime_one_jiffy * ticks; + cputime_t scaled, other; - if (steal_account_process_tick(ULONG_MAX)) + /* + * When returning from idle, many ticks can get accounted at + * once, including some ticks of steal, irq, and softirq time. + * Subtract those ticks from the amount of time accounted to + * idle, or potentially user or system time. Due to rounding, + * other time can exceed ticks occasionally. + */ + other = account_other_time(cputime); + if (other >= cputime) return; + cputime -= other; + scaled = cputime_to_scaled(cputime); - cputime *= ticks; - scaled *= ticks; - - if (irqtime_account_hi_update()) { - cpustat[CPUTIME_IRQ] += cputime; - } else if (irqtime_account_si_update()) { - cpustat[CPUTIME_SOFTIRQ] += cputime; - } else if (this_cpu_ksoftirqd() == p) { + if (this_cpu_ksoftirqd() == p) { /* * ksoftirqd time do not get accounted in cpu_softirq_time. * So, we have to handle it separately here. @@ -466,7 +491,7 @@ void thread_group_cputime_adjusted(struct task_struct *p, cputime_t *ut, cputime */ void account_process_tick(struct task_struct *p, int user_tick) { - cputime_t one_jiffy_scaled = cputime_to_scaled(cputime_one_jiffy); + cputime_t cputime, scaled, steal; struct rq *rq = this_rq(); if (vtime_accounting_cpu_enabled()) @@ -477,16 +502,21 @@ void account_process_tick(struct task_struct *p, int user_tick) return; } - if (steal_account_process_tick(ULONG_MAX)) + cputime = cputime_one_jiffy; + steal = steal_account_process_time(cputime); + + if (steal >= cputime) return; + cputime -= steal; + scaled = cputime_to_scaled(cputime); + if (user_tick) - account_user_time(p, cputime_one_jiffy, one_jiffy_scaled); + account_user_time(p, cputime, scaled); else if ((p != rq->idle) || (irq_count() != HARDIRQ_OFFSET)) - account_system_time(p, HARDIRQ_OFFSET, cputime_one_jiffy, - one_jiffy_scaled); + account_system_time(p, HARDIRQ_OFFSET, cputime, scaled); else - account_idle_time(cputime_one_jiffy); + account_idle_time(cputime); } /* @@ -681,14 +711,14 @@ static cputime_t vtime_delta(struct task_struct *tsk) static cputime_t get_vtime_delta(struct task_struct *tsk) { unsigned long now = READ_ONCE(jiffies); - unsigned long delta_jiffies, steal_jiffies; + cputime_t delta, steal; - delta_jiffies = now - tsk->vtime_snap; - steal_jiffies = steal_account_process_tick(delta_jiffies); + delta = jiffies_to_cputime(now - tsk->vtime_snap); + steal = steal_account_process_time(delta); WARN_ON_ONCE(tsk->vtime_snap_whence == VTIME_INACTIVE); tsk->vtime_snap = now; - return jiffies_to_cputime(delta_jiffies - steal_jiffies); + return delta - steal; } static void __vtime_account_system(struct task_struct *tsk) -- cgit v0.10.2 From b58c35840521bb02b150e1d0d34ca9197f8b7145 Mon Sep 17 00:00:00 2001 From: Rik van Riel Date: Wed, 13 Jul 2016 16:50:02 +0200 Subject: sched/cputime: Replace VTIME_GEN irq time code with IRQ_TIME_ACCOUNTING code The CONFIG_VIRT_CPU_ACCOUNTING_GEN irq time tracking code does not appear to currently work right. On CPUs without nohz_full=, only tick based irq time sampling is done, which breaks down when dealing with a nohz_idle CPU. On firewalls and similar systems, no ticks may happen on a CPU for a while, and the irq time spent may never get accounted properly. This can cause issues with capacity planning and power saving, which use the CPU statistics as inputs in decision making. Remove the VTIME_GEN vtime irq time code, and replace it with the IRQ_TIME_ACCOUNTING code, when selected as a config option by the user. Signed-off-by: Rik van Riel Signed-off-by: Frederic Weisbecker Cc: Linus Torvalds Cc: Mike Galbraith Cc: Paolo Bonzini Cc: Peter Zijlstra Cc: Radim Krcmar Cc: Thomas Gleixner Cc: Wanpeng Li Link: http://lkml.kernel.org/r/1468421405-20056-3-git-send-email-fweisbec@gmail.com Signed-off-by: Ingo Molnar diff --git a/include/linux/vtime.h b/include/linux/vtime.h index fa21969..d1977d84 100644 --- a/include/linux/vtime.h +++ b/include/linux/vtime.h @@ -14,6 +14,18 @@ struct task_struct; */ #ifdef CONFIG_VIRT_CPU_ACCOUNTING_NATIVE static inline bool vtime_accounting_cpu_enabled(void) { return true; } + +#ifdef __ARCH_HAS_VTIME_ACCOUNT +extern void vtime_account_irq_enter(struct task_struct *tsk); +#else +extern void vtime_common_account_irq_enter(struct task_struct *tsk); +static inline void vtime_account_irq_enter(struct task_struct *tsk) +{ + if (vtime_accounting_cpu_enabled()) + vtime_common_account_irq_enter(tsk); +} +#endif /* __ARCH_HAS_VTIME_ACCOUNT */ + #endif /* CONFIG_VIRT_CPU_ACCOUNTING_NATIVE */ #ifdef CONFIG_VIRT_CPU_ACCOUNTING_GEN @@ -64,17 +76,6 @@ extern void vtime_account_system(struct task_struct *tsk); extern void vtime_account_idle(struct task_struct *tsk); extern void vtime_account_user(struct task_struct *tsk); -#ifdef __ARCH_HAS_VTIME_ACCOUNT -extern void vtime_account_irq_enter(struct task_struct *tsk); -#else -extern void vtime_common_account_irq_enter(struct task_struct *tsk); -static inline void vtime_account_irq_enter(struct task_struct *tsk) -{ - if (vtime_accounting_cpu_enabled()) - vtime_common_account_irq_enter(tsk); -} -#endif /* __ARCH_HAS_VTIME_ACCOUNT */ - #else /* !CONFIG_VIRT_CPU_ACCOUNTING */ static inline void vtime_task_switch(struct task_struct *prev) { } @@ -85,13 +86,8 @@ static inline void vtime_account_irq_enter(struct task_struct *tsk) { } #ifdef CONFIG_VIRT_CPU_ACCOUNTING_GEN extern void arch_vtime_task_switch(struct task_struct *tsk); -extern void vtime_gen_account_irq_exit(struct task_struct *tsk); - -static inline void vtime_account_irq_exit(struct task_struct *tsk) -{ - if (vtime_accounting_cpu_enabled()) - vtime_gen_account_irq_exit(tsk); -} +static inline void vtime_account_irq_enter(struct task_struct *tsk) { } +static inline void vtime_account_irq_exit(struct task_struct *tsk) { } extern void vtime_user_enter(struct task_struct *tsk); diff --git a/init/Kconfig b/init/Kconfig index c02d897..787dd76 100644 --- a/init/Kconfig +++ b/init/Kconfig @@ -375,9 +375,11 @@ config VIRT_CPU_ACCOUNTING_GEN If unsure, say N. +endchoice + config IRQ_TIME_ACCOUNTING bool "Fine granularity task level IRQ time accounting" - depends on HAVE_IRQ_TIME_ACCOUNTING && !NO_HZ_FULL + depends on HAVE_IRQ_TIME_ACCOUNTING && !VIRT_CPU_ACCOUNTING_NATIVE help Select this option to enable fine granularity task irq time accounting. This is done by reading a timestamp on each @@ -386,8 +388,6 @@ config IRQ_TIME_ACCOUNTING If in doubt, say N here. -endchoice - config BSD_PROCESS_ACCT bool "BSD Process Accounting" depends on MULTIUSER diff --git a/kernel/sched/cputime.c b/kernel/sched/cputime.c index db82ae1..ca7e33c 100644 --- a/kernel/sched/cputime.c +++ b/kernel/sched/cputime.c @@ -711,14 +711,14 @@ static cputime_t vtime_delta(struct task_struct *tsk) static cputime_t get_vtime_delta(struct task_struct *tsk) { unsigned long now = READ_ONCE(jiffies); - cputime_t delta, steal; + cputime_t delta, other; delta = jiffies_to_cputime(now - tsk->vtime_snap); - steal = steal_account_process_time(delta); + other = account_other_time(delta); WARN_ON_ONCE(tsk->vtime_snap_whence == VTIME_INACTIVE); tsk->vtime_snap = now; - return delta - steal; + return delta - other; } static void __vtime_account_system(struct task_struct *tsk) @@ -738,16 +738,6 @@ void vtime_account_system(struct task_struct *tsk) write_seqcount_end(&tsk->vtime_seqcount); } -void vtime_gen_account_irq_exit(struct task_struct *tsk) -{ - write_seqcount_begin(&tsk->vtime_seqcount); - if (vtime_delta(tsk)) - __vtime_account_system(tsk); - if (context_tracking_in_user()) - tsk->vtime_snap_whence = VTIME_USER; - write_seqcount_end(&tsk->vtime_seqcount); -} - void vtime_account_user(struct task_struct *tsk) { cputime_t delta_cpu; -- cgit v0.10.2 From 0cfdf9a198b0d4f5ad6c87d894db7830b796b2cc Mon Sep 17 00:00:00 2001 From: Frederic Weisbecker Date: Wed, 13 Jul 2016 16:50:03 +0200 Subject: sched/cputime: Clean up the old vtime gen irqtime accounting completely Vtime generic irqtime accounting has been removed but there are a few remnants to clean up: * The vtime_accounting_cpu_enabled() check in irq entry was only used by CONFIG_VIRT_CPU_ACCOUNTING_GEN. We can safely remove it. * Without the vtime_accounting_cpu_enabled(), we no longer need to have a vtime_common_account_irq_enter() indirect function. * Move vtime_account_irq_enter() implementation under CONFIG_VIRT_CPU_ACCOUNTING_NATIVE which is the last user. * The vtime_account_user() call was only used on irq entry for CONFIG_VIRT_CPU_ACCOUNTING_GEN. We can remove that too. Signed-off-by: Frederic Weisbecker Cc: Linus Torvalds Cc: Mike Galbraith Cc: Paolo Bonzini Cc: Peter Zijlstra Cc: Radim Krcmar Cc: Rik van Riel Cc: Thomas Gleixner Cc: Wanpeng Li Link: http://lkml.kernel.org/r/1468421405-20056-4-git-send-email-fweisbec@gmail.com Signed-off-by: Ingo Molnar diff --git a/include/linux/vtime.h b/include/linux/vtime.h index d1977d84..65aef5e 100644 --- a/include/linux/vtime.h +++ b/include/linux/vtime.h @@ -14,18 +14,7 @@ struct task_struct; */ #ifdef CONFIG_VIRT_CPU_ACCOUNTING_NATIVE static inline bool vtime_accounting_cpu_enabled(void) { return true; } - -#ifdef __ARCH_HAS_VTIME_ACCOUNT extern void vtime_account_irq_enter(struct task_struct *tsk); -#else -extern void vtime_common_account_irq_enter(struct task_struct *tsk); -static inline void vtime_account_irq_enter(struct task_struct *tsk) -{ - if (vtime_accounting_cpu_enabled()) - vtime_common_account_irq_enter(tsk); -} -#endif /* __ARCH_HAS_VTIME_ACCOUNT */ - #endif /* CONFIG_VIRT_CPU_ACCOUNTING_NATIVE */ #ifdef CONFIG_VIRT_CPU_ACCOUNTING_GEN diff --git a/kernel/sched/cputime.c b/kernel/sched/cputime.c index ca7e33c..16a873c 100644 --- a/kernel/sched/cputime.c +++ b/kernel/sched/cputime.c @@ -431,6 +431,10 @@ void vtime_common_task_switch(struct task_struct *prev) } #endif +#endif /* CONFIG_VIRT_CPU_ACCOUNTING */ + + +#ifdef CONFIG_VIRT_CPU_ACCOUNTING_NATIVE /* * Archs that account the whole time spent in the idle task * (outside irq) as idle time can rely on this and just implement @@ -440,33 +444,16 @@ void vtime_common_task_switch(struct task_struct *prev) * vtime_account(). */ #ifndef __ARCH_HAS_VTIME_ACCOUNT -void vtime_common_account_irq_enter(struct task_struct *tsk) +void vtime_account_irq_enter(struct task_struct *tsk) { - if (!in_interrupt()) { - /* - * If we interrupted user, context_tracking_in_user() - * is 1 because the context tracking don't hook - * on irq entry/exit. This way we know if - * we need to flush user time on kernel entry. - */ - if (context_tracking_in_user()) { - vtime_account_user(tsk); - return; - } - - if (is_idle_task(tsk)) { - vtime_account_idle(tsk); - return; - } - } - vtime_account_system(tsk); + if (!in_interrupt() && is_idle_task(tsk)) + vtime_account_idle(tsk); + else + vtime_account_system(tsk); } -EXPORT_SYMBOL_GPL(vtime_common_account_irq_enter); +EXPORT_SYMBOL_GPL(vtime_account_irq_enter); #endif /* __ARCH_HAS_VTIME_ACCOUNT */ -#endif /* CONFIG_VIRT_CPU_ACCOUNTING */ - -#ifdef CONFIG_VIRT_CPU_ACCOUNTING_NATIVE void task_cputime_adjusted(struct task_struct *p, cputime_t *ut, cputime_t *st) { *ut = p->utime; -- cgit v0.10.2 From 8612f17ab99c1f0770792bc875f5f039212a2a85 Mon Sep 17 00:00:00 2001 From: Frederic Weisbecker Date: Wed, 13 Jul 2016 16:50:04 +0200 Subject: sched/cputime: Reorganize vtime native irqtime accounting headers The vtime irqtime accounting headers are very scattered and convoluted right now. Reorganize them such that it is obvious that only CONFIG_VIRT_CPU_ACCOUNTING_NATIVE does use it. Signed-off-by: Frederic Weisbecker Cc: Linus Torvalds Cc: Mike Galbraith Cc: Paolo Bonzini Cc: Peter Zijlstra Cc: Radim Krcmar Cc: Rik van Riel Cc: Thomas Gleixner Cc: Wanpeng Li Link: http://lkml.kernel.org/r/1468421405-20056-5-git-send-email-fweisbec@gmail.com Signed-off-by: Ingo Molnar diff --git a/include/linux/vtime.h b/include/linux/vtime.h index 65aef5e..aa9bfea 100644 --- a/include/linux/vtime.h +++ b/include/linux/vtime.h @@ -12,12 +12,9 @@ struct task_struct; /* * vtime_accounting_cpu_enabled() definitions/declarations */ -#ifdef CONFIG_VIRT_CPU_ACCOUNTING_NATIVE +#if defined(CONFIG_VIRT_CPU_ACCOUNTING_NATIVE) static inline bool vtime_accounting_cpu_enabled(void) { return true; } -extern void vtime_account_irq_enter(struct task_struct *tsk); -#endif /* CONFIG_VIRT_CPU_ACCOUNTING_NATIVE */ - -#ifdef CONFIG_VIRT_CPU_ACCOUNTING_GEN +#elif defined(CONFIG_VIRT_CPU_ACCOUNTING_GEN) /* * Checks if vtime is enabled on some CPU. Cputime readers want to be careful * in that case and compute the tickless cputime. @@ -38,11 +35,9 @@ static inline bool vtime_accounting_cpu_enabled(void) return false; } -#endif /* CONFIG_VIRT_CPU_ACCOUNTING_GEN */ - -#ifndef CONFIG_VIRT_CPU_ACCOUNTING +#else /* !CONFIG_VIRT_CPU_ACCOUNTING */ static inline bool vtime_accounting_cpu_enabled(void) { return false; } -#endif /* !CONFIG_VIRT_CPU_ACCOUNTING */ +#endif /* @@ -70,14 +65,10 @@ extern void vtime_account_user(struct task_struct *tsk); static inline void vtime_task_switch(struct task_struct *prev) { } static inline void vtime_account_system(struct task_struct *tsk) { } static inline void vtime_account_user(struct task_struct *tsk) { } -static inline void vtime_account_irq_enter(struct task_struct *tsk) { } #endif /* !CONFIG_VIRT_CPU_ACCOUNTING */ #ifdef CONFIG_VIRT_CPU_ACCOUNTING_GEN extern void arch_vtime_task_switch(struct task_struct *tsk); -static inline void vtime_account_irq_enter(struct task_struct *tsk) { } -static inline void vtime_account_irq_exit(struct task_struct *tsk) { } - extern void vtime_user_enter(struct task_struct *tsk); static inline void vtime_user_exit(struct task_struct *tsk) @@ -88,11 +79,6 @@ extern void vtime_guest_enter(struct task_struct *tsk); extern void vtime_guest_exit(struct task_struct *tsk); extern void vtime_init_idle(struct task_struct *tsk, int cpu); #else /* !CONFIG_VIRT_CPU_ACCOUNTING_GEN */ -static inline void vtime_account_irq_exit(struct task_struct *tsk) -{ - /* On hard|softirq exit we always account to hard|softirq cputime */ - vtime_account_system(tsk); -} static inline void vtime_user_enter(struct task_struct *tsk) { } static inline void vtime_user_exit(struct task_struct *tsk) { } static inline void vtime_guest_enter(struct task_struct *tsk) { } @@ -100,6 +86,19 @@ static inline void vtime_guest_exit(struct task_struct *tsk) { } static inline void vtime_init_idle(struct task_struct *tsk, int cpu) { } #endif +#ifdef CONFIG_VIRT_CPU_ACCOUNTING_NATIVE +extern void vtime_account_irq_enter(struct task_struct *tsk); +static inline void vtime_account_irq_exit(struct task_struct *tsk) +{ + /* On hard|softirq exit we always account to hard|softirq cputime */ + vtime_account_system(tsk); +} +#else /* !CONFIG_VIRT_CPU_ACCOUNTING_NATIVE */ +static inline void vtime_account_irq_enter(struct task_struct *tsk) { } +static inline void vtime_account_irq_exit(struct task_struct *tsk) { } +#endif + + #ifdef CONFIG_IRQ_TIME_ACCOUNTING extern void irqtime_account_irq(struct task_struct *tsk); #else -- cgit v0.10.2 From 553bf6bbfd8a540c70aee28eb50e24caff456a03 Mon Sep 17 00:00:00 2001 From: Rik van Riel Date: Wed, 13 Jul 2016 16:50:05 +0200 Subject: sched/cputime: Drop local_irq_save/restore from irqtime_account_irq() Paolo pointed out that irqs are already blocked when irqtime_account_irq() is called. That means there is no reason to call local_irq_save/restore() again. Suggested-by: Paolo Bonzini Signed-off-by: Rik van Riel Signed-off-by: Frederic Weisbecker Reviewed-by: Paolo Bonzini Cc: Linus Torvalds Cc: Mike Galbraith Cc: Peter Zijlstra Cc: Radim Krcmar Cc: Thomas Gleixner Cc: Wanpeng Li Link: http://lkml.kernel.org/r/1468421405-20056-6-git-send-email-fweisbec@gmail.com Signed-off-by: Ingo Molnar diff --git a/kernel/sched/cputime.c b/kernel/sched/cputime.c index 16a873c..ea0f6f3 100644 --- a/kernel/sched/cputime.c +++ b/kernel/sched/cputime.c @@ -49,15 +49,12 @@ DEFINE_PER_CPU(seqcount_t, irq_time_seq); */ void irqtime_account_irq(struct task_struct *curr) { - unsigned long flags; s64 delta; int cpu; if (!sched_clock_irqtime) return; - local_irq_save(flags); - cpu = smp_processor_id(); delta = sched_clock_cpu(cpu) - __this_cpu_read(irq_start_time); __this_cpu_add(irq_start_time, delta); @@ -75,7 +72,6 @@ void irqtime_account_irq(struct task_struct *curr) __this_cpu_add(cpu_softirq_time, delta); irq_time_write_end(); - local_irq_restore(flags); } EXPORT_SYMBOL_GPL(irqtime_account_irq); -- cgit v0.10.2 From a36aa80f3cb2540fb1dbad6240852de4365a2e82 Mon Sep 17 00:00:00 2001 From: Alexander Shishkin Date: Thu, 30 Jun 2016 11:51:44 +0300 Subject: intel_th: Fix a deadlock in modprobing Driver initialization tries to request a hub (GTH) driver module from its probe callback, resulting in a deadlock. This patch solves the problem by adding a deferred work for requesting the hub module. Signed-off-by: Alexander Shishkin Cc: # 4.4.x- diff --git a/drivers/hwtracing/intel_th/core.c b/drivers/hwtracing/intel_th/core.c index 1be543e..0b112ae 100644 --- a/drivers/hwtracing/intel_th/core.c +++ b/drivers/hwtracing/intel_th/core.c @@ -465,6 +465,38 @@ static struct intel_th_subdevice { }, }; +#ifdef CONFIG_MODULES +static void __intel_th_request_hub_module(struct work_struct *work) +{ + struct intel_th *th = container_of(work, struct intel_th, + request_module_work); + + request_module("intel_th_%s", th->hub->name); +} + +static int intel_th_request_hub_module(struct intel_th *th) +{ + INIT_WORK(&th->request_module_work, __intel_th_request_hub_module); + schedule_work(&th->request_module_work); + + return 0; +} + +static void intel_th_request_hub_module_flush(struct intel_th *th) +{ + flush_work(&th->request_module_work); +} +#else +static inline int intel_th_request_hub_module(struct intel_th *th) +{ + return -EINVAL; +} + +static inline void intel_th_request_hub_module_flush(struct intel_th *th) +{ +} +#endif /* CONFIG_MODULES */ + static int intel_th_populate(struct intel_th *th, struct resource *devres, unsigned int ndevres, int irq) { @@ -535,7 +567,7 @@ static int intel_th_populate(struct intel_th *th, struct resource *devres, /* need switch driver to be loaded to enumerate the rest */ if (subdev->type == INTEL_TH_SWITCH && !req) { th->hub = thdev; - err = request_module("intel_th_%s", subdev->name); + err = intel_th_request_hub_module(th); if (!err) req++; } @@ -652,6 +684,7 @@ void intel_th_free(struct intel_th *th) { int i; + intel_th_request_hub_module_flush(th); for (i = 0; i < TH_SUBDEVICE_MAX; i++) if (th->thdev[i] != th->hub) intel_th_device_remove(th->thdev[i]); diff --git a/drivers/hwtracing/intel_th/intel_th.h b/drivers/hwtracing/intel_th/intel_th.h index 0df22e3..0482848 100644 --- a/drivers/hwtracing/intel_th/intel_th.h +++ b/drivers/hwtracing/intel_th/intel_th.h @@ -205,6 +205,9 @@ struct intel_th { int id; int major; +#ifdef CONFIG_MODULES + struct work_struct request_module_work; +#endif /* CONFIG_MODULES */ #ifdef CONFIG_INTEL_TH_DEBUG struct dentry *dbg; #endif -- cgit v0.10.2 From 7a1a47ce35821b40f5b2ce46379ba14393bc3873 Mon Sep 17 00:00:00 2001 From: Alexander Shishkin Date: Tue, 28 Jun 2016 18:55:23 +0300 Subject: intel_th: pci: Add Kaby Lake PCH-H support This adds Intel(R) Trace Hub PCI ID for Kaby Lake PCH-H. Signed-off-by: Alexander Shishkin Cc: diff --git a/drivers/hwtracing/intel_th/pci.c b/drivers/hwtracing/intel_th/pci.c index 5e25c7e..0bba384 100644 --- a/drivers/hwtracing/intel_th/pci.c +++ b/drivers/hwtracing/intel_th/pci.c @@ -80,6 +80,11 @@ static const struct pci_device_id intel_th_pci_id_table[] = { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x1a8e), .driver_data = (kernel_ulong_t)0, }, + { + /* Kaby Lake PCH-H */ + PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xa2a6), + .driver_data = (kernel_ulong_t)0, + }, { 0 }, }; -- cgit v0.10.2 From b19240062722c39fa92c99f04cbfd93034625123 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 11 Jul 2016 14:46:17 +0100 Subject: drm/i915: Update ifdeffery for mutex->owner In commit 7608a43d8f2e ("locking/mutexes: Use MUTEX_SPIN_ON_OWNER when appropriate") the owner field in the mutex was updated from being dependent upon CONFIG_SMP to using optimistic spin. Update our peek function to suite. Fixes:7608a43d8f2e ("locking/mutexes: Use MUTEX_SPIN_ON_OWNER...") Reported-by: Hong Liu Signed-off-by: Chris Wilson Link: http://patchwork.freedesktop.org/patch/msgid/1468244777-4888-1-git-send-email-chris@chris-wilson.co.uk Reviewed-by: Matthew Auld (cherry picked from commit 4f074a5393431a7d2cc0de7fcfe2f61d24854628) Cc: stable@vger.kernel.org Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/i915_gem_shrinker.c b/drivers/gpu/drm/i915/i915_gem_shrinker.c index 425e721..6657146 100644 --- a/drivers/gpu/drm/i915/i915_gem_shrinker.c +++ b/drivers/gpu/drm/i915/i915_gem_shrinker.c @@ -40,7 +40,7 @@ static bool mutex_is_locked_by(struct mutex *mutex, struct task_struct *task) if (!mutex_is_locked(mutex)) return false; -#if defined(CONFIG_SMP) || defined(CONFIG_DEBUG_MUTEXES) +#if defined(CONFIG_DEBUG_MUTEXES) || defined(CONFIG_MUTEX_SPIN_ON_OWNER) return mutex->owner == task; #else /* Since UP may be pre-empted, we cannot assume that we own the lock */ -- cgit v0.10.2 From aeddda06c1a704bb97c8a7bfe7a472120193bd56 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Tue, 12 Jul 2016 15:00:37 +0300 Subject: drm/i915: Ignore panel type from OpRegion on SKL MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Dell XPS 13 9350 apparently doesn't like it when we use the panel type from OpRegion. The OpRegion panel type (0) tells us to use use low vswing for eDP, whereas the VBT panel type (2) tells us to use normal vswing. The problem is that low vswing results in some display flickers. Since no one seems to know how this stuff is supposed to be handled, let's just ignore the OpRegion panel type on SKL for now. v2: Print the panel type correctly in the debug output Reported-by: James Bottomley Cc: James Bottomley Cc: drm-intel-fixes@lists.freedesktop.org References: https://lists.freedesktop.org/archives/intel-gfx/2016-June/098826.html Fixes: a05628195a0d ("drm/i915: Get panel_type from OpRegion panel details") Signed-off-by: Ville Syrjälä Link: http://patchwork.freedesktop.org/patch/msgid/1468324837-29237-1-git-send-email-ville.syrjala@linux.intel.com Reviewed-by: Daniel Vetter Tested-by: James Bottomley Signed-off-by: Ville Syrjälä (cherry picked from commit bb10d4ec3be4b069bfb61c60ca4f708f58f440f1) [danvet: Fix up cherry-pick conflict with an s/dev_priv/dev/.] Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/intel_opregion.c b/drivers/gpu/drm/i915/intel_opregion.c index 99e2603..16e209d 100644 --- a/drivers/gpu/drm/i915/intel_opregion.c +++ b/drivers/gpu/drm/i915/intel_opregion.c @@ -1038,5 +1038,16 @@ intel_opregion_get_panel_type(struct drm_device *dev) return -ENODEV; } + /* + * FIXME On Dell XPS 13 9350 the OpRegion panel type (0) gives us + * low vswing for eDP, whereas the VBT panel type (2) gives us normal + * vswing instead. Low vswing results in some display flickers, so + * let's simply ignore the OpRegion panel type on SKL for now. + */ + if (IS_SKYLAKE(dev)) { + DRM_DEBUG_KMS("Ignoring OpRegion panel type (%d)\n", ret - 1); + return -ENODEV; + } + return ret - 1; } -- cgit v0.10.2 From ca575ad2093d7ca94238146c3c9267c61d2523bc Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 14 Jul 2016 11:23:25 -0300 Subject: tools lib traceevent: Add correct header for ipv6 definitions We need to include netinet/in.h to get the in6_addr struct definition, needed to build it on the Android NDK: In file included from event-parse.c:36:0: /home/acme/android/android-ndk-r12/platforms/android-24/arch-arm/usr/include/netinet/ip6.h:82:18: error: field 'ip6_src' has incomplete type struct in6_addr ip6_src; /* source address */ And it is the canonical way of getting IPv6 definitions, as described, for instance, in Linux's 'man ipv6' Doing that uncovers another problem: this source file uses PRIu64 but doesn't include it, depending on it being included by chance via the now replaced header (netinet/ip6.h), fix it. Cc: Adrian Hunter Cc: Chris Phlipot Cc: David Ahern Cc: Jiri Olsa Cc: Namhyung Kim Cc: Steven Rostedt Cc: Wang Nan Link: http://lkml.kernel.org/n/tip-tilr31n3yaba1whsd47qlwa3@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/lib/traceevent/event-parse.c b/tools/lib/traceevent/event-parse.c index 3a7bd17..664c90c 100644 --- a/tools/lib/traceevent/event-parse.c +++ b/tools/lib/traceevent/event-parse.c @@ -23,6 +23,7 @@ * Frederic Weisbecker gave his permission to relicense the code to * the Lesser General Public License. */ +#include #include #include #include @@ -33,7 +34,7 @@ #include #include -#include +#include #include "event-parse.h" #include "event-utils.h" -- cgit v0.10.2 From 09dd39d2d2682729174e40161df67f45c151f307 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 14 Jul 2016 12:02:04 -0300 Subject: perf tools: Do not provide dup sched_getcpu() prototype on Android The Bionic libc has this definition, so don't duplicate it. Cc: Adrian Hunter Cc: Chris Phlipot Cc: David Ahern Cc: Jiri Olsa Cc: Namhyung Kim Cc: Wang Nan Link: http://lkml.kernel.org/n/tip-rmd19832zkt07e4crdzyen9z@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h index 6178cab..843cbba 100644 --- a/tools/perf/util/util.h +++ b/tools/perf/util/util.h @@ -360,7 +360,7 @@ void print_binary(unsigned char *data, size_t len, size_t bytes_per_line, print_binary_t printer, void *extra); -#ifndef __GLIBC__ +#if !defined(__GLIBC__) && !defined(__ANDROID__) extern int sched_getcpu(void); #endif -- cgit v0.10.2 From 8c98abff43616a2a9c208189f86d32cefafbe708 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 14 Jul 2016 12:03:04 -0300 Subject: tools: Make "__always_inline" just "inline" on Android As the gcc there is producing tons of: "warning: always_inline function might not be inlinable" At least on android-ndk-r12/platforms/android-24/arch-arm, so, for the time being, use this big hammer. Cc: Adrian Hunter Cc: Chris Phlipot Cc: David Ahern Cc: Jiri Olsa Cc: Namhyung Kim Cc: Wang Nan Link: http://lkml.kernel.org/n/tip-97l3eg3fnk5shmo4rsyyvj2t@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/include/linux/compiler.h b/tools/include/linux/compiler.h index fa7208a..e33fc1d 100644 --- a/tools/include/linux/compiler.h +++ b/tools/include/linux/compiler.h @@ -9,6 +9,17 @@ # define __always_inline inline __attribute__((always_inline)) #endif +#ifdef __ANDROID__ +/* + * FIXME: Big hammer to get rid of tons of: + * "warning: always_inline function might not be inlinable" + * + * At least on android-ndk-r12/platforms/android-24/arch-arm + */ +#undef __always_inline +#define __always_inline inline +#endif + #define __user #ifndef __attribute_const__ -- cgit v0.10.2 From 32f0c4afb4363e31dad49202f1554ba591d649f2 Mon Sep 17 00:00:00 2001 From: Keith Busch Date: Wed, 13 Jul 2016 11:45:02 -0600 Subject: nvme: Remove RCU namespace protection We can't sleep with RCU read lock held, but we need to do potentially blocking stuff to namespace queues when iterating the list. This patch removes the RCU locking and holds a mutex instead. To prevent deadlocks, this patch removes holding the mutex during namespace scanning and removal. The unlocked namespace scanning is made safe by holding a reference to the namespace being scanned. List iteration that does IO has to be unlocked to allow error recovery. The caller must ensure the list can not be manipulated during such an event, so this patch adds a comment explaining this requirement to the only function that iterates an unlocked list. All callers currently meet this requirement, so no further changes required. List iterations that do not do IO can safely use the lock since it couldn't block recovery from missing forced IO completions. Reported-by: Ming Lin [fixes 0bf77e9 nvme: switch to RCU freeing the namespace] Signed-off-by: Keith Busch Signed-off-by: Jens Axboe diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c index 1a51584..d5fb55c 100644 --- a/drivers/nvme/host/core.c +++ b/drivers/nvme/host/core.c @@ -1394,19 +1394,22 @@ static int ns_cmp(void *priv, struct list_head *a, struct list_head *b) return nsa->ns_id - nsb->ns_id; } -static struct nvme_ns *nvme_find_ns(struct nvme_ctrl *ctrl, unsigned nsid) +static struct nvme_ns *nvme_find_get_ns(struct nvme_ctrl *ctrl, unsigned nsid) { - struct nvme_ns *ns; - - lockdep_assert_held(&ctrl->namespaces_mutex); + struct nvme_ns *ns, *ret = NULL; + mutex_lock(&ctrl->namespaces_mutex); list_for_each_entry(ns, &ctrl->namespaces, list) { - if (ns->ns_id == nsid) - return ns; + if (ns->ns_id == nsid) { + kref_get(&ns->kref); + ret = ns; + break; + } if (ns->ns_id > nsid) break; } - return NULL; + mutex_unlock(&ctrl->namespaces_mutex); + return ret; } static void nvme_alloc_ns(struct nvme_ctrl *ctrl, unsigned nsid) @@ -1415,8 +1418,6 @@ static void nvme_alloc_ns(struct nvme_ctrl *ctrl, unsigned nsid) struct gendisk *disk; int node = dev_to_node(ctrl->dev); - lockdep_assert_held(&ctrl->namespaces_mutex); - ns = kzalloc_node(sizeof(*ns), GFP_KERNEL, node); if (!ns) return; @@ -1457,7 +1458,10 @@ static void nvme_alloc_ns(struct nvme_ctrl *ctrl, unsigned nsid) if (nvme_revalidate_disk(ns->disk)) goto out_free_disk; - list_add_tail_rcu(&ns->list, &ctrl->namespaces); + mutex_lock(&ctrl->namespaces_mutex); + list_add_tail(&ns->list, &ctrl->namespaces); + mutex_unlock(&ctrl->namespaces_mutex); + kref_get(&ctrl->kref); if (ns->type == NVME_NS_LIGHTNVM) return; @@ -1480,8 +1484,6 @@ static void nvme_alloc_ns(struct nvme_ctrl *ctrl, unsigned nsid) static void nvme_ns_remove(struct nvme_ns *ns) { - lockdep_assert_held(&ns->ctrl->namespaces_mutex); - if (test_and_set_bit(NVME_NS_REMOVING, &ns->flags)) return; @@ -1494,8 +1496,11 @@ static void nvme_ns_remove(struct nvme_ns *ns) blk_mq_abort_requeue_list(ns->queue); blk_cleanup_queue(ns->queue); } + + mutex_lock(&ns->ctrl->namespaces_mutex); list_del_init(&ns->list); - synchronize_rcu(); + mutex_unlock(&ns->ctrl->namespaces_mutex); + nvme_put_ns(ns); } @@ -1503,10 +1508,11 @@ static void nvme_validate_ns(struct nvme_ctrl *ctrl, unsigned nsid) { struct nvme_ns *ns; - ns = nvme_find_ns(ctrl, nsid); + ns = nvme_find_get_ns(ctrl, nsid); if (ns) { if (revalidate_disk(ns->disk)) nvme_ns_remove(ns); + nvme_put_ns(ns); } else nvme_alloc_ns(ctrl, nsid); } @@ -1535,9 +1541,11 @@ static int nvme_scan_ns_list(struct nvme_ctrl *ctrl, unsigned nn) nvme_validate_ns(ctrl, nsid); while (++prev < nsid) { - ns = nvme_find_ns(ctrl, prev); - if (ns) + ns = nvme_find_get_ns(ctrl, prev); + if (ns) { nvme_ns_remove(ns); + nvme_put_ns(ns); + } } } nn -= j; @@ -1552,8 +1560,6 @@ static void nvme_scan_ns_sequential(struct nvme_ctrl *ctrl, unsigned nn) struct nvme_ns *ns, *next; unsigned i; - lockdep_assert_held(&ctrl->namespaces_mutex); - for (i = 1; i <= nn; i++) nvme_validate_ns(ctrl, i); @@ -1576,7 +1582,6 @@ static void nvme_scan_work(struct work_struct *work) if (nvme_identify_ctrl(ctrl, &id)) return; - mutex_lock(&ctrl->namespaces_mutex); nn = le32_to_cpu(id->nn); if (ctrl->vs >= NVME_VS(1, 1) && !(ctrl->quirks & NVME_QUIRK_IDENTIFY_CNS)) { @@ -1585,6 +1590,7 @@ static void nvme_scan_work(struct work_struct *work) } nvme_scan_ns_sequential(ctrl, nn); done: + mutex_lock(&ctrl->namespaces_mutex); list_sort(NULL, &ctrl->namespaces, ns_cmp); mutex_unlock(&ctrl->namespaces_mutex); kfree(id); @@ -1604,6 +1610,11 @@ void nvme_queue_scan(struct nvme_ctrl *ctrl) } EXPORT_SYMBOL_GPL(nvme_queue_scan); +/* + * This function iterates the namespace list unlocked to allow recovery from + * controller failure. It is up to the caller to ensure the namespace list is + * not modified by scan work while this function is executing. + */ void nvme_remove_namespaces(struct nvme_ctrl *ctrl) { struct nvme_ns *ns, *next; @@ -1617,10 +1628,8 @@ void nvme_remove_namespaces(struct nvme_ctrl *ctrl) if (ctrl->state == NVME_CTRL_DEAD) nvme_kill_queues(ctrl); - mutex_lock(&ctrl->namespaces_mutex); list_for_each_entry_safe(ns, next, &ctrl->namespaces, list) nvme_ns_remove(ns); - mutex_unlock(&ctrl->namespaces_mutex); } EXPORT_SYMBOL_GPL(nvme_remove_namespaces); @@ -1791,11 +1800,8 @@ void nvme_kill_queues(struct nvme_ctrl *ctrl) { struct nvme_ns *ns; - rcu_read_lock(); - list_for_each_entry_rcu(ns, &ctrl->namespaces, list) { - if (!kref_get_unless_zero(&ns->kref)) - continue; - + mutex_lock(&ctrl->namespaces_mutex); + list_for_each_entry(ns, &ctrl->namespaces, list) { /* * Revalidating a dead namespace sets capacity to 0. This will * end buffered writers dirtying pages that can't be synced. @@ -1806,10 +1812,8 @@ void nvme_kill_queues(struct nvme_ctrl *ctrl) blk_set_queue_dying(ns->queue); blk_mq_abort_requeue_list(ns->queue); blk_mq_start_stopped_hw_queues(ns->queue, true); - - nvme_put_ns(ns); } - rcu_read_unlock(); + mutex_unlock(&ctrl->namespaces_mutex); } EXPORT_SYMBOL_GPL(nvme_kill_queues); @@ -1817,8 +1821,8 @@ void nvme_stop_queues(struct nvme_ctrl *ctrl) { struct nvme_ns *ns; - rcu_read_lock(); - list_for_each_entry_rcu(ns, &ctrl->namespaces, list) { + mutex_lock(&ctrl->namespaces_mutex); + list_for_each_entry(ns, &ctrl->namespaces, list) { spin_lock_irq(ns->queue->queue_lock); queue_flag_set(QUEUE_FLAG_STOPPED, ns->queue); spin_unlock_irq(ns->queue->queue_lock); @@ -1826,7 +1830,7 @@ void nvme_stop_queues(struct nvme_ctrl *ctrl) blk_mq_cancel_requeue_work(ns->queue); blk_mq_stop_hw_queues(ns->queue); } - rcu_read_unlock(); + mutex_unlock(&ctrl->namespaces_mutex); } EXPORT_SYMBOL_GPL(nvme_stop_queues); @@ -1834,13 +1838,13 @@ void nvme_start_queues(struct nvme_ctrl *ctrl) { struct nvme_ns *ns; - rcu_read_lock(); - list_for_each_entry_rcu(ns, &ctrl->namespaces, list) { + mutex_lock(&ctrl->namespaces_mutex); + list_for_each_entry(ns, &ctrl->namespaces, list) { queue_flag_clear_unlocked(QUEUE_FLAG_STOPPED, ns->queue); blk_mq_start_stopped_hw_queues(ns->queue, true); blk_mq_kick_requeue_list(ns->queue); } - rcu_read_unlock(); + mutex_unlock(&ctrl->namespaces_mutex); } EXPORT_SYMBOL_GPL(nvme_start_queues); -- cgit v0.10.2 From 7ce9ea7e6b35a652034486133174d4e17055cef5 Mon Sep 17 00:00:00 2001 From: Teresa Remmet Date: Tue, 5 Jul 2016 11:32:30 +0200 Subject: mtd: nand: omap2: Add check for old elm binding commit c9711ec5250b ("mtd: nand: omap: Clean up device tree support") removes the check for the old elm phandle binding. Add it again to keep backward compatibility. Fixes: commit c9711ec5250b ("mtd: nand: omap: Clean up device tree support") Signed-off-by: Teresa Remmet Signed-off-by: Brian Norris diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c index 08e1588..a136da8 100644 --- a/drivers/mtd/nand/omap2.c +++ b/drivers/mtd/nand/omap2.c @@ -1657,8 +1657,11 @@ static int omap_get_dt_info(struct device *dev, struct omap_nand_info *info) /* detect availability of ELM module. Won't be present pre-OMAP4 */ info->elm_of_node = of_parse_phandle(child, "ti,elm-id", 0); - if (!info->elm_of_node) - dev_dbg(dev, "ti,elm-id not in DT\n"); + if (!info->elm_of_node) { + info->elm_of_node = of_parse_phandle(child, "elm_id", 0); + if (!info->elm_of_node) + dev_dbg(dev, "ti,elm-id not in DT\n"); + } /* select ecc-scheme for NAND */ if (of_property_read_string(child, "ti,nand-ecc-opt", &s)) { -- cgit v0.10.2 From 3e9161bfe0482f26efeaf584d5fd69398c69313c Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Thu, 14 Jul 2016 09:33:41 -0700 Subject: Revert "Input: wacom_w8001 - drop use of ABS_MT_TOOL_TYPE" This reverts commit 5f7e5445a2de848c66d2d80ba5479197e8287c33 because removal of input_mt_report_slot_state() means we no longer generate tracking IDs for the reported contacts. Cc: stable@vger.kernel.org Acked-by: Peter Hutterer Acked-by: Ping Cheng diff --git a/drivers/input/touchscreen/wacom_w8001.c b/drivers/input/touchscreen/wacom_w8001.c index 0c9191c..b6fc4bd 100644 --- a/drivers/input/touchscreen/wacom_w8001.c +++ b/drivers/input/touchscreen/wacom_w8001.c @@ -155,6 +155,7 @@ static void parse_multi_touch(struct w8001 *w8001) bool touch = data[0] & (1 << i); input_mt_slot(dev, i); + input_mt_report_slot_state(dev, MT_TOOL_FINGER, touch); if (touch) { x = (data[6 * i + 1] << 7) | data[6 * i + 2]; y = (data[6 * i + 3] << 7) | data[6 * i + 4]; @@ -522,6 +523,8 @@ static int w8001_setup_touch(struct w8001 *w8001, char *basename, 0, touch.x, 0, 0); input_set_abs_params(dev, ABS_MT_POSITION_Y, 0, touch.y, 0, 0); + input_set_abs_params(dev, ABS_MT_TOOL_TYPE, + 0, MT_TOOL_MAX, 0, 0); strlcat(basename, " 2FG", basename_sz); if (w8001->max_pen_x && w8001->max_pen_y) -- cgit v0.10.2 From 9624516db0f3ffcbd1ba1007775d068f54049773 Mon Sep 17 00:00:00 2001 From: Andrew Duggan Date: Thu, 14 Jul 2016 09:35:44 -0700 Subject: Input: synaptics-rmi4 - use of_get_child_by_name() to fix refcount Calling of_find_node_by_name() assumes that the caller has incremented the refcount of the of_node being passed in. Currently, the caller is not incrementing the refcount of the of_node which results in the node being prematurely freed when of_find_node_by_name() calls of_node_put() on it. Instead use of_get_child_by_name() which does not call put on the of_node. Signed-off-by: Andrew Duggan Signed-off-by: Dmitry Torokhov diff --git a/drivers/input/rmi4/rmi_bus.c b/drivers/input/rmi4/rmi_bus.c index b368b05..253df96 100644 --- a/drivers/input/rmi4/rmi_bus.c +++ b/drivers/input/rmi4/rmi_bus.c @@ -157,11 +157,11 @@ static int rmi_function_match(struct device *dev, struct device_driver *drv) static void rmi_function_of_probe(struct rmi_function *fn) { char of_name[9]; + struct device_node *node = fn->rmi_dev->xport->dev->of_node; snprintf(of_name, sizeof(of_name), "rmi4-f%02x", fn->fd.function_number); - fn->dev.of_node = of_find_node_by_name( - fn->rmi_dev->xport->dev->of_node, of_name); + fn->dev.of_node = of_get_child_by_name(node, of_name); } #else static inline void rmi_function_of_probe(struct rmi_function *fn) -- cgit v0.10.2 From 4d581259b7d44c8120a614b4e9244094c824d51f Mon Sep 17 00:00:00 2001 From: Alex Hung Date: Thu, 14 Jul 2016 18:05:56 +0800 Subject: x86/reboot: Add Dell Optiplex 7450 AIO reboot quirk Dell Optiplex 7450 AIO works with BOOT_ACPI; however, the quirk for "OptiPlex 745" changes its boot method to BOOT_BIOS and causes 7450 AIO hangs when rebooting; as a result, 7450 AIO is appended to overwrite BOOT_BIOS by BOOT_ACPI in order not to break the original 745 series Signed-off-by: Alex Hung Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: linux-kernel@vger.kernel.org Signed-off-by: Ingo Molnar diff --git a/arch/x86/kernel/reboot.c b/arch/x86/kernel/reboot.c index a9b31eb..15ed70f 100644 --- a/arch/x86/kernel/reboot.c +++ b/arch/x86/kernel/reboot.c @@ -55,6 +55,19 @@ bool port_cf9_safe = false; */ /* + * Some machines require the "reboot=a" commandline options + */ +static int __init set_acpi_reboot(const struct dmi_system_id *d) +{ + if (reboot_type != BOOT_ACPI) { + reboot_type = BOOT_ACPI; + pr_info("%s series board detected. Selecting %s-method for reboots.\n", + d->ident, "ACPI"); + } + return 0; +} + +/* * Some machines require the "reboot=b" or "reboot=k" commandline options, * this quirk makes that automatic. */ @@ -395,6 +408,14 @@ static struct dmi_system_id __initdata reboot_dmi_table[] = { DMI_MATCH(DMI_PRODUCT_NAME, "Dell XPS710"), }, }, + { /* Handle problems with rebooting on Dell Optiplex 7450 AIO */ + .callback = set_acpi_reboot, + .ident = "Dell OptiPlex 7450 AIO", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex 7450 AIO"), + }, + }, /* Hewlett-Packard */ { /* Handle problems with rebooting on HP laptops */ -- cgit v0.10.2 From 795c2109c287123dfc3bc987d20daef32d77e4d1 Mon Sep 17 00:00:00 2001 From: Ken Wang Date: Thu, 7 Jul 2016 09:56:53 +0800 Subject: drm/amdgpu: Add a missing register to Polaris golden setting Signed-off-by: Ken Wang Reviewed-by: Alex Deucher Signed-off-by: Alex Deucher diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c index b2ebd4f..42e3031 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c @@ -284,6 +284,7 @@ static const u32 golden_settings_polaris11_a11[] = mmTCP_ADDR_CONFIG, 0x000003ff, 0x000000f3, mmTCP_CHAN_STEER_HI, 0xffffffff, 0x00000000, mmTCP_CHAN_STEER_LO, 0xffffffff, 0x00003210, + mmVGT_RESET_DEBUG, 0x00000004, 0x00000004, }; static const u32 polaris11_golden_common_all[] = @@ -314,6 +315,7 @@ static const u32 golden_settings_polaris10_a11[] = mmTCC_CTRL, 0x00100000, 0xf31fff7f, mmTCP_ADDR_CONFIG, 0x000003ff, 0x000000f7, mmTCP_CHAN_STEER_HI, 0xffffffff, 0x00000000, + mmVGT_RESET_DEBUG, 0x00000004, 0x00000004, }; static const u32 polaris10_golden_common_all[] = -- cgit v0.10.2 From eeade25ad029cb1f31f27f8e0ddc9bb9c22b5537 Mon Sep 17 00:00:00 2001 From: Ken Wang Date: Mon, 11 Jul 2016 13:33:40 +0800 Subject: drm/amdgpu: fix power distribution issue for Polaris10 XT Signed-off-by: Ken Wang Reviewed-by: Alex Deucher Signed-off-by: Alex Deucher diff --git a/drivers/gpu/drm/amd/amdgpu/atombios_i2c.c b/drivers/gpu/drm/amd/amdgpu/atombios_i2c.c index 13cdb01..bc56c8a 100644 --- a/drivers/gpu/drm/amd/amdgpu/atombios_i2c.c +++ b/drivers/gpu/drm/amd/amdgpu/atombios_i2c.c @@ -156,3 +156,18 @@ u32 amdgpu_atombios_i2c_func(struct i2c_adapter *adap) return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; } +void amdgpu_atombios_i2c_channel_trans(struct amdgpu_device* adev, u8 slave_addr, u8 line_number, u8 offset, u8 data) +{ + PROCESS_I2C_CHANNEL_TRANSACTION_PS_ALLOCATION args; + int index = GetIndexIntoMasterTable(COMMAND, ProcessI2cChannelTransaction); + + args.ucRegIndex = offset; + args.lpI2CDataOut = data; + args.ucFlag = 1; + args.ucI2CSpeed = TARGET_HW_I2C_CLOCK; + args.ucTransBytes = 1; + args.ucSlaveAddr = slave_addr; + args.ucLineNumber = line_number; + + amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args); +} diff --git a/drivers/gpu/drm/amd/amdgpu/atombios_i2c.h b/drivers/gpu/drm/amd/amdgpu/atombios_i2c.h index d6128d9d..251aaf4 100644 --- a/drivers/gpu/drm/amd/amdgpu/atombios_i2c.h +++ b/drivers/gpu/drm/amd/amdgpu/atombios_i2c.h @@ -27,5 +27,7 @@ int amdgpu_atombios_i2c_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs, int num); u32 amdgpu_atombios_i2c_func(struct i2c_adapter *adap); +void amdgpu_atombios_i2c_channel_trans(struct amdgpu_device* adev, + u8 slave_addr, u8 line_number, u8 offset, u8 data); #endif diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c index 42e3031..c2ef945 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c @@ -28,6 +28,7 @@ #include "vid.h" #include "amdgpu_ucode.h" #include "amdgpu_atombios.h" +#include "atombios_i2c.h" #include "clearstate_vi.h" #include "gmc/gmc_8_2_d.h" @@ -698,6 +699,10 @@ static void gfx_v8_0_init_golden_registers(struct amdgpu_device *adev) polaris10_golden_common_all, (const u32)ARRAY_SIZE(polaris10_golden_common_all)); WREG32_SMC(ixCG_ACLK_CNTL, 0x0000001C); + if (adev->pdev->revision == 0xc7) { + amdgpu_atombios_i2c_channel_trans(adev, 0x10, 0x96, 0x1E, 0xDD); + amdgpu_atombios_i2c_channel_trans(adev, 0x10, 0x96, 0x1F, 0xD0); + } break; case CHIP_CARRIZO: amdgpu_program_register_sequence(adev, -- cgit v0.10.2 From 005db31d5f5f7c31cfdc43505d77eb3ca5cf8ec6 Mon Sep 17 00:00:00 2001 From: Beniamino Galvani Date: Wed, 13 Jul 2016 18:25:08 +0200 Subject: bonding: set carrier off for devices created through netlink Commit e826eafa65c6 ("bonding: Call netif_carrier_off after register_netdevice") moved netif_carrier_off() from bond_init() to bond_create(), but the latter is called only for initial default devices and ones created through sysfs: $ modprobe bonding $ echo +bond1 > /sys/class/net/bonding_masters $ ip link add bond2 type bond $ grep "MII Status" /proc/net/bonding/* /proc/net/bonding/bond0:MII Status: down /proc/net/bonding/bond1:MII Status: down /proc/net/bonding/bond2:MII Status: up Ensure that carrier is initially off also for devices created through netlink. Signed-off-by: Beniamino Galvani Signed-off-by: David S. Miller diff --git a/drivers/net/bonding/bond_netlink.c b/drivers/net/bonding/bond_netlink.c index db760e8..b8df0f5 100644 --- a/drivers/net/bonding/bond_netlink.c +++ b/drivers/net/bonding/bond_netlink.c @@ -446,7 +446,11 @@ static int bond_newlink(struct net *src_net, struct net_device *bond_dev, if (err < 0) return err; - return register_netdevice(bond_dev); + err = register_netdevice(bond_dev); + + netif_carrier_off(bond_dev); + + return err; } static size_t bond_get_size(const struct net_device *bond_dev) -- cgit v0.10.2 From a46cbf3bc53b6a93fb84a5ffb288c354fa807954 Mon Sep 17 00:00:00 2001 From: David Rientjes Date: Thu, 14 Jul 2016 12:06:50 -0700 Subject: mm, compaction: prevent VM_BUG_ON when terminating freeing scanner It's possible to isolate some freepages in a pageblock and then fail split_free_page() due to the low watermark check. In this case, we hit VM_BUG_ON() because the freeing scanner terminated early without a contended lock or enough freepages. This should never have been a VM_BUG_ON() since it's not a fatal condition. It should have been a VM_WARN_ON() at best, or even handled gracefully. Regardless, we need to terminate anytime the full pageblock scan was not done. The logic belongs in isolate_freepages_block(), so handle its state gracefully by terminating the pageblock loop and making a note to restart at the same pageblock next time since it was not possible to complete the scan this time. [rientjes@google.com: don't rescan pages in a pageblock] Link: http://lkml.kernel.org/r/alpine.DEB.2.10.1607111244150.83138@chino.kir.corp.google.com Link: http://lkml.kernel.org/r/alpine.DEB.2.10.1606291436300.145590@chino.kir.corp.google.com Signed-off-by: David Rientjes Reported-by: Minchan Kim Tested-by: Minchan Kim Cc: Joonsoo Kim Cc: Hugh Dickins Cc: Mel Gorman Cc: Vlastimil Babka Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/mm/compaction.c b/mm/compaction.c index 79bfe0e..7bc0477 100644 --- a/mm/compaction.c +++ b/mm/compaction.c @@ -1009,8 +1009,6 @@ static void isolate_freepages(struct compact_control *cc) block_end_pfn = block_start_pfn, block_start_pfn -= pageblock_nr_pages, isolate_start_pfn = block_start_pfn) { - unsigned long isolated; - /* * This can iterate a massively long zone without finding any * suitable migration targets, so periodically check if we need @@ -1034,36 +1032,30 @@ static void isolate_freepages(struct compact_control *cc) continue; /* Found a block suitable for isolating free pages from. */ - isolated = isolate_freepages_block(cc, &isolate_start_pfn, - block_end_pfn, freelist, false); - /* If isolation failed early, do not continue needlessly */ - if (!isolated && isolate_start_pfn < block_end_pfn && - cc->nr_migratepages > cc->nr_freepages) - break; + isolate_freepages_block(cc, &isolate_start_pfn, block_end_pfn, + freelist, false); /* - * If we isolated enough freepages, or aborted due to async - * compaction being contended, terminate the loop. - * Remember where the free scanner should restart next time, - * which is where isolate_freepages_block() left off. - * But if it scanned the whole pageblock, isolate_start_pfn - * now points at block_end_pfn, which is the start of the next - * pageblock. - * In that case we will however want to restart at the start - * of the previous pageblock. + * If we isolated enough freepages, or aborted due to lock + * contention, terminate. */ if ((cc->nr_freepages >= cc->nr_migratepages) || cc->contended) { - if (isolate_start_pfn >= block_end_pfn) + if (isolate_start_pfn >= block_end_pfn) { + /* + * Restart at previous pageblock if more + * freepages can be isolated next time. + */ isolate_start_pfn = block_start_pfn - pageblock_nr_pages; + } break; - } else { + } else if (isolate_start_pfn < block_end_pfn) { /* - * isolate_freepages_block() should not terminate - * prematurely unless contended, or isolated enough + * If isolation failed early, do not continue + * needlessly. */ - VM_BUG_ON(isolate_start_pfn < block_end_pfn); + break; } } -- cgit v0.10.2 From 2ba78056acfe8d63a29565f91dae4678ed6b81ca Mon Sep 17 00:00:00 2001 From: Dmitry Vyukov Date: Thu, 14 Jul 2016 12:06:53 -0700 Subject: kasan: add newline to messages Currently GPF messages with KASAN look as follows: kasan: GPF could be caused by NULL-ptr deref or user memory accessgeneral protection fault: 0000 [#1] SMP DEBUG_PAGEALLOC KASAN Add newlines. Link: http://lkml.kernel.org/r/1467294357-98002-1-git-send-email-dvyukov@google.com Signed-off-by: Dmitry Vyukov Acked-by: Andrey Ryabinin Cc: Alexander Potapenko Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/arch/x86/mm/kasan_init_64.c b/arch/x86/mm/kasan_init_64.c index 1b1110f..0493c17 100644 --- a/arch/x86/mm/kasan_init_64.c +++ b/arch/x86/mm/kasan_init_64.c @@ -54,8 +54,8 @@ static int kasan_die_handler(struct notifier_block *self, void *data) { if (val == DIE_GPF) { - pr_emerg("CONFIG_KASAN_INLINE enabled"); - pr_emerg("GPF could be caused by NULL-ptr deref or user memory access"); + pr_emerg("CONFIG_KASAN_INLINE enabled\n"); + pr_emerg("GPF could be caused by NULL-ptr deref or user memory access\n"); } return NOTIFY_OK; } -- cgit v0.10.2 From abb035b48270b226356552486c6de2b1652bdb90 Mon Sep 17 00:00:00 2001 From: Kieran Bingham Date: Thu, 14 Jul 2016 12:06:55 -0700 Subject: scripts/gdb: silence 'nothing to do' message The constants.py generation, involves a rule to link into the main makefile. This rule has no command and generates a spurious warning message in the build logs when CONFIG_SCRIPTS_GDB is enabled. Fix simply by giving a no-op action Link: http://lkml.kernel.org/r/1467127337-11135-2-git-send-email-kieran@bingham.xyz Signed-off-by: Kieran Bingham Reported-by: Jan Kiszka Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/scripts/gdb/linux/Makefile b/scripts/gdb/linux/Makefile index cd129e6..7a33556 100644 --- a/scripts/gdb/linux/Makefile +++ b/scripts/gdb/linux/Makefile @@ -17,5 +17,6 @@ $(obj)/constants.py: $(SRCTREE)/$(obj)/constants.py.in $(call if_changed,gen_constants_py) build_constants_py: $(obj)/constants.py + @: clean-files := *.pyc *.pyo $(if $(KBUILD_SRC),*.py) $(obj)/constants.py -- cgit v0.10.2 From 834a35296ab0a850e22cda1059e4c05b091c4ad9 Mon Sep 17 00:00:00 2001 From: Kieran Bingham Date: Thu, 14 Jul 2016 12:06:58 -0700 Subject: scripts/gdb: rebuild constants.py on dependancy change The autogenerated constants.py file was only being built on the initial call, and if the constants.py.in file changed. As we are utilising the CPP hooks, we can successfully use the call if_changed_dep rules to determine when to rebuild the file based on it's inclusions. Link: http://lkml.kernel.org/r/1467127337-11135-3-git-send-email-kieran@bingham.xyz Signed-off-by: Kieran Bingham Reported-by: Jan Kiszka Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/scripts/gdb/linux/Makefile b/scripts/gdb/linux/Makefile index 7a33556..8b00031 100644 --- a/scripts/gdb/linux/Makefile +++ b/scripts/gdb/linux/Makefile @@ -13,8 +13,9 @@ quiet_cmd_gen_constants_py = GEN $@ $(CPP) -E -x c -P $(c_flags) $< > $@ ;\ sed -i '1,//d;' $@ -$(obj)/constants.py: $(SRCTREE)/$(obj)/constants.py.in - $(call if_changed,gen_constants_py) +targets += constants.py +$(obj)/constants.py: $(SRCTREE)/$(obj)/constants.py.in FORCE + $(call if_changed_dep,gen_constants_py) build_constants_py: $(obj)/constants.py @: -- cgit v0.10.2 From e2aa2f8face230e284f6d344c6a4ee6f53e60207 Mon Sep 17 00:00:00 2001 From: Omar Sandoval Date: Thu, 14 Jul 2016 12:07:01 -0700 Subject: scripts/gdb: add constants.py to .gitignore Since scripts/gdb/linux/constants.py is autogenerated, this should have been added to .gitignore when it was introduced. Fixes: f197d75fcad1 ("scripts/gdb: provide linux constants") Link: http://lkml.kernel.org/r/1467127337-11135-4-git-send-email-kieran@bingham.xyz Signed-off-by: Omar Sandoval Signed-off-by: Kieran Bingham Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/scripts/gdb/linux/.gitignore b/scripts/gdb/linux/.gitignore index 52e4e61..2573543 100644 --- a/scripts/gdb/linux/.gitignore +++ b/scripts/gdb/linux/.gitignore @@ -1,2 +1,3 @@ *.pyc *.pyo +constants.py -- cgit v0.10.2 From 552ab2a3eaa4338fa5b33aa4c07ea2c542ddcea5 Mon Sep 17 00:00:00 2001 From: Nikolay Borisov Date: Thu, 14 Jul 2016 12:07:04 -0700 Subject: scripts/gdb: Perform path expansion to lx-symbol's arguments Python doesn't do automatic expansion of paths. In case one passes path of the from ~/foo/bar the gdb scripts won't automatically expand that and as a result the symbols files won't be loaded. Fix this by explicitly expanding all paths which begin with "~" Link: http://lkml.kernel.org/r/1467127337-11135-5-git-send-email-kieran@bingham.xyz Signed-off-by: Nikolay Borisov Signed-off-by: Kieran Bingham Reviewed-by: Jan Kiszka Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/scripts/gdb/linux/symbols.py b/scripts/gdb/linux/symbols.py index 9a0f892..004b0ac 100644 --- a/scripts/gdb/linux/symbols.py +++ b/scripts/gdb/linux/symbols.py @@ -153,7 +153,7 @@ lx-symbols command.""" saved_state['breakpoint'].enabled = saved_state['enabled'] def invoke(self, arg, from_tty): - self.module_paths = arg.split() + self.module_paths = [os.path.expanduser(p) for p in arg.split()] self.module_paths.append(os.getcwd()) # enforce update -- cgit v0.10.2 From b447e02548a3304c47b78b5e2d75a4312a8f17e1 Mon Sep 17 00:00:00 2001 From: Kieran Bingham Date: Thu, 14 Jul 2016 12:07:06 -0700 Subject: Revert "scripts/gdb: add a Radix Tree Parser" This reverts commit e127a73d41ac ("scripts/gdb: add a Radix Tree Parser") The python implementation of radix-tree was merged at the same time as the radix-tree system was heavily reworked from commit e9256efcc8e3 ("radix-tree: introduce radix_tree_empty") to 3bcadd6fa6c4 ("radix-tree: free up the bottom bit of exceptional entries for reuse") and no longer functions, but also prevents other gdb scripts from loading. This functionality has not yet hit a release, so simply remove it for now Link: http://lkml.kernel.org/r/1467127337-11135-6-git-send-email-kieran@bingham.xyz Signed-off-by: Kieran Bingham Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/scripts/gdb/linux/constants.py.in b/scripts/gdb/linux/constants.py.in index 07e6c2b..7986f4e 100644 --- a/scripts/gdb/linux/constants.py.in +++ b/scripts/gdb/linux/constants.py.in @@ -14,7 +14,6 @@ #include #include -#include /* We need to stringify expanded macros so that they can be parsed */ @@ -51,9 +50,3 @@ LX_VALUE(MNT_NOEXEC) LX_VALUE(MNT_NOATIME) LX_VALUE(MNT_NODIRATIME) LX_VALUE(MNT_RELATIME) - -/* linux/radix-tree.h */ -LX_VALUE(RADIX_TREE_INDIRECT_PTR) -LX_GDBPARSED(RADIX_TREE_HEIGHT_MASK) -LX_GDBPARSED(RADIX_TREE_MAP_SHIFT) -LX_GDBPARSED(RADIX_TREE_MAP_MASK) diff --git a/scripts/gdb/linux/radixtree.py b/scripts/gdb/linux/radixtree.py deleted file mode 100644 index 0fdef4e..0000000 --- a/scripts/gdb/linux/radixtree.py +++ /dev/null @@ -1,97 +0,0 @@ -# -# gdb helper commands and functions for Linux kernel debugging -# -# Radix Tree Parser -# -# Copyright (c) 2016 Linaro Ltd -# -# Authors: -# Kieran Bingham -# -# This work is licensed under the terms of the GNU GPL version 2. -# - -import gdb - -from linux import utils -from linux import constants - -radix_tree_root_type = utils.CachedType("struct radix_tree_root") -radix_tree_node_type = utils.CachedType("struct radix_tree_node") - - -def is_indirect_ptr(node): - long_type = utils.get_long_type() - return (node.cast(long_type) & constants.LX_RADIX_TREE_INDIRECT_PTR) - - -def indirect_to_ptr(node): - long_type = utils.get_long_type() - node_type = node.type - indirect_ptr = node.cast(long_type) & ~constants.LX_RADIX_TREE_INDIRECT_PTR - return indirect_ptr.cast(node_type) - - -def maxindex(height): - height = height & constants.LX_RADIX_TREE_HEIGHT_MASK - return gdb.parse_and_eval("height_to_maxindex["+str(height)+"]") - - -def lookup(root, index): - if root.type == radix_tree_root_type.get_type().pointer(): - root = root.dereference() - elif root.type != radix_tree_root_type.get_type(): - raise gdb.GdbError("Must be struct radix_tree_root not {}" - .format(root.type)) - - node = root['rnode'] - if node is 0: - return None - - if not (is_indirect_ptr(node)): - if (index > 0): - return None - return node - - node = indirect_to_ptr(node) - - height = node['path'] & constants.LX_RADIX_TREE_HEIGHT_MASK - if (index > maxindex(height)): - return None - - shift = (height-1) * constants.LX_RADIX_TREE_MAP_SHIFT - - while True: - new_index = (index >> shift) & constants.LX_RADIX_TREE_MAP_MASK - slot = node['slots'][new_index] - - node = slot.cast(node.type.pointer()).dereference() - if node is 0: - return None - - shift -= constants.LX_RADIX_TREE_MAP_SHIFT - height -= 1 - - if (height <= 0): - break - - return node - - -class LxRadixTree(gdb.Function): - """ Lookup and return a node from a RadixTree. - -$lx_radix_tree_lookup(root_node [, index]): Return the node at the given index. -If index is omitted, the root node is dereferenced and returned.""" - - def __init__(self): - super(LxRadixTree, self).__init__("lx_radix_tree_lookup") - - def invoke(self, root, index=0): - result = lookup(root, index) - if result is None: - raise gdb.GdbError("No entry in tree at index {}".format(index)) - - return result - -LxRadixTree() diff --git a/scripts/gdb/vmlinux-gdb.py b/scripts/gdb/vmlinux-gdb.py index 3a80ad6..6e0b0af 100644 --- a/scripts/gdb/vmlinux-gdb.py +++ b/scripts/gdb/vmlinux-gdb.py @@ -31,4 +31,3 @@ else: import linux.lists import linux.proc import linux.constants - import linux.radixtree -- cgit v0.10.2 From ef722fd4a7592ddbfa42bcb3ad8a5caa598589b3 Mon Sep 17 00:00:00 2001 From: Kieran Bingham Date: Thu, 14 Jul 2016 12:07:09 -0700 Subject: Revert "scripts/gdb: add documentation example for radix tree" This reverts commit 9b5580359a84 ("scripts/gdb: add documentation example for radix tree") The python implementation of radix tree was merged at the same time as a refactoring of the radix tree implementation and doesn't work. The feature is being reverted, thus we revert the documentation as well. Link: http://lkml.kernel.org/r/1467127337-11135-7-git-send-email-kieran@bingham.xyz Signed-off-by: Kieran Bingham Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/Documentation/gdb-kernel-debugging.txt b/Documentation/gdb-kernel-debugging.txt index 4ab7d43..7050ce8 100644 --- a/Documentation/gdb-kernel-debugging.txt +++ b/Documentation/gdb-kernel-debugging.txt @@ -139,27 +139,6 @@ Examples of using the Linux-provided gdb helpers start_comm = "swapper/2\000\000\000\000\000\000" } - o Dig into a radix tree data structure, such as the IRQ descriptors: - (gdb) print (struct irq_desc)$lx_radix_tree_lookup(irq_desc_tree, 18) - $6 = { - irq_common_data = { - state_use_accessors = 67584, - handler_data = 0x0 <__vectors_start>, - msi_desc = 0x0 <__vectors_start>, - affinity = {{ - bits = {65535} - }} - }, - irq_data = { - mask = 0, - irq = 18, - hwirq = 27, - common = 0xee803d80, - chip = 0xc0eb0854 , - domain = 0xee808000, - parent_data = 0x0 <__vectors_start>, - chip_data = 0xc0eb0854 - } <... trimmed ...> List of commands and functions ------------------------------ -- cgit v0.10.2 From 9818b8cde6221fe7a52aad816425f67d4439b14e Mon Sep 17 00:00:00 2001 From: Huang Ying Date: Thu, 14 Jul 2016 12:07:12 -0700 Subject: madvise_free, thp: fix madvise_free_huge_pmd return value after splitting madvise_free_huge_pmd should return 0 if the fallback PTE operations are required. In madvise_free_huge_pmd, if part pages of THP are discarded, the THP will be split and fallback PTE operations should be used if splitting succeeds. But the original code will make fallback PTE operations skipped, after splitting succeeds. Fix that via make madvise_free_huge_pmd return 0 after splitting successfully, so that the fallback PTE operations will be done. Link: http://lkml.kernel.org/r/1467135452-16688-1-git-send-email-ying.huang@intel.com Signed-off-by: "Huang, Ying" Acked-by: Minchan Kim Cc: "Kirill A. Shutemov" Cc: Vlastimil Babka Cc: Jerome Marchand Cc: Andrea Arcangeli Cc: Ebru Akagunduz Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/mm/huge_memory.c b/mm/huge_memory.c index 9ed5853..55940d1 100644 --- a/mm/huge_memory.c +++ b/mm/huge_memory.c @@ -1624,14 +1624,9 @@ int madvise_free_huge_pmd(struct mmu_gather *tlb, struct vm_area_struct *vma, if (next - addr != HPAGE_PMD_SIZE) { get_page(page); spin_unlock(ptl); - if (split_huge_page(page)) { - put_page(page); - unlock_page(page); - goto out_unlocked; - } + split_huge_page(page); put_page(page); unlock_page(page); - ret = 1; goto out_unlocked; } -- cgit v0.10.2 From 12cb22bb8ae9aff9d72a9c0a234f26d641b20eb6 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 14 Jul 2016 12:07:15 -0700 Subject: uapi: export lirc.h header This header contains the userspace API for lirc. This is a fixup for commit b7be755733dc ("[media] bz#75751: Move internal header file lirc.h to uapi/"). It moved the header to the right place, but it forgot to add it at Kbuild. So, despite being at uapi, it is not copied to the right place. Fixes: b7be755733dc44c72 ("[media] bz#75751: Move internal header file lirc.h to uapi/") Link: http://lkml.kernel.org/r/320c765d32bfc82c582e336d52ffe1026c73c644.1468439021.git.mchehab@s-opensource.com Signed-off-by: Mauro Carvalho Chehab Cc: Alec Leamas Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/include/uapi/linux/Kbuild b/include/uapi/linux/Kbuild index 8bdae34..ec10cfe 100644 --- a/include/uapi/linux/Kbuild +++ b/include/uapi/linux/Kbuild @@ -245,6 +245,7 @@ endif header-y += hw_breakpoint.h header-y += l2tp.h header-y += libc-compat.h +header-y += lirc.h header-y += limits.h header-y += llc.h header-y += loop.h -- cgit v0.10.2 From 0ab686d8c8303069e80300663b3be6201a8697fb Mon Sep 17 00:00:00 2001 From: Joonsoo Kim Date: Thu, 14 Jul 2016 12:07:17 -0700 Subject: kasan/quarantine: fix bugs on qlist_move_cache() There are two bugs on qlist_move_cache(). One is that qlist's tail isn't set properly. curr->next can be NULL since it is singly linked list and NULL value on tail is invalid if there is one item on qlist. Another one is that if cache is matched, qlist_put() is called and it will set curr->next to NULL. It would cause to stop the loop prematurely. These problems come from complicated implementation so I'd like to re-implement it completely. Implementation in this patch is really simple. Iterate all qlist_nodes and put them to appropriate list. Unfortunately, I got this bug sometime ago and lose oops message. But, the bug looks trivial and no need to attach oops. Fixes: 55834c59098d ("mm: kasan: initial memory quarantine implementation") Link: http://lkml.kernel.org/r/1467766348-22419-1-git-send-email-iamjoonsoo.kim@lge.com Signed-off-by: Joonsoo Kim Reviewed-by: Dmitry Vyukov Acked-by: Andrey Ryabinin Acked-by: Alexander Potapenko Cc: Kuthonuzo Luruo Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/mm/kasan/quarantine.c b/mm/kasan/quarantine.c index 4973505..65793f1 100644 --- a/mm/kasan/quarantine.c +++ b/mm/kasan/quarantine.c @@ -238,30 +238,23 @@ static void qlist_move_cache(struct qlist_head *from, struct qlist_head *to, struct kmem_cache *cache) { - struct qlist_node *prev = NULL, *curr; + struct qlist_node *curr; if (unlikely(qlist_empty(from))) return; curr = from->head; + qlist_init(from); while (curr) { - struct qlist_node *qlink = curr; - struct kmem_cache *obj_cache = qlink_to_cache(qlink); - - if (obj_cache == cache) { - if (unlikely(from->head == qlink)) { - from->head = curr->next; - prev = curr; - } else - prev->next = curr->next; - if (unlikely(from->tail == qlink)) - from->tail = curr->next; - from->bytes -= cache->size; - qlist_put(to, qlink, cache->size); - } else { - prev = curr; - } - curr = curr->next; + struct qlist_node *next = curr->next; + struct kmem_cache *obj_cache = qlink_to_cache(curr); + + if (obj_cache == cache) + qlist_put(to, curr, obj_cache->size); + else + qlist_put(from, curr, obj_cache->size); + + curr = next; } } -- cgit v0.10.2 From e4568d3803852d00effd41dcdd489e726b998879 Mon Sep 17 00:00:00 2001 From: Mel Gorman Date: Thu, 14 Jul 2016 12:07:20 -0700 Subject: mm, meminit: always return a valid node from early_pfn_to_nid early_pfn_to_nid can return node 0 if a PFN is invalid on machines that has no node 0. A machine with only node 1 was observed to crash with the following message: BUG: unable to handle kernel paging request at 000000000002a3c8 PGD 0 Modules linked in: Hardware name: Supermicro H8DSP-8/H8DSP-8, BIOS 080011 06/30/2006 task: ffffffff81c0d500 ti: ffffffff81c00000 task.ti: ffffffff81c00000 RIP: reserve_bootmem_region+0x6a/0xef CR2: 000000000002a3c8 CR3: 0000000001c06000 CR4: 00000000000006b0 Call Trace: free_all_bootmem+0x4b/0x12a mem_init+0x70/0xa3 start_kernel+0x25b/0x49b The problem is that early_page_uninitialised uses the early_pfn_to_nid helper which returns node 0 for invalid PFNs. No caller of early_pfn_to_nid cares except early_page_uninitialised. This patch has early_pfn_to_nid always return a valid node. Link: http://lkml.kernel.org/r/1468008031-3848-3-git-send-email-mgorman@techsingularity.net Signed-off-by: Mel Gorman Acked-by: David Rientjes Cc: [4.2+] Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/mm/page_alloc.c b/mm/page_alloc.c index 6903b69..5d01352 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -1273,7 +1273,7 @@ int __meminit early_pfn_to_nid(unsigned long pfn) spin_lock(&early_pfn_lock); nid = __early_pfn_to_nid(pfn, &early_pfnnid_cache); if (nid < 0) - nid = 0; + nid = first_online_node; spin_unlock(&early_pfn_lock); return nid; -- cgit v0.10.2 From ef70b6f41cda6270165a6f27b2548ed31cfa3cb2 Mon Sep 17 00:00:00 2001 From: Mel Gorman Date: Thu, 14 Jul 2016 12:07:23 -0700 Subject: mm, meminit: ensure node is online before checking whether pages are uninitialised early_page_uninitialised looks up an arbitrary PFN. While a machine without node 0 will boot with "mm, page_alloc: Always return a valid node from early_pfn_to_nid", it works because it assumes that nodes are always in PFN order. This is not guaranteed so this patch adds robustness by always checking if the node being checked is online. Link: http://lkml.kernel.org/r/1468008031-3848-4-git-send-email-mgorman@techsingularity.net Signed-off-by: Mel Gorman Acked-by: David Rientjes Cc: [4.2+] Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/mm/page_alloc.c b/mm/page_alloc.c index 5d01352..8b3e134 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -286,7 +286,9 @@ static inline void reset_deferred_meminit(pg_data_t *pgdat) /* Returns true if the struct page for the pfn is uninitialised */ static inline bool __meminit early_page_uninitialised(unsigned long pfn) { - if (pfn >= NODE_DATA(early_pfn_to_nid(pfn))->first_deferred_pfn) + int nid = early_pfn_to_nid(pfn); + + if (node_online(nid) && pfn >= NODE_DATA(nid)->first_deferred_pfn) return true; return false; -- cgit v0.10.2 From d02038f972538b93011d78c068f44514fbde0a8c Mon Sep 17 00:00:00 2001 From: Florian Meier Date: Thu, 14 Jul 2016 12:07:26 -0700 Subject: gcov: add support for gcc version >= 6 Link: http://lkml.kernel.org/r/20160701130914.GA23225@styxhp Signed-off-by: Florian Meier Reviewed-by: Peter Oberparleiter Tested-by: Peter Oberparleiter Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/kernel/gcov/gcc_4_7.c b/kernel/gcov/gcc_4_7.c index e25e92f..6a5c239 100644 --- a/kernel/gcov/gcc_4_7.c +++ b/kernel/gcov/gcc_4_7.c @@ -18,7 +18,7 @@ #include #include "gcov.h" -#if __GNUC__ == 5 && __GNUC_MINOR__ >= 1 +#if (__GNUC__ > 5) || (__GNUC__ == 5 && __GNUC_MINOR__ >= 1) #define GCOV_COUNTERS 10 #elif __GNUC__ == 4 && __GNUC_MINOR__ >= 9 #define GCOV_COUNTERS 9 -- cgit v0.10.2 From e41f501d391265ff568f3e49d6128cc30856a36f Mon Sep 17 00:00:00 2001 From: Dmitry Vyukov Date: Thu, 14 Jul 2016 12:07:29 -0700 Subject: vmlinux.lds: account for destructor sections If CONFIG_KASAN is enabled and gcc is configured with --disable-initfini-array and/or gold linker is used, gcc emits .ctors/.dtors and .text.startup/.text.exit sections instead of .init_array/.fini_array. .dtors section is not explicitly accounted in the linker script and messes vvar/percpu layout. We want: ffffffff822bfd80 D _edata ffffffff822c0000 D __vvar_beginning_hack ffffffff822c0000 A __vvar_page ffffffff822c0080 0000000000000098 D vsyscall_gtod_data ffffffff822c1000 A __init_begin ffffffff822c1000 D init_per_cpu__irq_stack_union ffffffff822c1000 A __per_cpu_load ffffffff822d3000 D init_per_cpu__gdt_page We got: ffffffff8279a600 D _edata ffffffff8279b000 A __vvar_page ffffffff8279c000 A __init_begin ffffffff8279c000 D init_per_cpu__irq_stack_union ffffffff8279c000 A __per_cpu_load ffffffff8279e000 D __vvar_beginning_hack ffffffff8279e080 0000000000000098 D vsyscall_gtod_data ffffffff827ae000 D init_per_cpu__gdt_page This happens because __vvar_page and .vvar get different addresses in arch/x86/kernel/vmlinux.lds.S: . = ALIGN(PAGE_SIZE); __vvar_page = .; .vvar : AT(ADDR(.vvar) - LOAD_OFFSET) { /* work around gold bug 13023 */ __vvar_beginning_hack = .; Discard .dtors/.fini_array/.text.exit, since we don't call dtors. Merge .text.startup into init text. Link: http://lkml.kernel.org/r/1467386363-120030-1-git-send-email-dvyukov@google.com Signed-off-by: Dmitry Vyukov Reviewed-by: Andrey Ryabinin Cc: [4.0+] Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h index 6a67ab9..081d0f2 100644 --- a/include/asm-generic/vmlinux.lds.h +++ b/include/asm-generic/vmlinux.lds.h @@ -542,15 +542,19 @@ #define INIT_TEXT \ *(.init.text) \ + *(.text.startup) \ MEM_DISCARD(init.text) #define EXIT_DATA \ *(.exit.data) \ + *(.fini_array) \ + *(.dtors) \ MEM_DISCARD(exit.data) \ MEM_DISCARD(exit.rodata) #define EXIT_TEXT \ *(.exit.text) \ + *(.text.exit) \ MEM_DISCARD(exit.text) #define EXIT_CALL \ -- cgit v0.10.2 From 33f4751e99601b7bfd1d66aedabd3ee9140922de Mon Sep 17 00:00:00 2001 From: Naoya Horiguchi Date: Thu, 14 Jul 2016 12:07:32 -0700 Subject: mm: thp: move pmd check inside ptl for freeze_page() I found a race condition triggering VM_BUG_ON() in freeze_page(), when running a testcase with 3 processes: - process 1: keep writing thp, - process 2: keep clearing soft-dirty bits from virtual address of process 1 - process 3: call migratepages for process 1, The kernel message is like this: kernel BUG at /src/linux-dev/mm/huge_memory.c:3096! invalid opcode: 0000 [#1] SMP Modules linked in: cfg80211 rfkill crc32c_intel ppdev serio_raw pcspkr virtio_balloon virtio_console parport_pc parport pvpanic acpi_cpufreq tpm_tis tpm i2c_piix4 virtio_blk virtio_net ata_generic pata_acpi floppy virtio_pci virtio_ring virtio CPU: 0 PID: 28863 Comm: migratepages Not tainted 4.6.0-v4.6-160602-0827-+ #2 Hardware name: Bochs Bochs, BIOS Bochs 01/01/2011 task: ffff880037320000 ti: ffff88007cdd0000 task.ti: ffff88007cdd0000 RIP: 0010:[] [] split_huge_page_to_list+0x496/0x590 RSP: 0018:ffff88007cdd3b70 EFLAGS: 00010202 RAX: 0000000000000001 RBX: ffff88007c7b88c0 RCX: 0000000000000000 RDX: 0000000000000000 RSI: 0000000700000200 RDI: ffffea0003188000 RBP: ffff88007cdd3bb8 R08: 0000000000000001 R09: 00003ffffffff000 R10: ffff880000000000 R11: ffffc000001fffff R12: ffffea0003188000 R13: ffffea0003188000 R14: 0000000000000000 R15: 0400000000000080 FS: 00007f8ec241d740(0000) GS:ffff88007dc00000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 00007f8ec1f3ed20 CR3: 000000003707b000 CR4: 00000000000006f0 Call Trace: ? list_del+0xd/0x30 queue_pages_pte_range+0x4d1/0x590 __walk_page_range+0x204/0x4e0 walk_page_range+0x71/0xf0 queue_pages_range+0x75/0x90 ? queue_pages_hugetlb+0x190/0x190 ? new_node_page+0xc0/0xc0 ? change_prot_numa+0x40/0x40 migrate_to_node+0x71/0xd0 do_migrate_pages+0x1c3/0x210 SyS_migrate_pages+0x261/0x290 entry_SYSCALL_64_fastpath+0x1a/0xa4 Code: e8 b0 87 fb ff 0f 0b 48 c7 c6 30 32 9f 81 e8 a2 87 fb ff 0f 0b 48 c7 c6 b8 46 9f 81 e8 94 87 fb ff 0f 0b 85 c0 0f 84 3e fd ff ff <0f> 0b 85 c0 0f 85 a6 00 00 00 48 8b 75 c0 4c 89 f7 41 be f0 ff RIP split_huge_page_to_list+0x496/0x590 I'm not sure of the full scenario of the reproduction, but my debug showed that split_huge_pmd_address(freeze=true) returned without running main code of pmd splitting because pmd_present(*pmd) in precheck somehow returned 0. If this happens, the subsequent try_to_unmap() fails and returns non-zero (because page_mapcount() still > 0), and finally VM_BUG_ON() fires. This patch tries to fix it by prechecking pmd state inside ptl. Link: http://lkml.kernel.org/r/1466990929-7452-1-git-send-email-n-horiguchi@ah.jp.nec.com Signed-off-by: Naoya Horiguchi Signed-off-by: Kirill A. Shutemov Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/include/linux/huge_mm.h b/include/linux/huge_mm.h index 419fb9e..f0a7a03 100644 --- a/include/linux/huge_mm.h +++ b/include/linux/huge_mm.h @@ -94,7 +94,7 @@ static inline int split_huge_page(struct page *page) void deferred_split_huge_page(struct page *page); void __split_huge_pmd(struct vm_area_struct *vma, pmd_t *pmd, - unsigned long address, bool freeze); + unsigned long address, bool freeze, struct page *page); #define split_huge_pmd(__vma, __pmd, __address) \ do { \ @@ -102,7 +102,7 @@ void __split_huge_pmd(struct vm_area_struct *vma, pmd_t *pmd, if (pmd_trans_huge(*____pmd) \ || pmd_devmap(*____pmd)) \ __split_huge_pmd(__vma, __pmd, __address, \ - false); \ + false, NULL); \ } while (0) diff --git a/mm/huge_memory.c b/mm/huge_memory.c index 55940d1..343a2b7 100644 --- a/mm/huge_memory.c +++ b/mm/huge_memory.c @@ -2984,7 +2984,7 @@ static void __split_huge_pmd_locked(struct vm_area_struct *vma, pmd_t *pmd, } void __split_huge_pmd(struct vm_area_struct *vma, pmd_t *pmd, - unsigned long address, bool freeze) + unsigned long address, bool freeze, struct page *page) { spinlock_t *ptl; struct mm_struct *mm = vma->vm_mm; @@ -2992,8 +2992,17 @@ void __split_huge_pmd(struct vm_area_struct *vma, pmd_t *pmd, mmu_notifier_invalidate_range_start(mm, haddr, haddr + HPAGE_PMD_SIZE); ptl = pmd_lock(mm, pmd); + + /* + * If caller asks to setup a migration entries, we need a page to check + * pmd against. Otherwise we can end up replacing wrong page. + */ + VM_BUG_ON(freeze && !page); + if (page && page != pmd_page(*pmd)) + goto out; + if (pmd_trans_huge(*pmd)) { - struct page *page = pmd_page(*pmd); + page = pmd_page(*pmd); if (PageMlocked(page)) clear_page_mlock(page); } else if (!pmd_devmap(*pmd)) @@ -3020,24 +3029,8 @@ void split_huge_pmd_address(struct vm_area_struct *vma, unsigned long address, return; pmd = pmd_offset(pud, address); - if (!pmd_present(*pmd) || (!pmd_trans_huge(*pmd) && !pmd_devmap(*pmd))) - return; - /* - * If caller asks to setup a migration entries, we need a page to check - * pmd against. Otherwise we can end up replacing wrong page. - */ - VM_BUG_ON(freeze && !page); - if (page && page != pmd_page(*pmd)) - return; - - /* - * Caller holds the mmap_sem write mode or the anon_vma lock, - * so a huge pmd cannot materialize from under us (khugepaged - * holds both the mmap_sem write mode and the anon_vma lock - * write mode). - */ - __split_huge_pmd(vma, pmd, address, freeze); + __split_huge_pmd(vma, pmd, address, freeze, page); } void vma_adjust_trans_huge(struct vm_area_struct *vma, -- cgit v0.10.2 From 55bda43bb26d2c11eeedac742eff87a8ac34c106 Mon Sep 17 00:00:00 2001 From: Naoya Horiguchi Date: Thu, 14 Jul 2016 12:07:35 -0700 Subject: mm: rmap: call page_check_address() with sync enabled to avoid racy check The previous patch addresses the race between split_huge_pmd_address() and someone changing the pmd. The fix is only for splitting of normal thp (i.e. pmd-mapped thp,) and for splitting of pte-mapped thp there still is the similar race. For splitting pte-mapped thp, the pte's conversion is done by try_to_unmap_one(TTU_MIGRATION). This function checks page_check_address() to get the target pte, but it can return NULL under some race, leading to VM_BUG_ON() in freeze_page(). Fortunately, page_check_address() already has an argument to decide whether we do a quick/racy check or not, so let's flip it when called from freeze_page(). Link: http://lkml.kernel.org/r/1466990929-7452-2-git-send-email-n-horiguchi@ah.jp.nec.com Signed-off-by: Naoya Horiguchi Cc: Kirill A. Shutemov Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/mm/rmap.c b/mm/rmap.c index 0ea5d90..e4b713a 100644 --- a/mm/rmap.c +++ b/mm/rmap.c @@ -1427,7 +1427,8 @@ static int try_to_unmap_one(struct page *page, struct vm_area_struct *vma, goto out; } - pte = page_check_address(page, mm, address, &ptl, 0); + pte = page_check_address(page, mm, address, &ptl, + PageTransCompound(page)); if (!pte) goto out; -- cgit v0.10.2 From 5a49973d7143ebbabd76e1dcd69ee42e349bb7b9 Mon Sep 17 00:00:00 2001 From: Hugh Dickins Date: Thu, 14 Jul 2016 12:07:38 -0700 Subject: mm: thp: refix false positive BUG in page_move_anon_rmap() The VM_BUG_ON_PAGE in page_move_anon_rmap() is more trouble than it's worth: the syzkaller fuzzer hit it again. It's still wrong for some THP cases, because linear_page_index() was never intended to apply to addresses before the start of a vma. That's easily fixed with a signed long cast inside linear_page_index(); and Dmitry has tested such a patch, to verify the false positive. But why extend linear_page_index() just for this case? when the avoidance in page_move_anon_rmap() has already grown ugly, and there's no reason for the check at all (nothing else there is using address or index). Remove address arg from page_move_anon_rmap(), remove VM_BUG_ON_PAGE, remove CONFIG_DEBUG_VM PageTransHuge adjustment. And one more thing: should the compound_head(page) be done inside or outside page_move_anon_rmap()? It's usually pushed down to the lowest level nowadays (and mm/memory.c shows no other explicit use of it), so I think it's better done in page_move_anon_rmap() than by caller. Fixes: 0798d3c022dc ("mm: thp: avoid false positive VM_BUG_ON_PAGE in page_move_anon_rmap()") Link: http://lkml.kernel.org/r/alpine.LSU.2.11.1607120444540.12528@eggly.anvils Signed-off-by: Hugh Dickins Reported-by: Dmitry Vyukov Acked-by: Kirill A. Shutemov Cc: Mika Westerberg Cc: Andrea Arcangeli Cc: Rik van Riel Cc: [4.5+] Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/include/linux/rmap.h b/include/linux/rmap.h index 49eb4f8..2b0fad8 100644 --- a/include/linux/rmap.h +++ b/include/linux/rmap.h @@ -158,7 +158,7 @@ struct anon_vma *page_get_anon_vma(struct page *page); /* * rmap interfaces called when adding or removing pte of page */ -void page_move_anon_rmap(struct page *, struct vm_area_struct *, unsigned long); +void page_move_anon_rmap(struct page *, struct vm_area_struct *); void page_add_anon_rmap(struct page *, struct vm_area_struct *, unsigned long, bool); void do_page_add_anon_rmap(struct page *, struct vm_area_struct *, diff --git a/mm/hugetlb.c b/mm/hugetlb.c index c1f3c0b..addfe4ac 100644 --- a/mm/hugetlb.c +++ b/mm/hugetlb.c @@ -3383,7 +3383,7 @@ retry_avoidcopy: /* If no-one else is actually using this page, avoid the copy * and just make the page writable */ if (page_mapcount(old_page) == 1 && PageAnon(old_page)) { - page_move_anon_rmap(old_page, vma, address); + page_move_anon_rmap(old_page, vma); set_huge_ptep_writable(vma, address, ptep); return 0; } diff --git a/mm/memory.c b/mm/memory.c index cd1f29e..9e04681 100644 --- a/mm/memory.c +++ b/mm/memory.c @@ -2399,8 +2399,7 @@ static int do_wp_page(struct mm_struct *mm, struct vm_area_struct *vma, * Protected against the rmap code by * the page lock. */ - page_move_anon_rmap(compound_head(old_page), - vma, address); + page_move_anon_rmap(old_page, vma); } unlock_page(old_page); return wp_page_reuse(mm, vma, address, page_table, ptl, diff --git a/mm/rmap.c b/mm/rmap.c index e4b713a..701b93f 100644 --- a/mm/rmap.c +++ b/mm/rmap.c @@ -1084,23 +1084,20 @@ EXPORT_SYMBOL_GPL(page_mkclean); * page_move_anon_rmap - move a page to our anon_vma * @page: the page to move to our anon_vma * @vma: the vma the page belongs to - * @address: the user virtual address mapped * * When a page belongs exclusively to one process after a COW event, * that page can be moved into the anon_vma that belongs to just that * process, so the rmap code will not search the parent or sibling * processes. */ -void page_move_anon_rmap(struct page *page, - struct vm_area_struct *vma, unsigned long address) +void page_move_anon_rmap(struct page *page, struct vm_area_struct *vma) { struct anon_vma *anon_vma = vma->anon_vma; + page = compound_head(page); + VM_BUG_ON_PAGE(!PageLocked(page), page); VM_BUG_ON_VMA(!anon_vma, vma); - if (IS_ENABLED(CONFIG_DEBUG_VM) && PageTransHuge(page)) - address &= HPAGE_PMD_MASK; - VM_BUG_ON_PAGE(page->index != linear_page_index(vma, address), page); anon_vma = (void *) anon_vma + PAGE_MAPPING_ANON; /* -- cgit v0.10.2 From d3d36c4b5c5fbdd68542be73ffd53eb210fbf7cf Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Thu, 14 Jul 2016 12:07:41 -0700 Subject: mm: workingset: printk missing log level, use pr_info() Commit 612e44939c3c ("mm: workingset: eviction buckets for bigmem/lowbit machines") added a printk without a log level. Quieten it by using pr_info(). Link: http://lkml.kernel.org/r/1466982072-29836-2-git-send-email-anton@ozlabs.org Signed-off-by: Anton Blanchard Acked-by: Johannes Weiner Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/mm/workingset.c b/mm/workingset.c index 8a75f8d..5772775 100644 --- a/mm/workingset.c +++ b/mm/workingset.c @@ -491,7 +491,7 @@ static int __init workingset_init(void) max_order = fls_long(totalram_pages - 1); if (max_order > timestamp_bits) bucket_order = max_order - timestamp_bits; - printk("workingset: timestamp_bits=%d max_order=%d bucket_order=%u\n", + pr_info("workingset: timestamp_bits=%d max_order=%d bucket_order=%u\n", timestamp_bits, max_order, bucket_order); ret = list_lru_init_key(&workingset_shadow_nodes, &shadow_nodes_key); -- cgit v0.10.2 From 9babed6a66b5577628d9e76e5a6cb6104d7ddd4c Mon Sep 17 00:00:00 2001 From: Sudip Mukherjee Date: Thu, 14 Jul 2016 12:07:43 -0700 Subject: m32r: fix build warning about putc We were getting build warning: arch/m32r/boot/compressed/m32r_sio.c:11:13: warning: conflicting types for built-in function 'putc' Here putc is used as a static function so lets just rename it to avoid the conflict with the builtin putc. Link: http://lkml.kernel.org/r/1466977046-24724-1-git-send-email-sudipm.mukherjee@gmail.com Signed-off-by: Sudip Mukherjee Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/arch/m32r/boot/compressed/m32r_sio.c b/arch/m32r/boot/compressed/m32r_sio.c index 01d877c..cf3023d 100644 --- a/arch/m32r/boot/compressed/m32r_sio.c +++ b/arch/m32r/boot/compressed/m32r_sio.c @@ -8,12 +8,13 @@ #include -static void putc(char c); +static void m32r_putc(char c); static int puts(const char *s) { char c; - while ((c = *s++)) putc(c); + while ((c = *s++)) + m32r_putc(c); return 0; } @@ -41,7 +42,7 @@ static int puts(const char *s) #define BOOT_SIO0TXB PLD_ESIO0TXB #endif -static void putc(char c) +static void m32r_putc(char c) { while ((*BOOT_SIO0STS & 0x3) != 0x3) cpu_relax(); @@ -61,7 +62,7 @@ static void putc(char c) #define SIO0TXB (volatile unsigned short *)(0x00efd000 + 30) #endif -static void putc(char c) +static void m32r_putc(char c) { while ((*SIO0STS & 0x1) == 0) cpu_relax(); -- cgit v0.10.2 From 858296c8784bf98450765cbc6b1bc2e44175cc01 Mon Sep 17 00:00:00 2001 From: Alexander Duyck Date: Tue, 14 Jun 2016 15:45:42 -0700 Subject: i40e/i40evf: Fix i40e_rx_checksum There are a couple of issues I found in i40e_rx_checksum while doing some recent testing. As a result I have found the Rx checksum logic is pretty much broken and returning that the checksum is valid for tunnels in cases where it is not. First the inner types are not the correct values to use to test for if a tunnel is present or not. In addition the inner protocol types are not a bitmask as such performing an OR of the values doesn't make sense. I have instead changed the code so that the inner protocol types are used to determine if we report CHECKSUM_UNNECESSARY or not. For anything that does not end in UDP, TCP, or SCTP it doesn't make much sense to report a checksum offload since it won't contain a checksum anyway. This leaves us with the need to set the csum_level based on some value. For that purpose I am using the tunnel_type field. If the tunnel type is GRENAT or greater then this means we have a GRE or UDP tunnel with an inner header. In the case of GRE or UDP we will have a possible checksum present so for this reason it should be safe to set the csum_level to 1 to indicate that we are reporting the state of the inner header. Signed-off-by: Alexander Duyck Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher diff --git a/drivers/net/ethernet/intel/i40e/i40e_txrx.c b/drivers/net/ethernet/intel/i40e/i40e_txrx.c index 55f151f..a8868e1 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_txrx.c +++ b/drivers/net/ethernet/intel/i40e/i40e_txrx.c @@ -1280,8 +1280,8 @@ static inline void i40e_rx_checksum(struct i40e_vsi *vsi, union i40e_rx_desc *rx_desc) { struct i40e_rx_ptype_decoded decoded; - bool ipv4, ipv6, tunnel = false; u32 rx_error, rx_status; + bool ipv4, ipv6; u8 ptype; u64 qword; @@ -1336,19 +1336,23 @@ static inline void i40e_rx_checksum(struct i40e_vsi *vsi, if (rx_error & BIT(I40E_RX_DESC_ERROR_PPRS_SHIFT)) return; - /* The hardware supported by this driver does not validate outer - * checksums for tunneled VXLAN or GENEVE frames. I don't agree - * with it but the specification states that you "MAY validate", it - * doesn't make it a hard requirement so if we have validated the - * inner checksum report CHECKSUM_UNNECESSARY. + /* If there is an outer header present that might contain a checksum + * we need to bump the checksum level by 1 to reflect the fact that + * we are indicating we validated the inner checksum. */ - if (decoded.inner_prot & (I40E_RX_PTYPE_INNER_PROT_TCP | - I40E_RX_PTYPE_INNER_PROT_UDP | - I40E_RX_PTYPE_INNER_PROT_SCTP)) - tunnel = true; - - skb->ip_summed = CHECKSUM_UNNECESSARY; - skb->csum_level = tunnel ? 1 : 0; + if (decoded.tunnel_type >= I40E_RX_PTYPE_TUNNEL_IP_GRENAT) + skb->csum_level = 1; + + /* Only report checksum unnecessary for TCP, UDP, or SCTP */ + switch (decoded.inner_prot) { + case I40E_RX_PTYPE_INNER_PROT_TCP: + case I40E_RX_PTYPE_INNER_PROT_UDP: + case I40E_RX_PTYPE_INNER_PROT_SCTP: + skb->ip_summed = CHECKSUM_UNNECESSARY; + /* fall though */ + default: + break; + } return; diff --git a/drivers/net/ethernet/intel/i40evf/i40e_txrx.c b/drivers/net/ethernet/intel/i40evf/i40e_txrx.c index be99189..79d99cd 100644 --- a/drivers/net/ethernet/intel/i40evf/i40e_txrx.c +++ b/drivers/net/ethernet/intel/i40evf/i40e_txrx.c @@ -752,8 +752,8 @@ static inline void i40e_rx_checksum(struct i40e_vsi *vsi, union i40e_rx_desc *rx_desc) { struct i40e_rx_ptype_decoded decoded; - bool ipv4, ipv6, tunnel = false; u32 rx_error, rx_status; + bool ipv4, ipv6; u8 ptype; u64 qword; @@ -808,19 +808,23 @@ static inline void i40e_rx_checksum(struct i40e_vsi *vsi, if (rx_error & BIT(I40E_RX_DESC_ERROR_PPRS_SHIFT)) return; - /* The hardware supported by this driver does not validate outer - * checksums for tunneled VXLAN or GENEVE frames. I don't agree - * with it but the specification states that you "MAY validate", it - * doesn't make it a hard requirement so if we have validated the - * inner checksum report CHECKSUM_UNNECESSARY. + /* If there is an outer header present that might contain a checksum + * we need to bump the checksum level by 1 to reflect the fact that + * we are indicating we validated the inner checksum. */ - if (decoded.inner_prot & (I40E_RX_PTYPE_INNER_PROT_TCP | - I40E_RX_PTYPE_INNER_PROT_UDP | - I40E_RX_PTYPE_INNER_PROT_SCTP)) - tunnel = true; - - skb->ip_summed = CHECKSUM_UNNECESSARY; - skb->csum_level = tunnel ? 1 : 0; + if (decoded.tunnel_type >= I40E_RX_PTYPE_TUNNEL_IP_GRENAT) + skb->csum_level = 1; + + /* Only report checksum unnecessary for TCP, UDP, or SCTP */ + switch (decoded.inner_prot) { + case I40E_RX_PTYPE_INNER_PROT_TCP: + case I40E_RX_PTYPE_INNER_PROT_UDP: + case I40E_RX_PTYPE_INNER_PROT_SCTP: + skb->ip_summed = CHECKSUM_UNNECESSARY; + /* fall though */ + default: + break; + } return; -- cgit v0.10.2 From f6bd09625ba66446821d55c61891bea9e2cdc5b3 Mon Sep 17 00:00:00 2001 From: Kiran Patil Date: Mon, 20 Jun 2016 09:10:34 -0700 Subject: i40e: enable VSI broadcast promiscuous mode instead of adding broadcast filter This patch sets VSI broadcast promiscuous mode during VSI add sequence and prevents adding MAC filter if specified MAC address is broadcast. Change-ID: Ia62251fca095bc449d0497fc44bec3a5a0136773 Signed-off-by: Kiran Patil Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index 5ea2200..1592dcb 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -1344,6 +1344,13 @@ struct i40e_mac_filter *i40e_add_filter(struct i40e_vsi *vsi, if (!vsi || !macaddr) return NULL; + /* Do not allow broadcast filter to be added since broadcast filter + * is added as part of add VSI for any newly created VSI except + * FDIR VSI + */ + if (is_broadcast_ether_addr(macaddr)) + return NULL; + f = i40e_find_filter(vsi, macaddr, vlan, is_vf, is_netdev); if (!f) { f = kzalloc(sizeof(*f), GFP_ATOMIC); @@ -2151,18 +2158,6 @@ int i40e_sync_vsi_filters(struct i40e_vsi *vsi) aq_ret, pf->hw.aq.asq_last_status); } } - aq_ret = i40e_aq_set_vsi_broadcast(&vsi->back->hw, - vsi->seid, - cur_promisc, NULL); - if (aq_ret) { - retval = i40e_aq_rc_to_posix(aq_ret, - pf->hw.aq.asq_last_status); - dev_info(&pf->pdev->dev, - "set brdcast promisc failed, err %s, aq_err %s\n", - i40e_stat_str(&pf->hw, aq_ret), - i40e_aq_str(&pf->hw, - pf->hw.aq.asq_last_status)); - } } out: /* if something went wrong then set the changed flag so we try again */ @@ -9224,6 +9219,7 @@ int i40e_is_vsi_uplink_mode_veb(struct i40e_vsi *vsi) static int i40e_add_vsi(struct i40e_vsi *vsi) { int ret = -ENODEV; + i40e_status aq_ret = 0; u8 laa_macaddr[ETH_ALEN]; bool found_laa_mac_filter = false; struct i40e_pf *pf = vsi->back; @@ -9413,6 +9409,18 @@ static int i40e_add_vsi(struct i40e_vsi *vsi) vsi->seid = ctxt.seid; vsi->id = ctxt.vsi_number; } + /* Except FDIR VSI, for all othet VSI set the broadcast filter */ + if (vsi->type != I40E_VSI_FDIR) { + aq_ret = i40e_aq_set_vsi_broadcast(hw, vsi->seid, true, NULL); + if (aq_ret) { + ret = i40e_aq_rc_to_posix(aq_ret, + hw->aq.asq_last_status); + dev_info(&pf->pdev->dev, + "set brdcast promisc failed, err %s, aq_err %s\n", + i40e_stat_str(hw, aq_ret), + i40e_aq_str(hw, hw->aq.asq_last_status)); + } + } spin_lock_bh(&vsi->mac_filter_list_lock); /* If macvlan filters already exist, force them to get loaded */ -- cgit v0.10.2 From 4b732cd4bb6006ad7fd4d5cdba27fcb751cdf4b7 Mon Sep 17 00:00:00 2001 From: Paolo Abeni Date: Wed, 15 Jun 2016 15:37:59 +0200 Subject: ixgbe: napi_poll must return the work done Currently the function ixgbe_poll() returns 0 when it clean completely the rx rings, but this foul budget accounting in core code. Fix this returning the actual work done, capped to weight - 1, since the core doesn't allow to return the full budget when the driver modifies the napi status Signed-off-by: Paolo Abeni Reviewed-by: Venkatesh Srinivas Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c index 088c47c..8bebd86 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c @@ -2887,7 +2887,7 @@ int ixgbe_poll(struct napi_struct *napi, int budget) if (!test_bit(__IXGBE_DOWN, &adapter->state)) ixgbe_irq_enable_queues(adapter, BIT_ULL(q_vector->v_idx)); - return 0; + return min(work_done, budget - 1); } /** -- cgit v0.10.2 From 7f6c553902bfa1c4e3f6cfa955c5ea036c7fe8e4 Mon Sep 17 00:00:00 2001 From: "Guilherme G. Piccoli" Date: Mon, 27 Jun 2016 12:16:43 -0300 Subject: i40e: use valid online CPU on q_vector initialization Currently, the q_vector initialization routine sets the affinity_mask of a q_vector based on v_idx value. Meaning a loop iterates on v_idx, which is an incremental value, and the cpumask is created based on this value. This is a problem in systems with multiple logical CPUs per core (like in SMT scenarios). If we disable some logical CPUs, by turning SMT off for example, we will end up with a sparse cpu_online_mask, i.e., only the first CPU in a core is online, and incremental filling in q_vector cpumask might lead to multiple offline CPUs being assigned to q_vectors. Example: if we have a system with 8 cores each one containing 8 logical CPUs (SMT == 8 in this case), we have 64 CPUs in total. But if SMT is disabled, only the 1st CPU in each core remains online, so the cpu_online_mask in this case would have only 8 bits set, in a sparse way. In general case, when SMT is off the cpu_online_mask has only C bits set: 0, 1*N, 2*N, ..., C*(N-1) where C == # of cores; N == # of logical CPUs per core. In our example, only bits 0, 8, 16, 24, 32, 40, 48, 56 would be set. This patch changes the way q_vector's affinity_mask is created: it iterates on v_idx, but consumes the CPU index from the cpu_online_mask instead of just using the v_idx incremental value. No functional changes were introduced. Signed-off-by: Guilherme G Piccoli Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index 1592dcb..501f15d 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -7721,10 +7721,11 @@ static int i40e_init_msix(struct i40e_pf *pf) * i40e_vsi_alloc_q_vector - Allocate memory for a single interrupt vector * @vsi: the VSI being configured * @v_idx: index of the vector in the vsi struct + * @cpu: cpu to be used on affinity_mask * * We allocate one q_vector. If allocation fails we return -ENOMEM. **/ -static int i40e_vsi_alloc_q_vector(struct i40e_vsi *vsi, int v_idx) +static int i40e_vsi_alloc_q_vector(struct i40e_vsi *vsi, int v_idx, int cpu) { struct i40e_q_vector *q_vector; @@ -7735,7 +7736,8 @@ static int i40e_vsi_alloc_q_vector(struct i40e_vsi *vsi, int v_idx) q_vector->vsi = vsi; q_vector->v_idx = v_idx; - cpumask_set_cpu(v_idx, &q_vector->affinity_mask); + cpumask_set_cpu(cpu, &q_vector->affinity_mask); + if (vsi->netdev) netif_napi_add(vsi->netdev, &q_vector->napi, i40e_napi_poll, NAPI_POLL_WEIGHT); @@ -7759,8 +7761,7 @@ static int i40e_vsi_alloc_q_vector(struct i40e_vsi *vsi, int v_idx) static int i40e_vsi_alloc_q_vectors(struct i40e_vsi *vsi) { struct i40e_pf *pf = vsi->back; - int v_idx, num_q_vectors; - int err; + int err, v_idx, num_q_vectors, current_cpu; /* if not MSIX, give the one vector only to the LAN VSI */ if (pf->flags & I40E_FLAG_MSIX_ENABLED) @@ -7770,10 +7771,15 @@ static int i40e_vsi_alloc_q_vectors(struct i40e_vsi *vsi) else return -EINVAL; + current_cpu = cpumask_first(cpu_online_mask); + for (v_idx = 0; v_idx < num_q_vectors; v_idx++) { - err = i40e_vsi_alloc_q_vector(vsi, v_idx); + err = i40e_vsi_alloc_q_vector(vsi, v_idx, current_cpu); if (err) goto err_out; + current_cpu = cpumask_next(current_cpu, cpu_online_mask); + if (unlikely(current_cpu >= nr_cpu_ids)) + current_cpu = cpumask_first(cpu_online_mask); } return 0; -- cgit v0.10.2 From af2cf278ef4f9289f88504c3e03cb12f76027575 Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Thu, 14 Jul 2016 13:22:49 -0700 Subject: x86/mm/hotplug: Don't remove PGD entries in remove_pagetable() So when memory hotplug removes a piece of physical memory from pagetable mappings, it also frees the underlying PGD entry. This complicates PGD management, so don't do this. We can keep the PGD mapped and the PUD table all clear - it's only a single 4K page per 512 GB of memory hotplugged. Signed-off-by: Ingo Molnar Signed-off-by: Andy Lutomirski Cc: Andrew Morton Cc: Andy Lutomirski Cc: Borislav Petkov Cc: Brian Gerst Cc: Denys Vlasenko Cc: H. Peter Anvin Cc: Josh Poimboeuf Cc: Linus Torvalds Cc: Oleg Nesterov Cc: Peter Zijlstra Cc: Rik van Riel Cc: Thomas Gleixner Cc: Waiman Long Cc: linux-mm@kvack.org Link: http://lkml.kernel.org/r/064ff6c7275734537f969e876f6cd0baa954d2cc.1468527351.git.luto@kernel.org Signed-off-by: Ingo Molnar diff --git a/arch/x86/mm/init_64.c b/arch/x86/mm/init_64.c index bb88fbc..e14f870 100644 --- a/arch/x86/mm/init_64.c +++ b/arch/x86/mm/init_64.c @@ -702,27 +702,6 @@ static void __meminit free_pmd_table(pmd_t *pmd_start, pud_t *pud) spin_unlock(&init_mm.page_table_lock); } -/* Return true if pgd is changed, otherwise return false. */ -static bool __meminit free_pud_table(pud_t *pud_start, pgd_t *pgd) -{ - pud_t *pud; - int i; - - for (i = 0; i < PTRS_PER_PUD; i++) { - pud = pud_start + i; - if (!pud_none(*pud)) - return false; - } - - /* free a pud table */ - free_pagetable(pgd_page(*pgd), 0); - spin_lock(&init_mm.page_table_lock); - pgd_clear(pgd); - spin_unlock(&init_mm.page_table_lock); - - return true; -} - static void __meminit remove_pte_table(pte_t *pte_start, unsigned long addr, unsigned long end, bool direct) @@ -913,7 +892,6 @@ remove_pagetable(unsigned long start, unsigned long end, bool direct) unsigned long addr; pgd_t *pgd; pud_t *pud; - bool pgd_changed = false; for (addr = start; addr < end; addr = next) { next = pgd_addr_end(addr, end); @@ -924,13 +902,8 @@ remove_pagetable(unsigned long start, unsigned long end, bool direct) pud = (pud_t *)pgd_page_vaddr(*pgd); remove_pud_table(pud, addr, next, direct); - if (free_pud_table(pud, pgd)) - pgd_changed = true; } - if (pgd_changed) - sync_global_pgds(start, end - 1, 1); - flush_tlb_all(); } -- cgit v0.10.2 From 360cb4d15567a7eca07a5f3ade6de308bbfb4e70 Mon Sep 17 00:00:00 2001 From: Andy Lutomirski Date: Thu, 14 Jul 2016 13:22:50 -0700 Subject: x86/mm/cpa: In populate_pgd(), don't set the PGD entry until it's populated This avoids pointless races in which another CPU or task might see a partially populated global PGD entry. These races should normally be harmless, but, if another CPU propagates the entry via vmalloc_fault() and then populate_pgd() fails (due to memory allocation failure, for example), this prevents a use-after-free of the PGD entry. Signed-off-by: Andy Lutomirski Cc: Borislav Petkov Cc: Brian Gerst Cc: Denys Vlasenko Cc: H. Peter Anvin Cc: Josh Poimboeuf Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/bf99df27eac6835f687005364bd1fbd89130946c.1468527351.git.luto@kernel.org Signed-off-by: Ingo Molnar diff --git a/arch/x86/mm/pageattr.c b/arch/x86/mm/pageattr.c index 7514215..26aa487 100644 --- a/arch/x86/mm/pageattr.c +++ b/arch/x86/mm/pageattr.c @@ -1104,8 +1104,6 @@ static int populate_pgd(struct cpa_data *cpa, unsigned long addr) pud = (pud_t *)get_zeroed_page(GFP_KERNEL | __GFP_NOTRACK); if (!pud) return -1; - - set_pgd(pgd_entry, __pgd(__pa(pud) | _KERNPG_TABLE)); } pgprot_val(pgprot) &= ~pgprot_val(cpa->mask_clr); @@ -1113,11 +1111,16 @@ static int populate_pgd(struct cpa_data *cpa, unsigned long addr) ret = populate_pud(cpa, addr, pgd_entry, pgprot); if (ret < 0) { - unmap_pgd_range(cpa->pgd, addr, + if (pud) + free_page((unsigned long)pud); + unmap_pud_range(pgd_entry, addr, addr + (cpa->numpages << PAGE_SHIFT)); return ret; } + if (pud) + set_pgd(pgd_entry, __pgd(__pa(pud) | _KERNPG_TABLE)); + cpa->numpages = ret; return 0; } -- cgit v0.10.2 From d92fc69ccac4c0a20679fdbdc81b2010685a6f33 Mon Sep 17 00:00:00 2001 From: Andy Lutomirski Date: Thu, 14 Jul 2016 13:22:51 -0700 Subject: x86/mm: Remove kernel_unmap_pages_in_pgd() and efi_cleanup_page_tables() kernel_unmap_pages_in_pgd() is dangerous: if a PGD entry in init_mm.pgd were to be cleared, callers would need to ensure that the pgd entry hadn't been propagated to any other pgd. Its only caller was efi_cleanup_page_tables(), and that, in turn, was unused, so just delete both functions. This leaves a couple of other helpers unused, so delete them, too. Signed-off-by: Andy Lutomirski Reviewed-by: Matt Fleming Acked-by: Borislav Petkov Cc: Borislav Petkov Cc: Brian Gerst Cc: Denys Vlasenko Cc: H. Peter Anvin Cc: Josh Poimboeuf Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: linux-efi@vger.kernel.org Link: http://lkml.kernel.org/r/77ff20fdde3b75cd393be5559ad8218870520248.1468527351.git.luto@kernel.org Signed-off-by: Ingo Molnar diff --git a/arch/x86/include/asm/efi.h b/arch/x86/include/asm/efi.h index 78d1e74..45ea38d 100644 --- a/arch/x86/include/asm/efi.h +++ b/arch/x86/include/asm/efi.h @@ -125,7 +125,6 @@ extern void __init efi_map_region_fixed(efi_memory_desc_t *md); extern void efi_sync_low_kernel_mappings(void); extern int __init efi_alloc_page_tables(void); extern int __init efi_setup_page_tables(unsigned long pa_memmap, unsigned num_pages); -extern void __init efi_cleanup_page_tables(unsigned long pa_memmap, unsigned num_pages); extern void __init old_map_region(efi_memory_desc_t *md); extern void __init runtime_code_page_mkexec(void); extern void __init efi_runtime_update_mappings(void); diff --git a/arch/x86/include/asm/pgtable_types.h b/arch/x86/include/asm/pgtable_types.h index d14d0a5..f1218f5 100644 --- a/arch/x86/include/asm/pgtable_types.h +++ b/arch/x86/include/asm/pgtable_types.h @@ -481,8 +481,6 @@ extern pmd_t *lookup_pmd_address(unsigned long address); extern phys_addr_t slow_virt_to_phys(void *__address); extern int kernel_map_pages_in_pgd(pgd_t *pgd, u64 pfn, unsigned long address, unsigned numpages, unsigned long page_flags); -void kernel_unmap_pages_in_pgd(pgd_t *root, unsigned long address, - unsigned numpages); #endif /* !__ASSEMBLY__ */ #endif /* _ASM_X86_PGTABLE_DEFS_H */ diff --git a/arch/x86/mm/pageattr.c b/arch/x86/mm/pageattr.c index 26aa487..26c93c6 100644 --- a/arch/x86/mm/pageattr.c +++ b/arch/x86/mm/pageattr.c @@ -746,18 +746,6 @@ static bool try_to_free_pmd_page(pmd_t *pmd) return true; } -static bool try_to_free_pud_page(pud_t *pud) -{ - int i; - - for (i = 0; i < PTRS_PER_PUD; i++) - if (!pud_none(pud[i])) - return false; - - free_page((unsigned long)pud); - return true; -} - static bool unmap_pte_range(pmd_t *pmd, unsigned long start, unsigned long end) { pte_t *pte = pte_offset_kernel(pmd, start); @@ -871,16 +859,6 @@ static void unmap_pud_range(pgd_t *pgd, unsigned long start, unsigned long end) */ } -static void unmap_pgd_range(pgd_t *root, unsigned long addr, unsigned long end) -{ - pgd_t *pgd_entry = root + pgd_index(addr); - - unmap_pud_range(pgd_entry, addr, end); - - if (try_to_free_pud_page((pud_t *)pgd_page_vaddr(*pgd_entry))) - pgd_clear(pgd_entry); -} - static int alloc_pte_page(pmd_t *pmd) { pte_t *pte = (pte_t *)get_zeroed_page(GFP_KERNEL | __GFP_NOTRACK); @@ -1994,12 +1972,6 @@ out: return retval; } -void kernel_unmap_pages_in_pgd(pgd_t *root, unsigned long address, - unsigned numpages) -{ - unmap_pgd_range(root, address, address + (numpages << PAGE_SHIFT)); -} - /* * The testcases use internal knowledge of the implementation that shouldn't * be exposed to the rest of the kernel. Include these directly here. diff --git a/arch/x86/platform/efi/efi.c b/arch/x86/platform/efi/efi.c index f93545e..62986e5 100644 --- a/arch/x86/platform/efi/efi.c +++ b/arch/x86/platform/efi/efi.c @@ -978,8 +978,6 @@ static void __init __efi_enter_virtual_mode(void) * EFI mixed mode we need all of memory to be accessible when * we pass parameters to the EFI runtime services in the * thunking code. - * - * efi_cleanup_page_tables(__pa(new_memmap), 1 << pg_shift); */ free_pages((unsigned long)new_memmap, pg_shift); diff --git a/arch/x86/platform/efi/efi_32.c b/arch/x86/platform/efi/efi_32.c index 338402b..cef39b0 100644 --- a/arch/x86/platform/efi/efi_32.c +++ b/arch/x86/platform/efi/efi_32.c @@ -49,9 +49,6 @@ int __init efi_setup_page_tables(unsigned long pa_memmap, unsigned num_pages) { return 0; } -void __init efi_cleanup_page_tables(unsigned long pa_memmap, unsigned num_pages) -{ -} void __init efi_map_region(efi_memory_desc_t *md) { diff --git a/arch/x86/platform/efi/efi_64.c b/arch/x86/platform/efi/efi_64.c index b226b3f..d288dce 100644 --- a/arch/x86/platform/efi/efi_64.c +++ b/arch/x86/platform/efi/efi_64.c @@ -285,11 +285,6 @@ int __init efi_setup_page_tables(unsigned long pa_memmap, unsigned num_pages) return 0; } -void __init efi_cleanup_page_tables(unsigned long pa_memmap, unsigned num_pages) -{ - kernel_unmap_pages_in_pgd(efi_pgd, pa_memmap, num_pages); -} - static void __init __map_region(efi_memory_desc_t *md, u64 va) { unsigned long flags = _PAGE_RW; -- cgit v0.10.2 From 9a2e9da3e003112399f2863b7b6b911043c01895 Mon Sep 17 00:00:00 2001 From: Andy Lutomirski Date: Thu, 14 Jul 2016 13:22:52 -0700 Subject: x86/dumpstack: Try harder to get a call trace on stack overflow If we overflow the stack, print_context_stack() will abort. Detect this case and rewind back into the valid part of the stack so that we can trace it. Signed-off-by: Andy Lutomirski Reviewed-by: Josh Poimboeuf Cc: Borislav Petkov Cc: Brian Gerst Cc: Denys Vlasenko Cc: H. Peter Anvin Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/ee1690eb2715ccc5dc187fde94effa4ca0ccbbcd.1468527351.git.luto@kernel.org Signed-off-by: Ingo Molnar diff --git a/arch/x86/kernel/dumpstack.c b/arch/x86/kernel/dumpstack.c index ef8017c..cc88e25 100644 --- a/arch/x86/kernel/dumpstack.c +++ b/arch/x86/kernel/dumpstack.c @@ -87,7 +87,7 @@ static inline int valid_stack_ptr(struct task_struct *task, else return 0; } - return p > t && p < t + THREAD_SIZE - size; + return p >= t && p < t + THREAD_SIZE - size; } unsigned long @@ -98,6 +98,14 @@ print_context_stack(struct task_struct *task, { struct stack_frame *frame = (struct stack_frame *)bp; + /* + * If we overflowed the stack into a guard page, jump back to the + * bottom of the usable stack. + */ + if ((unsigned long)task_stack_page(task) - (unsigned long)stack < + PAGE_SIZE) + stack = (unsigned long *)task_stack_page(task); + while (valid_stack_ptr(task, stack, sizeof(*stack), end)) { unsigned long addr; -- cgit v0.10.2 From 98f30b1207932b6553ea605c99393d8afca12324 Mon Sep 17 00:00:00 2001 From: Andy Lutomirski Date: Thu, 14 Jul 2016 13:22:53 -0700 Subject: x86/dumpstack/64: Handle faults when printing the "Stack: " part of an OOPS If we overflow the stack into a guard page, we'll recursively fault when trying to dump the contents of the guard page. Use probe_kernel_address() so we can recover if this happens. Signed-off-by: Andy Lutomirski Reviewed-by: Josh Poimboeuf Cc: Borislav Petkov Cc: Brian Gerst Cc: Denys Vlasenko Cc: H. Peter Anvin Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/e626d47a55d7b04dcb1b4d33faa95e8505b217c8.1468527351.git.luto@kernel.org Signed-off-by: Ingo Molnar diff --git a/arch/x86/kernel/dumpstack_64.c b/arch/x86/kernel/dumpstack_64.c index d558a8a..2552a1e 100644 --- a/arch/x86/kernel/dumpstack_64.c +++ b/arch/x86/kernel/dumpstack_64.c @@ -272,6 +272,8 @@ show_stack_log_lvl(struct task_struct *task, struct pt_regs *regs, stack = sp; for (i = 0; i < kstack_depth_to_print; i++) { + unsigned long word; + if (stack >= irq_stack && stack <= irq_stack_end) { if (stack == irq_stack_end) { stack = (unsigned long *) (irq_stack_end[-1]); @@ -281,12 +283,18 @@ show_stack_log_lvl(struct task_struct *task, struct pt_regs *regs, if (kstack_end(stack)) break; } + + if (probe_kernel_address(stack, word)) + break; + if ((i % STACKSLOTS_PER_LINE) == 0) { if (i != 0) pr_cont("\n"); - printk("%s %016lx", log_lvl, *stack++); + printk("%s %016lx", log_lvl, word); } else - pr_cont(" %016lx", *stack++); + pr_cont(" %016lx", word); + + stack++; touch_nmi_watchdog(); } preempt_enable(); -- cgit v0.10.2 From 46aea3873401836abb7f01200e7946e7d518b359 Mon Sep 17 00:00:00 2001 From: Andy Lutomirski Date: Thu, 14 Jul 2016 13:22:54 -0700 Subject: x86/mm/64: In vmalloc_fault(), use CR3 instead of current->active_mm If we get a vmalloc fault while current->active_mm->pgd doesn't match CR3, we'll crash without this change. I've seen this failure mode on heavily instrumented kernels with virtually mapped stacks. Signed-off-by: Andy Lutomirski Cc: Borislav Petkov Cc: Brian Gerst Cc: Denys Vlasenko Cc: H. Peter Anvin Cc: Josh Poimboeuf Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/4650d7674185f165ed8fdf9ac4c5c35c5c179ba8.1468527351.git.luto@kernel.org Signed-off-by: Ingo Molnar diff --git a/arch/x86/mm/fault.c b/arch/x86/mm/fault.c index 7d1fa7c..ca44e2e 100644 --- a/arch/x86/mm/fault.c +++ b/arch/x86/mm/fault.c @@ -439,7 +439,7 @@ static noinline int vmalloc_fault(unsigned long address) * happen within a race in page table update. In the later * case just flush: */ - pgd = pgd_offset(current->active_mm, address); + pgd = (pgd_t *)__va(read_cr3()) + pgd_index(address); pgd_ref = pgd_offset_k(address); if (pgd_none(*pgd_ref)) return -1; -- cgit v0.10.2 From 2deb4be28077638591fe5fc593b7f8aabc140f42 Mon Sep 17 00:00:00 2001 From: Andy Lutomirski Date: Thu, 14 Jul 2016 13:22:55 -0700 Subject: x86/dumpstack: When OOPSing, rewind the stack before do_exit() If we call do_exit() with a clean stack, we greatly reduce the risk of recursive oopses due to stack overflow in do_exit, and we allow do_exit to work even if we OOPS from an IST stack. The latter gives us a much better chance of surviving long enough after we detect a stack overflow to write out our logs. Signed-off-by: Andy Lutomirski Reviewed-by: Josh Poimboeuf Cc: Borislav Petkov Cc: Brian Gerst Cc: Denys Vlasenko Cc: H. Peter Anvin Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/32f73ceb372ec61889598da5e5b145889b9f2e19.1468527351.git.luto@kernel.org Signed-off-by: Ingo Molnar diff --git a/arch/x86/entry/entry_32.S b/arch/x86/entry/entry_32.S index 983e5d3..0b56666 100644 --- a/arch/x86/entry/entry_32.S +++ b/arch/x86/entry/entry_32.S @@ -1153,3 +1153,14 @@ ENTRY(async_page_fault) jmp error_code END(async_page_fault) #endif + +ENTRY(rewind_stack_do_exit) + /* Prevent any naive code from trying to unwind to our caller. */ + xorl %ebp, %ebp + + movl PER_CPU_VAR(cpu_current_top_of_stack), %esi + leal -TOP_OF_KERNEL_STACK_PADDING-PTREGS_SIZE(%esi), %esp + + call do_exit +1: jmp 1b +END(rewind_stack_do_exit) diff --git a/arch/x86/entry/entry_64.S b/arch/x86/entry/entry_64.S index 9ee0da1..b846875 100644 --- a/arch/x86/entry/entry_64.S +++ b/arch/x86/entry/entry_64.S @@ -1423,3 +1423,14 @@ ENTRY(ignore_sysret) mov $-ENOSYS, %eax sysret END(ignore_sysret) + +ENTRY(rewind_stack_do_exit) + /* Prevent any naive code from trying to unwind to our caller. */ + xorl %ebp, %ebp + + movq PER_CPU_VAR(cpu_current_top_of_stack), %rax + leaq -TOP_OF_KERNEL_STACK_PADDING-PTREGS_SIZE(%rax), %rsp + + call do_exit +1: jmp 1b +END(rewind_stack_do_exit) diff --git a/arch/x86/kernel/dumpstack.c b/arch/x86/kernel/dumpstack.c index cc88e25..de8242d 100644 --- a/arch/x86/kernel/dumpstack.c +++ b/arch/x86/kernel/dumpstack.c @@ -234,6 +234,8 @@ unsigned long oops_begin(void) EXPORT_SYMBOL_GPL(oops_begin); NOKPROBE_SYMBOL(oops_begin); +void __noreturn rewind_stack_do_exit(int signr); + void oops_end(unsigned long flags, struct pt_regs *regs, int signr) { if (regs && kexec_should_crash(current)) @@ -255,7 +257,13 @@ void oops_end(unsigned long flags, struct pt_regs *regs, int signr) panic("Fatal exception in interrupt"); if (panic_on_oops) panic("Fatal exception"); - do_exit(signr); + + /* + * We're not going to return, but we might be on an IST stack or + * have very little stack space left. Rewind the stack and kill + * the task. + */ + rewind_stack_do_exit(signr); } NOKPROBE_SYMBOL(oops_end); -- cgit v0.10.2 From dfa9a942fd7951c8f333cf3f377dde51ebd21685 Mon Sep 17 00:00:00 2001 From: Andy Lutomirski Date: Thu, 14 Jul 2016 13:22:56 -0700 Subject: x86/uaccess: Move thread_info::uaccess_err and thread_info::sig_on_uaccess_err to thread_struct struct thread_info is a legacy mess. To prepare for its partial removal, move the uaccess control fields out -- they're straightforward. Signed-off-by: Andy Lutomirski Cc: Borislav Petkov Cc: Brian Gerst Cc: Denys Vlasenko Cc: H. Peter Anvin Cc: Josh Poimboeuf Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/d0ac4d01c8e4d4d756264604e47445d5acc7900e.1468527351.git.luto@kernel.org Signed-off-by: Ingo Molnar diff --git a/arch/x86/entry/vsyscall/vsyscall_64.c b/arch/x86/entry/vsyscall/vsyscall_64.c index 174c254..3aba2b0 100644 --- a/arch/x86/entry/vsyscall/vsyscall_64.c +++ b/arch/x86/entry/vsyscall/vsyscall_64.c @@ -221,8 +221,8 @@ bool emulate_vsyscall(struct pt_regs *regs, unsigned long address) * With a real vsyscall, page faults cause SIGSEGV. We want to * preserve that behavior to make writing exploits harder. */ - prev_sig_on_uaccess_error = current_thread_info()->sig_on_uaccess_error; - current_thread_info()->sig_on_uaccess_error = 1; + prev_sig_on_uaccess_error = current->thread.sig_on_uaccess_error; + current->thread.sig_on_uaccess_error = 1; ret = -EFAULT; switch (vsyscall_nr) { @@ -243,7 +243,7 @@ bool emulate_vsyscall(struct pt_regs *regs, unsigned long address) break; } - current_thread_info()->sig_on_uaccess_error = prev_sig_on_uaccess_error; + current->thread.sig_on_uaccess_error = prev_sig_on_uaccess_error; check_fault: if (ret == -EFAULT) { diff --git a/arch/x86/include/asm/processor.h b/arch/x86/include/asm/processor.h index 62c6cc3..f53ae57 100644 --- a/arch/x86/include/asm/processor.h +++ b/arch/x86/include/asm/processor.h @@ -419,6 +419,9 @@ struct thread_struct { /* Max allowed port in the bitmap, in bytes: */ unsigned io_bitmap_max; + unsigned int sig_on_uaccess_error:1; + unsigned int uaccess_err:1; /* uaccess failed */ + /* Floating point and extended processor state */ struct fpu fpu; /* diff --git a/arch/x86/include/asm/thread_info.h b/arch/x86/include/asm/thread_info.h index 30c133a..7c47bb6 100644 --- a/arch/x86/include/asm/thread_info.h +++ b/arch/x86/include/asm/thread_info.h @@ -58,8 +58,6 @@ struct thread_info { __u32 status; /* thread synchronous flags */ __u32 cpu; /* current CPU */ mm_segment_t addr_limit; - unsigned int sig_on_uaccess_error:1; - unsigned int uaccess_err:1; /* uaccess failed */ }; #define INIT_THREAD_INFO(tsk) \ diff --git a/arch/x86/include/asm/uaccess.h b/arch/x86/include/asm/uaccess.h index d40ec72..8f66e56 100644 --- a/arch/x86/include/asm/uaccess.h +++ b/arch/x86/include/asm/uaccess.h @@ -487,13 +487,13 @@ struct __large_struct { unsigned long buf[100]; }; * uaccess_try and catch */ #define uaccess_try do { \ - current_thread_info()->uaccess_err = 0; \ + current->thread.uaccess_err = 0; \ __uaccess_begin(); \ barrier(); #define uaccess_catch(err) \ __uaccess_end(); \ - (err) |= (current_thread_info()->uaccess_err ? -EFAULT : 0); \ + (err) |= (current->thread.uaccess_err ? -EFAULT : 0); \ } while (0) /** diff --git a/arch/x86/mm/extable.c b/arch/x86/mm/extable.c index 4bb53b8..0f90cc2 100644 --- a/arch/x86/mm/extable.c +++ b/arch/x86/mm/extable.c @@ -37,7 +37,7 @@ bool ex_handler_ext(const struct exception_table_entry *fixup, struct pt_regs *regs, int trapnr) { /* Special hack for uaccess_err */ - current_thread_info()->uaccess_err = 1; + current->thread.uaccess_err = 1; regs->ip = ex_fixup_addr(fixup); return true; } diff --git a/arch/x86/mm/fault.c b/arch/x86/mm/fault.c index ca44e2e..69be03d 100644 --- a/arch/x86/mm/fault.c +++ b/arch/x86/mm/fault.c @@ -737,7 +737,7 @@ no_context(struct pt_regs *regs, unsigned long error_code, * In this case we need to make sure we're not recursively * faulting through the emulate_vsyscall() logic. */ - if (current_thread_info()->sig_on_uaccess_error && signal) { + if (current->thread.sig_on_uaccess_error && signal) { tsk->thread.trap_nr = X86_TRAP_PF; tsk->thread.error_code = error_code | PF_USER; tsk->thread.cr2 = address; -- cgit v0.10.2 From 2a53ccbc0de1b1950aeedd24680f7eca65c86ff5 Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Fri, 15 Jul 2016 10:21:11 +0200 Subject: x86/dumpstack: Rename thread_struct::sig_on_uaccess_error to sig_on_uaccess_err Rename it to match the thread_struct::uaccess_err pattern and also because it was too long. Cc: Andy Lutomirski Cc: Borislav Petkov Cc: Brian Gerst Cc: Denys Vlasenko Cc: H. Peter Anvin Cc: Josh Poimboeuf Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: linux-kernel@vger.kernel.org Signed-off-by: Ingo Molnar diff --git a/arch/x86/entry/vsyscall/vsyscall_64.c b/arch/x86/entry/vsyscall/vsyscall_64.c index 3aba2b0..75fc719 100644 --- a/arch/x86/entry/vsyscall/vsyscall_64.c +++ b/arch/x86/entry/vsyscall/vsyscall_64.c @@ -96,7 +96,7 @@ static bool write_ok_or_segv(unsigned long ptr, size_t size) { /* * XXX: if access_ok, get_user, and put_user handled - * sig_on_uaccess_error, this could go away. + * sig_on_uaccess_err, this could go away. */ if (!access_ok(VERIFY_WRITE, (void __user *)ptr, size)) { @@ -125,7 +125,7 @@ bool emulate_vsyscall(struct pt_regs *regs, unsigned long address) struct task_struct *tsk; unsigned long caller; int vsyscall_nr, syscall_nr, tmp; - int prev_sig_on_uaccess_error; + int prev_sig_on_uaccess_err; long ret; /* @@ -221,8 +221,8 @@ bool emulate_vsyscall(struct pt_regs *regs, unsigned long address) * With a real vsyscall, page faults cause SIGSEGV. We want to * preserve that behavior to make writing exploits harder. */ - prev_sig_on_uaccess_error = current->thread.sig_on_uaccess_error; - current->thread.sig_on_uaccess_error = 1; + prev_sig_on_uaccess_err = current->thread.sig_on_uaccess_err; + current->thread.sig_on_uaccess_err = 1; ret = -EFAULT; switch (vsyscall_nr) { @@ -243,7 +243,7 @@ bool emulate_vsyscall(struct pt_regs *regs, unsigned long address) break; } - current->thread.sig_on_uaccess_error = prev_sig_on_uaccess_error; + current->thread.sig_on_uaccess_err = prev_sig_on_uaccess_err; check_fault: if (ret == -EFAULT) { diff --git a/arch/x86/include/asm/processor.h b/arch/x86/include/asm/processor.h index f53ae57..cbdfe5f 100644 --- a/arch/x86/include/asm/processor.h +++ b/arch/x86/include/asm/processor.h @@ -419,7 +419,7 @@ struct thread_struct { /* Max allowed port in the bitmap, in bytes: */ unsigned io_bitmap_max; - unsigned int sig_on_uaccess_error:1; + unsigned int sig_on_uaccess_err:1; unsigned int uaccess_err:1; /* uaccess failed */ /* Floating point and extended processor state */ diff --git a/arch/x86/mm/fault.c b/arch/x86/mm/fault.c index 69be03d..d22161a 100644 --- a/arch/x86/mm/fault.c +++ b/arch/x86/mm/fault.c @@ -737,7 +737,7 @@ no_context(struct pt_regs *regs, unsigned long error_code, * In this case we need to make sure we're not recursively * faulting through the emulate_vsyscall() logic. */ - if (current->thread.sig_on_uaccess_error && signal) { + if (current->thread.sig_on_uaccess_err && signal) { tsk->thread.trap_nr = X86_TRAP_PF; tsk->thread.error_code = error_code | PF_USER; tsk->thread.cr2 = address; -- cgit v0.10.2 From 13d4ea097d18b419ad2a2b696063d44bf59acec0 Mon Sep 17 00:00:00 2001 From: Andy Lutomirski Date: Thu, 14 Jul 2016 13:22:57 -0700 Subject: x86/uaccess: Move thread_info::addr_limit to thread_struct struct thread_info is a legacy mess. To prepare for its partial removal, move thread_info::addr_limit out. As an added benefit, this way is simpler. Signed-off-by: Andy Lutomirski Cc: Borislav Petkov Cc: Brian Gerst Cc: Denys Vlasenko Cc: H. Peter Anvin Cc: Josh Poimboeuf Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/15bee834d09402b47ac86f2feccdf6529f9bc5b0.1468527351.git.luto@kernel.org Signed-off-by: Ingo Molnar diff --git a/arch/x86/include/asm/checksum_32.h b/arch/x86/include/asm/checksum_32.h index 532f85e..7b53743 100644 --- a/arch/x86/include/asm/checksum_32.h +++ b/arch/x86/include/asm/checksum_32.h @@ -2,8 +2,7 @@ #define _ASM_X86_CHECKSUM_32_H #include - -#include +#include /* * computes the checksum of a memory block at buff, length len, diff --git a/arch/x86/include/asm/processor.h b/arch/x86/include/asm/processor.h index cbdfe5f..89314ed 100644 --- a/arch/x86/include/asm/processor.h +++ b/arch/x86/include/asm/processor.h @@ -371,6 +371,10 @@ extern unsigned int xstate_size; struct perf_event; +typedef struct { + unsigned long seg; +} mm_segment_t; + struct thread_struct { /* Cached TLS descriptors: */ struct desc_struct tls_array[GDT_ENTRY_TLS_ENTRIES]; @@ -419,6 +423,8 @@ struct thread_struct { /* Max allowed port in the bitmap, in bytes: */ unsigned io_bitmap_max; + mm_segment_t addr_limit; + unsigned int sig_on_uaccess_err:1; unsigned int uaccess_err:1; /* uaccess failed */ @@ -493,11 +499,6 @@ static inline void load_sp0(struct tss_struct *tss, #define set_iopl_mask native_set_iopl_mask #endif /* CONFIG_PARAVIRT */ -typedef struct { - unsigned long seg; -} mm_segment_t; - - /* Free all resources held by a thread. */ extern void release_thread(struct task_struct *); @@ -719,6 +720,7 @@ static inline void spin_lock_prefetch(const void *x) .sp0 = TOP_OF_INIT_STACK, \ .sysenter_cs = __KERNEL_CS, \ .io_bitmap_ptr = NULL, \ + .addr_limit = KERNEL_DS, \ } extern unsigned long thread_saved_pc(struct task_struct *tsk); @@ -768,8 +770,9 @@ extern unsigned long thread_saved_pc(struct task_struct *tsk); #define STACK_TOP TASK_SIZE #define STACK_TOP_MAX TASK_SIZE_MAX -#define INIT_THREAD { \ - .sp0 = TOP_OF_INIT_STACK \ +#define INIT_THREAD { \ + .sp0 = TOP_OF_INIT_STACK, \ + .addr_limit = KERNEL_DS, \ } /* diff --git a/arch/x86/include/asm/thread_info.h b/arch/x86/include/asm/thread_info.h index 7c47bb6..89bff04 100644 --- a/arch/x86/include/asm/thread_info.h +++ b/arch/x86/include/asm/thread_info.h @@ -57,7 +57,6 @@ struct thread_info { __u32 flags; /* low level flags */ __u32 status; /* thread synchronous flags */ __u32 cpu; /* current CPU */ - mm_segment_t addr_limit; }; #define INIT_THREAD_INFO(tsk) \ @@ -65,7 +64,6 @@ struct thread_info { .task = &tsk, \ .flags = 0, \ .cpu = 0, \ - .addr_limit = KERNEL_DS, \ } #define init_thread_info (init_thread_union.thread_info) @@ -184,11 +182,6 @@ static inline unsigned long current_stack_pointer(void) # define cpu_current_top_of_stack (cpu_tss + TSS_sp0) #endif -/* Load thread_info address into "reg" */ -#define GET_THREAD_INFO(reg) \ - _ASM_MOV PER_CPU_VAR(cpu_current_top_of_stack),reg ; \ - _ASM_SUB $(THREAD_SIZE),reg ; - /* * ASM operand which evaluates to a 'thread_info' address of * the current task, if it is known that "reg" is exactly "off" diff --git a/arch/x86/include/asm/uaccess.h b/arch/x86/include/asm/uaccess.h index 8f66e56..c03bfb6 100644 --- a/arch/x86/include/asm/uaccess.h +++ b/arch/x86/include/asm/uaccess.h @@ -29,12 +29,12 @@ #define USER_DS MAKE_MM_SEG(TASK_SIZE_MAX) #define get_ds() (KERNEL_DS) -#define get_fs() (current_thread_info()->addr_limit) -#define set_fs(x) (current_thread_info()->addr_limit = (x)) +#define get_fs() (current->thread.addr_limit) +#define set_fs(x) (current->thread.addr_limit = (x)) #define segment_eq(a, b) ((a).seg == (b).seg) -#define user_addr_max() (current_thread_info()->addr_limit.seg) +#define user_addr_max() (current->thread.addr_limit.seg) #define __addr_ok(addr) \ ((unsigned long __force)(addr) < user_addr_max()) diff --git a/arch/x86/kernel/asm-offsets.c b/arch/x86/kernel/asm-offsets.c index 674134e..2bd5c6f 100644 --- a/arch/x86/kernel/asm-offsets.c +++ b/arch/x86/kernel/asm-offsets.c @@ -31,7 +31,9 @@ void common(void) { BLANK(); OFFSET(TI_flags, thread_info, flags); OFFSET(TI_status, thread_info, status); - OFFSET(TI_addr_limit, thread_info, addr_limit); + + BLANK(); + OFFSET(TASK_addr_limit, task_struct, thread.addr_limit); BLANK(); OFFSET(crypto_tfm_ctx_offset, crypto_tfm, __crt_ctx); diff --git a/arch/x86/lib/copy_user_64.S b/arch/x86/lib/copy_user_64.S index 2b0ef26..bf603eb 100644 --- a/arch/x86/lib/copy_user_64.S +++ b/arch/x86/lib/copy_user_64.S @@ -17,11 +17,11 @@ /* Standard copy_to_user with segment limit checking */ ENTRY(_copy_to_user) - GET_THREAD_INFO(%rax) + mov PER_CPU_VAR(current_task), %rax movq %rdi,%rcx addq %rdx,%rcx jc bad_to_user - cmpq TI_addr_limit(%rax),%rcx + cmpq TASK_addr_limit(%rax),%rcx ja bad_to_user ALTERNATIVE_2 "jmp copy_user_generic_unrolled", \ "jmp copy_user_generic_string", \ @@ -32,11 +32,11 @@ ENDPROC(_copy_to_user) /* Standard copy_from_user with segment limit checking */ ENTRY(_copy_from_user) - GET_THREAD_INFO(%rax) + mov PER_CPU_VAR(current_task), %rax movq %rsi,%rcx addq %rdx,%rcx jc bad_from_user - cmpq TI_addr_limit(%rax),%rcx + cmpq TASK_addr_limit(%rax),%rcx ja bad_from_user ALTERNATIVE_2 "jmp copy_user_generic_unrolled", \ "jmp copy_user_generic_string", \ diff --git a/arch/x86/lib/csum-wrappers_64.c b/arch/x86/lib/csum-wrappers_64.c index 28a6654..b6fcb9a 100644 --- a/arch/x86/lib/csum-wrappers_64.c +++ b/arch/x86/lib/csum-wrappers_64.c @@ -6,6 +6,7 @@ */ #include #include +#include #include /** diff --git a/arch/x86/lib/getuser.S b/arch/x86/lib/getuser.S index 46668cd..0ef5128 100644 --- a/arch/x86/lib/getuser.S +++ b/arch/x86/lib/getuser.S @@ -35,8 +35,8 @@ .text ENTRY(__get_user_1) - GET_THREAD_INFO(%_ASM_DX) - cmp TI_addr_limit(%_ASM_DX),%_ASM_AX + mov PER_CPU_VAR(current_task), %_ASM_DX + cmp TASK_addr_limit(%_ASM_DX),%_ASM_AX jae bad_get_user ASM_STAC 1: movzbl (%_ASM_AX),%edx @@ -48,8 +48,8 @@ ENDPROC(__get_user_1) ENTRY(__get_user_2) add $1,%_ASM_AX jc bad_get_user - GET_THREAD_INFO(%_ASM_DX) - cmp TI_addr_limit(%_ASM_DX),%_ASM_AX + mov PER_CPU_VAR(current_task), %_ASM_DX + cmp TASK_addr_limit(%_ASM_DX),%_ASM_AX jae bad_get_user ASM_STAC 2: movzwl -1(%_ASM_AX),%edx @@ -61,8 +61,8 @@ ENDPROC(__get_user_2) ENTRY(__get_user_4) add $3,%_ASM_AX jc bad_get_user - GET_THREAD_INFO(%_ASM_DX) - cmp TI_addr_limit(%_ASM_DX),%_ASM_AX + mov PER_CPU_VAR(current_task), %_ASM_DX + cmp TASK_addr_limit(%_ASM_DX),%_ASM_AX jae bad_get_user ASM_STAC 3: movl -3(%_ASM_AX),%edx @@ -75,8 +75,8 @@ ENTRY(__get_user_8) #ifdef CONFIG_X86_64 add $7,%_ASM_AX jc bad_get_user - GET_THREAD_INFO(%_ASM_DX) - cmp TI_addr_limit(%_ASM_DX),%_ASM_AX + mov PER_CPU_VAR(current_task), %_ASM_DX + cmp TASK_addr_limit(%_ASM_DX),%_ASM_AX jae bad_get_user ASM_STAC 4: movq -7(%_ASM_AX),%rdx @@ -86,8 +86,8 @@ ENTRY(__get_user_8) #else add $7,%_ASM_AX jc bad_get_user_8 - GET_THREAD_INFO(%_ASM_DX) - cmp TI_addr_limit(%_ASM_DX),%_ASM_AX + mov PER_CPU_VAR(current_task), %_ASM_DX + cmp TASK_addr_limit(%_ASM_DX),%_ASM_AX jae bad_get_user_8 ASM_STAC 4: movl -7(%_ASM_AX),%edx diff --git a/arch/x86/lib/putuser.S b/arch/x86/lib/putuser.S index e0817a1..c891ece 100644 --- a/arch/x86/lib/putuser.S +++ b/arch/x86/lib/putuser.S @@ -29,14 +29,14 @@ * as they get called from within inline assembly. */ -#define ENTER GET_THREAD_INFO(%_ASM_BX) +#define ENTER mov PER_CPU_VAR(current_task), %_ASM_BX #define EXIT ASM_CLAC ; \ ret .text ENTRY(__put_user_1) ENTER - cmp TI_addr_limit(%_ASM_BX),%_ASM_CX + cmp TASK_addr_limit(%_ASM_BX),%_ASM_CX jae bad_put_user ASM_STAC 1: movb %al,(%_ASM_CX) @@ -46,7 +46,7 @@ ENDPROC(__put_user_1) ENTRY(__put_user_2) ENTER - mov TI_addr_limit(%_ASM_BX),%_ASM_BX + mov TASK_addr_limit(%_ASM_BX),%_ASM_BX sub $1,%_ASM_BX cmp %_ASM_BX,%_ASM_CX jae bad_put_user @@ -58,7 +58,7 @@ ENDPROC(__put_user_2) ENTRY(__put_user_4) ENTER - mov TI_addr_limit(%_ASM_BX),%_ASM_BX + mov TASK_addr_limit(%_ASM_BX),%_ASM_BX sub $3,%_ASM_BX cmp %_ASM_BX,%_ASM_CX jae bad_put_user @@ -70,7 +70,7 @@ ENDPROC(__put_user_4) ENTRY(__put_user_8) ENTER - mov TI_addr_limit(%_ASM_BX),%_ASM_BX + mov TASK_addr_limit(%_ASM_BX),%_ASM_BX sub $7,%_ASM_BX cmp %_ASM_BX,%_ASM_CX jae bad_put_user diff --git a/arch/x86/lib/usercopy_64.c b/arch/x86/lib/usercopy_64.c index 0a42327..9f760cd 100644 --- a/arch/x86/lib/usercopy_64.c +++ b/arch/x86/lib/usercopy_64.c @@ -6,7 +6,7 @@ * Copyright 2002 Andi Kleen */ #include -#include +#include /* * Zero Userspace diff --git a/drivers/pnp/isapnp/proc.c b/drivers/pnp/isapnp/proc.c index 5edee64..262285e 100644 --- a/drivers/pnp/isapnp/proc.c +++ b/drivers/pnp/isapnp/proc.c @@ -21,7 +21,7 @@ #include #include #include -#include +#include extern struct pnp_protocol isapnp_protocol; diff --git a/lib/bitmap.c b/lib/bitmap.c index c66da50..eca8808 100644 --- a/lib/bitmap.c +++ b/lib/bitmap.c @@ -14,9 +14,9 @@ #include #include #include +#include #include -#include /* * bitmaps provide an array of bits, implemented using an an -- cgit v0.10.2 From fb59831b496a5bb7d0a06c7e702d88d1757edfca Mon Sep 17 00:00:00 2001 From: Andy Lutomirski Date: Thu, 14 Jul 2016 13:22:58 -0700 Subject: x86/smp: Remove stack_smp_processor_id() It serves no purpose -- raw_smp_processor_id() works fine. This change will be needed to move thread_info off the stack. Signed-off-by: Andy Lutomirski Cc: Borislav Petkov Cc: Brian Gerst Cc: Denys Vlasenko Cc: H. Peter Anvin Cc: Josh Poimboeuf Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/a2bf4f07fbc30fb32f9f7f3f8f94ad3580823847.1468527351.git.luto@kernel.org Signed-off-by: Ingo Molnar diff --git a/arch/x86/include/asm/cpu.h b/arch/x86/include/asm/cpu.h index 678637a..59d34c5 100644 --- a/arch/x86/include/asm/cpu.h +++ b/arch/x86/include/asm/cpu.h @@ -17,7 +17,6 @@ static inline void prefill_possible_map(void) {} #define cpu_physical_id(cpu) boot_cpu_physical_apicid #define safe_smp_processor_id() 0 -#define stack_smp_processor_id() 0 #endif /* CONFIG_SMP */ diff --git a/arch/x86/include/asm/smp.h b/arch/x86/include/asm/smp.h index 66b0573..0576b61 100644 --- a/arch/x86/include/asm/smp.h +++ b/arch/x86/include/asm/smp.h @@ -172,12 +172,6 @@ extern int safe_smp_processor_id(void); #elif defined(CONFIG_X86_64_SMP) #define raw_smp_processor_id() (this_cpu_read(cpu_number)) -#define stack_smp_processor_id() \ -({ \ - struct thread_info *ti; \ - __asm__("andq %%rsp,%0; ":"=r" (ti) : "0" (CURRENT_MASK)); \ - ti->cpu; \ -}) #define safe_smp_processor_id() smp_processor_id() #endif diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c index 0fe6953f..d22a7b9 100644 --- a/arch/x86/kernel/cpu/common.c +++ b/arch/x86/kernel/cpu/common.c @@ -1452,7 +1452,7 @@ void cpu_init(void) struct task_struct *me; struct tss_struct *t; unsigned long v; - int cpu = stack_smp_processor_id(); + int cpu = raw_smp_processor_id(); int i; wait_for_master_cpu(cpu); -- cgit v0.10.2 From eb43e8f85fffc1ba535e0362a872101dfe48abe3 Mon Sep 17 00:00:00 2001 From: Andy Lutomirski Date: Thu, 14 Jul 2016 13:22:59 -0700 Subject: x86/smp: Remove unnecessary initialization of thread_info::cpu It's statically initialized to zero -- no need to dynamically initialize it to zero as well. Signed-off-by: Andy Lutomirski Cc: Borislav Petkov Cc: Brian Gerst Cc: Denys Vlasenko Cc: H. Peter Anvin Cc: Josh Poimboeuf Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/6cf6314dce3051371a913ee19d1b88e29c68c560.1468527351.git.luto@kernel.org Signed-off-by: Ingo Molnar diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c index fafe8b9..0e91dbe 100644 --- a/arch/x86/kernel/smpboot.c +++ b/arch/x86/kernel/smpboot.c @@ -1285,7 +1285,6 @@ void __init native_smp_prepare_cpus(unsigned int max_cpus) cpumask_copy(cpu_callin_mask, cpumask_of(0)); mb(); - current_thread_info()->cpu = 0; /* needed? */ for_each_possible_cpu(i) { zalloc_cpumask_var(&per_cpu(cpu_sibling_map, i), GFP_KERNEL); zalloc_cpumask_var(&per_cpu(cpu_core_map, i), GFP_KERNEL); -- cgit v0.10.2 From 3ebfd81f7fb3e81a754e37283b7f38c62244641a Mon Sep 17 00:00:00 2001 From: "H.J. Lu" Date: Thu, 14 Jul 2016 12:31:53 -0700 Subject: x86/syscalls: Add compat_sys_preadv64v2/compat_sys_pwritev64v2 Don't use the same syscall numbers for 2 different syscalls: 534 x32 preadv compat_sys_preadv64 535 x32 pwritev compat_sys_pwritev64 534 x32 preadv2 compat_sys_preadv2 535 x32 pwritev2 compat_sys_pwritev2 Add compat_sys_preadv64v2() and compat_sys_pwritev64v2() so that 64-bit offset is passed in one 64-bit register on x32, similar to compat_sys_preadv64() and compat_sys_pwritev64(). Signed-off-by: H.J. Lu Cc: Andy Lutomirski Cc: Borislav Petkov Cc: Brian Gerst Cc: Christoph Hellwig Cc: Denys Vlasenko Cc: H. Peter Anvin Cc: Josh Poimboeuf Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/CAMe9rOovCMf-RQfx_n1U_Tu_DX1BYkjtFr%3DQ4-_PFVSj9BCzUA@mail.gmail.com Signed-off-by: Ingo Molnar diff --git a/arch/x86/entry/syscalls/syscall_64.tbl b/arch/x86/entry/syscalls/syscall_64.tbl index 555263e..e9ce9c7 100644 --- a/arch/x86/entry/syscalls/syscall_64.tbl +++ b/arch/x86/entry/syscalls/syscall_64.tbl @@ -374,5 +374,5 @@ 543 x32 io_setup compat_sys_io_setup 544 x32 io_submit compat_sys_io_submit 545 x32 execveat compat_sys_execveat/ptregs -534 x32 preadv2 compat_sys_preadv2 -535 x32 pwritev2 compat_sys_pwritev2 +546 x32 preadv2 compat_sys_preadv64v2 +547 x32 pwritev2 compat_sys_pwritev64v2 diff --git a/arch/x86/include/asm/unistd.h b/arch/x86/include/asm/unistd.h index 2b19caa..32712a9 100644 --- a/arch/x86/include/asm/unistd.h +++ b/arch/x86/include/asm/unistd.h @@ -26,6 +26,8 @@ # define __ARCH_WANT_COMPAT_SYS_GETDENTS64 # define __ARCH_WANT_COMPAT_SYS_PREADV64 # define __ARCH_WANT_COMPAT_SYS_PWRITEV64 +# define __ARCH_WANT_COMPAT_SYS_PREADV64V2 +# define __ARCH_WANT_COMPAT_SYS_PWRITEV64V2 # endif diff --git a/fs/read_write.c b/fs/read_write.c index 933b53a..66215a7 100644 --- a/fs/read_write.c +++ b/fs/read_write.c @@ -1168,6 +1168,15 @@ COMPAT_SYSCALL_DEFINE5(preadv, compat_ulong_t, fd, return do_compat_preadv64(fd, vec, vlen, pos, 0); } +#ifdef __ARCH_WANT_COMPAT_SYS_PREADV64V2 +COMPAT_SYSCALL_DEFINE5(preadv64v2, unsigned long, fd, + const struct compat_iovec __user *,vec, + unsigned long, vlen, loff_t, pos, int, flags) +{ + return do_compat_preadv64(fd, vec, vlen, pos, flags); +} +#endif + COMPAT_SYSCALL_DEFINE6(preadv2, compat_ulong_t, fd, const struct compat_iovec __user *,vec, compat_ulong_t, vlen, u32, pos_low, u32, pos_high, @@ -1265,6 +1274,15 @@ COMPAT_SYSCALL_DEFINE5(pwritev, compat_ulong_t, fd, return do_compat_pwritev64(fd, vec, vlen, pos, 0); } +#ifdef __ARCH_WANT_COMPAT_SYS_PWRITEV64V2 +COMPAT_SYSCALL_DEFINE5(pwritev64v2, unsigned long, fd, + const struct compat_iovec __user *,vec, + unsigned long, vlen, loff_t, pos, int, flags) +{ + return do_compat_pwritev64(fd, vec, vlen, pos, flags); +} +#endif + COMPAT_SYSCALL_DEFINE6(pwritev2, compat_ulong_t, fd, const struct compat_iovec __user *,vec, compat_ulong_t, vlen, u32, pos_low, u32, pos_high, int, flags) -- cgit v0.10.2 From c48ec42d6eae08f55685ab660f0743ed33b9f22a Mon Sep 17 00:00:00 2001 From: Wei Jiangang Date: Fri, 15 Jul 2016 16:12:10 +0800 Subject: x86/tsc: Remove the unused check_tsc_disabled() check_tsc_disabled() was introduced by commit: c73deb6aecda ("perf/x86: Add ability to calculate TSC from perf sample timestamps") The only caller was arch_perf_update_userpage(), which had been refactored by commit: d8b11a0cbd1c ("perf/x86: Clean up cap_user_time* setting") ... so no need keep and export it any more. Signed-off-by: Wei Jiangang Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: a.p.zijlstra@chello.nl Cc: adrian.hunter@intel.com Cc: bp@suse.de Link: http://lkml.kernel.org/r/1468570330-25810-1-git-send-email-weijg.fnst@cn.fujitsu.com Signed-off-by: Ingo Molnar diff --git a/arch/x86/include/asm/tsc.h b/arch/x86/include/asm/tsc.h index a30591e..33b6365 100644 --- a/arch/x86/include/asm/tsc.h +++ b/arch/x86/include/asm/tsc.h @@ -35,7 +35,6 @@ extern void tsc_init(void); extern void mark_tsc_unstable(char *reason); extern int unsynchronized_tsc(void); extern int check_tsc_unstable(void); -extern int check_tsc_disabled(void); extern unsigned long native_calibrate_cpu(void); extern unsigned long native_calibrate_tsc(void); extern unsigned long long native_sched_clock_from_tsc(u64 tsc); diff --git a/arch/x86/kernel/tsc.c b/arch/x86/kernel/tsc.c index 2a952fc..a804b5a 100644 --- a/arch/x86/kernel/tsc.c +++ b/arch/x86/kernel/tsc.c @@ -335,12 +335,6 @@ int check_tsc_unstable(void) } EXPORT_SYMBOL_GPL(check_tsc_unstable); -int check_tsc_disabled(void) -{ - return tsc_disabled; -} -EXPORT_SYMBOL_GPL(check_tsc_disabled); - #ifdef CONFIG_X86_TSC int __init notsc_setup(char *str) { -- cgit v0.10.2 From 102bb9fef68a21f357dc813d4792666c8295bc35 Mon Sep 17 00:00:00 2001 From: Wei Jiangang Date: Thu, 14 Jul 2016 10:24:06 +0800 Subject: x86/apic: Remove the unused struct apic::apic_id_mask field The only user verify_local_APIC() had been removed by commit: 4399c03c6780 ("x86/apic: Remove verify_local_APIC()") ... so there is no need to keep it. Signed-off-by: Wei Jiangang Cc: Borislav Petkov Cc: H. Peter Anvin Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: boris.ostrovsky@oracle.com Cc: bsd@redhat.com Cc: david.vrabel@citrix.com Cc: jgross@suse.com Cc: konrad.wilk@oracle.com Cc: xen-devel@lists.xenproject.org Link: http://lkml.kernel.org/r/1468463046-20849-1-git-send-email-weijg.fnst@cn.fujitsu.com Signed-off-by: Ingo Molnar diff --git a/arch/x86/include/asm/apic.h b/arch/x86/include/asm/apic.h index bc27611..f5befd4 100644 --- a/arch/x86/include/asm/apic.h +++ b/arch/x86/include/asm/apic.h @@ -300,7 +300,6 @@ struct apic { unsigned int (*get_apic_id)(unsigned long x); unsigned long (*set_apic_id)(unsigned int id); - unsigned long apic_id_mask; int (*cpu_mask_to_apicid_and)(const struct cpumask *cpumask, const struct cpumask *andmask, diff --git a/arch/x86/kernel/apic/apic_flat_64.c b/arch/x86/kernel/apic/apic_flat_64.c index 76f89e2..0487477 100644 --- a/arch/x86/kernel/apic/apic_flat_64.c +++ b/arch/x86/kernel/apic/apic_flat_64.c @@ -181,7 +181,6 @@ static struct apic apic_flat = { .get_apic_id = flat_get_apic_id, .set_apic_id = set_apic_id, - .apic_id_mask = 0xFFu << 24, .cpu_mask_to_apicid_and = flat_cpu_mask_to_apicid_and, @@ -278,7 +277,6 @@ static struct apic apic_physflat = { .get_apic_id = flat_get_apic_id, .set_apic_id = set_apic_id, - .apic_id_mask = 0xFFu << 24, .cpu_mask_to_apicid_and = default_cpu_mask_to_apicid_and, diff --git a/arch/x86/kernel/apic/apic_noop.c b/arch/x86/kernel/apic/apic_noop.c index 13d19ed..2cebf59 100644 --- a/arch/x86/kernel/apic/apic_noop.c +++ b/arch/x86/kernel/apic/apic_noop.c @@ -141,7 +141,6 @@ struct apic apic_noop = { .get_apic_id = noop_get_apic_id, .set_apic_id = NULL, - .apic_id_mask = 0x0F << 24, .cpu_mask_to_apicid_and = flat_cpu_mask_to_apicid_and, diff --git a/arch/x86/kernel/apic/apic_numachip.c b/arch/x86/kernel/apic/apic_numachip.c index ab5c2c6..714d4fd 100644 --- a/arch/x86/kernel/apic/apic_numachip.c +++ b/arch/x86/kernel/apic/apic_numachip.c @@ -269,7 +269,6 @@ static const struct apic apic_numachip1 __refconst = { .get_apic_id = numachip1_get_apic_id, .set_apic_id = numachip1_set_apic_id, - .apic_id_mask = 0xffU << 24, .cpu_mask_to_apicid_and = default_cpu_mask_to_apicid_and, @@ -321,7 +320,6 @@ static const struct apic apic_numachip2 __refconst = { .get_apic_id = numachip2_get_apic_id, .set_apic_id = numachip2_set_apic_id, - .apic_id_mask = 0xffU << 24, .cpu_mask_to_apicid_and = default_cpu_mask_to_apicid_and, diff --git a/arch/x86/kernel/apic/bigsmp_32.c b/arch/x86/kernel/apic/bigsmp_32.c index cf9bd89..06dbaa4 100644 --- a/arch/x86/kernel/apic/bigsmp_32.c +++ b/arch/x86/kernel/apic/bigsmp_32.c @@ -171,7 +171,6 @@ static struct apic apic_bigsmp = { .get_apic_id = bigsmp_get_apic_id, .set_apic_id = NULL, - .apic_id_mask = 0xFF << 24, .cpu_mask_to_apicid_and = default_cpu_mask_to_apicid_and, diff --git a/arch/x86/kernel/apic/probe_32.c b/arch/x86/kernel/apic/probe_32.c index f316e34..93edfa0 100644 --- a/arch/x86/kernel/apic/probe_32.c +++ b/arch/x86/kernel/apic/probe_32.c @@ -101,7 +101,6 @@ static struct apic apic_default = { .get_apic_id = default_get_apic_id, .set_apic_id = NULL, - .apic_id_mask = 0x0F << 24, .cpu_mask_to_apicid_and = flat_cpu_mask_to_apicid_and, diff --git a/arch/x86/kernel/apic/x2apic_cluster.c b/arch/x86/kernel/apic/x2apic_cluster.c index aca8b75..24170d0 100644 --- a/arch/x86/kernel/apic/x2apic_cluster.c +++ b/arch/x86/kernel/apic/x2apic_cluster.c @@ -270,7 +270,6 @@ static struct apic apic_x2apic_cluster = { .get_apic_id = x2apic_get_apic_id, .set_apic_id = x2apic_set_apic_id, - .apic_id_mask = 0xFFFFFFFFu, .cpu_mask_to_apicid_and = x2apic_cpu_mask_to_apicid_and, diff --git a/arch/x86/kernel/apic/x2apic_phys.c b/arch/x86/kernel/apic/x2apic_phys.c index a1242e2..4f13f54f 100644 --- a/arch/x86/kernel/apic/x2apic_phys.c +++ b/arch/x86/kernel/apic/x2apic_phys.c @@ -126,7 +126,6 @@ static struct apic apic_x2apic_phys = { .get_apic_id = x2apic_get_apic_id, .set_apic_id = x2apic_set_apic_id, - .apic_id_mask = 0xFFFFFFFFu, .cpu_mask_to_apicid_and = default_cpu_mask_to_apicid_and, diff --git a/arch/x86/kernel/apic/x2apic_uv_x.c b/arch/x86/kernel/apic/x2apic_uv_x.c index 2900315..5a58c91 100644 --- a/arch/x86/kernel/apic/x2apic_uv_x.c +++ b/arch/x86/kernel/apic/x2apic_uv_x.c @@ -582,7 +582,6 @@ static struct apic __refdata apic_x2apic_uv_x = { .get_apic_id = x2apic_get_apic_id, .set_apic_id = set_apic_id, - .apic_id_mask = 0xFFFFFFFFu, .cpu_mask_to_apicid_and = uv_cpu_mask_to_apicid_and, diff --git a/arch/x86/xen/apic.c b/arch/x86/xen/apic.c index db52a7f..44c88ad 100644 --- a/arch/x86/xen/apic.c +++ b/arch/x86/xen/apic.c @@ -177,7 +177,6 @@ static struct apic xen_pv_apic = { .get_apic_id = xen_get_apic_id, .set_apic_id = xen_set_apic_id, /* Can be NULL on 32-bit. */ - .apic_id_mask = 0xFF << 24, /* Used by verify_local_APIC. Match with what xen_get_apic_id does. */ .cpu_mask_to_apicid_and = flat_cpu_mask_to_apicid_and, -- cgit v0.10.2 From da0a0acaf8881c4fb960064d6cf6e7df2fd0f8b5 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 19 May 2016 09:14:20 +0200 Subject: drm/i915/psr: Implement PSR2 w/a for gen9 Found this while browsing Bspec. Looks like it applies to both skl and kbl. v2: Also for bxt (Art). Cc: Rodrigo Vivi Cc: Sonika Jindal Cc: Durgadoss R Cc: "Pandiyan, Dhinakaran" Cc: "Runyan, Arthur J" Reviewed-by: Sonika Jindal Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/1463642060-30728-1-git-send-email-daniel.vetter@ffwll.ch (cherry picked from commit dc00b6a07c2206e7b7dbcbeff856049264c40faa) Signed-off-by: Mika Kuoppala diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index b407411..bb43bb1 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -6031,6 +6031,7 @@ enum skl_disp_power_wells { #define CHICKEN_PAR1_1 _MMIO(0x42080) #define DPA_MASK_VBLANK_SRD (1 << 15) #define FORCE_ARB_IDLE_PLANES (1 << 14) +#define SKL_EDP_PSR_FIX_RDWRAP (1 << 3) #define _CHICKEN_PIPESL_1_A 0x420b0 #define _CHICKEN_PIPESL_1_B 0x420b4 diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index a7ef45d..3625975 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -58,6 +58,10 @@ static void bxt_init_clock_gating(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; + /* See Bspec note for PSR2_CTL bit 31, Wa#828:bxt */ + I915_WRITE(CHICKEN_PAR1_1, + I915_READ(CHICKEN_PAR1_1) | SKL_EDP_PSR_FIX_RDWRAP); + /* WaDisableSDEUnitClockGating:bxt */ I915_WRITE(GEN8_UCGCTL6, I915_READ(GEN8_UCGCTL6) | GEN8_SDEUNIT_CLOCK_GATE_DISABLE); @@ -6698,6 +6702,15 @@ static void lpt_suspend_hw(struct drm_device *dev) } } +static void skylake_init_clock_gating(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + /* See Bspec note for PSR2_CTL bit 31, Wa#828:skl,kbl */ + I915_WRITE(CHICKEN_PAR1_1, + I915_READ(CHICKEN_PAR1_1) | SKL_EDP_PSR_FIX_RDWRAP); +} + static void broadwell_init_clock_gating(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; @@ -7163,9 +7176,9 @@ static void nop_init_clock_gating(struct drm_device *dev) void intel_init_clock_gating_hooks(struct drm_i915_private *dev_priv) { if (IS_SKYLAKE(dev_priv)) - dev_priv->display.init_clock_gating = nop_init_clock_gating; + dev_priv->display.init_clock_gating = skylake_init_clock_gating; else if (IS_KABYLAKE(dev_priv)) - dev_priv->display.init_clock_gating = nop_init_clock_gating; + dev_priv->display.init_clock_gating = skylake_init_clock_gating; else if (IS_BROXTON(dev_priv)) dev_priv->display.init_clock_gating = bxt_init_clock_gating; else if (IS_BROADWELL(dev_priv)) -- cgit v0.10.2 From f98edb2b6f6baffe0d2be66ebe761b51486c6a40 Mon Sep 17 00:00:00 2001 From: "arun.siluvery@linux.intel.com" Date: Mon, 6 Jun 2016 09:52:49 +0100 Subject: drm/i915/gen9: Add WaVFEStateAfterPipeControlwithMediaStateClear Kernel only need to add a register to HW whitelist, required for a preemption related issue. Reference: HSD#2131039 Reviewed-by: Jeff McGee Signed-off-by: Arun Siluvery Signed-off-by: Tvrtko Ursulin Link: http://patchwork.freedesktop.org/patch/msgid/1465203169-16591-1-git-send-email-arun.siluvery@linux.intel.com (cherry picked from commit 6bb6285582e0cf9b3a8440e0e714aae5f66d9ce2) Signed-off-by: Mika Kuoppala diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index bb43bb1..7b47504 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -6070,6 +6070,7 @@ enum skl_disp_power_wells { #define GEN9_TSG_BARRIER_ACK_DISABLE (1<<8) #define GEN9_CS_DEBUG_MODE1 _MMIO(0x20ec) +#define GEN9_CTX_PREEMPT_REG _MMIO(0x2248) #define GEN8_CS_CHICKEN1 _MMIO(0x2580) /* GEN7 chicken */ diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 04402bb..d812501 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -992,6 +992,11 @@ static int gen9_init_workarounds(struct intel_engine_cs *engine) I915_WRITE(GEN8_L3SQCREG4, (I915_READ(GEN8_L3SQCREG4) | GEN8_LQSC_FLUSH_COHERENT_LINES)); + /* WaVFEStateAfterPipeControlwithMediaStateClear:skl,bxt */ + ret = wa_ring_whitelist_reg(engine, GEN9_CTX_PREEMPT_REG); + if (ret) + return ret; + /* WaEnablePreemptionGranularityControlByUMD:skl,bxt */ ret= wa_ring_whitelist_reg(engine, GEN8_CS_CHICKEN1); if (ret) -- cgit v0.10.2 From c000456c8c642c6474cd7b94344ff1c39e91c575 Mon Sep 17 00:00:00 2001 From: Mika Kuoppala Date: Tue, 7 Jun 2016 17:18:53 +0300 Subject: drm/i915/skl: Add WaDisableGafsUnitClkGating MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We need to disable clock gating in this unit to work around hardware issue causing possible corruption/hang. v2: name the bit (Ville) v3: leave the fix enabled for 2227050 and set correct bit (Matthew) References: HSD#2227156, HSD#2227050 Cc: Ville Syrjälä Cc: Matthew Auld Reviewed-by: Matthew Auld Signed-off-by: Mika Kuoppala Link: http://patchwork.freedesktop.org/patch/msgid/1465309159-30531-2-git-send-email-mika.kuoppala@intel.com (cherry picked from commit eee8efb02a0f9284d85e6b3688f944ca765d7ad3) Signed-off-by: Mika Kuoppala diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 7b47504..80ede80 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -6939,6 +6939,7 @@ enum skl_disp_power_wells { #define GEN7_UCGCTL4 _MMIO(0x940c) #define GEN7_L3BANK2X_CLOCK_GATE_DISABLE (1<<25) +#define GEN8_EU_GAUNIT_CLOCK_GATE_DISABLE (1<<14) #define GEN6_RCGCTL1 _MMIO(0x9410) #define GEN6_RCGCTL2 _MMIO(0x9414) diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index d812501..31d7e28 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -1125,6 +1125,9 @@ static int skl_init_workarounds(struct intel_engine_cs *engine) GEN7_HALF_SLICE_CHICKEN1, GEN7_SBE_SS_CACHE_DISPATCH_PORT_SHARING_DISABLE); + /* WaDisableGafsUnitClkGating:skl */ + WA_SET_BIT(GEN7_UCGCTL4, GEN8_EU_GAUNIT_CLOCK_GATE_DISABLE); + /* WaDisableLSQCROPERFforOCL:skl */ ret = wa_ring_whitelist_reg(engine, GEN8_L3SQCREG4); if (ret) -- cgit v0.10.2 From 68370e0ab1636efce7b7e8254430c1ec321564bc Mon Sep 17 00:00:00 2001 From: Mika Kuoppala Date: Tue, 7 Jun 2016 17:18:54 +0300 Subject: drm/i915/kbl: Init gen9 workarounds Kabylake is part of gen9 family so init the generic gen9 workarounds for it. v2: rebase Signed-off-by: Mika Kuoppala Reviewed-by: Matthew Auld Link: http://patchwork.freedesktop.org/patch/msgid/1465309159-30531-3-git-send-email-mika.kuoppala@intel.com (cherry picked from commit e5f81d65ac5a04020d790caf63b2324730ba0277) Signed-off-by: Mika Kuoppala diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 31d7e28..bcd9e70 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -916,21 +916,21 @@ static int gen9_init_workarounds(struct intel_engine_cs *engine) uint32_t tmp; int ret; - /* WaEnableLbsSlaRetryTimerDecrement:skl */ + /* WaEnableLbsSlaRetryTimerDecrement:skl,bxt,kbl */ I915_WRITE(BDW_SCRATCH1, I915_READ(BDW_SCRATCH1) | GEN9_LBS_SLA_RETRY_TIMER_DECREMENT_ENABLE); - /* WaDisableKillLogic:bxt,skl */ + /* WaDisableKillLogic:bxt,skl,kbl */ I915_WRITE(GAM_ECOCHK, I915_READ(GAM_ECOCHK) | ECOCHK_DIS_TLB); - /* WaClearFlowControlGpgpuContextSave:skl,bxt */ - /* WaDisablePartialInstShootdown:skl,bxt */ + /* WaClearFlowControlGpgpuContextSave:skl,bxt,kbl */ + /* WaDisablePartialInstShootdown:skl,bxt,kbl */ WA_SET_BIT_MASKED(GEN8_ROW_CHICKEN, FLOW_CONTROL_ENABLE | PARTIAL_INSTRUCTION_SHOOTDOWN_DISABLE); - /* Syncing dependencies between camera and graphics:skl,bxt */ + /* Syncing dependencies between camera and graphics:skl,bxt,kbl */ WA_SET_BIT_MASKED(HALF_SLICE_CHICKEN3, GEN9_DISABLE_OCL_OOB_SUPPRESS_LOGIC); @@ -952,18 +952,18 @@ static int gen9_init_workarounds(struct intel_engine_cs *engine) */ } - /* WaEnableYV12BugFixInHalfSliceChicken7:skl,bxt */ - /* WaEnableSamplerGPGPUPreemptionSupport:skl,bxt */ + /* WaEnableYV12BugFixInHalfSliceChicken7:skl,bxt,kbl */ + /* WaEnableSamplerGPGPUPreemptionSupport:skl,bxt,kbl */ WA_SET_BIT_MASKED(GEN9_HALF_SLICE_CHICKEN7, GEN9_ENABLE_YV12_BUGFIX | GEN9_ENABLE_GPGPU_PREEMPTION); - /* Wa4x4STCOptimizationDisable:skl,bxt */ - /* WaDisablePartialResolveInVc:skl,bxt */ + /* Wa4x4STCOptimizationDisable:skl,bxt,kbl */ + /* WaDisablePartialResolveInVc:skl,bxt,kbl */ WA_SET_BIT_MASKED(CACHE_MODE_1, (GEN8_4x4_STC_OPTIMIZATION_DISABLE | GEN9_PARTIAL_RESOLVE_IN_VC_DISABLE)); - /* WaCcsTlbPrefetchDisable:skl,bxt */ + /* WaCcsTlbPrefetchDisable:skl,bxt,kbl */ WA_CLR_BIT_MASKED(GEN9_HALF_SLICE_CHICKEN5, GEN9_CCS_TLB_PREFETCH_ENABLE); @@ -980,15 +980,17 @@ static int gen9_init_workarounds(struct intel_engine_cs *engine) tmp |= HDC_FORCE_CSR_NON_COHERENT_OVR_DISABLE; WA_SET_BIT_MASKED(HDC_CHICKEN0, tmp); - /* WaDisableSamplerPowerBypassForSOPingPong:skl,bxt */ - if (IS_SKYLAKE(dev) || IS_BXT_REVID(dev, 0, BXT_REVID_B0)) + /* WaDisableSamplerPowerBypassForSOPingPong:skl,bxt,kbl */ + if (IS_SKYLAKE(dev_priv) || + IS_KABYLAKE(dev_priv) || + IS_BXT_REVID(dev_priv, 0, BXT_REVID_B0)) WA_SET_BIT_MASKED(HALF_SLICE_CHICKEN3, GEN8_SAMPLER_POWER_BYPASS_DIS); - /* WaDisableSTUnitPowerOptimization:skl,bxt */ + /* WaDisableSTUnitPowerOptimization:skl,bxt,kbl */ WA_SET_BIT_MASKED(HALF_SLICE_CHICKEN2, GEN8_ST_PO_DISABLE); - /* WaOCLCoherentLineFlush:skl,bxt */ + /* WaOCLCoherentLineFlush:skl,bxt,kbl */ I915_WRITE(GEN8_L3SQCREG4, (I915_READ(GEN8_L3SQCREG4) | GEN8_LQSC_FLUSH_COHERENT_LINES)); @@ -997,12 +999,12 @@ static int gen9_init_workarounds(struct intel_engine_cs *engine) if (ret) return ret; - /* WaEnablePreemptionGranularityControlByUMD:skl,bxt */ + /* WaEnablePreemptionGranularityControlByUMD:skl,bxt,kbl */ ret= wa_ring_whitelist_reg(engine, GEN8_CS_CHICKEN1); if (ret) return ret; - /* WaAllowUMDToModifyHDCChicken1:skl,bxt */ + /* WaAllowUMDToModifyHDCChicken1:skl,bxt,kbl */ ret = wa_ring_whitelist_reg(engine, GEN8_HDC_CHICKEN1); if (ret) return ret; @@ -1185,6 +1187,17 @@ static int bxt_init_workarounds(struct intel_engine_cs *engine) return 0; } +static int kbl_init_workarounds(struct intel_engine_cs *engine) +{ + int ret; + + ret = gen9_init_workarounds(engine); + if (ret) + return ret; + + return 0; +} + int init_workarounds_ring(struct intel_engine_cs *engine) { struct drm_device *dev = engine->dev; @@ -1207,6 +1220,9 @@ int init_workarounds_ring(struct intel_engine_cs *engine) if (IS_BROXTON(dev)) return bxt_init_workarounds(engine); + if (IS_KABYLAKE(dev_priv)) + return kbl_init_workarounds(engine); + return 0; } -- cgit v0.10.2 From a1d97ca5b2998d137da4f4673edae472d23742e5 Mon Sep 17 00:00:00 2001 From: Mika Kuoppala Date: Tue, 7 Jun 2016 17:18:55 +0300 Subject: drm/i915/kbl: Add REVID macro Add REVID macro for kbl to limit wa applicability to particular revision range. Signed-off-by: Mika Kuoppala Reviewed-by: Matthew Auld Link: http://patchwork.freedesktop.org/patch/msgid/1465309159-30531-4-git-send-email-mika.kuoppala@intel.com (cherry picked from commit c033a37cd42c1b5492d95bfbc8c0891088e04b57) Signed-off-by: Mika Kuoppala diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 7c334e9..6ddd165 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -2600,6 +2600,12 @@ struct drm_i915_cmd_table { #define IS_BXT_REVID(p, since, until) (IS_BROXTON(p) && IS_REVID(p, since, until)) +#define KBL_REVID_A0 0x0 +#define KBL_REVID_B0 0x1 + +#define IS_KBL_REVID(p, since, until) \ + (IS_KABYLAKE(p) && IS_REVID(p, since, until)) + /* * The genX designation typically refers to the render engine, so render * capability related checks should use IS_GEN, while display and other checks -- cgit v0.10.2 From 89b54515d35789297611b9deca904da49a377800 Mon Sep 17 00:00:00 2001 From: Mika Kuoppala Date: Tue, 7 Jun 2016 17:18:56 +0300 Subject: drm/i915/kbl: Add WaSkipStolenMemoryFirstPage for A0 We need this for kbl a0 boards. Note that this should be also for bxt A0 but we omit that on purpose as bxt A0's are out of fashion already. References: HSD#1912158, HSD#4393097 Signed-off-by: Mika Kuoppala Reviewed-by: Matthew Auld Link: http://patchwork.freedesktop.org/patch/msgid/1465309159-30531-5-git-send-email-mika.kuoppala@intel.com (cherry picked from commit 6e4f10c33a8bd0df4412bc31c0f11930e0228123) Signed-off-by: Mika Kuoppala diff --git a/drivers/gpu/drm/i915/i915_gem_stolen.c b/drivers/gpu/drm/i915/i915_gem_stolen.c index b7ce963..44004e3 100644 --- a/drivers/gpu/drm/i915/i915_gem_stolen.c +++ b/drivers/gpu/drm/i915/i915_gem_stolen.c @@ -55,8 +55,10 @@ int i915_gem_stolen_insert_node_in_range(struct drm_i915_private *dev_priv, return -ENODEV; /* See the comment at the drm_mm_init() call for more about this check. - * WaSkipStolenMemoryFirstPage:bdw,chv (incomplete) */ - if (INTEL_INFO(dev_priv)->gen == 8 && start < 4096) + * WaSkipStolenMemoryFirstPage:bdw,chv,kbl (incomplete) + */ + if (start < 4096 && (IS_GEN8(dev_priv) || + IS_KBL_REVID(dev_priv, 0, KBL_REVID_A0))) start = 4096; mutex_lock(&dev_priv->mm.stolen_lock); -- cgit v0.10.2 From 6fd72492b382cb59beee97c7d5767f6e260620bd Mon Sep 17 00:00:00 2001 From: Mika Kuoppala Date: Tue, 7 Jun 2016 17:18:57 +0300 Subject: drm/i915/gen9: Always apply WaForceContextSaveRestoreNonCoherent The revision id range for this workaround has changed. So apply it to all revids on all gen9. References: HSD#2134449 Signed-off-by: Mika Kuoppala Reviewed-by: Matthew Auld Link: http://patchwork.freedesktop.org/patch/msgid/1465309159-30531-6-git-send-email-mika.kuoppala@intel.com (cherry picked from commit 5b0e3659296cc4a1484e60640ef10780194a195b) Signed-off-by: Mika Kuoppala diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index bcd9e70..e6fa1e6 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -913,7 +913,6 @@ static int gen9_init_workarounds(struct intel_engine_cs *engine) { struct drm_device *dev = engine->dev; struct drm_i915_private *dev_priv = dev->dev_private; - uint32_t tmp; int ret; /* WaEnableLbsSlaRetryTimerDecrement:skl,bxt,kbl */ @@ -973,12 +972,10 @@ static int gen9_init_workarounds(struct intel_engine_cs *engine) WA_SET_BIT_MASKED(SLICE_ECO_CHICKEN0, PIXEL_MASK_CAMMING_DISABLE); - /* WaForceContextSaveRestoreNonCoherent:skl,bxt */ - tmp = HDC_FORCE_CONTEXT_SAVE_RESTORE_NON_COHERENT; - if (IS_SKL_REVID(dev, SKL_REVID_F0, REVID_FOREVER) || - IS_BXT_REVID(dev, BXT_REVID_B0, REVID_FOREVER)) - tmp |= HDC_FORCE_CSR_NON_COHERENT_OVR_DISABLE; - WA_SET_BIT_MASKED(HDC_CHICKEN0, tmp); + /* WaForceContextSaveRestoreNonCoherent:skl,bxt,kbl */ + WA_SET_BIT_MASKED(HDC_CHICKEN0, + HDC_FORCE_CONTEXT_SAVE_RESTORE_NON_COHERENT | + HDC_FORCE_CSR_NON_COHERENT_OVR_DISABLE); /* WaDisableSamplerPowerBypassForSOPingPong:skl,bxt,kbl */ if (IS_SKYLAKE(dev_priv) || -- cgit v0.10.2 From 60f452e6147bcbe7d38cd2368cf5c7c1c27a4d38 Mon Sep 17 00:00:00 2001 From: Mika Kuoppala Date: Tue, 7 Jun 2016 17:18:58 +0300 Subject: drm/i915: Mimic skl with WaForceEnableNonCoherent Past evidence with system hangs and hsds tie WaForceEnableNonCoherent and WaDisableHDCInvalidation to WaForceContextSaveRestoreNonCoherent. Documentation states that WaForceContextSaveRestoreNonCoherent would not be needed on skl past E0 but evidence proved otherwise. See commit <510650e8b2ab> ("drm/i915/skl: Fix spurious gpu hang with gt3/gt4 revs"). In this scope consider kbl to be skl with a bigger revision than E0 so play it safe and bind these two workarounds to the WaForceContextSaveRestoreNonCoherent, and apply to all gen9. v2: fix comment (Matthew) References: HSD#2134449, HSD#2131413 Signed-off-by: Mika Kuoppala Reviewed-by: Matthew Auld Link: http://patchwork.freedesktop.org/patch/msgid/1465309159-30531-7-git-send-email-mika.kuoppala@intel.com (cherry picked from commit bbaefe72a00c93c6ec12e029019681e3f7d7de7a) Signed-off-by: Mika Kuoppala diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index e6fa1e6..5c7f3cf 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -977,6 +977,27 @@ static int gen9_init_workarounds(struct intel_engine_cs *engine) HDC_FORCE_CONTEXT_SAVE_RESTORE_NON_COHERENT | HDC_FORCE_CSR_NON_COHERENT_OVR_DISABLE); + /* WaForceEnableNonCoherent and WaDisableHDCInvalidation are + * both tied to WaForceContextSaveRestoreNonCoherent + * in some hsds for skl. We keep the tie for all gen9. The + * documentation is a bit hazy and so we want to get common behaviour, + * even though there is no clear evidence we would need both on kbl/bxt. + * This area has been source of system hangs so we play it safe + * and mimic the skl regardless of what bspec says. + * + * Use Force Non-Coherent whenever executing a 3D context. This + * is a workaround for a possible hang in the unlikely event + * a TLB invalidation occurs during a PSD flush. + */ + + /* WaForceEnableNonCoherent:skl,bxt,kbl */ + WA_SET_BIT_MASKED(HDC_CHICKEN0, + HDC_FORCE_NON_COHERENT); + + /* WaDisableHDCInvalidation:skl,bxt,kbl */ + I915_WRITE(GAM_ECOCHK, I915_READ(GAM_ECOCHK) | + BDW_DISABLE_HDC_INVALIDATION); + /* WaDisableSamplerPowerBypassForSOPingPong:skl,bxt,kbl */ if (IS_SKYLAKE(dev_priv) || IS_KABYLAKE(dev_priv) || @@ -1096,22 +1117,6 @@ static int skl_init_workarounds(struct intel_engine_cs *engine) WA_SET_BIT_MASKED(HIZ_CHICKEN, BDW_HIZ_POWER_COMPILER_CLOCK_GATING_DISABLE); - /* This is tied to WaForceContextSaveRestoreNonCoherent */ - if (IS_SKL_REVID(dev, 0, REVID_FOREVER)) { - /* - *Use Force Non-Coherent whenever executing a 3D context. This - * is a workaround for a possible hang in the unlikely event - * a TLB invalidation occurs during a PSD flush. - */ - /* WaForceEnableNonCoherent:skl */ - WA_SET_BIT_MASKED(HDC_CHICKEN0, - HDC_FORCE_NON_COHERENT); - - /* WaDisableHDCInvalidation:skl */ - I915_WRITE(GAM_ECOCHK, I915_READ(GAM_ECOCHK) | - BDW_DISABLE_HDC_INVALIDATION); - } - /* WaBarrierPerformanceFixDisable:skl */ if (IS_SKL_REVID(dev, SKL_REVID_C0, SKL_REVID_D0)) WA_SET_BIT_MASKED(HDC_CHICKEN0, -- cgit v0.10.2 From 791645098219ad3fd505db89d953a16275a8c89b Mon Sep 17 00:00:00 2001 From: Mika Kuoppala Date: Tue, 7 Jun 2016 17:18:59 +0300 Subject: drm/i915/kbl: Add WaEnableGapsTsvCreditFix We need this crucial workaround from skl also to all kbl revisions. Lack of it was causing system hangs on skl enabling so this is a must have. v2: Don't add revid checks to gen9 init workarounds (Arun) References: HSD#2126660 Cc: Arun Siluvery Signed-off-by: Mika Kuoppala Reviewed-by: Matthew Auld Link: http://patchwork.freedesktop.org/patch/msgid/1465309159-30531-8-git-send-email-mika.kuoppala@intel.com (cherry picked from commit e587f6cb0af140f3c0ea794d8616eb9a29969983) Signed-off-by: Mika Kuoppala diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 5c7f3cf..6d844e2 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -1191,12 +1191,17 @@ static int bxt_init_workarounds(struct intel_engine_cs *engine) static int kbl_init_workarounds(struct intel_engine_cs *engine) { + struct drm_i915_private *dev_priv = engine->dev->dev_private; int ret; ret = gen9_init_workarounds(engine); if (ret) return ret; + /* WaEnableGapsTsvCreditFix:kbl */ + I915_WRITE(GEN8_GARBCNTL, (I915_READ(GEN8_GARBCNTL) | + GEN9_GAPS_TSV_CREDIT_DISABLE)); + return 0; } -- cgit v0.10.2 From 3d042d4633d7b180e08abead7bd7de0bb194b256 Mon Sep 17 00:00:00 2001 From: Mika Kuoppala Date: Tue, 7 Jun 2016 17:19:00 +0300 Subject: drm/i915/kbl: Add WaDisableFenceDestinationToSLM for A0 Add this workaround for kbl revid A0 only. v2: rebase v3: carve out a non related workaround (Chris) References: HSD#1911714 Cc: Chris Wilson Signed-off-by: Mika Kuoppala Reviewed-by: Matthew Auld Link: http://patchwork.freedesktop.org/patch/msgid/1465309159-30531-9-git-send-email-mika.kuoppala@intel.com (cherry picked from commit 8401d42fd5adf709281e1700194805f393b49573) Signed-off-by: Mika Kuoppala diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 6d844e2..bdb3304 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -1202,6 +1202,11 @@ static int kbl_init_workarounds(struct intel_engine_cs *engine) I915_WRITE(GEN8_GARBCNTL, (I915_READ(GEN8_GARBCNTL) | GEN9_GAPS_TSV_CREDIT_DISABLE)); + /* WaDisableFenceDestinationToSLM:kbl (pre-prod) */ + if (IS_KBL_REVID(dev_priv, KBL_REVID_A0, KBL_REVID_A0)) + WA_SET_BIT_MASKED(HDC_CHICKEN0, + HDC_FENCE_DEST_SLM_DISABLE); + return 0; } -- cgit v0.10.2 From 9146f308d5916e20c53afe3ee0bd4dbd562a0ef9 Mon Sep 17 00:00:00 2001 From: Mika Kuoppala Date: Tue, 7 Jun 2016 17:19:01 +0300 Subject: drm/i915/kbl: Add WaDisableSDEUnitClockGating Add this workaround until upto kbl revid B0. References: HSD#1802092 Signed-off-by: Mika Kuoppala Reviewed-by: Matthew Auld Link: http://patchwork.freedesktop.org/patch/msgid/1465309159-30531-10-git-send-email-mika.kuoppala@intel.com (cherry picked from commit 9498dba7b4ffe40a1e2b23d7718b77e49841248f) Signed-off-by: Mika Kuoppala diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 3625975..bff740c 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -6702,11 +6702,25 @@ static void lpt_suspend_hw(struct drm_device *dev) } } +static void kabylake_init_clock_gating(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + /* See Bspec note for PSR2_CTL bit 31, Wa#828:kbl */ + I915_WRITE(CHICKEN_PAR1_1, + I915_READ(CHICKEN_PAR1_1) | SKL_EDP_PSR_FIX_RDWRAP); + + /* WaDisableSDEUnitClockGating:kbl */ + if (IS_KBL_REVID(dev_priv, 0, KBL_REVID_B0)) + I915_WRITE(GEN8_UCGCTL6, I915_READ(GEN8_UCGCTL6) | + GEN8_SDEUNIT_CLOCK_GATE_DISABLE); +} + static void skylake_init_clock_gating(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; - /* See Bspec note for PSR2_CTL bit 31, Wa#828:skl,kbl */ + /* See Bspec note for PSR2_CTL bit 31, Wa#828:skl */ I915_WRITE(CHICKEN_PAR1_1, I915_READ(CHICKEN_PAR1_1) | SKL_EDP_PSR_FIX_RDWRAP); } @@ -7178,7 +7192,7 @@ void intel_init_clock_gating_hooks(struct drm_i915_private *dev_priv) if (IS_SKYLAKE(dev_priv)) dev_priv->display.init_clock_gating = skylake_init_clock_gating; else if (IS_KABYLAKE(dev_priv)) - dev_priv->display.init_clock_gating = skylake_init_clock_gating; + dev_priv->display.init_clock_gating = kabylake_init_clock_gating; else if (IS_BROXTON(dev_priv)) dev_priv->display.init_clock_gating = bxt_init_clock_gating; else if (IS_BROADWELL(dev_priv)) -- cgit v0.10.2 From 738fa1b3123f9a3b4374b4156ad54a2b64273f51 Mon Sep 17 00:00:00 2001 From: Mika Kuoppala Date: Tue, 7 Jun 2016 17:19:03 +0300 Subject: drm/i915/kbl: Add WaDisableLSQCROPERFforOCL Extend the scope of this workaround, already used in skl, to also take effect in kbl. v2: Fix KBL_REVID_E0 (Matthew) References: HSD#2132677 Cc: Matthew Auld Signed-off-by: Mika Kuoppala Reviewed-by: Matthew Auld Link: http://patchwork.freedesktop.org/patch/msgid/1465309159-30531-12-git-send-email-mika.kuoppala@intel.com (cherry picked from commit fe90581987cd5fadd2942f59f8511bcb39fdec34) Signed-off-by: Mika Kuoppala diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 6ddd165..b0fffa0 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -2602,6 +2602,9 @@ struct drm_i915_cmd_table { #define KBL_REVID_A0 0x0 #define KBL_REVID_B0 0x1 +#define KBL_REVID_C0 0x2 +#define KBL_REVID_D0 0x3 +#define KBL_REVID_E0 0x4 #define IS_KBL_REVID(p, since, until) \ (IS_KABYLAKE(p) && IS_REVID(p, since, until)) diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 42eac37..cf18eac 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -1103,15 +1103,17 @@ static inline int gen8_emit_flush_coherentl3_wa(struct intel_engine_cs *engine, uint32_t *const batch, uint32_t index) { + struct drm_i915_private *dev_priv = engine->dev->dev_private; uint32_t l3sqc4_flush = (0x40400000 | GEN8_LQSC_FLUSH_COHERENT_LINES); /* - * WaDisableLSQCROPERFforOCL:skl + * WaDisableLSQCROPERFforOCL:skl,kbl * This WA is implemented in skl_init_clock_gating() but since * this batch updates GEN8_L3SQCREG4 with default value we need to * set this bit here to retain the WA during flush. */ - if (IS_SKL_REVID(engine->dev, 0, SKL_REVID_E0)) + if (IS_SKL_REVID(dev_priv, 0, SKL_REVID_E0) || + IS_KBL_REVID(dev_priv, 0, KBL_REVID_E0)) l3sqc4_flush |= GEN8_LQSC_RO_PERF_DIS; wa_ctx_emit(batch, index, (MI_STORE_REGISTER_MEM_GEN8 | diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index bdb3304..421e03d 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -1207,6 +1207,19 @@ static int kbl_init_workarounds(struct intel_engine_cs *engine) WA_SET_BIT_MASKED(HDC_CHICKEN0, HDC_FENCE_DEST_SLM_DISABLE); + /* GEN8_L3SQCREG4 has a dependency with WA batch so any new changes + * involving this register should also be added to WA batch as required. + */ + if (IS_KBL_REVID(dev_priv, 0, KBL_REVID_E0)) + /* WaDisableLSQCROPERFforOCL:kbl */ + I915_WRITE(GEN8_L3SQCREG4, I915_READ(GEN8_L3SQCREG4) | + GEN8_LQSC_RO_PERF_DIS); + + /* WaDisableLSQCROPERFforOCL:kbl */ + ret = wa_ring_whitelist_reg(engine, GEN8_L3SQCREG4); + if (ret) + return ret; + return 0; } -- cgit v0.10.2 From 11b283412e165abf1ad19c1ba4bdde399944b600 Mon Sep 17 00:00:00 2001 From: Mika Kuoppala Date: Tue, 7 Jun 2016 17:19:04 +0300 Subject: drm/i915/gen9: Enable must set chicken bits in config0 reg The bspec states that these must be set in CONFIG0 for all gen9. v2: rebase v3: fix spacing (Matthew) References: HSD#2134995 Signed-off-by: Mika Kuoppala Reviewed-by: Matthew Auld Link: http://patchwork.freedesktop.org/patch/msgid/1465309159-30531-13-git-send-email-mika.kuoppala@intel.com (cherry picked from commit b033bb6d5d3a0e51d56b3ba929a8db4e18da0892) Signed-off-by: Mika Kuoppala diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 80ede80..d014b8f 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -220,6 +220,9 @@ static inline bool i915_mmio_reg_valid(i915_reg_t reg) #define ECOCHK_PPGTT_WT_HSW (0x2<<3) #define ECOCHK_PPGTT_WB_HSW (0x3<<3) +#define GEN8_CONFIG0 _MMIO(0xD00) +#define GEN9_DEFAULT_FIXES (1 << 3 | 1 << 2 | 1 << 1) + #define GAC_ECO_BITS _MMIO(0x14090) #define ECOBITS_SNB_BIT (1<<13) #define ECOBITS_PPGTT_CACHE64B (3<<8) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index bff740c..7ae5bfd 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -54,14 +54,24 @@ #define INTEL_RC6p_ENABLE (1<<1) #define INTEL_RC6pp_ENABLE (1<<2) -static void bxt_init_clock_gating(struct drm_device *dev) +static void gen9_init_clock_gating(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; - /* See Bspec note for PSR2_CTL bit 31, Wa#828:bxt */ + /* See Bspec note for PSR2_CTL bit 31, Wa#828:skl,bxt,kbl */ I915_WRITE(CHICKEN_PAR1_1, I915_READ(CHICKEN_PAR1_1) | SKL_EDP_PSR_FIX_RDWRAP); + I915_WRITE(GEN8_CONFIG0, + I915_READ(GEN8_CONFIG0) | GEN9_DEFAULT_FIXES); +} + +static void bxt_init_clock_gating(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + gen9_init_clock_gating(dev); + /* WaDisableSDEUnitClockGating:bxt */ I915_WRITE(GEN8_UCGCTL6, I915_READ(GEN8_UCGCTL6) | GEN8_SDEUNIT_CLOCK_GATE_DISABLE); @@ -6706,9 +6716,7 @@ static void kabylake_init_clock_gating(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; - /* See Bspec note for PSR2_CTL bit 31, Wa#828:kbl */ - I915_WRITE(CHICKEN_PAR1_1, - I915_READ(CHICKEN_PAR1_1) | SKL_EDP_PSR_FIX_RDWRAP); + gen9_init_clock_gating(dev); /* WaDisableSDEUnitClockGating:kbl */ if (IS_KBL_REVID(dev_priv, 0, KBL_REVID_B0)) @@ -6718,11 +6726,7 @@ static void kabylake_init_clock_gating(struct drm_device *dev) static void skylake_init_clock_gating(struct drm_device *dev) { - struct drm_i915_private *dev_priv = dev->dev_private; - - /* See Bspec note for PSR2_CTL bit 31, Wa#828:skl */ - I915_WRITE(CHICKEN_PAR1_1, - I915_READ(CHICKEN_PAR1_1) | SKL_EDP_PSR_FIX_RDWRAP); + gen9_init_clock_gating(dev); } static void broadwell_init_clock_gating(struct drm_device *dev) -- cgit v0.10.2 From 4ac4199434ac1d847e02c61a6e9d1cb35bb91b0e Mon Sep 17 00:00:00 2001 From: Mika Kuoppala Date: Tue, 7 Jun 2016 17:19:05 +0300 Subject: drm/i915/kbl: Add WaDisableGamClockGating According to bspec we need to disable gam unit clock gating on on kbl revids A0 and B0. References: HSD#2226858, HSD#1944358 Signed-off-by: Mika Kuoppala Reviewed-by: Matthew Auld Link: http://patchwork.freedesktop.org/patch/msgid/1465309159-30531-14-git-send-email-mika.kuoppala@intel.com (cherry picked from commit 8aeb7f624fbf8a68a9c67f831d4158a0f80ea920) Signed-off-by: Mika Kuoppala diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index d014b8f..3e16b9d 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -6926,6 +6926,7 @@ enum skl_disp_power_wells { #define EDRAM_SETS_IDX(cap) (((cap) >> 8) & 0x3) #define GEN6_UCGCTL1 _MMIO(0x9400) +# define GEN6_GAMUNIT_CLOCK_GATE_DISABLE (1 << 22) # define GEN6_EU_TCUNIT_CLOCK_GATE_DISABLE (1 << 16) # define GEN6_BLBUNIT_CLOCK_GATE_DISABLE (1 << 5) # define GEN6_CSUNIT_CLOCK_GATE_DISABLE (1 << 7) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 7ae5bfd..3f0f188 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -6722,6 +6722,11 @@ static void kabylake_init_clock_gating(struct drm_device *dev) if (IS_KBL_REVID(dev_priv, 0, KBL_REVID_B0)) I915_WRITE(GEN8_UCGCTL6, I915_READ(GEN8_UCGCTL6) | GEN8_SDEUNIT_CLOCK_GATE_DISABLE); + + /* WaDisableGamClockGating:kbl */ + if (IS_KBL_REVID(dev_priv, 0, KBL_REVID_B0)) + I915_WRITE(GEN6_UCGCTL1, I915_READ(GEN6_UCGCTL1) | + GEN6_GAMUNIT_CLOCK_GATE_DISABLE); } static void skylake_init_clock_gating(struct drm_device *dev) -- cgit v0.10.2 From b90420467232529a4448364d8bd860fc0176d3b6 Mon Sep 17 00:00:00 2001 From: Mika Kuoppala Date: Tue, 7 Jun 2016 17:19:06 +0300 Subject: drm/i915/kbl: Add WaDisableDynamicCreditSharing Bspec states that we need to turn off dynamic credit sharing on kbl revid a0 and b0. This happens by writing bit 28 on 0x4ab8. References: HSD#2225601, HSD#2226938, HSD#2225763 Signed-off-by: Mika Kuoppala Reviewed-by: Matthew Auld Link: http://patchwork.freedesktop.org/patch/msgid/1465309159-30531-15-git-send-email-mika.kuoppala@intel.com (cherry picked from commit c0b730d572ea00d427f6112b17982c6b9d5e97bb) Signed-off-by: Mika Kuoppala diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 3e16b9d..b7cfb38 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -1672,6 +1672,9 @@ enum skl_disp_power_wells { #define GEN7_TLB_RD_ADDR _MMIO(0x4700) +#define GAMT_CHKN_BIT_REG _MMIO(0x4ab8) +#define GAMT_CHKN_DISABLE_DYNAMIC_CREDIT_SHARING (1<<28) + #if 0 #define PRB0_TAIL _MMIO(0x2030) #define PRB0_HEAD _MMIO(0x2034) diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 421e03d..8106a70 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -1202,6 +1202,11 @@ static int kbl_init_workarounds(struct intel_engine_cs *engine) I915_WRITE(GEN8_GARBCNTL, (I915_READ(GEN8_GARBCNTL) | GEN9_GAPS_TSV_CREDIT_DISABLE)); + /* WaDisableDynamicCreditSharing:kbl */ + if (IS_KBL_REVID(dev_priv, 0, KBL_REVID_B0)) + WA_SET_BIT(GAMT_CHKN_BIT_REG, + GAMT_CHKN_DISABLE_DYNAMIC_CREDIT_SHARING); + /* WaDisableFenceDestinationToSLM:kbl (pre-prod) */ if (IS_KBL_REVID(dev_priv, KBL_REVID_A0, KBL_REVID_A0)) WA_SET_BIT_MASKED(HDC_CHICKEN0, -- cgit v0.10.2 From 7b9005cd45f34f5c87fd2e28f4e56b348af4ddc5 Mon Sep 17 00:00:00 2001 From: Mika Kuoppala Date: Tue, 7 Jun 2016 17:19:07 +0300 Subject: drm/i915: Add WaInsertDummyPushConstP for bxt and kbl Add this workaround for both bxt and kbl up to until rev B0. References: HSD#2136703 Signed-off-by: Mika Kuoppala Reviewed-by: Matthew Auld Link: http://patchwork.freedesktop.org/patch/msgid/1465309159-30531-16-git-send-email-mika.kuoppala@intel.com (cherry picked from commit ad2bdb44b19529ba992bd0b7667e91b14fe9a9ee) Signed-off-by: Mika Kuoppala diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index b7cfb38..349470d 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -6084,6 +6084,7 @@ enum skl_disp_power_wells { # define GEN7_CSC1_RHWO_OPT_DISABLE_IN_RCC ((1<<10) | (1<<26)) # define GEN9_RHWO_OPTIMIZATION_DISABLE (1<<14) #define COMMON_SLICE_CHICKEN2 _MMIO(0x7014) +# define GEN8_SBE_DISABLE_REPLAY_BUF_OPTIMIZATION (1<<8) # define GEN8_CSC2_SBE_VUE_CACHE_CONSERVATIVE (1<<0) #define HIZ_CHICKEN _MMIO(0x7018) diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 8106a70..da9d243 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -1186,6 +1186,11 @@ static int bxt_init_workarounds(struct intel_engine_cs *engine) return ret; } + /* WaInsertDummyPushConstPs:bxt */ + if (IS_BXT_REVID(dev_priv, 0, BXT_REVID_B0)) + WA_SET_BIT_MASKED(COMMON_SLICE_CHICKEN2, + GEN8_SBE_DISABLE_REPLAY_BUF_OPTIMIZATION); + return 0; } @@ -1220,6 +1225,11 @@ static int kbl_init_workarounds(struct intel_engine_cs *engine) I915_WRITE(GEN8_L3SQCREG4, I915_READ(GEN8_L3SQCREG4) | GEN8_LQSC_RO_PERF_DIS); + /* WaInsertDummyPushConstPs:kbl */ + if (IS_KBL_REVID(dev_priv, 0, KBL_REVID_B0)) + WA_SET_BIT_MASKED(COMMON_SLICE_CHICKEN2, + GEN8_SBE_DISABLE_REPLAY_BUF_OPTIMIZATION); + /* WaDisableLSQCROPERFforOCL:kbl */ ret = wa_ring_whitelist_reg(engine, GEN8_L3SQCREG4); if (ret) -- cgit v0.10.2 From a725e1dc4e16a34e3de79b0a6db2ef608fecae4c Mon Sep 17 00:00:00 2001 From: Mika Kuoppala Date: Tue, 7 Jun 2016 17:19:10 +0300 Subject: drm/i915/kbl: Add WaForGAMHang Add this workaround for A0 and B0 revisions References: HSD#2226935 Signed-off-by: Mika Kuoppala Reviewed-by: Matthew Auld Link: http://patchwork.freedesktop.org/patch/msgid/1465309159-30531-19-git-send-email-mika.kuoppala@intel.com (cherry picked from commit 0b2d0934edceff9905b1202d0e7e91f1b6228485) Signed-off-by: Mika Kuoppala diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index cf18eac..3138d2f 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -1689,9 +1689,10 @@ static int gen8_emit_flush_render(struct drm_i915_gem_request *request, struct intel_ringbuffer *ringbuf = request->ringbuf; struct intel_engine_cs *engine = ringbuf->engine; u32 scratch_addr = engine->scratch.gtt_offset + 2 * CACHELINE_BYTES; - bool vf_flush_wa = false; + bool vf_flush_wa = false, dc_flush_wa = false; u32 flags = 0; int ret; + int len; flags |= PIPE_CONTROL_CS_STALL; @@ -1718,9 +1719,21 @@ static int gen8_emit_flush_render(struct drm_i915_gem_request *request, */ if (IS_GEN9(engine->dev)) vf_flush_wa = true; + + /* WaForGAMHang:kbl */ + if (IS_KBL_REVID(request->i915, 0, KBL_REVID_B0)) + dc_flush_wa = true; } - ret = intel_ring_begin(request, vf_flush_wa ? 12 : 6); + len = 6; + + if (vf_flush_wa) + len += 6; + + if (dc_flush_wa) + len += 12; + + ret = intel_ring_begin(request, len); if (ret) return ret; @@ -1733,12 +1746,31 @@ static int gen8_emit_flush_render(struct drm_i915_gem_request *request, intel_logical_ring_emit(ringbuf, 0); } + if (dc_flush_wa) { + intel_logical_ring_emit(ringbuf, GFX_OP_PIPE_CONTROL(6)); + intel_logical_ring_emit(ringbuf, PIPE_CONTROL_DC_FLUSH_ENABLE); + intel_logical_ring_emit(ringbuf, 0); + intel_logical_ring_emit(ringbuf, 0); + intel_logical_ring_emit(ringbuf, 0); + intel_logical_ring_emit(ringbuf, 0); + } + intel_logical_ring_emit(ringbuf, GFX_OP_PIPE_CONTROL(6)); intel_logical_ring_emit(ringbuf, flags); intel_logical_ring_emit(ringbuf, scratch_addr); intel_logical_ring_emit(ringbuf, 0); intel_logical_ring_emit(ringbuf, 0); intel_logical_ring_emit(ringbuf, 0); + + if (dc_flush_wa) { + intel_logical_ring_emit(ringbuf, GFX_OP_PIPE_CONTROL(6)); + intel_logical_ring_emit(ringbuf, PIPE_CONTROL_CS_STALL); + intel_logical_ring_emit(ringbuf, 0); + intel_logical_ring_emit(ringbuf, 0); + intel_logical_ring_emit(ringbuf, 0); + intel_logical_ring_emit(ringbuf, 0); + } + intel_logical_ring_advance(ringbuf); return 0; -- cgit v0.10.2 From 3af5f1137c8b5981c754e47d2c233bc3013d2d00 Mon Sep 17 00:00:00 2001 From: Mika Kuoppala Date: Tue, 7 Jun 2016 17:19:11 +0300 Subject: drm/i915/kbl: Add WaDisableGafsUnitClkGating MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We need to disable clock gating in this unit to work around hardware issue causing possible corruption/hang. v2: name the bit (Ville) v3: leave the fix enabled for 2227050 and set correct bit (Matthew) v4: Split out the skl part in separate commit for easier backport References: HSD#2227156, HSD#2227050 Cc: Ville Syrjälä Cc: Matthew Auld Signed-off-by: Mika Kuoppala Reviewed-by: Matthew Auld Link: http://patchwork.freedesktop.org/patch/msgid/1465309159-30531-20-git-send-email-mika.kuoppala@intel.com (cherry picked from commit 4de5d7ccbccc88d2f7b1bcdc2180196ded7db8b8) Signed-off-by: Mika Kuoppala diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index da9d243..a88ac27 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -1230,6 +1230,9 @@ static int kbl_init_workarounds(struct intel_engine_cs *engine) WA_SET_BIT_MASKED(COMMON_SLICE_CHICKEN2, GEN8_SBE_DISABLE_REPLAY_BUF_OPTIMIZATION); + /* WaDisableGafsUnitClkGating:kbl */ + WA_SET_BIT(GEN7_UCGCTL4, GEN8_EU_GAUNIT_CLOCK_GATE_DISABLE); + /* WaDisableLSQCROPERFforOCL:kbl */ ret = wa_ring_whitelist_reg(engine, GEN8_L3SQCREG4); if (ret) -- cgit v0.10.2 From 0a3e3f047b13c04cd69bdb5a242330566259fa48 Mon Sep 17 00:00:00 2001 From: Mika Kuoppala Date: Tue, 7 Jun 2016 17:19:12 +0300 Subject: drm/i915/kbl: Add WaDisableSbeCacheDispatchPortSharing This is needed for all kbl revision. v2: Don't add revid checks to generic gen9 init (Arun) References: HSD#2135593 Signed-off-by: Mika Kuoppala Reviewed-by: Matthew Auld Link: http://patchwork.freedesktop.org/patch/msgid/1465309159-30531-21-git-send-email-mika.kuoppala@intel.com (cherry picked from commit 954337aa96a31f6d4baf1e40ac219fbb1b1d92f4) Signed-off-by: Mika Kuoppala diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index a88ac27..279614c 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -1233,6 +1233,11 @@ static int kbl_init_workarounds(struct intel_engine_cs *engine) /* WaDisableGafsUnitClkGating:kbl */ WA_SET_BIT(GEN7_UCGCTL4, GEN8_EU_GAUNIT_CLOCK_GATE_DISABLE); + /* WaDisableSbeCacheDispatchPortSharing:kbl */ + WA_SET_BIT_MASKED( + GEN7_HALF_SLICE_CHICKEN1, + GEN7_SBE_SS_CACHE_DISPATCH_PORT_SHARING_DISABLE); + /* WaDisableLSQCROPERFforOCL:kbl */ ret = wa_ring_whitelist_reg(engine, GEN8_L3SQCREG4); if (ret) -- cgit v0.10.2 From 0e51c0bdc0e6503c9c1cf2c41b2f1ae4e9cf9a8b Mon Sep 17 00:00:00 2001 From: Mika Kuoppala Date: Tue, 7 Jun 2016 17:19:13 +0300 Subject: drm/i915/gen9: Add WaEnableChickenDCPR Workaround for display underrun issues with Y & Yf Tiling. Set this on all gen9 as stated by bspec. v2: proper workaround name References: HSD#2136383, BSID#857 Signed-off-by: Mika Kuoppala Reviewed-by: Matthew Auld Link: http://patchwork.freedesktop.org/patch/msgid/1465309159-30531-22-git-send-email-mika.kuoppala@intel.com (cherry picked from commit 590e8ff04bc0182dce97228e5e352d6413d80456) Signed-off-by: Mika Kuoppala diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 349470d..87655ac 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -6059,6 +6059,9 @@ enum skl_disp_power_wells { #define HSW_NDE_RSTWRN_OPT _MMIO(0x46408) #define RESET_PCH_HANDSHAKE_ENABLE (1<<4) +#define GEN8_CHICKEN_DCPR_1 _MMIO(0x46430) +#define MASK_WAKEMEM (1<<13) + #define SKL_DFSM _MMIO(0x51000) #define SKL_DFSM_CDCLK_LIMIT_MASK (3 << 23) #define SKL_DFSM_CDCLK_LIMIT_675 (0 << 23) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 3f0f188..362800b 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -64,6 +64,10 @@ static void gen9_init_clock_gating(struct drm_device *dev) I915_WRITE(GEN8_CONFIG0, I915_READ(GEN8_CONFIG0) | GEN9_DEFAULT_FIXES); + + /* WaEnableChickenDCPR:skl,bxt,kbl */ + I915_WRITE(GEN8_CHICKEN_DCPR_1, + I915_READ(GEN8_CHICKEN_DCPR_1) | MASK_WAKEMEM); } static void bxt_init_clock_gating(struct drm_device *dev) -- cgit v0.10.2 From 703d1282d513617d9561760309e9acd902c723a7 Mon Sep 17 00:00:00 2001 From: Mika Kuoppala Date: Tue, 7 Jun 2016 17:19:15 +0300 Subject: drm/i915/kbl: Add WaClearSlmSpaceAtContextSwitch This workaround for bdw and chv, is also needed for kbl A0. References: HSD#1911519, BSID#569 Signed-off-by: Mika Kuoppala Reviewed-by: Matthew Auld Link: http://patchwork.freedesktop.org/patch/msgid/1465309159-30531-24-git-send-email-mika.kuoppala@intel.com (cherry picked from commit 066d462888514af727008a450f4078b1a23d5cbe) Signed-off-by: Mika Kuoppala diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 3138d2f..7f2d841 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -1275,6 +1275,7 @@ static int gen9_init_indirectctx_bb(struct intel_engine_cs *engine, { int ret; struct drm_device *dev = engine->dev; + struct drm_i915_private *dev_priv = dev->dev_private; uint32_t index = wa_ctx_start(wa_ctx, *offset, CACHELINE_DWORDS); /* WaDisableCtxRestoreArbitration:skl,bxt */ @@ -1288,6 +1289,22 @@ static int gen9_init_indirectctx_bb(struct intel_engine_cs *engine, return ret; index = ret; + /* WaClearSlmSpaceAtContextSwitch:kbl */ + /* Actual scratch location is at 128 bytes offset */ + if (IS_KBL_REVID(dev_priv, 0, KBL_REVID_A0)) { + uint32_t scratch_addr + = engine->scratch.gtt_offset + 2*CACHELINE_BYTES; + + wa_ctx_emit(batch, index, GFX_OP_PIPE_CONTROL(6)); + wa_ctx_emit(batch, index, (PIPE_CONTROL_FLUSH_L3 | + PIPE_CONTROL_GLOBAL_GTT_IVB | + PIPE_CONTROL_CS_STALL | + PIPE_CONTROL_QW_WRITE)); + wa_ctx_emit(batch, index, scratch_addr); + wa_ctx_emit(batch, index, 0); + wa_ctx_emit(batch, index, 0); + wa_ctx_emit(batch, index, 0); + } /* Pad to end of cacheline */ while (index % CACHELINE_DWORDS) wa_ctx_emit(batch, index, MI_NOOP); -- cgit v0.10.2 From f20b1ba04e917be9cadd3171a99568a1badb8b1b Mon Sep 17 00:00:00 2001 From: Mika Kuoppala Date: Tue, 7 Jun 2016 17:19:16 +0300 Subject: drm/i915/gen9: Add WaFbcTurnOffFbcWatermark MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit According to bspec this prevents screen corruption when fbc is used. v2: This workaround has a name, use it (Ville) v3: remove bogus gen check on ilk/vlv wm path (Ville) References: HSD#2135555, HSD#2137270, BSID#562 Cc: Paulo Zanoni Cc: Ville Syrjälä Signed-off-by: Mika Kuoppala Reviewed-by: Ville Syrjälä Link: http://patchwork.freedesktop.org/patch/msgid/1465309159-30531-25-git-send-email-mika.kuoppala@intel.com (cherry picked from commit 0f78dee6f06a9399d4bdf79575094cc761b872ac) Signed-off-by: Mika Kuoppala diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 362800b..5eb48ad 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -68,6 +68,10 @@ static void gen9_init_clock_gating(struct drm_device *dev) /* WaEnableChickenDCPR:skl,bxt,kbl */ I915_WRITE(GEN8_CHICKEN_DCPR_1, I915_READ(GEN8_CHICKEN_DCPR_1) | MASK_WAKEMEM); + + /* WaFbcTurnOffFbcWatermark:skl,bxt,kbl */ + I915_WRITE(DISP_ARB_CTL, + I915_READ(DISP_ARB_CTL) | DISP_FBC_WM_DIS); } static void bxt_init_clock_gating(struct drm_device *dev) -- cgit v0.10.2 From 5b889896be07cb12f0401dc2cfdec6eb6413c774 Mon Sep 17 00:00:00 2001 From: Mika Kuoppala Date: Tue, 7 Jun 2016 17:19:17 +0300 Subject: drm/i915/gen9: Add WaFbcWakeMemOn MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Set bit 8 in 0x43224 to prevent screen corruption and system hangs on high memory bandwidth conditions. The same wa also suggest setting bit 31 on ARB_CTL. According to another workaround we gain better idle power savings when FBC is enabled. v2: use correct workaround name v3: split out overlapping wa for corruption avoidance (Ville) References: HSD#2137218, HSD#2227171, HSD#2136579, BSID#883 Cc: Paulo Zanoni Cc: Ville Syrjälä Signed-off-by: Mika Kuoppala Reviewed-by: Ville Syrjälä Link: http://patchwork.freedesktop.org/patch/msgid/1465309159-30531-26-git-send-email-mika.kuoppala@intel.com (cherry picked from commit 303d4ea522e8672a1b62d968a5b6764929adc292) Signed-off-by: Mika Kuoppala diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 87655ac..235dfac 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -6046,6 +6046,7 @@ enum skl_disp_power_wells { #define CHICKEN_PIPESL_1(pipe) _MMIO_PIPE(pipe, _CHICKEN_PIPESL_1_A, _CHICKEN_PIPESL_1_B) #define DISP_ARB_CTL _MMIO(0x45000) +#define DISP_FBC_MEMORY_WAKE (1<<31) #define DISP_TILE_SURFACE_SWIZZLING (1<<13) #define DISP_FBC_WM_DIS (1<<15) #define DISP_ARB_CTL2 _MMIO(0x45004) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 5eb48ad..61113a2 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -70,8 +70,10 @@ static void gen9_init_clock_gating(struct drm_device *dev) I915_READ(GEN8_CHICKEN_DCPR_1) | MASK_WAKEMEM); /* WaFbcTurnOffFbcWatermark:skl,bxt,kbl */ - I915_WRITE(DISP_ARB_CTL, - I915_READ(DISP_ARB_CTL) | DISP_FBC_WM_DIS); + /* WaFbcWakeMemOn:skl,bxt,kbl */ + I915_WRITE(DISP_ARB_CTL, I915_READ(DISP_ARB_CTL) | + DISP_FBC_WM_DIS | + DISP_FBC_MEMORY_WAKE); } static void bxt_init_clock_gating(struct drm_device *dev) -- cgit v0.10.2 From c584e2d38fb84513944feeb25072dd8b17a6d3b6 Mon Sep 17 00:00:00 2001 From: Mika Kuoppala Date: Tue, 7 Jun 2016 17:19:18 +0300 Subject: drm/i195/fbc: Add WaFbcNukeOnHostModify MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bspec states that we need to set nuke on modify all to prevent screen corruption with fbc on skl and kbl. v2: proper workaround name References: HSD#2227109, HSDES#1404569388 Cc: Ville Syrjälä Signed-off-by: Mika Kuoppala Reviewed-by: Ville Syrjälä Link: http://patchwork.freedesktop.org/patch/msgid/1465309159-30531-27-git-send-email-mika.kuoppala@intel.com (cherry picked from commit 031cd8c85aefad31e7af91eba7bc4735a6dfcc79) Signed-off-by: Mika Kuoppala diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 235dfac..3b37428 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -2206,6 +2206,7 @@ enum skl_disp_power_wells { #define ILK_DPFC_STATUS _MMIO(0x43210) #define ILK_DPFC_FENCE_YOFF _MMIO(0x43218) #define ILK_DPFC_CHICKEN _MMIO(0x43224) +#define ILK_DPFC_NUKE_ON_ANY_MODIFICATION (1<<23) #define ILK_FBC_RT_BASE _MMIO(0x2128) #define ILK_FBC_RT_VALID (1<<0) #define SNB_FBC_FRONT_BUFFER (1<<1) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 61113a2..074d6a5 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -6737,11 +6737,21 @@ static void kabylake_init_clock_gating(struct drm_device *dev) if (IS_KBL_REVID(dev_priv, 0, KBL_REVID_B0)) I915_WRITE(GEN6_UCGCTL1, I915_READ(GEN6_UCGCTL1) | GEN6_GAMUNIT_CLOCK_GATE_DISABLE); + + /* WaFbcNukeOnHostModify:kbl */ + I915_WRITE(ILK_DPFC_CHICKEN, I915_READ(ILK_DPFC_CHICKEN) | + ILK_DPFC_NUKE_ON_ANY_MODIFICATION); } static void skylake_init_clock_gating(struct drm_device *dev) { + struct drm_i915_private *dev_priv = dev->dev_private; + gen9_init_clock_gating(dev); + + /* WaFbcNukeOnHostModify:skl */ + I915_WRITE(ILK_DPFC_CHICKEN, I915_READ(ILK_DPFC_CHICKEN) | + ILK_DPFC_NUKE_ON_ANY_MODIFICATION); } static void broadwell_init_clock_gating(struct drm_device *dev) -- cgit v0.10.2 From a89bd7beb1791ad5ed634989b14c764114a68e53 Mon Sep 17 00:00:00 2001 From: Mika Kuoppala Date: Tue, 7 Jun 2016 17:19:19 +0300 Subject: drm/i915/gen9: Add WaFbcHighMemBwCorruptionAvoidance MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add this fbc related workaround for all gen9 Cc: Ville Syrjälä Signed-off-by: Mika Kuoppala Reviewed-by: Ville Syrjälä Link: http://patchwork.freedesktop.org/patch/msgid/1465309159-30531-28-git-send-email-mika.kuoppala@intel.com (cherry picked from commit d1b4eefdea6d63aa15321f539feec298d8aefdc1) Signed-off-by: Mika Kuoppala diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 3b37428..b2fbbfa 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -2206,6 +2206,7 @@ enum skl_disp_power_wells { #define ILK_DPFC_STATUS _MMIO(0x43210) #define ILK_DPFC_FENCE_YOFF _MMIO(0x43218) #define ILK_DPFC_CHICKEN _MMIO(0x43224) +#define ILK_DPFC_DISABLE_DUMMY0 (1<<8) #define ILK_DPFC_NUKE_ON_ANY_MODIFICATION (1<<23) #define ILK_FBC_RT_BASE _MMIO(0x2128) #define ILK_FBC_RT_VALID (1<<0) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 074d6a5..2863b92 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -74,6 +74,10 @@ static void gen9_init_clock_gating(struct drm_device *dev) I915_WRITE(DISP_ARB_CTL, I915_READ(DISP_ARB_CTL) | DISP_FBC_WM_DIS | DISP_FBC_MEMORY_WAKE); + + /* WaFbcHighMemBwCorruptionAvoidance:skl,bxt,kbl */ + I915_WRITE(ILK_DPFC_CHICKEN, I915_READ(ILK_DPFC_CHICKEN) | + ILK_DPFC_DISABLE_DUMMY0); } static void bxt_init_clock_gating(struct drm_device *dev) -- cgit v0.10.2 From 12be73a0f13ad5a044346d564804b4058426d4c2 Mon Sep 17 00:00:00 2001 From: Tim Gore Date: Mon, 13 Jun 2016 12:15:01 +0100 Subject: drm/i915/gen9: implement WaConextSwitchWithConcurrentTLBInvalidate This patch enables a workaround for a mid thread preemption issue where a hardware timing problem can prevent the context restore from happening, leading to a hang. v2: move to gen9_init_workarounds (Arun) v3: move to start of gen9_init_workarounds (Arun) Signed-off-by: Tim Gore Reviewed-by: Arun Siluvery Signed-off-by: Tvrtko Ursulin Link: http://patchwork.freedesktop.org/patch/msgid/1465816501-25557-1-git-send-email-tim.gore@intel.com (cherry picked from commit a8ab5ed5e1bf856eceaab5579236de6f92822b9f) Signed-off-by: Mika Kuoppala diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index b2fbbfa..3fcf7dd 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -1810,6 +1810,10 @@ enum skl_disp_power_wells { #define GEN9_IZ_HASHING_MASK(slice) (0x3 << ((slice) * 2)) #define GEN9_IZ_HASHING(slice, val) ((val) << ((slice) * 2)) +/* chicken reg for WaConextSwitchWithConcurrentTLBInvalidate */ +#define GEN9_CSFE_CHICKEN1_RCS _MMIO(0x20D4) +#define GEN9_PREEMPT_GPGPU_SYNC_SWITCH_DISABLE (1 << 2) + /* WaClearTdlStateAckDirtyBits */ #define GEN8_STATE_ACK _MMIO(0x20F0) #define GEN9_STATE_ACK_SLICE1 _MMIO(0x20F8) diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 279614c..68c5af0 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -915,6 +915,9 @@ static int gen9_init_workarounds(struct intel_engine_cs *engine) struct drm_i915_private *dev_priv = dev->dev_private; int ret; + /* WaConextSwitchWithConcurrentTLBInvalidate:skl,bxt,kbl */ + I915_WRITE(GEN9_CSFE_CHICKEN1_RCS, _MASKED_BIT_ENABLE(GEN9_PREEMPT_GPGPU_SYNC_SWITCH_DISABLE)); + /* WaEnableLbsSlaRetryTimerDecrement:skl,bxt,kbl */ I915_WRITE(BDW_SCRATCH1, I915_READ(BDW_SCRATCH1) | GEN9_LBS_SLA_RETRY_TIMER_DECREMENT_ENABLE); -- cgit v0.10.2 From bc7135b9a430520448590ffeb1ff54c0b4dfd8d5 Mon Sep 17 00:00:00 2001 From: Rodrigo Vivi Date: Fri, 1 Jul 2016 17:07:12 -0700 Subject: drm/i915: Introduce Kabypoint PCH for Kabylake H/DT. Some Kabylake SKUs are going to use Kabypoint PCH. It is mainly for Halo and DT ones. >From our specs it doesn't seem that KBP brings any change on the display south engine. So let's consider this as a continuation of SunrisePoint, i.e., SPT+. Since it is easy to get confused by a letter change: KBL = Kabylake - CPU/GPU codename. KBP = Kabypoint - PCH codename. Signed-off-by: Rodrigo Vivi Reviewed-by: Ander Conselvan de Oliveira Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=96826 Link: http://patchwork.freedesktop.org/patch/msgid/1467418032-15167-1-git-send-email-rodrigo.vivi@intel.com Signed-off-by: Rodrigo Vivi (cherry picked from commit 22dea0be50b2eb0bafd3c82e1fb080113e0c889e) Signed-off-by: Mika Kuoppala diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index f313b4d..85c4deb 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -512,6 +512,10 @@ void intel_detect_pch(struct drm_device *dev) DRM_DEBUG_KMS("Found SunrisePoint LP PCH\n"); WARN_ON(!IS_SKYLAKE(dev) && !IS_KABYLAKE(dev)); + } else if (id == INTEL_PCH_KBP_DEVICE_ID_TYPE) { + dev_priv->pch_type = PCH_KBP; + DRM_DEBUG_KMS("Found KabyPoint PCH\n"); + WARN_ON(!IS_KABYLAKE(dev)); } else if ((id == INTEL_PCH_P2X_DEVICE_ID_TYPE) || (id == INTEL_PCH_P3X_DEVICE_ID_TYPE) || ((id == INTEL_PCH_QEMU_DEVICE_ID_TYPE) && diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index b0fffa0..bc3f2e6 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -990,6 +990,7 @@ enum intel_pch { PCH_CPT, /* Cougarpoint PCH */ PCH_LPT, /* Lynxpoint PCH */ PCH_SPT, /* Sunrisepoint PCH */ + PCH_KBP, /* Kabypoint PCH */ PCH_NOP, }; @@ -2717,11 +2718,13 @@ struct drm_i915_cmd_table { #define INTEL_PCH_LPT_LP_DEVICE_ID_TYPE 0x9c00 #define INTEL_PCH_SPT_DEVICE_ID_TYPE 0xA100 #define INTEL_PCH_SPT_LP_DEVICE_ID_TYPE 0x9D00 +#define INTEL_PCH_KBP_DEVICE_ID_TYPE 0xA200 #define INTEL_PCH_P2X_DEVICE_ID_TYPE 0x7100 #define INTEL_PCH_P3X_DEVICE_ID_TYPE 0x7000 #define INTEL_PCH_QEMU_DEVICE_ID_TYPE 0x2900 /* qemu q35 has 2918 */ #define INTEL_PCH_TYPE(dev) (__I915__(dev)->pch_type) +#define HAS_PCH_KBP(dev) (INTEL_PCH_TYPE(dev) == PCH_KBP) #define HAS_PCH_SPT(dev) (INTEL_PCH_TYPE(dev) == PCH_SPT) #define HAS_PCH_LPT(dev) (INTEL_PCH_TYPE(dev) == PCH_LPT) #define HAS_PCH_LPT_LP(dev) (__I915__(dev)->pch_id == INTEL_PCH_LPT_LP_DEVICE_ID_TYPE) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 2f6fd33..aab47f7 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -2471,7 +2471,7 @@ gen8_de_irq_handler(struct drm_i915_private *dev_priv, u32 master_ctl) I915_WRITE(SDEIIR, iir); ret = IRQ_HANDLED; - if (HAS_PCH_SPT(dev_priv)) + if (HAS_PCH_SPT(dev_priv) || HAS_PCH_KBP(dev_priv)) spt_irq_handler(dev, iir); else cpt_irq_handler(dev, iir); @@ -4661,7 +4661,7 @@ void intel_irq_init(struct drm_i915_private *dev_priv) dev->driver->disable_vblank = gen8_disable_vblank; if (IS_BROXTON(dev)) dev_priv->display.hpd_irq_setup = bxt_hpd_irq_setup; - else if (HAS_PCH_SPT(dev)) + else if (HAS_PCH_SPT(dev) || HAS_PCH_KBP(dev)) dev_priv->display.hpd_irq_setup = spt_hpd_irq_setup; else dev_priv->display.hpd_irq_setup = ilk_hpd_irq_setup; diff --git a/drivers/gpu/drm/i915/intel_panel.c b/drivers/gpu/drm/i915/intel_panel.c index 8357d57..aba9409 100644 --- a/drivers/gpu/drm/i915/intel_panel.c +++ b/drivers/gpu/drm/i915/intel_panel.c @@ -1731,7 +1731,8 @@ intel_panel_init_backlight_funcs(struct intel_panel *panel) panel->backlight.set = bxt_set_backlight; panel->backlight.get = bxt_get_backlight; panel->backlight.hz_to_pwm = bxt_hz_to_pwm; - } else if (HAS_PCH_LPT(dev_priv) || HAS_PCH_SPT(dev_priv)) { + } else if (HAS_PCH_LPT(dev_priv) || HAS_PCH_SPT(dev_priv) || + HAS_PCH_KBP(dev_priv)) { panel->backlight.setup = lpt_setup_backlight; panel->backlight.enable = lpt_enable_backlight; panel->backlight.disable = lpt_disable_backlight; -- cgit v0.10.2 From 8811e8ea14c1056b09c794c67836b8a84584ddef Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 15 Jul 2016 10:05:19 -0300 Subject: perf tools: Just pr_debug() about not being able to read cacheline_size So far the cacheline_size is only useful for the "dcacheline" --sort order, i.e. if that is not used, which is the norm, then the user shouldn't care that he is running this, say, on an Android system where sysconf(_SC_LEVEL1_DCACHE_LINESIZE) and the /sys/devices/system/cpu/cpu0/cache/index0/coherency_line_size sysfs file isn't available. An upcoming patch will emit an warning only for "--sort ...,dcacheline,...". Cc: Adrian Hunter Cc: Chris Phlipot Cc: David Ahern Cc: Jiri Olsa Cc: Namhyung Kim Cc: Wang Nan Link: http://lkml.kernel.org/n/tip-580cnkvftunyvt9n7unsholi@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/perf.c b/tools/perf/perf.c index 4b2ff02..64c0696 100644 --- a/tools/perf/perf.c +++ b/tools/perf/perf.c @@ -503,7 +503,7 @@ void pthread__unblock_sigwinch(void) static void cache_line_size(int *cacheline_sizep) { if (sysfs__read_int("devices/system/cpu/cpu0/cache/index0/coherency_line_size", cacheline_sizep)) - perror("cannot determine cache line size"); + pr_debug("cannot determine cache line size"); } #endif -- cgit v0.10.2 From 0d203166de37ad50ea826f97570b3a2beea87c9d Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 15 Jul 2016 10:08:43 -0300 Subject: perf tools: Bail out at "--sort dcacheline" and cacheline_size not known There are cases where further work would be needed to overcome the fact that neither sysconf(_SC_LEVEL1_DCACHE_LINESIZE) nor /sys/devices/system/cpu/cpu0/cache/index0/coherency_line_size are available in some systems (Android, for instance), so bail out when such a situation takes place. Cc: Adrian Hunter Cc: David Ahern Cc: Jiri Olsa Cc: Namhyung Kim Cc: Wang Nan Link: http://lkml.kernel.org/n/tip-ho8d8g8mh0o2dri7ckcccafi@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c index 5854b46..947d21f 100644 --- a/tools/perf/util/sort.c +++ b/tools/perf/util/sort.c @@ -2381,6 +2381,9 @@ static int sort_dimension__add(struct perf_hpp_list *list, const char *tok, if (sort__mode != SORT_MODE__MEMORY) return -EINVAL; + if (sd->entry == &sort_mem_dcacheline && cacheline_size == 0) + return -EINVAL; + if (sd->entry == &sort_mem_daddr_sym) list->sym = 1; @@ -2424,7 +2427,10 @@ static int setup_sort_list(struct perf_hpp_list *list, char *str, if (*tok) { ret = sort_dimension__add(list, tok, evlist, level); if (ret == -EINVAL) { - error("Invalid --sort key: `%s'", tok); + if (!cacheline_size && !strncasecmp(tok, "dcacheline", strlen(tok))) + error("The \"dcacheline\" --sort key needs to know the cacheline size and it couldn't be determined on this system"); + else + error("Invalid --sort key: `%s'", tok); break; } else if (ret == -ESRCH) { error("Unknown --sort key: `%s'", tok); -- cgit v0.10.2 From db49120a32b347fb93aea3319305932657dd118c Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Fri, 15 Jul 2016 09:29:57 +0200 Subject: tools lib api fs: Use base 0 in filename__read_ull By using 0 for base, the strtoull() detects the base automatically (see 'man strtoull'). ATM we have just one user of this function, the cpu__get_max_freq function reading the "cpuinfo_max_freq" sysfs file. It should not get affected by this change. Committer note: This change seems motivated by this discussion: "[PATCH] [RFC V1]s390/perf: fix 'start' address of module's map" http://lkml.kernel.org/r/20160711120155.GA29929@krava I.e. this patches paves the way for filename__read_ull() to be used in a S/390 related fix. Signed-off-by: Jiri Olsa Cc: David Ahern Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Songshan Gong Link: http://lkml.kernel.org/r/1468567797-27564-4-git-send-email-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/lib/api/fs/fs.c b/tools/lib/api/fs/fs.c index 08556cf..ba7094b 100644 --- a/tools/lib/api/fs/fs.c +++ b/tools/lib/api/fs/fs.c @@ -283,6 +283,11 @@ int filename__read_int(const char *filename, int *value) return err; } +/* + * Parses @value out of @filename with strtoull. + * By using 0 for base, the strtoull detects the + * base automatically (see man strtoull). + */ int filename__read_ull(const char *filename, unsigned long long *value) { char line[64]; @@ -292,7 +297,7 @@ int filename__read_ull(const char *filename, unsigned long long *value) return -1; if (read(fd, line, sizeof(line)) > 0) { - *value = strtoull(line, NULL, 10); + *value = strtoull(line, NULL, 0); if (*value != ULLONG_MAX) err = 0; } -- cgit v0.10.2 From 32a951b4fd6bbe60ef5d65930b1712321e241b27 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 14 Jul 2016 08:34:33 +0000 Subject: perf evlist: Drop redundant evsel->overwrite indicator evsel->overwrite indicator means an event should be put into overwritable ring buffer. In current implementation, it equals to evsel->attr.write_backward. To reduce compliexity, remove evsel->overwrite, use evsel->attr.write_backward instead. In addition, in __perf_evsel__open(), if kernel doesn't support write_backward and user explicitly set it in evsel, don't fallback like other missing feature, since it is meaningless to fall back to a forward ring buffer in this case: we are unable to stably read from an forward overwritable ring buffer. Cc: He Kuang Cc: Jiri Olsa Cc: Masami Hiramatsu Cc: Namhyung Kim Cc: Nilay Vaish Cc: Wang Nan Cc: Zefan Li Cc: pi3orama@163.com Link: http://lkml.kernel.org/r/1468485287-33422-2-git-send-email-wangnan0@huawei.com Signed-off-by: Wang Nan Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/tests/backward-ring-buffer.c b/tools/perf/tests/backward-ring-buffer.c index f20ea4c..5cee387 100644 --- a/tools/perf/tests/backward-ring-buffer.c +++ b/tools/perf/tests/backward-ring-buffer.c @@ -101,6 +101,7 @@ int test__backward_ring_buffer(int subtest __maybe_unused) return TEST_FAIL; } + evlist->backward = true; err = perf_evlist__create_maps(evlist, &opts.target); if (err < 0) { pr_debug("Not enough memory to create thread/cpu maps\n"); diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index 862e69c..6803f5c 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c @@ -1003,7 +1003,7 @@ static bool perf_evlist__should_poll(struct perf_evlist *evlist __maybe_unused, struct perf_evsel *evsel) { - if (evsel->overwrite) + if (evsel->attr.write_backward) return false; return true; } @@ -1018,7 +1018,7 @@ static int perf_evlist__mmap_per_evsel(struct perf_evlist *evlist, int idx, evlist__for_each_entry(evlist, evsel) { int fd; - if (evsel->overwrite != (evlist->overwrite && evlist->backward)) + if (!!evsel->attr.write_backward != (evlist->overwrite && evlist->backward)) continue; if (evsel->system_wide && thread) diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index ba0f59f..9ac2f92 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c @@ -1377,6 +1377,9 @@ static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus, int pid = -1, err; enum { NO_CHANGE, SET_TO_MAX, INCREASED_MAX } set_rlimit = NO_CHANGE; + if (perf_missing_features.write_backward && evsel->attr.write_backward) + return -EINVAL; + if (evsel->system_wide) nthreads = 1; else @@ -1407,11 +1410,6 @@ fallback_missing_features: if (perf_missing_features.lbr_flags) evsel->attr.branch_sample_type &= ~(PERF_SAMPLE_BRANCH_NO_FLAGS | PERF_SAMPLE_BRANCH_NO_CYCLES); - if (perf_missing_features.write_backward) { - if (evsel->overwrite) - return -EINVAL; - evsel->attr.write_backward = false; - } retry_sample_id: if (perf_missing_features.sample_id_all) evsel->attr.sample_id_all = 0; @@ -1513,7 +1511,7 @@ try_fallback: */ if (!perf_missing_features.write_backward && evsel->attr.write_backward) { perf_missing_features.write_backward = true; - goto fallback_missing_features; + goto out_close; } else if (!perf_missing_features.clockid_wrong && evsel->attr.use_clockid) { perf_missing_features.clockid_wrong = true; goto fallback_missing_features; @@ -2422,7 +2420,7 @@ int perf_evsel__open_strerror(struct perf_evsel *evsel, struct target *target, "We found oprofile daemon running, please stop it and try again."); break; case EINVAL: - if (evsel->overwrite && perf_missing_features.write_backward) + if (evsel->attr.write_backward && perf_missing_features.write_backward) return scnprintf(msg, size, "Reading from overwrite event is not supported by this kernel."); if (perf_missing_features.clockid) return scnprintf(msg, size, "clockid feature not supported."); diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h index d73391e..e60cbfc 100644 --- a/tools/perf/util/evsel.h +++ b/tools/perf/util/evsel.h @@ -114,7 +114,6 @@ struct perf_evsel { bool tracking; bool per_pkg; bool precise_max; - bool overwrite; /* parse modifier helper */ int exclude_GH; int nr_members; -- cgit v0.10.2 From 6a5029e66404462a3322dba8e35615bd09332081 Mon Sep 17 00:00:00 2001 From: Peter Chen Date: Fri, 15 Jul 2016 09:32:54 -0700 Subject: Input: ts4800-ts - add missing of_node_put after calling of_parse_phandle of_node_put needs to be called when the device node which is got from of_parse_phandle has finished using. Signed-off-by: Peter Chen Signed-off-by: Dmitry Torokhov diff --git a/drivers/input/touchscreen/ts4800-ts.c b/drivers/input/touchscreen/ts4800-ts.c index 3c3dd78..fed73ee 100644 --- a/drivers/input/touchscreen/ts4800-ts.c +++ b/drivers/input/touchscreen/ts4800-ts.c @@ -118,6 +118,13 @@ static int ts4800_parse_dt(struct platform_device *pdev, return -ENODEV; } + ts->regmap = syscon_node_to_regmap(syscon_np); + of_node_put(syscon_np); + if (IS_ERR(ts->regmap)) { + dev_err(dev, "cannot get parent's regmap\n"); + return PTR_ERR(ts->regmap); + } + error = of_property_read_u32_index(np, "syscon", 1, ®); if (error < 0) { dev_err(dev, "no offset in syscon\n"); @@ -134,12 +141,6 @@ static int ts4800_parse_dt(struct platform_device *pdev, ts->bit = BIT(bit); - ts->regmap = syscon_node_to_regmap(syscon_np); - if (IS_ERR(ts->regmap)) { - dev_err(dev, "cannot get parent's regmap\n"); - return PTR_ERR(ts->regmap); - } - return 0; } -- cgit v0.10.2 From e81fcd43723d32e9c9dbb8e8d66f147b5b84256b Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Fri, 15 Jul 2016 12:38:18 -0300 Subject: tools: Simplify BITS_PER_LONG define Do it using (__CHAR_BIT__ * __SIZEOF_LONG__), simpler, works everywhere, reduces the complexity by ditching CONFIG_64BIT, that was being synthesized from yet another set of defines, which proved fragile, breaking the build on linux-next for no obvious reasons. Committer Note: Except on: gcc version 4.1.2 20080704 (Red Hat 4.1.2-55) Fallback to __WORDSIZE in that case... Reported-by: Stephen Rothwell Signed-off-by: Peter Zijlstra Tested-by: Arnaldo Carvalho de Melo Cc: Andy Lutomirski Cc: H. Peter Anvin Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/20160715072243.GP30154@twins.programming.kicks-ass.net Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/include/asm-generic/bitsperlong.h b/tools/include/asm-generic/bitsperlong.h index cfd661c..45eca51 100644 --- a/tools/include/asm-generic/bitsperlong.h +++ b/tools/include/asm-generic/bitsperlong.h @@ -3,31 +3,12 @@ #include -/* - * In the kernel, where this file comes from, we can rely on CONFIG_64BIT, - * here we have to make amends with what the various compilers provides us - * to figure out if we're on a 64-bit machine... - */ #ifdef __SIZEOF_LONG__ -# if __SIZEOF_LONG__ == 8 -# define CONFIG_64BIT -# endif +#define BITS_PER_LONG (__CHAR_BIT__ * __SIZEOF_LONG__) #else -# ifdef __WORDSIZE -# if __WORDSIZE == 64 -# define CONFIG_64BIT -# endif -# else -# error Failed to determine BITS_PER_LONG value -# endif +#define BITS_PER_LONG __WORDSIZE #endif -#ifdef CONFIG_64BIT -#define BITS_PER_LONG 64 -#else -#define BITS_PER_LONG 32 -#endif /* CONFIG_64BIT */ - #if BITS_PER_LONG != __BITS_PER_LONG #error Inconsistent word size. Check asm/bitsperlong.h #endif -- cgit v0.10.2 From 2b4383470675c85add72725cc08840d36b409276 Mon Sep 17 00:00:00 2001 From: Wang Nan Date: Thu, 14 Jul 2016 08:34:34 +0000 Subject: tools lib fd array: Allow associating a pointer cookie with each entry Add a 'ptr' field to fdarray->priv array. This feature will be used by following commits, which introduce muiltiple 'struct perf_mmap' arrays for different types of mapping. Because of this, during fdarray__filter(), a simple 'idx' is not enough. Add a pointer cookie that allows to directly associate a 'struct perf_mmap' pointer to an fdarray entry. Signed-off-by: Wang Nan Acked-by: Jiri Olsa Cc: Adrian Hunter Cc: David Ahern Cc: He Kuang Cc: Masami Hiramatsu Cc: Namhyung Kim Cc: Nilay Vaish Cc: Peter Zijlstra Cc: Zefan Li Cc: pi3orama@163.com Link: http://lkml.kernel.org/r/1468485287-33422-3-git-send-email-wangnan0@huawei.com Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/lib/api/fd/array.h b/tools/lib/api/fd/array.h index e87fd80..71287dd 100644 --- a/tools/lib/api/fd/array.h +++ b/tools/lib/api/fd/array.h @@ -22,6 +22,7 @@ struct fdarray { struct pollfd *entries; union { int idx; + void *ptr; } *priv; }; -- cgit v0.10.2 From 8db6d6b19e486eef3db41bbd74a1f4c2b82d7706 Mon Sep 17 00:00:00 2001 From: Wang Nan Date: Thu, 14 Jul 2016 08:34:35 +0000 Subject: perf evlist: Update mmap related APIs and helpers Currently, the evlist mmap related helpers and APIs accept evlist and idx, and dereference 'struct perf_mmap' by evlist->mmap[idx]. This is unnecessary, and force each evlist contains only one mmap array. Following commits are going to introduce multiple mmap arrays to a evlist. This patch refators these APIs and helpers, introduces functions accept perf_mmap pointer directly. New helpers and APIs are decoupled with perf_evlist, and become perf_mmap functions (so they have perf_mmap prefix). Old functions are reimplemented with new functions. Some of them will be removed in following commits. Signed-off-by: Wang Nan Acked-by: Jiri Olsa Cc: He Kuang Cc: Masami Hiramatsu Cc: Namhyung Kim Cc: Nilay Vaish Cc: Zefan Li Cc: pi3orama@163.com Link: http://lkml.kernel.org/r/1468485287-33422-4-git-send-email-wangnan0@huawei.com Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index 6803f5c..a4137e0 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c @@ -29,6 +29,7 @@ static void perf_evlist__mmap_put(struct perf_evlist *evlist, int idx); static void __perf_evlist__munmap(struct perf_evlist *evlist, int idx); +static void perf_mmap__munmap(struct perf_mmap *map); #define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y)) #define SID(e, x, y) xyarray__entry(e->sample_id, x, y) @@ -781,9 +782,8 @@ broken_event: return event; } -union perf_event *perf_evlist__mmap_read_forward(struct perf_evlist *evlist, int idx) +union perf_event *perf_mmap__read_forward(struct perf_mmap *md, bool check_messup) { - struct perf_mmap *md = &evlist->mmap[idx]; u64 head; u64 old = md->prev; @@ -795,13 +795,12 @@ union perf_event *perf_evlist__mmap_read_forward(struct perf_evlist *evlist, int head = perf_mmap__read_head(md); - return perf_mmap__read(md, evlist->overwrite, old, head, &md->prev); + return perf_mmap__read(md, check_messup, old, head, &md->prev); } union perf_event * -perf_evlist__mmap_read_backward(struct perf_evlist *evlist, int idx) +perf_mmap__read_backward(struct perf_mmap *md) { - struct perf_mmap *md = &evlist->mmap[idx]; u64 head, end; u64 start = md->prev; @@ -836,6 +835,31 @@ perf_evlist__mmap_read_backward(struct perf_evlist *evlist, int idx) return perf_mmap__read(md, false, start, end, &md->prev); } +union perf_event *perf_evlist__mmap_read_forward(struct perf_evlist *evlist, int idx) +{ + struct perf_mmap *md = &evlist->mmap[idx]; + + /* + * Check messup is required for forward overwritable ring buffer: + * memory pointed by md->prev can be overwritten in this case. + * No need for read-write ring buffer: kernel stop outputting when + * it hit md->prev (perf_mmap__consume()). + */ + return perf_mmap__read_forward(md, evlist->overwrite); +} + +union perf_event *perf_evlist__mmap_read_backward(struct perf_evlist *evlist, int idx) +{ + struct perf_mmap *md = &evlist->mmap[idx]; + + /* + * No need to check messup for backward ring buffer: + * We can always read arbitrary long data from a backward + * ring buffer unless we forget to pause it before reading. + */ + return perf_mmap__read_backward(md); +} + union perf_event *perf_evlist__mmap_read(struct perf_evlist *evlist, int idx) { if (!evlist->backward) @@ -843,9 +867,8 @@ union perf_event *perf_evlist__mmap_read(struct perf_evlist *evlist, int idx) return perf_evlist__mmap_read_backward(evlist, idx); } -void perf_evlist__mmap_read_catchup(struct perf_evlist *evlist, int idx) +void perf_mmap__read_catchup(struct perf_mmap *md) { - struct perf_mmap *md = &evlist->mmap[idx]; u64 head; if (!atomic_read(&md->refcnt)) @@ -855,38 +878,54 @@ void perf_evlist__mmap_read_catchup(struct perf_evlist *evlist, int idx) md->prev = head; } +void perf_evlist__mmap_read_catchup(struct perf_evlist *evlist, int idx) +{ + perf_mmap__read_catchup(&evlist->mmap[idx]); +} + static bool perf_mmap__empty(struct perf_mmap *md) { return perf_mmap__read_head(md) == md->prev && !md->auxtrace_mmap.base; } -static void perf_evlist__mmap_get(struct perf_evlist *evlist, int idx) +static void perf_mmap__get(struct perf_mmap *map) { - atomic_inc(&evlist->mmap[idx].refcnt); + atomic_inc(&map->refcnt); } -static void perf_evlist__mmap_put(struct perf_evlist *evlist, int idx) +static void perf_mmap__put(struct perf_mmap *md) { - struct perf_mmap *md = &evlist->mmap[idx]; - BUG_ON(md->base && atomic_read(&md->refcnt) == 0); if (atomic_dec_and_test(&md->refcnt)) - __perf_evlist__munmap(evlist, idx); + perf_mmap__munmap(md); } -void perf_evlist__mmap_consume(struct perf_evlist *evlist, int idx) +static void perf_evlist__mmap_get(struct perf_evlist *evlist, int idx) { - struct perf_mmap *md = &evlist->mmap[idx]; + perf_mmap__get(&evlist->mmap[idx]); +} + +static void perf_evlist__mmap_put(struct perf_evlist *evlist, int idx) +{ + perf_mmap__put(&evlist->mmap[idx]); +} - if (!evlist->overwrite) { +void perf_mmap__consume(struct perf_mmap *md, bool overwrite) +{ + if (!overwrite) { u64 old = md->prev; perf_mmap__write_tail(md, old); } if (atomic_read(&md->refcnt) == 1 && perf_mmap__empty(md)) - perf_evlist__mmap_put(evlist, idx); + perf_mmap__put(md); +} + +void perf_evlist__mmap_consume(struct perf_evlist *evlist, int idx) +{ + perf_mmap__consume(&evlist->mmap[idx], evlist->overwrite); } int __weak auxtrace_mmap__mmap(struct auxtrace_mmap *mm __maybe_unused, @@ -917,15 +956,20 @@ void __weak auxtrace_mmap_params__set_idx( { } -static void __perf_evlist__munmap(struct perf_evlist *evlist, int idx) +static void perf_mmap__munmap(struct perf_mmap *map) { - if (evlist->mmap[idx].base != NULL) { - munmap(evlist->mmap[idx].base, evlist->mmap_len); - evlist->mmap[idx].base = NULL; - evlist->mmap[idx].fd = -1; - atomic_set(&evlist->mmap[idx].refcnt, 0); + if (map->base != NULL) { + munmap(map->base, perf_mmap__mmap_len(map)); + map->base = NULL; + map->fd = -1; + atomic_set(&map->refcnt, 0); } - auxtrace_mmap__munmap(&evlist->mmap[idx].auxtrace_mmap); + auxtrace_mmap__munmap(&map->auxtrace_mmap); +} + +static void __perf_evlist__munmap(struct perf_evlist *evlist, int idx) +{ + perf_mmap__munmap(&evlist->mmap[idx]); } void perf_evlist__munmap(struct perf_evlist *evlist) @@ -941,20 +985,21 @@ void perf_evlist__munmap(struct perf_evlist *evlist) zfree(&evlist->mmap); } -static int perf_evlist__alloc_mmap(struct perf_evlist *evlist) +static struct perf_mmap *perf_evlist__alloc_mmap(struct perf_evlist *evlist) { int i; + struct perf_mmap *map; evlist->nr_mmaps = cpu_map__nr(evlist->cpus); if (cpu_map__empty(evlist->cpus)) evlist->nr_mmaps = thread_map__nr(evlist->threads); - evlist->mmap = zalloc(evlist->nr_mmaps * sizeof(struct perf_mmap)); - if (!evlist->mmap) - return -ENOMEM; + map = zalloc(evlist->nr_mmaps * sizeof(struct perf_mmap)); + if (!map) + return NULL; for (i = 0; i < evlist->nr_mmaps; i++) - evlist->mmap[i].fd = -1; - return 0; + map[i].fd = -1; + return map; } struct mmap_params { @@ -963,8 +1008,8 @@ struct mmap_params { struct auxtrace_mmap_params auxtrace_mp; }; -static int __perf_evlist__mmap(struct perf_evlist *evlist, int idx, - struct mmap_params *mp, int fd) +static int perf_mmap__mmap(struct perf_mmap *map, + struct mmap_params *mp, int fd) { /* * The last one will be done at perf_evlist__mmap_consume(), so that we @@ -979,26 +1024,32 @@ static int __perf_evlist__mmap(struct perf_evlist *evlist, int idx, * evlist layer can't just drop it when filtering events in * perf_evlist__filter_pollfd(). */ - atomic_set(&evlist->mmap[idx].refcnt, 2); - evlist->mmap[idx].prev = 0; - evlist->mmap[idx].mask = mp->mask; - evlist->mmap[idx].base = mmap(NULL, evlist->mmap_len, mp->prot, - MAP_SHARED, fd, 0); - if (evlist->mmap[idx].base == MAP_FAILED) { + atomic_set(&map->refcnt, 2); + map->prev = 0; + map->mask = mp->mask; + map->base = mmap(NULL, perf_mmap__mmap_len(map), mp->prot, + MAP_SHARED, fd, 0); + if (map->base == MAP_FAILED) { pr_debug2("failed to mmap perf event ring buffer, error %d\n", errno); - evlist->mmap[idx].base = NULL; + map->base = NULL; return -1; } - evlist->mmap[idx].fd = fd; + map->fd = fd; - if (auxtrace_mmap__mmap(&evlist->mmap[idx].auxtrace_mmap, - &mp->auxtrace_mp, evlist->mmap[idx].base, fd)) + if (auxtrace_mmap__mmap(&map->auxtrace_mmap, + &mp->auxtrace_mp, map->base, fd)) return -1; return 0; } +static int __perf_evlist__mmap(struct perf_evlist *evlist, int idx, + struct mmap_params *mp, int fd) +{ + return perf_mmap__mmap(&evlist->mmap[idx], mp, fd); +} + static bool perf_evlist__should_poll(struct perf_evlist *evlist __maybe_unused, struct perf_evsel *evsel) @@ -1248,7 +1299,9 @@ int perf_evlist__mmap_ex(struct perf_evlist *evlist, unsigned int pages, .prot = PROT_READ | (overwrite ? 0 : PROT_WRITE), }; - if (evlist->mmap == NULL && perf_evlist__alloc_mmap(evlist) < 0) + if (!evlist->mmap) + evlist->mmap = perf_evlist__alloc_mmap(evlist); + if (!evlist->mmap) return -ENOMEM; if (evlist->pollfd.entries == NULL && perf_evlist__alloc_pollfd(evlist) < 0) diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h index afd0877..9e680c6 100644 --- a/tools/perf/util/evlist.h +++ b/tools/perf/util/evlist.h @@ -35,6 +35,12 @@ struct perf_mmap { char event_copy[PERF_SAMPLE_MAX_SIZE] __attribute__((aligned(8))); }; +static inline size_t +perf_mmap__mmap_len(struct perf_mmap *map) +{ + return map->mask + 1 + page_size; +} + struct perf_evlist { struct list_head entries; struct hlist_head heads[PERF_EVLIST__HLIST_SIZE]; @@ -129,6 +135,12 @@ struct perf_evsel *perf_evlist__id2evsel_strict(struct perf_evlist *evlist, struct perf_sample_id *perf_evlist__id2sid(struct perf_evlist *evlist, u64 id); +union perf_event *perf_mmap__read_forward(struct perf_mmap *map, bool check_messup); +union perf_event *perf_mmap__read_backward(struct perf_mmap *map); + +void perf_mmap__read_catchup(struct perf_mmap *md); +void perf_mmap__consume(struct perf_mmap *md, bool overwrite); + union perf_event *perf_evlist__mmap_read(struct perf_evlist *evlist, int idx); union perf_event *perf_evlist__mmap_read_forward(struct perf_evlist *evlist, -- cgit v0.10.2 From a4ea0ec4f24a721bea5447a27ad5fbcb89275bae Mon Sep 17 00:00:00 2001 From: Wang Nan Date: Thu, 14 Jul 2016 08:34:36 +0000 Subject: perf record: Decouple record__mmap_read() and evlist. Perf evlist will have multiple mmap arrays. Update record__mmap_read(): it should read from 'struct perf_mmap' directly. Also, make record__mmap_read() ready to read from backward ring buffer. Signed-off-by: Wang Nan Acked-by: Jiri Olsa Cc: He Kuang Cc: Masami Hiramatsu Cc: Namhyung Kim Cc: Nilay Vaish Cc: Zefan Li Cc: pi3orama@163.com Link: http://lkml.kernel.org/r/1468485287-33422-5-git-send-email-wangnan0@huawei.com Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index d9f5cc3..d15517e 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -119,11 +119,10 @@ backward_rb_find_range(void *buf, int mask, u64 head, u64 *start, u64 *end) } static int -rb_find_range(struct perf_evlist *evlist, - void *data, int mask, u64 head, u64 old, - u64 *start, u64 *end) +rb_find_range(void *data, int mask, u64 head, u64 old, + u64 *start, u64 *end, bool backward) { - if (!evlist->backward) { + if (!backward) { *start = old; *end = head; return 0; @@ -132,9 +131,10 @@ rb_find_range(struct perf_evlist *evlist, return backward_rb_find_range(data, mask, head, start, end); } -static int record__mmap_read(struct record *rec, struct perf_evlist *evlist, int idx) +static int +record__mmap_read(struct record *rec, struct perf_mmap *md, + bool overwrite, bool backward) { - struct perf_mmap *md = &evlist->mmap[idx]; u64 head = perf_mmap__read_head(md); u64 old = md->prev; u64 end = head, start = old; @@ -143,8 +143,8 @@ static int record__mmap_read(struct record *rec, struct perf_evlist *evlist, int void *buf; int rc = 0; - if (rb_find_range(evlist, data, md->mask, head, - old, &start, &end)) + if (rb_find_range(data, md->mask, head, + old, &start, &end, backward)) return -1; if (start == end) @@ -157,7 +157,7 @@ static int record__mmap_read(struct record *rec, struct perf_evlist *evlist, int WARN_ONCE(1, "failed to keep up with mmap data. (warn only once)\n"); md->prev = head; - perf_evlist__mmap_consume(evlist, idx); + perf_mmap__consume(md, overwrite || backward); return 0; } @@ -182,7 +182,7 @@ static int record__mmap_read(struct record *rec, struct perf_evlist *evlist, int } md->prev = head; - perf_evlist__mmap_consume(evlist, idx); + perf_mmap__consume(md, overwrite || backward); out: return rc; } @@ -498,20 +498,27 @@ static struct perf_event_header finished_round_event = { .type = PERF_RECORD_FINISHED_ROUND, }; -static int record__mmap_read_evlist(struct record *rec, struct perf_evlist *evlist) +static int record__mmap_read_evlist(struct record *rec, struct perf_evlist *evlist, + bool backward) { u64 bytes_written = rec->bytes_written; int i; int rc = 0; + struct perf_mmap *maps; if (!evlist) return 0; + maps = evlist->mmap; + if (!maps) + return 0; + for (i = 0; i < evlist->nr_mmaps; i++) { - struct auxtrace_mmap *mm = &evlist->mmap[i].auxtrace_mmap; + struct auxtrace_mmap *mm = &maps[i].auxtrace_mmap; - if (evlist->mmap[i].base) { - if (record__mmap_read(rec, evlist, i) != 0) { + if (maps[i].base) { + if (record__mmap_read(rec, &maps[i], + evlist->overwrite, backward) != 0) { rc = -1; goto out; } @@ -539,7 +546,7 @@ static int record__mmap_read_all(struct record *rec) { int err; - err = record__mmap_read_evlist(rec, rec->evlist); + err = record__mmap_read_evlist(rec, rec->evlist, false); if (err) return err; -- cgit v0.10.2 From 4876075b3205af992bf1012f6d6fbc03593d55b9 Mon Sep 17 00:00:00 2001 From: Wang Nan Date: Thu, 14 Jul 2016 08:34:37 +0000 Subject: perf evlist: Record mmap cookie into fdarray private field Insetad of saving a index into fdarray entries private field, save the corresponding 'struct perf_mmap' pointer, and release them directly using perf_mmap__put(). Following commits introduce multiple mmap arrays to evlist. Without this patch, perf_evlist__munmap_filtered() is unable to retrive correct 'struct perf_mmap' pointer. Signed-off-by: Wang Nan Acked-by: Jiri Olsa Cc: He Kuang Cc: Masami Hiramatsu Cc: Namhyung Kim Cc: Nilay Vaish Cc: Zefan Li Cc: pi3orama@163.com Link: http://lkml.kernel.org/r/1468485287-33422-6-git-send-email-wangnan0@huawei.com Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index a4137e0..1462085 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c @@ -30,6 +30,7 @@ static void perf_evlist__mmap_put(struct perf_evlist *evlist, int idx); static void __perf_evlist__munmap(struct perf_evlist *evlist, int idx); static void perf_mmap__munmap(struct perf_mmap *map); +static void perf_mmap__put(struct perf_mmap *map); #define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y)) #define SID(e, x, y) xyarray__entry(e->sample_id, x, y) @@ -466,7 +467,8 @@ int perf_evlist__alloc_pollfd(struct perf_evlist *evlist) return 0; } -static int __perf_evlist__add_pollfd(struct perf_evlist *evlist, int fd, int idx, short revent) +static int __perf_evlist__add_pollfd(struct perf_evlist *evlist, int fd, + struct perf_mmap *map, short revent) { int pos = fdarray__add(&evlist->pollfd, fd, revent | POLLERR | POLLHUP); /* @@ -474,7 +476,7 @@ static int __perf_evlist__add_pollfd(struct perf_evlist *evlist, int fd, int idx * close the associated evlist->mmap[] entry. */ if (pos >= 0) { - evlist->pollfd.priv[pos].idx = idx; + evlist->pollfd.priv[pos].ptr = map; fcntl(fd, F_SETFL, O_NONBLOCK); } @@ -484,15 +486,16 @@ static int __perf_evlist__add_pollfd(struct perf_evlist *evlist, int fd, int idx int perf_evlist__add_pollfd(struct perf_evlist *evlist, int fd) { - return __perf_evlist__add_pollfd(evlist, fd, -1, POLLIN); + return __perf_evlist__add_pollfd(evlist, fd, NULL, POLLIN); } static void perf_evlist__munmap_filtered(struct fdarray *fda, int fd, void *arg __maybe_unused) { - struct perf_evlist *evlist = container_of(fda, struct perf_evlist, pollfd); + struct perf_mmap *map = fda->priv[fd].ptr; - perf_evlist__mmap_put(evlist, fda->priv[fd].idx); + if (map) + perf_mmap__put(map); } int perf_evlist__filter_pollfd(struct perf_evlist *evlist, short revents_and_mask) @@ -1098,7 +1101,7 @@ static int perf_evlist__mmap_per_evsel(struct perf_evlist *evlist, int idx, * Therefore don't add it for polling. */ if (!evsel->system_wide && - __perf_evlist__add_pollfd(evlist, fd, idx, revent) < 0) { + __perf_evlist__add_pollfd(evlist, fd, &evlist->mmap[idx], revent) < 0) { perf_evlist__mmap_put(evlist, idx); return -1; } -- cgit v0.10.2 From a1f72618346a4e7ce9cff6aec1a62737d5d08763 Mon Sep 17 00:00:00 2001 From: Wang Nan Date: Thu, 14 Jul 2016 08:34:38 +0000 Subject: perf evlist: Extract common code in mmap failure processing In perf_evlist__mmap_per_cpu() and perf_evlist__mmap_per_thread(), in case of mmap failure, successfully created maps should be cleared. Current code uses two loops calling __perf_evlist__munmap() for each function. This patch extracts common code to perf_evlist__munmap_nofree() and use previous introduced decoupled API perf_mmap__munmap(). Now __perf_evlist__munmap() can be removed because of no user. Signed-off-by: Wang Nan Acked-by: Jiri Olsa Cc: He Kuang Cc: Masami Hiramatsu Cc: Namhyung Kim Cc: Nilay Vaish Cc: Zefan Li Cc: pi3orama@163.com Link: http://lkml.kernel.org/r/1468485287-33422-7-git-send-email-wangnan0@huawei.com Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index 1462085..54ae0a0 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c @@ -28,7 +28,6 @@ #include static void perf_evlist__mmap_put(struct perf_evlist *evlist, int idx); -static void __perf_evlist__munmap(struct perf_evlist *evlist, int idx); static void perf_mmap__munmap(struct perf_mmap *map); static void perf_mmap__put(struct perf_mmap *map); @@ -970,12 +969,7 @@ static void perf_mmap__munmap(struct perf_mmap *map) auxtrace_mmap__munmap(&map->auxtrace_mmap); } -static void __perf_evlist__munmap(struct perf_evlist *evlist, int idx) -{ - perf_mmap__munmap(&evlist->mmap[idx]); -} - -void perf_evlist__munmap(struct perf_evlist *evlist) +static void perf_evlist__munmap_nofree(struct perf_evlist *evlist) { int i; @@ -983,8 +977,12 @@ void perf_evlist__munmap(struct perf_evlist *evlist) return; for (i = 0; i < evlist->nr_mmaps; i++) - __perf_evlist__munmap(evlist, i); + perf_mmap__munmap(&evlist->mmap[i]); +} +void perf_evlist__munmap(struct perf_evlist *evlist) +{ + perf_evlist__munmap_nofree(evlist); zfree(&evlist->mmap); } @@ -1142,8 +1140,7 @@ static int perf_evlist__mmap_per_cpu(struct perf_evlist *evlist, return 0; out_unmap: - for (cpu = 0; cpu < nr_cpus; cpu++) - __perf_evlist__munmap(evlist, cpu); + perf_evlist__munmap_nofree(evlist); return -1; } @@ -1168,8 +1165,7 @@ static int perf_evlist__mmap_per_thread(struct perf_evlist *evlist, return 0; out_unmap: - for (thread = 0; thread < nr_threads; thread++) - __perf_evlist__munmap(evlist, thread); + perf_evlist__munmap_nofree(evlist); return -1; } -- cgit v0.10.2 From b2cb615d8aaba520fe351ff456f6c7730828b3fe Mon Sep 17 00:00:00 2001 From: Wang Nan Date: Thu, 14 Jul 2016 08:34:39 +0000 Subject: perf evlist: Introduce backward_mmap array for evlist Add backward_mmap to evlist, free it together with normal mmap. Improve perf_evlist__pick_pc(), search backward_mmap if evlist->mmap is not available. This patch doesn't alloc this array. It will be allocated conditionally in the following commits. Signed-off-by: Wang Nan Acked-by: Jiri Olsa Cc: He Kuang Cc: Masami Hiramatsu Cc: Namhyung Kim Cc: Nilay Vaish Cc: Zefan Li Cc: pi3orama@163.com Link: http://lkml.kernel.org/r/1468485287-33422-8-git-send-email-wangnan0@huawei.com Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index d15517e..dbcb223 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -509,7 +509,7 @@ static int record__mmap_read_evlist(struct record *rec, struct perf_evlist *evli if (!evlist) return 0; - maps = evlist->mmap; + maps = backward ? evlist->backward_mmap : evlist->mmap; if (!maps) return 0; @@ -696,8 +696,12 @@ perf_event__synth_time_conv(const struct perf_event_mmap_page *pc __maybe_unused static const struct perf_event_mmap_page * perf_evlist__pick_pc(struct perf_evlist *evlist) { - if (evlist && evlist->mmap && evlist->mmap[0].base) - return evlist->mmap[0].base; + if (evlist) { + if (evlist->mmap && evlist->mmap[0].base) + return evlist->mmap[0].base; + if (evlist->backward_mmap && evlist->backward_mmap[0].base) + return evlist->backward_mmap[0].base; + } return NULL; } diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index 54ae0a0..24927e1 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c @@ -123,6 +123,7 @@ static void perf_evlist__purge(struct perf_evlist *evlist) void perf_evlist__exit(struct perf_evlist *evlist) { zfree(&evlist->mmap); + zfree(&evlist->backward_mmap); fdarray__exit(&evlist->pollfd); } @@ -973,17 +974,20 @@ static void perf_evlist__munmap_nofree(struct perf_evlist *evlist) { int i; - if (evlist->mmap == NULL) - return; + if (evlist->mmap) + for (i = 0; i < evlist->nr_mmaps; i++) + perf_mmap__munmap(&evlist->mmap[i]); - for (i = 0; i < evlist->nr_mmaps; i++) - perf_mmap__munmap(&evlist->mmap[i]); + if (evlist->backward_mmap) + for (i = 0; i < evlist->nr_mmaps; i++) + perf_mmap__munmap(&evlist->backward_mmap[i]); } void perf_evlist__munmap(struct perf_evlist *evlist) { perf_evlist__munmap_nofree(evlist); zfree(&evlist->mmap); + zfree(&evlist->backward_mmap); } static struct perf_mmap *perf_evlist__alloc_mmap(struct perf_evlist *evlist) diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h index 9e680c6..07a1ad0 100644 --- a/tools/perf/util/evlist.h +++ b/tools/perf/util/evlist.h @@ -61,6 +61,7 @@ struct perf_evlist { } workload; struct fdarray pollfd; struct perf_mmap *mmap; + struct perf_mmap *backward_mmap; struct thread_map *threads; struct cpu_map *cpus; struct perf_evsel *selected; -- cgit v0.10.2 From 078c33862e042b3778dce3bcc8eaef84ab40715c Mon Sep 17 00:00:00 2001 From: Wang Nan Date: Thu, 14 Jul 2016 08:34:40 +0000 Subject: perf evlist: Map backward events to backward_mmap In perf_evlist__mmap_per_evsel(), select backward_mmap for backward events. Utilize new perf_mmap APIs. Dynamically alloc backward_mmap. Remove useless functions. Signed-off-by: Wang Nan Acked-by: Jiri Olsa Cc: He Kuang Cc: Masami Hiramatsu Cc: Namhyung Kim Cc: Nilay Vaish Cc: Zefan Li Cc: pi3orama@163.com Link: http://lkml.kernel.org/r/1468485287-33422-9-git-send-email-wangnan0@huawei.com Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/tests/backward-ring-buffer.c b/tools/perf/tests/backward-ring-buffer.c index 5cee387..b2c6348 100644 --- a/tools/perf/tests/backward-ring-buffer.c +++ b/tools/perf/tests/backward-ring-buffer.c @@ -31,8 +31,8 @@ static int count_samples(struct perf_evlist *evlist, int *sample_count, for (i = 0; i < evlist->nr_mmaps; i++) { union perf_event *event; - perf_evlist__mmap_read_catchup(evlist, i); - while ((event = perf_evlist__mmap_read_backward(evlist, i)) != NULL) { + perf_mmap__read_catchup(&evlist->backward_mmap[i]); + while ((event = perf_mmap__read_backward(&evlist->backward_mmap[i])) != NULL) { const u32 type = event->header.type; switch (type) { diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index 24927e1..7570f90 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c @@ -27,7 +27,6 @@ #include #include -static void perf_evlist__mmap_put(struct perf_evlist *evlist, int idx); static void perf_mmap__munmap(struct perf_mmap *map); static void perf_mmap__put(struct perf_mmap *map); @@ -692,8 +691,11 @@ static int perf_evlist__set_paused(struct perf_evlist *evlist, bool value) { int i; + if (!evlist->backward_mmap) + return 0; + for (i = 0; i < evlist->nr_mmaps; i++) { - int fd = evlist->mmap[i].fd; + int fd = evlist->backward_mmap[i].fd; int err; if (fd < 0) @@ -904,16 +906,6 @@ static void perf_mmap__put(struct perf_mmap *md) perf_mmap__munmap(md); } -static void perf_evlist__mmap_get(struct perf_evlist *evlist, int idx) -{ - perf_mmap__get(&evlist->mmap[idx]); -} - -static void perf_evlist__mmap_put(struct perf_evlist *evlist, int idx) -{ - perf_mmap__put(&evlist->mmap[idx]); -} - void perf_mmap__consume(struct perf_mmap *md, bool overwrite) { if (!overwrite) { @@ -1049,12 +1041,6 @@ static int perf_mmap__mmap(struct perf_mmap *map, return 0; } -static int __perf_evlist__mmap(struct perf_evlist *evlist, int idx, - struct mmap_params *mp, int fd) -{ - return perf_mmap__mmap(&evlist->mmap[idx], mp, fd); -} - static bool perf_evlist__should_poll(struct perf_evlist *evlist __maybe_unused, struct perf_evsel *evsel) @@ -1066,16 +1052,27 @@ perf_evlist__should_poll(struct perf_evlist *evlist __maybe_unused, static int perf_evlist__mmap_per_evsel(struct perf_evlist *evlist, int idx, struct mmap_params *mp, int cpu, - int thread, int *output) + int thread, int *_output, int *_output_backward) { struct perf_evsel *evsel; int revent; evlist__for_each_entry(evlist, evsel) { + struct perf_mmap *maps = evlist->mmap; + int *output = _output; int fd; - if (!!evsel->attr.write_backward != (evlist->overwrite && evlist->backward)) - continue; + if (evsel->attr.write_backward) { + output = _output_backward; + maps = evlist->backward_mmap; + + if (!maps) { + maps = perf_evlist__alloc_mmap(evlist); + if (!maps) + return -1; + evlist->backward_mmap = maps; + } + } if (evsel->system_wide && thread) continue; @@ -1084,13 +1081,14 @@ static int perf_evlist__mmap_per_evsel(struct perf_evlist *evlist, int idx, if (*output == -1) { *output = fd; - if (__perf_evlist__mmap(evlist, idx, mp, *output) < 0) + + if (perf_mmap__mmap(&maps[idx], mp, *output) < 0) return -1; } else { if (ioctl(fd, PERF_EVENT_IOC_SET_OUTPUT, *output) != 0) return -1; - perf_evlist__mmap_get(evlist, idx); + perf_mmap__get(&maps[idx]); } revent = perf_evlist__should_poll(evlist, evsel) ? POLLIN : 0; @@ -1103,8 +1101,8 @@ static int perf_evlist__mmap_per_evsel(struct perf_evlist *evlist, int idx, * Therefore don't add it for polling. */ if (!evsel->system_wide && - __perf_evlist__add_pollfd(evlist, fd, &evlist->mmap[idx], revent) < 0) { - perf_evlist__mmap_put(evlist, idx); + __perf_evlist__add_pollfd(evlist, fd, &maps[idx], revent) < 0) { + perf_mmap__put(&maps[idx]); return -1; } @@ -1130,13 +1128,14 @@ static int perf_evlist__mmap_per_cpu(struct perf_evlist *evlist, pr_debug2("perf event ring buffer mmapped per cpu\n"); for (cpu = 0; cpu < nr_cpus; cpu++) { int output = -1; + int output_backward = -1; auxtrace_mmap_params__set_idx(&mp->auxtrace_mp, evlist, cpu, true); for (thread = 0; thread < nr_threads; thread++) { if (perf_evlist__mmap_per_evsel(evlist, cpu, mp, cpu, - thread, &output)) + thread, &output, &output_backward)) goto out_unmap; } } @@ -1157,12 +1156,13 @@ static int perf_evlist__mmap_per_thread(struct perf_evlist *evlist, pr_debug2("perf event ring buffer mmapped per thread\n"); for (thread = 0; thread < nr_threads; thread++) { int output = -1; + int output_backward = -1; auxtrace_mmap_params__set_idx(&mp->auxtrace_mp, evlist, thread, false); if (perf_evlist__mmap_per_evsel(evlist, thread, mp, 0, thread, - &output)) + &output, &output_backward)) goto out_unmap; } -- cgit v0.10.2 From a0c6f451f90204847ce5f91c3268d83a76bde1b6 Mon Sep 17 00:00:00 2001 From: Wang Nan Date: Thu, 14 Jul 2016 08:34:41 +0000 Subject: perf evlist: Drop evlist->backward Now there's no real user of evlist->backward. Drop it. We are going to use evlist->backward_mmap as a container for backward ring buffer. Signed-off-by: Wang Nan Acked-by: Jiri Olsa Cc: He Kuang Cc: Masami Hiramatsu Cc: Namhyung Kim Cc: Nilay Vaish Cc: Zefan Li Cc: pi3orama@163.com Link: http://lkml.kernel.org/r/1468485287-33422-10-git-send-email-wangnan0@huawei.com Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/tests/backward-ring-buffer.c b/tools/perf/tests/backward-ring-buffer.c index b2c6348..db9cd30 100644 --- a/tools/perf/tests/backward-ring-buffer.c +++ b/tools/perf/tests/backward-ring-buffer.c @@ -101,7 +101,6 @@ int test__backward_ring_buffer(int subtest __maybe_unused) return TEST_FAIL; } - evlist->backward = true; err = perf_evlist__create_maps(evlist, &opts.target); if (err < 0) { pr_debug("Not enough memory to create thread/cpu maps\n"); diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index 7570f90..5beb44f 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c @@ -44,7 +44,6 @@ void perf_evlist__init(struct perf_evlist *evlist, struct cpu_map *cpus, perf_evlist__set_maps(evlist, cpus, threads); fdarray__init(&evlist->pollfd, 64); evlist->workload.pid = -1; - evlist->backward = false; } struct perf_evlist *perf_evlist__new(void) @@ -867,9 +866,7 @@ union perf_event *perf_evlist__mmap_read_backward(struct perf_evlist *evlist, in union perf_event *perf_evlist__mmap_read(struct perf_evlist *evlist, int idx) { - if (!evlist->backward) - return perf_evlist__mmap_read_forward(evlist, idx); - return perf_evlist__mmap_read_backward(evlist, idx); + return perf_evlist__mmap_read_forward(evlist, idx); } void perf_mmap__read_catchup(struct perf_mmap *md) diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h index 07a1ad0..6a3d9bd 100644 --- a/tools/perf/util/evlist.h +++ b/tools/perf/util/evlist.h @@ -50,7 +50,6 @@ struct perf_evlist { bool overwrite; bool enabled; bool has_user_cpus; - bool backward; size_t mmap_len; int id_pos; int is_pos; -- cgit v0.10.2 From 54cc54decd79b2c92f4db06001b4b245f38181b7 Mon Sep 17 00:00:00 2001 From: Wang Nan Date: Thu, 14 Jul 2016 08:34:42 +0000 Subject: perf evlist: Setup backward mmap state machine Introduce a bkw_mmap_state state machine to evlist: .________________(forbid)_____________. | V NOTREADY --(0)--> RUNNING --(1)--> DATA_PENDING --(2)--> EMPTY ^ ^ | ^ | | |__(forbid)____/ |___(forbid)___/| | | \_________________(3)_______________/ NOTREADY : Backward ring buffers are not ready RUNNING : Backward ring buffers are recording DATA_PENDING : We are required to collect data from backward ring buffers EMPTY : We have collected data from backward ring buffers. (0): Setup backward ring buffer (1): Pause ring buffers for reading (2): Read from ring buffers (3): Resume ring buffers for recording We can't avoid this complexity. Since we deliberately drop records from overwritable ring buffer, there's no way for us to check remaining from ring buffer itself (by checking head and old pointers). Therefore, we need DATA_PENDING and EMPTY state to help us recording what we have done to the ring buffer. In record__mmap_read_evlist(), drive this state machine from DATA_PENDING to EMPTY. In perf_evlist__mmap_per_evsel(), drive this state machine from NOTREADY to RUNNING when creating backward mmap. Signed-off-by: Wang Nan Acked-by: Jiri Olsa Cc: He Kuang Cc: Masami Hiramatsu Cc: Namhyung Kim Cc: Nilay Vaish Cc: Zefan Li Cc: pi3orama@163.com Link: http://lkml.kernel.org/r/1468485287-33422-11-git-send-email-wangnan0@huawei.com Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index dbcb223..d4f15e7 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -513,6 +513,9 @@ static int record__mmap_read_evlist(struct record *rec, struct perf_evlist *evli if (!maps) return 0; + if (backward && evlist->bkw_mmap_state != BKW_MMAP_DATA_PENDING) + return 0; + for (i = 0; i < evlist->nr_mmaps; i++) { struct auxtrace_mmap *mm = &maps[i].auxtrace_mmap; @@ -538,6 +541,8 @@ static int record__mmap_read_evlist(struct record *rec, struct perf_evlist *evli if (bytes_written != rec->bytes_written) rc = record__write(rec, &finished_round_event, sizeof(finished_round_event)); + if (backward) + perf_evlist__toggle_bkw_mmap(evlist, BKW_MMAP_EMPTY); out: return rc; } diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index 5beb44f..93ab664 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c @@ -15,6 +15,7 @@ #include "evlist.h" #include "evsel.h" #include "debug.h" +#include "asm/bug.h" #include #include "parse-events.h" @@ -44,6 +45,7 @@ void perf_evlist__init(struct perf_evlist *evlist, struct cpu_map *cpus, perf_evlist__set_maps(evlist, cpus, threads); fdarray__init(&evlist->pollfd, 64); evlist->workload.pid = -1; + evlist->bkw_mmap_state = BKW_MMAP_NOTREADY; } struct perf_evlist *perf_evlist__new(void) @@ -1068,6 +1070,8 @@ static int perf_evlist__mmap_per_evsel(struct perf_evlist *evlist, int idx, if (!maps) return -1; evlist->backward_mmap = maps; + if (evlist->bkw_mmap_state == BKW_MMAP_NOTREADY) + perf_evlist__toggle_bkw_mmap(evlist, BKW_MMAP_RUNNING); } } @@ -1972,3 +1976,61 @@ perf_evlist__find_evsel_by_str(struct perf_evlist *evlist, return NULL; } + +void perf_evlist__toggle_bkw_mmap(struct perf_evlist *evlist, + enum bkw_mmap_state state) +{ + enum bkw_mmap_state old_state = evlist->bkw_mmap_state; + enum action { + NONE, + PAUSE, + RESUME, + } action = NONE; + + if (!evlist->backward_mmap) + return; + + switch (old_state) { + case BKW_MMAP_NOTREADY: { + if (state != BKW_MMAP_RUNNING) + goto state_err;; + break; + } + case BKW_MMAP_RUNNING: { + if (state != BKW_MMAP_DATA_PENDING) + goto state_err; + action = PAUSE; + break; + } + case BKW_MMAP_DATA_PENDING: { + if (state != BKW_MMAP_EMPTY) + goto state_err; + break; + } + case BKW_MMAP_EMPTY: { + if (state != BKW_MMAP_RUNNING) + goto state_err; + action = RESUME; + break; + } + default: + WARN_ONCE(1, "Shouldn't get there\n"); + } + + evlist->bkw_mmap_state = state; + + switch (action) { + case PAUSE: + perf_evlist__pause(evlist); + break; + case RESUME: + perf_evlist__resume(evlist); + break; + case NONE: + default: + break; + } + +state_err: + return; +} diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h index 6a3d9bd..20faaab 100644 --- a/tools/perf/util/evlist.h +++ b/tools/perf/util/evlist.h @@ -41,6 +41,34 @@ perf_mmap__mmap_len(struct perf_mmap *map) return map->mask + 1 + page_size; } +/* + * State machine of bkw_mmap_state: + * + * .________________(forbid)_____________. + * | V + * NOTREADY --(0)--> RUNNING --(1)--> DATA_PENDING --(2)--> EMPTY + * ^ ^ | ^ | + * | |__(forbid)____/ |___(forbid)___/| + * | | + * \_________________(3)_______________/ + * + * NOTREADY : Backward ring buffers are not ready + * RUNNING : Backward ring buffers are recording + * DATA_PENDING : We are required to collect data from backward ring buffers + * EMPTY : We have collected data from backward ring buffers. + * + * (0): Setup backward ring buffer + * (1): Pause ring buffers for reading + * (2): Read from ring buffers + * (3): Resume ring buffers for recording + */ +enum bkw_mmap_state { + BKW_MMAP_NOTREADY, + BKW_MMAP_RUNNING, + BKW_MMAP_DATA_PENDING, + BKW_MMAP_EMPTY, +}; + struct perf_evlist { struct list_head entries; struct hlist_head heads[PERF_EVLIST__HLIST_SIZE]; @@ -54,6 +82,7 @@ struct perf_evlist { int id_pos; int is_pos; u64 combined_sample_type; + enum bkw_mmap_state bkw_mmap_state; struct { int cork_fd; pid_t pid; @@ -135,6 +164,8 @@ struct perf_evsel *perf_evlist__id2evsel_strict(struct perf_evlist *evlist, struct perf_sample_id *perf_evlist__id2sid(struct perf_evlist *evlist, u64 id); +void perf_evlist__toggle_bkw_mmap(struct perf_evlist *evlist, enum bkw_mmap_state state); + union perf_event *perf_mmap__read_forward(struct perf_mmap *map, bool check_messup); union perf_event *perf_mmap__read_backward(struct perf_mmap *map); -- cgit v0.10.2 From 057374645bd42e8bcf22aa4529f99cf7c920a1c6 Mon Sep 17 00:00:00 2001 From: Wang Nan Date: Thu, 14 Jul 2016 08:34:43 +0000 Subject: perf record: Read from overwritable ring buffer Drive the evlist->bkw_mmap_state state machine during draining and when SIGUSR2 is received. Read the backward ring buffer in record__mmap_read_all. Signed-off-by: Wang Nan Acked-by: Jiri Olsa Cc: Masami Hiramatsu Cc: Namhyung Kim Cc: Nilay Vaish Cc: Zefan Li Cc: pi3orama@163.com Link: http://lkml.kernel.org/r/1468485287-33422-12-git-send-email-wangnan0@huawei.com Signed-off-by: He Kuang Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index d4f15e7..b87070b 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -555,7 +555,7 @@ static int record__mmap_read_all(struct record *rec) if (err) return err; - return err; + return record__mmap_read_evlist(rec, rec->evlist, true); } static void record__init_features(struct record *rec) @@ -953,6 +953,17 @@ static int __cmd_record(struct record *rec, int argc, const char **argv) for (;;) { unsigned long long hits = rec->samples; + /* + * rec->evlist->bkw_mmap_state is possible to be + * BKW_MMAP_EMPTY here: when done == true and + * hits != rec->samples in previous round. + * + * perf_evlist__toggle_bkw_mmap ensure we never + * convert BKW_MMAP_EMPTY to BKW_MMAP_DATA_PENDING. + */ + if (trigger_is_hit(&switch_output_trigger) || done || draining) + perf_evlist__toggle_bkw_mmap(rec->evlist, BKW_MMAP_DATA_PENDING); + if (record__mmap_read_all(rec) < 0) { trigger_error(&auxtrace_snapshot_trigger); trigger_error(&switch_output_trigger); @@ -972,8 +983,26 @@ static int __cmd_record(struct record *rec, int argc, const char **argv) } if (trigger_is_hit(&switch_output_trigger)) { + /* + * If switch_output_trigger is hit, the data in + * overwritable ring buffer should have been collected, + * so bkw_mmap_state should be set to BKW_MMAP_EMPTY. + * + * If SIGUSR2 raise after or during record__mmap_read_all(), + * record__mmap_read_all() didn't collect data from + * overwritable ring buffer. Read again. + */ + if (rec->evlist->bkw_mmap_state == BKW_MMAP_RUNNING) + continue; trigger_ready(&switch_output_trigger); + /* + * Reenable events in overwrite ring buffer after + * record__mmap_read_all(): we should have collected + * data from it. + */ + perf_evlist__toggle_bkw_mmap(rec->evlist, BKW_MMAP_RUNNING); + if (!quiet) fprintf(stderr, "[ perf record: dump data: Woken up %ld times ]\n", waking); -- cgit v0.10.2 From f6cdff8329e04b08cbc195194223e9dbadeeaa1e Mon Sep 17 00:00:00 2001 From: Wang Nan Date: Thu, 14 Jul 2016 08:34:44 +0000 Subject: perf evlist: Make {pause,resume} internal helpers There's no user of these two function outside evlist.c. Remove them from public namespace. Signed-off-by: Wang Nan Acked-by: Jiri Olsa Cc: He Kuang Cc: Masami Hiramatsu Cc: Namhyung Kim Cc: Nilay Vaish Cc: Zefan Li Cc: pi3orama@163.com Link: http://lkml.kernel.org/r/1468485287-33422-13-git-send-email-wangnan0@huawei.com Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index 93ab664..2a40b8e 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c @@ -708,12 +708,12 @@ static int perf_evlist__set_paused(struct perf_evlist *evlist, bool value) return 0; } -int perf_evlist__pause(struct perf_evlist *evlist) +static int perf_evlist__pause(struct perf_evlist *evlist) { return perf_evlist__set_paused(evlist, true); } -int perf_evlist__resume(struct perf_evlist *evlist) +static int perf_evlist__resume(struct perf_evlist *evlist) { return perf_evlist__set_paused(evlist, false); } diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h index 20faaab..4fd034f 100644 --- a/tools/perf/util/evlist.h +++ b/tools/perf/util/evlist.h @@ -182,8 +182,6 @@ void perf_evlist__mmap_read_catchup(struct perf_evlist *evlist, int idx); void perf_evlist__mmap_consume(struct perf_evlist *evlist, int idx); -int perf_evlist__pause(struct perf_evlist *evlist); -int perf_evlist__resume(struct perf_evlist *evlist); int perf_evlist__open(struct perf_evlist *evlist); void perf_evlist__close(struct perf_evlist *evlist); -- cgit v0.10.2 From 626a6b784e91bc61ca9fe0f9dd5bb60cb91ccb6b Mon Sep 17 00:00:00 2001 From: Wang Nan Date: Thu, 14 Jul 2016 08:34:45 +0000 Subject: perf tools: Enable overwrite settings This patch allows following config terms and option: Globally setting events to overwrite; # perf record --overwrite ... Set specific events to be overwrite or no-overwrite. # perf record --event cycles/overwrite/ ... # perf record --event cycles/no-overwrite/ ... Add missing config terms and update the config term array size because the longest string length has changed. For overwritable events, it automatically selects attr.write_backward since perf requires it to be backward for reading. Test result: # perf record --overwrite -e syscalls:*enter_nanosleep* usleep 1 [ perf record: Woken up 2 times to write data ] [ perf record: Captured and wrote 0.011 MB perf.data (1 samples) ] # perf evlist -v syscalls:sys_enter_nanosleep: type: 2, size: 112, config: 0x134, { sample_period, sample_freq }: 1, sample_type: IP|TID|TIME|CPU|PERIOD|RAW, disabled: 1, inherit: 1, mmap: 1, comm: 1, enable_on_exec: 1, task: 1, sample_id_all: 1, exclude_guest: 1, mmap2: 1, comm_exec: 1, write_backward: 1 # Tip: use 'perf evlist --trace-fields' to show fields for tracepoint events Signed-off-by: Wang Nan Tested-by: Arnaldo Carvalho de Melo Acked-by: Jiri Olsa Cc: Masami Hiramatsu Cc: Namhyung Kim Cc: Nilay Vaish Cc: Zefan Li Cc: pi3orama@163.com Link: http://lkml.kernel.org/r/1468485287-33422-14-git-send-email-wangnan0@huawei.com Signed-off-by: He Kuang Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/Documentation/perf-record.txt b/tools/perf/Documentation/perf-record.txt index 5b46b1d..384c630 100644 --- a/tools/perf/Documentation/perf-record.txt +++ b/tools/perf/Documentation/perf-record.txt @@ -367,6 +367,20 @@ options. 'perf record --dry-run -e' can act as a BPF script compiler if llvm.dump-obj in config file is set to true. +--overwrite:: +Makes all events use an overwritable ring buffer. An overwritable ring +buffer works like a flight recorder: when it gets full, the kernel will +overwrite the oldest records, that thus will never make it to the +perf.data file. + +When '--overwrite' and '--switch-output' are used perf records and drops +events until it receives a signal, meaning that something unusual was +detected that warrants taking a snapshot of the most current events, +those fitting in the ring buffer at that moment. + +'overwrite' attribute can also be set or canceled for an event using +config terms. For example: 'cycles/overwrite/' and 'instructions/no-overwrite/'. + SEE ALSO -------- linkperf:perf-stat[1], linkperf:perf-list[1] diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index b87070b..39c7486 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -1399,6 +1399,7 @@ struct option __record_options[] = { OPT_BOOLEAN_SET('i', "no-inherit", &record.opts.no_inherit, &record.opts.no_inherit_set, "child tasks do not inherit counters"), + OPT_BOOLEAN(0, "overwrite", &record.opts.overwrite, "use overwrite mode"), OPT_UINTEGER('F', "freq", &record.opts.user_freq, "profile at this frequency"), OPT_CALLBACK('m', "mmap-pages", &record.opts, "pages[,pages]", "number of mmap data pages and AUX area tracing mmap pages", diff --git a/tools/perf/perf.h b/tools/perf/perf.h index cd8f1b1..608b42b 100644 --- a/tools/perf/perf.h +++ b/tools/perf/perf.h @@ -59,6 +59,7 @@ struct record_opts { bool record_switch_events; bool all_kernel; bool all_user; + bool overwrite; unsigned int freq; unsigned int mmap_pages; unsigned int auxtrace_mmap_pages; diff --git a/tools/perf/tests/backward-ring-buffer.c b/tools/perf/tests/backward-ring-buffer.c index db9cd30..615780c 100644 --- a/tools/perf/tests/backward-ring-buffer.c +++ b/tools/perf/tests/backward-ring-buffer.c @@ -108,7 +108,11 @@ int test__backward_ring_buffer(int subtest __maybe_unused) } bzero(&parse_error, sizeof(parse_error)); - err = parse_events(evlist, "syscalls:sys_enter_prctl", &parse_error); + /* + * Set backward bit, ring buffer should be writing from end. Record + * it in aux evlist + */ + err = parse_events(evlist, "syscalls:sys_enter_prctl/overwrite/", &parse_error); if (err) { pr_debug("Failed to parse tracepoint event, try use root\n"); ret = TEST_SKIP; @@ -117,10 +121,6 @@ int test__backward_ring_buffer(int subtest __maybe_unused) perf_evlist__config(evlist, &opts, NULL); - /* Set backward bit, ring buffer should be writing from end */ - evlist__for_each_entry(evlist, evsel) - evsel->attr.write_backward = 1; - err = perf_evlist__open(evlist); if (err < 0) { pr_debug("perf_evlist__open: %s\n", diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index 9ac2f92..8c54df6 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c @@ -695,6 +695,9 @@ static void apply_config_terms(struct perf_evsel *evsel, */ attr->inherit = term->val.inherit ? 1 : 0; break; + case PERF_EVSEL__CONFIG_TERM_OVERWRITE: + attr->write_backward = term->val.overwrite ? 1 : 0; + break; default: break; } @@ -776,6 +779,7 @@ void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts, attr->sample_id_all = perf_missing_features.sample_id_all ? 0 : 1; attr->inherit = !opts->no_inherit; + attr->write_backward = opts->overwrite ? 1 : 0; perf_evsel__set_sample_bit(evsel, IP); perf_evsel__set_sample_bit(evsel, TID); diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h index e60cbfc..8a4a6c9 100644 --- a/tools/perf/util/evsel.h +++ b/tools/perf/util/evsel.h @@ -45,6 +45,7 @@ enum { PERF_EVSEL__CONFIG_TERM_STACK_USER, PERF_EVSEL__CONFIG_TERM_INHERIT, PERF_EVSEL__CONFIG_TERM_MAX_STACK, + PERF_EVSEL__CONFIG_TERM_OVERWRITE, PERF_EVSEL__CONFIG_TERM_MAX, }; @@ -59,6 +60,7 @@ struct perf_evsel_config_term { u64 stack_user; int max_stack; bool inherit; + bool overwrite; } val; }; diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index 375af0e..6c913c3 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -902,6 +902,8 @@ static const char *config_term_names[__PARSE_EVENTS__TERM_TYPE_NR] = { [PARSE_EVENTS__TERM_TYPE_NOINHERIT] = "no-inherit", [PARSE_EVENTS__TERM_TYPE_INHERIT] = "inherit", [PARSE_EVENTS__TERM_TYPE_MAX_STACK] = "max-stack", + [PARSE_EVENTS__TERM_TYPE_OVERWRITE] = "overwrite", + [PARSE_EVENTS__TERM_TYPE_NOOVERWRITE] = "no-overwrite", }; static bool config_term_shrinked; @@ -994,6 +996,12 @@ do { \ case PARSE_EVENTS__TERM_TYPE_NOINHERIT: CHECK_TYPE_VAL(NUM); break; + case PARSE_EVENTS__TERM_TYPE_OVERWRITE: + CHECK_TYPE_VAL(NUM); + break; + case PARSE_EVENTS__TERM_TYPE_NOOVERWRITE: + CHECK_TYPE_VAL(NUM); + break; case PARSE_EVENTS__TERM_TYPE_NAME: CHECK_TYPE_VAL(STR); break; @@ -1046,6 +1054,8 @@ static int config_term_tracepoint(struct perf_event_attr *attr, case PARSE_EVENTS__TERM_TYPE_INHERIT: case PARSE_EVENTS__TERM_TYPE_NOINHERIT: case PARSE_EVENTS__TERM_TYPE_MAX_STACK: + case PARSE_EVENTS__TERM_TYPE_OVERWRITE: + case PARSE_EVENTS__TERM_TYPE_NOOVERWRITE: return config_term_common(attr, term, err); default: if (err) { @@ -1118,6 +1128,12 @@ do { \ case PARSE_EVENTS__TERM_TYPE_MAX_STACK: ADD_CONFIG_TERM(MAX_STACK, max_stack, term->val.num); break; + case PARSE_EVENTS__TERM_TYPE_OVERWRITE: + ADD_CONFIG_TERM(OVERWRITE, overwrite, term->val.num ? 1 : 0); + break; + case PARSE_EVENTS__TERM_TYPE_NOOVERWRITE: + ADD_CONFIG_TERM(OVERWRITE, overwrite, term->val.num ? 0 : 1); + break; default: break; } @@ -2412,9 +2428,9 @@ static void config_terms_list(char *buf, size_t buf_sz) char *parse_events_formats_error_string(char *additional_terms) { char *str; - /* "branch_type" is the longest name */ + /* "no-overwrite" is the longest name */ char static_terms[__PARSE_EVENTS__TERM_TYPE_NR * - (sizeof("branch_type") - 1)]; + (sizeof("no-overwrite") - 1)]; config_terms_list(static_terms, sizeof(static_terms)); /* valid terms */ diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h index b4aa7eb..d1edbf8 100644 --- a/tools/perf/util/parse-events.h +++ b/tools/perf/util/parse-events.h @@ -69,6 +69,8 @@ enum { PARSE_EVENTS__TERM_TYPE_NOINHERIT, PARSE_EVENTS__TERM_TYPE_INHERIT, PARSE_EVENTS__TERM_TYPE_MAX_STACK, + PARSE_EVENTS__TERM_TYPE_NOOVERWRITE, + PARSE_EVENTS__TERM_TYPE_OVERWRITE, __PARSE_EVENTS__TERM_TYPE_NR, }; diff --git a/tools/perf/util/parse-events.l b/tools/perf/util/parse-events.l index 3c15b33..7a25194 100644 --- a/tools/perf/util/parse-events.l +++ b/tools/perf/util/parse-events.l @@ -202,6 +202,8 @@ stack-size { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_STACKSIZE); } max-stack { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_MAX_STACK); } inherit { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_INHERIT); } no-inherit { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_NOINHERIT); } +overwrite { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_OVERWRITE); } +no-overwrite { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_NOOVERWRITE); } , { return ','; } "/" { BEGIN(INITIAL); return '/'; } {name_minus} { return str(yyscanner, PE_NAME); } -- cgit v0.10.2 From f06149c0db430d3694d601df126b0944cc0156a6 Mon Sep 17 00:00:00 2001 From: Wang Nan Date: Thu, 14 Jul 2016 08:34:46 +0000 Subject: perf session: Don't warn about out of order event if write_backward is used If write_backward attribute is set, records are written into kernel ring buffer from end to beginning, but read from beginning to end. To avoid 'XX out of order events recorded' warning message (timestamps of records is in reverse order when using write_backward), suppress the warning message if write_backward is selected by at lease one event. Result: Before this patch: # perf record -m 1 -e raw_syscalls:sys_exit/overwrite/ \ -e raw_syscalls:sys_enter \ dd if=/dev/zero of=/dev/null count=300 300+0 records in 300+0 records out 153600 bytes (154 kB) copied, 0.000601617 s, 255 MB/s [ perf record: Woken up 5 times to write data ] Warning: 40 out of order events recorded. [ perf record: Captured and wrote 0.096 MB perf.data (696 samples) ] After this patch: # perf record -m 1 -e raw_syscalls:sys_exit/overwrite/ \ -e raw_syscalls:sys_enter \ dd if=/dev/zero of=/dev/null count=300 300+0 records in 300+0 records out 153600 bytes (154 kB) copied, 0.000644873 s, 238 MB/s [ perf record: Woken up 5 times to write data ] [ perf record: Captured and wrote 0.096 MB perf.data (696 samples) ] Signed-off-by: Wang Nan Acked-by: Jiri Olsa Tested-by: Arnaldo Carvalho de Melo Cc: Masami Hiramatsu Cc: Namhyung Kim Cc: Nilay Vaish Cc: Zefan Li Cc: pi3orama@163.com Link: http://lkml.kernel.org/r/1468485287-33422-15-git-send-email-wangnan0@huawei.com Signed-off-by: He Kuang Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index 078d496..5d61242 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c @@ -1499,10 +1499,27 @@ int perf_session__register_idle_thread(struct perf_session *session) return err; } +static void +perf_session__warn_order(const struct perf_session *session) +{ + const struct ordered_events *oe = &session->ordered_events; + struct perf_evsel *evsel; + bool should_warn = true; + + evlist__for_each_entry(session->evlist, evsel) { + if (evsel->attr.write_backward) + should_warn = false; + } + + if (!should_warn) + return; + if (oe->nr_unordered_events != 0) + ui__warning("%u out of order events recorded.\n", oe->nr_unordered_events); +} + static void perf_session__warn_about_errors(const struct perf_session *session) { const struct events_stats *stats = &session->evlist->stats; - const struct ordered_events *oe = &session->ordered_events; if (session->tool->lost == perf_event__process_lost && stats->nr_events[PERF_RECORD_LOST] != 0) { @@ -1559,8 +1576,7 @@ static void perf_session__warn_about_errors(const struct perf_session *session) stats->nr_unprocessable_samples); } - if (oe->nr_unordered_events != 0) - ui__warning("%u out of order events recorded.\n", oe->nr_unordered_events); + perf_session__warn_order(session); events_stats__auxtrace_error_warn(stats); -- cgit v0.10.2 From 4ea648aec01982d5a57816a95c4665d6081e78f9 Mon Sep 17 00:00:00 2001 From: Wang Nan Date: Thu, 14 Jul 2016 08:34:47 +0000 Subject: perf record: Add --tail-synthesize option When working with overwritable ring buffer there's a inconvenience problem: if perf dumps data after a long period after it starts, non-sample events may lost, which makes following 'perf report' unable to identify proc name and mmap layout. For example: # perf record -m 4 -e raw_syscalls:* -g --overwrite --switch-output \ dd if=/dev/zero of=/dev/null send SIGUSR2 after dd runs long enough. The resuling perf.data lost correct comm and mmap events: # perf script -i perf.data.2016061522374354 perf 24478 [004] 2581325.601789: raw_syscalls:sys_exit: NR 0 = 512 ^^^^ Should be 'dd' 27b2e8 syscall_slow_exit_work+0xfe2000e3 (/lib/modules/4.6.0-rc3+/build/vmlinux) 203cc7 do_syscall_64+0xfe200117 (/lib/modules/4.6.0-rc3+/build/vmlinux) b18d83 return_from_SYSCALL_64+0xfe200000 (/lib/modules/4.6.0-rc3+/build/vmlinux) 7f47c417edf0 [unknown] ([unknown]) ^^^^^^^^^^^^ Fail to unwind This patch provides a '--tail-synthesize' option, allows perf to collect system status when finalizing output file. In resuling output file, the non-sample events reflect system status when dumping data. After this patch: # perf record -m 4 -e raw_syscalls:* -g --overwrite --switch-output --tail-synthesize \ dd if=/dev/zero of=/dev/null # perf script -i perf.data.2016061600544998 dd 27364 [004] 2583244.994464: raw_syscalls:sys_enter: NR 1 (1, ... ^^ Correct comm 203a18 syscall_trace_enter_phase2+0xfe2001a8 ([kernel.kallsyms]) 203aa5 syscall_trace_enter+0xfe200055 ([kernel.kallsyms]) 203caa do_syscall_64+0xfe2000fa ([kernel.kallsyms]) b18d83 return_from_SYSCALL_64+0xfe200000 ([kernel.kallsyms]) d8e50 __GI___libc_write+0xffff01d9639f4010 (/tmp/oxygen_root-w00229757/lib64/libc-2.18.so) ^^^^^ Correct unwind This option doesn't aim to solve this problem completely. If a process terminates before SIGUSR2, we still lost its COMM and MMAP events. For example, we can't unwind correctly from the final perf.data we get from the previous example, because when perf collects the final output file (when we press C-c), 'dd' has been terminated so its '/proc//mmap' becomes empty. However, this is a cheaper choice. To completely solve this problem we need to continously output non-sample events. To satisify the requirement of daemonization, we need to merge them periodically. It is possible but requires much more code and cycles. Automatically select --tail-synthesize when --overwrite is provided. Signed-off-by: Wang Nan Cc: He Kuang Cc: Jiri Olsa Cc: Masami Hiramatsu Cc: Namhyung Kim Cc: Nilay Vaish Cc: Zefan Li Cc: pi3orama@163.com Link: http://lkml.kernel.org/r/1468485287-33422-16-git-send-email-wangnan0@huawei.com Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/Documentation/perf-record.txt b/tools/perf/Documentation/perf-record.txt index 384c630..69966ab 100644 --- a/tools/perf/Documentation/perf-record.txt +++ b/tools/perf/Documentation/perf-record.txt @@ -367,6 +367,12 @@ options. 'perf record --dry-run -e' can act as a BPF script compiler if llvm.dump-obj in config file is set to true. +--tail-synthesize:: +Instead of collecting non-sample events (for example, fork, comm, mmap) at +the beginning of record, collect them during finalizing an output file. +The collected non-sample events reflects the status of the system when +record is finished. + --overwrite:: Makes all events use an overwritable ring buffer. An overwritable ring buffer works like a flight recorder: when it gets full, the kernel will @@ -381,6 +387,8 @@ those fitting in the ring buffer at that moment. 'overwrite' attribute can also be set or canceled for an event using config terms. For example: 'cycles/overwrite/' and 'instructions/no-overwrite/'. +Implies --tail-synthesize. + SEE ALSO -------- linkperf:perf-stat[1], linkperf:perf-list[1] diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index 39c7486..8f2c16d 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -604,13 +604,16 @@ record__finish_output(struct record *rec) return; } -static int record__synthesize_workload(struct record *rec) +static int record__synthesize_workload(struct record *rec, bool tail) { struct { struct thread_map map; struct thread_map_data map_data; } thread_map; + if (rec->opts.tail_synthesize != tail) + return 0; + thread_map.map.nr = 1; thread_map.map.map[0].pid = rec->evlist->workload.pid; thread_map.map.map[0].comm = NULL; @@ -621,7 +624,7 @@ static int record__synthesize_workload(struct record *rec) rec->opts.proc_map_timeout); } -static int record__synthesize(struct record *rec); +static int record__synthesize(struct record *rec, bool tail); static int record__switch_output(struct record *rec, bool at_exit) @@ -632,6 +635,10 @@ record__switch_output(struct record *rec, bool at_exit) /* Same Size: "2015122520103046"*/ char timestamp[] = "InvalidTimestamp"; + record__synthesize(rec, true); + if (target__none(&rec->opts.target)) + record__synthesize_workload(rec, true); + rec->samples = 0; record__finish_output(rec); err = fetch_current_timestamp(timestamp, sizeof(timestamp)); @@ -654,7 +661,7 @@ record__switch_output(struct record *rec, bool at_exit) /* Output tracking events */ if (!at_exit) { - record__synthesize(rec); + record__synthesize(rec, false); /* * In 'perf record --switch-output' without -a, @@ -666,7 +673,7 @@ record__switch_output(struct record *rec, bool at_exit) * perf_event__synthesize_thread_map() for those events. */ if (target__none(&rec->opts.target)) - record__synthesize_workload(rec); + record__synthesize_workload(rec, false); } return fd; } @@ -720,7 +727,7 @@ static const struct perf_event_mmap_page *record__pick_pc(struct record *rec) return NULL; } -static int record__synthesize(struct record *rec) +static int record__synthesize(struct record *rec, bool tail) { struct perf_session *session = rec->session; struct machine *machine = &session->machines.host; @@ -730,6 +737,9 @@ static int record__synthesize(struct record *rec) int fd = perf_data_file__fd(file); int err = 0; + if (rec->opts.tail_synthesize != tail) + return 0; + if (file->is_pipe) { err = perf_event__synthesize_attrs(tool, session, process_synthesized_event); @@ -893,7 +903,7 @@ static int __cmd_record(struct record *rec, int argc, const char **argv) machine = &session->machines.host; - err = record__synthesize(rec); + err = record__synthesize(rec, false); if (err < 0) goto out_child; @@ -1057,6 +1067,9 @@ static int __cmd_record(struct record *rec, int argc, const char **argv) if (!quiet) fprintf(stderr, "[ perf record: Woken up %ld times to write data ]\n", waking); + if (target__none(&rec->opts.target)) + record__synthesize_workload(rec, true); + out_child: if (forks) { int exit_status; @@ -1075,6 +1088,7 @@ out_child: } else status = err; + record__synthesize(rec, true); /* this will be recalculated during process_buildids() */ rec->samples = 0; @@ -1399,6 +1413,8 @@ struct option __record_options[] = { OPT_BOOLEAN_SET('i', "no-inherit", &record.opts.no_inherit, &record.opts.no_inherit_set, "child tasks do not inherit counters"), + OPT_BOOLEAN(0, "tail-synthesize", &record.opts.tail_synthesize, + "synthesize non-sample events at the end of output"), OPT_BOOLEAN(0, "overwrite", &record.opts.overwrite, "use overwrite mode"), OPT_UINTEGER('F', "freq", &record.opts.user_freq, "profile at this frequency"), OPT_CALLBACK('m', "mmap-pages", &record.opts, "pages[,pages]", @@ -1610,6 +1626,9 @@ int cmd_record(int argc, const char **argv, const char *prefix __maybe_unused) } } + if (record.opts.overwrite) + record.opts.tail_synthesize = true; + if (rec->evlist->nr_entries == 0 && perf_evlist__add_default(rec->evlist) < 0) { pr_err("Not enough memory for event selector list\n"); diff --git a/tools/perf/perf.h b/tools/perf/perf.h index 608b42b..a7e0f14 100644 --- a/tools/perf/perf.h +++ b/tools/perf/perf.h @@ -59,6 +59,7 @@ struct record_opts { bool record_switch_events; bool all_kernel; bool all_user; + bool tail_synthesize; bool overwrite; unsigned int freq; unsigned int mmap_pages; -- cgit v0.10.2 From 4a0982f941d6f2550e8c39bc8bb0984b50dddf36 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 15 Jul 2016 17:23:46 -0300 Subject: objtool: Add -I$(srctree)/tools/arch/$(ARCH)/include/uapi So that it can find asm/bitsperlong.h to get the __BITS_PER_LONG definition. Cc: Adrian Hunter Cc: David Ahern Cc: Jiri Olsa Cc: Josh Poimboeuf Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Wang Nan Link: http://lkml.kernel.org/n/tip-pr3pvskh65pey4po7t122z4j@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/objtool/Makefile b/tools/objtool/Makefile index 9a3110c..1f75b0a 100644 --- a/tools/objtool/Makefile +++ b/tools/objtool/Makefile @@ -26,7 +26,7 @@ OBJTOOL_IN := $(OBJTOOL)-in.o all: $(OBJTOOL) -INCLUDES := -I$(srctree)/tools/include +INCLUDES := -I$(srctree)/tools/include -I$(srctree)/tools/arch/$(ARCH)/include/uapi CFLAGS += -Wall -Werror $(EXTRA_WARNINGS) -fomit-frame-pointer -O2 -g $(INCLUDES) LDFLAGS += -lelf $(LIBSUBCMD) -- cgit v0.10.2 From b49364f36cfdb6d540ac961102d7ffaf84279bb6 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 15 Jul 2016 17:32:52 -0300 Subject: objtool: Initialize variable to silence old compiler gcc version 4.1.2 20080704 (Red Hat 4.1.2-55) barfs with: CC /tmp/build/objtool/builtin-check.o cc1: warnings being treated as errors builtin-check.c: In function 'cmd_check': builtin-check.c:667: warning: 'prev_rela' may be used uninitialized in this function mv: cannot stat `/tmp/build/objtool/.builtin-check.o.tmp': No such file or directory make[1]: *** [/tmp/build/objtool/builtin-check.o] Error 1 Init it to NULL to silence it. Cc: Adrian Hunter Cc: David Ahern Cc: Jiri Olsa Cc: Josh Poimboeuf Cc: Namhyung Kim Cc: Wang Nan Link: http://lkml.kernel.org/n/tip-qolo31rl2ojlwj1lj9dhemyz@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/objtool/builtin-check.c b/tools/objtool/builtin-check.c index 92d84b2..4ed30f4 100644 --- a/tools/objtool/builtin-check.c +++ b/tools/objtool/builtin-check.c @@ -664,7 +664,7 @@ static int add_func_switch_tables(struct objtool_file *file, struct symbol *func) { struct instruction *insn, *prev_jump; - struct rela *text_rela, *rodata_rela, *prev_rela; + struct rela *text_rela, *rodata_rela, *prev_rela = NULL; int ret; prev_jump = NULL; -- cgit v0.10.2 From 0ba169ac3600ae4032ee14b4192e6bf5d67723f5 Mon Sep 17 00:00:00 2001 From: Tony Luck Date: Thu, 14 Jul 2016 15:38:43 -0700 Subject: EDAC, sb_edac: Fix Knights Landing In commit 2c1ea4c700af ("EDAC, sb_edac: Use cpu family/model in driver detection") I broke Knights Landing because I failed to notice that it called a wrapper macro "sbridge_get_all_devices_knl" instead of "sbridge_get_all_devices" like all the other types. Now that we include the processor type in the pci_id_table structure we can skip the wrappers and just have the sbridge_get_all_devices() check the type to decide whether to allow duplicate devices and controllers to have registers spread across buses. Fixes: 2c1ea4c700af ("EDAC, sb_edac: Use cpu family/model in driver detection") Tested-by: Lukasz Odzioba Acked-by: Aristeu Rozanski Signed-off-by: Tony Luck Signed-off-by: Linus Torvalds diff --git a/drivers/edac/sb_edac.c b/drivers/edac/sb_edac.c index 6744d88..4fb2eb7 100644 --- a/drivers/edac/sb_edac.c +++ b/drivers/edac/sb_edac.c @@ -2378,22 +2378,19 @@ static int sbridge_get_onedevice(struct pci_dev **prev, * @num_mc: pointer to the memory controllers count, to be incremented in case * of success. * @table: model specific table - * @allow_dups: allow for multiple devices to exist with the same device id - * (as implemented, this isn't expected to work correctly in the - * multi-socket case). - * @multi_bus: don't assume devices on different buses belong to different - * memory controllers. * * returns 0 in case of success or error code */ -static int sbridge_get_all_devices_full(u8 *num_mc, - const struct pci_id_table *table, - int allow_dups, - int multi_bus) +static int sbridge_get_all_devices(u8 *num_mc, + const struct pci_id_table *table) { int i, rc; struct pci_dev *pdev = NULL; + int allow_dups = 0; + int multi_bus = 0; + if (table->type == KNIGHTS_LANDING) + allow_dups = multi_bus = 1; while (table && table->descr) { for (i = 0; i < table->n_devs; i++) { if (!allow_dups || i == 0 || @@ -2420,11 +2417,6 @@ static int sbridge_get_all_devices_full(u8 *num_mc, return 0; } -#define sbridge_get_all_devices(num_mc, table) \ - sbridge_get_all_devices_full(num_mc, table, 0, 0) -#define sbridge_get_all_devices_knl(num_mc, table) \ - sbridge_get_all_devices_full(num_mc, table, 1, 1) - static int sbridge_mci_bind_devs(struct mem_ctl_info *mci, struct sbridge_dev *sbridge_dev) { -- cgit v0.10.2 From aa93d1fee85c890a34f2510a310e55ee76a27848 Mon Sep 17 00:00:00 2001 From: James Patrick-Evans Date: Fri, 15 Jul 2016 16:40:45 +0100 Subject: media: fix airspy usb probe error path Fix a memory leak on probe error of the airspy usb device driver. The problem is triggered when more than 64 usb devices register with v4l2 of type VFL_TYPE_SDR or VFL_TYPE_SUBDEV. The memory leak is caused by the probe function of the airspy driver mishandeling errors and not freeing the corresponding control structures when an error occours registering the device to v4l2 core. A badusb device can emulate 64 of these devices, and then through continual emulated connect/disconnect of the 65th device, cause the kernel to run out of RAM and crash the kernel, thus causing a local DOS vulnerability. Fixes CVE-2016-5400 Signed-off-by: James Patrick-Evans Reviewed-by: Kees Cook Cc: stable@vger.kernel.org # 3.17+ Signed-off-by: Linus Torvalds diff --git a/drivers/media/usb/airspy/airspy.c b/drivers/media/usb/airspy/airspy.c index 87c1293..92d9d42 100644 --- a/drivers/media/usb/airspy/airspy.c +++ b/drivers/media/usb/airspy/airspy.c @@ -1072,7 +1072,7 @@ static int airspy_probe(struct usb_interface *intf, if (ret) { dev_err(s->dev, "Failed to register as video device (%d)\n", ret); - goto err_unregister_v4l2_dev; + goto err_free_controls; } dev_info(s->dev, "Registered as %s\n", video_device_node_name(&s->vdev)); @@ -1081,7 +1081,6 @@ static int airspy_probe(struct usb_interface *intf, err_free_controls: v4l2_ctrl_handler_free(&s->hdl); -err_unregister_v4l2_dev: v4l2_device_unregister(&s->v4l2_dev); err_free_mem: kfree(s); -- cgit v0.10.2 From 083ae308280d13d187512b9babe3454342a7987e Mon Sep 17 00:00:00 2001 From: Jason Baron Date: Thu, 14 Jul 2016 11:38:40 -0400 Subject: tcp: enable per-socket rate limiting of all 'challenge acks' The per-socket rate limit for 'challenge acks' was introduced in the context of limiting ack loops: commit f2b2c582e824 ("tcp: mitigate ACK loops for connections as tcp_sock") And I think it can be extended to rate limit all 'challenge acks' on a per-socket basis. Since we have the global tcp_challenge_ack_limit, this patch allows for tcp_challenge_ack_limit to be set to a large value and effectively rely on the per-socket limit, or set tcp_challenge_ack_limit to a lower value and still prevents a single connections from consuming the entire challenge ack quota. It further moves in the direction of eliminating the global limit at some point, as Eric Dumazet has suggested. This a follow-up to: Subject: tcp: make challenge acks less predictable Cc: Eric Dumazet Cc: David S. Miller Cc: Neal Cardwell Cc: Yuchung Cheng Cc: Yue Cao Signed-off-by: Jason Baron Signed-off-by: David S. Miller diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 91868bb..42bf89a 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -3421,6 +3421,23 @@ static int tcp_ack_update_window(struct sock *sk, const struct sk_buff *skb, u32 return flag; } +static bool __tcp_oow_rate_limited(struct net *net, int mib_idx, + u32 *last_oow_ack_time) +{ + if (*last_oow_ack_time) { + s32 elapsed = (s32)(tcp_time_stamp - *last_oow_ack_time); + + if (0 <= elapsed && elapsed < sysctl_tcp_invalid_ratelimit) { + NET_INC_STATS(net, mib_idx); + return true; /* rate-limited: don't send yet! */ + } + } + + *last_oow_ack_time = tcp_time_stamp; + + return false; /* not rate-limited: go ahead, send dupack now! */ +} + /* Return true if we're currently rate-limiting out-of-window ACKs and * thus shouldn't send a dupack right now. We rate-limit dupacks in * response to out-of-window SYNs or ACKs to mitigate ACK loops or DoS @@ -3434,21 +3451,9 @@ bool tcp_oow_rate_limited(struct net *net, const struct sk_buff *skb, /* Data packets without SYNs are not likely part of an ACK loop. */ if ((TCP_SKB_CB(skb)->seq != TCP_SKB_CB(skb)->end_seq) && !tcp_hdr(skb)->syn) - goto not_rate_limited; - - if (*last_oow_ack_time) { - s32 elapsed = (s32)(tcp_time_stamp - *last_oow_ack_time); - - if (0 <= elapsed && elapsed < sysctl_tcp_invalid_ratelimit) { - NET_INC_STATS(net, mib_idx); - return true; /* rate-limited: don't send yet! */ - } - } - - *last_oow_ack_time = tcp_time_stamp; + return false; -not_rate_limited: - return false; /* not rate-limited: go ahead, send dupack now! */ + return __tcp_oow_rate_limited(net, mib_idx, last_oow_ack_time); } /* RFC 5961 7 [ACK Throttling] */ @@ -3461,9 +3466,9 @@ static void tcp_send_challenge_ack(struct sock *sk, const struct sk_buff *skb) u32 count, now; /* First check our per-socket dupack rate limit. */ - if (tcp_oow_rate_limited(sock_net(sk), skb, - LINUX_MIB_TCPACKSKIPPEDCHALLENGE, - &tp->last_oow_ack_time)) + if (__tcp_oow_rate_limited(sock_net(sk), + LINUX_MIB_TCPACKSKIPPEDCHALLENGE, + &tp->last_oow_ack_time)) return; /* Then check host-wide RFC 5961 rate limit. */ -- cgit v0.10.2 From c961e877cff4b669788900a7e12386f67efbe2d3 Mon Sep 17 00:00:00 2001 From: Grant Grundler Date: Thu, 14 Jul 2016 11:27:16 -0700 Subject: r8152: add MODULE_VERSION ethtool -i provides a driver version that is hard coded. Export the same value via "modinfo". Signed-off-by: Grant Grundler Signed-off-by: David S. Miller diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c index 63f4018..e9654a6 100644 --- a/drivers/net/usb/r8152.c +++ b/drivers/net/usb/r8152.c @@ -4425,3 +4425,4 @@ module_usb_driver(rtl8152_driver); MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); +MODULE_VERSION(DRIVER_VERSION); -- cgit v0.10.2 From 3e0a396546450536679ae4d3bd70290ce0b0c79c Mon Sep 17 00:00:00 2001 From: Jann Horn Date: Fri, 11 Sep 2015 21:39:33 +0200 Subject: xfs: fix type confusion in xfs_ioc_swapext Without this check, the following XFS_I invocations would return bad pointers when used on non-XFS inodes (perhaps pointers into preceding allocator chunks). This could be used by an attacker to trick xfs_swap_extents into performing locking operations on attacker-chosen structures in kernel memory, potentially leading to code execution in the kernel. (I have not investigated how likely this is to be usable for an attack in practice.) Signed-off-by: Jann Horn Cc: Andy Lutomirski Cc: Dave Chinner Signed-off-by: Linus Torvalds diff --git a/fs/xfs/xfs_ioctl.c b/fs/xfs/xfs_ioctl.c index dbca737..63a6ff2 100644 --- a/fs/xfs/xfs_ioctl.c +++ b/fs/xfs/xfs_ioctl.c @@ -1575,6 +1575,12 @@ xfs_ioc_swapext( goto out_put_tmp_file; } + if (f.file->f_op != &xfs_file_operations || + tmp.file->f_op != &xfs_file_operations) { + error = -EINVAL; + goto out_put_tmp_file; + } + ip = XFS_I(file_inode(f.file)); tip = XFS_I(file_inode(tmp.file)); -- cgit v0.10.2 From 6277d46b10a0b35c83656f085cf8e32ded6fdd60 Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Fri, 15 Jul 2016 11:14:58 +0200 Subject: mlxsw: spectrum: Force link training according to admin state When setting a new speed we need to disable and enable the port for the changes to take effect. We currently only do that if the operational state of the port is up. However, setting a new speed following link training failure will require us to explicitly set the port down and then up. Instead, disable and enable the port based on its administrative state. Fixes: 56ade8fe3fe1 ("mlxsw: spectrum: Add initial support for Spectrum ASIC") Signed-off-by: Ido Schimmel Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c index 660429e..5ccdf22 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c @@ -171,23 +171,6 @@ static int mlxsw_sp_port_admin_status_set(struct mlxsw_sp_port *mlxsw_sp_port, return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(paos), paos_pl); } -static int mlxsw_sp_port_oper_status_get(struct mlxsw_sp_port *mlxsw_sp_port, - bool *p_is_up) -{ - struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; - char paos_pl[MLXSW_REG_PAOS_LEN]; - u8 oper_status; - int err; - - mlxsw_reg_paos_pack(paos_pl, mlxsw_sp_port->local_port, 0); - err = mlxsw_reg_query(mlxsw_sp->core, MLXSW_REG(paos), paos_pl); - if (err) - return err; - oper_status = mlxsw_reg_paos_oper_status_get(paos_pl); - *p_is_up = oper_status == MLXSW_PORT_ADMIN_STATUS_UP ? true : false; - return 0; -} - static int mlxsw_sp_port_dev_addr_set(struct mlxsw_sp_port *mlxsw_sp_port, unsigned char *addr) { @@ -1493,7 +1476,6 @@ static int mlxsw_sp_port_set_settings(struct net_device *dev, u32 eth_proto_new; u32 eth_proto_cap; u32 eth_proto_admin; - bool is_up; int err; speed = ethtool_cmd_speed(cmd); @@ -1525,12 +1507,7 @@ static int mlxsw_sp_port_set_settings(struct net_device *dev, return err; } - err = mlxsw_sp_port_oper_status_get(mlxsw_sp_port, &is_up); - if (err) { - netdev_err(dev, "Failed to get oper status"); - return err; - } - if (!is_up) + if (!netif_running(dev)) return 0; err = mlxsw_sp_port_admin_status_set(mlxsw_sp_port, false); -- cgit v0.10.2 From c3f1576810affced47684e04a08c1ffa845144c9 Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Fri, 15 Jul 2016 11:14:59 +0200 Subject: mlxsw: spectrum: Indicate support for autonegotiation The device supports link autonegotiation, so let the user know about it by indicating support via ethtool ops. Fixes: 56ade8fe3fe1 ("mlxsw: spectrum: Add initial support for Spectrum ASIC") Signed-off-by: Ido Schimmel Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c index 5ccdf22..3740800 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c @@ -1417,7 +1417,8 @@ static int mlxsw_sp_port_get_settings(struct net_device *dev, cmd->supported = mlxsw_sp_from_ptys_supported_port(eth_proto_cap) | mlxsw_sp_from_ptys_supported_link(eth_proto_cap) | - SUPPORTED_Pause | SUPPORTED_Asym_Pause; + SUPPORTED_Pause | SUPPORTED_Asym_Pause | + SUPPORTED_Autoneg; cmd->advertising = mlxsw_sp_from_ptys_advert_link(eth_proto_admin); mlxsw_sp_from_ptys_speed_duplex(netif_carrier_ok(dev), eth_proto_oper, cmd); -- cgit v0.10.2 From 7347180dcaed9c5582732f9372ac940b9b1a907d Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Fri, 15 Jul 2016 11:15:00 +0200 Subject: mlxsw: spectrum: Don't emit errors when PFC is disabled We can't have PAUSE frames and PFC both enabled on the same port, but the fact that ieee_setpfc() was called doesn't necessarily mean PFC is enabled. Only emit errors when PAUSE frames and PFC are enabled simultaneously. Fixes: d81a6bdb87ce ("mlxsw: spectrum: Add IEEE 802.1Qbb PFC support") Signed-off-by: Ido Schimmel Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_dcb.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_dcb.c index 0b32366..5d4b1e7 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_dcb.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_dcb.c @@ -351,7 +351,8 @@ static int mlxsw_sp_dcbnl_ieee_setpfc(struct net_device *dev, struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev); int err; - if (mlxsw_sp_port->link.tx_pause || mlxsw_sp_port->link.rx_pause) { + if ((mlxsw_sp_port->link.tx_pause || mlxsw_sp_port->link.rx_pause) && + pfc->pfc_en) { netdev_err(dev, "PAUSE frames already enabled on port\n"); return -EINVAL; } -- cgit v0.10.2 From 28f5275e4aab97680c8243ec26e202e44c99e5bf Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Fri, 15 Jul 2016 11:15:01 +0200 Subject: mlxsw: spectrum: Prevent overwrite of DCB capability fields The number of supported traffic classes that can have ETS and PFC simultaneously enabled is not subject to user configuration, so make sure we always initialize them to the correct values following a set operation. Fixes: 8e8dfe9fdf06 ("mlxsw: spectrum: Add IEEE 802.1Qaz ETS support") Fixes: d81a6bdb87ce ("mlxsw: spectrum: Add IEEE 802.1Qbb PFC support") Signed-off-by: Ido Schimmel Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_dcb.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_dcb.c index 5d4b1e7..4af3f27 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_dcb.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_dcb.c @@ -249,6 +249,7 @@ static int mlxsw_sp_dcbnl_ieee_setets(struct net_device *dev, return err; memcpy(mlxsw_sp_port->dcb.ets, ets, sizeof(*ets)); + mlxsw_sp_port->dcb.ets->ets_cap = IEEE_8021QAZ_MAX_TCS; return 0; } @@ -372,6 +373,7 @@ static int mlxsw_sp_dcbnl_ieee_setpfc(struct net_device *dev, } memcpy(mlxsw_sp_port->dcb.pfc, pfc, sizeof(*pfc)); + mlxsw_sp_port->dcb.pfc->pfc_cap = IEEE_8021QAZ_MAX_TCS; return 0; -- cgit v0.10.2 From 11719a58bdf7724c463db54ea2abcec54a87b69c Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Fri, 15 Jul 2016 11:15:02 +0200 Subject: mlxsw: spectrum: Prevent invalid ingress buffer mapping Packets entering the switch are mapped to a Switch Priority (SP) according to their PCP value (untagged frames are mapped to SP 0). The packets are classified to a priority group (PG) buffer in the port's headroom according to their SP. The switch maintains another mapping (SP to IEEE priority), which is used to generate PFC frames for lossless PGs. This mapping is initialized to IEEE = SP % 8. Therefore, when mapping SP 'x' to PG 'y' we create a situation in which an IEEE priority is mapped to two different PGs: IEEE 'x' ---> SP 'x' ---> PG 'y' IEEE 'x' ---> SP 'x + 8' ---> PG '0' (default) Which is invalid, as a flow can use only one PG buffer. Fix this by mapping both SP 'x' and 'x + 8' to the same PG buffer. Fixes: 8e8dfe9fdf06 ("mlxsw: spectrum: Add IEEE 802.1Qaz ETS support") Signed-off-by: Ido Schimmel Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/mellanox/mlxsw/reg.h b/drivers/net/ethernet/mellanox/mlxsw/reg.h index 1977e7a..57d48da 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/reg.h +++ b/drivers/net/ethernet/mellanox/mlxsw/reg.h @@ -2718,7 +2718,7 @@ static inline void mlxsw_reg_ppcnt_pack(char *payload, u8 local_port, * Configures the switch priority to buffer table. */ #define MLXSW_REG_PPTB_ID 0x500B -#define MLXSW_REG_PPTB_LEN 0x0C +#define MLXSW_REG_PPTB_LEN 0x10 static const struct mlxsw_reg_info mlxsw_reg_pptb = { .id = MLXSW_REG_PPTB_ID, @@ -2784,6 +2784,13 @@ MLXSW_ITEM32(reg, pptb, pm_msb, 0x08, 24, 8); */ MLXSW_ITEM32(reg, pptb, untagged_buff, 0x08, 0, 4); +/* reg_pptb_prio_to_buff_msb + * Mapping of switch priority to one of the allocated receive port + * buffers. + * Access: RW + */ +MLXSW_ITEM_BIT_ARRAY(reg, pptb, prio_to_buff_msb, 0x0C, 0x04, 4); + #define MLXSW_REG_PPTB_ALL_PRIO 0xFF static inline void mlxsw_reg_pptb_pack(char *payload, u8 local_port) @@ -2792,6 +2799,14 @@ static inline void mlxsw_reg_pptb_pack(char *payload, u8 local_port) mlxsw_reg_pptb_mm_set(payload, MLXSW_REG_PPTB_MM_UM); mlxsw_reg_pptb_local_port_set(payload, local_port); mlxsw_reg_pptb_pm_set(payload, MLXSW_REG_PPTB_ALL_PRIO); + mlxsw_reg_pptb_pm_msb_set(payload, MLXSW_REG_PPTB_ALL_PRIO); +} + +static inline void mlxsw_reg_pptb_prio_to_buff_pack(char *payload, u8 prio, + u8 buff) +{ + mlxsw_reg_pptb_prio_to_buff_set(payload, prio, buff); + mlxsw_reg_pptb_prio_to_buff_msb_set(payload, prio, buff); } /* PBMC - Port Buffer Management Control Register diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_buffers.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_buffers.c index a3720a0..074cdda 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_buffers.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_buffers.c @@ -194,7 +194,7 @@ static int mlxsw_sp_port_pb_prio_init(struct mlxsw_sp_port *mlxsw_sp_port) mlxsw_reg_pptb_pack(pptb_pl, mlxsw_sp_port->local_port); for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) - mlxsw_reg_pptb_prio_to_buff_set(pptb_pl, i, 0); + mlxsw_reg_pptb_prio_to_buff_pack(pptb_pl, i, 0); return mlxsw_reg_write(mlxsw_sp_port->mlxsw_sp->core, MLXSW_REG(pptb), pptb_pl); } diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_dcb.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_dcb.c index 4af3f27..01cfb75 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_dcb.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_dcb.c @@ -103,7 +103,8 @@ static int mlxsw_sp_port_pg_prio_map(struct mlxsw_sp_port *mlxsw_sp_port, mlxsw_reg_pptb_pack(pptb_pl, mlxsw_sp_port->local_port); for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) - mlxsw_reg_pptb_prio_to_buff_set(pptb_pl, i, prio_tc[i]); + mlxsw_reg_pptb_prio_to_buff_pack(pptb_pl, i, prio_tc[i]); + return mlxsw_reg_write(mlxsw_sp_port->mlxsw_sp->core, MLXSW_REG(pptb), pptb_pl); } -- cgit v0.10.2 From e86663c475d384ab5f46cb5637e9b7ad08c5c505 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Fri, 15 Jul 2016 15:42:52 -0700 Subject: net: bgmac: Fix infinite loop in bgmac_dma_tx_add() Nothing is decrementing the index "i" while we are cleaning up the fragments we could not successful transmit. Fixes: 9cde94506eacf ("bgmac: implement scatter/gather support") Reported-by: coverity (CID 1352048) Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/broadcom/bgmac.c b/drivers/net/ethernet/broadcom/bgmac.c index a6333d3..25bbae5 100644 --- a/drivers/net/ethernet/broadcom/bgmac.c +++ b/drivers/net/ethernet/broadcom/bgmac.c @@ -231,7 +231,7 @@ err_dma: dma_unmap_single(dma_dev, slot->dma_addr, skb_headlen(skb), DMA_TO_DEVICE); - while (i > 0) { + while (i-- > 0) { int index = (ring->end + i) % BGMAC_TX_RING_SLOTS; struct bgmac_slot_info *slot = &ring->slots[index]; u32 ctl1 = le32_to_cpu(ring->cpu_base[index].ctl1); -- cgit v0.10.2 From 2b271cb7203dd4dcea991119367df2ed7e66f3c7 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Fri, 15 Jul 2016 15:58:55 -0700 Subject: lkdtm: hide unused functions A conversion of the lkdtm core module added an "#ifdef CONFIG_KPROBES" check, but a number of functions then become unused: drivers/misc/lkdtm_core.c:340:16: error: 'lkdtm_debugfs_entry' defined but not used [-Werror=unused-function] drivers/misc/lkdtm_core.c:122:12: error: 'jp_generic_ide_ioctl' defined but not used [-Werror=unused-function] drivers/misc/lkdtm_core.c:114:12: error: 'jp_scsi_dispatch_cmd' defined but not used [-Werror=unused-function] drivers/misc/lkdtm_core.c:106:12: error: 'jp_hrtimer_start' defined but not used [-Werror=unused-function] drivers/misc/lkdtm_core.c:97:22: error: 'jp_shrink_inactive_list' defined but not used [-Werror=unused-function] drivers/misc/lkdtm_core.c:89:13: error: 'jp_ll_rw_block' defined but not used [-Werror=unused-function] drivers/misc/lkdtm_core.c:83:13: error: 'jp_tasklet_action' defined but not used [-Werror=unused-function] drivers/misc/lkdtm_core.c:75:20: error: 'jp_handle_irq_event' defined but not used [-Werror=unused-function] drivers/misc/lkdtm_core.c:68:21: error: 'jp_do_irq' defined but not used [-Werror=unused-function] This adds the same #ifdef everywhere. There is probably a better way to do the same thing, but for now this avoids the new warnings. Signed-off-by: Arnd Bergmann Fixes: c479e3fd8870 ("lkdtm: use struct arrays instead of enums") [kees: moved some code around to better consolidate the #ifdefs] Signed-off-by: Kees Cook diff --git a/drivers/misc/lkdtm_core.c b/drivers/misc/lkdtm_core.c index de29a33..717aad6 100644 --- a/drivers/misc/lkdtm_core.c +++ b/drivers/misc/lkdtm_core.c @@ -53,12 +53,14 @@ #define DEFAULT_COUNT 10 -static void lkdtm_handler(void); static int lkdtm_debugfs_open(struct inode *inode, struct file *file); static ssize_t lkdtm_debugfs_read(struct file *f, char __user *user_buf, size_t count, loff_t *off); static ssize_t direct_entry(struct file *f, const char __user *user_buf, size_t count, loff_t *off); + +#ifdef CONFIG_KPROBES +static void lkdtm_handler(void); static ssize_t lkdtm_debugfs_entry(struct file *f, const char __user *user_buf, size_t count, loff_t *off); @@ -118,7 +120,7 @@ static int jp_scsi_dispatch_cmd(struct scsi_cmnd *cmd) return 0; } -#ifdef CONFIG_IDE +# ifdef CONFIG_IDE static int jp_generic_ide_ioctl(ide_drive_t *drive, struct file *file, struct block_device *bdev, unsigned int cmd, unsigned long arg) @@ -127,9 +129,9 @@ static int jp_generic_ide_ioctl(ide_drive_t *drive, struct file *file, jprobe_return(); return 0; } +# endif #endif - /* Crash points */ struct crashpoint { const char *name; @@ -238,10 +240,6 @@ static struct jprobe *lkdtm_jprobe; struct crashpoint *lkdtm_crashpoint; struct crashtype *lkdtm_crashtype; -/* Global crash counter and spinlock. */ -static int crash_count = DEFAULT_COUNT; -static DEFINE_SPINLOCK(crash_count_lock); - /* Module parameters */ static int recur_count = -1; module_param(recur_count, int, 0644); @@ -285,29 +283,6 @@ static noinline void lkdtm_do_action(struct crashtype *crashtype) crashtype->func(); } -/* Called by jprobe entry points. */ -static void lkdtm_handler(void) -{ - unsigned long flags; - bool do_it = false; - - BUG_ON(!lkdtm_crashpoint || !lkdtm_crashtype); - - spin_lock_irqsave(&crash_count_lock, flags); - crash_count--; - pr_info("Crash point %s of type %s hit, trigger in %d rounds\n", - lkdtm_crashpoint->name, lkdtm_crashtype->name, crash_count); - - if (crash_count == 0) { - do_it = true; - crash_count = cpoint_count; - } - spin_unlock_irqrestore(&crash_count_lock, flags); - - if (do_it) - lkdtm_do_action(lkdtm_crashtype); -} - static int lkdtm_register_cpoint(struct crashpoint *crashpoint, struct crashtype *crashtype) { @@ -337,6 +312,34 @@ static int lkdtm_register_cpoint(struct crashpoint *crashpoint, return ret; } +#ifdef CONFIG_KPROBES +/* Global crash counter and spinlock. */ +static int crash_count = DEFAULT_COUNT; +static DEFINE_SPINLOCK(crash_count_lock); + +/* Called by jprobe entry points. */ +static void lkdtm_handler(void) +{ + unsigned long flags; + bool do_it = false; + + BUG_ON(!lkdtm_crashpoint || !lkdtm_crashtype); + + spin_lock_irqsave(&crash_count_lock, flags); + crash_count--; + pr_info("Crash point %s of type %s hit, trigger in %d rounds\n", + lkdtm_crashpoint->name, lkdtm_crashtype->name, crash_count); + + if (crash_count == 0) { + do_it = true; + crash_count = cpoint_count; + } + spin_unlock_irqrestore(&crash_count_lock, flags); + + if (do_it) + lkdtm_do_action(lkdtm_crashtype); +} + static ssize_t lkdtm_debugfs_entry(struct file *f, const char __user *user_buf, size_t count, loff_t *off) @@ -374,6 +377,7 @@ static ssize_t lkdtm_debugfs_entry(struct file *f, return count; } +#endif /* Generic read callback that just prints out the available crash types */ static ssize_t lkdtm_debugfs_read(struct file *f, char __user *user_buf, @@ -476,8 +480,10 @@ static int __init lkdtm_module_init(void) } } +#ifdef CONFIG_KPROBES /* Set crash count. */ crash_count = cpoint_count; +#endif /* Handle test-specific initialization. */ lkdtm_bugs_init(&recur_count); -- cgit v0.10.2 From 6d2e91a662256fd88ec0505567a59d21094ed415 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Fri, 15 Jul 2016 16:04:39 -0700 Subject: lkdtm: silence warnings about function declarations When building under W=1, the lack of lkdtm.h in lkdtm_usercopy.c and lkdtm_rodata.c was discovered. This fixes the issue and consolidates the common header and the pr_fmt macro for simplicity and regularity across each test source file. Signed-off-by: Kees Cook diff --git a/drivers/misc/lkdtm.h b/drivers/misc/lkdtm.h index d70a417..fdf954c 100644 --- a/drivers/misc/lkdtm.h +++ b/drivers/misc/lkdtm.h @@ -1,6 +1,10 @@ #ifndef __LKDTM_H #define __LKDTM_H +#define pr_fmt(fmt) "lkdtm: " fmt + +#include + /* lkdtm_bugs.c */ void __init lkdtm_bugs_init(int *recur_param); void lkdtm_PANIC(void); @@ -53,5 +57,4 @@ void lkdtm_USERCOPY_STACK_FRAME_FROM(void); void lkdtm_USERCOPY_STACK_BEYOND(void); void lkdtm_USERCOPY_KERNEL(void); - #endif diff --git a/drivers/misc/lkdtm_bugs.c b/drivers/misc/lkdtm_bugs.c index e87071f..182ae18 100644 --- a/drivers/misc/lkdtm_bugs.c +++ b/drivers/misc/lkdtm_bugs.c @@ -4,12 +4,8 @@ * lockups) along with other things that don't fit well into existing LKDTM * test source files. */ -#define pr_fmt(fmt) "lkdtm: " fmt - -#include -#include - #include "lkdtm.h" +#include /* * Make sure our attempts to over run the kernel stack doesn't trigger diff --git a/drivers/misc/lkdtm_core.c b/drivers/misc/lkdtm_core.c index 717aad6..f9154b8 100644 --- a/drivers/misc/lkdtm_core.c +++ b/drivers/misc/lkdtm_core.c @@ -30,9 +30,7 @@ * * See Documentation/fault-injection/provoke-crashes.txt for instructions */ -#define pr_fmt(fmt) "lkdtm: " fmt - -#include +#include "lkdtm.h" #include #include #include @@ -49,8 +47,6 @@ #include #endif -#include "lkdtm.h" - #define DEFAULT_COUNT 10 static int lkdtm_debugfs_open(struct inode *inode, struct file *file); diff --git a/drivers/misc/lkdtm_heap.c b/drivers/misc/lkdtm_heap.c index 12f50e8..0f15816 100644 --- a/drivers/misc/lkdtm_heap.c +++ b/drivers/misc/lkdtm_heap.c @@ -2,12 +2,8 @@ * This is for all the tests relating directly to heap memory, including * page allocation and slab allocations. */ -#define pr_fmt(fmt) "lkdtm: " fmt - -#include -#include - #include "lkdtm.h" +#include /* * This tries to stay within the next largest power-of-2 kmalloc cache diff --git a/drivers/misc/lkdtm_perms.c b/drivers/misc/lkdtm_perms.c index 8201006..45f1c0f 100644 --- a/drivers/misc/lkdtm_perms.c +++ b/drivers/misc/lkdtm_perms.c @@ -3,17 +3,13 @@ * permissions: non-executable regions, non-writable regions, and * even non-readable regions. */ -#define pr_fmt(fmt) "lkdtm: " fmt - -#include +#include "lkdtm.h" #include #include #include #include #include -#include "lkdtm.h" - /* Whether or not to fill the target memory area with do_nothing(). */ #define CODE_WRITE true #define CODE_AS_IS false diff --git a/drivers/misc/lkdtm_rodata.c b/drivers/misc/lkdtm_rodata.c index 4d0d851..166b1db 100644 --- a/drivers/misc/lkdtm_rodata.c +++ b/drivers/misc/lkdtm_rodata.c @@ -2,7 +2,7 @@ * This includes functions that are meant to live entirely in .rodata * (via objcopy tricks), to validate the non-executability of .rodata. */ -#include +#include "lkdtm.h" void lkdtm_rodata_do_nothing(void) { diff --git a/drivers/misc/lkdtm_usercopy.c b/drivers/misc/lkdtm_usercopy.c index 9c748e8..5a3fd76 100644 --- a/drivers/misc/lkdtm_usercopy.c +++ b/drivers/misc/lkdtm_usercopy.c @@ -2,9 +2,7 @@ * This is for all the tests related to copy_to_user() and copy_from_user() * hardening. */ -#define pr_fmt(fmt) "lkdtm: " fmt - -#include +#include "lkdtm.h" #include #include #include -- cgit v0.10.2 From 50c22cd154e5f7d13072d98ef3e2baba3c074734 Mon Sep 17 00:00:00 2001 From: Matt Ranostay Date: Sat, 9 Jul 2016 23:49:18 -0700 Subject: hwmon: (sht3x) add humidity heater element control The enables control of the SHT31 sensors heating element that can turned on to remove excess humidity. Cc: Guenter Roeck Cc: David Frey Signed-off-by: Matt Ranostay Signed-off-by: Guenter Roeck diff --git a/Documentation/hwmon/sht3x b/Documentation/hwmon/sht3x index f5aa633..b0d8818 100644 --- a/Documentation/hwmon/sht3x +++ b/Documentation/hwmon/sht3x @@ -67,6 +67,10 @@ temp1_alarm: alarm flag is set to 1 if the temperature is outside the configured limits. Alarm only works in periodic measure mode humidity1_alarm: alarm flag is set to 1 if the humidity is outside the configured limits. Alarm only works in periodic measure mode +heater_enable: heater enable, heating element removes excess humidity from + sensor + 0: turned off + 1: turned on update_interval: update interval, 0 for single shot, interval in msec for periodic measurement. If the interval is not supported by the sensor, the next faster interval is chosen diff --git a/drivers/hwmon/sht3x.c b/drivers/hwmon/sht3x.c index 707a3f8..b73a488 100644 --- a/drivers/hwmon/sht3x.c +++ b/drivers/hwmon/sht3x.c @@ -44,6 +44,10 @@ static const unsigned char sht3x_cmd_measure_nonblocking_lpm[] = { 0x24, 0x16 }; static const unsigned char sht3x_cmd_measure_periodic_mode[] = { 0xe0, 0x00 }; static const unsigned char sht3x_cmd_break[] = { 0x30, 0x93 }; +/* commands for heater control */ +static const unsigned char sht3x_cmd_heater_on[] = { 0x30, 0x6d }; +static const unsigned char sht3x_cmd_heater_off[] = { 0x30, 0x66 }; + /* other commands */ static const unsigned char sht3x_cmd_read_status_reg[] = { 0xf3, 0x2d }; static const unsigned char sht3x_cmd_clear_status_reg[] = { 0x30, 0x41 }; @@ -507,6 +511,49 @@ static ssize_t humidity1_alarm_show(struct device *dev, return scnprintf(buf, PAGE_SIZE, "%d\n", !!(buffer[0] & 0x08)); } +static ssize_t heater_enable_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + char buffer[SHT3X_WORD_LEN + SHT3X_CRC8_LEN]; + int ret; + + ret = status_register_read(dev, attr, buffer, + SHT3X_WORD_LEN + SHT3X_CRC8_LEN); + if (ret) + return ret; + + return scnprintf(buf, PAGE_SIZE, "%d\n", !!(buffer[0] & 0x20)); +} + +static ssize_t heater_enable_store(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t count) +{ + struct sht3x_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; + int ret; + bool status; + + ret = kstrtobool(buf, &status); + if (ret) + return ret; + + mutex_lock(&data->i2c_lock); + + if (status) + ret = i2c_master_send(client, (char *)&sht3x_cmd_heater_on, + SHT3X_CMD_LENGTH); + else + ret = i2c_master_send(client, (char *)&sht3x_cmd_heater_off, + SHT3X_CMD_LENGTH); + + mutex_unlock(&data->i2c_lock); + + return ret; +} + static ssize_t update_interval_show(struct device *dev, struct device_attribute *attr, char *buf) @@ -612,6 +659,8 @@ static SENSOR_DEVICE_ATTR(humidity1_min_hyst, S_IRUGO | S_IWUSR, static SENSOR_DEVICE_ATTR(temp1_alarm, S_IRUGO, temp1_alarm_show, NULL, 0); static SENSOR_DEVICE_ATTR(humidity1_alarm, S_IRUGO, humidity1_alarm_show, NULL, 0); +static SENSOR_DEVICE_ATTR(heater_enable, S_IRUGO | S_IWUSR, + heater_enable_show, heater_enable_store, 0); static SENSOR_DEVICE_ATTR(update_interval, S_IRUGO | S_IWUSR, update_interval_show, update_interval_store, 0); @@ -628,6 +677,7 @@ static struct attribute *sht3x_attrs[] = { &sensor_dev_attr_humidity1_min_hyst.dev_attr.attr, &sensor_dev_attr_temp1_alarm.dev_attr.attr, &sensor_dev_attr_humidity1_alarm.dev_attr.attr, + &sensor_dev_attr_heater_enable.dev_attr.attr, &sensor_dev_attr_update_interval.dev_attr.attr, NULL }; -- cgit v0.10.2 From f89252ad19a1a93095bdee58a4d857023f069280 Mon Sep 17 00:00:00 2001 From: Bin Liu Date: Thu, 30 Jun 2016 12:12:21 -0500 Subject: usb: musb: add tracepoints support for debugging To avoid printk() overhead while debugging, this patch implements the foundation of tracepoints logging for musb driver to make debug easier. Signed-off-by: Bin Liu Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/musb/Makefile b/drivers/usb/musb/Makefile index f95befe..689d42a 100644 --- a/drivers/usb/musb/Makefile +++ b/drivers/usb/musb/Makefile @@ -2,9 +2,12 @@ # for USB OTG silicon based on Mentor Graphics INVENTRA designs # +# define_trace.h needs to know how to find our header +CFLAGS_musb_trace.o := -I$(src) + obj-$(CONFIG_USB_MUSB_HDRC) += musb_hdrc.o -musb_hdrc-y := musb_core.o +musb_hdrc-y := musb_core.o musb_trace.o musb_hdrc-$(CONFIG_USB_MUSB_HOST)$(CONFIG_USB_MUSB_DUAL_ROLE) += musb_virthub.o musb_host.o musb_hdrc-$(CONFIG_USB_MUSB_GADGET)$(CONFIG_USB_MUSB_DUAL_ROLE) += musb_gadget_ep0.o musb_gadget.o diff --git a/drivers/usb/musb/musb_debug.h b/drivers/usb/musb/musb_debug.h index 27ba8f7..9a78877 100644 --- a/drivers/usb/musb/musb_debug.h +++ b/drivers/usb/musb/musb_debug.h @@ -42,6 +42,8 @@ #define INFO(fmt, args...) yprintk(KERN_INFO, fmt, ## args) #define ERR(fmt, args...) yprintk(KERN_ERR, fmt, ## args) +void musb_dbg(struct musb *musb, const char *fmt, ...); + #ifdef CONFIG_DEBUG_FS int musb_init_debugfs(struct musb *musb); void musb_exit_debugfs(struct musb *musb); diff --git a/drivers/usb/musb/musb_trace.c b/drivers/usb/musb/musb_trace.c new file mode 100644 index 0000000..70973d9 --- /dev/null +++ b/drivers/usb/musb/musb_trace.c @@ -0,0 +1,33 @@ +/* + * musb_trace.c - MUSB Controller Trace Support + * + * Copyright (C) 2015 Texas Instruments Incorporated - http://www.ti.com + * + * Author: Bin Liu + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 of + * the License as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#define CREATE_TRACE_POINTS +#include "musb_trace.h" + +void musb_dbg(struct musb *musb, const char *fmt, ...) +{ + struct va_format vaf; + va_list args; + + va_start(args, fmt); + vaf.fmt = fmt; + vaf.va = &args; + + trace_musb_log(musb, &vaf); + + va_end(args); +} diff --git a/drivers/usb/musb/musb_trace.h b/drivers/usb/musb/musb_trace.h new file mode 100644 index 0000000..c6c593e --- /dev/null +++ b/drivers/usb/musb/musb_trace.h @@ -0,0 +1,54 @@ +/* + * musb_trace.h - MUSB Controller Trace Support + * + * Copyright (C) 2015 Texas Instruments Incorporated - http://www.ti.com + * + * Author: Bin Liu + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 of + * the License as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#undef TRACE_SYSTEM +#define TRACE_SYSTEM musb + +#if !defined(__MUSB_TRACE_H) || defined(TRACE_HEADER_MULTI_READ) +#define __MUSB_TRACE_H + +#include +#include +#include "musb_core.h" + +#define MUSB_MSG_MAX 500 + +TRACE_EVENT(musb_log, + TP_PROTO(struct musb *musb, struct va_format *vaf), + TP_ARGS(musb, vaf), + TP_STRUCT__entry( + __string(name, dev_name(musb->controller)) + __dynamic_array(char, msg, MUSB_MSG_MAX) + ), + TP_fast_assign( + __assign_str(name, dev_name(musb->controller)); + vsnprintf(__get_str(msg), MUSB_MSG_MAX, vaf->fmt, *vaf->va); + ), + TP_printk("%s: %s", __get_str(name), __get_str(msg)) +); + +#endif /* __MUSB_TRACE_H */ + +/* this part has to be here */ + +#undef TRACE_INCLUDE_PATH +#define TRACE_INCLUDE_PATH . + +#undef TRACE_INCLUDE_FILE +#define TRACE_INCLUDE_FILE musb_trace + +#include -- cgit v0.10.2 From b99d3659b309b358e5b789e644b046d6721c9da4 Mon Sep 17 00:00:00 2001 From: Bin Liu Date: Thu, 30 Jun 2016 12:12:22 -0500 Subject: usb: musb: switch dev_dbg to tracepoints Switch dev_dbg() to tracepoint debug musb_dbg(). Signed-off-by: Bin Liu Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/musb/cppi_dma.c b/drivers/usb/musb/cppi_dma.c index cc13410..5da93ec 100644 --- a/drivers/usb/musb/cppi_dma.c +++ b/drivers/usb/musb/cppi_dma.c @@ -232,7 +232,7 @@ static void cppi_controller_stop(struct cppi *controller) musb_writel(tibase, DAVINCI_RXCPPI_INTCLR_REG, DAVINCI_DMA_ALL_CHANNELS_ENABLE); - dev_dbg(musb->controller, "Tearing down RX and TX Channels\n"); + musb_dbg(musb, "Tearing down RX and TX Channels"); for (i = 0; i < ARRAY_SIZE(controller->tx); i++) { /* FIXME restructure of txdma to use bds like rxdma */ controller->tx[i].last_processed = NULL; @@ -297,13 +297,13 @@ cppi_channel_allocate(struct dma_controller *c, */ if (transmit) { if (index >= ARRAY_SIZE(controller->tx)) { - dev_dbg(musb->controller, "no %cX%d CPPI channel\n", 'T', index); + musb_dbg(musb, "no %cX%d CPPI channel", 'T', index); return NULL; } cppi_ch = controller->tx + index; } else { if (index >= ARRAY_SIZE(controller->rx)) { - dev_dbg(musb->controller, "no %cX%d CPPI channel\n", 'R', index); + musb_dbg(musb, "no %cX%d CPPI channel", 'R', index); return NULL; } cppi_ch = controller->rx + index; @@ -314,13 +314,13 @@ cppi_channel_allocate(struct dma_controller *c, * with the other DMA engine too */ if (cppi_ch->hw_ep) - dev_dbg(musb->controller, "re-allocating DMA%d %cX channel %p\n", + musb_dbg(musb, "re-allocating DMA%d %cX channel %p", index, transmit ? 'T' : 'R', cppi_ch); cppi_ch->hw_ep = ep; cppi_ch->channel.status = MUSB_DMA_STATUS_FREE; cppi_ch->channel.max_len = 0x7fffffff; - dev_dbg(musb->controller, "Allocate CPPI%d %cX\n", index, transmit ? 'T' : 'R'); + musb_dbg(musb, "Allocate CPPI%d %cX", index, transmit ? 'T' : 'R'); return &cppi_ch->channel; } @@ -335,8 +335,8 @@ static void cppi_channel_release(struct dma_channel *channel) c = container_of(channel, struct cppi_channel, channel); tibase = c->controller->tibase; if (!c->hw_ep) - dev_dbg(c->controller->musb->controller, - "releasing idle DMA channel %p\n", c); + musb_dbg(c->controller->musb, + "releasing idle DMA channel %p", c); else if (!c->transmit) core_rxirq_enable(tibase, c->index + 1); @@ -354,11 +354,10 @@ cppi_dump_rx(int level, struct cppi_channel *c, const char *tag) musb_ep_select(base, c->index + 1); - dev_dbg(c->controller->musb->controller, + musb_dbg(c->controller->musb, "RX DMA%d%s: %d left, csr %04x, " "%08x H%08x S%08x C%08x, " - "B%08x L%08x %08x .. %08x" - "\n", + "B%08x L%08x %08x .. %08x", c->index, tag, musb_readl(c->controller->tibase, DAVINCI_RXCPPI_BUFCNT0_REG + 4 * c->index), @@ -385,11 +384,10 @@ cppi_dump_tx(int level, struct cppi_channel *c, const char *tag) musb_ep_select(base, c->index + 1); - dev_dbg(c->controller->musb->controller, + musb_dbg(c->controller->musb, "TX DMA%d%s: csr %04x, " "H%08x S%08x C%08x %08x, " - "F%08x L%08x .. %08x" - "\n", + "F%08x L%08x .. %08x", c->index, tag, musb_readw(c->hw_ep->regs, MUSB_TXCSR), @@ -590,7 +588,7 @@ cppi_next_tx_segment(struct musb *musb, struct cppi_channel *tx) length = min(n_bds * maxpacket, length); } - dev_dbg(musb->controller, "TX DMA%d, pktSz %d %s bds %d dma 0x%llx len %u\n", + musb_dbg(musb, "TX DMA%d, pktSz %d %s bds %d dma 0x%llx len %u", tx->index, maxpacket, rndis ? "rndis" : "transparent", @@ -647,7 +645,7 @@ cppi_next_tx_segment(struct musb *musb, struct cppi_channel *tx) bd->hw_options |= CPPI_ZERO_SET; } - dev_dbg(musb->controller, "TXBD %p: nxt %08x buf %08x len %04x opt %08x\n", + musb_dbg(musb, "TXBD %p: nxt %08x buf %08x len %04x opt %08x", bd, bd->hw_next, bd->hw_bufp, bd->hw_off_len, bd->hw_options); @@ -813,8 +811,8 @@ cppi_next_rx_segment(struct musb *musb, struct cppi_channel *rx, int onepacket) length = min(n_bds * maxpacket, length); - dev_dbg(musb->controller, "RX DMA%d seg, maxp %d %s bds %d (cnt %d) " - "dma 0x%llx len %u %u/%u\n", + musb_dbg(musb, "RX DMA%d seg, maxp %d %s bds %d (cnt %d) " + "dma 0x%llx len %u %u/%u", rx->index, maxpacket, onepacket ? (is_rndis ? "rndis" : "onepacket") @@ -924,7 +922,7 @@ cppi_next_rx_segment(struct musb *musb, struct cppi_channel *rx, int onepacket) DAVINCI_RXCPPI_BUFCNT0_REG + (rx->index * 4)) & 0xffff; if (i < (2 + n_bds)) { - dev_dbg(musb->controller, "bufcnt%d underrun - %d (for %d)\n", + musb_dbg(musb, "bufcnt%d underrun - %d (for %d)", rx->index, i, n_bds); musb_writel(tibase, DAVINCI_RXCPPI_BUFCNT0_REG + (rx->index * 4), @@ -973,7 +971,7 @@ static int cppi_channel_program(struct dma_channel *ch, /* WARN_ON(1); */ break; case MUSB_DMA_STATUS_UNKNOWN: - dev_dbg(musb->controller, "%cX DMA%d not allocated!\n", + musb_dbg(musb, "%cX DMA%d not allocated!", cppi_ch->transmit ? 'T' : 'R', cppi_ch->index); /* FALLTHROUGH */ @@ -1029,8 +1027,8 @@ static bool cppi_rx_scan(struct cppi *cppi, unsigned ch) if (!completed && (bd->hw_options & CPPI_OWN_SET)) break; - dev_dbg(musb->controller, "C/RXBD %llx: nxt %08x buf %08x " - "off.len %08x opt.len %08x (%d)\n", + musb_dbg(musb, "C/RXBD %llx: nxt %08x buf %08x " + "off.len %08x opt.len %08x (%d)", (unsigned long long)bd->dma, bd->hw_next, bd->hw_bufp, bd->hw_off_len, bd->hw_options, rx->channel.actual_len); @@ -1051,7 +1049,7 @@ static bool cppi_rx_scan(struct cppi *cppi, unsigned ch) * CPPI ignores those BDs even though OWN is still set. */ completed = true; - dev_dbg(musb->controller, "rx short %d/%d (%d)\n", + musb_dbg(musb, "rx short %d/%d (%d)", len, bd->buflen, rx->channel.actual_len); } @@ -1101,7 +1099,7 @@ static bool cppi_rx_scan(struct cppi *cppi, unsigned ch) musb_ep_select(cppi->mregs, rx->index + 1); csr = musb_readw(regs, MUSB_RXCSR); if (csr & MUSB_RXCSR_DMAENAB) { - dev_dbg(musb->controller, "list%d %p/%p, last %llx%s, csr %04x\n", + musb_dbg(musb, "list%d %p/%p, last %llx%s, csr %04x", rx->index, rx->head, rx->tail, rx->last_processed @@ -1164,7 +1162,7 @@ irqreturn_t cppi_interrupt(int irq, void *dev_id) return IRQ_NONE; } - dev_dbg(musb->controller, "CPPI IRQ Tx%x Rx%x\n", tx, rx); + musb_dbg(musb, "CPPI IRQ Tx%x Rx%x", tx, rx); /* process TX channels */ for (index = 0; tx; tx = tx >> 1, index++) { @@ -1192,7 +1190,7 @@ irqreturn_t cppi_interrupt(int irq, void *dev_id) * that needs to be acknowledged. */ if (NULL == bd) { - dev_dbg(musb->controller, "null BD\n"); + musb_dbg(musb, "null BD"); musb_writel(&tx_ram->tx_complete, 0, 0); continue; } @@ -1207,7 +1205,7 @@ irqreturn_t cppi_interrupt(int irq, void *dev_id) if (bd->hw_options & CPPI_OWN_SET) break; - dev_dbg(musb->controller, "C/TXBD %p n %x b %x off %x opt %x\n", + musb_dbg(musb, "C/TXBD %p n %x b %x off %x opt %x", bd, bd->hw_next, bd->hw_bufp, bd->hw_off_len, bd->hw_options); diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c index f824336..d2bc45c 100644 --- a/drivers/usb/musb/musb_core.c +++ b/drivers/usb/musb/musb_core.c @@ -461,20 +461,21 @@ static void musb_otg_timer_func(unsigned long data) spin_lock_irqsave(&musb->lock, flags); switch (musb->xceiv->otg->state) { case OTG_STATE_B_WAIT_ACON: - dev_dbg(musb->controller, "HNP: b_wait_acon timeout; back to b_peripheral\n"); + musb_dbg(musb, + "HNP: b_wait_acon timeout; back to b_peripheral"); musb_g_disconnect(musb); musb->xceiv->otg->state = OTG_STATE_B_PERIPHERAL; musb->is_active = 0; break; case OTG_STATE_A_SUSPEND: case OTG_STATE_A_WAIT_BCON: - dev_dbg(musb->controller, "HNP: %s timeout\n", + musb_dbg(musb, "HNP: %s timeout", usb_otg_state_string(musb->xceiv->otg->state)); musb_platform_set_vbus(musb, 0); musb->xceiv->otg->state = OTG_STATE_A_WAIT_VFALL; break; default: - dev_dbg(musb->controller, "HNP: Unhandled mode %s\n", + musb_dbg(musb, "HNP: Unhandled mode %s", usb_otg_state_string(musb->xceiv->otg->state)); } spin_unlock_irqrestore(&musb->lock, flags); @@ -489,17 +490,17 @@ void musb_hnp_stop(struct musb *musb) void __iomem *mbase = musb->mregs; u8 reg; - dev_dbg(musb->controller, "HNP: stop from %s\n", + musb_dbg(musb, "HNP: stop from %s", usb_otg_state_string(musb->xceiv->otg->state)); switch (musb->xceiv->otg->state) { case OTG_STATE_A_PERIPHERAL: musb_g_disconnect(musb); - dev_dbg(musb->controller, "HNP: back to %s\n", + musb_dbg(musb, "HNP: back to %s", usb_otg_state_string(musb->xceiv->otg->state)); break; case OTG_STATE_B_HOST: - dev_dbg(musb->controller, "HNP: Disabling HR\n"); + musb_dbg(musb, "HNP: Disabling HR"); if (hcd) hcd->self.is_b_host = 0; musb->xceiv->otg->state = OTG_STATE_B_PERIPHERAL; @@ -510,7 +511,7 @@ void musb_hnp_stop(struct musb *musb) /* REVISIT: Start SESSION_REQUEST here? */ break; default: - dev_dbg(musb->controller, "HNP: Stopping in unknown state %s\n", + musb_dbg(musb, "HNP: Stopping in unknown state %s", usb_otg_state_string(musb->xceiv->otg->state)); } @@ -541,8 +542,7 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb, { irqreturn_t handled = IRQ_NONE; - dev_dbg(musb->controller, "<== DevCtl=%02x, int_usb=0x%x\n", devctl, - int_usb); + musb_dbg(musb, "<== DevCtl=%02x, int_usb=0x%x", devctl, int_usb); /* in host mode, the peripheral may issue remote wakeup. * in peripheral mode, the host may resume the link. @@ -550,7 +550,7 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb, */ if (int_usb & MUSB_INTR_RESUME) { handled = IRQ_HANDLED; - dev_dbg(musb->controller, "RESUME (%s)\n", + musb_dbg(musb, "RESUME (%s)", usb_otg_state_string(musb->xceiv->otg->state)); if (devctl & MUSB_DEVCTL_HM) { @@ -619,11 +619,11 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb, if ((devctl & MUSB_DEVCTL_VBUS) == MUSB_DEVCTL_VBUS && (devctl & MUSB_DEVCTL_BDEVICE)) { - dev_dbg(musb->controller, "SessReq while on B state\n"); + musb_dbg(musb, "SessReq while on B state"); return IRQ_HANDLED; } - dev_dbg(musb->controller, "SESSION_REQUEST (%s)\n", + musb_dbg(musb, "SESSION_REQUEST (%s)", usb_otg_state_string(musb->xceiv->otg->state)); /* IRQ arrives from ID pin sense or (later, if VBUS power @@ -714,7 +714,7 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb, } if (int_usb & MUSB_INTR_SUSPEND) { - dev_dbg(musb->controller, "SUSPEND (%s) devctl %02x\n", + musb_dbg(musb, "SUSPEND (%s) devctl %02x", usb_otg_state_string(musb->xceiv->otg->state), devctl); handled = IRQ_HANDLED; @@ -743,7 +743,7 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb, musb->is_active = musb->g.b_hnp_enable; if (musb->is_active) { musb->xceiv->otg->state = OTG_STATE_B_WAIT_ACON; - dev_dbg(musb->controller, "HNP: Setting timer for b_ase0_brst\n"); + musb_dbg(musb, "HNP: Setting timer for b_ase0_brst"); mod_timer(&musb->otg_timer, jiffies + msecs_to_jiffies( OTG_TIME_B_ASE0_BRST)); @@ -760,7 +760,7 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb, break; case OTG_STATE_B_HOST: /* Transition to B_PERIPHERAL, see 6.8.2.6 p 44 */ - dev_dbg(musb->controller, "REVISIT: SUSPEND as B_HOST\n"); + musb_dbg(musb, "REVISIT: SUSPEND as B_HOST"); break; default: /* "should not happen" */ @@ -797,14 +797,14 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb, switch (musb->xceiv->otg->state) { case OTG_STATE_B_PERIPHERAL: if (int_usb & MUSB_INTR_SUSPEND) { - dev_dbg(musb->controller, "HNP: SUSPEND+CONNECT, now b_host\n"); + musb_dbg(musb, "HNP: SUSPEND+CONNECT, now b_host"); int_usb &= ~MUSB_INTR_SUSPEND; goto b_host; } else - dev_dbg(musb->controller, "CONNECT as b_peripheral???\n"); + musb_dbg(musb, "CONNECT as b_peripheral???"); break; case OTG_STATE_B_WAIT_ACON: - dev_dbg(musb->controller, "HNP: CONNECT, now b_host\n"); + musb_dbg(musb, "HNP: CONNECT, now b_host"); b_host: musb->xceiv->otg->state = OTG_STATE_B_HOST; if (musb->hcd) @@ -823,12 +823,12 @@ b_host: musb_host_poke_root_hub(musb); - dev_dbg(musb->controller, "CONNECT (%s) devctl %02x\n", + musb_dbg(musb, "CONNECT (%s) devctl %02x", usb_otg_state_string(musb->xceiv->otg->state), devctl); } if (int_usb & MUSB_INTR_DISCONNECT) { - dev_dbg(musb->controller, "DISCONNECT (%s) as %s, devctl %02x\n", + musb_dbg(musb, "DISCONNECT (%s) as %s, devctl %02x", usb_otg_state_string(musb->xceiv->otg->state), MUSB_MODE(musb), devctl); handled = IRQ_HANDLED; @@ -891,7 +891,7 @@ b_host: if (is_host_active(musb)) musb_recover_from_babble(musb); } else { - dev_dbg(musb->controller, "BUS RESET as %s\n", + musb_dbg(musb, "BUS RESET as %s", usb_otg_state_string(musb->xceiv->otg->state)); switch (musb->xceiv->otg->state) { case OTG_STATE_A_SUSPEND: @@ -899,7 +899,7 @@ b_host: /* FALLTHROUGH */ case OTG_STATE_A_WAIT_BCON: /* OPT TD.4.7-900ms */ /* never use invalid T(a_wait_bcon) */ - dev_dbg(musb->controller, "HNP: in %s, %d msec timeout\n", + musb_dbg(musb, "HNP: in %s, %d msec timeout", usb_otg_state_string(musb->xceiv->otg->state), TA_WAIT_BCON(musb)); mod_timer(&musb->otg_timer, jiffies @@ -910,7 +910,7 @@ b_host: musb_g_reset(musb); break; case OTG_STATE_B_WAIT_ACON: - dev_dbg(musb->controller, "HNP: RESET (%s), to b_peripheral\n", + musb_dbg(musb, "HNP: RESET (%s), to b_peripheral", usb_otg_state_string(musb->xceiv->otg->state)); musb->xceiv->otg->state = OTG_STATE_B_PERIPHERAL; musb_g_reset(musb); @@ -922,7 +922,7 @@ b_host: musb_g_reset(musb); break; default: - dev_dbg(musb->controller, "Unhandled BUS RESET as %s\n", + musb_dbg(musb, "Unhandled BUS RESET as %s", usb_otg_state_string(musb->xceiv->otg->state)); } } @@ -1030,7 +1030,7 @@ void musb_start(struct musb *musb) u8 devctl = musb_readb(regs, MUSB_DEVCTL); u8 power; - dev_dbg(musb->controller, "<== devctl %02x\n", devctl); + musb_dbg(musb, "<== devctl %02x", devctl); musb_enable_interrupts(musb); musb_writeb(regs, MUSB_TESTMODE, 0); @@ -1078,7 +1078,7 @@ void musb_stop(struct musb *musb) /* stop IRQs, timers, ... */ musb_platform_disable(musb); musb_generic_disable(musb); - dev_dbg(musb->controller, "HDRC disabled\n"); + musb_dbg(musb, "HDRC disabled"); /* FIXME * - mark host and/or peripheral drivers unusable/inactive @@ -1391,7 +1391,7 @@ static int ep_config_from_hw(struct musb *musb) void __iomem *mbase = musb->mregs; int ret = 0; - dev_dbg(musb->controller, "<== static silicon ep config\n"); + musb_dbg(musb, "<== static silicon ep config"); /* FIXME pick up ep0 maxpacket size */ @@ -1532,8 +1532,7 @@ static int musb_core_init(u16 musb_type, struct musb *musb) hw_ep->tx_reinit = 1; if (hw_ep->max_packet_sz_tx) { - dev_dbg(musb->controller, - "%s: hw_ep %d%s, %smax %d\n", + musb_dbg(musb, "%s: hw_ep %d%s, %smax %d", musb_driver_name, i, hw_ep->is_shared_fifo ? "shared" : "tx", hw_ep->tx_double_buffered @@ -1541,8 +1540,7 @@ static int musb_core_init(u16 musb_type, struct musb *musb) hw_ep->max_packet_sz_tx); } if (hw_ep->max_packet_sz_rx && !hw_ep->is_shared_fifo) { - dev_dbg(musb->controller, - "%s: hw_ep %d%s, %smax %d\n", + musb_dbg(musb, "%s: hw_ep %d%s, %smax %d", musb_driver_name, i, "rx", hw_ep->rx_double_buffered @@ -1550,7 +1548,7 @@ static int musb_core_init(u16 musb_type, struct musb *musb) hw_ep->max_packet_sz_rx); } if (!(hw_ep->max_packet_sz_tx || hw_ep->max_packet_sz_rx)) - dev_dbg(musb->controller, "hw_ep %d not configured\n", i); + musb_dbg(musb, "hw_ep %d not configured", i); } return 0; @@ -1976,7 +1974,7 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl) * Fail when the board needs a feature that's not enabled. */ if (!plat) { - dev_dbg(dev, "no platform_data?\n"); + dev_err(dev, "no platform_data?\n"); status = -ENODEV; goto fail0; } diff --git a/drivers/usb/musb/musb_cppi41.c b/drivers/usb/musb/musb_cppi41.c index e499b86..f7bad72 100644 --- a/drivers/usb/musb/musb_cppi41.c +++ b/drivers/usb/musb/musb_cppi41.c @@ -96,8 +96,8 @@ static void update_rx_toggle(struct cppi41_dma_channel *cppi41_channel) if (!toggle && toggle == cppi41_channel->usb_toggle) { csr |= MUSB_RXCSR_H_DATATOGGLE | MUSB_RXCSR_H_WR_DATATOGGLE; musb_writew(cppi41_channel->hw_ep->regs, MUSB_RXCSR, csr); - dev_dbg(cppi41_channel->controller->musb->controller, - "Restoring DATA1 toggle.\n"); + musb_dbg(cppi41_channel->controller->musb, + "Restoring DATA1 toggle."); } cppi41_channel->usb_toggle = toggle; @@ -240,7 +240,7 @@ static void cppi41_dma_callback(void *private_data) transferred = cppi41_channel->prog_len - txstate.residue; cppi41_channel->transferred += transferred; - dev_dbg(musb->controller, "DMA transfer done on hw_ep=%d bytes=%d/%d\n", + musb_dbg(musb, "DMA transfer done on hw_ep=%d bytes=%d/%d", hw_ep->epnum, cppi41_channel->transferred, cppi41_channel->total_len); @@ -374,8 +374,8 @@ static bool cppi41_configure_channel(struct dma_channel *channel, struct musb *musb = cppi41_channel->controller->musb; unsigned use_gen_rndis = 0; - dev_dbg(musb->controller, - "configure ep%d/%x packet_sz=%d, mode=%d, dma_addr=0x%llx, len=%d is_tx=%d\n", + musb_dbg(musb, + "configure ep%d/%x packet_sz=%d, mode=%d, dma_addr=0x%llx, len=%d is_tx=%d", cppi41_channel->port_num, RNDIS_REG(cppi41_channel->port_num), packet_sz, mode, (unsigned long long) dma_addr, len, cppi41_channel->is_tx); @@ -537,7 +537,7 @@ static int cppi41_dma_channel_abort(struct dma_channel *channel) u16 csr; is_tx = cppi41_channel->is_tx; - dev_dbg(musb->controller, "abort channel=%d, is_tx=%d\n", + musb_dbg(musb, "abort channel=%d, is_tx=%d", cppi41_channel->port_num, is_tx); if (cppi41_channel->channel.status == MUSB_DMA_STATUS_FREE) diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c index af2a3a7..9616059 100644 --- a/drivers/usb/musb/musb_gadget.c +++ b/drivers/usb/musb/musb_gadget.c @@ -168,11 +168,11 @@ __acquires(ep->musb->lock) unmap_dma_buffer(req, musb); if (request->status == 0) - dev_dbg(musb->controller, "%s done request %p, %d/%d\n", + musb_dbg(musb, "%s done request %p, %d/", ep->end_point.name, request, req->request.actual, req->request.length); else - dev_dbg(musb->controller, "%s request %p, %d/%d fault %d\n", + musb_dbg(musb, "%s request %p, %d/%d fault %d", ep->end_point.name, request, req->request.actual, req->request.length, request->status); @@ -217,8 +217,7 @@ static void nuke(struct musb_ep *ep, const int status) } value = c->channel_abort(ep->dma); - dev_dbg(musb->controller, "%s: abort DMA --> %d\n", - ep->name, value); + musb_dbg(musb, "%s: abort DMA --> %d", ep->name, value); c->channel_release(ep->dma); ep->dma = NULL; } @@ -266,14 +265,14 @@ static void txstate(struct musb *musb, struct musb_request *req) /* Check if EP is disabled */ if (!musb_ep->desc) { - dev_dbg(musb->controller, "ep:%s disabled - ignore request\n", + musb_dbg(musb, "ep:%s disabled - ignore request", musb_ep->end_point.name); return; } /* we shouldn't get here while DMA is active ... but we do ... */ if (dma_channel_status(musb_ep->dma) == MUSB_DMA_STATUS_BUSY) { - dev_dbg(musb->controller, "dma pending...\n"); + musb_dbg(musb, "dma pending..."); return; } @@ -285,18 +284,18 @@ static void txstate(struct musb *musb, struct musb_request *req) (int)(request->length - request->actual)); if (csr & MUSB_TXCSR_TXPKTRDY) { - dev_dbg(musb->controller, "%s old packet still ready , txcsr %03x\n", + musb_dbg(musb, "%s old packet still ready , txcsr %03x", musb_ep->end_point.name, csr); return; } if (csr & MUSB_TXCSR_P_SENDSTALL) { - dev_dbg(musb->controller, "%s stalling, txcsr %03x\n", + musb_dbg(musb, "%s stalling, txcsr %03x", musb_ep->end_point.name, csr); return; } - dev_dbg(musb->controller, "hw_ep%d, maxpacket %d, fifo count %d, txcsr %03x\n", + musb_dbg(musb, "hw_ep%d, maxpacket %d, fifo count %d, txcsr %03x", epnum, musb_ep->packet_sz, fifo_count, csr); @@ -424,7 +423,7 @@ static void txstate(struct musb *musb, struct musb_request *req) } /* host may already have the data when this message shows... */ - dev_dbg(musb->controller, "%s TX/IN %s len %d/%d, txcsr %04x, fifo %d/%d\n", + musb_dbg(musb, "%s TX/IN %s len %d/%d, txcsr %04x, fifo %d/%d", musb_ep->end_point.name, use_dma ? "dma" : "pio", request->actual, request->length, musb_readw(epio, MUSB_TXCSR), @@ -451,7 +450,7 @@ void musb_g_tx(struct musb *musb, u8 epnum) request = &req->request; csr = musb_readw(epio, MUSB_TXCSR); - dev_dbg(musb->controller, "<== %s, txcsr %04x\n", musb_ep->end_point.name, csr); + musb_dbg(musb, "<== %s, txcsr %04x", musb_ep->end_point.name, csr); dma = is_dma_capable() ? musb_ep->dma : NULL; @@ -480,7 +479,7 @@ void musb_g_tx(struct musb *musb, u8 epnum) * SHOULD NOT HAPPEN... has with CPPI though, after * changing SENDSTALL (and other cases); harmless? */ - dev_dbg(musb->controller, "%s dma still busy?\n", musb_ep->end_point.name); + musb_dbg(musb, "%s dma still busy?", musb_ep->end_point.name); return; } @@ -497,7 +496,7 @@ void musb_g_tx(struct musb *musb, u8 epnum) /* Ensure writebuffer is empty. */ csr = musb_readw(epio, MUSB_TXCSR); request->actual += musb_ep->dma->actual_len; - dev_dbg(musb->controller, "TXCSR%d %04x, DMA off, len %zu, req %p\n", + musb_dbg(musb, "TXCSR%d %04x, DMA off, len %zu, req %p", epnum, csr, musb_ep->dma->actual_len, request); } @@ -524,7 +523,6 @@ void musb_g_tx(struct musb *musb, u8 epnum) if (csr & MUSB_TXCSR_TXPKTRDY) return; - dev_dbg(musb->controller, "sending zero pkt\n"); musb_writew(epio, MUSB_TXCSR, MUSB_TXCSR_MODE | MUSB_TXCSR_TXPKTRDY); request->zero = 0; @@ -543,7 +541,7 @@ void musb_g_tx(struct musb *musb, u8 epnum) musb_ep_select(mbase, epnum); req = musb_ep->desc ? next_request(musb_ep) : NULL; if (!req) { - dev_dbg(musb->controller, "%s idle now\n", + musb_dbg(musb, "%s idle now", musb_ep->end_point.name); return; } @@ -579,19 +577,19 @@ static void rxstate(struct musb *musb, struct musb_request *req) /* Check if EP is disabled */ if (!musb_ep->desc) { - dev_dbg(musb->controller, "ep:%s disabled - ignore request\n", + musb_dbg(musb, "ep:%s disabled - ignore request", musb_ep->end_point.name); return; } /* We shouldn't get here while DMA is active, but we do... */ if (dma_channel_status(musb_ep->dma) == MUSB_DMA_STATUS_BUSY) { - dev_dbg(musb->controller, "DMA pending...\n"); + musb_dbg(musb, "DMA pending..."); return; } if (csr & MUSB_RXCSR_P_SENDSTALL) { - dev_dbg(musb->controller, "%s stalling, RXCSR %04x\n", + musb_dbg(musb, "%s stalling, RXCSR %04x", musb_ep->end_point.name, csr); return; } @@ -766,7 +764,7 @@ static void rxstate(struct musb *musb, struct musb_request *req) } len = request->length - request->actual; - dev_dbg(musb->controller, "%s OUT/RX pio fifo %d/%d, maxpacket %d\n", + musb_dbg(musb, "%s OUT/RX pio fifo %d/%d, maxpacket %d", musb_ep->end_point.name, fifo_count, len, musb_ep->packet_sz); @@ -854,7 +852,7 @@ void musb_g_rx(struct musb *musb, u8 epnum) csr = musb_readw(epio, MUSB_RXCSR); dma = is_dma_capable() ? musb_ep->dma : NULL; - dev_dbg(musb->controller, "<== %s, rxcsr %04x%s %p\n", musb_ep->end_point.name, + musb_dbg(musb, "<== %s, rxcsr %04x%s %p", musb_ep->end_point.name, csr, dma ? " (dma)" : "", request); if (csr & MUSB_RXCSR_P_SENTSTALL) { @@ -869,18 +867,18 @@ void musb_g_rx(struct musb *musb, u8 epnum) csr &= ~MUSB_RXCSR_P_OVERRUN; musb_writew(epio, MUSB_RXCSR, csr); - dev_dbg(musb->controller, "%s iso overrun on %p\n", musb_ep->name, request); + musb_dbg(musb, "%s iso overrun on %p", musb_ep->name, request); if (request->status == -EINPROGRESS) request->status = -EOVERFLOW; } if (csr & MUSB_RXCSR_INCOMPRX) { /* REVISIT not necessarily an error */ - dev_dbg(musb->controller, "%s, incomprx\n", musb_ep->end_point.name); + musb_dbg(musb, "%s, incomprx", musb_ep->end_point.name); } if (dma_channel_status(dma) == MUSB_DMA_STATUS_BUSY) { /* "should not happen"; likely RXPKTRDY pending for DMA */ - dev_dbg(musb->controller, "%s busy, csr %04x\n", + musb_dbg(musb, "%s busy, csr %04x", musb_ep->end_point.name, csr); return; } @@ -894,7 +892,7 @@ void musb_g_rx(struct musb *musb, u8 epnum) request->actual += musb_ep->dma->actual_len; - dev_dbg(musb->controller, "RXCSR%d %04x, dma off, %04x, len %zu, req %p\n", + musb_dbg(musb, "RXCSR%d %04x, dma off, %04x, len %zu, req %p", epnum, csr, musb_readw(epio, MUSB_RXCSR), musb_ep->dma->actual_len, request); @@ -996,7 +994,7 @@ static int musb_gadget_enable(struct usb_ep *ep, ok = musb->hb_iso_rx; if (!ok) { - dev_dbg(musb->controller, "no support for high bandwidth ISO\n"); + musb_dbg(musb, "no support for high bandwidth ISO"); goto fail; } musb_ep->hb_mult = (tmp >> 11) & 3; @@ -1019,7 +1017,7 @@ static int musb_gadget_enable(struct usb_ep *ep, goto fail; if (tmp > hw_ep->max_packet_sz_tx) { - dev_dbg(musb->controller, "packet size beyond hardware FIFO size\n"); + musb_dbg(musb, "packet size beyond hardware FIFO size"); goto fail; } @@ -1062,7 +1060,7 @@ static int musb_gadget_enable(struct usb_ep *ep, goto fail; if (tmp > hw_ep->max_packet_sz_rx) { - dev_dbg(musb->controller, "packet size beyond hardware FIFO size\n"); + musb_dbg(musb, "packet size beyond hardware FIFO size"); goto fail; } @@ -1174,7 +1172,7 @@ static int musb_gadget_disable(struct usb_ep *ep) spin_unlock_irqrestore(&(musb->lock), flags); - dev_dbg(musb->controller, "%s\n", musb_ep->end_point.name); + musb_dbg(musb, "%s", musb_ep->end_point.name); return status; } @@ -1186,14 +1184,11 @@ static int musb_gadget_disable(struct usb_ep *ep) struct usb_request *musb_alloc_request(struct usb_ep *ep, gfp_t gfp_flags) { struct musb_ep *musb_ep = to_musb_ep(ep); - struct musb *musb = musb_ep->musb; struct musb_request *request = NULL; request = kzalloc(sizeof *request, gfp_flags); - if (!request) { - dev_dbg(musb->controller, "not enough memory\n"); + if (!request) return NULL; - } request->request.dma = DMA_ADDR_INVALID; request->epnum = musb_ep->current_epnum; @@ -1225,7 +1220,7 @@ struct free_record { */ void musb_ep_restart(struct musb *musb, struct musb_request *req) { - dev_dbg(musb->controller, "<== %s request %p len %u on hw_ep%d\n", + musb_dbg(musb, "<== %s request %p len %u on hw_ep%d", req->tx ? "TX/IN" : "RX/OUT", &req->request, req->request.length, req->epnum); @@ -1259,7 +1254,7 @@ static int musb_gadget_queue(struct usb_ep *ep, struct usb_request *req, if (request->ep != musb_ep) return -EINVAL; - dev_dbg(musb->controller, "<== to %s request=%p\n", ep->name, req); + musb_dbg(musb, "<== to %s request=%p", ep->name, req); /* request is mine now... */ request->request.actual = 0; @@ -1273,7 +1268,7 @@ static int musb_gadget_queue(struct usb_ep *ep, struct usb_request *req, /* don't queue if the ep is down */ if (!musb_ep->desc) { - dev_dbg(musb->controller, "req %p queued to %s while ep %s\n", + musb_dbg(musb, "req %p queued to %s while ep %s", req, ep->name, "disabled"); status = -ESHUTDOWN; unmap_dma_buffer(request, musb); @@ -1311,7 +1306,8 @@ static int musb_gadget_dequeue(struct usb_ep *ep, struct usb_request *request) break; } if (r != req) { - dev_dbg(musb->controller, "request %p not queued to %s\n", request, ep->name); + dev_err(musb->controller, "request %p not queued to %s\n", + request, ep->name); status = -EINVAL; goto done; } @@ -1377,7 +1373,7 @@ static int musb_gadget_set_halt(struct usb_ep *ep, int value) request = next_request(musb_ep); if (value) { if (request) { - dev_dbg(musb->controller, "request in progress, cannot halt %s\n", + musb_dbg(musb, "request in progress, cannot halt %s", ep->name); status = -EAGAIN; goto done; @@ -1386,7 +1382,8 @@ static int musb_gadget_set_halt(struct usb_ep *ep, int value) if (musb_ep->is_in) { csr = musb_readw(epio, MUSB_TXCSR); if (csr & MUSB_TXCSR_FIFONOTEMPTY) { - dev_dbg(musb->controller, "FIFO busy, cannot halt %s\n", ep->name); + musb_dbg(musb, "FIFO busy, cannot halt %s", + ep->name); status = -EAGAIN; goto done; } @@ -1395,7 +1392,7 @@ static int musb_gadget_set_halt(struct usb_ep *ep, int value) musb_ep->wedged = 0; /* set/clear the stall and toggle bits */ - dev_dbg(musb->controller, "%s: %s stall\n", ep->name, value ? "set" : "clear"); + musb_dbg(musb, "%s: %s stall", ep->name, value ? "set" : "clear"); if (musb_ep->is_in) { csr = musb_readw(epio, MUSB_TXCSR); csr |= MUSB_TXCSR_P_WZC_BITS @@ -1422,7 +1419,7 @@ static int musb_gadget_set_halt(struct usb_ep *ep, int value) /* maybe start the first request in the queue */ if (!musb_ep->busy && !value && request) { - dev_dbg(musb->controller, "restarting the request\n"); + musb_dbg(musb, "restarting the request"); musb_ep_restart(musb, request); } @@ -1558,7 +1555,7 @@ static int musb_gadget_wakeup(struct usb_gadget *gadget) case OTG_STATE_B_IDLE: /* Start SRP ... OTG not required. */ devctl = musb_readb(mregs, MUSB_DEVCTL); - dev_dbg(musb->controller, "Sending SRP: devctl: %02x\n", devctl); + musb_dbg(musb, "Sending SRP: devctl: %02x", devctl); devctl |= MUSB_DEVCTL_SESSION; musb_writeb(mregs, MUSB_DEVCTL, devctl); devctl = musb_readb(mregs, MUSB_DEVCTL); @@ -1586,7 +1583,7 @@ static int musb_gadget_wakeup(struct usb_gadget *gadget) status = 0; goto done; default: - dev_dbg(musb->controller, "Unhandled wake: %s\n", + musb_dbg(musb, "Unhandled wake: %s", usb_otg_state_string(musb->xceiv->otg->state)); goto done; } @@ -1596,7 +1593,7 @@ static int musb_gadget_wakeup(struct usb_gadget *gadget) power = musb_readb(mregs, MUSB_POWER); power |= MUSB_POWER_RESUME; musb_writeb(mregs, MUSB_POWER, power); - dev_dbg(musb->controller, "issue wakeup\n"); + musb_dbg(musb, "issue wakeup"); /* FIXME do this next chunk in a timer callback, no udelay */ mdelay(2); @@ -1628,7 +1625,7 @@ static void musb_pullup(struct musb *musb, int is_on) /* FIXME if on, HdrcStart; if off, HdrcStop */ - dev_dbg(musb->controller, "gadget D+ pullup %s\n", + musb_dbg(musb, "gadget D+ pullup %s", is_on ? "on" : "off"); musb_writeb(musb->mregs, MUSB_POWER, power); } @@ -1636,7 +1633,7 @@ static void musb_pullup(struct musb *musb, int is_on) #if 0 static int musb_gadget_vbus_session(struct usb_gadget *gadget, int is_active) { - dev_dbg(musb->controller, "<= %s =>\n", __func__); + musb_dbg(musb, "<= %s =>\n", __func__); /* * FIXME iff driver's softconnect flag is set (as it is during probe, @@ -2011,7 +2008,7 @@ void musb_g_suspend(struct musb *musb) u8 devctl; devctl = musb_readb(musb->mregs, MUSB_DEVCTL); - dev_dbg(musb->controller, "devctl %02x\n", devctl); + musb_dbg(musb, "musb_g_suspend: devctl %02x", devctl); switch (musb->xceiv->otg->state) { case OTG_STATE_B_IDLE: @@ -2030,7 +2027,7 @@ void musb_g_suspend(struct musb *musb) /* REVISIT if B_HOST, clear DEVCTL.HOSTREQ; * A_PERIPHERAL may need care too */ - WARNING("unhandled SUSPEND transition (%s)\n", + WARNING("unhandled SUSPEND transition (%s)", usb_otg_state_string(musb->xceiv->otg->state)); } } @@ -2047,7 +2044,7 @@ void musb_g_disconnect(struct musb *musb) void __iomem *mregs = musb->mregs; u8 devctl = musb_readb(mregs, MUSB_DEVCTL); - dev_dbg(musb->controller, "devctl %02x\n", devctl); + musb_dbg(musb, "musb_g_disconnect: devctl %02x", devctl); /* clear HR */ musb_writeb(mregs, MUSB_DEVCTL, devctl & MUSB_DEVCTL_SESSION); @@ -2064,7 +2061,7 @@ void musb_g_disconnect(struct musb *musb) switch (musb->xceiv->otg->state) { default: - dev_dbg(musb->controller, "Unhandled disconnect %s, setting a_idle\n", + musb_dbg(musb, "Unhandled disconnect %s, setting a_idle", usb_otg_state_string(musb->xceiv->otg->state)); musb->xceiv->otg->state = OTG_STATE_A_IDLE; MUSB_HST_MODE(musb); @@ -2094,7 +2091,7 @@ __acquires(musb->lock) u8 devctl = musb_readb(mbase, MUSB_DEVCTL); u8 power; - dev_dbg(musb->controller, "<== %s driver '%s'\n", + musb_dbg(musb, "<== %s driver '%s'", (devctl & MUSB_DEVCTL_BDEVICE) ? "B-Device" : "A-Device", musb->gadget_driver diff --git a/drivers/usb/musb/musb_gadget_ep0.c b/drivers/usb/musb/musb_gadget_ep0.c index 10d30af..844a309 100644 --- a/drivers/usb/musb/musb_gadget_ep0.c +++ b/drivers/usb/musb/musb_gadget_ep0.c @@ -206,7 +206,7 @@ static inline void musb_try_b_hnp_enable(struct musb *musb) void __iomem *mbase = musb->mregs; u8 devctl; - dev_dbg(musb->controller, "HNP: Setting HR\n"); + musb_dbg(musb, "HNP: Setting HR"); devctl = musb_readb(mbase, MUSB_DEVCTL); musb_writeb(mbase, MUSB_DEVCTL, devctl | MUSB_DEVCTL_HR); } @@ -303,7 +303,7 @@ __acquires(musb->lock) /* Maybe start the first request in the queue */ request = next_request(musb_ep); if (!musb_ep->busy && request) { - dev_dbg(musb->controller, "restarting the request\n"); + musb_dbg(musb, "restarting the request"); musb_ep_restart(musb, request); } @@ -550,7 +550,7 @@ static void ep0_txstate(struct musb *musb) if (!req) { /* WARN_ON(1); */ - dev_dbg(musb->controller, "odd; csr0 %04x\n", musb_readw(regs, MUSB_CSR0)); + musb_dbg(musb, "odd; csr0 %04x", musb_readw(regs, MUSB_CSR0)); return; } @@ -607,7 +607,7 @@ musb_read_setup(struct musb *musb, struct usb_ctrlrequest *req) /* NOTE: earlier 2.6 versions changed setup packets to host * order, but now USB packets always stay in USB byte order. */ - dev_dbg(musb->controller, "SETUP req%02x.%02x v%04x i%04x l%d\n", + musb_dbg(musb, "SETUP req%02x.%02x v%04x i%04x l%d", req->bRequestType, req->bRequest, le16_to_cpu(req->wValue), @@ -675,7 +675,7 @@ irqreturn_t musb_g_ep0_irq(struct musb *musb) csr = musb_readw(regs, MUSB_CSR0); len = musb_readb(regs, MUSB_COUNT0); - dev_dbg(musb->controller, "csr %04x, count %d, ep0stage %s\n", + musb_dbg(musb, "csr %04x, count %d, ep0stage %s", csr, len, decode_ep0stage(musb->ep0_state)); if (csr & MUSB_CSR0_P_DATAEND) { @@ -752,7 +752,7 @@ irqreturn_t musb_g_ep0_irq(struct musb *musb) /* enter test mode if needed (exit by reset) */ else if (musb->test_mode) { - dev_dbg(musb->controller, "entering TESTMODE\n"); + musb_dbg(musb, "entering TESTMODE"); if (MUSB_TEST_PACKET == musb->test_mode_nr) musb_load_testpacket(musb); @@ -864,7 +864,7 @@ setup: break; } - dev_dbg(musb->controller, "handled %d, csr %04x, ep0stage %s\n", + musb_dbg(musb, "handled %d, csr %04x, ep0stage %s", handled, csr, decode_ep0stage(musb->ep0_state)); @@ -881,7 +881,7 @@ setup: if (handled < 0) { musb_ep_select(mbase, 0); stall: - dev_dbg(musb->controller, "stall (%d)\n", handled); + musb_dbg(musb, "stall (%d)", handled); musb->ackpend |= MUSB_CSR0_P_SENDSTALL; musb->ep0_state = MUSB_EP0_STAGE_IDLE; finish: @@ -961,7 +961,7 @@ musb_g_ep0_queue(struct usb_ep *e, struct usb_request *r, gfp_t gfp_flags) status = 0; break; default: - dev_dbg(musb->controller, "ep0 request queued in state %d\n", + musb_dbg(musb, "ep0 request queued in state %d", musb->ep0_state); status = -EINVAL; goto cleanup; @@ -970,7 +970,7 @@ musb_g_ep0_queue(struct usb_ep *e, struct usb_request *r, gfp_t gfp_flags) /* add request to the list */ list_add_tail(&req->list, &ep->req_list); - dev_dbg(musb->controller, "queue to %s (%s), length=%d\n", + musb_dbg(musb, "queue to %s (%s), length=%d", ep->name, ep->is_in ? "IN/TX" : "OUT/RX", req->request.length); @@ -1063,7 +1063,7 @@ static int musb_g_ep0_halt(struct usb_ep *e, int value) musb->ackpend = 0; break; default: - dev_dbg(musb->controller, "ep0 can't halt in state %d\n", musb->ep0_state); + musb_dbg(musb, "ep0 can't halt in state %d", musb->ep0_state); status = -EINVAL; } diff --git a/drivers/usb/musb/musb_host.c b/drivers/usb/musb/musb_host.c index d227a71..7601ada 100644 --- a/drivers/usb/musb/musb_host.c +++ b/drivers/usb/musb/musb_host.c @@ -131,7 +131,7 @@ static void musb_h_tx_flush_fifo(struct musb_hw_ep *ep) * I found using a usb-ethernet device and running iperf * (client on AM335x) has very high chance to trigger it. * - * Better to turn on dev_dbg() in musb_cleanup_urb() with + * Better to turn on musb_dbg() in musb_cleanup_urb() with * CPPI enabled to see the issue when aborting the tx channel. */ if (dev_WARN_ONCE(musb->controller, retries-- < 1, @@ -254,7 +254,7 @@ musb_start_urb(struct musb *musb, int is_in, struct musb_qh *qh) len = urb->transfer_buffer_length - urb->actual_length; } - dev_dbg(musb->controller, "qh %p urb %p dev%d ep%d%s%s, hw_ep %d, %p/%d\n", + musb_dbg(musb, "qh %p urb %p dev%d ep%d%s%s, hw_ep %d, %p/%d", qh, urb, address, qh->epnum, is_in ? "in" : "out", ({char *s; switch (qh->type) { @@ -277,7 +277,7 @@ musb_start_urb(struct musb *musb, int is_in, struct musb_qh *qh) switch (qh->type) { case USB_ENDPOINT_XFER_ISOC: case USB_ENDPOINT_XFER_INT: - dev_dbg(musb->controller, "check whether there's still time for periodic Tx\n"); + musb_dbg(musb, "check whether there's still time for periodic Tx"); frame = musb_readw(mbase, MUSB_FRAME); /* FIXME this doesn't implement that scheduling policy ... * or handle framecounter wrapping @@ -291,7 +291,7 @@ musb_start_urb(struct musb *musb, int is_in, struct musb_qh *qh) } else { qh->frame = urb->start_frame; /* enable SOF interrupt so we can count down */ - dev_dbg(musb->controller, "SOF for %d\n", epnum); + musb_dbg(musb, "SOF for %d", epnum); #if 1 /* ifndef CONFIG_ARCH_DAVINCI */ musb_writeb(mbase, MUSB_INTRUSBE, 0xff); #endif @@ -299,7 +299,7 @@ musb_start_urb(struct musb *musb, int is_in, struct musb_qh *qh) break; default: start: - dev_dbg(musb->controller, "Start TX%d %s\n", epnum, + musb_dbg(musb, "Start TX%d %s", epnum, hw_ep->tx_channel ? "dma" : "pio"); if (!hw_ep->tx_channel) @@ -314,8 +314,7 @@ static void musb_giveback(struct musb *musb, struct urb *urb, int status) __releases(musb->lock) __acquires(musb->lock) { - dev_dbg(musb->controller, - "complete %p %pF (%d), dev%d ep%d%s, %d/%d\n", + musb_dbg(musb, "complete %p %pF (%d), dev%d ep%d%s, %d/%d", urb, urb->complete, status, usb_pipedevice(urb->pipe), usb_pipeendpoint(urb->pipe), @@ -441,7 +440,7 @@ static void musb_advance_schedule(struct musb *musb, struct urb *urb, * for RX, until we have a test case to understand the behavior of TX. */ if ((!status || !is_in) && qh && qh->is_ready) { - dev_dbg(musb->controller, "... next ep%d %cX urb %p\n", + musb_dbg(musb, "... next ep%d %cX urb %p", hw_ep->epnum, is_in ? 'R' : 'T', next_urb(qh)); musb_start_urb(musb, is_in, qh); } @@ -486,7 +485,7 @@ musb_host_packet_rx(struct musb *musb, struct urb *urb, u8 epnum, u8 iso_err) /* musb_ep_select(mbase, epnum); */ rx_count = musb_readw(epio, MUSB_RXCOUNT); - dev_dbg(musb->controller, "RX%d count %d, buffer %p len %d/%d\n", epnum, rx_count, + musb_dbg(musb, "RX%d count %d, buffer %p len %d/%d", epnum, rx_count, urb->transfer_buffer, qh->offset, urb->transfer_buffer_length); @@ -508,7 +507,7 @@ musb_host_packet_rx(struct musb *musb, struct urb *urb, u8 epnum, u8 iso_err) status = -EOVERFLOW; urb->error_count++; } - dev_dbg(musb->controller, "** OVERFLOW %d into %d\n", rx_count, length); + musb_dbg(musb, "OVERFLOW %d into %d", rx_count, length); do_flush = 1; } else length = rx_count; @@ -526,7 +525,7 @@ musb_host_packet_rx(struct musb *musb, struct urb *urb, u8 epnum, u8 iso_err) if (rx_count > length) { if (urb->status == -EINPROGRESS) urb->status = -EOVERFLOW; - dev_dbg(musb->controller, "** OVERFLOW %d into %d\n", rx_count, length); + musb_dbg(musb, "OVERFLOW %d into %d", rx_count, length); do_flush = 1; } else length = rx_count; @@ -750,8 +749,8 @@ static void musb_ep_program(struct musb *musb, u8 epnum, u8 use_dma = 1; u16 csr; - dev_dbg(musb->controller, "%s hw%d urb %p spd%d dev%d ep%d%s " - "h_addr%02x h_port%02x bytes %d\n", + musb_dbg(musb, "%s hw%d urb %p spd%d dev%d ep%d%s " + "h_addr%02x h_port%02x bytes %d", is_out ? "-->" : "<--", epnum, urb, urb->dev->speed, qh->addr_reg, qh->epnum, is_out ? "out" : "in", @@ -969,7 +968,7 @@ finish: } csr |= MUSB_RXCSR_H_REQPKT; - dev_dbg(musb->controller, "RXCSR%d := %04x\n", epnum, csr); + musb_dbg(musb, "RXCSR%d := %04x", epnum, csr); musb_writew(hw_ep->regs, MUSB_RXCSR, csr); csr = musb_readw(hw_ep->regs, MUSB_RXCSR); } @@ -1085,15 +1084,15 @@ static bool musb_h_ep0_continue(struct musb *musb, u16 len, struct urb *urb) request = (struct usb_ctrlrequest *) urb->setup_packet; if (!request->wLength) { - dev_dbg(musb->controller, "start no-DATA\n"); + musb_dbg(musb, "start no-DATA"); break; } else if (request->bRequestType & USB_DIR_IN) { - dev_dbg(musb->controller, "start IN-DATA\n"); + musb_dbg(musb, "start IN-DATA"); musb->ep0_stage = MUSB_EP0_IN; more = true; break; } else { - dev_dbg(musb->controller, "start OUT-DATA\n"); + musb_dbg(musb, "start OUT-DATA"); musb->ep0_stage = MUSB_EP0_OUT; more = true; } @@ -1105,7 +1104,7 @@ static bool musb_h_ep0_continue(struct musb *musb, u16 len, struct urb *urb) if (fifo_count) { fifo_dest = (u8 *) (urb->transfer_buffer + urb->actual_length); - dev_dbg(musb->controller, "Sending %d byte%s to ep0 fifo %p\n", + musb_dbg(musb, "Sending %d byte%s to ep0 fifo %p", fifo_count, (fifo_count == 1) ? "" : "s", fifo_dest); @@ -1150,7 +1149,7 @@ irqreturn_t musb_h_ep0_irq(struct musb *musb) ? musb_readb(epio, MUSB_COUNT0) : 0; - dev_dbg(musb->controller, "<== csr0 %04x, qh %p, count %d, urb %p, stage %d\n", + musb_dbg(musb, "<== csr0 %04x, qh %p, count %d, urb %p, stage %d", csr, qh, len, urb, musb->ep0_stage); /* if we just did status stage, we are done */ @@ -1161,15 +1160,15 @@ irqreturn_t musb_h_ep0_irq(struct musb *musb) /* prepare status */ if (csr & MUSB_CSR0_H_RXSTALL) { - dev_dbg(musb->controller, "STALLING ENDPOINT\n"); + musb_dbg(musb, "STALLING ENDPOINT"); status = -EPIPE; } else if (csr & MUSB_CSR0_H_ERROR) { - dev_dbg(musb->controller, "no response, csr0 %04x\n", csr); + musb_dbg(musb, "no response, csr0 %04x", csr); status = -EPROTO; } else if (csr & MUSB_CSR0_H_NAKTIMEOUT) { - dev_dbg(musb->controller, "control NAK timeout\n"); + musb_dbg(musb, "control NAK timeout"); /* NOTE: this code path would be a good place to PAUSE a * control transfer, if another one is queued, so that @@ -1184,7 +1183,7 @@ irqreturn_t musb_h_ep0_irq(struct musb *musb) } if (status) { - dev_dbg(musb->controller, "aborting\n"); + musb_dbg(musb, "aborting"); retval = IRQ_HANDLED; if (urb) urb->status = status; @@ -1237,7 +1236,7 @@ irqreturn_t musb_h_ep0_irq(struct musb *musb) /* flag status stage */ musb->ep0_stage = MUSB_EP0_STATUS; - dev_dbg(musb->controller, "ep0 STATUS, csr %04x\n", csr); + musb_dbg(musb, "ep0 STATUS, csr %04x", csr); } musb_writew(epio, MUSB_CSR0, csr); @@ -1291,38 +1290,36 @@ void musb_host_tx(struct musb *musb, u8 epnum) /* with CPPI, DMA sometimes triggers "extra" irqs */ if (!urb) { - dev_dbg(musb->controller, "extra TX%d ready, csr %04x\n", epnum, tx_csr); + musb_dbg(musb, "extra TX%d ready, csr %04x", epnum, tx_csr); return; } pipe = urb->pipe; dma = is_dma_capable() ? hw_ep->tx_channel : NULL; - dev_dbg(musb->controller, "OUT/TX%d end, csr %04x%s\n", epnum, tx_csr, + musb_dbg(musb, "OUT/TX%d end, csr %04x%s", epnum, tx_csr, dma ? ", dma" : ""); /* check for errors */ if (tx_csr & MUSB_TXCSR_H_RXSTALL) { /* dma was disabled, fifo flushed */ - dev_dbg(musb->controller, "TX end %d stall\n", epnum); + musb_dbg(musb, "TX end %d stall", epnum); /* stall; record URB status */ status = -EPIPE; } else if (tx_csr & MUSB_TXCSR_H_ERROR) { /* (NON-ISO) dma was disabled, fifo flushed */ - dev_dbg(musb->controller, "TX 3strikes on ep=%d\n", epnum); + musb_dbg(musb, "TX 3strikes on ep=%d", epnum); status = -ETIMEDOUT; } else if (tx_csr & MUSB_TXCSR_H_NAKTIMEOUT) { if (USB_ENDPOINT_XFER_BULK == qh->type && qh->mux == 1 && !list_is_singular(&musb->out_bulk)) { - dev_dbg(musb->controller, - "NAK timeout on TX%d ep\n", epnum); + musb_dbg(musb, "NAK timeout on TX%d ep", epnum); musb_bulk_nak_timeout(musb, hw_ep, 0); } else { - dev_dbg(musb->controller, - "TX end=%d device not responding\n", epnum); + musb_dbg(musb, "TX ep%d device not responding", epnum); /* NOTE: this code path would be a good place to PAUSE a * transfer, if there's some other (nonperiodic) tx urb * that could use this fifo. (dma complicates it...) @@ -1368,7 +1365,7 @@ done: /* second cppi case */ if (dma_channel_status(dma) == MUSB_DMA_STATUS_BUSY) { - dev_dbg(musb->controller, "extra TX%d ready, csr %04x\n", epnum, tx_csr); + musb_dbg(musb, "extra TX%d ready, csr %04x", epnum, tx_csr); return; } @@ -1427,8 +1424,9 @@ done: * FIFO mode too... */ if (tx_csr & (MUSB_TXCSR_FIFONOTEMPTY | MUSB_TXCSR_TXPKTRDY)) { - dev_dbg(musb->controller, "DMA complete but packet still in FIFO, " - "CSR %04x\n", tx_csr); + musb_dbg(musb, + "DMA complete but FIFO not empty, CSR %04x", + tx_csr); return; } } @@ -1494,7 +1492,7 @@ done: return; } } else if (tx_csr & MUSB_TXCSR_DMAENAB) { - dev_dbg(musb->controller, "not complete, but DMA enabled?\n"); + musb_dbg(musb, "not complete, but DMA enabled?"); return; } @@ -1723,7 +1721,7 @@ static int musb_rx_dma_in_inventra_cppi41(struct dma_controller *dma, d_status = -EOVERFLOW; urb->error_count++; } - dev_dbg(musb->controller, "** OVERFLOW %d into %d\n", + musb_dbg(musb, "** OVERFLOW %d into %d", rx_count, d->length); length = d->length; @@ -1847,28 +1845,28 @@ void musb_host_rx(struct musb *musb, u8 epnum) * usbtest #11 (unlinks) triggers it regularly, sometimes * with fifo full. (Only with DMA??) */ - dev_dbg(musb->controller, "BOGUS RX%d ready, csr %04x, count %d\n", epnum, val, - musb_readw(epio, MUSB_RXCOUNT)); + musb_dbg(musb, "BOGUS RX%d ready, csr %04x, count %d", + epnum, val, musb_readw(epio, MUSB_RXCOUNT)); musb_h_flush_rxfifo(hw_ep, MUSB_RXCSR_CLRDATATOG); return; } pipe = urb->pipe; - dev_dbg(musb->controller, "<== hw %d rxcsr %04x, urb actual %d (+dma %zu)\n", + musb_dbg(musb, "<== hw %d rxcsr %04x, urb actual %d (+dma %zu)", epnum, rx_csr, urb->actual_length, dma ? dma->actual_len : 0); /* check for errors, concurrent stall & unlink is not really * handled yet! */ if (rx_csr & MUSB_RXCSR_H_RXSTALL) { - dev_dbg(musb->controller, "RX end %d STALL\n", epnum); + musb_dbg(musb, "RX end %d STALL", epnum); /* stall; record URB status */ status = -EPIPE; } else if (rx_csr & MUSB_RXCSR_H_ERROR) { - dev_dbg(musb->controller, "end %d RX proto error\n", epnum); + musb_dbg(musb, "end %d RX proto error", epnum); status = -EPROTO; musb_writeb(epio, MUSB_RXINTERVAL, 0); @@ -1879,7 +1877,7 @@ void musb_host_rx(struct musb *musb, u8 epnum) } else if (rx_csr & MUSB_RXCSR_DATAERROR) { if (USB_ENDPOINT_XFER_ISOC != qh->type) { - dev_dbg(musb->controller, "RX end %d NAK timeout\n", epnum); + musb_dbg(musb, "RX end %d NAK timeout", epnum); /* NOTE: NAKing is *NOT* an error, so we want to * continue. Except ... if there's a request for @@ -1902,12 +1900,12 @@ void musb_host_rx(struct musb *musb, u8 epnum) goto finish; } else { - dev_dbg(musb->controller, "RX end %d ISO data error\n", epnum); + musb_dbg(musb, "RX end %d ISO data error", epnum); /* packet error reported later */ iso_err = true; } } else if (rx_csr & MUSB_RXCSR_INCOMPRX) { - dev_dbg(musb->controller, "end %d high bandwidth incomplete ISO packet RX\n", + musb_dbg(musb, "end %d high bandwidth incomplete ISO packet RX", epnum); status = -EPROTO; } @@ -1952,7 +1950,7 @@ void musb_host_rx(struct musb *musb, u8 epnum) done = true; } - dev_dbg(musb->controller, "RXCSR%d %04x, reqpkt, len %zu%s\n", epnum, rx_csr, + musb_dbg(musb, "RXCSR%d %04x, reqpkt, len %zu%s", epnum, rx_csr, xfer_len, dma ? ", dma" : ""); rx_csr &= ~MUSB_RXCSR_H_REQPKT; @@ -1973,8 +1971,8 @@ void musb_host_rx(struct musb *musb, u8 epnum) if (musb_dma_inventra(musb) || musb_dma_ux500(musb) || musb_dma_cppi41(musb)) { done = musb_rx_dma_inventra_cppi41(c, hw_ep, qh, urb, xfer_len); - dev_dbg(hw_ep->musb->controller, - "ep %d dma %s, rxcsr %04x, rxcount %d\n", + musb_dbg(hw_ep->musb, + "ep %d dma %s, rxcsr %04x, rxcount %d", epnum, done ? "off" : "reset", musb_readw(epio, MUSB_RXCSR), musb_readw(epio, MUSB_RXCOUNT)); @@ -2001,8 +1999,8 @@ void musb_host_rx(struct musb *musb, u8 epnum) /* we are expecting IN packets */ if ((musb_dma_inventra(musb) || musb_dma_ux500(musb) || musb_dma_cppi41(musb)) && dma) { - dev_dbg(hw_ep->musb->controller, - "RX%d count %d, buffer 0x%llx len %d/%d\n", + musb_dbg(hw_ep->musb, + "RX%d count %d, buffer 0x%llx len %d/%d", epnum, musb_readw(epio, MUSB_RXCOUNT), (unsigned long long) urb->transfer_dma + urb->actual_length, @@ -2054,7 +2052,7 @@ void musb_host_rx(struct musb *musb, u8 epnum) done = musb_host_packet_rx(musb, urb, epnum, iso_err); } - dev_dbg(musb->controller, "read %spacket\n", done ? "last " : ""); + musb_dbg(musb, "read %spacket", done ? "last " : ""); } } @@ -2178,7 +2176,7 @@ static int musb_schedule( idle = 1; qh->mux = 0; hw_ep = musb->endpoints + best_end; - dev_dbg(musb->controller, "qh %p periodic slot %d\n", qh, best_end); + musb_dbg(musb, "qh %p periodic slot %d", qh, best_end); success: if (head) { idle = list_empty(head); @@ -2400,8 +2398,7 @@ static int musb_cleanup_urb(struct urb *urb, struct musb_qh *qh) dma = is_in ? ep->rx_channel : ep->tx_channel; if (dma) { status = ep->musb->dma_controller->channel_abort(dma); - dev_dbg(musb->controller, - "abort %cX%d DMA for urb %p --> %d\n", + musb_dbg(musb, "abort %cX%d DMA for urb %p --> %d", is_in ? 'R' : 'T', ep->epnum, urb, status); urb->actual_length += dma->actual_len; @@ -2447,7 +2444,7 @@ static int musb_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) int is_in = usb_pipein(urb->pipe); int ret; - dev_dbg(musb->controller, "urb=%p, dev%d ep%d%s\n", urb, + musb_dbg(musb, "urb=%p, dev%d ep%d%s", urb, usb_pipedevice(urb->pipe), usb_pipeendpoint(urb->pipe), is_in ? "in" : "out"); diff --git a/drivers/usb/musb/musb_virthub.c b/drivers/usb/musb/musb_virthub.c index 92d5f71..192248f 100644 --- a/drivers/usb/musb/musb_virthub.c +++ b/drivers/usb/musb/musb_virthub.c @@ -55,8 +55,7 @@ void musb_host_finish_resume(struct work_struct *work) power = musb_readb(musb->mregs, MUSB_POWER); power &= ~MUSB_POWER_RESUME; - dev_dbg(musb->controller, "root port resume stopped, power %02x\n", - power); + musb_dbg(musb, "root port resume stopped, power %02x", power); musb_writeb(musb->mregs, MUSB_POWER, power); /* @@ -104,7 +103,7 @@ void musb_port_suspend(struct musb *musb, bool do_suspend) break; } - dev_dbg(musb->controller, "Root port suspended, power %02x\n", power); + musb_dbg(musb, "Root port suspended, power %02x", power); musb->port1_status |= USB_PORT_STAT_SUSPEND; switch (musb->xceiv->otg->state) { @@ -123,7 +122,7 @@ void musb_port_suspend(struct musb *musb, bool do_suspend) musb_platform_try_idle(musb, 0); break; default: - dev_dbg(musb->controller, "bogus rh suspend? %s\n", + musb_dbg(musb, "bogus rh suspend? %s", usb_otg_state_string(musb->xceiv->otg->state)); } } else if (power & MUSB_POWER_SUSPENDM) { @@ -131,7 +130,7 @@ void musb_port_suspend(struct musb *musb, bool do_suspend) power |= MUSB_POWER_RESUME; musb_writeb(mbase, MUSB_POWER, power); - dev_dbg(musb->controller, "Root port resuming, power %02x\n", power); + musb_dbg(musb, "Root port resuming, power %02x", power); /* later, GetPortStatus will stop RESUME signaling */ musb->port1_status |= MUSB_PORT_STAT_RESUME; @@ -146,7 +145,7 @@ void musb_port_reset(struct musb *musb, bool do_reset) void __iomem *mbase = musb->mregs; if (musb->xceiv->otg->state == OTG_STATE_B_IDLE) { - dev_dbg(musb->controller, "HNP: Returning from HNP; no hub reset from b_idle\n"); + musb_dbg(musb, "HNP: Returning from HNP; no hub reset from b_idle"); musb->port1_status &= ~USB_PORT_STAT_RESET; return; } @@ -194,7 +193,7 @@ void musb_port_reset(struct musb *musb, bool do_reset) schedule_delayed_work(&musb->deassert_reset_work, msecs_to_jiffies(50)); } else { - dev_dbg(musb->controller, "root port reset stopped\n"); + musb_dbg(musb, "root port reset stopped"); musb_platform_pre_root_reset_end(musb); musb_writeb(mbase, MUSB_POWER, power & ~MUSB_POWER_RESET); @@ -202,7 +201,7 @@ void musb_port_reset(struct musb *musb, bool do_reset) power = musb_readb(mbase, MUSB_POWER); if (power & MUSB_POWER_HSMODE) { - dev_dbg(musb->controller, "high-speed device connected\n"); + musb_dbg(musb, "high-speed device connected"); musb->port1_status |= USB_PORT_STAT_HIGH_SPEED; } @@ -242,7 +241,7 @@ void musb_root_disconnect(struct musb *musb) musb->xceiv->otg->state = OTG_STATE_B_IDLE; break; default: - dev_dbg(musb->controller, "host disconnect (%s)\n", + musb_dbg(musb, "host disconnect (%s)", usb_otg_state_string(musb->xceiv->otg->state)); } } @@ -337,7 +336,7 @@ int musb_hub_control( default: goto error; } - dev_dbg(musb->controller, "clear feature %d\n", wValue); + musb_dbg(musb, "clear feature %d", wValue); musb->port1_status &= ~(1 << wValue); break; case GetHubDescriptor: @@ -372,8 +371,7 @@ int musb_hub_control( (__le32 *) buf); /* port change status is more interesting */ - dev_dbg(musb->controller, "port status %08x\n", - musb->port1_status); + musb_dbg(musb, "port status %08x", musb->port1_status); break; case SetPortFeature: if ((wIndex & 0xff) != 1) @@ -443,7 +441,7 @@ int musb_hub_control( default: goto error; } - dev_dbg(musb->controller, "set feature %d\n", wValue); + musb_dbg(musb, "set feature %d", wValue); musb->port1_status |= 1 << wValue; break; diff --git a/drivers/usb/musb/musbhsdma.c b/drivers/usb/musb/musbhsdma.c index 8abfe4e..3620073 100644 --- a/drivers/usb/musb/musbhsdma.c +++ b/drivers/usb/musb/musbhsdma.c @@ -117,7 +117,7 @@ static void configure_channel(struct dma_channel *channel, u8 bchannel = musb_channel->idx; u16 csr = 0; - dev_dbg(musb->controller, "%p, pkt_sz %d, addr %pad, len %d, mode %d\n", + musb_dbg(musb, "%p, pkt_sz %d, addr %pad, len %d, mode %d", channel, packet_sz, &dma_addr, len, mode); if (mode) { @@ -152,7 +152,7 @@ static int dma_channel_program(struct dma_channel *channel, struct musb_dma_controller *controller = musb_channel->controller; struct musb *musb = controller->private_data; - dev_dbg(musb->controller, "ep%d-%s pkt_sz %d, dma_addr %pad length %d, mode %d\n", + musb_dbg(musb, "ep%d-%s pkt_sz %d, dma_addr %pad length %d, mode %d", musb_channel->epnum, musb_channel->transmit ? "Tx" : "Rx", packet_sz, &dma_addr, len, mode); @@ -266,7 +266,7 @@ static irqreturn_t dma_controller_irq(int irq, void *private_data) #endif if (!int_hsdma) { - dev_dbg(musb->controller, "spurious DMA irq\n"); + musb_dbg(musb, "spurious DMA irq"); for (bchannel = 0; bchannel < MUSB_HSDMA_CHANNELS; bchannel++) { musb_channel = (struct musb_dma_channel *) @@ -280,7 +280,7 @@ static irqreturn_t dma_controller_irq(int irq, void *private_data) } } - dev_dbg(musb->controller, "int_hsdma = 0x%x\n", int_hsdma); + musb_dbg(musb, "int_hsdma = 0x%x", int_hsdma); if (!int_hsdma) goto done; @@ -307,7 +307,7 @@ static irqreturn_t dma_controller_irq(int irq, void *private_data) channel->actual_len = addr - musb_channel->start_addr; - dev_dbg(musb->controller, "ch %p, 0x%x -> 0x%x (%zu / %d) %s\n", + musb_dbg(musb, "ch %p, 0x%x -> 0x%x (%zu / %d) %s", channel, musb_channel->start_addr, addr, channel->actual_len, musb_channel->len, -- cgit v0.10.2 From 086b288282884437cd588893d4501a8bbe4eb78c Mon Sep 17 00:00:00 2001 From: Bin Liu Date: Thu, 30 Jun 2016 12:12:23 -0500 Subject: usb: musb: dsps: use musb register read/write wrappers instead musb core already exports the register read/write wrappers, so clean up the duplication in dsps glue. Signed-off-by: Bin Liu Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/musb/musb_dsps.c b/drivers/usb/musb/musb_dsps.c index eeb7d9e..2537179 100644 --- a/drivers/usb/musb/musb_dsps.c +++ b/drivers/usb/musb/musb_dsps.c @@ -52,30 +52,6 @@ static const struct of_device_id musb_dsps_of_match[]; /** - * avoid using musb_readx()/musb_writex() as glue layer should not be - * dependent on musb core layer symbols. - */ -static inline u8 dsps_readb(const void __iomem *addr, unsigned offset) -{ - return __raw_readb(addr + offset); -} - -static inline u32 dsps_readl(const void __iomem *addr, unsigned offset) -{ - return __raw_readl(addr + offset); -} - -static inline void dsps_writeb(void __iomem *addr, unsigned offset, u8 data) -{ - __raw_writeb(data, addr + offset); -} - -static inline void dsps_writel(void __iomem *addr, unsigned offset, u32 data) -{ - __raw_writel(data, addr + offset); -} - -/** * DSPS musb wrapper register offset. * FIXME: This should be expanded to have all the wrapper registers from TI DSPS * musb ips. @@ -223,8 +199,8 @@ static void dsps_musb_enable(struct musb *musb) ((musb->epmask & wrp->rxep_mask) << wrp->rxep_shift); coremask = (wrp->usb_bitmap & ~MUSB_INTR_SOF); - dsps_writel(reg_base, wrp->epintr_set, epmask); - dsps_writel(reg_base, wrp->coreintr_set, coremask); + musb_writel(reg_base, wrp->epintr_set, epmask); + musb_writel(reg_base, wrp->coreintr_set, coremask); /* start polling for ID change in dual-role idle mode */ if (musb->xceiv->otg->state == OTG_STATE_B_IDLE && musb->port_mode == MUSB_PORT_MODE_DUAL_ROLE) @@ -244,10 +220,10 @@ static void dsps_musb_disable(struct musb *musb) const struct dsps_musb_wrapper *wrp = glue->wrp; void __iomem *reg_base = musb->ctrl_base; - dsps_writel(reg_base, wrp->coreintr_clear, wrp->usb_bitmap); - dsps_writel(reg_base, wrp->epintr_clear, + musb_writel(reg_base, wrp->coreintr_clear, wrp->usb_bitmap); + musb_writel(reg_base, wrp->epintr_clear, wrp->txep_bitmap | wrp->rxep_bitmap); - dsps_writeb(musb->mregs, MUSB_DEVCTL, 0); + musb_writeb(musb->mregs, MUSB_DEVCTL, 0); } static void otg_timer(unsigned long _musb) @@ -265,14 +241,14 @@ static void otg_timer(unsigned long _musb) * We poll because DSPS IP's won't expose several OTG-critical * status change events (from the transceiver) otherwise. */ - devctl = dsps_readb(mregs, MUSB_DEVCTL); + devctl = musb_readb(mregs, MUSB_DEVCTL); dev_dbg(musb->controller, "Poll devctl %02x (%s)\n", devctl, usb_otg_state_string(musb->xceiv->otg->state)); spin_lock_irqsave(&musb->lock, flags); switch (musb->xceiv->otg->state) { case OTG_STATE_A_WAIT_BCON: - dsps_writeb(musb->mregs, MUSB_DEVCTL, 0); + musb_writeb(musb->mregs, MUSB_DEVCTL, 0); skip_session = 1; /* fall */ @@ -286,13 +262,13 @@ static void otg_timer(unsigned long _musb) MUSB_HST_MODE(musb); } if (!(devctl & MUSB_DEVCTL_SESSION) && !skip_session) - dsps_writeb(mregs, MUSB_DEVCTL, MUSB_DEVCTL_SESSION); + musb_writeb(mregs, MUSB_DEVCTL, MUSB_DEVCTL_SESSION); mod_timer(&glue->timer, jiffies + msecs_to_jiffies(wrp->poll_timeout)); break; case OTG_STATE_A_WAIT_VFALL: musb->xceiv->otg->state = OTG_STATE_A_WAIT_VRISE; - dsps_writel(musb->ctrl_base, wrp->coreintr_set, + musb_writel(musb->ctrl_base, wrp->coreintr_set, MUSB_INTR_VBUSERROR << wrp->usb_shift); break; default: @@ -315,29 +291,29 @@ static irqreturn_t dsps_interrupt(int irq, void *hci) spin_lock_irqsave(&musb->lock, flags); /* Get endpoint interrupts */ - epintr = dsps_readl(reg_base, wrp->epintr_status); + epintr = musb_readl(reg_base, wrp->epintr_status); musb->int_rx = (epintr & wrp->rxep_bitmap) >> wrp->rxep_shift; musb->int_tx = (epintr & wrp->txep_bitmap) >> wrp->txep_shift; if (epintr) - dsps_writel(reg_base, wrp->epintr_status, epintr); + musb_writel(reg_base, wrp->epintr_status, epintr); /* Get usb core interrupts */ - usbintr = dsps_readl(reg_base, wrp->coreintr_status); + usbintr = musb_readl(reg_base, wrp->coreintr_status); if (!usbintr && !epintr) goto out; musb->int_usb = (usbintr & wrp->usb_bitmap) >> wrp->usb_shift; if (usbintr) - dsps_writel(reg_base, wrp->coreintr_status, usbintr); + musb_writel(reg_base, wrp->coreintr_status, usbintr); dev_dbg(musb->controller, "usbintr (%x) epintr(%x)\n", usbintr, epintr); if (usbintr & ((1 << wrp->drvvbus) << wrp->usb_shift)) { - int drvvbus = dsps_readl(reg_base, wrp->status); + int drvvbus = musb_readl(reg_base, wrp->status); void __iomem *mregs = musb->mregs; - u8 devctl = dsps_readb(mregs, MUSB_DEVCTL); + u8 devctl = musb_readb(mregs, MUSB_DEVCTL); int err; err = musb->int_usb & MUSB_INTR_VBUSERROR; @@ -442,7 +418,7 @@ static int dsps_musb_init(struct musb *musb) musb->phy = devm_phy_get(dev->parent, "usb2-phy"); /* Returns zero if e.g. not clocked */ - rev = dsps_readl(reg_base, wrp->revision); + rev = musb_readl(reg_base, wrp->revision); if (!rev) return -ENODEV; @@ -463,14 +439,14 @@ static int dsps_musb_init(struct musb *musb) setup_timer(&glue->timer, otg_timer, (unsigned long) musb); /* Reset the musb */ - dsps_writel(reg_base, wrp->control, (1 << wrp->reset)); + musb_writel(reg_base, wrp->control, (1 << wrp->reset)); musb->isr = dsps_interrupt; /* reset the otgdisable bit, needed for host mode to work */ - val = dsps_readl(reg_base, wrp->phy_utmi); + val = musb_readl(reg_base, wrp->phy_utmi); val &= ~(1 << wrp->otg_disable); - dsps_writel(musb->ctrl_base, wrp->phy_utmi, val); + musb_writel(musb->ctrl_base, wrp->phy_utmi, val); /* * Check whether the dsps version has babble control enabled. @@ -478,11 +454,11 @@ static int dsps_musb_init(struct musb *musb) * If MUSB_BABBLE_CTL returns 0x4 then we have the babble control * logic enabled. */ - val = dsps_readb(musb->mregs, MUSB_BABBLE_CTL); + val = musb_readb(musb->mregs, MUSB_BABBLE_CTL); if (val & MUSB_BABBLE_RCV_DISABLE) { glue->sw_babble_enabled = true; val |= MUSB_BABBLE_SW_SESSION_CTRL; - dsps_writeb(musb->mregs, MUSB_BABBLE_CTL, val); + musb_writeb(musb->mregs, MUSB_BABBLE_CTL, val); } return dsps_musb_dbg_init(musb, glue); @@ -510,7 +486,7 @@ static int dsps_musb_set_mode(struct musb *musb, u8 mode) void __iomem *ctrl_base = musb->ctrl_base; u32 reg; - reg = dsps_readl(ctrl_base, wrp->mode); + reg = musb_readl(ctrl_base, wrp->mode); switch (mode) { case MUSB_HOST: @@ -523,8 +499,8 @@ static int dsps_musb_set_mode(struct musb *musb, u8 mode) */ reg |= (1 << wrp->iddig_mux); - dsps_writel(ctrl_base, wrp->mode, reg); - dsps_writel(ctrl_base, wrp->phy_utmi, 0x02); + musb_writel(ctrl_base, wrp->mode, reg); + musb_writel(ctrl_base, wrp->phy_utmi, 0x02); break; case MUSB_PERIPHERAL: reg |= (1 << wrp->iddig); @@ -536,10 +512,10 @@ static int dsps_musb_set_mode(struct musb *musb, u8 mode) */ reg |= (1 << wrp->iddig_mux); - dsps_writel(ctrl_base, wrp->mode, reg); + musb_writel(ctrl_base, wrp->mode, reg); break; case MUSB_OTG: - dsps_writel(ctrl_base, wrp->phy_utmi, 0x02); + musb_writel(ctrl_base, wrp->phy_utmi, 0x02); break; default: dev_err(glue->dev, "unsupported mode %d\n", mode); @@ -554,7 +530,7 @@ static bool dsps_sw_babble_control(struct musb *musb) u8 babble_ctl; bool session_restart = false; - babble_ctl = dsps_readb(musb->mregs, MUSB_BABBLE_CTL); + babble_ctl = musb_readb(musb->mregs, MUSB_BABBLE_CTL); dev_dbg(musb->controller, "babble: MUSB_BABBLE_CTL value %x\n", babble_ctl); /* @@ -571,14 +547,14 @@ static bool dsps_sw_babble_control(struct musb *musb) * babble is due to noise, then set transmit idle (d7 bit) * to resume normal operation */ - babble_ctl = dsps_readb(musb->mregs, MUSB_BABBLE_CTL); + babble_ctl = musb_readb(musb->mregs, MUSB_BABBLE_CTL); babble_ctl |= MUSB_BABBLE_FORCE_TXIDLE; - dsps_writeb(musb->mregs, MUSB_BABBLE_CTL, babble_ctl); + musb_writeb(musb->mregs, MUSB_BABBLE_CTL, babble_ctl); /* wait till line monitor flag cleared */ dev_dbg(musb->controller, "Set TXIDLE, wait J to clear\n"); do { - babble_ctl = dsps_readb(musb->mregs, MUSB_BABBLE_CTL); + babble_ctl = musb_readb(musb->mregs, MUSB_BABBLE_CTL); udelay(1); } while ((babble_ctl & MUSB_BABBLE_STUCK_J) && timeout--); @@ -896,13 +872,13 @@ static int dsps_suspend(struct device *dev) return 0; mbase = musb->ctrl_base; - glue->context.control = dsps_readl(mbase, wrp->control); - glue->context.epintr = dsps_readl(mbase, wrp->epintr_set); - glue->context.coreintr = dsps_readl(mbase, wrp->coreintr_set); - glue->context.phy_utmi = dsps_readl(mbase, wrp->phy_utmi); - glue->context.mode = dsps_readl(mbase, wrp->mode); - glue->context.tx_mode = dsps_readl(mbase, wrp->tx_mode); - glue->context.rx_mode = dsps_readl(mbase, wrp->rx_mode); + glue->context.control = musb_readl(mbase, wrp->control); + glue->context.epintr = musb_readl(mbase, wrp->epintr_set); + glue->context.coreintr = musb_readl(mbase, wrp->coreintr_set); + glue->context.phy_utmi = musb_readl(mbase, wrp->phy_utmi); + glue->context.mode = musb_readl(mbase, wrp->mode); + glue->context.tx_mode = musb_readl(mbase, wrp->tx_mode); + glue->context.rx_mode = musb_readl(mbase, wrp->rx_mode); return 0; } @@ -918,13 +894,13 @@ static int dsps_resume(struct device *dev) return 0; mbase = musb->ctrl_base; - dsps_writel(mbase, wrp->control, glue->context.control); - dsps_writel(mbase, wrp->epintr_set, glue->context.epintr); - dsps_writel(mbase, wrp->coreintr_set, glue->context.coreintr); - dsps_writel(mbase, wrp->phy_utmi, glue->context.phy_utmi); - dsps_writel(mbase, wrp->mode, glue->context.mode); - dsps_writel(mbase, wrp->tx_mode, glue->context.tx_mode); - dsps_writel(mbase, wrp->rx_mode, glue->context.rx_mode); + musb_writel(mbase, wrp->control, glue->context.control); + musb_writel(mbase, wrp->epintr_set, glue->context.epintr); + musb_writel(mbase, wrp->coreintr_set, glue->context.coreintr); + musb_writel(mbase, wrp->phy_utmi, glue->context.phy_utmi); + musb_writel(mbase, wrp->mode, glue->context.mode); + musb_writel(mbase, wrp->tx_mode, glue->context.tx_mode); + musb_writel(mbase, wrp->rx_mode, glue->context.rx_mode); if (musb->xceiv->otg->state == OTG_STATE_B_IDLE && musb->port_mode == MUSB_PORT_MODE_DUAL_ROLE) mod_timer(&glue->timer, jiffies + -- cgit v0.10.2 From c74173fdd4fba23f237af48dff95f613f011cee3 Mon Sep 17 00:00:00 2001 From: Bin Liu Date: Thu, 30 Jun 2016 12:12:24 -0500 Subject: usb: musb: add tracepoints for register access This adds tracepoints to musb register read/write wrappers to get trace log for register access. The default tacepoint log prefix here would be musb_readX/writeX(), which is not much helpful. So this patch let the tracepoints use __buildin_return_address(0) to print the caller funciton name to provide more context of the register access. Signed-off-by: Bin Liu Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c index d2bc45c..c0c81ae 100644 --- a/drivers/usb/musb/musb_core.c +++ b/drivers/usb/musb/musb_core.c @@ -102,6 +102,7 @@ #include #include "musb_core.h" +#include "musb_trace.h" #define TA_WAIT_BCON(m) max_t(int, (m)->a_wait_bcon, OTG_TIME_A_WAIT_BCON) @@ -258,31 +259,43 @@ static u32 musb_default_busctl_offset(u8 epnum, u16 offset) static u8 musb_default_readb(const void __iomem *addr, unsigned offset) { - return __raw_readb(addr + offset); + u8 data = __raw_readb(addr + offset); + + trace_musb_readb(__builtin_return_address(0), addr, offset, data); + return data; } static void musb_default_writeb(void __iomem *addr, unsigned offset, u8 data) { + trace_musb_writeb(__builtin_return_address(0), addr, offset, data); __raw_writeb(data, addr + offset); } static u16 musb_default_readw(const void __iomem *addr, unsigned offset) { - return __raw_readw(addr + offset); + u16 data = __raw_readw(addr + offset); + + trace_musb_readw(__builtin_return_address(0), addr, offset, data); + return data; } static void musb_default_writew(void __iomem *addr, unsigned offset, u16 data) { + trace_musb_writew(__builtin_return_address(0), addr, offset, data); __raw_writew(data, addr + offset); } static u32 musb_default_readl(const void __iomem *addr, unsigned offset) { - return __raw_readl(addr + offset); + u32 data = __raw_readl(addr + offset); + + trace_musb_readl(__builtin_return_address(0), addr, offset, data); + return data; } static void musb_default_writel(void __iomem *addr, unsigned offset, u32 data) { + trace_musb_writel(__builtin_return_address(0), addr, offset, data); __raw_writel(data, addr + offset); } diff --git a/drivers/usb/musb/musb_trace.h b/drivers/usb/musb/musb_trace.h index c6c593e..c974f48 100644 --- a/drivers/usb/musb/musb_trace.h +++ b/drivers/usb/musb/musb_trace.h @@ -41,6 +41,93 @@ TRACE_EVENT(musb_log, TP_printk("%s: %s", __get_str(name), __get_str(msg)) ); +DECLARE_EVENT_CLASS(musb_regb, + TP_PROTO(void *caller, const void *addr, unsigned int offset, u8 data), + TP_ARGS(caller, addr, offset, data), + TP_STRUCT__entry( + __field(void *, caller) + __field(const void *, addr) + __field(unsigned int, offset) + __field(u8, data) + ), + TP_fast_assign( + __entry->caller = caller; + __entry->addr = addr; + __entry->offset = offset; + __entry->data = data; + ), + TP_printk("%pS: %p + %04x: %02x", + __entry->caller, __entry->addr, __entry->offset, __entry->data) +); + +DEFINE_EVENT(musb_regb, musb_readb, + TP_PROTO(void *caller, const void *addr, unsigned int offset, u8 data), + TP_ARGS(caller, addr, offset, data) +); + +DEFINE_EVENT(musb_regb, musb_writeb, + TP_PROTO(void *caller, const void *addr, unsigned int offset, u8 data), + TP_ARGS(caller, addr, offset, data) +); + +DECLARE_EVENT_CLASS(musb_regw, + TP_PROTO(void *caller, const void *addr, unsigned int offset, u16 data), + TP_ARGS(caller, addr, offset, data), + TP_STRUCT__entry( + __field(void *, caller) + __field(const void *, addr) + __field(unsigned int, offset) + __field(u16, data) + ), + TP_fast_assign( + __entry->caller = caller; + __entry->addr = addr; + __entry->offset = offset; + __entry->data = data; + ), + TP_printk("%pS: %p + %04x: %04x", + __entry->caller, __entry->addr, __entry->offset, __entry->data) +); + +DEFINE_EVENT(musb_regw, musb_readw, + TP_PROTO(void *caller, const void *addr, unsigned int offset, u16 data), + TP_ARGS(caller, addr, offset, data) +); + +DEFINE_EVENT(musb_regw, musb_writew, + TP_PROTO(void *caller, const void *addr, unsigned int offset, u16 data), + TP_ARGS(caller, addr, offset, data) +); + +DECLARE_EVENT_CLASS(musb_regl, + TP_PROTO(void *caller, const void *addr, unsigned int offset, u32 data), + TP_ARGS(caller, addr, offset, data), + TP_STRUCT__entry( + __field(void *, caller) + __field(const void *, addr) + __field(unsigned int, offset) + __field(u32, data) + ), + TP_fast_assign( + __entry->caller = caller; + __entry->addr = addr; + __entry->offset = offset; + __entry->data = data; + ), + TP_printk("%pS: %p + %04x: %08x", + __entry->caller, __entry->addr, __entry->offset, __entry->data) +); + +DEFINE_EVENT(musb_regl, musb_readl, + TP_PROTO(void *caller, const void *addr, unsigned int offset, u32 data), + TP_ARGS(caller, addr, offset, data) +); + +DEFINE_EVENT(musb_regl, musb_writel, + TP_PROTO(void *caller, const void *addr, unsigned int offset, u32 data), + TP_ARGS(caller, addr, offset, data) +); + #endif /* __MUSB_TRACE_H */ /* this part has to be here */ -- cgit v0.10.2 From cfb9a1bc6e65c6093ed5ac4f1c0cc20a9f25d597 Mon Sep 17 00:00:00 2001 From: Bin Liu Date: Thu, 30 Jun 2016 12:12:25 -0500 Subject: usb: musb: add tracepoints to dump interrupt events This adds tracepoints to dump musb interrupt events. Signed-off-by: Bin Liu Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c index c0c81ae..74fc306 100644 --- a/drivers/usb/musb/musb_core.c +++ b/drivers/usb/musb/musb_core.c @@ -1588,9 +1588,7 @@ irqreturn_t musb_interrupt(struct musb *musb) devctl = musb_readb(musb->mregs, MUSB_DEVCTL); - dev_dbg(musb->controller, "** IRQ %s usb%04x tx%04x rx%04x\n", - is_host_active(musb) ? "host" : "peripheral", - musb->int_usb, musb->int_tx, musb->int_rx); + trace_musb_isr(musb); /** * According to Mentor Graphics' documentation, flowchart on page 98, diff --git a/drivers/usb/musb/musb_trace.h b/drivers/usb/musb/musb_trace.h index c974f48..98acc1e 100644 --- a/drivers/usb/musb/musb_trace.h +++ b/drivers/usb/musb/musb_trace.h @@ -128,6 +128,27 @@ DEFINE_EVENT(musb_regl, musb_writel, TP_ARGS(caller, addr, offset, data) ); +TRACE_EVENT(musb_isr, + TP_PROTO(struct musb *musb), + TP_ARGS(musb), + TP_STRUCT__entry( + __string(name, dev_name(musb->controller)) + __field(u8, int_usb) + __field(u16, int_tx) + __field(u16, int_rx) + ), + TP_fast_assign( + __assign_str(name, dev_name(musb->controller)); + __entry->int_usb = musb->int_usb; + __entry->int_tx = musb->int_tx; + __entry->int_rx = musb->int_rx; + ), + TP_printk("%s: usb %02x, tx %04x, rx %04x", + __get_str(name), __entry->int_usb, + __entry->int_tx, __entry->int_rx + ) +); + #endif /* __MUSB_TRACE_H */ /* this part has to be here */ -- cgit v0.10.2 From 19ca682e03fbf0349e6c6ef76c786136176d3ca6 Mon Sep 17 00:00:00 2001 From: Bin Liu Date: Thu, 30 Jun 2016 12:12:26 -0500 Subject: usb: musb: host: add urb tracepoints Add urb tracepoints for host mode. Signed-off-by: Bin Liu Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/musb/musb_host.c b/drivers/usb/musb/musb_host.c index 7601ada..53bc4ce 100644 --- a/drivers/usb/musb/musb_host.c +++ b/drivers/usb/musb/musb_host.c @@ -44,6 +44,7 @@ #include "musb_core.h" #include "musb_host.h" +#include "musb_trace.h" /* MUSB HOST status 22-mar-2006 * @@ -225,8 +226,6 @@ musb_start_urb(struct musb *musb, int is_in, struct musb_qh *qh) void *buf = urb->transfer_buffer; u32 offset = 0; struct musb_hw_ep *hw_ep = qh->hw_ep; - unsigned pipe = urb->pipe; - u8 address = usb_pipedevice(pipe); int epnum = hw_ep->epnum; /* initialize software qh state */ @@ -254,16 +253,7 @@ musb_start_urb(struct musb *musb, int is_in, struct musb_qh *qh) len = urb->transfer_buffer_length - urb->actual_length; } - musb_dbg(musb, "qh %p urb %p dev%d ep%d%s%s, hw_ep %d, %p/%d", - qh, urb, address, qh->epnum, - is_in ? "in" : "out", - ({char *s; switch (qh->type) { - case USB_ENDPOINT_XFER_CONTROL: s = ""; break; - case USB_ENDPOINT_XFER_BULK: s = "-bulk"; break; - case USB_ENDPOINT_XFER_ISOC: s = "-iso"; break; - default: s = "-intr"; break; - } s; }), - epnum, buf + offset, len); + trace_musb_urb_start(musb, urb); /* Configure endpoint */ musb_ep_set_qh(hw_ep, is_in, qh); @@ -314,13 +304,7 @@ static void musb_giveback(struct musb *musb, struct urb *urb, int status) __releases(musb->lock) __acquires(musb->lock) { - musb_dbg(musb, "complete %p %pF (%d), dev%d ep%d%s, %d/%d", - urb, urb->complete, status, - usb_pipedevice(urb->pipe), - usb_pipeendpoint(urb->pipe), - usb_pipein(urb->pipe) ? "in" : "out", - urb->actual_length, urb->transfer_buffer_length - ); + trace_musb_urb_gb(musb, urb); usb_hcd_unlink_urb_from_ep(musb->hcd, urb); spin_unlock(&musb->lock); @@ -1296,6 +1280,7 @@ void musb_host_tx(struct musb *musb, u8 epnum) pipe = urb->pipe; dma = is_dma_capable() ? hw_ep->tx_channel : NULL; + trace_musb_urb_tx(musb, urb); musb_dbg(musb, "OUT/TX%d end, csr %04x%s", epnum, tx_csr, dma ? ", dma" : ""); @@ -1853,9 +1838,7 @@ void musb_host_rx(struct musb *musb, u8 epnum) pipe = urb->pipe; - musb_dbg(musb, "<== hw %d rxcsr %04x, urb actual %d (+dma %zu)", - epnum, rx_csr, urb->actual_length, - dma ? dma->actual_len : 0); + trace_musb_urb_rx(musb, urb); /* check for errors, concurrent stall & unlink is not really * handled yet! */ @@ -2208,6 +2191,8 @@ static int musb_urb_enqueue( if (!is_host_active(musb) || !musb->is_active) return -ENODEV; + trace_musb_urb_enq(musb, urb); + spin_lock_irqsave(&musb->lock, flags); ret = usb_hcd_link_urb_to_ep(hcd, urb); qh = ret ? NULL : hep->hcpriv; @@ -2444,10 +2429,7 @@ static int musb_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) int is_in = usb_pipein(urb->pipe); int ret; - musb_dbg(musb, "urb=%p, dev%d ep%d%s", urb, - usb_pipedevice(urb->pipe), - usb_pipeendpoint(urb->pipe), - is_in ? "in" : "out"); + trace_musb_urb_deq(musb, urb); spin_lock_irqsave(&musb->lock, flags); ret = usb_hcd_check_unlink_urb(hcd, urb, status); diff --git a/drivers/usb/musb/musb_trace.h b/drivers/usb/musb/musb_trace.h index 98acc1e..39258f6 100644 --- a/drivers/usb/musb/musb_trace.h +++ b/drivers/usb/musb/musb_trace.h @@ -23,6 +23,7 @@ #include #include +#include #include "musb_core.h" #define MUSB_MSG_MAX 500 @@ -149,6 +150,68 @@ TRACE_EVENT(musb_isr, ) ); +DECLARE_EVENT_CLASS(musb_urb, + TP_PROTO(struct musb *musb, struct urb *urb), + TP_ARGS(musb, urb), + TP_STRUCT__entry( + __string(name, dev_name(musb->controller)) + __field(struct urb *, urb) + __field(unsigned int, pipe) + __field(int, status) + __field(unsigned int, flag) + __field(u32, buf_len) + __field(u32, actual_len) + ), + TP_fast_assign( + __assign_str(name, dev_name(musb->controller)); + __entry->urb = urb; + __entry->pipe = urb->pipe; + __entry->status = urb->status; + __entry->flag = urb->transfer_flags; + __entry->buf_len = urb->transfer_buffer_length; + __entry->actual_len = urb->actual_length; + ), + TP_printk("%s: %p, dev%d ep%d%s, flag 0x%x, len %d/%d, status %d", + __get_str(name), __entry->urb, + usb_pipedevice(__entry->pipe), + usb_pipeendpoint(__entry->pipe), + usb_pipein(__entry->pipe) ? "in" : "out", + __entry->flag, + __entry->actual_len, __entry->buf_len, + __entry->status + ) +); + +DEFINE_EVENT(musb_urb, musb_urb_start, + TP_PROTO(struct musb *musb, struct urb *urb), + TP_ARGS(musb, urb) +); + +DEFINE_EVENT(musb_urb, musb_urb_gb, + TP_PROTO(struct musb *musb, struct urb *urb), + TP_ARGS(musb, urb) +); + +DEFINE_EVENT(musb_urb, musb_urb_rx, + TP_PROTO(struct musb *musb, struct urb *urb), + TP_ARGS(musb, urb) +); + +DEFINE_EVENT(musb_urb, musb_urb_tx, + TP_PROTO(struct musb *musb, struct urb *urb), + TP_ARGS(musb, urb) +); + +DEFINE_EVENT(musb_urb, musb_urb_enq, + TP_PROTO(struct musb *musb, struct urb *urb), + TP_ARGS(musb, urb) +); + +DEFINE_EVENT(musb_urb, musb_urb_deq, + TP_PROTO(struct musb *musb, struct urb *urb), + TP_ARGS(musb, urb) +); + #endif /* __MUSB_TRACE_H */ /* this part has to be here */ -- cgit v0.10.2 From fc78003e5345a3c0b8461dbb75190693407ae2ca Mon Sep 17 00:00:00 2001 From: Bin Liu Date: Thu, 30 Jun 2016 12:12:27 -0500 Subject: usb: musb: gadget: add usb-request tracepoints Add usb_request tracepoints for gadget mode. Signed-off-by: Bin Liu Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c index 9616059..6d1e975 100644 --- a/drivers/usb/musb/musb_gadget.c +++ b/drivers/usb/musb/musb_gadget.c @@ -44,6 +44,7 @@ #include #include "musb_core.h" +#include "musb_trace.h" /* ----------------------------------------------------------------------- */ @@ -167,15 +168,7 @@ __acquires(ep->musb->lock) if (!dma_mapping_error(&musb->g.dev, request->dma)) unmap_dma_buffer(req, musb); - if (request->status == 0) - musb_dbg(musb, "%s done request %p, %d/", - ep->end_point.name, request, - req->request.actual, req->request.length); - else - musb_dbg(musb, "%s request %p, %d/%d fault %d", - ep->end_point.name, request, - req->request.actual, req->request.length, - request->status); + trace_musb_req_gb(req); usb_gadget_giveback_request(&req->ep->end_point, &req->request); spin_lock(&musb->lock); ep->busy = busy; @@ -449,6 +442,7 @@ void musb_g_tx(struct musb *musb, u8 epnum) req = next_request(musb_ep); request = &req->request; + trace_musb_req_tx(req); csr = musb_readw(epio, MUSB_TXCSR); musb_dbg(musb, "<== %s, txcsr %04x", musb_ep->end_point.name, csr); @@ -847,6 +841,7 @@ void musb_g_rx(struct musb *musb, u8 epnum) if (!req) return; + trace_musb_req_rx(req); request = &req->request; csr = musb_readw(epio, MUSB_RXCSR); @@ -892,11 +887,6 @@ void musb_g_rx(struct musb *musb, u8 epnum) request->actual += musb_ep->dma->actual_len; - musb_dbg(musb, "RXCSR%d %04x, dma off, %04x, len %zu, req %p", - epnum, csr, - musb_readw(epio, MUSB_RXCSR), - musb_ep->dma->actual_len, request); - #if defined(CONFIG_USB_INVENTRA_DMA) || defined(CONFIG_USB_TUSB_OMAP_DMA) || \ defined(CONFIG_USB_UX500_DMA) /* Autoclear doesn't clear RxPktRdy for short packets */ @@ -1194,6 +1184,7 @@ struct usb_request *musb_alloc_request(struct usb_ep *ep, gfp_t gfp_flags) request->epnum = musb_ep->current_epnum; request->ep = musb_ep; + trace_musb_req_alloc(request); return &request->request; } @@ -1203,7 +1194,10 @@ struct usb_request *musb_alloc_request(struct usb_ep *ep, gfp_t gfp_flags) */ void musb_free_request(struct usb_ep *ep, struct usb_request *req) { - kfree(to_musb_request(req)); + struct musb_request *request = to_musb_request(req); + + trace_musb_req_free(request); + kfree(request); } static LIST_HEAD(buffers); @@ -1220,10 +1214,7 @@ struct free_record { */ void musb_ep_restart(struct musb *musb, struct musb_request *req) { - musb_dbg(musb, "<== %s request %p len %u on hw_ep%d", - req->tx ? "TX/IN" : "RX/OUT", - &req->request, req->request.length, req->epnum); - + trace_musb_req_start(req); musb_ep_select(musb->mregs, req->epnum); if (req->tx) txstate(musb, req); @@ -1254,7 +1245,7 @@ static int musb_gadget_queue(struct usb_ep *ep, struct usb_request *req, if (request->ep != musb_ep) return -EINVAL; - musb_dbg(musb, "<== to %s request=%p", ep->name, req); + trace_musb_req_enq(request); /* request is mine now... */ request->request.actual = 0; @@ -1296,9 +1287,11 @@ static int musb_gadget_dequeue(struct usb_ep *ep, struct usb_request *request) int status = 0; struct musb *musb = musb_ep->musb; - if (!ep || !request || to_musb_request(request)->ep != musb_ep) + if (!ep || !request || req->ep != musb_ep) return -EINVAL; + trace_musb_req_deq(req); + spin_lock_irqsave(&musb->lock, flags); list_for_each_entry(r, &musb_ep->req_list, list) { diff --git a/drivers/usb/musb/musb_trace.h b/drivers/usb/musb/musb_trace.h index 39258f6..27d1a9b 100644 --- a/drivers/usb/musb/musb_trace.h +++ b/drivers/usb/musb/musb_trace.h @@ -212,6 +212,82 @@ DEFINE_EVENT(musb_urb, musb_urb_deq, TP_ARGS(musb, urb) ); +DECLARE_EVENT_CLASS(musb_req, + TP_PROTO(struct musb_request *req), + TP_ARGS(req), + TP_STRUCT__entry( + __field(struct usb_request *, req) + __field(u8, is_tx) + __field(u8, epnum) + __field(int, status) + __field(unsigned int, buf_len) + __field(unsigned int, actual_len) + __field(unsigned int, zero) + __field(unsigned int, short_not_ok) + __field(unsigned int, no_interrupt) + ), + TP_fast_assign( + __entry->req = &req->request; + __entry->is_tx = req->tx; + __entry->epnum = req->epnum; + __entry->status = req->request.status; + __entry->buf_len = req->request.length; + __entry->actual_len = req->request.actual; + __entry->zero = req->request.zero; + __entry->short_not_ok = req->request.short_not_ok; + __entry->no_interrupt = req->request.no_interrupt; + ), + TP_printk("%p, ep%d %s, %s%s%s, len %d/%d, status %d", + __entry->req, __entry->epnum, + __entry->is_tx ? "tx/IN" : "rx/OUT", + __entry->zero ? "Z" : "z", + __entry->short_not_ok ? "S" : "s", + __entry->no_interrupt ? "I" : "i", + __entry->actual_len, __entry->buf_len, + __entry->status + ) +); + +DEFINE_EVENT(musb_req, musb_req_gb, + TP_PROTO(struct musb_request *req), + TP_ARGS(req) +); + +DEFINE_EVENT(musb_req, musb_req_tx, + TP_PROTO(struct musb_request *req), + TP_ARGS(req) +); + +DEFINE_EVENT(musb_req, musb_req_rx, + TP_PROTO(struct musb_request *req), + TP_ARGS(req) +); + +DEFINE_EVENT(musb_req, musb_req_alloc, + TP_PROTO(struct musb_request *req), + TP_ARGS(req) +); + +DEFINE_EVENT(musb_req, musb_req_free, + TP_PROTO(struct musb_request *req), + TP_ARGS(req) +); + +DEFINE_EVENT(musb_req, musb_req_start, + TP_PROTO(struct musb_request *req), + TP_ARGS(req) +); + +DEFINE_EVENT(musb_req, musb_req_enq, + TP_PROTO(struct musb_request *req), + TP_ARGS(req) +); + +DEFINE_EVENT(musb_req, musb_req_deq, + TP_PROTO(struct musb_request *req), + TP_ARGS(req) +); + #endif /* __MUSB_TRACE_H */ /* this part has to be here */ -- cgit v0.10.2 From 460ddbec8ff1237672a549740a288350e68ca00c Mon Sep 17 00:00:00 2001 From: Bin Liu Date: Thu, 30 Jun 2016 12:12:28 -0500 Subject: usb: musb: cleanup cppi_dma header davinci.h is not required by cppi_dma.h but cppi_dma.c, so move the include to the right place. Signed-off-by: Bin Liu Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/musb/cppi_dma.c b/drivers/usb/musb/cppi_dma.c index 5da93ec..1ae48e6 100644 --- a/drivers/usb/musb/cppi_dma.c +++ b/drivers/usb/musb/cppi_dma.c @@ -14,6 +14,7 @@ #include "musb_core.h" #include "musb_debug.h" #include "cppi_dma.h" +#include "davinci.h" /* CPPI DMA status 7-mar-2006: diff --git a/drivers/usb/musb/cppi_dma.h b/drivers/usb/musb/cppi_dma.h index 59bf949..40c31ce 100644 --- a/drivers/usb/musb/cppi_dma.h +++ b/drivers/usb/musb/cppi_dma.h @@ -11,14 +11,6 @@ #include "musb_dma.h" #include "musb_core.h" - -/* FIXME fully isolate CPPI from DaVinci ... the "CPPI generic" registers - * would seem to be shared with the TUSB6020 (over VLYNQ). - */ - -#include "davinci.h" - - /* CPPI RX/TX state RAM */ struct cppi_tx_stateram { -- cgit v0.10.2 From 239d2218108a5af7f6ffbd0752677ab46f8705be Mon Sep 17 00:00:00 2001 From: Bin Liu Date: Thu, 30 Jun 2016 12:12:29 -0500 Subject: usb: musb: cppi41: move struct cppi41_dma_channel to header Move struct cppi41_dma_channel to the header file so other modules can use it. Signed-off-by: Bin Liu Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/musb/cppi_dma.h b/drivers/usb/musb/cppi_dma.h index 40c31ce..7fdfb71 100644 --- a/drivers/usb/musb/cppi_dma.h +++ b/drivers/usb/musb/cppi_dma.h @@ -7,9 +7,10 @@ #include #include #include +#include -#include "musb_dma.h" #include "musb_core.h" +#include "musb_dma.h" /* CPPI RX/TX state RAM */ @@ -123,4 +124,24 @@ struct cppi { /* CPPI IRQ handler */ extern irqreturn_t cppi_interrupt(int, void *); +struct cppi41_dma_channel { + struct dma_channel channel; + struct cppi41_dma_controller *controller; + struct musb_hw_ep *hw_ep; + struct dma_chan *dc; + dma_cookie_t cookie; + u8 port_num; + u8 is_tx; + u8 is_allocated; + u8 usb_toggle; + + dma_addr_t buf_addr; + u32 total_len; + u32 prog_len; + u32 transferred; + u32 packet_sz; + struct list_head tx_check; + int tx_zlp; +}; + #endif /* end of ifndef _CPPI_DMA_H_ */ diff --git a/drivers/usb/musb/musb_cppi41.c b/drivers/usb/musb/musb_cppi41.c index f7bad72..602a230 100644 --- a/drivers/usb/musb/musb_cppi41.c +++ b/drivers/usb/musb/musb_cppi41.c @@ -5,6 +5,7 @@ #include #include +#include "cppi_dma.h" #include "musb_core.h" #define RNDIS_REG(x) (0x80 + ((x - 1) * 4)) @@ -22,26 +23,6 @@ #define USB_CTRL_AUTOREQ 0xd0 #define USB_TDOWN 0xd8 -struct cppi41_dma_channel { - struct dma_channel channel; - struct cppi41_dma_controller *controller; - struct musb_hw_ep *hw_ep; - struct dma_chan *dc; - dma_cookie_t cookie; - u8 port_num; - u8 is_tx; - u8 is_allocated; - u8 usb_toggle; - - dma_addr_t buf_addr; - u32 total_len; - u32 prog_len; - u32 transferred; - u32 packet_sz; - struct list_head tx_check; - int tx_zlp; -}; - #define MUSB_DMA_NUM_CHANNELS 15 struct cppi41_dma_controller { -- cgit v0.10.2 From 8ccb49dd5cdeb7bc1c12580698ffec9619fea14d Mon Sep 17 00:00:00 2001 From: Bin Liu Date: Thu, 30 Jun 2016 12:12:30 -0500 Subject: usb: musb: cppi41: add dma channel tracepoints Add tracepoints for cppi41 dma channels. Signed-off-by: Bin Liu Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/musb/musb_cppi41.c b/drivers/usb/musb/musb_cppi41.c index 602a230..d4d7c56 100644 --- a/drivers/usb/musb/musb_cppi41.c +++ b/drivers/usb/musb/musb_cppi41.c @@ -7,6 +7,7 @@ #include "cppi_dma.h" #include "musb_core.h" +#include "musb_trace.h" #define RNDIS_REG(x) (0x80 + ((x - 1) * 4)) @@ -126,6 +127,8 @@ static void cppi41_trans_done(struct cppi41_dma_channel *cppi41_channel) csr = MUSB_TXCSR_MODE | MUSB_TXCSR_TXPKTRDY; musb_writew(epio, MUSB_TXCSR, csr); } + + trace_musb_cppi41_done(cppi41_channel); musb_dma_completion(musb, hw_ep->epnum, cppi41_channel->is_tx); } else { /* next iteration, reload */ @@ -154,6 +157,7 @@ static void cppi41_trans_done(struct cppi41_dma_channel *cppi41_channel) dma_desc->callback = cppi41_dma_callback; dma_desc->callback_param = &cppi41_channel->channel; cppi41_channel->cookie = dma_desc->tx_submit(dma_desc); + trace_musb_cppi41_cont(cppi41_channel); dma_async_issue_pending(dc); if (!cppi41_channel->is_tx) { @@ -221,10 +225,7 @@ static void cppi41_dma_callback(void *private_data) transferred = cppi41_channel->prog_len - txstate.residue; cppi41_channel->transferred += transferred; - musb_dbg(musb, "DMA transfer done on hw_ep=%d bytes=%d/%d", - hw_ep->epnum, cppi41_channel->transferred, - cppi41_channel->total_len); - + trace_musb_cppi41_gb(cppi41_channel); update_rx_toggle(cppi41_channel); if (cppi41_channel->transferred == cppi41_channel->total_len || @@ -355,12 +356,6 @@ static bool cppi41_configure_channel(struct dma_channel *channel, struct musb *musb = cppi41_channel->controller->musb; unsigned use_gen_rndis = 0; - musb_dbg(musb, - "configure ep%d/%x packet_sz=%d, mode=%d, dma_addr=0x%llx, len=%d is_tx=%d", - cppi41_channel->port_num, RNDIS_REG(cppi41_channel->port_num), - packet_sz, mode, (unsigned long long) dma_addr, - len, cppi41_channel->is_tx); - cppi41_channel->buf_addr = dma_addr; cppi41_channel->total_len = len; cppi41_channel->transferred = 0; @@ -412,6 +407,8 @@ static bool cppi41_configure_channel(struct dma_channel *channel, cppi41_channel->cookie = dma_desc->tx_submit(dma_desc); cppi41_channel->channel.rx_packet_done = false; + trace_musb_cppi41_config(cppi41_channel); + save_rx_toggle(cppi41_channel); dma_async_issue_pending(dc); return true; @@ -442,6 +439,7 @@ static struct dma_channel *cppi41_dma_channel_allocate(struct dma_controller *c, cppi41_channel->hw_ep = hw_ep; cppi41_channel->is_allocated = 1; + trace_musb_cppi41_alloc(cppi41_channel); return &cppi41_channel->channel; } @@ -449,6 +447,7 @@ static void cppi41_dma_channel_release(struct dma_channel *channel) { struct cppi41_dma_channel *cppi41_channel = channel->private_data; + trace_musb_cppi41_free(cppi41_channel); if (cppi41_channel->is_allocated) { cppi41_channel->is_allocated = 0; channel->status = MUSB_DMA_STATUS_FREE; @@ -518,8 +517,7 @@ static int cppi41_dma_channel_abort(struct dma_channel *channel) u16 csr; is_tx = cppi41_channel->is_tx; - musb_dbg(musb, "abort channel=%d, is_tx=%d", - cppi41_channel->port_num, is_tx); + trace_musb_cppi41_abort(cppi41_channel); if (cppi41_channel->channel.status == MUSB_DMA_STATUS_FREE) return 0; diff --git a/drivers/usb/musb/musb_trace.h b/drivers/usb/musb/musb_trace.h index 27d1a9b..f031c9e 100644 --- a/drivers/usb/musb/musb_trace.h +++ b/drivers/usb/musb/musb_trace.h @@ -25,6 +25,9 @@ #include #include #include "musb_core.h" +#ifdef CONFIG_USB_TI_CPPI41_DMA +#include "cppi_dma.h" +#endif #define MUSB_MSG_MAX 500 @@ -288,6 +291,73 @@ DEFINE_EVENT(musb_req, musb_req_deq, TP_ARGS(req) ); +#ifdef CONFIG_USB_TI_CPPI41_DMA +DECLARE_EVENT_CLASS(musb_cppi41, + TP_PROTO(struct cppi41_dma_channel *ch), + TP_ARGS(ch), + TP_STRUCT__entry( + __field(struct cppi41_dma_channel *, ch) + __string(name, dev_name(ch->hw_ep->musb->controller)) + __field(u8, hwep) + __field(u8, port) + __field(u8, is_tx) + __field(u32, len) + __field(u32, prog_len) + __field(u32, xferred) + ), + TP_fast_assign( + __entry->ch = ch; + __assign_str(name, dev_name(ch->hw_ep->musb->controller)); + __entry->hwep = ch->hw_ep->epnum; + __entry->port = ch->port_num; + __entry->is_tx = ch->is_tx; + __entry->len = ch->total_len; + __entry->prog_len = ch->prog_len; + __entry->xferred = ch->transferred; + ), + TP_printk("%s: %p, hwep%d ch%d%s, prog_len %d, len %d/%d", + __get_str(name), __entry->ch, __entry->hwep, + __entry->port, __entry->is_tx ? "tx" : "rx", + __entry->prog_len, __entry->xferred, __entry->len + ) +); + +DEFINE_EVENT(musb_cppi41, musb_cppi41_done, + TP_PROTO(struct cppi41_dma_channel *ch), + TP_ARGS(ch) +); + +DEFINE_EVENT(musb_cppi41, musb_cppi41_gb, + TP_PROTO(struct cppi41_dma_channel *ch), + TP_ARGS(ch) +); + +DEFINE_EVENT(musb_cppi41, musb_cppi41_config, + TP_PROTO(struct cppi41_dma_channel *ch), + TP_ARGS(ch) +); + +DEFINE_EVENT(musb_cppi41, musb_cppi41_cont, + TP_PROTO(struct cppi41_dma_channel *ch), + TP_ARGS(ch) +); + +DEFINE_EVENT(musb_cppi41, musb_cppi41_alloc, + TP_PROTO(struct cppi41_dma_channel *ch), + TP_ARGS(ch) +); + +DEFINE_EVENT(musb_cppi41, musb_cppi41_abort, + TP_PROTO(struct cppi41_dma_channel *ch), + TP_ARGS(ch) +); + +DEFINE_EVENT(musb_cppi41, musb_cppi41_free, + TP_PROTO(struct cppi41_dma_channel *ch), + TP_ARGS(ch) +); +#endif /* CONFIG_USB_TI_CPPI41_DMA */ + #endif /* __MUSB_TRACE_H */ /* this part has to be here */ -- cgit v0.10.2 From cd53bd6893cc50fddc6f741ed091420965283ddc Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Thu, 30 Jun 2016 12:12:31 -0500 Subject: usb: musb: sunxi: make unexported symbols static The sunxi_musb_dma_controller_create and _destroy are not exported or used outside the driver, so fix sparse warnings by making these two static: drivers/usb/musb/sunxi.c:357:23: warning: symbol 'sunxi_musb_dma_controller_create' was not declared. Should it be static? drivers/usb/musb/sunxi.c:363:6: warning: symbol 'sunxi_musb_dma_controller_destroy' was not declared. Should it be static? Signed-off-by: Ben Dooks Signed-off-by: Bin Liu Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/musb/sunxi.c b/drivers/usb/musb/sunxi.c index 7650051..8522081 100644 --- a/drivers/usb/musb/sunxi.c +++ b/drivers/usb/musb/sunxi.c @@ -354,13 +354,13 @@ static void sunxi_musb_disable(struct musb *musb) clear_bit(SUNXI_MUSB_FL_ENABLED, &glue->flags); } -struct dma_controller *sunxi_musb_dma_controller_create(struct musb *musb, - void __iomem *base) +static struct dma_controller * +sunxi_musb_dma_controller_create(struct musb *musb, void __iomem *base) { return NULL; } -void sunxi_musb_dma_controller_destroy(struct dma_controller *c) +static void sunxi_musb_dma_controller_destroy(struct dma_controller *c) { } -- cgit v0.10.2 From a1ca2c6b2924a602bb19dce7390a6e9604dd45bf Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Thu, 30 Jun 2016 12:12:32 -0500 Subject: usb: musb: sunxi: Simplify dr_mode handling phy-sun4i-usb now has proper dr_mode handling, it always registers an extcon, and sends a notify with the mode (even when in peripheral- / host-only mode) at least once. So we can simply the sunxi musb glue by always registering its extcon notifier and relying on sunxi_musb_work() to enable vbus when in host-only mode. This also enables host- and peripheral-only mode with vbus monitoring. Tested-by: Maxime Ripard Signed-off-by: Hans de Goede Signed-off-by: Bin Liu Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/musb/sunxi.c b/drivers/usb/musb/sunxi.c index 8522081..c6ee166 100644 --- a/drivers/usb/musb/sunxi.c +++ b/drivers/usb/musb/sunxi.c @@ -256,12 +256,10 @@ static int sunxi_musb_init(struct musb *musb) writeb(SUNXI_MUSB_VEND0_PIO_MODE, musb->mregs + SUNXI_MUSB_VEND0); /* Register notifier before calling phy_init() */ - if (musb->port_mode == MUSB_PORT_MODE_DUAL_ROLE) { - ret = extcon_register_notifier(glue->extcon, EXTCON_USB_HOST, - &glue->host_nb); - if (ret) - goto error_reset_assert; - } + ret = extcon_register_notifier(glue->extcon, EXTCON_USB_HOST, + &glue->host_nb); + if (ret) + goto error_reset_assert; ret = phy_init(glue->phy); if (ret) @@ -275,9 +273,8 @@ static int sunxi_musb_init(struct musb *musb) return 0; error_unregister_notifier: - if (musb->port_mode == MUSB_PORT_MODE_DUAL_ROLE) - extcon_unregister_notifier(glue->extcon, EXTCON_USB_HOST, - &glue->host_nb); + extcon_unregister_notifier(glue->extcon, EXTCON_USB_HOST, + &glue->host_nb); error_reset_assert: if (test_bit(SUNXI_MUSB_FL_HAS_RESET, &glue->flags)) reset_control_assert(glue->rst); @@ -301,9 +298,8 @@ static int sunxi_musb_exit(struct musb *musb) phy_exit(glue->phy); - if (musb->port_mode == MUSB_PORT_MODE_DUAL_ROLE) - extcon_unregister_notifier(glue->extcon, EXTCON_USB_HOST, - &glue->host_nb); + extcon_unregister_notifier(glue->extcon, EXTCON_USB_HOST, + &glue->host_nb); if (test_bit(SUNXI_MUSB_FL_HAS_RESET, &glue->flags)) reset_control_assert(glue->rst); @@ -315,25 +311,6 @@ static int sunxi_musb_exit(struct musb *musb) return 0; } -static int sunxi_set_mode(struct musb *musb, u8 mode) -{ - struct sunxi_glue *glue = dev_get_drvdata(musb->controller->parent); - int ret; - - if (mode == MUSB_HOST) { - ret = phy_power_on(glue->phy); - if (ret) - return ret; - - set_bit(SUNXI_MUSB_FL_PHY_ON, &glue->flags); - /* Stop musb work from turning vbus off again */ - set_bit(SUNXI_MUSB_FL_VBUS_ON, &glue->flags); - musb->xceiv->otg->state = OTG_STATE_A_WAIT_VRISE; - } - - return 0; -} - static void sunxi_musb_enable(struct musb *musb) { struct sunxi_glue *glue = dev_get_drvdata(musb->controller->parent); @@ -582,7 +559,6 @@ static const struct musb_platform_ops sunxi_musb_ops = { .exit = sunxi_musb_exit, .enable = sunxi_musb_enable, .disable = sunxi_musb_disable, - .set_mode = sunxi_set_mode, .fifo_offset = sunxi_musb_fifo_offset, .ep_offset = sunxi_musb_ep_offset, .busctl_offset = sunxi_musb_busctl_offset, @@ -638,10 +614,6 @@ static int sunxi_musb_probe(struct platform_device *pdev) return -EINVAL; } - glue = devm_kzalloc(&pdev->dev, sizeof(*glue), GFP_KERNEL); - if (!glue) - return -ENOMEM; - memset(&pdata, 0, sizeof(pdata)); switch (usb_get_dr_mode(&pdev->dev)) { #if defined CONFIG_USB_MUSB_DUAL_ROLE || defined CONFIG_USB_MUSB_HOST @@ -649,15 +621,13 @@ static int sunxi_musb_probe(struct platform_device *pdev) pdata.mode = MUSB_PORT_MODE_HOST; break; #endif +#if defined CONFIG_USB_MUSB_DUAL_ROLE || defined CONFIG_USB_MUSB_GADGET + case USB_DR_MODE_PERIPHERAL: + pdata.mode = MUSB_PORT_MODE_GADGET; + break; +#endif #ifdef CONFIG_USB_MUSB_DUAL_ROLE case USB_DR_MODE_OTG: - glue->extcon = extcon_get_edev_by_phandle(&pdev->dev, 0); - if (IS_ERR(glue->extcon)) { - if (PTR_ERR(glue->extcon) == -EPROBE_DEFER) - return -EPROBE_DEFER; - dev_err(&pdev->dev, "Invalid or missing extcon\n"); - return PTR_ERR(glue->extcon); - } pdata.mode = MUSB_PORT_MODE_DUAL_ROLE; break; #endif @@ -668,6 +638,10 @@ static int sunxi_musb_probe(struct platform_device *pdev) pdata.platform_ops = &sunxi_musb_ops; pdata.config = &sunxi_musb_hdrc_config; + glue = devm_kzalloc(&pdev->dev, sizeof(*glue), GFP_KERNEL); + if (!glue) + return -ENOMEM; + glue->dev = &pdev->dev; INIT_WORK(&glue->work, sunxi_musb_work); glue->host_nb.notifier_call = sunxi_musb_host_notifier; @@ -701,6 +675,14 @@ static int sunxi_musb_probe(struct platform_device *pdev) } } + glue->extcon = extcon_get_edev_by_phandle(&pdev->dev, 0); + if (IS_ERR(glue->extcon)) { + if (PTR_ERR(glue->extcon) == -EPROBE_DEFER) + return -EPROBE_DEFER; + dev_err(&pdev->dev, "Invalid or missing extcon\n"); + return PTR_ERR(glue->extcon); + } + glue->phy = devm_phy_get(&pdev->dev, "usb"); if (IS_ERR(glue->phy)) { if (PTR_ERR(glue->phy) == -EPROBE_DEFER) -- cgit v0.10.2 From 18d3df3eab23796d7f852f9c6bb60962b8372ced Mon Sep 17 00:00:00 2001 From: Paolo Abeni Date: Thu, 14 Jul 2016 18:00:10 +0200 Subject: vlan: use a valid default mtu value for vlan over macsec macsec can't cope with mtu frames which need vlan tag insertion, and vlan device set the default mtu equal to the underlying dev's one. By default vlan over macsec devices use invalid mtu, dropping all the large packets. This patch adds a netif helper to check if an upper vlan device needs mtu reduction. The helper is used during vlan devices initialization to set a valid default and during mtu updating to forbid invalid, too bit, mtu values. The helper currently only check if the lower dev is a macsec device, if we get more users, we need to update only the helper (possibly reserving an additional IFF bit). Signed-off-by: Paolo Abeni Signed-off-by: David S. Miller diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index f45929c..da4b33b 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -4145,6 +4145,13 @@ static inline void netif_keep_dst(struct net_device *dev) dev->priv_flags &= ~(IFF_XMIT_DST_RELEASE | IFF_XMIT_DST_RELEASE_PERM); } +/* return true if dev can't cope with mtu frames that need vlan tag insertion */ +static inline bool netif_reduces_vlan_mtu(struct net_device *dev) +{ + /* TODO: reserve and use an additional IFF bit, if we get more users */ + return dev->priv_flags & IFF_MACSEC; +} + extern struct pernet_operations __net_initdata loopback_net_ops; /* Logging, debugging and troubleshooting/diagnostic helpers. */ diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c index 86ae75b..516b0e7 100644 --- a/net/8021q/vlan_dev.c +++ b/net/8021q/vlan_dev.c @@ -146,10 +146,12 @@ static netdev_tx_t vlan_dev_hard_start_xmit(struct sk_buff *skb, static int vlan_dev_change_mtu(struct net_device *dev, int new_mtu) { - /* TODO: gotta make sure the underlying layer can handle it, - * maybe an IFF_VLAN_CAPABLE flag for devices? - */ - if (vlan_dev_priv(dev)->real_dev->mtu < new_mtu) + struct net_device *real_dev = vlan_dev_priv(dev)->real_dev; + unsigned int max_mtu = real_dev->mtu; + + if (netif_reduces_vlan_mtu(real_dev)) + max_mtu -= VLAN_HLEN; + if (max_mtu < new_mtu) return -ERANGE; dev->mtu = new_mtu; diff --git a/net/8021q/vlan_netlink.c b/net/8021q/vlan_netlink.c index c92b52f..1270207 100644 --- a/net/8021q/vlan_netlink.c +++ b/net/8021q/vlan_netlink.c @@ -118,6 +118,7 @@ static int vlan_newlink(struct net *src_net, struct net_device *dev, { struct vlan_dev_priv *vlan = vlan_dev_priv(dev); struct net_device *real_dev; + unsigned int max_mtu; __be16 proto; int err; @@ -144,9 +145,11 @@ static int vlan_newlink(struct net *src_net, struct net_device *dev, if (err < 0) return err; + max_mtu = netif_reduces_vlan_mtu(real_dev) ? real_dev->mtu - VLAN_HLEN : + real_dev->mtu; if (!tb[IFLA_MTU]) - dev->mtu = real_dev->mtu; - else if (dev->mtu > real_dev->mtu) + dev->mtu = max_mtu; + else if (dev->mtu > max_mtu) return -EINVAL; err = vlan_changelink(dev, tb, data); -- cgit v0.10.2 From de702da7a823ab0c4a1e53ed79a2695f0d453855 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Fri, 15 Jul 2016 16:40:22 -0700 Subject: et131x: Fix logical vs bitwise check in et131x_tx_timeout() We should be using a logical check here instead of a bitwise operation to check if the device is closed already in et131x_tx_timeout(). Reported-by: coverity (CID 146498) Fixes: 38df6492eb511 ("et131x: Add PCIe gigabit ethernet driver et131x to drivers/net") Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/agere/et131x.c b/drivers/net/ethernet/agere/et131x.c index 30defe6..821d86c 100644 --- a/drivers/net/ethernet/agere/et131x.c +++ b/drivers/net/ethernet/agere/et131x.c @@ -3851,7 +3851,7 @@ static void et131x_tx_timeout(struct net_device *netdev) unsigned long flags; /* If the device is closed, ignore the timeout */ - if (~(adapter->flags & FMP_ADAPTER_INTERRUPT_IN_USE)) + if (!(adapter->flags & FMP_ADAPTER_INTERRUPT_IN_USE)) return; /* Any nonrecoverable hardware error? -- cgit v0.10.2 From ea6ff112b095dce2060c304195904d859c3e2625 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Fri, 15 Jul 2016 16:41:16 -0700 Subject: net: nb8800: Fix SKB leak in nb8800_receive() In case nb8800_receive() fails to allocate a fragment, we would leak the SKB freshly allocated and just return, instead, free it. Reported-by: coverity (CID 1341750) Signed-off-by: Florian Fainelli Acked-by: Mans Rullgard Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/aurora/nb8800.c b/drivers/net/ethernet/aurora/nb8800.c index 08a23e6..1a3555d 100644 --- a/drivers/net/ethernet/aurora/nb8800.c +++ b/drivers/net/ethernet/aurora/nb8800.c @@ -259,6 +259,7 @@ static void nb8800_receive(struct net_device *dev, unsigned int i, if (err) { netdev_err(dev, "rx buffer allocation failed\n"); dev->stats.rx_dropped++; + dev_kfree_skb(skb); return; } -- cgit v0.10.2 From 8e6ce7ebeb34f0992f56de078c3744fb383657fa Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Fri, 15 Jul 2016 16:42:16 -0700 Subject: net: cavium: liquidio: Avoid dma_unmap_single on uninitialized ndata The label lio_xmit_failed is used 3 times through liquidio_xmit() but it always makes a call to dma_unmap_single() using potentially uninitialized variables from "ndata" variable. Out of the 3 gotos, 2 run after ndata has been initialized, and had a prior dma_map_single() call. Fix this by adding a new error label: lio_xmit_dma_failed which does this dma_unmap_single() and then processed with the lio_xmit_failed fallthrough. Fixes: f21fb3ed364bb ("Add support of Cavium Liquidio ethernet adapters") Reported-by: coverity (CID 1309740) Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/cavium/liquidio/lio_main.c b/drivers/net/ethernet/cavium/liquidio/lio_main.c index 8de79ae..0e7e7da 100644 --- a/drivers/net/ethernet/cavium/liquidio/lio_main.c +++ b/drivers/net/ethernet/cavium/liquidio/lio_main.c @@ -2821,7 +2821,7 @@ static int liquidio_xmit(struct sk_buff *skb, struct net_device *netdev) if (!g) { netif_info(lio, tx_err, lio->netdev, "Transmit scatter gather: glist null!\n"); - goto lio_xmit_failed; + goto lio_xmit_dma_failed; } cmdsetup.s.gather = 1; @@ -2892,7 +2892,7 @@ static int liquidio_xmit(struct sk_buff *skb, struct net_device *netdev) else status = octnet_send_nic_data_pkt(oct, &ndata, xmit_more); if (status == IQ_SEND_FAILED) - goto lio_xmit_failed; + goto lio_xmit_dma_failed; netif_info(lio, tx_queued, lio->netdev, "Transmit queued successfully\n"); @@ -2906,12 +2906,13 @@ static int liquidio_xmit(struct sk_buff *skb, struct net_device *netdev) return NETDEV_TX_OK; +lio_xmit_dma_failed: + dma_unmap_single(&oct->pci_dev->dev, ndata.cmd.dptr, + ndata.datasize, DMA_TO_DEVICE); lio_xmit_failed: stats->tx_dropped++; netif_info(lio, tx_err, lio->netdev, "IQ%d Transmit dropped:%llu\n", iq_no, stats->tx_dropped); - dma_unmap_single(&oct->pci_dev->dev, ndata.cmd.dptr, - ndata.datasize, DMA_TO_DEVICE); recv_buffer_free(skb); return NETDEV_TX_OK; } -- cgit v0.10.2 From a46e667887448da10e26e46442bda01d1f311aaf Mon Sep 17 00:00:00 2001 From: Lans Zhang Date: Mon, 18 Jul 2016 00:10:39 +0100 Subject: PKCS#7: Fix panic when referring to the empty AKID when DEBUG defined This fix resolves the following kernel panic if an empty or missing AuthorityKeyIdentifier is encountered and DEBUG is defined in pkcs7_verify.c. [ 459.041989] PKEY: <==public_key_verify_signature() = 0 [ 459.041993] PKCS7: Verified signature 1 [ 459.041995] PKCS7: ==> pkcs7_verify_sig_chain() [ 459.041999] PKCS7: verify Sample DB Certificate for SCP: 01 [ 459.042002] PKCS7: - issuer Sample KEK Certificate for SCP [ 459.042014] BUG: unable to handle kernel NULL pointer dereference at (null) [ 459.042135] IP: [] pkcs7_verify+0x72c/0x7f0 [ 459.042217] PGD 739e6067 PUD 77719067 PMD 0 [ 459.042286] Oops: 0000 [#1] PREEMPT SMP [ 459.042328] Modules linked in: [ 459.042368] CPU: 0 PID: 474 Comm: kexec Not tainted 4.7.0-rc7-WR8.0.0.0_standard+ #18 [ 459.042462] Hardware name: To be filled by O.E.M. To be filled by O.E.M./Aptio CRB, BIOS 5.6.5 10/09/2014 [ 459.042586] task: ffff880073a50000 ti: ffff8800738e8000 task.ti: ffff8800738e8000 [ 459.042675] RIP: 0010:[] [] pkcs7_verify+0x72c/0x7f0 [ 459.042784] RSP: 0018:ffff8800738ebd58 EFLAGS: 00010246 [ 459.042845] RAX: 0000000000000000 RBX: ffff880076b7da80 RCX: 0000000000000006 [ 459.042929] RDX: 0000000000000001 RSI: ffffffff81c85001 RDI: ffffffff81ca00a9 [ 459.043014] RBP: ffff8800738ebd98 R08: 0000000000000400 R09: ffff8800788a304c [ 459.043098] R10: 0000000000000000 R11: 00000000000060ca R12: ffff8800769a2bc0 [ 459.043182] R13: ffff880077358300 R14: 0000000000000000 R15: ffff8800769a2dc0 [ 459.043268] FS: 00007f24cc741700(0000) GS:ffff880074e00000(0000) knlGS:0000000000000000 [ 459.043365] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 459.043431] CR2: 0000000000000000 CR3: 0000000073a36000 CR4: 00000000001006f0 [ 459.043514] Stack: [ 459.043530] 0000000000000000 ffffffbf00000020 31ffffff813e68b0 0000000000000002 [ 459.043644] ffff8800769a2bc0 0000000000000000 00000000007197b8 0000000000000002 [ 459.043756] ffff8800738ebdd8 ffffffff81153fb1 0000000000000000 0000000000000000 [ 459.043869] Call Trace: [ 459.043898] [] verify_pkcs7_signature+0x61/0x140 [ 459.043974] [] verify_pefile_signature+0x2cb/0x830 [ 459.044052] [] ? verify_pefile_signature+0x830/0x830 [ 459.044134] [] bzImage64_verify_sig+0x15/0x20 [ 459.046332] [] arch_kexec_kernel_verify_sig+0x29/0x40 [ 459.048552] [] SyS_kexec_file_load+0x1f4/0x6c0 [ 459.050768] [] ? __do_page_fault+0x1b6/0x550 [ 459.052996] [] entry_SYSCALL_64_fastpath+0x17/0x93 [ 459.055242] Code: e8 0a d6 ff ff 85 c0 0f 88 7a fb ff ff 4d 39 fd 4d 89 7d 08 74 45 4d 89 fd e9 14 fe ff ff 4d 8b 76 08 31 c0 48 c7 c7 a9 00 ca 81 <41> 0f b7 36 49 8d 56 02 e8 d0 91 d6 ff 4d 8b 3c 24 4d 85 ff 0f [ 459.060535] RIP [] pkcs7_verify+0x72c/0x7f0 [ 459.063040] RSP [ 459.065456] CR2: 0000000000000000 [ 459.075998] ---[ end trace c15f0e897cda28dc ]--- Signed-off-by: Lans Zhang Signed-off-by: David Howells Cc: Dave Young Cc: Baoquan He Cc: Vivek Goyal cc: linux-crypto@vger.kernel.org cc: kexec@lists.infradead.org Signed-off-by: James Morris diff --git a/crypto/asymmetric_keys/pkcs7_verify.c b/crypto/asymmetric_keys/pkcs7_verify.c index 44b746e..2ffd697 100644 --- a/crypto/asymmetric_keys/pkcs7_verify.c +++ b/crypto/asymmetric_keys/pkcs7_verify.c @@ -227,7 +227,7 @@ static int pkcs7_verify_sig_chain(struct pkcs7_message *pkcs7, if (asymmetric_key_id_same(p->id, auth)) goto found_issuer_check_skid; } - } else { + } else if (sig->auth_ids[1]) { auth = sig->auth_ids[1]; pr_debug("- want %*phN\n", auth->len, auth->data); for (p = pkcs7->certs; p; p = p->next) { -- cgit v0.10.2 From d128471a14775cd11abd81c09b2a086997ab3150 Mon Sep 17 00:00:00 2001 From: Lans Zhang Date: Mon, 18 Jul 2016 00:10:47 +0100 Subject: pefile: Fix the failure of calculation for digest Commit e68503bd68 forgot to set digest_len and thus cause the following error reported by kexec when launching a crash kernel: kexec_file_load failed: Bad message Fixes: e68503bd68 (KEYS: Generalise system_verify_data() to provide access to internal content) Signed-off-by: Lans Zhang Tested-by: Dave Young Signed-off-by: David Howells Cc: Baoquan He Cc: Vivek Goyal cc: kexec@lists.infradead.org cc: linux-crypto@vger.kernel.org Signed-off-by: James Morris diff --git a/crypto/asymmetric_keys/mscode_parser.c b/crypto/asymmetric_keys/mscode_parser.c index 6a76d5c..9492e1c 100644 --- a/crypto/asymmetric_keys/mscode_parser.c +++ b/crypto/asymmetric_keys/mscode_parser.c @@ -124,5 +124,10 @@ int mscode_note_digest(void *context, size_t hdrlen, struct pefile_context *ctx = context; ctx->digest = kmemdup(value, vlen, GFP_KERNEL); - return ctx->digest ? 0 : -ENOMEM; + if (!ctx->digest) + return -ENOMEM; + + ctx->digest_len = vlen; + + return 0; } -- cgit v0.10.2 From acddc72015e5bc8f640b02d38b36afd7841c9c14 Mon Sep 17 00:00:00 2001 From: Mat Martineau Date: Mon, 18 Jul 2016 00:10:55 +0100 Subject: KEYS: Fix for erroneous trust of incorrectly signed X.509 certs Arbitrary X.509 certificates without authority key identifiers (AKIs) can be added to "trusted" keyrings, including IMA or EVM certs loaded from the filesystem. Signature verification is currently bypassed for certs without AKIs. Trusted keys were recently refactored, and this bug is not present in 4.6. restrict_link_by_signature should return -ENOKEY (no matching parent certificate found) if the certificate being evaluated has no AKIs, instead of bypassing signature checks and returning 0 (new certificate accepted). Reported-by: Petko Manolov Signed-off-by: Mat Martineau Signed-off-by: David Howells Signed-off-by: James Morris diff --git a/crypto/asymmetric_keys/restrict.c b/crypto/asymmetric_keys/restrict.c index ac4bddf..19d1afb9 100644 --- a/crypto/asymmetric_keys/restrict.c +++ b/crypto/asymmetric_keys/restrict.c @@ -87,7 +87,7 @@ int restrict_link_by_signature(struct key *trust_keyring, sig = payload->data[asym_auth]; if (!sig->auth_ids[0] && !sig->auth_ids[1]) - return 0; + return -ENOKEY; if (ca_keyid && !asymmetric_key_id_partial(sig->auth_ids[1], ca_keyid)) return -EPERM; -- cgit v0.10.2 From bfe5b1b1e013f7b1c0fd2ac3b3c8c380114b3fb9 Mon Sep 17 00:00:00 2001 From: Ville Viinikka Date: Fri, 8 Jul 2016 18:27:02 +0300 Subject: mmc: block: fix free of uninitialized 'idata->buf' Set 'idata->buf' to NULL so that it never gets returned without initialization. This fixes a bug where mmc_blk_ioctl_cmd() would free both 'idata' and 'idata->buf' but 'idata->buf' was returned uninitialized. Fixes: 1ff8950c0433 ("mmc: block: change to use kmalloc when copy data from userspace") Signed-off-by: Ville Viinikka Cc: Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c index e62fde3..c13ba2a 100644 --- a/drivers/mmc/card/block.c +++ b/drivers/mmc/card/block.c @@ -355,8 +355,10 @@ static struct mmc_blk_ioc_data *mmc_blk_ioctl_copy_from_user( goto idata_err; } - if (!idata->buf_bytes) + if (!idata->buf_bytes) { + idata->buf = NULL; return idata; + } idata->buf = kmalloc(idata->buf_bytes, GFP_KERNEL); if (!idata->buf) { -- cgit v0.10.2 From f68381a70bb2b26c31b13fdaf67c778f92fd32b4 Mon Sep 17 00:00:00 2001 From: Taras Kondratiuk Date: Wed, 13 Jul 2016 22:05:38 +0000 Subject: mmc: block: fix packed command header endianness The code that fills packed command header assumes that CPU runs in little-endian mode. Hence the header is malformed in big-endian mode and causes MMC data transfer errors: [ 563.200828] mmcblk0: error -110 transferring data, sector 2048, nr 8, cmd response 0x900, card status 0xc40 [ 563.219647] mmcblk0: packed cmd failed, nr 2, sectors 16, failure index: -1 Convert header data to LE. Signed-off-by: Taras Kondratiuk Fixes: ce39f9d17c14 ("mmc: support packed write command for eMMC4.5 devices") Cc: Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c index c13ba2a..c5472e3 100644 --- a/drivers/mmc/card/block.c +++ b/drivers/mmc/card/block.c @@ -1788,8 +1788,8 @@ static void mmc_blk_packed_hdr_wrq_prep(struct mmc_queue_req *mqrq, packed_cmd_hdr = packed->cmd_hdr; memset(packed_cmd_hdr, 0, sizeof(packed->cmd_hdr)); - packed_cmd_hdr[0] = (packed->nr_entries << 16) | - (PACKED_CMD_WR << 8) | PACKED_CMD_VER; + packed_cmd_hdr[0] = cpu_to_le32((packed->nr_entries << 16) | + (PACKED_CMD_WR << 8) | PACKED_CMD_VER); hdr_blocks = mmc_large_sector(card) ? 8 : 1; /* @@ -1803,14 +1803,14 @@ static void mmc_blk_packed_hdr_wrq_prep(struct mmc_queue_req *mqrq, ((brq->data.blocks * brq->data.blksz) >= card->ext_csd.data_tag_unit_size); /* Argument of CMD23 */ - packed_cmd_hdr[(i * 2)] = + packed_cmd_hdr[(i * 2)] = cpu_to_le32( (do_rel_wr ? MMC_CMD23_ARG_REL_WR : 0) | (do_data_tag ? MMC_CMD23_ARG_TAG_REQ : 0) | - blk_rq_sectors(prq); + blk_rq_sectors(prq)); /* Argument of CMD18 or CMD25 */ - packed_cmd_hdr[((i * 2)) + 1] = + packed_cmd_hdr[((i * 2)) + 1] = cpu_to_le32( mmc_card_blockaddr(card) ? - blk_rq_pos(prq) : blk_rq_pos(prq) << 9; + blk_rq_pos(prq) : blk_rq_pos(prq) << 9); packed->blocks += blk_rq_sectors(prq); i++; } -- cgit v0.10.2 From b3802db5eb72d2a96f4aa4ff0abb937033df2acf Mon Sep 17 00:00:00 2001 From: Robert Jarzmik Date: Thu, 14 Jul 2016 17:05:50 +0200 Subject: mmc: pxamci: fix potential oops As reported by Dan in his report in [1], there is a potential NULL pointer derefence if these conditions are met : - there is no platform_data provided, ie. host->pdata = NULL Fix this by only using the platform data ro_invert when a gpio for read-only is provided by the platform data. This doesn't appear yet as every pxa board provides a platform_data, and calls pxa_set_mci_info() with a non NULL pointer. [1] [bug report] mmc: pxamci: fix card detect with slot-gpio API. The commit fd546ee6a7dc ("mmc: pxamci: fix card detect with slot-gpio API") from Sep 26, 2015, leads to the following static checker warning: drivers/mmc/host/pxamci.c:809 pxamci_probe() warn: variable dereferenced before check 'host->pdata' (see line 798) Fixes: fd546ee6a7dc ("mmc: pxamci: fix card detect with slot-gpio API") Reported-by: Dan Carpenter Signed-off-by: Robert Jarzmik Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/host/pxamci.c b/drivers/mmc/host/pxamci.c index 86fac3e..c763b40 100644 --- a/drivers/mmc/host/pxamci.c +++ b/drivers/mmc/host/pxamci.c @@ -789,14 +789,16 @@ static int pxamci_probe(struct platform_device *pdev) gpio_direction_output(gpio_power, host->pdata->gpio_power_invert); } - if (gpio_is_valid(gpio_ro)) + if (gpio_is_valid(gpio_ro)) { ret = mmc_gpio_request_ro(mmc, gpio_ro); - if (ret) { - dev_err(&pdev->dev, "Failed requesting gpio_ro %d\n", gpio_ro); - goto out; - } else { - mmc->caps2 |= host->pdata->gpio_card_ro_invert ? - 0 : MMC_CAP2_RO_ACTIVE_HIGH; + if (ret) { + dev_err(&pdev->dev, "Failed requesting gpio_ro %d\n", + gpio_ro); + goto out; + } else { + mmc->caps2 |= host->pdata->gpio_card_ro_invert ? + 0 : MMC_CAP2_RO_ACTIVE_HIGH; + } } if (gpio_is_valid(gpio_cd)) -- cgit v0.10.2 From 76df52969711ae3725a98f26fbbc6a349803dcbf Mon Sep 17 00:00:00 2001 From: Kazuki Oikawa Date: Mon, 18 Jul 2016 01:16:15 +0900 Subject: ALSA: usb-audio: Fix quirks code is not called snd_usb_{set_interface,ctl_msg}_quirk checks chip->usb_id to need calling a quirks code. But existed code path that not calling dev_set_drvdata in usb_audio_probe. Fixes: 79289e24194a ("ALSA: usb-audio: Refer to chip->usb_id for quirks and MIDI creation") Signed-off-by: Kazuki Oikawa Cc: # v4.6+ Reviewed-by: Takashi Sakamoto Tested-by: Takashi Sakamoto Signed-off-by: Takashi Iwai diff --git a/sound/usb/card.c b/sound/usb/card.c index 69860da..9e5276d 100644 --- a/sound/usb/card.c +++ b/sound/usb/card.c @@ -556,7 +556,6 @@ static int usb_audio_probe(struct usb_interface *intf, goto __error; } chip = usb_chip[i]; - dev_set_drvdata(&dev->dev, chip); atomic_inc(&chip->active); /* avoid autopm */ break; } @@ -582,6 +581,7 @@ static int usb_audio_probe(struct usb_interface *intf, goto __error; } } + dev_set_drvdata(&dev->dev, chip); /* * For devices with more than one control interface, we assume the -- cgit v0.10.2 From c71d4d58981bed3366769ef5cf1f20e588fe16d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Mon, 18 Jul 2016 13:15:14 +0300 Subject: drm/i915: Treat eDP as always connected, again MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit eDP should be treated as connected even if doesn't have an EDID. In that case we'll use the timings from the VBT. That used to be the case until commit f21a21983ef1 ("drm/i915: Splitting intel_dp_detect") broke things by considering even eDP disconnected if we fail to get an EDID for it. Fix things up again by treating eDP as always connected. Cc: Shubhangi Shrivastava Cc: Nathan D Ciobanu Cc: Sivakumar Thulasimani Cc: Ander Conselvan de Oliveira Cc: Larry Finger Reported-by: Larry Finger Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=96675 Cc: drm-intel-fixes@lists.freedesktop.org Fixes: f21a21983ef1 ("drm/i915: Splitting intel_dp_detect") Signed-off-by: Ville Syrjälä Tested-by: Larry Finger Link: http://patchwork.freedesktop.org/patch/msgid/1468836914-16537-1-git-send-email-ville.syrjala@linux.intel.com (cherry picked from commit 1b7f2c8b0773d5ccbef43ef38a13ad33136c9679) Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 40745e38d..891107f 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -4645,7 +4645,7 @@ intel_dp_detect(struct drm_connector *connector, bool force) intel_dp->detect_done = false; - if (intel_connector->detect_edid) + if (is_edp(intel_dp) || intel_connector->detect_edid) return connector_status_connected; else return connector_status_disconnected; -- cgit v0.10.2 From ed2eebbd61af8d378ca39ad7aef7017f29eed6f3 Mon Sep 17 00:00:00 2001 From: Lionel Landwerlin Date: Wed, 25 May 2016 14:30:41 +0100 Subject: drm/i915: add missing condition for committing planes on crtc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The i915 driver checks for color management properties changes as part of a plane update. Therefore a color management update must imply a plane update, otherwise we never update the transformation matrixes and degamma/gamma LUTs. v2: add comment about moving the commit of color management registers to an async worker v3: Commit color management register right after vblank v4: Move back color management commit condition together with planes commit v5: Trigger color management commit through the planes commit (Daniel) v6: Make plane change update more readable Fixes: 20a34e78f0d7 (drm/i915: Update color management during vblank evasion.) Cc: Maarten Lankhorst Cc: Ville Syrjälä Cc: Daniel Vetter Cc: drm-intel-fixes@lists.freedesktop.org Signed-off-by: Lionel Landwerlin References: https://lkml.org/lkml/2016/7/14/614 Reviewed-and-tested-by: Mario Kleiner Link: http://patchwork.freedesktop.org/patch/msgid/1464183041-8478-1-git-send-email-lionel.g.landwerlin@intel.com (cherry picked from commit e7852a4b3a4fb6f6c18fdaff934580aa8521599a) Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 04452cf..3074c56 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -11997,6 +11997,12 @@ static int intel_crtc_atomic_check(struct drm_crtc *crtc, ret = intel_color_check(crtc, crtc_state); if (ret) return ret; + + /* + * Changing color management on Intel hardware is + * handled as part of planes update. + */ + crtc_state->planes_changed = true; } ret = 0; -- cgit v0.10.2 From e03141db361399619f9ee97e00d4c6fe2b472104 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Sat, 16 Jul 2016 00:07:12 +0300 Subject: perf jit: Add missing curly braces It doesn't change the runtime behavior, but my static checker complains that curly braces were intended. Signed-off-by: Dan Carpenter Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Peter Zijlstra Cc: Stephane Eranian Cc: kernel-janitors@vger.kernel.org Link: http://lkml.kernel.org/r/20160715210712.GA19522@mwanda Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/jvmti/jvmti_agent.c b/tools/perf/jvmti/jvmti_agent.c index 3573f31..91bf333 100644 --- a/tools/perf/jvmti/jvmti_agent.c +++ b/tools/perf/jvmti/jvmti_agent.c @@ -491,10 +491,11 @@ jvmti_write_debug_info(void *agent, uint64_t code, const char *file, if (sret != 1) goto error; } - if (padding_count) + if (padding_count) { sret = fwrite_unlocked(pad_bytes, padding_count, 1, fp); if (sret != 1) goto error; + } funlockfile(fp); return 0; -- cgit v0.10.2 From 9fcfcdf3c7b613c0d9536f57587456411b8a4e33 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Sat, 16 Jul 2016 00:08:36 +0300 Subject: perf jit: Remove some no-op error handling The 'info.e_machine' struct member is an uint16_t so 'm' is never less than zero. It looks like this was maybe left over code from earlier versions so I've just removed it. Signed-off-by: Dan Carpenter Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Peter Zijlstra Cc: Stephane Eranian Cc: kernel-janitors@vger.kernel.org Link: http://lkml.kernel.org/r/20160715210836.GB19522@mwanda Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/jvmti/jvmti_agent.c b/tools/perf/jvmti/jvmti_agent.c index 91bf333..55daeff 100644 --- a/tools/perf/jvmti/jvmti_agent.c +++ b/tools/perf/jvmti/jvmti_agent.c @@ -59,7 +59,6 @@ static int get_e_machine(struct jitheader *hdr) ssize_t sret; char id[16]; int fd, ret = -1; - int m = -1; struct { uint16_t e_type; uint16_t e_machine; @@ -81,11 +80,7 @@ static int get_e_machine(struct jitheader *hdr) if (sret != sizeof(info)) goto error; - m = info.e_machine; - if (m < 0) - m = 0; /* ELF EM_NONE */ - - hdr->elf_mach = m; + hdr->elf_mach = info.e_machine; ret = 0; error: close(fd); -- cgit v0.10.2 From e4c6fb779498243ec001c5547b3504fe6b1993ec Mon Sep 17 00:00:00 2001 From: Oliver Neukum Date: Thu, 14 Jul 2016 15:41:30 +0200 Subject: usbnet: move the CDC parser into USB core The dependencies were impossible to handle preventing drivers for CDC devices not which are not network drivers from using the common parser. Signed-off-by: Oliver Neukum Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c index 61ba464..b56d78a 100644 --- a/drivers/net/usb/usbnet.c +++ b/drivers/net/usb/usbnet.c @@ -42,7 +42,6 @@ #include #include #include -#include #include #include #include @@ -1968,143 +1967,6 @@ out: return err; } -int cdc_parse_cdc_header(struct usb_cdc_parsed_header *hdr, - struct usb_interface *intf, - u8 *buffer, - int buflen) -{ - /* duplicates are ignored */ - struct usb_cdc_union_desc *union_header = NULL; - - /* duplicates are not tolerated */ - struct usb_cdc_header_desc *header = NULL; - struct usb_cdc_ether_desc *ether = NULL; - struct usb_cdc_mdlm_detail_desc *detail = NULL; - struct usb_cdc_mdlm_desc *desc = NULL; - - unsigned int elength; - int cnt = 0; - - memset(hdr, 0x00, sizeof(struct usb_cdc_parsed_header)); - hdr->phonet_magic_present = false; - while (buflen > 0) { - elength = buffer[0]; - if (!elength) { - dev_err(&intf->dev, "skipping garbage byte\n"); - elength = 1; - goto next_desc; - } - if (buffer[1] != USB_DT_CS_INTERFACE) { - dev_err(&intf->dev, "skipping garbage\n"); - goto next_desc; - } - - switch (buffer[2]) { - case USB_CDC_UNION_TYPE: /* we've found it */ - if (elength < sizeof(struct usb_cdc_union_desc)) - goto next_desc; - if (union_header) { - dev_err(&intf->dev, "More than one union descriptor, skipping ...\n"); - goto next_desc; - } - union_header = (struct usb_cdc_union_desc *)buffer; - break; - case USB_CDC_COUNTRY_TYPE: - if (elength < sizeof(struct usb_cdc_country_functional_desc)) - goto next_desc; - hdr->usb_cdc_country_functional_desc = - (struct usb_cdc_country_functional_desc *)buffer; - break; - case USB_CDC_HEADER_TYPE: - if (elength != sizeof(struct usb_cdc_header_desc)) - goto next_desc; - if (header) - return -EINVAL; - header = (struct usb_cdc_header_desc *)buffer; - break; - case USB_CDC_ACM_TYPE: - if (elength < sizeof(struct usb_cdc_acm_descriptor)) - goto next_desc; - hdr->usb_cdc_acm_descriptor = - (struct usb_cdc_acm_descriptor *)buffer; - break; - case USB_CDC_ETHERNET_TYPE: - if (elength != sizeof(struct usb_cdc_ether_desc)) - goto next_desc; - if (ether) - return -EINVAL; - ether = (struct usb_cdc_ether_desc *)buffer; - break; - case USB_CDC_CALL_MANAGEMENT_TYPE: - if (elength < sizeof(struct usb_cdc_call_mgmt_descriptor)) - goto next_desc; - hdr->usb_cdc_call_mgmt_descriptor = - (struct usb_cdc_call_mgmt_descriptor *)buffer; - break; - case USB_CDC_DMM_TYPE: - if (elength < sizeof(struct usb_cdc_dmm_desc)) - goto next_desc; - hdr->usb_cdc_dmm_desc = - (struct usb_cdc_dmm_desc *)buffer; - break; - case USB_CDC_MDLM_TYPE: - if (elength < sizeof(struct usb_cdc_mdlm_desc *)) - goto next_desc; - if (desc) - return -EINVAL; - desc = (struct usb_cdc_mdlm_desc *)buffer; - break; - case USB_CDC_MDLM_DETAIL_TYPE: - if (elength < sizeof(struct usb_cdc_mdlm_detail_desc *)) - goto next_desc; - if (detail) - return -EINVAL; - detail = (struct usb_cdc_mdlm_detail_desc *)buffer; - break; - case USB_CDC_NCM_TYPE: - if (elength < sizeof(struct usb_cdc_ncm_desc)) - goto next_desc; - hdr->usb_cdc_ncm_desc = (struct usb_cdc_ncm_desc *)buffer; - break; - case USB_CDC_MBIM_TYPE: - if (elength < sizeof(struct usb_cdc_mbim_desc)) - goto next_desc; - - hdr->usb_cdc_mbim_desc = (struct usb_cdc_mbim_desc *)buffer; - break; - case USB_CDC_MBIM_EXTENDED_TYPE: - if (elength < sizeof(struct usb_cdc_mbim_extended_desc)) - break; - hdr->usb_cdc_mbim_extended_desc = - (struct usb_cdc_mbim_extended_desc *)buffer; - break; - case CDC_PHONET_MAGIC_NUMBER: - hdr->phonet_magic_present = true; - break; - default: - /* - * there are LOTS more CDC descriptors that - * could legitimately be found here. - */ - dev_dbg(&intf->dev, "Ignoring descriptor: type %02x, length %ud\n", - buffer[2], elength); - goto next_desc; - } - cnt++; -next_desc: - buflen -= elength; - buffer += elength; - } - hdr->usb_cdc_union_desc = union_header; - hdr->usb_cdc_header_desc = header; - hdr->usb_cdc_mdlm_detail_desc = detail; - hdr->usb_cdc_mdlm_desc = desc; - hdr->usb_cdc_ether_desc = ether; - return cnt; -} - -EXPORT_SYMBOL(cdc_parse_cdc_header); - /* * The function can't be called inside suspend/resume callback, * otherwise deadlock will be caused. diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c index ea681f1..0406a59 100644 --- a/drivers/usb/core/message.c +++ b/drivers/usb/core/message.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include /* for usbcore internals */ #include @@ -2023,3 +2024,155 @@ int usb_driver_set_configuration(struct usb_device *udev, int config) return 0; } EXPORT_SYMBOL_GPL(usb_driver_set_configuration); + +/** + * cdc_parse_cdc_header - parse the extra headers present in CDC devices + * @hdr: the place to put the results of the parsing + * @intf: the interface for which parsing is requested + * @buffer: pointer to the extra headers to be parsed + * @buflen: length of the extra headers + * + * This evaluates the extra headers present in CDC devices which + * bind the interfaces for data and control and provide details + * about the capabilities of the device. + * + * Return: number of descriptors parsed or -EINVAL + * if the header is contradictory beyond salvage + */ + +int cdc_parse_cdc_header(struct usb_cdc_parsed_header *hdr, + struct usb_interface *intf, + u8 *buffer, + int buflen) +{ + /* duplicates are ignored */ + struct usb_cdc_union_desc *union_header = NULL; + + /* duplicates are not tolerated */ + struct usb_cdc_header_desc *header = NULL; + struct usb_cdc_ether_desc *ether = NULL; + struct usb_cdc_mdlm_detail_desc *detail = NULL; + struct usb_cdc_mdlm_desc *desc = NULL; + + unsigned int elength; + int cnt = 0; + + memset(hdr, 0x00, sizeof(struct usb_cdc_parsed_header)); + hdr->phonet_magic_present = false; + while (buflen > 0) { + elength = buffer[0]; + if (!elength) { + dev_err(&intf->dev, "skipping garbage byte\n"); + elength = 1; + goto next_desc; + } + if (buffer[1] != USB_DT_CS_INTERFACE) { + dev_err(&intf->dev, "skipping garbage\n"); + goto next_desc; + } + + switch (buffer[2]) { + case USB_CDC_UNION_TYPE: /* we've found it */ + if (elength < sizeof(struct usb_cdc_union_desc)) + goto next_desc; + if (union_header) { + dev_err(&intf->dev, "More than one union descriptor, skipping ...\n"); + goto next_desc; + } + union_header = (struct usb_cdc_union_desc *)buffer; + break; + case USB_CDC_COUNTRY_TYPE: + if (elength < sizeof(struct usb_cdc_country_functional_desc)) + goto next_desc; + hdr->usb_cdc_country_functional_desc = + (struct usb_cdc_country_functional_desc *)buffer; + break; + case USB_CDC_HEADER_TYPE: + if (elength != sizeof(struct usb_cdc_header_desc)) + goto next_desc; + if (header) + return -EINVAL; + header = (struct usb_cdc_header_desc *)buffer; + break; + case USB_CDC_ACM_TYPE: + if (elength < sizeof(struct usb_cdc_acm_descriptor)) + goto next_desc; + hdr->usb_cdc_acm_descriptor = + (struct usb_cdc_acm_descriptor *)buffer; + break; + case USB_CDC_ETHERNET_TYPE: + if (elength != sizeof(struct usb_cdc_ether_desc)) + goto next_desc; + if (ether) + return -EINVAL; + ether = (struct usb_cdc_ether_desc *)buffer; + break; + case USB_CDC_CALL_MANAGEMENT_TYPE: + if (elength < sizeof(struct usb_cdc_call_mgmt_descriptor)) + goto next_desc; + hdr->usb_cdc_call_mgmt_descriptor = + (struct usb_cdc_call_mgmt_descriptor *)buffer; + break; + case USB_CDC_DMM_TYPE: + if (elength < sizeof(struct usb_cdc_dmm_desc)) + goto next_desc; + hdr->usb_cdc_dmm_desc = + (struct usb_cdc_dmm_desc *)buffer; + break; + case USB_CDC_MDLM_TYPE: + if (elength < sizeof(struct usb_cdc_mdlm_desc *)) + goto next_desc; + if (desc) + return -EINVAL; + desc = (struct usb_cdc_mdlm_desc *)buffer; + break; + case USB_CDC_MDLM_DETAIL_TYPE: + if (elength < sizeof(struct usb_cdc_mdlm_detail_desc *)) + goto next_desc; + if (detail) + return -EINVAL; + detail = (struct usb_cdc_mdlm_detail_desc *)buffer; + break; + case USB_CDC_NCM_TYPE: + if (elength < sizeof(struct usb_cdc_ncm_desc)) + goto next_desc; + hdr->usb_cdc_ncm_desc = (struct usb_cdc_ncm_desc *)buffer; + break; + case USB_CDC_MBIM_TYPE: + if (elength < sizeof(struct usb_cdc_mbim_desc)) + goto next_desc; + + hdr->usb_cdc_mbim_desc = (struct usb_cdc_mbim_desc *)buffer; + break; + case USB_CDC_MBIM_EXTENDED_TYPE: + if (elength < sizeof(struct usb_cdc_mbim_extended_desc)) + break; + hdr->usb_cdc_mbim_extended_desc = + (struct usb_cdc_mbim_extended_desc *)buffer; + break; + case CDC_PHONET_MAGIC_NUMBER: + hdr->phonet_magic_present = true; + break; + default: + /* + * there are LOTS more CDC descriptors that + * could legitimately be found here. + */ + dev_dbg(&intf->dev, "Ignoring descriptor: type %02x, length %ud\n", + buffer[2], elength); + goto next_desc; + } + cnt++; +next_desc: + buflen -= elength; + buffer += elength; + } + hdr->usb_cdc_union_desc = union_header; + hdr->usb_cdc_header_desc = header; + hdr->usb_cdc_mdlm_detail_desc = detail; + hdr->usb_cdc_mdlm_desc = desc; + hdr->usb_cdc_ether_desc = ether; + return cnt; +} + +EXPORT_SYMBOL(cdc_parse_cdc_header); -- cgit v0.10.2 From eccf2a4e6b64d249929acc1f7aaa2ab0fb199d3d Mon Sep 17 00:00:00 2001 From: Oliver Neukum Date: Thu, 14 Jul 2016 15:41:31 +0200 Subject: cdc-acm: use the common parser This introduces the common parser for extra CDC headers now that it no longer depends on usbnet. Signed-off-by: Oliver Neukum Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index def5a54..561baed 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c @@ -1147,6 +1147,7 @@ static int acm_probe(struct usb_interface *intf, { struct usb_cdc_union_desc *union_header = NULL; struct usb_cdc_country_functional_desc *cfd = NULL; + struct usb_cdc_call_mgmt_descriptor *cmd = NULL; unsigned char *buffer = intf->altsetting->extra; int buflen = intf->altsetting->extralen; struct usb_interface *control_interface; @@ -1155,18 +1156,16 @@ static int acm_probe(struct usb_interface *intf, struct usb_endpoint_descriptor *epread = NULL; struct usb_endpoint_descriptor *epwrite = NULL; struct usb_device *usb_dev = interface_to_usbdev(intf); + struct usb_cdc_parsed_header hdr; struct acm *acm; int minor; int ctrlsize, readsize; u8 *buf; - u8 ac_management_function = 0; - u8 call_management_function = 0; int call_interface_num = -1; int data_interface_num = -1; unsigned long quirks; int num_rx_buf; int i; - unsigned int elength = 0; int combined_interfaces = 0; struct device *tty_dev; int rv = -ENOMEM; @@ -1210,61 +1209,11 @@ static int acm_probe(struct usb_interface *intf, } } - while (buflen > 0) { - elength = buffer[0]; - if (!elength) { - dev_err(&intf->dev, "skipping garbage byte\n"); - elength = 1; - goto next_desc; - } - if (buffer[1] != USB_DT_CS_INTERFACE) { - dev_err(&intf->dev, "skipping garbage\n"); - goto next_desc; - } - - switch (buffer[2]) { - case USB_CDC_UNION_TYPE: /* we've found it */ - if (elength < sizeof(struct usb_cdc_union_desc)) - goto next_desc; - if (union_header) { - dev_err(&intf->dev, "More than one " - "union descriptor, skipping ...\n"); - goto next_desc; - } - union_header = (struct usb_cdc_union_desc *)buffer; - break; - case USB_CDC_COUNTRY_TYPE: /* export through sysfs*/ - if (elength < sizeof(struct usb_cdc_country_functional_desc)) - goto next_desc; - cfd = (struct usb_cdc_country_functional_desc *)buffer; - break; - case USB_CDC_HEADER_TYPE: /* maybe check version */ - break; /* for now we ignore it */ - case USB_CDC_ACM_TYPE: - if (elength < 4) - goto next_desc; - ac_management_function = buffer[3]; - break; - case USB_CDC_CALL_MANAGEMENT_TYPE: - if (elength < 5) - goto next_desc; - call_management_function = buffer[3]; - call_interface_num = buffer[4]; - break; - default: - /* - * there are LOTS more CDC descriptors that - * could legitimately be found here. - */ - dev_dbg(&intf->dev, "Ignoring descriptor: " - "type %02x, length %ud\n", - buffer[2], elength); - break; - } -next_desc: - buflen -= elength; - buffer += elength; - } + cdc_parse_cdc_header(&hdr, intf, buffer, buflen); + union_header = hdr.usb_cdc_union_desc; + cmd = hdr.usb_cdc_call_mgmt_descriptor; + if (cmd) + call_interface_num = cmd->bDataInterface; if (!union_header) { if (call_interface_num > 0) { @@ -1394,7 +1343,8 @@ made_compressed_probe: acm->data = data_interface; acm->minor = minor; acm->dev = usb_dev; - acm->ctrl_caps = ac_management_function; + if (hdr.usb_cdc_acm_descriptor) + acm->ctrl_caps = hdr.usb_cdc_acm_descriptor->bmCapabilities; if (quirks & NO_CAP_LINE) acm->ctrl_caps &= ~USB_CDC_CAP_LINE; acm->ctrlsize = ctrlsize; @@ -1488,6 +1438,7 @@ made_compressed_probe: if (i < 0) goto alloc_fail7; + cfd = hdr.usb_cdc_country_functional_desc; if (cfd) { /* export the country data */ acm->country_codes = kmalloc(cfd->bLength - 4, GFP_KERNEL); if (!acm->country_codes) -- cgit v0.10.2 From 6dd3587f515ec4b1b8bcaaeb628ed1921eeed2ea Mon Sep 17 00:00:00 2001 From: Oliver Neukum Date: Thu, 14 Jul 2016 15:41:32 +0200 Subject: cdc-acm: cleanup error handling A small update to unify error handling during probe(). Signed-off-by: Oliver Neukum Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index 561baed..2e5dea8 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c @@ -1328,11 +1328,8 @@ made_compressed_probe: goto alloc_fail; minor = acm_alloc_minor(acm); - if (minor < 0) { - dev_err(&intf->dev, "no more free acm devices\n"); - kfree(acm); - return -ENODEV; - } + if (minor < 0) + goto alloc_fail1; ctrlsize = usb_endpoint_maxp(epctrl); readsize = usb_endpoint_maxp(epread) * @@ -1523,6 +1520,7 @@ alloc_fail4: usb_free_coherent(usb_dev, ctrlsize, acm->ctrl_buffer, acm->ctrl_dma); alloc_fail2: acm_release_minor(acm); +alloc_fail1: kfree(acm); alloc_fail: return rv; -- cgit v0.10.2 From 7fae7bfb9a58ae66a29a6017abb7f62d2eb971e2 Mon Sep 17 00:00:00 2001 From: Oliver Neukum Date: Thu, 14 Jul 2016 15:41:33 +0200 Subject: cdc-wdm: use the common CDC parser Now that the common parser resides in USB core, it can be used for CDC-WDM. Signed-off-by: Oliver Neukum Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/class/cdc-wdm.c b/drivers/usb/class/cdc-wdm.c index 61ea879..337948c 100644 --- a/drivers/usb/class/cdc-wdm.c +++ b/drivers/usb/class/cdc-wdm.c @@ -875,38 +875,18 @@ static int wdm_probe(struct usb_interface *intf, const struct usb_device_id *id) int rv = -EINVAL; struct usb_host_interface *iface; struct usb_endpoint_descriptor *ep; - struct usb_cdc_dmm_desc *dmhd; + struct usb_cdc_parsed_header hdr; u8 *buffer = intf->altsetting->extra; int buflen = intf->altsetting->extralen; u16 maxcom = WDM_DEFAULT_BUFSIZE; if (!buffer) goto err; - while (buflen > 2) { - if (buffer[1] != USB_DT_CS_INTERFACE) { - dev_err(&intf->dev, "skipping garbage\n"); - goto next_desc; - } - switch (buffer[2]) { - case USB_CDC_HEADER_TYPE: - break; - case USB_CDC_DMM_TYPE: - dmhd = (struct usb_cdc_dmm_desc *)buffer; - maxcom = le16_to_cpu(dmhd->wMaxCommand); - dev_dbg(&intf->dev, - "Finding maximum buffer length: %d", maxcom); - break; - default: - dev_err(&intf->dev, - "Ignoring extra header, type %d, length %d\n", - buffer[2], buffer[0]); - break; - } -next_desc: - buflen -= buffer[0]; - buffer += buffer[0]; - } + cdc_parse_cdc_header(&hdr, intf, buffer, buflen); + + if (hdr.usb_cdc_dmm_desc) + maxcom = le16_to_cpu(hdr.usb_cdc_dmm_desc->wMaxCommand); iface = intf->cur_altsetting; if (iface->desc.bNumEndpoints != 1) -- cgit v0.10.2 From cb42b63d893d8d22d1739ddea0d86b10fd921aac Mon Sep 17 00:00:00 2001 From: Oliver Neukum Date: Thu, 14 Jul 2016 15:41:34 +0200 Subject: cdc-acm: beautify probe() This removes some overly long lines by renaming variables and giving them local scope. Signed-off-by: Oliver Neukum Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index 2e5dea8..7191230 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c @@ -1146,8 +1146,7 @@ static int acm_probe(struct usb_interface *intf, const struct usb_device_id *id) { struct usb_cdc_union_desc *union_header = NULL; - struct usb_cdc_country_functional_desc *cfd = NULL; - struct usb_cdc_call_mgmt_descriptor *cmd = NULL; + struct usb_cdc_call_mgmt_descriptor *cmgmd = NULL; unsigned char *buffer = intf->altsetting->extra; int buflen = intf->altsetting->extralen; struct usb_interface *control_interface; @@ -1156,13 +1155,13 @@ static int acm_probe(struct usb_interface *intf, struct usb_endpoint_descriptor *epread = NULL; struct usb_endpoint_descriptor *epwrite = NULL; struct usb_device *usb_dev = interface_to_usbdev(intf); - struct usb_cdc_parsed_header hdr; + struct usb_cdc_parsed_header h; struct acm *acm; int minor; int ctrlsize, readsize; u8 *buf; - int call_interface_num = -1; - int data_interface_num = -1; + int call_intf_num = -1; + int data_intf_num = -1; unsigned long quirks; int num_rx_buf; int i; @@ -1209,20 +1208,22 @@ static int acm_probe(struct usb_interface *intf, } } - cdc_parse_cdc_header(&hdr, intf, buffer, buflen); - union_header = hdr.usb_cdc_union_desc; - cmd = hdr.usb_cdc_call_mgmt_descriptor; - if (cmd) - call_interface_num = cmd->bDataInterface; + cdc_parse_cdc_header(&h, intf, buffer, buflen); + union_header = h.usb_cdc_union_desc; + cmgmd = h.usb_cdc_call_mgmt_descriptor; + if (cmgmd) + call_intf_num = cmgmd->bDataInterface; if (!union_header) { - if (call_interface_num > 0) { + if (call_intf_num > 0) { dev_dbg(&intf->dev, "No union descriptor, using call management descriptor\n"); /* quirks for Droids MuIn LCD */ - if (quirks & NO_DATA_INTERFACE) + if (quirks & NO_DATA_INTERFACE) { data_interface = usb_ifnum_to_if(usb_dev, 0); - else - data_interface = usb_ifnum_to_if(usb_dev, (data_interface_num = call_interface_num)); + } else { + data_intf_num = call_intf_num; + data_interface = usb_ifnum_to_if(usb_dev, data_intf_num); + } control_interface = intf; } else { if (intf->cur_altsetting->desc.bNumEndpoints != 3) { @@ -1236,8 +1237,9 @@ static int acm_probe(struct usb_interface *intf, } } } else { + data_intf_num = union_header->bSlaveInterface0; control_interface = usb_ifnum_to_if(usb_dev, union_header->bMasterInterface0); - data_interface = usb_ifnum_to_if(usb_dev, (data_interface_num = union_header->bSlaveInterface0)); + data_interface = usb_ifnum_to_if(usb_dev, data_intf_num); } if (!control_interface || !data_interface) { @@ -1245,7 +1247,7 @@ static int acm_probe(struct usb_interface *intf, return -ENODEV; } - if (data_interface_num != call_interface_num) + if (data_intf_num != call_intf_num) dev_dbg(&intf->dev, "Separate call control interface. That is not fully supported.\n"); if (control_interface == data_interface) { @@ -1340,8 +1342,8 @@ made_compressed_probe: acm->data = data_interface; acm->minor = minor; acm->dev = usb_dev; - if (hdr.usb_cdc_acm_descriptor) - acm->ctrl_caps = hdr.usb_cdc_acm_descriptor->bmCapabilities; + if (h.usb_cdc_acm_descriptor) + acm->ctrl_caps = h.usb_cdc_acm_descriptor->bmCapabilities; if (quirks & NO_CAP_LINE) acm->ctrl_caps &= ~USB_CDC_CAP_LINE; acm->ctrlsize = ctrlsize; @@ -1435,8 +1437,10 @@ made_compressed_probe: if (i < 0) goto alloc_fail7; - cfd = hdr.usb_cdc_country_functional_desc; - if (cfd) { /* export the country data */ + if (h.usb_cdc_country_functional_desc) { /* export the country data */ + struct usb_cdc_country_functional_desc * cfd = + h.usb_cdc_country_functional_desc; + acm->country_codes = kmalloc(cfd->bLength - 4, GFP_KERNEL); if (!acm->country_codes) goto skip_countries; -- cgit v0.10.2 From a4a027a860ff58df8df0796d730397a3b30dbc9a Mon Sep 17 00:00:00 2001 From: Rodrigo Vivi Date: Tue, 26 Apr 2016 14:59:51 -0700 Subject: drm/i915/kbl: Introduce the first official DMC for Kabylake. Version 1.01. This firmware is made for Kabylake platform so it doesn't need the stepping workaround that we had before. v2: Rebased on top of latest nightly with min version required change. v3: With right CSR_VERSION (Patrik). Cc: Christophe Prigent Cc: Patrik Jakobsson Reviewed-by: Ben Widawsky (v1) Signed-off-by: Rodrigo Vivi Reviewed-by: Patrik Jakobsson Link: http://patchwork.freedesktop.org/patch/msgid/1461707991-15336-1-git-send-email-rodrigo.vivi@intel.com (cherry picked from commit 4922d4919596219864686be1e70dcd92c685ec9f) Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/intel_csr.c b/drivers/gpu/drm/i915/intel_csr.c index a34c23e..2b3b428 100644 --- a/drivers/gpu/drm/i915/intel_csr.c +++ b/drivers/gpu/drm/i915/intel_csr.c @@ -41,16 +41,22 @@ * be moved to FW_FAILED. */ +#define I915_CSR_KBL "i915/kbl_dmc_ver1.bin" +MODULE_FIRMWARE(I915_CSR_KBL); +#define KBL_CSR_VERSION_REQUIRED CSR_VERSION(1, 1) + #define I915_CSR_SKL "i915/skl_dmc_ver1.bin" +MODULE_FIRMWARE(I915_CSR_SKL); +#define SKL_CSR_VERSION_REQUIRED CSR_VERSION(1, 23) + #define I915_CSR_BXT "i915/bxt_dmc_ver1.bin" +MODULE_FIRMWARE(I915_CSR_BXT); +#define BXT_CSR_VERSION_REQUIRED CSR_VERSION(1, 7) #define FIRMWARE_URL "https://01.org/linuxgraphics/intel-linux-graphics-firmwares" -MODULE_FIRMWARE(I915_CSR_SKL); -MODULE_FIRMWARE(I915_CSR_BXT); -#define SKL_CSR_VERSION_REQUIRED CSR_VERSION(1, 23) -#define BXT_CSR_VERSION_REQUIRED CSR_VERSION(1, 7) + #define CSR_MAX_FW_SIZE 0x2FFF #define CSR_DEFAULT_FW_OFFSET 0xFFFFFFFF @@ -169,12 +175,10 @@ struct stepping_info { char substepping; }; -/* - * Kabylake derivated from Skylake H0, so SKL H0 - * is the right firmware for KBL A0 (revid 0). - */ static const struct stepping_info kbl_stepping_info[] = { - {'H', '0'}, {'I', '0'} + {'A', '0'}, {'B', '0'}, {'C', '0'}, + {'D', '0'}, {'E', '0'}, {'F', '0'}, + {'G', '0'}, {'H', '0'}, {'I', '0'}, }; static const struct stepping_info skl_stepping_info[] = { @@ -298,7 +302,9 @@ static uint32_t *parse_csr_fw(struct drm_i915_private *dev_priv, csr->version = css_header->version; - if (IS_SKYLAKE(dev_priv) || IS_KABYLAKE(dev_priv)) { + if (IS_KABYLAKE(dev_priv)) { + required_min_version = KBL_CSR_VERSION_REQUIRED; + } else if (IS_SKYLAKE(dev_priv)) { required_min_version = SKL_CSR_VERSION_REQUIRED; } else if (IS_BROXTON(dev_priv)) { required_min_version = BXT_CSR_VERSION_REQUIRED; @@ -446,7 +452,9 @@ void intel_csr_ucode_init(struct drm_i915_private *dev_priv) if (!HAS_CSR(dev_priv)) return; - if (IS_SKYLAKE(dev_priv) || IS_KABYLAKE(dev_priv)) + if (IS_KABYLAKE(dev_priv)) + csr->fw_path = I915_CSR_KBL; + else if (IS_SKYLAKE(dev_priv)) csr->fw_path = I915_CSR_SKL; else if (IS_BROXTON(dev_priv)) csr->fw_path = I915_CSR_BXT; -- cgit v0.10.2 From 14f0652b4fbebd0b05da36a06b17ac6d4d87a8f8 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Mon, 18 Jul 2016 17:40:49 -0300 Subject: perf tools: Add missing linux/compiler.h include to perf-sys.h It uses the likely/unlikely macros, so need to include . Cc: Adrian Hunter Cc: David Ahern Cc: Jiri Olsa Cc: Namhyung Kim Cc: Wang Nan Link: http://lkml.kernel.org/n/tip-p0xrhgbkicsii9ohmhhprqpi@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/perf-sys.h b/tools/perf/perf-sys.h index 5cee8a3..7ed72a4 100644 --- a/tools/perf/perf-sys.h +++ b/tools/perf/perf-sys.h @@ -5,6 +5,7 @@ #include #include #include +#include #include #include -- cgit v0.10.2 From 7e3f36411342a54f1981fa97b43550b8406a3d69 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Mon, 18 Jul 2016 17:42:16 -0300 Subject: perf tools: Remove tools/perf/util/include/asm/byteorder.h Not used anymore. This also stops include linux/swab.h directly from the kernel sources, remove that reference from the MANIFEST. Cc: Adrian Hunter Cc: David Ahern Cc: Jiri Olsa Cc: Namhyung Kim Cc: Wang Nan Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/MANIFEST b/tools/perf/MANIFEST index 923eda2..4790f19 100644 --- a/tools/perf/MANIFEST +++ b/tools/perf/MANIFEST @@ -84,10 +84,8 @@ include/asm-generic/bitops/__fls.h include/asm-generic/bitops/fls.h include/linux/list.h include/linux/hash.h -include/linux/swab.h arch/*/include/asm/unistd*.h arch/*/include/uapi/asm/unistd*.h tools/arch/*/include/uapi/asm/perf_regs.h include/linux/poison.h include/uapi/linux/const.h -include/uapi/linux/swab.h diff --git a/tools/perf/util/include/asm/byteorder.h b/tools/perf/util/include/asm/byteorder.h deleted file mode 100644 index 2a9bdc0..0000000 --- a/tools/perf/util/include/asm/byteorder.h +++ /dev/null @@ -1,2 +0,0 @@ -#include -#include "../../../../include/uapi/linux/swab.h" -- cgit v0.10.2 From e0643c4e9fdb2e77ab83ca596460e2c9c15728aa Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Mon, 18 Jul 2016 17:48:37 -0300 Subject: perf tools: Remove tools/perf/util/include/linux/const.h Not used anymore, remove one more file referencing kernel sources, i.e. outside of tools/ Cc: Adrian Hunter Cc: David Ahern Cc: Jiri Olsa Cc: Namhyung Kim Cc: Wang Nan Link: http://lkml.kernel.org/n/tip-ykfjt3t8l0npxfwmekiwwyu6@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/MANIFEST b/tools/perf/MANIFEST index 4790f19..d059b72 100644 --- a/tools/perf/MANIFEST +++ b/tools/perf/MANIFEST @@ -88,4 +88,3 @@ arch/*/include/asm/unistd*.h arch/*/include/uapi/asm/unistd*.h tools/arch/*/include/uapi/asm/perf_regs.h include/linux/poison.h -include/uapi/linux/const.h diff --git a/tools/perf/util/include/linux/const.h b/tools/perf/util/include/linux/const.h deleted file mode 100644 index c10a35e..0000000 --- a/tools/perf/util/include/linux/const.h +++ /dev/null @@ -1 +0,0 @@ -#include "../../../../include/uapi/linux/const.h" -- cgit v0.10.2 From ad430729ae00dd63f7dcadbeb638e589bc03b5a3 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Mon, 18 Jul 2016 18:00:50 -0300 Subject: Remove: kernel unistd*h files from perf's MANIFEST, not used No need to copy it to a detached tarball as they aren't used anymore Cc: Adrian Hunter Cc: David Ahern Cc: Jiri Olsa Cc: Namhyung Kim Cc: Wang Nan Link: http://lkml.kernel.org/n/tip-lopmaqi439ke10g1j9cxrxwt@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/MANIFEST b/tools/perf/MANIFEST index d059b72..e18df99 100644 --- a/tools/perf/MANIFEST +++ b/tools/perf/MANIFEST @@ -84,7 +84,5 @@ include/asm-generic/bitops/__fls.h include/asm-generic/bitops/fls.h include/linux/list.h include/linux/hash.h -arch/*/include/asm/unistd*.h -arch/*/include/uapi/asm/unistd*.h tools/arch/*/include/uapi/asm/perf_regs.h include/linux/poison.h -- cgit v0.10.2 From de1e17b1d0c81be472039798698b517c8a68b516 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Mon, 18 Jul 2016 18:13:22 -0300 Subject: tools: Copy the bitops files accessed from the kernel and check for drift copy some more kernel files accessed from tools/, check for drift. Cc: Adrian Hunter Cc: David Ahern Cc: Jiri Olsa Cc: Namhyung Kim Cc: Wang Nan Link: http://lkml.kernel.org/n/tip-omz8xdyvvxgjiuqzwj6ecm6j@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/include/asm-generic/bitops/__fls.h b/tools/include/asm-generic/bitops/__fls.h index 494c9c6..a60a7cc 100644 --- a/tools/include/asm-generic/bitops/__fls.h +++ b/tools/include/asm-generic/bitops/__fls.h @@ -1 +1,43 @@ -#include "../../../../include/asm-generic/bitops/__fls.h" +#ifndef _ASM_GENERIC_BITOPS___FLS_H_ +#define _ASM_GENERIC_BITOPS___FLS_H_ + +#include + +/** + * __fls - find last (most-significant) set bit in a long word + * @word: the word to search + * + * Undefined if no set bit exists, so code should check against 0 first. + */ +static __always_inline unsigned long __fls(unsigned long word) +{ + int num = BITS_PER_LONG - 1; + +#if BITS_PER_LONG == 64 + if (!(word & (~0ul << 32))) { + num -= 32; + word <<= 32; + } +#endif + if (!(word & (~0ul << (BITS_PER_LONG-16)))) { + num -= 16; + word <<= 16; + } + if (!(word & (~0ul << (BITS_PER_LONG-8)))) { + num -= 8; + word <<= 8; + } + if (!(word & (~0ul << (BITS_PER_LONG-4)))) { + num -= 4; + word <<= 4; + } + if (!(word & (~0ul << (BITS_PER_LONG-2)))) { + num -= 2; + word <<= 2; + } + if (!(word & (~0ul << (BITS_PER_LONG-1)))) + num -= 1; + return num; +} + +#endif /* _ASM_GENERIC_BITOPS___FLS_H_ */ diff --git a/tools/include/asm-generic/bitops/arch_hweight.h b/tools/include/asm-generic/bitops/arch_hweight.h index 318bb2b..6a211f4 100644 --- a/tools/include/asm-generic/bitops/arch_hweight.h +++ b/tools/include/asm-generic/bitops/arch_hweight.h @@ -1 +1,25 @@ -#include "../../../../include/asm-generic/bitops/arch_hweight.h" +#ifndef _ASM_GENERIC_BITOPS_ARCH_HWEIGHT_H_ +#define _ASM_GENERIC_BITOPS_ARCH_HWEIGHT_H_ + +#include + +static inline unsigned int __arch_hweight32(unsigned int w) +{ + return __sw_hweight32(w); +} + +static inline unsigned int __arch_hweight16(unsigned int w) +{ + return __sw_hweight16(w); +} + +static inline unsigned int __arch_hweight8(unsigned int w) +{ + return __sw_hweight8(w); +} + +static inline unsigned long __arch_hweight64(__u64 w) +{ + return __sw_hweight64(w); +} +#endif /* _ASM_GENERIC_BITOPS_HWEIGHT_H_ */ diff --git a/tools/include/asm-generic/bitops/const_hweight.h b/tools/include/asm-generic/bitops/const_hweight.h index 0afd644..0a7e066 100644 --- a/tools/include/asm-generic/bitops/const_hweight.h +++ b/tools/include/asm-generic/bitops/const_hweight.h @@ -1 +1,43 @@ -#include "../../../../include/asm-generic/bitops/const_hweight.h" +#ifndef _ASM_GENERIC_BITOPS_CONST_HWEIGHT_H_ +#define _ASM_GENERIC_BITOPS_CONST_HWEIGHT_H_ + +/* + * Compile time versions of __arch_hweightN() + */ +#define __const_hweight8(w) \ + ((unsigned int) \ + ((!!((w) & (1ULL << 0))) + \ + (!!((w) & (1ULL << 1))) + \ + (!!((w) & (1ULL << 2))) + \ + (!!((w) & (1ULL << 3))) + \ + (!!((w) & (1ULL << 4))) + \ + (!!((w) & (1ULL << 5))) + \ + (!!((w) & (1ULL << 6))) + \ + (!!((w) & (1ULL << 7))))) + +#define __const_hweight16(w) (__const_hweight8(w) + __const_hweight8((w) >> 8 )) +#define __const_hweight32(w) (__const_hweight16(w) + __const_hweight16((w) >> 16)) +#define __const_hweight64(w) (__const_hweight32(w) + __const_hweight32((w) >> 32)) + +/* + * Generic interface. + */ +#define hweight8(w) (__builtin_constant_p(w) ? __const_hweight8(w) : __arch_hweight8(w)) +#define hweight16(w) (__builtin_constant_p(w) ? __const_hweight16(w) : __arch_hweight16(w)) +#define hweight32(w) (__builtin_constant_p(w) ? __const_hweight32(w) : __arch_hweight32(w)) +#define hweight64(w) (__builtin_constant_p(w) ? __const_hweight64(w) : __arch_hweight64(w)) + +/* + * Interface for known constant arguments + */ +#define HWEIGHT8(w) (BUILD_BUG_ON_ZERO(!__builtin_constant_p(w)) + __const_hweight8(w)) +#define HWEIGHT16(w) (BUILD_BUG_ON_ZERO(!__builtin_constant_p(w)) + __const_hweight16(w)) +#define HWEIGHT32(w) (BUILD_BUG_ON_ZERO(!__builtin_constant_p(w)) + __const_hweight32(w)) +#define HWEIGHT64(w) (BUILD_BUG_ON_ZERO(!__builtin_constant_p(w)) + __const_hweight64(w)) + +/* + * Type invariant interface to the compile time constant hweight functions. + */ +#define HWEIGHT(w) HWEIGHT64((u64)w) + +#endif /* _ASM_GENERIC_BITOPS_CONST_HWEIGHT_H_ */ diff --git a/tools/include/asm-generic/bitops/fls.h b/tools/include/asm-generic/bitops/fls.h index 0e4995f..0576d1f 100644 --- a/tools/include/asm-generic/bitops/fls.h +++ b/tools/include/asm-generic/bitops/fls.h @@ -1 +1,41 @@ -#include "../../../../include/asm-generic/bitops/fls.h" +#ifndef _ASM_GENERIC_BITOPS_FLS_H_ +#define _ASM_GENERIC_BITOPS_FLS_H_ + +/** + * fls - find last (most-significant) bit set + * @x: the word to search + * + * This is defined the same way as ffs. + * Note fls(0) = 0, fls(1) = 1, fls(0x80000000) = 32. + */ + +static __always_inline int fls(int x) +{ + int r = 32; + + if (!x) + return 0; + if (!(x & 0xffff0000u)) { + x <<= 16; + r -= 16; + } + if (!(x & 0xff000000u)) { + x <<= 8; + r -= 8; + } + if (!(x & 0xf0000000u)) { + x <<= 4; + r -= 4; + } + if (!(x & 0xc0000000u)) { + x <<= 2; + r -= 2; + } + if (!(x & 0x80000000u)) { + x <<= 1; + r -= 1; + } + return r; +} + +#endif /* _ASM_GENERIC_BITOPS_FLS_H_ */ diff --git a/tools/include/asm-generic/bitops/fls64.h b/tools/include/asm-generic/bitops/fls64.h index 35bee00..b097cf8 100644 --- a/tools/include/asm-generic/bitops/fls64.h +++ b/tools/include/asm-generic/bitops/fls64.h @@ -1 +1,36 @@ -#include "../../../../include/asm-generic/bitops/fls64.h" +#ifndef _ASM_GENERIC_BITOPS_FLS64_H_ +#define _ASM_GENERIC_BITOPS_FLS64_H_ + +#include + +/** + * fls64 - find last set bit in a 64-bit word + * @x: the word to search + * + * This is defined in a similar way as the libc and compiler builtin + * ffsll, but returns the position of the most significant set bit. + * + * fls64(value) returns 0 if value is 0 or the position of the last + * set bit if value is nonzero. The last (most significant) bit is + * at position 64. + */ +#if BITS_PER_LONG == 32 +static __always_inline int fls64(__u64 x) +{ + __u32 h = x >> 32; + if (h) + return fls(h) + 32; + return fls(x); +} +#elif BITS_PER_LONG == 64 +static __always_inline int fls64(__u64 x) +{ + if (x == 0) + return 0; + return __fls(x) + 1; +} +#else +#error BITS_PER_LONG not 32 or 64 +#endif + +#endif /* _ASM_GENERIC_BITOPS_FLS64_H_ */ diff --git a/tools/perf/MANIFEST b/tools/perf/MANIFEST index e18df99..eeb2fdc 100644 --- a/tools/perf/MANIFEST +++ b/tools/perf/MANIFEST @@ -77,11 +77,6 @@ tools/include/linux/stringify.h tools/include/linux/types.h tools/include/linux/err.h tools/include/linux/bitmap.h -include/asm-generic/bitops/arch_hweight.h -include/asm-generic/bitops/const_hweight.h -include/asm-generic/bitops/fls64.h -include/asm-generic/bitops/__fls.h -include/asm-generic/bitops/fls.h include/linux/list.h include/linux/hash.h tools/arch/*/include/uapi/asm/perf_regs.h diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf index a129fbc..580f4e2 100644 --- a/tools/perf/Makefile.perf +++ b/tools/perf/Makefile.perf @@ -411,6 +411,21 @@ $(PERF_IN): prepare FORCE @(test -f ../../arch/arm64/include/uapi/asm/kvm.h && ( \ (diff -B ../arch/arm64/include/uapi/asm/kvm.h ../../arch/arm64/include/uapi/asm/kvm.h >/dev/null) \ || echo "Warning: tools/arch/arm64/include/uapi/asm/kvm.h differs from kernel" >&2 )) || true + @(test -f ../../include/asm-generic/bitops/arch_hweight.h && ( \ + (diff -B ../include/asm-generic/bitops/arch_hweight.h ../../include/asm-generic/bitops/arch_hweight.h >/dev/null) \ + || echo "Warning: tools/include/asm-generic/bitops/arch_hweight.h differs from kernel" >&2 )) || true + @(test -f ../../include/asm-generic/bitops/const_hweight.h && ( \ + (diff -B ../include/asm-generic/bitops/const_hweight.h ../../include/asm-generic/bitops/const_hweight.h >/dev/null) \ + || echo "Warning: tools/include/asm-generic/bitops/const_hweight.h differs from kernel" >&2 )) || true + @(test -f ../../include/asm-generic/bitops/__fls.h && ( \ + (diff -B ../include/asm-generic/bitops/__fls.h ../../include/asm-generic/bitops/__fls.h >/dev/null) \ + || echo "Warning: tools/include/asm-generic/bitops/__fls.h differs from kernel" >&2 )) || true + @(test -f ../../include/asm-generic/bitops/fls.h && ( \ + (diff -B ../include/asm-generic/bitops/fls.h ../../include/asm-generic/bitops/fls.h >/dev/null) \ + || echo "Warning: tools/include/asm-generic/bitops/fls.h differs from kernel" >&2 )) || true + @(test -f ../../include/asm-generic/bitops/fls64.h && ( \ + (diff -B ../include/asm-generic/bitops/fls64.h ../../include/asm-generic/bitops/fls64.h >/dev/null) \ + || echo "Warning: tools/include/asm-generic/bitops/fls64.h differs from kernel" >&2 )) || true $(Q)$(MAKE) $(build)=perf $(OUTPUT)perf: $(PERFLIBS) $(PERF_IN) $(LIBTRACEEVENT_DYNAMIC_LIST) -- cgit v0.10.2 From 3aa0042769313b720142c0ef8514dac389e14ebe Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Mon, 18 Jul 2016 18:35:11 -0300 Subject: perf tools: Remove include/linux/list.h from perf's MANIFEST It hasn't been used since we made tools/ self sufficiente wrt list.h. Cc: Adrian Hunter Cc: David Ahern Cc: Jiri Olsa Cc: Josh Poimboeuf Cc: Namhyung Kim Cc: Wang Nan Fixes: d1b39d41ebec ("tools: Make list.h self-sufficient") Link: http://lkml.kernel.org/n/tip-w20ueqlf22kh7ctjqo0zjpig@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/MANIFEST b/tools/perf/MANIFEST index eeb2fdc..3ac7f8d 100644 --- a/tools/perf/MANIFEST +++ b/tools/perf/MANIFEST @@ -77,7 +77,6 @@ tools/include/linux/stringify.h tools/include/linux/types.h tools/include/linux/err.h tools/include/linux/bitmap.h -include/linux/list.h include/linux/hash.h tools/arch/*/include/uapi/asm/perf_regs.h include/linux/poison.h -- cgit v0.10.2 From ae3c14a028ed10552803b68276b6833295ba18cf Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Mon, 18 Jul 2016 18:39:36 -0300 Subject: tools: Copy linux/{hash,poison}.h and check for drift We were also using this directly from the kernel sources, the two last cases, fix it. Cc: Adrian Hunter Cc: David Ahern Cc: Jiri Olsa Cc: Namhyung Kim Cc: Wang Nan Link: http://lkml.kernel.org/n/tip-7o14xvacqcjc5llc7gvjjyl8@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/include/linux/hash.h b/tools/include/linux/hash.h index d026c65..ad6fa21 100644 --- a/tools/include/linux/hash.h +++ b/tools/include/linux/hash.h @@ -1,5 +1,104 @@ -#include "../../../include/linux/hash.h" +#ifndef _LINUX_HASH_H +#define _LINUX_HASH_H +/* Fast hashing routine for ints, longs and pointers. + (C) 2002 Nadia Yvette Chambers, IBM */ -#ifndef _TOOLS_LINUX_HASH_H -#define _TOOLS_LINUX_HASH_H +#include +#include + +/* + * The "GOLDEN_RATIO_PRIME" is used in ifs/btrfs/brtfs_inode.h and + * fs/inode.c. It's not actually prime any more (the previous primes + * were actively bad for hashing), but the name remains. + */ +#if BITS_PER_LONG == 32 +#define GOLDEN_RATIO_PRIME GOLDEN_RATIO_32 +#define hash_long(val, bits) hash_32(val, bits) +#elif BITS_PER_LONG == 64 +#define hash_long(val, bits) hash_64(val, bits) +#define GOLDEN_RATIO_PRIME GOLDEN_RATIO_64 +#else +#error Wordsize not 32 or 64 +#endif + +/* + * This hash multiplies the input by a large odd number and takes the + * high bits. Since multiplication propagates changes to the most + * significant end only, it is essential that the high bits of the + * product be used for the hash value. + * + * Chuck Lever verified the effectiveness of this technique: + * http://www.citi.umich.edu/techreports/reports/citi-tr-00-1.pdf + * + * Although a random odd number will do, it turns out that the golden + * ratio phi = (sqrt(5)-1)/2, or its negative, has particularly nice + * properties. (See Knuth vol 3, section 6.4, exercise 9.) + * + * These are the negative, (1 - phi) = phi**2 = (3 - sqrt(5))/2, + * which is very slightly easier to multiply by and makes no + * difference to the hash distribution. + */ +#define GOLDEN_RATIO_32 0x61C88647 +#define GOLDEN_RATIO_64 0x61C8864680B583EBull + +#ifdef CONFIG_HAVE_ARCH_HASH +/* This header may use the GOLDEN_RATIO_xx constants */ +#include +#endif + +/* + * The _generic versions exist only so lib/test_hash.c can compare + * the arch-optimized versions with the generic. + * + * Note that if you change these, any that aren't updated + * to match need to have their HAVE_ARCH_* define values updated so the + * self-test will not false-positive. + */ +#ifndef HAVE_ARCH__HASH_32 +#define __hash_32 __hash_32_generic +#endif +static inline u32 __hash_32_generic(u32 val) +{ + return val * GOLDEN_RATIO_32; +} + +#ifndef HAVE_ARCH_HASH_32 +#define hash_32 hash_32_generic #endif +static inline u32 hash_32_generic(u32 val, unsigned int bits) +{ + /* High bits are more random, so use them. */ + return __hash_32(val) >> (32 - bits); +} + +#ifndef HAVE_ARCH_HASH_64 +#define hash_64 hash_64_generic +#endif +static __always_inline u32 hash_64_generic(u64 val, unsigned int bits) +{ +#if BITS_PER_LONG == 64 + /* 64x64-bit multiply is efficient on all 64-bit processors */ + return val * GOLDEN_RATIO_64 >> (64 - bits); +#else + /* Hash 64 bits using only 32x32-bit multiply. */ + return hash_32((u32)val ^ __hash_32(val >> 32), bits); +#endif +} + +static inline u32 hash_ptr(const void *ptr, unsigned int bits) +{ + return hash_long((unsigned long)ptr, bits); +} + +/* This really should be called fold32_ptr; it does no hashing to speak of. */ +static inline u32 hash32_ptr(const void *ptr) +{ + unsigned long val = (unsigned long)ptr; + +#if BITS_PER_LONG == 64 + val ^= (val >> 32); +#endif + return (u32)val; +} + +#endif /* _LINUX_HASH_H */ diff --git a/tools/include/linux/poison.h b/tools/include/linux/poison.h index 0c27bdf..51334ed 100644 --- a/tools/include/linux/poison.h +++ b/tools/include/linux/poison.h @@ -1 +1,90 @@ -#include "../../../include/linux/poison.h" +#ifndef _LINUX_POISON_H +#define _LINUX_POISON_H + +/********** include/linux/list.h **********/ + +/* + * Architectures might want to move the poison pointer offset + * into some well-recognized area such as 0xdead000000000000, + * that is also not mappable by user-space exploits: + */ +#ifdef CONFIG_ILLEGAL_POINTER_VALUE +# define POISON_POINTER_DELTA _AC(CONFIG_ILLEGAL_POINTER_VALUE, UL) +#else +# define POISON_POINTER_DELTA 0 +#endif + +/* + * These are non-NULL pointers that will result in page faults + * under normal circumstances, used to verify that nobody uses + * non-initialized list entries. + */ +#define LIST_POISON1 ((void *) 0x100 + POISON_POINTER_DELTA) +#define LIST_POISON2 ((void *) 0x200 + POISON_POINTER_DELTA) + +/********** include/linux/timer.h **********/ +/* + * Magic number "tsta" to indicate a static timer initializer + * for the object debugging code. + */ +#define TIMER_ENTRY_STATIC ((void *) 0x300 + POISON_POINTER_DELTA) + +/********** mm/debug-pagealloc.c **********/ +#ifdef CONFIG_PAGE_POISONING_ZERO +#define PAGE_POISON 0x00 +#else +#define PAGE_POISON 0xaa +#endif + +/********** mm/page_alloc.c ************/ + +#define TAIL_MAPPING ((void *) 0x400 + POISON_POINTER_DELTA) + +/********** mm/slab.c **********/ +/* + * Magic nums for obj red zoning. + * Placed in the first word before and the first word after an obj. + */ +#define RED_INACTIVE 0x09F911029D74E35BULL /* when obj is inactive */ +#define RED_ACTIVE 0xD84156C5635688C0ULL /* when obj is active */ + +#define SLUB_RED_INACTIVE 0xbb +#define SLUB_RED_ACTIVE 0xcc + +/* ...and for poisoning */ +#define POISON_INUSE 0x5a /* for use-uninitialised poisoning */ +#define POISON_FREE 0x6b /* for use-after-free poisoning */ +#define POISON_END 0xa5 /* end-byte of poisoning */ + +/********** arch/$ARCH/mm/init.c **********/ +#define POISON_FREE_INITMEM 0xcc + +/********** arch/ia64/hp/common/sba_iommu.c **********/ +/* + * arch/ia64/hp/common/sba_iommu.c uses a 16-byte poison string with a + * value of "SBAIOMMU POISON\0" for spill-over poisoning. + */ + +/********** fs/jbd/journal.c **********/ +#define JBD_POISON_FREE 0x5b +#define JBD2_POISON_FREE 0x5c + +/********** drivers/base/dmapool.c **********/ +#define POOL_POISON_FREED 0xa7 /* !inuse */ +#define POOL_POISON_ALLOCATED 0xa9 /* !initted */ + +/********** drivers/atm/ **********/ +#define ATM_POISON_FREE 0x12 +#define ATM_POISON 0xdeadbeef + +/********** kernel/mutexes **********/ +#define MUTEX_DEBUG_INIT 0x11 +#define MUTEX_DEBUG_FREE 0x22 + +/********** lib/flex_array.c **********/ +#define FLEX_ARRAY_FREE 0x6c /* for use-after-free poisoning */ + +/********** security/ **********/ +#define KEY_DESTROY 0xbd + +#endif diff --git a/tools/perf/MANIFEST b/tools/perf/MANIFEST index 3ac7f8d..ad2534d 100644 --- a/tools/perf/MANIFEST +++ b/tools/perf/MANIFEST @@ -77,6 +77,4 @@ tools/include/linux/stringify.h tools/include/linux/types.h tools/include/linux/err.h tools/include/linux/bitmap.h -include/linux/hash.h tools/arch/*/include/uapi/asm/perf_regs.h -include/linux/poison.h diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf index 580f4e2..6641abb 100644 --- a/tools/perf/Makefile.perf +++ b/tools/perf/Makefile.perf @@ -351,6 +351,9 @@ $(PERF_IN): prepare FORCE @(test -f ../../include/uapi/linux/perf_event.h && ( \ (diff -B ../include/uapi/linux/perf_event.h ../../include/uapi/linux/perf_event.h >/dev/null) \ || echo "Warning: tools/include/uapi/linux/perf_event.h differs from kernel" >&2 )) || true + @(test -f ../../include/linux/hash.h && ( \ + (diff -B ../include/linux/hash.h ../../include/linux/hash.h >/dev/null) \ + || echo "Warning: tools/include/linux/hash.h differs from kernel" >&2 )) || true @(test -f ../../include/uapi/linux/hw_breakpoint.h && ( \ (diff -B ../include/uapi/linux/hw_breakpoint.h ../../include/uapi/linux/hw_breakpoint.h >/dev/null) \ || echo "Warning: tools/include/uapi/linux/hw_breakpoint.h differs from kernel" >&2 )) || true -- cgit v0.10.2 From 1488a1e3828d60d74c9b802a05e24c0487babe4e Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 18 Jul 2016 18:40:00 -0400 Subject: libata: LITE-ON CX1-JB256-HP needs lower max_sectors Since 34b48db66e08 ("block: remove artifical max_hw_sectors cap"), max_sectors is no longer limited to BLK_DEF_MAX_SECTORS and LITE-ON CX1-JB256-HP keeps timing out with higher max_sectors. Revert it to the previous value. Signed-off-by: Tejun Heo Reported-by: dgerasimov@gmail.com Link: https://bugzilla.kernel.org/show_bug.cgi?id=121671 Cc: stable@vger.kernel.org # v3.19+ Fixes: 34b48db66e08 ("block: remove artifical max_hw_sectors cap") Signed-off-by: Tejun Heo diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 6be7770..31c183a 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -4314,6 +4314,12 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = { */ { "ST380013AS", "3.20", ATA_HORKAGE_MAX_SEC_1024 }, + /* + * Device times out with higher max sects. + * https://bugzilla.kernel.org/show_bug.cgi?id=121671 + */ + { "LITEON CX1-JB256-HP", NULL, ATA_HORKAGE_MAX_SEC_1024 }, + /* Devices we expect to fail diagnostics */ /* Devices where NCQ should be avoided */ -- cgit v0.10.2 From 00e727bb389359c81101b03d34fec8cc7be5168d Mon Sep 17 00:00:00 2001 From: Mark Rutland Date: Fri, 15 Jul 2016 11:08:10 +0100 Subject: perf stat: Balance opening and reading events In create_perf_stat_counter, when a target CPU has not been provided, we call __perf_evsel__open with empty_cpu_map, and open a single FD per thread. However, in read_counter we assume that we opened events for the product of threads and CPUs described in the evsel's cpu_map. Thus, if an evsel has a cpu_map with more than one entry, we will attempt to access FDs that we didn't open. This could result in a number of problems (e.g. blocking while reading from STDIN if the fd memory happened to be initialised to zero). This is problematic for systems were a logical CPU PMU covers some arbitrary subset of CPUs. The cpu_map of any evsel for that PMU will be initialised based on the cpumask exposed through sysfs, even if the user requests per-thread events. Signed-off-by: Mark Rutland Acked-by: Jiri Olsa Cc: Adrian Hunter Cc: Alexander Shishkin Cc: He Kuang Cc: Kan Liang Cc: Mark Rutland Cc: Peter Zijlstra Cc: Wang Nan Link: http://lkml.kernel.org/r/1468577293-19667-2-git-send-email-mark.rutland@arm.com Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index 8c5a3bf..0c16d20 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c @@ -290,8 +290,12 @@ perf_evsel__write_stat_event(struct perf_evsel *counter, u32 cpu, u32 thread, static int read_counter(struct perf_evsel *counter) { int nthreads = thread_map__nr(evsel_list->threads); - int ncpus = perf_evsel__nr_cpus(counter); - int cpu, thread; + int ncpus, cpu, thread; + + if (target__has_cpu(&target)) + ncpus = perf_evsel__nr_cpus(counter); + else + ncpus = 1; if (!counter->supported) return -ENOENT; -- cgit v0.10.2 From 9a6c582d57a0fc37fa4e13a69d9129fb3d98a401 Mon Sep 17 00:00:00 2001 From: Mark Rutland Date: Fri, 15 Jul 2016 11:08:11 +0100 Subject: perf cpu_map: Add more helpers In some cases it's necessry to figure out the map-local index of a given Linux logical CPU ID. Add a new helper, cpu_map__idx, to acquire this. As the logic is largely the same as the existing cpu_map__has, this is rewritten in terms of the new helper. At the same time, add the inverse operation, cpu_map__cpu, which yields the logical CPU id for a map-local index. While this can be performed manually, wrapping this in a helper can make code more legible. Signed-off-by: Mark Rutland Acked-by: Jiri Olsa Cc: Adrian Hunter Cc: Alexander Shishkin Cc: He Kuang Cc: Kan Liang Cc: Mark Rutland Cc: Peter Zijlstra Cc: Wang Nan Link: http://lkml.kernel.org/r/1468577293-19667-3-git-send-email-mark.rutland@arm.com Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/util/cpumap.c b/tools/perf/util/cpumap.c index 15f83ac..2c0b522 100644 --- a/tools/perf/util/cpumap.c +++ b/tools/perf/util/cpumap.c @@ -589,14 +589,24 @@ int cpu__setup_cpunode_map(void) bool cpu_map__has(struct cpu_map *cpus, int cpu) { + return cpu_map__idx(cpus, cpu) != -1; +} + +int cpu_map__idx(struct cpu_map *cpus, int cpu) +{ int i; for (i = 0; i < cpus->nr; ++i) { if (cpus->map[i] == cpu) - return true; + return i; } - return false; + return -1; +} + +int cpu_map__cpu(struct cpu_map *cpus, int idx) +{ + return cpus->map[idx]; } size_t cpu_map__snprint(struct cpu_map *map, char *buf, size_t size) diff --git a/tools/perf/util/cpumap.h b/tools/perf/util/cpumap.h index 206dc55..06bd689 100644 --- a/tools/perf/util/cpumap.h +++ b/tools/perf/util/cpumap.h @@ -68,5 +68,7 @@ int cpu_map__build_map(struct cpu_map *cpus, struct cpu_map **res, int (*f)(struct cpu_map *map, int cpu, void *data), void *data); +int cpu_map__cpu(struct cpu_map *cpus, int idx); bool cpu_map__has(struct cpu_map *cpus, int cpu); +int cpu_map__idx(struct cpu_map *cpus, int cpu); #endif /* __PERF_CPUMAP_H */ -- cgit v0.10.2 From e70493429bb1acaad829caae01c61dd7056fe671 Mon Sep 17 00:00:00 2001 From: Masami Hiramatsu Date: Tue, 19 Jul 2016 01:12:41 +0900 Subject: perf probe: Warn unmatched function filter correctly Warn unmatched function filter correctly instead of warning "symbol-loading error", since that can be a filter issue. From the technical point of view, this adds a filter chech in map__load and if there is a filter, it returns -2 (filter-out), instead of -1 (error), and perf-probe checks it and change message. E.g. without this fix: # perf probe -F rt_sp* no symbols found in [kernel.kallsyms], maybe install a debug package? Failed to load symbols in kernel With this fix: # perf probe -F rt_sp* no symbols passed the given filter. Failed to find symbols matched to "rt_sp*" Error: Failed to show functions. Reported-and-Tested-by: Arnaldo Carvalho de Melo Signed-off-by: Masami Hiramatsu Cc: Namhyung Kim Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/146885835596.16106.2293540792775552481.stgit@devbox Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c index b39b12a..728129a 100644 --- a/tools/perf/util/map.c +++ b/tools/perf/util/map.c @@ -312,6 +312,9 @@ int map__load(struct map *map, symbol_filter_t filter) pr_warning("%.*s was updated (is prelink enabled?). " "Restart the long running apps that use it!\n", (int)real_len, name); + } else if (filter) { + pr_warning("no symbols passed the given filter.\n"); + return -2; /* Empty but maybe by the filter */ } else { pr_warning("no symbols found in %s, maybe install " "a debug package?\n", name); diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c index d4f8835..953dc1a 100644 --- a/tools/perf/util/probe-event.c +++ b/tools/perf/util/probe-event.c @@ -3312,8 +3312,16 @@ int show_available_funcs(const char *target, struct strfilter *_filter, /* Load symbols with given filter */ available_func_filter = _filter; - if (map__load(map, filter_available_functions)) { - pr_err("Failed to load symbols in %s\n", (target) ? : "kernel"); + ret = map__load(map, filter_available_functions); + if (ret) { + if (ret == -2) { + char *str = strfilter__string(_filter); + pr_err("Failed to find symbols matched to \"%s\"\n", + str); + free(str); + } else + pr_err("Failed to load symbols in %s\n", + (target) ? : "kernel"); goto end; } if (!dso__sorted_by_name(map->dso, map->type)) -- cgit v0.10.2 From 249de6e074580988d3ee4902236803098e2cda4c Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Sat, 16 Jul 2016 18:11:18 +0200 Subject: perf script python: Fix string vs byte array resolving Jirka reported that python code returns all arrays as strings. This makes impossible to get all items for byte array tracepoint field containing 0x00 value item. Fixing this by scanning full length of the array and returning it as PyByteArray object in case non printable byte is found. Signed-off-by: Jiri Olsa Reported-and-Tested-by: Jiri Pirko Cc: David Ahern Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Steven Rostedt Link: http://lkml.kernel.org/r/1468685480-18951-2-git-send-email-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c index 6ac6b7a..7bd6da8 100644 --- a/tools/perf/util/scripting-engines/trace-event-python.c +++ b/tools/perf/util/scripting-engines/trace-event-python.c @@ -386,6 +386,21 @@ exit: return pylist; } +static int is_printable_array(char *p, unsigned int len) +{ + unsigned int i; + + if (!p || !len || p[len - 1] != 0) + return 0; + + len--; + + for (i = 0; i < len; i++) { + if (!isprint(p[i]) && !isspace(p[i])) + return 0; + } + return 1; +} static void python_process_tracepoint(struct perf_sample *sample, struct perf_evsel *evsel, @@ -457,14 +472,26 @@ static void python_process_tracepoint(struct perf_sample *sample, pydict_set_item_string_decref(dict, "common_callchain", callchain); } for (field = event->format.fields; field; field = field->next) { - if (field->flags & FIELD_IS_STRING) { - int offset; + unsigned int offset, len; + unsigned long long val; + + if (field->flags & FIELD_IS_ARRAY) { + offset = field->offset; + len = field->size; if (field->flags & FIELD_IS_DYNAMIC) { - offset = *(int *)(data + field->offset); + val = pevent_read_number(scripting_context->pevent, + data + offset, len); + offset = val; + len = offset >> 16; offset &= 0xffff; - } else - offset = field->offset; - obj = PyString_FromString((char *)data + offset); + } + if (field->flags & FIELD_IS_STRING && + is_printable_array(data + offset, len)) { + obj = PyString_FromString((char *) data + offset); + } else { + obj = PyByteArray_FromStringAndSize((const char *) data + offset, len); + field->flags &= ~FIELD_IS_STRING; + } } else { /* FIELD_IS_NUMERIC */ obj = get_field_numeric_entry(event, field, data); } -- cgit v0.10.2 From accaed2659530b4047678070cb23fd1d9a1c1a59 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Sat, 16 Jul 2016 18:11:19 +0200 Subject: perf tools: Make is_printable_array global It's used from 2 objects in perf, so it's better to keep just one copy. Signed-off-by: Jiri Olsa Cc: David Ahern Cc: Jiri Pirko Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Steven Rostedt Link: http://lkml.kernel.org/r/1468685480-18951-3-git-send-email-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/util/python.c b/tools/perf/util/python.c index d32f970..a5fbc01 100644 --- a/tools/perf/util/python.c +++ b/tools/perf/util/python.c @@ -295,18 +295,6 @@ static bool is_tracepoint(struct pyrf_event *pevent) return pevent->evsel->attr.type == PERF_TYPE_TRACEPOINT; } -static int is_printable_array(char *p, unsigned int len) -{ - unsigned int i; - - for (i = 0; i < len; i++) { - if (!isprint(p[i]) && !isspace(p[i])) - return 0; - } - - return 1; -} - static PyObject* tracepoint_field(struct pyrf_event *pe, struct format_field *field) { diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c index 7bd6da8..e0203b9 100644 --- a/tools/perf/util/scripting-engines/trace-event-python.c +++ b/tools/perf/util/scripting-engines/trace-event-python.c @@ -386,22 +386,6 @@ exit: return pylist; } -static int is_printable_array(char *p, unsigned int len) -{ - unsigned int i; - - if (!p || !len || p[len - 1] != 0) - return 0; - - len--; - - for (i = 0; i < len; i++) { - if (!isprint(p[i]) && !isspace(p[i])) - return 0; - } - return 1; -} - static void python_process_tracepoint(struct perf_sample *sample, struct perf_evsel *evsel, struct addr_location *al) diff --git a/tools/perf/util/util.c b/tools/perf/util/util.c index 5f44a21..cee559d 100644 --- a/tools/perf/util/util.c +++ b/tools/perf/util/util.c @@ -746,3 +746,19 @@ void print_binary(unsigned char *data, size_t len, } printer(BINARY_PRINT_DATA_END, -1, extra); } + +int is_printable_array(char *p, unsigned int len) +{ + unsigned int i; + + if (!p || !len || p[len - 1] != 0) + return 0; + + len--; + + for (i = 0; i < len; i++) { + if (!isprint(p[i]) && !isspace(p[i])) + return 0; + } + return 1; +} diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h index 843cbba..e5f5547 100644 --- a/tools/perf/util/util.h +++ b/tools/perf/util/util.h @@ -364,4 +364,5 @@ void print_binary(unsigned char *data, size_t len, extern int sched_getcpu(void); #endif +int is_printable_array(char *p, unsigned int len); #endif /* GIT_COMPAT_UTIL_H */ -- cgit v0.10.2 From 988dd774dcbd9151c2a643fc7284c5c3c4d0adb7 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Sat, 16 Jul 2016 18:11:20 +0200 Subject: perf tests: Add is_printable_array test Add automated test for is_printable_array function. Signed-off-by: Jiri Olsa Cc: David Ahern Cc: Jiri Pirko Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Steven Rostedt Link: http://lkml.kernel.org/r/1468685480-18951-4-git-send-email-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/tests/Build b/tools/perf/tests/Build index 4158422..cb20ae1 100644 --- a/tools/perf/tests/Build +++ b/tools/perf/tests/Build @@ -40,6 +40,7 @@ perf-y += event_update.o perf-y += event-times.o perf-y += backward-ring-buffer.o perf-y += sdt.o +perf-y += is_printable_array.o $(OUTPUT)tests/llvm-src-base.c: tests/bpf-script-example.c tests/Build $(call rule_mkdir) diff --git a/tools/perf/tests/builtin-test.c b/tools/perf/tests/builtin-test.c index 4dd2d05..10eb306 100644 --- a/tools/perf/tests/builtin-test.c +++ b/tools/perf/tests/builtin-test.c @@ -222,6 +222,10 @@ static struct test generic_tests[] = { .func = test__sdt_event, }, { + .desc = "Test is_printable_array function", + .func = test__is_printable_array, + }, + { .func = NULL, }, }; diff --git a/tools/perf/tests/is_printable_array.c b/tools/perf/tests/is_printable_array.c new file mode 100644 index 0000000..42e1339 --- /dev/null +++ b/tools/perf/tests/is_printable_array.c @@ -0,0 +1,36 @@ +#include +#include "tests.h" +#include "debug.h" +#include "util.h" + +int test__is_printable_array(int subtest __maybe_unused) +{ + char buf1[] = { 'k', 'r', 4, 'v', 'a', 0 }; + char buf2[] = { 'k', 'r', 'a', 'v', 4, 0 }; + struct { + char *buf; + unsigned int len; + int ret; + } t[] = { + { (char *) "krava", sizeof("krava"), 1 }, + { (char *) "krava", sizeof("krava") - 1, 0 }, + { (char *) "", sizeof(""), 1 }, + { (char *) "", 0, 0 }, + { NULL, 0, 0 }, + { buf1, sizeof(buf1), 0 }, + { buf2, sizeof(buf2), 0 }, + }; + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(t); i++) { + int ret; + + ret = is_printable_array((char *) t[i].buf, t[i].len); + if (ret != t[i].ret) { + pr_err("failed: test %u\n", i); + return TEST_FAIL; + } + } + + return TEST_OK; +} diff --git a/tools/perf/tests/tests.h b/tools/perf/tests/tests.h index a0288f8..9bfc0e0 100644 --- a/tools/perf/tests/tests.h +++ b/tools/perf/tests/tests.h @@ -89,6 +89,7 @@ int test__event_times(int subtest); int test__backward_ring_buffer(int subtest); int test__cpu_map_print(int subtest); int test__sdt_event(int subtest); +int test__is_printable_array(int subtest); #if defined(__arm__) || defined(__aarch64__) #ifdef HAVE_DWARF_UNWIND_SUPPORT -- cgit v0.10.2 From f96423f483b1a7854270335b319e8d1cdd6f3585 Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Mon, 18 Jul 2016 09:49:12 +0200 Subject: clk: at91: fix clk_programmable_set_parent() Since commit 1bdf02326b71e ("clk: at91: make use of syscon/regmap internally"), clk_programmable_set_parent() is always selecting the first parent (AKA slow_clk), no matter what's passed in the 'index' parameter. Fix that by initializing the pckr variable to the index value. Signed-off-by: Boris Brezillon Reported-by: Hans Verkuil Fixes: 1bdf02326b71e ("clk: at91: make use of syscon/regmap internally") Cc: Signed-off-by: Michael Turquette Link: lkml.kernel.org/r/1468828152-18389-1-git-send-email-boris.brezillon@free-electrons.com diff --git a/drivers/clk/at91/clk-programmable.c b/drivers/clk/at91/clk-programmable.c index 10f846c..25d5906 100644 --- a/drivers/clk/at91/clk-programmable.c +++ b/drivers/clk/at91/clk-programmable.c @@ -99,7 +99,7 @@ static int clk_programmable_set_parent(struct clk_hw *hw, u8 index) struct clk_programmable *prog = to_clk_programmable(hw); const struct clk_programmable_layout *layout = prog->layout; unsigned int mask = layout->css_mask; - unsigned int pckr = 0; + unsigned int pckr = index; if (layout->have_slck_mck) mask |= AT91_PMC_CSSMCK_MCK; -- cgit v0.10.2 From 0564bf0afae443deeb16f36e2c39fefff89d05f2 Mon Sep 17 00:00:00 2001 From: Konstantin Khlebnikov Date: Sat, 16 Jul 2016 17:08:56 +0300 Subject: net/sched/sch_htb: clamp xstats tokens to fit into 32-bit int In kernel HTB keeps tokens in signed 64-bit in nanoseconds. In netlink protocol these values are converted into pshed ticks (64ns for now) and truncated to 32-bit. In struct tc_htb_xstats fields "tokens" and "ctokens" are declared as unsigned 32-bit but they could be negative thus tool 'tc' prints them as signed. Big values loose higher bits and/or become negative. This patch clamps tokens in xstat into range from INT_MIN to INT_MAX. In this way it's easier to understand what's going on here. Signed-off-by: Konstantin Khlebnikov Signed-off-by: David S. Miller diff --git a/net/sched/sch_htb.c b/net/sched/sch_htb.c index 62f9d81..052f84d 100644 --- a/net/sched/sch_htb.c +++ b/net/sched/sch_htb.c @@ -1140,8 +1140,10 @@ htb_dump_class_stats(struct Qdisc *sch, unsigned long arg, struct gnet_dump *d) if (!cl->level && cl->un.leaf.q) qlen = cl->un.leaf.q->q.qlen; - cl->xstats.tokens = PSCHED_NS2TICKS(cl->tokens); - cl->xstats.ctokens = PSCHED_NS2TICKS(cl->ctokens); + cl->xstats.tokens = clamp_t(s64, PSCHED_NS2TICKS(cl->tokens), + INT_MIN, INT_MAX); + cl->xstats.ctokens = clamp_t(s64, PSCHED_NS2TICKS(cl->ctokens), + INT_MIN, INT_MAX); if (gnet_stats_copy_basic(d, NULL, &cl->bstats) < 0 || gnet_stats_copy_rate_est(d, NULL, &cl->rate_est) < 0 || -- cgit v0.10.2 From c74bfbdba0e8d056e4ba579a666b5cdb8ec3cd35 Mon Sep 17 00:00:00 2001 From: Willem de Bruijn Date: Sat, 16 Jul 2016 17:33:15 -0400 Subject: sctp: load transport header after sk_filter Do not cache pointers into the skb linear segment across sk_filter. The function call can trigger pskb_expand_head. Signed-off-by: Willem de Bruijn Acked-by: Daniel Borkmann Acked-by: Marcelo Ricardo Leitner Signed-off-by: David S. Miller diff --git a/net/sctp/input.c b/net/sctp/input.c index a701527..47cf460 100644 --- a/net/sctp/input.c +++ b/net/sctp/input.c @@ -112,7 +112,6 @@ int sctp_rcv(struct sk_buff *skb) struct sctp_ep_common *rcvr; struct sctp_transport *transport = NULL; struct sctp_chunk *chunk; - struct sctphdr *sh; union sctp_addr src; union sctp_addr dest; int family; @@ -127,8 +126,6 @@ int sctp_rcv(struct sk_buff *skb) if (skb_linearize(skb)) goto discard_it; - sh = sctp_hdr(skb); - /* Pull up the IP and SCTP headers. */ __skb_pull(skb, skb_transport_offset(skb)); if (skb->len < sizeof(struct sctphdr)) @@ -230,7 +227,7 @@ int sctp_rcv(struct sk_buff *skb) chunk->rcvr = rcvr; /* Remember the SCTP header. */ - chunk->sctp_hdr = sh; + chunk->sctp_hdr = sctp_hdr(skb); /* Set the source and destination addresses of the incoming chunk. */ sctp_init_addrs(chunk, &src, &dest); -- cgit v0.10.2 From 6bd80f372371a7b3f5ff13e4e8a560066299c001 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Mon, 6 Jun 2016 09:43:00 +0200 Subject: m68k/defconfig: Update defconfigs for v4.7-rc2 Signed-off-by: Geert Uytterhoeven diff --git a/arch/m68k/configs/amiga_defconfig b/arch/m68k/configs/amiga_defconfig index 3ee6976..8f5b6f7 100644 --- a/arch/m68k/configs/amiga_defconfig +++ b/arch/m68k/configs/amiga_defconfig @@ -9,6 +9,7 @@ CONFIG_LOG_BUF_SHIFT=16 # CONFIG_PID_NS is not set # CONFIG_NET_NS is not set CONFIG_BLK_DEV_INITRD=y +CONFIG_CC_OPTIMIZE_FOR_SIZE=y CONFIG_USERFAULTFD=y CONFIG_SLAB=y CONFIG_MODULES=y @@ -359,6 +360,7 @@ CONFIG_MACVTAP=m CONFIG_IPVLAN=m CONFIG_VXLAN=m CONFIG_GENEVE=m +CONFIG_GTP=m CONFIG_MACSEC=m CONFIG_NETCONSOLE=m CONFIG_NETCONSOLE_DYNAMIC=y @@ -553,7 +555,9 @@ CONFIG_TEST_STRING_HELPERS=m CONFIG_TEST_KSTRTOX=m CONFIG_TEST_PRINTF=m CONFIG_TEST_BITMAP=m +CONFIG_TEST_UUID=m CONFIG_TEST_RHASHTABLE=m +CONFIG_TEST_HASH=m CONFIG_TEST_LKM=m CONFIG_TEST_USER_COPY=m CONFIG_TEST_BPF=m diff --git a/arch/m68k/configs/apollo_defconfig b/arch/m68k/configs/apollo_defconfig index e96787f..31bded9 100644 --- a/arch/m68k/configs/apollo_defconfig +++ b/arch/m68k/configs/apollo_defconfig @@ -9,6 +9,7 @@ CONFIG_LOG_BUF_SHIFT=16 # CONFIG_PID_NS is not set # CONFIG_NET_NS is not set CONFIG_BLK_DEV_INITRD=y +CONFIG_CC_OPTIMIZE_FOR_SIZE=y CONFIG_USERFAULTFD=y CONFIG_SLAB=y CONFIG_MODULES=y @@ -341,6 +342,7 @@ CONFIG_MACVTAP=m CONFIG_IPVLAN=m CONFIG_VXLAN=m CONFIG_GENEVE=m +CONFIG_GTP=m CONFIG_MACSEC=m CONFIG_NETCONSOLE=m CONFIG_NETCONSOLE_DYNAMIC=y @@ -512,7 +514,9 @@ CONFIG_TEST_STRING_HELPERS=m CONFIG_TEST_KSTRTOX=m CONFIG_TEST_PRINTF=m CONFIG_TEST_BITMAP=m +CONFIG_TEST_UUID=m CONFIG_TEST_RHASHTABLE=m +CONFIG_TEST_HASH=m CONFIG_TEST_LKM=m CONFIG_TEST_USER_COPY=m CONFIG_TEST_BPF=m diff --git a/arch/m68k/configs/atari_defconfig b/arch/m68k/configs/atari_defconfig index 083fe6b..0d7739e 100644 --- a/arch/m68k/configs/atari_defconfig +++ b/arch/m68k/configs/atari_defconfig @@ -9,6 +9,7 @@ CONFIG_LOG_BUF_SHIFT=16 # CONFIG_PID_NS is not set # CONFIG_NET_NS is not set CONFIG_BLK_DEV_INITRD=y +CONFIG_CC_OPTIMIZE_FOR_SIZE=y CONFIG_USERFAULTFD=y CONFIG_SLAB=y CONFIG_MODULES=y @@ -350,6 +351,7 @@ CONFIG_MACVTAP=m CONFIG_IPVLAN=m CONFIG_VXLAN=m CONFIG_GENEVE=m +CONFIG_GTP=m CONFIG_MACSEC=m CONFIG_NETCONSOLE=m CONFIG_NETCONSOLE_DYNAMIC=y @@ -533,7 +535,9 @@ CONFIG_TEST_STRING_HELPERS=m CONFIG_TEST_KSTRTOX=m CONFIG_TEST_PRINTF=m CONFIG_TEST_BITMAP=m +CONFIG_TEST_UUID=m CONFIG_TEST_RHASHTABLE=m +CONFIG_TEST_HASH=m CONFIG_TEST_LKM=m CONFIG_TEST_USER_COPY=m CONFIG_TEST_BPF=m diff --git a/arch/m68k/configs/bvme6000_defconfig b/arch/m68k/configs/bvme6000_defconfig index 475130c..2cbb5c4 100644 --- a/arch/m68k/configs/bvme6000_defconfig +++ b/arch/m68k/configs/bvme6000_defconfig @@ -9,6 +9,7 @@ CONFIG_LOG_BUF_SHIFT=16 # CONFIG_PID_NS is not set # CONFIG_NET_NS is not set CONFIG_BLK_DEV_INITRD=y +CONFIG_CC_OPTIMIZE_FOR_SIZE=y CONFIG_USERFAULTFD=y CONFIG_SLAB=y CONFIG_MODULES=y @@ -340,6 +341,7 @@ CONFIG_MACVTAP=m CONFIG_IPVLAN=m CONFIG_VXLAN=m CONFIG_GENEVE=m +CONFIG_GTP=m CONFIG_MACSEC=m CONFIG_NETCONSOLE=m CONFIG_NETCONSOLE_DYNAMIC=y @@ -504,7 +506,9 @@ CONFIG_TEST_STRING_HELPERS=m CONFIG_TEST_KSTRTOX=m CONFIG_TEST_PRINTF=m CONFIG_TEST_BITMAP=m +CONFIG_TEST_UUID=m CONFIG_TEST_RHASHTABLE=m +CONFIG_TEST_HASH=m CONFIG_TEST_LKM=m CONFIG_TEST_USER_COPY=m CONFIG_TEST_BPF=m diff --git a/arch/m68k/configs/hp300_defconfig b/arch/m68k/configs/hp300_defconfig index 4339658..96102a4 100644 --- a/arch/m68k/configs/hp300_defconfig +++ b/arch/m68k/configs/hp300_defconfig @@ -9,6 +9,7 @@ CONFIG_LOG_BUF_SHIFT=16 # CONFIG_PID_NS is not set # CONFIG_NET_NS is not set CONFIG_BLK_DEV_INITRD=y +CONFIG_CC_OPTIMIZE_FOR_SIZE=y CONFIG_USERFAULTFD=y CONFIG_SLAB=y CONFIG_MODULES=y @@ -341,6 +342,7 @@ CONFIG_MACVTAP=m CONFIG_IPVLAN=m CONFIG_VXLAN=m CONFIG_GENEVE=m +CONFIG_GTP=m CONFIG_MACSEC=m CONFIG_NETCONSOLE=m CONFIG_NETCONSOLE_DYNAMIC=y @@ -514,7 +516,9 @@ CONFIG_TEST_STRING_HELPERS=m CONFIG_TEST_KSTRTOX=m CONFIG_TEST_PRINTF=m CONFIG_TEST_BITMAP=m +CONFIG_TEST_UUID=m CONFIG_TEST_RHASHTABLE=m +CONFIG_TEST_HASH=m CONFIG_TEST_LKM=m CONFIG_TEST_USER_COPY=m CONFIG_TEST_BPF=m diff --git a/arch/m68k/configs/mac_defconfig b/arch/m68k/configs/mac_defconfig index 831cc8c..97d88f7 100644 --- a/arch/m68k/configs/mac_defconfig +++ b/arch/m68k/configs/mac_defconfig @@ -9,6 +9,7 @@ CONFIG_LOG_BUF_SHIFT=16 # CONFIG_PID_NS is not set # CONFIG_NET_NS is not set CONFIG_BLK_DEV_INITRD=y +CONFIG_CC_OPTIMIZE_FOR_SIZE=y CONFIG_USERFAULTFD=y CONFIG_SLAB=y CONFIG_MODULES=y @@ -357,6 +358,7 @@ CONFIG_MACVTAP=m CONFIG_IPVLAN=m CONFIG_VXLAN=m CONFIG_GENEVE=m +CONFIG_GTP=m CONFIG_MACSEC=m CONFIG_NETCONSOLE=m CONFIG_NETCONSOLE_DYNAMIC=y @@ -536,7 +538,9 @@ CONFIG_TEST_STRING_HELPERS=m CONFIG_TEST_KSTRTOX=m CONFIG_TEST_PRINTF=m CONFIG_TEST_BITMAP=m +CONFIG_TEST_UUID=m CONFIG_TEST_RHASHTABLE=m +CONFIG_TEST_HASH=m CONFIG_TEST_LKM=m CONFIG_TEST_USER_COPY=m CONFIG_TEST_BPF=m diff --git a/arch/m68k/configs/multi_defconfig b/arch/m68k/configs/multi_defconfig index 6377afe..be25ef2 100644 --- a/arch/m68k/configs/multi_defconfig +++ b/arch/m68k/configs/multi_defconfig @@ -9,6 +9,7 @@ CONFIG_LOG_BUF_SHIFT=16 # CONFIG_PID_NS is not set # CONFIG_NET_NS is not set CONFIG_BLK_DEV_INITRD=y +CONFIG_CC_OPTIMIZE_FOR_SIZE=y CONFIG_USERFAULTFD=y CONFIG_SLAB=y CONFIG_MODULES=y @@ -390,6 +391,7 @@ CONFIG_MACVTAP=m CONFIG_IPVLAN=m CONFIG_VXLAN=m CONFIG_GENEVE=m +CONFIG_GTP=m CONFIG_MACSEC=m CONFIG_NETCONSOLE=m CONFIG_NETCONSOLE_DYNAMIC=y @@ -616,7 +618,9 @@ CONFIG_TEST_STRING_HELPERS=m CONFIG_TEST_KSTRTOX=m CONFIG_TEST_PRINTF=m CONFIG_TEST_BITMAP=m +CONFIG_TEST_UUID=m CONFIG_TEST_RHASHTABLE=m +CONFIG_TEST_HASH=m CONFIG_TEST_LKM=m CONFIG_TEST_USER_COPY=m CONFIG_TEST_BPF=m diff --git a/arch/m68k/configs/mvme147_defconfig b/arch/m68k/configs/mvme147_defconfig index 4304b3d..a008344 100644 --- a/arch/m68k/configs/mvme147_defconfig +++ b/arch/m68k/configs/mvme147_defconfig @@ -9,6 +9,7 @@ CONFIG_LOG_BUF_SHIFT=16 # CONFIG_PID_NS is not set # CONFIG_NET_NS is not set CONFIG_BLK_DEV_INITRD=y +CONFIG_CC_OPTIMIZE_FOR_SIZE=y CONFIG_USERFAULTFD=y CONFIG_SLAB=y CONFIG_MODULES=y @@ -339,6 +340,7 @@ CONFIG_MACVTAP=m CONFIG_IPVLAN=m CONFIG_VXLAN=m CONFIG_GENEVE=m +CONFIG_GTP=m CONFIG_MACSEC=m CONFIG_NETCONSOLE=m CONFIG_NETCONSOLE_DYNAMIC=y @@ -504,7 +506,9 @@ CONFIG_TEST_STRING_HELPERS=m CONFIG_TEST_KSTRTOX=m CONFIG_TEST_PRINTF=m CONFIG_TEST_BITMAP=m +CONFIG_TEST_UUID=m CONFIG_TEST_RHASHTABLE=m +CONFIG_TEST_HASH=m CONFIG_TEST_LKM=m CONFIG_TEST_USER_COPY=m CONFIG_TEST_BPF=m diff --git a/arch/m68k/configs/mvme16x_defconfig b/arch/m68k/configs/mvme16x_defconfig index 074bda4..6735a25 100644 --- a/arch/m68k/configs/mvme16x_defconfig +++ b/arch/m68k/configs/mvme16x_defconfig @@ -9,6 +9,7 @@ CONFIG_LOG_BUF_SHIFT=16 # CONFIG_PID_NS is not set # CONFIG_NET_NS is not set CONFIG_BLK_DEV_INITRD=y +CONFIG_CC_OPTIMIZE_FOR_SIZE=y CONFIG_USERFAULTFD=y CONFIG_SLAB=y CONFIG_MODULES=y @@ -340,6 +341,7 @@ CONFIG_MACVTAP=m CONFIG_IPVLAN=m CONFIG_VXLAN=m CONFIG_GENEVE=m +CONFIG_GTP=m CONFIG_MACSEC=m CONFIG_NETCONSOLE=m CONFIG_NETCONSOLE_DYNAMIC=y @@ -504,7 +506,9 @@ CONFIG_TEST_STRING_HELPERS=m CONFIG_TEST_KSTRTOX=m CONFIG_TEST_PRINTF=m CONFIG_TEST_BITMAP=m +CONFIG_TEST_UUID=m CONFIG_TEST_RHASHTABLE=m +CONFIG_TEST_HASH=m CONFIG_TEST_LKM=m CONFIG_TEST_USER_COPY=m CONFIG_TEST_BPF=m diff --git a/arch/m68k/configs/q40_defconfig b/arch/m68k/configs/q40_defconfig index 07b9fa8..780c6e9 100644 --- a/arch/m68k/configs/q40_defconfig +++ b/arch/m68k/configs/q40_defconfig @@ -9,6 +9,7 @@ CONFIG_LOG_BUF_SHIFT=16 # CONFIG_PID_NS is not set # CONFIG_NET_NS is not set CONFIG_BLK_DEV_INITRD=y +CONFIG_CC_OPTIMIZE_FOR_SIZE=y CONFIG_USERFAULTFD=y CONFIG_SLAB=y CONFIG_MODULES=y @@ -346,6 +347,7 @@ CONFIG_MACVTAP=m CONFIG_IPVLAN=m CONFIG_VXLAN=m CONFIG_GENEVE=m +CONFIG_GTP=m CONFIG_MACSEC=m CONFIG_NETCONSOLE=m CONFIG_NETCONSOLE_DYNAMIC=y @@ -527,7 +529,9 @@ CONFIG_TEST_STRING_HELPERS=m CONFIG_TEST_KSTRTOX=m CONFIG_TEST_PRINTF=m CONFIG_TEST_BITMAP=m +CONFIG_TEST_UUID=m CONFIG_TEST_RHASHTABLE=m +CONFIG_TEST_HASH=m CONFIG_TEST_LKM=m CONFIG_TEST_USER_COPY=m CONFIG_TEST_BPF=m diff --git a/arch/m68k/configs/sun3_defconfig b/arch/m68k/configs/sun3_defconfig index 36e6fae..44693cf 100644 --- a/arch/m68k/configs/sun3_defconfig +++ b/arch/m68k/configs/sun3_defconfig @@ -9,6 +9,7 @@ CONFIG_LOG_BUF_SHIFT=16 # CONFIG_PID_NS is not set # CONFIG_NET_NS is not set CONFIG_BLK_DEV_INITRD=y +CONFIG_CC_OPTIMIZE_FOR_SIZE=y CONFIG_USERFAULTFD=y CONFIG_SLAB=y CONFIG_MODULES=y @@ -337,6 +338,7 @@ CONFIG_MACVTAP=m CONFIG_IPVLAN=m CONFIG_VXLAN=m CONFIG_GENEVE=m +CONFIG_GTP=m CONFIG_MACSEC=m CONFIG_NETCONSOLE=m CONFIG_NETCONSOLE_DYNAMIC=y @@ -506,7 +508,9 @@ CONFIG_TEST_STRING_HELPERS=m CONFIG_TEST_KSTRTOX=m CONFIG_TEST_PRINTF=m CONFIG_TEST_BITMAP=m +CONFIG_TEST_UUID=m CONFIG_TEST_RHASHTABLE=m +CONFIG_TEST_HASH=m CONFIG_TEST_LKM=m CONFIG_TEST_USER_COPY=m CONFIG_TEST_BPF=m diff --git a/arch/m68k/configs/sun3x_defconfig b/arch/m68k/configs/sun3x_defconfig index 903acf9..ef0071d 100644 --- a/arch/m68k/configs/sun3x_defconfig +++ b/arch/m68k/configs/sun3x_defconfig @@ -9,6 +9,7 @@ CONFIG_LOG_BUF_SHIFT=16 # CONFIG_PID_NS is not set # CONFIG_NET_NS is not set CONFIG_BLK_DEV_INITRD=y +CONFIG_CC_OPTIMIZE_FOR_SIZE=y CONFIG_USERFAULTFD=y CONFIG_SLAB=y CONFIG_MODULES=y @@ -337,6 +338,7 @@ CONFIG_MACVTAP=m CONFIG_IPVLAN=m CONFIG_VXLAN=m CONFIG_GENEVE=m +CONFIG_GTP=m CONFIG_MACSEC=m CONFIG_NETCONSOLE=m CONFIG_NETCONSOLE_DYNAMIC=y @@ -506,7 +508,9 @@ CONFIG_TEST_STRING_HELPERS=m CONFIG_TEST_KSTRTOX=m CONFIG_TEST_PRINTF=m CONFIG_TEST_BITMAP=m +CONFIG_TEST_UUID=m CONFIG_TEST_RHASHTABLE=m +CONFIG_TEST_HASH=m CONFIG_TEST_LKM=m CONFIG_TEST_USER_COPY=m CONFIG_TEST_BPF=m -- cgit v0.10.2 From 775be506266a860f141f6b848c92c316c602a94f Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Fri, 17 Jun 2016 16:56:14 +0100 Subject: clockevents: Make clockevents_subsys static The clockevents_subsys struct is used for sysfs support and is not declared or used outside the file it is defined in. Fix the following warning by making it static: kernel/time/clockevents.c:648:17: warning: symbol 'clockevents_subsys' was not declared. Should it be static? Signed-off-by: Ben Dooks Cc: linux-kernel@lists.codethink.co.uk Link: http://lkml.kernel.org/r/1466178974-7105-1-git-send-email-ben.dooks@codethink.co.uk Signed-off-by: Thomas Gleixner diff --git a/kernel/time/clockevents.c b/kernel/time/clockevents.c index a9b76a4..2c5bc77 100644 --- a/kernel/time/clockevents.c +++ b/kernel/time/clockevents.c @@ -645,7 +645,7 @@ void tick_cleanup_dead_cpu(int cpu) #endif #ifdef CONFIG_SYSFS -struct bus_type clockevents_subsys = { +static struct bus_type clockevents_subsys = { .name = "clockevents", .dev_name = "clockevent", }; -- cgit v0.10.2 From eb0dc47ab6810c432e8193beccd9905ba0db8b22 Mon Sep 17 00:00:00 2001 From: Vincent Stehle Date: Mon, 18 Jul 2016 22:56:26 +0200 Subject: genirq: Fix missing irq allocation affinity hint MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The new affinity hint argument of __irq_domain_alloc_irqs() is missing in irq_reserve_ipi(). Add it. This fixes the following compilation error: kernel/irq/ipi.c: In function ‘irq_reserve_ipi’: kernel/irq/ipi.c:85:9: error: too few arguments to function ‘__irq_domain_alloc_irqs’ virq = __irq_domain_alloc_irqs(domain, virq, nr_irqs, NUMA_NO_NODE, ^ Fixes: 06ee6d571f0e ("genirq: Add affinity hint to irq allocation") Signed-off-by: Vincent Stehlé Cc: linux-pci@vger.kernel.org Cc: Christoph Hellwig Signed-off-by: Thomas Gleixner diff --git a/kernel/irq/ipi.c b/kernel/irq/ipi.c index 4fd2351..1a9abc1 100644 --- a/kernel/irq/ipi.c +++ b/kernel/irq/ipi.c @@ -83,7 +83,7 @@ int irq_reserve_ipi(struct irq_domain *domain, } virq = __irq_domain_alloc_irqs(domain, virq, nr_irqs, NUMA_NO_NODE, - (void *) dest, true); + (void *) dest, true, NULL); if (virq <= 0) { pr_warn("Can't reserve IPI, failed to alloc hw irqs\n"); -- cgit v0.10.2 From 1f3b0f8243cb934307f59bd4d8e43b868e61d4d9 Mon Sep 17 00:00:00 2001 From: Gaurav Jindal Date: Thu, 14 Jul 2016 12:04:20 +0000 Subject: tick/nohz: Optimize nohz idle enter tick_nohz_start_idle is called before checking whether the idle tick can be stopped. If the tick cannot be stopped, calling tick_nohz_start_idle() is pointless and just wasting CPU cycles. Only invoke tick_nohz_start_idle() when can_stop_idle_tick() returns true. A short one minute observation of the effect on ARM64 shows a reduction of calls by 1.5% thus optimizing the idle entry sequence. [tglx: Massaged changelog ] Co-developed-by: Sanjeev Yadav Signed-off-by: Gaurav Jindal Link: http://lkml.kernel.org/r/20160714120416.GB21099@gaurav.jindal@spreadtrum.com Signed-off-by: Thomas Gleixner diff --git a/kernel/time/tick-sched.c b/kernel/time/tick-sched.c index 2ec7c00..204fdc8 100644 --- a/kernel/time/tick-sched.c +++ b/kernel/time/tick-sched.c @@ -908,11 +908,10 @@ static void __tick_nohz_idle_enter(struct tick_sched *ts) ktime_t now, expires; int cpu = smp_processor_id(); - now = tick_nohz_start_idle(ts); - if (can_stop_idle_tick(cpu, ts)) { int was_stopped = ts->tick_stopped; + now = tick_nohz_start_idle(ts); ts->idle_calls++; expires = tick_nohz_stop_sched_tick(ts, now, cpu); -- cgit v0.10.2 From a72255983f12f31f0c8d8275fb1a781546cfacb7 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Tue, 19 Jul 2016 12:32:39 -0700 Subject: nfit: make DIMM DSMs optional Commit 4995734e973a "acpi, nfit: fix acpi_check_dsm() vs zero functions implemented" attempted to fix a QEMU regression by supporting its usage of a zero-mask as a valid response to a DSM-family probe request. However, this behavior breaks HP platforms that return a zero-mask by default causing the probe to misidentify the DSM-family. Instead, the QEMU regression can be fixed by simply not requiring the DSM family to be identified. This effectively reverts commit 4995734e973a, and removes the DSM requirement from the init path. Cc: "Rafael J. Wysocki" Cc: Xiao Guangrong Cc: Linda Knippers Fixes: 4995734e973a ("acpi, nfit: fix acpi_check_dsm() vs zero functions implemented") Reported-by: Jerry Hoemann Tested-by: Jerry Hoemann Signed-off-by: Dan Williams diff --git a/drivers/acpi/nfit.c b/drivers/acpi/nfit.c index ac6ddcc0..1f0e060 100644 --- a/drivers/acpi/nfit.c +++ b/drivers/acpi/nfit.c @@ -1131,11 +1131,11 @@ static int acpi_nfit_add_dimm(struct acpi_nfit_desc *acpi_desc, /* * Until standardization materializes we need to consider up to 3 - * different command sets. Note, that checking for zero functions - * tells us if any commands might be reachable through this uuid. + * different command sets. Note, that checking for function0 (bit0) + * tells us if any commands are reachable through this uuid. */ for (i = NVDIMM_FAMILY_INTEL; i <= NVDIMM_FAMILY_HPE2; i++) - if (acpi_check_dsm(adev_dimm->handle, to_nfit_uuid(i), 1, 0)) + if (acpi_check_dsm(adev_dimm->handle, to_nfit_uuid(i), 1, 1)) break; /* limit the supported commands to those that are publicly documented */ @@ -1151,9 +1151,10 @@ static int acpi_nfit_add_dimm(struct acpi_nfit_desc *acpi_desc, if (disable_vendor_specific) dsm_mask &= ~(1 << 8); } else { - dev_err(dev, "unknown dimm command family\n"); + dev_dbg(dev, "unknown dimm command family\n"); nfit_mem->family = -1; - return force_enable_dimms ? 0 : -ENODEV; + /* DSMs are optional, continue loading the driver... */ + return 0; } uuid = to_nfit_uuid(nfit_mem->family); diff --git a/drivers/acpi/utils.c b/drivers/acpi/utils.c index b4de130..22c0995 100644 --- a/drivers/acpi/utils.c +++ b/drivers/acpi/utils.c @@ -680,6 +680,9 @@ bool acpi_check_dsm(acpi_handle handle, const u8 *uuid, u64 rev, u64 funcs) u64 mask = 0; union acpi_object *obj; + if (funcs == 0) + return false; + obj = acpi_evaluate_dsm(handle, uuid, rev, 0, NULL); if (!obj) return false; @@ -692,9 +695,6 @@ bool acpi_check_dsm(acpi_handle handle, const u8 *uuid, u64 rev, u64 funcs) mask |= (((u64)obj->buffer.pointer[i]) << (i * 8)); ACPI_FREE(obj); - if (funcs == 0) - return true; - /* * Bit 0 indicates whether there's support for any functions other than * function 0 for the specified UUID and revision. -- cgit v0.10.2 From 30f56e3ced0f4966e8a84ece1acceccbbb73d365 Mon Sep 17 00:00:00 2001 From: Eugenia Emantayev Date: Mon, 18 Jul 2016 18:35:11 +0300 Subject: net/mlx4_en: Move filters cleanup to a proper location Filters cleanup should be done once before destroying net device, since filters list is contained in the private data. Fixes: 1eb8c695bda9 ('net/mlx4_en: Add accelerated RFS support') Signed-off-by: Eugenia Emantayev Signed-off-by: Tariq Toukan Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c index 0c0dfd6..5d809c8 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c @@ -2080,6 +2080,10 @@ void mlx4_en_destroy_netdev(struct net_device *dev) mdev->upper[priv->port] = NULL; mutex_unlock(&mdev->state_lock); +#ifdef CONFIG_RFS_ACCEL + mlx4_en_cleanup_filters(priv); +#endif + mlx4_en_free_resources(priv); kfree(priv->tx_ring); diff --git a/drivers/net/ethernet/mellanox/mlx4/en_rx.c b/drivers/net/ethernet/mellanox/mlx4/en_rx.c index c1b3a9c..99b5407 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_rx.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_rx.c @@ -514,9 +514,6 @@ void mlx4_en_destroy_rx_ring(struct mlx4_en_priv *priv, ring->rx_info = NULL; kfree(ring); *pring = NULL; -#ifdef CONFIG_RFS_ACCEL - mlx4_en_cleanup_filters(priv); -#endif } void mlx4_en_deactivate_rx_ring(struct mlx4_en_priv *priv, -- cgit v0.10.2 From ec25bc04ed8e12947738468cbe2191f1529f9e39 Mon Sep 17 00:00:00 2001 From: Eugenia Emantayev Date: Mon, 18 Jul 2016 18:35:12 +0300 Subject: net/mlx4_en: Add resilience in low memory systems This patch fixes the lost of Ethernet port on low memory system, when driver frees its resources and fails to allocate new resources. Issue could happen while changing number of channels, rings size or changing the timestamp configuration. This fix is necessary because of removing vmap use in the code. When vmap was in use driver could allocate non-contiguous memory and make it contiguous with vmap. Now it could fail to allocate a large chunk of contiguous memory and lose the port. Current code tries to allocate new resources and then upon success frees the old resources. Fixes: 73898db04301 ('net/mlx4: Avoid wrong virtual mappings') Signed-off-by: Eugenia Emantayev Signed-off-by: Tariq Toukan Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c b/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c index fc95aff..44cf16d 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c @@ -1042,6 +1042,8 @@ static int mlx4_en_set_ringparam(struct net_device *dev, { struct mlx4_en_priv *priv = netdev_priv(dev); struct mlx4_en_dev *mdev = priv->mdev; + struct mlx4_en_port_profile new_prof; + struct mlx4_en_priv *tmp; u32 rx_size, tx_size; int port_up = 0; int err = 0; @@ -1061,22 +1063,25 @@ static int mlx4_en_set_ringparam(struct net_device *dev, tx_size == priv->tx_ring[0]->size) return 0; + tmp = kzalloc(sizeof(*tmp), GFP_KERNEL); + if (!tmp) + return -ENOMEM; + mutex_lock(&mdev->state_lock); + memcpy(&new_prof, priv->prof, sizeof(struct mlx4_en_port_profile)); + new_prof.tx_ring_size = tx_size; + new_prof.rx_ring_size = rx_size; + err = mlx4_en_try_alloc_resources(priv, tmp, &new_prof); + if (err) + goto out; + if (priv->port_up) { port_up = 1; mlx4_en_stop_port(dev, 1); } - mlx4_en_free_resources(priv); - - priv->prof->tx_ring_size = tx_size; - priv->prof->rx_ring_size = rx_size; + mlx4_en_safe_replace_resources(priv, tmp); - err = mlx4_en_alloc_resources(priv); - if (err) { - en_err(priv, "Failed reallocating port resources\n"); - goto out; - } if (port_up) { err = mlx4_en_start_port(dev); if (err) @@ -1084,8 +1089,8 @@ static int mlx4_en_set_ringparam(struct net_device *dev, } err = mlx4_en_moderation_update(priv); - out: + kfree(tmp); mutex_unlock(&mdev->state_lock); return err; } @@ -1714,6 +1719,8 @@ static int mlx4_en_set_channels(struct net_device *dev, { struct mlx4_en_priv *priv = netdev_priv(dev); struct mlx4_en_dev *mdev = priv->mdev; + struct mlx4_en_port_profile new_prof; + struct mlx4_en_priv *tmp; int port_up = 0; int err = 0; @@ -1723,23 +1730,26 @@ static int mlx4_en_set_channels(struct net_device *dev, !channel->tx_count || !channel->rx_count) return -EINVAL; + tmp = kzalloc(sizeof(*tmp), GFP_KERNEL); + if (!tmp) + return -ENOMEM; + mutex_lock(&mdev->state_lock); + memcpy(&new_prof, priv->prof, sizeof(struct mlx4_en_port_profile)); + new_prof.num_tx_rings_p_up = channel->tx_count; + new_prof.tx_ring_num = channel->tx_count * MLX4_EN_NUM_UP; + new_prof.rx_ring_num = channel->rx_count; + + err = mlx4_en_try_alloc_resources(priv, tmp, &new_prof); + if (err) + goto out; + if (priv->port_up) { port_up = 1; mlx4_en_stop_port(dev, 1); } - mlx4_en_free_resources(priv); - - priv->num_tx_rings_p_up = channel->tx_count; - priv->tx_ring_num = channel->tx_count * MLX4_EN_NUM_UP; - priv->rx_ring_num = channel->rx_count; - - err = mlx4_en_alloc_resources(priv); - if (err) { - en_err(priv, "Failed reallocating port resources\n"); - goto out; - } + mlx4_en_safe_replace_resources(priv, tmp); netif_set_real_num_tx_queues(dev, priv->tx_ring_num); netif_set_real_num_rx_queues(dev, priv->rx_ring_num); @@ -1757,8 +1767,8 @@ static int mlx4_en_set_channels(struct net_device *dev, } err = mlx4_en_moderation_update(priv); - out: + kfree(tmp); mutex_unlock(&mdev->state_lock); return err; } diff --git a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c index 5d809c8..8359e9e 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c @@ -1954,7 +1954,7 @@ static int mlx4_en_close(struct net_device *dev) return 0; } -void mlx4_en_free_resources(struct mlx4_en_priv *priv) +static void mlx4_en_free_resources(struct mlx4_en_priv *priv) { int i; @@ -1979,7 +1979,7 @@ void mlx4_en_free_resources(struct mlx4_en_priv *priv) } -int mlx4_en_alloc_resources(struct mlx4_en_priv *priv) +static int mlx4_en_alloc_resources(struct mlx4_en_priv *priv) { struct mlx4_en_port_profile *prof = priv->prof; int i; @@ -2044,6 +2044,77 @@ static void mlx4_en_shutdown(struct net_device *dev) rtnl_unlock(); } +static int mlx4_en_copy_priv(struct mlx4_en_priv *dst, + struct mlx4_en_priv *src, + struct mlx4_en_port_profile *prof) +{ + memcpy(&dst->hwtstamp_config, &prof->hwtstamp_config, + sizeof(dst->hwtstamp_config)); + dst->num_tx_rings_p_up = src->mdev->profile.num_tx_rings_p_up; + dst->tx_ring_num = prof->tx_ring_num; + dst->rx_ring_num = prof->rx_ring_num; + dst->flags = prof->flags; + dst->mdev = src->mdev; + dst->port = src->port; + dst->dev = src->dev; + dst->prof = prof; + dst->stride = roundup_pow_of_two(sizeof(struct mlx4_en_rx_desc) + + DS_SIZE * MLX4_EN_MAX_RX_FRAGS); + + dst->tx_ring = kzalloc(sizeof(struct mlx4_en_tx_ring *) * MAX_TX_RINGS, + GFP_KERNEL); + if (!dst->tx_ring) + return -ENOMEM; + + dst->tx_cq = kzalloc(sizeof(struct mlx4_en_cq *) * MAX_TX_RINGS, + GFP_KERNEL); + if (!dst->tx_cq) { + kfree(dst->tx_ring); + return -ENOMEM; + } + return 0; +} + +static void mlx4_en_update_priv(struct mlx4_en_priv *dst, + struct mlx4_en_priv *src) +{ + memcpy(dst->rx_ring, src->rx_ring, + sizeof(struct mlx4_en_rx_ring *) * src->rx_ring_num); + memcpy(dst->rx_cq, src->rx_cq, + sizeof(struct mlx4_en_cq *) * src->rx_ring_num); + memcpy(&dst->hwtstamp_config, &src->hwtstamp_config, + sizeof(dst->hwtstamp_config)); + dst->tx_ring_num = src->tx_ring_num; + dst->rx_ring_num = src->rx_ring_num; + dst->tx_ring = src->tx_ring; + dst->tx_cq = src->tx_cq; + memcpy(dst->prof, src->prof, sizeof(struct mlx4_en_port_profile)); +} + +int mlx4_en_try_alloc_resources(struct mlx4_en_priv *priv, + struct mlx4_en_priv *tmp, + struct mlx4_en_port_profile *prof) +{ + mlx4_en_copy_priv(tmp, priv, prof); + + if (mlx4_en_alloc_resources(tmp)) { + en_warn(priv, + "%s: Resource allocation failed, using previous configuration\n", + __func__); + kfree(tmp->tx_ring); + kfree(tmp->tx_cq); + return -ENOMEM; + } + return 0; +} + +void mlx4_en_safe_replace_resources(struct mlx4_en_priv *priv, + struct mlx4_en_priv *tmp) +{ + mlx4_en_free_resources(priv); + mlx4_en_update_priv(priv, tmp); +} + void mlx4_en_destroy_netdev(struct net_device *dev) { struct mlx4_en_priv *priv = netdev_priv(dev); @@ -3128,6 +3199,8 @@ int mlx4_en_reset_config(struct net_device *dev, { struct mlx4_en_priv *priv = netdev_priv(dev); struct mlx4_en_dev *mdev = priv->mdev; + struct mlx4_en_port_profile new_prof; + struct mlx4_en_priv *tmp; int port_up = 0; int err = 0; @@ -3144,19 +3217,29 @@ int mlx4_en_reset_config(struct net_device *dev, return -EINVAL; } + tmp = kzalloc(sizeof(*tmp), GFP_KERNEL); + if (!tmp) + return -ENOMEM; + mutex_lock(&mdev->state_lock); + + memcpy(&new_prof, priv->prof, sizeof(struct mlx4_en_port_profile)); + memcpy(&new_prof.hwtstamp_config, &ts_config, sizeof(ts_config)); + + err = mlx4_en_try_alloc_resources(priv, tmp, &new_prof); + if (err) + goto out; + if (priv->port_up) { port_up = 1; mlx4_en_stop_port(dev, 1); } - mlx4_en_free_resources(priv); - en_warn(priv, "Changing device configuration rx filter(%x) rx vlan(%x)\n", - ts_config.rx_filter, !!(features & NETIF_F_HW_VLAN_CTAG_RX)); + ts_config.rx_filter, + !!(features & NETIF_F_HW_VLAN_CTAG_RX)); - priv->hwtstamp_config.tx_type = ts_config.tx_type; - priv->hwtstamp_config.rx_filter = ts_config.rx_filter; + mlx4_en_safe_replace_resources(priv, tmp); if (DEV_FEATURE_CHANGED(dev, features, NETIF_F_HW_VLAN_CTAG_RX)) { if (features & NETIF_F_HW_VLAN_CTAG_RX) @@ -3190,11 +3273,6 @@ int mlx4_en_reset_config(struct net_device *dev, dev->features &= ~NETIF_F_HW_VLAN_CTAG_RX; } - err = mlx4_en_alloc_resources(priv); - if (err) { - en_err(priv, "Failed reallocating port resources\n"); - goto out; - } if (port_up) { err = mlx4_en_start_port(dev); if (err) @@ -3203,6 +3281,8 @@ int mlx4_en_reset_config(struct net_device *dev, out: mutex_unlock(&mdev->state_lock); - netdev_features_change(dev); + kfree(tmp); + if (!err) + netdev_features_change(dev); return err; } diff --git a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h index 467d47e..13d297e 100644 --- a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h +++ b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h @@ -353,12 +353,14 @@ struct mlx4_en_port_profile { u32 rx_ring_num; u32 tx_ring_size; u32 rx_ring_size; + u8 num_tx_rings_p_up; u8 rx_pause; u8 rx_ppp; u8 tx_pause; u8 tx_ppp; int rss_rings; int inline_thold; + struct hwtstamp_config hwtstamp_config; }; struct mlx4_en_profile { @@ -623,8 +625,11 @@ void mlx4_en_set_stats_bitmap(struct mlx4_dev *dev, u8 rx_ppp, u8 rx_pause, u8 tx_ppp, u8 tx_pause); -void mlx4_en_free_resources(struct mlx4_en_priv *priv); -int mlx4_en_alloc_resources(struct mlx4_en_priv *priv); +int mlx4_en_try_alloc_resources(struct mlx4_en_priv *priv, + struct mlx4_en_priv *tmp, + struct mlx4_en_port_profile *prof); +void mlx4_en_safe_replace_resources(struct mlx4_en_priv *priv, + struct mlx4_en_priv *tmp); int mlx4_en_create_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq **pcq, int entries, int ring, enum cq_type mode, int node); -- cgit v0.10.2 From 97b041971e1c70da077fcfa7a50b362e22cd241e Mon Sep 17 00:00:00 2001 From: Douglas Miller Date: Mon, 18 Jul 2016 12:28:45 -0500 Subject: Update maintainer for EHEA driver. Since Thadeu left IBM, EHEA has gone mostly unmaintained, since his email address doesn't work anymore. I'm stepping up to help maintain this driver upstream. I'm adding Thadeu's personal e-mail address in Cc, hoping that we can get his ack. CC: Thadeu Lima de Souza Cascardo Signed-off-by: Douglas Miller Acked-by: Thadeu Lima de Souza Cascardo Signed-off-by: David S. Miller diff --git a/MAINTAINERS b/MAINTAINERS index 1209323..bda8825 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -4477,7 +4477,7 @@ S: Orphan F: fs/efs/ EHEA (IBM pSeries eHEA 10Gb ethernet adapter) DRIVER -M: Thadeu Lima de Souza Cascardo +M: Douglas Miller L: netdev@vger.kernel.org S: Maintained F: drivers/net/ethernet/ibm/ehea/ -- cgit v0.10.2 From eabfdda93477f6ee5e153f560560e9cb1c617fd7 Mon Sep 17 00:00:00 2001 From: Vivien Didelot Date: Mon, 18 Jul 2016 15:02:06 -0400 Subject: net: switchdev: change ageing_time type to clock_t The switchdev value for the SWITCHDEV_ATTR_ID_BRIDGE_AGEING_TIME attribute is a clock_t and requires to use helpers such as clock_t_to_jiffies() to convert to milliseconds. Change ageing_time type from u32 to clock_t to make it explicit. Fixes: f55ac58ae64c ("switchdev: add bridge ageing_time attribute") Signed-off-by: Vivien Didelot Signed-off-by: David S. Miller diff --git a/include/net/switchdev.h b/include/net/switchdev.h index 985619a..1d8e158 100644 --- a/include/net/switchdev.h +++ b/include/net/switchdev.h @@ -60,7 +60,7 @@ struct switchdev_attr { struct netdev_phys_item_id ppid; /* PORT_PARENT_ID */ u8 stp_state; /* PORT_STP_STATE */ unsigned long brport_flags; /* PORT_BRIDGE_FLAGS */ - u32 ageing_time; /* BRIDGE_AGEING_TIME */ + clock_t ageing_time; /* BRIDGE_AGEING_TIME */ bool vlan_filtering; /* BRIDGE_VLAN_FILTERING */ } u; }; -- cgit v0.10.2 From e4add7b6beaff4061693d0632bc1dcb306edba10 Mon Sep 17 00:00:00 2001 From: Andrew Duggan Date: Tue, 19 Jul 2016 17:53:59 -0700 Subject: Input: synaptics-rmi4 - fix maximum size check for F12 control register 8 According to the RMI4 spec the maximum size of F12 control register 8 is 15 bytes. The current code incorrectly reports an error if control 8 is greater then 14. Making sensors with a control register 8 with 15 bytes unusable. Signed-off-by: Andrew Duggan Reported-by: Chris Healy Cc: stable@vger.kernel.org Signed-off-by: Dmitry Torokhov diff --git a/drivers/input/rmi4/rmi_f12.c b/drivers/input/rmi4/rmi_f12.c index 8dd3fb5..88e9155 100644 --- a/drivers/input/rmi4/rmi_f12.c +++ b/drivers/input/rmi4/rmi_f12.c @@ -66,7 +66,7 @@ static int rmi_f12_read_sensor_tuning(struct f12_data *f12) struct rmi_device *rmi_dev = fn->rmi_dev; int ret; int offset; - u8 buf[14]; + u8 buf[15]; int pitch_x = 0; int pitch_y = 0; int clip_x_low = 0; @@ -86,9 +86,10 @@ static int rmi_f12_read_sensor_tuning(struct f12_data *f12) offset = rmi_register_desc_calc_reg_offset(&f12->control_reg_desc, 8); - if (item->reg_size > 14) { - dev_err(&fn->dev, "F12 control8 should be 14 bytes, not: %ld\n", - item->reg_size); + if (item->reg_size > sizeof(buf)) { + dev_err(&fn->dev, + "F12 control8 should be no bigger than %zd bytes, not: %ld\n", + sizeof(buf), item->reg_size); return -ENODEV; } -- cgit v0.10.2 From edbe77462302ec0b11a90244de13f9012118c538 Mon Sep 17 00:00:00 2001 From: Yoshihiro Shimoda Date: Tue, 19 Jul 2016 14:40:51 +0900 Subject: packet: fix second argument of sock_tx_timestamp() This patch fixes an issue that a syscall (e.g. sendto syscall) cannot work correctly. Since the sendto syscall doesn't have msg_control buffer, the sock_tx_timestamp() in packet_snd() cannot work correctly because the socks.tsflags is set to 0. So, this patch sets the socks.tsflags to sk->sk_tsflags as default. Fixes: c14ac9451c34 ("sock: enable timestamping using control messages") Reported-by: Kazuya Mizuguchi Reported-by: Keita Kobayashi Signed-off-by: Yoshihiro Shimoda Acked-by: Soheil Hassas Yeganeh Acked-by: Willem de Bruijn Signed-off-by: David S. Miller diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index 9f0983f..53e87ce 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c @@ -1927,7 +1927,7 @@ retry: goto out_unlock; } - sockc.tsflags = 0; + sockc.tsflags = sk->sk_tsflags; if (msg->msg_controllen) { err = sock_cmsg_send(sk, msg, &sockc); if (unlikely(err)) { @@ -2678,7 +2678,7 @@ static int tpacket_snd(struct packet_sock *po, struct msghdr *msg) dev = dev_get_by_index(sock_net(&po->sk), saddr->sll_ifindex); } - sockc.tsflags = 0; + sockc.tsflags = po->sk.sk_tsflags; if (msg->msg_controllen) { err = sock_cmsg_send(&po->sk, msg, &sockc); if (unlikely(err)) @@ -2881,7 +2881,7 @@ static int packet_snd(struct socket *sock, struct msghdr *msg, size_t len) if (unlikely(!(dev->flags & IFF_UP))) goto out_unlock; - sockc.tsflags = 0; + sockc.tsflags = sk->sk_tsflags; sockc.mark = sk->sk_mark; if (msg->msg_controllen) { err = sock_cmsg_send(sk, msg, &sockc); -- cgit v0.10.2 From 6f6ef07f412c5bfc37cde57e94b1fec789471907 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Wed, 20 Jul 2016 11:30:34 +0300 Subject: x86/insn: perf tools: Fix vcvtph2ps instruction decoding vcvtph2ps does not have an immediate operand, so remove the erroneous 'Ib' from its opcode map entry. Add vcvtph2ps to the perf tools new instructions test to verify it. Signed-off-by: Adrian Hunter Acked-by: Ingo Molnar Acked-by: Masami Hiramatsu Cc: Andy Lutomirski Cc: Dan Williams Cc: H. Peter Anvin Cc: Jiri Olsa Cc: Thomas Gleixner Cc: X86 ML Link: http://lkml.kernel.org/r/1469003437-32706-2-git-send-email-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo diff --git a/arch/x86/lib/x86-opcode-map.txt b/arch/x86/lib/x86-opcode-map.txt index d388de7..28082de 100644 --- a/arch/x86/lib/x86-opcode-map.txt +++ b/arch/x86/lib/x86-opcode-map.txt @@ -629,7 +629,7 @@ AVXcode: 2 10: pblendvb Vdq,Wdq (66) 11: 12: -13: vcvtph2ps Vx,Wx,Ib (66),(v) +13: vcvtph2ps Vx,Wx (66),(v) 14: blendvps Vdq,Wdq (66) 15: blendvpd Vdq,Wdq (66) 16: vpermps Vqq,Hqq,Wqq (66),(v) diff --git a/tools/perf/arch/x86/tests/insn-x86-dat-32.c b/tools/perf/arch/x86/tests/insn-x86-dat-32.c index 3b491cf..ca08e6e 100644 --- a/tools/perf/arch/x86/tests/insn-x86-dat-32.c +++ b/tools/perf/arch/x86/tests/insn-x86-dat-32.c @@ -6,6 +6,8 @@ {{0x0f, 0x31, }, 2, 0, "", "", "0f 31 \trdtsc ",}, +{{0xc4, 0xe2, 0x7d, 0x13, 0xeb, }, 5, 0, "", "", +"c4 e2 7d 13 eb \tvcvtph2ps %xmm3,%ymm5",}, {{0xf3, 0x0f, 0x1b, 0x00, }, 4, 0, "", "", "f3 0f 1b 00 \tbndmk (%eax),%bnd0",}, {{0xf3, 0x0f, 0x1b, 0x05, 0x78, 0x56, 0x34, 0x12, }, 8, 0, "", "", @@ -309,19 +311,19 @@ {{0x0f, 0x1b, 0x84, 0x08, 0x78, 0x56, 0x34, 0x12, }, 8, 0, "", "", "0f 1b 84 08 78 56 34 12 \tbndstx %bnd0,0x12345678(%eax,%ecx,1)",}, {{0xf2, 0xe8, 0xfc, 0xff, 0xff, 0xff, }, 6, 0xfffffffc, "call", "unconditional", -"f2 e8 fc ff ff ff \tbnd call 3c3 ",}, +"f2 e8 fc ff ff ff \tbnd call 3c8 ",}, {{0xf2, 0xff, 0x10, }, 3, 0, "call", "indirect", "f2 ff 10 \tbnd call *(%eax)",}, {{0xf2, 0xc3, }, 2, 0, "ret", "indirect", "f2 c3 \tbnd ret ",}, {{0xf2, 0xe9, 0xfc, 0xff, 0xff, 0xff, }, 6, 0xfffffffc, "jmp", "unconditional", -"f2 e9 fc ff ff ff \tbnd jmp 3ce ",}, +"f2 e9 fc ff ff ff \tbnd jmp 3d3 ",}, {{0xf2, 0xe9, 0xfc, 0xff, 0xff, 0xff, }, 6, 0xfffffffc, "jmp", "unconditional", -"f2 e9 fc ff ff ff \tbnd jmp 3d4 ",}, +"f2 e9 fc ff ff ff \tbnd jmp 3d9 ",}, {{0xf2, 0xff, 0x21, }, 3, 0, "jmp", "indirect", "f2 ff 21 \tbnd jmp *(%ecx)",}, {{0xf2, 0x0f, 0x85, 0xfc, 0xff, 0xff, 0xff, }, 7, 0xfffffffc, "jcc", "conditional", -"f2 0f 85 fc ff ff ff \tbnd jne 3de ",}, +"f2 0f 85 fc ff ff ff \tbnd jne 3e3 ",}, {{0x0f, 0x3a, 0xcc, 0xc1, 0x00, }, 5, 0, "", "", "0f 3a cc c1 00 \tsha1rnds4 $0x0,%xmm1,%xmm0",}, {{0x0f, 0x3a, 0xcc, 0xd7, 0x91, }, 5, 0, "", "", diff --git a/tools/perf/arch/x86/tests/insn-x86-dat-64.c b/tools/perf/arch/x86/tests/insn-x86-dat-64.c index 4fe7cce..262d9d2 100644 --- a/tools/perf/arch/x86/tests/insn-x86-dat-64.c +++ b/tools/perf/arch/x86/tests/insn-x86-dat-64.c @@ -6,6 +6,8 @@ {{0x0f, 0x31, }, 2, 0, "", "", "0f 31 \trdtsc ",}, +{{0xc4, 0xe2, 0x7d, 0x13, 0xeb, }, 5, 0, "", "", +"c4 e2 7d 13 eb \tvcvtph2ps %xmm3,%ymm5",}, {{0xf3, 0x0f, 0x1b, 0x00, }, 4, 0, "", "", "f3 0f 1b 00 \tbndmk (%rax),%bnd0",}, {{0xf3, 0x41, 0x0f, 0x1b, 0x00, }, 5, 0, "", "", @@ -325,19 +327,19 @@ {{0x0f, 0x1b, 0x84, 0x08, 0x78, 0x56, 0x34, 0x12, }, 8, 0, "", "", "0f 1b 84 08 78 56 34 12 \tbndstx %bnd0,0x12345678(%rax,%rcx,1)",}, {{0xf2, 0xe8, 0x00, 0x00, 0x00, 0x00, }, 6, 0, "call", "unconditional", -"f2 e8 00 00 00 00 \tbnd callq 3f6 ",}, +"f2 e8 00 00 00 00 \tbnd callq 3fb ",}, {{0x67, 0xf2, 0xff, 0x10, }, 4, 0, "call", "indirect", "67 f2 ff 10 \tbnd callq *(%eax)",}, {{0xf2, 0xc3, }, 2, 0, "ret", "indirect", "f2 c3 \tbnd retq ",}, {{0xf2, 0xe9, 0x00, 0x00, 0x00, 0x00, }, 6, 0, "jmp", "unconditional", -"f2 e9 00 00 00 00 \tbnd jmpq 402 ",}, +"f2 e9 00 00 00 00 \tbnd jmpq 407 ",}, {{0xf2, 0xe9, 0x00, 0x00, 0x00, 0x00, }, 6, 0, "jmp", "unconditional", -"f2 e9 00 00 00 00 \tbnd jmpq 408 ",}, +"f2 e9 00 00 00 00 \tbnd jmpq 40d ",}, {{0x67, 0xf2, 0xff, 0x21, }, 4, 0, "jmp", "indirect", "67 f2 ff 21 \tbnd jmpq *(%ecx)",}, {{0xf2, 0x0f, 0x85, 0x00, 0x00, 0x00, 0x00, }, 7, 0, "jcc", "conditional", -"f2 0f 85 00 00 00 00 \tbnd jne 413 ",}, +"f2 0f 85 00 00 00 00 \tbnd jne 418 ",}, {{0x0f, 0x3a, 0xcc, 0xc1, 0x00, }, 5, 0, "", "", "0f 3a cc c1 00 \tsha1rnds4 $0x0,%xmm1,%xmm0",}, {{0x0f, 0x3a, 0xcc, 0xd7, 0x91, }, 5, 0, "", "", diff --git a/tools/perf/arch/x86/tests/insn-x86-dat-src.c b/tools/perf/arch/x86/tests/insn-x86-dat-src.c index 41b1b1c..3cd6775 100644 --- a/tools/perf/arch/x86/tests/insn-x86-dat-src.c +++ b/tools/perf/arch/x86/tests/insn-x86-dat-src.c @@ -19,6 +19,10 @@ int main(void) /* Following line is a marker for the awk script - do not change */ asm volatile("rdtsc"); /* Start here */ + /* Test fix for vcvtph2ps in x86-opcode-map.txt */ + + asm volatile("vcvtph2ps %xmm3,%ymm5"); + #ifdef __x86_64__ /* bndmk m64, bnd */ diff --git a/tools/perf/util/intel-pt-decoder/x86-opcode-map.txt b/tools/perf/util/intel-pt-decoder/x86-opcode-map.txt index d388de7..28082de 100644 --- a/tools/perf/util/intel-pt-decoder/x86-opcode-map.txt +++ b/tools/perf/util/intel-pt-decoder/x86-opcode-map.txt @@ -629,7 +629,7 @@ AVXcode: 2 10: pblendvb Vdq,Wdq (66) 11: 12: -13: vcvtph2ps Vx,Wx,Ib (66),(v) +13: vcvtph2ps Vx,Wx (66),(v) 14: blendvps Vdq,Wdq (66) 15: blendvpd Vdq,Wdq (66) 16: vpermps Vqq,Hqq,Wqq (66),(v) -- cgit v0.10.2 From 08426eda58e07af44aac7c9900ec8a6a62e16b2f Mon Sep 17 00:00:00 2001 From: Thilo Cestonaro Date: Mon, 18 Jul 2016 13:51:29 +0200 Subject: hwmon: Add driver for FTS BMC chip "Teutates" This driver implements hardware monitoring and watchdog support for the FTS BMC Chip "Teutates". Signed-off-by: Thilo Cestonaro [groeck: Updated subject and description; fixed dependencies] Signed-off-by: Guenter Roeck diff --git a/Documentation/hwmon/ftsteutates b/Documentation/hwmon/ftsteutates new file mode 100644 index 0000000..2a1bf69 --- /dev/null +++ b/Documentation/hwmon/ftsteutates @@ -0,0 +1,23 @@ +Kernel driver ftsteutates +===================== + +Supported chips: + * FTS Teutates + Prefix: 'ftsteutates' + Addresses scanned: I2C 0x73 (7-Bit) + +Author: Thilo Cestonaro + + +Description +----------- +The BMC Teutates is the Eleventh generation of Superior System +monitoring and thermal management solution. It is builds on the basic +functionality of the BMC Theseus and contains several new features and +enhancements. It can monitor up to 4 voltages, 16 temperatures and +8 fans. It also contains an integrated watchdog which is currently +implemented in this driver. + +Specification of the chip can be found here: +ftp:///pub/Mainboard-OEM-Sales/Services/Software&Tools/Linux_SystemMonitoring&Watchdog&GPIO/BMC-Teutates_Specification_V1.21.pdf +ftp:///pub/Mainboard-OEM-Sales/Services/Software&Tools/Linux_SystemMonitoring&Watchdog&GPIO/Fujitsu_mainboards-1-Sensors_HowTo-en-US.pdf diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index e72cd3d..eaf2f91 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -486,6 +486,18 @@ config SENSORS_FSCHMD This driver can also be built as a module. If so, the module will be called fschmd. +config SENSORS_FTSTEUTATES + tristate "Fujitsu Technology Solutions sensor chip Teutates" + depends on I2C && WATCHDOG + select WATCHDOG_CORE + help + If you say yes here you get support for the Fujitsu Technology + Solutions (FTS) sensor chip "Teutates" including support for + the integrated watchdog. + + This driver can also be built as a module. If so, the module + will be called ftsteutates. + config SENSORS_GL518SM tristate "Genesys Logic GL518SM" depends on I2C diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile index 446a4e7..fe87d28 100644 --- a/drivers/hwmon/Makefile +++ b/drivers/hwmon/Makefile @@ -62,6 +62,7 @@ obj-$(CONFIG_SENSORS_F71882FG) += f71882fg.o obj-$(CONFIG_SENSORS_F75375S) += f75375s.o obj-$(CONFIG_SENSORS_FAM15H_POWER) += fam15h_power.o obj-$(CONFIG_SENSORS_FSCHMD) += fschmd.o +obj-$(CONFIG_SENSORS_FTSTEUTATES) += ftsteutates.o obj-$(CONFIG_SENSORS_G760A) += g760a.o obj-$(CONFIG_SENSORS_G762) += g762.o obj-$(CONFIG_SENSORS_GL518SM) += gl518sm.o diff --git a/drivers/hwmon/ftsteutates.c b/drivers/hwmon/ftsteutates.c new file mode 100644 index 0000000..aaef5b5 --- /dev/null +++ b/drivers/hwmon/ftsteutates.c @@ -0,0 +1,820 @@ +/* + * Support for the FTS Systemmonitoring Chip "Teutates" + * + * Copyright (C) 2016 Fujitsu Technology Solutions GmbH, + * Thilo Cestonaro + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define FTS_DEVICE_ID_REG 0x0000 +#define FTS_DEVICE_REVISION_REG 0x0001 +#define FTS_DEVICE_STATUS_REG 0x0004 +#define FTS_SATELLITE_STATUS_REG 0x0005 +#define FTS_EVENT_STATUS_REG 0x0006 +#define FTS_GLOBAL_CONTROL_REG 0x0007 + +#define FTS_SENSOR_EVENT_REG 0x0010 + +#define FTS_FAN_EVENT_REG 0x0014 +#define FTS_FAN_PRESENT_REG 0x0015 + +#define FTS_POWER_ON_TIME_COUNTER_A 0x007A +#define FTS_POWER_ON_TIME_COUNTER_B 0x007B +#define FTS_POWER_ON_TIME_COUNTER_C 0x007C + +#define FTS_PAGE_SELECT_REG 0x007F + +#define FTS_WATCHDOG_TIME_PRESET 0x000B +#define FTS_WATCHDOG_CONTROL 0x5081 + +#define FTS_NO_FAN_SENSORS 0x08 +#define FTS_NO_TEMP_SENSORS 0x10 +#define FTS_NO_VOLT_SENSORS 0x04 + +static struct i2c_device_id fts_id[] = { + { "ftsteutates", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, fts_id); + +enum WATCHDOG_RESOLUTION { + seconds = 1, + minutes = 60 +}; + +struct fts_data { + struct i2c_client *client; + /* update sensor data lock */ + struct mutex update_lock; + /* read/write register lock */ + struct mutex access_lock; + unsigned long last_updated; /* in jiffies */ + struct watchdog_device wdd; + enum WATCHDOG_RESOLUTION resolution; + bool valid; /* false until following fields are valid */ + + u8 volt[FTS_NO_VOLT_SENSORS]; + + u8 temp_input[FTS_NO_TEMP_SENSORS]; + u8 temp_alarm; + + u8 fan_present; + u8 fan_input[FTS_NO_FAN_SENSORS]; /* in rps */ + u8 fan_source[FTS_NO_FAN_SENSORS]; + u8 fan_alarm; +}; + +#define FTS_REG_FAN_INPUT(idx) ((idx) + 0x20) +#define FTS_REG_FAN_SOURCE(idx) ((idx) + 0x30) +#define FTS_REG_FAN_CONTROL(idx) (((idx) << 16) + 0x4881) + +#define FTS_REG_TEMP_INPUT(idx) ((idx) + 0x40) +#define FTS_REG_TEMP_CONTROL(idx) (((idx) << 16) + 0x0681) + +#define FTS_REG_VOLT(idx) ((idx) + 0x18) + +/*****************************************************************************/ +/* I2C Helper functions */ +/*****************************************************************************/ +static int fts_read_byte(struct i2c_client *client, unsigned short reg) +{ + int ret; + unsigned char page = reg >> 8; + struct fts_data *data = dev_get_drvdata(&client->dev); + + mutex_lock(&data->access_lock); + + dev_dbg(&client->dev, "page select - page: 0x%.02x\n", page); + ret = i2c_smbus_write_byte_data(client, FTS_PAGE_SELECT_REG, page); + if (ret < 0) + goto error; + + reg &= 0xFF; + ret = i2c_smbus_read_byte_data(client, reg); + dev_dbg(&client->dev, "read - reg: 0x%.02x: val: 0x%.02x\n", reg, ret); + +error: + mutex_unlock(&data->access_lock); + return ret; +} + +static int fts_write_byte(struct i2c_client *client, unsigned short reg, + unsigned char value) +{ + int ret; + unsigned char page = reg >> 8; + struct fts_data *data = dev_get_drvdata(&client->dev); + + mutex_lock(&data->access_lock); + + dev_dbg(&client->dev, "page select - page: 0x%.02x\n", page); + ret = i2c_smbus_write_byte_data(client, FTS_PAGE_SELECT_REG, page); + if (ret < 0) + goto error; + + reg &= 0xFF; + dev_dbg(&client->dev, + "write - reg: 0x%.02x: val: 0x%.02x\n", reg, value); + ret = i2c_smbus_write_byte_data(client, reg, value); + +error: + mutex_unlock(&data->access_lock); + return ret; +} + +/*****************************************************************************/ +/* Data Updater Helper function */ +/*****************************************************************************/ +static int fts_update_device(struct fts_data *data) +{ + int i; + int err = 0; + + mutex_lock(&data->update_lock); + if (!time_after(jiffies, data->last_updated + 2 * HZ) && data->valid) + goto exit; + + err = fts_read_byte(data->client, FTS_DEVICE_STATUS_REG); + if (err < 0) + goto exit; + + data->valid = !!(err & 0x02); /* Data not ready yet */ + if (unlikely(!data->valid)) { + err = -EAGAIN; + goto exit; + } + + err = fts_read_byte(data->client, FTS_FAN_PRESENT_REG); + if (err < 0) + goto exit; + data->fan_present = err; + + err = fts_read_byte(data->client, FTS_FAN_EVENT_REG); + if (err < 0) + goto exit; + data->fan_alarm = err; + + for (i = 0; i < FTS_NO_FAN_SENSORS; i++) { + if (data->fan_present & BIT(i)) { + err = fts_read_byte(data->client, FTS_REG_FAN_INPUT(i)); + if (err < 0) + goto exit; + data->fan_input[i] = err; + + err = fts_read_byte(data->client, + FTS_REG_FAN_SOURCE(i)); + if (err < 0) + goto exit; + data->fan_source[i] = err; + } else { + data->fan_input[i] = 0; + data->fan_source[i] = 0; + } + } + + err = fts_read_byte(data->client, FTS_SENSOR_EVENT_REG); + if (err < 0) + goto exit; + data->temp_alarm = err; + + for (i = 0; i < FTS_NO_TEMP_SENSORS; i++) { + err = fts_read_byte(data->client, FTS_REG_TEMP_INPUT(i)); + if (err < 0) + goto exit; + data->temp_input[i] = err; + } + + for (i = 0; i < FTS_NO_VOLT_SENSORS; i++) { + err = fts_read_byte(data->client, FTS_REG_VOLT(i)); + if (err < 0) + goto exit; + data->volt[i] = err; + } + data->last_updated = jiffies; + err = 0; +exit: + mutex_unlock(&data->update_lock); + return err; +} + +/*****************************************************************************/ +/* Watchdog functions */ +/*****************************************************************************/ +static int fts_wd_set_resolution(struct fts_data *data, + enum WATCHDOG_RESOLUTION resolution) +{ + int ret; + + if (data->resolution == resolution) + return 0; + + ret = fts_read_byte(data->client, FTS_WATCHDOG_CONTROL); + if (ret < 0) + return ret; + + if ((resolution == seconds && ret & BIT(1)) || + (resolution == minutes && (ret & BIT(1)) == 0)) { + data->resolution = resolution; + return 0; + } + + if (resolution == seconds) + set_bit(1, (unsigned long *)&ret); + else + ret &= ~BIT(1); + + ret = fts_write_byte(data->client, FTS_WATCHDOG_CONTROL, ret); + if (ret < 0) + return ret; + + data->resolution = resolution; + return ret; +} + +static int fts_wd_set_timeout(struct watchdog_device *wdd, unsigned int timeout) +{ + struct fts_data *data; + enum WATCHDOG_RESOLUTION resolution = seconds; + int ret; + + data = watchdog_get_drvdata(wdd); + /* switch watchdog resolution to minutes if timeout does not fit + * into a byte + */ + if (timeout > 0xFF) { + timeout = DIV_ROUND_UP(timeout, 60) * 60; + resolution = minutes; + } + + ret = fts_wd_set_resolution(data, resolution); + if (ret < 0) + return ret; + + wdd->timeout = timeout; + return 0; +} + +static int fts_wd_start(struct watchdog_device *wdd) +{ + struct fts_data *data = watchdog_get_drvdata(wdd); + + return fts_write_byte(data->client, FTS_WATCHDOG_TIME_PRESET, + wdd->timeout / (u8)data->resolution); +} + +static int fts_wd_stop(struct watchdog_device *wdd) +{ + struct fts_data *data; + + data = watchdog_get_drvdata(wdd); + return fts_write_byte(data->client, FTS_WATCHDOG_TIME_PRESET, 0); +} + +static const struct watchdog_info fts_wd_info = { + .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE, + .identity = "FTS Teutates Hardware Watchdog", +}; + +static const struct watchdog_ops fts_wd_ops = { + .owner = THIS_MODULE, + .start = fts_wd_start, + .stop = fts_wd_stop, + .set_timeout = fts_wd_set_timeout, +}; + +static int fts_watchdog_init(struct fts_data *data) +{ + int timeout, ret; + + watchdog_set_drvdata(&data->wdd, data); + + timeout = fts_read_byte(data->client, FTS_WATCHDOG_TIME_PRESET); + if (timeout < 0) + return timeout; + + /* watchdog not running, set timeout to a default of 60 sec. */ + if (timeout == 0) { + ret = fts_wd_set_resolution(data, seconds); + if (ret < 0) + return ret; + data->wdd.timeout = 60; + } else { + ret = fts_read_byte(data->client, FTS_WATCHDOG_CONTROL); + if (ret < 0) + return ret; + + data->resolution = ret & BIT(1) ? seconds : minutes; + data->wdd.timeout = timeout * (u8)data->resolution; + set_bit(WDOG_HW_RUNNING, &data->wdd.status); + } + + /* Register our watchdog part */ + data->wdd.info = &fts_wd_info; + data->wdd.ops = &fts_wd_ops; + data->wdd.parent = &data->client->dev; + data->wdd.min_timeout = 1; + + /* max timeout 255 minutes. */ + data->wdd.max_hw_heartbeat_ms = 0xFF * 60 * MSEC_PER_SEC; + + return watchdog_register_device(&data->wdd); +} + +/*****************************************************************************/ +/* SysFS handler functions */ +/*****************************************************************************/ +static ssize_t show_in_value(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + struct fts_data *data = dev_get_drvdata(dev); + int index = to_sensor_dev_attr(devattr)->index; + int err; + + err = fts_update_device(data); + if (err < 0) + return err; + + return sprintf(buf, "%u\n", data->volt[index]); +} + +static ssize_t show_temp_value(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + struct fts_data *data = dev_get_drvdata(dev); + int index = to_sensor_dev_attr(devattr)->index; + int err; + + err = fts_update_device(data); + if (err < 0) + return err; + + return sprintf(buf, "%u\n", data->temp_input[index]); +} + +static ssize_t show_temp_fault(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + struct fts_data *data = dev_get_drvdata(dev); + int index = to_sensor_dev_attr(devattr)->index; + int err; + + err = fts_update_device(data); + if (err < 0) + return err; + + /* 00h Temperature = Sensor Error */ + return sprintf(buf, "%d\n", data->temp_input[index] == 0); +} + +static ssize_t show_temp_alarm(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + struct fts_data *data = dev_get_drvdata(dev); + int index = to_sensor_dev_attr(devattr)->index; + int err; + + err = fts_update_device(data); + if (err < 0) + return err; + + return sprintf(buf, "%u\n", !!(data->temp_alarm & BIT(index))); +} + +static ssize_t +clear_temp_alarm(struct device *dev, struct device_attribute *devattr, + const char *buf, size_t count) +{ + struct fts_data *data = dev_get_drvdata(dev); + int index = to_sensor_dev_attr(devattr)->index; + long ret; + + ret = fts_update_device(data); + if (ret < 0) + return ret; + + if (kstrtoul(buf, 10, &ret) || ret != 0) + return -EINVAL; + + mutex_lock(&data->update_lock); + ret = fts_read_byte(data->client, FTS_REG_TEMP_CONTROL(index)); + if (ret < 0) + goto error; + + ret = fts_write_byte(data->client, FTS_REG_TEMP_CONTROL(index), + ret | 0x1); + if (ret < 0) + goto error; + + data->valid = false; +error: + mutex_unlock(&data->update_lock); + return ret; +} + +static ssize_t show_fan_value(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + struct fts_data *data = dev_get_drvdata(dev); + int index = to_sensor_dev_attr(devattr)->index; + int err; + + err = fts_update_device(data); + if (err < 0) + return err; + + return sprintf(buf, "%u\n", data->fan_input[index]); +} + +static ssize_t show_fan_source(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + struct fts_data *data = dev_get_drvdata(dev); + int index = to_sensor_dev_attr(devattr)->index; + int err; + + err = fts_update_device(data); + if (err < 0) + return err; + + return sprintf(buf, "%u\n", data->fan_source[index]); +} + +static ssize_t show_fan_alarm(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + struct fts_data *data = dev_get_drvdata(dev); + int index = to_sensor_dev_attr(devattr)->index; + int err; + + err = fts_update_device(data); + if (err < 0) + return err; + + return sprintf(buf, "%d\n", !!(data->fan_alarm & BIT(index))); +} + +static ssize_t +clear_fan_alarm(struct device *dev, struct device_attribute *devattr, + const char *buf, size_t count) +{ + struct fts_data *data = dev_get_drvdata(dev); + int index = to_sensor_dev_attr(devattr)->index; + long ret; + + ret = fts_update_device(data); + if (ret < 0) + return ret; + + if (kstrtoul(buf, 10, &ret) || ret != 0) + return -EINVAL; + + mutex_lock(&data->update_lock); + ret = fts_read_byte(data->client, FTS_REG_FAN_CONTROL(index)); + if (ret < 0) + goto error; + + ret = fts_write_byte(data->client, FTS_REG_FAN_CONTROL(index), + ret | 0x1); + if (ret < 0) + goto error; + + data->valid = false; +error: + mutex_unlock(&data->update_lock); + return ret; +} + +/*****************************************************************************/ +/* SysFS structs */ +/*****************************************************************************/ + +/* Temprature sensors */ +static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp_value, NULL, 0); +static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_temp_value, NULL, 1); +static SENSOR_DEVICE_ATTR(temp3_input, S_IRUGO, show_temp_value, NULL, 2); +static SENSOR_DEVICE_ATTR(temp4_input, S_IRUGO, show_temp_value, NULL, 3); +static SENSOR_DEVICE_ATTR(temp5_input, S_IRUGO, show_temp_value, NULL, 4); +static SENSOR_DEVICE_ATTR(temp6_input, S_IRUGO, show_temp_value, NULL, 5); +static SENSOR_DEVICE_ATTR(temp7_input, S_IRUGO, show_temp_value, NULL, 6); +static SENSOR_DEVICE_ATTR(temp8_input, S_IRUGO, show_temp_value, NULL, 7); +static SENSOR_DEVICE_ATTR(temp9_input, S_IRUGO, show_temp_value, NULL, 8); +static SENSOR_DEVICE_ATTR(temp10_input, S_IRUGO, show_temp_value, NULL, 9); +static SENSOR_DEVICE_ATTR(temp11_input, S_IRUGO, show_temp_value, NULL, 10); +static SENSOR_DEVICE_ATTR(temp12_input, S_IRUGO, show_temp_value, NULL, 11); +static SENSOR_DEVICE_ATTR(temp13_input, S_IRUGO, show_temp_value, NULL, 12); +static SENSOR_DEVICE_ATTR(temp14_input, S_IRUGO, show_temp_value, NULL, 13); +static SENSOR_DEVICE_ATTR(temp15_input, S_IRUGO, show_temp_value, NULL, 14); +static SENSOR_DEVICE_ATTR(temp16_input, S_IRUGO, show_temp_value, NULL, 15); + +static SENSOR_DEVICE_ATTR(temp1_fault, S_IRUGO, show_temp_fault, NULL, 0); +static SENSOR_DEVICE_ATTR(temp2_fault, S_IRUGO, show_temp_fault, NULL, 1); +static SENSOR_DEVICE_ATTR(temp3_fault, S_IRUGO, show_temp_fault, NULL, 2); +static SENSOR_DEVICE_ATTR(temp4_fault, S_IRUGO, show_temp_fault, NULL, 3); +static SENSOR_DEVICE_ATTR(temp5_fault, S_IRUGO, show_temp_fault, NULL, 4); +static SENSOR_DEVICE_ATTR(temp6_fault, S_IRUGO, show_temp_fault, NULL, 5); +static SENSOR_DEVICE_ATTR(temp7_fault, S_IRUGO, show_temp_fault, NULL, 6); +static SENSOR_DEVICE_ATTR(temp8_fault, S_IRUGO, show_temp_fault, NULL, 7); +static SENSOR_DEVICE_ATTR(temp9_fault, S_IRUGO, show_temp_fault, NULL, 8); +static SENSOR_DEVICE_ATTR(temp10_fault, S_IRUGO, show_temp_fault, NULL, 9); +static SENSOR_DEVICE_ATTR(temp11_fault, S_IRUGO, show_temp_fault, NULL, 10); +static SENSOR_DEVICE_ATTR(temp12_fault, S_IRUGO, show_temp_fault, NULL, 11); +static SENSOR_DEVICE_ATTR(temp13_fault, S_IRUGO, show_temp_fault, NULL, 12); +static SENSOR_DEVICE_ATTR(temp14_fault, S_IRUGO, show_temp_fault, NULL, 13); +static SENSOR_DEVICE_ATTR(temp15_fault, S_IRUGO, show_temp_fault, NULL, 14); +static SENSOR_DEVICE_ATTR(temp16_fault, S_IRUGO, show_temp_fault, NULL, 15); + +static SENSOR_DEVICE_ATTR(temp1_alarm, S_IRUGO | S_IWUSR, show_temp_alarm, + clear_temp_alarm, 0); +static SENSOR_DEVICE_ATTR(temp2_alarm, S_IRUGO | S_IWUSR, show_temp_alarm, + clear_temp_alarm, 1); +static SENSOR_DEVICE_ATTR(temp3_alarm, S_IRUGO | S_IWUSR, show_temp_alarm, + clear_temp_alarm, 2); +static SENSOR_DEVICE_ATTR(temp4_alarm, S_IRUGO | S_IWUSR, show_temp_alarm, + clear_temp_alarm, 3); +static SENSOR_DEVICE_ATTR(temp5_alarm, S_IRUGO | S_IWUSR, show_temp_alarm, + clear_temp_alarm, 4); +static SENSOR_DEVICE_ATTR(temp6_alarm, S_IRUGO | S_IWUSR, show_temp_alarm, + clear_temp_alarm, 5); +static SENSOR_DEVICE_ATTR(temp7_alarm, S_IRUGO | S_IWUSR, show_temp_alarm, + clear_temp_alarm, 6); +static SENSOR_DEVICE_ATTR(temp8_alarm, S_IRUGO | S_IWUSR, show_temp_alarm, + clear_temp_alarm, 7); +static SENSOR_DEVICE_ATTR(temp9_alarm, S_IRUGO | S_IWUSR, show_temp_alarm, + clear_temp_alarm, 8); +static SENSOR_DEVICE_ATTR(temp10_alarm, S_IRUGO | S_IWUSR, show_temp_alarm, + clear_temp_alarm, 9); +static SENSOR_DEVICE_ATTR(temp11_alarm, S_IRUGO | S_IWUSR, show_temp_alarm, + clear_temp_alarm, 10); +static SENSOR_DEVICE_ATTR(temp12_alarm, S_IRUGO | S_IWUSR, show_temp_alarm, + clear_temp_alarm, 11); +static SENSOR_DEVICE_ATTR(temp13_alarm, S_IRUGO | S_IWUSR, show_temp_alarm, + clear_temp_alarm, 12); +static SENSOR_DEVICE_ATTR(temp14_alarm, S_IRUGO | S_IWUSR, show_temp_alarm, + clear_temp_alarm, 13); +static SENSOR_DEVICE_ATTR(temp15_alarm, S_IRUGO | S_IWUSR, show_temp_alarm, + clear_temp_alarm, 14); +static SENSOR_DEVICE_ATTR(temp16_alarm, S_IRUGO | S_IWUSR, show_temp_alarm, + clear_temp_alarm, 15); + +static struct attribute *fts_temp_attrs[] = { + &sensor_dev_attr_temp1_input.dev_attr.attr, + &sensor_dev_attr_temp2_input.dev_attr.attr, + &sensor_dev_attr_temp3_input.dev_attr.attr, + &sensor_dev_attr_temp4_input.dev_attr.attr, + &sensor_dev_attr_temp5_input.dev_attr.attr, + &sensor_dev_attr_temp6_input.dev_attr.attr, + &sensor_dev_attr_temp7_input.dev_attr.attr, + &sensor_dev_attr_temp8_input.dev_attr.attr, + &sensor_dev_attr_temp9_input.dev_attr.attr, + &sensor_dev_attr_temp10_input.dev_attr.attr, + &sensor_dev_attr_temp11_input.dev_attr.attr, + &sensor_dev_attr_temp12_input.dev_attr.attr, + &sensor_dev_attr_temp13_input.dev_attr.attr, + &sensor_dev_attr_temp14_input.dev_attr.attr, + &sensor_dev_attr_temp15_input.dev_attr.attr, + &sensor_dev_attr_temp16_input.dev_attr.attr, + + &sensor_dev_attr_temp1_fault.dev_attr.attr, + &sensor_dev_attr_temp2_fault.dev_attr.attr, + &sensor_dev_attr_temp3_fault.dev_attr.attr, + &sensor_dev_attr_temp4_fault.dev_attr.attr, + &sensor_dev_attr_temp5_fault.dev_attr.attr, + &sensor_dev_attr_temp6_fault.dev_attr.attr, + &sensor_dev_attr_temp7_fault.dev_attr.attr, + &sensor_dev_attr_temp8_fault.dev_attr.attr, + &sensor_dev_attr_temp9_fault.dev_attr.attr, + &sensor_dev_attr_temp10_fault.dev_attr.attr, + &sensor_dev_attr_temp11_fault.dev_attr.attr, + &sensor_dev_attr_temp12_fault.dev_attr.attr, + &sensor_dev_attr_temp13_fault.dev_attr.attr, + &sensor_dev_attr_temp14_fault.dev_attr.attr, + &sensor_dev_attr_temp15_fault.dev_attr.attr, + &sensor_dev_attr_temp16_fault.dev_attr.attr, + + &sensor_dev_attr_temp1_alarm.dev_attr.attr, + &sensor_dev_attr_temp2_alarm.dev_attr.attr, + &sensor_dev_attr_temp3_alarm.dev_attr.attr, + &sensor_dev_attr_temp4_alarm.dev_attr.attr, + &sensor_dev_attr_temp5_alarm.dev_attr.attr, + &sensor_dev_attr_temp6_alarm.dev_attr.attr, + &sensor_dev_attr_temp7_alarm.dev_attr.attr, + &sensor_dev_attr_temp8_alarm.dev_attr.attr, + &sensor_dev_attr_temp9_alarm.dev_attr.attr, + &sensor_dev_attr_temp10_alarm.dev_attr.attr, + &sensor_dev_attr_temp11_alarm.dev_attr.attr, + &sensor_dev_attr_temp12_alarm.dev_attr.attr, + &sensor_dev_attr_temp13_alarm.dev_attr.attr, + &sensor_dev_attr_temp14_alarm.dev_attr.attr, + &sensor_dev_attr_temp15_alarm.dev_attr.attr, + &sensor_dev_attr_temp16_alarm.dev_attr.attr, + NULL +}; + +/* Fans */ +static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, show_fan_value, NULL, 0); +static SENSOR_DEVICE_ATTR(fan2_input, S_IRUGO, show_fan_value, NULL, 1); +static SENSOR_DEVICE_ATTR(fan3_input, S_IRUGO, show_fan_value, NULL, 2); +static SENSOR_DEVICE_ATTR(fan4_input, S_IRUGO, show_fan_value, NULL, 3); +static SENSOR_DEVICE_ATTR(fan5_input, S_IRUGO, show_fan_value, NULL, 4); +static SENSOR_DEVICE_ATTR(fan6_input, S_IRUGO, show_fan_value, NULL, 5); +static SENSOR_DEVICE_ATTR(fan7_input, S_IRUGO, show_fan_value, NULL, 6); +static SENSOR_DEVICE_ATTR(fan8_input, S_IRUGO, show_fan_value, NULL, 7); + +static SENSOR_DEVICE_ATTR(fan1_source, S_IRUGO, show_fan_source, NULL, 0); +static SENSOR_DEVICE_ATTR(fan2_source, S_IRUGO, show_fan_source, NULL, 1); +static SENSOR_DEVICE_ATTR(fan3_source, S_IRUGO, show_fan_source, NULL, 2); +static SENSOR_DEVICE_ATTR(fan4_source, S_IRUGO, show_fan_source, NULL, 3); +static SENSOR_DEVICE_ATTR(fan5_source, S_IRUGO, show_fan_source, NULL, 4); +static SENSOR_DEVICE_ATTR(fan6_source, S_IRUGO, show_fan_source, NULL, 5); +static SENSOR_DEVICE_ATTR(fan7_source, S_IRUGO, show_fan_source, NULL, 6); +static SENSOR_DEVICE_ATTR(fan8_source, S_IRUGO, show_fan_source, NULL, 7); + +static SENSOR_DEVICE_ATTR(fan1_alarm, S_IRUGO | S_IWUSR, + show_fan_alarm, clear_fan_alarm, 0); +static SENSOR_DEVICE_ATTR(fan2_alarm, S_IRUGO | S_IWUSR, + show_fan_alarm, clear_fan_alarm, 1); +static SENSOR_DEVICE_ATTR(fan3_alarm, S_IRUGO | S_IWUSR, + show_fan_alarm, clear_fan_alarm, 2); +static SENSOR_DEVICE_ATTR(fan4_alarm, S_IRUGO | S_IWUSR, + show_fan_alarm, clear_fan_alarm, 3); +static SENSOR_DEVICE_ATTR(fan5_alarm, S_IRUGO | S_IWUSR, + show_fan_alarm, clear_fan_alarm, 4); +static SENSOR_DEVICE_ATTR(fan6_alarm, S_IRUGO | S_IWUSR, + show_fan_alarm, clear_fan_alarm, 5); +static SENSOR_DEVICE_ATTR(fan7_alarm, S_IRUGO | S_IWUSR, + show_fan_alarm, clear_fan_alarm, 6); +static SENSOR_DEVICE_ATTR(fan8_alarm, S_IRUGO | S_IWUSR, + show_fan_alarm, clear_fan_alarm, 7); + +static struct attribute *fts_fan_attrs[] = { + &sensor_dev_attr_fan1_input.dev_attr.attr, + &sensor_dev_attr_fan2_input.dev_attr.attr, + &sensor_dev_attr_fan3_input.dev_attr.attr, + &sensor_dev_attr_fan4_input.dev_attr.attr, + &sensor_dev_attr_fan5_input.dev_attr.attr, + &sensor_dev_attr_fan6_input.dev_attr.attr, + &sensor_dev_attr_fan7_input.dev_attr.attr, + &sensor_dev_attr_fan8_input.dev_attr.attr, + + &sensor_dev_attr_fan1_source.dev_attr.attr, + &sensor_dev_attr_fan2_source.dev_attr.attr, + &sensor_dev_attr_fan3_source.dev_attr.attr, + &sensor_dev_attr_fan4_source.dev_attr.attr, + &sensor_dev_attr_fan5_source.dev_attr.attr, + &sensor_dev_attr_fan6_source.dev_attr.attr, + &sensor_dev_attr_fan7_source.dev_attr.attr, + &sensor_dev_attr_fan8_source.dev_attr.attr, + + &sensor_dev_attr_fan1_alarm.dev_attr.attr, + &sensor_dev_attr_fan2_alarm.dev_attr.attr, + &sensor_dev_attr_fan3_alarm.dev_attr.attr, + &sensor_dev_attr_fan4_alarm.dev_attr.attr, + &sensor_dev_attr_fan5_alarm.dev_attr.attr, + &sensor_dev_attr_fan6_alarm.dev_attr.attr, + &sensor_dev_attr_fan7_alarm.dev_attr.attr, + &sensor_dev_attr_fan8_alarm.dev_attr.attr, + NULL +}; + +/* Voltages */ +static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, show_in_value, NULL, 0); +static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, show_in_value, NULL, 1); +static SENSOR_DEVICE_ATTR(in3_input, S_IRUGO, show_in_value, NULL, 2); +static SENSOR_DEVICE_ATTR(in4_input, S_IRUGO, show_in_value, NULL, 3); +static struct attribute *fts_voltage_attrs[] = { + &sensor_dev_attr_in1_input.dev_attr.attr, + &sensor_dev_attr_in2_input.dev_attr.attr, + &sensor_dev_attr_in3_input.dev_attr.attr, + &sensor_dev_attr_in4_input.dev_attr.attr, + NULL +}; + +static const struct attribute_group fts_voltage_attr_group = { + .attrs = fts_voltage_attrs +}; + +static const struct attribute_group fts_temp_attr_group = { + .attrs = fts_temp_attrs +}; + +static const struct attribute_group fts_fan_attr_group = { + .attrs = fts_fan_attrs +}; + +static const struct attribute_group *fts_attr_groups[] = { + &fts_voltage_attr_group, + &fts_temp_attr_group, + &fts_fan_attr_group, + NULL +}; + +/*****************************************************************************/ +/* Module initialization / remove functions */ +/*****************************************************************************/ +static int fts_remove(struct i2c_client *client) +{ + struct fts_data *data = dev_get_drvdata(&client->dev); + + watchdog_unregister_device(&data->wdd); + return 0; +} + +static int fts_probe(struct i2c_client *client, const struct i2c_device_id *id) +{ + u8 revision; + struct fts_data *data; + int err; + s8 deviceid; + struct device *hwmon_dev; + + if (client->addr != 0x73) + return -ENODEV; + + /* Baseboard Management Controller check */ + deviceid = i2c_smbus_read_byte_data(client, FTS_DEVICE_ID_REG); + if (deviceid > 0 && (deviceid & 0xF0) == 0x10) { + switch (deviceid & 0x0F) { + case 0x01: + break; + default: + dev_dbg(&client->dev, + "No Baseboard Management Controller\n"); + return -ENODEV; + } + } else { + dev_dbg(&client->dev, "No fujitsu board\n"); + return -ENODEV; + } + + data = devm_kzalloc(&client->dev, sizeof(struct fts_data), + GFP_KERNEL); + if (!data) + return -ENOMEM; + + mutex_init(&data->update_lock); + mutex_init(&data->access_lock); + data->client = client; + dev_set_drvdata(&client->dev, data); + + err = i2c_smbus_read_byte_data(client, FTS_DEVICE_REVISION_REG); + if (err < 0) + return err; + revision = err; + + hwmon_dev = devm_hwmon_device_register_with_groups(&client->dev, + "ftsteutates", + data, + fts_attr_groups); + if (IS_ERR(hwmon_dev)) + return PTR_ERR(hwmon_dev); + + err = fts_watchdog_init(data); + if (err) + return err; + + dev_info(&client->dev, "Detected FTS Teutates chip, revision: %d.%d\n", + (revision & 0xF0) >> 4, revision & 0x0F); + return 0; +} + +/*****************************************************************************/ +/* Module Details */ +/*****************************************************************************/ +static struct i2c_driver fts_driver = { + .driver = { + .name = "ftsteutates", + }, + .id_table = fts_id, + .probe = fts_probe, + .remove = fts_remove, +}; + +module_i2c_driver(fts_driver); + +MODULE_AUTHOR("Thilo Cestonaro "); +MODULE_DESCRIPTION("FTS Teutates driver"); +MODULE_LICENSE("GPL"); -- cgit v0.10.2 From b53893aae441a034bf4dbbad42fe218561d7d81f Mon Sep 17 00:00:00 2001 From: Michael Walle Date: Tue, 19 Jul 2016 16:43:26 +0200 Subject: hwmon: (adt7411) set bit 3 in CFG1 register According to the datasheet you should only write 1 to this bit. If it is not set, at least AIN3 will return bad values on newer silicon revisions. Fixes: d84ca5b345c2 ("hwmon: Add driver for ADT7411 voltage and temperature sensor") Signed-off-by: Michael Walle Signed-off-by: Guenter Roeck diff --git a/drivers/hwmon/adt7411.c b/drivers/hwmon/adt7411.c index 827c037..a7f8869 100644 --- a/drivers/hwmon/adt7411.c +++ b/drivers/hwmon/adt7411.c @@ -30,6 +30,7 @@ #define ADT7411_REG_CFG1 0x18 #define ADT7411_CFG1_START_MONITOR (1 << 0) +#define ADT7411_CFG1_RESERVED_BIT3 (1 << 3) #define ADT7411_REG_CFG2 0x19 #define ADT7411_CFG2_DISABLE_AVG (1 << 5) @@ -296,8 +297,10 @@ static int adt7411_probe(struct i2c_client *client, mutex_init(&data->device_lock); mutex_init(&data->update_lock); + /* According to the datasheet, we must only write 1 to bit 3 */ ret = adt7411_modify_bit(client, ADT7411_REG_CFG1, - ADT7411_CFG1_START_MONITOR, 1); + ADT7411_CFG1_RESERVED_BIT3 + | ADT7411_CFG1_START_MONITOR, 1); if (ret < 0) return ret; -- cgit v0.10.2 From c55374cd862e3b42831c6001cbd9d28b0e182ed4 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Wed, 20 Jul 2016 12:06:16 +0000 Subject: hwmon: (ftsteutates) Remove unused including Remove including that don't need it. Signed-off-by: Wei Yongjun Signed-off-by: Guenter Roeck diff --git a/drivers/hwmon/ftsteutates.c b/drivers/hwmon/ftsteutates.c index aaef5b5..2b2ff67 100644 --- a/drivers/hwmon/ftsteutates.c +++ b/drivers/hwmon/ftsteutates.c @@ -27,7 +27,6 @@ #include #include #include -#include #include #define FTS_DEVICE_ID_REG 0x0000 -- cgit v0.10.2 From 882b0f2fba83374149f0a5869d95aa8b44dad31e Mon Sep 17 00:00:00 2001 From: Saeed Mahameed Date: Thu, 21 Jul 2016 00:39:53 +0300 Subject: net/mlx5e: Fix del vxlan port command buffer memset memset the command buffers rather than the pointers to them. Fixes: b3f63c3d5e2c ("net/mlx5e: Add netdev support for VXLAN tunneling") Signed-off-by: Saeed Mahameed Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/mellanox/mlx5/core/vxlan.c b/drivers/net/ethernet/mellanox/mlx5/core/vxlan.c index 05de772..e25a73ed 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/vxlan.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/vxlan.c @@ -72,8 +72,8 @@ static int mlx5e_vxlan_core_del_port_cmd(struct mlx5_core_dev *mdev, u16 port) u32 in[MLX5_ST_SZ_DW(delete_vxlan_udp_dport_in)]; u32 out[MLX5_ST_SZ_DW(delete_vxlan_udp_dport_out)]; - memset(&in, 0, sizeof(in)); - memset(&out, 0, sizeof(out)); + memset(in, 0, sizeof(in)); + memset(out, 0, sizeof(out)); MLX5_SET(delete_vxlan_udp_dport_in, in, opcode, MLX5_CMD_OP_DELETE_VXLAN_UDP_DPORT); -- cgit v0.10.2 From 510cccb5b0c8868a2b302a0ab524da7912da648b Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Mon, 27 Jun 2016 14:12:34 -0700 Subject: tty/vt/keyboard: fix OOB access in do_compute_shiftstate() The size of individual keymap in drivers/tty/vt/keyboard.c is NR_KEYS, which is currently 256, whereas number of keys/buttons in input device (and therefor in key_down) is much larger - KEY_CNT - 768, and that can cause out-of-bound access when we do sym = U(key_maps[0][k]); with large 'k'. To fix it we should not attempt iterating beyond smaller of NR_KEYS and KEY_CNT. Also while at it let's switch to for_each_set_bit() instead of open-coding it. Reported-by: Sasha Levin Reviewed-by: Guenter Roeck Cc: stable@vger.kernel.org Signed-off-by: Dmitry Torokhov diff --git a/drivers/tty/vt/keyboard.c b/drivers/tty/vt/keyboard.c index f973bfc..1e93a37 100644 --- a/drivers/tty/vt/keyboard.c +++ b/drivers/tty/vt/keyboard.c @@ -366,34 +366,22 @@ static void to_utf8(struct vc_data *vc, uint c) static void do_compute_shiftstate(void) { - unsigned int i, j, k, sym, val; + unsigned int k, sym, val; shift_state = 0; memset(shift_down, 0, sizeof(shift_down)); - for (i = 0; i < ARRAY_SIZE(key_down); i++) { - - if (!key_down[i]) + for_each_set_bit(k, key_down, min(NR_KEYS, KEY_CNT)) { + sym = U(key_maps[0][k]); + if (KTYP(sym) != KT_SHIFT && KTYP(sym) != KT_SLOCK) continue; - k = i * BITS_PER_LONG; - - for (j = 0; j < BITS_PER_LONG; j++, k++) { - - if (!test_bit(k, key_down)) - continue; + val = KVAL(sym); + if (val == KVAL(K_CAPSSHIFT)) + val = KVAL(K_SHIFT); - sym = U(key_maps[0][k]); - if (KTYP(sym) != KT_SHIFT && KTYP(sym) != KT_SLOCK) - continue; - - val = KVAL(sym); - if (val == KVAL(K_CAPSSHIFT)) - val = KVAL(K_SHIFT); - - shift_down[val]++; - shift_state |= (1 << val); - } + shift_down[val]++; + shift_state |= BIT(val); } } -- cgit v0.10.2 From e9003c9cfaa17d26991688268b04244adb67ee2b Mon Sep 17 00:00:00 2001 From: Michael Welling Date: Wed, 20 Jul 2016 10:02:07 -0700 Subject: Input: tsc200x - report proper input_dev name MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Passes input_id struct to the common probe function for the tsc200x drivers instead of just the bustype. This allows for the use of the product variable to set the input_dev->name variable according to the type of touchscreen used. Note that when we introduced support for TSC2004 we started calling everything TSC200X, so let's keep this quirk. Signed-off-by: Michael Welling Cc: stable@vger.kernel.org Acked-by: Pavel Machek Acked-by: Pali Rohár Signed-off-by: Dmitry Torokhov diff --git a/drivers/input/touchscreen/tsc2004.c b/drivers/input/touchscreen/tsc2004.c index 7295c19..6fe55d5 100644 --- a/drivers/input/touchscreen/tsc2004.c +++ b/drivers/input/touchscreen/tsc2004.c @@ -22,6 +22,11 @@ #include #include "tsc200x-core.h" +static const struct input_id tsc2004_input_id = { + .bustype = BUS_I2C, + .product = 2004, +}; + static int tsc2004_cmd(struct device *dev, u8 cmd) { u8 tx = TSC200X_CMD | TSC200X_CMD_12BIT | cmd; @@ -42,7 +47,7 @@ static int tsc2004_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { - return tsc200x_probe(&i2c->dev, i2c->irq, BUS_I2C, + return tsc200x_probe(&i2c->dev, i2c->irq, &tsc2004_input_id, devm_regmap_init_i2c(i2c, &tsc200x_regmap_config), tsc2004_cmd); } diff --git a/drivers/input/touchscreen/tsc2005.c b/drivers/input/touchscreen/tsc2005.c index b9f593d..f2c5f0e 100644 --- a/drivers/input/touchscreen/tsc2005.c +++ b/drivers/input/touchscreen/tsc2005.c @@ -24,6 +24,11 @@ #include #include "tsc200x-core.h" +static const struct input_id tsc2005_input_id = { + .bustype = BUS_SPI, + .product = 2005, +}; + static int tsc2005_cmd(struct device *dev, u8 cmd) { u8 tx = TSC200X_CMD | TSC200X_CMD_12BIT | cmd; @@ -62,7 +67,7 @@ static int tsc2005_probe(struct spi_device *spi) if (error) return error; - return tsc200x_probe(&spi->dev, spi->irq, BUS_SPI, + return tsc200x_probe(&spi->dev, spi->irq, &tsc2005_input_id, devm_regmap_init_spi(spi, &tsc200x_regmap_config), tsc2005_cmd); } diff --git a/drivers/input/touchscreen/tsc200x-core.c b/drivers/input/touchscreen/tsc200x-core.c index 15240c1..dfa7f1c 100644 --- a/drivers/input/touchscreen/tsc200x-core.c +++ b/drivers/input/touchscreen/tsc200x-core.c @@ -450,7 +450,7 @@ static void tsc200x_close(struct input_dev *input) mutex_unlock(&ts->mutex); } -int tsc200x_probe(struct device *dev, int irq, __u16 bustype, +int tsc200x_probe(struct device *dev, int irq, const struct input_id *tsc_id, struct regmap *regmap, int (*tsc200x_cmd)(struct device *dev, u8 cmd)) { @@ -547,9 +547,18 @@ int tsc200x_probe(struct device *dev, int irq, __u16 bustype, snprintf(ts->phys, sizeof(ts->phys), "%s/input-ts", dev_name(dev)); - input_dev->name = "TSC200X touchscreen"; + if (tsc_id->product == 2004) { + input_dev->name = "TSC200X touchscreen"; + } else { + input_dev->name = devm_kasprintf(dev, GFP_KERNEL, + "TSC%04d touchscreen", + tsc_id->product); + if (!input_dev->name) + return -ENOMEM; + } + input_dev->phys = ts->phys; - input_dev->id.bustype = bustype; + input_dev->id = *tsc_id; input_dev->dev.parent = dev; input_dev->evbit[0] = BIT(EV_ABS) | BIT(EV_KEY); input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH); diff --git a/drivers/input/touchscreen/tsc200x-core.h b/drivers/input/touchscreen/tsc200x-core.h index 7a482d1..49a63a3 100644 --- a/drivers/input/touchscreen/tsc200x-core.h +++ b/drivers/input/touchscreen/tsc200x-core.h @@ -70,7 +70,7 @@ extern const struct regmap_config tsc200x_regmap_config; extern const struct dev_pm_ops tsc200x_pm_ops; -int tsc200x_probe(struct device *dev, int irq, __u16 bustype, +int tsc200x_probe(struct device *dev, int irq, const struct input_id *tsc_id, struct regmap *regmap, int (*tsc200x_cmd)(struct device *dev, u8 cmd)); int tsc200x_remove(struct device *dev); -- cgit v0.10.2 From 81dc0365cfa7bc7c08a0e44d9ee04964df782e19 Mon Sep 17 00:00:00 2001 From: Jan Stancek Date: Thu, 30 Jun 2016 12:23:51 +0200 Subject: crypto: qat - make qat_asym_algs.o depend on asn1 headers Parallel build can sporadically fail because asn1 headers may not be built yet by the time qat_asym_algs.o is compiled: drivers/crypto/qat/qat_common/qat_asym_algs.c:55:32: fatal error: qat_rsapubkey-asn1.h: No such file or directory #include "qat_rsapubkey-asn1.h" Cc: stable@vger.kernel.org Signed-off-by: Jan Stancek Signed-off-by: Herbert Xu diff --git a/drivers/crypto/qat/qat_common/Makefile b/drivers/crypto/qat/qat_common/Makefile index 6d74b91..5fc3dbb 100644 --- a/drivers/crypto/qat/qat_common/Makefile +++ b/drivers/crypto/qat/qat_common/Makefile @@ -2,6 +2,7 @@ $(obj)/qat_rsapubkey-asn1.o: $(obj)/qat_rsapubkey-asn1.c \ $(obj)/qat_rsapubkey-asn1.h $(obj)/qat_rsaprivkey-asn1.o: $(obj)/qat_rsaprivkey-asn1.c \ $(obj)/qat_rsaprivkey-asn1.h +$(obj)/qat_asym_algs.o: $(obj)/qat_rsapubkey-asn1.h $(obj)/qat_rsaprivkey-asn1.h clean-files += qat_rsapubkey-asn1.c qat_rsapubkey-asn1.h clean-files += qat_rsaprivkey-asn1.c qat_rsaprivkey-asn1.h -- cgit v0.10.2 From edce21216a8887bf06ba85ee49a00695e44c4341 Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Thu, 21 Jul 2016 09:53:52 +0200 Subject: x86/boot: Reorganize and clean up the BIOS area reservation code So the reserve_ebda_region() code has accumulated a number of problems over the years that make it really difficult to read and understand: - The calculation of 'lowmem' and 'ebda_addr' is an unnecessarily interleaved mess of first lowmem, then ebda_addr, then lowmem tweaks... - 'lowmem' here means 'super low mem' - i.e. 16-bit addressable memory. In other parts of the x86 code 'lowmem' means 32-bit addressable memory... This makes it super confusing to read. - It does not help at all that we have various memory range markers, half of which are 'start of range', half of which are 'end of range' - but this crucial property is not obvious in the naming at all ... gave me a headache trying to understand all this. - Also, the 'ebda_addr' name sucks: it highlights that it's an address (which is obvious, all values here are addresses!), while it does not highlight that it's the _start_ of the EBDA region ... - 'BIOS_LOWMEM_KILOBYTES' says a lot of things, except that this is the only value that is a pointer to a value, not a memory range address! - The function name itself is a misnomer: it says 'reserve_ebda_region()' while its main purpose is to reserve all the firmware ROM typically between 640K and 1MB, while the 'EBDA' part is only a small part of that ... - Likewise, the paravirt quirk flag name 'ebda_search' is misleading as well: this too should be about whether to reserve firmware areas in the paravirt case. - In fact thinking about this as 'end of RAM' is confusing: what this function *really* wants to reserve is firmware data and code areas! Once the thinking is inverted from a mixed 'ram' and 'reserved firmware area' notion to a pure 'reserved area' notion everything becomes a lot clearer. To improve all this rewrite the whole code (without changing the logic): - Firstly invert the naming from 'lowmem end' to 'BIOS reserved area start' and propagate this concept through all the variable names and constants. BIOS_RAM_SIZE_KB_PTR // was: BIOS_LOWMEM_KILOBYTES BIOS_START_MIN // was: INSANE_CUTOFF ebda_start // was: ebda_addr bios_start // was: lowmem BIOS_START_MAX // was: LOWMEM_CAP - Then clean up the name of the function itself by renaming it to reserve_bios_regions() and renaming the ::ebda_search paravirt flag to ::reserve_bios_regions. - Fix up all the comments (fix typos), harmonize and simplify their formulation and remove comments that become unnecessary due to the much better naming all around. Signed-off-by: Ingo Molnar diff --git a/arch/x86/include/asm/bios_ebda.h b/arch/x86/include/asm/bios_ebda.h index 2b00c77..4b7b8e7 100644 --- a/arch/x86/include/asm/bios_ebda.h +++ b/arch/x86/include/asm/bios_ebda.h @@ -17,7 +17,7 @@ static inline unsigned int get_bios_ebda(void) return address; /* 0 means none */ } -void reserve_ebda_region(void); +void reserve_bios_regions(void); #ifdef CONFIG_X86_CHECK_BIOS_CORRUPTION /* diff --git a/arch/x86/include/asm/x86_init.h b/arch/x86/include/asm/x86_init.h index 4dcdf74..c519c05 100644 --- a/arch/x86/include/asm/x86_init.h +++ b/arch/x86/include/asm/x86_init.h @@ -168,14 +168,14 @@ struct x86_legacy_devices { * struct x86_legacy_features - legacy x86 features * * @rtc: this device has a CMOS real-time clock present - * @ebda_search: it's safe to search for the EBDA signature in the hardware's + * @reserve_bios_regions: it's safe to search for the EBDA signature in the hardware's * low RAM * @devices: legacy x86 devices, refer to struct x86_legacy_devices * documentation for further details. */ struct x86_legacy_features { int rtc; - int ebda_search; + int reserve_bios_regions; struct x86_legacy_devices devices; }; diff --git a/arch/x86/kernel/ebda.c b/arch/x86/kernel/ebda.c index afe65df..6219eef 100644 --- a/arch/x86/kernel/ebda.c +++ b/arch/x86/kernel/ebda.c @@ -6,66 +6,104 @@ #include /* + * This function reserves all conventional PC system BIOS related + * firmware memory areas (some of which are data, some of which + * are code), that must not be used by the kernel as available + * RAM. + * * The BIOS places the EBDA/XBDA at the top of conventional * memory, and usually decreases the reported amount of - * conventional memory (int 0x12) too. This also contains a - * workaround for Dell systems that neglect to reserve EBDA. - * The same workaround also avoids a problem with the AMD768MPX - * chipset: reserve a page before VGA to prevent PCI prefetch - * into it (errata #56). Usually the page is reserved anyways, - * unless you have no PS/2 mouse plugged in. + * conventional memory (int 0x12) too. + * + * This means that as a first approximation on most systems we can + * guess the reserved BIOS area by looking at the low BIOS RAM size + * value and assume that everything above that value (up to 1MB) is + * reserved. + * + * But life in firmware country is not that simple: + * + * - This code also contains a quirk for Dell systems that neglect + * to reserve the EBDA area in the 'RAM size' value ... + * + * - The same quirk also avoids a problem with the AMD768MPX + * chipset: reserve a page before VGA to prevent PCI prefetch + * into it (errata #56). (Usually the page is reserved anyways, + * unless you have no PS/2 mouse plugged in.) + * + * - Plus paravirt systems don't have a reliable value in the + * 'BIOS RAM size' pointer we can rely on, so we must quirk + * them too. + * + * Due to those various problems this function is deliberately + * very conservative and tries to err on the side of reserving + * too much, to not risk reserving too little. + * + * Losing a small amount of memory in the bottom megabyte is + * rarely a problem, as long as we have enough memory to install + * the SMP bootup trampoline which *must* be in this area. * - * This functions is deliberately very conservative. Losing - * memory in the bottom megabyte is rarely a problem, as long - * as we have enough memory to install the trampoline. Using - * memory that is in use by the BIOS or by some DMA device - * the BIOS didn't shut down *is* a big problem. + * Using memory that is in use by the BIOS or by some DMA device + * the BIOS didn't shut down *is* a big problem to the kernel, + * obviously. */ -#define BIOS_LOWMEM_KILOBYTES 0x413 -#define LOWMEM_CAP 0x9f000U /* Absolute maximum */ -#define INSANE_CUTOFF 0x20000U /* Less than this = insane */ +#define BIOS_RAM_SIZE_KB_PTR 0x413 -void __init reserve_ebda_region(void) +#define BIOS_START_MIN 0x20000U /* 128K, less than this is insane */ +#define BIOS_START_MAX 0x9f000U /* 640K, absolute maximum */ + +void __init reserve_bios_regions(void) { - unsigned int lowmem, ebda_addr; + unsigned int bios_start, ebda_start; /* - * To determine the position of the EBDA and the - * end of conventional memory, we need to look at - * the BIOS data area. In a paravirtual environment - * that area is absent. We'll just have to assume - * that the paravirt case can handle memory setup - * correctly, without our help. + * NOTE: In a paravirtual environment the BIOS reserved + * area is absent. We'll just have to assume that the + * paravirt case can handle memory setup correctly, + * without our help. */ - if (!x86_platform.legacy.ebda_search) + if (!x86_platform.legacy.reserve_bios_regions) return; - /* end of low (conventional) memory */ - lowmem = *(unsigned short *)__va(BIOS_LOWMEM_KILOBYTES); - lowmem <<= 10; - - /* start of EBDA area */ - ebda_addr = get_bios_ebda(); + /* Get the start address of the EBDA page: */ + ebda_start = get_bios_ebda(); /* - * Note: some old Dells seem to need 4k EBDA without - * reporting so, so just consider the memory above 0x9f000 - * to be off limits (bugzilla 2990). + * Quirk: some old Dells seem to have a 4k EBDA without + * reporting so in their BIOS RAM size value, so just + * consider the memory above 640K to be off limits + * (bugzilla 2990). + * + * We detect this case by filtering for nonsensical EBDA + * addresses below 128K, where we can assume that they + * are bogus and bump it up to a fixed 640K value: */ + if (ebda_start < BIOS_START_MIN) + ebda_start = BIOS_START_MAX; - /* If the EBDA address is below 128K, assume it is bogus */ - if (ebda_addr < INSANE_CUTOFF) - ebda_addr = LOWMEM_CAP; + /* + * BIOS RAM size is encoded in kilobytes, convert it + * to bytes to get a first guess at where the BIOS + * firmware area starts: + */ + bios_start = *(unsigned short *)__va(BIOS_RAM_SIZE_KB_PTR); + bios_start <<= 10; - /* If lowmem is less than 128K, assume it is bogus */ - if (lowmem < INSANE_CUTOFF) - lowmem = LOWMEM_CAP; + /* + * If bios_start is less than 128K, assume it is bogus + * and bump it up to 640K: + */ + if (bios_start < BIOS_START_MIN) + bios_start = BIOS_START_MAX; - /* Use the lower of the lowmem and EBDA markers as the cutoff */ - lowmem = min(lowmem, ebda_addr); - lowmem = min(lowmem, LOWMEM_CAP); /* Absolute cap */ + /* + * Use the lower of the bios_start and ebda_start + * as the starting point, but don't allow it to + * go beyond 640K: + */ + bios_start = min(bios_start, ebda_start); + bios_start = min(bios_start, BIOS_START_MAX); - /* reserve all memory between lowmem and the 1MB mark */ - memblock_reserve(lowmem, 0x100000 - lowmem); + /* Reserve all memory between bios_start and the 1MB mark: */ + memblock_reserve(bios_start, 0x100000 - bios_start); } diff --git a/arch/x86/kernel/head32.c b/arch/x86/kernel/head32.c index d784bb5..2dda0bc 100644 --- a/arch/x86/kernel/head32.c +++ b/arch/x86/kernel/head32.c @@ -26,7 +26,7 @@ static void __init i386_default_early_setup(void) x86_init.resources.reserve_resources = i386_reserve_resources; x86_init.mpparse.setup_ioapic_ids = setup_ioapic_ids_from_mpc; - reserve_ebda_region(); + reserve_bios_regions(); } asmlinkage __visible void __init i386_start_kernel(void) diff --git a/arch/x86/kernel/head64.c b/arch/x86/kernel/head64.c index b72fb0b..99d48e7 100644 --- a/arch/x86/kernel/head64.c +++ b/arch/x86/kernel/head64.c @@ -183,7 +183,7 @@ void __init x86_64_start_reservations(char *real_mode_data) copy_bootdata(__va(real_mode_data)); x86_early_init_platform_quirks(); - reserve_ebda_region(); + reserve_bios_regions(); switch (boot_params.hdr.hardware_subarch) { case X86_SUBARCH_INTEL_MID: diff --git a/arch/x86/kernel/platform-quirks.c b/arch/x86/kernel/platform-quirks.c index b2f8a33..24a5030 100644 --- a/arch/x86/kernel/platform-quirks.c +++ b/arch/x86/kernel/platform-quirks.c @@ -7,12 +7,12 @@ void __init x86_early_init_platform_quirks(void) { x86_platform.legacy.rtc = 1; - x86_platform.legacy.ebda_search = 0; + x86_platform.legacy.reserve_bios_regions = 0; x86_platform.legacy.devices.pnpbios = 1; switch (boot_params.hdr.hardware_subarch) { case X86_SUBARCH_PC: - x86_platform.legacy.ebda_search = 1; + x86_platform.legacy.reserve_bios_regions = 1; break; case X86_SUBARCH_XEN: case X86_SUBARCH_LGUEST: -- cgit v0.10.2 From 25af37f4e1e0a747824e3713b80d6b97dad28b7c Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Wed, 20 Jul 2016 11:30:35 +0300 Subject: x86/insn: Add AVX-512 support to the instruction decoder Add support for Intel's AVX-512 instructions to the instruction decoder. AVX-512 instructions are documented in Intel Architecture Instruction Set Extensions Programming Reference (February 2016). AVX-512 instructions are identified by a EVEX prefix which, for the purpose of instruction decoding, can be treated as though it were a 4-byte VEX prefix. Existing instructions which can now accept an EVEX prefix need not be further annotated in the op code map (x86-opcode-map.txt). In the case of new instructions, the op code map is updated accordingly. Also add associated Mask Instructions that are used to manipulate mask registers used in AVX-512 instructions. The 'perf tools' instruction decoder is updated in a subsequent patch. And a representative set of instructions is added to the perf tools new instructions test in a subsequent patch. Signed-off-by: Adrian Hunter Acked-by: Ingo Molnar Acked-by: Masami Hiramatsu Cc: Andy Lutomirski Cc: Dan Williams Cc: H. Peter Anvin Cc: Jiri Olsa Cc: Thomas Gleixner Cc: X86 ML Link: http://lkml.kernel.org/r/1469003437-32706-3-git-send-email-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo diff --git a/arch/x86/include/asm/inat.h b/arch/x86/include/asm/inat.h index 74a2e31..02aff08 100644 --- a/arch/x86/include/asm/inat.h +++ b/arch/x86/include/asm/inat.h @@ -48,6 +48,7 @@ /* AVX VEX prefixes */ #define INAT_PFX_VEX2 13 /* 2-bytes VEX prefix */ #define INAT_PFX_VEX3 14 /* 3-bytes VEX prefix */ +#define INAT_PFX_EVEX 15 /* EVEX prefix */ #define INAT_LSTPFX_MAX 3 #define INAT_LGCPFX_MAX 11 @@ -89,6 +90,7 @@ #define INAT_VARIANT (1 << (INAT_FLAG_OFFS + 4)) #define INAT_VEXOK (1 << (INAT_FLAG_OFFS + 5)) #define INAT_VEXONLY (1 << (INAT_FLAG_OFFS + 6)) +#define INAT_EVEXONLY (1 << (INAT_FLAG_OFFS + 7)) /* Attribute making macros for attribute tables */ #define INAT_MAKE_PREFIX(pfx) (pfx << INAT_PFX_OFFS) #define INAT_MAKE_ESCAPE(esc) (esc << INAT_ESC_OFFS) @@ -141,7 +143,13 @@ static inline int inat_last_prefix_id(insn_attr_t attr) static inline int inat_is_vex_prefix(insn_attr_t attr) { attr &= INAT_PFX_MASK; - return attr == INAT_PFX_VEX2 || attr == INAT_PFX_VEX3; + return attr == INAT_PFX_VEX2 || attr == INAT_PFX_VEX3 || + attr == INAT_PFX_EVEX; +} + +static inline int inat_is_evex_prefix(insn_attr_t attr) +{ + return (attr & INAT_PFX_MASK) == INAT_PFX_EVEX; } static inline int inat_is_vex3_prefix(insn_attr_t attr) @@ -216,6 +224,11 @@ static inline int inat_accept_vex(insn_attr_t attr) static inline int inat_must_vex(insn_attr_t attr) { - return attr & INAT_VEXONLY; + return attr & (INAT_VEXONLY | INAT_EVEXONLY); +} + +static inline int inat_must_evex(insn_attr_t attr) +{ + return attr & INAT_EVEXONLY; } #endif diff --git a/arch/x86/include/asm/insn.h b/arch/x86/include/asm/insn.h index e7814b7..b3e32b0 100644 --- a/arch/x86/include/asm/insn.h +++ b/arch/x86/include/asm/insn.h @@ -91,6 +91,7 @@ struct insn { #define X86_VEX_B(vex) ((vex) & 0x20) /* VEX3 Byte1 */ #define X86_VEX_L(vex) ((vex) & 0x04) /* VEX3 Byte2, VEX2 Byte1 */ /* VEX bit fields */ +#define X86_EVEX_M(vex) ((vex) & 0x03) /* EVEX Byte1 */ #define X86_VEX3_M(vex) ((vex) & 0x1f) /* VEX3 Byte1 */ #define X86_VEX2_M 1 /* VEX2.M always 1 */ #define X86_VEX_V(vex) (((vex) & 0x78) >> 3) /* VEX3 Byte2, VEX2 Byte1 */ @@ -133,6 +134,13 @@ static inline int insn_is_avx(struct insn *insn) return (insn->vex_prefix.value != 0); } +static inline int insn_is_evex(struct insn *insn) +{ + if (!insn->prefixes.got) + insn_get_prefixes(insn); + return (insn->vex_prefix.nbytes == 4); +} + /* Ensure this instruction is decoded completely */ static inline int insn_complete(struct insn *insn) { @@ -144,8 +152,10 @@ static inline insn_byte_t insn_vex_m_bits(struct insn *insn) { if (insn->vex_prefix.nbytes == 2) /* 2 bytes VEX */ return X86_VEX2_M; - else + else if (insn->vex_prefix.nbytes == 3) /* 3 bytes VEX */ return X86_VEX3_M(insn->vex_prefix.bytes[1]); + else /* EVEX */ + return X86_EVEX_M(insn->vex_prefix.bytes[1]); } static inline insn_byte_t insn_vex_p_bits(struct insn *insn) diff --git a/arch/x86/lib/insn.c b/arch/x86/lib/insn.c index 1a41693..1088eb8 100644 --- a/arch/x86/lib/insn.c +++ b/arch/x86/lib/insn.c @@ -155,14 +155,24 @@ found: /* * In 32-bits mode, if the [7:6] bits (mod bits of * ModRM) on the second byte are not 11b, it is - * LDS or LES. + * LDS or LES or BOUND. */ if (X86_MODRM_MOD(b2) != 3) goto vex_end; } insn->vex_prefix.bytes[0] = b; insn->vex_prefix.bytes[1] = b2; - if (inat_is_vex3_prefix(attr)) { + if (inat_is_evex_prefix(attr)) { + b2 = peek_nbyte_next(insn_byte_t, insn, 2); + insn->vex_prefix.bytes[2] = b2; + b2 = peek_nbyte_next(insn_byte_t, insn, 3); + insn->vex_prefix.bytes[3] = b2; + insn->vex_prefix.nbytes = 4; + insn->next_byte += 4; + if (insn->x86_64 && X86_VEX_W(b2)) + /* VEX.W overrides opnd_size */ + insn->opnd_bytes = 8; + } else if (inat_is_vex3_prefix(attr)) { b2 = peek_nbyte_next(insn_byte_t, insn, 2); insn->vex_prefix.bytes[2] = b2; insn->vex_prefix.nbytes = 3; @@ -221,7 +231,9 @@ void insn_get_opcode(struct insn *insn) m = insn_vex_m_bits(insn); p = insn_vex_p_bits(insn); insn->attr = inat_get_avx_attribute(op, m, p); - if (!inat_accept_vex(insn->attr) && !inat_is_group(insn->attr)) + if ((inat_must_evex(insn->attr) && !insn_is_evex(insn)) || + (!inat_accept_vex(insn->attr) && + !inat_is_group(insn->attr))) insn->attr = 0; /* This instruction is bad */ goto end; /* VEX has only 1 byte for opcode */ } diff --git a/arch/x86/lib/x86-opcode-map.txt b/arch/x86/lib/x86-opcode-map.txt index 28082de..ec378cd 100644 --- a/arch/x86/lib/x86-opcode-map.txt +++ b/arch/x86/lib/x86-opcode-map.txt @@ -13,12 +13,17 @@ # opcode: escape # escaped-name # EndTable # +# mnemonics that begin with lowercase 'v' accept a VEX or EVEX prefix +# mnemonics that begin with lowercase 'k' accept a VEX prefix +# # # GrpTable: GrpXXX # reg: mnemonic [operand1[,operand2...]] [(extra1)[,(extra2)...] [| 2nd-mnemonic ...] # EndTable # # AVX Superscripts +# (ev): this opcode requires EVEX prefix. +# (evo): this opcode is changed by EVEX prefix (EVEX opcode) # (v): this opcode requires VEX prefix. # (v1): this opcode only supports 128bit VEX. # @@ -137,7 +142,7 @@ AVXcode: # 0x60 - 0x6f 60: PUSHA/PUSHAD (i64) 61: POPA/POPAD (i64) -62: BOUND Gv,Ma (i64) +62: BOUND Gv,Ma (i64) | EVEX (Prefix) 63: ARPL Ew,Gw (i64) | MOVSXD Gv,Ev (o64) 64: SEG=FS (Prefix) 65: SEG=GS (Prefix) @@ -399,17 +404,17 @@ AVXcode: 1 3f: # 0x0f 0x40-0x4f 40: CMOVO Gv,Ev -41: CMOVNO Gv,Ev -42: CMOVB/C/NAE Gv,Ev +41: CMOVNO Gv,Ev | kandw/q Vk,Hk,Uk | kandb/d Vk,Hk,Uk (66) +42: CMOVB/C/NAE Gv,Ev | kandnw/q Vk,Hk,Uk | kandnb/d Vk,Hk,Uk (66) 43: CMOVAE/NB/NC Gv,Ev -44: CMOVE/Z Gv,Ev -45: CMOVNE/NZ Gv,Ev -46: CMOVBE/NA Gv,Ev -47: CMOVA/NBE Gv,Ev +44: CMOVE/Z Gv,Ev | knotw/q Vk,Uk | knotb/d Vk,Uk (66) +45: CMOVNE/NZ Gv,Ev | korw/q Vk,Hk,Uk | korb/d Vk,Hk,Uk (66) +46: CMOVBE/NA Gv,Ev | kxnorw/q Vk,Hk,Uk | kxnorb/d Vk,Hk,Uk (66) +47: CMOVA/NBE Gv,Ev | kxorw/q Vk,Hk,Uk | kxorb/d Vk,Hk,Uk (66) 48: CMOVS Gv,Ev 49: CMOVNS Gv,Ev -4a: CMOVP/PE Gv,Ev -4b: CMOVNP/PO Gv,Ev +4a: CMOVP/PE Gv,Ev | kaddw/q Vk,Hk,Uk | kaddb/d Vk,Hk,Uk (66) +4b: CMOVNP/PO Gv,Ev | kunpckbw Vk,Hk,Uk (66) | kunpckwd/dq Vk,Hk,Uk 4c: CMOVL/NGE Gv,Ev 4d: CMOVNL/GE Gv,Ev 4e: CMOVLE/NG Gv,Ev @@ -426,7 +431,7 @@ AVXcode: 1 58: vaddps Vps,Hps,Wps | vaddpd Vpd,Hpd,Wpd (66) | vaddss Vss,Hss,Wss (F3),(v1) | vaddsd Vsd,Hsd,Wsd (F2),(v1) 59: vmulps Vps,Hps,Wps | vmulpd Vpd,Hpd,Wpd (66) | vmulss Vss,Hss,Wss (F3),(v1) | vmulsd Vsd,Hsd,Wsd (F2),(v1) 5a: vcvtps2pd Vpd,Wps | vcvtpd2ps Vps,Wpd (66) | vcvtss2sd Vsd,Hx,Wss (F3),(v1) | vcvtsd2ss Vss,Hx,Wsd (F2),(v1) -5b: vcvtdq2ps Vps,Wdq | vcvtps2dq Vdq,Wps (66) | vcvttps2dq Vdq,Wps (F3) +5b: vcvtdq2ps Vps,Wdq | vcvtqq2ps Vps,Wqq (evo) | vcvtps2dq Vdq,Wps (66) | vcvttps2dq Vdq,Wps (F3) 5c: vsubps Vps,Hps,Wps | vsubpd Vpd,Hpd,Wpd (66) | vsubss Vss,Hss,Wss (F3),(v1) | vsubsd Vsd,Hsd,Wsd (F2),(v1) 5d: vminps Vps,Hps,Wps | vminpd Vpd,Hpd,Wpd (66) | vminss Vss,Hss,Wss (F3),(v1) | vminsd Vsd,Hsd,Wsd (F2),(v1) 5e: vdivps Vps,Hps,Wps | vdivpd Vpd,Hpd,Wpd (66) | vdivss Vss,Hss,Wss (F3),(v1) | vdivsd Vsd,Hsd,Wsd (F2),(v1) @@ -447,7 +452,7 @@ AVXcode: 1 6c: vpunpcklqdq Vx,Hx,Wx (66),(v1) 6d: vpunpckhqdq Vx,Hx,Wx (66),(v1) 6e: movd/q Pd,Ey | vmovd/q Vy,Ey (66),(v1) -6f: movq Pq,Qq | vmovdqa Vx,Wx (66) | vmovdqu Vx,Wx (F3) +6f: movq Pq,Qq | vmovdqa Vx,Wx (66) | vmovdqa32/64 Vx,Wx (66),(evo) | vmovdqu Vx,Wx (F3) | vmovdqu32/64 Vx,Wx (F3),(evo) | vmovdqu8/16 Vx,Wx (F2),(ev) # 0x0f 0x70-0x7f 70: pshufw Pq,Qq,Ib | vpshufd Vx,Wx,Ib (66),(v1) | vpshufhw Vx,Wx,Ib (F3),(v1) | vpshuflw Vx,Wx,Ib (F2),(v1) 71: Grp12 (1A) @@ -458,14 +463,14 @@ AVXcode: 1 76: pcmpeqd Pq,Qq | vpcmpeqd Vx,Hx,Wx (66),(v1) # Note: Remove (v), because vzeroall and vzeroupper becomes emms without VEX. 77: emms | vzeroupper | vzeroall -78: VMREAD Ey,Gy -79: VMWRITE Gy,Ey -7a: -7b: +78: VMREAD Ey,Gy | vcvttps2udq/pd2udq Vx,Wpd (evo) | vcvttsd2usi Gv,Wx (F2),(ev) | vcvttss2usi Gv,Wx (F3),(ev) | vcvttps2uqq/pd2uqq Vx,Wx (66),(ev) +79: VMWRITE Gy,Ey | vcvtps2udq/pd2udq Vx,Wpd (evo) | vcvtsd2usi Gv,Wx (F2),(ev) | vcvtss2usi Gv,Wx (F3),(ev) | vcvtps2uqq/pd2uqq Vx,Wx (66),(ev) +7a: vcvtudq2pd/uqq2pd Vpd,Wx (F3),(ev) | vcvtudq2ps/uqq2ps Vpd,Wx (F2),(ev) | vcvttps2qq/pd2qq Vx,Wx (66),(ev) +7b: vcvtusi2sd Vpd,Hpd,Ev (F2),(ev) | vcvtusi2ss Vps,Hps,Ev (F3),(ev) | vcvtps2qq/pd2qq Vx,Wx (66),(ev) 7c: vhaddpd Vpd,Hpd,Wpd (66) | vhaddps Vps,Hps,Wps (F2) 7d: vhsubpd Vpd,Hpd,Wpd (66) | vhsubps Vps,Hps,Wps (F2) 7e: movd/q Ey,Pd | vmovd/q Ey,Vy (66),(v1) | vmovq Vq,Wq (F3),(v1) -7f: movq Qq,Pq | vmovdqa Wx,Vx (66) | vmovdqu Wx,Vx (F3) +7f: movq Qq,Pq | vmovdqa Wx,Vx (66) | vmovdqa32/64 Wx,Vx (66),(evo) | vmovdqu Wx,Vx (F3) | vmovdqu32/64 Wx,Vx (F3),(evo) | vmovdqu8/16 Wx,Vx (F2),(ev) # 0x0f 0x80-0x8f # Note: "forced64" is Intel CPU behavior (see comment about CALL insn). 80: JO Jz (f64) @@ -485,16 +490,16 @@ AVXcode: 1 8e: JLE/JNG Jz (f64) 8f: JNLE/JG Jz (f64) # 0x0f 0x90-0x9f -90: SETO Eb -91: SETNO Eb -92: SETB/C/NAE Eb -93: SETAE/NB/NC Eb +90: SETO Eb | kmovw/q Vk,Wk | kmovb/d Vk,Wk (66) +91: SETNO Eb | kmovw/q Mv,Vk | kmovb/d Mv,Vk (66) +92: SETB/C/NAE Eb | kmovw Vk,Rv | kmovb Vk,Rv (66) | kmovq/d Vk,Rv (F2) +93: SETAE/NB/NC Eb | kmovw Gv,Uk | kmovb Gv,Uk (66) | kmovq/d Gv,Uk (F2) 94: SETE/Z Eb 95: SETNE/NZ Eb 96: SETBE/NA Eb 97: SETA/NBE Eb -98: SETS Eb -99: SETNS Eb +98: SETS Eb | kortestw/q Vk,Uk | kortestb/d Vk,Uk (66) +99: SETNS Eb | ktestw/q Vk,Uk | ktestb/d Vk,Uk (66) 9a: SETP/PE Eb 9b: SETNP/PO Eb 9c: SETL/NGE Eb @@ -564,11 +569,11 @@ d7: pmovmskb Gd,Nq | vpmovmskb Gd,Ux (66),(v1) d8: psubusb Pq,Qq | vpsubusb Vx,Hx,Wx (66),(v1) d9: psubusw Pq,Qq | vpsubusw Vx,Hx,Wx (66),(v1) da: pminub Pq,Qq | vpminub Vx,Hx,Wx (66),(v1) -db: pand Pq,Qq | vpand Vx,Hx,Wx (66),(v1) +db: pand Pq,Qq | vpand Vx,Hx,Wx (66),(v1) | vpandd/q Vx,Hx,Wx (66),(evo) dc: paddusb Pq,Qq | vpaddusb Vx,Hx,Wx (66),(v1) dd: paddusw Pq,Qq | vpaddusw Vx,Hx,Wx (66),(v1) de: pmaxub Pq,Qq | vpmaxub Vx,Hx,Wx (66),(v1) -df: pandn Pq,Qq | vpandn Vx,Hx,Wx (66),(v1) +df: pandn Pq,Qq | vpandn Vx,Hx,Wx (66),(v1) | vpandnd/q Vx,Hx,Wx (66),(evo) # 0x0f 0xe0-0xef e0: pavgb Pq,Qq | vpavgb Vx,Hx,Wx (66),(v1) e1: psraw Pq,Qq | vpsraw Vx,Hx,Wx (66),(v1) @@ -576,16 +581,16 @@ e2: psrad Pq,Qq | vpsrad Vx,Hx,Wx (66),(v1) e3: pavgw Pq,Qq | vpavgw Vx,Hx,Wx (66),(v1) e4: pmulhuw Pq,Qq | vpmulhuw Vx,Hx,Wx (66),(v1) e5: pmulhw Pq,Qq | vpmulhw Vx,Hx,Wx (66),(v1) -e6: vcvttpd2dq Vx,Wpd (66) | vcvtdq2pd Vx,Wdq (F3) | vcvtpd2dq Vx,Wpd (F2) +e6: vcvttpd2dq Vx,Wpd (66) | vcvtdq2pd Vx,Wdq (F3) | vcvtdq2pd/qq2pd Vx,Wdq (F3),(evo) | vcvtpd2dq Vx,Wpd (F2) e7: movntq Mq,Pq | vmovntdq Mx,Vx (66) e8: psubsb Pq,Qq | vpsubsb Vx,Hx,Wx (66),(v1) e9: psubsw Pq,Qq | vpsubsw Vx,Hx,Wx (66),(v1) ea: pminsw Pq,Qq | vpminsw Vx,Hx,Wx (66),(v1) -eb: por Pq,Qq | vpor Vx,Hx,Wx (66),(v1) +eb: por Pq,Qq | vpor Vx,Hx,Wx (66),(v1) | vpord/q Vx,Hx,Wx (66),(evo) ec: paddsb Pq,Qq | vpaddsb Vx,Hx,Wx (66),(v1) ed: paddsw Pq,Qq | vpaddsw Vx,Hx,Wx (66),(v1) ee: pmaxsw Pq,Qq | vpmaxsw Vx,Hx,Wx (66),(v1) -ef: pxor Pq,Qq | vpxor Vx,Hx,Wx (66),(v1) +ef: pxor Pq,Qq | vpxor Vx,Hx,Wx (66),(v1) | vpxord/q Vx,Hx,Wx (66),(evo) # 0x0f 0xf0-0xff f0: vlddqu Vx,Mx (F2) f1: psllw Pq,Qq | vpsllw Vx,Hx,Wx (66),(v1) @@ -626,81 +631,105 @@ AVXcode: 2 0e: vtestps Vx,Wx (66),(v) 0f: vtestpd Vx,Wx (66),(v) # 0x0f 0x38 0x10-0x1f -10: pblendvb Vdq,Wdq (66) -11: -12: -13: vcvtph2ps Vx,Wx (66),(v) -14: blendvps Vdq,Wdq (66) -15: blendvpd Vdq,Wdq (66) -16: vpermps Vqq,Hqq,Wqq (66),(v) +10: pblendvb Vdq,Wdq (66) | vpsrlvw Vx,Hx,Wx (66),(evo) | vpmovuswb Wx,Vx (F3),(ev) +11: vpmovusdb Wx,Vd (F3),(ev) | vpsravw Vx,Hx,Wx (66),(ev) +12: vpmovusqb Wx,Vq (F3),(ev) | vpsllvw Vx,Hx,Wx (66),(ev) +13: vcvtph2ps Vx,Wx (66),(v) | vpmovusdw Wx,Vd (F3),(ev) +14: blendvps Vdq,Wdq (66) | vpmovusqw Wx,Vq (F3),(ev) | vprorvd/q Vx,Hx,Wx (66),(evo) +15: blendvpd Vdq,Wdq (66) | vpmovusqd Wx,Vq (F3),(ev) | vprolvd/q Vx,Hx,Wx (66),(evo) +16: vpermps Vqq,Hqq,Wqq (66),(v) | vpermps/d Vqq,Hqq,Wqq (66),(evo) 17: vptest Vx,Wx (66) 18: vbroadcastss Vx,Wd (66),(v) -19: vbroadcastsd Vqq,Wq (66),(v) -1a: vbroadcastf128 Vqq,Mdq (66),(v) -1b: +19: vbroadcastsd Vqq,Wq (66),(v) | vbroadcastf32x2 Vqq,Wq (66),(evo) +1a: vbroadcastf128 Vqq,Mdq (66),(v) | vbroadcastf32x4/64x2 Vqq,Wq (66),(evo) +1b: vbroadcastf32x8/64x4 Vqq,Mdq (66),(ev) 1c: pabsb Pq,Qq | vpabsb Vx,Wx (66),(v1) 1d: pabsw Pq,Qq | vpabsw Vx,Wx (66),(v1) 1e: pabsd Pq,Qq | vpabsd Vx,Wx (66),(v1) -1f: +1f: vpabsq Vx,Wx (66),(ev) # 0x0f 0x38 0x20-0x2f -20: vpmovsxbw Vx,Ux/Mq (66),(v1) -21: vpmovsxbd Vx,Ux/Md (66),(v1) -22: vpmovsxbq Vx,Ux/Mw (66),(v1) -23: vpmovsxwd Vx,Ux/Mq (66),(v1) -24: vpmovsxwq Vx,Ux/Md (66),(v1) -25: vpmovsxdq Vx,Ux/Mq (66),(v1) -26: -27: -28: vpmuldq Vx,Hx,Wx (66),(v1) -29: vpcmpeqq Vx,Hx,Wx (66),(v1) -2a: vmovntdqa Vx,Mx (66),(v1) +20: vpmovsxbw Vx,Ux/Mq (66),(v1) | vpmovswb Wx,Vx (F3),(ev) +21: vpmovsxbd Vx,Ux/Md (66),(v1) | vpmovsdb Wx,Vd (F3),(ev) +22: vpmovsxbq Vx,Ux/Mw (66),(v1) | vpmovsqb Wx,Vq (F3),(ev) +23: vpmovsxwd Vx,Ux/Mq (66),(v1) | vpmovsdw Wx,Vd (F3),(ev) +24: vpmovsxwq Vx,Ux/Md (66),(v1) | vpmovsqw Wx,Vq (F3),(ev) +25: vpmovsxdq Vx,Ux/Mq (66),(v1) | vpmovsqd Wx,Vq (F3),(ev) +26: vptestmb/w Vk,Hx,Wx (66),(ev) | vptestnmb/w Vk,Hx,Wx (F3),(ev) +27: vptestmd/q Vk,Hx,Wx (66),(ev) | vptestnmd/q Vk,Hx,Wx (F3),(ev) +28: vpmuldq Vx,Hx,Wx (66),(v1) | vpmovm2b/w Vx,Uk (F3),(ev) +29: vpcmpeqq Vx,Hx,Wx (66),(v1) | vpmovb2m/w2m Vk,Ux (F3),(ev) +2a: vmovntdqa Vx,Mx (66),(v1) | vpbroadcastmb2q Vx,Uk (F3),(ev) 2b: vpackusdw Vx,Hx,Wx (66),(v1) -2c: vmaskmovps Vx,Hx,Mx (66),(v) -2d: vmaskmovpd Vx,Hx,Mx (66),(v) +2c: vmaskmovps Vx,Hx,Mx (66),(v) | vscalefps/d Vx,Hx,Wx (66),(evo) +2d: vmaskmovpd Vx,Hx,Mx (66),(v) | vscalefss/d Vx,Hx,Wx (66),(evo) 2e: vmaskmovps Mx,Hx,Vx (66),(v) 2f: vmaskmovpd Mx,Hx,Vx (66),(v) # 0x0f 0x38 0x30-0x3f -30: vpmovzxbw Vx,Ux/Mq (66),(v1) -31: vpmovzxbd Vx,Ux/Md (66),(v1) -32: vpmovzxbq Vx,Ux/Mw (66),(v1) -33: vpmovzxwd Vx,Ux/Mq (66),(v1) -34: vpmovzxwq Vx,Ux/Md (66),(v1) -35: vpmovzxdq Vx,Ux/Mq (66),(v1) -36: vpermd Vqq,Hqq,Wqq (66),(v) +30: vpmovzxbw Vx,Ux/Mq (66),(v1) | vpmovwb Wx,Vx (F3),(ev) +31: vpmovzxbd Vx,Ux/Md (66),(v1) | vpmovdb Wx,Vd (F3),(ev) +32: vpmovzxbq Vx,Ux/Mw (66),(v1) | vpmovqb Wx,Vq (F3),(ev) +33: vpmovzxwd Vx,Ux/Mq (66),(v1) | vpmovdw Wx,Vd (F3),(ev) +34: vpmovzxwq Vx,Ux/Md (66),(v1) | vpmovqw Wx,Vq (F3),(ev) +35: vpmovzxdq Vx,Ux/Mq (66),(v1) | vpmovqd Wx,Vq (F3),(ev) +36: vpermd Vqq,Hqq,Wqq (66),(v) | vpermd/q Vqq,Hqq,Wqq (66),(evo) 37: vpcmpgtq Vx,Hx,Wx (66),(v1) -38: vpminsb Vx,Hx,Wx (66),(v1) -39: vpminsd Vx,Hx,Wx (66),(v1) -3a: vpminuw Vx,Hx,Wx (66),(v1) -3b: vpminud Vx,Hx,Wx (66),(v1) +38: vpminsb Vx,Hx,Wx (66),(v1) | vpmovm2d/q Vx,Uk (F3),(ev) +39: vpminsd Vx,Hx,Wx (66),(v1) | vpminsd/q Vx,Hx,Wx (66),(evo) | vpmovd2m/q2m Vk,Ux (F3),(ev) +3a: vpminuw Vx,Hx,Wx (66),(v1) | vpbroadcastmw2d Vx,Uk (F3),(ev) +3b: vpminud Vx,Hx,Wx (66),(v1) | vpminud/q Vx,Hx,Wx (66),(evo) 3c: vpmaxsb Vx,Hx,Wx (66),(v1) -3d: vpmaxsd Vx,Hx,Wx (66),(v1) +3d: vpmaxsd Vx,Hx,Wx (66),(v1) | vpmaxsd/q Vx,Hx,Wx (66),(evo) 3e: vpmaxuw Vx,Hx,Wx (66),(v1) -3f: vpmaxud Vx,Hx,Wx (66),(v1) +3f: vpmaxud Vx,Hx,Wx (66),(v1) | vpmaxud/q Vx,Hx,Wx (66),(evo) # 0x0f 0x38 0x40-0x8f -40: vpmulld Vx,Hx,Wx (66),(v1) +40: vpmulld Vx,Hx,Wx (66),(v1) | vpmulld/q Vx,Hx,Wx (66),(evo) 41: vphminposuw Vdq,Wdq (66),(v1) -42: -43: -44: +42: vgetexpps/d Vx,Wx (66),(ev) +43: vgetexpss/d Vx,Hx,Wx (66),(ev) +44: vplzcntd/q Vx,Wx (66),(ev) 45: vpsrlvd/q Vx,Hx,Wx (66),(v) -46: vpsravd Vx,Hx,Wx (66),(v) +46: vpsravd Vx,Hx,Wx (66),(v) | vpsravd/q Vx,Hx,Wx (66),(evo) 47: vpsllvd/q Vx,Hx,Wx (66),(v) -# Skip 0x48-0x57 +# Skip 0x48-0x4b +4c: vrcp14ps/d Vpd,Wpd (66),(ev) +4d: vrcp14ss/d Vsd,Hpd,Wsd (66),(ev) +4e: vrsqrt14ps/d Vpd,Wpd (66),(ev) +4f: vrsqrt14ss/d Vsd,Hsd,Wsd (66),(ev) +# Skip 0x50-0x57 58: vpbroadcastd Vx,Wx (66),(v) -59: vpbroadcastq Vx,Wx (66),(v) -5a: vbroadcasti128 Vqq,Mdq (66),(v) -# Skip 0x5b-0x77 +59: vpbroadcastq Vx,Wx (66),(v) | vbroadcasti32x2 Vx,Wx (66),(evo) +5a: vbroadcasti128 Vqq,Mdq (66),(v) | vbroadcasti32x4/64x2 Vx,Wx (66),(evo) +5b: vbroadcasti32x8/64x4 Vqq,Mdq (66),(ev) +# Skip 0x5c-0x63 +64: vpblendmd/q Vx,Hx,Wx (66),(ev) +65: vblendmps/d Vx,Hx,Wx (66),(ev) +66: vpblendmb/w Vx,Hx,Wx (66),(ev) +# Skip 0x67-0x74 +75: vpermi2b/w Vx,Hx,Wx (66),(ev) +76: vpermi2d/q Vx,Hx,Wx (66),(ev) +77: vpermi2ps/d Vx,Hx,Wx (66),(ev) 78: vpbroadcastb Vx,Wx (66),(v) 79: vpbroadcastw Vx,Wx (66),(v) -# Skip 0x7a-0x7f +7a: vpbroadcastb Vx,Rv (66),(ev) +7b: vpbroadcastw Vx,Rv (66),(ev) +7c: vpbroadcastd/q Vx,Rv (66),(ev) +7d: vpermt2b/w Vx,Hx,Wx (66),(ev) +7e: vpermt2d/q Vx,Hx,Wx (66),(ev) +7f: vpermt2ps/d Vx,Hx,Wx (66),(ev) 80: INVEPT Gy,Mdq (66) 81: INVPID Gy,Mdq (66) 82: INVPCID Gy,Mdq (66) +83: vpmultishiftqb Vx,Hx,Wx (66),(ev) +88: vexpandps/d Vpd,Wpd (66),(ev) +89: vpexpandd/q Vx,Wx (66),(ev) +8a: vcompressps/d Wx,Vx (66),(ev) +8b: vpcompressd/q Wx,Vx (66),(ev) 8c: vpmaskmovd/q Vx,Hx,Mx (66),(v) +8d: vpermb/w Vx,Hx,Wx (66),(ev) 8e: vpmaskmovd/q Mx,Vx,Hx (66),(v) # 0x0f 0x38 0x90-0xbf (FMA) -90: vgatherdd/q Vx,Hx,Wx (66),(v) -91: vgatherqd/q Vx,Hx,Wx (66),(v) +90: vgatherdd/q Vx,Hx,Wx (66),(v) | vpgatherdd/q Vx,Wx (66),(evo) +91: vgatherqd/q Vx,Hx,Wx (66),(v) | vpgatherqd/q Vx,Wx (66),(evo) 92: vgatherdps/d Vx,Hx,Wx (66),(v) 93: vgatherqps/d Vx,Hx,Wx (66),(v) 94: @@ -715,6 +744,10 @@ AVXcode: 2 9d: vfnmadd132ss/d Vx,Hx,Wx (66),(v),(v1) 9e: vfnmsub132ps/d Vx,Hx,Wx (66),(v) 9f: vfnmsub132ss/d Vx,Hx,Wx (66),(v),(v1) +a0: vpscatterdd/q Wx,Vx (66),(ev) +a1: vpscatterqd/q Wx,Vx (66),(ev) +a2: vscatterdps/d Wx,Vx (66),(ev) +a3: vscatterqps/d Wx,Vx (66),(ev) a6: vfmaddsub213ps/d Vx,Hx,Wx (66),(v) a7: vfmsubadd213ps/d Vx,Hx,Wx (66),(v) a8: vfmadd213ps/d Vx,Hx,Wx (66),(v) @@ -725,6 +758,8 @@ ac: vfnmadd213ps/d Vx,Hx,Wx (66),(v) ad: vfnmadd213ss/d Vx,Hx,Wx (66),(v),(v1) ae: vfnmsub213ps/d Vx,Hx,Wx (66),(v) af: vfnmsub213ss/d Vx,Hx,Wx (66),(v),(v1) +b4: vpmadd52luq Vx,Hx,Wx (66),(ev) +b5: vpmadd52huq Vx,Hx,Wx (66),(ev) b6: vfmaddsub231ps/d Vx,Hx,Wx (66),(v) b7: vfmsubadd231ps/d Vx,Hx,Wx (66),(v) b8: vfmadd231ps/d Vx,Hx,Wx (66),(v) @@ -736,12 +771,15 @@ bd: vfnmadd231ss/d Vx,Hx,Wx (66),(v),(v1) be: vfnmsub231ps/d Vx,Hx,Wx (66),(v) bf: vfnmsub231ss/d Vx,Hx,Wx (66),(v),(v1) # 0x0f 0x38 0xc0-0xff -c8: sha1nexte Vdq,Wdq +c4: vpconflictd/q Vx,Wx (66),(ev) +c6: Grp18 (1A) +c7: Grp19 (1A) +c8: sha1nexte Vdq,Wdq | vexp2ps/d Vx,Wx (66),(ev) c9: sha1msg1 Vdq,Wdq -ca: sha1msg2 Vdq,Wdq -cb: sha256rnds2 Vdq,Wdq -cc: sha256msg1 Vdq,Wdq -cd: sha256msg2 Vdq,Wdq +ca: sha1msg2 Vdq,Wdq | vrcp28ps/d Vx,Wx (66),(ev) +cb: sha256rnds2 Vdq,Wdq | vrcp28ss/d Vx,Hx,Wx (66),(ev) +cc: sha256msg1 Vdq,Wdq | vrsqrt28ps/d Vx,Wx (66),(ev) +cd: sha256msg2 Vdq,Wdq | vrsqrt28ss/d Vx,Hx,Wx (66),(ev) db: VAESIMC Vdq,Wdq (66),(v1) dc: VAESENC Vdq,Hdq,Wdq (66),(v1) dd: VAESENCLAST Vdq,Hdq,Wdq (66),(v1) @@ -763,15 +801,15 @@ AVXcode: 3 00: vpermq Vqq,Wqq,Ib (66),(v) 01: vpermpd Vqq,Wqq,Ib (66),(v) 02: vpblendd Vx,Hx,Wx,Ib (66),(v) -03: +03: valignd/q Vx,Hx,Wx,Ib (66),(ev) 04: vpermilps Vx,Wx,Ib (66),(v) 05: vpermilpd Vx,Wx,Ib (66),(v) 06: vperm2f128 Vqq,Hqq,Wqq,Ib (66),(v) 07: -08: vroundps Vx,Wx,Ib (66) -09: vroundpd Vx,Wx,Ib (66) -0a: vroundss Vss,Wss,Ib (66),(v1) -0b: vroundsd Vsd,Wsd,Ib (66),(v1) +08: vroundps Vx,Wx,Ib (66) | vrndscaleps Vx,Wx,Ib (66),(evo) +09: vroundpd Vx,Wx,Ib (66) | vrndscalepd Vx,Wx,Ib (66),(evo) +0a: vroundss Vss,Wss,Ib (66),(v1) | vrndscaless Vx,Hx,Wx,Ib (66),(evo) +0b: vroundsd Vsd,Wsd,Ib (66),(v1) | vrndscalesd Vx,Hx,Wx,Ib (66),(evo) 0c: vblendps Vx,Hx,Wx,Ib (66) 0d: vblendpd Vx,Hx,Wx,Ib (66) 0e: vpblendw Vx,Hx,Wx,Ib (66),(v1) @@ -780,26 +818,51 @@ AVXcode: 3 15: vpextrw Rd/Mw,Vdq,Ib (66),(v1) 16: vpextrd/q Ey,Vdq,Ib (66),(v1) 17: vextractps Ed,Vdq,Ib (66),(v1) -18: vinsertf128 Vqq,Hqq,Wqq,Ib (66),(v) -19: vextractf128 Wdq,Vqq,Ib (66),(v) +18: vinsertf128 Vqq,Hqq,Wqq,Ib (66),(v) | vinsertf32x4/64x2 Vqq,Hqq,Wqq,Ib (66),(evo) +19: vextractf128 Wdq,Vqq,Ib (66),(v) | vextractf32x4/64x2 Wdq,Vqq,Ib (66),(evo) +1a: vinsertf32x8/64x4 Vqq,Hqq,Wqq,Ib (66),(ev) +1b: vextractf32x8/64x4 Wdq,Vqq,Ib (66),(ev) 1d: vcvtps2ph Wx,Vx,Ib (66),(v) +1e: vpcmpud/q Vk,Hd,Wd,Ib (66),(ev) +1f: vpcmpd/q Vk,Hd,Wd,Ib (66),(ev) 20: vpinsrb Vdq,Hdq,Ry/Mb,Ib (66),(v1) 21: vinsertps Vdq,Hdq,Udq/Md,Ib (66),(v1) 22: vpinsrd/q Vdq,Hdq,Ey,Ib (66),(v1) -38: vinserti128 Vqq,Hqq,Wqq,Ib (66),(v) -39: vextracti128 Wdq,Vqq,Ib (66),(v) +23: vshuff32x4/64x2 Vx,Hx,Wx,Ib (66),(ev) +25: vpternlogd/q Vx,Hx,Wx,Ib (66),(ev) +26: vgetmantps/d Vx,Wx,Ib (66),(ev) +27: vgetmantss/d Vx,Hx,Wx,Ib (66),(ev) +30: kshiftrb/w Vk,Uk,Ib (66),(v) +31: kshiftrd/q Vk,Uk,Ib (66),(v) +32: kshiftlb/w Vk,Uk,Ib (66),(v) +33: kshiftld/q Vk,Uk,Ib (66),(v) +38: vinserti128 Vqq,Hqq,Wqq,Ib (66),(v) | vinserti32x4/64x2 Vqq,Hqq,Wqq,Ib (66),(evo) +39: vextracti128 Wdq,Vqq,Ib (66),(v) | vextracti32x4/64x2 Wdq,Vqq,Ib (66),(evo) +3a: vinserti32x8/64x4 Vqq,Hqq,Wqq,Ib (66),(ev) +3b: vextracti32x8/64x4 Wdq,Vqq,Ib (66),(ev) +3e: vpcmpub/w Vk,Hk,Wx,Ib (66),(ev) +3f: vpcmpb/w Vk,Hk,Wx,Ib (66),(ev) 40: vdpps Vx,Hx,Wx,Ib (66) 41: vdppd Vdq,Hdq,Wdq,Ib (66),(v1) -42: vmpsadbw Vx,Hx,Wx,Ib (66),(v1) +42: vmpsadbw Vx,Hx,Wx,Ib (66),(v1) | vdbpsadbw Vx,Hx,Wx,Ib (66),(evo) +43: vshufi32x4/64x2 Vx,Hx,Wx,Ib (66),(ev) 44: vpclmulqdq Vdq,Hdq,Wdq,Ib (66),(v1) 46: vperm2i128 Vqq,Hqq,Wqq,Ib (66),(v) 4a: vblendvps Vx,Hx,Wx,Lx (66),(v) 4b: vblendvpd Vx,Hx,Wx,Lx (66),(v) 4c: vpblendvb Vx,Hx,Wx,Lx (66),(v1) +50: vrangeps/d Vx,Hx,Wx,Ib (66),(ev) +51: vrangess/d Vx,Hx,Wx,Ib (66),(ev) +54: vfixupimmps/d Vx,Hx,Wx,Ib (66),(ev) +55: vfixupimmss/d Vx,Hx,Wx,Ib (66),(ev) +56: vreduceps/d Vx,Wx,Ib (66),(ev) +57: vreducess/d Vx,Hx,Wx,Ib (66),(ev) 60: vpcmpestrm Vdq,Wdq,Ib (66),(v1) 61: vpcmpestri Vdq,Wdq,Ib (66),(v1) 62: vpcmpistrm Vdq,Wdq,Ib (66),(v1) 63: vpcmpistri Vdq,Wdq,Ib (66),(v1) +66: vfpclassps/d Vk,Wx,Ib (66),(ev) +67: vfpclassss/d Vk,Wx,Ib (66),(ev) cc: sha1rnds4 Vdq,Wdq,Ib df: VAESKEYGEN Vdq,Wdq,Ib (66),(v1) f0: RORX Gy,Ey,Ib (F2),(v) @@ -927,8 +990,10 @@ GrpTable: Grp12 EndTable GrpTable: Grp13 +0: vprord/q Hx,Wx,Ib (66),(ev) +1: vprold/q Hx,Wx,Ib (66),(ev) 2: psrld Nq,Ib (11B) | vpsrld Hx,Ux,Ib (66),(11B),(v1) -4: psrad Nq,Ib (11B) | vpsrad Hx,Ux,Ib (66),(11B),(v1) +4: psrad Nq,Ib (11B) | vpsrad Hx,Ux,Ib (66),(11B),(v1) | vpsrad/q Hx,Ux,Ib (66),(evo) 6: pslld Nq,Ib (11B) | vpslld Hx,Ux,Ib (66),(11B),(v1) EndTable @@ -963,6 +1028,20 @@ GrpTable: Grp17 3: BLSI By,Ey (v) EndTable +GrpTable: Grp18 +1: vgatherpf0dps/d Wx (66),(ev) +2: vgatherpf1dps/d Wx (66),(ev) +5: vscatterpf0dps/d Wx (66),(ev) +6: vscatterpf1dps/d Wx (66),(ev) +EndTable + +GrpTable: Grp19 +1: vgatherpf0qps/d Wx (66),(ev) +2: vgatherpf1qps/d Wx (66),(ev) +5: vscatterpf0qps/d Wx (66),(ev) +6: vscatterpf1qps/d Wx (66),(ev) +EndTable + # AMD's Prefetch Group GrpTable: GrpP 0: PREFETCH diff --git a/arch/x86/tools/gen-insn-attr-x86.awk b/arch/x86/tools/gen-insn-attr-x86.awk index 093a892..a3d2c62 100644 --- a/arch/x86/tools/gen-insn-attr-x86.awk +++ b/arch/x86/tools/gen-insn-attr-x86.awk @@ -72,12 +72,14 @@ BEGIN { lprefix_expr = "\\((66|F2|F3)\\)" max_lprefix = 4 - # All opcodes starting with lower-case 'v' or with (v1) superscript + # All opcodes starting with lower-case 'v', 'k' or with (v1) superscript # accepts VEX prefix - vexok_opcode_expr = "^v.*" + vexok_opcode_expr = "^[vk].*" vexok_expr = "\\(v1\\)" # All opcodes with (v) superscript supports *only* VEX prefix vexonly_expr = "\\(v\\)" + # All opcodes with (ev) superscript supports *only* EVEX prefix + evexonly_expr = "\\(ev\\)" prefix_expr = "\\(Prefix\\)" prefix_num["Operand-Size"] = "INAT_PFX_OPNDSZ" @@ -95,6 +97,7 @@ BEGIN { prefix_num["Address-Size"] = "INAT_PFX_ADDRSZ" prefix_num["VEX+1byte"] = "INAT_PFX_VEX2" prefix_num["VEX+2byte"] = "INAT_PFX_VEX3" + prefix_num["EVEX"] = "INAT_PFX_EVEX" clear_vars() } @@ -319,7 +322,9 @@ function convert_operands(count,opnd, i,j,imm,mod) flags = add_flags(flags, "INAT_MODRM") # check VEX codes - if (match(ext, vexonly_expr)) + if (match(ext, evexonly_expr)) + flags = add_flags(flags, "INAT_VEXOK | INAT_EVEXONLY") + else if (match(ext, vexonly_expr)) flags = add_flags(flags, "INAT_VEXOK | INAT_VEXONLY") else if (match(ext, vexok_expr) || match(opcode, vexok_opcode_expr)) flags = add_flags(flags, "INAT_VEXOK") -- cgit v0.10.2 From c61f4d5ebaf05fbd90bf43aa2096690b85e34761 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Wed, 20 Jul 2016 11:30:36 +0300 Subject: perf tools: Add AVX-512 support to the instruction decoder used by Intel PT Add support for Intel's AVX-512 instructions to perf tools instruction decoder used by Intel PT. The kernel's instruction decoder was updated in a previous patch. AVX-512 instructions are documented in Intel Architecture Instruction Set Extensions Programming Reference (February 2016). AVX-512 instructions are identified by a EVEX prefix which, for the purpose of instruction decoding, can be treated as though it were a 4-byte VEX prefix. Existing instructions which can now accept an EVEX prefix need not be further annotated in the op code map (x86-opcode-map.txt). In the case of new instructions, the op code map is updated accordingly. Also add associated Mask Instructions that are used to manipulate mask registers used in AVX-512 instructions. A representative set of instructions is added to the perf tools new instructions test in a subsequent patch. Signed-off-by: Adrian Hunter Acked-by: Ingo Molnar Acked-by: Masami Hiramatsu Cc: Andy Lutomirski Cc: Dan Williams Cc: H. Peter Anvin Cc: Jiri Olsa Cc: Thomas Gleixner Cc: X86 ML Link: http://lkml.kernel.org/r/1469003437-32706-4-git-send-email-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/util/intel-pt-decoder/gen-insn-attr-x86.awk b/tools/perf/util/intel-pt-decoder/gen-insn-attr-x86.awk index 51756734..54e9616 100644 --- a/tools/perf/util/intel-pt-decoder/gen-insn-attr-x86.awk +++ b/tools/perf/util/intel-pt-decoder/gen-insn-attr-x86.awk @@ -72,12 +72,14 @@ BEGIN { lprefix_expr = "\\((66|F2|F3)\\)" max_lprefix = 4 - # All opcodes starting with lower-case 'v' or with (v1) superscript + # All opcodes starting with lower-case 'v', 'k' or with (v1) superscript # accepts VEX prefix - vexok_opcode_expr = "^v.*" + vexok_opcode_expr = "^[vk].*" vexok_expr = "\\(v1\\)" # All opcodes with (v) superscript supports *only* VEX prefix vexonly_expr = "\\(v\\)" + # All opcodes with (ev) superscript supports *only* EVEX prefix + evexonly_expr = "\\(ev\\)" prefix_expr = "\\(Prefix\\)" prefix_num["Operand-Size"] = "INAT_PFX_OPNDSZ" @@ -95,6 +97,7 @@ BEGIN { prefix_num["Address-Size"] = "INAT_PFX_ADDRSZ" prefix_num["VEX+1byte"] = "INAT_PFX_VEX2" prefix_num["VEX+2byte"] = "INAT_PFX_VEX3" + prefix_num["EVEX"] = "INAT_PFX_EVEX" clear_vars() } @@ -319,7 +322,9 @@ function convert_operands(count,opnd, i,j,imm,mod) flags = add_flags(flags, "INAT_MODRM") # check VEX codes - if (match(ext, vexonly_expr)) + if (match(ext, evexonly_expr)) + flags = add_flags(flags, "INAT_VEXOK | INAT_EVEXONLY") + else if (match(ext, vexonly_expr)) flags = add_flags(flags, "INAT_VEXOK | INAT_VEXONLY") else if (match(ext, vexok_expr) || match(opcode, vexok_opcode_expr)) flags = add_flags(flags, "INAT_VEXOK") diff --git a/tools/perf/util/intel-pt-decoder/inat.h b/tools/perf/util/intel-pt-decoder/inat.h index 611645e..125ecd2 100644 --- a/tools/perf/util/intel-pt-decoder/inat.h +++ b/tools/perf/util/intel-pt-decoder/inat.h @@ -48,6 +48,7 @@ /* AVX VEX prefixes */ #define INAT_PFX_VEX2 13 /* 2-bytes VEX prefix */ #define INAT_PFX_VEX3 14 /* 3-bytes VEX prefix */ +#define INAT_PFX_EVEX 15 /* EVEX prefix */ #define INAT_LSTPFX_MAX 3 #define INAT_LGCPFX_MAX 11 @@ -89,6 +90,7 @@ #define INAT_VARIANT (1 << (INAT_FLAG_OFFS + 4)) #define INAT_VEXOK (1 << (INAT_FLAG_OFFS + 5)) #define INAT_VEXONLY (1 << (INAT_FLAG_OFFS + 6)) +#define INAT_EVEXONLY (1 << (INAT_FLAG_OFFS + 7)) /* Attribute making macros for attribute tables */ #define INAT_MAKE_PREFIX(pfx) (pfx << INAT_PFX_OFFS) #define INAT_MAKE_ESCAPE(esc) (esc << INAT_ESC_OFFS) @@ -141,7 +143,13 @@ static inline int inat_last_prefix_id(insn_attr_t attr) static inline int inat_is_vex_prefix(insn_attr_t attr) { attr &= INAT_PFX_MASK; - return attr == INAT_PFX_VEX2 || attr == INAT_PFX_VEX3; + return attr == INAT_PFX_VEX2 || attr == INAT_PFX_VEX3 || + attr == INAT_PFX_EVEX; +} + +static inline int inat_is_evex_prefix(insn_attr_t attr) +{ + return (attr & INAT_PFX_MASK) == INAT_PFX_EVEX; } static inline int inat_is_vex3_prefix(insn_attr_t attr) @@ -216,6 +224,11 @@ static inline int inat_accept_vex(insn_attr_t attr) static inline int inat_must_vex(insn_attr_t attr) { - return attr & INAT_VEXONLY; + return attr & (INAT_VEXONLY | INAT_EVEXONLY); +} + +static inline int inat_must_evex(insn_attr_t attr) +{ + return attr & INAT_EVEXONLY; } #endif diff --git a/tools/perf/util/intel-pt-decoder/insn.c b/tools/perf/util/intel-pt-decoder/insn.c index 9f26eae..ca983e2 100644 --- a/tools/perf/util/intel-pt-decoder/insn.c +++ b/tools/perf/util/intel-pt-decoder/insn.c @@ -155,14 +155,24 @@ found: /* * In 32-bits mode, if the [7:6] bits (mod bits of * ModRM) on the second byte are not 11b, it is - * LDS or LES. + * LDS or LES or BOUND. */ if (X86_MODRM_MOD(b2) != 3) goto vex_end; } insn->vex_prefix.bytes[0] = b; insn->vex_prefix.bytes[1] = b2; - if (inat_is_vex3_prefix(attr)) { + if (inat_is_evex_prefix(attr)) { + b2 = peek_nbyte_next(insn_byte_t, insn, 2); + insn->vex_prefix.bytes[2] = b2; + b2 = peek_nbyte_next(insn_byte_t, insn, 3); + insn->vex_prefix.bytes[3] = b2; + insn->vex_prefix.nbytes = 4; + insn->next_byte += 4; + if (insn->x86_64 && X86_VEX_W(b2)) + /* VEX.W overrides opnd_size */ + insn->opnd_bytes = 8; + } else if (inat_is_vex3_prefix(attr)) { b2 = peek_nbyte_next(insn_byte_t, insn, 2); insn->vex_prefix.bytes[2] = b2; insn->vex_prefix.nbytes = 3; @@ -221,7 +231,9 @@ void insn_get_opcode(struct insn *insn) m = insn_vex_m_bits(insn); p = insn_vex_p_bits(insn); insn->attr = inat_get_avx_attribute(op, m, p); - if (!inat_accept_vex(insn->attr) && !inat_is_group(insn->attr)) + if ((inat_must_evex(insn->attr) && !insn_is_evex(insn)) || + (!inat_accept_vex(insn->attr) && + !inat_is_group(insn->attr))) insn->attr = 0; /* This instruction is bad */ goto end; /* VEX has only 1 byte for opcode */ } diff --git a/tools/perf/util/intel-pt-decoder/insn.h b/tools/perf/util/intel-pt-decoder/insn.h index dd12da0..e23578c 100644 --- a/tools/perf/util/intel-pt-decoder/insn.h +++ b/tools/perf/util/intel-pt-decoder/insn.h @@ -91,6 +91,7 @@ struct insn { #define X86_VEX_B(vex) ((vex) & 0x20) /* VEX3 Byte1 */ #define X86_VEX_L(vex) ((vex) & 0x04) /* VEX3 Byte2, VEX2 Byte1 */ /* VEX bit fields */ +#define X86_EVEX_M(vex) ((vex) & 0x03) /* EVEX Byte1 */ #define X86_VEX3_M(vex) ((vex) & 0x1f) /* VEX3 Byte1 */ #define X86_VEX2_M 1 /* VEX2.M always 1 */ #define X86_VEX_V(vex) (((vex) & 0x78) >> 3) /* VEX3 Byte2, VEX2 Byte1 */ @@ -133,6 +134,13 @@ static inline int insn_is_avx(struct insn *insn) return (insn->vex_prefix.value != 0); } +static inline int insn_is_evex(struct insn *insn) +{ + if (!insn->prefixes.got) + insn_get_prefixes(insn); + return (insn->vex_prefix.nbytes == 4); +} + /* Ensure this instruction is decoded completely */ static inline int insn_complete(struct insn *insn) { @@ -144,8 +152,10 @@ static inline insn_byte_t insn_vex_m_bits(struct insn *insn) { if (insn->vex_prefix.nbytes == 2) /* 2 bytes VEX */ return X86_VEX2_M; - else + else if (insn->vex_prefix.nbytes == 3) /* 3 bytes VEX */ return X86_VEX3_M(insn->vex_prefix.bytes[1]); + else /* EVEX */ + return X86_EVEX_M(insn->vex_prefix.bytes[1]); } static inline insn_byte_t insn_vex_p_bits(struct insn *insn) diff --git a/tools/perf/util/intel-pt-decoder/x86-opcode-map.txt b/tools/perf/util/intel-pt-decoder/x86-opcode-map.txt index 28082de..ec378cd 100644 --- a/tools/perf/util/intel-pt-decoder/x86-opcode-map.txt +++ b/tools/perf/util/intel-pt-decoder/x86-opcode-map.txt @@ -13,12 +13,17 @@ # opcode: escape # escaped-name # EndTable # +# mnemonics that begin with lowercase 'v' accept a VEX or EVEX prefix +# mnemonics that begin with lowercase 'k' accept a VEX prefix +# # # GrpTable: GrpXXX # reg: mnemonic [operand1[,operand2...]] [(extra1)[,(extra2)...] [| 2nd-mnemonic ...] # EndTable # # AVX Superscripts +# (ev): this opcode requires EVEX prefix. +# (evo): this opcode is changed by EVEX prefix (EVEX opcode) # (v): this opcode requires VEX prefix. # (v1): this opcode only supports 128bit VEX. # @@ -137,7 +142,7 @@ AVXcode: # 0x60 - 0x6f 60: PUSHA/PUSHAD (i64) 61: POPA/POPAD (i64) -62: BOUND Gv,Ma (i64) +62: BOUND Gv,Ma (i64) | EVEX (Prefix) 63: ARPL Ew,Gw (i64) | MOVSXD Gv,Ev (o64) 64: SEG=FS (Prefix) 65: SEG=GS (Prefix) @@ -399,17 +404,17 @@ AVXcode: 1 3f: # 0x0f 0x40-0x4f 40: CMOVO Gv,Ev -41: CMOVNO Gv,Ev -42: CMOVB/C/NAE Gv,Ev +41: CMOVNO Gv,Ev | kandw/q Vk,Hk,Uk | kandb/d Vk,Hk,Uk (66) +42: CMOVB/C/NAE Gv,Ev | kandnw/q Vk,Hk,Uk | kandnb/d Vk,Hk,Uk (66) 43: CMOVAE/NB/NC Gv,Ev -44: CMOVE/Z Gv,Ev -45: CMOVNE/NZ Gv,Ev -46: CMOVBE/NA Gv,Ev -47: CMOVA/NBE Gv,Ev +44: CMOVE/Z Gv,Ev | knotw/q Vk,Uk | knotb/d Vk,Uk (66) +45: CMOVNE/NZ Gv,Ev | korw/q Vk,Hk,Uk | korb/d Vk,Hk,Uk (66) +46: CMOVBE/NA Gv,Ev | kxnorw/q Vk,Hk,Uk | kxnorb/d Vk,Hk,Uk (66) +47: CMOVA/NBE Gv,Ev | kxorw/q Vk,Hk,Uk | kxorb/d Vk,Hk,Uk (66) 48: CMOVS Gv,Ev 49: CMOVNS Gv,Ev -4a: CMOVP/PE Gv,Ev -4b: CMOVNP/PO Gv,Ev +4a: CMOVP/PE Gv,Ev | kaddw/q Vk,Hk,Uk | kaddb/d Vk,Hk,Uk (66) +4b: CMOVNP/PO Gv,Ev | kunpckbw Vk,Hk,Uk (66) | kunpckwd/dq Vk,Hk,Uk 4c: CMOVL/NGE Gv,Ev 4d: CMOVNL/GE Gv,Ev 4e: CMOVLE/NG Gv,Ev @@ -426,7 +431,7 @@ AVXcode: 1 58: vaddps Vps,Hps,Wps | vaddpd Vpd,Hpd,Wpd (66) | vaddss Vss,Hss,Wss (F3),(v1) | vaddsd Vsd,Hsd,Wsd (F2),(v1) 59: vmulps Vps,Hps,Wps | vmulpd Vpd,Hpd,Wpd (66) | vmulss Vss,Hss,Wss (F3),(v1) | vmulsd Vsd,Hsd,Wsd (F2),(v1) 5a: vcvtps2pd Vpd,Wps | vcvtpd2ps Vps,Wpd (66) | vcvtss2sd Vsd,Hx,Wss (F3),(v1) | vcvtsd2ss Vss,Hx,Wsd (F2),(v1) -5b: vcvtdq2ps Vps,Wdq | vcvtps2dq Vdq,Wps (66) | vcvttps2dq Vdq,Wps (F3) +5b: vcvtdq2ps Vps,Wdq | vcvtqq2ps Vps,Wqq (evo) | vcvtps2dq Vdq,Wps (66) | vcvttps2dq Vdq,Wps (F3) 5c: vsubps Vps,Hps,Wps | vsubpd Vpd,Hpd,Wpd (66) | vsubss Vss,Hss,Wss (F3),(v1) | vsubsd Vsd,Hsd,Wsd (F2),(v1) 5d: vminps Vps,Hps,Wps | vminpd Vpd,Hpd,Wpd (66) | vminss Vss,Hss,Wss (F3),(v1) | vminsd Vsd,Hsd,Wsd (F2),(v1) 5e: vdivps Vps,Hps,Wps | vdivpd Vpd,Hpd,Wpd (66) | vdivss Vss,Hss,Wss (F3),(v1) | vdivsd Vsd,Hsd,Wsd (F2),(v1) @@ -447,7 +452,7 @@ AVXcode: 1 6c: vpunpcklqdq Vx,Hx,Wx (66),(v1) 6d: vpunpckhqdq Vx,Hx,Wx (66),(v1) 6e: movd/q Pd,Ey | vmovd/q Vy,Ey (66),(v1) -6f: movq Pq,Qq | vmovdqa Vx,Wx (66) | vmovdqu Vx,Wx (F3) +6f: movq Pq,Qq | vmovdqa Vx,Wx (66) | vmovdqa32/64 Vx,Wx (66),(evo) | vmovdqu Vx,Wx (F3) | vmovdqu32/64 Vx,Wx (F3),(evo) | vmovdqu8/16 Vx,Wx (F2),(ev) # 0x0f 0x70-0x7f 70: pshufw Pq,Qq,Ib | vpshufd Vx,Wx,Ib (66),(v1) | vpshufhw Vx,Wx,Ib (F3),(v1) | vpshuflw Vx,Wx,Ib (F2),(v1) 71: Grp12 (1A) @@ -458,14 +463,14 @@ AVXcode: 1 76: pcmpeqd Pq,Qq | vpcmpeqd Vx,Hx,Wx (66),(v1) # Note: Remove (v), because vzeroall and vzeroupper becomes emms without VEX. 77: emms | vzeroupper | vzeroall -78: VMREAD Ey,Gy -79: VMWRITE Gy,Ey -7a: -7b: +78: VMREAD Ey,Gy | vcvttps2udq/pd2udq Vx,Wpd (evo) | vcvttsd2usi Gv,Wx (F2),(ev) | vcvttss2usi Gv,Wx (F3),(ev) | vcvttps2uqq/pd2uqq Vx,Wx (66),(ev) +79: VMWRITE Gy,Ey | vcvtps2udq/pd2udq Vx,Wpd (evo) | vcvtsd2usi Gv,Wx (F2),(ev) | vcvtss2usi Gv,Wx (F3),(ev) | vcvtps2uqq/pd2uqq Vx,Wx (66),(ev) +7a: vcvtudq2pd/uqq2pd Vpd,Wx (F3),(ev) | vcvtudq2ps/uqq2ps Vpd,Wx (F2),(ev) | vcvttps2qq/pd2qq Vx,Wx (66),(ev) +7b: vcvtusi2sd Vpd,Hpd,Ev (F2),(ev) | vcvtusi2ss Vps,Hps,Ev (F3),(ev) | vcvtps2qq/pd2qq Vx,Wx (66),(ev) 7c: vhaddpd Vpd,Hpd,Wpd (66) | vhaddps Vps,Hps,Wps (F2) 7d: vhsubpd Vpd,Hpd,Wpd (66) | vhsubps Vps,Hps,Wps (F2) 7e: movd/q Ey,Pd | vmovd/q Ey,Vy (66),(v1) | vmovq Vq,Wq (F3),(v1) -7f: movq Qq,Pq | vmovdqa Wx,Vx (66) | vmovdqu Wx,Vx (F3) +7f: movq Qq,Pq | vmovdqa Wx,Vx (66) | vmovdqa32/64 Wx,Vx (66),(evo) | vmovdqu Wx,Vx (F3) | vmovdqu32/64 Wx,Vx (F3),(evo) | vmovdqu8/16 Wx,Vx (F2),(ev) # 0x0f 0x80-0x8f # Note: "forced64" is Intel CPU behavior (see comment about CALL insn). 80: JO Jz (f64) @@ -485,16 +490,16 @@ AVXcode: 1 8e: JLE/JNG Jz (f64) 8f: JNLE/JG Jz (f64) # 0x0f 0x90-0x9f -90: SETO Eb -91: SETNO Eb -92: SETB/C/NAE Eb -93: SETAE/NB/NC Eb +90: SETO Eb | kmovw/q Vk,Wk | kmovb/d Vk,Wk (66) +91: SETNO Eb | kmovw/q Mv,Vk | kmovb/d Mv,Vk (66) +92: SETB/C/NAE Eb | kmovw Vk,Rv | kmovb Vk,Rv (66) | kmovq/d Vk,Rv (F2) +93: SETAE/NB/NC Eb | kmovw Gv,Uk | kmovb Gv,Uk (66) | kmovq/d Gv,Uk (F2) 94: SETE/Z Eb 95: SETNE/NZ Eb 96: SETBE/NA Eb 97: SETA/NBE Eb -98: SETS Eb -99: SETNS Eb +98: SETS Eb | kortestw/q Vk,Uk | kortestb/d Vk,Uk (66) +99: SETNS Eb | ktestw/q Vk,Uk | ktestb/d Vk,Uk (66) 9a: SETP/PE Eb 9b: SETNP/PO Eb 9c: SETL/NGE Eb @@ -564,11 +569,11 @@ d7: pmovmskb Gd,Nq | vpmovmskb Gd,Ux (66),(v1) d8: psubusb Pq,Qq | vpsubusb Vx,Hx,Wx (66),(v1) d9: psubusw Pq,Qq | vpsubusw Vx,Hx,Wx (66),(v1) da: pminub Pq,Qq | vpminub Vx,Hx,Wx (66),(v1) -db: pand Pq,Qq | vpand Vx,Hx,Wx (66),(v1) +db: pand Pq,Qq | vpand Vx,Hx,Wx (66),(v1) | vpandd/q Vx,Hx,Wx (66),(evo) dc: paddusb Pq,Qq | vpaddusb Vx,Hx,Wx (66),(v1) dd: paddusw Pq,Qq | vpaddusw Vx,Hx,Wx (66),(v1) de: pmaxub Pq,Qq | vpmaxub Vx,Hx,Wx (66),(v1) -df: pandn Pq,Qq | vpandn Vx,Hx,Wx (66),(v1) +df: pandn Pq,Qq | vpandn Vx,Hx,Wx (66),(v1) | vpandnd/q Vx,Hx,Wx (66),(evo) # 0x0f 0xe0-0xef e0: pavgb Pq,Qq | vpavgb Vx,Hx,Wx (66),(v1) e1: psraw Pq,Qq | vpsraw Vx,Hx,Wx (66),(v1) @@ -576,16 +581,16 @@ e2: psrad Pq,Qq | vpsrad Vx,Hx,Wx (66),(v1) e3: pavgw Pq,Qq | vpavgw Vx,Hx,Wx (66),(v1) e4: pmulhuw Pq,Qq | vpmulhuw Vx,Hx,Wx (66),(v1) e5: pmulhw Pq,Qq | vpmulhw Vx,Hx,Wx (66),(v1) -e6: vcvttpd2dq Vx,Wpd (66) | vcvtdq2pd Vx,Wdq (F3) | vcvtpd2dq Vx,Wpd (F2) +e6: vcvttpd2dq Vx,Wpd (66) | vcvtdq2pd Vx,Wdq (F3) | vcvtdq2pd/qq2pd Vx,Wdq (F3),(evo) | vcvtpd2dq Vx,Wpd (F2) e7: movntq Mq,Pq | vmovntdq Mx,Vx (66) e8: psubsb Pq,Qq | vpsubsb Vx,Hx,Wx (66),(v1) e9: psubsw Pq,Qq | vpsubsw Vx,Hx,Wx (66),(v1) ea: pminsw Pq,Qq | vpminsw Vx,Hx,Wx (66),(v1) -eb: por Pq,Qq | vpor Vx,Hx,Wx (66),(v1) +eb: por Pq,Qq | vpor Vx,Hx,Wx (66),(v1) | vpord/q Vx,Hx,Wx (66),(evo) ec: paddsb Pq,Qq | vpaddsb Vx,Hx,Wx (66),(v1) ed: paddsw Pq,Qq | vpaddsw Vx,Hx,Wx (66),(v1) ee: pmaxsw Pq,Qq | vpmaxsw Vx,Hx,Wx (66),(v1) -ef: pxor Pq,Qq | vpxor Vx,Hx,Wx (66),(v1) +ef: pxor Pq,Qq | vpxor Vx,Hx,Wx (66),(v1) | vpxord/q Vx,Hx,Wx (66),(evo) # 0x0f 0xf0-0xff f0: vlddqu Vx,Mx (F2) f1: psllw Pq,Qq | vpsllw Vx,Hx,Wx (66),(v1) @@ -626,81 +631,105 @@ AVXcode: 2 0e: vtestps Vx,Wx (66),(v) 0f: vtestpd Vx,Wx (66),(v) # 0x0f 0x38 0x10-0x1f -10: pblendvb Vdq,Wdq (66) -11: -12: -13: vcvtph2ps Vx,Wx (66),(v) -14: blendvps Vdq,Wdq (66) -15: blendvpd Vdq,Wdq (66) -16: vpermps Vqq,Hqq,Wqq (66),(v) +10: pblendvb Vdq,Wdq (66) | vpsrlvw Vx,Hx,Wx (66),(evo) | vpmovuswb Wx,Vx (F3),(ev) +11: vpmovusdb Wx,Vd (F3),(ev) | vpsravw Vx,Hx,Wx (66),(ev) +12: vpmovusqb Wx,Vq (F3),(ev) | vpsllvw Vx,Hx,Wx (66),(ev) +13: vcvtph2ps Vx,Wx (66),(v) | vpmovusdw Wx,Vd (F3),(ev) +14: blendvps Vdq,Wdq (66) | vpmovusqw Wx,Vq (F3),(ev) | vprorvd/q Vx,Hx,Wx (66),(evo) +15: blendvpd Vdq,Wdq (66) | vpmovusqd Wx,Vq (F3),(ev) | vprolvd/q Vx,Hx,Wx (66),(evo) +16: vpermps Vqq,Hqq,Wqq (66),(v) | vpermps/d Vqq,Hqq,Wqq (66),(evo) 17: vptest Vx,Wx (66) 18: vbroadcastss Vx,Wd (66),(v) -19: vbroadcastsd Vqq,Wq (66),(v) -1a: vbroadcastf128 Vqq,Mdq (66),(v) -1b: +19: vbroadcastsd Vqq,Wq (66),(v) | vbroadcastf32x2 Vqq,Wq (66),(evo) +1a: vbroadcastf128 Vqq,Mdq (66),(v) | vbroadcastf32x4/64x2 Vqq,Wq (66),(evo) +1b: vbroadcastf32x8/64x4 Vqq,Mdq (66),(ev) 1c: pabsb Pq,Qq | vpabsb Vx,Wx (66),(v1) 1d: pabsw Pq,Qq | vpabsw Vx,Wx (66),(v1) 1e: pabsd Pq,Qq | vpabsd Vx,Wx (66),(v1) -1f: +1f: vpabsq Vx,Wx (66),(ev) # 0x0f 0x38 0x20-0x2f -20: vpmovsxbw Vx,Ux/Mq (66),(v1) -21: vpmovsxbd Vx,Ux/Md (66),(v1) -22: vpmovsxbq Vx,Ux/Mw (66),(v1) -23: vpmovsxwd Vx,Ux/Mq (66),(v1) -24: vpmovsxwq Vx,Ux/Md (66),(v1) -25: vpmovsxdq Vx,Ux/Mq (66),(v1) -26: -27: -28: vpmuldq Vx,Hx,Wx (66),(v1) -29: vpcmpeqq Vx,Hx,Wx (66),(v1) -2a: vmovntdqa Vx,Mx (66),(v1) +20: vpmovsxbw Vx,Ux/Mq (66),(v1) | vpmovswb Wx,Vx (F3),(ev) +21: vpmovsxbd Vx,Ux/Md (66),(v1) | vpmovsdb Wx,Vd (F3),(ev) +22: vpmovsxbq Vx,Ux/Mw (66),(v1) | vpmovsqb Wx,Vq (F3),(ev) +23: vpmovsxwd Vx,Ux/Mq (66),(v1) | vpmovsdw Wx,Vd (F3),(ev) +24: vpmovsxwq Vx,Ux/Md (66),(v1) | vpmovsqw Wx,Vq (F3),(ev) +25: vpmovsxdq Vx,Ux/Mq (66),(v1) | vpmovsqd Wx,Vq (F3),(ev) +26: vptestmb/w Vk,Hx,Wx (66),(ev) | vptestnmb/w Vk,Hx,Wx (F3),(ev) +27: vptestmd/q Vk,Hx,Wx (66),(ev) | vptestnmd/q Vk,Hx,Wx (F3),(ev) +28: vpmuldq Vx,Hx,Wx (66),(v1) | vpmovm2b/w Vx,Uk (F3),(ev) +29: vpcmpeqq Vx,Hx,Wx (66),(v1) | vpmovb2m/w2m Vk,Ux (F3),(ev) +2a: vmovntdqa Vx,Mx (66),(v1) | vpbroadcastmb2q Vx,Uk (F3),(ev) 2b: vpackusdw Vx,Hx,Wx (66),(v1) -2c: vmaskmovps Vx,Hx,Mx (66),(v) -2d: vmaskmovpd Vx,Hx,Mx (66),(v) +2c: vmaskmovps Vx,Hx,Mx (66),(v) | vscalefps/d Vx,Hx,Wx (66),(evo) +2d: vmaskmovpd Vx,Hx,Mx (66),(v) | vscalefss/d Vx,Hx,Wx (66),(evo) 2e: vmaskmovps Mx,Hx,Vx (66),(v) 2f: vmaskmovpd Mx,Hx,Vx (66),(v) # 0x0f 0x38 0x30-0x3f -30: vpmovzxbw Vx,Ux/Mq (66),(v1) -31: vpmovzxbd Vx,Ux/Md (66),(v1) -32: vpmovzxbq Vx,Ux/Mw (66),(v1) -33: vpmovzxwd Vx,Ux/Mq (66),(v1) -34: vpmovzxwq Vx,Ux/Md (66),(v1) -35: vpmovzxdq Vx,Ux/Mq (66),(v1) -36: vpermd Vqq,Hqq,Wqq (66),(v) +30: vpmovzxbw Vx,Ux/Mq (66),(v1) | vpmovwb Wx,Vx (F3),(ev) +31: vpmovzxbd Vx,Ux/Md (66),(v1) | vpmovdb Wx,Vd (F3),(ev) +32: vpmovzxbq Vx,Ux/Mw (66),(v1) | vpmovqb Wx,Vq (F3),(ev) +33: vpmovzxwd Vx,Ux/Mq (66),(v1) | vpmovdw Wx,Vd (F3),(ev) +34: vpmovzxwq Vx,Ux/Md (66),(v1) | vpmovqw Wx,Vq (F3),(ev) +35: vpmovzxdq Vx,Ux/Mq (66),(v1) | vpmovqd Wx,Vq (F3),(ev) +36: vpermd Vqq,Hqq,Wqq (66),(v) | vpermd/q Vqq,Hqq,Wqq (66),(evo) 37: vpcmpgtq Vx,Hx,Wx (66),(v1) -38: vpminsb Vx,Hx,Wx (66),(v1) -39: vpminsd Vx,Hx,Wx (66),(v1) -3a: vpminuw Vx,Hx,Wx (66),(v1) -3b: vpminud Vx,Hx,Wx (66),(v1) +38: vpminsb Vx,Hx,Wx (66),(v1) | vpmovm2d/q Vx,Uk (F3),(ev) +39: vpminsd Vx,Hx,Wx (66),(v1) | vpminsd/q Vx,Hx,Wx (66),(evo) | vpmovd2m/q2m Vk,Ux (F3),(ev) +3a: vpminuw Vx,Hx,Wx (66),(v1) | vpbroadcastmw2d Vx,Uk (F3),(ev) +3b: vpminud Vx,Hx,Wx (66),(v1) | vpminud/q Vx,Hx,Wx (66),(evo) 3c: vpmaxsb Vx,Hx,Wx (66),(v1) -3d: vpmaxsd Vx,Hx,Wx (66),(v1) +3d: vpmaxsd Vx,Hx,Wx (66),(v1) | vpmaxsd/q Vx,Hx,Wx (66),(evo) 3e: vpmaxuw Vx,Hx,Wx (66),(v1) -3f: vpmaxud Vx,Hx,Wx (66),(v1) +3f: vpmaxud Vx,Hx,Wx (66),(v1) | vpmaxud/q Vx,Hx,Wx (66),(evo) # 0x0f 0x38 0x40-0x8f -40: vpmulld Vx,Hx,Wx (66),(v1) +40: vpmulld Vx,Hx,Wx (66),(v1) | vpmulld/q Vx,Hx,Wx (66),(evo) 41: vphminposuw Vdq,Wdq (66),(v1) -42: -43: -44: +42: vgetexpps/d Vx,Wx (66),(ev) +43: vgetexpss/d Vx,Hx,Wx (66),(ev) +44: vplzcntd/q Vx,Wx (66),(ev) 45: vpsrlvd/q Vx,Hx,Wx (66),(v) -46: vpsravd Vx,Hx,Wx (66),(v) +46: vpsravd Vx,Hx,Wx (66),(v) | vpsravd/q Vx,Hx,Wx (66),(evo) 47: vpsllvd/q Vx,Hx,Wx (66),(v) -# Skip 0x48-0x57 +# Skip 0x48-0x4b +4c: vrcp14ps/d Vpd,Wpd (66),(ev) +4d: vrcp14ss/d Vsd,Hpd,Wsd (66),(ev) +4e: vrsqrt14ps/d Vpd,Wpd (66),(ev) +4f: vrsqrt14ss/d Vsd,Hsd,Wsd (66),(ev) +# Skip 0x50-0x57 58: vpbroadcastd Vx,Wx (66),(v) -59: vpbroadcastq Vx,Wx (66),(v) -5a: vbroadcasti128 Vqq,Mdq (66),(v) -# Skip 0x5b-0x77 +59: vpbroadcastq Vx,Wx (66),(v) | vbroadcasti32x2 Vx,Wx (66),(evo) +5a: vbroadcasti128 Vqq,Mdq (66),(v) | vbroadcasti32x4/64x2 Vx,Wx (66),(evo) +5b: vbroadcasti32x8/64x4 Vqq,Mdq (66),(ev) +# Skip 0x5c-0x63 +64: vpblendmd/q Vx,Hx,Wx (66),(ev) +65: vblendmps/d Vx,Hx,Wx (66),(ev) +66: vpblendmb/w Vx,Hx,Wx (66),(ev) +# Skip 0x67-0x74 +75: vpermi2b/w Vx,Hx,Wx (66),(ev) +76: vpermi2d/q Vx,Hx,Wx (66),(ev) +77: vpermi2ps/d Vx,Hx,Wx (66),(ev) 78: vpbroadcastb Vx,Wx (66),(v) 79: vpbroadcastw Vx,Wx (66),(v) -# Skip 0x7a-0x7f +7a: vpbroadcastb Vx,Rv (66),(ev) +7b: vpbroadcastw Vx,Rv (66),(ev) +7c: vpbroadcastd/q Vx,Rv (66),(ev) +7d: vpermt2b/w Vx,Hx,Wx (66),(ev) +7e: vpermt2d/q Vx,Hx,Wx (66),(ev) +7f: vpermt2ps/d Vx,Hx,Wx (66),(ev) 80: INVEPT Gy,Mdq (66) 81: INVPID Gy,Mdq (66) 82: INVPCID Gy,Mdq (66) +83: vpmultishiftqb Vx,Hx,Wx (66),(ev) +88: vexpandps/d Vpd,Wpd (66),(ev) +89: vpexpandd/q Vx,Wx (66),(ev) +8a: vcompressps/d Wx,Vx (66),(ev) +8b: vpcompressd/q Wx,Vx (66),(ev) 8c: vpmaskmovd/q Vx,Hx,Mx (66),(v) +8d: vpermb/w Vx,Hx,Wx (66),(ev) 8e: vpmaskmovd/q Mx,Vx,Hx (66),(v) # 0x0f 0x38 0x90-0xbf (FMA) -90: vgatherdd/q Vx,Hx,Wx (66),(v) -91: vgatherqd/q Vx,Hx,Wx (66),(v) +90: vgatherdd/q Vx,Hx,Wx (66),(v) | vpgatherdd/q Vx,Wx (66),(evo) +91: vgatherqd/q Vx,Hx,Wx (66),(v) | vpgatherqd/q Vx,Wx (66),(evo) 92: vgatherdps/d Vx,Hx,Wx (66),(v) 93: vgatherqps/d Vx,Hx,Wx (66),(v) 94: @@ -715,6 +744,10 @@ AVXcode: 2 9d: vfnmadd132ss/d Vx,Hx,Wx (66),(v),(v1) 9e: vfnmsub132ps/d Vx,Hx,Wx (66),(v) 9f: vfnmsub132ss/d Vx,Hx,Wx (66),(v),(v1) +a0: vpscatterdd/q Wx,Vx (66),(ev) +a1: vpscatterqd/q Wx,Vx (66),(ev) +a2: vscatterdps/d Wx,Vx (66),(ev) +a3: vscatterqps/d Wx,Vx (66),(ev) a6: vfmaddsub213ps/d Vx,Hx,Wx (66),(v) a7: vfmsubadd213ps/d Vx,Hx,Wx (66),(v) a8: vfmadd213ps/d Vx,Hx,Wx (66),(v) @@ -725,6 +758,8 @@ ac: vfnmadd213ps/d Vx,Hx,Wx (66),(v) ad: vfnmadd213ss/d Vx,Hx,Wx (66),(v),(v1) ae: vfnmsub213ps/d Vx,Hx,Wx (66),(v) af: vfnmsub213ss/d Vx,Hx,Wx (66),(v),(v1) +b4: vpmadd52luq Vx,Hx,Wx (66),(ev) +b5: vpmadd52huq Vx,Hx,Wx (66),(ev) b6: vfmaddsub231ps/d Vx,Hx,Wx (66),(v) b7: vfmsubadd231ps/d Vx,Hx,Wx (66),(v) b8: vfmadd231ps/d Vx,Hx,Wx (66),(v) @@ -736,12 +771,15 @@ bd: vfnmadd231ss/d Vx,Hx,Wx (66),(v),(v1) be: vfnmsub231ps/d Vx,Hx,Wx (66),(v) bf: vfnmsub231ss/d Vx,Hx,Wx (66),(v),(v1) # 0x0f 0x38 0xc0-0xff -c8: sha1nexte Vdq,Wdq +c4: vpconflictd/q Vx,Wx (66),(ev) +c6: Grp18 (1A) +c7: Grp19 (1A) +c8: sha1nexte Vdq,Wdq | vexp2ps/d Vx,Wx (66),(ev) c9: sha1msg1 Vdq,Wdq -ca: sha1msg2 Vdq,Wdq -cb: sha256rnds2 Vdq,Wdq -cc: sha256msg1 Vdq,Wdq -cd: sha256msg2 Vdq,Wdq +ca: sha1msg2 Vdq,Wdq | vrcp28ps/d Vx,Wx (66),(ev) +cb: sha256rnds2 Vdq,Wdq | vrcp28ss/d Vx,Hx,Wx (66),(ev) +cc: sha256msg1 Vdq,Wdq | vrsqrt28ps/d Vx,Wx (66),(ev) +cd: sha256msg2 Vdq,Wdq | vrsqrt28ss/d Vx,Hx,Wx (66),(ev) db: VAESIMC Vdq,Wdq (66),(v1) dc: VAESENC Vdq,Hdq,Wdq (66),(v1) dd: VAESENCLAST Vdq,Hdq,Wdq (66),(v1) @@ -763,15 +801,15 @@ AVXcode: 3 00: vpermq Vqq,Wqq,Ib (66),(v) 01: vpermpd Vqq,Wqq,Ib (66),(v) 02: vpblendd Vx,Hx,Wx,Ib (66),(v) -03: +03: valignd/q Vx,Hx,Wx,Ib (66),(ev) 04: vpermilps Vx,Wx,Ib (66),(v) 05: vpermilpd Vx,Wx,Ib (66),(v) 06: vperm2f128 Vqq,Hqq,Wqq,Ib (66),(v) 07: -08: vroundps Vx,Wx,Ib (66) -09: vroundpd Vx,Wx,Ib (66) -0a: vroundss Vss,Wss,Ib (66),(v1) -0b: vroundsd Vsd,Wsd,Ib (66),(v1) +08: vroundps Vx,Wx,Ib (66) | vrndscaleps Vx,Wx,Ib (66),(evo) +09: vroundpd Vx,Wx,Ib (66) | vrndscalepd Vx,Wx,Ib (66),(evo) +0a: vroundss Vss,Wss,Ib (66),(v1) | vrndscaless Vx,Hx,Wx,Ib (66),(evo) +0b: vroundsd Vsd,Wsd,Ib (66),(v1) | vrndscalesd Vx,Hx,Wx,Ib (66),(evo) 0c: vblendps Vx,Hx,Wx,Ib (66) 0d: vblendpd Vx,Hx,Wx,Ib (66) 0e: vpblendw Vx,Hx,Wx,Ib (66),(v1) @@ -780,26 +818,51 @@ AVXcode: 3 15: vpextrw Rd/Mw,Vdq,Ib (66),(v1) 16: vpextrd/q Ey,Vdq,Ib (66),(v1) 17: vextractps Ed,Vdq,Ib (66),(v1) -18: vinsertf128 Vqq,Hqq,Wqq,Ib (66),(v) -19: vextractf128 Wdq,Vqq,Ib (66),(v) +18: vinsertf128 Vqq,Hqq,Wqq,Ib (66),(v) | vinsertf32x4/64x2 Vqq,Hqq,Wqq,Ib (66),(evo) +19: vextractf128 Wdq,Vqq,Ib (66),(v) | vextractf32x4/64x2 Wdq,Vqq,Ib (66),(evo) +1a: vinsertf32x8/64x4 Vqq,Hqq,Wqq,Ib (66),(ev) +1b: vextractf32x8/64x4 Wdq,Vqq,Ib (66),(ev) 1d: vcvtps2ph Wx,Vx,Ib (66),(v) +1e: vpcmpud/q Vk,Hd,Wd,Ib (66),(ev) +1f: vpcmpd/q Vk,Hd,Wd,Ib (66),(ev) 20: vpinsrb Vdq,Hdq,Ry/Mb,Ib (66),(v1) 21: vinsertps Vdq,Hdq,Udq/Md,Ib (66),(v1) 22: vpinsrd/q Vdq,Hdq,Ey,Ib (66),(v1) -38: vinserti128 Vqq,Hqq,Wqq,Ib (66),(v) -39: vextracti128 Wdq,Vqq,Ib (66),(v) +23: vshuff32x4/64x2 Vx,Hx,Wx,Ib (66),(ev) +25: vpternlogd/q Vx,Hx,Wx,Ib (66),(ev) +26: vgetmantps/d Vx,Wx,Ib (66),(ev) +27: vgetmantss/d Vx,Hx,Wx,Ib (66),(ev) +30: kshiftrb/w Vk,Uk,Ib (66),(v) +31: kshiftrd/q Vk,Uk,Ib (66),(v) +32: kshiftlb/w Vk,Uk,Ib (66),(v) +33: kshiftld/q Vk,Uk,Ib (66),(v) +38: vinserti128 Vqq,Hqq,Wqq,Ib (66),(v) | vinserti32x4/64x2 Vqq,Hqq,Wqq,Ib (66),(evo) +39: vextracti128 Wdq,Vqq,Ib (66),(v) | vextracti32x4/64x2 Wdq,Vqq,Ib (66),(evo) +3a: vinserti32x8/64x4 Vqq,Hqq,Wqq,Ib (66),(ev) +3b: vextracti32x8/64x4 Wdq,Vqq,Ib (66),(ev) +3e: vpcmpub/w Vk,Hk,Wx,Ib (66),(ev) +3f: vpcmpb/w Vk,Hk,Wx,Ib (66),(ev) 40: vdpps Vx,Hx,Wx,Ib (66) 41: vdppd Vdq,Hdq,Wdq,Ib (66),(v1) -42: vmpsadbw Vx,Hx,Wx,Ib (66),(v1) +42: vmpsadbw Vx,Hx,Wx,Ib (66),(v1) | vdbpsadbw Vx,Hx,Wx,Ib (66),(evo) +43: vshufi32x4/64x2 Vx,Hx,Wx,Ib (66),(ev) 44: vpclmulqdq Vdq,Hdq,Wdq,Ib (66),(v1) 46: vperm2i128 Vqq,Hqq,Wqq,Ib (66),(v) 4a: vblendvps Vx,Hx,Wx,Lx (66),(v) 4b: vblendvpd Vx,Hx,Wx,Lx (66),(v) 4c: vpblendvb Vx,Hx,Wx,Lx (66),(v1) +50: vrangeps/d Vx,Hx,Wx,Ib (66),(ev) +51: vrangess/d Vx,Hx,Wx,Ib (66),(ev) +54: vfixupimmps/d Vx,Hx,Wx,Ib (66),(ev) +55: vfixupimmss/d Vx,Hx,Wx,Ib (66),(ev) +56: vreduceps/d Vx,Wx,Ib (66),(ev) +57: vreducess/d Vx,Hx,Wx,Ib (66),(ev) 60: vpcmpestrm Vdq,Wdq,Ib (66),(v1) 61: vpcmpestri Vdq,Wdq,Ib (66),(v1) 62: vpcmpistrm Vdq,Wdq,Ib (66),(v1) 63: vpcmpistri Vdq,Wdq,Ib (66),(v1) +66: vfpclassps/d Vk,Wx,Ib (66),(ev) +67: vfpclassss/d Vk,Wx,Ib (66),(ev) cc: sha1rnds4 Vdq,Wdq,Ib df: VAESKEYGEN Vdq,Wdq,Ib (66),(v1) f0: RORX Gy,Ey,Ib (F2),(v) @@ -927,8 +990,10 @@ GrpTable: Grp12 EndTable GrpTable: Grp13 +0: vprord/q Hx,Wx,Ib (66),(ev) +1: vprold/q Hx,Wx,Ib (66),(ev) 2: psrld Nq,Ib (11B) | vpsrld Hx,Ux,Ib (66),(11B),(v1) -4: psrad Nq,Ib (11B) | vpsrad Hx,Ux,Ib (66),(11B),(v1) +4: psrad Nq,Ib (11B) | vpsrad Hx,Ux,Ib (66),(11B),(v1) | vpsrad/q Hx,Ux,Ib (66),(evo) 6: pslld Nq,Ib (11B) | vpslld Hx,Ux,Ib (66),(11B),(v1) EndTable @@ -963,6 +1028,20 @@ GrpTable: Grp17 3: BLSI By,Ey (v) EndTable +GrpTable: Grp18 +1: vgatherpf0dps/d Wx (66),(ev) +2: vgatherpf1dps/d Wx (66),(ev) +5: vscatterpf0dps/d Wx (66),(ev) +6: vscatterpf1dps/d Wx (66),(ev) +EndTable + +GrpTable: Grp19 +1: vgatherpf0qps/d Wx (66),(ev) +2: vgatherpf1qps/d Wx (66),(ev) +5: vscatterpf0qps/d Wx (66),(ev) +6: vscatterpf1qps/d Wx (66),(ev) +EndTable + # AMD's Prefetch Group GrpTable: GrpP 0: PREFETCH -- cgit v0.10.2 From 6c4d0b41ce3e61fe87e6195582c66cd262399b82 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Wed, 20 Jul 2016 11:30:37 +0300 Subject: perf tools: Add AVX-512 instructions to the new instructions test Previous patches added support for Intel's AVX-512 instructions to the kernel and perf tools instruction decoders. AVX-512 instructions are documented in Intel Architecture Instruction Set Extensions Programming Reference (February 2016). Add a representative set of instructions to perf's "new instructions" test. e.g. perf test "new instructions" Or to view a particular instruction: perf test -v "new instructions" 2>&1 | grep vbroadcasti64x4 Signed-off-by: Adrian Hunter Acked-by: Ingo Molnar Acked-by: Masami Hiramatsu Tested-by: Arnaldo Carvalho de Melo Cc: Andy Lutomirski Cc: Dan Williams Cc: H. Peter Anvin Cc: Jiri Olsa Cc: Thomas Gleixner Cc: X86 ML Link: http://lkml.kernel.org/r/1469003437-32706-5-git-send-email-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/arch/x86/tests/insn-x86-dat-32.c b/tools/perf/arch/x86/tests/insn-x86-dat-32.c index ca08e6e..3918dd5 100644 --- a/tools/perf/arch/x86/tests/insn-x86-dat-32.c +++ b/tools/perf/arch/x86/tests/insn-x86-dat-32.c @@ -8,6 +8,1014 @@ "0f 31 \trdtsc ",}, {{0xc4, 0xe2, 0x7d, 0x13, 0xeb, }, 5, 0, "", "", "c4 e2 7d 13 eb \tvcvtph2ps %xmm3,%ymm5",}, +{{0x62, 0x81, 0x78, 0x56, 0x34, 0x12, }, 6, 0, "", "", +"62 81 78 56 34 12 \tbound %eax,0x12345678(%ecx)",}, +{{0x62, 0x88, 0x78, 0x56, 0x34, 0x12, }, 6, 0, "", "", +"62 88 78 56 34 12 \tbound %ecx,0x12345678(%eax)",}, +{{0x62, 0x90, 0x78, 0x56, 0x34, 0x12, }, 6, 0, "", "", +"62 90 78 56 34 12 \tbound %edx,0x12345678(%eax)",}, +{{0x62, 0x98, 0x78, 0x56, 0x34, 0x12, }, 6, 0, "", "", +"62 98 78 56 34 12 \tbound %ebx,0x12345678(%eax)",}, +{{0x62, 0xa0, 0x78, 0x56, 0x34, 0x12, }, 6, 0, "", "", +"62 a0 78 56 34 12 \tbound %esp,0x12345678(%eax)",}, +{{0x62, 0xa8, 0x78, 0x56, 0x34, 0x12, }, 6, 0, "", "", +"62 a8 78 56 34 12 \tbound %ebp,0x12345678(%eax)",}, +{{0x62, 0xb0, 0x78, 0x56, 0x34, 0x12, }, 6, 0, "", "", +"62 b0 78 56 34 12 \tbound %esi,0x12345678(%eax)",}, +{{0x62, 0xb8, 0x78, 0x56, 0x34, 0x12, }, 6, 0, "", "", +"62 b8 78 56 34 12 \tbound %edi,0x12345678(%eax)",}, +{{0x62, 0x08, }, 2, 0, "", "", +"62 08 \tbound %ecx,(%eax)",}, +{{0x62, 0x05, 0x78, 0x56, 0x34, 0x12, }, 6, 0, "", "", +"62 05 78 56 34 12 \tbound %eax,0x12345678",}, +{{0x62, 0x14, 0x01, }, 3, 0, "", "", +"62 14 01 \tbound %edx,(%ecx,%eax,1)",}, +{{0x62, 0x14, 0x05, 0x78, 0x56, 0x34, 0x12, }, 7, 0, "", "", +"62 14 05 78 56 34 12 \tbound %edx,0x12345678(,%eax,1)",}, +{{0x62, 0x14, 0x08, }, 3, 0, "", "", +"62 14 08 \tbound %edx,(%eax,%ecx,1)",}, +{{0x62, 0x14, 0xc8, }, 3, 0, "", "", +"62 14 c8 \tbound %edx,(%eax,%ecx,8)",}, +{{0x62, 0x50, 0x12, }, 3, 0, "", "", +"62 50 12 \tbound %edx,0x12(%eax)",}, +{{0x62, 0x55, 0x12, }, 3, 0, "", "", +"62 55 12 \tbound %edx,0x12(%ebp)",}, +{{0x62, 0x54, 0x01, 0x12, }, 4, 0, "", "", +"62 54 01 12 \tbound %edx,0x12(%ecx,%eax,1)",}, +{{0x62, 0x54, 0x05, 0x12, }, 4, 0, "", "", +"62 54 05 12 \tbound %edx,0x12(%ebp,%eax,1)",}, +{{0x62, 0x54, 0x08, 0x12, }, 4, 0, "", "", +"62 54 08 12 \tbound %edx,0x12(%eax,%ecx,1)",}, +{{0x62, 0x54, 0xc8, 0x12, }, 4, 0, "", "", +"62 54 c8 12 \tbound %edx,0x12(%eax,%ecx,8)",}, +{{0x62, 0x90, 0x78, 0x56, 0x34, 0x12, }, 6, 0, "", "", +"62 90 78 56 34 12 \tbound %edx,0x12345678(%eax)",}, +{{0x62, 0x95, 0x78, 0x56, 0x34, 0x12, }, 6, 0, "", "", +"62 95 78 56 34 12 \tbound %edx,0x12345678(%ebp)",}, +{{0x62, 0x94, 0x01, 0x78, 0x56, 0x34, 0x12, }, 7, 0, "", "", +"62 94 01 78 56 34 12 \tbound %edx,0x12345678(%ecx,%eax,1)",}, +{{0x62, 0x94, 0x05, 0x78, 0x56, 0x34, 0x12, }, 7, 0, "", "", +"62 94 05 78 56 34 12 \tbound %edx,0x12345678(%ebp,%eax,1)",}, +{{0x62, 0x94, 0x08, 0x78, 0x56, 0x34, 0x12, }, 7, 0, "", "", +"62 94 08 78 56 34 12 \tbound %edx,0x12345678(%eax,%ecx,1)",}, +{{0x62, 0x94, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 7, 0, "", "", +"62 94 c8 78 56 34 12 \tbound %edx,0x12345678(%eax,%ecx,8)",}, +{{0x66, 0x62, 0x81, 0x78, 0x56, 0x34, 0x12, }, 7, 0, "", "", +"66 62 81 78 56 34 12 \tbound %ax,0x12345678(%ecx)",}, +{{0x66, 0x62, 0x88, 0x78, 0x56, 0x34, 0x12, }, 7, 0, "", "", +"66 62 88 78 56 34 12 \tbound %cx,0x12345678(%eax)",}, +{{0x66, 0x62, 0x90, 0x78, 0x56, 0x34, 0x12, }, 7, 0, "", "", +"66 62 90 78 56 34 12 \tbound %dx,0x12345678(%eax)",}, +{{0x66, 0x62, 0x98, 0x78, 0x56, 0x34, 0x12, }, 7, 0, "", "", +"66 62 98 78 56 34 12 \tbound %bx,0x12345678(%eax)",}, +{{0x66, 0x62, 0xa0, 0x78, 0x56, 0x34, 0x12, }, 7, 0, "", "", +"66 62 a0 78 56 34 12 \tbound %sp,0x12345678(%eax)",}, +{{0x66, 0x62, 0xa8, 0x78, 0x56, 0x34, 0x12, }, 7, 0, "", "", +"66 62 a8 78 56 34 12 \tbound %bp,0x12345678(%eax)",}, +{{0x66, 0x62, 0xb0, 0x78, 0x56, 0x34, 0x12, }, 7, 0, "", "", +"66 62 b0 78 56 34 12 \tbound %si,0x12345678(%eax)",}, +{{0x66, 0x62, 0xb8, 0x78, 0x56, 0x34, 0x12, }, 7, 0, "", "", +"66 62 b8 78 56 34 12 \tbound %di,0x12345678(%eax)",}, +{{0x66, 0x62, 0x08, }, 3, 0, "", "", +"66 62 08 \tbound %cx,(%eax)",}, +{{0x66, 0x62, 0x05, 0x78, 0x56, 0x34, 0x12, }, 7, 0, "", "", +"66 62 05 78 56 34 12 \tbound %ax,0x12345678",}, +{{0x66, 0x62, 0x14, 0x01, }, 4, 0, "", "", +"66 62 14 01 \tbound %dx,(%ecx,%eax,1)",}, +{{0x66, 0x62, 0x14, 0x05, 0x78, 0x56, 0x34, 0x12, }, 8, 0, "", "", +"66 62 14 05 78 56 34 12 \tbound %dx,0x12345678(,%eax,1)",}, +{{0x66, 0x62, 0x14, 0x08, }, 4, 0, "", "", +"66 62 14 08 \tbound %dx,(%eax,%ecx,1)",}, +{{0x66, 0x62, 0x14, 0xc8, }, 4, 0, "", "", +"66 62 14 c8 \tbound %dx,(%eax,%ecx,8)",}, +{{0x66, 0x62, 0x50, 0x12, }, 4, 0, "", "", +"66 62 50 12 \tbound %dx,0x12(%eax)",}, +{{0x66, 0x62, 0x55, 0x12, }, 4, 0, "", "", +"66 62 55 12 \tbound %dx,0x12(%ebp)",}, +{{0x66, 0x62, 0x54, 0x01, 0x12, }, 5, 0, "", "", +"66 62 54 01 12 \tbound %dx,0x12(%ecx,%eax,1)",}, +{{0x66, 0x62, 0x54, 0x05, 0x12, }, 5, 0, "", "", +"66 62 54 05 12 \tbound %dx,0x12(%ebp,%eax,1)",}, +{{0x66, 0x62, 0x54, 0x08, 0x12, }, 5, 0, "", "", +"66 62 54 08 12 \tbound %dx,0x12(%eax,%ecx,1)",}, +{{0x66, 0x62, 0x54, 0xc8, 0x12, }, 5, 0, "", "", +"66 62 54 c8 12 \tbound %dx,0x12(%eax,%ecx,8)",}, +{{0x66, 0x62, 0x90, 0x78, 0x56, 0x34, 0x12, }, 7, 0, "", "", +"66 62 90 78 56 34 12 \tbound %dx,0x12345678(%eax)",}, +{{0x66, 0x62, 0x95, 0x78, 0x56, 0x34, 0x12, }, 7, 0, "", "", +"66 62 95 78 56 34 12 \tbound %dx,0x12345678(%ebp)",}, +{{0x66, 0x62, 0x94, 0x01, 0x78, 0x56, 0x34, 0x12, }, 8, 0, "", "", +"66 62 94 01 78 56 34 12 \tbound %dx,0x12345678(%ecx,%eax,1)",}, +{{0x66, 0x62, 0x94, 0x05, 0x78, 0x56, 0x34, 0x12, }, 8, 0, "", "", +"66 62 94 05 78 56 34 12 \tbound %dx,0x12345678(%ebp,%eax,1)",}, +{{0x66, 0x62, 0x94, 0x08, 0x78, 0x56, 0x34, 0x12, }, 8, 0, "", "", +"66 62 94 08 78 56 34 12 \tbound %dx,0x12345678(%eax,%ecx,1)",}, +{{0x66, 0x62, 0x94, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 8, 0, "", "", +"66 62 94 c8 78 56 34 12 \tbound %dx,0x12345678(%eax,%ecx,8)",}, +{{0x0f, 0x41, 0xd8, }, 3, 0, "", "", +"0f 41 d8 \tcmovno %eax,%ebx",}, +{{0x0f, 0x41, 0x88, 0x78, 0x56, 0x34, 0x12, }, 7, 0, "", "", +"0f 41 88 78 56 34 12 \tcmovno 0x12345678(%eax),%ecx",}, +{{0x66, 0x0f, 0x41, 0x88, 0x78, 0x56, 0x34, 0x12, }, 8, 0, "", "", +"66 0f 41 88 78 56 34 12 \tcmovno 0x12345678(%eax),%cx",}, +{{0x0f, 0x44, 0xd8, }, 3, 0, "", "", +"0f 44 d8 \tcmove %eax,%ebx",}, +{{0x0f, 0x44, 0x88, 0x78, 0x56, 0x34, 0x12, }, 7, 0, "", "", +"0f 44 88 78 56 34 12 \tcmove 0x12345678(%eax),%ecx",}, +{{0x66, 0x0f, 0x44, 0x88, 0x78, 0x56, 0x34, 0x12, }, 8, 0, "", "", +"66 0f 44 88 78 56 34 12 \tcmove 0x12345678(%eax),%cx",}, +{{0x0f, 0x90, 0x80, 0x78, 0x56, 0x34, 0x12, }, 7, 0, "", "", +"0f 90 80 78 56 34 12 \tseto 0x12345678(%eax)",}, +{{0x0f, 0x91, 0x80, 0x78, 0x56, 0x34, 0x12, }, 7, 0, "", "", +"0f 91 80 78 56 34 12 \tsetno 0x12345678(%eax)",}, +{{0x0f, 0x92, 0x80, 0x78, 0x56, 0x34, 0x12, }, 7, 0, "", "", +"0f 92 80 78 56 34 12 \tsetb 0x12345678(%eax)",}, +{{0x0f, 0x92, 0x80, 0x78, 0x56, 0x34, 0x12, }, 7, 0, "", "", +"0f 92 80 78 56 34 12 \tsetb 0x12345678(%eax)",}, +{{0x0f, 0x92, 0x80, 0x78, 0x56, 0x34, 0x12, }, 7, 0, "", "", +"0f 92 80 78 56 34 12 \tsetb 0x12345678(%eax)",}, +{{0x0f, 0x93, 0x80, 0x78, 0x56, 0x34, 0x12, }, 7, 0, "", "", +"0f 93 80 78 56 34 12 \tsetae 0x12345678(%eax)",}, +{{0x0f, 0x93, 0x80, 0x78, 0x56, 0x34, 0x12, }, 7, 0, "", "", +"0f 93 80 78 56 34 12 \tsetae 0x12345678(%eax)",}, +{{0x0f, 0x93, 0x80, 0x78, 0x56, 0x34, 0x12, }, 7, 0, "", "", +"0f 93 80 78 56 34 12 \tsetae 0x12345678(%eax)",}, +{{0x0f, 0x98, 0x80, 0x78, 0x56, 0x34, 0x12, }, 7, 0, "", "", +"0f 98 80 78 56 34 12 \tsets 0x12345678(%eax)",}, +{{0x0f, 0x99, 0x80, 0x78, 0x56, 0x34, 0x12, }, 7, 0, "", "", +"0f 99 80 78 56 34 12 \tsetns 0x12345678(%eax)",}, +{{0xc5, 0xcc, 0x41, 0xef, }, 4, 0, "", "", +"c5 cc 41 ef \tkandw %k7,%k6,%k5",}, +{{0xc4, 0xe1, 0xcc, 0x41, 0xef, }, 5, 0, "", "", +"c4 e1 cc 41 ef \tkandq %k7,%k6,%k5",}, +{{0xc5, 0xcd, 0x41, 0xef, }, 4, 0, "", "", +"c5 cd 41 ef \tkandb %k7,%k6,%k5",}, +{{0xc4, 0xe1, 0xcd, 0x41, 0xef, }, 5, 0, "", "", +"c4 e1 cd 41 ef \tkandd %k7,%k6,%k5",}, +{{0xc5, 0xcc, 0x42, 0xef, }, 4, 0, "", "", +"c5 cc 42 ef \tkandnw %k7,%k6,%k5",}, +{{0xc4, 0xe1, 0xcc, 0x42, 0xef, }, 5, 0, "", "", +"c4 e1 cc 42 ef \tkandnq %k7,%k6,%k5",}, +{{0xc5, 0xcd, 0x42, 0xef, }, 4, 0, "", "", +"c5 cd 42 ef \tkandnb %k7,%k6,%k5",}, +{{0xc4, 0xe1, 0xcd, 0x42, 0xef, }, 5, 0, "", "", +"c4 e1 cd 42 ef \tkandnd %k7,%k6,%k5",}, +{{0xc5, 0xf8, 0x44, 0xf7, }, 4, 0, "", "", +"c5 f8 44 f7 \tknotw %k7,%k6",}, +{{0xc4, 0xe1, 0xf8, 0x44, 0xf7, }, 5, 0, "", "", +"c4 e1 f8 44 f7 \tknotq %k7,%k6",}, +{{0xc5, 0xf9, 0x44, 0xf7, }, 4, 0, "", "", +"c5 f9 44 f7 \tknotb %k7,%k6",}, +{{0xc4, 0xe1, 0xf9, 0x44, 0xf7, }, 5, 0, "", "", +"c4 e1 f9 44 f7 \tknotd %k7,%k6",}, +{{0xc5, 0xcc, 0x45, 0xef, }, 4, 0, "", "", +"c5 cc 45 ef \tkorw %k7,%k6,%k5",}, +{{0xc4, 0xe1, 0xcc, 0x45, 0xef, }, 5, 0, "", "", +"c4 e1 cc 45 ef \tkorq %k7,%k6,%k5",}, +{{0xc5, 0xcd, 0x45, 0xef, }, 4, 0, "", "", +"c5 cd 45 ef \tkorb %k7,%k6,%k5",}, +{{0xc4, 0xe1, 0xcd, 0x45, 0xef, }, 5, 0, "", "", +"c4 e1 cd 45 ef \tkord %k7,%k6,%k5",}, +{{0xc5, 0xcc, 0x46, 0xef, }, 4, 0, "", "", +"c5 cc 46 ef \tkxnorw %k7,%k6,%k5",}, +{{0xc4, 0xe1, 0xcc, 0x46, 0xef, }, 5, 0, "", "", +"c4 e1 cc 46 ef \tkxnorq %k7,%k6,%k5",}, +{{0xc5, 0xcd, 0x46, 0xef, }, 4, 0, "", "", +"c5 cd 46 ef \tkxnorb %k7,%k6,%k5",}, +{{0xc4, 0xe1, 0xcd, 0x46, 0xef, }, 5, 0, "", "", +"c4 e1 cd 46 ef \tkxnord %k7,%k6,%k5",}, +{{0xc5, 0xcc, 0x47, 0xef, }, 4, 0, "", "", +"c5 cc 47 ef \tkxorw %k7,%k6,%k5",}, +{{0xc4, 0xe1, 0xcc, 0x47, 0xef, }, 5, 0, "", "", +"c4 e1 cc 47 ef \tkxorq %k7,%k6,%k5",}, +{{0xc5, 0xcd, 0x47, 0xef, }, 4, 0, "", "", +"c5 cd 47 ef \tkxorb %k7,%k6,%k5",}, +{{0xc4, 0xe1, 0xcd, 0x47, 0xef, }, 5, 0, "", "", +"c4 e1 cd 47 ef \tkxord %k7,%k6,%k5",}, +{{0xc5, 0xcc, 0x4a, 0xef, }, 4, 0, "", "", +"c5 cc 4a ef \tkaddw %k7,%k6,%k5",}, +{{0xc4, 0xe1, 0xcc, 0x4a, 0xef, }, 5, 0, "", "", +"c4 e1 cc 4a ef \tkaddq %k7,%k6,%k5",}, +{{0xc5, 0xcd, 0x4a, 0xef, }, 4, 0, "", "", +"c5 cd 4a ef \tkaddb %k7,%k6,%k5",}, +{{0xc4, 0xe1, 0xcd, 0x4a, 0xef, }, 5, 0, "", "", +"c4 e1 cd 4a ef \tkaddd %k7,%k6,%k5",}, +{{0xc5, 0xcd, 0x4b, 0xef, }, 4, 0, "", "", +"c5 cd 4b ef \tkunpckbw %k7,%k6,%k5",}, +{{0xc5, 0xcc, 0x4b, 0xef, }, 4, 0, "", "", +"c5 cc 4b ef \tkunpckwd %k7,%k6,%k5",}, +{{0xc4, 0xe1, 0xcc, 0x4b, 0xef, }, 5, 0, "", "", +"c4 e1 cc 4b ef \tkunpckdq %k7,%k6,%k5",}, +{{0xc5, 0xf8, 0x90, 0xee, }, 4, 0, "", "", +"c5 f8 90 ee \tkmovw %k6,%k5",}, +{{0xc5, 0xf8, 0x90, 0x29, }, 4, 0, "", "", +"c5 f8 90 29 \tkmovw (%ecx),%k5",}, +{{0xc5, 0xf8, 0x90, 0xac, 0xc8, 0x23, 0x01, 0x00, 0x00, }, 9, 0, "", "", +"c5 f8 90 ac c8 23 01 00 00 \tkmovw 0x123(%eax,%ecx,8),%k5",}, +{{0xc5, 0xf8, 0x91, 0x29, }, 4, 0, "", "", +"c5 f8 91 29 \tkmovw %k5,(%ecx)",}, +{{0xc5, 0xf8, 0x91, 0xac, 0xc8, 0x23, 0x01, 0x00, 0x00, }, 9, 0, "", "", +"c5 f8 91 ac c8 23 01 00 00 \tkmovw %k5,0x123(%eax,%ecx,8)",}, +{{0xc5, 0xf8, 0x92, 0xe8, }, 4, 0, "", "", +"c5 f8 92 e8 \tkmovw %eax,%k5",}, +{{0xc5, 0xf8, 0x92, 0xed, }, 4, 0, "", "", +"c5 f8 92 ed \tkmovw %ebp,%k5",}, +{{0xc5, 0xf8, 0x93, 0xc5, }, 4, 0, "", "", +"c5 f8 93 c5 \tkmovw %k5,%eax",}, +{{0xc5, 0xf8, 0x93, 0xed, }, 4, 0, "", "", +"c5 f8 93 ed \tkmovw %k5,%ebp",}, +{{0xc4, 0xe1, 0xf8, 0x90, 0xee, }, 5, 0, "", "", +"c4 e1 f8 90 ee \tkmovq %k6,%k5",}, +{{0xc4, 0xe1, 0xf8, 0x90, 0x29, }, 5, 0, "", "", +"c4 e1 f8 90 29 \tkmovq (%ecx),%k5",}, +{{0xc4, 0xe1, 0xf8, 0x90, 0xac, 0xc8, 0x23, 0x01, 0x00, 0x00, }, 10, 0, "", "", +"c4 e1 f8 90 ac c8 23 01 00 00 \tkmovq 0x123(%eax,%ecx,8),%k5",}, +{{0xc4, 0xe1, 0xf8, 0x91, 0x29, }, 5, 0, "", "", +"c4 e1 f8 91 29 \tkmovq %k5,(%ecx)",}, +{{0xc4, 0xe1, 0xf8, 0x91, 0xac, 0xc8, 0x23, 0x01, 0x00, 0x00, }, 10, 0, "", "", +"c4 e1 f8 91 ac c8 23 01 00 00 \tkmovq %k5,0x123(%eax,%ecx,8)",}, +{{0xc5, 0xf9, 0x90, 0xee, }, 4, 0, "", "", +"c5 f9 90 ee \tkmovb %k6,%k5",}, +{{0xc5, 0xf9, 0x90, 0x29, }, 4, 0, "", "", +"c5 f9 90 29 \tkmovb (%ecx),%k5",}, +{{0xc5, 0xf9, 0x90, 0xac, 0xc8, 0x23, 0x01, 0x00, 0x00, }, 9, 0, "", "", +"c5 f9 90 ac c8 23 01 00 00 \tkmovb 0x123(%eax,%ecx,8),%k5",}, +{{0xc5, 0xf9, 0x91, 0x29, }, 4, 0, "", "", +"c5 f9 91 29 \tkmovb %k5,(%ecx)",}, +{{0xc5, 0xf9, 0x91, 0xac, 0xc8, 0x23, 0x01, 0x00, 0x00, }, 9, 0, "", "", +"c5 f9 91 ac c8 23 01 00 00 \tkmovb %k5,0x123(%eax,%ecx,8)",}, +{{0xc5, 0xf9, 0x92, 0xe8, }, 4, 0, "", "", +"c5 f9 92 e8 \tkmovb %eax,%k5",}, +{{0xc5, 0xf9, 0x92, 0xed, }, 4, 0, "", "", +"c5 f9 92 ed \tkmovb %ebp,%k5",}, +{{0xc5, 0xf9, 0x93, 0xc5, }, 4, 0, "", "", +"c5 f9 93 c5 \tkmovb %k5,%eax",}, +{{0xc5, 0xf9, 0x93, 0xed, }, 4, 0, "", "", +"c5 f9 93 ed \tkmovb %k5,%ebp",}, +{{0xc4, 0xe1, 0xf9, 0x90, 0xee, }, 5, 0, "", "", +"c4 e1 f9 90 ee \tkmovd %k6,%k5",}, +{{0xc4, 0xe1, 0xf9, 0x90, 0x29, }, 5, 0, "", "", +"c4 e1 f9 90 29 \tkmovd (%ecx),%k5",}, +{{0xc4, 0xe1, 0xf9, 0x90, 0xac, 0xc8, 0x23, 0x01, 0x00, 0x00, }, 10, 0, "", "", +"c4 e1 f9 90 ac c8 23 01 00 00 \tkmovd 0x123(%eax,%ecx,8),%k5",}, +{{0xc4, 0xe1, 0xf9, 0x91, 0x29, }, 5, 0, "", "", +"c4 e1 f9 91 29 \tkmovd %k5,(%ecx)",}, +{{0xc4, 0xe1, 0xf9, 0x91, 0xac, 0xc8, 0x23, 0x01, 0x00, 0x00, }, 10, 0, "", "", +"c4 e1 f9 91 ac c8 23 01 00 00 \tkmovd %k5,0x123(%eax,%ecx,8)",}, +{{0xc5, 0xfb, 0x92, 0xe8, }, 4, 0, "", "", +"c5 fb 92 e8 \tkmovd %eax,%k5",}, +{{0xc5, 0xfb, 0x92, 0xed, }, 4, 0, "", "", +"c5 fb 92 ed \tkmovd %ebp,%k5",}, +{{0xc5, 0xfb, 0x93, 0xc5, }, 4, 0, "", "", +"c5 fb 93 c5 \tkmovd %k5,%eax",}, +{{0xc5, 0xfb, 0x93, 0xed, }, 4, 0, "", "", +"c5 fb 93 ed \tkmovd %k5,%ebp",}, +{{0xc5, 0xf8, 0x98, 0xee, }, 4, 0, "", "", +"c5 f8 98 ee \tkortestw %k6,%k5",}, +{{0xc4, 0xe1, 0xf8, 0x98, 0xee, }, 5, 0, "", "", +"c4 e1 f8 98 ee \tkortestq %k6,%k5",}, +{{0xc5, 0xf9, 0x98, 0xee, }, 4, 0, "", "", +"c5 f9 98 ee \tkortestb %k6,%k5",}, +{{0xc4, 0xe1, 0xf9, 0x98, 0xee, }, 5, 0, "", "", +"c4 e1 f9 98 ee \tkortestd %k6,%k5",}, +{{0xc5, 0xf8, 0x99, 0xee, }, 4, 0, "", "", +"c5 f8 99 ee \tktestw %k6,%k5",}, +{{0xc4, 0xe1, 0xf8, 0x99, 0xee, }, 5, 0, "", "", +"c4 e1 f8 99 ee \tktestq %k6,%k5",}, +{{0xc5, 0xf9, 0x99, 0xee, }, 4, 0, "", "", +"c5 f9 99 ee \tktestb %k6,%k5",}, +{{0xc4, 0xe1, 0xf9, 0x99, 0xee, }, 5, 0, "", "", +"c4 e1 f9 99 ee \tktestd %k6,%k5",}, +{{0xc4, 0xe3, 0xf9, 0x30, 0xee, 0x12, }, 6, 0, "", "", +"c4 e3 f9 30 ee 12 \tkshiftrw $0x12,%k6,%k5",}, +{{0xc4, 0xe3, 0xf9, 0x31, 0xee, 0x5b, }, 6, 0, "", "", +"c4 e3 f9 31 ee 5b \tkshiftrq $0x5b,%k6,%k5",}, +{{0xc4, 0xe3, 0xf9, 0x32, 0xee, 0x12, }, 6, 0, "", "", +"c4 e3 f9 32 ee 12 \tkshiftlw $0x12,%k6,%k5",}, +{{0xc4, 0xe3, 0xf9, 0x33, 0xee, 0x5b, }, 6, 0, "", "", +"c4 e3 f9 33 ee 5b \tkshiftlq $0x5b,%k6,%k5",}, +{{0xc5, 0xf8, 0x5b, 0xf5, }, 4, 0, "", "", +"c5 f8 5b f5 \tvcvtdq2ps %xmm5,%xmm6",}, +{{0x62, 0xf1, 0xfc, 0x4f, 0x5b, 0xf5, }, 6, 0, "", "", +"62 f1 fc 4f 5b f5 \tvcvtqq2ps %zmm5,%ymm6{%k7}",}, +{{0xc5, 0xf9, 0x5b, 0xf5, }, 4, 0, "", "", +"c5 f9 5b f5 \tvcvtps2dq %xmm5,%xmm6",}, +{{0xc5, 0xfa, 0x5b, 0xf5, }, 4, 0, "", "", +"c5 fa 5b f5 \tvcvttps2dq %xmm5,%xmm6",}, +{{0x0f, 0x6f, 0xe0, }, 3, 0, "", "", +"0f 6f e0 \tmovq %mm0,%mm4",}, +{{0xc5, 0xfd, 0x6f, 0xf4, }, 4, 0, "", "", +"c5 fd 6f f4 \tvmovdqa %ymm4,%ymm6",}, +{{0x62, 0xf1, 0x7d, 0x48, 0x6f, 0xf5, }, 6, 0, "", "", +"62 f1 7d 48 6f f5 \tvmovdqa32 %zmm5,%zmm6",}, +{{0x62, 0xf1, 0xfd, 0x48, 0x6f, 0xf5, }, 6, 0, "", "", +"62 f1 fd 48 6f f5 \tvmovdqa64 %zmm5,%zmm6",}, +{{0xc5, 0xfe, 0x6f, 0xf4, }, 4, 0, "", "", +"c5 fe 6f f4 \tvmovdqu %ymm4,%ymm6",}, +{{0x62, 0xf1, 0x7e, 0x48, 0x6f, 0xf5, }, 6, 0, "", "", +"62 f1 7e 48 6f f5 \tvmovdqu32 %zmm5,%zmm6",}, +{{0x62, 0xf1, 0xfe, 0x48, 0x6f, 0xf5, }, 6, 0, "", "", +"62 f1 fe 48 6f f5 \tvmovdqu64 %zmm5,%zmm6",}, +{{0x62, 0xf1, 0x7f, 0x48, 0x6f, 0xf5, }, 6, 0, "", "", +"62 f1 7f 48 6f f5 \tvmovdqu8 %zmm5,%zmm6",}, +{{0x62, 0xf1, 0xff, 0x48, 0x6f, 0xf5, }, 6, 0, "", "", +"62 f1 ff 48 6f f5 \tvmovdqu16 %zmm5,%zmm6",}, +{{0x0f, 0x78, 0xc3, }, 3, 0, "", "", +"0f 78 c3 \tvmread %eax,%ebx",}, +{{0x62, 0xf1, 0x7c, 0x48, 0x78, 0xf5, }, 6, 0, "", "", +"62 f1 7c 48 78 f5 \tvcvttps2udq %zmm5,%zmm6",}, +{{0x62, 0xf1, 0xfc, 0x4f, 0x78, 0xf5, }, 6, 0, "", "", +"62 f1 fc 4f 78 f5 \tvcvttpd2udq %zmm5,%ymm6{%k7}",}, +{{0x62, 0xf1, 0x7f, 0x08, 0x78, 0xc6, }, 6, 0, "", "", +"62 f1 7f 08 78 c6 \tvcvttsd2usi %xmm6,%eax",}, +{{0x62, 0xf1, 0x7e, 0x08, 0x78, 0xc6, }, 6, 0, "", "", +"62 f1 7e 08 78 c6 \tvcvttss2usi %xmm6,%eax",}, +{{0x62, 0xf1, 0x7d, 0x4f, 0x78, 0xf5, }, 6, 0, "", "", +"62 f1 7d 4f 78 f5 \tvcvttps2uqq %ymm5,%zmm6{%k7}",}, +{{0x62, 0xf1, 0xfd, 0x48, 0x78, 0xf5, }, 6, 0, "", "", +"62 f1 fd 48 78 f5 \tvcvttpd2uqq %zmm5,%zmm6",}, +{{0x0f, 0x79, 0xd8, }, 3, 0, "", "", +"0f 79 d8 \tvmwrite %eax,%ebx",}, +{{0x62, 0xf1, 0x7c, 0x48, 0x79, 0xf5, }, 6, 0, "", "", +"62 f1 7c 48 79 f5 \tvcvtps2udq %zmm5,%zmm6",}, +{{0x62, 0xf1, 0xfc, 0x4f, 0x79, 0xf5, }, 6, 0, "", "", +"62 f1 fc 4f 79 f5 \tvcvtpd2udq %zmm5,%ymm6{%k7}",}, +{{0x62, 0xf1, 0x7f, 0x08, 0x79, 0xc6, }, 6, 0, "", "", +"62 f1 7f 08 79 c6 \tvcvtsd2usi %xmm6,%eax",}, +{{0x62, 0xf1, 0x7e, 0x08, 0x79, 0xc6, }, 6, 0, "", "", +"62 f1 7e 08 79 c6 \tvcvtss2usi %xmm6,%eax",}, +{{0x62, 0xf1, 0x7d, 0x4f, 0x79, 0xf5, }, 6, 0, "", "", +"62 f1 7d 4f 79 f5 \tvcvtps2uqq %ymm5,%zmm6{%k7}",}, +{{0x62, 0xf1, 0xfd, 0x48, 0x79, 0xf5, }, 6, 0, "", "", +"62 f1 fd 48 79 f5 \tvcvtpd2uqq %zmm5,%zmm6",}, +{{0x62, 0xf1, 0x7e, 0x4f, 0x7a, 0xf5, }, 6, 0, "", "", +"62 f1 7e 4f 7a f5 \tvcvtudq2pd %ymm5,%zmm6{%k7}",}, +{{0x62, 0xf1, 0xfe, 0x48, 0x7a, 0xf5, }, 6, 0, "", "", +"62 f1 fe 48 7a f5 \tvcvtuqq2pd %zmm5,%zmm6",}, +{{0x62, 0xf1, 0x7f, 0x48, 0x7a, 0xf5, }, 6, 0, "", "", +"62 f1 7f 48 7a f5 \tvcvtudq2ps %zmm5,%zmm6",}, +{{0x62, 0xf1, 0xff, 0x4f, 0x7a, 0xf5, }, 6, 0, "", "", +"62 f1 ff 4f 7a f5 \tvcvtuqq2ps %zmm5,%ymm6{%k7}",}, +{{0x62, 0xf1, 0x7d, 0x4f, 0x7a, 0xf5, }, 6, 0, "", "", +"62 f1 7d 4f 7a f5 \tvcvttps2qq %ymm5,%zmm6{%k7}",}, +{{0x62, 0xf1, 0xfd, 0x48, 0x7a, 0xf5, }, 6, 0, "", "", +"62 f1 fd 48 7a f5 \tvcvttpd2qq %zmm5,%zmm6",}, +{{0x62, 0xf1, 0x57, 0x08, 0x7b, 0xf0, }, 6, 0, "", "", +"62 f1 57 08 7b f0 \tvcvtusi2sd %eax,%xmm5,%xmm6",}, +{{0x62, 0xf1, 0x56, 0x08, 0x7b, 0xf0, }, 6, 0, "", "", +"62 f1 56 08 7b f0 \tvcvtusi2ss %eax,%xmm5,%xmm6",}, +{{0x62, 0xf1, 0x7d, 0x4f, 0x7b, 0xf5, }, 6, 0, "", "", +"62 f1 7d 4f 7b f5 \tvcvtps2qq %ymm5,%zmm6{%k7}",}, +{{0x62, 0xf1, 0xfd, 0x48, 0x7b, 0xf5, }, 6, 0, "", "", +"62 f1 fd 48 7b f5 \tvcvtpd2qq %zmm5,%zmm6",}, +{{0x0f, 0x7f, 0xc4, }, 3, 0, "", "", +"0f 7f c4 \tmovq %mm0,%mm4",}, +{{0xc5, 0xfd, 0x7f, 0xee, }, 4, 0, "", "", +"c5 fd 7f ee \tvmovdqa %ymm5,%ymm6",}, +{{0x62, 0xf1, 0x7d, 0x48, 0x7f, 0xee, }, 6, 0, "", "", +"62 f1 7d 48 7f ee \tvmovdqa32 %zmm5,%zmm6",}, +{{0x62, 0xf1, 0xfd, 0x48, 0x7f, 0xee, }, 6, 0, "", "", +"62 f1 fd 48 7f ee \tvmovdqa64 %zmm5,%zmm6",}, +{{0xc5, 0xfe, 0x7f, 0xee, }, 4, 0, "", "", +"c5 fe 7f ee \tvmovdqu %ymm5,%ymm6",}, +{{0x62, 0xf1, 0x7e, 0x48, 0x7f, 0xee, }, 6, 0, "", "", +"62 f1 7e 48 7f ee \tvmovdqu32 %zmm5,%zmm6",}, +{{0x62, 0xf1, 0xfe, 0x48, 0x7f, 0xee, }, 6, 0, "", "", +"62 f1 fe 48 7f ee \tvmovdqu64 %zmm5,%zmm6",}, +{{0x62, 0xf1, 0x7f, 0x48, 0x7f, 0xee, }, 6, 0, "", "", +"62 f1 7f 48 7f ee \tvmovdqu8 %zmm5,%zmm6",}, +{{0x62, 0xf1, 0xff, 0x48, 0x7f, 0xee, }, 6, 0, "", "", +"62 f1 ff 48 7f ee \tvmovdqu16 %zmm5,%zmm6",}, +{{0x0f, 0xdb, 0xd1, }, 3, 0, "", "", +"0f db d1 \tpand %mm1,%mm2",}, +{{0x66, 0x0f, 0xdb, 0xd1, }, 4, 0, "", "", +"66 0f db d1 \tpand %xmm1,%xmm2",}, +{{0xc5, 0xcd, 0xdb, 0xd4, }, 4, 0, "", "", +"c5 cd db d4 \tvpand %ymm4,%ymm6,%ymm2",}, +{{0x62, 0xf1, 0x55, 0x48, 0xdb, 0xf4, }, 6, 0, "", "", +"62 f1 55 48 db f4 \tvpandd %zmm4,%zmm5,%zmm6",}, +{{0x62, 0xf1, 0xd5, 0x48, 0xdb, 0xf4, }, 6, 0, "", "", +"62 f1 d5 48 db f4 \tvpandq %zmm4,%zmm5,%zmm6",}, +{{0x0f, 0xdf, 0xd1, }, 3, 0, "", "", +"0f df d1 \tpandn %mm1,%mm2",}, +{{0x66, 0x0f, 0xdf, 0xd1, }, 4, 0, "", "", +"66 0f df d1 \tpandn %xmm1,%xmm2",}, +{{0xc5, 0xcd, 0xdf, 0xd4, }, 4, 0, "", "", +"c5 cd df d4 \tvpandn %ymm4,%ymm6,%ymm2",}, +{{0x62, 0xf1, 0x55, 0x48, 0xdf, 0xf4, }, 6, 0, "", "", +"62 f1 55 48 df f4 \tvpandnd %zmm4,%zmm5,%zmm6",}, +{{0x62, 0xf1, 0xd5, 0x48, 0xdf, 0xf4, }, 6, 0, "", "", +"62 f1 d5 48 df f4 \tvpandnq %zmm4,%zmm5,%zmm6",}, +{{0xc5, 0xf9, 0xe6, 0xd1, }, 4, 0, "", "", +"c5 f9 e6 d1 \tvcvttpd2dq %xmm1,%xmm2",}, +{{0xc5, 0xfa, 0xe6, 0xf5, }, 4, 0, "", "", +"c5 fa e6 f5 \tvcvtdq2pd %xmm5,%xmm6",}, +{{0x62, 0xf1, 0x7e, 0x4f, 0xe6, 0xf5, }, 6, 0, "", "", +"62 f1 7e 4f e6 f5 \tvcvtdq2pd %ymm5,%zmm6{%k7}",}, +{{0x62, 0xf1, 0xfe, 0x48, 0xe6, 0xf5, }, 6, 0, "", "", +"62 f1 fe 48 e6 f5 \tvcvtqq2pd %zmm5,%zmm6",}, +{{0xc5, 0xfb, 0xe6, 0xd1, }, 4, 0, "", "", +"c5 fb e6 d1 \tvcvtpd2dq %xmm1,%xmm2",}, +{{0x0f, 0xeb, 0xf4, }, 3, 0, "", "", +"0f eb f4 \tpor %mm4,%mm6",}, +{{0xc5, 0xcd, 0xeb, 0xd4, }, 4, 0, "", "", +"c5 cd eb d4 \tvpor %ymm4,%ymm6,%ymm2",}, +{{0x62, 0xf1, 0x55, 0x48, 0xeb, 0xf4, }, 6, 0, "", "", +"62 f1 55 48 eb f4 \tvpord %zmm4,%zmm5,%zmm6",}, +{{0x62, 0xf1, 0xd5, 0x48, 0xeb, 0xf4, }, 6, 0, "", "", +"62 f1 d5 48 eb f4 \tvporq %zmm4,%zmm5,%zmm6",}, +{{0x0f, 0xef, 0xf4, }, 3, 0, "", "", +"0f ef f4 \tpxor %mm4,%mm6",}, +{{0xc5, 0xcd, 0xef, 0xd4, }, 4, 0, "", "", +"c5 cd ef d4 \tvpxor %ymm4,%ymm6,%ymm2",}, +{{0x62, 0xf1, 0x55, 0x48, 0xef, 0xf4, }, 6, 0, "", "", +"62 f1 55 48 ef f4 \tvpxord %zmm4,%zmm5,%zmm6",}, +{{0x62, 0xf1, 0xd5, 0x48, 0xef, 0xf4, }, 6, 0, "", "", +"62 f1 d5 48 ef f4 \tvpxorq %zmm4,%zmm5,%zmm6",}, +{{0x66, 0x0f, 0x38, 0x10, 0xc1, }, 5, 0, "", "", +"66 0f 38 10 c1 \tpblendvb %xmm0,%xmm1,%xmm0",}, +{{0x62, 0xf2, 0xd5, 0x48, 0x10, 0xf4, }, 6, 0, "", "", +"62 f2 d5 48 10 f4 \tvpsrlvw %zmm4,%zmm5,%zmm6",}, +{{0x62, 0xf2, 0x7e, 0x4f, 0x10, 0xee, }, 6, 0, "", "", +"62 f2 7e 4f 10 ee \tvpmovuswb %zmm5,%ymm6{%k7}",}, +{{0x62, 0xf2, 0x7e, 0x4f, 0x11, 0xee, }, 6, 0, "", "", +"62 f2 7e 4f 11 ee \tvpmovusdb %zmm5,%xmm6{%k7}",}, +{{0x62, 0xf2, 0xd5, 0x48, 0x11, 0xf4, }, 6, 0, "", "", +"62 f2 d5 48 11 f4 \tvpsravw %zmm4,%zmm5,%zmm6",}, +{{0x62, 0xf2, 0x7e, 0x4f, 0x12, 0xee, }, 6, 0, "", "", +"62 f2 7e 4f 12 ee \tvpmovusqb %zmm5,%xmm6{%k7}",}, +{{0x62, 0xf2, 0xd5, 0x48, 0x12, 0xf4, }, 6, 0, "", "", +"62 f2 d5 48 12 f4 \tvpsllvw %zmm4,%zmm5,%zmm6",}, +{{0xc4, 0xe2, 0x7d, 0x13, 0xeb, }, 5, 0, "", "", +"c4 e2 7d 13 eb \tvcvtph2ps %xmm3,%ymm5",}, +{{0x62, 0xf2, 0x7d, 0x4f, 0x13, 0xf5, }, 6, 0, "", "", +"62 f2 7d 4f 13 f5 \tvcvtph2ps %ymm5,%zmm6{%k7}",}, +{{0x62, 0xf2, 0x7e, 0x4f, 0x13, 0xee, }, 6, 0, "", "", +"62 f2 7e 4f 13 ee \tvpmovusdw %zmm5,%ymm6{%k7}",}, +{{0x66, 0x0f, 0x38, 0x14, 0xc1, }, 5, 0, "", "", +"66 0f 38 14 c1 \tblendvps %xmm0,%xmm1,%xmm0",}, +{{0x62, 0xf2, 0x7e, 0x4f, 0x14, 0xee, }, 6, 0, "", "", +"62 f2 7e 4f 14 ee \tvpmovusqw %zmm5,%xmm6{%k7}",}, +{{0x62, 0xf2, 0x55, 0x48, 0x14, 0xf4, }, 6, 0, "", "", +"62 f2 55 48 14 f4 \tvprorvd %zmm4,%zmm5,%zmm6",}, +{{0x62, 0xf2, 0xd5, 0x48, 0x14, 0xf4, }, 6, 0, "", "", +"62 f2 d5 48 14 f4 \tvprorvq %zmm4,%zmm5,%zmm6",}, +{{0x66, 0x0f, 0x38, 0x15, 0xc1, }, 5, 0, "", "", +"66 0f 38 15 c1 \tblendvpd %xmm0,%xmm1,%xmm0",}, +{{0x62, 0xf2, 0x7e, 0x4f, 0x15, 0xee, }, 6, 0, "", "", +"62 f2 7e 4f 15 ee \tvpmovusqd %zmm5,%ymm6{%k7}",}, +{{0x62, 0xf2, 0x55, 0x48, 0x15, 0xf4, }, 6, 0, "", "", +"62 f2 55 48 15 f4 \tvprolvd %zmm4,%zmm5,%zmm6",}, +{{0x62, 0xf2, 0xd5, 0x48, 0x15, 0xf4, }, 6, 0, "", "", +"62 f2 d5 48 15 f4 \tvprolvq %zmm4,%zmm5,%zmm6",}, +{{0xc4, 0xe2, 0x4d, 0x16, 0xd4, }, 5, 0, "", "", +"c4 e2 4d 16 d4 \tvpermps %ymm4,%ymm6,%ymm2",}, +{{0x62, 0xf2, 0x4d, 0x2f, 0x16, 0xd4, }, 6, 0, "", "", +"62 f2 4d 2f 16 d4 \tvpermps %ymm4,%ymm6,%ymm2{%k7}",}, +{{0x62, 0xf2, 0xcd, 0x2f, 0x16, 0xd4, }, 6, 0, "", "", +"62 f2 cd 2f 16 d4 \tvpermpd %ymm4,%ymm6,%ymm2{%k7}",}, +{{0xc4, 0xe2, 0x7d, 0x19, 0xf4, }, 5, 0, "", "", +"c4 e2 7d 19 f4 \tvbroadcastsd %xmm4,%ymm6",}, +{{0x62, 0xf2, 0x7d, 0x48, 0x19, 0xf7, }, 6, 0, "", "", +"62 f2 7d 48 19 f7 \tvbroadcastf32x2 %xmm7,%zmm6",}, +{{0xc4, 0xe2, 0x7d, 0x1a, 0x21, }, 5, 0, "", "", +"c4 e2 7d 1a 21 \tvbroadcastf128 (%ecx),%ymm4",}, +{{0x62, 0xf2, 0x7d, 0x48, 0x1a, 0x31, }, 6, 0, "", "", +"62 f2 7d 48 1a 31 \tvbroadcastf32x4 (%ecx),%zmm6",}, +{{0x62, 0xf2, 0xfd, 0x48, 0x1a, 0x31, }, 6, 0, "", "", +"62 f2 fd 48 1a 31 \tvbroadcastf64x2 (%ecx),%zmm6",}, +{{0x62, 0xf2, 0x7d, 0x48, 0x1b, 0x31, }, 6, 0, "", "", +"62 f2 7d 48 1b 31 \tvbroadcastf32x8 (%ecx),%zmm6",}, +{{0x62, 0xf2, 0xfd, 0x48, 0x1b, 0x31, }, 6, 0, "", "", +"62 f2 fd 48 1b 31 \tvbroadcastf64x4 (%ecx),%zmm6",}, +{{0x62, 0xf2, 0xfd, 0x48, 0x1f, 0xf4, }, 6, 0, "", "", +"62 f2 fd 48 1f f4 \tvpabsq %zmm4,%zmm6",}, +{{0xc4, 0xe2, 0x79, 0x20, 0xec, }, 5, 0, "", "", +"c4 e2 79 20 ec \tvpmovsxbw %xmm4,%xmm5",}, +{{0x62, 0xf2, 0x7e, 0x4f, 0x20, 0xee, }, 6, 0, "", "", +"62 f2 7e 4f 20 ee \tvpmovswb %zmm5,%ymm6{%k7}",}, +{{0xc4, 0xe2, 0x7d, 0x21, 0xf4, }, 5, 0, "", "", +"c4 e2 7d 21 f4 \tvpmovsxbd %xmm4,%ymm6",}, +{{0x62, 0xf2, 0x7e, 0x4f, 0x21, 0xee, }, 6, 0, "", "", +"62 f2 7e 4f 21 ee \tvpmovsdb %zmm5,%xmm6{%k7}",}, +{{0xc4, 0xe2, 0x7d, 0x22, 0xe4, }, 5, 0, "", "", +"c4 e2 7d 22 e4 \tvpmovsxbq %xmm4,%ymm4",}, +{{0x62, 0xf2, 0x7e, 0x4f, 0x22, 0xee, }, 6, 0, "", "", +"62 f2 7e 4f 22 ee \tvpmovsqb %zmm5,%xmm6{%k7}",}, +{{0xc4, 0xe2, 0x7d, 0x23, 0xe4, }, 5, 0, "", "", +"c4 e2 7d 23 e4 \tvpmovsxwd %xmm4,%ymm4",}, +{{0x62, 0xf2, 0x7e, 0x4f, 0x23, 0xee, }, 6, 0, "", "", +"62 f2 7e 4f 23 ee \tvpmovsdw %zmm5,%ymm6{%k7}",}, +{{0xc4, 0xe2, 0x7d, 0x24, 0xf4, }, 5, 0, "", "", +"c4 e2 7d 24 f4 \tvpmovsxwq %xmm4,%ymm6",}, +{{0x62, 0xf2, 0x7e, 0x4f, 0x24, 0xee, }, 6, 0, "", "", +"62 f2 7e 4f 24 ee \tvpmovsqw %zmm5,%xmm6{%k7}",}, +{{0xc4, 0xe2, 0x7d, 0x25, 0xe4, }, 5, 0, "", "", +"c4 e2 7d 25 e4 \tvpmovsxdq %xmm4,%ymm4",}, +{{0x62, 0xf2, 0x7e, 0x4f, 0x25, 0xee, }, 6, 0, "", "", +"62 f2 7e 4f 25 ee \tvpmovsqd %zmm5,%ymm6{%k7}",}, +{{0x62, 0xf2, 0x4d, 0x48, 0x26, 0xed, }, 6, 0, "", "", +"62 f2 4d 48 26 ed \tvptestmb %zmm5,%zmm6,%k5",}, +{{0x62, 0xf2, 0xcd, 0x48, 0x26, 0xed, }, 6, 0, "", "", +"62 f2 cd 48 26 ed \tvptestmw %zmm5,%zmm6,%k5",}, +{{0x62, 0xf2, 0x56, 0x48, 0x26, 0xec, }, 6, 0, "", "", +"62 f2 56 48 26 ec \tvptestnmb %zmm4,%zmm5,%k5",}, +{{0x62, 0xf2, 0xd6, 0x48, 0x26, 0xec, }, 6, 0, "", "", +"62 f2 d6 48 26 ec \tvptestnmw %zmm4,%zmm5,%k5",}, +{{0x62, 0xf2, 0x4d, 0x48, 0x27, 0xed, }, 6, 0, "", "", +"62 f2 4d 48 27 ed \tvptestmd %zmm5,%zmm6,%k5",}, +{{0x62, 0xf2, 0xcd, 0x48, 0x27, 0xed, }, 6, 0, "", "", +"62 f2 cd 48 27 ed \tvptestmq %zmm5,%zmm6,%k5",}, +{{0x62, 0xf2, 0x56, 0x48, 0x27, 0xec, }, 6, 0, "", "", +"62 f2 56 48 27 ec \tvptestnmd %zmm4,%zmm5,%k5",}, +{{0x62, 0xf2, 0xd6, 0x48, 0x27, 0xec, }, 6, 0, "", "", +"62 f2 d6 48 27 ec \tvptestnmq %zmm4,%zmm5,%k5",}, +{{0xc4, 0xe2, 0x4d, 0x28, 0xd4, }, 5, 0, "", "", +"c4 e2 4d 28 d4 \tvpmuldq %ymm4,%ymm6,%ymm2",}, +{{0x62, 0xf2, 0x7e, 0x48, 0x28, 0xf5, }, 6, 0, "", "", +"62 f2 7e 48 28 f5 \tvpmovm2b %k5,%zmm6",}, +{{0x62, 0xf2, 0xfe, 0x48, 0x28, 0xf5, }, 6, 0, "", "", +"62 f2 fe 48 28 f5 \tvpmovm2w %k5,%zmm6",}, +{{0xc4, 0xe2, 0x4d, 0x29, 0xd4, }, 5, 0, "", "", +"c4 e2 4d 29 d4 \tvpcmpeqq %ymm4,%ymm6,%ymm2",}, +{{0x62, 0xf2, 0x7e, 0x48, 0x29, 0xee, }, 6, 0, "", "", +"62 f2 7e 48 29 ee \tvpmovb2m %zmm6,%k5",}, +{{0x62, 0xf2, 0xfe, 0x48, 0x29, 0xee, }, 6, 0, "", "", +"62 f2 fe 48 29 ee \tvpmovw2m %zmm6,%k5",}, +{{0xc4, 0xe2, 0x7d, 0x2a, 0x21, }, 5, 0, "", "", +"c4 e2 7d 2a 21 \tvmovntdqa (%ecx),%ymm4",}, +{{0x62, 0xf2, 0xfe, 0x48, 0x2a, 0xce, }, 6, 0, "", "", +"62 f2 fe 48 2a ce \tvpbroadcastmb2q %k6,%zmm1",}, +{{0xc4, 0xe2, 0x5d, 0x2c, 0x31, }, 5, 0, "", "", +"c4 e2 5d 2c 31 \tvmaskmovps (%ecx),%ymm4,%ymm6",}, +{{0x62, 0xf2, 0x55, 0x48, 0x2c, 0xf4, }, 6, 0, "", "", +"62 f2 55 48 2c f4 \tvscalefps %zmm4,%zmm5,%zmm6",}, +{{0x62, 0xf2, 0xd5, 0x48, 0x2c, 0xf4, }, 6, 0, "", "", +"62 f2 d5 48 2c f4 \tvscalefpd %zmm4,%zmm5,%zmm6",}, +{{0xc4, 0xe2, 0x5d, 0x2d, 0x31, }, 5, 0, "", "", +"c4 e2 5d 2d 31 \tvmaskmovpd (%ecx),%ymm4,%ymm6",}, +{{0x62, 0xf2, 0x55, 0x0f, 0x2d, 0xf4, }, 6, 0, "", "", +"62 f2 55 0f 2d f4 \tvscalefss %xmm4,%xmm5,%xmm6{%k7}",}, +{{0x62, 0xf2, 0xd5, 0x0f, 0x2d, 0xf4, }, 6, 0, "", "", +"62 f2 d5 0f 2d f4 \tvscalefsd %xmm4,%xmm5,%xmm6{%k7}",}, +{{0xc4, 0xe2, 0x7d, 0x30, 0xe4, }, 5, 0, "", "", +"c4 e2 7d 30 e4 \tvpmovzxbw %xmm4,%ymm4",}, +{{0x62, 0xf2, 0x7e, 0x4f, 0x30, 0xee, }, 6, 0, "", "", +"62 f2 7e 4f 30 ee \tvpmovwb %zmm5,%ymm6{%k7}",}, +{{0xc4, 0xe2, 0x7d, 0x31, 0xf4, }, 5, 0, "", "", +"c4 e2 7d 31 f4 \tvpmovzxbd %xmm4,%ymm6",}, +{{0x62, 0xf2, 0x7e, 0x4f, 0x31, 0xee, }, 6, 0, "", "", +"62 f2 7e 4f 31 ee \tvpmovdb %zmm5,%xmm6{%k7}",}, +{{0xc4, 0xe2, 0x7d, 0x32, 0xe4, }, 5, 0, "", "", +"c4 e2 7d 32 e4 \tvpmovzxbq %xmm4,%ymm4",}, +{{0x62, 0xf2, 0x7e, 0x4f, 0x32, 0xee, }, 6, 0, "", "", +"62 f2 7e 4f 32 ee \tvpmovqb %zmm5,%xmm6{%k7}",}, +{{0xc4, 0xe2, 0x7d, 0x33, 0xe4, }, 5, 0, "", "", +"c4 e2 7d 33 e4 \tvpmovzxwd %xmm4,%ymm4",}, +{{0x62, 0xf2, 0x7e, 0x4f, 0x33, 0xee, }, 6, 0, "", "", +"62 f2 7e 4f 33 ee \tvpmovdw %zmm5,%ymm6{%k7}",}, +{{0xc4, 0xe2, 0x7d, 0x34, 0xf4, }, 5, 0, "", "", +"c4 e2 7d 34 f4 \tvpmovzxwq %xmm4,%ymm6",}, +{{0x62, 0xf2, 0x7e, 0x4f, 0x34, 0xee, }, 6, 0, "", "", +"62 f2 7e 4f 34 ee \tvpmovqw %zmm5,%xmm6{%k7}",}, +{{0xc4, 0xe2, 0x7d, 0x35, 0xe4, }, 5, 0, "", "", +"c4 e2 7d 35 e4 \tvpmovzxdq %xmm4,%ymm4",}, +{{0x62, 0xf2, 0x7e, 0x4f, 0x35, 0xee, }, 6, 0, "", "", +"62 f2 7e 4f 35 ee \tvpmovqd %zmm5,%ymm6{%k7}",}, +{{0xc4, 0xe2, 0x4d, 0x36, 0xd4, }, 5, 0, "", "", +"c4 e2 4d 36 d4 \tvpermd %ymm4,%ymm6,%ymm2",}, +{{0x62, 0xf2, 0x4d, 0x2f, 0x36, 0xd4, }, 6, 0, "", "", +"62 f2 4d 2f 36 d4 \tvpermd %ymm4,%ymm6,%ymm2{%k7}",}, +{{0x62, 0xf2, 0xcd, 0x2f, 0x36, 0xd4, }, 6, 0, "", "", +"62 f2 cd 2f 36 d4 \tvpermq %ymm4,%ymm6,%ymm2{%k7}",}, +{{0xc4, 0xe2, 0x4d, 0x38, 0xd4, }, 5, 0, "", "", +"c4 e2 4d 38 d4 \tvpminsb %ymm4,%ymm6,%ymm2",}, +{{0x62, 0xf2, 0x7e, 0x48, 0x38, 0xf5, }, 6, 0, "", "", +"62 f2 7e 48 38 f5 \tvpmovm2d %k5,%zmm6",}, +{{0x62, 0xf2, 0xfe, 0x48, 0x38, 0xf5, }, 6, 0, "", "", +"62 f2 fe 48 38 f5 \tvpmovm2q %k5,%zmm6",}, +{{0xc4, 0xe2, 0x69, 0x39, 0xd9, }, 5, 0, "", "", +"c4 e2 69 39 d9 \tvpminsd %xmm1,%xmm2,%xmm3",}, +{{0x62, 0xf2, 0x55, 0x48, 0x39, 0xf4, }, 6, 0, "", "", +"62 f2 55 48 39 f4 \tvpminsd %zmm4,%zmm5,%zmm6",}, +{{0x62, 0xf2, 0xd5, 0x48, 0x39, 0xf4, }, 6, 0, "", "", +"62 f2 d5 48 39 f4 \tvpminsq %zmm4,%zmm5,%zmm6",}, +{{0x62, 0xf2, 0x7e, 0x48, 0x39, 0xee, }, 6, 0, "", "", +"62 f2 7e 48 39 ee \tvpmovd2m %zmm6,%k5",}, +{{0x62, 0xf2, 0xfe, 0x48, 0x39, 0xee, }, 6, 0, "", "", +"62 f2 fe 48 39 ee \tvpmovq2m %zmm6,%k5",}, +{{0xc4, 0xe2, 0x4d, 0x3a, 0xd4, }, 5, 0, "", "", +"c4 e2 4d 3a d4 \tvpminuw %ymm4,%ymm6,%ymm2",}, +{{0x62, 0xf2, 0x7e, 0x48, 0x3a, 0xf6, }, 6, 0, "", "", +"62 f2 7e 48 3a f6 \tvpbroadcastmw2d %k6,%zmm6",}, +{{0xc4, 0xe2, 0x4d, 0x3b, 0xd4, }, 5, 0, "", "", +"c4 e2 4d 3b d4 \tvpminud %ymm4,%ymm6,%ymm2",}, +{{0x62, 0xf2, 0x55, 0x48, 0x3b, 0xf4, }, 6, 0, "", "", +"62 f2 55 48 3b f4 \tvpminud %zmm4,%zmm5,%zmm6",}, +{{0x62, 0xf2, 0xd5, 0x48, 0x3b, 0xf4, }, 6, 0, "", "", +"62 f2 d5 48 3b f4 \tvpminuq %zmm4,%zmm5,%zmm6",}, +{{0xc4, 0xe2, 0x4d, 0x3d, 0xd4, }, 5, 0, "", "", +"c4 e2 4d 3d d4 \tvpmaxsd %ymm4,%ymm6,%ymm2",}, +{{0x62, 0xf2, 0x55, 0x48, 0x3d, 0xf4, }, 6, 0, "", "", +"62 f2 55 48 3d f4 \tvpmaxsd %zmm4,%zmm5,%zmm6",}, +{{0x62, 0xf2, 0xd5, 0x48, 0x3d, 0xf4, }, 6, 0, "", "", +"62 f2 d5 48 3d f4 \tvpmaxsq %zmm4,%zmm5,%zmm6",}, +{{0xc4, 0xe2, 0x4d, 0x3f, 0xd4, }, 5, 0, "", "", +"c4 e2 4d 3f d4 \tvpmaxud %ymm4,%ymm6,%ymm2",}, +{{0x62, 0xf2, 0x55, 0x48, 0x3f, 0xf4, }, 6, 0, "", "", +"62 f2 55 48 3f f4 \tvpmaxud %zmm4,%zmm5,%zmm6",}, +{{0x62, 0xf2, 0xd5, 0x48, 0x3f, 0xf4, }, 6, 0, "", "", +"62 f2 d5 48 3f f4 \tvpmaxuq %zmm4,%zmm5,%zmm6",}, +{{0xc4, 0xe2, 0x4d, 0x40, 0xd4, }, 5, 0, "", "", +"c4 e2 4d 40 d4 \tvpmulld %ymm4,%ymm6,%ymm2",}, +{{0x62, 0xf2, 0x55, 0x48, 0x40, 0xf4, }, 6, 0, "", "", +"62 f2 55 48 40 f4 \tvpmulld %zmm4,%zmm5,%zmm6",}, +{{0x62, 0xf2, 0xd5, 0x48, 0x40, 0xf4, }, 6, 0, "", "", +"62 f2 d5 48 40 f4 \tvpmullq %zmm4,%zmm5,%zmm6",}, +{{0x62, 0xf2, 0x7d, 0x48, 0x42, 0xf5, }, 6, 0, "", "", +"62 f2 7d 48 42 f5 \tvgetexpps %zmm5,%zmm6",}, +{{0x62, 0xf2, 0xfd, 0x48, 0x42, 0xf5, }, 6, 0, "", "", +"62 f2 fd 48 42 f5 \tvgetexppd %zmm5,%zmm6",}, +{{0x62, 0xf2, 0x55, 0x0f, 0x43, 0xf4, }, 6, 0, "", "", +"62 f2 55 0f 43 f4 \tvgetexpss %xmm4,%xmm5,%xmm6{%k7}",}, +{{0x62, 0xf2, 0xe5, 0x0f, 0x43, 0xe2, }, 6, 0, "", "", +"62 f2 e5 0f 43 e2 \tvgetexpsd %xmm2,%xmm3,%xmm4{%k7}",}, +{{0x62, 0xf2, 0x7d, 0x48, 0x44, 0xf5, }, 6, 0, "", "", +"62 f2 7d 48 44 f5 \tvplzcntd %zmm5,%zmm6",}, +{{0x62, 0xf2, 0xfd, 0x48, 0x44, 0xf5, }, 6, 0, "", "", +"62 f2 fd 48 44 f5 \tvplzcntq %zmm5,%zmm6",}, +{{0xc4, 0xe2, 0x4d, 0x46, 0xd4, }, 5, 0, "", "", +"c4 e2 4d 46 d4 \tvpsravd %ymm4,%ymm6,%ymm2",}, +{{0x62, 0xf2, 0x55, 0x48, 0x46, 0xf4, }, 6, 0, "", "", +"62 f2 55 48 46 f4 \tvpsravd %zmm4,%zmm5,%zmm6",}, +{{0x62, 0xf2, 0xd5, 0x48, 0x46, 0xf4, }, 6, 0, "", "", +"62 f2 d5 48 46 f4 \tvpsravq %zmm4,%zmm5,%zmm6",}, +{{0x62, 0xf2, 0x7d, 0x48, 0x4c, 0xf5, }, 6, 0, "", "", +"62 f2 7d 48 4c f5 \tvrcp14ps %zmm5,%zmm6",}, +{{0x62, 0xf2, 0xfd, 0x48, 0x4c, 0xf5, }, 6, 0, "", "", +"62 f2 fd 48 4c f5 \tvrcp14pd %zmm5,%zmm6",}, +{{0x62, 0xf2, 0x55, 0x0f, 0x4d, 0xf4, }, 6, 0, "", "", +"62 f2 55 0f 4d f4 \tvrcp14ss %xmm4,%xmm5,%xmm6{%k7}",}, +{{0x62, 0xf2, 0xd5, 0x0f, 0x4d, 0xf4, }, 6, 0, "", "", +"62 f2 d5 0f 4d f4 \tvrcp14sd %xmm4,%xmm5,%xmm6{%k7}",}, +{{0x62, 0xf2, 0x7d, 0x48, 0x4e, 0xf5, }, 6, 0, "", "", +"62 f2 7d 48 4e f5 \tvrsqrt14ps %zmm5,%zmm6",}, +{{0x62, 0xf2, 0xfd, 0x48, 0x4e, 0xf5, }, 6, 0, "", "", +"62 f2 fd 48 4e f5 \tvrsqrt14pd %zmm5,%zmm6",}, +{{0x62, 0xf2, 0x55, 0x0f, 0x4f, 0xf4, }, 6, 0, "", "", +"62 f2 55 0f 4f f4 \tvrsqrt14ss %xmm4,%xmm5,%xmm6{%k7}",}, +{{0x62, 0xf2, 0xd5, 0x0f, 0x4f, 0xf4, }, 6, 0, "", "", +"62 f2 d5 0f 4f f4 \tvrsqrt14sd %xmm4,%xmm5,%xmm6{%k7}",}, +{{0xc4, 0xe2, 0x79, 0x59, 0xf4, }, 5, 0, "", "", +"c4 e2 79 59 f4 \tvpbroadcastq %xmm4,%xmm6",}, +{{0x62, 0xf2, 0x7d, 0x48, 0x59, 0xf7, }, 6, 0, "", "", +"62 f2 7d 48 59 f7 \tvbroadcasti32x2 %xmm7,%zmm6",}, +{{0xc4, 0xe2, 0x7d, 0x5a, 0x21, }, 5, 0, "", "", +"c4 e2 7d 5a 21 \tvbroadcasti128 (%ecx),%ymm4",}, +{{0x62, 0xf2, 0x7d, 0x48, 0x5a, 0x31, }, 6, 0, "", "", +"62 f2 7d 48 5a 31 \tvbroadcasti32x4 (%ecx),%zmm6",}, +{{0x62, 0xf2, 0xfd, 0x48, 0x5a, 0x31, }, 6, 0, "", "", +"62 f2 fd 48 5a 31 \tvbroadcasti64x2 (%ecx),%zmm6",}, +{{0x62, 0xf2, 0x7d, 0x48, 0x5b, 0x31, }, 6, 0, "", "", +"62 f2 7d 48 5b 31 \tvbroadcasti32x8 (%ecx),%zmm6",}, +{{0x62, 0xf2, 0xfd, 0x48, 0x5b, 0x31, }, 6, 0, "", "", +"62 f2 fd 48 5b 31 \tvbroadcasti64x4 (%ecx),%zmm6",}, +{{0x62, 0xf2, 0x55, 0x48, 0x64, 0xf4, }, 6, 0, "", "", +"62 f2 55 48 64 f4 \tvpblendmd %zmm4,%zmm5,%zmm6",}, +{{0x62, 0xf2, 0xd5, 0x48, 0x64, 0xf4, }, 6, 0, "", "", +"62 f2 d5 48 64 f4 \tvpblendmq %zmm4,%zmm5,%zmm6",}, +{{0x62, 0xf2, 0x55, 0x48, 0x65, 0xf4, }, 6, 0, "", "", +"62 f2 55 48 65 f4 \tvblendmps %zmm4,%zmm5,%zmm6",}, +{{0x62, 0xf2, 0xd5, 0x48, 0x65, 0xf4, }, 6, 0, "", "", +"62 f2 d5 48 65 f4 \tvblendmpd %zmm4,%zmm5,%zmm6",}, +{{0x62, 0xf2, 0x55, 0x48, 0x66, 0xf4, }, 6, 0, "", "", +"62 f2 55 48 66 f4 \tvpblendmb %zmm4,%zmm5,%zmm6",}, +{{0x62, 0xf2, 0xd5, 0x48, 0x66, 0xf4, }, 6, 0, "", "", +"62 f2 d5 48 66 f4 \tvpblendmw %zmm4,%zmm5,%zmm6",}, +{{0x62, 0xf2, 0x55, 0x48, 0x75, 0xf4, }, 6, 0, "", "", +"62 f2 55 48 75 f4 \tvpermi2b %zmm4,%zmm5,%zmm6",}, +{{0x62, 0xf2, 0xd5, 0x48, 0x75, 0xf4, }, 6, 0, "", "", +"62 f2 d5 48 75 f4 \tvpermi2w %zmm4,%zmm5,%zmm6",}, +{{0x62, 0xf2, 0x55, 0x48, 0x76, 0xf4, }, 6, 0, "", "", +"62 f2 55 48 76 f4 \tvpermi2d %zmm4,%zmm5,%zmm6",}, +{{0x62, 0xf2, 0xd5, 0x48, 0x76, 0xf4, }, 6, 0, "", "", +"62 f2 d5 48 76 f4 \tvpermi2q %zmm4,%zmm5,%zmm6",}, +{{0x62, 0xf2, 0x55, 0x48, 0x77, 0xf4, }, 6, 0, "", "", +"62 f2 55 48 77 f4 \tvpermi2ps %zmm4,%zmm5,%zmm6",}, +{{0x62, 0xf2, 0xd5, 0x48, 0x77, 0xf4, }, 6, 0, "", "", +"62 f2 d5 48 77 f4 \tvpermi2pd %zmm4,%zmm5,%zmm6",}, +{{0x62, 0xf2, 0x7d, 0x08, 0x7a, 0xd8, }, 6, 0, "", "", +"62 f2 7d 08 7a d8 \tvpbroadcastb %eax,%xmm3",}, +{{0x62, 0xf2, 0x7d, 0x08, 0x7b, 0xd8, }, 6, 0, "", "", +"62 f2 7d 08 7b d8 \tvpbroadcastw %eax,%xmm3",}, +{{0x62, 0xf2, 0x7d, 0x08, 0x7c, 0xd8, }, 6, 0, "", "", +"62 f2 7d 08 7c d8 \tvpbroadcastd %eax,%xmm3",}, +{{0x62, 0xf2, 0x55, 0x48, 0x7d, 0xf4, }, 6, 0, "", "", +"62 f2 55 48 7d f4 \tvpermt2b %zmm4,%zmm5,%zmm6",}, +{{0x62, 0xf2, 0xd5, 0x48, 0x7d, 0xf4, }, 6, 0, "", "", +"62 f2 d5 48 7d f4 \tvpermt2w %zmm4,%zmm5,%zmm6",}, +{{0x62, 0xf2, 0x55, 0x48, 0x7e, 0xf4, }, 6, 0, "", "", +"62 f2 55 48 7e f4 \tvpermt2d %zmm4,%zmm5,%zmm6",}, +{{0x62, 0xf2, 0xd5, 0x48, 0x7e, 0xf4, }, 6, 0, "", "", +"62 f2 d5 48 7e f4 \tvpermt2q %zmm4,%zmm5,%zmm6",}, +{{0x62, 0xf2, 0x55, 0x48, 0x7f, 0xf4, }, 6, 0, "", "", +"62 f2 55 48 7f f4 \tvpermt2ps %zmm4,%zmm5,%zmm6",}, +{{0x62, 0xf2, 0xd5, 0x48, 0x7f, 0xf4, }, 6, 0, "", "", +"62 f2 d5 48 7f f4 \tvpermt2pd %zmm4,%zmm5,%zmm6",}, +{{0x62, 0xf2, 0xd5, 0x48, 0x83, 0xf4, }, 6, 0, "", "", +"62 f2 d5 48 83 f4 \tvpmultishiftqb %zmm4,%zmm5,%zmm6",}, +{{0x62, 0xf2, 0x7d, 0x48, 0x88, 0x31, }, 6, 0, "", "", +"62 f2 7d 48 88 31 \tvexpandps (%ecx),%zmm6",}, +{{0x62, 0xf2, 0xfd, 0x48, 0x88, 0x31, }, 6, 0, "", "", +"62 f2 fd 48 88 31 \tvexpandpd (%ecx),%zmm6",}, +{{0x62, 0xf2, 0x7d, 0x48, 0x89, 0x31, }, 6, 0, "", "", +"62 f2 7d 48 89 31 \tvpexpandd (%ecx),%zmm6",}, +{{0x62, 0xf2, 0xfd, 0x48, 0x89, 0x31, }, 6, 0, "", "", +"62 f2 fd 48 89 31 \tvpexpandq (%ecx),%zmm6",}, +{{0x62, 0xf2, 0x7d, 0x48, 0x8a, 0x31, }, 6, 0, "", "", +"62 f2 7d 48 8a 31 \tvcompressps %zmm6,(%ecx)",}, +{{0x62, 0xf2, 0xfd, 0x48, 0x8a, 0x31, }, 6, 0, "", "", +"62 f2 fd 48 8a 31 \tvcompresspd %zmm6,(%ecx)",}, +{{0x62, 0xf2, 0x7d, 0x48, 0x8b, 0x31, }, 6, 0, "", "", +"62 f2 7d 48 8b 31 \tvpcompressd %zmm6,(%ecx)",}, +{{0x62, 0xf2, 0xfd, 0x48, 0x8b, 0x31, }, 6, 0, "", "", +"62 f2 fd 48 8b 31 \tvpcompressq %zmm6,(%ecx)",}, +{{0x62, 0xf2, 0x55, 0x48, 0x8d, 0xf4, }, 6, 0, "", "", +"62 f2 55 48 8d f4 \tvpermb %zmm4,%zmm5,%zmm6",}, +{{0x62, 0xf2, 0xd5, 0x48, 0x8d, 0xf4, }, 6, 0, "", "", +"62 f2 d5 48 8d f4 \tvpermw %zmm4,%zmm5,%zmm6",}, +{{0xc4, 0xe2, 0x69, 0x90, 0x4c, 0x7d, 0x02, }, 7, 0, "", "", +"c4 e2 69 90 4c 7d 02 \tvpgatherdd %xmm2,0x2(%ebp,%xmm7,2),%xmm1",}, +{{0xc4, 0xe2, 0xe9, 0x90, 0x4c, 0x7d, 0x04, }, 7, 0, "", "", +"c4 e2 e9 90 4c 7d 04 \tvpgatherdq %xmm2,0x4(%ebp,%xmm7,2),%xmm1",}, +{{0x62, 0xf2, 0x7d, 0x49, 0x90, 0xb4, 0xfd, 0x7b, 0x00, 0x00, 0x00, }, 11, 0, "", "", +"62 f2 7d 49 90 b4 fd 7b 00 00 00 \tvpgatherdd 0x7b(%ebp,%zmm7,8),%zmm6{%k1}",}, +{{0x62, 0xf2, 0xfd, 0x49, 0x90, 0xb4, 0xfd, 0x7b, 0x00, 0x00, 0x00, }, 11, 0, "", "", +"62 f2 fd 49 90 b4 fd 7b 00 00 00 \tvpgatherdq 0x7b(%ebp,%ymm7,8),%zmm6{%k1}",}, +{{0xc4, 0xe2, 0x69, 0x91, 0x4c, 0x7d, 0x02, }, 7, 0, "", "", +"c4 e2 69 91 4c 7d 02 \tvpgatherqd %xmm2,0x2(%ebp,%xmm7,2),%xmm1",}, +{{0xc4, 0xe2, 0xe9, 0x91, 0x4c, 0x7d, 0x02, }, 7, 0, "", "", +"c4 e2 e9 91 4c 7d 02 \tvpgatherqq %xmm2,0x2(%ebp,%xmm7,2),%xmm1",}, +{{0x62, 0xf2, 0x7d, 0x49, 0x91, 0xb4, 0xfd, 0x7b, 0x00, 0x00, 0x00, }, 11, 0, "", "", +"62 f2 7d 49 91 b4 fd 7b 00 00 00 \tvpgatherqd 0x7b(%ebp,%zmm7,8),%ymm6{%k1}",}, +{{0x62, 0xf2, 0xfd, 0x49, 0x91, 0xb4, 0xfd, 0x7b, 0x00, 0x00, 0x00, }, 11, 0, "", "", +"62 f2 fd 49 91 b4 fd 7b 00 00 00 \tvpgatherqq 0x7b(%ebp,%zmm7,8),%zmm6{%k1}",}, +{{0x62, 0xf2, 0x7d, 0x49, 0xa0, 0xb4, 0xfd, 0x7b, 0x00, 0x00, 0x00, }, 11, 0, "", "", +"62 f2 7d 49 a0 b4 fd 7b 00 00 00 \tvpscatterdd %zmm6,0x7b(%ebp,%zmm7,8){%k1}",}, +{{0x62, 0xf2, 0xfd, 0x49, 0xa0, 0xb4, 0xfd, 0x7b, 0x00, 0x00, 0x00, }, 11, 0, "", "", +"62 f2 fd 49 a0 b4 fd 7b 00 00 00 \tvpscatterdq %zmm6,0x7b(%ebp,%ymm7,8){%k1}",}, +{{0x62, 0xf2, 0x7d, 0x49, 0xa1, 0xb4, 0xfd, 0x7b, 0x00, 0x00, 0x00, }, 11, 0, "", "", +"62 f2 7d 49 a1 b4 fd 7b 00 00 00 \tvpscatterqd %ymm6,0x7b(%ebp,%zmm7,8){%k1}",}, +{{0x62, 0xf2, 0xfd, 0x29, 0xa1, 0xb4, 0xfd, 0x7b, 0x00, 0x00, 0x00, }, 11, 0, "", "", +"62 f2 fd 29 a1 b4 fd 7b 00 00 00 \tvpscatterqq %ymm6,0x7b(%ebp,%ymm7,8){%k1}",}, +{{0x62, 0xf2, 0x7d, 0x49, 0xa2, 0xb4, 0xfd, 0x7b, 0x00, 0x00, 0x00, }, 11, 0, "", "", +"62 f2 7d 49 a2 b4 fd 7b 00 00 00 \tvscatterdps %zmm6,0x7b(%ebp,%zmm7,8){%k1}",}, +{{0x62, 0xf2, 0xfd, 0x49, 0xa2, 0xb4, 0xfd, 0x7b, 0x00, 0x00, 0x00, }, 11, 0, "", "", +"62 f2 fd 49 a2 b4 fd 7b 00 00 00 \tvscatterdpd %zmm6,0x7b(%ebp,%ymm7,8){%k1}",}, +{{0x62, 0xf2, 0x7d, 0x49, 0xa3, 0xb4, 0xfd, 0x7b, 0x00, 0x00, 0x00, }, 11, 0, "", "", +"62 f2 7d 49 a3 b4 fd 7b 00 00 00 \tvscatterqps %ymm6,0x7b(%ebp,%zmm7,8){%k1}",}, +{{0x62, 0xf2, 0xfd, 0x49, 0xa3, 0xb4, 0xfd, 0x7b, 0x00, 0x00, 0x00, }, 11, 0, "", "", +"62 f2 fd 49 a3 b4 fd 7b 00 00 00 \tvscatterqpd %zmm6,0x7b(%ebp,%zmm7,8){%k1}",}, +{{0x62, 0xf2, 0xd5, 0x48, 0xb4, 0xf4, }, 6, 0, "", "", +"62 f2 d5 48 b4 f4 \tvpmadd52luq %zmm4,%zmm5,%zmm6",}, +{{0x62, 0xf2, 0xd5, 0x48, 0xb5, 0xf4, }, 6, 0, "", "", +"62 f2 d5 48 b5 f4 \tvpmadd52huq %zmm4,%zmm5,%zmm6",}, +{{0x62, 0xf2, 0x7d, 0x48, 0xc4, 0xf5, }, 6, 0, "", "", +"62 f2 7d 48 c4 f5 \tvpconflictd %zmm5,%zmm6",}, +{{0x62, 0xf2, 0xfd, 0x48, 0xc4, 0xf5, }, 6, 0, "", "", +"62 f2 fd 48 c4 f5 \tvpconflictq %zmm5,%zmm6",}, +{{0x62, 0xf2, 0x7d, 0x48, 0xc8, 0xfe, }, 6, 0, "", "", +"62 f2 7d 48 c8 fe \tvexp2ps %zmm6,%zmm7",}, +{{0x62, 0xf2, 0xfd, 0x48, 0xc8, 0xfe, }, 6, 0, "", "", +"62 f2 fd 48 c8 fe \tvexp2pd %zmm6,%zmm7",}, +{{0x62, 0xf2, 0x7d, 0x48, 0xca, 0xfe, }, 6, 0, "", "", +"62 f2 7d 48 ca fe \tvrcp28ps %zmm6,%zmm7",}, +{{0x62, 0xf2, 0xfd, 0x48, 0xca, 0xfe, }, 6, 0, "", "", +"62 f2 fd 48 ca fe \tvrcp28pd %zmm6,%zmm7",}, +{{0x62, 0xf2, 0x4d, 0x0f, 0xcb, 0xfd, }, 6, 0, "", "", +"62 f2 4d 0f cb fd \tvrcp28ss %xmm5,%xmm6,%xmm7{%k7}",}, +{{0x62, 0xf2, 0xcd, 0x0f, 0xcb, 0xfd, }, 6, 0, "", "", +"62 f2 cd 0f cb fd \tvrcp28sd %xmm5,%xmm6,%xmm7{%k7}",}, +{{0x62, 0xf2, 0x7d, 0x48, 0xcc, 0xfe, }, 6, 0, "", "", +"62 f2 7d 48 cc fe \tvrsqrt28ps %zmm6,%zmm7",}, +{{0x62, 0xf2, 0xfd, 0x48, 0xcc, 0xfe, }, 6, 0, "", "", +"62 f2 fd 48 cc fe \tvrsqrt28pd %zmm6,%zmm7",}, +{{0x62, 0xf2, 0x4d, 0x0f, 0xcd, 0xfd, }, 6, 0, "", "", +"62 f2 4d 0f cd fd \tvrsqrt28ss %xmm5,%xmm6,%xmm7{%k7}",}, +{{0x62, 0xf2, 0xcd, 0x0f, 0xcd, 0xfd, }, 6, 0, "", "", +"62 f2 cd 0f cd fd \tvrsqrt28sd %xmm5,%xmm6,%xmm7{%k7}",}, +{{0x62, 0xf3, 0x4d, 0x48, 0x03, 0xfd, 0x12, }, 7, 0, "", "", +"62 f3 4d 48 03 fd 12 \tvalignd $0x12,%zmm5,%zmm6,%zmm7",}, +{{0x62, 0xf3, 0xcd, 0x48, 0x03, 0xfd, 0x12, }, 7, 0, "", "", +"62 f3 cd 48 03 fd 12 \tvalignq $0x12,%zmm5,%zmm6,%zmm7",}, +{{0xc4, 0xe3, 0x7d, 0x08, 0xd6, 0x05, }, 6, 0, "", "", +"c4 e3 7d 08 d6 05 \tvroundps $0x5,%ymm6,%ymm2",}, +{{0x62, 0xf3, 0x7d, 0x48, 0x08, 0xf5, 0x12, }, 7, 0, "", "", +"62 f3 7d 48 08 f5 12 \tvrndscaleps $0x12,%zmm5,%zmm6",}, +{{0xc4, 0xe3, 0x7d, 0x09, 0xd6, 0x05, }, 6, 0, "", "", +"c4 e3 7d 09 d6 05 \tvroundpd $0x5,%ymm6,%ymm2",}, +{{0x62, 0xf3, 0xfd, 0x48, 0x09, 0xf5, 0x12, }, 7, 0, "", "", +"62 f3 fd 48 09 f5 12 \tvrndscalepd $0x12,%zmm5,%zmm6",}, +{{0xc4, 0xe3, 0x49, 0x0a, 0xd4, 0x05, }, 6, 0, "", "", +"c4 e3 49 0a d4 05 \tvroundss $0x5,%xmm4,%xmm6,%xmm2",}, +{{0x62, 0xf3, 0x55, 0x0f, 0x0a, 0xf4, 0x12, }, 7, 0, "", "", +"62 f3 55 0f 0a f4 12 \tvrndscaless $0x12,%xmm4,%xmm5,%xmm6{%k7}",}, +{{0xc4, 0xe3, 0x49, 0x0b, 0xd4, 0x05, }, 6, 0, "", "", +"c4 e3 49 0b d4 05 \tvroundsd $0x5,%xmm4,%xmm6,%xmm2",}, +{{0x62, 0xf3, 0xd5, 0x0f, 0x0b, 0xf4, 0x12, }, 7, 0, "", "", +"62 f3 d5 0f 0b f4 12 \tvrndscalesd $0x12,%xmm4,%xmm5,%xmm6{%k7}",}, +{{0xc4, 0xe3, 0x5d, 0x18, 0xf4, 0x05, }, 6, 0, "", "", +"c4 e3 5d 18 f4 05 \tvinsertf128 $0x5,%xmm4,%ymm4,%ymm6",}, +{{0x62, 0xf3, 0x55, 0x4f, 0x18, 0xf4, 0x12, }, 7, 0, "", "", +"62 f3 55 4f 18 f4 12 \tvinsertf32x4 $0x12,%xmm4,%zmm5,%zmm6{%k7}",}, +{{0x62, 0xf3, 0xd5, 0x4f, 0x18, 0xf4, 0x12, }, 7, 0, "", "", +"62 f3 d5 4f 18 f4 12 \tvinsertf64x2 $0x12,%xmm4,%zmm5,%zmm6{%k7}",}, +{{0xc4, 0xe3, 0x7d, 0x19, 0xe4, 0x05, }, 6, 0, "", "", +"c4 e3 7d 19 e4 05 \tvextractf128 $0x5,%ymm4,%xmm4",}, +{{0x62, 0xf3, 0x7d, 0x4f, 0x19, 0xee, 0x12, }, 7, 0, "", "", +"62 f3 7d 4f 19 ee 12 \tvextractf32x4 $0x12,%zmm5,%xmm6{%k7}",}, +{{0x62, 0xf3, 0xfd, 0x4f, 0x19, 0xee, 0x12, }, 7, 0, "", "", +"62 f3 fd 4f 19 ee 12 \tvextractf64x2 $0x12,%zmm5,%xmm6{%k7}",}, +{{0x62, 0xf3, 0x4d, 0x4f, 0x1a, 0xfd, 0x12, }, 7, 0, "", "", +"62 f3 4d 4f 1a fd 12 \tvinsertf32x8 $0x12,%ymm5,%zmm6,%zmm7{%k7}",}, +{{0x62, 0xf3, 0xcd, 0x4f, 0x1a, 0xfd, 0x12, }, 7, 0, "", "", +"62 f3 cd 4f 1a fd 12 \tvinsertf64x4 $0x12,%ymm5,%zmm6,%zmm7{%k7}",}, +{{0x62, 0xf3, 0x7d, 0x4f, 0x1b, 0xf7, 0x12, }, 7, 0, "", "", +"62 f3 7d 4f 1b f7 12 \tvextractf32x8 $0x12,%zmm6,%ymm7{%k7}",}, +{{0x62, 0xf3, 0xfd, 0x4f, 0x1b, 0xf7, 0x12, }, 7, 0, "", "", +"62 f3 fd 4f 1b f7 12 \tvextractf64x4 $0x12,%zmm6,%ymm7{%k7}",}, +{{0x62, 0xf3, 0x45, 0x48, 0x1e, 0xee, 0x12, }, 7, 0, "", "", +"62 f3 45 48 1e ee 12 \tvpcmpud $0x12,%zmm6,%zmm7,%k5",}, +{{0x62, 0xf3, 0xc5, 0x48, 0x1e, 0xee, 0x12, }, 7, 0, "", "", +"62 f3 c5 48 1e ee 12 \tvpcmpuq $0x12,%zmm6,%zmm7,%k5",}, +{{0x62, 0xf3, 0x45, 0x48, 0x1f, 0xee, 0x12, }, 7, 0, "", "", +"62 f3 45 48 1f ee 12 \tvpcmpd $0x12,%zmm6,%zmm7,%k5",}, +{{0x62, 0xf3, 0xc5, 0x48, 0x1f, 0xee, 0x12, }, 7, 0, "", "", +"62 f3 c5 48 1f ee 12 \tvpcmpq $0x12,%zmm6,%zmm7,%k5",}, +{{0x62, 0xf3, 0x4d, 0x48, 0x23, 0xfd, 0x12, }, 7, 0, "", "", +"62 f3 4d 48 23 fd 12 \tvshuff32x4 $0x12,%zmm5,%zmm6,%zmm7",}, +{{0x62, 0xf3, 0xcd, 0x48, 0x23, 0xfd, 0x12, }, 7, 0, "", "", +"62 f3 cd 48 23 fd 12 \tvshuff64x2 $0x12,%zmm5,%zmm6,%zmm7",}, +{{0x62, 0xf3, 0x4d, 0x48, 0x25, 0xfd, 0x12, }, 7, 0, "", "", +"62 f3 4d 48 25 fd 12 \tvpternlogd $0x12,%zmm5,%zmm6,%zmm7",}, +{{0x62, 0xf3, 0xcd, 0x48, 0x25, 0xfd, 0x12, }, 7, 0, "", "", +"62 f3 cd 48 25 fd 12 \tvpternlogq $0x12,%zmm5,%zmm6,%zmm7",}, +{{0x62, 0xf3, 0x7d, 0x48, 0x26, 0xfe, 0x12, }, 7, 0, "", "", +"62 f3 7d 48 26 fe 12 \tvgetmantps $0x12,%zmm6,%zmm7",}, +{{0x62, 0xf3, 0xfd, 0x48, 0x26, 0xfe, 0x12, }, 7, 0, "", "", +"62 f3 fd 48 26 fe 12 \tvgetmantpd $0x12,%zmm6,%zmm7",}, +{{0x62, 0xf3, 0x4d, 0x0f, 0x27, 0xfd, 0x12, }, 7, 0, "", "", +"62 f3 4d 0f 27 fd 12 \tvgetmantss $0x12,%xmm5,%xmm6,%xmm7{%k7}",}, +{{0x62, 0xf3, 0xcd, 0x0f, 0x27, 0xfd, 0x12, }, 7, 0, "", "", +"62 f3 cd 0f 27 fd 12 \tvgetmantsd $0x12,%xmm5,%xmm6,%xmm7{%k7}",}, +{{0xc4, 0xe3, 0x5d, 0x38, 0xf4, 0x05, }, 6, 0, "", "", +"c4 e3 5d 38 f4 05 \tvinserti128 $0x5,%xmm4,%ymm4,%ymm6",}, +{{0x62, 0xf3, 0x55, 0x4f, 0x38, 0xf4, 0x12, }, 7, 0, "", "", +"62 f3 55 4f 38 f4 12 \tvinserti32x4 $0x12,%xmm4,%zmm5,%zmm6{%k7}",}, +{{0x62, 0xf3, 0xd5, 0x4f, 0x38, 0xf4, 0x12, }, 7, 0, "", "", +"62 f3 d5 4f 38 f4 12 \tvinserti64x2 $0x12,%xmm4,%zmm5,%zmm6{%k7}",}, +{{0xc4, 0xe3, 0x7d, 0x39, 0xe6, 0x05, }, 6, 0, "", "", +"c4 e3 7d 39 e6 05 \tvextracti128 $0x5,%ymm4,%xmm6",}, +{{0x62, 0xf3, 0x7d, 0x4f, 0x39, 0xee, 0x12, }, 7, 0, "", "", +"62 f3 7d 4f 39 ee 12 \tvextracti32x4 $0x12,%zmm5,%xmm6{%k7}",}, +{{0x62, 0xf3, 0xfd, 0x4f, 0x39, 0xee, 0x12, }, 7, 0, "", "", +"62 f3 fd 4f 39 ee 12 \tvextracti64x2 $0x12,%zmm5,%xmm6{%k7}",}, +{{0x62, 0xf3, 0x4d, 0x4f, 0x3a, 0xfd, 0x12, }, 7, 0, "", "", +"62 f3 4d 4f 3a fd 12 \tvinserti32x8 $0x12,%ymm5,%zmm6,%zmm7{%k7}",}, +{{0x62, 0xf3, 0xcd, 0x4f, 0x3a, 0xfd, 0x12, }, 7, 0, "", "", +"62 f3 cd 4f 3a fd 12 \tvinserti64x4 $0x12,%ymm5,%zmm6,%zmm7{%k7}",}, +{{0x62, 0xf3, 0x7d, 0x4f, 0x3b, 0xf7, 0x12, }, 7, 0, "", "", +"62 f3 7d 4f 3b f7 12 \tvextracti32x8 $0x12,%zmm6,%ymm7{%k7}",}, +{{0x62, 0xf3, 0xfd, 0x4f, 0x3b, 0xf7, 0x12, }, 7, 0, "", "", +"62 f3 fd 4f 3b f7 12 \tvextracti64x4 $0x12,%zmm6,%ymm7{%k7}",}, +{{0x62, 0xf3, 0x45, 0x48, 0x3e, 0xee, 0x12, }, 7, 0, "", "", +"62 f3 45 48 3e ee 12 \tvpcmpub $0x12,%zmm6,%zmm7,%k5",}, +{{0x62, 0xf3, 0xc5, 0x48, 0x3e, 0xee, 0x12, }, 7, 0, "", "", +"62 f3 c5 48 3e ee 12 \tvpcmpuw $0x12,%zmm6,%zmm7,%k5",}, +{{0x62, 0xf3, 0x45, 0x48, 0x3f, 0xee, 0x12, }, 7, 0, "", "", +"62 f3 45 48 3f ee 12 \tvpcmpb $0x12,%zmm6,%zmm7,%k5",}, +{{0x62, 0xf3, 0xc5, 0x48, 0x3f, 0xee, 0x12, }, 7, 0, "", "", +"62 f3 c5 48 3f ee 12 \tvpcmpw $0x12,%zmm6,%zmm7,%k5",}, +{{0xc4, 0xe3, 0x4d, 0x42, 0xd4, 0x05, }, 6, 0, "", "", +"c4 e3 4d 42 d4 05 \tvmpsadbw $0x5,%ymm4,%ymm6,%ymm2",}, +{{0x62, 0xf3, 0x55, 0x48, 0x42, 0xf4, 0x12, }, 7, 0, "", "", +"62 f3 55 48 42 f4 12 \tvdbpsadbw $0x12,%zmm4,%zmm5,%zmm6",}, +{{0x62, 0xf3, 0x4d, 0x48, 0x43, 0xfd, 0x12, }, 7, 0, "", "", +"62 f3 4d 48 43 fd 12 \tvshufi32x4 $0x12,%zmm5,%zmm6,%zmm7",}, +{{0x62, 0xf3, 0xcd, 0x48, 0x43, 0xfd, 0x12, }, 7, 0, "", "", +"62 f3 cd 48 43 fd 12 \tvshufi64x2 $0x12,%zmm5,%zmm6,%zmm7",}, +{{0x62, 0xf3, 0x4d, 0x48, 0x50, 0xfd, 0x12, }, 7, 0, "", "", +"62 f3 4d 48 50 fd 12 \tvrangeps $0x12,%zmm5,%zmm6,%zmm7",}, +{{0x62, 0xf3, 0xcd, 0x48, 0x50, 0xfd, 0x12, }, 7, 0, "", "", +"62 f3 cd 48 50 fd 12 \tvrangepd $0x12,%zmm5,%zmm6,%zmm7",}, +{{0x62, 0xf3, 0x4d, 0x08, 0x51, 0xfd, 0x12, }, 7, 0, "", "", +"62 f3 4d 08 51 fd 12 \tvrangess $0x12,%xmm5,%xmm6,%xmm7",}, +{{0x62, 0xf3, 0xcd, 0x08, 0x51, 0xfd, 0x12, }, 7, 0, "", "", +"62 f3 cd 08 51 fd 12 \tvrangesd $0x12,%xmm5,%xmm6,%xmm7",}, +{{0x62, 0xf3, 0x4d, 0x48, 0x54, 0xfd, 0x12, }, 7, 0, "", "", +"62 f3 4d 48 54 fd 12 \tvfixupimmps $0x12,%zmm5,%zmm6,%zmm7",}, +{{0x62, 0xf3, 0xcd, 0x48, 0x54, 0xfd, 0x12, }, 7, 0, "", "", +"62 f3 cd 48 54 fd 12 \tvfixupimmpd $0x12,%zmm5,%zmm6,%zmm7",}, +{{0x62, 0xf3, 0x4d, 0x0f, 0x55, 0xfd, 0x12, }, 7, 0, "", "", +"62 f3 4d 0f 55 fd 12 \tvfixupimmss $0x12,%xmm5,%xmm6,%xmm7{%k7}",}, +{{0x62, 0xf3, 0xcd, 0x0f, 0x55, 0xfd, 0x12, }, 7, 0, "", "", +"62 f3 cd 0f 55 fd 12 \tvfixupimmsd $0x12,%xmm5,%xmm6,%xmm7{%k7}",}, +{{0x62, 0xf3, 0x7d, 0x48, 0x56, 0xfe, 0x12, }, 7, 0, "", "", +"62 f3 7d 48 56 fe 12 \tvreduceps $0x12,%zmm6,%zmm7",}, +{{0x62, 0xf3, 0xfd, 0x48, 0x56, 0xfe, 0x12, }, 7, 0, "", "", +"62 f3 fd 48 56 fe 12 \tvreducepd $0x12,%zmm6,%zmm7",}, +{{0x62, 0xf3, 0x4d, 0x08, 0x57, 0xfd, 0x12, }, 7, 0, "", "", +"62 f3 4d 08 57 fd 12 \tvreducess $0x12,%xmm5,%xmm6,%xmm7",}, +{{0x62, 0xf3, 0xcd, 0x08, 0x57, 0xfd, 0x12, }, 7, 0, "", "", +"62 f3 cd 08 57 fd 12 \tvreducesd $0x12,%xmm5,%xmm6,%xmm7",}, +{{0x62, 0xf3, 0x7d, 0x48, 0x66, 0xef, 0x12, }, 7, 0, "", "", +"62 f3 7d 48 66 ef 12 \tvfpclassps $0x12,%zmm7,%k5",}, +{{0x62, 0xf3, 0xfd, 0x48, 0x66, 0xef, 0x12, }, 7, 0, "", "", +"62 f3 fd 48 66 ef 12 \tvfpclasspd $0x12,%zmm7,%k5",}, +{{0x62, 0xf3, 0x7d, 0x08, 0x67, 0xef, 0x12, }, 7, 0, "", "", +"62 f3 7d 08 67 ef 12 \tvfpclassss $0x12,%xmm7,%k5",}, +{{0x62, 0xf3, 0xfd, 0x08, 0x67, 0xef, 0x12, }, 7, 0, "", "", +"62 f3 fd 08 67 ef 12 \tvfpclasssd $0x12,%xmm7,%k5",}, +{{0x62, 0xf1, 0x4d, 0x48, 0x72, 0xc5, 0x12, }, 7, 0, "", "", +"62 f1 4d 48 72 c5 12 \tvprord $0x12,%zmm5,%zmm6",}, +{{0x62, 0xf1, 0xcd, 0x48, 0x72, 0xc5, 0x12, }, 7, 0, "", "", +"62 f1 cd 48 72 c5 12 \tvprorq $0x12,%zmm5,%zmm6",}, +{{0x62, 0xf1, 0x4d, 0x48, 0x72, 0xcd, 0x12, }, 7, 0, "", "", +"62 f1 4d 48 72 cd 12 \tvprold $0x12,%zmm5,%zmm6",}, +{{0x62, 0xf1, 0xcd, 0x48, 0x72, 0xcd, 0x12, }, 7, 0, "", "", +"62 f1 cd 48 72 cd 12 \tvprolq $0x12,%zmm5,%zmm6",}, +{{0x0f, 0x72, 0xe6, 0x02, }, 4, 0, "", "", +"0f 72 e6 02 \tpsrad $0x2,%mm6",}, +{{0xc5, 0xed, 0x72, 0xe6, 0x05, }, 5, 0, "", "", +"c5 ed 72 e6 05 \tvpsrad $0x5,%ymm6,%ymm2",}, +{{0x62, 0xf1, 0x6d, 0x48, 0x72, 0xe6, 0x05, }, 7, 0, "", "", +"62 f1 6d 48 72 e6 05 \tvpsrad $0x5,%zmm6,%zmm2",}, +{{0x62, 0xf1, 0xed, 0x48, 0x72, 0xe6, 0x05, }, 7, 0, "", "", +"62 f1 ed 48 72 e6 05 \tvpsraq $0x5,%zmm6,%zmm2",}, +{{0x62, 0xf2, 0x7d, 0x49, 0xc6, 0x8c, 0xfd, 0x7b, 0x00, 0x00, 0x00, }, 11, 0, "", "", +"62 f2 7d 49 c6 8c fd 7b 00 00 00 \tvgatherpf0dps 0x7b(%ebp,%zmm7,8){%k1}",}, +{{0x62, 0xf2, 0xfd, 0x49, 0xc6, 0x8c, 0xfd, 0x7b, 0x00, 0x00, 0x00, }, 11, 0, "", "", +"62 f2 fd 49 c6 8c fd 7b 00 00 00 \tvgatherpf0dpd 0x7b(%ebp,%ymm7,8){%k1}",}, +{{0x62, 0xf2, 0x7d, 0x49, 0xc6, 0x94, 0xfd, 0x7b, 0x00, 0x00, 0x00, }, 11, 0, "", "", +"62 f2 7d 49 c6 94 fd 7b 00 00 00 \tvgatherpf1dps 0x7b(%ebp,%zmm7,8){%k1}",}, +{{0x62, 0xf2, 0xfd, 0x49, 0xc6, 0x94, 0xfd, 0x7b, 0x00, 0x00, 0x00, }, 11, 0, "", "", +"62 f2 fd 49 c6 94 fd 7b 00 00 00 \tvgatherpf1dpd 0x7b(%ebp,%ymm7,8){%k1}",}, +{{0x62, 0xf2, 0x7d, 0x49, 0xc6, 0xac, 0xfd, 0x7b, 0x00, 0x00, 0x00, }, 11, 0, "", "", +"62 f2 7d 49 c6 ac fd 7b 00 00 00 \tvscatterpf0dps 0x7b(%ebp,%zmm7,8){%k1}",}, +{{0x62, 0xf2, 0xfd, 0x49, 0xc6, 0xac, 0xfd, 0x7b, 0x00, 0x00, 0x00, }, 11, 0, "", "", +"62 f2 fd 49 c6 ac fd 7b 00 00 00 \tvscatterpf0dpd 0x7b(%ebp,%ymm7,8){%k1}",}, +{{0x62, 0xf2, 0x7d, 0x49, 0xc6, 0xb4, 0xfd, 0x7b, 0x00, 0x00, 0x00, }, 11, 0, "", "", +"62 f2 7d 49 c6 b4 fd 7b 00 00 00 \tvscatterpf1dps 0x7b(%ebp,%zmm7,8){%k1}",}, +{{0x62, 0xf2, 0xfd, 0x49, 0xc6, 0xb4, 0xfd, 0x7b, 0x00, 0x00, 0x00, }, 11, 0, "", "", +"62 f2 fd 49 c6 b4 fd 7b 00 00 00 \tvscatterpf1dpd 0x7b(%ebp,%ymm7,8){%k1}",}, +{{0x62, 0xf2, 0x7d, 0x49, 0xc7, 0x8c, 0xfd, 0x7b, 0x00, 0x00, 0x00, }, 11, 0, "", "", +"62 f2 7d 49 c7 8c fd 7b 00 00 00 \tvgatherpf0qps 0x7b(%ebp,%zmm7,8){%k1}",}, +{{0x62, 0xf2, 0xfd, 0x49, 0xc7, 0x8c, 0xfd, 0x7b, 0x00, 0x00, 0x00, }, 11, 0, "", "", +"62 f2 fd 49 c7 8c fd 7b 00 00 00 \tvgatherpf0qpd 0x7b(%ebp,%zmm7,8){%k1}",}, +{{0x62, 0xf2, 0x7d, 0x49, 0xc7, 0x94, 0xfd, 0x7b, 0x00, 0x00, 0x00, }, 11, 0, "", "", +"62 f2 7d 49 c7 94 fd 7b 00 00 00 \tvgatherpf1qps 0x7b(%ebp,%zmm7,8){%k1}",}, +{{0x62, 0xf2, 0xfd, 0x49, 0xc7, 0x94, 0xfd, 0x7b, 0x00, 0x00, 0x00, }, 11, 0, "", "", +"62 f2 fd 49 c7 94 fd 7b 00 00 00 \tvgatherpf1qpd 0x7b(%ebp,%zmm7,8){%k1}",}, +{{0x62, 0xf2, 0x7d, 0x49, 0xc7, 0xac, 0xfd, 0x7b, 0x00, 0x00, 0x00, }, 11, 0, "", "", +"62 f2 7d 49 c7 ac fd 7b 00 00 00 \tvscatterpf0qps 0x7b(%ebp,%zmm7,8){%k1}",}, +{{0x62, 0xf2, 0xfd, 0x49, 0xc7, 0xac, 0xfd, 0x7b, 0x00, 0x00, 0x00, }, 11, 0, "", "", +"62 f2 fd 49 c7 ac fd 7b 00 00 00 \tvscatterpf0qpd 0x7b(%ebp,%zmm7,8){%k1}",}, +{{0x62, 0xf2, 0x7d, 0x49, 0xc7, 0xb4, 0xfd, 0x7b, 0x00, 0x00, 0x00, }, 11, 0, "", "", +"62 f2 7d 49 c7 b4 fd 7b 00 00 00 \tvscatterpf1qps 0x7b(%ebp,%zmm7,8){%k1}",}, +{{0x62, 0xf2, 0xfd, 0x49, 0xc7, 0xb4, 0xfd, 0x7b, 0x00, 0x00, 0x00, }, 11, 0, "", "", +"62 f2 fd 49 c7 b4 fd 7b 00 00 00 \tvscatterpf1qpd 0x7b(%ebp,%zmm7,8){%k1}",}, +{{0x62, 0xf1, 0xd5, 0x48, 0x58, 0xf4, }, 6, 0, "", "", +"62 f1 d5 48 58 f4 \tvaddpd %zmm4,%zmm5,%zmm6",}, +{{0x62, 0xf1, 0xd5, 0x4f, 0x58, 0xf4, }, 6, 0, "", "", +"62 f1 d5 4f 58 f4 \tvaddpd %zmm4,%zmm5,%zmm6{%k7}",}, +{{0x62, 0xf1, 0xd5, 0xcf, 0x58, 0xf4, }, 6, 0, "", "", +"62 f1 d5 cf 58 f4 \tvaddpd %zmm4,%zmm5,%zmm6{%k7}{z}",}, +{{0x62, 0xf1, 0xd5, 0x18, 0x58, 0xf4, }, 6, 0, "", "", +"62 f1 d5 18 58 f4 \tvaddpd {rn-sae},%zmm4,%zmm5,%zmm6",}, +{{0x62, 0xf1, 0xd5, 0x58, 0x58, 0xf4, }, 6, 0, "", "", +"62 f1 d5 58 58 f4 \tvaddpd {ru-sae},%zmm4,%zmm5,%zmm6",}, +{{0x62, 0xf1, 0xd5, 0x38, 0x58, 0xf4, }, 6, 0, "", "", +"62 f1 d5 38 58 f4 \tvaddpd {rd-sae},%zmm4,%zmm5,%zmm6",}, +{{0x62, 0xf1, 0xd5, 0x78, 0x58, 0xf4, }, 6, 0, "", "", +"62 f1 d5 78 58 f4 \tvaddpd {rz-sae},%zmm4,%zmm5,%zmm6",}, +{{0x62, 0xf1, 0xd5, 0x48, 0x58, 0x31, }, 6, 0, "", "", +"62 f1 d5 48 58 31 \tvaddpd (%ecx),%zmm5,%zmm6",}, +{{0x62, 0xf1, 0xd5, 0x48, 0x58, 0xb4, 0xc8, 0x23, 0x01, 0x00, 0x00, }, 11, 0, "", "", +"62 f1 d5 48 58 b4 c8 23 01 00 00 \tvaddpd 0x123(%eax,%ecx,8),%zmm5,%zmm6",}, +{{0x62, 0xf1, 0xd5, 0x58, 0x58, 0x31, }, 6, 0, "", "", +"62 f1 d5 58 58 31 \tvaddpd (%ecx){1to8},%zmm5,%zmm6",}, +{{0x62, 0xf1, 0xd5, 0x48, 0x58, 0x72, 0x7f, }, 7, 0, "", "", +"62 f1 d5 48 58 72 7f \tvaddpd 0x1fc0(%edx),%zmm5,%zmm6",}, +{{0x62, 0xf1, 0xd5, 0x58, 0x58, 0x72, 0x7f, }, 7, 0, "", "", +"62 f1 d5 58 58 72 7f \tvaddpd 0x3f8(%edx){1to8},%zmm5,%zmm6",}, +{{0x62, 0xf1, 0x4c, 0x58, 0xc2, 0x6a, 0x7f, 0x08, }, 8, 0, "", "", +"62 f1 4c 58 c2 6a 7f 08 \tvcmpeq_uqps 0x1fc(%edx){1to16},%zmm6,%k5",}, +{{0x62, 0xf1, 0xe7, 0x0f, 0xc2, 0xac, 0xc8, 0x23, 0x01, 0x00, 0x00, 0x01, }, 12, 0, "", "", +"62 f1 e7 0f c2 ac c8 23 01 00 00 01 \tvcmpltsd 0x123(%eax,%ecx,8),%xmm3,%k5{%k7}",}, +{{0x62, 0xf1, 0xd7, 0x1f, 0xc2, 0xec, 0x02, }, 7, 0, "", "", +"62 f1 d7 1f c2 ec 02 \tvcmplesd {sae},%xmm4,%xmm5,%k5{%k7}",}, +{{0x62, 0xf3, 0x5d, 0x0f, 0x27, 0xac, 0xc8, 0x23, 0x01, 0x00, 0x00, 0x5b, }, 12, 0, "", "", +"62 f3 5d 0f 27 ac c8 23 01 00 00 5b \tvgetmantss $0x5b,0x123(%eax,%ecx,8),%xmm4,%xmm5{%k7}",}, {{0xf3, 0x0f, 0x1b, 0x00, }, 4, 0, "", "", "f3 0f 1b 00 \tbndmk (%eax),%bnd0",}, {{0xf3, 0x0f, 0x1b, 0x05, 0x78, 0x56, 0x34, 0x12, }, 8, 0, "", "", @@ -311,19 +1319,19 @@ {{0x0f, 0x1b, 0x84, 0x08, 0x78, 0x56, 0x34, 0x12, }, 8, 0, "", "", "0f 1b 84 08 78 56 34 12 \tbndstx %bnd0,0x12345678(%eax,%ecx,1)",}, {{0xf2, 0xe8, 0xfc, 0xff, 0xff, 0xff, }, 6, 0xfffffffc, "call", "unconditional", -"f2 e8 fc ff ff ff \tbnd call 3c8 ",}, +"f2 e8 fc ff ff ff \tbnd call fce ",}, {{0xf2, 0xff, 0x10, }, 3, 0, "call", "indirect", "f2 ff 10 \tbnd call *(%eax)",}, {{0xf2, 0xc3, }, 2, 0, "ret", "indirect", "f2 c3 \tbnd ret ",}, {{0xf2, 0xe9, 0xfc, 0xff, 0xff, 0xff, }, 6, 0xfffffffc, "jmp", "unconditional", -"f2 e9 fc ff ff ff \tbnd jmp 3d3 ",}, +"f2 e9 fc ff ff ff \tbnd jmp fd9 ",}, {{0xf2, 0xe9, 0xfc, 0xff, 0xff, 0xff, }, 6, 0xfffffffc, "jmp", "unconditional", -"f2 e9 fc ff ff ff \tbnd jmp 3d9 ",}, +"f2 e9 fc ff ff ff \tbnd jmp fdf ",}, {{0xf2, 0xff, 0x21, }, 3, 0, "jmp", "indirect", "f2 ff 21 \tbnd jmp *(%ecx)",}, {{0xf2, 0x0f, 0x85, 0xfc, 0xff, 0xff, 0xff, }, 7, 0xfffffffc, "jcc", "conditional", -"f2 0f 85 fc ff ff ff \tbnd jne 3e3 ",}, +"f2 0f 85 fc ff ff ff \tbnd jne fe9 ",}, {{0x0f, 0x3a, 0xcc, 0xc1, 0x00, }, 5, 0, "", "", "0f 3a cc c1 00 \tsha1rnds4 $0x0,%xmm1,%xmm0",}, {{0x0f, 0x3a, 0xcc, 0xd7, 0x91, }, 5, 0, "", "", diff --git a/tools/perf/arch/x86/tests/insn-x86-dat-64.c b/tools/perf/arch/x86/tests/insn-x86-dat-64.c index 262d9d2..9c8c61e 100644 --- a/tools/perf/arch/x86/tests/insn-x86-dat-64.c +++ b/tools/perf/arch/x86/tests/insn-x86-dat-64.c @@ -8,6 +8,936 @@ "0f 31 \trdtsc ",}, {{0xc4, 0xe2, 0x7d, 0x13, 0xeb, }, 5, 0, "", "", "c4 e2 7d 13 eb \tvcvtph2ps %xmm3,%ymm5",}, +{{0x48, 0x0f, 0x41, 0xd8, }, 4, 0, "", "", +"48 0f 41 d8 \tcmovno %rax,%rbx",}, +{{0x48, 0x0f, 0x41, 0x88, 0x78, 0x56, 0x34, 0x12, }, 8, 0, "", "", +"48 0f 41 88 78 56 34 12 \tcmovno 0x12345678(%rax),%rcx",}, +{{0x66, 0x0f, 0x41, 0x88, 0x78, 0x56, 0x34, 0x12, }, 8, 0, "", "", +"66 0f 41 88 78 56 34 12 \tcmovno 0x12345678(%rax),%cx",}, +{{0x48, 0x0f, 0x44, 0xd8, }, 4, 0, "", "", +"48 0f 44 d8 \tcmove %rax,%rbx",}, +{{0x48, 0x0f, 0x44, 0x88, 0x78, 0x56, 0x34, 0x12, }, 8, 0, "", "", +"48 0f 44 88 78 56 34 12 \tcmove 0x12345678(%rax),%rcx",}, +{{0x66, 0x0f, 0x44, 0x88, 0x78, 0x56, 0x34, 0x12, }, 8, 0, "", "", +"66 0f 44 88 78 56 34 12 \tcmove 0x12345678(%rax),%cx",}, +{{0x0f, 0x90, 0x80, 0x78, 0x56, 0x34, 0x12, }, 7, 0, "", "", +"0f 90 80 78 56 34 12 \tseto 0x12345678(%rax)",}, +{{0x0f, 0x91, 0x80, 0x78, 0x56, 0x34, 0x12, }, 7, 0, "", "", +"0f 91 80 78 56 34 12 \tsetno 0x12345678(%rax)",}, +{{0x0f, 0x92, 0x80, 0x78, 0x56, 0x34, 0x12, }, 7, 0, "", "", +"0f 92 80 78 56 34 12 \tsetb 0x12345678(%rax)",}, +{{0x0f, 0x92, 0x80, 0x78, 0x56, 0x34, 0x12, }, 7, 0, "", "", +"0f 92 80 78 56 34 12 \tsetb 0x12345678(%rax)",}, +{{0x0f, 0x92, 0x80, 0x78, 0x56, 0x34, 0x12, }, 7, 0, "", "", +"0f 92 80 78 56 34 12 \tsetb 0x12345678(%rax)",}, +{{0x0f, 0x93, 0x80, 0x78, 0x56, 0x34, 0x12, }, 7, 0, "", "", +"0f 93 80 78 56 34 12 \tsetae 0x12345678(%rax)",}, +{{0x0f, 0x93, 0x80, 0x78, 0x56, 0x34, 0x12, }, 7, 0, "", "", +"0f 93 80 78 56 34 12 \tsetae 0x12345678(%rax)",}, +{{0x0f, 0x93, 0x80, 0x78, 0x56, 0x34, 0x12, }, 7, 0, "", "", +"0f 93 80 78 56 34 12 \tsetae 0x12345678(%rax)",}, +{{0x0f, 0x98, 0x80, 0x78, 0x56, 0x34, 0x12, }, 7, 0, "", "", +"0f 98 80 78 56 34 12 \tsets 0x12345678(%rax)",}, +{{0x0f, 0x99, 0x80, 0x78, 0x56, 0x34, 0x12, }, 7, 0, "", "", +"0f 99 80 78 56 34 12 \tsetns 0x12345678(%rax)",}, +{{0xc5, 0xcc, 0x41, 0xef, }, 4, 0, "", "", +"c5 cc 41 ef \tkandw %k7,%k6,%k5",}, +{{0xc4, 0xe1, 0xcc, 0x41, 0xef, }, 5, 0, "", "", +"c4 e1 cc 41 ef \tkandq %k7,%k6,%k5",}, +{{0xc5, 0xcd, 0x41, 0xef, }, 4, 0, "", "", +"c5 cd 41 ef \tkandb %k7,%k6,%k5",}, +{{0xc4, 0xe1, 0xcd, 0x41, 0xef, }, 5, 0, "", "", +"c4 e1 cd 41 ef \tkandd %k7,%k6,%k5",}, +{{0xc5, 0xcc, 0x42, 0xef, }, 4, 0, "", "", +"c5 cc 42 ef \tkandnw %k7,%k6,%k5",}, +{{0xc4, 0xe1, 0xcc, 0x42, 0xef, }, 5, 0, "", "", +"c4 e1 cc 42 ef \tkandnq %k7,%k6,%k5",}, +{{0xc5, 0xcd, 0x42, 0xef, }, 4, 0, "", "", +"c5 cd 42 ef \tkandnb %k7,%k6,%k5",}, +{{0xc4, 0xe1, 0xcd, 0x42, 0xef, }, 5, 0, "", "", +"c4 e1 cd 42 ef \tkandnd %k7,%k6,%k5",}, +{{0xc5, 0xf8, 0x44, 0xf7, }, 4, 0, "", "", +"c5 f8 44 f7 \tknotw %k7,%k6",}, +{{0xc4, 0xe1, 0xf8, 0x44, 0xf7, }, 5, 0, "", "", +"c4 e1 f8 44 f7 \tknotq %k7,%k6",}, +{{0xc5, 0xf9, 0x44, 0xf7, }, 4, 0, "", "", +"c5 f9 44 f7 \tknotb %k7,%k6",}, +{{0xc4, 0xe1, 0xf9, 0x44, 0xf7, }, 5, 0, "", "", +"c4 e1 f9 44 f7 \tknotd %k7,%k6",}, +{{0xc5, 0xcc, 0x45, 0xef, }, 4, 0, "", "", +"c5 cc 45 ef \tkorw %k7,%k6,%k5",}, +{{0xc4, 0xe1, 0xcc, 0x45, 0xef, }, 5, 0, "", "", +"c4 e1 cc 45 ef \tkorq %k7,%k6,%k5",}, +{{0xc5, 0xcd, 0x45, 0xef, }, 4, 0, "", "", +"c5 cd 45 ef \tkorb %k7,%k6,%k5",}, +{{0xc4, 0xe1, 0xcd, 0x45, 0xef, }, 5, 0, "", "", +"c4 e1 cd 45 ef \tkord %k7,%k6,%k5",}, +{{0xc5, 0xcc, 0x46, 0xef, }, 4, 0, "", "", +"c5 cc 46 ef \tkxnorw %k7,%k6,%k5",}, +{{0xc4, 0xe1, 0xcc, 0x46, 0xef, }, 5, 0, "", "", +"c4 e1 cc 46 ef \tkxnorq %k7,%k6,%k5",}, +{{0xc5, 0xcd, 0x46, 0xef, }, 4, 0, "", "", +"c5 cd 46 ef \tkxnorb %k7,%k6,%k5",}, +{{0xc4, 0xe1, 0xcd, 0x46, 0xef, }, 5, 0, "", "", +"c4 e1 cd 46 ef \tkxnord %k7,%k6,%k5",}, +{{0xc5, 0xcc, 0x47, 0xef, }, 4, 0, "", "", +"c5 cc 47 ef \tkxorw %k7,%k6,%k5",}, +{{0xc4, 0xe1, 0xcc, 0x47, 0xef, }, 5, 0, "", "", +"c4 e1 cc 47 ef \tkxorq %k7,%k6,%k5",}, +{{0xc5, 0xcd, 0x47, 0xef, }, 4, 0, "", "", +"c5 cd 47 ef \tkxorb %k7,%k6,%k5",}, +{{0xc4, 0xe1, 0xcd, 0x47, 0xef, }, 5, 0, "", "", +"c4 e1 cd 47 ef \tkxord %k7,%k6,%k5",}, +{{0xc5, 0xcc, 0x4a, 0xef, }, 4, 0, "", "", +"c5 cc 4a ef \tkaddw %k7,%k6,%k5",}, +{{0xc4, 0xe1, 0xcc, 0x4a, 0xef, }, 5, 0, "", "", +"c4 e1 cc 4a ef \tkaddq %k7,%k6,%k5",}, +{{0xc5, 0xcd, 0x4a, 0xef, }, 4, 0, "", "", +"c5 cd 4a ef \tkaddb %k7,%k6,%k5",}, +{{0xc4, 0xe1, 0xcd, 0x4a, 0xef, }, 5, 0, "", "", +"c4 e1 cd 4a ef \tkaddd %k7,%k6,%k5",}, +{{0xc5, 0xcd, 0x4b, 0xef, }, 4, 0, "", "", +"c5 cd 4b ef \tkunpckbw %k7,%k6,%k5",}, +{{0xc5, 0xcc, 0x4b, 0xef, }, 4, 0, "", "", +"c5 cc 4b ef \tkunpckwd %k7,%k6,%k5",}, +{{0xc4, 0xe1, 0xcc, 0x4b, 0xef, }, 5, 0, "", "", +"c4 e1 cc 4b ef \tkunpckdq %k7,%k6,%k5",}, +{{0xc5, 0xf8, 0x90, 0xee, }, 4, 0, "", "", +"c5 f8 90 ee \tkmovw %k6,%k5",}, +{{0xc5, 0xf8, 0x90, 0x29, }, 4, 0, "", "", +"c5 f8 90 29 \tkmovw (%rcx),%k5",}, +{{0xc4, 0xa1, 0x78, 0x90, 0xac, 0xf0, 0x23, 0x01, 0x00, 0x00, }, 10, 0, "", "", +"c4 a1 78 90 ac f0 23 01 00 00 \tkmovw 0x123(%rax,%r14,8),%k5",}, +{{0xc5, 0xf8, 0x91, 0x29, }, 4, 0, "", "", +"c5 f8 91 29 \tkmovw %k5,(%rcx)",}, +{{0xc4, 0xa1, 0x78, 0x91, 0xac, 0xf0, 0x23, 0x01, 0x00, 0x00, }, 10, 0, "", "", +"c4 a1 78 91 ac f0 23 01 00 00 \tkmovw %k5,0x123(%rax,%r14,8)",}, +{{0xc5, 0xf8, 0x92, 0xe8, }, 4, 0, "", "", +"c5 f8 92 e8 \tkmovw %eax,%k5",}, +{{0xc5, 0xf8, 0x92, 0xed, }, 4, 0, "", "", +"c5 f8 92 ed \tkmovw %ebp,%k5",}, +{{0xc4, 0xc1, 0x78, 0x92, 0xed, }, 5, 0, "", "", +"c4 c1 78 92 ed \tkmovw %r13d,%k5",}, +{{0xc5, 0xf8, 0x93, 0xc5, }, 4, 0, "", "", +"c5 f8 93 c5 \tkmovw %k5,%eax",}, +{{0xc5, 0xf8, 0x93, 0xed, }, 4, 0, "", "", +"c5 f8 93 ed \tkmovw %k5,%ebp",}, +{{0xc5, 0x78, 0x93, 0xed, }, 4, 0, "", "", +"c5 78 93 ed \tkmovw %k5,%r13d",}, +{{0xc4, 0xe1, 0xf8, 0x90, 0xee, }, 5, 0, "", "", +"c4 e1 f8 90 ee \tkmovq %k6,%k5",}, +{{0xc4, 0xe1, 0xf8, 0x90, 0x29, }, 5, 0, "", "", +"c4 e1 f8 90 29 \tkmovq (%rcx),%k5",}, +{{0xc4, 0xa1, 0xf8, 0x90, 0xac, 0xf0, 0x23, 0x01, 0x00, 0x00, }, 10, 0, "", "", +"c4 a1 f8 90 ac f0 23 01 00 00 \tkmovq 0x123(%rax,%r14,8),%k5",}, +{{0xc4, 0xe1, 0xf8, 0x91, 0x29, }, 5, 0, "", "", +"c4 e1 f8 91 29 \tkmovq %k5,(%rcx)",}, +{{0xc4, 0xa1, 0xf8, 0x91, 0xac, 0xf0, 0x23, 0x01, 0x00, 0x00, }, 10, 0, "", "", +"c4 a1 f8 91 ac f0 23 01 00 00 \tkmovq %k5,0x123(%rax,%r14,8)",}, +{{0xc4, 0xe1, 0xfb, 0x92, 0xe8, }, 5, 0, "", "", +"c4 e1 fb 92 e8 \tkmovq %rax,%k5",}, +{{0xc4, 0xe1, 0xfb, 0x92, 0xed, }, 5, 0, "", "", +"c4 e1 fb 92 ed \tkmovq %rbp,%k5",}, +{{0xc4, 0xc1, 0xfb, 0x92, 0xed, }, 5, 0, "", "", +"c4 c1 fb 92 ed \tkmovq %r13,%k5",}, +{{0xc4, 0xe1, 0xfb, 0x93, 0xc5, }, 5, 0, "", "", +"c4 e1 fb 93 c5 \tkmovq %k5,%rax",}, +{{0xc4, 0xe1, 0xfb, 0x93, 0xed, }, 5, 0, "", "", +"c4 e1 fb 93 ed \tkmovq %k5,%rbp",}, +{{0xc4, 0x61, 0xfb, 0x93, 0xed, }, 5, 0, "", "", +"c4 61 fb 93 ed \tkmovq %k5,%r13",}, +{{0xc5, 0xf9, 0x90, 0xee, }, 4, 0, "", "", +"c5 f9 90 ee \tkmovb %k6,%k5",}, +{{0xc5, 0xf9, 0x90, 0x29, }, 4, 0, "", "", +"c5 f9 90 29 \tkmovb (%rcx),%k5",}, +{{0xc4, 0xa1, 0x79, 0x90, 0xac, 0xf0, 0x23, 0x01, 0x00, 0x00, }, 10, 0, "", "", +"c4 a1 79 90 ac f0 23 01 00 00 \tkmovb 0x123(%rax,%r14,8),%k5",}, +{{0xc5, 0xf9, 0x91, 0x29, }, 4, 0, "", "", +"c5 f9 91 29 \tkmovb %k5,(%rcx)",}, +{{0xc4, 0xa1, 0x79, 0x91, 0xac, 0xf0, 0x23, 0x01, 0x00, 0x00, }, 10, 0, "", "", +"c4 a1 79 91 ac f0 23 01 00 00 \tkmovb %k5,0x123(%rax,%r14,8)",}, +{{0xc5, 0xf9, 0x92, 0xe8, }, 4, 0, "", "", +"c5 f9 92 e8 \tkmovb %eax,%k5",}, +{{0xc5, 0xf9, 0x92, 0xed, }, 4, 0, "", "", +"c5 f9 92 ed \tkmovb %ebp,%k5",}, +{{0xc4, 0xc1, 0x79, 0x92, 0xed, }, 5, 0, "", "", +"c4 c1 79 92 ed \tkmovb %r13d,%k5",}, +{{0xc5, 0xf9, 0x93, 0xc5, }, 4, 0, "", "", +"c5 f9 93 c5 \tkmovb %k5,%eax",}, +{{0xc5, 0xf9, 0x93, 0xed, }, 4, 0, "", "", +"c5 f9 93 ed \tkmovb %k5,%ebp",}, +{{0xc5, 0x79, 0x93, 0xed, }, 4, 0, "", "", +"c5 79 93 ed \tkmovb %k5,%r13d",}, +{{0xc4, 0xe1, 0xf9, 0x90, 0xee, }, 5, 0, "", "", +"c4 e1 f9 90 ee \tkmovd %k6,%k5",}, +{{0xc4, 0xe1, 0xf9, 0x90, 0x29, }, 5, 0, "", "", +"c4 e1 f9 90 29 \tkmovd (%rcx),%k5",}, +{{0xc4, 0xa1, 0xf9, 0x90, 0xac, 0xf0, 0x23, 0x01, 0x00, 0x00, }, 10, 0, "", "", +"c4 a1 f9 90 ac f0 23 01 00 00 \tkmovd 0x123(%rax,%r14,8),%k5",}, +{{0xc4, 0xe1, 0xf9, 0x91, 0x29, }, 5, 0, "", "", +"c4 e1 f9 91 29 \tkmovd %k5,(%rcx)",}, +{{0xc4, 0xa1, 0xf9, 0x91, 0xac, 0xf0, 0x23, 0x01, 0x00, 0x00, }, 10, 0, "", "", +"c4 a1 f9 91 ac f0 23 01 00 00 \tkmovd %k5,0x123(%rax,%r14,8)",}, +{{0xc5, 0xfb, 0x92, 0xe8, }, 4, 0, "", "", +"c5 fb 92 e8 \tkmovd %eax,%k5",}, +{{0xc5, 0xfb, 0x92, 0xed, }, 4, 0, "", "", +"c5 fb 92 ed \tkmovd %ebp,%k5",}, +{{0xc4, 0xc1, 0x7b, 0x92, 0xed, }, 5, 0, "", "", +"c4 c1 7b 92 ed \tkmovd %r13d,%k5",}, +{{0xc5, 0xfb, 0x93, 0xc5, }, 4, 0, "", "", +"c5 fb 93 c5 \tkmovd %k5,%eax",}, +{{0xc5, 0xfb, 0x93, 0xed, }, 4, 0, "", "", +"c5 fb 93 ed \tkmovd %k5,%ebp",}, +{{0xc5, 0x7b, 0x93, 0xed, }, 4, 0, "", "", +"c5 7b 93 ed \tkmovd %k5,%r13d",}, +{{0xc5, 0xf8, 0x98, 0xee, }, 4, 0, "", "", +"c5 f8 98 ee \tkortestw %k6,%k5",}, +{{0xc4, 0xe1, 0xf8, 0x98, 0xee, }, 5, 0, "", "", +"c4 e1 f8 98 ee \tkortestq %k6,%k5",}, +{{0xc5, 0xf9, 0x98, 0xee, }, 4, 0, "", "", +"c5 f9 98 ee \tkortestb %k6,%k5",}, +{{0xc4, 0xe1, 0xf9, 0x98, 0xee, }, 5, 0, "", "", +"c4 e1 f9 98 ee \tkortestd %k6,%k5",}, +{{0xc5, 0xf8, 0x99, 0xee, }, 4, 0, "", "", +"c5 f8 99 ee \tktestw %k6,%k5",}, +{{0xc4, 0xe1, 0xf8, 0x99, 0xee, }, 5, 0, "", "", +"c4 e1 f8 99 ee \tktestq %k6,%k5",}, +{{0xc5, 0xf9, 0x99, 0xee, }, 4, 0, "", "", +"c5 f9 99 ee \tktestb %k6,%k5",}, +{{0xc4, 0xe1, 0xf9, 0x99, 0xee, }, 5, 0, "", "", +"c4 e1 f9 99 ee \tktestd %k6,%k5",}, +{{0xc4, 0xe3, 0xf9, 0x30, 0xee, 0x12, }, 6, 0, "", "", +"c4 e3 f9 30 ee 12 \tkshiftrw $0x12,%k6,%k5",}, +{{0xc4, 0xe3, 0xf9, 0x31, 0xee, 0x5b, }, 6, 0, "", "", +"c4 e3 f9 31 ee 5b \tkshiftrq $0x5b,%k6,%k5",}, +{{0xc4, 0xe3, 0xf9, 0x32, 0xee, 0x12, }, 6, 0, "", "", +"c4 e3 f9 32 ee 12 \tkshiftlw $0x12,%k6,%k5",}, +{{0xc4, 0xe3, 0xf9, 0x33, 0xee, 0x5b, }, 6, 0, "", "", +"c4 e3 f9 33 ee 5b \tkshiftlq $0x5b,%k6,%k5",}, +{{0xc5, 0xf8, 0x5b, 0xf5, }, 4, 0, "", "", +"c5 f8 5b f5 \tvcvtdq2ps %xmm5,%xmm6",}, +{{0x62, 0x91, 0xfc, 0x4f, 0x5b, 0xf5, }, 6, 0, "", "", +"62 91 fc 4f 5b f5 \tvcvtqq2ps %zmm29,%ymm6{%k7}",}, +{{0xc5, 0xf9, 0x5b, 0xf5, }, 4, 0, "", "", +"c5 f9 5b f5 \tvcvtps2dq %xmm5,%xmm6",}, +{{0xc5, 0xfa, 0x5b, 0xf5, }, 4, 0, "", "", +"c5 fa 5b f5 \tvcvttps2dq %xmm5,%xmm6",}, +{{0x0f, 0x6f, 0xe0, }, 3, 0, "", "", +"0f 6f e0 \tmovq %mm0,%mm4",}, +{{0xc5, 0xfd, 0x6f, 0xf4, }, 4, 0, "", "", +"c5 fd 6f f4 \tvmovdqa %ymm4,%ymm6",}, +{{0x62, 0x01, 0x7d, 0x48, 0x6f, 0xd1, }, 6, 0, "", "", +"62 01 7d 48 6f d1 \tvmovdqa32 %zmm25,%zmm26",}, +{{0x62, 0x01, 0xfd, 0x48, 0x6f, 0xd1, }, 6, 0, "", "", +"62 01 fd 48 6f d1 \tvmovdqa64 %zmm25,%zmm26",}, +{{0xc5, 0xfe, 0x6f, 0xf4, }, 4, 0, "", "", +"c5 fe 6f f4 \tvmovdqu %ymm4,%ymm6",}, +{{0x62, 0x01, 0x7e, 0x48, 0x6f, 0xf5, }, 6, 0, "", "", +"62 01 7e 48 6f f5 \tvmovdqu32 %zmm29,%zmm30",}, +{{0x62, 0x01, 0xfe, 0x48, 0x6f, 0xd1, }, 6, 0, "", "", +"62 01 fe 48 6f d1 \tvmovdqu64 %zmm25,%zmm26",}, +{{0x62, 0x01, 0x7f, 0x48, 0x6f, 0xf5, }, 6, 0, "", "", +"62 01 7f 48 6f f5 \tvmovdqu8 %zmm29,%zmm30",}, +{{0x62, 0x01, 0xff, 0x48, 0x6f, 0xd1, }, 6, 0, "", "", +"62 01 ff 48 6f d1 \tvmovdqu16 %zmm25,%zmm26",}, +{{0x0f, 0x78, 0xc3, }, 3, 0, "", "", +"0f 78 c3 \tvmread %rax,%rbx",}, +{{0x62, 0x01, 0x7c, 0x48, 0x78, 0xd1, }, 6, 0, "", "", +"62 01 7c 48 78 d1 \tvcvttps2udq %zmm25,%zmm26",}, +{{0x62, 0x91, 0xfc, 0x4f, 0x78, 0xf5, }, 6, 0, "", "", +"62 91 fc 4f 78 f5 \tvcvttpd2udq %zmm29,%ymm6{%k7}",}, +{{0x62, 0xf1, 0xff, 0x08, 0x78, 0xc6, }, 6, 0, "", "", +"62 f1 ff 08 78 c6 \tvcvttsd2usi %xmm6,%rax",}, +{{0x62, 0xf1, 0xfe, 0x08, 0x78, 0xc6, }, 6, 0, "", "", +"62 f1 fe 08 78 c6 \tvcvttss2usi %xmm6,%rax",}, +{{0x62, 0x61, 0x7d, 0x4f, 0x78, 0xd5, }, 6, 0, "", "", +"62 61 7d 4f 78 d5 \tvcvttps2uqq %ymm5,%zmm26{%k7}",}, +{{0x62, 0x01, 0xfd, 0x48, 0x78, 0xf5, }, 6, 0, "", "", +"62 01 fd 48 78 f5 \tvcvttpd2uqq %zmm29,%zmm30",}, +{{0x0f, 0x79, 0xd8, }, 3, 0, "", "", +"0f 79 d8 \tvmwrite %rax,%rbx",}, +{{0x62, 0x01, 0x7c, 0x48, 0x79, 0xd1, }, 6, 0, "", "", +"62 01 7c 48 79 d1 \tvcvtps2udq %zmm25,%zmm26",}, +{{0x62, 0x91, 0xfc, 0x4f, 0x79, 0xf5, }, 6, 0, "", "", +"62 91 fc 4f 79 f5 \tvcvtpd2udq %zmm29,%ymm6{%k7}",}, +{{0x62, 0xf1, 0xff, 0x08, 0x79, 0xc6, }, 6, 0, "", "", +"62 f1 ff 08 79 c6 \tvcvtsd2usi %xmm6,%rax",}, +{{0x62, 0xf1, 0xfe, 0x08, 0x79, 0xc6, }, 6, 0, "", "", +"62 f1 fe 08 79 c6 \tvcvtss2usi %xmm6,%rax",}, +{{0x62, 0x61, 0x7d, 0x4f, 0x79, 0xd5, }, 6, 0, "", "", +"62 61 7d 4f 79 d5 \tvcvtps2uqq %ymm5,%zmm26{%k7}",}, +{{0x62, 0x01, 0xfd, 0x48, 0x79, 0xf5, }, 6, 0, "", "", +"62 01 fd 48 79 f5 \tvcvtpd2uqq %zmm29,%zmm30",}, +{{0x62, 0x61, 0x7e, 0x4f, 0x7a, 0xed, }, 6, 0, "", "", +"62 61 7e 4f 7a ed \tvcvtudq2pd %ymm5,%zmm29{%k7}",}, +{{0x62, 0x01, 0xfe, 0x48, 0x7a, 0xd1, }, 6, 0, "", "", +"62 01 fe 48 7a d1 \tvcvtuqq2pd %zmm25,%zmm26",}, +{{0x62, 0x01, 0x7f, 0x48, 0x7a, 0xf5, }, 6, 0, "", "", +"62 01 7f 48 7a f5 \tvcvtudq2ps %zmm29,%zmm30",}, +{{0x62, 0x01, 0xff, 0x4f, 0x7a, 0xd1, }, 6, 0, "", "", +"62 01 ff 4f 7a d1 \tvcvtuqq2ps %zmm25,%ymm26{%k7}",}, +{{0x62, 0x01, 0x7d, 0x4f, 0x7a, 0xd1, }, 6, 0, "", "", +"62 01 7d 4f 7a d1 \tvcvttps2qq %ymm25,%zmm26{%k7}",}, +{{0x62, 0x01, 0xfd, 0x48, 0x7a, 0xf5, }, 6, 0, "", "", +"62 01 fd 48 7a f5 \tvcvttpd2qq %zmm29,%zmm30",}, +{{0x62, 0xf1, 0x57, 0x08, 0x7b, 0xf0, }, 6, 0, "", "", +"62 f1 57 08 7b f0 \tvcvtusi2sd %eax,%xmm5,%xmm6",}, +{{0x62, 0xf1, 0x56, 0x08, 0x7b, 0xf0, }, 6, 0, "", "", +"62 f1 56 08 7b f0 \tvcvtusi2ss %eax,%xmm5,%xmm6",}, +{{0x62, 0x61, 0x7d, 0x4f, 0x7b, 0xd5, }, 6, 0, "", "", +"62 61 7d 4f 7b d5 \tvcvtps2qq %ymm5,%zmm26{%k7}",}, +{{0x62, 0x01, 0xfd, 0x48, 0x7b, 0xf5, }, 6, 0, "", "", +"62 01 fd 48 7b f5 \tvcvtpd2qq %zmm29,%zmm30",}, +{{0x0f, 0x7f, 0xc4, }, 3, 0, "", "", +"0f 7f c4 \tmovq %mm0,%mm4",}, +{{0xc5, 0x7d, 0x7f, 0xc6, }, 4, 0, "", "", +"c5 7d 7f c6 \tvmovdqa %ymm8,%ymm6",}, +{{0x62, 0x01, 0x7d, 0x48, 0x7f, 0xca, }, 6, 0, "", "", +"62 01 7d 48 7f ca \tvmovdqa32 %zmm25,%zmm26",}, +{{0x62, 0x01, 0xfd, 0x48, 0x7f, 0xca, }, 6, 0, "", "", +"62 01 fd 48 7f ca \tvmovdqa64 %zmm25,%zmm26",}, +{{0xc5, 0x7e, 0x7f, 0xc6, }, 4, 0, "", "", +"c5 7e 7f c6 \tvmovdqu %ymm8,%ymm6",}, +{{0x62, 0x01, 0x7e, 0x48, 0x7f, 0xca, }, 6, 0, "", "", +"62 01 7e 48 7f ca \tvmovdqu32 %zmm25,%zmm26",}, +{{0x62, 0x01, 0xfe, 0x48, 0x7f, 0xca, }, 6, 0, "", "", +"62 01 fe 48 7f ca \tvmovdqu64 %zmm25,%zmm26",}, +{{0x62, 0x61, 0x7f, 0x48, 0x7f, 0x31, }, 6, 0, "", "", +"62 61 7f 48 7f 31 \tvmovdqu8 %zmm30,(%rcx)",}, +{{0x62, 0x01, 0xff, 0x48, 0x7f, 0xca, }, 6, 0, "", "", +"62 01 ff 48 7f ca \tvmovdqu16 %zmm25,%zmm26",}, +{{0x0f, 0xdb, 0xd1, }, 3, 0, "", "", +"0f db d1 \tpand %mm1,%mm2",}, +{{0x66, 0x0f, 0xdb, 0xd1, }, 4, 0, "", "", +"66 0f db d1 \tpand %xmm1,%xmm2",}, +{{0xc5, 0xcd, 0xdb, 0xd4, }, 4, 0, "", "", +"c5 cd db d4 \tvpand %ymm4,%ymm6,%ymm2",}, +{{0x62, 0x01, 0x35, 0x40, 0xdb, 0xd0, }, 6, 0, "", "", +"62 01 35 40 db d0 \tvpandd %zmm24,%zmm25,%zmm26",}, +{{0x62, 0x01, 0xb5, 0x40, 0xdb, 0xd0, }, 6, 0, "", "", +"62 01 b5 40 db d0 \tvpandq %zmm24,%zmm25,%zmm26",}, +{{0x0f, 0xdf, 0xd1, }, 3, 0, "", "", +"0f df d1 \tpandn %mm1,%mm2",}, +{{0x66, 0x0f, 0xdf, 0xd1, }, 4, 0, "", "", +"66 0f df d1 \tpandn %xmm1,%xmm2",}, +{{0xc5, 0xcd, 0xdf, 0xd4, }, 4, 0, "", "", +"c5 cd df d4 \tvpandn %ymm4,%ymm6,%ymm2",}, +{{0x62, 0x01, 0x35, 0x40, 0xdf, 0xd0, }, 6, 0, "", "", +"62 01 35 40 df d0 \tvpandnd %zmm24,%zmm25,%zmm26",}, +{{0x62, 0x01, 0xb5, 0x40, 0xdf, 0xd0, }, 6, 0, "", "", +"62 01 b5 40 df d0 \tvpandnq %zmm24,%zmm25,%zmm26",}, +{{0xc5, 0xf9, 0xe6, 0xd1, }, 4, 0, "", "", +"c5 f9 e6 d1 \tvcvttpd2dq %xmm1,%xmm2",}, +{{0xc5, 0xfa, 0xe6, 0xf5, }, 4, 0, "", "", +"c5 fa e6 f5 \tvcvtdq2pd %xmm5,%xmm6",}, +{{0x62, 0x61, 0x7e, 0x4f, 0xe6, 0xd5, }, 6, 0, "", "", +"62 61 7e 4f e6 d5 \tvcvtdq2pd %ymm5,%zmm26{%k7}",}, +{{0x62, 0x01, 0xfe, 0x48, 0xe6, 0xd1, }, 6, 0, "", "", +"62 01 fe 48 e6 d1 \tvcvtqq2pd %zmm25,%zmm26",}, +{{0xc5, 0xfb, 0xe6, 0xd1, }, 4, 0, "", "", +"c5 fb e6 d1 \tvcvtpd2dq %xmm1,%xmm2",}, +{{0x0f, 0xeb, 0xf4, }, 3, 0, "", "", +"0f eb f4 \tpor %mm4,%mm6",}, +{{0xc5, 0xcd, 0xeb, 0xd4, }, 4, 0, "", "", +"c5 cd eb d4 \tvpor %ymm4,%ymm6,%ymm2",}, +{{0x62, 0x01, 0x35, 0x40, 0xeb, 0xd0, }, 6, 0, "", "", +"62 01 35 40 eb d0 \tvpord %zmm24,%zmm25,%zmm26",}, +{{0x62, 0x01, 0xb5, 0x40, 0xeb, 0xd0, }, 6, 0, "", "", +"62 01 b5 40 eb d0 \tvporq %zmm24,%zmm25,%zmm26",}, +{{0x0f, 0xef, 0xf4, }, 3, 0, "", "", +"0f ef f4 \tpxor %mm4,%mm6",}, +{{0xc5, 0xcd, 0xef, 0xd4, }, 4, 0, "", "", +"c5 cd ef d4 \tvpxor %ymm4,%ymm6,%ymm2",}, +{{0x62, 0x01, 0x35, 0x40, 0xef, 0xd0, }, 6, 0, "", "", +"62 01 35 40 ef d0 \tvpxord %zmm24,%zmm25,%zmm26",}, +{{0x62, 0x01, 0xb5, 0x40, 0xef, 0xd0, }, 6, 0, "", "", +"62 01 b5 40 ef d0 \tvpxorq %zmm24,%zmm25,%zmm26",}, +{{0x66, 0x0f, 0x38, 0x10, 0xc1, }, 5, 0, "", "", +"66 0f 38 10 c1 \tpblendvb %xmm0,%xmm1,%xmm0",}, +{{0x62, 0x02, 0x9d, 0x40, 0x10, 0xeb, }, 6, 0, "", "", +"62 02 9d 40 10 eb \tvpsrlvw %zmm27,%zmm28,%zmm29",}, +{{0x62, 0x62, 0x7e, 0x4f, 0x10, 0xe6, }, 6, 0, "", "", +"62 62 7e 4f 10 e6 \tvpmovuswb %zmm28,%ymm6{%k7}",}, +{{0x62, 0x62, 0x7e, 0x4f, 0x11, 0xe6, }, 6, 0, "", "", +"62 62 7e 4f 11 e6 \tvpmovusdb %zmm28,%xmm6{%k7}",}, +{{0x62, 0x02, 0x9d, 0x40, 0x11, 0xeb, }, 6, 0, "", "", +"62 02 9d 40 11 eb \tvpsravw %zmm27,%zmm28,%zmm29",}, +{{0x62, 0x62, 0x7e, 0x4f, 0x12, 0xde, }, 6, 0, "", "", +"62 62 7e 4f 12 de \tvpmovusqb %zmm27,%xmm6{%k7}",}, +{{0x62, 0x02, 0x9d, 0x40, 0x12, 0xeb, }, 6, 0, "", "", +"62 02 9d 40 12 eb \tvpsllvw %zmm27,%zmm28,%zmm29",}, +{{0xc4, 0xe2, 0x7d, 0x13, 0xeb, }, 5, 0, "", "", +"c4 e2 7d 13 eb \tvcvtph2ps %xmm3,%ymm5",}, +{{0x62, 0x62, 0x7d, 0x4f, 0x13, 0xdd, }, 6, 0, "", "", +"62 62 7d 4f 13 dd \tvcvtph2ps %ymm5,%zmm27{%k7}",}, +{{0x62, 0x62, 0x7e, 0x4f, 0x13, 0xde, }, 6, 0, "", "", +"62 62 7e 4f 13 de \tvpmovusdw %zmm27,%ymm6{%k7}",}, +{{0x66, 0x0f, 0x38, 0x14, 0xc1, }, 5, 0, "", "", +"66 0f 38 14 c1 \tblendvps %xmm0,%xmm1,%xmm0",}, +{{0x62, 0x62, 0x7e, 0x4f, 0x14, 0xde, }, 6, 0, "", "", +"62 62 7e 4f 14 de \tvpmovusqw %zmm27,%xmm6{%k7}",}, +{{0x62, 0x02, 0x1d, 0x40, 0x14, 0xeb, }, 6, 0, "", "", +"62 02 1d 40 14 eb \tvprorvd %zmm27,%zmm28,%zmm29",}, +{{0x62, 0x02, 0x9d, 0x40, 0x14, 0xeb, }, 6, 0, "", "", +"62 02 9d 40 14 eb \tvprorvq %zmm27,%zmm28,%zmm29",}, +{{0x66, 0x0f, 0x38, 0x15, 0xc1, }, 5, 0, "", "", +"66 0f 38 15 c1 \tblendvpd %xmm0,%xmm1,%xmm0",}, +{{0x62, 0x62, 0x7e, 0x4f, 0x15, 0xde, }, 6, 0, "", "", +"62 62 7e 4f 15 de \tvpmovusqd %zmm27,%ymm6{%k7}",}, +{{0x62, 0x02, 0x1d, 0x40, 0x15, 0xeb, }, 6, 0, "", "", +"62 02 1d 40 15 eb \tvprolvd %zmm27,%zmm28,%zmm29",}, +{{0x62, 0x02, 0x9d, 0x40, 0x15, 0xeb, }, 6, 0, "", "", +"62 02 9d 40 15 eb \tvprolvq %zmm27,%zmm28,%zmm29",}, +{{0xc4, 0xe2, 0x4d, 0x16, 0xd4, }, 5, 0, "", "", +"c4 e2 4d 16 d4 \tvpermps %ymm4,%ymm6,%ymm2",}, +{{0x62, 0x82, 0x2d, 0x27, 0x16, 0xf0, }, 6, 0, "", "", +"62 82 2d 27 16 f0 \tvpermps %ymm24,%ymm26,%ymm22{%k7}",}, +{{0x62, 0x82, 0xad, 0x27, 0x16, 0xf0, }, 6, 0, "", "", +"62 82 ad 27 16 f0 \tvpermpd %ymm24,%ymm26,%ymm22{%k7}",}, +{{0xc4, 0xe2, 0x7d, 0x19, 0xf4, }, 5, 0, "", "", +"c4 e2 7d 19 f4 \tvbroadcastsd %xmm4,%ymm6",}, +{{0x62, 0x02, 0x7d, 0x48, 0x19, 0xd3, }, 6, 0, "", "", +"62 02 7d 48 19 d3 \tvbroadcastf32x2 %xmm27,%zmm26",}, +{{0xc4, 0xe2, 0x7d, 0x1a, 0x21, }, 5, 0, "", "", +"c4 e2 7d 1a 21 \tvbroadcastf128 (%rcx),%ymm4",}, +{{0x62, 0x62, 0x7d, 0x48, 0x1a, 0x11, }, 6, 0, "", "", +"62 62 7d 48 1a 11 \tvbroadcastf32x4 (%rcx),%zmm26",}, +{{0x62, 0x62, 0xfd, 0x48, 0x1a, 0x11, }, 6, 0, "", "", +"62 62 fd 48 1a 11 \tvbroadcastf64x2 (%rcx),%zmm26",}, +{{0x62, 0x62, 0x7d, 0x48, 0x1b, 0x19, }, 6, 0, "", "", +"62 62 7d 48 1b 19 \tvbroadcastf32x8 (%rcx),%zmm27",}, +{{0x62, 0x62, 0xfd, 0x48, 0x1b, 0x11, }, 6, 0, "", "", +"62 62 fd 48 1b 11 \tvbroadcastf64x4 (%rcx),%zmm26",}, +{{0x62, 0x02, 0xfd, 0x48, 0x1f, 0xe3, }, 6, 0, "", "", +"62 02 fd 48 1f e3 \tvpabsq %zmm27,%zmm28",}, +{{0xc4, 0xe2, 0x79, 0x20, 0xec, }, 5, 0, "", "", +"c4 e2 79 20 ec \tvpmovsxbw %xmm4,%xmm5",}, +{{0x62, 0x62, 0x7e, 0x4f, 0x20, 0xde, }, 6, 0, "", "", +"62 62 7e 4f 20 de \tvpmovswb %zmm27,%ymm6{%k7}",}, +{{0xc4, 0xe2, 0x7d, 0x21, 0xf4, }, 5, 0, "", "", +"c4 e2 7d 21 f4 \tvpmovsxbd %xmm4,%ymm6",}, +{{0x62, 0x62, 0x7e, 0x4f, 0x21, 0xde, }, 6, 0, "", "", +"62 62 7e 4f 21 de \tvpmovsdb %zmm27,%xmm6{%k7}",}, +{{0xc4, 0xe2, 0x7d, 0x22, 0xe4, }, 5, 0, "", "", +"c4 e2 7d 22 e4 \tvpmovsxbq %xmm4,%ymm4",}, +{{0x62, 0x62, 0x7e, 0x4f, 0x22, 0xde, }, 6, 0, "", "", +"62 62 7e 4f 22 de \tvpmovsqb %zmm27,%xmm6{%k7}",}, +{{0xc4, 0xe2, 0x7d, 0x23, 0xe4, }, 5, 0, "", "", +"c4 e2 7d 23 e4 \tvpmovsxwd %xmm4,%ymm4",}, +{{0x62, 0x62, 0x7e, 0x4f, 0x23, 0xde, }, 6, 0, "", "", +"62 62 7e 4f 23 de \tvpmovsdw %zmm27,%ymm6{%k7}",}, +{{0xc4, 0xe2, 0x7d, 0x24, 0xf4, }, 5, 0, "", "", +"c4 e2 7d 24 f4 \tvpmovsxwq %xmm4,%ymm6",}, +{{0x62, 0x62, 0x7e, 0x4f, 0x24, 0xde, }, 6, 0, "", "", +"62 62 7e 4f 24 de \tvpmovsqw %zmm27,%xmm6{%k7}",}, +{{0xc4, 0xe2, 0x7d, 0x25, 0xe4, }, 5, 0, "", "", +"c4 e2 7d 25 e4 \tvpmovsxdq %xmm4,%ymm4",}, +{{0x62, 0x62, 0x7e, 0x4f, 0x25, 0xde, }, 6, 0, "", "", +"62 62 7e 4f 25 de \tvpmovsqd %zmm27,%ymm6{%k7}",}, +{{0x62, 0x92, 0x1d, 0x40, 0x26, 0xeb, }, 6, 0, "", "", +"62 92 1d 40 26 eb \tvptestmb %zmm27,%zmm28,%k5",}, +{{0x62, 0x92, 0x9d, 0x40, 0x26, 0xeb, }, 6, 0, "", "", +"62 92 9d 40 26 eb \tvptestmw %zmm27,%zmm28,%k5",}, +{{0x62, 0x92, 0x26, 0x40, 0x26, 0xea, }, 6, 0, "", "", +"62 92 26 40 26 ea \tvptestnmb %zmm26,%zmm27,%k5",}, +{{0x62, 0x92, 0xa6, 0x40, 0x26, 0xea, }, 6, 0, "", "", +"62 92 a6 40 26 ea \tvptestnmw %zmm26,%zmm27,%k5",}, +{{0x62, 0x92, 0x1d, 0x40, 0x27, 0xeb, }, 6, 0, "", "", +"62 92 1d 40 27 eb \tvptestmd %zmm27,%zmm28,%k5",}, +{{0x62, 0x92, 0x9d, 0x40, 0x27, 0xeb, }, 6, 0, "", "", +"62 92 9d 40 27 eb \tvptestmq %zmm27,%zmm28,%k5",}, +{{0x62, 0x92, 0x26, 0x40, 0x27, 0xea, }, 6, 0, "", "", +"62 92 26 40 27 ea \tvptestnmd %zmm26,%zmm27,%k5",}, +{{0x62, 0x92, 0xa6, 0x40, 0x27, 0xea, }, 6, 0, "", "", +"62 92 a6 40 27 ea \tvptestnmq %zmm26,%zmm27,%k5",}, +{{0xc4, 0xe2, 0x4d, 0x28, 0xd4, }, 5, 0, "", "", +"c4 e2 4d 28 d4 \tvpmuldq %ymm4,%ymm6,%ymm2",}, +{{0x62, 0x62, 0x7e, 0x48, 0x28, 0xe5, }, 6, 0, "", "", +"62 62 7e 48 28 e5 \tvpmovm2b %k5,%zmm28",}, +{{0x62, 0x62, 0xfe, 0x48, 0x28, 0xe5, }, 6, 0, "", "", +"62 62 fe 48 28 e5 \tvpmovm2w %k5,%zmm28",}, +{{0xc4, 0xe2, 0x4d, 0x29, 0xd4, }, 5, 0, "", "", +"c4 e2 4d 29 d4 \tvpcmpeqq %ymm4,%ymm6,%ymm2",}, +{{0x62, 0x92, 0x7e, 0x48, 0x29, 0xec, }, 6, 0, "", "", +"62 92 7e 48 29 ec \tvpmovb2m %zmm28,%k5",}, +{{0x62, 0x92, 0xfe, 0x48, 0x29, 0xec, }, 6, 0, "", "", +"62 92 fe 48 29 ec \tvpmovw2m %zmm28,%k5",}, +{{0xc4, 0xe2, 0x7d, 0x2a, 0x21, }, 5, 0, "", "", +"c4 e2 7d 2a 21 \tvmovntdqa (%rcx),%ymm4",}, +{{0x62, 0x62, 0xfe, 0x48, 0x2a, 0xf6, }, 6, 0, "", "", +"62 62 fe 48 2a f6 \tvpbroadcastmb2q %k6,%zmm30",}, +{{0xc4, 0xe2, 0x5d, 0x2c, 0x31, }, 5, 0, "", "", +"c4 e2 5d 2c 31 \tvmaskmovps (%rcx),%ymm4,%ymm6",}, +{{0x62, 0x02, 0x35, 0x40, 0x2c, 0xd0, }, 6, 0, "", "", +"62 02 35 40 2c d0 \tvscalefps %zmm24,%zmm25,%zmm26",}, +{{0x62, 0x02, 0xb5, 0x40, 0x2c, 0xd0, }, 6, 0, "", "", +"62 02 b5 40 2c d0 \tvscalefpd %zmm24,%zmm25,%zmm26",}, +{{0xc4, 0xe2, 0x5d, 0x2d, 0x31, }, 5, 0, "", "", +"c4 e2 5d 2d 31 \tvmaskmovpd (%rcx),%ymm4,%ymm6",}, +{{0x62, 0x02, 0x35, 0x07, 0x2d, 0xd0, }, 6, 0, "", "", +"62 02 35 07 2d d0 \tvscalefss %xmm24,%xmm25,%xmm26{%k7}",}, +{{0x62, 0x02, 0xb5, 0x07, 0x2d, 0xd0, }, 6, 0, "", "", +"62 02 b5 07 2d d0 \tvscalefsd %xmm24,%xmm25,%xmm26{%k7}",}, +{{0xc4, 0xe2, 0x7d, 0x30, 0xe4, }, 5, 0, "", "", +"c4 e2 7d 30 e4 \tvpmovzxbw %xmm4,%ymm4",}, +{{0x62, 0x62, 0x7e, 0x4f, 0x30, 0xde, }, 6, 0, "", "", +"62 62 7e 4f 30 de \tvpmovwb %zmm27,%ymm6{%k7}",}, +{{0xc4, 0xe2, 0x7d, 0x31, 0xf4, }, 5, 0, "", "", +"c4 e2 7d 31 f4 \tvpmovzxbd %xmm4,%ymm6",}, +{{0x62, 0x62, 0x7e, 0x4f, 0x31, 0xde, }, 6, 0, "", "", +"62 62 7e 4f 31 de \tvpmovdb %zmm27,%xmm6{%k7}",}, +{{0xc4, 0xe2, 0x7d, 0x32, 0xe4, }, 5, 0, "", "", +"c4 e2 7d 32 e4 \tvpmovzxbq %xmm4,%ymm4",}, +{{0x62, 0x62, 0x7e, 0x4f, 0x32, 0xde, }, 6, 0, "", "", +"62 62 7e 4f 32 de \tvpmovqb %zmm27,%xmm6{%k7}",}, +{{0xc4, 0xe2, 0x7d, 0x33, 0xe4, }, 5, 0, "", "", +"c4 e2 7d 33 e4 \tvpmovzxwd %xmm4,%ymm4",}, +{{0x62, 0x62, 0x7e, 0x4f, 0x33, 0xde, }, 6, 0, "", "", +"62 62 7e 4f 33 de \tvpmovdw %zmm27,%ymm6{%k7}",}, +{{0xc4, 0xe2, 0x7d, 0x34, 0xf4, }, 5, 0, "", "", +"c4 e2 7d 34 f4 \tvpmovzxwq %xmm4,%ymm6",}, +{{0x62, 0x62, 0x7e, 0x4f, 0x34, 0xde, }, 6, 0, "", "", +"62 62 7e 4f 34 de \tvpmovqw %zmm27,%xmm6{%k7}",}, +{{0xc4, 0xe2, 0x7d, 0x35, 0xe4, }, 5, 0, "", "", +"c4 e2 7d 35 e4 \tvpmovzxdq %xmm4,%ymm4",}, +{{0x62, 0x62, 0x7e, 0x4f, 0x35, 0xde, }, 6, 0, "", "", +"62 62 7e 4f 35 de \tvpmovqd %zmm27,%ymm6{%k7}",}, +{{0xc4, 0xe2, 0x4d, 0x36, 0xd4, }, 5, 0, "", "", +"c4 e2 4d 36 d4 \tvpermd %ymm4,%ymm6,%ymm2",}, +{{0x62, 0x82, 0x2d, 0x27, 0x36, 0xf0, }, 6, 0, "", "", +"62 82 2d 27 36 f0 \tvpermd %ymm24,%ymm26,%ymm22{%k7}",}, +{{0x62, 0x82, 0xad, 0x27, 0x36, 0xf0, }, 6, 0, "", "", +"62 82 ad 27 36 f0 \tvpermq %ymm24,%ymm26,%ymm22{%k7}",}, +{{0xc4, 0xe2, 0x4d, 0x38, 0xd4, }, 5, 0, "", "", +"c4 e2 4d 38 d4 \tvpminsb %ymm4,%ymm6,%ymm2",}, +{{0x62, 0x62, 0x7e, 0x48, 0x38, 0xe5, }, 6, 0, "", "", +"62 62 7e 48 38 e5 \tvpmovm2d %k5,%zmm28",}, +{{0x62, 0x62, 0xfe, 0x48, 0x38, 0xe5, }, 6, 0, "", "", +"62 62 fe 48 38 e5 \tvpmovm2q %k5,%zmm28",}, +{{0xc4, 0xe2, 0x69, 0x39, 0xd9, }, 5, 0, "", "", +"c4 e2 69 39 d9 \tvpminsd %xmm1,%xmm2,%xmm3",}, +{{0x62, 0x02, 0x35, 0x40, 0x39, 0xd0, }, 6, 0, "", "", +"62 02 35 40 39 d0 \tvpminsd %zmm24,%zmm25,%zmm26",}, +{{0x62, 0x02, 0xb5, 0x40, 0x39, 0xd0, }, 6, 0, "", "", +"62 02 b5 40 39 d0 \tvpminsq %zmm24,%zmm25,%zmm26",}, +{{0x62, 0x92, 0x7e, 0x48, 0x39, 0xec, }, 6, 0, "", "", +"62 92 7e 48 39 ec \tvpmovd2m %zmm28,%k5",}, +{{0x62, 0x92, 0xfe, 0x48, 0x39, 0xec, }, 6, 0, "", "", +"62 92 fe 48 39 ec \tvpmovq2m %zmm28,%k5",}, +{{0xc4, 0xe2, 0x4d, 0x3a, 0xd4, }, 5, 0, "", "", +"c4 e2 4d 3a d4 \tvpminuw %ymm4,%ymm6,%ymm2",}, +{{0x62, 0x62, 0x7e, 0x48, 0x3a, 0xe6, }, 6, 0, "", "", +"62 62 7e 48 3a e6 \tvpbroadcastmw2d %k6,%zmm28",}, +{{0xc4, 0xe2, 0x4d, 0x3b, 0xd4, }, 5, 0, "", "", +"c4 e2 4d 3b d4 \tvpminud %ymm4,%ymm6,%ymm2",}, +{{0x62, 0x02, 0x35, 0x40, 0x3b, 0xd0, }, 6, 0, "", "", +"62 02 35 40 3b d0 \tvpminud %zmm24,%zmm25,%zmm26",}, +{{0x62, 0x02, 0xb5, 0x40, 0x3b, 0xd0, }, 6, 0, "", "", +"62 02 b5 40 3b d0 \tvpminuq %zmm24,%zmm25,%zmm26",}, +{{0xc4, 0xe2, 0x4d, 0x3d, 0xd4, }, 5, 0, "", "", +"c4 e2 4d 3d d4 \tvpmaxsd %ymm4,%ymm6,%ymm2",}, +{{0x62, 0x02, 0x35, 0x40, 0x3d, 0xd0, }, 6, 0, "", "", +"62 02 35 40 3d d0 \tvpmaxsd %zmm24,%zmm25,%zmm26",}, +{{0x62, 0x02, 0xb5, 0x40, 0x3d, 0xd0, }, 6, 0, "", "", +"62 02 b5 40 3d d0 \tvpmaxsq %zmm24,%zmm25,%zmm26",}, +{{0xc4, 0xe2, 0x4d, 0x3f, 0xd4, }, 5, 0, "", "", +"c4 e2 4d 3f d4 \tvpmaxud %ymm4,%ymm6,%ymm2",}, +{{0x62, 0x02, 0x35, 0x40, 0x3f, 0xd0, }, 6, 0, "", "", +"62 02 35 40 3f d0 \tvpmaxud %zmm24,%zmm25,%zmm26",}, +{{0x62, 0x02, 0xb5, 0x40, 0x3f, 0xd0, }, 6, 0, "", "", +"62 02 b5 40 3f d0 \tvpmaxuq %zmm24,%zmm25,%zmm26",}, +{{0xc4, 0xe2, 0x4d, 0x40, 0xd4, }, 5, 0, "", "", +"c4 e2 4d 40 d4 \tvpmulld %ymm4,%ymm6,%ymm2",}, +{{0x62, 0x02, 0x35, 0x40, 0x40, 0xd0, }, 6, 0, "", "", +"62 02 35 40 40 d0 \tvpmulld %zmm24,%zmm25,%zmm26",}, +{{0x62, 0x02, 0xb5, 0x40, 0x40, 0xd0, }, 6, 0, "", "", +"62 02 b5 40 40 d0 \tvpmullq %zmm24,%zmm25,%zmm26",}, +{{0x62, 0x02, 0x7d, 0x48, 0x42, 0xd1, }, 6, 0, "", "", +"62 02 7d 48 42 d1 \tvgetexpps %zmm25,%zmm26",}, +{{0x62, 0x02, 0xfd, 0x48, 0x42, 0xe3, }, 6, 0, "", "", +"62 02 fd 48 42 e3 \tvgetexppd %zmm27,%zmm28",}, +{{0x62, 0x02, 0x35, 0x07, 0x43, 0xd0, }, 6, 0, "", "", +"62 02 35 07 43 d0 \tvgetexpss %xmm24,%xmm25,%xmm26{%k7}",}, +{{0x62, 0x02, 0x95, 0x07, 0x43, 0xf4, }, 6, 0, "", "", +"62 02 95 07 43 f4 \tvgetexpsd %xmm28,%xmm29,%xmm30{%k7}",}, +{{0x62, 0x02, 0x7d, 0x48, 0x44, 0xe3, }, 6, 0, "", "", +"62 02 7d 48 44 e3 \tvplzcntd %zmm27,%zmm28",}, +{{0x62, 0x02, 0xfd, 0x48, 0x44, 0xe3, }, 6, 0, "", "", +"62 02 fd 48 44 e3 \tvplzcntq %zmm27,%zmm28",}, +{{0xc4, 0xe2, 0x4d, 0x46, 0xd4, }, 5, 0, "", "", +"c4 e2 4d 46 d4 \tvpsravd %ymm4,%ymm6,%ymm2",}, +{{0x62, 0x02, 0x35, 0x40, 0x46, 0xd0, }, 6, 0, "", "", +"62 02 35 40 46 d0 \tvpsravd %zmm24,%zmm25,%zmm26",}, +{{0x62, 0x02, 0xb5, 0x40, 0x46, 0xd0, }, 6, 0, "", "", +"62 02 b5 40 46 d0 \tvpsravq %zmm24,%zmm25,%zmm26",}, +{{0x62, 0x02, 0x7d, 0x48, 0x4c, 0xd1, }, 6, 0, "", "", +"62 02 7d 48 4c d1 \tvrcp14ps %zmm25,%zmm26",}, +{{0x62, 0x02, 0xfd, 0x48, 0x4c, 0xe3, }, 6, 0, "", "", +"62 02 fd 48 4c e3 \tvrcp14pd %zmm27,%zmm28",}, +{{0x62, 0x02, 0x35, 0x07, 0x4d, 0xd0, }, 6, 0, "", "", +"62 02 35 07 4d d0 \tvrcp14ss %xmm24,%xmm25,%xmm26{%k7}",}, +{{0x62, 0x02, 0xb5, 0x07, 0x4d, 0xd0, }, 6, 0, "", "", +"62 02 b5 07 4d d0 \tvrcp14sd %xmm24,%xmm25,%xmm26{%k7}",}, +{{0x62, 0x02, 0x7d, 0x48, 0x4e, 0xd1, }, 6, 0, "", "", +"62 02 7d 48 4e d1 \tvrsqrt14ps %zmm25,%zmm26",}, +{{0x62, 0x02, 0xfd, 0x48, 0x4e, 0xe3, }, 6, 0, "", "", +"62 02 fd 48 4e e3 \tvrsqrt14pd %zmm27,%zmm28",}, +{{0x62, 0x02, 0x35, 0x07, 0x4f, 0xd0, }, 6, 0, "", "", +"62 02 35 07 4f d0 \tvrsqrt14ss %xmm24,%xmm25,%xmm26{%k7}",}, +{{0x62, 0x02, 0xb5, 0x07, 0x4f, 0xd0, }, 6, 0, "", "", +"62 02 b5 07 4f d0 \tvrsqrt14sd %xmm24,%xmm25,%xmm26{%k7}",}, +{{0xc4, 0xe2, 0x79, 0x59, 0xf4, }, 5, 0, "", "", +"c4 e2 79 59 f4 \tvpbroadcastq %xmm4,%xmm6",}, +{{0x62, 0x02, 0x7d, 0x48, 0x59, 0xd3, }, 6, 0, "", "", +"62 02 7d 48 59 d3 \tvbroadcasti32x2 %xmm27,%zmm26",}, +{{0xc4, 0xe2, 0x7d, 0x5a, 0x21, }, 5, 0, "", "", +"c4 e2 7d 5a 21 \tvbroadcasti128 (%rcx),%ymm4",}, +{{0x62, 0x62, 0x7d, 0x48, 0x5a, 0x11, }, 6, 0, "", "", +"62 62 7d 48 5a 11 \tvbroadcasti32x4 (%rcx),%zmm26",}, +{{0x62, 0x62, 0xfd, 0x48, 0x5a, 0x11, }, 6, 0, "", "", +"62 62 fd 48 5a 11 \tvbroadcasti64x2 (%rcx),%zmm26",}, +{{0x62, 0x62, 0x7d, 0x48, 0x5b, 0x21, }, 6, 0, "", "", +"62 62 7d 48 5b 21 \tvbroadcasti32x8 (%rcx),%zmm28",}, +{{0x62, 0x62, 0xfd, 0x48, 0x5b, 0x11, }, 6, 0, "", "", +"62 62 fd 48 5b 11 \tvbroadcasti64x4 (%rcx),%zmm26",}, +{{0x62, 0x02, 0x25, 0x40, 0x64, 0xe2, }, 6, 0, "", "", +"62 02 25 40 64 e2 \tvpblendmd %zmm26,%zmm27,%zmm28",}, +{{0x62, 0x02, 0xa5, 0x40, 0x64, 0xe2, }, 6, 0, "", "", +"62 02 a5 40 64 e2 \tvpblendmq %zmm26,%zmm27,%zmm28",}, +{{0x62, 0x02, 0x35, 0x40, 0x65, 0xd0, }, 6, 0, "", "", +"62 02 35 40 65 d0 \tvblendmps %zmm24,%zmm25,%zmm26",}, +{{0x62, 0x02, 0xa5, 0x40, 0x65, 0xe2, }, 6, 0, "", "", +"62 02 a5 40 65 e2 \tvblendmpd %zmm26,%zmm27,%zmm28",}, +{{0x62, 0x02, 0x25, 0x40, 0x66, 0xe2, }, 6, 0, "", "", +"62 02 25 40 66 e2 \tvpblendmb %zmm26,%zmm27,%zmm28",}, +{{0x62, 0x02, 0xa5, 0x40, 0x66, 0xe2, }, 6, 0, "", "", +"62 02 a5 40 66 e2 \tvpblendmw %zmm26,%zmm27,%zmm28",}, +{{0x62, 0x02, 0x35, 0x40, 0x75, 0xd0, }, 6, 0, "", "", +"62 02 35 40 75 d0 \tvpermi2b %zmm24,%zmm25,%zmm26",}, +{{0x62, 0x02, 0xa5, 0x40, 0x75, 0xe2, }, 6, 0, "", "", +"62 02 a5 40 75 e2 \tvpermi2w %zmm26,%zmm27,%zmm28",}, +{{0x62, 0x02, 0x25, 0x40, 0x76, 0xe2, }, 6, 0, "", "", +"62 02 25 40 76 e2 \tvpermi2d %zmm26,%zmm27,%zmm28",}, +{{0x62, 0x02, 0xa5, 0x40, 0x76, 0xe2, }, 6, 0, "", "", +"62 02 a5 40 76 e2 \tvpermi2q %zmm26,%zmm27,%zmm28",}, +{{0x62, 0x02, 0x25, 0x40, 0x77, 0xe2, }, 6, 0, "", "", +"62 02 25 40 77 e2 \tvpermi2ps %zmm26,%zmm27,%zmm28",}, +{{0x62, 0x02, 0xa5, 0x40, 0x77, 0xe2, }, 6, 0, "", "", +"62 02 a5 40 77 e2 \tvpermi2pd %zmm26,%zmm27,%zmm28",}, +{{0x62, 0x62, 0x7d, 0x08, 0x7a, 0xf0, }, 6, 0, "", "", +"62 62 7d 08 7a f0 \tvpbroadcastb %eax,%xmm30",}, +{{0x62, 0x62, 0x7d, 0x08, 0x7b, 0xf0, }, 6, 0, "", "", +"62 62 7d 08 7b f0 \tvpbroadcastw %eax,%xmm30",}, +{{0x62, 0x62, 0x7d, 0x08, 0x7c, 0xf0, }, 6, 0, "", "", +"62 62 7d 08 7c f0 \tvpbroadcastd %eax,%xmm30",}, +{{0x62, 0x62, 0xfd, 0x48, 0x7c, 0xf0, }, 6, 0, "", "", +"62 62 fd 48 7c f0 \tvpbroadcastq %rax,%zmm30",}, +{{0x62, 0x02, 0x25, 0x40, 0x7d, 0xe2, }, 6, 0, "", "", +"62 02 25 40 7d e2 \tvpermt2b %zmm26,%zmm27,%zmm28",}, +{{0x62, 0x02, 0xa5, 0x40, 0x7d, 0xe2, }, 6, 0, "", "", +"62 02 a5 40 7d e2 \tvpermt2w %zmm26,%zmm27,%zmm28",}, +{{0x62, 0x02, 0x25, 0x40, 0x7e, 0xe2, }, 6, 0, "", "", +"62 02 25 40 7e e2 \tvpermt2d %zmm26,%zmm27,%zmm28",}, +{{0x62, 0x02, 0xa5, 0x40, 0x7e, 0xe2, }, 6, 0, "", "", +"62 02 a5 40 7e e2 \tvpermt2q %zmm26,%zmm27,%zmm28",}, +{{0x62, 0x02, 0x25, 0x40, 0x7f, 0xe2, }, 6, 0, "", "", +"62 02 25 40 7f e2 \tvpermt2ps %zmm26,%zmm27,%zmm28",}, +{{0x62, 0x02, 0xa5, 0x40, 0x7f, 0xe2, }, 6, 0, "", "", +"62 02 a5 40 7f e2 \tvpermt2pd %zmm26,%zmm27,%zmm28",}, +{{0x62, 0x02, 0xa5, 0x40, 0x83, 0xe2, }, 6, 0, "", "", +"62 02 a5 40 83 e2 \tvpmultishiftqb %zmm26,%zmm27,%zmm28",}, +{{0x62, 0x62, 0x7d, 0x48, 0x88, 0x11, }, 6, 0, "", "", +"62 62 7d 48 88 11 \tvexpandps (%rcx),%zmm26",}, +{{0x62, 0x62, 0xfd, 0x48, 0x88, 0x21, }, 6, 0, "", "", +"62 62 fd 48 88 21 \tvexpandpd (%rcx),%zmm28",}, +{{0x62, 0x62, 0x7d, 0x48, 0x89, 0x21, }, 6, 0, "", "", +"62 62 7d 48 89 21 \tvpexpandd (%rcx),%zmm28",}, +{{0x62, 0x62, 0xfd, 0x48, 0x89, 0x11, }, 6, 0, "", "", +"62 62 fd 48 89 11 \tvpexpandq (%rcx),%zmm26",}, +{{0x62, 0x62, 0x7d, 0x48, 0x8a, 0x21, }, 6, 0, "", "", +"62 62 7d 48 8a 21 \tvcompressps %zmm28,(%rcx)",}, +{{0x62, 0x62, 0xfd, 0x48, 0x8a, 0x21, }, 6, 0, "", "", +"62 62 fd 48 8a 21 \tvcompresspd %zmm28,(%rcx)",}, +{{0x62, 0x62, 0x7d, 0x48, 0x8b, 0x21, }, 6, 0, "", "", +"62 62 7d 48 8b 21 \tvpcompressd %zmm28,(%rcx)",}, +{{0x62, 0x62, 0xfd, 0x48, 0x8b, 0x11, }, 6, 0, "", "", +"62 62 fd 48 8b 11 \tvpcompressq %zmm26,(%rcx)",}, +{{0x62, 0x02, 0x25, 0x40, 0x8d, 0xe2, }, 6, 0, "", "", +"62 02 25 40 8d e2 \tvpermb %zmm26,%zmm27,%zmm28",}, +{{0x62, 0x02, 0xa5, 0x40, 0x8d, 0xe2, }, 6, 0, "", "", +"62 02 a5 40 8d e2 \tvpermw %zmm26,%zmm27,%zmm28",}, +{{0xc4, 0xe2, 0x69, 0x90, 0x4c, 0x7d, 0x02, }, 7, 0, "", "", +"c4 e2 69 90 4c 7d 02 \tvpgatherdd %xmm2,0x2(%rbp,%xmm7,2),%xmm1",}, +{{0xc4, 0xe2, 0xe9, 0x90, 0x4c, 0x7d, 0x04, }, 7, 0, "", "", +"c4 e2 e9 90 4c 7d 04 \tvpgatherdq %xmm2,0x4(%rbp,%xmm7,2),%xmm1",}, +{{0x62, 0x22, 0x7d, 0x41, 0x90, 0x94, 0xdd, 0x7b, 0x00, 0x00, 0x00, }, 11, 0, "", "", +"62 22 7d 41 90 94 dd 7b 00 00 00 \tvpgatherdd 0x7b(%rbp,%zmm27,8),%zmm26{%k1}",}, +{{0x62, 0x22, 0xfd, 0x41, 0x90, 0x94, 0xdd, 0x7b, 0x00, 0x00, 0x00, }, 11, 0, "", "", +"62 22 fd 41 90 94 dd 7b 00 00 00 \tvpgatherdq 0x7b(%rbp,%ymm27,8),%zmm26{%k1}",}, +{{0xc4, 0xe2, 0x69, 0x91, 0x4c, 0x7d, 0x02, }, 7, 0, "", "", +"c4 e2 69 91 4c 7d 02 \tvpgatherqd %xmm2,0x2(%rbp,%xmm7,2),%xmm1",}, +{{0xc4, 0xe2, 0xe9, 0x91, 0x4c, 0x7d, 0x02, }, 7, 0, "", "", +"c4 e2 e9 91 4c 7d 02 \tvpgatherqq %xmm2,0x2(%rbp,%xmm7,2),%xmm1",}, +{{0x62, 0x22, 0x7d, 0x41, 0x91, 0x94, 0xdd, 0x7b, 0x00, 0x00, 0x00, }, 11, 0, "", "", +"62 22 7d 41 91 94 dd 7b 00 00 00 \tvpgatherqd 0x7b(%rbp,%zmm27,8),%ymm26{%k1}",}, +{{0x62, 0x22, 0xfd, 0x41, 0x91, 0x94, 0xdd, 0x7b, 0x00, 0x00, 0x00, }, 11, 0, "", "", +"62 22 fd 41 91 94 dd 7b 00 00 00 \tvpgatherqq 0x7b(%rbp,%zmm27,8),%zmm26{%k1}",}, +{{0x62, 0x22, 0x7d, 0x41, 0xa0, 0xa4, 0xed, 0x7b, 0x00, 0x00, 0x00, }, 11, 0, "", "", +"62 22 7d 41 a0 a4 ed 7b 00 00 00 \tvpscatterdd %zmm28,0x7b(%rbp,%zmm29,8){%k1}",}, +{{0x62, 0x22, 0xfd, 0x41, 0xa0, 0x94, 0xdd, 0x7b, 0x00, 0x00, 0x00, }, 11, 0, "", "", +"62 22 fd 41 a0 94 dd 7b 00 00 00 \tvpscatterdq %zmm26,0x7b(%rbp,%ymm27,8){%k1}",}, +{{0x62, 0xb2, 0x7d, 0x41, 0xa1, 0xb4, 0xed, 0x7b, 0x00, 0x00, 0x00, }, 11, 0, "", "", +"62 b2 7d 41 a1 b4 ed 7b 00 00 00 \tvpscatterqd %ymm6,0x7b(%rbp,%zmm29,8){%k1}",}, +{{0x62, 0xb2, 0xfd, 0x21, 0xa1, 0xb4, 0xdd, 0x7b, 0x00, 0x00, 0x00, }, 11, 0, "", "", +"62 b2 fd 21 a1 b4 dd 7b 00 00 00 \tvpscatterqq %ymm6,0x7b(%rbp,%ymm27,8){%k1}",}, +{{0x62, 0x22, 0x7d, 0x41, 0xa2, 0xa4, 0xed, 0x7b, 0x00, 0x00, 0x00, }, 11, 0, "", "", +"62 22 7d 41 a2 a4 ed 7b 00 00 00 \tvscatterdps %zmm28,0x7b(%rbp,%zmm29,8){%k1}",}, +{{0x62, 0x22, 0xfd, 0x41, 0xa2, 0xa4, 0xdd, 0x7b, 0x00, 0x00, 0x00, }, 11, 0, "", "", +"62 22 fd 41 a2 a4 dd 7b 00 00 00 \tvscatterdpd %zmm28,0x7b(%rbp,%ymm27,8){%k1}",}, +{{0x62, 0xb2, 0x7d, 0x41, 0xa3, 0xb4, 0xed, 0x7b, 0x00, 0x00, 0x00, }, 11, 0, "", "", +"62 b2 7d 41 a3 b4 ed 7b 00 00 00 \tvscatterqps %ymm6,0x7b(%rbp,%zmm29,8){%k1}",}, +{{0x62, 0x22, 0xfd, 0x41, 0xa3, 0xa4, 0xed, 0x7b, 0x00, 0x00, 0x00, }, 11, 0, "", "", +"62 22 fd 41 a3 a4 ed 7b 00 00 00 \tvscatterqpd %zmm28,0x7b(%rbp,%zmm29,8){%k1}",}, +{{0x62, 0x02, 0xa5, 0x40, 0xb4, 0xe2, }, 6, 0, "", "", +"62 02 a5 40 b4 e2 \tvpmadd52luq %zmm26,%zmm27,%zmm28",}, +{{0x62, 0x02, 0xa5, 0x40, 0xb5, 0xe2, }, 6, 0, "", "", +"62 02 a5 40 b5 e2 \tvpmadd52huq %zmm26,%zmm27,%zmm28",}, +{{0x62, 0x02, 0x7d, 0x48, 0xc4, 0xda, }, 6, 0, "", "", +"62 02 7d 48 c4 da \tvpconflictd %zmm26,%zmm27",}, +{{0x62, 0x02, 0xfd, 0x48, 0xc4, 0xda, }, 6, 0, "", "", +"62 02 fd 48 c4 da \tvpconflictq %zmm26,%zmm27",}, +{{0x62, 0x02, 0x7d, 0x48, 0xc8, 0xf5, }, 6, 0, "", "", +"62 02 7d 48 c8 f5 \tvexp2ps %zmm29,%zmm30",}, +{{0x62, 0x02, 0xfd, 0x48, 0xc8, 0xda, }, 6, 0, "", "", +"62 02 fd 48 c8 da \tvexp2pd %zmm26,%zmm27",}, +{{0x62, 0x02, 0x7d, 0x48, 0xca, 0xf5, }, 6, 0, "", "", +"62 02 7d 48 ca f5 \tvrcp28ps %zmm29,%zmm30",}, +{{0x62, 0x02, 0xfd, 0x48, 0xca, 0xda, }, 6, 0, "", "", +"62 02 fd 48 ca da \tvrcp28pd %zmm26,%zmm27",}, +{{0x62, 0x02, 0x15, 0x07, 0xcb, 0xf4, }, 6, 0, "", "", +"62 02 15 07 cb f4 \tvrcp28ss %xmm28,%xmm29,%xmm30{%k7}",}, +{{0x62, 0x02, 0xad, 0x07, 0xcb, 0xd9, }, 6, 0, "", "", +"62 02 ad 07 cb d9 \tvrcp28sd %xmm25,%xmm26,%xmm27{%k7}",}, +{{0x62, 0x02, 0x7d, 0x48, 0xcc, 0xf5, }, 6, 0, "", "", +"62 02 7d 48 cc f5 \tvrsqrt28ps %zmm29,%zmm30",}, +{{0x62, 0x02, 0xfd, 0x48, 0xcc, 0xda, }, 6, 0, "", "", +"62 02 fd 48 cc da \tvrsqrt28pd %zmm26,%zmm27",}, +{{0x62, 0x02, 0x15, 0x07, 0xcd, 0xf4, }, 6, 0, "", "", +"62 02 15 07 cd f4 \tvrsqrt28ss %xmm28,%xmm29,%xmm30{%k7}",}, +{{0x62, 0x02, 0xad, 0x07, 0xcd, 0xd9, }, 6, 0, "", "", +"62 02 ad 07 cd d9 \tvrsqrt28sd %xmm25,%xmm26,%xmm27{%k7}",}, +{{0x62, 0x03, 0x15, 0x40, 0x03, 0xf4, 0x12, }, 7, 0, "", "", +"62 03 15 40 03 f4 12 \tvalignd $0x12,%zmm28,%zmm29,%zmm30",}, +{{0x62, 0x03, 0xad, 0x40, 0x03, 0xd9, 0x12, }, 7, 0, "", "", +"62 03 ad 40 03 d9 12 \tvalignq $0x12,%zmm25,%zmm26,%zmm27",}, +{{0xc4, 0xe3, 0x7d, 0x08, 0xd6, 0x05, }, 6, 0, "", "", +"c4 e3 7d 08 d6 05 \tvroundps $0x5,%ymm6,%ymm2",}, +{{0x62, 0x03, 0x7d, 0x48, 0x08, 0xd1, 0x12, }, 7, 0, "", "", +"62 03 7d 48 08 d1 12 \tvrndscaleps $0x12,%zmm25,%zmm26",}, +{{0xc4, 0xe3, 0x7d, 0x09, 0xd6, 0x05, }, 6, 0, "", "", +"c4 e3 7d 09 d6 05 \tvroundpd $0x5,%ymm6,%ymm2",}, +{{0x62, 0x03, 0xfd, 0x48, 0x09, 0xd1, 0x12, }, 7, 0, "", "", +"62 03 fd 48 09 d1 12 \tvrndscalepd $0x12,%zmm25,%zmm26",}, +{{0xc4, 0xe3, 0x49, 0x0a, 0xd4, 0x05, }, 6, 0, "", "", +"c4 e3 49 0a d4 05 \tvroundss $0x5,%xmm4,%xmm6,%xmm2",}, +{{0x62, 0x03, 0x35, 0x07, 0x0a, 0xd0, 0x12, }, 7, 0, "", "", +"62 03 35 07 0a d0 12 \tvrndscaless $0x12,%xmm24,%xmm25,%xmm26{%k7}",}, +{{0xc4, 0xe3, 0x49, 0x0b, 0xd4, 0x05, }, 6, 0, "", "", +"c4 e3 49 0b d4 05 \tvroundsd $0x5,%xmm4,%xmm6,%xmm2",}, +{{0x62, 0x03, 0xb5, 0x07, 0x0b, 0xd0, 0x12, }, 7, 0, "", "", +"62 03 b5 07 0b d0 12 \tvrndscalesd $0x12,%xmm24,%xmm25,%xmm26{%k7}",}, +{{0xc4, 0xe3, 0x5d, 0x18, 0xf4, 0x05, }, 6, 0, "", "", +"c4 e3 5d 18 f4 05 \tvinsertf128 $0x5,%xmm4,%ymm4,%ymm6",}, +{{0x62, 0x03, 0x35, 0x47, 0x18, 0xd0, 0x12, }, 7, 0, "", "", +"62 03 35 47 18 d0 12 \tvinsertf32x4 $0x12,%xmm24,%zmm25,%zmm26{%k7}",}, +{{0x62, 0x03, 0xb5, 0x47, 0x18, 0xd0, 0x12, }, 7, 0, "", "", +"62 03 b5 47 18 d0 12 \tvinsertf64x2 $0x12,%xmm24,%zmm25,%zmm26{%k7}",}, +{{0xc4, 0xe3, 0x7d, 0x19, 0xe4, 0x05, }, 6, 0, "", "", +"c4 e3 7d 19 e4 05 \tvextractf128 $0x5,%ymm4,%xmm4",}, +{{0x62, 0x03, 0x7d, 0x4f, 0x19, 0xca, 0x12, }, 7, 0, "", "", +"62 03 7d 4f 19 ca 12 \tvextractf32x4 $0x12,%zmm25,%xmm26{%k7}",}, +{{0x62, 0x03, 0xfd, 0x4f, 0x19, 0xca, 0x12, }, 7, 0, "", "", +"62 03 fd 4f 19 ca 12 \tvextractf64x2 $0x12,%zmm25,%xmm26{%k7}",}, +{{0x62, 0x03, 0x2d, 0x47, 0x1a, 0xd9, 0x12, }, 7, 0, "", "", +"62 03 2d 47 1a d9 12 \tvinsertf32x8 $0x12,%ymm25,%zmm26,%zmm27{%k7}",}, +{{0x62, 0x03, 0x95, 0x47, 0x1a, 0xf4, 0x12, }, 7, 0, "", "", +"62 03 95 47 1a f4 12 \tvinsertf64x4 $0x12,%ymm28,%zmm29,%zmm30{%k7}",}, +{{0x62, 0x03, 0x7d, 0x4f, 0x1b, 0xee, 0x12, }, 7, 0, "", "", +"62 03 7d 4f 1b ee 12 \tvextractf32x8 $0x12,%zmm29,%ymm30{%k7}",}, +{{0x62, 0x03, 0xfd, 0x4f, 0x1b, 0xd3, 0x12, }, 7, 0, "", "", +"62 03 fd 4f 1b d3 12 \tvextractf64x4 $0x12,%zmm26,%ymm27{%k7}",}, +{{0x62, 0x93, 0x0d, 0x40, 0x1e, 0xed, 0x12, }, 7, 0, "", "", +"62 93 0d 40 1e ed 12 \tvpcmpud $0x12,%zmm29,%zmm30,%k5",}, +{{0x62, 0x93, 0xa5, 0x40, 0x1e, 0xea, 0x12, }, 7, 0, "", "", +"62 93 a5 40 1e ea 12 \tvpcmpuq $0x12,%zmm26,%zmm27,%k5",}, +{{0x62, 0x93, 0x0d, 0x40, 0x1f, 0xed, 0x12, }, 7, 0, "", "", +"62 93 0d 40 1f ed 12 \tvpcmpd $0x12,%zmm29,%zmm30,%k5",}, +{{0x62, 0x93, 0xa5, 0x40, 0x1f, 0xea, 0x12, }, 7, 0, "", "", +"62 93 a5 40 1f ea 12 \tvpcmpq $0x12,%zmm26,%zmm27,%k5",}, +{{0x62, 0x03, 0x15, 0x40, 0x23, 0xf4, 0x12, }, 7, 0, "", "", +"62 03 15 40 23 f4 12 \tvshuff32x4 $0x12,%zmm28,%zmm29,%zmm30",}, +{{0x62, 0x03, 0xad, 0x40, 0x23, 0xd9, 0x12, }, 7, 0, "", "", +"62 03 ad 40 23 d9 12 \tvshuff64x2 $0x12,%zmm25,%zmm26,%zmm27",}, +{{0x62, 0x03, 0x15, 0x40, 0x25, 0xf4, 0x12, }, 7, 0, "", "", +"62 03 15 40 25 f4 12 \tvpternlogd $0x12,%zmm28,%zmm29,%zmm30",}, +{{0x62, 0x03, 0x95, 0x40, 0x25, 0xf4, 0x12, }, 7, 0, "", "", +"62 03 95 40 25 f4 12 \tvpternlogq $0x12,%zmm28,%zmm29,%zmm30",}, +{{0x62, 0x03, 0x7d, 0x48, 0x26, 0xda, 0x12, }, 7, 0, "", "", +"62 03 7d 48 26 da 12 \tvgetmantps $0x12,%zmm26,%zmm27",}, +{{0x62, 0x03, 0xfd, 0x48, 0x26, 0xf5, 0x12, }, 7, 0, "", "", +"62 03 fd 48 26 f5 12 \tvgetmantpd $0x12,%zmm29,%zmm30",}, +{{0x62, 0x03, 0x2d, 0x07, 0x27, 0xd9, 0x12, }, 7, 0, "", "", +"62 03 2d 07 27 d9 12 \tvgetmantss $0x12,%xmm25,%xmm26,%xmm27{%k7}",}, +{{0x62, 0x03, 0x95, 0x07, 0x27, 0xf4, 0x12, }, 7, 0, "", "", +"62 03 95 07 27 f4 12 \tvgetmantsd $0x12,%xmm28,%xmm29,%xmm30{%k7}",}, +{{0xc4, 0xe3, 0x5d, 0x38, 0xf4, 0x05, }, 6, 0, "", "", +"c4 e3 5d 38 f4 05 \tvinserti128 $0x5,%xmm4,%ymm4,%ymm6",}, +{{0x62, 0x03, 0x35, 0x47, 0x38, 0xd0, 0x12, }, 7, 0, "", "", +"62 03 35 47 38 d0 12 \tvinserti32x4 $0x12,%xmm24,%zmm25,%zmm26{%k7}",}, +{{0x62, 0x03, 0xb5, 0x47, 0x38, 0xd0, 0x12, }, 7, 0, "", "", +"62 03 b5 47 38 d0 12 \tvinserti64x2 $0x12,%xmm24,%zmm25,%zmm26{%k7}",}, +{{0xc4, 0xe3, 0x7d, 0x39, 0xe6, 0x05, }, 6, 0, "", "", +"c4 e3 7d 39 e6 05 \tvextracti128 $0x5,%ymm4,%xmm6",}, +{{0x62, 0x03, 0x7d, 0x4f, 0x39, 0xca, 0x12, }, 7, 0, "", "", +"62 03 7d 4f 39 ca 12 \tvextracti32x4 $0x12,%zmm25,%xmm26{%k7}",}, +{{0x62, 0x03, 0xfd, 0x4f, 0x39, 0xca, 0x12, }, 7, 0, "", "", +"62 03 fd 4f 39 ca 12 \tvextracti64x2 $0x12,%zmm25,%xmm26{%k7}",}, +{{0x62, 0x03, 0x15, 0x47, 0x3a, 0xf4, 0x12, }, 7, 0, "", "", +"62 03 15 47 3a f4 12 \tvinserti32x8 $0x12,%ymm28,%zmm29,%zmm30{%k7}",}, +{{0x62, 0x03, 0xad, 0x47, 0x3a, 0xd9, 0x12, }, 7, 0, "", "", +"62 03 ad 47 3a d9 12 \tvinserti64x4 $0x12,%ymm25,%zmm26,%zmm27{%k7}",}, +{{0x62, 0x03, 0x7d, 0x4f, 0x3b, 0xee, 0x12, }, 7, 0, "", "", +"62 03 7d 4f 3b ee 12 \tvextracti32x8 $0x12,%zmm29,%ymm30{%k7}",}, +{{0x62, 0x03, 0xfd, 0x4f, 0x3b, 0xd3, 0x12, }, 7, 0, "", "", +"62 03 fd 4f 3b d3 12 \tvextracti64x4 $0x12,%zmm26,%ymm27{%k7}",}, +{{0x62, 0x93, 0x0d, 0x40, 0x3e, 0xed, 0x12, }, 7, 0, "", "", +"62 93 0d 40 3e ed 12 \tvpcmpub $0x12,%zmm29,%zmm30,%k5",}, +{{0x62, 0x93, 0xa5, 0x40, 0x3e, 0xea, 0x12, }, 7, 0, "", "", +"62 93 a5 40 3e ea 12 \tvpcmpuw $0x12,%zmm26,%zmm27,%k5",}, +{{0x62, 0x93, 0x0d, 0x40, 0x3f, 0xed, 0x12, }, 7, 0, "", "", +"62 93 0d 40 3f ed 12 \tvpcmpb $0x12,%zmm29,%zmm30,%k5",}, +{{0x62, 0x93, 0xa5, 0x40, 0x3f, 0xea, 0x12, }, 7, 0, "", "", +"62 93 a5 40 3f ea 12 \tvpcmpw $0x12,%zmm26,%zmm27,%k5",}, +{{0xc4, 0xe3, 0x4d, 0x42, 0xd4, 0x05, }, 6, 0, "", "", +"c4 e3 4d 42 d4 05 \tvmpsadbw $0x5,%ymm4,%ymm6,%ymm2",}, +{{0x62, 0xf3, 0x55, 0x48, 0x42, 0xf4, 0x12, }, 7, 0, "", "", +"62 f3 55 48 42 f4 12 \tvdbpsadbw $0x12,%zmm4,%zmm5,%zmm6",}, +{{0x62, 0x03, 0x2d, 0x40, 0x43, 0xd9, 0x12, }, 7, 0, "", "", +"62 03 2d 40 43 d9 12 \tvshufi32x4 $0x12,%zmm25,%zmm26,%zmm27",}, +{{0x62, 0x03, 0x95, 0x40, 0x43, 0xf4, 0x12, }, 7, 0, "", "", +"62 03 95 40 43 f4 12 \tvshufi64x2 $0x12,%zmm28,%zmm29,%zmm30",}, +{{0x62, 0x03, 0x2d, 0x40, 0x50, 0xd9, 0x12, }, 7, 0, "", "", +"62 03 2d 40 50 d9 12 \tvrangeps $0x12,%zmm25,%zmm26,%zmm27",}, +{{0x62, 0x03, 0x95, 0x40, 0x50, 0xf4, 0x12, }, 7, 0, "", "", +"62 03 95 40 50 f4 12 \tvrangepd $0x12,%zmm28,%zmm29,%zmm30",}, +{{0x62, 0x03, 0x2d, 0x00, 0x51, 0xd9, 0x12, }, 7, 0, "", "", +"62 03 2d 00 51 d9 12 \tvrangess $0x12,%xmm25,%xmm26,%xmm27",}, +{{0x62, 0x03, 0x95, 0x00, 0x51, 0xf4, 0x12, }, 7, 0, "", "", +"62 03 95 00 51 f4 12 \tvrangesd $0x12,%xmm28,%xmm29,%xmm30",}, +{{0x62, 0x03, 0x15, 0x40, 0x54, 0xf4, 0x12, }, 7, 0, "", "", +"62 03 15 40 54 f4 12 \tvfixupimmps $0x12,%zmm28,%zmm29,%zmm30",}, +{{0x62, 0x03, 0xad, 0x40, 0x54, 0xd9, 0x12, }, 7, 0, "", "", +"62 03 ad 40 54 d9 12 \tvfixupimmpd $0x12,%zmm25,%zmm26,%zmm27",}, +{{0x62, 0x03, 0x15, 0x07, 0x55, 0xf4, 0x12, }, 7, 0, "", "", +"62 03 15 07 55 f4 12 \tvfixupimmss $0x12,%xmm28,%xmm29,%xmm30{%k7}",}, +{{0x62, 0x03, 0xad, 0x07, 0x55, 0xd9, 0x12, }, 7, 0, "", "", +"62 03 ad 07 55 d9 12 \tvfixupimmsd $0x12,%xmm25,%xmm26,%xmm27{%k7}",}, +{{0x62, 0x03, 0x7d, 0x48, 0x56, 0xda, 0x12, }, 7, 0, "", "", +"62 03 7d 48 56 da 12 \tvreduceps $0x12,%zmm26,%zmm27",}, +{{0x62, 0x03, 0xfd, 0x48, 0x56, 0xf5, 0x12, }, 7, 0, "", "", +"62 03 fd 48 56 f5 12 \tvreducepd $0x12,%zmm29,%zmm30",}, +{{0x62, 0x03, 0x2d, 0x00, 0x57, 0xd9, 0x12, }, 7, 0, "", "", +"62 03 2d 00 57 d9 12 \tvreducess $0x12,%xmm25,%xmm26,%xmm27",}, +{{0x62, 0x03, 0x95, 0x00, 0x57, 0xf4, 0x12, }, 7, 0, "", "", +"62 03 95 00 57 f4 12 \tvreducesd $0x12,%xmm28,%xmm29,%xmm30",}, +{{0x62, 0x93, 0x7d, 0x48, 0x66, 0xeb, 0x12, }, 7, 0, "", "", +"62 93 7d 48 66 eb 12 \tvfpclassps $0x12,%zmm27,%k5",}, +{{0x62, 0x93, 0xfd, 0x48, 0x66, 0xee, 0x12, }, 7, 0, "", "", +"62 93 fd 48 66 ee 12 \tvfpclasspd $0x12,%zmm30,%k5",}, +{{0x62, 0x93, 0x7d, 0x08, 0x67, 0xeb, 0x12, }, 7, 0, "", "", +"62 93 7d 08 67 eb 12 \tvfpclassss $0x12,%xmm27,%k5",}, +{{0x62, 0x93, 0xfd, 0x08, 0x67, 0xee, 0x12, }, 7, 0, "", "", +"62 93 fd 08 67 ee 12 \tvfpclasssd $0x12,%xmm30,%k5",}, +{{0x62, 0x91, 0x2d, 0x40, 0x72, 0xc1, 0x12, }, 7, 0, "", "", +"62 91 2d 40 72 c1 12 \tvprord $0x12,%zmm25,%zmm26",}, +{{0x62, 0x91, 0xad, 0x40, 0x72, 0xc1, 0x12, }, 7, 0, "", "", +"62 91 ad 40 72 c1 12 \tvprorq $0x12,%zmm25,%zmm26",}, +{{0x62, 0x91, 0x0d, 0x40, 0x72, 0xcd, 0x12, }, 7, 0, "", "", +"62 91 0d 40 72 cd 12 \tvprold $0x12,%zmm29,%zmm30",}, +{{0x62, 0x91, 0x8d, 0x40, 0x72, 0xcd, 0x12, }, 7, 0, "", "", +"62 91 8d 40 72 cd 12 \tvprolq $0x12,%zmm29,%zmm30",}, +{{0x0f, 0x72, 0xe6, 0x02, }, 4, 0, "", "", +"0f 72 e6 02 \tpsrad $0x2,%mm6",}, +{{0xc5, 0xed, 0x72, 0xe6, 0x05, }, 5, 0, "", "", +"c5 ed 72 e6 05 \tvpsrad $0x5,%ymm6,%ymm2",}, +{{0x62, 0x91, 0x4d, 0x40, 0x72, 0xe2, 0x05, }, 7, 0, "", "", +"62 91 4d 40 72 e2 05 \tvpsrad $0x5,%zmm26,%zmm22",}, +{{0x62, 0x91, 0xcd, 0x40, 0x72, 0xe2, 0x05, }, 7, 0, "", "", +"62 91 cd 40 72 e2 05 \tvpsraq $0x5,%zmm26,%zmm22",}, +{{0x62, 0x92, 0x7d, 0x41, 0xc6, 0x8c, 0xfe, 0x7b, 0x00, 0x00, 0x00, }, 11, 0, "", "", +"62 92 7d 41 c6 8c fe 7b 00 00 00 \tvgatherpf0dps 0x7b(%r14,%zmm31,8){%k1}",}, +{{0x62, 0x92, 0xfd, 0x41, 0xc6, 0x8c, 0xfe, 0x7b, 0x00, 0x00, 0x00, }, 11, 0, "", "", +"62 92 fd 41 c6 8c fe 7b 00 00 00 \tvgatherpf0dpd 0x7b(%r14,%ymm31,8){%k1}",}, +{{0x62, 0x92, 0x7d, 0x41, 0xc6, 0x94, 0xfe, 0x7b, 0x00, 0x00, 0x00, }, 11, 0, "", "", +"62 92 7d 41 c6 94 fe 7b 00 00 00 \tvgatherpf1dps 0x7b(%r14,%zmm31,8){%k1}",}, +{{0x62, 0x92, 0xfd, 0x41, 0xc6, 0x94, 0xfe, 0x7b, 0x00, 0x00, 0x00, }, 11, 0, "", "", +"62 92 fd 41 c6 94 fe 7b 00 00 00 \tvgatherpf1dpd 0x7b(%r14,%ymm31,8){%k1}",}, +{{0x62, 0x92, 0x7d, 0x41, 0xc6, 0xac, 0xfe, 0x7b, 0x00, 0x00, 0x00, }, 11, 0, "", "", +"62 92 7d 41 c6 ac fe 7b 00 00 00 \tvscatterpf0dps 0x7b(%r14,%zmm31,8){%k1}",}, +{{0x62, 0x92, 0xfd, 0x41, 0xc6, 0xac, 0xfe, 0x7b, 0x00, 0x00, 0x00, }, 11, 0, "", "", +"62 92 fd 41 c6 ac fe 7b 00 00 00 \tvscatterpf0dpd 0x7b(%r14,%ymm31,8){%k1}",}, +{{0x62, 0x92, 0x7d, 0x41, 0xc6, 0xb4, 0xfe, 0x7b, 0x00, 0x00, 0x00, }, 11, 0, "", "", +"62 92 7d 41 c6 b4 fe 7b 00 00 00 \tvscatterpf1dps 0x7b(%r14,%zmm31,8){%k1}",}, +{{0x62, 0x92, 0xfd, 0x41, 0xc6, 0xb4, 0xfe, 0x7b, 0x00, 0x00, 0x00, }, 11, 0, "", "", +"62 92 fd 41 c6 b4 fe 7b 00 00 00 \tvscatterpf1dpd 0x7b(%r14,%ymm31,8){%k1}",}, +{{0x62, 0x92, 0x7d, 0x41, 0xc7, 0x8c, 0xfe, 0x7b, 0x00, 0x00, 0x00, }, 11, 0, "", "", +"62 92 7d 41 c7 8c fe 7b 00 00 00 \tvgatherpf0qps 0x7b(%r14,%zmm31,8){%k1}",}, +{{0x62, 0x92, 0xfd, 0x41, 0xc7, 0x8c, 0xfe, 0x7b, 0x00, 0x00, 0x00, }, 11, 0, "", "", +"62 92 fd 41 c7 8c fe 7b 00 00 00 \tvgatherpf0qpd 0x7b(%r14,%zmm31,8){%k1}",}, +{{0x62, 0x92, 0x7d, 0x41, 0xc7, 0x94, 0xfe, 0x7b, 0x00, 0x00, 0x00, }, 11, 0, "", "", +"62 92 7d 41 c7 94 fe 7b 00 00 00 \tvgatherpf1qps 0x7b(%r14,%zmm31,8){%k1}",}, +{{0x62, 0x92, 0xfd, 0x41, 0xc7, 0x94, 0xfe, 0x7b, 0x00, 0x00, 0x00, }, 11, 0, "", "", +"62 92 fd 41 c7 94 fe 7b 00 00 00 \tvgatherpf1qpd 0x7b(%r14,%zmm31,8){%k1}",}, +{{0x62, 0x92, 0x7d, 0x41, 0xc7, 0xac, 0xfe, 0x7b, 0x00, 0x00, 0x00, }, 11, 0, "", "", +"62 92 7d 41 c7 ac fe 7b 00 00 00 \tvscatterpf0qps 0x7b(%r14,%zmm31,8){%k1}",}, +{{0x62, 0x92, 0xfd, 0x41, 0xc7, 0xac, 0xfe, 0x7b, 0x00, 0x00, 0x00, }, 11, 0, "", "", +"62 92 fd 41 c7 ac fe 7b 00 00 00 \tvscatterpf0qpd 0x7b(%r14,%zmm31,8){%k1}",}, +{{0x62, 0x92, 0x7d, 0x41, 0xc7, 0xb4, 0xfe, 0x7b, 0x00, 0x00, 0x00, }, 11, 0, "", "", +"62 92 7d 41 c7 b4 fe 7b 00 00 00 \tvscatterpf1qps 0x7b(%r14,%zmm31,8){%k1}",}, +{{0x62, 0x92, 0xfd, 0x41, 0xc7, 0xb4, 0xfe, 0x7b, 0x00, 0x00, 0x00, }, 11, 0, "", "", +"62 92 fd 41 c7 b4 fe 7b 00 00 00 \tvscatterpf1qpd 0x7b(%r14,%zmm31,8){%k1}",}, +{{0x62, 0x01, 0x95, 0x40, 0x58, 0xf4, }, 6, 0, "", "", +"62 01 95 40 58 f4 \tvaddpd %zmm28,%zmm29,%zmm30",}, +{{0x62, 0x01, 0x95, 0x47, 0x58, 0xf4, }, 6, 0, "", "", +"62 01 95 47 58 f4 \tvaddpd %zmm28,%zmm29,%zmm30{%k7}",}, +{{0x62, 0x01, 0x95, 0xc7, 0x58, 0xf4, }, 6, 0, "", "", +"62 01 95 c7 58 f4 \tvaddpd %zmm28,%zmm29,%zmm30{%k7}{z}",}, +{{0x62, 0x01, 0x95, 0x10, 0x58, 0xf4, }, 6, 0, "", "", +"62 01 95 10 58 f4 \tvaddpd {rn-sae},%zmm28,%zmm29,%zmm30",}, +{{0x62, 0x01, 0x95, 0x50, 0x58, 0xf4, }, 6, 0, "", "", +"62 01 95 50 58 f4 \tvaddpd {ru-sae},%zmm28,%zmm29,%zmm30",}, +{{0x62, 0x01, 0x95, 0x30, 0x58, 0xf4, }, 6, 0, "", "", +"62 01 95 30 58 f4 \tvaddpd {rd-sae},%zmm28,%zmm29,%zmm30",}, +{{0x62, 0x01, 0x95, 0x70, 0x58, 0xf4, }, 6, 0, "", "", +"62 01 95 70 58 f4 \tvaddpd {rz-sae},%zmm28,%zmm29,%zmm30",}, +{{0x62, 0x61, 0x95, 0x40, 0x58, 0x31, }, 6, 0, "", "", +"62 61 95 40 58 31 \tvaddpd (%rcx),%zmm29,%zmm30",}, +{{0x62, 0x21, 0x95, 0x40, 0x58, 0xb4, 0xf0, 0x23, 0x01, 0x00, 0x00, }, 11, 0, "", "", +"62 21 95 40 58 b4 f0 23 01 00 00 \tvaddpd 0x123(%rax,%r14,8),%zmm29,%zmm30",}, +{{0x62, 0x61, 0x95, 0x50, 0x58, 0x31, }, 6, 0, "", "", +"62 61 95 50 58 31 \tvaddpd (%rcx){1to8},%zmm29,%zmm30",}, +{{0x62, 0x61, 0x95, 0x40, 0x58, 0x72, 0x7f, }, 7, 0, "", "", +"62 61 95 40 58 72 7f \tvaddpd 0x1fc0(%rdx),%zmm29,%zmm30",}, +{{0x62, 0x61, 0x95, 0x50, 0x58, 0x72, 0x7f, }, 7, 0, "", "", +"62 61 95 50 58 72 7f \tvaddpd 0x3f8(%rdx){1to8},%zmm29,%zmm30",}, +{{0x62, 0xf1, 0x0c, 0x50, 0xc2, 0x6a, 0x7f, 0x08, }, 8, 0, "", "", +"62 f1 0c 50 c2 6a 7f 08 \tvcmpeq_uqps 0x1fc(%rdx){1to16},%zmm30,%k5",}, +{{0x62, 0xb1, 0x97, 0x07, 0xc2, 0xac, 0xf0, 0x23, 0x01, 0x00, 0x00, 0x01, }, 12, 0, "", "", +"62 b1 97 07 c2 ac f0 23 01 00 00 01 \tvcmpltsd 0x123(%rax,%r14,8),%xmm29,%k5{%k7}",}, +{{0x62, 0x91, 0x97, 0x17, 0xc2, 0xec, 0x02, }, 7, 0, "", "", +"62 91 97 17 c2 ec 02 \tvcmplesd {sae},%xmm28,%xmm29,%k5{%k7}",}, +{{0x62, 0x23, 0x15, 0x07, 0x27, 0xb4, 0xf0, 0x23, 0x01, 0x00, 0x00, 0x5b, }, 12, 0, "", "", +"62 23 15 07 27 b4 f0 23 01 00 00 5b \tvgetmantss $0x5b,0x123(%rax,%r14,8),%xmm29,%xmm30{%k7}",}, {{0xf3, 0x0f, 0x1b, 0x00, }, 4, 0, "", "", "f3 0f 1b 00 \tbndmk (%rax),%bnd0",}, {{0xf3, 0x41, 0x0f, 0x1b, 0x00, }, 5, 0, "", "", @@ -327,19 +1257,19 @@ {{0x0f, 0x1b, 0x84, 0x08, 0x78, 0x56, 0x34, 0x12, }, 8, 0, "", "", "0f 1b 84 08 78 56 34 12 \tbndstx %bnd0,0x12345678(%rax,%rcx,1)",}, {{0xf2, 0xe8, 0x00, 0x00, 0x00, 0x00, }, 6, 0, "call", "unconditional", -"f2 e8 00 00 00 00 \tbnd callq 3fb ",}, +"f2 e8 00 00 00 00 \tbnd callq f22 ",}, {{0x67, 0xf2, 0xff, 0x10, }, 4, 0, "call", "indirect", "67 f2 ff 10 \tbnd callq *(%eax)",}, {{0xf2, 0xc3, }, 2, 0, "ret", "indirect", "f2 c3 \tbnd retq ",}, {{0xf2, 0xe9, 0x00, 0x00, 0x00, 0x00, }, 6, 0, "jmp", "unconditional", -"f2 e9 00 00 00 00 \tbnd jmpq 407 ",}, +"f2 e9 00 00 00 00 \tbnd jmpq f2e ",}, {{0xf2, 0xe9, 0x00, 0x00, 0x00, 0x00, }, 6, 0, "jmp", "unconditional", -"f2 e9 00 00 00 00 \tbnd jmpq 40d ",}, +"f2 e9 00 00 00 00 \tbnd jmpq f34 ",}, {{0x67, 0xf2, 0xff, 0x21, }, 4, 0, "jmp", "indirect", "67 f2 ff 21 \tbnd jmpq *(%ecx)",}, {{0xf2, 0x0f, 0x85, 0x00, 0x00, 0x00, 0x00, }, 7, 0, "jcc", "conditional", -"f2 0f 85 00 00 00 00 \tbnd jne 418 ",}, +"f2 0f 85 00 00 00 00 \tbnd jne f3f ",}, {{0x0f, 0x3a, 0xcc, 0xc1, 0x00, }, 5, 0, "", "", "0f 3a cc c1 00 \tsha1rnds4 $0x0,%xmm1,%xmm0",}, {{0x0f, 0x3a, 0xcc, 0xd7, 0x91, }, 5, 0, "", "", diff --git a/tools/perf/arch/x86/tests/insn-x86-dat-src.c b/tools/perf/arch/x86/tests/insn-x86-dat-src.c index 3cd6775..76e0ec3 100644 --- a/tools/perf/arch/x86/tests/insn-x86-dat-src.c +++ b/tools/perf/arch/x86/tests/insn-x86-dat-src.c @@ -25,6 +25,876 @@ int main(void) #ifdef __x86_64__ + /* AVX-512: Instructions with the same op codes as Mask Instructions */ + + asm volatile("cmovno %rax,%rbx"); + asm volatile("cmovno 0x12345678(%rax),%rcx"); + asm volatile("cmovno 0x12345678(%rax),%cx"); + + asm volatile("cmove %rax,%rbx"); + asm volatile("cmove 0x12345678(%rax),%rcx"); + asm volatile("cmove 0x12345678(%rax),%cx"); + + asm volatile("seto 0x12345678(%rax)"); + asm volatile("setno 0x12345678(%rax)"); + asm volatile("setb 0x12345678(%rax)"); + asm volatile("setc 0x12345678(%rax)"); + asm volatile("setnae 0x12345678(%rax)"); + asm volatile("setae 0x12345678(%rax)"); + asm volatile("setnb 0x12345678(%rax)"); + asm volatile("setnc 0x12345678(%rax)"); + asm volatile("sets 0x12345678(%rax)"); + asm volatile("setns 0x12345678(%rax)"); + + /* AVX-512: Mask Instructions */ + + asm volatile("kandw %k7,%k6,%k5"); + asm volatile("kandq %k7,%k6,%k5"); + asm volatile("kandb %k7,%k6,%k5"); + asm volatile("kandd %k7,%k6,%k5"); + + asm volatile("kandnw %k7,%k6,%k5"); + asm volatile("kandnq %k7,%k6,%k5"); + asm volatile("kandnb %k7,%k6,%k5"); + asm volatile("kandnd %k7,%k6,%k5"); + + asm volatile("knotw %k7,%k6"); + asm volatile("knotq %k7,%k6"); + asm volatile("knotb %k7,%k6"); + asm volatile("knotd %k7,%k6"); + + asm volatile("korw %k7,%k6,%k5"); + asm volatile("korq %k7,%k6,%k5"); + asm volatile("korb %k7,%k6,%k5"); + asm volatile("kord %k7,%k6,%k5"); + + asm volatile("kxnorw %k7,%k6,%k5"); + asm volatile("kxnorq %k7,%k6,%k5"); + asm volatile("kxnorb %k7,%k6,%k5"); + asm volatile("kxnord %k7,%k6,%k5"); + + asm volatile("kxorw %k7,%k6,%k5"); + asm volatile("kxorq %k7,%k6,%k5"); + asm volatile("kxorb %k7,%k6,%k5"); + asm volatile("kxord %k7,%k6,%k5"); + + asm volatile("kaddw %k7,%k6,%k5"); + asm volatile("kaddq %k7,%k6,%k5"); + asm volatile("kaddb %k7,%k6,%k5"); + asm volatile("kaddd %k7,%k6,%k5"); + + asm volatile("kunpckbw %k7,%k6,%k5"); + asm volatile("kunpckwd %k7,%k6,%k5"); + asm volatile("kunpckdq %k7,%k6,%k5"); + + asm volatile("kmovw %k6,%k5"); + asm volatile("kmovw (%rcx),%k5"); + asm volatile("kmovw 0x123(%rax,%r14,8),%k5"); + asm volatile("kmovw %k5,(%rcx)"); + asm volatile("kmovw %k5,0x123(%rax,%r14,8)"); + asm volatile("kmovw %eax,%k5"); + asm volatile("kmovw %ebp,%k5"); + asm volatile("kmovw %r13d,%k5"); + asm volatile("kmovw %k5,%eax"); + asm volatile("kmovw %k5,%ebp"); + asm volatile("kmovw %k5,%r13d"); + + asm volatile("kmovq %k6,%k5"); + asm volatile("kmovq (%rcx),%k5"); + asm volatile("kmovq 0x123(%rax,%r14,8),%k5"); + asm volatile("kmovq %k5,(%rcx)"); + asm volatile("kmovq %k5,0x123(%rax,%r14,8)"); + asm volatile("kmovq %rax,%k5"); + asm volatile("kmovq %rbp,%k5"); + asm volatile("kmovq %r13,%k5"); + asm volatile("kmovq %k5,%rax"); + asm volatile("kmovq %k5,%rbp"); + asm volatile("kmovq %k5,%r13"); + + asm volatile("kmovb %k6,%k5"); + asm volatile("kmovb (%rcx),%k5"); + asm volatile("kmovb 0x123(%rax,%r14,8),%k5"); + asm volatile("kmovb %k5,(%rcx)"); + asm volatile("kmovb %k5,0x123(%rax,%r14,8)"); + asm volatile("kmovb %eax,%k5"); + asm volatile("kmovb %ebp,%k5"); + asm volatile("kmovb %r13d,%k5"); + asm volatile("kmovb %k5,%eax"); + asm volatile("kmovb %k5,%ebp"); + asm volatile("kmovb %k5,%r13d"); + + asm volatile("kmovd %k6,%k5"); + asm volatile("kmovd (%rcx),%k5"); + asm volatile("kmovd 0x123(%rax,%r14,8),%k5"); + asm volatile("kmovd %k5,(%rcx)"); + asm volatile("kmovd %k5,0x123(%rax,%r14,8)"); + asm volatile("kmovd %eax,%k5"); + asm volatile("kmovd %ebp,%k5"); + asm volatile("kmovd %r13d,%k5"); + asm volatile("kmovd %k5,%eax"); + asm volatile("kmovd %k5,%ebp"); + asm volatile("kmovd %k5,%r13d"); + + asm volatile("kortestw %k6,%k5"); + asm volatile("kortestq %k6,%k5"); + asm volatile("kortestb %k6,%k5"); + asm volatile("kortestd %k6,%k5"); + + asm volatile("ktestw %k6,%k5"); + asm volatile("ktestq %k6,%k5"); + asm volatile("ktestb %k6,%k5"); + asm volatile("ktestd %k6,%k5"); + + asm volatile("kshiftrw $0x12,%k6,%k5"); + asm volatile("kshiftrq $0x5b,%k6,%k5"); + asm volatile("kshiftlw $0x12,%k6,%k5"); + asm volatile("kshiftlq $0x5b,%k6,%k5"); + + /* AVX-512: Op code 0f 5b */ + asm volatile("vcvtdq2ps %xmm5,%xmm6"); + asm volatile("vcvtqq2ps %zmm29,%ymm6{%k7}"); + asm volatile("vcvtps2dq %xmm5,%xmm6"); + asm volatile("vcvttps2dq %xmm5,%xmm6"); + + /* AVX-512: Op code 0f 6f */ + + asm volatile("movq %mm0,%mm4"); + asm volatile("vmovdqa %ymm4,%ymm6"); + asm volatile("vmovdqa32 %zmm25,%zmm26"); + asm volatile("vmovdqa64 %zmm25,%zmm26"); + asm volatile("vmovdqu %ymm4,%ymm6"); + asm volatile("vmovdqu32 %zmm29,%zmm30"); + asm volatile("vmovdqu64 %zmm25,%zmm26"); + asm volatile("vmovdqu8 %zmm29,%zmm30"); + asm volatile("vmovdqu16 %zmm25,%zmm26"); + + /* AVX-512: Op code 0f 78 */ + + asm volatile("vmread %rax,%rbx"); + asm volatile("vcvttps2udq %zmm25,%zmm26"); + asm volatile("vcvttpd2udq %zmm29,%ymm6{%k7}"); + asm volatile("vcvttsd2usi %xmm6,%rax"); + asm volatile("vcvttss2usi %xmm6,%rax"); + asm volatile("vcvttps2uqq %ymm5,%zmm26{%k7}"); + asm volatile("vcvttpd2uqq %zmm29,%zmm30"); + + /* AVX-512: Op code 0f 79 */ + + asm volatile("vmwrite %rax,%rbx"); + asm volatile("vcvtps2udq %zmm25,%zmm26"); + asm volatile("vcvtpd2udq %zmm29,%ymm6{%k7}"); + asm volatile("vcvtsd2usi %xmm6,%rax"); + asm volatile("vcvtss2usi %xmm6,%rax"); + asm volatile("vcvtps2uqq %ymm5,%zmm26{%k7}"); + asm volatile("vcvtpd2uqq %zmm29,%zmm30"); + + /* AVX-512: Op code 0f 7a */ + + asm volatile("vcvtudq2pd %ymm5,%zmm29{%k7}"); + asm volatile("vcvtuqq2pd %zmm25,%zmm26"); + asm volatile("vcvtudq2ps %zmm29,%zmm30"); + asm volatile("vcvtuqq2ps %zmm25,%ymm26{%k7}"); + asm volatile("vcvttps2qq %ymm25,%zmm26{%k7}"); + asm volatile("vcvttpd2qq %zmm29,%zmm30"); + + /* AVX-512: Op code 0f 7b */ + + asm volatile("vcvtusi2sd %eax,%xmm5,%xmm6"); + asm volatile("vcvtusi2ss %eax,%xmm5,%xmm6"); + asm volatile("vcvtps2qq %ymm5,%zmm26{%k7}"); + asm volatile("vcvtpd2qq %zmm29,%zmm30"); + + /* AVX-512: Op code 0f 7f */ + + asm volatile("movq.s %mm0,%mm4"); + asm volatile("vmovdqa %ymm8,%ymm6"); + asm volatile("vmovdqa32.s %zmm25,%zmm26"); + asm volatile("vmovdqa64.s %zmm25,%zmm26"); + asm volatile("vmovdqu %ymm8,%ymm6"); + asm volatile("vmovdqu32.s %zmm25,%zmm26"); + asm volatile("vmovdqu64.s %zmm25,%zmm26"); + asm volatile("vmovdqu8.s %zmm30,(%rcx)"); + asm volatile("vmovdqu16.s %zmm25,%zmm26"); + + /* AVX-512: Op code 0f db */ + + asm volatile("pand %mm1,%mm2"); + asm volatile("pand %xmm1,%xmm2"); + asm volatile("vpand %ymm4,%ymm6,%ymm2"); + asm volatile("vpandd %zmm24,%zmm25,%zmm26"); + asm volatile("vpandq %zmm24,%zmm25,%zmm26"); + + /* AVX-512: Op code 0f df */ + + asm volatile("pandn %mm1,%mm2"); + asm volatile("pandn %xmm1,%xmm2"); + asm volatile("vpandn %ymm4,%ymm6,%ymm2"); + asm volatile("vpandnd %zmm24,%zmm25,%zmm26"); + asm volatile("vpandnq %zmm24,%zmm25,%zmm26"); + + /* AVX-512: Op code 0f e6 */ + + asm volatile("vcvttpd2dq %xmm1,%xmm2"); + asm volatile("vcvtdq2pd %xmm5,%xmm6"); + asm volatile("vcvtdq2pd %ymm5,%zmm26{%k7}"); + asm volatile("vcvtqq2pd %zmm25,%zmm26"); + asm volatile("vcvtpd2dq %xmm1,%xmm2"); + + /* AVX-512: Op code 0f eb */ + + asm volatile("por %mm4,%mm6"); + asm volatile("vpor %ymm4,%ymm6,%ymm2"); + asm volatile("vpord %zmm24,%zmm25,%zmm26"); + asm volatile("vporq %zmm24,%zmm25,%zmm26"); + + /* AVX-512: Op code 0f ef */ + + asm volatile("pxor %mm4,%mm6"); + asm volatile("vpxor %ymm4,%ymm6,%ymm2"); + asm volatile("vpxord %zmm24,%zmm25,%zmm26"); + asm volatile("vpxorq %zmm24,%zmm25,%zmm26"); + + /* AVX-512: Op code 0f 38 10 */ + + asm volatile("pblendvb %xmm1,%xmm0"); + asm volatile("vpsrlvw %zmm27,%zmm28,%zmm29"); + asm volatile("vpmovuswb %zmm28,%ymm6{%k7}"); + + /* AVX-512: Op code 0f 38 11 */ + + asm volatile("vpmovusdb %zmm28,%xmm6{%k7}"); + asm volatile("vpsravw %zmm27,%zmm28,%zmm29"); + + /* AVX-512: Op code 0f 38 12 */ + + asm volatile("vpmovusqb %zmm27,%xmm6{%k7}"); + asm volatile("vpsllvw %zmm27,%zmm28,%zmm29"); + + /* AVX-512: Op code 0f 38 13 */ + + asm volatile("vcvtph2ps %xmm3,%ymm5"); + asm volatile("vcvtph2ps %ymm5,%zmm27{%k7}"); + asm volatile("vpmovusdw %zmm27,%ymm6{%k7}"); + + /* AVX-512: Op code 0f 38 14 */ + + asm volatile("blendvps %xmm1,%xmm0"); + asm volatile("vpmovusqw %zmm27,%xmm6{%k7}"); + asm volatile("vprorvd %zmm27,%zmm28,%zmm29"); + asm volatile("vprorvq %zmm27,%zmm28,%zmm29"); + + /* AVX-512: Op code 0f 38 15 */ + + asm volatile("blendvpd %xmm1,%xmm0"); + asm volatile("vpmovusqd %zmm27,%ymm6{%k7}"); + asm volatile("vprolvd %zmm27,%zmm28,%zmm29"); + asm volatile("vprolvq %zmm27,%zmm28,%zmm29"); + + /* AVX-512: Op code 0f 38 16 */ + + asm volatile("vpermps %ymm4,%ymm6,%ymm2"); + asm volatile("vpermps %ymm24,%ymm26,%ymm22{%k7}"); + asm volatile("vpermpd %ymm24,%ymm26,%ymm22{%k7}"); + + /* AVX-512: Op code 0f 38 19 */ + + asm volatile("vbroadcastsd %xmm4,%ymm6"); + asm volatile("vbroadcastf32x2 %xmm27,%zmm26"); + + /* AVX-512: Op code 0f 38 1a */ + + asm volatile("vbroadcastf128 (%rcx),%ymm4"); + asm volatile("vbroadcastf32x4 (%rcx),%zmm26"); + asm volatile("vbroadcastf64x2 (%rcx),%zmm26"); + + /* AVX-512: Op code 0f 38 1b */ + + asm volatile("vbroadcastf32x8 (%rcx),%zmm27"); + asm volatile("vbroadcastf64x4 (%rcx),%zmm26"); + + /* AVX-512: Op code 0f 38 1f */ + + asm volatile("vpabsq %zmm27,%zmm28"); + + /* AVX-512: Op code 0f 38 20 */ + + asm volatile("vpmovsxbw %xmm4,%xmm5"); + asm volatile("vpmovswb %zmm27,%ymm6{%k7}"); + + /* AVX-512: Op code 0f 38 21 */ + + asm volatile("vpmovsxbd %xmm4,%ymm6"); + asm volatile("vpmovsdb %zmm27,%xmm6{%k7}"); + + /* AVX-512: Op code 0f 38 22 */ + + asm volatile("vpmovsxbq %xmm4,%ymm4"); + asm volatile("vpmovsqb %zmm27,%xmm6{%k7}"); + + /* AVX-512: Op code 0f 38 23 */ + + asm volatile("vpmovsxwd %xmm4,%ymm4"); + asm volatile("vpmovsdw %zmm27,%ymm6{%k7}"); + + /* AVX-512: Op code 0f 38 24 */ + + asm volatile("vpmovsxwq %xmm4,%ymm6"); + asm volatile("vpmovsqw %zmm27,%xmm6{%k7}"); + + /* AVX-512: Op code 0f 38 25 */ + + asm volatile("vpmovsxdq %xmm4,%ymm4"); + asm volatile("vpmovsqd %zmm27,%ymm6{%k7}"); + + /* AVX-512: Op code 0f 38 26 */ + + asm volatile("vptestmb %zmm27,%zmm28,%k5"); + asm volatile("vptestmw %zmm27,%zmm28,%k5"); + asm volatile("vptestnmb %zmm26,%zmm27,%k5"); + asm volatile("vptestnmw %zmm26,%zmm27,%k5"); + + /* AVX-512: Op code 0f 38 27 */ + + asm volatile("vptestmd %zmm27,%zmm28,%k5"); + asm volatile("vptestmq %zmm27,%zmm28,%k5"); + asm volatile("vptestnmd %zmm26,%zmm27,%k5"); + asm volatile("vptestnmq %zmm26,%zmm27,%k5"); + + /* AVX-512: Op code 0f 38 28 */ + + asm volatile("vpmuldq %ymm4,%ymm6,%ymm2"); + asm volatile("vpmovm2b %k5,%zmm28"); + asm volatile("vpmovm2w %k5,%zmm28"); + + /* AVX-512: Op code 0f 38 29 */ + + asm volatile("vpcmpeqq %ymm4,%ymm6,%ymm2"); + asm volatile("vpmovb2m %zmm28,%k5"); + asm volatile("vpmovw2m %zmm28,%k5"); + + /* AVX-512: Op code 0f 38 2a */ + + asm volatile("vmovntdqa (%rcx),%ymm4"); + asm volatile("vpbroadcastmb2q %k6,%zmm30"); + + /* AVX-512: Op code 0f 38 2c */ + + asm volatile("vmaskmovps (%rcx),%ymm4,%ymm6"); + asm volatile("vscalefps %zmm24,%zmm25,%zmm26"); + asm volatile("vscalefpd %zmm24,%zmm25,%zmm26"); + + /* AVX-512: Op code 0f 38 2d */ + + asm volatile("vmaskmovpd (%rcx),%ymm4,%ymm6"); + asm volatile("vscalefss %xmm24,%xmm25,%xmm26{%k7}"); + asm volatile("vscalefsd %xmm24,%xmm25,%xmm26{%k7}"); + + /* AVX-512: Op code 0f 38 30 */ + + asm volatile("vpmovzxbw %xmm4,%ymm4"); + asm volatile("vpmovwb %zmm27,%ymm6{%k7}"); + + /* AVX-512: Op code 0f 38 31 */ + + asm volatile("vpmovzxbd %xmm4,%ymm6"); + asm volatile("vpmovdb %zmm27,%xmm6{%k7}"); + + /* AVX-512: Op code 0f 38 32 */ + + asm volatile("vpmovzxbq %xmm4,%ymm4"); + asm volatile("vpmovqb %zmm27,%xmm6{%k7}"); + + /* AVX-512: Op code 0f 38 33 */ + + asm volatile("vpmovzxwd %xmm4,%ymm4"); + asm volatile("vpmovdw %zmm27,%ymm6{%k7}"); + + /* AVX-512: Op code 0f 38 34 */ + + asm volatile("vpmovzxwq %xmm4,%ymm6"); + asm volatile("vpmovqw %zmm27,%xmm6{%k7}"); + + /* AVX-512: Op code 0f 38 35 */ + + asm volatile("vpmovzxdq %xmm4,%ymm4"); + asm volatile("vpmovqd %zmm27,%ymm6{%k7}"); + + /* AVX-512: Op code 0f 38 38 */ + + asm volatile("vpermd %ymm4,%ymm6,%ymm2"); + asm volatile("vpermd %ymm24,%ymm26,%ymm22{%k7}"); + asm volatile("vpermq %ymm24,%ymm26,%ymm22{%k7}"); + + /* AVX-512: Op code 0f 38 38 */ + + asm volatile("vpminsb %ymm4,%ymm6,%ymm2"); + asm volatile("vpmovm2d %k5,%zmm28"); + asm volatile("vpmovm2q %k5,%zmm28"); + + /* AVX-512: Op code 0f 38 39 */ + + asm volatile("vpminsd %xmm1,%xmm2,%xmm3"); + asm volatile("vpminsd %zmm24,%zmm25,%zmm26"); + asm volatile("vpminsq %zmm24,%zmm25,%zmm26"); + asm volatile("vpmovd2m %zmm28,%k5"); + asm volatile("vpmovq2m %zmm28,%k5"); + + /* AVX-512: Op code 0f 38 3a */ + + asm volatile("vpminuw %ymm4,%ymm6,%ymm2"); + asm volatile("vpbroadcastmw2d %k6,%zmm28"); + + /* AVX-512: Op code 0f 38 3b */ + + asm volatile("vpminud %ymm4,%ymm6,%ymm2"); + asm volatile("vpminud %zmm24,%zmm25,%zmm26"); + asm volatile("vpminuq %zmm24,%zmm25,%zmm26"); + + /* AVX-512: Op code 0f 38 3d */ + + asm volatile("vpmaxsd %ymm4,%ymm6,%ymm2"); + asm volatile("vpmaxsd %zmm24,%zmm25,%zmm26"); + asm volatile("vpmaxsq %zmm24,%zmm25,%zmm26"); + + /* AVX-512: Op code 0f 38 3f */ + + asm volatile("vpmaxud %ymm4,%ymm6,%ymm2"); + asm volatile("vpmaxud %zmm24,%zmm25,%zmm26"); + asm volatile("vpmaxuq %zmm24,%zmm25,%zmm26"); + + /* AVX-512: Op code 0f 38 42 */ + + asm volatile("vpmulld %ymm4,%ymm6,%ymm2"); + asm volatile("vpmulld %zmm24,%zmm25,%zmm26"); + asm volatile("vpmullq %zmm24,%zmm25,%zmm26"); + + /* AVX-512: Op code 0f 38 42 */ + + asm volatile("vgetexpps %zmm25,%zmm26"); + asm volatile("vgetexppd %zmm27,%zmm28"); + + /* AVX-512: Op code 0f 38 43 */ + + asm volatile("vgetexpss %xmm24,%xmm25,%xmm26{%k7}"); + asm volatile("vgetexpsd %xmm28,%xmm29,%xmm30{%k7}"); + + /* AVX-512: Op code 0f 38 44 */ + + asm volatile("vplzcntd %zmm27,%zmm28"); + asm volatile("vplzcntq %zmm27,%zmm28"); + + /* AVX-512: Op code 0f 38 46 */ + + asm volatile("vpsravd %ymm4,%ymm6,%ymm2"); + asm volatile("vpsravd %zmm24,%zmm25,%zmm26"); + asm volatile("vpsravq %zmm24,%zmm25,%zmm26"); + + /* AVX-512: Op code 0f 38 4c */ + + asm volatile("vrcp14ps %zmm25,%zmm26"); + asm volatile("vrcp14pd %zmm27,%zmm28"); + + /* AVX-512: Op code 0f 38 4d */ + + asm volatile("vrcp14ss %xmm24,%xmm25,%xmm26{%k7}"); + asm volatile("vrcp14sd %xmm24,%xmm25,%xmm26{%k7}"); + + /* AVX-512: Op code 0f 38 4e */ + + asm volatile("vrsqrt14ps %zmm25,%zmm26"); + asm volatile("vrsqrt14pd %zmm27,%zmm28"); + + /* AVX-512: Op code 0f 38 4f */ + + asm volatile("vrsqrt14ss %xmm24,%xmm25,%xmm26{%k7}"); + asm volatile("vrsqrt14sd %xmm24,%xmm25,%xmm26{%k7}"); + + /* AVX-512: Op code 0f 38 59 */ + + asm volatile("vpbroadcastq %xmm4,%xmm6"); + asm volatile("vbroadcasti32x2 %xmm27,%zmm26"); + + /* AVX-512: Op code 0f 38 5a */ + + asm volatile("vbroadcasti128 (%rcx),%ymm4"); + asm volatile("vbroadcasti32x4 (%rcx),%zmm26"); + asm volatile("vbroadcasti64x2 (%rcx),%zmm26"); + + /* AVX-512: Op code 0f 38 5b */ + + asm volatile("vbroadcasti32x8 (%rcx),%zmm28"); + asm volatile("vbroadcasti64x4 (%rcx),%zmm26"); + + /* AVX-512: Op code 0f 38 64 */ + + asm volatile("vpblendmd %zmm26,%zmm27,%zmm28"); + asm volatile("vpblendmq %zmm26,%zmm27,%zmm28"); + + /* AVX-512: Op code 0f 38 65 */ + + asm volatile("vblendmps %zmm24,%zmm25,%zmm26"); + asm volatile("vblendmpd %zmm26,%zmm27,%zmm28"); + + /* AVX-512: Op code 0f 38 66 */ + + asm volatile("vpblendmb %zmm26,%zmm27,%zmm28"); + asm volatile("vpblendmw %zmm26,%zmm27,%zmm28"); + + /* AVX-512: Op code 0f 38 75 */ + + asm volatile("vpermi2b %zmm24,%zmm25,%zmm26"); + asm volatile("vpermi2w %zmm26,%zmm27,%zmm28"); + + /* AVX-512: Op code 0f 38 76 */ + + asm volatile("vpermi2d %zmm26,%zmm27,%zmm28"); + asm volatile("vpermi2q %zmm26,%zmm27,%zmm28"); + + /* AVX-512: Op code 0f 38 77 */ + + asm volatile("vpermi2ps %zmm26,%zmm27,%zmm28"); + asm volatile("vpermi2pd %zmm26,%zmm27,%zmm28"); + + /* AVX-512: Op code 0f 38 7a */ + + asm volatile("vpbroadcastb %eax,%xmm30"); + + /* AVX-512: Op code 0f 38 7b */ + + asm volatile("vpbroadcastw %eax,%xmm30"); + + /* AVX-512: Op code 0f 38 7c */ + + asm volatile("vpbroadcastd %eax,%xmm30"); + asm volatile("vpbroadcastq %rax,%zmm30"); + + /* AVX-512: Op code 0f 38 7d */ + + asm volatile("vpermt2b %zmm26,%zmm27,%zmm28"); + asm volatile("vpermt2w %zmm26,%zmm27,%zmm28"); + + /* AVX-512: Op code 0f 38 7e */ + + asm volatile("vpermt2d %zmm26,%zmm27,%zmm28"); + asm volatile("vpermt2q %zmm26,%zmm27,%zmm28"); + + /* AVX-512: Op code 0f 38 7f */ + + asm volatile("vpermt2ps %zmm26,%zmm27,%zmm28"); + asm volatile("vpermt2pd %zmm26,%zmm27,%zmm28"); + + /* AVX-512: Op code 0f 38 83 */ + + asm volatile("vpmultishiftqb %zmm26,%zmm27,%zmm28"); + + /* AVX-512: Op code 0f 38 88 */ + + asm volatile("vexpandps (%rcx),%zmm26"); + asm volatile("vexpandpd (%rcx),%zmm28"); + + /* AVX-512: Op code 0f 38 89 */ + + asm volatile("vpexpandd (%rcx),%zmm28"); + asm volatile("vpexpandq (%rcx),%zmm26"); + + /* AVX-512: Op code 0f 38 8a */ + + asm volatile("vcompressps %zmm28,(%rcx)"); + asm volatile("vcompresspd %zmm28,(%rcx)"); + + /* AVX-512: Op code 0f 38 8b */ + + asm volatile("vpcompressd %zmm28,(%rcx)"); + asm volatile("vpcompressq %zmm26,(%rcx)"); + + /* AVX-512: Op code 0f 38 8d */ + + asm volatile("vpermb %zmm26,%zmm27,%zmm28"); + asm volatile("vpermw %zmm26,%zmm27,%zmm28"); + + /* AVX-512: Op code 0f 38 90 */ + + asm volatile("vpgatherdd %xmm2,0x02(%rbp,%xmm7,2),%xmm1"); + asm volatile("vpgatherdq %xmm2,0x04(%rbp,%xmm7,2),%xmm1"); + asm volatile("vpgatherdd 0x7b(%rbp,%zmm27,8),%zmm26{%k1}"); + asm volatile("vpgatherdq 0x7b(%rbp,%ymm27,8),%zmm26{%k1}"); + + /* AVX-512: Op code 0f 38 91 */ + + asm volatile("vpgatherqd %xmm2,0x02(%rbp,%xmm7,2),%xmm1"); + asm volatile("vpgatherqq %xmm2,0x02(%rbp,%xmm7,2),%xmm1"); + asm volatile("vpgatherqd 0x7b(%rbp,%zmm27,8),%ymm26{%k1}"); + asm volatile("vpgatherqq 0x7b(%rbp,%zmm27,8),%zmm26{%k1}"); + + /* AVX-512: Op code 0f 38 a0 */ + + asm volatile("vpscatterdd %zmm28,0x7b(%rbp,%zmm29,8){%k1}"); + asm volatile("vpscatterdq %zmm26,0x7b(%rbp,%ymm27,8){%k1}"); + + /* AVX-512: Op code 0f 38 a1 */ + + asm volatile("vpscatterqd %ymm6,0x7b(%rbp,%zmm29,8){%k1}"); + asm volatile("vpscatterqq %ymm6,0x7b(%rbp,%ymm27,8){%k1}"); + + /* AVX-512: Op code 0f 38 a2 */ + + asm volatile("vscatterdps %zmm28,0x7b(%rbp,%zmm29,8){%k1}"); + asm volatile("vscatterdpd %zmm28,0x7b(%rbp,%ymm27,8){%k1}"); + + /* AVX-512: Op code 0f 38 a3 */ + + asm volatile("vscatterqps %ymm6,0x7b(%rbp,%zmm29,8){%k1}"); + asm volatile("vscatterqpd %zmm28,0x7b(%rbp,%zmm29,8){%k1}"); + + /* AVX-512: Op code 0f 38 b4 */ + + asm volatile("vpmadd52luq %zmm26,%zmm27,%zmm28"); + + /* AVX-512: Op code 0f 38 b5 */ + + asm volatile("vpmadd52huq %zmm26,%zmm27,%zmm28"); + + /* AVX-512: Op code 0f 38 c4 */ + + asm volatile("vpconflictd %zmm26,%zmm27"); + asm volatile("vpconflictq %zmm26,%zmm27"); + + /* AVX-512: Op code 0f 38 c8 */ + + asm volatile("vexp2ps %zmm29,%zmm30"); + asm volatile("vexp2pd %zmm26,%zmm27"); + + /* AVX-512: Op code 0f 38 ca */ + + asm volatile("vrcp28ps %zmm29,%zmm30"); + asm volatile("vrcp28pd %zmm26,%zmm27"); + + /* AVX-512: Op code 0f 38 cb */ + + asm volatile("vrcp28ss %xmm28,%xmm29,%xmm30{%k7}"); + asm volatile("vrcp28sd %xmm25,%xmm26,%xmm27{%k7}"); + + /* AVX-512: Op code 0f 38 cc */ + + asm volatile("vrsqrt28ps %zmm29,%zmm30"); + asm volatile("vrsqrt28pd %zmm26,%zmm27"); + + /* AVX-512: Op code 0f 38 cd */ + + asm volatile("vrsqrt28ss %xmm28,%xmm29,%xmm30{%k7}"); + asm volatile("vrsqrt28sd %xmm25,%xmm26,%xmm27{%k7}"); + + /* AVX-512: Op code 0f 3a 03 */ + + asm volatile("valignd $0x12,%zmm28,%zmm29,%zmm30"); + asm volatile("valignq $0x12,%zmm25,%zmm26,%zmm27"); + + /* AVX-512: Op code 0f 3a 08 */ + + asm volatile("vroundps $0x5,%ymm6,%ymm2"); + asm volatile("vrndscaleps $0x12,%zmm25,%zmm26"); + + /* AVX-512: Op code 0f 3a 09 */ + + asm volatile("vroundpd $0x5,%ymm6,%ymm2"); + asm volatile("vrndscalepd $0x12,%zmm25,%zmm26"); + + /* AVX-512: Op code 0f 3a 1a */ + + asm volatile("vroundss $0x5,%xmm4,%xmm6,%xmm2"); + asm volatile("vrndscaless $0x12,%xmm24,%xmm25,%xmm26{%k7}"); + + /* AVX-512: Op code 0f 3a 0b */ + + asm volatile("vroundsd $0x5,%xmm4,%xmm6,%xmm2"); + asm volatile("vrndscalesd $0x12,%xmm24,%xmm25,%xmm26{%k7}"); + + /* AVX-512: Op code 0f 3a 18 */ + + asm volatile("vinsertf128 $0x5,%xmm4,%ymm4,%ymm6"); + asm volatile("vinsertf32x4 $0x12,%xmm24,%zmm25,%zmm26{%k7}"); + asm volatile("vinsertf64x2 $0x12,%xmm24,%zmm25,%zmm26{%k7}"); + + /* AVX-512: Op code 0f 3a 19 */ + + asm volatile("vextractf128 $0x5,%ymm4,%xmm4"); + asm volatile("vextractf32x4 $0x12,%zmm25,%xmm26{%k7}"); + asm volatile("vextractf64x2 $0x12,%zmm25,%xmm26{%k7}"); + + /* AVX-512: Op code 0f 3a 1a */ + + asm volatile("vinsertf32x8 $0x12,%ymm25,%zmm26,%zmm27{%k7}"); + asm volatile("vinsertf64x4 $0x12,%ymm28,%zmm29,%zmm30{%k7}"); + + /* AVX-512: Op code 0f 3a 1b */ + + asm volatile("vextractf32x8 $0x12,%zmm29,%ymm30{%k7}"); + asm volatile("vextractf64x4 $0x12,%zmm26,%ymm27{%k7}"); + + /* AVX-512: Op code 0f 3a 1e */ + + asm volatile("vpcmpud $0x12,%zmm29,%zmm30,%k5"); + asm volatile("vpcmpuq $0x12,%zmm26,%zmm27,%k5"); + + /* AVX-512: Op code 0f 3a 1f */ + + asm volatile("vpcmpd $0x12,%zmm29,%zmm30,%k5"); + asm volatile("vpcmpq $0x12,%zmm26,%zmm27,%k5"); + + /* AVX-512: Op code 0f 3a 23 */ + + asm volatile("vshuff32x4 $0x12,%zmm28,%zmm29,%zmm30"); + asm volatile("vshuff64x2 $0x12,%zmm25,%zmm26,%zmm27"); + + /* AVX-512: Op code 0f 3a 25 */ + + asm volatile("vpternlogd $0x12,%zmm28,%zmm29,%zmm30"); + asm volatile("vpternlogq $0x12,%zmm28,%zmm29,%zmm30"); + + /* AVX-512: Op code 0f 3a 26 */ + + asm volatile("vgetmantps $0x12,%zmm26,%zmm27"); + asm volatile("vgetmantpd $0x12,%zmm29,%zmm30"); + + /* AVX-512: Op code 0f 3a 27 */ + + asm volatile("vgetmantss $0x12,%xmm25,%xmm26,%xmm27{%k7}"); + asm volatile("vgetmantsd $0x12,%xmm28,%xmm29,%xmm30{%k7}"); + + /* AVX-512: Op code 0f 3a 38 */ + + asm volatile("vinserti128 $0x5,%xmm4,%ymm4,%ymm6"); + asm volatile("vinserti32x4 $0x12,%xmm24,%zmm25,%zmm26{%k7}"); + asm volatile("vinserti64x2 $0x12,%xmm24,%zmm25,%zmm26{%k7}"); + + /* AVX-512: Op code 0f 3a 39 */ + + asm volatile("vextracti128 $0x5,%ymm4,%xmm6"); + asm volatile("vextracti32x4 $0x12,%zmm25,%xmm26{%k7}"); + asm volatile("vextracti64x2 $0x12,%zmm25,%xmm26{%k7}"); + + /* AVX-512: Op code 0f 3a 3a */ + + asm volatile("vinserti32x8 $0x12,%ymm28,%zmm29,%zmm30{%k7}"); + asm volatile("vinserti64x4 $0x12,%ymm25,%zmm26,%zmm27{%k7}"); + + /* AVX-512: Op code 0f 3a 3b */ + + asm volatile("vextracti32x8 $0x12,%zmm29,%ymm30{%k7}"); + asm volatile("vextracti64x4 $0x12,%zmm26,%ymm27{%k7}"); + + /* AVX-512: Op code 0f 3a 3e */ + + asm volatile("vpcmpub $0x12,%zmm29,%zmm30,%k5"); + asm volatile("vpcmpuw $0x12,%zmm26,%zmm27,%k5"); + + /* AVX-512: Op code 0f 3a 3f */ + + asm volatile("vpcmpb $0x12,%zmm29,%zmm30,%k5"); + asm volatile("vpcmpw $0x12,%zmm26,%zmm27,%k5"); + + /* AVX-512: Op code 0f 3a 43 */ + + asm volatile("vmpsadbw $0x5,%ymm4,%ymm6,%ymm2"); + asm volatile("vdbpsadbw $0x12,%zmm4,%zmm5,%zmm6"); + + /* AVX-512: Op code 0f 3a 43 */ + + asm volatile("vshufi32x4 $0x12,%zmm25,%zmm26,%zmm27"); + asm volatile("vshufi64x2 $0x12,%zmm28,%zmm29,%zmm30"); + + /* AVX-512: Op code 0f 3a 50 */ + + asm volatile("vrangeps $0x12,%zmm25,%zmm26,%zmm27"); + asm volatile("vrangepd $0x12,%zmm28,%zmm29,%zmm30"); + + /* AVX-512: Op code 0f 3a 51 */ + + asm volatile("vrangess $0x12,%xmm25,%xmm26,%xmm27"); + asm volatile("vrangesd $0x12,%xmm28,%xmm29,%xmm30"); + + /* AVX-512: Op code 0f 3a 54 */ + + asm volatile("vfixupimmps $0x12,%zmm28,%zmm29,%zmm30"); + asm volatile("vfixupimmpd $0x12,%zmm25,%zmm26,%zmm27"); + + /* AVX-512: Op code 0f 3a 55 */ + + asm volatile("vfixupimmss $0x12,%xmm28,%xmm29,%xmm30{%k7}"); + asm volatile("vfixupimmsd $0x12,%xmm25,%xmm26,%xmm27{%k7}"); + + /* AVX-512: Op code 0f 3a 56 */ + + asm volatile("vreduceps $0x12,%zmm26,%zmm27"); + asm volatile("vreducepd $0x12,%zmm29,%zmm30"); + + /* AVX-512: Op code 0f 3a 57 */ + + asm volatile("vreducess $0x12,%xmm25,%xmm26,%xmm27"); + asm volatile("vreducesd $0x12,%xmm28,%xmm29,%xmm30"); + + /* AVX-512: Op code 0f 3a 66 */ + + asm volatile("vfpclassps $0x12,%zmm27,%k5"); + asm volatile("vfpclasspd $0x12,%zmm30,%k5"); + + /* AVX-512: Op code 0f 3a 67 */ + + asm volatile("vfpclassss $0x12,%xmm27,%k5"); + asm volatile("vfpclasssd $0x12,%xmm30,%k5"); + + /* AVX-512: Op code 0f 72 (Grp13) */ + + asm volatile("vprord $0x12,%zmm25,%zmm26"); + asm volatile("vprorq $0x12,%zmm25,%zmm26"); + asm volatile("vprold $0x12,%zmm29,%zmm30"); + asm volatile("vprolq $0x12,%zmm29,%zmm30"); + asm volatile("psrad $0x2,%mm6"); + asm volatile("vpsrad $0x5,%ymm6,%ymm2"); + asm volatile("vpsrad $0x5,%zmm26,%zmm22"); + asm volatile("vpsraq $0x5,%zmm26,%zmm22"); + + /* AVX-512: Op code 0f 38 c6 (Grp18) */ + + asm volatile("vgatherpf0dps 0x7b(%r14,%zmm31,8){%k1}"); + asm volatile("vgatherpf0dpd 0x7b(%r14,%ymm31,8){%k1}"); + asm volatile("vgatherpf1dps 0x7b(%r14,%zmm31,8){%k1}"); + asm volatile("vgatherpf1dpd 0x7b(%r14,%ymm31,8){%k1}"); + asm volatile("vscatterpf0dps 0x7b(%r14,%zmm31,8){%k1}"); + asm volatile("vscatterpf0dpd 0x7b(%r14,%ymm31,8){%k1}"); + asm volatile("vscatterpf1dps 0x7b(%r14,%zmm31,8){%k1}"); + asm volatile("vscatterpf1dpd 0x7b(%r14,%ymm31,8){%k1}"); + + /* AVX-512: Op code 0f 38 c7 (Grp19) */ + + asm volatile("vgatherpf0qps 0x7b(%r14,%zmm31,8){%k1}"); + asm volatile("vgatherpf0qpd 0x7b(%r14,%zmm31,8){%k1}"); + asm volatile("vgatherpf1qps 0x7b(%r14,%zmm31,8){%k1}"); + asm volatile("vgatherpf1qpd 0x7b(%r14,%zmm31,8){%k1}"); + asm volatile("vscatterpf0qps 0x7b(%r14,%zmm31,8){%k1}"); + asm volatile("vscatterpf0qpd 0x7b(%r14,%zmm31,8){%k1}"); + asm volatile("vscatterpf1qps 0x7b(%r14,%zmm31,8){%k1}"); + asm volatile("vscatterpf1qpd 0x7b(%r14,%zmm31,8){%k1}"); + + /* AVX-512: Examples */ + + asm volatile("vaddpd %zmm28,%zmm29,%zmm30"); + asm volatile("vaddpd %zmm28,%zmm29,%zmm30{%k7}"); + asm volatile("vaddpd %zmm28,%zmm29,%zmm30{%k7}{z}"); + asm volatile("vaddpd {rn-sae},%zmm28,%zmm29,%zmm30"); + asm volatile("vaddpd {ru-sae},%zmm28,%zmm29,%zmm30"); + asm volatile("vaddpd {rd-sae},%zmm28,%zmm29,%zmm30"); + asm volatile("vaddpd {rz-sae},%zmm28,%zmm29,%zmm30"); + asm volatile("vaddpd (%rcx),%zmm29,%zmm30"); + asm volatile("vaddpd 0x123(%rax,%r14,8),%zmm29,%zmm30"); + asm volatile("vaddpd (%rcx){1to8},%zmm29,%zmm30"); + asm volatile("vaddpd 0x1fc0(%rdx),%zmm29,%zmm30"); + asm volatile("vaddpd 0x3f8(%rdx){1to8},%zmm29,%zmm30"); + asm volatile("vcmpeq_uqps 0x1fc(%rdx){1to16},%zmm30,%k5"); + asm volatile("vcmpltsd 0x123(%rax,%r14,8),%xmm29,%k5{%k7}"); + asm volatile("vcmplesd {sae},%xmm28,%xmm29,%k5{%k7}"); + asm volatile("vgetmantss $0x5b,0x123(%rax,%r14,8),%xmm29,%xmm30{%k7}"); + /* bndmk m64, bnd */ asm volatile("bndmk (%rax), %bnd0"); @@ -475,6 +1345,921 @@ int main(void) #else /* #ifdef __x86_64__ */ + /* bound r32, mem (same op code as EVEX prefix) */ + + asm volatile("bound %eax, 0x12345678(%ecx)"); + asm volatile("bound %ecx, 0x12345678(%eax)"); + asm volatile("bound %edx, 0x12345678(%eax)"); + asm volatile("bound %ebx, 0x12345678(%eax)"); + asm volatile("bound %esp, 0x12345678(%eax)"); + asm volatile("bound %ebp, 0x12345678(%eax)"); + asm volatile("bound %esi, 0x12345678(%eax)"); + asm volatile("bound %edi, 0x12345678(%eax)"); + asm volatile("bound %ecx, (%eax)"); + asm volatile("bound %eax, (0x12345678)"); + asm volatile("bound %edx, (%ecx,%eax,1)"); + asm volatile("bound %edx, 0x12345678(,%eax,1)"); + asm volatile("bound %edx, (%eax,%ecx,1)"); + asm volatile("bound %edx, (%eax,%ecx,8)"); + asm volatile("bound %edx, 0x12(%eax)"); + asm volatile("bound %edx, 0x12(%ebp)"); + asm volatile("bound %edx, 0x12(%ecx,%eax,1)"); + asm volatile("bound %edx, 0x12(%ebp,%eax,1)"); + asm volatile("bound %edx, 0x12(%eax,%ecx,1)"); + asm volatile("bound %edx, 0x12(%eax,%ecx,8)"); + asm volatile("bound %edx, 0x12345678(%eax)"); + asm volatile("bound %edx, 0x12345678(%ebp)"); + asm volatile("bound %edx, 0x12345678(%ecx,%eax,1)"); + asm volatile("bound %edx, 0x12345678(%ebp,%eax,1)"); + asm volatile("bound %edx, 0x12345678(%eax,%ecx,1)"); + asm volatile("bound %edx, 0x12345678(%eax,%ecx,8)"); + + /* bound r16, mem (same op code as EVEX prefix) */ + + asm volatile("bound %ax, 0x12345678(%ecx)"); + asm volatile("bound %cx, 0x12345678(%eax)"); + asm volatile("bound %dx, 0x12345678(%eax)"); + asm volatile("bound %bx, 0x12345678(%eax)"); + asm volatile("bound %sp, 0x12345678(%eax)"); + asm volatile("bound %bp, 0x12345678(%eax)"); + asm volatile("bound %si, 0x12345678(%eax)"); + asm volatile("bound %di, 0x12345678(%eax)"); + asm volatile("bound %cx, (%eax)"); + asm volatile("bound %ax, (0x12345678)"); + asm volatile("bound %dx, (%ecx,%eax,1)"); + asm volatile("bound %dx, 0x12345678(,%eax,1)"); + asm volatile("bound %dx, (%eax,%ecx,1)"); + asm volatile("bound %dx, (%eax,%ecx,8)"); + asm volatile("bound %dx, 0x12(%eax)"); + asm volatile("bound %dx, 0x12(%ebp)"); + asm volatile("bound %dx, 0x12(%ecx,%eax,1)"); + asm volatile("bound %dx, 0x12(%ebp,%eax,1)"); + asm volatile("bound %dx, 0x12(%eax,%ecx,1)"); + asm volatile("bound %dx, 0x12(%eax,%ecx,8)"); + asm volatile("bound %dx, 0x12345678(%eax)"); + asm volatile("bound %dx, 0x12345678(%ebp)"); + asm volatile("bound %dx, 0x12345678(%ecx,%eax,1)"); + asm volatile("bound %dx, 0x12345678(%ebp,%eax,1)"); + asm volatile("bound %dx, 0x12345678(%eax,%ecx,1)"); + asm volatile("bound %dx, 0x12345678(%eax,%ecx,8)"); + + /* AVX-512: Instructions with the same op codes as Mask Instructions */ + + asm volatile("cmovno %eax,%ebx"); + asm volatile("cmovno 0x12345678(%eax),%ecx"); + asm volatile("cmovno 0x12345678(%eax),%cx"); + + asm volatile("cmove %eax,%ebx"); + asm volatile("cmove 0x12345678(%eax),%ecx"); + asm volatile("cmove 0x12345678(%eax),%cx"); + + asm volatile("seto 0x12345678(%eax)"); + asm volatile("setno 0x12345678(%eax)"); + asm volatile("setb 0x12345678(%eax)"); + asm volatile("setc 0x12345678(%eax)"); + asm volatile("setnae 0x12345678(%eax)"); + asm volatile("setae 0x12345678(%eax)"); + asm volatile("setnb 0x12345678(%eax)"); + asm volatile("setnc 0x12345678(%eax)"); + asm volatile("sets 0x12345678(%eax)"); + asm volatile("setns 0x12345678(%eax)"); + + /* AVX-512: Mask Instructions */ + + asm volatile("kandw %k7,%k6,%k5"); + asm volatile("kandq %k7,%k6,%k5"); + asm volatile("kandb %k7,%k6,%k5"); + asm volatile("kandd %k7,%k6,%k5"); + + asm volatile("kandnw %k7,%k6,%k5"); + asm volatile("kandnq %k7,%k6,%k5"); + asm volatile("kandnb %k7,%k6,%k5"); + asm volatile("kandnd %k7,%k6,%k5"); + + asm volatile("knotw %k7,%k6"); + asm volatile("knotq %k7,%k6"); + asm volatile("knotb %k7,%k6"); + asm volatile("knotd %k7,%k6"); + + asm volatile("korw %k7,%k6,%k5"); + asm volatile("korq %k7,%k6,%k5"); + asm volatile("korb %k7,%k6,%k5"); + asm volatile("kord %k7,%k6,%k5"); + + asm volatile("kxnorw %k7,%k6,%k5"); + asm volatile("kxnorq %k7,%k6,%k5"); + asm volatile("kxnorb %k7,%k6,%k5"); + asm volatile("kxnord %k7,%k6,%k5"); + + asm volatile("kxorw %k7,%k6,%k5"); + asm volatile("kxorq %k7,%k6,%k5"); + asm volatile("kxorb %k7,%k6,%k5"); + asm volatile("kxord %k7,%k6,%k5"); + + asm volatile("kaddw %k7,%k6,%k5"); + asm volatile("kaddq %k7,%k6,%k5"); + asm volatile("kaddb %k7,%k6,%k5"); + asm volatile("kaddd %k7,%k6,%k5"); + + asm volatile("kunpckbw %k7,%k6,%k5"); + asm volatile("kunpckwd %k7,%k6,%k5"); + asm volatile("kunpckdq %k7,%k6,%k5"); + + asm volatile("kmovw %k6,%k5"); + asm volatile("kmovw (%ecx),%k5"); + asm volatile("kmovw 0x123(%eax,%ecx,8),%k5"); + asm volatile("kmovw %k5,(%ecx)"); + asm volatile("kmovw %k5,0x123(%eax,%ecx,8)"); + asm volatile("kmovw %eax,%k5"); + asm volatile("kmovw %ebp,%k5"); + asm volatile("kmovw %k5,%eax"); + asm volatile("kmovw %k5,%ebp"); + + asm volatile("kmovq %k6,%k5"); + asm volatile("kmovq (%ecx),%k5"); + asm volatile("kmovq 0x123(%eax,%ecx,8),%k5"); + asm volatile("kmovq %k5,(%ecx)"); + asm volatile("kmovq %k5,0x123(%eax,%ecx,8)"); + + asm volatile("kmovb %k6,%k5"); + asm volatile("kmovb (%ecx),%k5"); + asm volatile("kmovb 0x123(%eax,%ecx,8),%k5"); + asm volatile("kmovb %k5,(%ecx)"); + asm volatile("kmovb %k5,0x123(%eax,%ecx,8)"); + asm volatile("kmovb %eax,%k5"); + asm volatile("kmovb %ebp,%k5"); + asm volatile("kmovb %k5,%eax"); + asm volatile("kmovb %k5,%ebp"); + + asm volatile("kmovd %k6,%k5"); + asm volatile("kmovd (%ecx),%k5"); + asm volatile("kmovd 0x123(%eax,%ecx,8),%k5"); + asm volatile("kmovd %k5,(%ecx)"); + asm volatile("kmovd %k5,0x123(%eax,%ecx,8)"); + asm volatile("kmovd %eax,%k5"); + asm volatile("kmovd %ebp,%k5"); + asm volatile("kmovd %k5,%eax"); + asm volatile("kmovd %k5,%ebp"); + + asm volatile("kortestw %k6,%k5"); + asm volatile("kortestq %k6,%k5"); + asm volatile("kortestb %k6,%k5"); + asm volatile("kortestd %k6,%k5"); + + asm volatile("ktestw %k6,%k5"); + asm volatile("ktestq %k6,%k5"); + asm volatile("ktestb %k6,%k5"); + asm volatile("ktestd %k6,%k5"); + + asm volatile("kshiftrw $0x12,%k6,%k5"); + asm volatile("kshiftrq $0x5b,%k6,%k5"); + asm volatile("kshiftlw $0x12,%k6,%k5"); + asm volatile("kshiftlq $0x5b,%k6,%k5"); + + /* AVX-512: Op code 0f 5b */ + asm volatile("vcvtdq2ps %xmm5,%xmm6"); + asm volatile("vcvtqq2ps %zmm5,%ymm6{%k7}"); + asm volatile("vcvtps2dq %xmm5,%xmm6"); + asm volatile("vcvttps2dq %xmm5,%xmm6"); + + /* AVX-512: Op code 0f 6f */ + + asm volatile("movq %mm0,%mm4"); + asm volatile("vmovdqa %ymm4,%ymm6"); + asm volatile("vmovdqa32 %zmm5,%zmm6"); + asm volatile("vmovdqa64 %zmm5,%zmm6"); + asm volatile("vmovdqu %ymm4,%ymm6"); + asm volatile("vmovdqu32 %zmm5,%zmm6"); + asm volatile("vmovdqu64 %zmm5,%zmm6"); + asm volatile("vmovdqu8 %zmm5,%zmm6"); + asm volatile("vmovdqu16 %zmm5,%zmm6"); + + /* AVX-512: Op code 0f 78 */ + + asm volatile("vmread %eax,%ebx"); + asm volatile("vcvttps2udq %zmm5,%zmm6"); + asm volatile("vcvttpd2udq %zmm5,%ymm6{%k7}"); + asm volatile("vcvttsd2usi %xmm6,%eax"); + asm volatile("vcvttss2usi %xmm6,%eax"); + asm volatile("vcvttps2uqq %ymm5,%zmm6{%k7}"); + asm volatile("vcvttpd2uqq %zmm5,%zmm6"); + + /* AVX-512: Op code 0f 79 */ + + asm volatile("vmwrite %eax,%ebx"); + asm volatile("vcvtps2udq %zmm5,%zmm6"); + asm volatile("vcvtpd2udq %zmm5,%ymm6{%k7}"); + asm volatile("vcvtsd2usi %xmm6,%eax"); + asm volatile("vcvtss2usi %xmm6,%eax"); + asm volatile("vcvtps2uqq %ymm5,%zmm6{%k7}"); + asm volatile("vcvtpd2uqq %zmm5,%zmm6"); + + /* AVX-512: Op code 0f 7a */ + + asm volatile("vcvtudq2pd %ymm5,%zmm6{%k7}"); + asm volatile("vcvtuqq2pd %zmm5,%zmm6"); + asm volatile("vcvtudq2ps %zmm5,%zmm6"); + asm volatile("vcvtuqq2ps %zmm5,%ymm6{%k7}"); + asm volatile("vcvttps2qq %ymm5,%zmm6{%k7}"); + asm volatile("vcvttpd2qq %zmm5,%zmm6"); + + /* AVX-512: Op code 0f 7b */ + + asm volatile("vcvtusi2sd %eax,%xmm5,%xmm6"); + asm volatile("vcvtusi2ss %eax,%xmm5,%xmm6"); + asm volatile("vcvtps2qq %ymm5,%zmm6{%k7}"); + asm volatile("vcvtpd2qq %zmm5,%zmm6"); + + /* AVX-512: Op code 0f 7f */ + + asm volatile("movq.s %mm0,%mm4"); + asm volatile("vmovdqa.s %ymm5,%ymm6"); + asm volatile("vmovdqa32.s %zmm5,%zmm6"); + asm volatile("vmovdqa64.s %zmm5,%zmm6"); + asm volatile("vmovdqu.s %ymm5,%ymm6"); + asm volatile("vmovdqu32.s %zmm5,%zmm6"); + asm volatile("vmovdqu64.s %zmm5,%zmm6"); + asm volatile("vmovdqu8.s %zmm5,%zmm6"); + asm volatile("vmovdqu16.s %zmm5,%zmm6"); + + /* AVX-512: Op code 0f db */ + + asm volatile("pand %mm1,%mm2"); + asm volatile("pand %xmm1,%xmm2"); + asm volatile("vpand %ymm4,%ymm6,%ymm2"); + asm volatile("vpandd %zmm4,%zmm5,%zmm6"); + asm volatile("vpandq %zmm4,%zmm5,%zmm6"); + + /* AVX-512: Op code 0f df */ + + asm volatile("pandn %mm1,%mm2"); + asm volatile("pandn %xmm1,%xmm2"); + asm volatile("vpandn %ymm4,%ymm6,%ymm2"); + asm volatile("vpandnd %zmm4,%zmm5,%zmm6"); + asm volatile("vpandnq %zmm4,%zmm5,%zmm6"); + + /* AVX-512: Op code 0f e6 */ + + asm volatile("vcvttpd2dq %xmm1,%xmm2"); + asm volatile("vcvtdq2pd %xmm5,%xmm6"); + asm volatile("vcvtdq2pd %ymm5,%zmm6{%k7}"); + asm volatile("vcvtqq2pd %zmm5,%zmm6"); + asm volatile("vcvtpd2dq %xmm1,%xmm2"); + + /* AVX-512: Op code 0f eb */ + + asm volatile("por %mm4,%mm6"); + asm volatile("vpor %ymm4,%ymm6,%ymm2"); + asm volatile("vpord %zmm4,%zmm5,%zmm6"); + asm volatile("vporq %zmm4,%zmm5,%zmm6"); + + /* AVX-512: Op code 0f ef */ + + asm volatile("pxor %mm4,%mm6"); + asm volatile("vpxor %ymm4,%ymm6,%ymm2"); + asm volatile("vpxord %zmm4,%zmm5,%zmm6"); + asm volatile("vpxorq %zmm4,%zmm5,%zmm6"); + + /* AVX-512: Op code 0f 38 10 */ + + asm volatile("pblendvb %xmm1,%xmm0"); + asm volatile("vpsrlvw %zmm4,%zmm5,%zmm6"); + asm volatile("vpmovuswb %zmm5,%ymm6{%k7}"); + + /* AVX-512: Op code 0f 38 11 */ + + asm volatile("vpmovusdb %zmm5,%xmm6{%k7}"); + asm volatile("vpsravw %zmm4,%zmm5,%zmm6"); + + /* AVX-512: Op code 0f 38 12 */ + + asm volatile("vpmovusqb %zmm5,%xmm6{%k7}"); + asm volatile("vpsllvw %zmm4,%zmm5,%zmm6"); + + /* AVX-512: Op code 0f 38 13 */ + + asm volatile("vcvtph2ps %xmm3,%ymm5"); + asm volatile("vcvtph2ps %ymm5,%zmm6{%k7}"); + asm volatile("vpmovusdw %zmm5,%ymm6{%k7}"); + + /* AVX-512: Op code 0f 38 14 */ + + asm volatile("blendvps %xmm1,%xmm0"); + asm volatile("vpmovusqw %zmm5,%xmm6{%k7}"); + asm volatile("vprorvd %zmm4,%zmm5,%zmm6"); + asm volatile("vprorvq %zmm4,%zmm5,%zmm6"); + + /* AVX-512: Op code 0f 38 15 */ + + asm volatile("blendvpd %xmm1,%xmm0"); + asm volatile("vpmovusqd %zmm5,%ymm6{%k7}"); + asm volatile("vprolvd %zmm4,%zmm5,%zmm6"); + asm volatile("vprolvq %zmm4,%zmm5,%zmm6"); + + /* AVX-512: Op code 0f 38 16 */ + + asm volatile("vpermps %ymm4,%ymm6,%ymm2"); + asm volatile("vpermps %ymm4,%ymm6,%ymm2{%k7}"); + asm volatile("vpermpd %ymm4,%ymm6,%ymm2{%k7}"); + + /* AVX-512: Op code 0f 38 19 */ + + asm volatile("vbroadcastsd %xmm4,%ymm6"); + asm volatile("vbroadcastf32x2 %xmm7,%zmm6"); + + /* AVX-512: Op code 0f 38 1a */ + + asm volatile("vbroadcastf128 (%ecx),%ymm4"); + asm volatile("vbroadcastf32x4 (%ecx),%zmm6"); + asm volatile("vbroadcastf64x2 (%ecx),%zmm6"); + + /* AVX-512: Op code 0f 38 1b */ + + asm volatile("vbroadcastf32x8 (%ecx),%zmm6"); + asm volatile("vbroadcastf64x4 (%ecx),%zmm6"); + + /* AVX-512: Op code 0f 38 1f */ + + asm volatile("vpabsq %zmm4,%zmm6"); + + /* AVX-512: Op code 0f 38 20 */ + + asm volatile("vpmovsxbw %xmm4,%xmm5"); + asm volatile("vpmovswb %zmm5,%ymm6{%k7}"); + + /* AVX-512: Op code 0f 38 21 */ + + asm volatile("vpmovsxbd %xmm4,%ymm6"); + asm volatile("vpmovsdb %zmm5,%xmm6{%k7}"); + + /* AVX-512: Op code 0f 38 22 */ + + asm volatile("vpmovsxbq %xmm4,%ymm4"); + asm volatile("vpmovsqb %zmm5,%xmm6{%k7}"); + + /* AVX-512: Op code 0f 38 23 */ + + asm volatile("vpmovsxwd %xmm4,%ymm4"); + asm volatile("vpmovsdw %zmm5,%ymm6{%k7}"); + + /* AVX-512: Op code 0f 38 24 */ + + asm volatile("vpmovsxwq %xmm4,%ymm6"); + asm volatile("vpmovsqw %zmm5,%xmm6{%k7}"); + + /* AVX-512: Op code 0f 38 25 */ + + asm volatile("vpmovsxdq %xmm4,%ymm4"); + asm volatile("vpmovsqd %zmm5,%ymm6{%k7}"); + + /* AVX-512: Op code 0f 38 26 */ + + asm volatile("vptestmb %zmm5,%zmm6,%k5"); + asm volatile("vptestmw %zmm5,%zmm6,%k5"); + asm volatile("vptestnmb %zmm4,%zmm5,%k5"); + asm volatile("vptestnmw %zmm4,%zmm5,%k5"); + + /* AVX-512: Op code 0f 38 27 */ + + asm volatile("vptestmd %zmm5,%zmm6,%k5"); + asm volatile("vptestmq %zmm5,%zmm6,%k5"); + asm volatile("vptestnmd %zmm4,%zmm5,%k5"); + asm volatile("vptestnmq %zmm4,%zmm5,%k5"); + + /* AVX-512: Op code 0f 38 28 */ + + asm volatile("vpmuldq %ymm4,%ymm6,%ymm2"); + asm volatile("vpmovm2b %k5,%zmm6"); + asm volatile("vpmovm2w %k5,%zmm6"); + + /* AVX-512: Op code 0f 38 29 */ + + asm volatile("vpcmpeqq %ymm4,%ymm6,%ymm2"); + asm volatile("vpmovb2m %zmm6,%k5"); + asm volatile("vpmovw2m %zmm6,%k5"); + + /* AVX-512: Op code 0f 38 2a */ + + asm volatile("vmovntdqa (%ecx),%ymm4"); + asm volatile("vpbroadcastmb2q %k6,%zmm1"); + + /* AVX-512: Op code 0f 38 2c */ + + asm volatile("vmaskmovps (%ecx),%ymm4,%ymm6"); + asm volatile("vscalefps %zmm4,%zmm5,%zmm6"); + asm volatile("vscalefpd %zmm4,%zmm5,%zmm6"); + + /* AVX-512: Op code 0f 38 2d */ + + asm volatile("vmaskmovpd (%ecx),%ymm4,%ymm6"); + asm volatile("vscalefss %xmm4,%xmm5,%xmm6{%k7}"); + asm volatile("vscalefsd %xmm4,%xmm5,%xmm6{%k7}"); + + /* AVX-512: Op code 0f 38 30 */ + + asm volatile("vpmovzxbw %xmm4,%ymm4"); + asm volatile("vpmovwb %zmm5,%ymm6{%k7}"); + + /* AVX-512: Op code 0f 38 31 */ + + asm volatile("vpmovzxbd %xmm4,%ymm6"); + asm volatile("vpmovdb %zmm5,%xmm6{%k7}"); + + /* AVX-512: Op code 0f 38 32 */ + + asm volatile("vpmovzxbq %xmm4,%ymm4"); + asm volatile("vpmovqb %zmm5,%xmm6{%k7}"); + + /* AVX-512: Op code 0f 38 33 */ + + asm volatile("vpmovzxwd %xmm4,%ymm4"); + asm volatile("vpmovdw %zmm5,%ymm6{%k7}"); + + /* AVX-512: Op code 0f 38 34 */ + + asm volatile("vpmovzxwq %xmm4,%ymm6"); + asm volatile("vpmovqw %zmm5,%xmm6{%k7}"); + + /* AVX-512: Op code 0f 38 35 */ + + asm volatile("vpmovzxdq %xmm4,%ymm4"); + asm volatile("vpmovqd %zmm5,%ymm6{%k7}"); + + /* AVX-512: Op code 0f 38 36 */ + + asm volatile("vpermd %ymm4,%ymm6,%ymm2"); + asm volatile("vpermd %ymm4,%ymm6,%ymm2{%k7}"); + asm volatile("vpermq %ymm4,%ymm6,%ymm2{%k7}"); + + /* AVX-512: Op code 0f 38 38 */ + + asm volatile("vpminsb %ymm4,%ymm6,%ymm2"); + asm volatile("vpmovm2d %k5,%zmm6"); + asm volatile("vpmovm2q %k5,%zmm6"); + + /* AVX-512: Op code 0f 38 39 */ + + asm volatile("vpminsd %xmm1,%xmm2,%xmm3"); + asm volatile("vpminsd %zmm4,%zmm5,%zmm6"); + asm volatile("vpminsq %zmm4,%zmm5,%zmm6"); + asm volatile("vpmovd2m %zmm6,%k5"); + asm volatile("vpmovq2m %zmm6,%k5"); + + /* AVX-512: Op code 0f 38 3a */ + + asm volatile("vpminuw %ymm4,%ymm6,%ymm2"); + asm volatile("vpbroadcastmw2d %k6,%zmm6"); + + /* AVX-512: Op code 0f 38 3b */ + + asm volatile("vpminud %ymm4,%ymm6,%ymm2"); + asm volatile("vpminud %zmm4,%zmm5,%zmm6"); + asm volatile("vpminuq %zmm4,%zmm5,%zmm6"); + + /* AVX-512: Op code 0f 38 3d */ + + asm volatile("vpmaxsd %ymm4,%ymm6,%ymm2"); + asm volatile("vpmaxsd %zmm4,%zmm5,%zmm6"); + asm volatile("vpmaxsq %zmm4,%zmm5,%zmm6"); + + /* AVX-512: Op code 0f 38 3f */ + + asm volatile("vpmaxud %ymm4,%ymm6,%ymm2"); + asm volatile("vpmaxud %zmm4,%zmm5,%zmm6"); + asm volatile("vpmaxuq %zmm4,%zmm5,%zmm6"); + + /* AVX-512: Op code 0f 38 40 */ + + asm volatile("vpmulld %ymm4,%ymm6,%ymm2"); + asm volatile("vpmulld %zmm4,%zmm5,%zmm6"); + asm volatile("vpmullq %zmm4,%zmm5,%zmm6"); + + /* AVX-512: Op code 0f 38 42 */ + + asm volatile("vgetexpps %zmm5,%zmm6"); + asm volatile("vgetexppd %zmm5,%zmm6"); + + /* AVX-512: Op code 0f 38 43 */ + + asm volatile("vgetexpss %xmm4,%xmm5,%xmm6{%k7}"); + asm volatile("vgetexpsd %xmm2,%xmm3,%xmm4{%k7}"); + + /* AVX-512: Op code 0f 38 44 */ + + asm volatile("vplzcntd %zmm5,%zmm6"); + asm volatile("vplzcntq %zmm5,%zmm6"); + + /* AVX-512: Op code 0f 38 46 */ + + asm volatile("vpsravd %ymm4,%ymm6,%ymm2"); + asm volatile("vpsravd %zmm4,%zmm5,%zmm6"); + asm volatile("vpsravq %zmm4,%zmm5,%zmm6"); + + /* AVX-512: Op code 0f 38 4c */ + + asm volatile("vrcp14ps %zmm5,%zmm6"); + asm volatile("vrcp14pd %zmm5,%zmm6"); + + /* AVX-512: Op code 0f 38 4d */ + + asm volatile("vrcp14ss %xmm4,%xmm5,%xmm6{%k7}"); + asm volatile("vrcp14sd %xmm4,%xmm5,%xmm6{%k7}"); + + /* AVX-512: Op code 0f 38 4e */ + + asm volatile("vrsqrt14ps %zmm5,%zmm6"); + asm volatile("vrsqrt14pd %zmm5,%zmm6"); + + /* AVX-512: Op code 0f 38 4f */ + + asm volatile("vrsqrt14ss %xmm4,%xmm5,%xmm6{%k7}"); + asm volatile("vrsqrt14sd %xmm4,%xmm5,%xmm6{%k7}"); + + /* AVX-512: Op code 0f 38 59 */ + + asm volatile("vpbroadcastq %xmm4,%xmm6"); + asm volatile("vbroadcasti32x2 %xmm7,%zmm6"); + + /* AVX-512: Op code 0f 38 5a */ + + asm volatile("vbroadcasti128 (%ecx),%ymm4"); + asm volatile("vbroadcasti32x4 (%ecx),%zmm6"); + asm volatile("vbroadcasti64x2 (%ecx),%zmm6"); + + /* AVX-512: Op code 0f 38 5b */ + + asm volatile("vbroadcasti32x8 (%ecx),%zmm6"); + asm volatile("vbroadcasti64x4 (%ecx),%zmm6"); + + /* AVX-512: Op code 0f 38 64 */ + + asm volatile("vpblendmd %zmm4,%zmm5,%zmm6"); + asm volatile("vpblendmq %zmm4,%zmm5,%zmm6"); + + /* AVX-512: Op code 0f 38 65 */ + + asm volatile("vblendmps %zmm4,%zmm5,%zmm6"); + asm volatile("vblendmpd %zmm4,%zmm5,%zmm6"); + + /* AVX-512: Op code 0f 38 66 */ + + asm volatile("vpblendmb %zmm4,%zmm5,%zmm6"); + asm volatile("vpblendmw %zmm4,%zmm5,%zmm6"); + + /* AVX-512: Op code 0f 38 75 */ + + asm volatile("vpermi2b %zmm4,%zmm5,%zmm6"); + asm volatile("vpermi2w %zmm4,%zmm5,%zmm6"); + + /* AVX-512: Op code 0f 38 76 */ + + asm volatile("vpermi2d %zmm4,%zmm5,%zmm6"); + asm volatile("vpermi2q %zmm4,%zmm5,%zmm6"); + + /* AVX-512: Op code 0f 38 77 */ + + asm volatile("vpermi2ps %zmm4,%zmm5,%zmm6"); + asm volatile("vpermi2pd %zmm4,%zmm5,%zmm6"); + + /* AVX-512: Op code 0f 38 7a */ + + asm volatile("vpbroadcastb %eax,%xmm3"); + + /* AVX-512: Op code 0f 38 7b */ + + asm volatile("vpbroadcastw %eax,%xmm3"); + + /* AVX-512: Op code 0f 38 7c */ + + asm volatile("vpbroadcastd %eax,%xmm3"); + + /* AVX-512: Op code 0f 38 7d */ + + asm volatile("vpermt2b %zmm4,%zmm5,%zmm6"); + asm volatile("vpermt2w %zmm4,%zmm5,%zmm6"); + + /* AVX-512: Op code 0f 38 7e */ + + asm volatile("vpermt2d %zmm4,%zmm5,%zmm6"); + asm volatile("vpermt2q %zmm4,%zmm5,%zmm6"); + + /* AVX-512: Op code 0f 38 7f */ + + asm volatile("vpermt2ps %zmm4,%zmm5,%zmm6"); + asm volatile("vpermt2pd %zmm4,%zmm5,%zmm6"); + + /* AVX-512: Op code 0f 38 83 */ + + asm volatile("vpmultishiftqb %zmm4,%zmm5,%zmm6"); + + /* AVX-512: Op code 0f 38 88 */ + + asm volatile("vexpandps (%ecx),%zmm6"); + asm volatile("vexpandpd (%ecx),%zmm6"); + + /* AVX-512: Op code 0f 38 89 */ + + asm volatile("vpexpandd (%ecx),%zmm6"); + asm volatile("vpexpandq (%ecx),%zmm6"); + + /* AVX-512: Op code 0f 38 8a */ + + asm volatile("vcompressps %zmm6,(%ecx)"); + asm volatile("vcompresspd %zmm6,(%ecx)"); + + /* AVX-512: Op code 0f 38 8b */ + + asm volatile("vpcompressd %zmm6,(%ecx)"); + asm volatile("vpcompressq %zmm6,(%ecx)"); + + /* AVX-512: Op code 0f 38 8d */ + + asm volatile("vpermb %zmm4,%zmm5,%zmm6"); + asm volatile("vpermw %zmm4,%zmm5,%zmm6"); + + /* AVX-512: Op code 0f 38 90 */ + + asm volatile("vpgatherdd %xmm2,0x02(%ebp,%xmm7,2),%xmm1"); + asm volatile("vpgatherdq %xmm2,0x04(%ebp,%xmm7,2),%xmm1"); + asm volatile("vpgatherdd 0x7b(%ebp,%zmm7,8),%zmm6{%k1}"); + asm volatile("vpgatherdq 0x7b(%ebp,%ymm7,8),%zmm6{%k1}"); + + /* AVX-512: Op code 0f 38 91 */ + + asm volatile("vpgatherqd %xmm2,0x02(%ebp,%xmm7,2),%xmm1"); + asm volatile("vpgatherqq %xmm2,0x02(%ebp,%xmm7,2),%xmm1"); + asm volatile("vpgatherqd 0x7b(%ebp,%zmm7,8),%ymm6{%k1}"); + asm volatile("vpgatherqq 0x7b(%ebp,%zmm7,8),%zmm6{%k1}"); + + /* AVX-512: Op code 0f 38 a0 */ + + asm volatile("vpscatterdd %zmm6,0x7b(%ebp,%zmm7,8){%k1}"); + asm volatile("vpscatterdq %zmm6,0x7b(%ebp,%ymm7,8){%k1}"); + + /* AVX-512: Op code 0f 38 a1 */ + + asm volatile("vpscatterqd %ymm6,0x7b(%ebp,%zmm7,8){%k1}"); + asm volatile("vpscatterqq %ymm6,0x7b(%ebp,%ymm7,8){%k1}"); + + /* AVX-512: Op code 0f 38 a2 */ + + asm volatile("vscatterdps %zmm6,0x7b(%ebp,%zmm7,8){%k1}"); + asm volatile("vscatterdpd %zmm6,0x7b(%ebp,%ymm7,8){%k1}"); + + /* AVX-512: Op code 0f 38 a3 */ + + asm volatile("vscatterqps %ymm6,0x7b(%ebp,%zmm7,8){%k1}"); + asm volatile("vscatterqpd %zmm6,0x7b(%ebp,%zmm7,8){%k1}"); + + /* AVX-512: Op code 0f 38 b4 */ + + asm volatile("vpmadd52luq %zmm4,%zmm5,%zmm6"); + + /* AVX-512: Op code 0f 38 b5 */ + + asm volatile("vpmadd52huq %zmm4,%zmm5,%zmm6"); + + /* AVX-512: Op code 0f 38 c4 */ + + asm volatile("vpconflictd %zmm5,%zmm6"); + asm volatile("vpconflictq %zmm5,%zmm6"); + + /* AVX-512: Op code 0f 38 c8 */ + + asm volatile("vexp2ps %zmm6,%zmm7"); + asm volatile("vexp2pd %zmm6,%zmm7"); + + /* AVX-512: Op code 0f 38 ca */ + + asm volatile("vrcp28ps %zmm6,%zmm7"); + asm volatile("vrcp28pd %zmm6,%zmm7"); + + /* AVX-512: Op code 0f 38 cb */ + + asm volatile("vrcp28ss %xmm5,%xmm6,%xmm7{%k7}"); + asm volatile("vrcp28sd %xmm5,%xmm6,%xmm7{%k7}"); + + /* AVX-512: Op code 0f 38 cc */ + + asm volatile("vrsqrt28ps %zmm6,%zmm7"); + asm volatile("vrsqrt28pd %zmm6,%zmm7"); + + /* AVX-512: Op code 0f 38 cd */ + + asm volatile("vrsqrt28ss %xmm5,%xmm6,%xmm7{%k7}"); + asm volatile("vrsqrt28sd %xmm5,%xmm6,%xmm7{%k7}"); + + /* AVX-512: Op code 0f 3a 03 */ + + asm volatile("valignd $0x12,%zmm5,%zmm6,%zmm7"); + asm volatile("valignq $0x12,%zmm5,%zmm6,%zmm7"); + + /* AVX-512: Op code 0f 3a 08 */ + + asm volatile("vroundps $0x5,%ymm6,%ymm2"); + asm volatile("vrndscaleps $0x12,%zmm5,%zmm6"); + + /* AVX-512: Op code 0f 3a 09 */ + + asm volatile("vroundpd $0x5,%ymm6,%ymm2"); + asm volatile("vrndscalepd $0x12,%zmm5,%zmm6"); + + /* AVX-512: Op code 0f 3a 0a */ + + asm volatile("vroundss $0x5,%xmm4,%xmm6,%xmm2"); + asm volatile("vrndscaless $0x12,%xmm4,%xmm5,%xmm6{%k7}"); + + /* AVX-512: Op code 0f 3a 0b */ + + asm volatile("vroundsd $0x5,%xmm4,%xmm6,%xmm2"); + asm volatile("vrndscalesd $0x12,%xmm4,%xmm5,%xmm6{%k7}"); + + /* AVX-512: Op code 0f 3a 18 */ + + asm volatile("vinsertf128 $0x5,%xmm4,%ymm4,%ymm6"); + asm volatile("vinsertf32x4 $0x12,%xmm4,%zmm5,%zmm6{%k7}"); + asm volatile("vinsertf64x2 $0x12,%xmm4,%zmm5,%zmm6{%k7}"); + + /* AVX-512: Op code 0f 3a 19 */ + + asm volatile("vextractf128 $0x5,%ymm4,%xmm4"); + asm volatile("vextractf32x4 $0x12,%zmm5,%xmm6{%k7}"); + asm volatile("vextractf64x2 $0x12,%zmm5,%xmm6{%k7}"); + + /* AVX-512: Op code 0f 3a 1a */ + + asm volatile("vinsertf32x8 $0x12,%ymm5,%zmm6,%zmm7{%k7}"); + asm volatile("vinsertf64x4 $0x12,%ymm5,%zmm6,%zmm7{%k7}"); + + /* AVX-512: Op code 0f 3a 1b */ + + asm volatile("vextractf32x8 $0x12,%zmm6,%ymm7{%k7}"); + asm volatile("vextractf64x4 $0x12,%zmm6,%ymm7{%k7}"); + + /* AVX-512: Op code 0f 3a 1e */ + + asm volatile("vpcmpud $0x12,%zmm6,%zmm7,%k5"); + asm volatile("vpcmpuq $0x12,%zmm6,%zmm7,%k5"); + + /* AVX-512: Op code 0f 3a 1f */ + + asm volatile("vpcmpd $0x12,%zmm6,%zmm7,%k5"); + asm volatile("vpcmpq $0x12,%zmm6,%zmm7,%k5"); + + /* AVX-512: Op code 0f 3a 23 */ + + asm volatile("vshuff32x4 $0x12,%zmm5,%zmm6,%zmm7"); + asm volatile("vshuff64x2 $0x12,%zmm5,%zmm6,%zmm7"); + + /* AVX-512: Op code 0f 3a 25 */ + + asm volatile("vpternlogd $0x12,%zmm5,%zmm6,%zmm7"); + asm volatile("vpternlogq $0x12,%zmm5,%zmm6,%zmm7"); + + /* AVX-512: Op code 0f 3a 26 */ + + asm volatile("vgetmantps $0x12,%zmm6,%zmm7"); + asm volatile("vgetmantpd $0x12,%zmm6,%zmm7"); + + /* AVX-512: Op code 0f 3a 27 */ + + asm volatile("vgetmantss $0x12,%xmm5,%xmm6,%xmm7{%k7}"); + asm volatile("vgetmantsd $0x12,%xmm5,%xmm6,%xmm7{%k7}"); + + /* AVX-512: Op code 0f 3a 38 */ + + asm volatile("vinserti128 $0x5,%xmm4,%ymm4,%ymm6"); + asm volatile("vinserti32x4 $0x12,%xmm4,%zmm5,%zmm6{%k7}"); + asm volatile("vinserti64x2 $0x12,%xmm4,%zmm5,%zmm6{%k7}"); + + /* AVX-512: Op code 0f 3a 39 */ + + asm volatile("vextracti128 $0x5,%ymm4,%xmm6"); + asm volatile("vextracti32x4 $0x12,%zmm5,%xmm6{%k7}"); + asm volatile("vextracti64x2 $0x12,%zmm5,%xmm6{%k7}"); + + /* AVX-512: Op code 0f 3a 3a */ + + asm volatile("vinserti32x8 $0x12,%ymm5,%zmm6,%zmm7{%k7}"); + asm volatile("vinserti64x4 $0x12,%ymm5,%zmm6,%zmm7{%k7}"); + + /* AVX-512: Op code 0f 3a 3b */ + + asm volatile("vextracti32x8 $0x12,%zmm6,%ymm7{%k7}"); + asm volatile("vextracti64x4 $0x12,%zmm6,%ymm7{%k7}"); + + /* AVX-512: Op code 0f 3a 3e */ + + asm volatile("vpcmpub $0x12,%zmm6,%zmm7,%k5"); + asm volatile("vpcmpuw $0x12,%zmm6,%zmm7,%k5"); + + /* AVX-512: Op code 0f 3a 3f */ + + asm volatile("vpcmpb $0x12,%zmm6,%zmm7,%k5"); + asm volatile("vpcmpw $0x12,%zmm6,%zmm7,%k5"); + + /* AVX-512: Op code 0f 3a 42 */ + + asm volatile("vmpsadbw $0x5,%ymm4,%ymm6,%ymm2"); + asm volatile("vdbpsadbw $0x12,%zmm4,%zmm5,%zmm6"); + + /* AVX-512: Op code 0f 3a 43 */ + + asm volatile("vshufi32x4 $0x12,%zmm5,%zmm6,%zmm7"); + asm volatile("vshufi64x2 $0x12,%zmm5,%zmm6,%zmm7"); + + /* AVX-512: Op code 0f 3a 50 */ + + asm volatile("vrangeps $0x12,%zmm5,%zmm6,%zmm7"); + asm volatile("vrangepd $0x12,%zmm5,%zmm6,%zmm7"); + + /* AVX-512: Op code 0f 3a 51 */ + + asm volatile("vrangess $0x12,%xmm5,%xmm6,%xmm7"); + asm volatile("vrangesd $0x12,%xmm5,%xmm6,%xmm7"); + + /* AVX-512: Op code 0f 3a 54 */ + + asm volatile("vfixupimmps $0x12,%zmm5,%zmm6,%zmm7"); + asm volatile("vfixupimmpd $0x12,%zmm5,%zmm6,%zmm7"); + + /* AVX-512: Op code 0f 3a 55 */ + + asm volatile("vfixupimmss $0x12,%xmm5,%xmm6,%xmm7{%k7}"); + asm volatile("vfixupimmsd $0x12,%xmm5,%xmm6,%xmm7{%k7}"); + + /* AVX-512: Op code 0f 3a 56 */ + + asm volatile("vreduceps $0x12,%zmm6,%zmm7"); + asm volatile("vreducepd $0x12,%zmm6,%zmm7"); + + /* AVX-512: Op code 0f 3a 57 */ + + asm volatile("vreducess $0x12,%xmm5,%xmm6,%xmm7"); + asm volatile("vreducesd $0x12,%xmm5,%xmm6,%xmm7"); + + /* AVX-512: Op code 0f 3a 66 */ + + asm volatile("vfpclassps $0x12,%zmm7,%k5"); + asm volatile("vfpclasspd $0x12,%zmm7,%k5"); + + /* AVX-512: Op code 0f 3a 67 */ + + asm volatile("vfpclassss $0x12,%xmm7,%k5"); + asm volatile("vfpclasssd $0x12,%xmm7,%k5"); + + /* AVX-512: Op code 0f 72 (Grp13) */ + + asm volatile("vprord $0x12,%zmm5,%zmm6"); + asm volatile("vprorq $0x12,%zmm5,%zmm6"); + asm volatile("vprold $0x12,%zmm5,%zmm6"); + asm volatile("vprolq $0x12,%zmm5,%zmm6"); + asm volatile("psrad $0x2,%mm6"); + asm volatile("vpsrad $0x5,%ymm6,%ymm2"); + asm volatile("vpsrad $0x5,%zmm6,%zmm2"); + asm volatile("vpsraq $0x5,%zmm6,%zmm2"); + + /* AVX-512: Op code 0f 38 c6 (Grp18) */ + + asm volatile("vgatherpf0dps 0x7b(%ebp,%zmm7,8){%k1}"); + asm volatile("vgatherpf0dpd 0x7b(%ebp,%ymm7,8){%k1}"); + asm volatile("vgatherpf1dps 0x7b(%ebp,%zmm7,8){%k1}"); + asm volatile("vgatherpf1dpd 0x7b(%ebp,%ymm7,8){%k1}"); + asm volatile("vscatterpf0dps 0x7b(%ebp,%zmm7,8){%k1}"); + asm volatile("vscatterpf0dpd 0x7b(%ebp,%ymm7,8){%k1}"); + asm volatile("vscatterpf1dps 0x7b(%ebp,%zmm7,8){%k1}"); + asm volatile("vscatterpf1dpd 0x7b(%ebp,%ymm7,8){%k1}"); + + /* AVX-512: Op code 0f 38 c7 (Grp19) */ + + asm volatile("vgatherpf0qps 0x7b(%ebp,%zmm7,8){%k1}"); + asm volatile("vgatherpf0qpd 0x7b(%ebp,%zmm7,8){%k1}"); + asm volatile("vgatherpf1qps 0x7b(%ebp,%zmm7,8){%k1}"); + asm volatile("vgatherpf1qpd 0x7b(%ebp,%zmm7,8){%k1}"); + asm volatile("vscatterpf0qps 0x7b(%ebp,%zmm7,8){%k1}"); + asm volatile("vscatterpf0qpd 0x7b(%ebp,%zmm7,8){%k1}"); + asm volatile("vscatterpf1qps 0x7b(%ebp,%zmm7,8){%k1}"); + asm volatile("vscatterpf1qpd 0x7b(%ebp,%zmm7,8){%k1}"); + + /* AVX-512: Examples */ + + asm volatile("vaddpd %zmm4,%zmm5,%zmm6"); + asm volatile("vaddpd %zmm4,%zmm5,%zmm6{%k7}"); + asm volatile("vaddpd %zmm4,%zmm5,%zmm6{%k7}{z}"); + asm volatile("vaddpd {rn-sae},%zmm4,%zmm5,%zmm6"); + asm volatile("vaddpd {ru-sae},%zmm4,%zmm5,%zmm6"); + asm volatile("vaddpd {rd-sae},%zmm4,%zmm5,%zmm6"); + asm volatile("vaddpd {rz-sae},%zmm4,%zmm5,%zmm6"); + asm volatile("vaddpd (%ecx),%zmm5,%zmm6"); + asm volatile("vaddpd 0x123(%eax,%ecx,8),%zmm5,%zmm6"); + asm volatile("vaddpd (%ecx){1to8},%zmm5,%zmm6"); + asm volatile("vaddpd 0x1fc0(%edx),%zmm5,%zmm6"); + asm volatile("vaddpd 0x3f8(%edx){1to8},%zmm5,%zmm6"); + asm volatile("vcmpeq_uqps 0x1fc(%edx){1to16},%zmm6,%k5"); + asm volatile("vcmpltsd 0x123(%eax,%ecx,8),%xmm3,%k5{%k7}"); + asm volatile("vcmplesd {sae},%xmm4,%xmm5,%k5{%k7}"); + asm volatile("vgetmantss $0x5b,0x123(%eax,%ecx,8),%xmm4,%xmm5{%k7}"); + /* bndmk m32, bnd */ asm volatile("bndmk (%eax), %bnd0"); -- cgit v0.10.2 From ec3ed4a2104b8d1ab8da2db5b1221b2ba8a7a6e1 Mon Sep 17 00:00:00 2001 From: Dave Hansen Date: Wed, 20 Jul 2016 12:45:51 -0700 Subject: x86/fpu: Do not BUG_ON() in early FPU code I don't think it is really possible to have a system where CPUID enumerates support for XSAVE but that it does not have FP/SSE (they are "legacy" features and always present). But, I did manage to hit this case in qemu when I enabled its somewhat shaky XSAVE support. The bummer is that the FPU is set up before we parse the command-line or have *any* console support including earlyprintk. That turned what should have been an easy thing to debug in to a bit more of an odyssey. So a BUG() here is worthless. All it does it guarantee that if/when we hit this case we have an empty console. So, remove the BUG() and try to limp along by disabling XSAVE and trying to continue. Add a comment on why we are doing this, and also add a common "out_disable" path for leaving fpu__init_system_xstate(). Signed-off-by: Dave Hansen Cc: Andy Lutomirski Cc: Borislav Petkov Cc: Brian Gerst Cc: Dave Hansen Cc: Denys Vlasenko Cc: Fenghua Yu Cc: H. Peter Anvin Cc: Josh Poimboeuf Cc: Linus Torvalds Cc: Oleg Nesterov Cc: Peter Zijlstra Cc: Quentin Casasnovas Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/20160720194551.63BB2B58@viggo.jf.intel.com Signed-off-by: Ingo Molnar diff --git a/arch/x86/kernel/fpu/xstate.c b/arch/x86/kernel/fpu/xstate.c index 3169bca..680049a 100644 --- a/arch/x86/kernel/fpu/xstate.c +++ b/arch/x86/kernel/fpu/xstate.c @@ -714,8 +714,13 @@ void __init fpu__init_system_xstate(void) xfeatures_mask = eax + ((u64)edx << 32); if ((xfeatures_mask & XFEATURE_MASK_FPSSE) != XFEATURE_MASK_FPSSE) { + /* + * This indicates that something really unexpected happened + * with the enumeration. Disable XSAVE and try to continue + * booting without it. This is too early to BUG(). + */ pr_err("x86/fpu: FP/SSE not present amongst the CPU's xstate features: 0x%llx.\n", xfeatures_mask); - BUG(); + goto out_disable; } xfeatures_mask &= fpu__get_supported_xfeatures_mask(); @@ -723,11 +728,8 @@ void __init fpu__init_system_xstate(void) /* Enable xstate instructions to be able to continue with initialization: */ fpu__init_cpu_xstate(); err = init_xstate_size(); - if (err) { - /* something went wrong, boot without any XSAVE support */ - fpu__init_disable_system_xstate(); - return; - } + if (err) + goto out_disable; /* * Update info used for ptrace frames; use standard-format size and no @@ -744,6 +746,11 @@ void __init fpu__init_system_xstate(void) xfeatures_mask, fpu_kernel_xstate_size, boot_cpu_has(X86_FEATURE_XSAVES) ? "compacted" : "standard"); + return; + +out_disable: + /* something went wrong, try to boot without any XSAVE support */ + fpu__init_disable_system_xstate(); } /* -- cgit v0.10.2 From e1cb6be9e142e6cc6246f3ab2776b4d7a2b3d9f0 Mon Sep 17 00:00:00 2001 From: Bob Peterson Date: Thu, 21 Jul 2016 13:02:44 -0500 Subject: GFS2: Fix gfs2_replay_incr_blk for multiple journal sizes Before this patch, if you used gfs2_jadd to add new journals of a size smaller than the existing journals, replaying those new journals would withdraw. That's because function gfs2_replay_incr_blk was using the number of journal blocks (jd_block) from the superblock's journal pointer. In other words, "My journal's max size" rather than "the journal we're replaying's size." This patch changes the function to use the size of the pertinent journal rather than always using the journal we happen to be using. Signed-off-by: Bob Peterson diff --git a/fs/gfs2/lops.c b/fs/gfs2/lops.c index d5369a1..8e3ba20 100644 --- a/fs/gfs2/lops.c +++ b/fs/gfs2/lops.c @@ -535,9 +535,9 @@ static int buf_lo_scan_elements(struct gfs2_jdesc *jd, unsigned int start, if (pass != 1 || be32_to_cpu(ld->ld_type) != GFS2_LOG_DESC_METADATA) return 0; - gfs2_replay_incr_blk(sdp, &start); + gfs2_replay_incr_blk(jd, &start); - for (; blks; gfs2_replay_incr_blk(sdp, &start), blks--) { + for (; blks; gfs2_replay_incr_blk(jd, &start), blks--) { blkno = be64_to_cpu(*ptr++); jd->jd_found_blocks++; @@ -693,7 +693,7 @@ static int revoke_lo_scan_elements(struct gfs2_jdesc *jd, unsigned int start, offset = sizeof(struct gfs2_log_descriptor); - for (; blks; gfs2_replay_incr_blk(sdp, &start), blks--) { + for (; blks; gfs2_replay_incr_blk(jd, &start), blks--) { error = gfs2_replay_read_block(jd, start, &bh); if (error) return error; @@ -762,7 +762,6 @@ static int databuf_lo_scan_elements(struct gfs2_jdesc *jd, unsigned int start, __be64 *ptr, int pass) { struct gfs2_inode *ip = GFS2_I(jd->jd_inode); - struct gfs2_sbd *sdp = GFS2_SB(jd->jd_inode); struct gfs2_glock *gl = ip->i_gl; unsigned int blks = be32_to_cpu(ld->ld_data1); struct buffer_head *bh_log, *bh_ip; @@ -773,8 +772,8 @@ static int databuf_lo_scan_elements(struct gfs2_jdesc *jd, unsigned int start, if (pass != 1 || be32_to_cpu(ld->ld_type) != GFS2_LOG_DESC_JDATA) return 0; - gfs2_replay_incr_blk(sdp, &start); - for (; blks; gfs2_replay_incr_blk(sdp, &start), blks--) { + gfs2_replay_incr_blk(jd, &start); + for (; blks; gfs2_replay_incr_blk(jd, &start), blks--) { blkno = be64_to_cpu(*ptr++); esc = be64_to_cpu(*ptr++); diff --git a/fs/gfs2/recovery.c b/fs/gfs2/recovery.c index 1b64577..113b609 100644 --- a/fs/gfs2/recovery.c +++ b/fs/gfs2/recovery.c @@ -338,7 +338,7 @@ static int foreach_descriptor(struct gfs2_jdesc *jd, unsigned int start, struct gfs2_log_header_host lh; error = get_log_header(jd, start, &lh); if (!error) { - gfs2_replay_incr_blk(sdp, &start); + gfs2_replay_incr_blk(jd, &start); brelse(bh); continue; } @@ -360,7 +360,7 @@ static int foreach_descriptor(struct gfs2_jdesc *jd, unsigned int start, } while (length--) - gfs2_replay_incr_blk(sdp, &start); + gfs2_replay_incr_blk(jd, &start); brelse(bh); } @@ -390,7 +390,7 @@ static int clean_journal(struct gfs2_jdesc *jd, struct gfs2_log_header_host *hea struct buffer_head bh_map = { .b_state = 0, .b_blocknr = 0 }; lblock = head->lh_blkno; - gfs2_replay_incr_blk(sdp, &lblock); + gfs2_replay_incr_blk(jd, &lblock); bh_map.b_size = 1 << ip->i_inode.i_blkbits; error = gfs2_block_map(&ip->i_inode, lblock, &bh_map, 0); if (error) diff --git a/fs/gfs2/recovery.h b/fs/gfs2/recovery.h index 6142836..11fdfab 100644 --- a/fs/gfs2/recovery.h +++ b/fs/gfs2/recovery.h @@ -14,9 +14,9 @@ extern struct workqueue_struct *gfs_recovery_wq; -static inline void gfs2_replay_incr_blk(struct gfs2_sbd *sdp, unsigned int *blk) +static inline void gfs2_replay_incr_blk(struct gfs2_jdesc *jd, unsigned int *blk) { - if (++*blk == sdp->sd_jdesc->jd_blocks) + if (++*blk == jd->jd_blocks) *blk = 0; } -- cgit v0.10.2 From 1d3dd4ce210f347dd214913544e22fd9a8122901 Mon Sep 17 00:00:00 2001 From: hotran Date: Thu, 21 Jul 2016 13:55:55 -0700 Subject: Documentation: dtb: xgene: Add hwmon dts binding documentation This patch adds the APM X-Gene hwmon device tree node documentation. Signed-off-by: Hoan Tran Acked-by: Rob Herring Signed-off-by: Guenter Roeck diff --git a/Documentation/devicetree/bindings/hwmon/apm-xgene-hwmon.txt b/Documentation/devicetree/bindings/hwmon/apm-xgene-hwmon.txt new file mode 100644 index 0000000..59b3855 --- /dev/null +++ b/Documentation/devicetree/bindings/hwmon/apm-xgene-hwmon.txt @@ -0,0 +1,14 @@ +APM X-Gene hwmon driver + +APM X-Gene SOC sensors are accessed over the "SLIMpro" mailbox. + +Required properties : + - compatible : should be "apm,xgene-slimpro-hwmon" + - mboxes : use the label reference for the mailbox as the first parameter. + The second parameter is the channel number. + +Example : + hwmonslimpro { + compatible = "apm,xgene-slimpro-hwmon"; + mboxes = <&mailbox 7>; + }; -- cgit v0.10.2 From f8e7718cc0445587fe8530fc2d240d9aac2c9072 Mon Sep 17 00:00:00 2001 From: Soheil Hassas Yeganeh Date: Wed, 20 Jul 2016 18:01:18 -0400 Subject: packet: propagate sock_cmsg_send() error sock_cmsg_send() can return different error codes and not only -EINVAL, and we should properly propagate them. Fixes: c14ac9451c34 ("sock: enable timestamping using control messages") Signed-off-by: Soheil Hassas Yeganeh Cc: Willem de Bruijn Signed-off-by: David S. Miller diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index 53e87ce..b43c401 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c @@ -1930,10 +1930,8 @@ retry: sockc.tsflags = sk->sk_tsflags; if (msg->msg_controllen) { err = sock_cmsg_send(sk, msg, &sockc); - if (unlikely(err)) { - err = -EINVAL; + if (unlikely(err)) goto out_unlock; - } } skb->protocol = proto; -- cgit v0.10.2 From cfc9fde0b07c3b44b570057c5f93dda59dca1c94 Mon Sep 17 00:00:00 2001 From: Maxim Patlasov Date: Thu, 21 Jul 2016 18:24:26 -0700 Subject: ovl: verify upper dentry in ovl_remove_and_whiteout() The upper dentry may become stale before we call ovl_lock_rename_workdir. For example, someone could (mistakenly or maliciously) manually unlink(2) it directly from upperdir. To ensure it is not stale, let's lookup it after ovl_lock_rename_workdir and and check if it matches the upper dentry. Essentially, it is the same problem and similar solution as in commit 11f3710417d0 ("ovl: verify upper dentry before unlink and rename"). Signed-off-by: Maxim Patlasov Signed-off-by: Miklos Szeredi Cc: diff --git a/fs/overlayfs/dir.c b/fs/overlayfs/dir.c index c2a6b08..5c9d2d8 100644 --- a/fs/overlayfs/dir.c +++ b/fs/overlayfs/dir.c @@ -505,6 +505,7 @@ static int ovl_remove_and_whiteout(struct dentry *dentry, bool is_dir) struct dentry *upper; struct dentry *opaquedir = NULL; int err; + int flags = 0; if (WARN_ON(!workdir)) return -EROFS; @@ -534,46 +535,39 @@ static int ovl_remove_and_whiteout(struct dentry *dentry, bool is_dir) if (err) goto out_dput; - whiteout = ovl_whiteout(workdir, dentry); - err = PTR_ERR(whiteout); - if (IS_ERR(whiteout)) + upper = lookup_one_len(dentry->d_name.name, upperdir, + dentry->d_name.len); + err = PTR_ERR(upper); + if (IS_ERR(upper)) goto out_unlock; - upper = ovl_dentry_upper(dentry); - if (!upper) { - upper = lookup_one_len(dentry->d_name.name, upperdir, - dentry->d_name.len); - err = PTR_ERR(upper); - if (IS_ERR(upper)) - goto kill_whiteout; - - err = ovl_do_rename(wdir, whiteout, udir, upper, 0); - dput(upper); - if (err) - goto kill_whiteout; - } else { - int flags = 0; + err = -ESTALE; + if ((opaquedir && upper != opaquedir) || + (!opaquedir && ovl_dentry_upper(dentry) && + upper != ovl_dentry_upper(dentry))) { + goto out_dput_upper; + } - if (opaquedir) - upper = opaquedir; - err = -ESTALE; - if (upper->d_parent != upperdir) - goto kill_whiteout; + whiteout = ovl_whiteout(workdir, dentry); + err = PTR_ERR(whiteout); + if (IS_ERR(whiteout)) + goto out_dput_upper; - if (is_dir) - flags |= RENAME_EXCHANGE; + if (d_is_dir(upper)) + flags = RENAME_EXCHANGE; - err = ovl_do_rename(wdir, whiteout, udir, upper, flags); - if (err) - goto kill_whiteout; + err = ovl_do_rename(wdir, whiteout, udir, upper, flags); + if (err) + goto kill_whiteout; + if (flags) + ovl_cleanup(wdir, upper); - if (is_dir) - ovl_cleanup(wdir, upper); - } ovl_dentry_version_inc(dentry->d_parent); out_d_drop: d_drop(dentry); dput(whiteout); +out_dput_upper: + dput(upper); out_unlock: unlock_rename(workdir, upperdir); out_dput: -- cgit v0.10.2 From 30f027398b329c75c8f23a3c13be240b50866fdc Mon Sep 17 00:00:00 2001 From: Andy Lutomirski Date: Thu, 21 Jul 2016 14:16:51 -0700 Subject: x86/boot: Clarify what x86_legacy_features.reserve_bios_regions does It doesn't just control probing for the EBDA -- it controls whether we detect and reserve the <1MB BIOS regions in general. Signed-off-by: Andy Lutomirski Cc: Andrew Morton Cc: Borislav Petkov Cc: Brian Gerst Cc: Denys Vlasenko Cc: H. Peter Anvin Cc: Josh Poimboeuf Cc: Kees Cook Cc: Linus Torvalds Cc: Luis R. Rodriguez Cc: Mario Limonciello Cc: Matthew Garrett Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: Toshi Kani Link: http://lkml.kernel.org/r/55bd591115498440d461857a7b64f349a5d911f3.1469135598.git.luto@kernel.org Signed-off-by: Ingo Molnar diff --git a/arch/x86/include/asm/x86_init.h b/arch/x86/include/asm/x86_init.h index c519c05..66c15a0 100644 --- a/arch/x86/include/asm/x86_init.h +++ b/arch/x86/include/asm/x86_init.h @@ -168,8 +168,9 @@ struct x86_legacy_devices { * struct x86_legacy_features - legacy x86 features * * @rtc: this device has a CMOS real-time clock present - * @reserve_bios_regions: it's safe to search for the EBDA signature in the hardware's - * low RAM + * @reserve_bios_regions: boot code will search for the EBDA address and the + * start of the 640k - 1M BIOS region. If false, the platform must + * ensure that its memory map correctly reserves sub-1MB regions as needed. * @devices: legacy x86 devices, refer to struct x86_legacy_devices * documentation for further details. */ -- cgit v0.10.2 From 6a79296cb15d947bcb4558011fe066e5d8252b35 Mon Sep 17 00:00:00 2001 From: Andy Lutomirski Date: Thu, 21 Jul 2016 14:16:52 -0700 Subject: x86/boot: Simplify EBDA-vs-BIOS reservation logic Both the intent and the effect of reserve_bios_regions() is simple: reserve the range from the apparent BIOS start (suitably filtered) through 1MB and, if the EBDA start address is sensible, extend that reservation downward to cover the EBDA as well. The code is overcomplicated, though, and contains head-scratchers like: if (ebda_start < BIOS_START_MIN) ebda_start = BIOS_START_MAX; That snipped is trying to say "if ebda_start < BIOS_START_MIN, ignore it". Simplify it: reorder the code so that it makes sense. This should have no functional effect under any circumstances. Signed-off-by: Andy Lutomirski Cc: Andrew Morton Cc: Borislav Petkov Cc: Brian Gerst Cc: Denys Vlasenko Cc: H. Peter Anvin Cc: Josh Poimboeuf Cc: Kees Cook Cc: Linus Torvalds Cc: Luis R. Rodriguez Cc: Mario Limonciello Cc: Matthew Garrett Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: Toshi Kani Link: http://lkml.kernel.org/r/ef89c0c761be20ead8bd9a3275743e6259b6092a.1469135598.git.luto@kernel.org Signed-off-by: Ingo Molnar diff --git a/arch/x86/kernel/ebda.c b/arch/x86/kernel/ebda.c index 6219eef..4312f8a 100644 --- a/arch/x86/kernel/ebda.c +++ b/arch/x86/kernel/ebda.c @@ -65,22 +65,6 @@ void __init reserve_bios_regions(void) if (!x86_platform.legacy.reserve_bios_regions) return; - /* Get the start address of the EBDA page: */ - ebda_start = get_bios_ebda(); - - /* - * Quirk: some old Dells seem to have a 4k EBDA without - * reporting so in their BIOS RAM size value, so just - * consider the memory above 640K to be off limits - * (bugzilla 2990). - * - * We detect this case by filtering for nonsensical EBDA - * addresses below 128K, where we can assume that they - * are bogus and bump it up to a fixed 640K value: - */ - if (ebda_start < BIOS_START_MIN) - ebda_start = BIOS_START_MAX; - /* * BIOS RAM size is encoded in kilobytes, convert it * to bytes to get a first guess at where the BIOS @@ -91,18 +75,22 @@ void __init reserve_bios_regions(void) /* * If bios_start is less than 128K, assume it is bogus - * and bump it up to 640K: + * and bump it up to 640K. Similarly, if bios_start is above 640K, + * don't trust it. */ - if (bios_start < BIOS_START_MIN) + if (bios_start < BIOS_START_MIN || bios_start > BIOS_START_MAX) bios_start = BIOS_START_MAX; + /* Get the start address of the EBDA page: */ + ebda_start = get_bios_ebda(); + /* - * Use the lower of the bios_start and ebda_start - * as the starting point, but don't allow it to - * go beyond 640K: + * If the EBDA start address is sane and is below the BIOS region, + * then also reserve everything from the EBDA start address up to + * the BIOS region. */ - bios_start = min(bios_start, ebda_start); - bios_start = min(bios_start, BIOS_START_MAX); + if (ebda_start >= BIOS_START_MIN && ebda_start < bios_start) + bios_start = ebda_start; /* Reserve all memory between bios_start and the 1MB mark: */ memblock_reserve(bios_start, 0x100000 - bios_start); -- cgit v0.10.2 From 87dcdebd6beb54f183ae874664ba47bf071ebf95 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Fri, 22 Jul 2016 17:58:21 +0800 Subject: crypto: rsa-pkcs1pad - fix rsa-pkcs1pad request struct To allow for child request context the struct akcipher_request child_req needs to be at the end of the structure. Cc: stable@vger.kernel.org Signed-off-by: Tadeusz Struk Signed-off-by: Herbert Xu diff --git a/crypto/rsa-pkcs1pad.c b/crypto/rsa-pkcs1pad.c index ead8dc0..8ba4266 100644 --- a/crypto/rsa-pkcs1pad.c +++ b/crypto/rsa-pkcs1pad.c @@ -102,10 +102,10 @@ struct pkcs1pad_inst_ctx { }; struct pkcs1pad_request { - struct akcipher_request child_req; - struct scatterlist in_sg[3], out_sg[2]; uint8_t *in_buf, *out_buf; + + struct akcipher_request child_req; }; static int pkcs1pad_set_pub_key(struct crypto_akcipher *tfm, const void *key, -- cgit v0.10.2 From 930c532869774ebf8af9efe9484c597f896a7d46 Mon Sep 17 00:00:00 2001 From: Ilya Dryomov Date: Tue, 19 Jul 2016 03:50:28 +0200 Subject: libceph: apply new_state before new_up_client on incrementals Currently, osd_weight and osd_state fields are updated in the encoding order. This is wrong, because an incremental map may look like e.g. new_up_client: { osd=6, addr=... } # set osd_state and addr new_state: { osd=6, xorstate=EXISTS } # clear osd_state Suppose osd6's current osd_state is EXISTS (i.e. osd6 is down). After applying new_up_client, osd_state is changed to EXISTS | UP. Carrying on with the new_state update, we flip EXISTS and leave osd6 in a weird "!EXISTS but UP" state. A non-existent OSD is considered down by the mapping code 2087 for (i = 0; i < pg->pg_temp.len; i++) { 2088 if (ceph_osd_is_down(osdmap, pg->pg_temp.osds[i])) { 2089 if (ceph_can_shift_osds(pi)) 2090 continue; 2091 2092 temp->osds[temp->size++] = CRUSH_ITEM_NONE; and so requests get directed to the second OSD in the set instead of the first, resulting in OSD-side errors like: [WRN] : client.4239 192.168.122.21:0/2444980242 misdirected client.4239.1:2827 pg 2.5df899f2 to osd.4 not [1,4,6] in e680/680 and hung rbds on the client: [ 493.566367] rbd: rbd0: write 400000 at 11cc00000 (0) [ 493.566805] rbd: rbd0: result -6 xferred 400000 [ 493.567011] blk_update_request: I/O error, dev rbd0, sector 9330688 The fix is to decouple application from the decoding and: - apply new_weight first - apply new_state before new_up_client - twiddle osd_state flags if marking in - clear out some of the state if osd is destroyed Fixes: http://tracker.ceph.com/issues/14901 Cc: stable@vger.kernel.org # 3.15+: 6dd74e44dc1d: libceph: set 'exists' flag for newly up osd Cc: stable@vger.kernel.org # 3.15+ Signed-off-by: Ilya Dryomov Reviewed-by: Josh Durgin diff --git a/net/ceph/osdmap.c b/net/ceph/osdmap.c index 03062bb..7e480bf 100644 --- a/net/ceph/osdmap.c +++ b/net/ceph/osdmap.c @@ -1261,6 +1261,115 @@ struct ceph_osdmap *ceph_osdmap_decode(void **p, void *end) } /* + * Encoding order is (new_up_client, new_state, new_weight). Need to + * apply in the (new_weight, new_state, new_up_client) order, because + * an incremental map may look like e.g. + * + * new_up_client: { osd=6, addr=... } # set osd_state and addr + * new_state: { osd=6, xorstate=EXISTS } # clear osd_state + */ +static int decode_new_up_state_weight(void **p, void *end, + struct ceph_osdmap *map) +{ + void *new_up_client; + void *new_state; + void *new_weight_end; + u32 len; + + new_up_client = *p; + ceph_decode_32_safe(p, end, len, e_inval); + len *= sizeof(u32) + sizeof(struct ceph_entity_addr); + ceph_decode_need(p, end, len, e_inval); + *p += len; + + new_state = *p; + ceph_decode_32_safe(p, end, len, e_inval); + len *= sizeof(u32) + sizeof(u8); + ceph_decode_need(p, end, len, e_inval); + *p += len; + + /* new_weight */ + ceph_decode_32_safe(p, end, len, e_inval); + while (len--) { + s32 osd; + u32 w; + + ceph_decode_need(p, end, 2*sizeof(u32), e_inval); + osd = ceph_decode_32(p); + w = ceph_decode_32(p); + BUG_ON(osd >= map->max_osd); + pr_info("osd%d weight 0x%x %s\n", osd, w, + w == CEPH_OSD_IN ? "(in)" : + (w == CEPH_OSD_OUT ? "(out)" : "")); + map->osd_weight[osd] = w; + + /* + * If we are marking in, set the EXISTS, and clear the + * AUTOOUT and NEW bits. + */ + if (w) { + map->osd_state[osd] |= CEPH_OSD_EXISTS; + map->osd_state[osd] &= ~(CEPH_OSD_AUTOOUT | + CEPH_OSD_NEW); + } + } + new_weight_end = *p; + + /* new_state (up/down) */ + *p = new_state; + len = ceph_decode_32(p); + while (len--) { + s32 osd; + u8 xorstate; + int ret; + + osd = ceph_decode_32(p); + xorstate = ceph_decode_8(p); + if (xorstate == 0) + xorstate = CEPH_OSD_UP; + BUG_ON(osd >= map->max_osd); + if ((map->osd_state[osd] & CEPH_OSD_UP) && + (xorstate & CEPH_OSD_UP)) + pr_info("osd%d down\n", osd); + if ((map->osd_state[osd] & CEPH_OSD_EXISTS) && + (xorstate & CEPH_OSD_EXISTS)) { + pr_info("osd%d does not exist\n", osd); + map->osd_weight[osd] = CEPH_OSD_IN; + ret = set_primary_affinity(map, osd, + CEPH_OSD_DEFAULT_PRIMARY_AFFINITY); + if (ret) + return ret; + memset(map->osd_addr + osd, 0, sizeof(*map->osd_addr)); + map->osd_state[osd] = 0; + } else { + map->osd_state[osd] ^= xorstate; + } + } + + /* new_up_client */ + *p = new_up_client; + len = ceph_decode_32(p); + while (len--) { + s32 osd; + struct ceph_entity_addr addr; + + osd = ceph_decode_32(p); + ceph_decode_copy(p, &addr, sizeof(addr)); + ceph_decode_addr(&addr); + BUG_ON(osd >= map->max_osd); + pr_info("osd%d up\n", osd); + map->osd_state[osd] |= CEPH_OSD_EXISTS | CEPH_OSD_UP; + map->osd_addr[osd] = addr; + } + + *p = new_weight_end; + return 0; + +e_inval: + return -EINVAL; +} + +/* * decode and apply an incremental map update. */ struct ceph_osdmap *osdmap_apply_incremental(void **p, void *end, @@ -1358,49 +1467,10 @@ struct ceph_osdmap *osdmap_apply_incremental(void **p, void *end, __remove_pg_pool(&map->pg_pools, pi); } - /* new_up */ - ceph_decode_32_safe(p, end, len, e_inval); - while (len--) { - u32 osd; - struct ceph_entity_addr addr; - ceph_decode_32_safe(p, end, osd, e_inval); - ceph_decode_copy_safe(p, end, &addr, sizeof(addr), e_inval); - ceph_decode_addr(&addr); - pr_info("osd%d up\n", osd); - BUG_ON(osd >= map->max_osd); - map->osd_state[osd] |= CEPH_OSD_UP | CEPH_OSD_EXISTS; - map->osd_addr[osd] = addr; - } - - /* new_state */ - ceph_decode_32_safe(p, end, len, e_inval); - while (len--) { - u32 osd; - u8 xorstate; - ceph_decode_32_safe(p, end, osd, e_inval); - xorstate = **(u8 **)p; - (*p)++; /* clean flag */ - if (xorstate == 0) - xorstate = CEPH_OSD_UP; - if (xorstate & CEPH_OSD_UP) - pr_info("osd%d down\n", osd); - if (osd < map->max_osd) - map->osd_state[osd] ^= xorstate; - } - - /* new_weight */ - ceph_decode_32_safe(p, end, len, e_inval); - while (len--) { - u32 osd, off; - ceph_decode_need(p, end, sizeof(u32)*2, e_inval); - osd = ceph_decode_32(p); - off = ceph_decode_32(p); - pr_info("osd%d weight 0x%x %s\n", osd, off, - off == CEPH_OSD_IN ? "(in)" : - (off == CEPH_OSD_OUT ? "(out)" : "")); - if (osd < map->max_osd) - map->osd_weight[osd] = off; - } + /* new_up_client, new_state, new_weight */ + err = decode_new_up_state_weight(p, end, map); + if (err) + goto bad; /* new_pg_temp */ err = decode_new_pg_temp(p, end, map); -- cgit v0.10.2 From 0bfb85c6ba620c39c0e5124851a1bea0f5a56e05 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 6 Jul 2016 14:54:03 +0200 Subject: gpio: tegra: don't auto-enable for COMPILE_TEST I stumbled over a build error with COMPILE_TEST and CONFIG_OF disabled: drivers/gpio/gpio-tegra.c: In function 'tegra_gpio_probe': drivers/gpio/gpio-tegra.c:603:9: error: 'struct gpio_chip' has no member named 'of_node' The problem is that the newly added GPIO_TEGRA Kconfig symbol does not have a dependency on CONFIG_OF. However, there is another problem here as the driver gets enabled unconditionally whenever COMPILE_TEST is set. This fixes both problems, by making the symbol user-visible when COMPILE_TEST is set and default-enabled for ARCH_TEGRA=y. As a side-effect, it is now possible to compile-test a Tegra kernel with GPIO support disabled, which is harmless. Signed-off-by: Arnd Bergmann Fixes: 4dd4dd1d2120 ("gpio: tegra: Allow compile test") Signed-off-by: Linus Walleij diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 536112f..d786061 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -402,9 +402,12 @@ config GPIO_TB10X select OF_GPIO config GPIO_TEGRA - bool - default y + bool "NVIDIA Tegra GPIO support" + default ARCH_TEGRA depends on ARCH_TEGRA || COMPILE_TEST + depends on OF + help + Say yes here to support GPIO pins on NVIDIA Tegra SoCs. config GPIO_TS4800 tristate "TS-4800 DIO blocks and compatibles" -- cgit v0.10.2 From e5e6312b5bc74c6f119993f32257927a6b646bd7 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 22 Jul 2016 12:12:49 -0300 Subject: perf tests kmod-path: Fix build on ubuntu:16.04-x-armhf Cross building it on Ubuntu 16.04 to ARM ends up showing we get the free() prototype by luck in other environments, fix it. Cc: Adrian Hunter Cc: David Ahern Cc: Jiri Olsa Cc: Namhyung Kim Cc: Wang Nan Link: http://lkml.kernel.org/n/tip-0ktfgmmyhcfw8ondka2013f3@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/tests/kmod-path.c b/tools/perf/tests/kmod-path.c index d2af781..76f41f2 100644 --- a/tools/perf/tests/kmod-path.c +++ b/tools/perf/tests/kmod-path.c @@ -1,4 +1,5 @@ #include +#include #include "tests.h" #include "dso.h" #include "debug.h" -- cgit v0.10.2 From 0a943cb10ce783a1c55adf6f52f62bcbd5f49314 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 22 Jul 2016 09:55:53 -0300 Subject: tools build: Add HOSTARCH Makefile variable For tools that needs to be always compiled with the host headers. Cc: Adrian Hunter Cc: David Ahern Cc: Jiri Olsa Cc: Josh Poimboeuf Cc: Namhyung Kim Cc: Stephen Rothwell Cc: Wang Nan Link: http://lkml.kernel.org/n/tip-907q32k2nep6q670dkxypmu6@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/scripts/Makefile.arch b/tools/scripts/Makefile.arch index e11fbd6..887321c 100644 --- a/tools/scripts/Makefile.arch +++ b/tools/scripts/Makefile.arch @@ -1,14 +1,13 @@ -ifndef ARCH -ARCH := $(shell uname -m 2>/dev/null || echo not) -endif - -ARCH := $(shell echo $(ARCH) | sed -e s/i.86/x86/ -e s/x86_64/x86/ \ +HOSTARCH := $(shell uname -m | sed -e s/i.86/x86/ -e s/x86_64/x86/ \ -e s/sun4u/sparc/ -e s/sparc64/sparc/ \ -e /arm64/!s/arm.*/arm/ -e s/sa110/arm/ \ -e s/s390x/s390/ -e s/parisc64/parisc/ \ -e s/ppc.*/powerpc/ -e s/mips.*/mips/ \ -e s/sh[234].*/sh/ -e s/aarch64.*/arm64/ \ -e s/tile.*/tile/ ) +ifndef ARCH +ARCH := $(HOSTARCH) +endif LP64 := $(shell echo __LP64__ | ${CC} ${CFLAGS} -E -x c - | tail -n 1) ifeq ($(LP64), 1) -- cgit v0.10.2 From 630e7a2904a271a519093aff611f50e06d55085c Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 22 Jul 2016 09:59:24 -0300 Subject: objtool: Use tools/scripts/Makefile.arch to get ARCH and HOSTARCH objtool's Makefile was setting up ARCH but fixing up just the x86_64 -> x86, using Makefile.arch will do the necessary fixups for all arches. Cc: Adrian Hunter Cc: David Ahern Cc: Jiri Olsa Cc: Josh Poimboeuf Cc: Namhyung Kim Cc: Stephen Rothwell Cc: Wang Nan Link: http://lkml.kernel.org/n/tip-hbq0bbh03u2b722vozcyql31@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/objtool/Makefile b/tools/objtool/Makefile index 1f75b0a..988129c 100644 --- a/tools/objtool/Makefile +++ b/tools/objtool/Makefile @@ -1,11 +1,9 @@ include ../scripts/Makefile.include +include ../scripts/Makefile.arch -ifndef ($(ARCH)) -ARCH ?= $(shell uname -m) ifeq ($(ARCH),x86_64) ARCH := x86 endif -endif # always use the host compiler CC = gcc -- cgit v0.10.2 From 0cf6eb603b83ea386f26363b5b12e64297822bb1 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 22 Jul 2016 16:28:46 -0300 Subject: objtool: Always use host headers From a conversation with Josh: From http://lkml.kernel.org/r/20160722034118.guckaniobf3f7czc@treble : It needs to be compiled with the host (powerpc) compiler, but then it needs to disassemble target (x86) files. ---- So use HOSTARCH instead of ARCH. Cc: Adrian Hunter Cc: David Ahern Cc: Jiri Olsa Cc: Josh Poimboeuf Cc: Namhyung Kim Cc: Stephen Rothwell Cc: Wang Nan Link: http://lkml.kernel.org/r/20160722034118.guckaniobf3f7czc@treble Link: http://lkml.kernel.org/n/tip-le1m1yzxnfpt3msbblu40nm8@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/objtool/Makefile b/tools/objtool/Makefile index 988129c..91b5f98 100644 --- a/tools/objtool/Makefile +++ b/tools/objtool/Makefile @@ -24,7 +24,7 @@ OBJTOOL_IN := $(OBJTOOL)-in.o all: $(OBJTOOL) -INCLUDES := -I$(srctree)/tools/include -I$(srctree)/tools/arch/$(ARCH)/include/uapi +INCLUDES := -I$(srctree)/tools/include -I$(srctree)/tools/arch/$(HOSTARCH)/include/uapi CFLAGS += -Wall -Werror $(EXTRA_WARNINGS) -fomit-frame-pointer -O2 -g $(INCLUDES) LDFLAGS += -lelf $(LIBSUBCMD) -- cgit v0.10.2 From 60cbdf5d051d4f4db23d267d511ca241d4be7c0d Mon Sep 17 00:00:00 2001 From: Josh Poimboeuf Date: Fri, 22 Jul 2016 14:19:20 -0500 Subject: tools build: Fix objtool build with ARCH=x86_64 The objtool build fails in a cross-compiled environment on a non-x86 host with "ARCH=x86_64": tools/objtool/objtool-in.o: In function `decode_instructions': tools/objtool/builtin-check.c:276: undefined reference to `arch_decode_instruction' We could override the ARCH environment variable and change it back to x86, similar to what the objtool Makefile was doing before; but it's tricky to override environment variables consistently. Instead, take a similar approach used by the Linux top-level Makefile and introduce a SRCARCH Makefile variable which evaluates to "x86" when ARCH is either "x86_64" or "x86". Reported-by: Stephen Rothwell Signed-off-by: Josh Poimboeuf Cc: Andy Lutomirski Cc: H. Peter Anvin Cc: Peter Zijlstra Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/20160722191920.ej62fnspnqurbaa7@treble Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/objtool/Build b/tools/objtool/Build index 2457916..d6cdece 100644 --- a/tools/objtool/Build +++ b/tools/objtool/Build @@ -1,4 +1,4 @@ -objtool-y += arch/$(ARCH)/ +objtool-y += arch/$(SRCARCH)/ objtool-y += builtin-check.o objtool-y += elf.o objtool-y += special.o diff --git a/tools/objtool/Makefile b/tools/objtool/Makefile index 91b5f98..0b43770 100644 --- a/tools/objtool/Makefile +++ b/tools/objtool/Makefile @@ -33,7 +33,7 @@ elfshdr := $(shell echo '\#include ' | $(CC) $(CFLAGS) -x c -E - | gre CFLAGS += $(if $(elfshdr),,-DLIBELF_USE_DEPRECATED) AWK = awk -export srctree OUTPUT CFLAGS ARCH AWK +export srctree OUTPUT CFLAGS SRCARCH AWK include $(srctree)/tools/build/Makefile.include $(OBJTOOL_IN): fixdep FORCE diff --git a/tools/scripts/Makefile.arch b/tools/scripts/Makefile.arch index 887321c..ad85b92 100644 --- a/tools/scripts/Makefile.arch +++ b/tools/scripts/Makefile.arch @@ -5,10 +5,42 @@ HOSTARCH := $(shell uname -m | sed -e s/i.86/x86/ -e s/x86_64/x86/ \ -e s/ppc.*/powerpc/ -e s/mips.*/mips/ \ -e s/sh[234].*/sh/ -e s/aarch64.*/arm64/ \ -e s/tile.*/tile/ ) + ifndef ARCH ARCH := $(HOSTARCH) endif +SRCARCH := $(ARCH) + +# Additional ARCH settings for x86 +ifeq ($(ARCH),i386) + SRCARCH := x86 +endif +ifeq ($(ARCH),x86_64) + SRCARCH := x86 +endif + +# Additional ARCH settings for sparc +ifeq ($(ARCH),sparc32) + SRCARCH := sparc +endif +ifeq ($(ARCH),sparc64) + SRCARCH := sparc +endif + +# Additional ARCH settings for sh +ifeq ($(ARCH),sh64) + SRCARCH := sh +endif + +# Additional ARCH settings for tile +ifeq ($(ARCH),tilepro) + SRCARCH := tile +endif +ifeq ($(ARCH),tilegx) + SRCARCH := tile +endif + LP64 := $(shell echo __LP64__ | ${CC} ${CFLAGS} -E -x c - | tail -n 1) ifeq ($(LP64), 1) IS_64_BIT := 1 -- cgit v0.10.2 From 73f576c04b9410ed19660f74f97521bee6e1c546 Mon Sep 17 00:00:00 2001 From: Johannes Weiner Date: Wed, 20 Jul 2016 15:44:57 -0700 Subject: mm: memcontrol: fix cgroup creation failure after many small jobs The memory controller has quite a bit of state that usually outlives the cgroup and pins its CSS until said state disappears. At the same time it imposes a 16-bit limit on the CSS ID space to economically store IDs in the wild. Consequently, when we use cgroups to contain frequent but small and short-lived jobs that leave behind some page cache, we quickly run into the 64k limitations of outstanding CSSs. Creating a new cgroup fails with -ENOSPC while there are only a few, or even no user-visible cgroups in existence. Although pinning CSSs past cgroup removal is common, there are only two instances that actually need an ID after a cgroup is deleted: cache shadow entries and swapout records. Cache shadow entries reference the ID weakly and can deal with the CSS having disappeared when it's looked up later. They pose no hurdle. Swap-out records do need to pin the css to hierarchically attribute swapins after the cgroup has been deleted; though the only pages that remain swapped out after offlining are tmpfs/shmem pages. And those references are under the user's control, so they are manageable. This patch introduces a private 16-bit memcg ID and switches swap and cache shadow entries over to using that. This ID can then be recycled after offlining when the CSS remains pinned only by objects that don't specifically need it. This script demonstrates the problem by faulting one cache page in a new cgroup and deleting it again: set -e mkdir -p pages for x in `seq 128000`; do [ $((x % 1000)) -eq 0 ] && echo $x mkdir /cgroup/foo echo $$ >/cgroup/foo/cgroup.procs echo trex >pages/$x echo $$ >/cgroup/cgroup.procs rmdir /cgroup/foo done When run on an unpatched kernel, we eventually run out of possible IDs even though there are no visible cgroups: [root@ham ~]# ./cssidstress.sh [...] 65000 mkdir: cannot create directory '/cgroup/foo': No space left on device After this patch, the IDs get released upon cgroup destruction and the cache and css objects get released once memory reclaim kicks in. [hannes@cmpxchg.org: init the IDR] Link: http://lkml.kernel.org/r/20160621154601.GA22431@cmpxchg.org Fixes: b2052564e66d ("mm: memcontrol: continue cache reclaim from offlined groups") Link: http://lkml.kernel.org/r/20160617162516.GD19084@cmpxchg.org Signed-off-by: Johannes Weiner Reported-by: John Garcia Reviewed-by: Vladimir Davydov Acked-by: Tejun Heo Cc: Nikolay Borisov Cc: [3.19+] Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/include/linux/memcontrol.h b/include/linux/memcontrol.h index a805474..56e6069 100644 --- a/include/linux/memcontrol.h +++ b/include/linux/memcontrol.h @@ -97,6 +97,11 @@ enum mem_cgroup_events_target { #define MEM_CGROUP_ID_SHIFT 16 #define MEM_CGROUP_ID_MAX USHRT_MAX +struct mem_cgroup_id { + int id; + atomic_t ref; +}; + struct mem_cgroup_stat_cpu { long count[MEMCG_NR_STAT]; unsigned long events[MEMCG_NR_EVENTS]; @@ -172,6 +177,9 @@ enum memcg_kmem_state { struct mem_cgroup { struct cgroup_subsys_state css; + /* Private memcg ID. Used to ID objects that outlive the cgroup */ + struct mem_cgroup_id id; + /* Accounted resources */ struct page_counter memory; struct page_counter swap; @@ -330,22 +338,9 @@ static inline unsigned short mem_cgroup_id(struct mem_cgroup *memcg) if (mem_cgroup_disabled()) return 0; - return memcg->css.id; -} - -/** - * mem_cgroup_from_id - look up a memcg from an id - * @id: the id to look up - * - * Caller must hold rcu_read_lock() and use css_tryget() as necessary. - */ -static inline struct mem_cgroup *mem_cgroup_from_id(unsigned short id) -{ - struct cgroup_subsys_state *css; - - css = css_from_id(id, &memory_cgrp_subsys); - return mem_cgroup_from_css(css); + return memcg->id.id; } +struct mem_cgroup *mem_cgroup_from_id(unsigned short id); /** * parent_mem_cgroup - find the accounting parent of a memcg diff --git a/mm/memcontrol.c b/mm/memcontrol.c index ac8664db..5339c89 100644 --- a/mm/memcontrol.c +++ b/mm/memcontrol.c @@ -4057,6 +4057,60 @@ static struct cftype mem_cgroup_legacy_files[] = { { }, /* terminate */ }; +/* + * Private memory cgroup IDR + * + * Swap-out records and page cache shadow entries need to store memcg + * references in constrained space, so we maintain an ID space that is + * limited to 16 bit (MEM_CGROUP_ID_MAX), limiting the total number of + * memory-controlled cgroups to 64k. + * + * However, there usually are many references to the oflline CSS after + * the cgroup has been destroyed, such as page cache or reclaimable + * slab objects, that don't need to hang on to the ID. We want to keep + * those dead CSS from occupying IDs, or we might quickly exhaust the + * relatively small ID space and prevent the creation of new cgroups + * even when there are much fewer than 64k cgroups - possibly none. + * + * Maintain a private 16-bit ID space for memcg, and allow the ID to + * be freed and recycled when it's no longer needed, which is usually + * when the CSS is offlined. + * + * The only exception to that are records of swapped out tmpfs/shmem + * pages that need to be attributed to live ancestors on swapin. But + * those references are manageable from userspace. + */ + +static DEFINE_IDR(mem_cgroup_idr); + +static void mem_cgroup_id_get(struct mem_cgroup *memcg) +{ + atomic_inc(&memcg->id.ref); +} + +static void mem_cgroup_id_put(struct mem_cgroup *memcg) +{ + if (atomic_dec_and_test(&memcg->id.ref)) { + idr_remove(&mem_cgroup_idr, memcg->id.id); + memcg->id.id = 0; + + /* Memcg ID pins CSS */ + css_put(&memcg->css); + } +} + +/** + * mem_cgroup_from_id - look up a memcg from a memcg id + * @id: the memcg id to look up + * + * Caller must hold rcu_read_lock(). + */ +struct mem_cgroup *mem_cgroup_from_id(unsigned short id) +{ + WARN_ON_ONCE(!rcu_read_lock_held()); + return idr_find(&mem_cgroup_idr, id); +} + static int alloc_mem_cgroup_per_zone_info(struct mem_cgroup *memcg, int node) { struct mem_cgroup_per_node *pn; @@ -4116,6 +4170,12 @@ static struct mem_cgroup *mem_cgroup_alloc(void) if (!memcg) return NULL; + memcg->id.id = idr_alloc(&mem_cgroup_idr, NULL, + 1, MEM_CGROUP_ID_MAX, + GFP_KERNEL); + if (memcg->id.id < 0) + goto fail; + memcg->stat = alloc_percpu(struct mem_cgroup_stat_cpu); if (!memcg->stat) goto fail; @@ -4142,8 +4202,11 @@ static struct mem_cgroup *mem_cgroup_alloc(void) #ifdef CONFIG_CGROUP_WRITEBACK INIT_LIST_HEAD(&memcg->cgwb_list); #endif + idr_replace(&mem_cgroup_idr, memcg, memcg->id.id); return memcg; fail: + if (memcg->id.id > 0) + idr_remove(&mem_cgroup_idr, memcg->id.id); mem_cgroup_free(memcg); return NULL; } @@ -4206,12 +4269,11 @@ fail: return ERR_PTR(-ENOMEM); } -static int -mem_cgroup_css_online(struct cgroup_subsys_state *css) +static int mem_cgroup_css_online(struct cgroup_subsys_state *css) { - if (css->id > MEM_CGROUP_ID_MAX) - return -ENOSPC; - + /* Online state pins memcg ID, memcg ID pins CSS */ + mem_cgroup_id_get(mem_cgroup_from_css(css)); + css_get(css); return 0; } @@ -4234,6 +4296,8 @@ static void mem_cgroup_css_offline(struct cgroup_subsys_state *css) memcg_offline_kmem(memcg); wb_memcg_offline(memcg); + + mem_cgroup_id_put(memcg); } static void mem_cgroup_css_released(struct cgroup_subsys_state *css) @@ -5756,6 +5820,7 @@ void mem_cgroup_swapout(struct page *page, swp_entry_t entry) if (!memcg) return; + mem_cgroup_id_get(memcg); oldid = swap_cgroup_record(entry, mem_cgroup_id(memcg)); VM_BUG_ON_PAGE(oldid, page); mem_cgroup_swap_statistics(memcg, true); @@ -5774,6 +5839,9 @@ void mem_cgroup_swapout(struct page *page, swp_entry_t entry) VM_BUG_ON(!irqs_disabled()); mem_cgroup_charge_statistics(memcg, page, false, -1); memcg_check_events(memcg, page); + + if (!mem_cgroup_is_root(memcg)) + css_put(&memcg->css); } /* @@ -5804,11 +5872,11 @@ int mem_cgroup_try_charge_swap(struct page *page, swp_entry_t entry) !page_counter_try_charge(&memcg->swap, 1, &counter)) return -ENOMEM; + mem_cgroup_id_get(memcg); oldid = swap_cgroup_record(entry, mem_cgroup_id(memcg)); VM_BUG_ON_PAGE(oldid, page); mem_cgroup_swap_statistics(memcg, true); - css_get(&memcg->css); return 0; } @@ -5837,7 +5905,7 @@ void mem_cgroup_uncharge_swap(swp_entry_t entry) page_counter_uncharge(&memcg->memsw, 1); } mem_cgroup_swap_statistics(memcg, false); - css_put(&memcg->css); + mem_cgroup_id_put(memcg); } rcu_read_unlock(); } diff --git a/mm/slab_common.c b/mm/slab_common.c index a65dad7..82317ab 100644 --- a/mm/slab_common.c +++ b/mm/slab_common.c @@ -526,8 +526,8 @@ void memcg_create_kmem_cache(struct mem_cgroup *memcg, goto out_unlock; cgroup_name(css->cgroup, memcg_name_buf, sizeof(memcg_name_buf)); - cache_name = kasprintf(GFP_KERNEL, "%s(%d:%s)", root_cache->name, - css->id, memcg_name_buf); + cache_name = kasprintf(GFP_KERNEL, "%s(%llu:%s)", root_cache->name, + css->serial_nr, memcg_name_buf); if (!cache_name) goto out_unlock; -- cgit v0.10.2 From 3cb9185c67304b2a7ea9be73e7d13df6fb2793a1 Mon Sep 17 00:00:00 2001 From: Andrey Ryabinin Date: Wed, 20 Jul 2016 15:45:00 -0700 Subject: radix-tree: fix radix_tree_iter_retry() for tagged iterators. radix_tree_iter_retry() resets slot to NULL, but it doesn't reset tags. Then NULL slot and non-zero iter.tags passed to radix_tree_next_slot() leading to crash: RIP: radix_tree_next_slot include/linux/radix-tree.h:473 find_get_pages_tag+0x334/0x930 mm/filemap.c:1452 .... Call Trace: pagevec_lookup_tag+0x3a/0x80 mm/swap.c:960 mpage_prepare_extent_to_map+0x321/0xa90 fs/ext4/inode.c:2516 ext4_writepages+0x10be/0x2b20 fs/ext4/inode.c:2736 do_writepages+0x97/0x100 mm/page-writeback.c:2364 __filemap_fdatawrite_range+0x248/0x2e0 mm/filemap.c:300 filemap_write_and_wait_range+0x121/0x1b0 mm/filemap.c:490 ext4_sync_file+0x34d/0xdb0 fs/ext4/fsync.c:115 vfs_fsync_range+0x10a/0x250 fs/sync.c:195 vfs_fsync fs/sync.c:209 do_fsync+0x42/0x70 fs/sync.c:219 SYSC_fdatasync fs/sync.c:232 SyS_fdatasync+0x19/0x20 fs/sync.c:230 entry_SYSCALL_64_fastpath+0x23/0xc1 arch/x86/entry/entry_64.S:207 We must reset iterator's tags to bail out from radix_tree_next_slot() and go to the slow-path in radix_tree_next_chunk(). Fixes: 46437f9a554f ("radix-tree: fix race in gang lookup") Link: http://lkml.kernel.org/r/1468495196-10604-1-git-send-email-aryabinin@virtuozzo.com Signed-off-by: Andrey Ryabinin Reported-by: Dmitry Vyukov Acked-by: Konstantin Khlebnikov Cc: Matthew Wilcox Cc: Hugh Dickins Cc: Ross Zwisler Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/include/linux/radix-tree.h b/include/linux/radix-tree.h index cb4b7e8..eca6f62 100644 --- a/include/linux/radix-tree.h +++ b/include/linux/radix-tree.h @@ -407,6 +407,7 @@ static inline __must_check void **radix_tree_iter_retry(struct radix_tree_iter *iter) { iter->next_index = iter->index; + iter->tags = 0; return NULL; } -- cgit v0.10.2 From b301aac5ad67079710a1a7c7b15bf62cddd63295 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 20 Jul 2016 15:45:03 -0700 Subject: testing/radix-tree: fix a macro expansion bug There are no parentheses around this macro and it causes a problem when we do: index = rand() % THRASH_SIZE; Link: http://lkml.kernel.org/r/20160715210953.GC19522@mwanda Signed-off-by: Dan Carpenter Acked-by: Ross Zwisler Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/tools/testing/radix-tree/tag_check.c b/tools/testing/radix-tree/tag_check.c index b7447ce..b0ac057 100644 --- a/tools/testing/radix-tree/tag_check.c +++ b/tools/testing/radix-tree/tag_check.c @@ -122,7 +122,7 @@ enum { NODE_TAGGED = 2, }; -#define THRASH_SIZE 1000 * 1000 +#define THRASH_SIZE (1000 * 1000) #define N 127 #define BATCH 33 -- cgit v0.10.2 From 2d6a4d64812bb12dda53704943b61a7496d02098 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 20 Jul 2016 15:45:05 -0700 Subject: tools/vm/slabinfo: fix an unintentional printf The curly braces are missing here so we print stuff unintentionally. Fixes: 9da4714a2d44 ('slub: slabinfo update for cmpxchg handling') Link: http://lkml.kernel.org/r/20160715211243.GE19522@mwanda Signed-off-by: Dan Carpenter Acked-by: Christoph Lameter Cc: Sergey Senozhatsky Cc: Colin Ian King Cc: Laura Abbott Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/tools/vm/slabinfo.c b/tools/vm/slabinfo.c index 7cf6e17..b9d34b3 100644 --- a/tools/vm/slabinfo.c +++ b/tools/vm/slabinfo.c @@ -510,10 +510,11 @@ static void slab_stats(struct slabinfo *s) s->alloc_node_mismatch, (s->alloc_node_mismatch * 100) / total); } - if (s->cmpxchg_double_fail || s->cmpxchg_double_cpu_fail) + if (s->cmpxchg_double_fail || s->cmpxchg_double_cpu_fail) { printf("\nCmpxchg_double Looping\n------------------------\n"); printf("Locked Cmpxchg Double redos %lu\nUnlocked Cmpxchg Double redos %lu\n", s->cmpxchg_double_fail, s->cmpxchg_double_cpu_fail); + } } static void report(struct slabinfo *s) -- cgit v0.10.2 From 368301f2fe4b07e5fb71dba3cc566bc59eb6705f Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Wed, 20 Jul 2016 15:45:08 -0700 Subject: pps: do not crash when failed to register With this command sequence: modprobe plip modprobe pps_parport rmmod pps_parport the partport_pps modules causes this crash: BUG: unable to handle kernel NULL pointer dereference at (null) IP: parport_detach+0x1d/0x60 [pps_parport] Oops: 0000 [#1] SMP ... Call Trace: parport_unregister_driver+0x65/0xc0 [parport] SyS_delete_module+0x187/0x210 The sequence that builds up to this is: 1) plip is loaded and takes the parport device for exclusive use: plip0: Parallel port at 0x378, using IRQ 7. 2) pps_parport then fails to grab the device: pps_parport: parallel port PPS client parport0: cannot grant exclusive access for device pps_parport pps_parport: couldn't register with parport0 3) rmmod of pps_parport is then killed because it tries to access pardev->name, but pardev (taken from port->cad) is NULL. So add a check for NULL in the test there too. Link: http://lkml.kernel.org/r/20160714115245.12651-1-jslaby@suse.cz Signed-off-by: Jiri Slaby Acked-by: Rodolfo Giometti Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/pps/clients/pps_parport.c b/drivers/pps/clients/pps_parport.c index 38a8bbe..83797d8 100644 --- a/drivers/pps/clients/pps_parport.c +++ b/drivers/pps/clients/pps_parport.c @@ -195,7 +195,7 @@ static void parport_detach(struct parport *port) struct pps_client_pp *device; /* FIXME: oooh, this is ugly! */ - if (strcmp(pardev->name, KBUILD_MODNAME)) + if (!pardev || strcmp(pardev->name, KBUILD_MODNAME)) /* not our port */ return; -- cgit v0.10.2 From 530dd8d4b9daf77e3e5d145a26210d91ced954c7 Mon Sep 17 00:00:00 2001 From: Andy Lutomirski Date: Fri, 22 Jul 2016 21:58:08 -0700 Subject: x86/mm/cpa: Fix populate_pgd(): Stop trying to deallocate failed PUDs Valdis Kletnieks bisected a boot failure back to this recent commit: 360cb4d15567 ("x86/mm/cpa: In populate_pgd(), don't set the PGD entry until it's populated") I broke the case where a PUD table got allocated -- populate_pud() would wander off a pgd_none entry and get lost. I'm not sure how this survived my testing. Fix the original issue in a much simpler way. The problem was that, if we allocated a PUD table, failed to populate it, and freed it, another CPU could potentially keep using the PGD entry we installed (either by copying it via vmalloc_fault or by speculatively caching it). There's a straightforward fix: simply leave the top-level entry in place if this happens. This can't waste any significant amount of memory -- there are at most 256 entries like this systemwide and, as a practical matter, if we hit this failure path repeatedly, we're likely to reuse the same page anyway. For context, this is a reversion with this hunk added in: if (ret < 0) { + /* + * Leave the PUD page in place in case some other CPU or thread + * already found it, but remove any useless entries we just + * added to it. + */ - unmap_pgd_range(cpa->pgd, addr, + unmap_pud_range(pgd_entry, addr, addr + (cpa->numpages << PAGE_SHIFT)); return ret; } This effectively open-codes what the now-deleted unmap_pgd_range() function used to do except that unmap_pgd_range() used to try to free the page as well. Reported-by: Valdis Kletnieks Signed-off-by: Andy Lutomirski Cc: Andrew Morton Cc: Borislav Petkov Cc: Brian Gerst Cc: Denys Vlasenko Cc: H. Peter Anvin Cc: Josh Poimboeuf Cc: Linus Torvalds Cc: Luis R. Rodriguez Cc: Mike Krinkin Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: Toshi Kani Link: http://lkml.kernel.org/r/21cbc2822aa18aa812c0215f4231dbf5f65afa7f.1469249789.git.luto@kernel.org Signed-off-by: Ingo Molnar diff --git a/arch/x86/mm/pageattr.c b/arch/x86/mm/pageattr.c index 26c93c6..2bc6ea1 100644 --- a/arch/x86/mm/pageattr.c +++ b/arch/x86/mm/pageattr.c @@ -1082,6 +1082,8 @@ static int populate_pgd(struct cpa_data *cpa, unsigned long addr) pud = (pud_t *)get_zeroed_page(GFP_KERNEL | __GFP_NOTRACK); if (!pud) return -1; + + set_pgd(pgd_entry, __pgd(__pa(pud) | _KERNPG_TABLE)); } pgprot_val(pgprot) &= ~pgprot_val(cpa->mask_clr); @@ -1089,16 +1091,11 @@ static int populate_pgd(struct cpa_data *cpa, unsigned long addr) ret = populate_pud(cpa, addr, pgd_entry, pgprot); if (ret < 0) { - if (pud) - free_page((unsigned long)pud); unmap_pud_range(pgd_entry, addr, addr + (cpa->numpages << PAGE_SHIFT)); return ret; } - if (pud) - set_pgd(pgd_entry, __pgd(__pa(pud) | _KERNPG_TABLE)); - cpa->numpages = ret; return 0; } -- cgit v0.10.2 From 55920d31f1e3fea06702c74271dd56c4fc9b70ca Mon Sep 17 00:00:00 2001 From: Andy Lutomirski Date: Sat, 23 Jul 2016 09:59:28 -0700 Subject: x86/mm/cpa: Add missing comment in populate_pdg() In commit: 21cbc2822aa1 ("x86/mm/cpa: Unbreak populate_pgd(): stop trying to deallocate failed PUDs") I intended to add this comment, but I failed at using git. Signed-off-by: Andy Lutomirski Cc: Borislav Petkov Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/242baf8612394f4e31216f96d13c4d2e9b90d1b7.1469293159.git.luto@kernel.org Signed-off-by: Ingo Molnar diff --git a/arch/x86/mm/pageattr.c b/arch/x86/mm/pageattr.c index 2bc6ea1..47870a5 100644 --- a/arch/x86/mm/pageattr.c +++ b/arch/x86/mm/pageattr.c @@ -1091,6 +1091,11 @@ static int populate_pgd(struct cpa_data *cpa, unsigned long addr) ret = populate_pud(cpa, addr, pgd_entry, pgprot); if (ret < 0) { + /* + * Leave the PUD page in place in case some other CPU or thread + * already found it, but remove any useless entries we just + * added to it. + */ unmap_pud_range(pgd_entry, addr, addr + (cpa->numpages << PAGE_SHIFT)); return ret; -- cgit v0.10.2 From 523d939ef98fd712632d93a5a2b588e477a7565e Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Sun, 24 Jul 2016 12:23:50 -0700 Subject: Linux 4.7 diff --git a/Makefile b/Makefile index 81b2262..66da9a3 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ VERSION = 4 PATCHLEVEL = 7 SUBLEVEL = 0 -EXTRAVERSION = -rc7 +EXTRAVERSION = NAME = Psychotic Stoned Sheep # *DOCUMENTATION* -- cgit v0.10.2 From d51306f1a3bc0e3a7b86d8f2b2dedf34b356d3dd Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Sat, 23 Jul 2016 14:35:40 +1000 Subject: x86: Make the vdso2c compiler use the host architecture headers To be clear: this is a ppc64le hosted, x86_64 target cross build. Signed-off-by: Stephen Rothwell Acked-by: Andy Lutomirski Cc: H. Peter Anvin Cc: Josh Poimboeuf Cc: Peter Zijlstra Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/20160723150845.3af8e452@canb.auug.org.au Signed-off-by: Arnaldo Carvalho de Melo diff --git a/arch/x86/entry/vdso/Makefile b/arch/x86/entry/vdso/Makefile index 253b72e..25e88c0 100644 --- a/arch/x86/entry/vdso/Makefile +++ b/arch/x86/entry/vdso/Makefile @@ -55,7 +55,7 @@ VDSO_LDFLAGS_vdso.lds = -m64 -Wl,-soname=linux-vdso.so.1 \ $(obj)/vdso64.so.dbg: $(src)/vdso.lds $(vobjs) FORCE $(call if_changed,vdso) -HOST_EXTRACFLAGS += -I$(srctree)/tools/include -I$(srctree)/include/uapi -I$(srctree)/arch/x86/include/uapi +HOST_EXTRACFLAGS += -I$(srctree)/tools/include -I$(srctree)/include/uapi -I$(srctree)/arch/$(SUBARCH)/include/uapi hostprogs-y += vdso2c quiet_cmd_vdso2c = VDSO2C $@ -- cgit v0.10.2 From 4e3ba8af21b00b91b451e7c4a9fa3a63b025dd56 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Mon, 25 Jul 2016 11:57:37 -0300 Subject: Revert "perf tools: event.h needs asm/perf_regs.h" This reverts commit e083a21fcac9311ca425e600a15332f4792c56cc. Not needed at all, tools/perf/util/perf_regs.h, included via: #include "perf_regs.h" Should have a definition for PERF_REGS_MAX, and since this is dependent on HAVE_PERF_REGS_SUPPORT, fixes the build on powerpc, noticed by trying to cross compile this from ubuntu16.04 with a locally build libz & elfutils pair, since those are not available in multilib packages. Cc: Jiri Olsa Cc: Naveen N. Rao Cc: Stephane Eranian Cc: Sukadev Bhattiprolu Link: http://lkml.kernel.org/n/tip-0bv204s71t4wuw1l53b6fz79@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h index b32464b..8d363d5 100644 --- a/tools/perf/util/event.h +++ b/tools/perf/util/event.h @@ -8,7 +8,6 @@ #include "map.h" #include "build-id.h" #include "perf_regs.h" -#include struct mmap_event { struct perf_event_header header; -- cgit v0.10.2